2016-11-08 67 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類型定義通用行爲和屬性。它應該對法郎或美元等一無所知......法郎的具體行爲應完全封裝在法郎類別中。要麼使用一個類來處理所有的貨幣,要麼使用繼承 - 兩者都沒有太大的意義。