evan.musing << current

life and tech stuff by Evan Phoenix

super is your friend

with 4 comments

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.

Written by evanphx

April 2, 2008 at 5:48 am

Posted in ruby

4 Responses

Subscribe to comments with RSS.

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

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

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

  4. It gets better. N is an ancestor of A, so you could do:

    class A < B
    include N
    def go
    puts "A#go"
    super
    end
    end

    which will then print:

    irb(main):021:0> A.new.go
    A#go
    N#go
    B#go

    Graeme Mathieson

    April 25, 2008 at 7:14 am


Leave a Reply