Life without IntelliSense in Ruby. Part 2: the IRB

In my previous post I talked about using some of TextMate’s features to make up for the lack of Visual Studio style IntelliSense. IntelliSense makes it easy to discover the APIs of the objects that we are working with. A benefit of using an interpreted language such as Ruby is the availability of a REPL (Read-eval-print-loop). Ruby’s REPL is called the Interactive Ruby Shell (IRB). We can use the IRB to discover the APIs of the objects and Gems we are working with. The IRB also gives us another benefit over IntelliSense – the ability to quickly experiment with the objects in our programs.

To start the IRB from the terminal type irb (unsurprisingly!).

admin ~ $ irb

This produces a prompt like this, where you can type and evaluate Ruby commands:

ruby-1.8.7-p302 :001 >

The Methods Method Method for Discovering Methods

We can use Ruby’s reflection functionality to find the methods available on any object we are working with by using the methods method. For example to find the methods available on a string:

"".methods
=> ["upcase!", "zip", "find_index", "between?", "unpack", "enum_slice", "to_f", "minmax", "lines", "sub", "methods", "send", "replace", "empty?", "group_by", "squeeze", "crypt", "gsub!", "taint", "instance_variable_defined?", "match", "downcase!", "take", "find_all", "min_by", "bytes", "each_cons", "entries", "gsub", "singleton_methods", "instance_eval", "to_str", "first", "chop!", "intern", "nil?", "succ", "capitalize!", "take_while", "select", "max_by", "chars", "enum_cons", "tr!", "protected_methods", "instance_exec", "display", "sort", "chop", "tainted?", "dump", "method", "include?", "untaint", "instance_of?", "chomp!", "swapcase!", "drop", "equal?", "reject", "hex", "minmax_by", "sum", "hash", "private_methods", "all?", "tr_s!", "sort_by", "chomp", "upcase", "start_with?", "succ!", "kind_of?", "strip!", "freeze", "drop_while", "eql?", "next", "collect", "oct", "id", "slice", "casecmp", "grep", "strip", "any?", "delete!", "public_methods", "end_with?", "downcase", "%", "object_id", "is_a?", "scan", "lstrip!", "cycle", "map", "member?", "tap", "type", "*", "split", "insert", "each_with_index", "+", "count", "lstrip", "one?", "squeeze!", "instance_variables", "__id__", "frozen?", "capitalize", "next!", "each_line", "to_enum", "rstrip!", "to_a", "ljust", "respond_to?", "upto", "each", "inject", "tr", "slice!", "class", "reverse", "length", "enum_with_index", "rpartition", "rstrip", "<=>", "none?", "instance_variable_get", "find", "==", "swapcase", "__send__", "===", "min", "each_byte", "enum_for", "extend", "to_s", "rjust", "index", ">=", "size", "reduce", "tr_s", "<=", "clone", "reverse_each", "to_sym", "bytesize", "=~", "instance_variable_set", "<", "detect", "max", "each_char", "each_slice", ">", "to_i", "center", "inspect", "[]", "reverse!", "rindex", "partition", "delete", "[]=", "concat", "sub!", "dup", "<<"] 

I usually append a sort call to make the output alphabetic and easier to scan:

"".methods.sort
 => ["%", "*", "+", "<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", "[]", "[]=", "__id__", "__send__", "all?", "any?", "between?", "bytes", "bytesize", "capitalize", "capitalize!", "casecmp", "center", "chars", "chomp", "chomp!", "chop", "chop!", "class", "clone", "collect", "concat", "count", "crypt", "cycle", "delete", "delete!", "detect", "display", "downcase", "downcase!", "drop", "drop_while", "dump", "dup", "each", "each_byte", "each_char", "each_cons", "each_line", "each_slice", "each_with_index", "empty?", "end_with?", "entries", "enum_cons", "enum_for", "enum_slice", "enum_with_index", "eql?", "equal?", "extend", "find", "find_all", "find_index", "first", "freeze", "frozen?", "grep", "group_by", "gsub", "gsub!", "hash", "hex", "id", "include?", "index", "inject", "insert", "inspect", "instance_eval", "instance_exec", "instance_of?", "instance_variable_defined?", "instance_variable_get", "instance_variable_set", "instance_variables", "intern", "is_a?", "kind_of?", "length", "lines", "ljust", "lstrip", "lstrip!", "map", "match", "max", "max_by", "member?", "method", "methods", "min", "min_by", "minmax", "minmax_by", "next", "next!", "nil?", "none?", "object_id", "oct", "one?", "partition", "private_methods", "protected_methods", "public_methods", "reduce", "reject", "replace", "respond_to?", "reverse", "reverse!", "reverse_each", "rindex", "rjust", "rpartition", "rstrip", "rstrip!", "scan", "select", "send", "singleton_methods", "size", "slice", "slice!", "sort", "sort_by", "split", "squeeze", "squeeze!", "start_with?", "strip", "strip!", "sub", "sub!", "succ", "succ!", "sum", "swapcase", "swapcase!", "taint", "tainted?", "take", "take_while", "tap", "to_a", "to_enum", "to_f", "to_i", "to_s", "to_str", "to_sym", "tr", "tr!", "tr_s", "tr_s!", "type", "unpack", "untaint", "upcase", "upcase!", "upto", "zip"] 

