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

时间:2019-02-11 07:04:59

标签: ruby methods factory

我正在尝试将工厂方法集成到此英制到公制转换器中。我可以使它独立运行,但是当它遍历一个哈希值时,它会弹出一个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

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:0)

致电@units[unit]会得到nil,因为在其上方您正在以{strong> unit 和 amount 。参见for。签名是Gramulator.for(@amount, @unit)

话虽这么说... 也许我过于简化了,但是我认为您的代码可以减少。

下面,我将其重写为脚本,可以将其设置为可执行文件(使用def self.for(unit, amount))并以 ./ gramulator.rb 运行。

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

chmod +x

注意#!/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的结果。

但是,在Ruby中,使用其他有用的ingredients.each {...}方法(如 map detect 等)可能会带来更多乐趣。它们返回的结果有所不同而不是您要迭代的原始集合,因此循环的最后一行需要是“某物”。我强烈建议您调查一下。

很抱歉,很长一段时间,它只是为了帮助您 Ruby可以为您提供什么。