RubyBits: Source Diving

By Luis FerreiraOn May 24, 2016

Debugging is something that (un)fortunately we as developers are all used to doing, but depending on the language, the techniques and tools might differ, if ever so slightly.

Ruby being a language that relies heavily on methods without namespacing (i.e. you call a method the same way regardless of it being defined in the same class, in a parent class, in an included module, a global method), it is at times hard to know where a method you're using is defined. There are other issues inherent to this behaviour, but that's a whole other story.

The method method

As a stepping stone to helping us with solving this issue, let's look at the method method, which creates an instance of Method with the method you want. I said method way to many times on that sentence, so here's an example to help consolidate the idea:

str = "I am a String"
str_size = str.method(:size)
str_size.class # => Method # => 13

Hopefully it is now clearer that method gets us a Proc like object that we can call later. As an apart, this can be useful (albeit not the most performant solution) when paired with symbol to proc.

def double(num)
  num * 2

[1, 2].map(&method(:double)) # => [2, 4]

Without the call to method this would try to call double on the instance of Fixnum. This is way we don't have to write the full block nor resort to monkey patching.

In some situation we might be able to call methods that could only be called from a block otherwise. Like Math.sqrt.

[4, 9, 16].map(&Math.method(:sqrt)) 
## => [2.0, 3.0, 4.0]

Diving into the source

Now that we know about the Method class, it's time to find out about a very useful method on it, called source_location. As the name suggest it tells us the file and line where a certain method is defined (except for native method, for which we get nil).

Since Rails methods are not native, it is a good example of a gem where can use this technique.

p method(:has_many).source_location
## => ["/[RETRACTED]/activerecord-4.2.5/lib/active_record/associations.rb", 1258]

The Method class has some other useful method to introspect on methods, such as super_method, owner or original_name, check it out.

Other techniques

Hopefully this was useful, and can be helpful when you're really confused as to where a method is really defined, but as a first pass you can use ctags to solve the same issue (with the difference that ctags cannot know for sure which method is actually being called, if it is a common name, or is overridden a lot). There is a RubyBit about ctags if you're interested.

More Ruby Bits

If you've enjoyed this Ruby Bit you should really subscribe to our newsletter, where other Ruby Bits and more great articles are shared every week.

If you want to meet us and/or see some talks on Ruby topics, come join us at RubyConf Portugal 2016. For making all the way to the end of this article you get 25% off the price of the ticket.