Powering your Ruby & Rails development with Pry

Tiago Parreira
Jul 6, 2018 · 12 min read
Image for post
Image for post

(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
and start your console with , or install 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?

Image for post
Image for post
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.”

Image for post
Image for post

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 ()
  • Syntax highlighting
  • Navigation around state (, 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 in your Gemfile, and ! Now every time you boot your you’ll have a Pry shell as opposed to the standard IRB. Simple!

The one thing all Pryers probably use is .

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

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

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

We can see that 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 :

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
b = get_binding("hello")
eval("param", b) #=> "hello"

We used one of Pry’s commands: . It shows us the documentation for any given method on the go!
So now we know: 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 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
example On any object
example With options
def my_method
binding.pry :quiet => true
@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 is actually just a regular method that starts a Pry REPL over our object.

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

So now we understand what binding.pry is, and learned about along the way!
I wonder if there’s any options we can pass ? We can call 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 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 alias in the form of , which allows us to simply call 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

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

pry("some TEXT!")> self
=> "some TEXT!"
pry("some TEXT!")> upcase
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
% 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 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 , but seems the method does not exist, so we used the Pry command 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 to which allowed us to greb the methods with and get what we wanted quickly: the 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 .
  • 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 ‘d the pry over the string, which brought us back to the regular Pry context.

Calling by itself in that context is the same as calling , or even in the regular Pry context because it gets called over .

We could’ve gotten to the through other means by using the 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

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

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

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 /

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

Another useful command is , 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

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

You can dynamically edit code from within Pry with , 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!"

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 back on, you’ll find out that Array#second still goes Woop!.

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

What if you love using Sublime Text or something else instead? Well, you can. is a special file that Pry loads every time it starts (like some sort of ), 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:
Now if we were to redo the 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 to list the current session’s command history, and even grep with or replay with .

pry(main)> puts "p"
pry(main)> puts "r"
pry(main)> puts "y"
pry(main)> hist
1: puts "p"
2: puts "r"
3: puts "y"
pry(main)> hist -r 1..3
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 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 and which list out all the attributes a given attribute have, and all their relationships, and usable with the flag for grepping attribute names or types:

pry(main)> show-models -G text
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
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 , which does what the name implies, and also takes a flag for grepping.
No more starting up a new shell to execute 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?

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

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.

Image for post
Image for post

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 :)

Ruby Inside

Ruby articles and posts

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store