我一直在试图弄清楚如何扩展initialize
模块的行为。我想在不调用initialize
被混入的类的 super 的情况下做到这一点。我想支持include
我无法弄清楚的正常调用模式。我已经阅读了我能找到的关于这件事的所有内容,虽然人们有建议,但它们似乎都没有真正起作用(至少在我手中)。
这是我(认为)我知道的:
- 如果它可以完成,则必须使用
include
(ieModule.included(base)
) 上的钩子来完成。 - 该
include
钩子将在包含类定义之前执行,initialize
因此简单地尝试定义是没有意义的initialize
,base.instance_eval
因为它会被覆盖。 有人建议使用
method_added
钩子并在那里处理它。这就是我现在正在尝试的,但看起来钩子在方法定义的开头执行,所以你最终得到了你在下面看到的内容。module Mo def self.included(klass) klass.instance_eval do def method_added(method) puts "Starting creation of #{method} for #{self.name}" case method when :initialize alias_method :original_initialize, :initialize puts "About to define initialize in Mo" def initialize original_initialize puts "Hello from Mo#initialize" end puts "Finished defining initialize in Mo" end puts "Finishing creation of #{method} for #{self.name}" end end end end class Foo include Mo def initialize puts "Hello from Foo#initialize" end end foo = Foo.new
这将产生以下输出:
Starting creation of initialize for Foo
Starting creation of original_initialize for Foo
Finishing creation of original_initialize for Foo
About to define initialize in Mo
Finished defining initialize in Mo
Finishing creation of initialize for Foo
Hello from Foo#initialize
在我看来initialize
,类 Foo 仍在覆盖模块中的定义。我猜这是因为定义仍然是开放的,这表明最后开始哪个块不是最后一个“获胜”的问题。
如果有人真的知道如何做到这一点并让它发挥作用,请赐教。
FWIW,是的,我认为我有充分的理由想要这样做。