Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > Overriding methods in a class using a mixin

Reply
Thread Tools

Overriding methods in a class using a mixin

 
 
James Coglan
Guest
Posts: n/a
 
      11-14-2008
[Note: parts of this message were removed to make it a legal post.]

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:
http://gist.github.com/25104

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.

--
James Coglan

Lead JavaScript Developer
theOTHERmedia
http://ojay.othermedia.org
+44 (0) 7771512510

 
Reply With Quote
 
 
 
 
Trans
Guest
Posts: n/a
 
      11-15-2008


On Nov 14, 5:02=A0pm, "James Coglan" <(E-Mail Removed)> 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 ol=

d
> implementations, the sort of thing people like to use alias_method_chain
> for. I tend to favour this approach, though:
>
> class Foo
> =A0 meth =3D instance_method(:foo)
> =A0 define_method(:foo) do |some, args|
> =A0 =A0 result =3D meth.bind(self).call(some, args)
> =A0 =A0 # do extra stuff...
> =A0 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 u=

p
> with a way in which you can copy the class's methods into a module, inclu=

de
> 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 an=

d
> use 'super' to refer to them. This lets you insert code between an existi=

ng
> class and all its subclasses, which can be useful.
>
> Code on github, with an example:http://gist.github.com/25104


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 'includ=

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



 
Reply With Quote
 
 
 
 
ara.t.howard
Guest
Posts: n/a
 
      11-15-2008

On Nov 14, 2008, at 3:02 PM, James Coglan 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



alias_method_chain_is_crap_because_it_leads_to_mad ness_like_this

your method is *ok* but it chops the method in half - dropping blocks
on the floor

check this out

http://drawohara.com/post/7241442/ru...define-methods

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




 
Reply With Quote
 
James Coglan
Guest
Posts: n/a
 
      11-15-2008
[Note: parts of this message were removed to make it a legal post.]

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

http://gist.github.com/25104

 
Reply With Quote
 
ara.t.howard
Guest
Posts: n/a
 
      11-15-2008

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.
>
> http://gist.github.com/25104



couple observations after a quick browse

your override method will not allow one to redefine a method which
takes a block. you cannot say

override(:map) do
list = []
each(&block){|element| list << element} # block does not
exist!
list
end

because you lose the handle on any block passed to the method. any
use of define_method drops a block on the floor.

m.bind(self).call(*args[0...m.arity], &block)

blows up when arity is negative, which it often is

cfp:~ > ruby -e' def foo(a,b,*c) end; p
Object.instance_method(:foo).arity '
-3

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.

,
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




 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Mixin module with class variables and class methods John Lane Ruby 6 02-09-2010 09:48 PM
How to get class' filepath from methods in included mixin? Nigel Hennan Ruby 2 05-07-2009 01:08 AM
Is there a way to find the class methods of a class, just like'methods' finds the instance methods? Kenneth McDonald Ruby 5 09-26-2008 03:09 PM
Mixin of class methods? Michael Roth Ruby 8 09-26-2005 08:00 AM
Extract methods in a class to mixin? Florian Frank Ruby 0 09-10-2003 01:20 PM



Advertisments