Mark Jerde Mark Jerde - 4 months ago 12
Ruby Question

Ruby: Get a method's class or module name

I'm trying to understand a mixin precedence situation. If I run

foo.bar
I'm trying to figure out exactly which
bar
will be executed. Here is a snipped irb session where I tried to find out where an array's
assoc
method is defined.

2.3.0 :032 > ray = ['cat', nil, 'dog']
=> ["cat", nil, "dog"]
2.3.0 :033 > ray.methods
=> [:fill, :assoc, :rassoc, :uniq, ...
2.3.0 :034 > ray.method("assoc").class_or_module_name
NoMethodError: undefined method `class_or_module_name' for #<Method: Array#assoc>
from (irb):34
from /Users/mark/.rvm/rubies/ruby-2.3.0/bin/irb:11:in `<main>'
2.3.0 :035 > ray.methods("assoc").class_or_module_name
NoMethodError: undefined method `class_or_module_name' for #<Array:0x007ffb8aa286a8>
from (irb):35
from /Users/mark/.rvm/rubies/ruby-2.3.0/bin/irb:11:in `<main>'
2.3.0 :036 > ray.methods("assoc")
=> [:fill, :assoc, :rassoc, :uniq, :uniq!, :compact, ...


If possible I would like to see the methods and their source location that lost precedence.

Answer

To find out which class or module defines a method (rather than what file), use Method#owner.

For example,

[].method(:last).owner #=> Array
[].method(:flat_map).owner #=> Enumerable

You'll actually find that a lot of the methods that Array could get from Enumerable, it actually defines itself (presumably to provide a more efficient implementation):

irb(main):018:0> Enumerable.instance_methods.select {|meth_name| [].method(meth_name).owner == Array }
=> [:to_a, :to_h, :sort, :count, :find_index, :select, :reject, :collect, :map, :first, :include?, :reverse_each, :zip, :take, :take_while, :drop, :drop_while, :cycle]
Comments