2013-11-20 119 views
2

我测试元编程,我有一个情况下,我不明白:模块扩展和class_eval红宝石

module Bar 
def self.append_features klass 
    klass.class_eval do 
    def self.a 
     puts 'a' 
    end 
    end 
end 
end 

class Foo 
extend Bar 
end 

哪里是界定“一”的方法? 因为:

Foo.new.a,Foo.a和Class.a不起作用!如果我使用include而不是Foo类的扩展,方法“a”定义为Foo类(Foo.a作品),我认为:如果include为“self”,Class =“self”为extend = Metaclass,但没有。

能解释方法“a”在哪里?

回答

6

append_features是红宝石中的钩子方法,当你做了include Bar时,它被调用。现在它将类方法a添加到类Bar,然后它使类方法aFoo可用。

让我来解释一下a如何成为Bar的类方法。当您执行了include Bar时,将调用挂接方法,并将其参数klass设置为Bar。现在klass.class_eval {..},class_eval设置self块内{..}Bar。现在def self.a;puts 'a';end实际上意味着def Bar.a;puts 'a';end

module Bar 
def self.append_features klass 
    klass.class_eval do 
    def self.a 
     puts 'a' 
    end 
    end 
end 
end 

class Foo 
include Bar 
end 

Foo.a # => a 

哪里是界定 “一” 的方法?因为:Foo.new.a,Foo.a和Class.a不起作用!

这是因为你做了extend Bar,它没有调用钩子方法append_features。正如你所期望的那样,类的类方法还没有在类Bar中定义。

+1

+1有趣! :)不知道'append_features';从来没有想过关于'extend'和'include'的区别。 – kiddorails

+0

@kiddorails这是一个聪明的主意,因为有一个简单的'ri append_features'甚至'ri Module.append_features'可以给你提供足够的信息,然后发布到SO上;} –

+0

你变得相当不错:-) –

1

“当这个模块是包含在另一个,Ruby调用此模块中append_features”(docs) - 你extended酒吧,不included酒吧。包含和扩展做了一些不同的事情,除了改变self的定义之外 - 例如,它们的钩子方法是不同的。我怀疑append_features永远不会被呼吁在你的情况下,你extend酒吧。