Ruby 工厂方法在调用时返回 NoMethodError。发生了什么事?



我正在尝试将工厂方法集成到这个英制到公制转换器中。我可以让它独立工作,但是当它迭代一个成分哈希时,它会NoMethodError。我做错了什么?

我已经通过工厂运行了独立的实例变量,没有问题:

@item = "cups"
@number = 89.2
Gramulator.for(@number, @item) # => 828.0300000000001

我已经确认它与输入一起正常工作。我什至用@dough.unit运行它并成功@dough.amount

Gramulator for(@dough.amount, @dough.unit) # => 828.0300000000001

但是当我通过迭代方法本身指向它时,@dough.gramulate不起作用。

class Unit
def initialize(amount)
@amount = amount
end
def calculate
@amount.to_f
end
end
class Cup < Unit
def calculate
(super * 236.58)
end
end
class Recipe
attr_accessor :amount
attr_reader   :name, :unit
def initialize(ingredient_hash)
@ingredient_hash = ingredient_hash
end
def gramulate
puts "CONVERTED TO GRAMS:"
@ingredient_hash.each do |name, quantity|
quantity_array = quantity.split
@name    =  name
@amount  =  quantity_array[0].to_f
@unit    =  quantity_array[1]
Gramulator.for(@amount, @unit)
puts "#{@name}: #{@amount} grams"
end
end
end
module Gramulator
@units = {
"cups"   => Cup
# <other measurements>
}
def self.for(unit, amount)
(@units[unit]).new(amount).calculate
end
end
@dough = Recipe.new({
bread_flour: "3.5 cups"
# <other ingredients>
})

预期成果:

CONVERTED TO GRAMS:
bread_flour: 828.0300000000001 grams

实际结果:

CONVERTED TO GRAMS:
NoMethodError: undefined method 'new' for nil:NilClass

您使用Gramulator.for(@amount, @unit),但Gramulator.for期望unit, amount

这会导致@units[unit]返回 nil,因为您是在 unit 参数中"3.5"而不是"cups"它。

当你调用@units[unit]时,你会得到nil,因为在它上面,你调用的是单位数量倒置的for。请参阅Gramulator.for(@amount, @unit)。标志是def self.for(unit, amount).

话虽如此... 也许我过于简化它,但我认为您的代码可以减少。

下面我把它重写为一个脚本,可以设置为可执行文件(带chmod +x)并作为./gramulator.rb运行。

如果您需要将其合并到更大的项目中,请随意跳过第一行和最后两行。

#!/usr/bin/env ruby
class Gramulator
UNITS = { "cups" => 236.58 }
def self.for(unit, amount)
amount.to_f * UNITS[unit]
end
end
class Recipe
def initialize(ingredients)
@ingredients = ingredients
end
def gramulate
puts "CONVERTED TO GRAMS"
@ingredients.each do |name, quantity|
amount, unit = quantity.split
puts "%s: %.2f grams" % [name, amount]
Gramulator.for(unit, amount)
end
end
end
dough = Recipe.new({ bread_flour: "3.5 cups" })
dough.gramulate

请注意puts返回nil,因此避免在循环/迭代矿石方法结束时使用它是一个好习惯。在这里,您使用的是each,这很好,因为您可能对重用ingredients.each {...}结果不感兴趣。

但是,在 Ruby 中,您可以使用其他有用的Enumerable方法获得更多乐趣,例如map检测等。它们返回的内容与您正在迭代的原始集合不同,因此其循环的最后一行必须是"某些内容"。我强烈建议您研究它们。

很抱歉时间太长了,这只是为了帮助您感受Ruby 可以为您提供什么。

相关内容

最新更新