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
какие мысли? Спасибо заранее.
3 ответов
Если я правильно понял ваш вопрос, вы хотите что-то вроде этого:
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
Это, если Вы читаете примеры здесь 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
при этом: 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. вот учебник использовать method_missing для реализации того же функциональность, которую вы собираетесь (find_by_<x>
)