2010-08-19 89 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 
相關問題