Programming Ruby 1.9 & 2.0: The Pragmatic Programmers’ Guide (2013)
Part 2. Ruby in Its Setting
Chapter 18. Interactive Ruby Shell
Back in Section 14.2, Interactive Ruby we introduced irb, a Ruby module that lets you enter Ruby programs interactively and see the results immediately. This chapter goes into more detail on using and customizing irb.
18.1 Command Line
irb is run from the command line:
irb <irb-options> <ruby_script> <program arguments>
The command-line options for irb are listed in Table 9, irb Command-line options. Typically, you’ll run irb with no options, but if you want to run a script and watch the blow-by-blow description as it runs, you can provide the name of the Ruby script and any options for that script.
Once started, irb displays a prompt and waits for you to type Ruby code. irb understands Ruby, so it knows when statements are incomplete. When this happens, the cursor will be indented on the next line. (In the examples that follow, we’ll use irb’s default prompt.)
|
ruby 2.0 > 1 + 2 |
|
=> 3 |
|
ruby 2.0 > 3 + |
|
ruby 2.0 > 4 |
|
=> 7 |
You can leave irb by typing exit or quit or by entering an end-of-file character (unless IGNORE_EOF mode is set).
During an irb session, the work you do is accumulated in irb’s workspace. Variables you set, methods you define, and classes you create are all remembered and may be used subsequently in that session.
|
ruby 2.0 > def fib_up_to(n) |
|
ruby 2.0 ?> f1, f2 = 1, 1 |
|
ruby 2.0 ?> while f1 <= n |
|
ruby 2.0 ?> puts f1 |
|
ruby 2.0 ?> f1, f2 = f2, f1+f2 |
|
ruby 2.0 ?> end |
|
ruby 2.0 ?> end |
|
=> nil |
|
ruby 2.0 > fib_up_to(4) |
|
1 |
|
1 |
|
2 |
|
3 |
|
=> nil |
Notice the nil return values. These are the results of defining the method and then running it—our method printed the Fibonacci numbers but then returned nil.
A great use of irb is experimenting with code you’ve already written. Perhaps you want to track down a bug, or maybe you just want to play. If you load your program into irb, you can then create instances of the classes it defines and invoke its methods. For example, the file code/irb/fibbonacci_sequence.rb contains the following method definition:
irb/fibonacci_sequence.rb |
|
|
def fibonacci_sequence |
|
Enumerator.new do |generator| |
|
i1, i2 = 1, 1 |
|
loop do |
|
generator.yield i1 |
|
i1, i2 = i2, i1+i2 |
|
end |
|
end |
|
end |
We can load this into irb and play with the method:
|
ruby 2.0 > load 'code/irb/fibonacci_sequence.rb' |
|
=> True |
|
ruby 2.0 > fibonacci_sequence.first(10) |
|
=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] |
In this example, we use load , rather than require , to include the file in our session. We do this as a matter of practice: load allows us to load the same file multiple times, so if we find a bug and edit the file, we could reload it into our irb session.
Table 9. irb Command-line options
Option |
Description |
--back-trace-limit n |
Displays backtrace information using the top n and last n entries. The default value is 16. |
--context-mode n |
:CONTEXT_MODE is describd later. |
-d |
Sets $DEBUG to true (same as ruby -d). |
-E enc |
Same as Ruby’s -E option. |
-f |
Suppresses reading >~/.irbrc. |
-h, --help |
Displays usage information. |
-I directories |
Same as Ruby’s -I option. |
--inf-ruby-mode |
Sets up irb to run in inf-ruby-mode under Emacs. Same as --prompt inf-ruby --noreadline. |
--inspect, --noinspect |
Uses/doesn’t use Object#inspect to format output (--inspect is the default, unless in math mode). |
--irb_debug n |
Sets internal debug level to n (useful only for irb development). |
-m |
Math mode (fraction and matrix support is available). |
--noprompt |
Does not display a prompt. Same as --prompt null. |
--prompt prompt-mode |
Switches prompt. Predefined prompt modes are null, default, classic, simple, xmp, and inf-ruby. |
--prompt-mode prompt-mode |
Same as --prompt. |
-r module |
Requires module. Same as ruby -r. |
--readline, --noreadline |
Uses/doesn’t use readline extension module. |
--sample-book-mode |
Same as --prompt simple. |
--simple-prompt |
Same as --prompt simple. |
--single-irb |
Nested irb sessions will all share the same context. |
--tracer |
Displays trace for execution of commands. |
-U |
Same as Ruby’s -U option. |
-v, --version |
Prints the version of irb. |
Tab Completion
If your Ruby installation has readline support, then you can use irb’s completion facility. Once loaded (and we’ll get to how to load it shortly), completion changes the meaning of the Tab key when typing expressions at the irb prompt. When you press Tab partway through a word, irb will look for possible completions that make sense at that point. If there is only one, irb will fill it in automatically. If there’s more than one valid option, irb initially does nothing. However, if you hit Tab again, it will display the list of valid completions at that point.
For example, the following snippet shows the middle of an irb session, where you just assigned a string object to the variable a.
|
ruby 2.0 > a = "cat" |
|
=> "cat" |
You now want to try the method String#reverse on this object. You start by typing a.re and hitting Tab twice.
|
ruby 2.0 > a.reTabTab |
|
a.replace a.respond_to? a.reverse a.reverse! a.respond_to_missing? |
irb lists all the methods supported by the object in a whose names start with re. We see the one we want, reverse , and enter the next character of its name, v, followed by the Tab key:
|
ruby 2.0 > a.revTAB |
|
ruby 2.0 > a.reverse |
|
=> "tac" |
irb responds to the Tab key by expanding the name as far as it can go, in this case completing the word reverse . If we keyed Tab twice at this point, it would show us the current options, reverse and reverse! . However, because reverse is the one we want, we instead hit Enter , and the line of code is executed.
Tab completion isn’t limited to built-in names. If we define a class in irb, then tab completion works when we try to invoke one of its methods:
|
ruby 2.0 > class Test |
|
ruby 2.0 ?> def my_method |
|
ruby 2.0 ?> end |
|
ruby 2.0 ?> end |
|
=> nil |
|
ruby 2.0 > t = Test.new |
|
=> #<Test:0x000001009fc8c8> |
|
ruby 2.0 > t.myTAB |
|
ruby 2.0 > t.my_method |
|
=> nil |
Tab completion is implemented as an extension library. On some systems this is loaded by default. On others you’ll need to load it when you invoke irb from the command line:
|
$ irb -r irb/completion |
You can also load the completion library when irb is running:
|
ruby 2.0 > require 'irb/completion' |
If you use tab completion all the time and if it doesn’t load by default, it’s probably most convenient to put the require command into your .irbrc file:
Subsessions
irb supports multiple, concurrent sessions. One is always current; the others lie dormant until activated. Entering the command irb within irb creates a subsession, entering the jobs command lists all sessions, and entering fg activates a particular dormant session. This example also illustrates the -r command-line option, which loads in the given file before irb starts:
|
dave[ruby4/Book 13:44:16] irb -r ./code/irb/fibonacci_sequence.rb |
|
ruby 2.0 > result = fibonacci_sequence.first(5) |
|
=> [1, 1, 2, 3, 5] |
|
ruby 2.0 > # Created nested irb session |
|
ruby 2.0 > irb |
|
ruby 2.0 > result = %w{ cat dog elk } |
|
=> ["cat", "dog", "elk"] |
|
ruby 2.0 > result.map(&:upcase) |
|
=> ["CAT", "DOG", "ELK"] |
|
ruby 2.0 > jobs |
|
=> #0->irb on main (#<Thread:0x00000100887678>: stop) |
|
#1->irb#1 on main (#<Thread:0x00000100952710>: running) |
|
ruby 2.0 > fg 0 |
|
=> #<IRB::Irb: @context=#<IRB::Context:0x000001008ea6d8>, ... |
|
ruby 2.0 > result |
|
=> [1, 1, 2, 3, 5] |
|
ruby 2.0 > fg 1 |
|
=> #<IRB::Irb: @context=#<IRB::Context:0x00000100952670>, ... |
|
ruby 2.0 > result |
|
=> ["cat", "dog", "elk"] |
|
ruby 2.0 > |
Subsessions and Bindings
If you specify an object when you create a subsession, that object becomes the value of self in that binding. This is a convenient way to experiment with objects. In the following example, we create a subsession with the string “wombat” as the default object. Methods with no receiver will be executed by that object.
|
ruby 2.0 > self |
|
=> main |
|
ruby 2.0 > irb "wombat" |
|
ruby 2.0 > self |
|
=> "wombat" |
|
ruby 2.0 > upcase |
|
=> "WOMBAT" |
|
ruby 2.0 > size |
|
=> 6 |
|
ruby 2.0 > gsub(/[aeiou]/, '*') |
|
=> "w*mb*t" |
|
ruby 2.0 > irb_exit |
|
=> #<IRB::Irb: @context=#<IRB::Context:0x000001009dc4d8>, ... |
|
ruby 2.0 > self |
|
=> main |
|
ruby 2.0 > upcase |
|
NameError: undefined local variable or method `upcase' for main:Object |
|
from (irb):4 |
|
from /Users/dave/.rvm/rubies/ruby 2.0/bin/irb:17:in `<main>' |
irb is remarkably configurable. You can set configuration options with command-line options from within an initialization file and while you’re inside irb itself.
Initialization File
irb uses an initialization file in which you can set commonly used options or execute any required Ruby statements. When irb is run, it will try to load an initialization file from one of the following sources in order: ~/.irbrc, .irbrc, irb.rc, _irbrc, and $irbrc.
Within the initialization file, you may run any arbitrary Ruby code. You can also set configuration values. The list of configuration variables is given in irb Configuration Options—the values that can be used in an initialization file are the symbols (starting with a colon). You use these symbols to set values into the IRB.conf hash. For example, to make SIMPLE the default prompt mode for all your irb sessions, you could have the following in your initialization file:
|
IRB.conf[:PROMPT_MODE] = :SIMPLE |
As an interesting twist on configuring irb, you can set IRB.conf[:IRB_RC] to a Proc object. This proc will be invoked whenever the irb context is changed and will receive the configuration for that context as a parameter. You can use this facility to change the configuration dynamically based on the context. For example, the following .irbrc file sets the prompt so that only the main prompt shows the irb level, but continuation prompts and the result still line up:
|
IRB.conf[:IRB_RC] = lambda do |conf| |
|
leader = " " * conf.irb_name.length |
|
conf.prompt_i = "#{conf.irb_name} --> " |
|
conf.prompt_s = leader + ' \-" ' |
|
conf.prompt_c = leader + ' \-+ ' |
|
conf.return_format = leader + " ==> %s\n\n" |
|
puts "Welcome!" |
|
end |
An irb session using this .irbrc file looks like the following:
|
$ irb |
|
Welcome! |
|
irb --> 1 + 2 |
|
==> 3 |
|
|
|
irb --> 2 + |
|
\-+ 6 |
|
==> 8 |
Extending irb
Because the things you type into irb are interpreted as Ruby code, you can effectively extend irb by defining new top-level methods. For example, you may want to time how long certain things take. You can use the measure method in the Benchmark library to do this, but it’s more convenient to wrap this in a helper method.
Add the following to your .irbrc file:
|
def time(&block) |
|
require 'benchmark' |
|
result = nil |
|
timing = Benchmark.measure do |
|
result = block.() |
|
end |
|
puts "It took: #{timing}" |
|
result |
|
end |
The next time you start irb, you’ll be able to use this method to get timings:
|
ruby 2.0 > time { 1_000_000.times { "cat".upcase } } |
|
It took: 0.320000 0.000000 0.320000 ( 0.323104) |
|
=> 1000000 |
Interactive Configuration
Most configuration values are also available while you’re running irb. The list in irb Configuration Options shows these values as conf.xxx. For example, to change your prompt back to SIMPLE, you could use the following:
|
ruby 2.0 > 1 + |
|
ruby 2.0 > 2 |
|
=> 3 |
|
ruby 2.0 > conf.prompt_mode = :SIMPLE |
|
=> :SIMPLE |
|
>> 1 + |
|
?> 2 |
|
=> 3 |
irb Configuration Options
In the descriptions that follow, a label of the form :XXX signifies a key used in the IRB.conf hash in an initialization file, and conf.xxx signifies a value that can be set interactively. The value in square brackets at the end of the description is the option’s default.
:AUTO_INDENT / auto_indent_mode
If true, irb will indent nested structures as you type them. [true]
:BACK_TRACE_LIMIT / back_trace_limit
Displays n initial and n final lines of backtrace. [16]
:CONTEXT_MODE
Specifies what binding to use for new workspaces: 0→proc at the top level, 1→binding in a loaded, anonymous file, 2→per thread binding in a loaded file, 3→binding in a top-level function. [3]
:DEBUG_LEVEL / debug_level
Sets the internal debug level to n. This is useful if you’re debugging irb’s lexer. [0]
:IGNORE_EOF / ignore_eof
Specifies the behavior of an end of file received on input. If true, it will be ignored; otherwise, irb will quit. [false]
:IGNORE_SIGINT / ignore_sigint
If false, ^C (Ctrl+c) will quit irb. If true, ^C during input will cancel input and return to the top level; during execution, ^C will abort the current operation. [true]
:INSPECT_MODE / inspect_mode
Specifies how values will be displayed: true means use inspect , false uses to_s , and nil uses inspect in nonmath mode and to_s in math mode. [nil]
:IRB_RC
Can be set to a proc object that will be called when an irb session (or subsession) is started. [nil]
last_value
The last value output by irb. [...]
:LOAD_MODULES / load_modules
A list of modules loaded via the -r command-line option. [[]]
:MATH_MODE / math_mode
If true, irb runs with the mathn library loaded (described in the library section) and does not use inspect to display values. [false]
prompt_c
The prompt for a continuing statement (for example, immediately after an if). [depends]
prompt_i
The standard, top-level prompt. [depends]
:PROMPT_MODE / prompt_mode
The style of prompt to display. [:DEFAULT]
prompt_s
The prompt for a continuing string. [depends]
:PROMPT
See Configuring the Prompt. [...]
:RC / rc
If false, do not load an initialization file. [true]
return_format
The format used to display the results of expressions entered interactively. [depends]
:SAVE_HISTORY / save_history
The number of commands to save between irb sessions. [nil]
:SINGLE_IRB
If true, nested irb sessions will all share the same binding; otherwise, a new binding will be created according to the value of :CONTEXT_MODE. [nil]
thread
A read-only reference to the currently executing Thread object. [current thread]
:USE_LOADER / use_loader
Specifies whether irb’s own file reader method is used with load / require . [false]
:USE_READLINE / use_readline
irb will use the readline library (described in the library section) if available, unless this option is set to false, in which case readline will never be used, or nil, in which case readline will not be used in inf-ruby-mode. [depends]
:USE_TRACER / use_tracer
If true, traces the execution of statements. [false]
:VERBOSE / verbose
In theory, switches on additional tracing when true; in practice, almost no extra tracing results. [true]
18.2 Commands
At the irb prompt, you can enter any valid Ruby expression and see the results. You can also use any of the following commands to control the irb session:[87]
help ClassName, string, or symbol
Displays the ri help for the given thing.
|
irb(main):001:0> help "String.encoding" |
|
------------------------------------------------- String#encoding |
|
obj.encoding => encoding |
|
----------------------------------------------------------------- |
|
Returns the Encoding object that represents the encoding of obj. |
exit, quit, irb_exit, irb_quit
Quits this irb session or subsession. If you’ve used cb to change bindings (detailed in a moment), exits from this binding mode.
conf, context, irb_context
Displays current configuration. Modifying the configuration is achieved by invoking methods of conf. The list in irb Configuration Options shows the available conf settings.
For example, to set the default prompt to something subservient, you could use this:
|
irb(main):001:0> conf.prompt_i = "Yes, Master? " |
|
=> "Yes, Master? " |
|
Yes, Master? 1 + 2 |
cb, irb_change_binding <obj>
Creates and enters a new binding (sometimes called a workspace) that has its own scope for local variables. If obj is given, it will be used as self in the new binding.
pushb obj, popb
Pushes and pops the current binding.
bindings
Lists the current bindings.
irb_cwws
Prints the object that’s the binding of the current workspace.
irb <obj>
Starts an irb subsession. If obj is given, it will be used as self.
jobs, irb_jobs
Lists irb subsessions.
fg n, irb_fg n
Switches into the specified irb subsession. n may be any of the following: an irb subsession number, a thread ID, an irb object, or the object that was the value of self when a subsession was launched.
kill n, irb_kill n
Kills an irb subsession. n may be any of the values as described for irb_fg.
source filename
Loads and executes the given file, displaying the source lines.
Configuring the Prompt
You have a lot of flexibility in configuring the prompts that irb uses. Sets of prompts are stored in the prompt hash, IRB.conf[:PROMPT].
For example, to establish a new prompt mode called MY_PROMPT, you could enter the following (either directly at an irb prompt or in the .irbrc file):
|
IRB.conf[:PROMPT][:MY_PROMPT] = { # name of prompt mode |
|
:PROMPT_I => '-->', # normal prompt |
|
:PROMPT_S => '--"', # prompt for continuing strings |
|
:PROMPT_C => '--+', # prompt for continuing statement |
|
:RETURN => " ==>%s\n" # format to return value |
|
} |
Once you’ve defined a prompt, you have to tell irb to use it. From the command line, you can use the --prompt option. (Notice how the name of the prompt on the command line is automatically converted to uppercase, with hyphens changing to underscores.)
|
$ irb --prompt my-prompt |
If you want to use this prompt in all your future irb sessions, you can set it as a configuration value in your .irbrc file:
|
IRB.conf[:PROMPT_MODE] = :MY_PROMPT |
The symbols :PROMPT_I, :PROMPT_S, and :PROMPT_C specify the format for each of the prompt strings. In a format string, certain % sequences are expanded:
Table 10. irb prompt string substitutions
Flag |
Description |
%N |
Current command. |
%m |
to_s of the main object (self). |
%M |
inspect of the main object (self). |
%l |
Delimiter type. In strings that are continued across a line break, %l will display the type of delimiter used to begin the string, so you’ll know how to end it. The delimiter will be one of ", ’, /, ], or ‘. |
%ni |
Indent level. The optional number n is used as a width specification to printf, as printf("%nd"). |
%nn |
Current line number (n used as with the indent level). |
%% |
A literal percent sign. |
For instance, the default prompt mode is defined as follows:
|
IRB.conf[:PROMPT][:DEFAULT] = { |
|
:PROMPT_I => "%N(%m):%03n:%i> ", |
|
:PROMPT_S => "%N(%m):%03n:%i%l ", |
|
:PROMPT_C => "%N(%m):%03n:%i* ", |
|
:RETURN => "=> %s\n" |
|
} |
Saving Your Session History
If you have readline support in irb (that is, you can hit the up arrow key and irb recalls the previous command you entered), then you can also configure irb to remember the commands you enter between sessions. Simply add the following to your .irbrc file:
|
IRB.conf[:SAVE_HISTORY] = 50 # save last 50 commands |
Footnotes
[87] |
For some inexplicable reason, many of these commands have up to nine different aliases. We don’t bother to show all of them. |