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.
Navigating Objects with Pry
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 theArray#sortmethod.show-source Array#sort— View the implementation of theArray#sortmethod (in this case: C code).- Use Pry as your debugger by inserting
binding.pryat the target line and executing it with Pry. - Execute arbitrary shell commands by prepending a
.(e.g.,.lsor.git status) - Use the
awesome_printgem 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.