super is your friend
Sitting here in Copenhagen, at RubyFools, I thought I’d share a technique that I’ve known about for some time, but seems to not have gotten into the normal ruby vernacular.
This trick is the use of super in methods contained in a Module. Consider the following code:
module N
def go
puts "N#go"
super
end
end
class B
def go
puts "B#go"
end
end
class A < B
include N
end
A.new.go
Will print:
N#go B#go
This is HIGHLY useful implementing rails plugins, where normally you’d use alias_method_chain to change a method directly inside ActiveRecord::Base. Instead, simply call super in the method that provides the new functionality, and when your module is included in your module class (which is a subclass of ActiveRecord::Base), and the main, ActiveRecord::Base implementation will be called.
NOTE: This trick only works if the method you wish to wrap is located in a superclass of the class you have defined the module in. IE, if N were included in B directly rather than A, N#go would never be called.
“if N were included in B directly rather than A, N#go would never be called.”
If wishes were horses then beggars would ride, as they say. But I have always wished that if you called super in a module that it would call the method in its including class. IOW, I have always wished that if class B includes N, you will still get N#go followed by B#go…
Reg Braithwaite
April 2, 2008 at 7:45 am
Underused indeed. I do avoid it in some cases where I don’t want the module to be tightly coupled to the superclass’s interface. As you say, this is a good way to implement a “plug-in” module which is probably a case where you are working with a specific interface to beging with anyway.
Brian Mitchell
April 2, 2008 at 9:23 am
Hang on, this isn’t a ‘trick’ this one of the fundamental ideas of OO programming.
Piers Cawley
April 3, 2008 at 6:40 am
It gets better.
Nis an ancestor of A, so you could do:class A < Binclude N
def go
puts "A#go"
super
end
end
which will then print:
irb(main):021:0> A.new.goA#go
N#go
B#go
Graeme Mathieson
April 25, 2008 at 7:14 am