我正在测试元编程,我有一个案例,我不明白:
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
在哪里定义“a”方法? 这是因为:
Foo.new.a,Foo.a和Class.a不起作用!
如果我在Foo类中使用include而不是extend,方法“a”是为Class Foo定义的(Foo.a可以工作),我想:如果“self”为include = Class,“self”为extend = Metaclass ,但没有。
可以解释方法“a”在哪里?
答案 0 :(得分:7)
append_features
是ruby中的一个钩子方法,当你执行include Bar
时,它被调用。现在它将类方法a
添加到类Bar
,然后它将类方法a
提供给Foo
。
让我解释一下这个方法a
如何成为Bar
的类方法。当您执行include Bar
时,将调用hook方法,并将其参数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
在哪里定义“a”方法?因为:Foo.new.a,Foo.a和Class.a不起作用!
这是因为你做了extend Bar
,它没有调用钩子方法append_features
。因此,类a
尚未在类Bar
中定义,正如您所期望的那样。
答案 1 :(得分:1)
“当这个模块包含在中时,Ruby会调用此模块中的append_features”(docs) - 你extended
栏,而不是included
栏。除了更改self
的定义之外,包含和扩展做了一些不同的事情 - 例如,它们的钩子方法是不同的。我怀疑在您append_features
Bar的情况下,extend
永远不会被调用。