2016-11-08 4 views
1

Я пытаюсь реализовать приложения, основанного валюты с помощью 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 

Это прямой перевод некоторого кода из книги Кента Бекка в Руби. Когда я бегу 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 выполнит ваш второй_скрипт.

EDIT: Циркуляр требует не проблема:

# 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, ... и ничего не вкладывать в Фран в Деньгах.

2

Я собирался добавить это в качестве комментария, когда понял, что он начнет становиться слишком длинным.

Когда вы говорите, что вы переводили непосредственно из книги Кента Бек, я предполагаю, что вы ссылаетесь на его TDD по книге примеров (это единственная книга, которую я могу найти в его книге, которая ссылается на пример валюты). Однако я не могу найти пример в этой книге, но это относится к циклической зависимости, однако из предыдущего опыта работы с Java и C++ вы обычно пытаетесь разбить циклическую зависимость, реализуя интерфейс - для Ruby вы можете обратиться к следующий SO вопроса, который имеет хорошие ответы на эту проблему:

Circular Dependancies in Ruby

Сказав, что я думаю, что ваш дизайн сломан. Ваш класс Money должен определять общее поведение и атрибуты для всех типов денег. Он не должен знать ничего о франках или долларах и т. Д. Конкретное поведение для франка должно быть полностью инкапсулировано внутри класса франков. Либо используйте один класс для обработки всех валют или использования наследования - не имеет смысла делать то и другое.

Смежные вопросы