2016-11-08 65 views
1

我想实现使用Ruby的货币基础的应用,我发现:通知要求的问题和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>' 
+0

spec_helper应该包含'require_relative'lib/money.rb'' –

+0

你可以发布[mcve]吗? – Stefan

回答

1

你应该把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 

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

不过,您应该用money.rb,franc.rb中的Franc来定义Money,而不是将任何有关Franc的东西放在Money中。

2

当我意识到它会开始变得太长时,我会添加这个作为评论。

当你说你直接从Kent Beck的书翻译过来的时候,我假设你指的是他的TDD by Example book(这是我能找到的关于他的货币例子的唯一书)。但是我实际上找不到那本书中提到循环依赖的例子,但是从以前使用Java和C++的经验来看,您通常会尝试通过实现一个接口来打破循环依赖 - 对于Ruby,您可能需要参考下面SO质疑其具有良好的回答这个问题:

Circular Dependancies in Ruby

话虽如此,我认为你的设计是坏了。您的Money类应该为所有Money类型定义通用行为和属性。它应该对法郎或美元等一无所知......法郎的具体行为应完全封装在法郎类别中。要么使用一个类来处理所有的货币,要么使用继承 - 两者都没有太大的意义。