内核#__ method__似乎在动态定义的方法中无法正常工作

时间:2011-02-26 21:14:07

标签: ruby

我一直在尝试在Ruby 1.9中动态定义一些实例方法。这是我用来尝试这个的代码:

class Testing
  [:one, :two].each do |name|
    define_method(name) do
      puts __method__
    end
  end
end

这是输出:

ruby-1.9.2-p180 :008 > t = Testing.new
 => #<Testing:0x00000100961878> 
ruby-1.9.2-p180 :009 > t.one
two
 => nil 
ruby-1.9.2-p180 :010 > t.two
two
 => nil 
ruby-1.9.2-p180 :011 > 

我希望结果分别为onetwo。如果我在迭代之外调用每个define_method,它会按预期工作。我在这里不理解什么?

以下是我在网上看到的在迭代中调用define_method的众多示例之一。 Dynamically defined setter methods using define_method?

缺少什么?

另外:使用__method__对我来说并不重要,但这是我展示的最佳方式,似乎只有发送到define_method的最后一个块被用于定义的方法。也许这开始向我解释问题,但我仍然不明白..

3 个答案:

答案 0 :(得分:3)

很好的发现奇怪的行为。在我测试的所有红宝石中,只有MRI 1.9.2证明了这一点。

Ryan Davis reported the bug on the ruby-core list(参考此问题)。

答案 1 :(得分:0)

您可以使用此类内容而非define_method

class Testing
  [:one, :two].each do |name|
    eval <<-EOM 
        def #{name}
            puts __method__
        end
    EOM
  end
end

t = Testing.new
t.one #=> "one"
t.two #=> "two"

答案 2 :(得分:0)

发生这种情况的原因是define_method以与def相比稍微不同的方式定义方法。它与创建匿名触发器和lambda有关。我建议只是使用方法名称,因为你已经拥有它。这应该避免必须在堆栈跟踪中搜索方法名称,因此它应该执行得更好:

class Testing
  [:one, :two].each do |name|
    define_method name do
      "This method's name is #{name}."
    end
  end
end

Testing.new.one
=> This method's name is one.
Testing.new.two
=> This method's name is two.

要澄清,请注意以下两个陈述返回的内容:

class Testing
  define_method :one do
    __method__
  end
end
=> #<Proc:0x000001009ebfc8@(irb):54 (lambda)>

class Testing
  def one
    __method__
  end
end
=> nil

P.S:使用这两种格式之间也存在性能差异。您可以使用Benchmark验证自己def的速度比define_method快。