skip to content

At a Ruby debug gem (rdbg) prompt, what do step, next, finish and continue do, and how do info and bt help?

level: juniorimportance: should knowfreq 48%

answer

  1. into, over, out, run
  2. Enter repeats step and next
  3. info shows %self and locals
  4. bt lists the frames
  5. p n, since n is a command

basics

~20 s

In the debug gem, step enters the next call, next runs to the next line of the same method, finish runs until the current method returns, and continue runs to the next breakpoint. info lists locals; bt prints the call stack.

solid answer

~40 s

`step` (`s`) moves to the next breakable point, entering any method called on the current line; `next` (`n`) runs the current line and stops on the following one in the same frame; `finish` (`fin`) runs until the current method returns; `continue` (`c`) runs until the next breakpoint or the end. Pressing Enter on an empty line repeats commands such as `step` and `next`. `info` shows the current frame's locals, with `self` as `%self` and, after a return, the value as `_return`; `info ivars` shows instance variables. `bt` (`backtrace`) lists frames, and `up`, `down` or `frame 2` switch which frame expressions are evaluated in. One trap: a line that starts with a command name is run as that command, so to print a local named `n` or `c` type `p n`.

code

ruby · 12 lines
ruby
(rdbg) info locals
%self = #<TaxCalculator:0x...>
order = [{price: 600, qty: 2, country: "UK"}]
net = 1200
(rdbg) step
(rdbg) p country
=> "UK"
(rdbg) bt
=>#0    TaxCalculator#tax_on(net=1200, country="UK") at tax_calc.rb:15
  #1    TaxCalculator#total_for(order=[...]) at tax_calc.rb:9
  #2    <main> at tax_calc.rb:20
(rdbg) finish

go deeper

for a junior

Recall the four moves: step into, next over, finish out, continue to the next breakpoint, and that info shows the locals.

for a middle

Use bt with up and down to inspect callers, _return after finish, and p for variables whose names collide with commands.

for a senior

Step efficiently through real failures: pick breakpoints so stepping is short, filter bt, and move frames instead of re-running.

for a principal

Judge when interactive stepping is the wrong tool compared with logs, traces or a failing test, especially for concurrency bugs.

## The four movement commands When the debug gem stops a Ruby program, the `(rdbg)` prompt accepts **debug commands** and plain Ruby expressions. Four commands move execution forward: | Command (short form) | Runs until | |---|---| | `step` (`s`) | the next breakable point, **entering** any method or block the current line calls | | `next` (`n`) | the next line of the **current** frame, running calls on this line without stopping in them | | `finish` (`fin`) | the current frame **returns** to its caller | | `continue` (`c`, `cont`) | the next breakpoint, or the end of the program | Each takes a count (`step 3`, `finish 2` for two frames). A related command, `until` (`u`), is like `next` but only stops on later lines — handy for leaving a loop. **Pressing Enter** on an empty prompt repeats `step`, `next`, `finish` and `continue`, so stepping through a method is a matter of tapping Enter. ## Looking around: info, bt and frames - **`info`** (`i`) prints the current frame's local variables, instance variables and relevant constants. `info locals` narrows to locals; the list starts with `%self` (the receiver) and, right after a method returns, includes **`_return`** (its return value). `info ivars`, `info consts` and `info globals` show the other groups, and `info ... /regexp/` filters. - **`bt`** (`backtrace`) prints the call stack, one frame per line with its location and arguments. `bt 10` limits the count and `bt /tax/` filters by method or path. - **`up`**, **`down`** and **`frame <n>`** change the **current frame** without moving execution, so `p order` in a caller's frame shows that caller's variable. - **`list`** (`l`) prints more of the current source; **`whereami`** reprints where you are. ## Evaluating Ruby at the prompt Anything that is not a debug command is evaluated as Ruby in the current frame and printed with `pp`, so `net * 0.19` just works. The catch is that **single-letter and short names are commands first**: `s`, `n`, `c`, `b`, `i`, `l`, `p`, `q`, `u` and others. In a method with a local called `n` or `c`, typing `n` steps instead of printing it. The debug gem's own advice is to use **`p`**, **`pp`** or **`eval`** explicitly for expressions: `p n`. ## Walking a failing tax calculation Suppose `TaxCalculator#total_for` raises `KeyError` for an order from "UK" and you have stopped at a `binding.break` just before `tax_on` is called: 1. `info` — check `net` and `order`; `%self` confirms which calculator you are in. 2. `step` — enter `tax_on`, rather than jumping over it as `next` would. 3. `p country` — confirms the key is `"UK"`, which `RATES` does not contain. 4. `bt` — shows that `tax_on` was called from `total_for`, called from the report script. 5. `up` then `p order` — inspect the caller's data without moving. 6. `finish` or `continue` — let it run on (here into the `KeyError`). ## Ending the session - `continue` with no breakpoints left lets the program run to completion. - `quit` (`q`, or Ctrl-D) ends the debugger and, in a local session, the program; it asks for confirmation, `quit!` does not. - `kill` terminates the debuggee with `Kernel#exit!`.

  • You are stopped in a method with a local named c. What does typing c at the (rdbg) prompt do?
    It runs the `c` (continue) command, because input that matches a debug command is executed as that command before any Ruby evaluation. The program resumes instead of printing the variable. Use `p c`, `pp c` or `eval c` to evaluate it.
  • How do you see a method's return value right after it finishes?
    Use `finish` to run until the current frame returns; the debugger stops at the return event, and `info` (or `info locals`) then lists the value as `_return` alongside the other locals. It is a quick way to check what a helper like `tax_on` produced without adding a print.
  • How do up and down differ from finish?
    `up` and `down` change which frame the prompt inspects and evaluates in, without running any code. `finish` actually resumes execution until the current frame returns. Use `up` to read a caller's locals; use `finish` to move on.

saying these in an interview costs you the question

  • next steps into every method called on the current line.
  • finish runs the program to the end, like continue.
  • Typing a local variable named n always prints it at the rdbg prompt.
  • up moves execution back to the caller and re-runs it.
  • info only works after you declare which variables to watch.