Debugging with pry-byebug: moving in the stack frame
It is a truth universally acknowledged that a single developer in possession of a good codebase must be in want of a bug-free application 1.
Alas, debugging never ends. The more you learn, the more debugging becomes complex.
I think it is high time we dive deeper into pry-byebug
. Are you new to pry-byebug
? Go and check the beginners introduction to debugging your code first.
Here our menu du jour: moving in the stack frame, adding breakpoints on the fly, and some handy shortcuts (because who loves to write continue
continually).
Step into the stack frame: step
I discovered step
only recently. One easy way to understand step
is to explain it in contrast to next
.
next
executes the next line in your current context. step
steps into the specific context - the frame - of the next line in your code.
The following example is a basic endpoint that allows me to get all available books and a Book
model with a class method.
The breakpoint will pause execution before .available
and open a debugging console.
When I type next
, the result of Book.available
is assigned to available_books
and the execution stops before the next line.
What happened in Book.available
? I don’t know. I only executed that line of code and stayed in my current frame - BooksController
.
Let’s re-run my code and use step
instead.
Typing step
takes me from my BooksController
to my Book
model. I’ve changed frames. I’m now exploring the class method Book.available
.
I can now check whether my class method works as intended.
Disclaimer: step
is a bit of a rabbit hole. It’s a great way to explore how Rails works. For instance, if I type step
before where(available: true)
, my console returns:
Yep, I’m now checking out ActiveRecord’s inner gut.
Move up the stack frame: up
Remember when we dived into the frames? Well, how do I come back to my BooksController
? With up
, of course.
If I type up
in my console, I’ll move up the frames towards my initial breakpoint.
What if I’ve moved down frames several times? I can either pass the number of frames I’d like to go up as an argument - up(2)
- or type up
several times.
Add and remove breakpoints on the fly
1) Add a breakpoint from the console: break
If I realize, once I’m in my debugging console, that I would have needed another breakpoint, I can add it on the fly with break line_number
.
I can type break 06
, resume the execution, and have it paused before the render json
.
A few things to consider:
Breakpoint 1: /path/controllers/books_controller.rb @ 06 (Enabled)
gives me my new breakpoint reference number:1
. This will come handly later.- What appears after
Breakpoint 1 ...
is part of my breakpoint’s information. Not where my program is currently paused.
Adding breakpoint son the fly makes for a pretty seamless debugging experience. I used to exit the pry
session, go back to my code, add a new breakpoint, then re-run execution. Let me tell you, break 06
came as a relief!
2) Remove a breakpoint from the console: break --delete breakpoint_number
or break -D breakpoint_number
So, now my program is paused before the line 04, and I know I added a second breakpoint on the line 06:
What if I want to remove this second breakpoint?
First, I want to find my breakpoint’s reference by listing all breakpoints with break
. Then, I can delete the breakpoint with break --delete breakpoint_number
.
break
outputs the list of all the breakpoints added in the console.
break --delete breakpoint_number
outputs the list of all remaining breakpoints.
3) Show breakpoints information: break --show breakpoint_number
This is the same output that the one I get after adding a breakpoint.
Check your latest commands: history
history
gives me a list of all past commands I ran during the current pry
session.
Commands and aliases
Finally, here’s a handy table with some commands and their aliases.
command | alias | expected behavior |
---|---|---|
wherami |
@ |
prints out your current context |
continue |
c |
continue program execution |
next |
n |
execute the next line in the current stack frame |
step |
s |
step execution into the next line |
break --delete |
break -D |
delete a breakpoint |
break --show |
break -s |
show a breakpoints details and source |
There’s only one thing left to say: Happy debugging!
Noticed something? Ping me on Twitter or create an issue on GitHub.
Cheers,
Rémi
-
Sorry, just re-read for the umpteenth time Pride and Prejudice. ↩