loading...
Runtime Revolution

Four things about Pry

brunjact profile image B Jacquet Originally published at revs.runtime-revolution.com on ・4 min read

Pry is ready for action.

I love REPL s. It’s a great development tool. Any decent language has a REPL. Lisp has it. Python has it. So does Haskell. And Ruby , obviously, has it!

REPL stands for R ead E val P rint L oop. It’s a command line interface to interact with a programming language. Most interactive programming languages have a REPL. (I didn’t check.) This nomenclature derives from Lisp’s implementation which, in its most basic form, can be a one-liner:

(loop (print (eval (read))))

Lisp REPLs are very powerful. We can inspect the stack tree, (re-)execute a frame (usually a function call), change frame arguments and re-execute it, change a function definition and re-execute the frame calling it.

With such high expectations, it’s no wonder that IRB (Ruby’s default REPL) doesn’t look that powerful. (I think you’ll agree with me on this.) Pry is a pretty powerful alternative to IRB and packs a lot of new functionality. But still… it can’t be compared with Lisp’s. Nevertheless, there are a few features which (I think) will appeal to newcomers. I intend to go over them in this post.

Previous evaluation value

When learning Ruby, one of the things I was constantly needing to do was using the value of the previous evaluation. Let’s say I had calculated the tax value of a product and now wanted to get the final price:

pry(main)\> price, tax\_rate = 34, 0.08
=\> [34, 0.08]
pry(main)\> price \* tax\_rate
=\> 2.72
pry(main)\> final\_price = price + # damn! -\_-

It took me ages to find out we can access the previous value with _ (underscore). With two underscores __ we access the second from last value.

pry(main)\> price, tax\_rate = 34, 0.08
=\> [34, 0.08]
pry(main)\> price \* tax\_rate
=\> 2.72
pry(main)\> final\_price = price + \_
=\> 36.72
pry(main)\> \_\_
=\> 2.72

Where am I?

One debug methodology is to put breakpoints in our code. With Pry we do that with the binding.pry expression. This causes the execution to stop on that line. When that happens ruby’s console will show something like this:

pry(main)\> Grid.generate(6, 6)

From: /Users/bjacquet/Projects/gol/gol.rb @ line 27 Grid.generate:

25: def self.generate(width, height)
 26: self.new(Array.new(height).collect do
 =\> 27: binding.pry
 28: Array.new(width).collect { rand(2) }
 29: end
[1] pry(Grid)\>

It shows the line of code where the execution stopped, indicated with =>. (Being the 27th line.) Also some code context with surrounding lines. We can also infer that it stopped inside the method Grid.generate and it’s defined in file gol.rb.

This information is also available at any time by typing in the whereami command.

Were this method twice its size, we could still see its full content by using the show-source command as such:

pry(main)\> show-source Grid.generate

From: gol.rb @ line 25:
Owner: #\<Class:Grid\>
Visibility: public
Number of lines: 7

def self.generate(width, height)
 self.new(Array.new(height).collect do
 binding.pry
 Array.new(width).collect { rand(2) }
 end
 )
end
pry(Grid)\>

Replaying history

Pry’s hist command is really something. It enables you to view, search, and replay history, among other things. When invoked with no options it displays all of Pry’s history, that is, all the inputs we’ve given it.

pry(main)\> hist
1: price, tax\_rate = 34, 0.08
2: price \* tax\_rate
3: price, tax\_rate = 34, 0.08
4: price \* tax\_rate
5: final\_price = price + \_
6: \_\_
7: Grid.generate(6, 6)
8: show-command Grid.generate
pry(main)\>

With the --replay option we can re-evaluate expression(s):

pry(main)\> hist --replay 3..4
=\> [34, 0.08]
=\> 2.72

I find it faster to use this command than revolving previous inputs with the up arrow.

Let me fix that right now

Quite often we are typing in multiple-line expressions into Pry. More often than we would like we type in a line with an error. To fix it we use the amend-line command. It takes a line number and the replacement code as arguments.

pry(main)\> def hello
pry(main)\* puts “hello #{name}”
pry(main)\* amend-line 1 def hello(name)
1: def hello(name)
2: puts “hello #{name}”
pry(main)\* end
=\> :hello

In this example I realised that I forgot to specify name as a method argument. Thus I correct that by calling the amend-line command on line 1 with the new code. Pry then shows all input lines provided so far and waits for more. I type in end and the method is defined.

Going further

Off by one error, sorry about that! It’s worth it.

Pry also gives us the possibility of changing methods on the fly. To do so we need to use two commands. First we change the method using the edit command.

pry(main)\> edit Grid.generate

This will open an editor with the cursor on the first line of the method definition. When we’re done, we save the changes and exit the editor.

Next we need to evaluate the new definition. Command reload-method does just that.

pry(main)\> reload-method Grid.generate

From now on it will use the new version of Grid.generate.

Further reading

Pry has a lot more features to discover. Whilst preparing this post I discovered the amend-line command. It is so useful that I had to include it. Other commands you should know about include:

  • show-model , lists the model attributes and class associations.
  • show-stack , shows the frames call stack. (More often than not, this takes a lot of time to display anything.)

Pry's wiki is well documented and also has links to other resources.

Pry’s help command is also very useful. I learned most of these features through there. (RTFM syndrome)

That’s all for now. Have fun and be nice! :-)

I work at Runtime Revolution as a Rails developer. We also work with Python, JavaScript… both of which have REPL! We also help startups reach the next level.


Posted on by:

brunjact profile

B Jacquet

@brunjact

Former Lisp engineer turned Ruby engineer who is trying to understand Rails, JavaScript, Life, the Universe, and Everything. I work at Runtime Revolution, which is based in Lisbon, Portugal.

Discussion

pic
Editor guide