Interactive Debugging with Pry

Interactive Debugging with Pry #

This article was written in summer 2012, and the topic is not evergreen. I stand by the core recommendations! Use Pry, use its debugging plugins. But the links and exact details may have shifted over time.

I wrote a post about pry earlier, but at the time, I didn’t realize just how much muscle Pry was packing. Install two simple plugins and one builtin function, and you turn Pry into a stepping debugger. It can pause at a breakpoint, step through code one line at a time, and even shuttle up and down the call stack; and since you never lose your Pry superpowers, you can rummage around your state to your heart’s content.

Time Stop #

binding.pry. Two simple words with immense power. Speak them aloud, and your program will pause in place, frozen in time, while the Pry REPL springs up around it. Here’s an example, from the single most important project on Github, an experimental puppy display grid.

# generate HTML from template
template = File.read config["files"]["template"]

binding.pry # ENTER THE MATRIX

engine = Haml::Engine.new template, :format => :html5;
output = engine.render Object.new, :images => images;

This scrap of script crams cute puppies into a HAML template, but first, binding.pry freezes reality. Loops stop looping, events stop listening, and the world halts in an eyeblink. Except for you. You have total freedom: you can peek at your code and tinker with its innards at will. To resume, Ctrl-D; your code will roar back to life and keep going until it hits another binding.pry.

If you run your local Rails instance with rails server or ./script/server, you can even drop into a Pry session right in your terminal, using the same binding.pry technique. Rails debug spam stops: Pry starts.

One Step at a Time #

The pry-nav plugin makes it easy to execute your code one step at a time. When your code hits the brick wall of binding.py, you can walk it forward, line by line, with next – or if you’re not feeling so talkative, alias it to ‘n’ in .pryrc.

We pause at binding.pry; now we can step forward. There will be a little arrow showing us what line we’re on. We can execute any code we want at the command line; we’ll get our output and then skim a little off the top.

gem install pry-nav or add it to your Gemfile to acquire it; require 'pry-nav' to equip it.

Elevator Action #

The pry-stack_explorer gem lets you move up and down the call stack. Can’t debug much of anything without that. These two methods make a nice easy target. They don’t do much of anything, so there’s nothing to debug, but they’re simple, so debugging is easy. Life should be more like that.

require 'pry'
require 'pry-nav'
require 'pry-stack_explorer'

def outer(message, number)
  inner(message)
end

def inner(message)
  local = true
  binding.pry
end

outer("hello", 1000)

Plain old Pry lets you look at your locals when binding.pry sets its teeth. Try to look at something outside the current scope, though, and Ruby stonewalls you, but pry-stack_explorer doesn’t care much for walls. Just use up and down to traverse the stack.

Your program hasn’t moved… just your point of view. show-stack shows you the whole call stack, with a little arrow saying you are here.

Further Reading #

In this post by Pry’s author, you can read more about pry-nav, pry-stack_explorer, and other plugins that might help you out.