ruby super keyword
Ruby on-RailsRubyActiverecordRuby on-Rails Problem Overview
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.
Ruby on-Rails Solutions
Solution 1 - Ruby on-Rails
super
keyword:
The example provided in the Ruby Docs for the 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!
Solution 2 - Ruby on-Rails
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?(...
)
Solution 3 - Ruby on-Rails
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>
Solution 4 - Ruby on-Rails
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
Solution 5 - Ruby on-Rails
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
Solution 6 - Ruby on-Rails
The relevant superclass method is probably Module#autoload.