-
Notifications
You must be signed in to change notification settings - Fork 0
Pry ecosystem
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.
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 - however 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. Pry-nav should work on all Ruby implementations that implement set_trace_func
.
[source language="ruby"]
[2] (pry) main: 0> show-stack
=> #0 [method] gamma #1 [method] beta #2 [method] alpha [/source]
The reason pry-stack_explorer
and pry-nav
are not bundled together as a single gem is because pry-stack_explorer
only works on Ruby 1.9.2+ MRI, whereas pry-nav
works on Ruby 1.8 as well. Nonetheless we will probably build a meta-gem at some point for the 1.9 MRI users.
When both debugging gems are installed, they work seamlessly together and constitute a decent alternative to ruby-debug, especially on Ruby 1.9.3 where ruby-debug support is not that great.
Alternatively, if your preference is for ruby-debug you can still make use of Pry with the ruby-debug-pry gem. It provides the `pry` command to open a Pry session in the current debugging context. 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 a network or the Internet. They are particularly useful for getting Pry into places not normally possible, such as apps started with the Pow webserver. 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
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 one of the most exciting projects in the Pry ecosystem, 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, indeed a Ruby variant of the game core war could easily be built on the pry-remote-em
base.
One limitation of pry-remote-em
at the moment is the lack of pry-nav support, but this will be added soon.
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.
Avdi's nifty Hammertime gem is one attempt to bring this functionality to Ruby, Pry-exception_explorer is another. Pry-exception_explorer is particularly powerful as it's enhanced by an aggressive C extension and comes with all the Pry accoutrements.
A specialized version of Pry-exception_explorer for failing tests, 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 proved 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 for failing tests. When a test fails, a Pry session starts in the context of the failure. Plymouth also gives you an opportunity to edit the failing test code on disk with the `edit --current` command.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]
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.
If you would like to see the Pry project come to fruition please consider making a monetary donation, Pry has a very small core team and working on Pry takes up a substantial portion of their time! 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!