[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Module intercepts containing class's initialize method?

Lloyd Zusman

2/6/2005 1:37:00 AM

I'm wondering if something like this is possible:

module Intercept
def intercept_initialize
puts "performing Intercept#intercept_initialize"
# somehow call containing class's 'initialize' method here
end
end

class Foo
def initialize
puts "performing Foo#initialize"
end
end

class Bar
include Intercept
def initialize
puts "performing Bar#initialize"
end
end

puts "instatiating Foo"
Foo.new
puts "instatiating Bar"
Bar.new
puts "done"

Desired results:

instantiating Foo
performing Foo#initialize
instantiating Bar
performing Intercept#intercept_initialize
performing Bar#initialize
done

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.

Is this possible? If so, how?

Thanks in advance.


--
Lloyd Zusman
ljz@asfast.com
God bless you.



5 Answers

Florian Gross

2/6/2005 2:16:00 AM

0

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...

I'd also like there to be a better way of doing this and if I'm not
completely wrong and confusing things matz is already thinking about
this issue.

Lloyd Zusman

2/6/2005 2:53:00 AM

0

Florian Gross <flgr@ccan.de> writes:

> 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?


> I'd also like there to be a better way of doing this and if I'm not
> completely wrong and confusing things matz is already thinking about
> this issue.

Yes, that would be great.


Thank you very much.


--
Lloyd Zusman
ljz@asfast.com
God bless you.



Florian Gross

2/6/2005 3:39:00 AM

0

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...

Assaph Mehr

2/6/2005 10:44:00 PM

0


Lloyd Zusman wrote:
> I'm wondering if something like this is possible:
>
> module Intercept
> def intercept_initialize
> puts "performing Intercept#intercept_initialize"
> # somehow call containing class's 'initialize' method here
> end
> end
>
> class Foo
> def initialize
> puts "performing Foo#initialize"
> end
> end
>
> class Bar
> include Intercept
> def initialize
> puts "performing Bar#initialize"
> end
> end
>
> puts "instatiating Foo"
> Foo.new
> puts "instatiating Bar"
> Bar.new
> puts "done"
>
> Desired results:
>
> instantiating Foo
> performing Foo#initialize
> instantiating Bar
> performing Intercept#intercept_initialize
> performing Bar#initialize
> done
>
> 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.

Simply redefine IncludingClass::new like this:

.. module Intercept
.. def self.included(mod)
.. super(mod)
.. def mod.intercept_initialize
.. puts "performing Intercept#intercept_initialize"
.. # somehow call containing class's 'initialize' method here
.. end
.. def mod.new *args
.. inst = super *args
.. intercept_initialize
.. inst
.. end
.. end
.. end
.
.. class Foo
.. def initialize
.. puts "performing Foo#initialize"
.. end
.. end
.
.. class Bar
.. include Intercept
.. def initialize
.. puts "performing Bar#initialize"
.. end
.. end
.
.. puts "instatiating Foo"
.. Foo.new
.. puts "instatiating Bar"
.. Bar.new
.. puts "done"

Robert Klemme

2/7/2005 9:26:00 AM

0


"Lloyd Zusman" <ljz@asfast.com> schrieb im Newsbeitrag
news:m3vf968oa9.fsf@asfast.com...
> I'm wondering if something like this is possible:
>
> module Intercept
> def intercept_initialize
> puts "performing Intercept#intercept_initialize"
> # somehow call containing class's 'initialize' method here
> end
> end
>
> class Foo
> def initialize
> puts "performing Foo#initialize"
> end
> end
>
> class Bar
> include Intercept
> def initialize
> puts "performing Bar#initialize"
> end
> end
>
> puts "instatiating Foo"
> Foo.new
> puts "instatiating Bar"
> Bar.new
> puts "done"
>
> Desired results:
>
> instantiating Foo
> performing Foo#initialize
> instantiating Bar
> performing Intercept#intercept_initialize
> performing Bar#initialize
> done
>
> 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.
>
> Is this possible? If so, how?

The proper way is to use super IMHO:

module Intercept
def initialize(*a,&b)
super
puts "performing Intercept#intercept_initialize"
# somehow call containing class's 'initialize' method here
end
end

class Foo
def initialize
super
puts "performing Foo#initialize"
end
end

class Bar
include Intercept
def initialize
super
puts "performing Bar#initialize"
end
end

All other suggested approaches (changing a class's new or using a hook)
are more complicated than necessary IMHO.

Kind regards

robert