11

[红宝石 1.8]

假设我有:

dummy "string" do
    puts "thing" 
end

现在,这是对一个方法的调用,该方法具有一个字符串和一个块作为输入参数。好的。

现在假设我可以有很多类似的调用(不同的方法名称,相同的参数)。例子:

otherdummy "string" do
    puts "thing"
end

现在因为他们做同样的事情,而且他们可能有数百个,我不想为想要的类中的每个创建一个实例方法。我宁愿找到一种聪明的方法来根据一般规则在运行时动态定义方法。

那可能吗?常用的技术有哪些?

谢谢

4

3 回答 3

8

我特别喜欢使用method_missing,尤其是当您要使用的代码在各种方法调用中非常相似时。这是该站点的一个示例- 每当有人调用x.booboo不存在时,method_missing 会使用boo、 的参数boo和(可选)块调用:

class ActiveRecord::Base
  def method_missing(meth, *args, &block)
    if meth.to_s =~ /^find_by_(.+)$/
      run_find_by_method($1, *args, &block)
    else
      super # You *must* call super if you don't handle the
            # method, otherwise you'll mess up Ruby's method
            # lookup.
    end
  end

  def run_find_by_method(attrs, *args, &block)
    # Make an array of attribute names
    attrs = attrs.split('_and_')

    # #transpose will zip the two arrays together like so:
    #   [[:a, :b, :c], [1, 2, 3]].transpose
    #   # => [[:a, 1], [:b, 2], [:c, 3]]
    attrs_with_args = [attrs, args].transpose

    # Hash[] will take the passed associative array and turn it
    # into a hash like so:
    #   Hash[[[:a, 2], [:b, 4]]] # => { :a => 2, :b => 4 }
    conditions = Hash[attrs_with_args]

    # #where and #all are new AREL goodness that will find all
    # records matching our conditions
    where(conditions).all
  end
end

define_method看起来它也适合你,但我对它的经验比method_missing. 这是来自同一链接的示例:

%w(user email food).each do |meth|
  define_method(meth) { @data[meth.to_sym] }
end
于 2011-07-28T16:00:21.710 回答
8

是的,有几个选择。

第一个是method_missing。它的第一个参数是一个符号,它是被调用的方法,其余参数是使用的参数。

class MyClass
  def method_missing(meth, *args, &block)
    # handle the method dispatch as you want;
    # call super if you cannot resolve it
  end
end

如果您事先知道需要哪些方法,则另一个选项是在运行时动态创建实例方法。这应该在课堂上完成,一个例子是这样的:

class MyClass
  1.upto(1000) do |n|
    define_method :"method_#{n}" do
      puts "I am method #{n}!"
    end
  end
end

define_method调用需要在运行时创建新实例方法的类方法是一种常见的模式。

于 2011-07-28T16:04:49.600 回答
4

使用定义方法:

class Bar 
end

bar_obj = Bar.new

class << bar_obj
 define_method :new_dynamic_method do
  puts "content goes here"
 end
end

bar_obj.new_dynamic_method

输出:

content goes here
于 2015-06-08T19:00:18.457 回答