Interactive Ruby Shell - Ruby in Its Setting - Programming Ruby 1.9 & 2.0: The Pragmatic Programmers’ Guide (2013)

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.