Thu Jun 12 2008
ri is the local, command-line viewer for Ruby documentation. I vastly prefer looking up documentation with ri over mousing up and down and in and out of HTML frames, scrolling through PDFs, and flipping through books, which have unfortunately become much more common ways to search Ruby documentation.
ri rocks. But one thing ri does not handle well is ambiguous method lookups.
For example, if I type
ri detect
I get this output:
More than one method matched your request. You can refine
your search by asking for information on one of:
Enumerable#detect, YAML::detect_implicit, EnumerablePass#detect,
HTML5::HTMLInputStream#detect_bom,
HTML5::HTMLInputStream#detect_encoding,
HTML5::HTMLInputStream#detect_encoding_meta,
Mocha::ExpectationList#detect
And now I would have to type this to get the documentation for Enumerable#detect:
ri Enumerable#detect
That’s a lot of typing. Not good.
There’s also this problem. If I have multiple versions of a gem installed, ri can make it impossible to get documentation for a method, because it won’t be able to disambiguate the method you specify. If I type
ri ActiveRecord::Base.find
ri gives me this output:
More than one method matched your request. You can refine
your search by asking for information on one of:
ActiveRecord::Base::find, ActiveRecord::Base::find_by_sql,
ActiveRecord::Base::find, ActiveRecord::Base::find_by_sql,
ActiveRecord::Base::find, ActiveRecord::Base::find_by_sql
Now you’re stuck. There’s no way forward.
To make ri better, I wrote a patch for the ri utility. It adds two simple enhancements.
With the patch, ri will handle ambiguous methods more sanely. If you give ri an ambiguous method, it will go into interactive mode and let you pick from a menu of numbered alternatives. Enter a number, and it will give you the documentation you want.
So if I type
ri detect
I’ll now get
More than one method matched your request. Type the number of the method you want, or press Return to cancel: 1 Enumerable#detect 2 EnumerablePass#detect 3 Mocha::ExpectationList#detect >>
You can then type a number, hit return, and call up that method’s documentation.
The other problem is solved too:
$ ri ActiveRecord::Base.find More than one method matched your request. Type the number of the method you want, or press Return to cancel: 1 ActiveRecord::Base::find (1.15.6) 2 ActiveRecord::Base::find (2.0.2) 3 ActiveRecord::Base::find (2.1.0) >>
And if I type in a number, I’ll actually be able to get documentation.
You might notice that my ri enhancement doesn’t return partial method name matches if it can find exact matches. That’s because allowing partial matches will often result in really huge lists. This would make using ri needlessly complicated.
But if ri can’t find an exact match, the patch lets you choose among partial matches. Example:
$ ri link_to_ There are no exact matches, but 11 partial matches: Type the number of the method you want, or press Return to cancel: 1 ActionView::Helpers::JavaScriptHelper#link_to_function (1.13.6) 2 ActionView::Helpers::JavaScriptHelper#link_to_function (2.0.2) 3 ActionView::Helpers::PrototypeHelper#link_to_remote (1.13.6) 4 ActionView::Helpers::PrototypeHelper#link_to_remote (2.0.2) 5 ActionView::Helpers::UrlHelper#link_to_if (1.13.6) 6 ActionView::Helpers::UrlHelper#link_to_image 7 ActionView::Helpers::UrlHelper#link_to_unless (1.13.6) 8 ActionView::Helpers::UrlHelper#link_to_unless_current (1.13.6) 9 ActionView::Helpers::UrlHelper#link_to_if (2.0.2) 10 ActionView::Helpers::UrlHelper#link_to_unless (2.0.2) 11 ActionView::Helpers::UrlHelper#link_to_unless_current (2.0.2) >>
The patch also makes it easier to browse the methods of a particular Ruby class or module. You can do this by adding an asterisk to the end of a class or module name1.
Example:
$ ri ActiveRecord::Base*
---------------------------------------------- Class: ActiveRecord::Base
Class methods:
--------------
===, abstract_class?, aggregate_mapping, all, attr_accessible,
attr_protected, attr_readonly, base_class, benchmark,
class_of_active_record_descendant, clear_active_connections!,
clear_reloadable_connections!, column_names, columns, columns_hash,
compute_type, connected?, connection, connection=, content_columns,
count_by_sql, create, decrement_counter, delete, delete_all,
descends_from_active_record?, destroy, destroy_all,
establish_connection, exists?,
expand_hash_conditions_for_aggregates, find, find_by_sql, first,
increment_counter, inheritance_column, inspect, last, new,
primary_key, readonly_attributes, remove_connection, require_mysql,
reset_column_information, respond_to?, sanitize_sql,
sanitize_sql_array, sanitize_sql_for_assignment,
sanitize_sql_for_conditions, sanitize_sql_hash,
sanitize_sql_hash_for_assignment, sanitize_sql_hash_for_conditions,
serialize, serialized_attributes, set_inheritance_column,
set_primary_key, set_sequence_name, set_table_name, silence,
sti_name, table_exists?, table_name, update, update_all,
update_counters, with_exclusive_scope, with_scope
Instance methods:
-----------------
==, [], []=, attribute_for_inspect, attribute_names,
attribute_present?, attributes, attributes=,
attributes_before_type_cast, becomes, cache_key, clone,
column_for_attribute, connection, decrement, decrement!, destroy,
eql?, freeze, frozen?, has_attribute?, hash, id, id=, increment,
increment!, inspect, new_record?, readonly!, readonly?, reload,
respond_to?, save, save!, to_param, toggle, toggle!,
update_attribute, update_attributes, update_attributes!
Enter the method name you want. You can use tab to autocomplete.
>> increment[TAB KEY PRESSED TWICE]
increment increment_counter increment!
>> increment!
------------------------------------------ ActiveRecord::Base#increment!
increment!(attribute)
------------------------------------------------------------------------
Increments the +attribute+ and saves the record.
The tab-autocomplete feature is available if Ruby’s Readline module is enabled.
You can limit the results to just instance methods like so:
$ ri String*i
Or just class methods:
$ ri ActiveRecord::Base*c
To install this patch, just follow these steps.
1. If you don’t have one yet, create a /bin directory in your home directory.
2. Put this bin directory at the head of your PATH. You can do this with a line in your .bash_profile or .bashrc file like this:
export PATH="$HOME/bin:$PATH"
3. Create a file in your new /bin directory named “ri”.
4. Copy the code on this page into the file.
5. Make the file executable:
chmod u+x ri
Now you should be able to run the enhanced version of ri.
$ ri has_many
More than one method matched your request. Type the number
of the method you want, or press Return to cancel:
1 ActiveRecord::Associations::ClassMethods#has_many (1.15.6)
2 ActiveRecord::Associations::ClassMethods#has_many (2.0.2)
3 ActiveRecord::Associations::ClassMethods#has_many (2.1.0)
>> 1
---------------------- ActiveRecord::Associations::ClassMethods#has_many
has_many(association_id, options = {}, &extension)
------------------------------------------------------------------------
Adds the following methods for retrieval and query of collections
of associated objects. +collection+ is replaced with the symbol
passed as the first argument, so +has_many :clients+ would add
among others +clients.empty?+.
* +collection(force_reload = false)+ - returns an array of all
the associated objects. An empty array is returned if none are
found.
* +collection<<(object, ...)+ - adds one or more objects to the
collection by setting their foreign keys to the collection's
primary key.
...
etc.
Enjoy.
I added gem version numbers in the output to help disambiguate methods. This was Leslie Viljoen’s excellent idea on the comp.lang.ruby discussion thread about this patch. Leslie also provided the some of the code for displaying the version numbers.
Ryan Davis suggested I forward this patch to the Ruby project so it can be incorporated into a future version of ri. I’ve done so.
1 The only catch is if you issue the command in a directory where the argument, e.g. String*, can be expanded by the shell to match a file in that directory. Then the command won’t work as expected. This scenario should be rare, but if it’s ever the case, you can enclose the argument in quotes to make the command work properly. This is what you have to do with ri anyway when looking up methods containing certain punctuation characters.
a tweaked version of the micro theme by seaofclouds, and powered by YAML, Textile, and this simple, home-grown ruby build script.