33
class C1
  def pr
    puts 'C1'
  end
end

class C2 < C1
  def pr
    puts 'C2'
    super
    puts self.method(:pr).source_location
  end
end

c = C2.new
c.pr

In the program above is it possible to obtain location of the code executed by super (C1::pr in our case) as well as we obtain the location of C2::pr code using source_location method?

ndnenkov
  • 35,425
  • 9
  • 72
  • 104
  • Knowing that the method is going to re-despatch via `super` from the outside is *hard*, but finding ancestor classes that implement `pr` and getting those source locations is reasonably straightforward. – Neil Slater Apr 29 '13 at 16:58
  • `method(:your_method).super_method.source_location` – Dorian Jan 17 '22 at 18:24

5 Answers5

33

From ruby 2.2 you can use super_method like this:

Class A
  def pr
    puts "pr"
  end
end

Class B < A
  def pr
    puts "Super method: #{method(:pr).super_method}"
  end
end

As super_method returns a Method, you can chain them to find the ancestor:

def ancestor(m)
  m = method(m) if m.is_a? Symbol
  super_m = m.super_method
  if super_m.nil?
    return m
  else
    return ancestor super_m
  end
end
bukk530
  • 1,858
  • 2
  • 20
  • 30
9

You just have to get to the superclass, then use instance_method to get the method from the superclass.

class C2 < C1
  def pr
    puts "C2"
    super
    puts "Child: #{self.method(:pr).source_location}"
    puts "Parent: #{self.class.superclass.instance_method(:pr).source_location}"
  end
end

EDIT—regarding the comment about checking the ancestry chain, it (surprisingly) seems to be unnecessary.

class C1
  def pr
    puts "C1"
  end
end

class C2 < C1; end

class C3 < C2
  def pr
    puts "C3"
    super
    puts "Child source location: #{self.method(:pr).source_location}"
    puts "Parent source location: #{self.class.superclass.instance_method(:pr).source_location}"
  end
end

c = C3.new
c.pr

prints

C3
C1
Child source location: ["source_location.rb", 10]
Parent source location: ["source_location.rb", 2]
Wally Altman
  • 3,535
  • 3
  • 25
  • 33
  • I think this answer could be extended to look at ancestors list and check whether any of them implement `pr` - was looking at same, and is best I can come up with – Neil Slater Apr 29 '13 at 16:54
  • 1
    Remember: `super` also calls methods defined in included modules, so checking only methods defined in super classes may not cover all super methods. – David Winiecki Dec 19 '17 at 06:23
6

As per @bukk530, super_method gets you what you want but a good way to access it via the console is

ClassName.new.method(:method_name).super_method.source_location
saywhatnow
  • 1,026
  • 2
  • 15
  • 26
5

If you're using pry you could use the -s flag to show the super method. Documentation about the feature is here.

show-source Class#method -s
KARASZI István
  • 30,900
  • 8
  • 101
  • 128
2

To See the Whole Ancestry Of The Method...

Define this in an irb session:

class Object
  def method_ancestry(method_name)
    method_ancestors = []
    method = method(method_name)
    while method
      method_ancestors << [method.owner, method.source_location]
      method = method.super_method
    end
    method_ancestors
  end
end

For instance, in the Rails console, I can do:

# assuming User is an ActiveRecord class
User.new.method_ancestry(:save)

=> [[ActiveRecord::Suppressor,
  ["/Users/me/.gem/ruby/2.3.1/gems/activerecord-5.0.1/lib/active_record/suppressor.rb", 40]],
 [ActiveRecord::Transactions,
  ["/Users/me/.gem/ruby/2.3.1/gems/activerecord-5.0.1/lib/active_record/transactions.rb", 317]],
 [ActiveRecord::AttributeMethods::Dirty,
  ["/Users/me/.gem/ruby/2.3.1/gems/activerecord-5.0.1/lib/active_record/attribute_methods/dirty.rb",
   21]],
 [ActiveRecord::Validations,
  ["/Users/me/.gem/ruby/2.3.1/gems/activerecord-5.0.1/lib/active_record/validations.rb", 43]],
 [ActiveRecord::Persistence,
  ["/Users/me/.gem/ruby/2.3.1/gems/activerecord-5.0.1/lib/active_record/persistence.rb", 124]]]

This list alone doesn't tell you whether any of the method definitions listed actually call super or just override their inherited definition. But if you see super in one of them, it goes to the next one in the list.

If you use this a lot, you might put it in your ~/.irbrc or ~/.pryrc.

Nathan Long
  • 122,748
  • 97
  • 336
  • 451