Another handy trick is to use the Array’s grep method to see just the methods you are interested in.

"".methods.grep /each/
 => ["each_cons", "each_with_index", "each_line", "each", "each_byte", "reverse_each", "each_char", "each_slice"] 

Playing with Gems

When experimenting with a new gem it is straightforward to just load them into the IRB using require. In most Ruby projects there is a convention to have an init.rb or environment.rb file that loads all the libraries used by the project and sets up database connections etc. In the IRB you can require this file and then play around with the objects in your project. Rails has this feature built-in: if you type rails console (or script/console in Rails 2) an IRB opens with all the project’s classes loaded and a database connection established. You can then use the rails console to create or retrieve active record objects and inspect their state. For example:

User.first
 => #<User id: 1, name: "Jason Neylon", email: "jason@gmail.com", created_at: "2011-01-07 19:40:34", updated_at: "2011-01-07 19:40:34"> 

The rails console is also great for ad-hoc administration or investigation of production issues.

Bye Bye IntelliSense Hello Fast Feedback

I would be lying if I said I didn’t sometimes miss Visual Studio’s IntelliSense features. But I love the ability that the IRB gives you to quickly experiment with objects. The fast feedback really helps to make development more productive. The Visual Studio/C# compile/test/debug cycle seems slow and painful in comparison.

Advertisements

7 comments

  1. michael baldry · March 5, 2011

    Another trick I use when in IRB is: puts obj.methods.sort.join(“\n”)

    Makes it nicer to read in a list.

  2. michael baldry · March 5, 2011

    Also irb -renvironment is easier than requiring it inside irb

  3. Baris Vakuc · March 6, 2011

    If you require ‘pp’ then you can use pretty formatting to achieve the same thing like so..

    pp obj.methods.sort

    • jasonneylon · March 6, 2011

      Thanks for the tips, guys. I require a pp – should be easy to remember!

  4. thattommyhall · March 11, 2011

    I use some_object.methods – Object.methods to see what the object has besides the methods in Object. The top level object in ruby has quite a lot of methods.

    ruby-1.9.2-p136 :001 > [].methods
    => [:inspect, :to_s, :to_a, :to_ary, :frozen?, :==, :eql?, :hash, :[], :[]=, :at, :fetch, :first, :last, :concat, :<<, :push, :pop, :shift, :unshift, :insert, :each, :each_index, :reverse_each, :length, :size, :empty?, :find_index, :index, :rindex, :join, :reverse, :reverse!, :rotate, :rotate!, :sort, :sort!, :sort_by!, :collect, :collect!, :map, :map!, :select, :select!, :keep_if, :values_at, :delete, :delete_at, :delete_if, :reject, :reject!, :zip, :transpose, :replace, :clear, :fill, :include?, :, :slice, :slice!, :assoc, :rassoc, :+, :*, :-, :&, :|, :uniq, :uniq!, :compact, :compact!, :flatten, :flatten!, :count, :shuffle!, :shuffle, :sample, :cycle, :permutation, :combination, :repeated_permutation, :repeated_combination, :product, :take, :take_while, :drop, :drop_while, :pack, :entries, :sort_by, :grep, :find, :detect, :find_all, :flat_map, :collect_concat, :inject, :reduce, :partition, :group_by, :all?, :any?, :one?, :none?, :min, :max, :minmax, :min_by, :max_by, :minmax_by, :member?, :each_with_index, :each_entry, :each_slice, :each_cons, :each_with_object, :chunk, :slice_before, :nil?, :===, :=~, :!~, :class, :singleton_class, :clone, :dup, :initialize_dup, :initialize_clone, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :freeze, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :respond_to_missing?, :extend, :display, :method, :public_method, :define_singleton_method, :__id__, :object_id, :to_enum, :enum_for, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__]

    ruby-1.9.2-p136 :002 > [].methods – Object.methods
    => [:to_a, :to_ary, :[], :[]=, :at, :fetch, :first, :last, :concat, :<<, :push, :pop, :shift, :unshift, :insert, :each, :each_index, :reverse_each, :length, :size, :empty?, :find_index, :index, :rindex, :join, :reverse, :reverse!, :rotate, :rotate!, :sort, :sort!, :sort_by!, :collect, :collect!, :map, :map!, :select, :select!, :keep_if, :values_at, :delete, :delete_at, :delete_if, :reject, :reject!, :zip, :transpose, :replace, :clear, :fill, :slice, :slice!, :assoc, :rassoc, :+, :*, :-, :&, :|, :uniq, :uniq!, :compact, :compact!, :flatten, :flatten!, :count, :shuffle!, :shuffle, :sample, :cycle, :permutation, :combination, :repeated_permutation, :repeated_combination, :product, :take, :take_while, :drop, :drop_while, :pack, :entries, :sort_by, :grep, :find, :detect, :find_all, :flat_map, :collect_concat, :inject, :reduce, :partition, :group_by, :all?, :any?, :one?, :none?, :min, :max, :minmax, :min_by, :max_by, :minmax_by, :member?, :each_with_index, :each_entry, :each_slice, :each_cons, :each_with_object, :chunk, :slice_before]

  5. thattommyhall · April 14, 2011

    class Object; def mymethods; methods-Object.methods end end

    Works nice too

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s