Exploring How To Configure Irb
In my last post we discussed irb’s commands. This post goes further into irb’s innards, exploring all of its configuration options.
Gettin Ready
For starters, I refer you to the pickaxe which has an excellent section on configuring irb. Also, this post assumes ruby 1.8.6 and irb 0.9.5, though it should apply to 1.9ers. Yes, I know I should get on the 1.9 train.
This post will cover every irb configuration option. If I miss one, please let me know. Not all of irb’s features are enabled/used through configuration i.e. completion and xmp. I’ll save those for another blog post.
Let’s first cover some irb configuration basics:
- By default, irb loads the first configuration file it finds among these files:
~/.irbrc, .irbrc, irb.rc, _irbrc, $irbrc and /etc/irbrc
. For the curious, read the source. That file is also where most of irb’s configuration is setup. - To override the default configuration file, set the IRBRC environment variable:
bash> IRBRC=‘/i/like/my/irbrc/elsewhere’ irb
- Irb saves its configuration in a hash accessible through
IRB.conf
. By convention, the config keys are symbols in all caps. Simply set an option by setting a key’s value:IRB.conf[:SAVE_HISTORY] = 1000
- Unlike irb commands in the last post, there isn’t much to getting most of the global configuration options:
bash> irb -f --prompt simple >> IRB.conf.keys >> [:CONTEXT_MODE, :PROMPT_MODE, :PROMPT, :INSPECT_MODE, :VERBOSE, :RC, :SINGLE_IRB, :USE_TRACER, :EVAL_HISTORY, :LOAD_MODULES, :LC_MESSAGES, :USE_LOADER, :SAVE_HISTORY, :MATH_MODE, :IGNORE_SIGINT, :IRB_RC, :AP_NAME, :MAIN_CONTEXT, :AUTO_INDENT, :BACK_TRACE_LIMIT, :DEBUG_LEVEL, :IGNORE_EOF, :IRB_NAME, :ECHO, :IRB_LIB_PATH]
- To get the full list of global irb configuration options, just grep it:
# Cd to your ruby source's directory bash> cd /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8 # You probably don't want to see this output bash> grep -r 'conf\[\|@CONF' irb.rb irb/
- Each irb subsession copies the global config options into its
IRB::Context
object. Since you have easy access to this object throughirb_context() or conf()
, here’s how you can figure out what configuration options you can change within irb:
bash> irb >> (irb_context.methods - Object.methods).grep(/=$/).sort => ["ap_name=", "auto_indent_mode=", "back_trace_limit=", "debug_level=", "echo=", "eval_history=", "history_file=", "ignore_eof=", "ignore_sigint=", "inspect_mode=", "io=", "irb=", "irb_name=", "irb_path=", "load_modules=", "math_mode=", "prompt_c=", "prompt_i=", "prompt_mode=", "prompt_n=", "prompt_s=", "rc=", "return_format=", "save_history=", "use_loader=", "use_readline=", "use_tracer=", "verbose=", "workspace="] # To change the ap_name >> conf.ap_name = "Doh!" => "Doh!"
Note that all these modify configuration options except for io=
and workspace=
which set a context’s IRB::InputMethod
and IRB::Workspace
objects.
The Overview
Since we’re going to cover all the configuration options, let’s group them into understandable chunks:
- History Options: These keep track of input and output history: :SAVE_HISTORY, :HISTORY_FILE, :EVAL_HISTORY
- Basic Options: These modify irb’s in basic ways with booleans: :SINGLE_IRB, :MATH_MODE, :RC, :USE_LOADER, :IGNORE_EOF, :IGNORE_SIGINT, :USE_READLINE
- Advanced Options: These modify irb in more advanced ways i.e. with non-booleans: :IRB_RC, :SCRIPT, :LOAD_MODULES, :CONTEXT_MODE, :RC_NAME_GENERATOR
- Visual Options: These modify visual irb behavior: :AUTO_INDENT, :INSPECT_MODE, :ECHO, :PROMPT, :PROMPT_MODE
- Debug Options: These change the behavior of debugging code in irb or in irb’s internals: :BACK_TRACE_LIMIT, :USE_TRACER, :VERBOSE, :DEBUG_LEVEL
- Questionable Options: These are questionable options, questionable that you’ll ever want to configure them: :AP_NAME, :IRB_LIB_PATH, :VERSION, :IRB_NAME, :LC_MESSAGES, :MAIN_CONTEXT
History Options
- :SAVE_HISTORY(number): Sets number of statements to keep in a history file.
- :HISTORY_FILE (filename): Specify a history file.
- :EVAL_HISTORY (number): Stores the outputs of the last number of statements in
__
.
A sample config:
IRB.conf[:SAVE_HISTORY] = 1000 IRB.conf[:HISTORY_FILE] = "/i/like/my/history/here" IRB.conf[:EVAL_HISTORY] = 200
Enabling an irb history with :SAVE_HISTORY
allows you to reevaluate statements in two ways. First, if your irb has a working readline library, you can look up and execute previous statements in reverse search mode. To enter this mode, type Control-R. Any keys you type will pull up the first statement that contains those letters. Familiarize yourself with what Control-A, Control-E, Control-R and Enter keys do in this mode. The second way is by using irb commands to manipulate and reevaluate several statements. Although irb doesn’t come with any such commands, utility_belt has some decent history commands. I also have my own version that I blogged about a long time ago.
:HISTORY_FILE
If :HISTORY_FILE
isn’t set, irb uses the same directory and file format of the detected irbrc for the irb history file. For example, ~/.irbrc leads to a ~/.irb_history whereas a ./irbrc leads to ./irb_history. For related discussion on this read :RC_NAME_GENERATOR.
:EVAL_HISTORY
The :EVAL_HISTORY
option saves output/eval history per irb subsession in an IRB::History
object stored in __
. The number it’s given represents the number of the latest outputs to save. An example of using this option:
bash> irb >> Math.cos 0 => 1.0 >> Math.cos Math::PI/2 => 6.12323399573677e-17 >> Math.cos Math::PI => -1.0 >> Math.cos Math::PI * 3/2 => -1.83697019872103e-16 # Print out the eval history >> __ => 1 1.0 2 6.12323399573677e-17 3 -1.0 4 -1.83697019872103e-16 >> __.class => IRB::History # Creating and switching to another irb subsession >> irb Class >> :yo => :yo # New eval history >> __ => 1 :yo
If you’re curious how/where irb sets the __
, see here. In the same way, _
, which saves the last output of any statement, is defined here.
Basic Options
These options either take true or false except for :USE_READLINE
.
- :SINGLE_IRB: Enables all irb subsessions to be evaluated under the same binding. Default is false.
- :MATH_MODE: Enables math mode. Default is false. Enabling
:MATH_MODE
orirb -m
, alters the default inspect mode and provides math commands by extending theMath
module. - :RC: Enables loading an irbrc file. Default is true. Disabling
:RC
orirb -f
, turns off any irbrc loading. - :USE_LOADER: Enabling
:USE_LOADER
overrides the defaultload()
andrequire()
with irb’s own commands,irb_load()
andirb_require()
. Default is false. Irb’s commands evaluate and display each line as if they had been input into irb. Read this to learn more about these irb commands. If you’re unsure what I mean by override, read the implementation. - :IGNORE_EOF: Ignores end of line input (Control-D in *nix) or exits current subsession. Default is false.
- :IGNORE_SIGINT: If true, aborts current operation or returns to top level. If false, exits irb. Default is true.
- :USE_READLINE: Enables using readline for input. This is a tri-state option: true, false or nil. Default is false or nil depending on readline’s existence. nil acts just like true except when irb is in inf-ruby-mode.
:SINGLE_IRB
If you enable :SINGLE_IRB
, all irb subsessions get evaluated under the same global binding, TOPLEVEL_BINDING
. This means that any local variables or methods you define are accessible across subsessions:
# This flag isn't mentioned in irb -h. Whoops. bash> irb --single-irb >> it = 5 => 5 >> def say(num); puts "You can't escape this" + " binding ..." * num; end => nil >> say it You can't escape this binding ... binding ... binding ... binding ... binding ... => nil # Start a new subsession >> irb Date # Method and local variable still exist >> say it You can't escape this binding ... binding ... binding ... binding ... binding ... => nil
In my previous post’s explanation of workspace commands, I mentioned that the one main difference they had from subsession commands was preservation of variables aka same binding. Well, since enabling this option removes that difference, it’s fair to ask: What do workspaces offer that subsessions can’t? The only answer I can come up with is that workspaces use the same context configuration.
Advanced Options
- :IRB_RC (proc): This proc is called every time a subsession is created.
- :SCRIPT (string): This is used implicitly when irb is passed arguments on the commandline. Sets irb in a file input mode in which it evaluates the file’s contents as input and prints out the interaction to stdout.
- :LOAD_MODULES(paths): At startup, loads the given paths using
require()
. Sincerequire()
uses$LOAD_PATH
to find files, gems as well as paths relative to the current directory are valid paths. - :CONTEXT_MODE (number): Sets the type of binding that irb uses when evaluating statements. Can be either 0, 1, 2 or 3 (3 is the default).
- :RC_NAME_GENERATOR (proc): Generates an irb config file. Used by irb_history and irbrc. When not set defaults to this.
:IRB_RC
Let’s see if the :IRB_RC
proc is called every time an irb subsession is created:
bash> irb # :IRB_RC is called at startup but it's not called this time since we haven't defined it yet. # The argument passed to lambda is the current context. >> IRB.conf[:IRB_RC] = lambda {|context| puts "Entered #{context.main}" } => #<Proc:0x00057648@(irb):1> # Create subsessions >> irb 'testin' Entered testin >> irb Array Entered Array
It sure does. What if we only want to have the proc run once i.e. prevent future subsessions from calling it?:
>> IRB.conf[:IRB_RC] = lambda {|e| puts "Entered #{e.main}"; IRB.conf.delete(:IRB_RC) } => #<Proc:0x00091ac8@(irb#2):1> >> irb 'byebye' Entered byebye >> IRB.conf[:IRB_RC] => nil # Proc isn't called anymore since it doesn't exist >> irb 'testin' >>
Utility belt extends the functionality of this option by setting it to a hash of procs like this:
Object.const_set("IRB_PROCS",{}) unless Object.const_defined?(:IRB_PROCS)
IRB.conf[:IRB_RC] = lambda do
IRB_PROCS.each {|key, proc| proc.call }
end
With this version of :IRB_RC
, multiple libraries/files can have their procs run if they define their entries in IRB_PROCS
:
# in a rails-specific file IRB_PROCS[:rails] = lambda { "set my final rails irb tweaks here"} # ... in some other file IRB_PROCS[:other] = lambda { "other tweaks"}
Personally, I like to have my procs run once and to pass the current IRB::Context
object:
Object.const_set("IRB_PROCS",{}) unless Object.const_defined?(:IRB_PROCS)
IRB.conf[:IRB_RC] = lambda do |context|
IRB_PROCS.each {|key, proc| proc.call(context); IRB_PROCS.delete(key)}
end
:SCRIPT
This option is used quietly whenever you pass irb an argument. The argument, usually a file, is processed by Kernel#open
and its result is fed to irb as input. For example:
# Create a file message.rb: message = "irb from " message + __FILE__ # Run from the commandline bash> irb -f --prompt simple message.rb >> message = "irb from " => "irb from " >> message + __FILE__ => "irb from blah.rb" >> bash>
Since Kernel#open
can open a subprocess and read its output:
# Generates a mandelbrot set, from http://www.xcombinator.com/2008/02/22/ruby-inject-and-the-mandelbrot-set bash> irb -f "|curl -s http://gist.github.com/raw/120183/22aa68d0451ab2ac69a252f5d6a2acff2a04ea3b/gistfile1.rb" # Prints out irb processing the code and then generates: ** ****** ******** ****** ******** ** * *** ***************** ************************ *** **************************** ****************************** ****************************** ************************************ * ********************************** ** ***** * ********************************** *********** ************************************ ************** ************************************ *************************************************** ***************************************************** *********************************************************************** ***************************************************** *************************************************** ************** ************************************ *********** ************************************ ** ***** * ********************************** * ********************************** ************************************ ****************************** ****************************** **************************** ************************ *** *** ***************** ******** ** * ****** ******** ****** **
Instead of opening a subprocess, you could just pipe a command into irb:
bash> curl -s http://gist.github.com/raw/120183/22aa68d0451ab2ac69a252f5d6a2acff2a04ea3b/gistfile1.rb | irb -f # same output as above ...
:CONTEXT_MODE
This option is perhaps the only option whose use case I don’t understand. Depending on the option’s value, irb statements are evaluated with a different type of binding:
- 0: Creates binding with eval(“proc{binding}.call”, TOPLEVEL_BINDING …).
- 1: Creates binding in a temporary file.
- 2: Create binding in a temporary file using threads.
- 3: Creates binding with eval(“def irb_binding; binding; end; irb_binding”, TOPLEVEL_BINDING …)
My guesses for using values 1 and 2 are for security. As for values 0 and 3, the difference is that the former has access to TOPLEVEL_BINDING
while the latter doesn’t:
>> eval("a = 2", TOPLEVEL_BINDING) => 2 >> eval "a", eval("proc{binding}.call", TOPLEVEL_BINDING) => 2 >> eval "a", eval("def irb_binding; binding; end; irb_binding", TOPLEVEL_BINDING) NameError: undefined local variable or method `a' for main:Object from (irb):4:in `eval' from (eval):1 from (eval):1
:RC_NAME_GENERATOR
This option is used to generate irb config files i.e. irbrc and irb_history files in a standard way. Since irbrc is already loaded when your config is read, most irb users would only have this effect their irb_history. An example use case:
# In your irbrc:
# This looks for the first config file that exists in /etc/irb/ and then ~/.irb/
IRB.conf[:RC_NAME_GENERATOR] = lambda {|name|
["/etc/irb/#{name}.rb", "#{ENV['HOME']}/.irb/#{name}.rb"].detect {|f|
File.exists?(f)
}
}
# In an irb lib for rails:
load(config) if (config = IRB.rc_file("rails"))
# Loads /etc/irb/rails.rb or ~/.irb/rails.rb
Visual Options
- :AUTO_INDENT(boolean): Auto indents code when defining blocks, methods, classes, etc. Default is false.
- :INSPECT_MODE (booleanish): When true or nil, formats output by calling
inspect()
on the statement result. When false just prints output. Default is nil. Note that setting this option from the commandline i.e. @context.inspect_mode= is buggy: it needs to be called twice to set it to false when initially nil. - :ECHO (booleanish): When true or nil, a statement’s output is printed. When false, no output is shown. Default is nil.
- :PROMPT (hash): Hash of available prompts, mapping symbols to prompt hashes.
- :PROMPT_MODE(symbol): Current prompt, pointing to a key in
:PROMPT
.
:ECHO
A common irb complaint is that its output is too verbose. Disabling this option makes irb print no output. Here’s a handy snippet that uses this option to toggle irb output:
def irb_verbosity_toggle
irb_context.echo ? irb_context.echo = false : irb_context.echo = true
end
Note: Utility belt has another way to toggle irb’s verbosity, although not as terse.
:PROMPT
To create your own prompts, add an entry in :PROMPT
. Your prompt should be a hash with the following keys:
- :PROMPT_I: Normal prompt
- :PROMPT_S: Prompt when continuing a string
- :PROMPT_C: Prompt when continuing a statement
- :PROMPT_N: Prompt when indenting code
- :RETURN: String that prefixes output of a statement. Since this is passed to
Kernel#printf()
, the output could be displayed with any of its string flags, though most choose %s.
Updated: The different prompt types that start with :PROMPT* substitute string flags for certain values:
- %N – Value from
Irb.conf[:IRB_NAME]
- %m –
self.to_s
- %M –
self.inspect
- %l – Character needed to finish continuing a string. Should be used with
:PROMPT_S
. - %zi – Indent level with optional number z for printf width.
- %zn – Line number with optional number z for printf width.
- %% – Literal percentage sign.
For more details on prompts I suggest the Configuring the Prompt section in the pickaxe or just check out the irb implementation code.
Here’s an example of creating a custom prompt:
bash> irb --prompt simple # Create a basic prompt :DEMO >> IRB.conf[:PROMPT][:DEMO] = {:PROMPT_I => "normal> ", :PROMPT_S => "string_continue> ", >> :PROMPT_C => "statement_continue> ", :PROMPT_N => "indent> ", :RETURN => "<< %s >>\n" } => {:PROMPT_I=>"normal> ", :PROMPT_S=>"string_continue> ", :PROMPT_C=>"statement_continue> ", :PROMPT_N=>"indent> ", :RETURN=>"<< %s >>\n" } # Enable the created prompt >> conf.prompt_mode = :DEMO << :DEMO >> # PROMPT_I and PROMPT_C normal> 5 * statement_continue> 5 << 25 >> # PROMPT_S normal> 'yoda string_continue> ' << "yoda\n" >> # PROMPT_N normal> class Yoda indent> end << nil >>
Debug Options
- :BACK_TRACE_LIMIT (number): Number of messages to display from beginning and end of a caught error’s backtrace. Default is 16.
- :USE_TRACER (boolean): Enables using the standard library
Tracer
to trace execution in irb. - :VERBOSE (boolean): Sets the verbosity of a few context-related events. Seeing that verbose? is used by context objects, which doesn’t respect this option, my guess is this option is broken.
- :DEBUG_LEVEL(number): Enables debugging for irb developers i.e. debugging the ruby lexical analyzer.
:BACK_TRACE_LIMIT
To better understand :BACK_TRACE_LIMIT
, let’s play ping pong:
# Define the players >> def ping(num,max); raise "Ping wins" if num > max; pong(num+1,max); end => nil >> def pong(num,max); raise "Pong wins" if num > max; ping(num+1,max); end => nil >> conf.back_trace_limit => 16 # The stacktrace is much less than the limit so we should see the full stacktrace. >> ping 1,10 RuntimeError: Ping wins from (irb):1:in `ping' from (irb):2:in `pong' from (irb):1:in `ping' from (irb):2:in `pong' from (irb):1:in `ping' from (irb):2:in `pong' from (irb):1:in `ping' from (irb):2:in `pong' from (irb):1:in `ping' from (irb):2:in `pong' from (irb):1:in `ping' from (irb):4 >> conf.back_trace_limit = 3 => 3 # Now that the limit is 3, we only see the first and last 3 messages of the trace. >> ping 1,10 RuntimeError: Ping wins from (irb):1:in `ping' from (irb):2:in `pong' from (irb):1:in `ping' ... 6 levels... from (irb):2:in `pong' from (irb):1:in `ping' from (irb):6>>
:USE_TRACER
(#use_tracer):USE_TRACER
uses the Tracer
standard library to trace statements. Since Tracer
isn’t that well documented, I should at least explain that it’s basically a wrapper around Kernel#set_trace_func
. Here’s what it looks like:
bash> irb -f --tracer --prompt simple /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/tracer.rb:150: warning: tried to create Proc object without a block /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/tracer.rb:146: warning: tried to create Proc object without a block >> :dude.to_s #0:(irb):1:Object:-: - #0:(irb):1:Symbol:>: - #0:(irb):1:Symbol:<: - => "dude" # To turn it off >> conf.use_tracer = false #0:(irb):5:Object:-: - => false
Probably the most confusing aspect of Tracer is not knowing what the different fields delimited by ‘:’ represent. Looking into the source reveals the fields in order are: thread number, file, line, klass, event type (defined by Tracer::EVENT_SYMBOL
) and the actual line of code ( – if line not found).
Questionable Options
The main reason to describe these options isn’t to use them but to know there is little need to use them.
- :AP_NAME: Give your irb app a name.
- :IRB_LIB_PATH: The directory of the currently used irb.rb. Used when tracing with :USE_TRACER
- :VERSION: Version of irb specified by the version file.
- :IRB_NAME: A name for the current irb subsession, which is available as %N in an irb prompt string. Used internally to set a context’s
irb_path()
. - :__*: There are at least two options that start with underscores that don’t have an apparent reason for being in
IRB.conf
. Just ignore ’em. - :LC_MESSAGES: Stores the current
IRB::Locale
object. If you want to change languages, you can modify this object directly or you can set environment variables such asENV['IRB_LANG']
. - :MAIN_CONTEXT: This stores the
IRB::Context
object belonging to the first subsession. Used internally as a global setting in a couple of useful places. Remembering that irb_context saves the currentIRB::Context
object, let’s relate it to this option:
bash> irb >> irb_context == IRB.conf[:MAIN_CONTEXT] => true >> irb ‘another subsession’ >> irb_context == IRB.conf[:MAIN_CONTEXT] => false
Wrap Up
If you survived this in one sitting, wow! For further irb exploration, here’s my irbrc. Some future irb topics I’m thinking of writing up include customizing irb completion, a guide to hacking irb, strategies for creating/managing many irb commands and using irb’s xmp. If you have suggestions on irb topics you’d like to learn about, please comment them.