2010-08-19 64 views
5
class Foo 
    include Module.new { class_eval "def lab; puts 'm' end" } 

    def lab 
     super 
     puts 'c' 
    end 
end 

Foo.new.lab #=> m c 

======================================= =================================instance_eval vs class_eval in module

class Foo 
    include Module.new { instance_eval "def lab; puts 'm' end" } 

    def lab 
     super 
     puts 'c' 
    end 
end 

注意这里我改变class_eval到instance_eval的

Foo.new.lab rescue nil#=> no super class method lab 
Foo.lab #=> undefined method lab for Foo class 

所以看起来包括模块既没有定义实例方法也没有定义类方法。

任何解释发生了什么?

这段代码在mac上用ruby 1.8.7测试过。

回答

9

首先,想想include的功能。它使得该模块的方法被包括在实例上的包含类的方法。即除了您的工作示例使用匿名模块,它相当于一个事实:

module M1 
    def lab 
    puts 'm' 
    end 
end 

class Foo 
    include M1 

    def lab 
     super 
     puts 'c' 
    end 
end 

接下来,想到什么做class_eval。它在类或模块的上下文中评估给定的代码。即完全像您重新打开模块并键入传递给class_eval的代码。所以MyModule = Module.new { class_eval "def lab; puts 'm' end" }相当于

module MyModule 
    def lab 
    puts 'm' 
    end 
end 

希望这可以解释工程案例。

当使用instance_eval您正在评估的接收对象的上下文中的代码(在这种情况下,模块的实例),因此MyMod2 = Module.new { instance_eval "def lab; puts 'm' end" }相当于

module MyMod2 
    def MyMod2.lab 
    puts 'm' 
    end 
end 

即它创建一个模块方法,其你可以通过MyMod2.lab调用,并且这种方法不作为include的实例方法添加。


请注意:这个答案借用一点的解释从Ruby编程语言书有关的一个例子的答案,我写信给previous question asking about instance_eval vs. class_eval。你可能会发现这个答案也有帮助。

+0

优秀的解释。将事情分开并一次一步地看着它会有所帮助。 – 2010-08-19 17:41:41

3

包括一个模块只需要实例方法 - 您正在寻找扩展。幸运的是,以获得两全其美的,你可以简单地做:

module Something 
    def self.included(base) 
    base.extend ClassMethods 
    end 

    module ClassMethods 
    def blah 
     puts "lol" 
    end 
    end 
end 

class Test 
    include Something 
end 

IRB:

>> Test.blah 
lol 
=> nil