I have been trying to figure out how to extend the behavior of initialize
from a module. I want to do it without calling super in initialize
of the class that is being mixed into. I want to support the normal pattern of calling include
I can't figure it out. I've read everything I can find on the matter and, while people to have suggestions, none of them actually seem to work (in my hands at least).
Here is what I (think) I know:
include
(i.e. Module.included(base)
).include
hook will execute before the including class defines initialize
so there is no point to simply trying to define initialize
with base.instance_eval
because it will get overwritten.A suggestion was made to make use of the method_added
hook and deal with it in there. That is what I'm trying now but it appears that the hook executes at the beginning of method definition so you end up with what you see below.
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
This results in the following output:
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
It looks to me like initialize
from class Foo is still overwriting the definition from the module. I'm guessing that this is because the definition is still open, suggesting that it isn't a matter of which block is started last be which is finished last that "wins".
If anyone out there really knows how to do this and have it work please enlighten me.
FWIW, yes, I think I have a good reason for wanting to do this.
Overriding main methodYou cannot override static methods and since the public static void main() method is static we cannot override it.
The answer is No, you cannot override the same method in one class.
Verb Congress overrode the President's veto. These new rules override the old ones.
The final way of preventing overriding is by using the final keyword in your method. The final keyword puts a stop to being an inheritance. Hence, if a method is made final it will be considered final implementation and no other class can override the behavior.
Ok, well in Ruby 1.9 you could add functionality to the new
class method...
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
That returns...
Hello from Mo
Hello from Foo
If you're on Ruby 2.0 or later, you can just use prepend
. Either require the user to prepend
rather than include
, or do:
module Mo
module Initializer
def initialize
puts "Hello from Mo#initialize"
super
end
end
def self.included(klass)
klass.send :prepend, Initializer
end
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With