2010-07-30 34 views
2

我正在阅读Ruby中的元编程。Ruby define_method question

下面是书中的两段代码:

my_var = "Success" 

MyClass = Class.new do 
    puts "#{my_var} in the class definition!" 
    define_method :my_method do 
    puts "#{my_var} in the method!" 
    end 
end 

MyClass.new.my_method 

⇒ Success in the class definition! 
    Success in the method! 

和:

def define_methods 
    shared = 0 

    Kernel.send :define_method, :counter do 
    shared 
    end 

    Kernel.send :define_method, :inc do |x| 
    shared += x 
    end 
end 

define_methods 

counter # => 0 
inc(4) 
counter # => 4 

我不知道为什么一个不必须使用动态调度(使用Kernel.send)的定义方法时在第一个例子中,而在第二个例子中必须使用它。

我给了它一些想法,但不能理解它。

谢谢!

回答

4

Module#define_method是私人的。私人方法只能在没有接收者的情况下被调用。因此,在第二个示例中,您需要使用反射(即send)来规避访问限制。

请注意,第一个例子仍然使用动态分派。事实上,在Ruby中,的一切(除了变量访问和某些内置运算符)都使用动态分派。

+0

“只有在没有接收器的情况下才能调用私有方法。” - 所以...只需省略接收器,那么它将是一个隐式接收器,并且它工作正常。看到我的答案。我误解了什么吗? – 2013-04-03 00:09:19

+0

@ KarolyHorvath:隐式接收者是'self',但作者希望接收者是'Kernel'。 – 2013-04-03 01:10:16

0

与本书所说的相反,它的工作原理没有Kernel.send,您只需要一个上下文,其中self的类包括Kernel--这几乎总是如此。

例如,如果你这样做的主要适用范围,它的存在:

irb(main):024:0> self.class.ancestors 
=> [Object, Kernel, BasicObject] 

因此,使用

define_method :counter do 
    shared 
    end 

工作正常。

如果在当前范围内不包含Kernel,您只需要这个技巧,例如,如果你在一个简单的BasicObject或某个用户​​创建后代类。