Powering up your Ruby & Rails development with Pry

Tiago Parreira
Ruby Inside
Published in
12 min readJul 6, 2018

(Most of what here applies to Plain old Ruby development without Rails, except the last show-model and show-routes helpers, simply use the plain
gem 'pry' and start your console with pry , or install pry globally. )

What is Pry?

It’s something I believe every Ruby & Rails developer should use. Everyone has their own workflow for debugging and developing software, and clearly you can be a godly developer without using a proper debugger, but everyone can take at least some advantage off of Pry. Even if just for the Syntax Highlighting, which by itself is a huge plus: where can you more quickly read off the relevant data below?

Hmmmm… colors…

Put succinctly, it’s an alternative to the standard IRB shell for Ruby, extremely powerful and tailored to make our development lives easier!

This post is geared towards motivating those who do not use Pry to do so, and for showing off powerful Pry features that current Pryers might not be aware of.

I stumbled across this really interesting excerpt here, and I think it illustrates something we should always have in mind: don’t just constantly hack away, think how to hack away more efficiently!

There’s a guy who stumbled into a lumberjack in the mountains. The man stops to observe the lumberjack, watching him feverishly sawing at this very large tree. He noticed that the lumberjack was working up a sweat, sawing and sawing, yet going nowhere. The bystander noticed that the saw the lumberjack was using was about as sharp as a butter knife. So, he says to the lumberjack, “Excuse me Mr. Lumberjack, but I couldn’t help noticing how hard you are working on that tree, but going nowhere.” The lumberjack replies with sweat dripping off of his brow, “Yes… I know. This tree seems to be giving me some trouble.” The bystander replies and says, “But Mr. Lumberjack, your saw is so dull that it couldn’t possibly cut through anything.” “I know”, says the lumberjack, “but I am too busy sawing to take time to sharpen my saw.”

