#!/usr/bin/env ruby # usage: # # ri name... # # where name can be # # Class | Class::method | Class#method | Class.method | method # # All names may be abbreviated to their minimum unbiguous form. If a name # _is_ ambiguous, all valid options will be listed. # require 'rdoc/ri/ri_paths' require 'rdoc/ri/ri_cache' require 'rdoc/ri/ri_util' require 'rdoc/ri/ri_reader' require 'rdoc/ri/ri_formatter' ###################################################################### def display_usage File.open(__FILE__) do |f| f.gets puts $1 while (f.gets =~ /^# ?(.*)/) end exit end ###################################################################### class RiDisplay def initialize paths = RI::Paths::PATH if paths.empty? $stderr.puts "No ri documentation found in:" [ RI::Paths::SYSDIR, RI::Paths::SITEDIR, RI::Paths::HOMEDIR].each do |d| $stderr.puts " #{d}" end $stderr.puts "\nIs ri correctly installed?" exit 1 end @ri_reader = RI::RiReader.new(RI::RiCache.new(paths)) @formatter = RI::RiFormatter.new(72, " ") end ###################################################################### def display_params(method) params = method.params if params[0,1] == "(" if method.is_singleton params = method.full_name + params else params = method.name + params end end @formatter.wrap(params) end ###################################################################### def display_flow(flow) if !flow || flow.empty? @formatter.wrap("(no description...)") else @formatter.display_flow(flow) end end ###################################################################### def display_method_info(method_entry) method = @ri_reader.get_method(method_entry) @formatter.draw_line(method.full_name) display_params(method) @formatter.draw_line display_flow(method.comment) if method.aliases && !method.aliases.empty? @formatter.blankline aka = "(also known as " aka << method.aliases.map {|a| a.name }.join(", ") aka << ")" @formatter.wrap(aka) end end ###################################################################### def display_class_info(class_entry) klass = @ri_reader.get_class(class_entry) @formatter.draw_line("Class: " + klass.full_name) display_flow(klass.comment) @formatter.draw_line unless klass.constants.empty? @formatter.blankline @formatter.wrap("Constants:", "") len = 0 klass.constants.each { |c| len = c.name.length if c.name.length > len } len += 2 klass.constants.each do |c| @formatter.wrap(c.value, @formatter.indent+((c.name+":").ljust(len))) end end unless klass.method_list.empty? @formatter.blankline @formatter.wrap("Methods:", "") @formatter.wrap(klass.method_list.map{|m| m.name}.sort.join(', ')) end unless klass.attributes.empty? @formatter.blankline @formatter.wrap("Attributes:", "") @formatter.wrap(klass.attributes.map{|a| a.name}.sort.join(', ')) end end ###################################################################### # If the list of matching methods contains exactly one entry, or # if it contains an entry that exactly matches the requested method, # then display that entry, otherwise display the list of # matching method names def report_method_stuff(requested_method_name, methods) if methods.size == 1 display_method_info(methods[0]) elsif (entry = methods.find {|m| m.name == requested_method_name}) display_method_info(entry) else puts "More than one method matched your request. You can refine" puts "your search by asking for information on one of:\n\n" @formatter.wrap(methods.map {|m| m.full_name} .join(", ")) end end ###################################################################### def report_class_stuff(namespaces) if namespaces.size > 1 puts "More than one class or module matched your request. You can refine" puts "your search by asking for information on one of:\n\n" puts @formatter.wrap("", namespaces.map {|m| m.full_name} .join(", ")) else class_desc = @ri_reader.get_class(namespaces[0]) display_class_info(namespaces[0]) end end ###################################################################### def display_info_for(arg) desc = NameDescriptor.new(arg) namespaces = @ri_reader.top_level_namespace for class_name in desc.class_names namespaces = @ri_reader.lookup_namespace_in(class_name, namespaces) if namespaces.empty? raise RiError.new("Nothing known about #{arg}") end end if desc.method_name.nil? report_class_stuff(namespaces) else methods = @ri_reader.find_methods(desc.method_name, desc.is_class_method, namespaces) if methods.empty? raise RiError.new("Nothing known about #{arg}") else report_method_stuff(desc.method_name, methods) end end end end ###################################################################### if ARGV.size.zero? display_usage else ri = RiDisplay.new begin ARGV.each do |arg| ri.display_info_for(arg) end rescue RiError => e $stderr.puts(e.message) exit(1) end end