define_method:如何使用参数动态创建方法

时间:2016-07-06 20:20:44

标签: ruby metaprogramming

我想为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 个答案:

答案 0 :(得分:37)

如果我理解你的问题,你需要这样的东西:

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

答案 1 :(得分:5)

如果你阅读这里的例子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

答案 2 :(得分:1)

执行此操作时: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_brandfind_by_name生成类方法。

请注意,如果您正在研究元编程,这是method_missing的一个很好的用例。 here's a tutorial使用method_missing实现您想要的相同功能(find_by_<x>