模块扩展和ruby中的class_eval

时间:2013-11-20 19:29:30

标签: ruby metaprogramming

我正在测试元编程,我有一个案例,我不明白:

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”在哪里?

2 个答案:

答案 0 :(得分:7)

append_features是ruby中的一个钩子方法,当你执行include Bar时,它被调用。现在它将类方法a添加到类Bar,然后它将类方法a提供给Foo

让我解释一下这个方法a如何成为Bar的类方法。当您执行include Bar时,将调用hook方法,并将其参数klass设置为Bar。现在klass.class_eval {..}class_evalself块中设置{..}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永远不会被调用。