Tracking down method definitions in Ruby
One of my favourite features of Ruby 1.9 is the
#source_location method of
Method. Let me explain. Often I am confronted with a large code base (usually Rails), and want to figure out exactly where some method on some object is defined. Rails has many dark corners, and sometimes finding things isn’t entirely straightforward.
A trick that I often use is to get a
Method object for the method that
I want to find, and then to print out its location. Like this:
class Foo def bar "omg, where am I?" end end p Foo.new.method(:bar).source_location # found you!
Recently I was trying to find out where the
#flash method of
ActionDispatch::TestRequest was defined. It’s not defined in the main
files that contain the definitions for
ActionDispatch::Request (which is the superclass).
So I pulled out my standard tool:
r = ActionDispatch::TestRequest.new p r.method(:flash).source_location
It didn’t work:
ArgumentError: wrong number of arguments (1 for 0)
It turns out that
ActionDispatch::Request has its own
which relates to the HTTP method. Hence Ruby’s
method method is
However, all was not lost! Ruby also makes it possible to get a
reference to a method definition that isn’t bound to any particular
object. This is called an
UnboundMethod, and you can’t call it until
you bind it to some object. So I was able to get an unbound reference to
method method and then bind it to my object. Like so:
r = ActionDispatch::TestRequest.new meth = Object.instance_method(:method) p meth.bind(r).call(:flash).source_location # found it!
It turns out that the
Request class is reopened in
actionpack/lib/action_dispatch/middleware/flash.rb and the
method gets defined there.
19 February 2012
Jon Leighton is an experienced software engineer, specialising in Ruby. He is based in the beautiful mountains of Snowdonia in North Wales, and is particularly interested in projects with a social purpose. Do get in touch if you'd like to chat.