summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rwxr-xr-xbin/ri47
-rw-r--r--lib/rdoc.rb18
-rw-r--r--lib/rdoc/rdoc.rb16
-rw-r--r--lib/rdoc/ri.rb4
-rw-r--r--lib/rdoc/ri/ri_display.rb131
-rw-r--r--lib/rdoc/ri/ri_driver.rb495
-rw-r--r--lib/rdoc/ri/ri_formatter.rb69
-rw-r--r--lib/rdoc/ri/ri_options.rb319
-rw-r--r--lib/rdoc/ri/ri_paths.rb4
-rw-r--r--lib/rdoc/template.rb3
11 files changed, 531 insertions, 579 deletions
diff --git a/ChangeLog b/ChangeLog
index 333777e..8bfc5d8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+Tue Jan 8 18:05:35 2008 Eric Hodel <drbrain@segment7.net>
+
+ * bin/ri, lib/rdoc/ri/*: Replace with Ryan Davis' cached ri.
+
Tue Jan 8 15:47:43 2008 NAKAMURA Usaku <usa@ruby-lang.org>
* enc/utf{16,32}_{be,le}.c: use &OnigEncodingName(*) instead of
diff --git a/bin/ri b/bin/ri
index ae793f6..e563521 100755
--- a/bin/ri
+++ b/bin/ri
@@ -1,49 +1,6 @@
-#!/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 unambiguous form. If a name
-# _is_ ambiguous, all valid options will be listed.
-#
-# The form '.' method matches either class or instance methods, while
-# #method matches only instance and ::method matches only class methods.
-#
-#
-# == Installing Documentation
-#
-# 'ri' uses a database of documentation built by the RDoc utility.
-#
-# So, how do you install this documentation on your system?
-# It depends on how you installed Ruby.
-#
-# <em>If you installed Ruby from source files</em> (that is, if it some point
-# you typed 'make' during the process :), you can install the RDoc
-# documentation yourself. Just go back to the place where you have
-# your Ruby source and type
-#
-# make install-doc
-#
-# You'll probably need to do this as a superuser, as the documentation
-# is installed in the Ruby target tree (normally somewhere under
-# <tt>/usr/local</tt>.
-#
-# <em>If you installed Ruby from a binary distribution</em> (perhaps
-# using a one-click installer, or using some other packaging system),
-# then the team that produced the package probably forgot to package
-# the documentation as well. Contact them, and see if they can add
-# it to the next release.
-#
-
+#!/usr//bin/env ruby
require 'rdoc/ri/ri_driver'
-######################################################################
-
-ri = RiDriver.new
-ri.process_args
+RDoc::RI::RiDriver.run ARGV
diff --git a/lib/rdoc.rb b/lib/rdoc.rb
new file mode 100644
index 0000000..0d2dc26
--- /dev/null
+++ b/lib/rdoc.rb
@@ -0,0 +1,18 @@
+##
+# :include: rdoc/README
+
+module RDoc
+
+ ##
+ # RDoc version you are using
+
+ VERSION = "2.0.0"
+
+ ##
+ # Name of the dotfile that contains the description of files to be processed
+ # in the current directory
+
+ DOT_DOC_FILENAME = ".document"
+
+end
+
diff --git a/lib/rdoc/rdoc.rb b/lib/rdoc/rdoc.rb
index b135951..57f8fe0 100644
--- a/lib/rdoc/rdoc.rb
+++ b/lib/rdoc/rdoc.rb
@@ -1,3 +1,5 @@
+require 'rdoc'
+
require 'rdoc/parsers/parse_rb.rb'
require 'rdoc/parsers/parse_c.rb'
require 'rdoc/parsers/parse_f95.rb'
@@ -11,23 +13,9 @@ require 'find'
require 'fileutils'
require 'time'
-##
-# :include: README
-
module RDoc
##
- # RDoc version you are using
-
- VERSION = "2.0.0"
-
- ##
- # Name of the dotfile that contains the description of files to be processed
- # in the current directory
-
- DOT_DOC_FILENAME = ".document"
-
- ##
# Simple stats collector
class Stats
diff --git a/lib/rdoc/ri.rb b/lib/rdoc/ri.rb
new file mode 100644
index 0000000..08cc4a1
--- /dev/null
+++ b/lib/rdoc/ri.rb
@@ -0,0 +1,4 @@
+require 'rdoc'
+
+module RDoc::RI; end
+
diff --git a/lib/rdoc/ri/ri_display.rb b/lib/rdoc/ri/ri_display.rb
index 8e5d07e..efc8928 100644
--- a/lib/rdoc/ri/ri_display.rb
+++ b/lib/rdoc/ri/ri_display.rb
@@ -1,13 +1,8 @@
-require 'rdoc/ri/ri_util'
-require 'rdoc/ri/ri_formatter'
-require 'rdoc/ri/ri_options'
-
-
# This is a kind of 'flag' module. If you want to write your
# own 'ri' display module (perhaps because you'r writing
# an IDE or somesuch beast), you simply write a class
# which implements the various 'display' methods in 'DefaultDisplay',
-# and include the 'RiDisplay' module in that class.
+# and include the 'RiDisplay' module in that class.
#
# To access your class from the command line, you can do
#
@@ -34,18 +29,17 @@ end
# actual presentation
#
-class DefaultDisplay
+class DefaultDisplay
include RiDisplay
- def initialize(options)
- @options = options
- @formatter = @options.formatter.new(@options, " ")
- end
-
-
+ def initialize(formatter, width, use_stdout)
+ @use_stdout = use_stdout
+ @formatter = formatter.new width, " "
+ end
+
######################################################################
-
+
def display_usage
page do
RI::Options::OptionList.usage(short_form=true)
@@ -54,7 +48,7 @@ class DefaultDisplay
######################################################################
-
+
def display_method_info(method)
page do
@formatter.draw_line(method.full_name)
@@ -64,31 +58,31 @@ class DefaultDisplay
if method.aliases && !method.aliases.empty?
@formatter.blankline
aka = "(also known as "
- aka << method.aliases.map {|a| a.name }.join(", ")
+ aka << method.aliases.map {|a| a.name }.join(", ")
aka << ")"
@formatter.wrap(aka)
end
end
end
-
+
######################################################################
-
+
def display_class_info(klass, ri_reader)
- page do
+ page do
superclass = klass.superclass_string
-
+
if superclass
superclass = " < " + superclass
else
superclass = ""
end
-
+
@formatter.draw_line(klass.display_name + ": " +
klass.full_name + superclass)
-
+
display_flow(klass.comment)
- @formatter.draw_line
-
+ @formatter.draw_line
+
unless klass.includes.empty?
@formatter.blankline
@formatter.display_heading("Includes:", 2, "")
@@ -106,7 +100,7 @@ class DefaultDisplay
end
@formatter.wrap(incs.sort.join(', '))
end
-
+
unless klass.constants.empty?
@formatter.blankline
@formatter.display_heading("Constants:", 2, "")
@@ -114,23 +108,35 @@ class DefaultDisplay
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.wrap(c.value,
@formatter.indent+((c.name+":").ljust(len)))
- end
+ end
end
-
+
unless klass.class_methods.empty?
@formatter.blankline
@formatter.display_heading("Class methods:", 2, "")
@formatter.wrap(klass.class_methods.map{|m| m.name}.sort.join(', '))
end
-
+
+ unless klass.class_method_extensions.empty?
+ @formatter.blankline
+ @formatter.display_heading("Class Method Extensions:", 2, "")
+ @formatter.wrap(klass.class_method_extensions.map{|m| m.name}.sort.join(', '))
+ end
+
unless klass.instance_methods.empty?
@formatter.blankline
@formatter.display_heading("Instance methods:", 2, "")
@formatter.wrap(klass.instance_methods.map{|m| m.name}.sort.join(', '))
end
-
+
+ unless klass.instance_method_extensions.empty?
+ @formatter.blankline
+ @formatter.display_heading("Instance Method Extensions:", 2, "")
+ @formatter.wrap(klass.instance_method_extensions.map{|m| m.name}.sort.join(', '))
+ end
+
unless klass.attributes.empty?
@formatter.blankline
@formatter.wrap("Attributes:", "")
@@ -138,11 +144,11 @@ class DefaultDisplay
end
end
end
-
+
######################################################################
-
+
# Display a list of method names
-
+
def display_method_list(methods)
page do
puts "More than one method matched your request. You can refine"
@@ -150,9 +156,9 @@ class DefaultDisplay
@formatter.wrap(methods.map {|m| m.full_name} .join(", "))
end
end
-
+
######################################################################
-
+
def display_class_list(namespaces)
page do
puts "More than one class or module matched your request. You can refine"
@@ -160,14 +166,14 @@ class DefaultDisplay
@formatter.wrap(namespaces.map {|m| m.full_name}.join(", "))
end
end
-
+
######################################################################
def list_known_classes(classes)
if classes.empty?
warn_no_database
else
- page do
+ page do
@formatter.draw_line("Known classes and modules")
@formatter.blankline
@formatter.wrap(classes.sort.join(", "))
@@ -181,7 +187,7 @@ class DefaultDisplay
if names.empty?
warn_no_database
else
- page do
+ page do
names.each {|n| @formatter.raw_print_line(n)}
end
end
@@ -194,34 +200,36 @@ class DefaultDisplay
######################################################################
def page
- return yield unless pager = setup_pager
- begin
- save_stdout = STDOUT.clone
- STDOUT.reopen(pager)
+ if pager = setup_pager then
+ begin
+ orig_stdout = $stdout
+ $stdout = pager
+ yield
+ ensure
+ $stdout = orig_stdout
+ pager.close
+ end
+ else
yield
- ensure
- STDOUT.reopen(save_stdout)
- save_stdout.close
- pager.close
end
+ rescue Errno::EPIPE
end
######################################################################
def setup_pager
- unless @options.use_stdout
+ unless @use_stdout then
for pager in [ ENV['PAGER'], "less", "more", 'pager' ].compact.uniq
return IO.popen(pager, "w") rescue nil
end
- @options.use_stdout = true
+ @use_stdout = true
nil
end
end
######################################################################
-
- def display_params(method)
+ def display_params(method)
params = method.params
if params[0,1] == "("
@@ -232,13 +240,16 @@ class DefaultDisplay
end
end
params.split(/\n/).each do |p|
- @formatter.wrap(p)
+ @formatter.wrap(p)
@formatter.break_to_newline
end
+ if method.source_path then
+ @formatter.blankline
+ @formatter.wrap("Extension from #{method.source_path}")
+ end
end
-
######################################################################
-
+
def display_flow(flow)
if !flow || flow.empty?
@formatter.wrap("(no description...)")
@@ -248,9 +259,17 @@ class DefaultDisplay
end
######################################################################
-
+
def warn_no_database
- puts "Before using ri, you need to generate documentation"
- puts "using 'rdoc' with the --ri option"
+ puts "No ri data found"
+ puts
+ puts "If you've installed Ruby yourself, you need to generate documentation using:"
+ puts
+ puts " make install-doc"
+ puts
+ puts "from the same place you ran `make` to build ruby."
+ puts
+ puts "If you installed Ruby from a packaging system, then you may need to"
+ puts "install an additional package, or ask the packager to enable ri generation."
end
end # class RiDisplay
diff --git a/lib/rdoc/ri/ri_driver.rb b/lib/rdoc/ri/ri_driver.rb
index a00f20e..9f07db8 100644
--- a/lib/rdoc/ri/ri_driver.rb
+++ b/lib/rdoc/ri/ri_driver.rb
@@ -1,143 +1,424 @@
+require 'optparse'
+require 'yaml'
+
+require 'rdoc/ri'
require 'rdoc/ri/ri_paths'
-require 'rdoc/usage'
-require 'rdoc/ri/ri_cache'
-require 'rdoc/ri/ri_util'
-require 'rdoc/ri/ri_reader'
require 'rdoc/ri/ri_formatter'
-require 'rdoc/ri/ri_options'
+require 'rdoc/ri/ri_display'
+require 'fileutils'
+require 'rdoc/markup/simple_markup'
+require 'rdoc/markup/simple_markup/to_flow'
+
+class RDoc::RI::RiDriver
+
+ def self.process_args(argv)
+ options = {}
+ options[:use_stdout] = !$stdout.tty?
+ options[:width] = 72
+ options[:formatter] = RI::TextFormatter.for 'plain'
+ options[:list_classes] = false
+ options[:list_names] = false
+
+ # 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 = []
+
+ opts = OptionParser.new do |opt|
+ opt.program_name = File.basename $0
+ opt.version = RDoc::VERSION
+ opt.summary_indent = ' ' * 4
+
+ directories = [
+ RI::Paths::SYSDIR,
+ RI::Paths::SITEDIR,
+ RI::Paths::HOMEDIR
+ ]
+
+ if RI::Paths::GEMDIRS then
+ Gem.path.each do |dir|
+ directories << "#{dir}/doc/*/ri"
+ end
+ end
+
+ opt.banner = <<-EOT
+Usage: #{opt.program_name} [options] [names...]
+
+Where name can be:
+
+ Class | Class::method | Class#method | Class.method | method
+
+All class names may be abbreviated to their minimum unambiguous form. If a name
+is ambiguous, all valid options will be listed.
+
+The form '.' method matches either class or instance methods, while
+#method matches only instance and ::method matches only class methods.
+
+For example:
+
+ #{opt.program_name} Fil
+ #{opt.program_name} File
+ #{opt.program_name} File.new
+ #{opt.program_name} zip
+
+Note that shell quoting may be required for method names containing
+punctuation:
+
+ #{opt.program_name} 'Array.[]'
+ #{opt.program_name} compact\\!
+By default ri searches for documentation in the following directories:
-######################################################################
+ #{directories.join "\n "}
-class RiDriver
+Specifying the --system, --site, --home, --gems or --doc-dir options will
+limit ri to searching only the specified directories.
- def initialize
- @options = RI::Options.instance
+Options may also be set in the 'RI' environment variable.
+ EOT
- args = ARGV
- if ENV["RI"]
- args = ENV["RI"].split.concat(ARGV)
+ opt.separator nil
+ 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
+ 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|
+ value.each do |dir|
+ unless File.directory? dir then
+ raise OptionParser::InvalidArgument, "#{dir} is not a directory"
+ end
+ end
+
+ doc_dirs.concat value
+ end
+
+ opt.separator nil
+
+ opt.on("--fmt=FORMAT", "--format=FORMAT", "-f",
+ RI::TextFormatter.list.split(', '), # HACK
+ "Format to use when displaying output:",
+ " #{RI::TextFormatter.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] = RI::TextFormatter.for value
+ end
+
+ opt.separator nil
+
+ if RI::Paths::GEMDIRS then
+ opt.on("--[no-]gems",
+ "Include documentation from RubyGems.") do |value|
+ use_gems = value
+ end
+ end
+
+ opt.separator nil
+
+ opt.on("--[no-]home",
+ "Include documentation stored in ~/.rdoc.") do |value|
+ use_home = 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
+ end
+
+ opt.separator nil
+
+ opt.on("--no-pager", "-T",
+ "Send output directly to stdout.") do |value|
+ options[:use_stdout] = !value
+ end
+
+ opt.separator nil
+
+ opt.on("--[no-]site",
+ "Include documentation from libraries",
+ "installed in site_lib.") do |value|
+ use_site = value
+ end
+
+ opt.separator nil
+
+ opt.on("--[no-]system",
+ "Include documentation from Ruby's standard",
+ "library.") do |value|
+ use_system = value
+ end
+
+ opt.separator nil
+
+ opt.on("--width=WIDTH", "-w", OptionParser::DecimalInteger,
+ "Set the width of the output.") do |value|
+ options[:width] = value
+ end
end
- @options.parse(args)
+ argv = ENV['RI'].to_s.split.concat argv
+
+ opts.parse! argv
+
+ options[:names] = argv
+
+ options[:path] = RI::Paths.path(use_system, use_site, use_home, use_gems,
+ *doc_dirs)
+ options[:raw_path] = RI::Paths.raw_path(use_system, use_site, use_home,
+ use_gems, *doc_dirs)
- path = @options.path
- report_missing_documentation @options.raw_path if path.empty?
+ options
- @ri_reader = RI::RiReader.new(RI::RiCache.new(path))
- @display = @options.displayer
+ rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e
+ puts opts
+ puts
+ puts e
+ exit 1
end
-
- # Couldn't find documentation in +path+, so tell the user what to do
- def report_missing_documentation(path)
- STDERR.puts "No ri documentation found in:"
- path.each do |d|
- STDERR.puts " #{d}"
- end
- STDERR.puts "\nWas rdoc run to create documentation?\n\n"
- RDoc::usage("Installing Documentation")
+ def self.run(argv = ARGV)
+ options = process_args argv
+ ri = new options
+ ri.run
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
- method = @ri_reader.get_method(methods[0])
- @display.display_method_info(method)
- else
- entries = methods.find_all {|m| m.name == requested_method_name}
- if entries.size == 1
- method = @ri_reader.get_method(entries[0])
- @display.display_method_info(method)
- else
- @display.display_method_list(methods)
- end
- end
+
+ def initialize(options)
+ @names = options[:names]
+
+ @class_cache_name = 'classes'
+ @all_dirs = RI::Paths.path(true, true, true, true)
+ @homepath = RI::Paths.raw_path(false, false, true, false).first
+ @homepath = @homepath.sub(/\.rdoc/, '.ri')
+ @sys_dirs = RI::Paths.raw_path(true, false, false, false)
+
+ FileUtils.mkdir_p cache_file_path unless File.directory? cache_file_path
+
+ @class_cache = nil
+
+ @display = DefaultDisplay.new(options[:formatter], options[:width],
+ options[:use_stdout])
end
-
- ######################################################################
-
- def report_class_stuff(namespaces)
- if namespaces.size == 1
- klass = @ri_reader.get_class(namespaces[0])
- @display.display_class_info(klass, @ri_reader)
- else
-# entries = namespaces.find_all {|m| m.full_name == requested_class_name}
-# if entries.size == 1
-# klass = @ri_reader.get_class(entries[0])
-# @display.display_class_info(klass, @ri_reader)
-# else
- @display.display_class_list(namespaces)
-# end
- end
+
+ def class_cache
+ return @class_cache if @class_cache
+
+ newest = map_dirs('created.rid', :all) do |f|
+ File.mtime f if test ?f, f
+ end.max
+
+ up_to_date = (File.exist?(class_cache_file_path) and
+ newest < File.mtime(class_cache_file_path))
+
+ @class_cache = if up_to_date then
+ load_cache_for @class_cache_name
+ else
+ class_cache = {}
+
+ classes = map_dirs('**/cdesc*.yaml', :sys) { |f| Dir[f] }
+ populate_class_cache class_cache, classes
+
+ classes = map_dirs('**/cdesc*.yaml') { |f| Dir[f] }
+ warn "Updating class cache with #{classes.size} classes..."
+
+ populate_class_cache class_cache, classes, true
+ write_cache class_cache, class_cache_file_path
+ end
end
-
- ######################################################################
-
-
- def get_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}")
+ def class_cache_file_path
+ File.join cache_file_path, @class_cache_name
+ end
+
+ def cache_file_for(klassname)
+ File.join cache_file_path, klassname
+ end
+
+ def cache_file_path
+ File.join @homepath, 'cache'
+ end
+
+ def display_class(name)
+ klass = class_cache[name]
+ @display.display_class_info klass, class_cache
+ end
+
+ def load_cache_for(klassname)
+ path = cache_file_for klassname
+
+ if File.exist? path and
+ File.mtime(path) >= File.mtime(class_cache_file_path) then
+ File.open path, 'rb' do |fp|
+ Marshal.load fp
end
+ else
+ class_cache = nil
+
+ File.open class_cache_file_path, 'rb' do |fp|
+ class_cache = Marshal.load fp
+ end
+
+ klass = class_cache[klassname]
+ return nil unless klass
+
+ method_files = klass["sources"]
+ cache = {}
+
+ 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] = method
+ end
+ end
+
+ write_cache cache, path
end
+ end
- # at this point, if we have multiple possible namespaces, but one
- # is an exact match for our requested class, prune down to just it
+ 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
- full_class_name = desc.full_class_name
- entries = namespaces.find_all {|m| m.full_name == full_class_name}
- namespaces = entries if entries.size == 1
+ dirs.map { |dir| yield File.join(dir, file_name) }.flatten.compact
+ end
- if desc.method_name.nil?
- report_class_stuff(namespaces)
- else
- methods = @ri_reader.find_methods(desc.method_name,
- desc.is_class_method,
- namespaces)
+ def populate_class_cache(class_cache, classes, extension = false)
+ classes.each do |cdesc|
+ desc = read_yaml cdesc
+ klassname = desc["full_name"]
- if methods.empty?
- raise RiError.new("Nothing known about #{arg}")
+ 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
- report_method_stuff(desc.method_name, methods)
+ 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 read_yaml(path)
+ YAML.load File.read(path).gsub(/ \!ruby\/(object|struct):RI.*/, '')
+ end
- def process_args
- if @options.list_classes
- classes = @ri_reader.full_class_names
- @display.list_known_classes(classes)
- elsif @options.list_names
- names = @ri_reader.all_names
- @display.list_known_names(names)
+ def run
+ if @names.empty? then
+ @display.list_known_classes select_classes
else
- if ARGV.size.zero?
- @display.display_usage
- else
- begin
- ARGV.each do |arg|
- get_info_for(arg)
+ @names.each do |name|
+ case name
+ when /::|\#|\./ then
+ if class_cache.key? name then
+ display_class name
+ else
+ klass, meth = name.split(/::|\#|\./)
+ cache = load_cache_for klass
+ # HACK Does not support F.n
+ abort "Nothing known about #{name}" unless cache
+ method = cache[name.gsub(/\./, '#')]
+ abort "Nothing known about #{name}" unless method
+ @display.display_method_info method
+ end
+ else
+ if class_cache.key? name then
+ display_class name
+ else
+ @display.list_known_classes select_classes(/^#{name}/)
end
- rescue RiError => e
- STDERR.puts(e.message)
- exit(1)
end
end
end
end
+
+ def select_classes(pattern = nil)
+ classes = class_cache.keys.sort
+ classes = classes.grep pattern if pattern
+ classes
+ end
+
+ def write_cache(cache, path)
+ File.open path, "wb" do |cache_file|
+ Marshal.dump cache, cache_file
+ end
+
+ cache
+ end
+
+ # Couldn't find documentation in +path+, so tell the user what to do
+
+ def report_missing_documentation(path)
+ STDERR.puts "No ri documentation found in:"
+ path.each do |d|
+ STDERR.puts " #{d}"
+ end
+ STDERR.puts "\nWas rdoc run to create documentation?\n\n"
+ RDoc::usage("Installing Documentation")
+ end
+
+end
+
+class Hash
+ def method_missing method, *args
+ self[method.to_s]
+ end
+
+ def merge_enums(other)
+ other.each do |k,v|
+ if self[k] then
+ case v
+ when Array then
+ self[k] += v
+ when Hash then
+ self[k].merge! v
+ else
+ # do nothing
+ end
+ else
+ self[k] = v
+ end
+ end
+ end
+end
-end # class RiDriver
diff --git a/lib/rdoc/ri/ri_formatter.rb b/lib/rdoc/ri/ri_formatter.rb
index 34eb561..d317170 100644
--- a/lib/rdoc/ri/ri_formatter.rb
+++ b/lib/rdoc/ri/ri_formatter.rb
@@ -2,29 +2,28 @@ module RI
class TextFormatter
attr_reader :indent
-
- def initialize(options, indent)
- @options = options
- @width = options.width
+
+ def initialize(width, indent)
+ @width = width
@indent = indent
end
-
-
+
+
######################################################################
-
+
def draw_line(label=nil)
len = @width
len -= (label.size+1) if label
print "-"*len
if label
print(" ")
- bold_print(label)
+ bold_print(label)
end
puts
end
-
+
######################################################################
-
+
def wrap(txt, prefix=@indent, linelen=@width)
return unless txt && !txt.empty?
work = conv_markup(txt)
@@ -51,7 +50,7 @@ module RI
def blankline
puts
end
-
+
######################################################################
# called when we want to ensure a nbew 'wrap' starts on a newline
@@ -60,7 +59,7 @@ module RI
def break_to_newline
end
-
+
######################################################################
def bold_print(txt)
@@ -82,7 +81,7 @@ module RI
gsub(/&lt;/, '<').
gsub(/&quot;/, '"').
gsub(/&amp;/, '&')
-
+
end
# convert markup into display form
@@ -99,7 +98,7 @@ module RI
def display_list(list)
case list.type
- when SM::ListBase::BULLET
+ when SM::ListBase::BULLET
prefixer = proc { |ignored| @indent + "* " }
when SM::ListBase::NUMBER,
@@ -116,7 +115,7 @@ module RI
start = start.succ
res
end
-
+
when SM::ListBase::LABELED
prefixer = proc do |li|
li.label
@@ -156,7 +155,7 @@ module RI
when SM::Flow::P, SM::Flow::LI
wrap(conv_html(item.body), prefix)
blankline
-
+
when SM::Flow::LIST
display_list(item)
@@ -194,7 +193,7 @@ module RI
puts text.upcase
puts ul
# puts
-
+
when 2
ul = "-" * text.length
puts
@@ -215,7 +214,7 @@ module RI
def strip_attributes(txt)
tokens = txt.split(%r{(</?(?:b|code|em|i|tt)>)})
- text = []
+ text = []
attributes = 0
tokens.each do |tok|
case tok
@@ -230,16 +229,16 @@ module RI
end
-
-
+
+
######################################################################
# Handle text with attributes. We're a base class: there are
# different presentation classes (one, for example, uses overstrikes
# to handle bold and underlining, while another using ANSI escape
# sequences
-
+
class AttributeFormatter < TextFormatter
-
+
BOLD = 1
ITALIC = 2
CODE = 4
@@ -263,7 +262,7 @@ module RI
end
end
-
+
class AttributeString
attr_reader :txt
@@ -363,7 +362,7 @@ module RI
##################################################
-
+
# This formatter generates overstrike-style formatting, which
# works with pagers such as man and less.
@@ -395,7 +394,7 @@ module RI
end
##################################################
-
+
# This formatter uses ANSI escape sequences
# to colorize stuff
# works with pages such as man and less.
@@ -441,7 +440,7 @@ module RI
print strip_attributes(text)
puts heading[1]
end
-
+
private
ATTR_MAP = {
@@ -462,7 +461,7 @@ module RI
end
##################################################
-
+
# This formatter uses HTML.
class HtmlFormatter < AttributeFormatter
@@ -508,13 +507,13 @@ module RI
tag("h#{level}") { text }
puts
end
-
+
######################################################################
def display_list(list)
case list.type
- when SM::ListBase::BULLET
+ when SM::ListBase::BULLET
list_type = "ul"
prefixer = proc { |ignored| "<li>" }
@@ -523,7 +522,7 @@ module RI
SM::ListBase::LOWERALPHA
list_type = "ol"
prefixer = proc { |ignored| "<li>" }
-
+
when SM::ListBase::LABELED
list_type = "dl"
prefixer = proc do |li|
@@ -554,7 +553,9 @@ module RI
def display_verbatim_flow_item(item, prefix=@indent)
print("<pre>")
- puts item.body
+ item.body.split(/\n/).each do |line|
+ puts conv_html(line)
+ end
puts("</pre>")
end
@@ -602,7 +603,7 @@ module RI
end
##################################################
-
+
# This formatter reduces extra lines for a simpler output.
# It improves way output looks for tools like IRC bots.
@@ -621,7 +622,7 @@ module RI
def draw_line(label=nil)
unless label.nil? then
- bold_print(label)
+ bold_print(label)
puts
end
end
@@ -656,7 +657,7 @@ module RI
"plain" => TextFormatter,
"simple" => SimpleFormatter,
}
-
+
def TextFormatter.list
FORMATTERS.keys.sort.join(", ")
end
diff --git a/lib/rdoc/ri/ri_options.rb b/lib/rdoc/ri/ri_options.rb
deleted file mode 100644
index 179ef96..0000000
--- a/lib/rdoc/ri/ri_options.rb
+++ /dev/null
@@ -1,319 +0,0 @@
-# We handle the parsing of options, and subsequently as a singleton
-# object to be queried for option values
-
-module RI
-
- require 'rdoc/ri/ri_paths'
- require 'rdoc/ri/ri_display'
-
- VERSION_STRING = "ri v1.0.1 - 20041108"
-
- class Options
-
- require 'singleton'
- require 'getoptlong'
-
- include Singleton
-
- # No not use a pager. Writable, because ri sets it if it
- # can't find a pager
- attr_accessor :use_stdout
-
- # should we just display a class list and exit
- attr_reader :list_classes
-
- # should we display a list of all names
- attr_reader :list_names
-
- # The width of the output line
- attr_reader :width
-
- # the formatting we apply to the output
- attr_reader :formatter
-
- # the directory we search for original documentation
- attr_reader :doc_dir
-
- module OptionList
-
- OPTION_LIST = [
- [ "--help", "-h", nil,
- "you're looking at it" ],
-
- [ "--classes", "-c", nil,
- "Display the names of classes and modules we\n" +
- "know about"],
-
- [ "--doc-dir", "-d", "<dirname>",
- "A directory to search for documentation. If not\n" +
- "specified, we search the standard rdoc/ri directories.\n" +
- "May be repeated."],
-
- [ "--system", nil, nil,
- "Include documentation from Ruby's standard library:\n " +
- RI::Paths::SYSDIR ],
-
- [ "--site", nil, nil,
- "Include documentation from libraries installed in site_lib:\n " +
- RI::Paths::SITEDIR ],
-
- [ "--home", nil, nil,
- "Include documentation stored in ~/.rdoc:\n " +
- (RI::Paths::HOMEDIR || "No ~/.rdoc found") ],
-
- [ "--gems", nil, nil,
- "Include documentation from RubyGems:\n" +
- (RI::Paths::GEMDIRS ?
- Gem.path.map { |dir| " #{dir}/doc/*/ri" }.join("\n") :
- "No Rubygems ri found.") ],
-
- [ "--format", "-f", "<name>",
- "Format to use when displaying output:\n" +
- " " + RI::TextFormatter.list + "\n" +
- "Use 'bs' (backspace) with most pager programs.\n" +
- "To use ANSI, either also use the -T option, or\n" +
- "tell your pager to allow control characters\n" +
- "(for example using the -R option to less)"],
-
- [ "--list-names", "-l", nil,
- "List all the names known to RDoc, one per line"
- ],
-
- [ "--no-pager", "-T", nil,
- "Send output directly to stdout."
- ],
-
- [ "--width", "-w", "output width",
- "Set the width of the output" ],
-
- [ "--version", "-v", nil,
- "Display the version of ri"
- ],
-
- ]
-
- def OptionList.options
- OPTION_LIST.map do |long, short, arg,|
- option = []
- option << long
- option << short unless short.nil?
- option << (arg ? GetoptLong::REQUIRED_ARGUMENT :
- GetoptLong::NO_ARGUMENT)
- option
- end
- end
-
-
- def OptionList.strip_output(text)
- text =~ /^\s+/
- leading_spaces = $&
- text.gsub!(/^#{leading_spaces}/, '')
- $stdout.puts text
- end
-
-
- # Show an error and exit
-
- def OptionList.error(msg)
- $stderr.puts
- $stderr.puts msg
- name = File.basename $PROGRAM_NAME
- $stderr.puts "\nFor help on options, try '#{name} --help'\n\n"
- exit 1
- end
-
- # Show usage and exit
-
- def OptionList.usage(short_form=false)
-
- puts
- puts(RI::VERSION_STRING)
- puts
-
- name = File.basename($0)
-
- directories = [
- RI::Paths::SYSDIR,
- RI::Paths::SITEDIR,
- RI::Paths::HOMEDIR
- ]
-
- if RI::Paths::GEMDIRS then
- Gem.path.each do |dir|
- directories << "#{dir}/doc/*/ri"
- end
- end
-
- directories = directories.join("\n ")
-
- OptionList.strip_output(<<-EOT)
- Usage:
-
- #{name} [options] [names...]
-
- Display information on Ruby classes, modules, and methods.
- Give the names of classes or methods to see their documentation.
- Partial names may be given: if the names match more than
- one entity, a list will be shown, otherwise details on
- that entity will be displayed.
-
- Nested classes and modules can be specified using the normal
- Name::Name notation, and instance methods can be distinguished
- from class methods using "." (or "#") instead of "::".
-
- For example:
-
- #{name} File
- #{name} File.new
- #{name} F.n
- #{name} zip
-
- Note that shell quoting may be required for method names
- containing punctuation:
-
- #{name} 'Array.[]'
- #{name} compact\\!
-
- By default ri searches for documentation in the following
- directories:
-
- #{directories}
-
- Specifying the --system, --site, --home, --gems or --doc-dir
- options will limit ri to searching only the specified
- directories.
-
- EOT
-
- if short_form
- puts "For help on options, type '#{name} -h'"
- puts "For a list of classes I know about, type '#{name} -c'"
- else
- puts "Options:\n\n"
- OPTION_LIST.each do|long, short, arg, desc|
- opt = ''
- opt << (short ? sprintf("%15s", "#{long}, #{short}") :
- sprintf("%15s", long))
- if arg
- opt << " " << arg
- end
- print opt
- desc = desc.split("\n")
- if opt.size < 17
- print " "*(18-opt.size)
- puts desc.shift
- else
- puts
- end
- desc.each do |line|
- puts(" "*18 + line)
- end
- puts
- end
- puts "Options may also be passed in the 'RI' environment variable"
- exit 0
- end
- end
- end
-
- # Show the version and exit
- def show_version
- puts VERSION_STRING
- exit(0)
- end
-
- def initialize
- @use_stdout = !STDOUT.tty?
- @width = 72
- @formatter = RI::TextFormatter.for("plain")
- @list_classes = false
- @list_names = false
-
- # 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 = []
- end
-
- # Parse command line options.
-
- def parse(args)
-
- old_argv = ARGV.dup
-
- ARGV.replace(args)
-
- begin
-
- go = GetoptLong.new(*OptionList.options)
- go.quiet = true
-
- go.each do |opt, arg|
- case opt
- when "--help" then OptionList.usage
- when "--version" then show_version
- when "--list-names" then @list_names = true
- when "--no-pager" then @use_stdout = true
- when "--classes" then @list_classes = true
-
- when "--system" then @use_system = true
- when "--site" then @use_site = true
- when "--home" then @use_home = true
- when "--gems" then @use_gems = true
-
- when "--doc-dir"
- if File.directory?(arg)
- @doc_dirs << arg
- else
- $stderr.puts "Invalid directory: #{arg}"
- exit 1
- end
-
- when "--format"
- @formatter = RI::TextFormatter.for(arg)
- unless @formatter
- $stderr.print "Invalid formatter (should be one of "
- $stderr.puts RI::TextFormatter.list + ")"
- exit 1
- end
- when "--width"
- begin
- @width = Integer(arg)
- rescue
- $stderr.puts "Invalid width: '#{arg}'"
- exit 1
- end
- end
- end
-
- rescue GetoptLong::InvalidOption, GetoptLong::MissingArgument => error
- OptionList.error(error.message)
-
- end
- end
-
- # Return the selected documentation directories.
-
- def path
- RI::Paths.path(@use_system, @use_site, @use_home, @use_gems, *@doc_dirs)
- end
-
- def raw_path
- RI::Paths.raw_path(@use_system, @use_site, @use_home, @use_gems,
- *@doc_dirs)
- end
-
- # Return an instance of the displayer (the thing that actually writes
- # the information). This allows us to load in new displayer classes
- # at runtime (for example to help with IDE integration)
-
- def displayer
- ::RiDisplay.new(self)
- end
- end
-
-end
-
diff --git a/lib/rdoc/ri/ri_paths.rb b/lib/rdoc/ri/ri_paths.rb
index 6f58151..0957216 100644
--- a/lib/rdoc/ri/ri_paths.rb
+++ b/lib/rdoc/ri/ri_paths.rb
@@ -23,7 +23,7 @@ module RI
#:stopdoc:
require 'rbconfig'
-
+
DOC_DIR = "doc/rdoc"
version = RbConfig::CONFIG['ruby_version']
@@ -42,7 +42,7 @@ module RI
# This is the search path for 'ri'
PATH = [ SYSDIR, SITEDIR, HOMEDIR ].find_all {|p| p && File.directory?(p)}
- require 'rubygems'
+ require 'rubygems' unless defined?(Gem) and Gem::Enable
# HACK dup'd from Gem.latest_partials and friends
all_paths = []
diff --git a/lib/rdoc/template.rb b/lib/rdoc/template.rb
index 09fe1e8..368a553 100644
--- a/lib/rdoc/template.rb
+++ b/lib/rdoc/template.rb
@@ -48,9 +48,8 @@ class RDoc::TemplatePage
# Process the template using +values+, writing the result to +io+.
def write_html_on(io, values)
- template_include = ""
-
b = binding
+ template_include = ""
@templates.reverse_each do |template|
template_include = ERB.new(template).result b