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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38233060/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-06 06:50:20  来源:igfitidea点击:

define_method: How to dynamically create methods with arguments

rubymetaprogramming

提问by Kostas Andrianos

I want to create a bunch of methods for a find_by feature. I don't want to write the same thing over and over again so I want to use metaprogramming.

我想为 find_by 功能创建一堆方法。我不想一遍又一遍地写同样的东西,所以我想使用元编程。

Say I want to create a method for finding by name, accepting the name as an argument. How would I do it? I've used define_method in the past but I didn't have any arguments for the method to take. Here's my (bad) approach

假设我想创建一个按名称查找的方法,接受名称作为参数。我该怎么做?我过去使用过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

Any thoughts? Thanks in advance.

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

回答by Jordan Running

If I understand your question correctly, you want something like this:

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

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

(I'm assuming that the allmethod returns an Enumerable.)

(我假设该all方法返回一个 Enumerable。)

The above is more-or-less equivalent to defining two class methods like this:

上面的内容或多或少等同于定义两个这样的类方法:

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

回答by Albin

It if you read the examples here http://apidock.com/ruby/Module/define_methodyou will find this one:

如果您阅读此处的示例http://apidock.com/ruby/Module/define_method,您会发现以下示例:

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

is the same as

是相同的

def my_method(foo, bar)
   # do something
end

回答by max pleaner

When you do this: define_method("self.find_by_#{attribute}")

当你这样做时: define_method("self.find_by_#{attribute}")

that is incorrect. The argument to define_method is a symbol with a single word.

这是不正确的。define_method 的参数是一个带有单个单词的符号。

Let me show you some correct code, hopefully this will be clear:

让我向您展示一些正确的代码,希望这会很清楚:

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

This will produce class methods for find_by_brandand find_by_name.

这将产生类的方法find_by_brandfind_by_name

Note that if you're looking into metaprogramming, this is a good use-case for method_missing. here's a tutorialto use method_missing to implement the same functionality you're going for (find_by_<x>)

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