Florian Gross
2/6/2005 3:39:00 AM
Lloyd Zusman wrote:
>>> class Bar
>>> include Intercept
>>> def initialize
>>> puts "performing Bar#initialize"
>>> end
>>> end
>>>
>>>In other words, simply by including the "Intercept" module in a class,
>>>I'd like to intercept that class's call to "initialize" and have the
>>>Intercept module's code get invoked first, and _then_ the containing
>>>class's "initialize" method should be called as it normally would.
>>
>>I think the only way of doing that without putting the include() behind
>>the initialize def would be using a method_added hook...
>
> Could you explain how this could be done with a method_added hook?
Like this:
require 'thread'
module Intercept
def self.included(other)
install_initialize = lambda do
other.class_eval do
alias :old_initialize :initialize
def initialize(*args, &block)
intercept_initialize
old_initialize(*args, &block)
end
end
end
class << other; self; end.class_eval do
alias :old_method_added :method_added
ignore = false
define_method(:method_added) do |name|
return if ignore
case name
when :initialize then
Thread.exclusive do
ignore = true
install_initialize.call
ignore = false
end
else
old_method_added(name)
end
end
end
install_initialize.call
super
end
def intercept_initialize
puts "performing Intercept#intercept_initialize"
end
end
class Bar
include Intercept
def initialize
puts "performing Bar#initialize"
end
end
Bar.new
But note that in that case the user could still redefine
Bar.method_added() and circumvent the restore logic. I think adding a
singleton_method_added handler would fix that.
I'm also not sure if the Thread.exclusive stuff can be done in a cleaner
way...