Debugging With Pry

Pry is a REPL (Read Eval Print Loop) that was written as a better alternative to IRB. It comes with syntax highlighting, code indentation that actually works and several other features that make it easier to debug code. I stumbled upon Pry when looking for an alternative to both IRB and the way I was debugging my code (placing puts all over the place, I think it's called "Puts Driven Development").

Pry tries to do a lot of things and I was actually quite surprised how well it does that. It might not stick to the Unix idea of only doing a single thing (and doing that very well) but it makes my life (and the lifes of others) so much easier that it's easy to forget.

Pry is primarily meant to be used as a REPL. There are a lot of things that make Pry so much more pleasant to use than IRB. One of the things almost any Ruby programmer will notice when using IRB is that its indentation support is a bit clunky. Indenting itself works fine most of the time but it fails to un-indent code properly as illustrated in the code snippet below (pasted directly from an IRB session):

ruby-1.9.3-p0 :001 > class User
ruby-1.9.3-p0 :002?>   def greet
ruby-1.9.3-p0 :003?>     puts "Hello world"
ruby-1.9.3-p0 :004?>     end
ruby-1.9.3-p0 :005?>   end

Luckily Pry handles this just fine, whether you're trying to indent a class or a hash containing an array containing a proc and so on. Pry does this by resetting the terminal output every time a new line is entered. The downside of this approach is that it only works on terminals that understand ANSI escape codes. In Pry the above example works like it should do:

[1] pry(main)> class User
[1] pry(main)*   def greet
[1] pry(main)*     puts "Hello world"
[1] pry(main)*   end
[1] pry(main)* end

Besides indentation Pry does a lot more. A feature that I think is very cool is the ability to show documentation and source code of methods right in your REPL (sadly this feature doesn't work with classes or modules at the time of writing). This means that you no longer have to use the ri command to search documentation for methods. You also don't need to install the RDoc documentation as Pry pulls it directly from the source code. Showing the source code of a method or its documentation can be done by using the show-method and show-doc command. For example, invoking show-method pry in a Pry session would give you the following output:

[1] pry(main)> show-method pry

From: /path/trimmed/for/readability/lib/pry/core_extensions.rb @ line 19:
Number of lines: 3
Owner: Object
Visibility: public

def pry(target=self)
  Pry.start(target)
end

Calling show-doc pry would instead show the following:

[2] pry(main)> show-doc pry

From: /path/trimmed/for/readability/lib/pry/core_extensions.rb @ line 19:
Number of lines: 17
Owner: Object
Visibility: public
Signature: pry(target=?)

Start a Pry REPL.
This method differs from Pry.start in that it does not
support an options hash. Also, when no parameter is provided, the Pry
session will start on the implied receiver rather than on
top-level (as in the case of Pry.start).
It has two forms of invocation. In the first form no parameter
should be provided and it will start a pry session on the
receiver. In the second form it should be invoked without an
explicit receiver and one parameter; this will start a Pry
session on the parameter.
param [Object, Binding] target The receiver of the Pry session.
example First form
  "dummy".pry
example Second form
   pry "dummy"
example Start a Pry session on current self (whatever that is)
  pry

You can also run these commands for code that was written in C. This requires you to install the gem pry-doc (gem install pry-doc). Do note that this only works for core C code, currently Pry does not support this for third party extensions.

Another very cool feature is that Pry can be used as a debugging tool for your code without having to manually jump into a session. By loading Pry, which can be done by writing require "pry" or by using the option -r pry when invoking Ruby you gain access to everything Pry has to offer. The most useful tool is binding.pry. This method starts a Pry session and pauses the script.

Lets say you have the following script and want to see the values of the variables:

language = 'Ruby'
number   = 10

# Do something awesome with the above variables.

The typical approach would be to insert a puts statement above the comment followed by an exit statement. Pry in a way can do a similar thing, it just makes it a lot more awesome. If you modify the script as following you can truly debug your code like a boss:

language = 'Ruby'
number   = 10

binding.pry

# Do something awesome with the above variables.

If you now run the script by calling ruby -r pry file.rb you get a fancy Pry session:

[yorickpeterse@Wifi-Ninja in ~]$ ruby -r pry file.rb

From: file.rb @ line 4 in Object#N/A:

     1: language = 'Ruby'
     2: number   = 10
     3:
 =>  4: binding.pry
     5:
     6: # Do something awesome with the above variables.
[1] pry(main)>

A nice thing about starting Pry this way is that it starts in the context of the call to binding.pry meaning you get access to data such as the local variables. These can be displayed by calling ls or by simply typing their name.

[yorickpeterse@Wifi-Ninja in ~]$ ruby -r pry file.rb

From: file.rb @ line 4 in Object#N/A:

     1: language = 'Ruby'
     2: number   = 10
     3:
 =>  4: binding.pry
     5:
     6: # Do something awesome with the above variables.
[1] pry(main)> ls
self methods: include  private  public  to_s
locals: _  _dir_  _ex_  _file_  _in_  _out_  _pry_  language  number
[2] pry(main)> number
=> 10
[3] pry(main)>

Moving out of the "breakpoint" (or moving to the next one if you have multiple ones defined) can be done by hitting ^D (Ctrl+D usually).

Besides the features mentioned in this article Pry has several more. For example, long output is piped to Less. This can be quite useful if you're trying to display a big hash using pp. The full list of features can be found on the Pry website as well as by invoking the help command inside a Pry session. If you're in need of help or have any suggestions you can join the IRC channel #pry on the Freenode network (irc.freenode.net). The source code of Pry is hosted on Github.