Development

Code Spelunking in Rails with Pry

By October 2, 2014 No Comments

In this article, we’ll look at using Pry, an IRB alternative, in a Rails application. In the LISP world, it’s common to develop the entire program interactively from the REPL (language shell) —writing functions, testing and modifying them as you go and saving them to files as needed. Because Ruby is dynamic and allows you to easily modify code at runtime, we can do the same thing. The REPL can be a great tool to explore a codebase or prototype a new feature.

Rails developers should be familiar with the rails console command, which by default, opens a Ruby REPL with IRB (the Interactive Ruby Shell). While IRB certainly gets the job done, it’s very bare-bones out of the box. By default, it doesn’t save history between sessions, it doesn’t auto-complete your code, and it doesn’t provide syntax-highlighting or auto-indentation. While you can fix some of this in your ~/.irbrc by configuring options and loading additional gems, Pry provides all this and more right out of the box.

Getting Pry

First, you’ll need the gem:

gem install pry

Next, test it out with:

pry

If you run any commands, you’ll notice that most things work just about the same way they do in IRB. Like IRB, Pry is first and foremost a Ruby REPL.

Adding Pry to a Rails App

To use Pry with your Rails app, you just need to load the Rails environment. If you don’t mind changing the default rails console, the easiest way to integrate Pry with your Rails app is to add the pry-rails gem to your Gemfile.

# Gemfile
gem 'pry-rails', :group => :development

If you don’t want to change the defaults just yet, there’s another way to load Pry without adding anything to your Gemfile. In your app’s root directory, add a .pryrc file:

# .pryrc
rails = File.join Dir.getwd, 'config', 'environment.rb'
if File.exist?(rails) && ENV['SKIP_RAILS'].nil?
  require rails
  if Rails.version[0..0] == "2"
    require 'console_app'
    require 'console_with_helpers'
  elsif Rails.version[0..0] == "3"
    require 'rails/console/app'
    require 'rails/console/helpers'
  else
    warn "[WARN] cannot load Rails console commands (Not on Rails2 or Rails3?)"
  end
end

(The snippet above is from this page of the Pry wiki.)

If you do add a .pryrc, it’s worth mentioning that you can also define your own methods here that will be loaded each time you start Pry. If you often find yourself running the same series of statements in the console, try adding a method to your .pryrc.

Ever wanted to see at a glance what instance methods are defined by a class? In IRB, you might get the list of methods with vanilla Ruby like this:

irb(main):001:0> Array.instance_methods(false)  # false to exclude methods defined by super 
=> [:inspect, :to_s, :to_a, :to_ary, :frozen?, ...]

This works, but Pry introduces a better way to work with objects. Exploring objects in Pry is a lot like exploring a filesystem from the UNIX command line. Whereas in a BASH session, you have a current working directory, in Pry, you have the current scope (a Ruby object). Just as shell commands like ls work relative to the current directory, Pry commands work relative to the current scope. Here’s how you’d view an object’s instance methods in Pry:

pry(main)> cd Array
pry(Array):1> ls -M   # Run `help ls` in Pry to see what each option does.
Array#methods:
    &    []=      collect      dclone      empty?            first   
    *    abbrev   collect!     delete      encode_json       flatten
    ...

Of course, if you weren’t planning on doing anything else within Array, you could also get the above via ls -M Array. It’s the same concept you’re probably already familiar with in BASH.

Once you’ve cd-ed into an object, even method calls work relative to the current scope:

pry(main)> cd Math::PI
pry(3.14159):1> self
=> 3.141592653589793
pry(3.14159):1> floor
=> 3
pry(3.14159):1> send(:/, 2)
=> 1.5707963267948966

Like BASH, it’s also easy to move around:

pry(main)> cd String
pry(String):1> cd Float
pry(Float):1> cd -
pry(String):1> cd ..
pry(main)>

If this looks interesting, this is just the tip of the iceberg. Check out State Navigation on Pry’s wiki for more details.

Editor Integration

While debugging in Pry, you’ll probably need to modify the code at some point. The standard way to go about this is to switch to your editor, find and open the relevant file, and then find the relevant line. Pry makes this a bit easier with its editor integration.

First, tell Pry about your favorite editor by creating a ~/.pryrc (in your home directory) and configuring the editor. (If you already have $EDITOR defined, Pry will use that, and you can skip this step.)

# ~/.pryrc
Pry.config.editor = 'vim'  # Or 'emacs', 'subl', 'mvim', etc.

The editor value should be an executable in your $PATH or a full path to one somewhere else.

Once you have this set up and have reloaded Pry, you can start to use the editor integrations. This is where Pry’s editcommand comes in. The simplest thing you can do is provide a file path:

pry(main)> edit app/models/post.rb:12

This will open app/models/post.rb in your editor, with the cursor on line 12. After you close your editor, Pry will reload app/models/post.rb with any changes you’ve made.

You can even provide a method as argument, and Pry will find the file that defines the method and open your editor at the start of the method’s definition. Here’s how debugging a method might look in Pry:

pry(main)> Post.most_popular          # oh no, there's an error
RuntimeError: ...
pry(main)> edit Post.most_popular     # edit the method in editor
pry(main)> Post.most_popular          # Pry reloads changes, now try to call the method again
=> [#<Post id:1>, #<Post id:2>, ...]  # it works

Check out Editor Integration on the Pry wiki for more details.

Rails Integrations

If you went with the pry-rails gem, there are a few useful tools it provides:

The show-routes command prints your routes, accepting an optional --grep flag which allows you to filter the results. In essence, it’s a faster version of rake routes | grep PATTERN that knows a little more about your Rails project than the command-line grep:

pry(main)> show-routes --grep admin
    admin_posts   GET    /admin/posts(.:format)           admin/posts#index
    admin_posts   POST   /admin/posts(.:format)           admin/posts#create
edit_admin_post   GET    /admin/posts/:id/edit(.:format)  admin/posts#edit
...

Similarly, the show-models command prints your model schemas, also accepting an optional --grep flag to filter the results.

pry(main)> show-models --grep deleted_at
User
    id: integer
    email: string
    deleted_at: datetime
    ...
Post
    id: integer
    title: string
    deleted_at: datetime
    ...

Honorable Mentions

There are a lot of other cool features that I didn’t have time to describe in depth. Here are the cliff notes on a few of them:

  • show-doc Array#sort — View the documentation for the Array#sort method.
  • show-source Array#sort — View the implementation of the Array#sort method (in this case: C code).
  • Use Pry as your debugger by inserting binding.pry at the target line and executing it with Pry.
  • Execute arbitrary shell commands by prepending a . (e.g., .ls or .git status)
  • Use the awesome_print gem to format output by adding it to your ~/.pryrc. See here for more details.
  • As with IRB, _ gets you the result of the last expression. Very useful for those times you forget to save the result to a variable.

That’s it for now. If you decide to give Pry a try, be sure to read the wiki. It’s very thorough and goes much more in-depth on these features.

Web Application Startup Guide

A 30-page ebook that covers positioning, marketing, pricing, and building your startup product, plus more.