【问题标题】:How to dynamically create instance methods at runtime?如何在运行时动态创建实例方法?
【发布时间】:2011-10-15 06:28:38
【问题描述】:

[红宝石 1.8]

假设我有:

dummy "string" do
    puts "thing" 
end

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

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

otherdummy "string" do
    puts "thing"
end

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

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

谢谢

【问题讨论】:

    标签: ruby metaprogramming ruby-1.8


    【解决方案1】:

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

    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
    

    【讨论】:

    • 感谢有用的示例(我还需要以这种方式管理方法名称)。我肯定会选择 method_missing 是不知道先验的方法。
    【解决方案2】:

    是的,有几个选项。

    第一个是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 是一种常见模式。

    【讨论】:

    • 我猜应该是puts "I am method #{n}!"。无论如何,很好的答案!
    【解决方案3】:

    使用define_method:

    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
    

    【讨论】:

      猜你喜欢
      • 2020-12-23
      • 1970-01-01
      • 1970-01-01
      • 2011-03-14
      • 2012-06-23
      • 1970-01-01
      • 1970-01-01
      • 2020-06-25
      • 1970-01-01
      相关资源
      最近更新 更多