我一直试图弄清楚如何从模块中扩展initialize
的行为。我想这样做,而不是在混合的类的initialize
中调用super。我想支持调用include
的正常模式我无法理解。我已经阅读了我能在这件事上找到的所有内容,虽然有人提出建议,但实际上似乎没有任何建议(至少在我手中)。
以下是我认为的事情:
include
上的挂钩(即Module.included(base)
)来完成。include
挂钩将在包含类定义initialize
之前执行,因此无需简单地尝试使用initialize
定义base.instance_eval
,因为它会被覆盖。< / LI>
建议使用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
在我看来,来自Foo类的initialize
仍在覆盖模块中的定义。我猜这是因为定义仍然是开放的,这表明不是最后一个块启动的问题,最后是“胜利”。
如果那里的任何人真的知道如何做到这一点并让它运作,请启发我。
FWIW,是的,我认为我有充分的理由想要这样做。
答案 0 :(得分:28)
如果您使用的是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
答案 1 :(得分:6)
好的,在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
返回......
Hello from Mo
Hello from Foo
答案 2 :(得分:0)
在Foo的初始化中有一个条件调用是否满足,如果它存在,只调用一个包含的方法?
module Mo
def initialize_extra
puts "Hello from Mo"
end
end
class Foo
include Mo
def initialize
if defined? initialize_extra
initialize_extra
else
puts "Hello from Foo"
end
end
end
x = Foo.new
答案 3 :(得分:0)
如果使用Rails ,您还可以使用ActiveSupport::Concern
这样操作:
module M
extend ActiveSupport::Concern
included do
attr_reader :some_reader
end
def initialize
puts 'module initialize'
end
end
class Foo
include M
def initialize
super
puts 'class initialize'
end
end
呼叫Foo.new
将会输出
module initialize
class initialize
如果有兴趣,您也可以阅读this文章