Pry offers us a plethora of advanced features to aid in this, such as (taken from pry’s documentation):

  • Source code browsing (including core C source with the pry-doc gem)
  • Documentation browsing
  • Live help system
  • Open methods in editors (edit Class#method)
  • Syntax highlighting
  • Navigation around state (cd, ls and friends)
  • Runtime invocation (use Pry as a developer console or debugger)

We’ll talk a little about all these throughout.

To get started using Pry, simply include the gem 'pry-rails' in your Gemfile, and bundle install! Now every time you boot your rails console you’ll have a Pry shell as opposed to the standard IRB. Simple!

The one thing all Pryers probably use is binding.pry.

What does it do? If the Ruby interpreter comes across that magical line, it’ll stop execution and start a REPL (read-evaluate-print-loop), allowing us to dynamically type Ruby code, which gets evaluated, and we can see the result! Amazing stuff.

But what is it? The magical binding.pry we Pryers constantly type?

Let’s stop looking at it as a magical keyword and look at some basic Ruby:

$ rails console
pry(main)> text = “sample string”
pry(main)> text.upcase
=> "SAMPLE STRING"

What did we do? We simply invoked an instance method over the String object text. It’s the same as binding.pry:

$ rails console
pry(main)> binding
=> #<Binding:0x007fee1297a308>
pry(main)> binding.class
=> Binding

We can see that binding is an actual object here, of the Binding class. But… what is it? Is it from Pry? Let’s start a rails console without Pry and check it out:

$ DISABLE_PRY_RAILS=1 rails console
irb(main)> binding
=> #<Binding:0x007fb29c85c4a0>

We still have it… so it’s not from Pry. Is it from Rails? Let’s boot IRB:

$ irb
irb(main)> binding
=> #<Binding:0x007fce81825f30>

So plain Ruby has the binding object? Hmm. I wonder what’s a binding then!

Enter Pry. One of its very powerful features is the command system, with which you can implement commands that fit your own personal workflows. But that’s not to be covered here.

Pry already has some useful commands for source code browsing implemented, and there’s a cool one we could really use right now to answer our question. Let’s try out show-doc:

pry(main)> show-doc bindingFrom: proc.c (C Method):
Owner: Kernel
Visibility: private
Signature: binding()
Number of lines: 10
Returns a Binding object, describing the variable and
method bindings at the point of call. This object can be used when
calling eval to execute the evaluated command in this
environment. See also the description of class Binding.
def get_binding(param)
return binding
end
b = get_binding("hello")
eval("param", b) #=> "hello"

We used one of Pry’s commands: show-doc. It shows us the documentation for any given method on the go!
So now we know: binding is actually an object that describes a variable and its state at the point of call.

So what is pry? Let’s do the same with pry… we reached the conclusion it was an instance method, right? Let’s try calling show-doc over the binding.pry itself and see if it works:

pry(main)> show-doc binding.pryFrom: (...)/gems/pry-0.10.4/lib/pry/core_extensions.rb @ line 23:
Owner: Object
Visibility: public
Signature: pry(object=?, hash=?)
Number of lines: 18
Start a Pry REPL on self.If `self` is a Binding then that will be used to evaluate expressions;
otherwise a new binding will be created.
param [Object] object the object or binding to pry
(__deprecated__, use `object.pry`)
param [Hash] hash the options hash
example With a binding
binding.pry
example On any object
"dummy".pry
example With options
def my_method
binding.pry :quiet => true
end
my_method()
@see Pry.start

It works: Pry’s parser understands that you’re interested in seeing the documentation for the method you’re calling, not the object.

So now we know pry is actually just a regular method that starts a Pry REPL over our binding object.

When we’re getting our binding.pry onto a Controller, Model, or some other Object, all we are doing is starting a Pry REPL over the binding of, for example, an ApplicationController or ActiveRecord::Base object, which would be the self described in the above pry documentation. Which means binding.pry is equivalent to pry self.send(:binding) (binding is a private method, so you have to send it.), in which we start a Pry REPL over the binding of the current self object.

So now we understand what binding.pry is, and learned about show-doc along the way!
I wonder if there’s any options we can pass show-doc ? We can call help show-doc to check this:

pry(main)> help show-docUsage:   show-doc [OPTIONS] [METH]
Aliases: ?
Show the documentation for a method or class. Tries instance methods first and
then methods by default.
show-doc hi_method # docs for hi_method
show-doc Pry # for Pry class
show-doc Pry -a # for all definitions of Pry class (all monkey patches)
-s, --super Select the 'super' method. Can be repeated to traverse the ancestors
-l, --line-numbers Show line numbers
-b, --base-one Show line numbers but start numbering at 1 (useful for `amend-line` and `play` commands)
-a, --all Show all definitions and monkeypatches of the module/class
-h, --help Show this message.

We can call help by itself, which will list us all the Pry commands that are available, even ones you implement yourself. If you check it out, we can see we have a show-doc alias in the form of ? , which allows us to simply call ? binding.pry for the same result. Handy!

So does this mean we can pry anything? Yes, any object can be pry’d! Let’s take a string’s example:

pry(main)> our_string = "text!"
pry(main)> our_string.pry
pry("text!")>

We can see that the pry context is now the string:

pry("some TEXT!")> self
=> "some TEXT!"
pry("some TEXT!")> upcase
=> "SOME TEXT!"
pry("some TEXT!")> lowercase
NameError: undefined local variable or method `lowercase' for "some TEXT!":String
from (pry):32:in `__pry__'
pry("some TEXT!")> ls
(...)
Colorize::InstanceMethods#methods: colorize colorized? uncolorize
String#methods:
% classify gray mb_chars rpartition to_c
* clear grayish next rstrip to_d
+ codepoints green next rstrip! to_date
(...)
pry("some TEXT!")> ls -G case
String#methods: camelcase casecmp downcase downcase! swapcase swapcase! titlecase upcase upcase!
pry("some TEXT!")> downcase
=> "some text!"
pry("some TEXT!")> exit
=> nil
pry(main)> self
=> main

We can see here that self is now our string, so any methods we are calling are in the context of that same string: the same would happen for any other Pry’d object. We tried calling lowercase , but seems the method does not exist, so we used the Pry command ls over it, which lists us pretty much all we need to know about an object: it’s class and instance methods along with the namespaces that implemented those, local and instance variables… anything that applies given which type of object it is.
But that’s too much information, so we passed the option -G case to ls which allowed us to greb the methods with case and get what we wanted quickly: the *case methods.
Doesn’t this beat the other alternative, of:

  • Changing to browser;
  • Possibly getting distracted by whatever (don’t pretend you don’t have an open tab with cute cat pictures for the stressful moments!);
  • Refocusing and going on google;
  • Searching for “Ruby lowercase string”;
  • Entering the nearest stackoverflow/ruby-doc/whatever and finding out that the method is downcase .
  • Some more cat picture viewing…
  • Back to terminal. What was I doing again?

Of course, this is a very contrived example, but you get my point, the less you go out of the developing context, the better, even if you’re not distraction-prone.
And to boot you learn so much about Ruby by stumbling upon new methods you did not know!
And then we exit ‘d the pry over the string, which brought us back to the regular Pry context.

Calling ls by itself in that context is the same as calling ls "some TEXT!" , or even ls String in the regular Pry context because it gets called over self .

We could’ve gotten to the downcase through other means by using the find-method command, where the first parameter is the string we’re Grep’ing by, and the second one the object:

pry(main)> find-method case our_string
String
String#camelcase
String#titlecase
String#casecmp
String#upcase
String#downcase
String#swapcase
String#upcase!
String#downcase!
String#swapcase!

Have you ever paid attention when using binding.pry in a controller or model? This is what you might get: pry(#<PostsController>)> , you’re just Prying an instance of the PostsController class, whilst running code interactively.

Then there’s Pry command cd , with which you can pry into objects, just like pry . You can use pry for this like we have been doing, but using cd is preferable because it gives us additional features, like nesting :

pry(main)> our_hash = { first: [1, 2, 3], second: "text" }
=> { :first => [1, 2, 3], :second => "text" }
pry(main)> cd our_hash
pry(#<Hash>):1> self
=> { :first => [1, 2, 3], :second => "text" }
pry(#<Hash>):1> cd self[:first]
pry(#<Array>):2> self
=> [1, 2, 3]
pry(#<Array>):2> nesting
Nesting status:
--
0. main (Pry top level)
1. #<Hash>
2. #<Array>
pry(#<Array>):2> jump-to 1
pry(#<Hash>):1> self
=> { :first => [1, 2, 3], :second => "text" }
pry(#<Hash>):1> cd self[:first]
pry(#<Array>):2> nesting
Nesting status:
--
0. main (Pry top level)
1. #<Hash>
2. #<Array>
pry(#<Array>):2> cd ..
pry(#<Hash>):1> self
=> { :first => [1, 2, 3], :second => "text" }
pry(#<Hash>):1> nesting
Nesting status:
--
0. main (Pry top level)
1. #<Hash>
pry(#<Hash>):1> cd /
pry(main)>

By using cd you can access nesting which allows you to jump within the objects as if they were folders, you can jump-to # between nesting levels, cd .. to go back, cd / to return to the original context, or even cd complex paths at once: cd ../object_1/object_2

Another useful command is show-source , also accessible through the $ alias. Calling it over any method, class or object, will show it’s definition:

pry(main)> show-source ArrayFrom: (...)/lib/active_support/core_ext/array/access.rb @ line 1:
Class name: Array
Number of monkeypatches: 13. Use the `-a` option to display all available monkeypatches
Number of lines: 64
class Array
# Returns the tail of the array from +position+.
(...)
pry(main)> show-source Array#secondFrom: (...)/lib/active_support/core_ext/array/access.rb @ line 33:
Owner: Array
Visibility: public
Number of lines: 3
def second
self[1]
end

A useful option you can pass to show-source is -a , which will also list all the monkeypatches that object might have.

You can dynamically edit code from within Pry with edit , which can be used for simply viewing code in your favorite editor, or actually editing it. Let’s try screwing with Array’s #second method:

pry(main)> our_array = ["a", "b", "c"]
=> ["a", "b", "c"]
pry(main)> our_array.second
=> "b"
pry(main)> edit Array#second
# Here you are taken to your configured Editor (Vi by default?).
# I replaced Array#second with the following, saved and exited:
# def second
# "Woop!"
# end
pry(main)> our_array.second
=> "Woop!"
pry(main)>

What happened? We edited the file containing the Array#second method definition, and Pry instantly reloaded the newly-edited code in. Nifty, huh?
But be careful: this was a permanent change. If you reboot your rails console back on, you’ll find out that Array#second still goes Woop!.

You can pass a -p flag onto the edit method to just patch the currently running code, but not modify the actual file. If we had used that flag, on a rails console reboot, our Array#second method would be back to normal.

What if you love using Sublime Text or something else instead? Well, you can. ~/.pryrc is a special file that Pry loads every time it starts (like some sort of ~/.bashrc ), and you can configure a LOT of functionality with it, as well as add your own methods and Pry commands. This is where we tell Pry what editor to use.

I personally use Sublime Text, so I’ll boot this line onto the file and save it: Pry.editor = "sublime"
Now if we were to redo the edit command, we’re taken to Sublime! The Pry session will hang up until the file is not saved, but closed. When it’s closed, Pry detects the file as having the “edit done”, and reloads it in.

You can also use hist to list the current session’s command history, and even grep with -G or replay with -r .

pry(main)> puts "p"
p
pry(main)> puts "r"
r
pry(main)> puts "y"
y
pry(main)> hist
1: puts "p"
2: puts "r"
3: puts "y"
pry(main)> hist -r 1..3
p
r
y
pry(main)> hist -G y
3: puts "y"

Ever found yourself in a Pry session in the context of a running rails app retyping the lines you are stopped on, or copy and pasting them from your editor? Don’t, just play them:

From: (...)/application_controller.rb @ line 7 ApplicationController#controller_method:5: def controller_method
6: binding.pry
=> 7: puts "lots of code with"
8: puts "nestings and loops..."
9: end
pry(#<ApplicationController>)> play -l 7..8
lots of code with
nestings and loops...

Just like that, you can play single lines or a range of them consecutively, very handy!

Then if you’re riding on da Railzzz, you also have show-models and show-model which list out all the attributes a given attribute have, and all their relationships, and usable with the -G flag for grepping attribute names or types:

pry(main)> show-models -G text
Post
id: integer
content: text # This will be highlighted due to the "text" grep
author_name: string
belongs_to: author
pry(main)> show-models -G auth
Post
id: integer
content: text
author_name: string # Highlighted due to the "auth" grep
belongs_to: author # Highlighted due to the "auth" grep

Use case? “Ahhhhhh, where was that authentication token for facebook again? Or that cryptic attribute whose name I remotely remember? I’ll just do a search over some subset of files on my project. Ahhhhhh, so many irrelevant results…”

Last but not least, there’s show-routes , which does what the name implies, and also takes a -G flag for grepping.
No more starting up a new shell to execute rake routes | grep login and wait for it to boot up Rails just to give us the routes on the side!

pry(main)> show-routes -G login
login GET /login(.:format) sessions#index

This was an introduction to Pry, and this is but the tip of what it’s capable of, but what I deem the most frequently useful commands.
What should you take from this?

  • ls a lot to figure out what methods/variables/locals an object/context has.
  • find-method for looking up methods/objects whose names you do not remember. It’s very powerful.
  • show-source to quickly see the method definitions of code you want to understand better.
  • show-doc to see documentation for methods or Objects you are not sure about.
  • show-models and show-routes for checking out models and routes (Rails-only!).
  • Print a pretty history of what you’ve done in the Pry sessions with hist , and play back lines you want to.
  • Jump around within objects to check their state with cd .

A lot of these functions were not-as-clean-and-configurable methods I had myself made on my .pryrc and used frequently. But when I started exploring Pry I noticed that a lot of useful .pryrc methods were already actual features!

What can we sum this up as? I’ll quote Pry here on their motto:

Get to the Code.

Any feedback (I love feedback, good or bad, have at me!) or any sort of comment, fling me an email at parreirat@gmail.com :)

Thanks for reading.

PS — I live in Berlin and looking for a job, hit me up if you’d like to have a chat or know a cool company. Thanks :)

--

--