Метод фабрики Ruby возвращает NoMethodError при вызове.Что случилось? - PullRequest
0 голосов
/ 11 февраля 2019

Я пытаюсь интегрировать фабричный метод в этот имперско-метрический преобразователь.Я могу заставить его работать независимо, но когда он проходит через хэш ингредиентов, он вызывает 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 голосов
/ 11 февраля 2019

Когда вы звоните @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 вы могли бы получить гораздо больше удовольствия от других полезных *Методы 1030 *, такие как map , обнаружить и т. Д. Они возвращают нечто иное, чем исходная коллекция, с которой вы работаете, поэтому последняя строка их циклов должна быть 'что-то'.Я настоятельно рекомендую вам взглянуть на них.

Извините за то, что долго, это просто чтобы помочь вам чувствовать , что может предложить вам Руби.

0 голосов
/ 11 февраля 2019

Вы используете Gramulator.for(@amount, @unit), но Gramulator.for ожидает unit, amount.

Это заставляет @units[unit] возвращать ноль, потому что вы даете ему "3.5" вместо "cups" в аргументе единицы.

...