Get class location from class object

For Methods and Procs Ruby 1.9 has method called source_location:

Returns the Ruby source filename and line number containing this method or nil if this method was not defined in Ruby (i.e. native)

So you can request for the method:

m = Foo::Bar.method(:create)

And then ask for the source_location of that method:

m.source_location

This will return an array with filename and line number. E.g for ActiveRecord::Base#validates this returns:

ActiveRecord::Base.method(:validates).source_location
# => ["/Users/laas/.rvm/gems/ruby-1.9.2-p0@arveaurik/gems/activemodel-3.2.2/lib/active_model/validations/validates.rb", 81]

For classes and modules, Ruby does not offer built in support, but there is an excellent Gist out there that builds upon source_location to return file for a given method or first file for a class if no method was specified:

  • ruby where_is module

EDIT: For Ruby 1.8.7 there is a gem that backports source_location:

  • ruby18_source_location

FYI, In Rails's console or debugging sessions of Rails apps, you can find out the disk-location of the file where that particular class is defined. like

> show-source Job

this will give you

From: /home/john/projects/iisifix/app/models/job.rb @ line 13:
Class name: Job
Number of monkeypatches: 6. Use the `-a` option to display all available monkeypatches
Number of lines: 66

class Job < ApplicationRecord
  belongs_to :quote_request
  belongs_to :garage

Here's a simple example showing how I track locations in code. If I need to know a location in a module:

class Foo
  attr_reader :initialize_loc
  def initialize
    @initialize_loc = [__FILE__, __LINE__]
    # do more stuff...
  end
end

If I need to know where something happened:

require_relative 't1'

foo = Foo.new
# do lots of stuff until you want to know where something was initialized.
puts 'foo initialized at %s:%s' % foo.initialize_loc

When I run the code I get:

FooBar:Desktop foobar ruby t2.rb 
foo initilized at /Users/foobar/Desktop/t1.rb:4

If I don't want to mess with the source-code of the module, and want the debugger to jump in when I need it, I'll have the debugger do just that:

require_relative 't1'
require 'ruby-debug'

debugger
foo = Foo.new
# do lots of stuff until you want to know where something was initilized.
puts 'foo initilized at %s:%s' % foo.initialize_loc

The execution will stop and I'll drop into the debugger at the line immediately following debugger:

[0, 9] in t2.rb
  1  require_relative 't1'
  2  require 'ruby-debug'
  3  
  4  debugger
=> 5  foo = Foo.new
  6  # do lots of stuff until you want to know where something was initilized.
  7  puts 'foo initilized at %s:%s' % foo.initialize_loc
  8  
t2.rb:5
foo = Foo.new
(rdb:1) 

A simple s will "step" me into the next line of code, which will be in the initialize block for Foo:

(rdb:1) s
[-1, 8] in /Users/foobar/Desktop/t1.rb
  1  class Foo
  2    attr_reader :initialize_loc
  3    def initialize
=> 4      @initialize_loc = [__FILE__, __LINE__]
  5      # do more stuff...
  6    end
  7  end
  8  
/Users/foobar/Desktop/t1.rb:4
@initialize_loc = [__FILE__, __LINE__]
(rdb:1) 

Beyond this, using tools like grep -rn target_to_find path_to_search to recursively search directories and list the filename and line numbers of lines matching the target, will go a long ways to helping find what you're looking for.

Or, using :vim /target_to_find/ path_to_search from inside Vim will return the files you're looking for.