Подтвердить что ты не робот

Define_method: как динамически создавать методы с аргументами

Я хочу создать кучу методов для функции find_by. Я не хочу писать одно и то же снова и снова, поэтому я хочу использовать метапрограммирование.

Скажем, я хочу создать метод для поиска по имени, принимая имя в качестве аргумента. Как мне это сделать? Я использовал define_method в прошлом, но у меня не было аргументов для метода. Здесь мой (плохой) подход

["name", "brand"].each do |attribute|
    define_method("self.find_by_#{attribute}") do |attr_|
      all.each do |prod|
        return prod if prod.attr_ == attr_
      end
    end
  end

Любые мысли? Спасибо заранее.

4b9b3361

Ответ 1

Если я правильно понял ваш вопрос, вам нужно что-то вроде этого:

class Product
  class << self
    [:name, :brand].each do |attribute|
      define_method :"find_by_#{attribute}" do |value|
        all.find {|prod| prod.public_send(attribute) == value }
      end
    end
  end
end

(Я предполагаю, что метод all возвращает Enumerable.)

Вышеупомянутое более или менее эквивалентно определению двух методов класса, таких как:

class Product
  def self.find_by_name(value)
    all.find {|prod| prod.name == value }
  end

  def self.find_by_brand(value)
    all.find {|prod| prod.brand == value }
  end
end

Ответ 2

Если вы прочтете примеры здесь http://apidock.com/ruby/Module/define_method, вы найдете следующее:

define_method(:my_method) do |foo, bar| # or even |*args|
  # do something
end

совпадает с

def my_method(foo, bar)
   # do something
end

Ответ 3

Когда вы это сделаете: define_method("self.find_by_#{attribute}")

неверно. Аргументом для define_method является символ с одним словом.

Позвольте мне показать вам правильный код, надеюсь, это будет ясно:

class MyClass < ActiveRecord::Base
  ["name", "brand"].each do |attribute|
    define_method(:"find_by_#{attribute}") do |attr_|
      first(attribute.to_sym => attr_)
    end
  end
end

Это вызовет методы класса для find_by_brand и find_by_name.

Обратите внимание, что если вы смотрите на метапрограммирование, это хороший пример использования метода method_missing. здесь учебник, чтобы использовать метод_missing для реализации той же функциональности, в которой вы собираетесь (find_by_<x>)