Hi list,
I just had this idea and thought I'd share it in case someone can improve
upon it, make it more robust. Basically, I've run into a situation a few
times where I want to override methods in a class but retain access to old
implementations, the sort of thing people like to use alias_method_chain
for. I tend to favour this approach, though:
class Foo
meth = instance_method(:foo)
define_method(:foo) do |some, args|
result = meth.bind(self).call(some, args)
# do extra stuff...
end
end
But, then you've lost the old implementation: it's hidden in the closure and
you can't get another reference to it from anywhere else. So, I've come up
with a way in which you can copy the class's methods into a module, include
that module (making it part of the inheritance chain) and then mix other
modules in. Later modules can thereby override the class's own methods and
use 'super' to refer to them. This lets you insert code between an existing
class and all its subclasses, which can be useful.
Code on github, with an example:
Comments, suggestions, and accusations of idiocy all very much welcome.
Expanding from this, I'd like to figure out how I can insert modules at
arbitrary points in the inheritance chain, rather than just using 'include'
to come between a module and it's last included module.
Hi list,
I just had this idea and thought I'd share it in case someone can improve
upon it, make it more robust. Basically, I've run into a situation a few
times where I want to override methods in a class but retain access to old
implementations, the sort of thing people like to use alias_method_chain
for. I tend to favour this approach, though:
class Foo
meth = instance_method(:foo)
define_method(:foo) do |some, args|
result = meth.bind(self).call(some, args)
# do extra stuff...
end
end
But, then you've lost the old implementation: it's hidden in the closure and
you can't get another reference to it from anywhere else. So, I've come up
with a way in which you can copy the class's methods into a module, include
that module (making it part of the inheritance chain) and then mix other
modules in. Later modules can thereby override the class's own methods and
use 'super' to refer to them. This lets you insert code between an existing
class and all its subclasses, which can be useful.
Well done. I've explored a number of approaches to this is a pretty
good one.
On the downside though the reoccurring binding is going to slow things
down.
Anther approach is to override #new and #extend the object with the
"aspect" module upon creation.
Comments, suggestions, and accusations of idiocy all very much welcome.
Expanding from this, I'd like to figure out how I can insert modules at
arbitrary points in the inheritance chain, rather than just using 'include'
to come between a module and it's last included module.
You can just include it in the ancestor you want it to go after. But
of course that's going to effect all subclasses of that class.
Facets definition of Kernel#at() might interest you though.
T.
···
On Nov 14, 5:02 pm, "James Coglan" <jcog...@googlemail.com> wrote:
Hi list,
I just had this idea and thought I'd share it in case someone can improve
upon it, make it more robust. Basically, I've run into a situation a few
times where I want to override methods in a class but retain access to old
implementations, the sort of thing people like to use alias_method_chain
for. I tend to favour this approach, though:
class Foo
meth = instance_method(:foo)
define_method(:foo) do |some, args|
result = meth.bind(self).call(some, args)
# do extra stuff...
end
end
--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama
your method is *ok* but it chops the method in half - dropping blocks on
the floor
I made some changes that mean blocks are supported -- turns out storing a
reference to the module a method is defined in is a little messy. I notice
you look up old methods via the class that's calling the method, whereas I
want the exact module storing the method to handle the lookup. Not sure if
there's much practical difference but I find my way easier to think about.
. override will blow up stashing methods which may or may not actually be defined on that class, for instance
override('inspect'){ 'but inspect is not an instance method' }
the pre-clusion ability is handy for sure though.
cheers.
···
On Nov 15, 2008, at 5:33 AM, James Coglan wrote:
I made some changes that mean blocks are supported -- turns out storing a
reference to the module a method is defined in is a little messy. I notice
you look up old methods via the class that's calling the method, whereas I
want the exact module storing the method to handle the lookup. Not sure if
there's much practical difference but I find my way easier to think about.
,
a @ http://codeforpeople.com/
--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama