Back to home

Pry Debugger Tips main image

Pry Debugger Tips

This post will cover some of the most basic tips on getting more value from the Pry gem.

Source code can be found here

Getting started

We initialize the project demo-pry-debugging, initializer Bundler and add some files:

# Create the project folder $ mkdir demo-pry-debugging $ cd demo-pry-debugging $ touch main.rb # Initialize the project $ bundler init $ bundler add pry --group="development" $ bundler add pry-doc --group="development"

At this stage, our project is now ready to start working with.

Add some basic code

In main.rb, add the following:

require 'pry' require 'pry-doc' class ContrivedMath # A simple function to add two numbers def add(x, y) x + y end # A simple function to subtract the second # argument from the first def subtract(x, y) x + y end end def main v = ContrivedMath.new p v.add(1, 2) binding.pry end main

Here we require the Pry gems we installed.

Then, we create a contrived class with two basic math functions.

Finally, we define and invoke a main function that creates an instance of our contrived class and calls binding.pry to enter the debugger.

The debugger in action

If we run ruby main.rb, we will enter the Pry debugger once the code hits line 20.

ruby main.rb 3 From: /blog-projects/demo-pry-debugging/main.rb:20 Object#main: 17: def main 18: v = ContrivedMath.new 19: p v.add(1, 2) => 20: binding.pry 21: end [1] pry(main)>

Once in this state, we can run some commands so that we can see the variables and methods available to us.

First of all, we can use ls -h with -h as the helper flag to see what helpers we have available for listing objects.

[1] pry(main)> ls -h Usage: ls [-m|-M|-p|-pM] [-q|-v] [-c|-i] [Object] ls [-g] [-l] ls shows you which methods, constants and variables are accessible to Pry. By default it shows you the local variables defined in the current shell, and any public methods or instance variables defined on the current object. The colours used are configurable using Pry.config.ls.*_color, and the separator is Pry.config.ls.separator. Pry.config.ls.ceiling is used to hide methods defined higher up in the inheritance chain, this is by default set to [Object, Module, Class] so that methods defined on all Objects are omitted. The -v flag can be used to ignore this setting and show all methods, while the -q can be used to set the ceiling much lower and show only methods defined on the object or its direct class. Also check out `find-method` command (run `help find-method`). -m, --methods Show public methods defined on the Object -M, --instance-methods Show public methods defined in a Module or Class -p, --ppp Show public, protected (in yellow) and private (in green) methods -q, --quiet Show only methods defined on object.singleton_class and object.class -v, --verbose Show methods and constants on all super-classes (ignores Pry.config.ls.ceiling) -g, --globals Show global variables, including those builtin to Ruby (in cyan) -l, --locals Show hash of local vars, sorted by descending size -c, --constants Show constants, highlighting classes (in blue), and exceptions (in purple). Constants that are pending autoload? are also shown (in yellow) -i, --ivars Show instance variables (in blue) and class variables (in bright blue) -G, --grep Filter output by regular expression -d, --dconstants Show deprecated constants -h, --help Show this message.

Some of the useful flags that I use a lot are -m, -M and -l. If we run ls -l, we can see local variables in this scope:

[2] pry(main)> ls -l v = #<ContrivedMath:0x00007f8096d9a580>

This tells us that we have the local variable v that is an instance of the ContrivedMath class.

Another useful command is the cd command which allows us to switch context.

[3] pry(main)> cd -h Usage: cd [OPTIONS] [--help] Move into new context (object or scope). As in UNIX shells use `cd ..` to go back, `cd /` to return to Pry top-level and `cd -` to toggle between last two scopes. Complex syntax (e.g `cd ../@x/@y`) also supported. cd @x cd .. cd / cd - https://github.com/pry/pry/wiki/State-navigation#wiki-Changing_scope -h, --help Show this message.

We can use that to switch context to v:

[4] pry(main)> cd v [5] pry(#<ContrivedMath>):1>

As you can see, we are now in the context of the ContrivedMath class.

We can then use ls -m to see what instance methods are available:

[6] pry(#<ContrivedMath>):1> ls -m ContrivedMath#methods: add subtract self.methods: __pry__

This is a helpful way to see what other functions could be invoked on the object.

We can also find definitions using the ? command.

[7] pry(#<ContrivedMath>):1> ? add From: main.rb:5: Owner: ContrivedMath Visibility: public Signature: add(x, y) Number of lines: 5 A simple function to add two numbers def add(x, y) x + y end [8] pry(#<ContrivedMath>):1> ? subtract From: main.rb:10: Owner: ContrivedMath Visibility: public Signature: subtract(x, y) Number of lines: 6 A simple function to subtract the second argument from the first def subtract(x, y) x + y end

This gives us an overview of the function definition as well as the doc block above it (plus some other metadata).

When in doubt and looking for tips, you can also use the help command to display all the options for the Pry gem.

Pry-doc and documentation

Using the pry-doc gem, we can also see the source code of the standard library from within the debugger.

First, return context to the top with cd /, then do the following:

[9] pry(main)> ? Array#map! From: array.c (C Method): Owner: Array Visibility: public Signature: map!() Number of lines: 24 Calls the block, if given, with each element; replaces the element with the block's return value: a = [:foo, 'bar', 2] a.map! { |element| element.class } # => [Symbol, String, Integer] Returns a new \Enumerator if no block given: a = [:foo, 'bar', 2] a1 = a.map! a1 # => #<Enumerator: [:foo, "bar", 2]:map!> Array#collect! is an alias for Array#map!. static VALUE rb_ary_collect_bang(VALUE ary) { long i; RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); rb_ary_modify(ary); for (i = 0; i < RARRAY_LEN(ary); i++) { rb_ary_store(ary, i, rb_yield(RARRAY_AREF(ary, i))); } return ary; }

This could be used for any of the standard library methods.

Summary

Today's post demonstrated some of the most useful features of the pry gem and how it can be used to get a better concept of scope and context when debugging.

Resources and further reading

  • Pry
  • Source code

Photo credit: angeloabear

Personal image

Dennis O'Keeffe

@dennisokeeffe92
  • Melbourne, Australia

Hi, I am a professional Software Engineer. Formerly of Culture Amp, UsabilityHub, Present Company and NightGuru.
I am currently working on workingoutloud.dev, Den Dribbles and LandPad .

1,200+ PEOPLE ALREADY JOINED ❤️️

Get fresh posts + news direct to your inbox.

No spam. We only send you relevant content.