ripl: Why should you use an irb alternative?
What does it mean when the guy who blogged about irb’s details and wrote most of the successful irb gems (hirb, bond, boson) decides to implement his own irb alternative? There must be something wrong with irb!
OK, to be polite, nothing is wrong with irb. Except that it is old and big. irb consists of more than 5000 lines – is this really necessary? You can build a simple irb in less then 40 byte ;)
The purpose of most of irb’s code is to analyse the input for multi-line and auto-indent support. ripl (which stands for “ruby interpreter print loop”) does not care about these things and aims to be small and modern.
So, what does it do better than the “5000 lines” and “39 bytes” approaches? The github description tells it:
ripl is a light, modular alternative to irb. Like irb, it loads ~/.irbrc, has autocompletion and keeps history in ~/.irb_history. Unlike irb, it is highly customizable via plugins and supports commands i.e. ripl-play. This customizability makes it easy to build custom shells (i.e. for a gem or application) and complex shells (i.e. for the web).
The main advantage: It is easily extendable!
Furthermore, it is better documented than irb and comes with tests ;)
Usage
ripl can be installed with:
$ gem install ripl
As already mentioned, ripl even comes without multi-line support, but it is available as plugin:
$ gem install ripl-multi_line
To enable a plugin, you have to add it to your ~/.riplrc
file (create one if it does not exit) like this:
require 'ripl/multi_line'
ripl loads your ~/.irbrc
file, which typically contains some irb specific options (e.g. IRB.conf[:PROMPT]
). To avoid errors, you can install ripl-irb
, which catches calls to the IRB
constant and prints messages to convert irb configuration to ripl equivalents.
Now you can start ripl
and play around!
Hm… pretty boring. Just like irb… It needs more plugins!
Available plugins
You can install ripltools, a meta gem which downloads some useful general ripl plugins:
$ gem install ripltools
There are some plugins, which improve your ripl experience without requiring you to learn something (I would call them “passive” plugins): There is ripl-color_error, ripl-color_result, ripl-color_streams and ripl-auto_indent which are pretty self-descriptive. Another one is ripl-short_errors which modifies error messages to only show the first backtrace entry of an error. The complete backtrace can be shown manually by the _!
method.
Furthermore, some “extra commands” plugins are included in ripltools.
ripl-commands adds some basic commands, similar to irb’s commands. Because there are no sub-sessions in ripl, it provides another way of getting “into” an object – jumps:
>> jump [1,2,3,4]
=> [1, 2, 3, 4]
>> size
=> 4
>> jumps
=> [main, [1, 2, 3, 4]]
ripl-play allows you to record (and playback) input sequences in ripl. It also allows playback of code snippets from the internet.
$ ripl play https://gist.github.com/725338
>> a = 10 ** 2
=> 100
>> a + 10
=> 110
>>
It is also possible to create your specialized sub-shell (e.g. for your gem). Currently, there is a rails console, a rack console, a hijack shell using ripl, a web shell, my ruby/system hybrid shell and even a javascript (firefox tracemonkey) shell!
More plugins
The ripl github page has a large list of available plugins. You can also search through rubygems with:
$ gem list -r ripl-.*
It is also worth mentioning that a lot of irb gems do actually not use irb specific methods and are fully compatible with ripl.
Write your own plugins
It is super
simple to write your own ripl plugins. Here is a short example plugin:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# by cldwalker require 'ripl' module Ripl::CustomErrors def print_eval_error(err) if handler = config[:custom_errors][err.class] handler.call(err) else super end end end Ripl::Shell.send :include, Ripl::CustomErrors Ripl.config[:custom_errors] = {}
All it does: When an error is encountered, check if it is a one of an error class that should be treated differently.
A plugin basically consists of one big and two small parts:
- Firstly, a module with all the logic – this is the main part (see below)
- Secondly, the
include
statement to hook the code in, in this example:Ripl::Shell.send :include, Ripl::CustomErrors
- And thirdly, some plugin default configuration for the
Ripl.config
hash. The settings a plugin uses should be prefixed with the plugin name.
The Ripl::Shell
module is the most important one, because it contains the ruby interpreter print loop:
before_loop
loop
loop_once
get_input
prompt
eval_input
loop_eval
(print_eval_error)
format_error
print_result
format_result
(handle_interrupt)
after_loop
You can extend each of these methods, except loop
. You can (and mostly should) use the super
keyword to call the original ripl functionality (or the next plugin). This is possible, because the base methods are not directly declared in the Ripl::Shell
class, but in an API
module which gets included before any plugin. You should also read the main source file before starting to hack.
Besides Ripl::Shell
, there is Ripl::Commands
and Ripl::Runner
, which work in a similar manner. You can include your custom module into Ripl::Commands
and its methods become available in a ripl session (although, they are only available after a call to add_commands(eval("self", @binding))
). You can extend Ripl::Runner
to customize the starting process, e.g. by adding command line options.
To see some small example plugins, take a look at ripl-misc!
cldwalker | December 18, 2010
You may want to mention that unlike irb, ripl is well documented and tested. Also ripl has better autocompletion and 0.3.0 should have autocompletion hooks for plugins. As for ripl-irb, it's worth knowing it prints messages to convert irb configuration to ripl equivalents.
Thanks for the writeup. :)
J-_-L | December 18, 2010
Yep, added these points.
trans | December 19, 2010
Instead of using `Ripl::Shell..send :include, ...` why don't you just make `include` a public method for Shell? Either that or define a new method like `use` to do the same.
J-_-L | December 19, 2010
Hi trans. I don't know exactly, why he did not do that, but I guess the reason is to highlight that no more magic happens. Just the including Ruby programmers are used to.