Section 21.4. The ri Utility


21.3. Using irb

The irb utility (interactive Ruby) has been distributed with Ruby for many years. It can be thought of as a "testbed" or "playground" where you try out quick hacks and new ideas.

Basic usage of irb is simple. When you start it, you get a prompt where you can type Ruby expressions; each expression is evaluated, and the result is printed for you. Here's a small example of a session:

$ irb irb(main):001:0> "cell" + "o" => "cello" irb(main):002:0> 3*79 => 237 irb(main):003:0> Dir.entries(".").size => 17 irb(main):004:0> rand => 0.850757389880155 irb(main):005:0> rand => 0.679879756672551 irb(main):006:0> defined? foo => nil irb(main):007:0> defined? Object => "constant" irb(main):008:0> quit $


Of course, it's more than just a calculator. You can type in arbitrary Ruby code if you want:

[hal@localhost ch21]$ irb irb(main):001:0> require 'mathn' => true irb(main):002:0> gen = Prime.new => #


The -r option will do a require so that you can include code from a file. Suppose this was a source file of yours:

# File: foo.rb class MyClass   attr_accessor :alpha, :beta   def initialize(a, b)     @alpha, @beta = a, b   end end obj1 = MyClass.new(23,34) obj2 = MyClass.new("abc","xyz")


Then we can do this:

$ irb -rfoo irb(main):001:0> obj = MyClass.new(88,99) => #


But notice that although we can get at the contents of the file (for example, the constant MyClass), that doesn't include the local variables. The local variables for a file are accessible only within that file; a require (inside or outside irb) won't allow you to see them.

Newbies are sometimes confused by output printed in irb:

$ irb -rfoo irb(main):001:0> puts "hello" hello => nil


What is the nil doing there? That, of course, is the return value from the puts method.

Another minor source of confusion concerns eval. See the behavior in the following session:

$ irb irb(main):001:0> eval("var = 567") => 567 irb(main):002:0> eval("var") => 567 irb(main):003:0> var => 567


This may not seem surprising to you. But run the following script and see what happens:

p eval("var = 567") p eval("var") p var # Results: # 567 # 567 # temp.rb:3: undefined local variable or method `var' for main:Object (NameError)


It is a quirk of Ruby that when you do an eval and then do another, they have in a sense the "same scope." So the variable defined in the first line can be accessed again in the second line (inside or outside irb). But the difference comes when we try to access that variable without using eval. In irb it works, but in the script we get an error. What's going on?

The script's behavior should be considered the more correct one. Bear in mind that irb itself is written in Ruby; common sense indicates it probably uses eval internally to do its job. But we've seen that eval can give us different results from what we see at the top level; therefore, running code in irb is not always exactly the same as running it in a standalone script. That is the lesson to be remembered here, especially if you are trying some kind of esoteric experiment.

Be aware that irb is highly customizable. When you start it up, it reads whatever initialization data it finds first, looking for them in this order:

  • File ~/.irbrc

  • File .irbrc

  • File irb.rc

  • File _irbrc

  • Path stored in environment variable $irbrc

The initialization file is pure Ruby. It enables customization of prompts and much more. For a complete discussion of this file, the best source is the so-called "Pickaxe Book," Programming Ruby. The remainder of this section will only hit a few highlights.

If your Ruby installation is built with GNU readline support (as is usually the case), you can use the up and down arrow keys to navigate back and forth in the command history. More importantly, you get tab completion as a feature. This works as you would expect: When you type a partial identifier and then press the Tab key, irb TRies to complete the rest of the identifier name for you.

To enable tab completion, add this fragment to your .irbrc file:

IRB.conf[:AUTO_INDENT] = true IRB.conf[:USE_READLINE] = true IRB.conf[:LOAD_MODULES] ||= [] IRB.conf[:LOAD_MODULES] |= ['irb/completion']


Bear in mind it's possible to put arbitrary code in your .irbrc file. For example, here is a method I find useful sometimes. It is named sm for brevity ("show methods"); its purpose is to list (in alphabetical order) all the methods that can be called on an object, excluding the ones it gets from its ancestors:

def sm(obj)   list = obj.methods   anc = obj.class.ancestors - [obj.class]   anc.each {|a| list -= a.instance_methods }   list.sort end


The following is an example of its usage:

