[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

extending instance methods from a class object

William Morgan

10/29/2004 3:30:00 PM

Hi all,

I'm currently drowning in a pool of instance_methods and define_methods
and I can't seem to get out. I know there's an elegant solution
somewhere....

I have a Class object klass. It has an instance method meth(). I'd like
to "extend" meth() so that when it's called, the output is changed---I
want to call the original meth(), tweak its result, and then return it.
I need to return a Class object that has this tweak in place; I can
either change klass and return that or I can subclass it and return the
subclass.

Something like:

def tweaked_class(klass)
old_meth = klass.instance_method(:to_html)
klass.define_method(:meth) do |*a|
r = old_meth(*a)
# ... transform r ...
r
end
klass
end

But that doesn't work, and I might be on the wrong track completely.
So what's the best way to do this?

Thanks,

--
William <wmorgan-ruby-talk@masanjin.net>


2 Answers

Joel VanderWerf

10/30/2004 4:35:00 AM

0

William Morgan wrote:
> Hi all,
>
> I'm currently drowning in a pool of instance_methods and define_methods
> and I can't seem to get out. I know there's an elegant solution
> somewhere....
>
> I have a Class object klass. It has an instance method meth(). I'd like
> to "extend" meth() so that when it's called, the output is changed---I
> want to call the original meth(), tweak its result, and then return it.
> I need to return a Class object that has this tweak in place; I can
> either change klass and return that or I can subclass it and return the
> subclass.
>
> Something like:
>
> def tweaked_class(klass)
> old_meth = klass.instance_method(:to_html)
> klass.define_method(:meth) do |*a|
> r = old_meth(*a)
> # ... transform r ...
> r
> end
> klass
> end
>
> But that doesn't work, and I might be on the wrong track completely.
> So what's the best way to do this?
>
> Thanks,
>

Here are two ways. There are probably more, knowing ruby :)

def tweak(klass, old_meth, new_meth)

if old_meth == new_meth

old_meth_unbound = klass.instance_method(old_meth)

klass.class_eval do
define_method(new_meth) do |*args|
yield old_meth_unbound.bind(self).call(*args)
end
end

else

klass.class_eval do
define_method(new_meth) do |*args|
yield send(old_meth, *args)
end
end

end

klass
end

class Foo
def whazzup; "nothing"; end
end

tweak(Foo, :whazzup, :whaddaya) do |r|
r + " much"
end

p Foo.new.whaddaya

tweak(Foo, :whazzup, :whazzup) do |r|
r + " else"
end

p Foo.new.whazzup


William Morgan

11/1/2004 1:16:00 AM

0

Excerpts from Joel VanderWerf's mail of 30 Oct 2004 (EDT):
> Here are two ways. There are probably more, knowing ruby :)

Thanks! It was the class_eval I was forgetting.

--
William <wmorgan-ruby-talk@masanjin.net>