How to Find Where a Ruby Method Is Declared

How to find where a method is defined at runtime?

This is really late, but here's how you can find where a method is defined:

http://gist.github.com/76951

# How to find out where a method comes from.
# Learned this from Dave Thomas while teaching Advanced Ruby Studio
# Makes the case for separating method definitions into
# modules, especially when enhancing built-in classes.
module Perpetrator
def crime
end
end

class Fixnum
include Perpetrator
end

p 2.method(:crime) # The "2" here is an instance of Fixnum.
#<Method: Fixnum(Perpetrator)#crime>

If you're on Ruby 1.9+, you can use source_location

require 'csv'

p CSV.new('string').method(:flock)
# => #<Method: CSV#flock>

CSV.new('string').method(:flock).source_location
# => ["/path/to/ruby/1.9.2-p290/lib/ruby/1.9.1/forwardable.rb", 180]

Note that this won't work on everything, like native compiled code. The Method class has some neat functions, too, like Method#owner which returns the file where the method is defined.

EDIT: Also see the __file__ and __line__ and notes for REE in the other answer, they're handy too. -- wg

How do I find where a ruby method is declared?

When I need to find where a method is declared on some class, say 'Model', I do

Model.ancestors.find {|c| c.instance_methods(false).include? :deactivate! }

This searches the ancestor tree in the same order that ruby does for the first that has the method in instance_methods(false), which only includes non-inherited methods.

Note: before ruby 1.9, the methods were listed as strings not symbols, so it would be

Model.ancestors.find {|c| c.instance_methods(false).include?('deactivate!') }

Finding out where methods are defined in Ruby/Rails (as opposed to Java)

The Pry gem is designed precisely for this kind of explorative use-case.

Pry is an interactive shell that lets you navigate your way around a program's source-code using shell-like commands such as cd and ls.

You can pull the documentation for any method you encounter and even view the source code, including the native C code in some cases (with the pry-doc plugin). You can even jump directly to the file/line where a particular method is defined with the edit-method command. The show-method and show-doc commands also display the precise location of the method they're acting on.

Watch the railscast screencast for more information.

Here are some examples below:

pry(main)> show-doc OpenStruct#initialize

From: /Users/john/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/ostruct.rb @ line 46:
Number of lines: 11

visibility: private
signature: initialize(hash=?)

Create a new OpenStruct object. The optional hash, if given, will
generate attributes and values. For example.

require 'ostruct'
hash = { "country" => "Australia", :population => 20_000_000 }
data = OpenStruct.new(hash)

p data # -> <OpenStruct country="Australia" population=20000000>

By default, the resulting OpenStruct object will have no attributes.

pry(main)>

You can also look up sourcecode with the show-method command:

pry(main)> show-method OpenStruct#initialize

From: /Users/john/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/ostruct.rb @ line 46:
Number of lines: 9

def initialize(hash=nil)
@table = {}
if hash
for k,v in hash
@table[k.to_sym] = v
new_ostruct_member(k)
end
end
end
pry(main)>

See http://pry.github.com for more information :)

checking if a method is defined on the class

Use this:

C.instance_methods(false).include?(:a)
C.instance_methods(false).include?(:b)
C.instance_methods(false).include?(:c)

The method instance_methods return an Array of methods that an instance of this class would have. Passing false as first parameter returns only methods of this class, not methods of super classes.

So C.instance_methods(false) returns the list of methods defined by C.

Then you just have to check if that method is in the returned Array (this is what the include? calls do).

See docs

Ruby - determining method origins?

Object#method returns a Method object giving meta-data about a given method. For example:

> [].method(:length).inspect
=> "#<Method: Array#length>"
> [].method(:max).inspect
=> "#<Method: Array(Enumerable)#max>"

In Ruby 1.8.7 and later, you can use Method#owner to determine the class or module that defined the method.

To get a list of all the methods with the name of the class or module where they are defined you could do something like the following:

obj.methods.collect {|m| "#{m} defined by #{obj.method(m).owner}"}

Source location of a class

[not actually an answer to your problem, but too long for a comment]

source_location doesn't seem to help here, because dynamic methods can be created with an arbitrary location:

# my_class.rb

class MyClass
attr_accessor :foo

class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
def bar
end
RUBY

class_eval(<<-RUBY, 'dummy.rb', 42)
def baz
end
RUBY
end

p MyClass.instance_method(:foo).source_location
p MyClass.instance_method(:bar).source_location
p MyClass.instance_method(:baz).source_location

Output:

$ ruby my_class.rb
["my_class.rb", 4]
["my_class.rb", 7]
["dummy.rb", 42]


Related Topics



Leave a reply



Submit