Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find where a method is defined at runtime?

We recently had a problem where, after a series of commits had occurred, a backend process failed to run. Now, we were good little boys and girls and ran rake test after every check-in but, due to some oddities in Rails' library loading, it only occurred when we ran it directly from Mongrel in production mode.

I tracked the bug down and it was due to a new Rails gem overwriting a method in the String class in a way that broke one narrow use in the runtime Rails code.

Anyway, long story short, is there a way, at runtime, to ask Ruby where a method has been defined? Something like whereami( :foo ) that returns /path/to/some/file.rb line #45? In this case, telling me that it was defined in class String would be unhelpful, because it was overloaded by some library.

I cannot guarantee the source lives in my project, so grepping for 'def foo' won't necessarily give me what I need, not to mention if I have many def foo's, sometimes I don't know until runtime which one I may be using.

like image 799
Matt Rogish Avatar asked Oct 06 '08 18:10

Matt Rogish


People also ask

What is a Ruby method?

A method in Ruby is a set of expressions that returns a value. Within a method, you can organize your code into subroutines which can be easily invoked from other areas of their program. A method name must start a letter or a character with the eight-bit set.

How to call a method in c sharp?

Calling a method is like accessing a field. After the object name (if you're calling an instance method) or the type name (if you're calling a static method), add a period, the name of the method, and parentheses. Arguments are listed within the parentheses and are separated by commas.

Can you define a method within a method in Ruby?

In short: no, Ruby does not support nested methods.


2 Answers

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

like image 120
wesgarrison Avatar answered Oct 19 '22 08:10

wesgarrison


You can actually go a bit further than the solution above. For Ruby 1.8 Enterprise Edition, there is the __file__ and __line__ methods on Method instances:

require 'rubygems' require 'activesupport'  m = 2.days.method(:ago) # => #<Method: Fixnum(ActiveSupport::CoreExtensions::Numeric::Time)#ago>  m.__file__ # => "/Users/james/.rvm/gems/ree-1.8.7-2010.01/gems/activesupport-2.3.8/lib/active_support/core_ext/numeric/time.rb" m.__line__ # => 64 

For Ruby 1.9 and beyond, there is source_location (thanks Jonathan!):

require 'active_support/all' m = 2.days.method(:ago) # => #<Method: Fixnum(Numeric)#ago>    # comes from the Numeric module  m.source_location   # show file and line # => ["/var/lib/gems/1.9.1/gems/activesupport-3.0.6/.../numeric/time.rb", 63] 
like image 27
James Adam Avatar answered Oct 19 '22 07:10

James Adam