summaryrefslogtreecommitdiff
path: root/lib/rdoc/ri
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rdoc/ri')
-rw-r--r--lib/rdoc/ri/cache.rb11
-rw-r--r--lib/rdoc/ri/descriptions.rb3
-rw-r--r--lib/rdoc/ri/display.rb201
-rw-r--r--lib/rdoc/ri/driver.rb522
-rw-r--r--lib/rdoc/ri/formatter.rb2
-rw-r--r--lib/rdoc/ri/paths.rb13
-rw-r--r--lib/rdoc/ri/reader.rb6
-rw-r--r--lib/rdoc/ri/util.rb2
8 files changed, 494 insertions, 266 deletions
diff --git a/lib/rdoc/ri/cache.rb b/lib/rdoc/ri/cache.rb
index 2e267d95fb..06177a00de 100644
--- a/lib/rdoc/ri/cache.rb
+++ b/lib/rdoc/ri/cache.rb
@@ -14,7 +14,7 @@ class RDoc::RI::ClassEntry
@inferior_classes = []
end
- # We found this class in more tha one place, so add
+ # We found this class in more than one place, so add
# in the name from there.
def add_path(path)
@path_names << path
@@ -37,10 +37,10 @@ class RDoc::RI::ClassEntry
if name =~ /^(.*?)-(c|i).yaml$/
external_name = $1
is_class_method = $2 == "c"
- internal_name = RiWriter.external_to_internal(external_name)
+ internal_name = RDoc::RI::Writer.external_to_internal(external_name)
list = is_class_method ? @class_methods : @instance_methods
path = File.join(dir, name)
- list << MethodEntry.new(path, internal_name, is_class_method, self)
+ list << RDoc::RI::MethodEntry.new(path, internal_name, is_class_method, self)
else
full_name = File.join(dir, name)
if File.directory?(full_name)
@@ -48,7 +48,7 @@ class RDoc::RI::ClassEntry
if inf_class
inf_class.add_path(full_name)
else
- inf_class = ClassEntry.new(full_name, name, self)
+ inf_class = RDoc::RI::ClassEntry.new(full_name, name, self)
@inferior_classes << inf_class
end
inf_class.load_from(full_name)
@@ -168,7 +168,7 @@ class RDoc::RI::MethodEntry
end
##
-# We represent everything know about all 'ri' files accessible to this program
+# We represent everything known about all 'ri' files accessible to this program
class RDoc::RI::Cache
@@ -185,4 +185,3 @@ class RDoc::RI::Cache
end
end
-
diff --git a/lib/rdoc/ri/descriptions.rb b/lib/rdoc/ri/descriptions.rb
index 0d8560323a..467b7de2a9 100644
--- a/lib/rdoc/ri/descriptions.rb
+++ b/lib/rdoc/ri/descriptions.rb
@@ -77,7 +77,9 @@ end
class RDoc::RI::ModuleDescription < RDoc::RI::Description
attr_accessor :class_methods
+ attr_accessor :class_method_extensions
attr_accessor :instance_methods
+ attr_accessor :instance_method_extensions
attr_accessor :attributes
attr_accessor :constants
attr_accessor :includes
@@ -148,6 +150,7 @@ class RDoc::RI::MethodDescription < RDoc::RI::Description
attr_accessor :aliases
attr_accessor :is_alias_for
attr_accessor :params
+ attr_accessor :source_path
end
diff --git a/lib/rdoc/ri/display.rb b/lib/rdoc/ri/display.rb
index 379cef11b3..05a7cf253d 100644
--- a/lib/rdoc/ri/display.rb
+++ b/lib/rdoc/ri/display.rb
@@ -1,5 +1,15 @@
require 'rdoc/ri'
+# readline support might not be present, so be careful
+# when requiring it.
+begin
+ require('readline')
+ require('abbrev')
+ CAN_USE_READLINE = true
+rescue
+ CAN_USE_READLINE = false
+end
+
##
# This is a kind of 'flag' module. If you want to write your own 'ri' display
# module (perhaps because you're writing an IDE), you write a class which
@@ -41,7 +51,7 @@ class RDoc::RI::DefaultDisplay
# Display information about +klass+. Fetches additional information from
# +ri_reader+ as necessary.
- def display_class_info(klass, ri_reader)
+ def display_class_info(klass)
page do
superclass = klass.superclass_string
@@ -61,17 +71,11 @@ class RDoc::RI::DefaultDisplay
@formatter.blankline
@formatter.display_heading("Includes:", 2, "")
incs = []
+
klass.includes.each do |inc|
- inc_desc = ri_reader.find_class_by_name(inc.name)
- if inc_desc
- str = inc.name + "("
- str << inc_desc.instance_methods.map{|m| m.name}.join(", ")
- str << ")"
- incs << str
- else
- incs << inc.name
- end
- end
+ incs << inc.name
+ end
+
@formatter.wrap(incs.sort.join(', '))
end
@@ -82,42 +86,19 @@ class RDoc::RI::DefaultDisplay
constants = klass.constants.sort_by { |constant| constant.name }
constants.each do |constant|
+ @formatter.wrap "#{constant.name} = #{constant.value}"
if constant.comment then
- @formatter.wrap "#{constant.name}:"
-
@formatter.indent do
@formatter.display_flow constant.comment
end
else
- @formatter.wrap constant.name
+ @formatter.break_to_newline
end
end
end
- class_data = [
- :class_methods,
- :class_method_extensions,
- :instance_methods,
- :instance_method_extensions,
- ]
-
- class_data.each do |data_type|
- data = klass.send data_type
-
- unless data.empty? then
- @formatter.blankline
-
- heading = data_type.to_s.split('_').join(' ').capitalize << ':'
- @formatter.display_heading heading, 2, ''
-
- data = data.map { |item| item.name }.sort.join ', '
- @formatter.wrap data
- end
- end
-
unless klass.attributes.empty? then
@formatter.blankline
-
@formatter.display_heading 'Attributes:', 2, ''
attributes = klass.attributes.sort_by { |attribute| attribute.name }
@@ -130,11 +111,119 @@ class RDoc::RI::DefaultDisplay
end
else
@formatter.wrap "#{attribute.name} (#{attribute.rw})"
+ @formatter.break_to_newline
end
end
end
+
+ return display_class_method_list(klass)
end
end
+
+ ##
+ # Given a Hash mapping a class' methods to method types (returned by
+ # display_class_method_list), this method allows the user to
+ # choose one of the methods.
+
+ def get_class_method_choice(method_map)
+ if CAN_USE_READLINE
+ # prepare abbreviations for tab completion
+ abbreviations = method_map.keys.abbrev
+ Readline.completion_proc = proc do |string|
+ abbreviations.values.uniq.grep(/^#{string}/)
+ end
+ end
+
+ @formatter.raw_print_line "\nEnter the method name you want.\n"
+ @formatter.raw_print_line "Class methods can be preceeded by '::' and instance methods by '#'.\n"
+
+ if CAN_USE_READLINE
+ @formatter.raw_print_line "You can use tab to autocomplete.\n"
+ @formatter.raw_print_line "Enter a blank line to exit.\n"
+
+ choice_string = Readline.readline(">> ").strip
+ else
+ @formatter.raw_print_line "Enter a blank line to exit.\n"
+ @formatter.raw_print_line ">> "
+ choice_string = $stdin.gets.strip
+ end
+
+ if choice_string == ''
+ return nil
+ else
+ class_or_instance = method_map[choice_string]
+
+ if class_or_instance
+ # If the user's choice is not preceeded by a '::' or a '#', figure
+ # out whether they want a class or an instance method and decorate
+ # the choice appropriately.
+ if(choice_string =~ /^[a-zA-Z]/)
+ if(class_or_instance == :class)
+ choice_string = "::#{choice_string}"
+ else
+ choice_string = "##{choice_string}"
+ end
+ end
+
+ return choice_string
+ else
+ @formatter.raw_print_line "No method matched '#{choice_string}'.\n"
+ return nil
+ end
+ end
+ end
+
+
+ ##
+ # Display methods on +klass+
+ # Returns a hash mapping method name to method contents (HACK?)
+
+ def display_class_method_list(klass)
+ method_map = {}
+
+ class_data = [
+ :class_methods,
+ :class_method_extensions,
+ :instance_methods,
+ :instance_method_extensions,
+ ]
+
+ class_data.each do |data_type|
+ data = klass.send data_type
+
+ unless data.nil? or data.empty? then
+ @formatter.blankline
+
+ heading = data_type.to_s.split('_').join(' ').capitalize << ':'
+ @formatter.display_heading heading, 2, ''
+
+ method_names = []
+ data.each do |item|
+ method_names << item.name
+
+ if(data_type == :class_methods ||
+ data_type == :class_method_extensions) then
+ method_map["::#{item.name}"] = :class
+ method_map[item.name] = :class
+ else
+ #
+ # Since we iterate over instance methods after class methods,
+ # an instance method always will overwrite the unqualified
+ # class method entry for a class method of the same name.
+ #
+ method_map["##{item.name}"] = :instance
+ method_map[item.name] = :instance
+ end
+ end
+ method_names.sort!
+
+ @formatter.wrap method_names.join(',')
+ end
+ end
+
+ method_map
+ end
+ private :display_class_method_list
##
# Display an Array of RDoc::Markup::Flow objects, +flow+.
@@ -172,10 +261,42 @@ class RDoc::RI::DefaultDisplay
def display_method_list(methods)
page do
@formatter.wrap "More than one method matched your request. You can refine your search by asking for information on one of:"
+ @formatter.blankline
+ methods.each do |method|
+ @formatter.raw_print_line "#{method.full_name} [#{method.source_path}]\n"
+ end
+ end
+ end
+
+ ##
+ # Display a list of +methods+ and allow the user to select one of them.
+
+ def display_method_list_choice(methods)
+ page do
+ @formatter.wrap "More than one method matched your request. Please choose one of the possible matches."
@formatter.blankline
- @formatter.wrap methods.map { |m| m.full_name }.join(", ")
+ methods.each_with_index do |method, index|
+ @formatter.raw_print_line "%3d %s [%s]\n" % [index + 1, method.full_name, method.source_path]
+ end
+
+ @formatter.raw_print_line ">> "
+
+ choice = $stdin.gets.strip!
+
+ if(choice == '')
+ return
+ end
+
+ choice = choice.to_i
+
+ if ((choice == 0) || (choice > methods.size)) then
+ @formatter.raw_print_line "Invalid choice!\n"
+ else
+ method = methods[choice - 1]
+ display_method_info(method)
+ end
end
end
@@ -198,10 +319,8 @@ class RDoc::RI::DefaultDisplay
@formatter.break_to_newline
end
- if method.source_path then
- @formatter.blankline
- @formatter.wrap("Extension from #{method.source_path}")
- end
+ @formatter.blankline
+ @formatter.wrap("From #{method.source_path}")
end
##
diff --git a/lib/rdoc/ri/driver.rb b/lib/rdoc/ri/driver.rb
index dfc5f2f98a..0c91232b70 100644
--- a/lib/rdoc/ri/driver.rb
+++ b/lib/rdoc/ri/driver.rb
@@ -11,29 +11,33 @@ require 'rdoc/markup/to_flow'
class RDoc::RI::Driver
- class Hash < ::Hash
- def self.convert(hash)
- hash = new.update hash
-
- hash.each do |key, value|
- hash[key] = case value
- when ::Hash then
- convert value
- when Array then
- value = value.map do |v|
- ::Hash === v ? convert(v) : v
- end
- value
- else
- value
- end
- end
-
- hash
- end
+ #
+ # This class offers both Hash and OpenStruct functionality.
+ # We convert from the Core Hash to this before calling any of
+ # the display methods, in order to give the display methods
+ # a cleaner API for accessing the data.
+ #
+ class OpenStructHash < Hash
+ #
+ # This method converts from a Hash to an OpenStructHash.
+ #
+ def self.convert(object)
+ case object
+ when Hash then
+ new_hash = new # Convert Hash -> OpenStructHash
+
+ object.each do |key, value|
+ new_hash[key] = convert(value)
+ end
- def method_missing method, *args
- self[method.to_s]
+ new_hash
+ when Array then
+ object.map do |element|
+ convert(element)
+ end
+ else
+ object
+ end
end
def merge_enums(other)
@@ -57,6 +61,10 @@ class RDoc::RI::Driver
end
end
end
+
+ def method_missing method, *args
+ self[method.to_s]
+ end
end
class Error < RDoc::RI::Error; end
@@ -69,25 +77,31 @@ class RDoc::RI::Driver
attr_accessor :homepath # :nodoc:
- def self.process_args(argv)
+ def self.default_options
options = {}
options[:use_stdout] = !$stdout.tty?
options[:width] = 72
options[:formatter] = RDoc::RI::Formatter.for 'plain'
- options[:list_classes] = false
- options[:list_names] = false
+ options[:interactive] = false
+ options[:use_cache] = true
+
+ # By default all standard paths are used.
+ options[:use_system] = true
+ options[:use_site] = true
+ options[:use_home] = true
+ options[:use_gems] = true
+ options[:extra_doc_dirs] = []
+
+ return options
+ end
- # By default all paths are used. If any of these are true, only those
- # directories are used.
- use_system = false
- use_site = false
- use_home = false
- use_gems = false
- doc_dirs = []
+ def self.process_args(argv)
+ options = default_options
opts = OptionParser.new do |opt|
opt.program_name = File.basename $0
opt.version = RDoc::VERSION
+ opt.release = nil
opt.summary_indent = ' ' * 4
directories = [
@@ -142,86 +156,114 @@ Options may also be set in the 'RI' environment variable.
opt.separator "Options:"
opt.separator nil
- opt.on("--classes", "-c",
- "Display the names of classes and modules we",
- "know about.") do |value|
- options[:list_classes] = value
+ opt.on("--fmt=FORMAT", "--format=FORMAT", "-f",
+ RDoc::RI::Formatter::FORMATTERS.keys,
+ "Format to use when displaying output:",
+ " #{RDoc::RI::Formatter.list}",
+ "Use 'bs' (backspace) with most pager",
+ "programs. To use ANSI, either disable the",
+ "pager or tell the pager to allow control",
+ "characters.") do |value|
+ options[:formatter] = RDoc::RI::Formatter.for value
end
opt.separator nil
opt.on("--doc-dir=DIRNAME", "-d", Array,
- "List of directories to search for",
- "documentation. If not specified, we search",
- "the standard rdoc/ri directories. May be",
- "repeated.") do |value|
+ "List of directories from which to source",
+ "documentation in addition to the standard",
+ "directories. May be repeated.") do |value|
value.each do |dir|
unless File.directory? dir then
raise OptionParser::InvalidArgument, "#{dir} is not a directory"
end
+
+ options[:extra_doc_dirs] << File.expand_path(dir)
end
+ end
+
+ opt.separator nil
- doc_dirs.concat value
+ opt.on("--[no-]use-cache",
+ "Whether or not to use ri's cache.",
+ "True by default.") do |value|
+ options[:use_cache] = value
end
opt.separator nil
- opt.on("--fmt=FORMAT", "--format=FORMAT", "-f",
- RDoc::RI::Formatter::FORMATTERS.keys,
- "Format to use when displaying output:",
- " #{RDoc::RI::Formatter.list}",
- "Use 'bs' (backspace) with most pager",
- "programs. To use ANSI, either disable the",
- "pager or tell the pager to allow control",
- "characters.") do |value|
- options[:formatter] = RDoc::RI::Formatter.for value
+ opt.on("--no-standard-docs",
+ "Do not include documentation from",
+ "the Ruby standard library, site_lib,",
+ "installed gems, or ~/.rdoc.",
+ "Equivalent to specifying",
+ "the options --no-system, --no-site, --no-gems,",
+ "and --no-home") do
+ options[:use_system] = false
+ options[:use_site] = false
+ options[:use_gems] = false
+ options[:use_home] = false
end
opt.separator nil
- unless RDoc::RI::Paths::GEMDIRS.empty? then
- opt.on("--[no-]gems",
- "Include documentation from RubyGems.") do |value|
- use_gems = value
- end
+ opt.on("--[no-]system",
+ "Include documentation from Ruby's standard",
+ "library. Defaults to true.") do |value|
+ options[:use_system] = value
end
opt.separator nil
- opt.on("--[no-]home",
- "Include documentation stored in ~/.rdoc.") do |value|
- use_home = value
+ opt.on("--[no-]site",
+ "Include documentation from libraries",
+ "installed in site_lib.",
+ "Defaults to true.") do |value|
+ options[:use_site] = value
end
opt.separator nil
- opt.on("--[no-]list-names", "-l",
- "List all the names known to RDoc, one per",
- "line.") do |value|
- options[:list_names] = value
+ opt.on("--[no-]gems",
+ "Include documentation from RubyGems.",
+ "Defaults to true.") do |value|
+ options[:use_gems] = value
end
opt.separator nil
- opt.on("--no-pager", "-T",
- "Send output directly to stdout.") do |value|
- options[:use_stdout] = !value
+ opt.on("--[no-]home",
+ "Include documentation stored in ~/.rdoc.",
+ "Defaults to true.") do |value|
+ options[:use_home] = value
end
opt.separator nil
- opt.on("--[no-]site",
- "Include documentation from libraries",
- "installed in site_lib.") do |value|
- use_site = value
+ opt.on("--list-doc-dirs",
+ "List the directories from which ri will",
+ "source documentation on stdout and exit.") do
+ options[:list_doc_dirs] = true
end
opt.separator nil
- opt.on("--[no-]system",
- "Include documentation from Ruby's standard",
- "library.") do |value|
- use_system = value
+ opt.on("--no-pager", "-T",
+ "Send output directly to stdout,",
+ "rather than to a pager.") do
+ options[:use_stdout] = true
+ end
+
+ opt.on("--interactive", "-i",
+ "This makes ri go into interactive mode.",
+ "When ri is in interactive mode it will",
+ "allow the user to disambiguate lists of",
+ "methods in case multiple methods match",
+ "against a method search string. It also",
+ "will allow the user to enter in a method",
+ "name (with auto-completion, if readline",
+ "is supported) when viewing a class.") do
+ options[:interactive] = true
end
opt.separator nil
@@ -238,10 +280,10 @@ Options may also be set in the 'RI' environment variable.
options[:names] = argv
- options[:path] = RDoc::RI::Paths.path(use_system, use_site, use_home,
- use_gems, *doc_dirs)
- options[:raw_path] = RDoc::RI::Paths.raw_path(use_system, use_site,
- use_home, use_gems, *doc_dirs)
+ options[:formatter] ||= RDoc::RI::Formatter.for('plain')
+ options[:use_stdout] ||= !$stdout.tty?
+ options[:use_stdout] ||= options[:interactive]
+ options[:width] ||= 72
options
@@ -258,22 +300,30 @@ Options may also be set in the 'RI' environment variable.
ri.run
end
- def initialize(options={})
- options[:formatter] ||= RDoc::RI::Formatter.for('plain')
- options[:use_stdout] ||= !$stdout.tty?
- options[:width] ||= 72
- @names = options[:names]
+ def initialize(initial_options={})
+ options = self.class.default_options.update(initial_options)
+ @names = options[:names]
@class_cache_name = 'classes'
- @all_dirs = RDoc::RI::Paths.path(true, true, true, true)
+
+ @doc_dirs = RDoc::RI::Paths.path(options[:use_system],
+ options[:use_site],
+ options[:use_home],
+ options[:use_gems],
+ options[:extra_doc_dirs])
+
@homepath = RDoc::RI::Paths.raw_path(false, false, true, false).first
@homepath = @homepath.sub(/\.rdoc/, '.ri')
- @sys_dirs = RDoc::RI::Paths.raw_path(true, false, false, false)
+ @sys_dir = RDoc::RI::Paths.raw_path(true, false, false, false).first
+ @list_doc_dirs = options[:list_doc_dirs]
FileUtils.mkdir_p cache_file_path unless File.directory? cache_file_path
+ @cache_doc_dirs_path = File.join cache_file_path, ".doc_dirs"
+ @use_cache = options[:use_cache]
@class_cache = nil
+ @interactive = options[:interactive]
@display = RDoc::RI::DefaultDisplay.new(options[:formatter],
options[:width],
options[:use_stdout])
@@ -282,30 +332,92 @@ Options may also be set in the 'RI' environment variable.
def class_cache
return @class_cache if @class_cache
- newest = map_dirs('created.rid', :all) do |f|
+ # Get the documentation directories used to make the cache in order to see
+ # whether the cache is valid for the current ri instantiation.
+ if(File.readable?(@cache_doc_dirs_path))
+ cache_doc_dirs = IO.read(@cache_doc_dirs_path).split("\n")
+ else
+ cache_doc_dirs = []
+ end
+
+ newest = map_dirs('created.rid') do |f|
File.mtime f if test ?f, f
end.max
+ # An up to date cache file must have been created more recently than
+ # the last modification of any of the documentation directories. It also
+ # must have been created with the same documentation directories
+ # as those from which ri currently is sourcing documentation.
up_to_date = (File.exist?(class_cache_file_path) and
- newest and newest < File.mtime(class_cache_file_path))
+ newest and newest < File.mtime(class_cache_file_path) and
+ (cache_doc_dirs == @doc_dirs))
+
+ if up_to_date and @use_cache then
+ open class_cache_file_path, 'rb' do |fp|
+ begin
+ @class_cache = Marshal.load fp.read
+ rescue
+ #
+ # This shouldn't be necessary, since the up_to_date logic above
+ # should force the cache to be recreated when a new version of
+ # rdoc is installed. This seems like a worthwhile enhancement
+ # to ri's robustness, however.
+ #
+ $stderr.puts "Error reading the class cache; recreating the class cache!"
+ @class_cache = create_class_cache
+ end
+ end
+ else
+ @class_cache = create_class_cache
+ end
+
+ @class_cache
+ end
- @class_cache = if up_to_date then
- load_cache_for @class_cache_name
- else
- class_cache = RDoc::RI::Driver::Hash.new
+ def create_class_cache
+ class_cache = OpenStructHash.new
- classes = map_dirs('**/cdesc*.yaml', :sys) { |f| Dir[f] }
- populate_class_cache class_cache, classes
+ if(@use_cache)
+ # Dump the documentation directories to a file in the cache, so that
+ # we only will use the cache for future instantiations with identical
+ # documentation directories.
+ File.open @cache_doc_dirs_path, "wb" do |fp|
+ fp << @doc_dirs.join("\n")
+ end
+ end
- classes = map_dirs('**/cdesc*.yaml') { |f| Dir[f] }
- warn "Updating class cache with #{classes.size} classes..."
+ classes = map_dirs('**/cdesc*.yaml') { |f| Dir[f] }
+ warn "Updating class cache with #{classes.size} classes..."
+ populate_class_cache class_cache, classes
- populate_class_cache class_cache, classes, true
- write_cache class_cache, class_cache_file_path
- end
+ write_cache class_cache, class_cache_file_path
- @class_cache = RDoc::RI::Driver::Hash.convert @class_cache
- @class_cache
+ class_cache
+ end
+
+ def populate_class_cache(class_cache, classes, extension = false)
+ classes.each do |cdesc|
+ desc = read_yaml cdesc
+ klassname = desc["full_name"]
+
+ unless class_cache.has_key? klassname then
+ desc["display_name"] = "Class"
+ desc["sources"] = [cdesc]
+ desc["instance_method_extensions"] = []
+ desc["class_method_extensions"] = []
+ class_cache[klassname] = desc
+ else
+ klass = class_cache[klassname]
+
+ if extension then
+ desc["instance_method_extensions"] = desc.delete "instance_methods"
+ desc["class_method_extensions"] = desc.delete "class_methods"
+ end
+
+ klass.merge_enums desc
+ klass["sources"] << cdesc
+ end
+ end
end
def class_cache_file_path
@@ -322,8 +434,11 @@ Options may also be set in the 'RI' environment variable.
def display_class(name)
klass = class_cache[name]
- klass = RDoc::RI::Driver::Hash.convert klass
- @display.display_class_info klass, class_cache
+ @display.display_class_info klass
+ end
+
+ def display_method(method)
+ @display.display_method_info method
end
def get_info_for(arg)
@@ -337,48 +452,74 @@ Options may also be set in the 'RI' environment variable.
cache = nil
if File.exist? path and
- File.mtime(path) >= File.mtime(class_cache_file_path) then
+ File.mtime(path) >= File.mtime(class_cache_file_path) and
+ @use_cache then
open path, 'rb' do |fp|
- cache = Marshal.load fp.read
+ begin
+ cache = Marshal.load fp.read
+ rescue
+ #
+ # The cache somehow is bad. Recreate the cache.
+ #
+ $stderr.puts "Error reading the cache for #{klassname}; recreating the cache!"
+ cache = create_cache_for klassname, path
+ end
end
else
- class_cache = nil
+ cache = create_cache_for klassname, path
+ end
- open class_cache_file_path, 'rb' do |fp|
- class_cache = Marshal.load fp.read
- end
+ cache
+ end
- klass = class_cache[klassname]
- return nil unless klass
-
- method_files = klass["sources"]
- cache = RDoc::RI::Driver::Hash.new
-
- sys_dir = @sys_dirs.first
- method_files.each do |f|
- system_file = f.index(sys_dir) == 0
- Dir[File.join(File.dirname(f), "*")].each do |yaml|
- next unless yaml =~ /yaml$/
- next if yaml =~ /cdesc-[^\/]+yaml$/
- method = read_yaml yaml
- name = method["full_name"]
- ext_path = f
- ext_path = "gem #{$1}" if f =~ %r%gems/[\d.]+/doc/([^/]+)%
- method["source_path"] = ext_path unless system_file
- cache[name] = RDoc::RI::Driver::Hash.convert method
+ def create_cache_for(klassname, path)
+ klass = class_cache[klassname]
+ return nil unless klass
+
+ method_files = klass["sources"]
+ cache = OpenStructHash.new
+
+ method_files.each do |f|
+ system_file = f.index(@sys_dir) == 0
+ Dir[File.join(File.dirname(f), "*")].each do |yaml|
+ next unless yaml =~ /yaml$/
+ next if yaml =~ /cdesc-[^\/]+yaml$/
+
+ method = read_yaml yaml
+
+ if system_file then
+ method["source_path"] = "Ruby #{RDoc::RI::Paths::VERSION}"
+ else
+ if(f =~ %r%gems/[\d.]+/doc/([^/]+)%) then
+ ext_path = "gem #{$1}"
+ else
+ ext_path = f
+ end
+
+ method["source_path"] = ext_path
end
- end
- write_cache cache, path
+ name = method["full_name"]
+ cache[name] = method
+ end
end
- RDoc::RI::Driver::Hash.convert cache
+ write_cache cache, path
end
##
# Finds the next ancestor of +orig_klass+ after +klass+.
def lookup_ancestor(klass, orig_klass)
+ # This is a bit hacky, but ri will go into an infinite
+ # loop otherwise, since Object has an Object ancestor
+ # for some reason. Depending on the documentation state, I've seen
+ # Kernel as an ancestor of Object and not as an ancestor of Object.
+ if ((orig_klass == "Object") &&
+ ((klass == "Kernel") || (klass == "Object")))
+ return nil
+ end
+
cache = class_cache[orig_klass]
return nil unless cache
@@ -386,10 +527,13 @@ Options may also be set in the 'RI' environment variable.
ancestors = [orig_klass]
ancestors.push(*cache.includes.map { |inc| inc['name'] })
ancestors << cache.superclass
+
+ ancestor_index = ancestors.index(klass)
- ancestor = ancestors[ancestors.index(klass) + 1]
-
- return ancestor if ancestor
+ if ancestor_index
+ ancestor = ancestors[ancestors.index(klass) + 1]
+ return ancestor if ancestor
+ end
lookup_ancestor klass, cache.superclass
end
@@ -406,18 +550,8 @@ Options may also be set in the 'RI' environment variable.
method
end
- def map_dirs(file_name, system=false)
- dirs = if system == :all then
- @all_dirs
- else
- if system then
- @sys_dirs
- else
- @all_dirs - @sys_dirs
- end
- end
-
- dirs.map { |dir| yield File.join(dir, file_name) }.flatten.compact
+ def map_dirs(file_name)
+ @doc_dirs.map { |dir| yield File.join(dir, file_name) }.flatten.compact
end
##
@@ -436,83 +570,66 @@ Options may also be set in the 'RI' environment variable.
[klass, meth]
end
- def populate_class_cache(class_cache, classes, extension = false)
- classes.each do |cdesc|
- desc = read_yaml cdesc
- klassname = desc["full_name"]
-
- unless class_cache.has_key? klassname then
- desc["display_name"] = "Class"
- desc["sources"] = [cdesc]
- desc["instance_method_extensions"] = []
- desc["class_method_extensions"] = []
- class_cache[klassname] = desc
- else
- klass = class_cache[klassname]
-
- if extension then
- desc["instance_method_extensions"] = desc.delete "instance_methods"
- desc["class_method_extensions"] = desc.delete "class_methods"
- end
-
- klass = RDoc::RI::Driver::Hash.convert klass
-
- klass.merge_enums desc
- klass["sources"] << cdesc
- end
- end
- end
-
def read_yaml(path)
data = File.read path
+
+ # Necessary to be backward-compatible with documentation generated
+ # by earliar RDoc versions.
data = data.gsub(/ \!ruby\/(object|struct):(RDoc::RI|RI).*/, '')
data = data.gsub(/ \!ruby\/(object|struct):SM::(\S+)/,
' !ruby/\1:RDoc::Markup::\2')
- YAML.load data
+ OpenStructHash.convert(YAML.load(data))
end
def run
- if @names.empty? then
+ if(@list_doc_dirs)
+ puts @doc_dirs.join("\n")
+ elsif @names.empty? then
@display.list_known_classes class_cache.keys.sort
else
@names.each do |name|
- case name
- when /::|\#|\./ then
- if class_cache.key? name then
- display_class name
- else
- klass, = parse_name name
+ if class_cache.key? name then
+ method_map = display_class name
+ if(@interactive)
+ method_name = @display.get_class_method_choice(method_map)
+
+ if(method_name != nil)
+ method = lookup_method "#{name}#{method_name}", name
+ display_method method
+ end
+ end
+ elsif name =~ /::|\#|\./ then
+ klass, = parse_name name
- orig_klass = klass
- orig_name = name
+ orig_klass = klass
+ orig_name = name
- until klass == 'Kernel' do
- method = lookup_method name, klass
+ loop do
+ method = lookup_method name, klass
- break method if method
+ break method if method
- ancestor = lookup_ancestor klass, orig_klass
+ ancestor = lookup_ancestor klass, orig_klass
- break unless ancestor
+ break unless ancestor
- name = name.sub klass, ancestor
- klass = ancestor
- end
+ name = name.sub klass, ancestor
+ klass = ancestor
+ end
- raise NotFoundError, orig_name unless method
+ raise NotFoundError, orig_name unless method
- @display.display_method_info method
- end
+ display_method method
else
- if class_cache.key? name then
- display_class name
- else
- methods = select_methods(/^#{name}/)
+ methods = select_methods(/#{name}/)
- if methods.size == 0
- raise NotFoundError, name
- elsif methods.size == 1
- @display.display_method_info methods.first
+ if methods.size == 0
+ raise NotFoundError, name
+ elsif methods.size == 1
+ display_method methods[0]
+ else
+ if(@interactive)
+ @display.display_method_list_choice methods
else
@display.display_method_list methods
end
@@ -540,12 +657,13 @@ Options may also be set in the 'RI' environment variable.
end
def write_cache(cache, path)
- File.open path, "wb" do |cache_file|
- Marshal.dump cache, cache_file
+ if(@use_cache)
+ File.open path, "wb" do |cache_file|
+ Marshal.dump cache, cache_file
+ end
end
cache
end
end
-
diff --git a/lib/rdoc/ri/formatter.rb b/lib/rdoc/ri/formatter.rb
index 0a0c3f7380..933882abc4 100644
--- a/lib/rdoc/ri/formatter.rb
+++ b/lib/rdoc/ri/formatter.rb
@@ -93,7 +93,7 @@ class RDoc::RI::Formatter
end
def raw_print_line(txt)
- @output.puts txt
+ @output.print txt
end
##
diff --git a/lib/rdoc/ri/paths.rb b/lib/rdoc/ri/paths.rb
index b4b6c64925..2f72b9dfd5 100644
--- a/lib/rdoc/ri/paths.rb
+++ b/lib/rdoc/ri/paths.rb
@@ -26,9 +26,9 @@ module RDoc::RI::Paths
DOC_DIR = "doc/rdoc"
- version = RbConfig::CONFIG['ruby_version']
+ VERSION = RbConfig::CONFIG['ruby_version']
- base = File.join(RbConfig::CONFIG['datadir'], "ri", version)
+ base = File.join(RbConfig::CONFIG['datadir'], "ri", VERSION)
SYSDIR = File.join(base, "system")
SITEDIR = File.join(base, "site")
homedir = ENV['HOME'] || ENV['USERPROFILE'] || ENV['HOMEPATH']
@@ -39,9 +39,6 @@ module RDoc::RI::Paths
HOMEDIR = nil
end
- # This is the search path for 'ri'
- PATH = [ SYSDIR, SITEDIR, HOMEDIR ].find_all {|p| p && File.directory?(p)}
-
begin
require 'rubygems' unless defined?(Gem) and defined?(Gem::Enable) and
Gem::Enable
@@ -67,7 +64,6 @@ module RDoc::RI::Paths
end
GEMDIRS = ri_paths.map { |k,v| v.last }.sort
- GEMDIRS.each { |dir| PATH << dir }
rescue LoadError
GEMDIRS = []
end
@@ -85,9 +81,6 @@ module RDoc::RI::Paths
# found.
def self.raw_path(use_system, use_site, use_home, use_gems, *extra_dirs)
- return PATH unless use_system or use_site or use_home or use_gems or
- not extra_dirs.empty?
-
path = []
path << extra_dirs unless extra_dirs.empty?
path << SYSDIR if use_system
@@ -97,6 +90,4 @@ module RDoc::RI::Paths
return path.flatten.compact
end
-
end
-
diff --git a/lib/rdoc/ri/reader.rb b/lib/rdoc/ri/reader.rb
index 986bb75954..de3c8d9afa 100644
--- a/lib/rdoc/ri/reader.rb
+++ b/lib/rdoc/ri/reader.rb
@@ -45,7 +45,7 @@ class RDoc::RI::Reader
def get_method(method_entry)
path = method_entry.path_name
- File.open(path) { |f| RI::Description.deserialize(f) }
+ File.open(path) { |f| RDoc::RI::Description.deserialize(f) }
end
##
@@ -54,8 +54,8 @@ class RDoc::RI::Reader
def get_class(class_entry)
result = nil
for path in class_entry.path_names
- path = RiWriter.class_desc_path(path, class_entry)
- desc = File.open(path) {|f| RI::Description.deserialize(f) }
+ path = RDoc::RI::Writer.class_desc_path(path, class_entry)
+ desc = File.open(path) {|f| RDoc::RI::Description.deserialize(f) }
if result
result.merge_in(desc)
else
diff --git a/lib/rdoc/ri/util.rb b/lib/rdoc/ri/util.rb
index 34277f2594..4e91eb978d 100644
--- a/lib/rdoc/ri/util.rb
+++ b/lib/rdoc/ri/util.rb
@@ -1,7 +1,5 @@
require 'rdoc/ri'
-class RDoc::RI::Error < RuntimeError; end
-
##
# Break argument into its constituent class or module names, an
# optional method type, and a method name