循环要求Ruby问题

时间:2016-11-08 09:52:05

标签: ruby rspec

我正在尝试使用Ruby实现基于货币的应用程序,我发现:

  require 'dollar'
  require 'franc'

 puts 'Why does this not work?'

 class Money

   attr_reader :amount

   def self.dollar(number)
     Dollar.new number
   end

   def ==(other)
     self.amount == other.amount
   end 

   def self.franc(number)
     Franc.new(number)
   end

end

我有Franc类看起来像这样:

require 'money'

class Franc < Money

  attr_reader :amount

  def initialize(amount)
    @amount = number
  end

  def times(mul)
    amount = @amount * mul
    Franc.new(amount)
  end

  def ==(other)
    return false unless other.is_a? self.class
    super
  end

end

这是将Kent Beck的一些代码直接翻译成Ruby。当我运行bin/rspec时,我看到了:

/home/vamsi/Do/wycash/lib/franc.rb:3:in `<top (required)>': uninitialized constant Money (NameError)
    from /home/vamsi/Do/wycash/lib/money.rb:2:in `require'
    from /home/vamsi/Do/wycash/lib/money.rb:2:in `<top (required)>'
    from /home/vamsi/Do/wycash/lib/dollar.rb:1:in `require'
    from /home/vamsi/Do/wycash/lib/dollar.rb:1:in `<top (required)>'
    from /home/vamsi/Do/wycash/spec/dollar_spec.rb:1:in `require'
    from /home/vamsi/Do/wycash/spec/dollar_spec.rb:1:in `<top (required)>'
    from /home/vamsi/Do/wycash/.bundle/ruby/2.3.0/gems/rspec-core-3.5.4/lib/rspec/core/configuration.rb:1435:in `load'
    from /home/vamsi/Do/wycash/.bundle/ruby/2.3.0/gems/rspec-core-3.5.4/lib/rspec/core/configuration.rb:1435:in `block in load_spec_files'
    from /home/vamsi/Do/wycash/.bundle/ruby/2.3.0/gems/rspec-core-3.5.4/lib/rspec/core/configuration.rb:1433:in `each'
    from /home/vamsi/Do/wycash/.bundle/ruby/2.3.0/gems/rspec-core-3.5.4/lib/rspec/core/configuration.rb:1433:in `load_spec_files'
    from /home/vamsi/Do/wycash/.bundle/ruby/2.3.0/gems/rspec-core-3.5.4/lib/rspec/core/runner.rb:100:in `setup'
    from /home/vamsi/Do/wycash/.bundle/ruby/2.3.0/gems/rspec-core-3.5.4/lib/rspec/core/runner.rb:86:in `run'
    from /home/vamsi/Do/wycash/.bundle/ruby/2.3.0/gems/rspec-core-3.5.4/lib/rspec/core/runner.rb:71:in `run'
    from /home/vamsi/Do/wycash/.bundle/ruby/2.3.0/gems/rspec-core-3.5.4/lib/rspec/core/runner.rb:45:in `invoke'
    from /home/vamsi/Do/wycash/.bundle/ruby/2.3.0/gems/rspec-core-3.5.4/exe/rspec:4:in `<top (required)>'
    from bin/rspec:17:in `load'
    from bin/rspec:17:in `<main>'

2 个答案:

答案 0 :(得分:2)

当我意识到它会开始变得过于冗长时,我会将其添加为评论。

当你说你直接从Kent Beck的书中翻译时,我假设你指的是他的TDD by Example book(这是我能找到的唯一一本参考货币例子的书)。我实际上无法在那本书中找到一个例子,但是它指的是循环依赖,但是根据以前的Java和C ++经验,你通常试图通过实现一个接口来打破循环依赖 - 对于Ruby,你可能想要参考以下问题对这个问题有很好的答案:

Circular Dependancies in Ruby

话虽如此,我认为你的设计已被打破。您的Money类应该定义所有Money类型的通用行为和属性。它应该对法郎或美元等一无所知......法郎的具体行为应完全包含在法郎类中。使用单个类来处理所有货币或使用继承 - 两者都没有多大意义。

答案 1 :(得分:1)

在第一个脚本中定义Money之后,应该放置require 'franc'

当Ruby执行你的second_script时,将定义Money类。

编辑: 通知要求不是问题:

# a.rb
puts "A"
require_relative 'b'

# b.rb
puts "B"
require_relative 'a'

# ruby a.rb
A
B
A

load './b.rb'替换require_relative将导致无限循环和“堆栈级别太深”错误。

尽管如此,你应该用money.rb定义Money,franc.rb中的Franc,......并且不要在Money中添加任何有关Franc的内容。