Checking the existence of a super method in Ruby

Ruby gives methods the ability to call up to the superclass definition of themselves. Or it may not be a parent class definition; it might call up to a definition in a module included further up the ancestor chain. Either way, it’s an elegant way to build on the functionality of class ancestors.

But sometimes you may not know if there is a superclass method to be called. For instance, you may be writing a module. You want the module methods to delegate back to their superclass definitions if those definitions exist; but you don’t want the code to crash with a NoMethodError if they don’t exist. What to do?

As always, Ruby gives us the tools we need. defined? to the rescue:

module Stuff
  def foo
    puts "In Stuff#foo"
    if defined?(super)
      puts "Calling super"
      super
    else
      puts "No super"
    end
  end
end

module OtherStuff
  def foo
    puts "In OtherStuff#foo"
  end
end

class NoSuper
  include Stuff
end
NoSuper.new.foo
# >> In Stuff#foo
# >> No super

class WithSuper
  include OtherStuff
  include Stuff
end
WithSuper.new.foo
# >> In Stuff#foo
# >> Calling super
# >> In OtherStuff#foo

defined? is a built-in Ruby operator (not an ordinary method!) which can tell you if a given method or variable has been defined. It also works for determining if a super method exists somewhere in the ancestor chain. Use defined?(super) to write generic modules that play well with others.

2 comments

  1. Quick note, this fails with SimpleDelegator because self is not the wrapped object but the delegator object. This is what I came up with instead: def description; __getobj__.respond_to?(__method__) ? super : 'No description'; end.

Leave a Reply

Your email address will not be published. Required fields are marked *