define_method: 如何动态创建带参数的方法

define_method: How to dynamically create methods with arguments

我想为 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

有什么想法吗?提前致谢。

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

如果我没有正确理解你的问题,你想要这样的东西:

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 方法 returns 是一个 Enumerable。)

以上或多或少等同于定义两个 class 方法,如下所示:

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

当你这样做时: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 生成 class 方法。

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