I've been having a little trouble the past couple days getting an
alias_method_chain working on the initialize method via a module getting
mixed into a class. For example:
- - - - -
module Dsl
def self.included(base)
base.instance_eval do
include InstanceMethods
alias_method :initialize_without_block_support, :initialize
alias_method :initialize, :initialize_with_block_support
end
end
module InstanceMethods
def initialize_with_block_support
p "initialize_with_block_support"
initialize_without_block_support
end
end
end
class Something
include Dsl
def initialize
p "initialize_without_block_support"
end
end
Something.new #=> prints "initialize_without_block_support", should
print "initialize_with_block_support" as well.
- - - - -
The problem in this contrived example (I believe) is that initialize is
redefined in the Something class body after the module is mixed in, thus
negating the alias_method_chain that was set up previously. So one
option is to just include modules after the initialize method is
defined, but that's not at all elegant, so I've been trying to find a
better way.
The next possibility I considered was using the method_added hook.
Something that would work like the following:
- - - - -
module Dsl
def self.included(base)
base.extend ClassMethods
base.instance_eval { include InstanceMethods }
end
module ClassMethods
def method_added(name)
if name == :initialize && !@redefining_initialize
@redefining_initialize = :stop_those_infinite_loops!
alias_method :initialize_without_block_support, :initialize
alias_method :initialize, :initialize_with_block_support
remove_instance_variable :@redefining_initialize
end
end
end
module InstanceMethods
def initialize_with_block_support
p "initialize_with_block_support"
initialize_without_block_support
end
end
end
class Something
include Dsl
def initialize
p "initialize_without_block_support"
end
end
Something.new
- - - - -
This works, but feels pretty hackety. If you happen to have any
experience doing something like this and have an alternative solution,
or feedback on this implementation using method_added, I'd appreciate
hearing it. As a note, the @redefining_initialize guard is necessary
because alias_method triggers the method_added hook.
Thanks for your time!
--
Posted via http://www.ruby-forum.com/.
> Hi,
>
> I've been having a little trouble the past couple days getting an
> alias_method_chain working on the initialize method via a module
> getting
> mixed into a class. For example:
Don't use alias_method_chain.
Ever.
You already have inheritance.
It works far better.
Use super:
module DSL
def initialize
puts "dsl initialize"
end
end
class Something
include DSL
def initialize
super
puts "something initialize"
end
end
Oh, inheritance also works when you don't bother to define initialize
in Something.
class A
def initialize(&block)
@_original_self = block.binding.eval("self")
instance_eval(&block) if block_given?
remove_instance_variable :@_original_self
finish_init if defined? :finish_init
end
def print_me_a
p "print_me_a"
end
def method_missing(name, *args, &block)
@_original_self ? @_original_self.send(name, *args, &block) : super
end
end
class B < A
def initialize
super
end
def finish_init
p "finish_init"
end
def print_me_b
p "print_me_b"
end
end
class C
def self.run
B.new do
print_me_a
print_me_b
print_me_c
end
end
def self.print_me_c
p "print_me_c"
end
end
b = C.run
#=> "print_me_a"
#=> "print_me_b"
#=> "print_me_c"
#=> "finish_init"
Thanks for the input, it was helpful!