Better pry for Ruby REPL
· 4 min read
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
-
pryguides : there is a ton of useful information for post-graduated pryests, -
prythemes : 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!