irb(main):001:0> str = "hello" => "hello" irb(main):002:0> sm str => ["%", "*", "+", "<<", "<=>", "[]", "[]=", "capitalize", "capitalize!", "casecmp", "center", "chomp", "chomp!", "chop", "chop!", "concat", "count", "crypt", "delete", "delete!", "downcase", "downcase!", "dump", "each", "each_byte", "each_line", "empty?", "gsub", "gsub!", "hex", "index", "insert", "intern", "length", "ljust", "lstrip", "lstrip!", "match", "next", "next!", "oct", "replace", "reverse", "reverse!", "rindex", "rjust", "rstrip", "rstrip!", "scan", "size", "slice", "slice!", "split", "squeeze", "squeeze!", "strip", "strip!", "sub", "sub!", "succ", "succ!", "sum", "swapcase", "swapcase!", "to_f", "to_i", "to_str", "to_sym", "tr", "tr!", "tr_s", "tr_s!", "unpack", "upcase", "upcase!", "upto"] irb(main):003:0> sm String => ["allocate", "new", "superclass"] irb(main):004:0> sm 123 => ["%", "&", "*", "**", "+", "-", "/", "<<", ">>", "[]", "^", "id2name", "power!", "rdiv", "rpower", "size", "to_f", "to_sym", "|", "~"]


It's not seen much, but irb makes it possible to run subsessions within a session. It's possible to run multiple sessions and switch back and forth between them; each one maintains a separate binding.

That may not necessarily seem useful, but one trick that makes it more useful is to specify an object along with the irb subcommand. Then the context of the subsession is that object; self is set as you would expect, the scope is that of the object, and so on:

$ irb irb(main):001:0> t0 = Time.now => Mon Jul 31 04:51:50 CDT 2006 irb(main):002:0> irb t0 irb#1(Mon Jul 31 04:51:50 CDT 2006):001:0> strftime("%a %b %c") => "Mon Jul Mon Jul 31 04:51:50 2006" irb#1(Mon Jul 31 04:51:50 CDT 2006):002:0> to_i => 1154339510 irb#1(Mon Jul 31 04:51:50 CDT 2006):003:0> self + 1000 => Mon Jul 31 05:08:30 CDT 2006 irb#1(Mon Jul 31 04:51:50 CDT 2006):004:0> wday => 1 irb#1(Mon Jul 31 04:51:50 CDT 2006):005:0> class SyntaxError: compile error (irb#1):5: syntax error, unexpected $end         from (irb#1):5 irb#1(Mon Jul 31 04:51:50 CDT 2006):006:0> self.class => Time irb#1(Mon Jul 31 04:51:50 CDT 2006):007:0> quit => #<IRB::Irb: @scanner=#<RubyLex:0xb7ee8394>, @signal_status=:IN_EVAL, @context=#<IRB::Context:0xb7ee86f0>> irb(main):003:0> quit $


We've already seen the usefulness of the ruby-breakpoint library in Chapter 16. In conjunction with that library, irb becomes a more powerful debugging tool because you can set a breakpoint and "jump into" an irb session. Of course, it isn't a real debugger because you can't step around in the code.

The xmp library is sometimes useful. It takes Ruby statements, evaluates them, and places the return value in comments. Programming Ruby covers xmp and also rtags (which generates a TAGS file for emacs or vi).

There is another "goodie" associated with irb that you might like to know about. Naturally irb is capable of analyzing Ruby code; the lexer is easily used by other applications as well. Here is a simple example of a program that opens its own file to analyze itself; it produces a sorted list of all identifiers and constants used in the program:

require 'irb/ruby-lex' file = File.new(__FILE__) parse = RubyLex.new # (file) parse.set_input(file) idents = [] loop do   token =  parse.token   break if token.nil?   if token.is_a? RubyToken::TkIDENTIFIER or      token.is_a? RubyToken::TkCONSTANT     idents << token.name   end end p idents.uniq.sort # Output: # ["File", "RubyLex", "RubyToken", "TkCONSTANT", "TkIDENTIFIER", "file", #  "idents", "loop", "name", "new", "p", "parse", "require", "set_input", #  "sort", "token", "uniq"]


So far as I am aware, this is not documented anywhere in English. But if you need a Ruby lexer, you can probably read the source and adapt this one for your needs.




The Ruby Way(c) Solutions and Techniques in Ruby Programming
The Ruby Way, Second Edition: Solutions and Techniques in Ruby Programming (2nd Edition)
ISBN: 0672328844
EAN: 2147483647
Year: 2004
Pages: 269
Authors: Hal Fulton

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net