1

How can one get the class a method was defined in?

I've found how to look up descendents and ansestors: Look up all descendants of a class in Ruby

But that doesn't necessarily get me the defining class (last defining class really).

I've found how to get the calling class: Ruby Inheritance Get Caller Class Name

But I want the opposite. I would like how to get the defining class.

I've also tried Module.nesting. That gets me what I want in this case, but I worry it will be inconsistent and not acceptable in a larger codebase of which I don't have ultimate control.

puts RUBY_VERSION


# Test class vs super.
class Super
    def test_func
      puts "#{self.class}, #{ __method__}"
    end
end

class Child < Super
  def test_func2
     self.test_func
  end
end

Child.new.test_func

I had hoped for:

1.8.7

Super, test_func

But got:

1.8.7

Child, test_func

Community
  • 1
  • 1
jayreed1
  • 152
  • 2
  • 8
  • 2
    Ruby 1.8.7 is super old and really obsolete, so if you have any way of upgrading that would help a lot as a ton of new things have happened to Ruby since then, including, most critically, proper UTF-8 support. – tadman Aug 28 '19 at 22:02
  • Unfotunately, I'm stuck on 1.8.7 for this particular project. Worse still, I can't use gems. : / – jayreed1 Aug 28 '19 at 22:33
  • That sounds like the opposite of fun. Hope you survive this! – tadman Aug 28 '19 at 22:44

1 Answers1

6

You asked self.class of Child object and you got it.

You need use Method#owner to return the class or module that defines the method.

class Super
  def test_func
    puts "#{method(__method__).owner}, #{ __method__}"
  end
end

class Child < Super
  def test_func2
     self.test_func
  end
end

Child.new.test_func
# will print: Super, test_func

or just

Child.new.method(:test_func).owner
#=> Super

or

Child.instance_method(:test_func).owner
#=> Super
mechnicov
  • 12,025
  • 4
  • 33
  • 56
  • 2
    This is fantastic! It works in 1.8.7 even. Thank you! I'm using this to add a log line instead of typing the class and method manually. – jayreed1 Aug 28 '19 at 22:35
  • I've upvoted your answer. I can't find where to mark it as accepted. Maybe that's because of my fairly minuscule reputation? – jayreed1 Aug 28 '19 at 23:06
  • 1
    Why `UnboundMethod#owner` rather than [Method#owner](https://ruby-doc.org/core-2.6.3/Method.html#method-i-owner), considering that `test_func` is bound to `Child.new`? jayreed1, do you need the class where it was defined programmatically or just to see it, for debugging, say. If the latter, look at the return value for `...method(:some_method)` and you will see that it is there--you don't have to tack on `.owner`. – Cary Swoveland Aug 28 '19 at 23:09
  • ...For example, `22.method(:zero?) #=> #`, showing that `Integer#zero?`is defined in `Numeric`, whereas `22.method(:+) #=> #` tells us that `Integer#+` is defined in `Integer` (as `#` is interpreted as `#)`. – Cary Swoveland Aug 28 '19 at 23:31
  • 1
    Or `Child.instance_method(:test_func).owner`, so you don't have to create an instance. – Stefan Aug 29 '19 at 07:58