Pry Logo

REPL

REPL in CS stands for Real Eval Print Loop.

Ruby, like many other languages, comes with it’s own REPL implementation called irb. While it likely does it’s primitive job, there is a way better alternative for it: pry.

The excerpt from pry’s official site claims

Pry is a powerful alternative to the standard IRB shell for Ruby. It features syntax highlighting, a flexible plugin architecture, runtime invocation and source and documentation browsing.

And all the above is indeed true. I am going to show how to install and configure pry for user’s better experience. I would assume you already have Ruby up and running on the target machine.

Preparation step

Go the to console and execute:

$ gem install pry pry-theme awesome_print coderay

Now you should be all set. Try to run pry and see no difference against irb. Frustrating enough.

Let’s teach pry to be smarter.

Configuration matters

There is a config file .pryrc located in your home directory, that tells pry how it should look and behave like. If there is none, execute cd && touch .pryrc to create it.

Tweaking .pryrc

I am going to reveal pry features step by step. For those impatient:

TL;DR: gist with my .pryrc

  • pry guides: there is a ton of useful information for post-graduated pryests,
  • pry themes: use, create, howtos, wtfs.

Editor

Pry.editor = 'vi' # 'code', 'subl'

Prompt

Pry.config.prompt =
  [
    ->(_obj, _nest_level, _) { "✎ " },
    ->(*) { "  " }
  ]

One might dump the current object name, or maintain different propmts based on the level of nesting or whatever. Since .pryrc is a plain ruby file, this procs might execute any code you want or even mine bitcoins while you are waiting for the next prompt to appear.

I do use minimalistic setting to make copy-paste easy (not requiring any cleanup before pasting.)

Colors

This is driven by pry-theme gem. I switch coloring on (unless started as PRY_BW=true pry) and set the predefined theme that does not hurt eyes much. For folders under Rails supervision (read: for Rails projects) that might show something even fancier. I hate Rails, that’s why I’d never seen it and I cannot tell what exactly happens there.

unless ENV['PRY_BW']
  Pry.color = true
  Pry.config.theme = "railscasts"
  Pry.config.prompt = PryRails::RAILS_PROMPT if defined?(PryRails::RAILS_PROMPT)
  Pry.config.prompt ||= Pry.prompt
end

History

This is a godsend. While in debugger mode, or whether the command (not an evaluation) was executed right before, press and it’ll be repeated. Extremely helpful for stepping into code in debugger (unless you spot all the bugs with your glance and never ever enter debugging sessions, like me.)

Pry.config.history.should_save = true
Pry::Commands.command /^$/, "repeat last command" do
  _pry_.run_command Pry.history.to_a.last
end

Commands

Debugger. Don’t trust much this config, I just borrowed it from my teammate who is spending his whole life debugging stuff.

Pry.commands.alias_command 'c', 'continue' rescue nil
Pry.commands.alias_command 's', 'step' rescue nil
Pry.commands.alias_command 'n', 'next' rescue nil
Pry.commands.alias_command 'f', 'finish' rescue nil
Pry.commands.alias_command 'l', 'whereami' rescue nil

Listing config

Pry.config.ls.separator = "\n" # new lines between methods
Pry.config.ls.heading_color = :magenta
Pry.config.ls.public_method_color = :green
Pry.config.ls.protected_method_color = :yellow
Pry.config.ls.private_method_color = :bright_black

This should be self-explanatory.

Plugins

The below is just a sample of configuring some (read: awesome) plugin. I am positive you dislike bloated configs and tend to maintain them line by line pixel by pixel for decades. The snippet below is provided just for the sake of an example. Also comments in the code speak for themselves.

# `awesome_print` gem is a great syntax colorized printing
# look at `~/.aprc` for more settings for awesome_print
begin
  require 'awesome_print'
  # The following line enables awesome_print for all pry output,
  # and it also enables paging
  Pry.config.print = proc {|output, value| Pry::Helpers::BaseHelpers.stagger_output("=> #{value.ai}", output)}

  # If you want awesome_print without automatic pagination, use the line below
  module AwesomePrint
    Formatter.prepend(Module.new do
      def awesome_self(object, type)
        return super(object, type) unless type == :string
        return super(object, type) unless @options[:string_limit]
        return super(object, type) unless object.inspect.to_s.length > @options[:string_limit]

        colorize(object.inspect.to_s[0..@options[:string_limit]] + "...", type)
      end
    end)
  end

  AwesomePrint.defaults = {
    :string_limit => 80,
    :indent => 2,
    :multiline => true
  }
  AwesomePrint.pry!
rescue LoadError => err
  puts "gem install awesome_print  # <-- highly recommended"
end

Custom commands

Did I say that pry is very powerful? You can even define your own set of commands to be used within pry. The example below shows how to create sql command to execute raw SQL from the console (provided you have a working AR connection there) with a minimum of keystrokes.

default_command_set = Pry::CommandSet.new do
  command "sql", "Send sql over AR." do |query|
    if ENV['RAILS_ENV'] || defined?(Rails)
      pp ActiveRecord::Base.connection.select_all(query)
    else
      pp "No rails env defined"
    end
  end
end

Pry.config.commands.import default_command_set

Monkeypatches and globals

Yeah, you might tweak any Ruby code with your own monkeypatches, that are available in pry sessions only. The following is very handy for playing with arrays and hashes.

class Array
  def self.sample(count = 10, &block)
    Array.new(count, &(block || :succ))
  end
end

Hash.singleton_class.prepend(Module.new
  def sample(count = 10)
    (?a...count.times.reduce(?a) { |o| o.succ }).
      map(&:to_sym).zip(0...count).to_h
  end
end)

Sidenote: if you think the snippet above is overcomplicated with Integer#succ, you surely never dealt with long hashes having more than 26 keys :)

Color customization

Everything below is for customizing colors, using coderay gem. The result would be worth it. Symbols are red and numbers are blue, all that stuff.

CodeRay.scan("example", :ruby).term # just to load necessary files
$LOAD_PATH << File.dirname(File.realpath(__FILE__))
require "escaped_colors"

module CodeRay
  module Encoders
    class Terminal < Encoder
      TERM_TOKEN_COLORS.each_pair do |key, value|
        TOKEN_COLORS[key] = value
      end
    end
  end
end

That’s pretty much it

I hope I gave you the first impression on what pry is and how is it better than irb. I did not cover debugging experiences, mostly because I do not debug, I write the correct code from the scratch. But I hope I could interest you and—please—don’t hesitate to sink into and reconfigure everything to your own taste.

Happy prying!