I joined the Wombat team a few months ago, and have been working on the ThreatSim team. We had a bit of a bug backlog, so I’ve been doing lots of bug fixing.

ThreatSim is a Ruby on Rails application; any developer out there who works with Rails has probably used Pry extensively in debugging their application. Pry “pauses” your application’s execution and lets you observe and manipulate state, wherever the pry happens to be.

Most pry usage is pretty simple - put a pry in your code, cause that line of code to be executed, and then poke around in the session in your terminal.

For me, this can feel unwieldy when I am trying to do a broad examination of the application. Pry is great at showing me the state of the variables contained within the method that the Pry was placed at, but I don’t always want to see just this code and its variables, I want to skip around the application and peek into different components.

The ThreatSim codebase is large, and still very new to me, so I’ve had to sharpen my skills with tools like Pry to most quickly wrap my head around complex applications.

All of the following tips are intended to be used inside the Pry REPL.

Looking at methods

You can use show-method to view any piece of code in your application.

There are two primary ways I use show-method:

  1. show-method without a specific method argument
  2. show-method with a specific method argument

‘show-method’ without method arguments

If you call just show-method it will show all of the code in the method that you’ve placed the pry.

For example:

<CookiesController:0x00007f9156c57670>:0> show-method -l

From: /full/path/to/file.rb @ line 78:
Owner: CookiesController
Visibility: private
Number of lines: 37

 78: def load_cookie_jar
 79:   cookies[:tasty] = true
 80:   count = count_cookies
 81:   .
       lots of other code here

111:   require "pry"; binding.pry
113:   Repo::FakeClass::NotActuallyAModule.do_something(options)
114: end

(An astute observer may notice that I passed the -l argument to show-method. This will print out the line numbers along side the method itself.)

‘show-method’ with method argument

See that the line about to be executed in the above example (line 113)? What if you want to see what that method is, without jumping into your code editor?

If you want to see what that method is, it’s easy! Use show-method App::Class.method_name:

<CookiesController:0x00007f9156c57670>:0> show-method Repo::FakeClass::NotActuallyAModule.do_something -l

From: full/path/to/file.rvb @ line 165:
Owner: #<Class:Repo::FakeClass::NotActuallyAModule>
Visibility: public
Number of lines: 22

165: def do_something(options = {})
166:   cookies_type = options.fetch(:cookie_type)
167:   is_tasty?      = options.fetch(:is_valid, false)
169:   if is_tasty?
170:     log_it "load_cookies", "is_tasty"
171:     options[:consumed] = nil
172:     options[:pairs_with] = ""
185:   end
186: end

In the above example, I passed in the full “namespace path” (I just made that term up) to reveal the code behind any method you’d like to see.

(I’m still adding -l to force line-numbers to be printed out.

more about show-source from Pry

Breakpoints in Pry

Often, when using show-method to look at other pieces of code about to be executed, you might decide you want to examine that specific method with a binding.pry in it.

For example, in the last section we just looked at Repo::FakeClass::NotActuallyAModule.do_something using show-method, but what if we wanted to step through the method, one line at a time, in pry?

Enter breakpoints. Just like with javascript in the browser, you can add/remove breakpoints to your code with Pry. You don’t have to exit the session, jump to the new method, and add a binding.pry to it.

You’ll need to add pry-byebug to your Gemfile.

With pry-byebug, breakpoint functionality is fairly straightforward:

  • break shows all current breakpoints. (this list should be empty if you’re running break for the first time.
  • break <Class#method> adds a breakpoint to the start of the given method.

if you add a breakpoint, and call break you’ll see something like:

  # Enabled At

  1 Yes     Cookies::CookiesController::CookiesLoader.do_something

Once you’ve added a breakpoint, you can continue your way from the current pry and code execution will stop when it hits that breakpoint.

break --help is a fruitful summary of what breakpoint-related methods are available to you.

more about breakpoints in Pry

Where was I?

Sometimes, I go so far down a rabbit hole of digging around in Pry, I forget where the binding.pry actually is, and what I was trying to do in the first place.

Enter whereami

This command simply prints out the code surrounding the current binding.pry. It’s run by default as soon as you hit the pry, which is how you can quickly get your bearings.

from the pry docs: whereami

View stack traces

What was that stack trace from the last exception you saw?

wtf prints said stack trace:

<CookiesController:0x00007f9156c57670>:0> not_a_variable
NameError: undefined local variable or method `not_a_variable' for #<CookiesController:0x00007f9156c57670>
from (pry):16:in `load_cookie_jar'

and then, anytime later, call wtf in pry:

<CookiesController:0x00007f9156c57670>:0> wtf
Exception: NameError: undefined local variable or method `not_a_variable' for #<CookiesController:0x00007f9156c57670>
0: (pry):16:in `load_live_action'
1: /Users/joshthompson/.rvm/gems/ruby-2.3.7/gems/pry-0.10.3/lib/pry/pry_instance.rb:355:in `eval'
2: /Users/joshthompson/.rvm/gems/ruby-2.3.7/gems/pry-0.10.3/lib/pry/pry_instance.rb:355:in `evaluate_ruby'
3: /Users/joshthompson/.rvm/gems/ruby-2.3.7/gems/pry-0.10.3/lib/pry/pry_instance.rb:323:in `handle_line'
4: /Users/joshthompson/.rvm/gems/ruby-2.3.7/gems/pry-0.10.3/lib/pry/pry_instance.rb:243:in `block (2 levels) in eval'

more about wtf in Pry

Calling all callers

Ever wanted to see what called the code that hit your breakpoint?

I sure have!

As usual, Stack Overflow has a most helpful answer.

You can just call caller in pry, to get a full list of all current callers.

The author of the post points out that you immediately get a giant array of mostly-irrelevant items, and suggests filtering by keyword, using a one-liner like so:

caller.select {|line| line.include? "current_repo_name" }

Or, alternatively:

caller.reject { |l| l[".rvm/gems"] }

(I’m partial to the bottom one)

Pry is an incredible tool, and I am continually impressed at how powerful it is. I am thankful to the team that maintains it!

Additional reading, or articles that helped me learn more about Pry: