34

Using pry, it's very simple to find where a method is defined and see the source by edit-method command. Yet there is no correspondence for class itself. When that class has no methods defined itself, it's hard to locate the source through pry.

Classes are constants, so it's equivalent to ask where to find the source in which a particular Ruby constant is defined. Thank you very much.

Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
Minqi Pan
  • 2,722
  • 2
  • 22
  • 26
  • 4
    Could you accept answers to your previous questions? – Arsen7 Mar 26 '12 at 08:21
  • 4
    @Arsen7 Oh thank you very much for reminding me. I am quite new to this community. I have accepted them now. – Minqi Pan Mar 26 '12 at 09:21
  • That's nice. :-) And how about `grep`? Or you, actually, meant that _this_ was what I have reminded You of? ;-) – Arsen7 Mar 26 '12 at 11:27
  • @Arsen7 Hahaha Not at all do I find any selfishness:) god I am beginning to love this community. – Minqi Pan Mar 28 '12 at 04:07
  • Yeah, `grep` is fine if you at least know the possible scope and the scope is small. Sometimes the main project relies on too many dependencies and constants are defined outside somewhere else. – Minqi Pan Mar 28 '12 at 04:10
  • THe most recent version of Pry can show the source for modules/classes using the normal `show-source` command. It requires that the module/class has at least one defined method however. – horseyguy Apr 19 '12 at 04:59
  • `grep` is not always sufficient. I just had a case where a model class in a Rails project is being used both as a class and as a namespace. Say it's `Foo`. Defining nested class `Bar` like `class Foo::Bar` triggers autoload on the `Foo` class and loads it properly. Doing it as `class Foo; class Bar; end; end;` causes `Foo` to be defined as an empty class and the actual model definition isn't loaded. Fortunately, we figured this out, but it would have been **so** much easier if we could have asked Ruby where the class was defined. grepping for mentions returned a LOT of results. – Nathan Long Jul 25 '12 at 13:49

6 Answers6

21

There is a better way to do this as of Ruby 2.7, which is Module.const_source_location.

> Admin.const_source_location(:LIMIT)
#=> ["SOME_PATH/user.rb", 2]

References:

Chris Salzberg
  • 27,099
  • 4
  • 75
  • 82
19

In ruby, $"holds all the file names that are loaded via Kernel.load. So you could try something like this:

constant = User
$".detect{|load_path|
  load_path.include?(constant.to_s.underscore)
}

Note: The method underscore is part of Rails/ActiveSupport

Alex
  • 2,398
  • 1
  • 16
  • 30
  • This is a great suggestion! – sandstrom Jan 27 '16 at 10:06
  • Great answer. I found `underscore` wasn't available for me in String on Ruby 2.4.2. I got by with `downcase`, but if your class name is multiple words, you'd need to turn it to snake case somehow. – Eric Hu Dec 05 '17 at 14:14
8

Use ack, sometimes if I reach the limits of Pry (and Ruby) i resort to using it. Great thing about it is you can invoke it from within Pry itself using its shell integration features, usually just typing .ack ClassName does the trick, however it requires that the class is defined in a file under the current directory.

In the case that the class is not defined in the current directory, then you can always resort to look up one of its methods, take the source location from there, and then use Pry's cat command to display it (with syntax highlighting) or Pry's edit command to jump directly to its definition.

The case where a class does NOT have any instance methods defined is fairly rare -- and such a class is usually quite uninteresting anyway :)

EDIT:

The most recent version of Pry (0.9.9) can now show the source for modules/classes using the normal show-source command. It requires that the module/class has at least one defined method however

horseyguy
  • 29,455
  • 20
  • 103
  • 145
  • Consider [ripgrep](https://github.com/BurntSushi/ripgrep#quick-examples-comparing-tools) rather than `ack`, it is way faster! [`ag`](https://github.com/ggreer/the_silver_searcher) is also a good alternative. – Ulysse BN Dec 15 '20 at 13:00
4

If the constant you're looking for has methods (is a class or module) you can use the Method class to find out where it is defined.

class Foo
  def bar
  end

  def self.baz
  end
end

Foo.instance_method(:bar).source_location
Foo.method(:baz).source_location

A bit of a hack and doesn't help with pure constants class Foo; BAHZ = 2; end but it is better than nothing.

Schneems
  • 14,918
  • 9
  • 57
  • 84
4

A hacky way for debugging purposes: start a console (for instance with binding.irb) and redefine the constant. You'll get an error message with the previous definition path!

> Foo = ""
(irb):11: warning: already initialized constant Foo
/path/to/foo.rb:1: warning: previous definition of Foo was here
=> ""
Ulysse BN
  • 10,116
  • 7
  • 54
  • 82
  • wow, never would have thought of that, this works for Modules and Classes too, awesome! – mswieboda Sep 09 '21 at 16:25
  • also I found this gem for Class and Class methods, maybe it helps someone too https://github.com/daveallie/where_is – mswieboda Sep 09 '21 at 16:57
  • 1
    This is great since the project I'm working on is not quite yet on Ruby 2.7. Thank you! – Nick Dec 08 '21 at 21:43
2

Well you could try Module.constants(true) as stated here It might take a bit more than using pry offers but it would allow you a chance to peek into the Modules involved

Community
  • 1
  • 1
ScottJShea
  • 7,041
  • 11
  • 44
  • 67