使用 rspec 时用 irb 加载程序
loading program with irb when using rspec
我正在用 ruby 创建一个简单的二十一点程序。我这样做是为了提高我的 TDD 技能,因此我使用 Rspec 进行测试覆盖。为了使工作更清晰,我的文件结构是一个名为 blackjack 的主文件夹。其中有 lib 和 spec 文件夹。到目前为止,在 lib 中有一个 deck.rb 和 card.rb 文件。然后我为每个都有回顾性的规范文件夹。当我尝试在 irb 中加载程序时,我 运行 遇到了这样的问题。如果我想测试在两个文件夹之间拆分的方法,我会有点困惑,我应该怎么做。单独加载卡片组和卡片文件时,出现以下错误。
2.1.1 :001 > require "./deck.rb"
=> true
2.1.1 :002 > cards = Deck.build_cards
NameError: uninitialized constant Deck::Card
from /Users/em/ruby/blackjack/lib/deck.rb:7:in `block (2 levels) in build_cards'
from /Users/em/ruby/blackjack/lib/deck.rb:6:in `each'
from /Users/em/ruby/blackjack/lib/deck.rb:6:in `block in build_cards'
from /Users/em/ruby/blackjack/lib/deck.rb:5:in `each'
from /Users/em/ruby/blackjack/lib/deck.rb:5:in `build_cards'
from (irb):2
from /Users/em/.rvm/rubies/ruby-2.1.1/bin/irb:11:in `<main>'
2.1.1 :001 > require './card'
=> true
2.1.1 :002 > cards = Deck.build_cards
NameError: uninitialized constant Deck
from (irb):2
from /Users/em/.rvm/rubies/ruby-2.1.1/bin/irb:11:in `<main>'
如果有人能帮我澄清一下,我将不胜感激。我已经包含了下面的其余代码。
card_spec.rb
require 'card'
require 'deck'
describe Card do
it "should accept a suit and value when building" do
card = Card.new(:clubs, 10)
expect(card.suit).to eq (:clubs)
expect(card.value).to eq(10)
end
it "should have a value of 10 for facecards" do
facecards = ["J", "Q", "K"]
facecards.each do |facecard|
card = Card.new(:hearts, facecard)
expect(card.value).to eq(10)
end
end
it "should have a value of 4 for the 4-clubs" do
card = Card.new(:clubs, 4)
expect(card.value).to eq(4)
end
it "should return 11 for Ace" do
card = Card.new(:diamonds, "A")
expect(card.value).to eq(11)
end
it "should be formatted nicely" do
card = Card.new(:diamonds, "A")
expect(card.to_s).to eq("A-diamonds")
end
end
deck_spec.rb
require 'card'
require 'deck'
describe Deck do
it 'should build 52 cards' do
expect(Deck.build_cards.length).to eq(52)
end
end
card.rb
require 'deck'
class Card
attr_reader :suit, :value
def initialize(suit, value)
@suit = suit
@value = value
#the value here is what the card should return-facevalue
end
def value
return 10 if ["J", "Q", "K"].include?(@value)
return 11 if @value == "A"
return @value
end
def to_s
"A-diamonds"
"#{@value}-#{suit}"
end
end
deck.rb
class Deck
def self.build_cards
cards = []
[:clubs, :diamonds, :spades, :hearts].each do |suit|
(2..10).each do |number|
cards << Card.new(suit, number)
end
["J", "Q", "K", "A"].each do |facecard|
cards << Card.new(suit, facecard)
end
end
cards
end
#going to occur on the class as it is a class method and will execute once
#The idea of a deck needs to be able to build a deck
end
您需要将 require "card"
添加到 deck.rb
,因为您在 .build_cards
中引用了 Card
。您还需要将 lib
添加到您的加载路径,因为在 Ruby 中不再为您完成。您可以在命令行上执行此操作:
irb -Ilib
ruby -Ilib
请注意,rspec
会自动为您执行此操作,这就是您的规格有效的原因。
如果需要(假设您在 bin
中有一个脚本,您想在 lib
中加载文件),您也可以在代码中执行此操作。
# Assuming this code is in bin
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
加载路径说明
-I
标志将目录添加到 $LOAD_PATH
全局变量。您可以直接在您的程序中检查它:
> ruby -e 'puts $LOAD_PATH'
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/site_ruby/2.1.0
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/site_ruby/2.1.0/x86_64-darwin13.0
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/site_ruby
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/vendor_ruby/2.1.0
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/vendor_ruby/2.1.0/x86_64-darwin13.0
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/vendor_ruby
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/2.1.0
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/2.1.0/x86_64-darwin13.0
> ruby -Itesting -e 'puts $LOAD_PATH'
/Users/xavier/Code/ex/ruby/testing
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/site_ruby/2.1.0
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/site_ruby/2.1.0/x86_64-darwin13.0
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/site_ruby
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/vendor_ruby/2.1.0
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/vendor_ruby/2.1.0/x86_64-darwin13.0
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/vendor_ruby
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/2.1.0
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/2.1.0/x86_64-darwin13.0
注意第二次调用如何包含额外的 testing
目录。如果您使用 IRB 进行了类似的测试,您会发现如果没有 -I
,您的 lib
目录将不在 $LOAD_PATH
中,这就是它无法找到您需要的文件的原因。
Ruby 使用此 $LOAD_PATH
变量来确定在您需要某些东西时要查找的位置。在伪代码中:
def require(filename)
$LOAD_PATH.each do |dir|
path = File.join(dir, filename)
if File.exist?(path)
load(path)
return
end
end
end
它实际上比那更复杂(也更高效),但这就是它的要点。如果你有兴趣,我 talked about it some at RubyConf 2013.
其他没有直接回答你问题的相关点:
您还应该从 card.rb
中删除 require "deck"
,因为该文件中的任何内容都不需要了解 Deck
。如果你有警告,这会警告你 "circular require",如果你有两个文件互相加载就会发生这种情况。这通常是一种不好的做法。 (要清楚:这不是你在这里做的,因为 card.rb
并不 实际上 依赖于 deck.rb
。
您的规格应该只需要正在测试的特定事物。在这种情况下,card_spec.rb
应该需要 card 而 deck_spec.rb
应该需要 deck。他们不需要两者都需要。
您的 IRB 要求中的 .rb
是多余的,不是必需的。
我正在用 ruby 创建一个简单的二十一点程序。我这样做是为了提高我的 TDD 技能,因此我使用 Rspec 进行测试覆盖。为了使工作更清晰,我的文件结构是一个名为 blackjack 的主文件夹。其中有 lib 和 spec 文件夹。到目前为止,在 lib 中有一个 deck.rb 和 card.rb 文件。然后我为每个都有回顾性的规范文件夹。当我尝试在 irb 中加载程序时,我 运行 遇到了这样的问题。如果我想测试在两个文件夹之间拆分的方法,我会有点困惑,我应该怎么做。单独加载卡片组和卡片文件时,出现以下错误。
2.1.1 :001 > require "./deck.rb"
=> true
2.1.1 :002 > cards = Deck.build_cards
NameError: uninitialized constant Deck::Card
from /Users/em/ruby/blackjack/lib/deck.rb:7:in `block (2 levels) in build_cards'
from /Users/em/ruby/blackjack/lib/deck.rb:6:in `each'
from /Users/em/ruby/blackjack/lib/deck.rb:6:in `block in build_cards'
from /Users/em/ruby/blackjack/lib/deck.rb:5:in `each'
from /Users/em/ruby/blackjack/lib/deck.rb:5:in `build_cards'
from (irb):2
from /Users/em/.rvm/rubies/ruby-2.1.1/bin/irb:11:in `<main>'
2.1.1 :001 > require './card'
=> true
2.1.1 :002 > cards = Deck.build_cards
NameError: uninitialized constant Deck
from (irb):2
from /Users/em/.rvm/rubies/ruby-2.1.1/bin/irb:11:in `<main>'
如果有人能帮我澄清一下,我将不胜感激。我已经包含了下面的其余代码。
card_spec.rb
require 'card'
require 'deck'
describe Card do
it "should accept a suit and value when building" do
card = Card.new(:clubs, 10)
expect(card.suit).to eq (:clubs)
expect(card.value).to eq(10)
end
it "should have a value of 10 for facecards" do
facecards = ["J", "Q", "K"]
facecards.each do |facecard|
card = Card.new(:hearts, facecard)
expect(card.value).to eq(10)
end
end
it "should have a value of 4 for the 4-clubs" do
card = Card.new(:clubs, 4)
expect(card.value).to eq(4)
end
it "should return 11 for Ace" do
card = Card.new(:diamonds, "A")
expect(card.value).to eq(11)
end
it "should be formatted nicely" do
card = Card.new(:diamonds, "A")
expect(card.to_s).to eq("A-diamonds")
end
end
deck_spec.rb
require 'card'
require 'deck'
describe Deck do
it 'should build 52 cards' do
expect(Deck.build_cards.length).to eq(52)
end
end
card.rb
require 'deck'
class Card
attr_reader :suit, :value
def initialize(suit, value)
@suit = suit
@value = value
#the value here is what the card should return-facevalue
end
def value
return 10 if ["J", "Q", "K"].include?(@value)
return 11 if @value == "A"
return @value
end
def to_s
"A-diamonds"
"#{@value}-#{suit}"
end
end
deck.rb
class Deck
def self.build_cards
cards = []
[:clubs, :diamonds, :spades, :hearts].each do |suit|
(2..10).each do |number|
cards << Card.new(suit, number)
end
["J", "Q", "K", "A"].each do |facecard|
cards << Card.new(suit, facecard)
end
end
cards
end
#going to occur on the class as it is a class method and will execute once
#The idea of a deck needs to be able to build a deck
end
您需要将 require "card"
添加到 deck.rb
,因为您在 .build_cards
中引用了 Card
。您还需要将 lib
添加到您的加载路径,因为在 Ruby 中不再为您完成。您可以在命令行上执行此操作:
irb -Ilib
ruby -Ilib
请注意,rspec
会自动为您执行此操作,这就是您的规格有效的原因。
如果需要(假设您在 bin
中有一个脚本,您想在 lib
中加载文件),您也可以在代码中执行此操作。
# Assuming this code is in bin
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
加载路径说明
-I
标志将目录添加到 $LOAD_PATH
全局变量。您可以直接在您的程序中检查它:
> ruby -e 'puts $LOAD_PATH'
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/site_ruby/2.1.0
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/site_ruby/2.1.0/x86_64-darwin13.0
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/site_ruby
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/vendor_ruby/2.1.0
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/vendor_ruby/2.1.0/x86_64-darwin13.0
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/vendor_ruby
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/2.1.0
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/2.1.0/x86_64-darwin13.0
> ruby -Itesting -e 'puts $LOAD_PATH'
/Users/xavier/Code/ex/ruby/testing
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/site_ruby/2.1.0
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/site_ruby/2.1.0/x86_64-darwin13.0
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/site_ruby
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/vendor_ruby/2.1.0
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/vendor_ruby/2.1.0/x86_64-darwin13.0
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/vendor_ruby
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/2.1.0
/Users/xavier/.rubies/ruby-2.1.3/lib/ruby/2.1.0/x86_64-darwin13.0
注意第二次调用如何包含额外的 testing
目录。如果您使用 IRB 进行了类似的测试,您会发现如果没有 -I
,您的 lib
目录将不在 $LOAD_PATH
中,这就是它无法找到您需要的文件的原因。
Ruby 使用此 $LOAD_PATH
变量来确定在您需要某些东西时要查找的位置。在伪代码中:
def require(filename)
$LOAD_PATH.each do |dir|
path = File.join(dir, filename)
if File.exist?(path)
load(path)
return
end
end
end
它实际上比那更复杂(也更高效),但这就是它的要点。如果你有兴趣,我 talked about it some at RubyConf 2013.
其他没有直接回答你问题的相关点:
您还应该从 card.rb
中删除 require "deck"
,因为该文件中的任何内容都不需要了解 Deck
。如果你有警告,这会警告你 "circular require",如果你有两个文件互相加载就会发生这种情况。这通常是一种不好的做法。 (要清楚:这不是你在这里做的,因为 card.rb
并不 实际上 依赖于 deck.rb
。
您的规格应该只需要正在测试的特定事物。在这种情况下,card_spec.rb
应该需要 card 而 deck_spec.rb
应该需要 deck。他们不需要两者都需要。
您的 IRB 要求中的 .rb
是多余的,不是必需的。