Pry is a wonderful interactive environment for Ruby. It is (more or less) a replacement to IRB. We already know that interactive environments are highly useful and the Rails Console is a great example of utilizing that interactive environment effectively.

However, if you’re like me, then you don’t work in Rails. The majority of my work is in custom Ruby programs, EM-driven programs and Sinatra APIs. You don’t get anything like Rails Console for free when you’re building a custom Ruby program. So, when you start up an interactive environment, you may find yourself starting each session like so:

 1 require 'bundler/setup'
 2 bundler.require(:development, :test, :console)
 3  
 4 $: << File.expand_path('../src', __FILE__)
 5 require 'app'
 6 require 'models/user_account'
 7 require 'models/cat'
 8  
 9 # Load config and connect to DB
10 App.init()
11  
12 def random_helper_method
13   # ... helpful code ...
14 end
15  
16 # maybe some other random junk depending 
17 # on what your testing at the moment
18  
19  
20 # FINALLY time to test!

You may keep your console running just because you don’t want to have to type all of that junk again. But eventually you will restart your computer, close your terminal, etc. and you will loose all of the work you put into setting up your console environment.

My question to you (and to myself), is why go through all this trouble when creating your own console is so easy! Just create a console file in the root of your project and insert all of that code that you would normally put into an interactive session. You can even get fancy with a little color output and various, generic helper methods that are useful for debugging. A console example from one of my [current projects] looks like the following:

 1 #!/usr/bin/env ruby
 2  
 3 # require all the necessary files
 4 $: << ::File.expand_path('../src', __FILE__)
 5 require 'app'
 6 require 'geofence'
 7  
 8 # at this point bundler should be setup and the :development group
 9 # should have been included. However, just to be sure, I'm going to
10 # include bundler again and require the console group.
11 require 'bundler/setup'
12 Bundler.require(:console)
13  
14 # specify some sample fences to play with
15 # 
16 # format:
17 #   [
18 #     [:lon, :lat],
19 #     ...
20 #   ]
21 fence_1 = [
22   [0, 0],
23   [3, 0],
24   [4, 2],
25   [6, 3],
26   [6, 6],
27   [5, 7],
28   [3, 5],
29   [2, 4],
30   [0, 1]
31 ]
32  
33 fence_2 = [
34   [5, 5],
35   [7, 5],
36   [3, 2],
37   [10, 2],
38   [12, 7],
39   [12, 10],
40   [15, 10],
41   [15, 15],
42   [12, 15],
43   [10, 18],
44   [8, 15],
45   [7, 15],
46   [6, 13],
47   [5, 10]
48 ]
49  
50 # patch pretty-print to use a smaller width for looking at our fences
51 class PP
52   class << self
53     alias_method :old_pp, :pp
54     def pp(obj, out = $>, width = 40)
55       old_pp(obj, out, width)
56     end
57   end
58 end
59  
60  
61 # include helpers to play around with Sinatra application
62 include Rack::Test::Methods
63 self.instance_eval do
64   @app = App.new
65   def app; @app; end
66 end
67  
68  
69 # add ability to reload console
70 def reload
71   reload_msg = '# Reloading the console...'
72   puts CodeRay.scan(reload_msg, :ruby).term
73   Pry.save_history
74   exec('./console')
75 end
76  
77 g = Class.new {
78   def method_missing(m, *args, &block)
79     Geofence.send(m, *args, &block)
80   end
81 }.new
82  
83  
84 # start the console! :-)
85 system('clear')
86 welcome = <<eos
87 # This is my interactive playground. You can call the Sinatra methods in
88 # the same way you would in RSpec (get, post). There are also a couple of
89 # test fences defined for you (fence_1, fence_2). I also monkey-patched
90 # 'pp' to print short arrays nicer.
91 #
92 # Everything you would want to play with (for this project) should be in here
93 # 
94 eos
95 puts CodeRay.scan(welcome, :ruby).term
96 Pry.start

In my console I:

  • Load my project files
  • Define test-data to work with
  • redefine PP.pp to use a shorter-width for printing out test-coordinates
  • load Rack helper methods so that I can make calls to my Sinatra app from within the console
  • add the ability to reload my console
  • define a helper object to call private methods on the Geofence class
  • print a nice welcome message (colorized with CodeRay which is packaged with Pry)

That’s quite a bit of work if I were to do that each time I started a new interactive Pry session. And to be honest, I just wouldn’t. I would do the bare minimum required to test something. With the console, I can have some other niceties because I only have to write them once. So nice!

This has now become a mandatory step when getting started on any new Ruby project. I add some basics that I put into all of my console files and then I evolve the console as the project moves forward. I can’t imagine working any other way (well… I can, I just don’t prefer it).