58

From what I understand, super keyword invokes a method with the same name as the current method in the superclass of the current class. Below in the autoload method, there is a call to super. I would like to know in which superclass I would find a method with the same name or what does the call to super do here

module ActiveSupport
  module Autoload
    ...      
    def autoload(const_name, path = @@at_path)
      full = [self.name, @@under_path, const_name.to_s, path].compact.join("::")
      location = path || Inflector.underscore(full)

      if @@eager_autoload
        @@autoloads[const_name] = location
      end
      super const_name, location
    end
   .... 
  end
end

module ActiveRecord
  extend ActiveSupport::Autoload
  ...
  autoload :TestCase
  autoload :TestFixtures, 'active_record/fixtures'
end

This code is from the rails master branch. Thanks much.

Ryan Haining
  • 35,360
  • 15
  • 114
  • 174
user290870
  • 1,591
  • 3
  • 19
  • 27

6 Answers6

45

The example provided in the Ruby Docs for the super keyword:

module Vehicular
  def move_forward(n)
    @position += n
  end
end

class Vehicle
  include Vehicular  # Adds Vehicular to the lookup path
end

class Car < Vehicle
  def move_forward(n)
    puts "Vrooom!"
    super            # Calls Vehicular#move_forward
  end
end

Inspecting ancestors

puts Car.ancestors.inspect

# Output
# [Car, Vehicle, Vehicular, Object, Kernel, BasicObject]

Note the inclusion of the Vehicular Module object!

abraham
  • 46,583
  • 10
  • 100
  • 152
maček
  • 76,434
  • 37
  • 167
  • 198
  • Hi, Per your example 'Module' is not in the ancestry tree here and the autoload method you are referring to is in Module#autoload. What I am saying is ActiveSupport.class is Module but it is not the superclass. ActiveSupport.superclass will give you an error – user290870 Apr 08 '10 at 21:10
  • Hi what about the argument? if you just call super from Car does it automatically pass in the argument to super of Vehicular??? – preston Aug 22 '19 at 12:32
16

Check objRef.class.ancestors or ClassName.ancestors to know the inheritance chain. If the super class does not contain the method, then all modules included by the super class are checked (last included checked first). If no match, then it moves up one level to the grandparent class and so on.
You can use the list of ancestors and then call AncestorClass.methods.select{|m| m.include?("auto_load")} to zone in on the method that's being called.

(Note: the above code is Ruby 1.8. In 1.9 methods returns symbols instead of strings. so you'd have to do a m.to_s.include?(...)

Strigoides
  • 4,329
  • 5
  • 23
  • 25
Gishu
  • 134,492
  • 47
  • 225
  • 308
  • 1
    Perhaps I'm not reading your answer as you intended, but the first place checked in the ancestry chain as I understand it is not the super class, but the modules included in the current class. Only after those are exhausted does the search move on to the super class. I found http://blog.rubybestpractices.com/posts/gregory/030-issue-1-method-lookup.html helpful in understanding what happens. – Peter Alfvin Jun 07 '13 at 00:14
15

Use Pry

Insert a binding.pry call right before you use super, and then invoke show-source -s (-s means superclass) to show the superclass method and find out where it's defined:

class A
  def hello
    puts "hi"
  end
end

class B < A
  def hello
    binding.pry
    super
  end
end

b = B.new
b.hello

From: (pry) @ line 7 B#hello:

     7: def hello
 =>  8:   binding.pry
     9:   super
    10: end

[1] (pry) #<B>: 0> show-source -s

From: (pry) @ line 2:
Number of lines: 3
Owner: A   # <--see owner here (i.e superclass)
Visibility: public

def hello
  puts "hi"
end
[2] (pry) #<B>: 0>    
horseyguy
  • 29,455
  • 20
  • 103
  • 145
5

The super keyword checks all the way up the ancestry tree to find the inherited method.

Do a search on the entire rails master branch. You will only find one def autoload which is exactly the one you're looking at in active_support/lib/active_support/dependencies/autoload.rb.

The method being overridden is native Ruby. It is Module#autoload

maček
  • 76,434
  • 37
  • 167
  • 198
  • Can you explain me how Module is part of the ancestry tree. Any class (let's say C) that includes 'ActiveSupport::Autoload' gets the method 'autoload' as an instance method. Per my understanding, the superclass of any class other than the class 'Class' is Object. So when an instance of our class 'C' calls 'autoload', the super should look in the superclass of 'C' which is Object. What am I missing. – user290870 Apr 08 '10 at 07:15
  • @ash34, this is all wrapped inside `module ActiveSupport` which is a `Module` object. – maček Apr 08 '10 at 07:33
  • 1
    @ash34, included Modules are part of the ancestry of a class. Check for example `Array.ancestors` to see the list of modules and classes it checks for method definitions. – mckeed Apr 08 '10 at 18:00
2

I added this method to find the owner of a method to my .irbrc, does anyone see a better way to do this, especially in handling singleton methods where the superclass of the singleton class is the singleton class of the superclass?

  class Object
    def find_method(method_string)
        if klasses = self.class.ancestors.select { |a| a if a.methods.include? method_string }
          puts "class method in #{klasses.join(',')}" unless klasses.empty?
        end
        if klasses = self.class.ancestors.select { |a| a if a.instance_methods.include? method_string }
          puts "instance method in #{klasses.join(',')}" unless klasses.empty?
        end
      rescue
        raise "owning class not found"
    end
  end
Eric Steen
  • 719
  • 2
  • 8
  • 19
1

The relevant superclass method is probably Module#autoload.

Greg Campbell
  • 15,182
  • 3
  • 44
  • 45
  • How is module the superclass of ActiveSupport::Autoload It would be the class of ActiveSupport::Autoload right? Thanks. – user290870 Apr 08 '10 at 05:30
  • @ash34, `super` keeps going up the ancestry tree until it finds the the closest inherited method. See my answer for more details. – maček Apr 08 '10 at 05:58