Skip to content
rwfitzge edited this page Feb 14, 2012 · 13 revisions

Roughly a year ago I wrote my first article introducing Pry to the Ruby world. Back then Pry was a very a different creature: just a simple runtime variant of IRB with a few added extras. In the year that's passed Pry has blossomed, radiating out in a number of  interesting directions. In fact Pry is no longer a single project, but has become an ecosystem of plugins and spinoff projects. This blog post will attempt to describe the current state of the Pry ecosystem, provide a brief synopsis of some of the plugins available, and attempt to chart the course of future development.

Debugging

Aside from its use as an IRB alternative, Pry's other primary use-case is as a debugger. The Pry gem by itself hasn't any facilities for a ruby-debug style `next` or `step` so any debugging was limited to examining program snapshots around the `binding.pry` call.

However two recent plugins, pry-nav and pry-stack_explorer change this situation, transforming Pry into a fairly full-featured debugger.

This plugin adds the `next`,`step` and `continue` commands to Pry. After requiring this gem you use Pry as normal, placing the `binding.pry` at the point you want to start your session - entering `next` will advance execution along one line:

[source language="ruby"] [1] (pry) main: 0> next

From: ./y.rb @ line 5 in Object#hello:

1: require 'pry-nav'
2:
3: def hello
4:   binding.pry

=> 5: x = 20 6: end 7: 8: hello [/source]

pry-nav also has support for pry-remote, enabling you to perform remote debugging.

This plugin implements the other side of the debugging coin, namely call-stack navigation. It provides the show-stackframeup, and down commands. From the point a Pry session is started, you can move up the call-stack through parent stack-frames, examine state, and even evaluate code!

[source language="ruby"]

[2] (pry) main: 0> show-stack

Showing all accessible frames in stack (5 in total):

=> #0 [method] gamma #1 [method] beta #2 [method] alpha [/source]

While these two gems create a very powerful debugger, if you do find yourself needing to use ruby-debug, it's also possible to embed pry into it with the ruby-debug-pry gem.

Remote sessions

Remote sessions have been another important development in the Pry ecosystem. A remote session allows you to start instances of Pry in a running program and connect to those instances over the Internet. They are particularly useful for getting Pry into places not normally possible, such as apps started with the Pow webserver, or even Rails applications. They also open the door for such exotica as multi-user sessions.

Pry has two plugins that implement remote sessions: pry-remote and the newer and more ambitious pry-remote-em.

pry-remote uses the DRb library and should work on Ruby versions and implementations. To use, simply replace the normal `binding.pry` call with `binding.remote_pry` as the example below illustrates. A DRb server will await connections and a remote session in the context of the binding will start once a client connects.

We set up the server as follows:

[source language="ruby"] require 'pry-remote'

class Foo def initialize(x, y) binding.remote_pry end end

Foo.new 10, 20 [/source]

We can then connect to it using the pry-remote executable.

Pry-remote-em is a sophisticated EventMachine-based alternative to pry-remote. It adds user authentication and SSL support along with tab-completion and paging. It also allows multiple clients to connect to the same server, and multiple servers to run on the same computer and even within the same process.

I am very excited about pry-remote-em as it opens up possibilities for multi-user remote-debugging/exploration, as well as educational applications. It is also just fun to interact with other programmers in a live environment, for example a Ruby variant of the game core war could easily be built on the pry-remote-em base.

Starting the pry-remote-em server:

[source language="ruby"] require 'pry-remote-em/server'

class Foo def initialize(x, y) binding.remote_pry_em end end

EM.run { Foo.new 10, 20 } [/source]

And similar to pry-remote, we  connect using the pry-remote-em executable.

Error consoles

As discussed in Avdi's blog post the Lisp and Smalltalk communities have great tools for debugging exceptions. Instead of their programs dying from an unrescued exception, they are presented with an interactive console and given an opportunity to correct the problem.

Avdi's nifty Hammertime gem is one attempt to bring this functionality to Ruby, Pry-exception_explorer is another. A specialized version of Pry-exception_explorer for intercepting test failures, called Plymouth, is also available.

When an exception is raised it is intercepted and  a Pry session started. The binding for the session is the context where the exception was raised, so the user gets access to all state at the error site. Further,  the user can walk the exception's entire call-stack to isolate the precise cause of the error.

Another feature of pry-exception_explorer is the ability to define exactly when it's triggered. This can be as simple as specifying an exception type, or as sophisticated as an assertion over the entire state of the call-stack. Rudimentary support for some C-level exceptions is also provided and activated with a command line switch.

In the example below, we configure a call-stack assertion so that Pry starts when an ArgumentError is raised, but only if the exception context is an instance of MyClass and the parent's context is an instance of MyCallingClass:

[source language="ruby"] EE.intercept do |frame, ex| ex.is_a?(ArgumentError) && frame.klass == MyClass && frame.prev.klass == MyCallingClass end [/source]

Pry-exception_explorer has proven itself to be a very powerful and useful gem, often obviating the need for a bona fide debugger. For a quick demo of it in action check out the following mini screencast.

Plymouth is a specialized error console designed to help you debug failing tests. When a test fails, a Pry session starts immediately at the site of the failure. You can start executing ruby to find out what's wrong, or use `edit --current` to edit the current test in your editor.

Plymouth is also illustrative of the power of pry-exception_explorer, its functionality is implemented using the pry-exception_explorer API, indeed the following code is all that's required to intercept failing tests on RSpec:

[source language="ruby"] EE.intercept do |frame, ex| if ex.class.name =~ /RSpec::Expectations::ExpectationNotMetError/ message = ex.message true else false end end.skip_until do |frame| frame.klass.name =~ /RSpec::Core::ExampleGroup::Nested/ end [/source]

Plymouth currently supports the RSpec, Bacon and MiniTest libraries, support for other libraries is coming soon.

What's next for Pry?

The projects described above represent a generous slice of the Pry universe, but there's still a lot more out there. Plugins for live syntax highlighting, Rails integration and bash alias integration to name just a few; the Pry ecosystem is expanding at an impressive rate. Pry-exception_explorer and Plymouth demonstrate it's possible to incorporate a level of Smalltalk-style interactivity into the ordinary Ruby development workflow, and we intend to take this even further.

The ultimate goal of the Pry project is to make REPL-driven development a reality for the Ruby language and to get as close as possible to the Smalltalk model as we can without the Smalltalk 'image'. Indeed, a GUI front-end for Pry is also in the planning stage.

Pry has been a huge amount of work over the last year or so, but good progress has been made. Multi-user Pry sessions, full debugging functionality, and remote sessions are now a reality.

We need your help

If you would like to see the Pry project come to fruition please us work through the issues, if you're too busy please consider making a monetary donation. The core team is small and there's only so much we can do, with a bit of funding the project can develop at a faster rate and with a higher degree of polish. Alternatively, if your company would like to be more officially associated with the project through sponsorship, this is very welcome too: please contact the project maintainer to arrange this.

Thanks!

Clone this wiki locally