我一直在试图弄清楚如何扩展initialize
模块的行为.我想这样做而不会调用initialize
正在混入的类中的超级.我想支持正常的呼叫模式,include
我无法弄明白.我已经阅读了我能找到的关于这个问题的所有内容,虽然有人提出建议,但实际上它们似乎都没有(至少在我手中).
这是我(我想)我知道的:
include
(即Module.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
Run Code Online (Sandbox Code Playgroud)这导致以下输出:
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
Run Code Online (Sandbox Code Playgroud)
在我看来,initialize
Foo类仍然会覆盖模块中的定义.我猜这是因为定义仍然是开放的,这表明不是最后一个块启动的问题,最后是"胜利".
如果有人真的知道如何做到这一点并让它工作,请启发我.
FWIW,是的,我认为我有充分的理由想要这样做.
Chu*_*uck 29
如果您使用的是Ruby 2.0或更高版本,则可以使用prepend
.要么需要用户prepend
,而不是include
,或做:
module Mo
module Initializer
def initialize
puts "Hello from Mo#initialize"
super
end
end
def self.included(klass)
klass.send :prepend, Initializer
end
end
Run Code Online (Sandbox Code Playgroud)
好的,在Ruby 1.9中你可以为new
类方法添加功能......
module Mo
def new(*var)
additional_initialize(*var)
super(*var)
end
def additional_initialize(*var)
puts "Hello from Mo"
end
end
class Foo
extend Mo
def initialize
puts "Hello from Foo"
end
end
foo = Foo.new
Run Code Online (Sandbox Code Playgroud)
那回来......
Hello from Mo
Hello from Foo
Run Code Online (Sandbox Code Playgroud)