summaryrefslogtreecommitdiff
path: root/ruby_1_8_6/lib/rdoc/ri
diff options
context:
space:
mode:
Diffstat (limited to 'ruby_1_8_6/lib/rdoc/ri')
-rw-r--r--ruby_1_8_6/lib/rdoc/ri/ri_cache.rb187
-rw-r--r--ruby_1_8_6/lib/rdoc/ri/ri_descriptions.rb154
-rw-r--r--ruby_1_8_6/lib/rdoc/ri/ri_display.rb255
-rw-r--r--ruby_1_8_6/lib/rdoc/ri/ri_driver.rb143
-rw-r--r--ruby_1_8_6/lib/rdoc/ri/ri_formatter.rb672
-rw-r--r--ruby_1_8_6/lib/rdoc/ri/ri_options.rb313
-rw-r--r--ruby_1_8_6/lib/rdoc/ri/ri_paths.rb80
-rw-r--r--ruby_1_8_6/lib/rdoc/ri/ri_reader.rb100
-rw-r--r--ruby_1_8_6/lib/rdoc/ri/ri_util.rb75
-rw-r--r--ruby_1_8_6/lib/rdoc/ri/ri_writer.rb62
10 files changed, 2041 insertions, 0 deletions
diff --git a/ruby_1_8_6/lib/rdoc/ri/ri_cache.rb b/ruby_1_8_6/lib/rdoc/ri/ri_cache.rb
new file mode 100644
index 0000000000..1844ac969e
--- /dev/null
+++ b/ruby_1_8_6/lib/rdoc/ri/ri_cache.rb
@@ -0,0 +1,187 @@
+module RI
+
+ class ClassEntry
+
+ attr_reader :name
+ attr_reader :path_names
+
+ def initialize(path_name, name, in_class)
+ @path_names = [ path_name ]
+ @name = name
+ @in_class = in_class
+ @class_methods = []
+ @instance_methods = []
+ @inferior_classes = []
+ end
+
+ # We found this class in more tha one place, so add
+ # in the name from there.
+ def add_path(path)
+ @path_names << path
+ end
+
+ # read in our methods and any classes
+ # and modules in our namespace. Methods are
+ # stored in files called name-c|i.yaml,
+ # where the 'name' portion is the external
+ # form of the method name and the c|i is a class|instance
+ # flag
+
+ def load_from(dir)
+ Dir.foreach(dir) do |name|
+ next if name =~ /^\./
+
+ # convert from external to internal form, and
+ # extract the instance/class flag
+
+ if name =~ /^(.*?)-(c|i).yaml$/
+ external_name = $1
+ is_class_method = $2 == "c"
+ internal_name = RiWriter.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)
+ else
+ full_name = File.join(dir, name)
+ if File.directory?(full_name)
+ inf_class = @inferior_classes.find {|c| c.name == name }
+ if inf_class
+ inf_class.add_path(full_name)
+ else
+ inf_class = ClassEntry.new(full_name, name, self)
+ @inferior_classes << inf_class
+ end
+ inf_class.load_from(full_name)
+ end
+ end
+ end
+ end
+
+ # Return a list of any classes or modules that we contain
+ # that match a given string
+
+ def contained_modules_matching(name)
+ @inferior_classes.find_all {|c| c.name[name]}
+ end
+
+ def classes_and_modules
+ @inferior_classes
+ end
+
+ # Return an exact match to a particular name
+ def contained_class_named(name)
+ @inferior_classes.find {|c| c.name == name}
+ end
+
+ # return the list of local methods matching name
+ # We're split into two because we need distinct behavior
+ # when called from the _toplevel_
+ def methods_matching(name, is_class_method)
+ local_methods_matching(name, is_class_method)
+ end
+
+ # Find methods matching 'name' in ourselves and in
+ # any classes we contain
+ def recursively_find_methods_matching(name, is_class_method)
+ res = local_methods_matching(name, is_class_method)
+ @inferior_classes.each do |c|
+ res.concat(c.recursively_find_methods_matching(name, is_class_method))
+ end
+ res
+ end
+
+
+ # Return our full name
+ def full_name
+ res = @in_class.full_name
+ res << "::" unless res.empty?
+ res << @name
+ end
+
+ # Return a list of all out method names
+ def all_method_names
+ res = @class_methods.map {|m| m.full_name }
+ @instance_methods.each {|m| res << m.full_name}
+ res
+ end
+
+ private
+
+ # Return a list of all our methods matching a given string.
+ # Is +is_class_methods+ if 'nil', we don't care if the method
+ # is a class method or not, otherwise we only return
+ # those methods that match
+ def local_methods_matching(name, is_class_method)
+
+ list = case is_class_method
+ when nil then @class_methods + @instance_methods
+ when true then @class_methods
+ when false then @instance_methods
+ else fail "Unknown is_class_method: #{is_class_method.inspect}"
+ end
+
+ list.find_all {|m| m.name; m.name[name]}
+ end
+ end
+
+ # A TopLevelEntry is like a class entry, but when asked to search
+ # for methods searches all classes, not just itself
+
+ class TopLevelEntry < ClassEntry
+ def methods_matching(name, is_class_method)
+ res = recursively_find_methods_matching(name, is_class_method)
+ end
+
+ def full_name
+ ""
+ end
+
+ def module_named(name)
+
+ end
+
+ end
+
+ class MethodEntry
+ attr_reader :name
+ attr_reader :path_name
+
+ def initialize(path_name, name, is_class_method, in_class)
+ @path_name = path_name
+ @name = name
+ @is_class_method = is_class_method
+ @in_class = in_class
+ end
+
+ def full_name
+ res = @in_class.full_name
+ unless res.empty?
+ if @is_class_method
+ res << "::"
+ else
+ res << "#"
+ end
+ end
+ res << @name
+ end
+ end
+
+ # We represent everything know about all 'ri' files
+ # accessible to this program
+
+ class RiCache
+
+ attr_reader :toplevel
+
+ def initialize(dirs)
+ # At the top level we have a dummy module holding the
+ # overall namespace
+ @toplevel = TopLevelEntry.new('', '::', nil)
+
+ dirs.each do |dir|
+ @toplevel.load_from(dir)
+ end
+ end
+
+ end
+end
diff --git a/ruby_1_8_6/lib/rdoc/ri/ri_descriptions.rb b/ruby_1_8_6/lib/rdoc/ri/ri_descriptions.rb
new file mode 100644
index 0000000000..e5ea9f2fbf
--- /dev/null
+++ b/ruby_1_8_6/lib/rdoc/ri/ri_descriptions.rb
@@ -0,0 +1,154 @@
+require 'yaml'
+require 'rdoc/markup/simple_markup/fragments'
+
+# Descriptions are created by RDoc (in ri_generator) and
+# written out in serialized form into the documentation
+# tree. ri then reads these to generate the documentation
+
+module RI
+ class NamedThing
+ attr_reader :name
+ def initialize(name)
+ @name = name
+ end
+ def <=>(other)
+ @name <=> other.name
+ end
+
+ def hash
+ @name.hash
+ end
+
+ def eql?(other)
+ @name.eql?(other)
+ end
+ end
+
+# Alias = Struct.new(:old_name, :new_name)
+
+ class AliasName < NamedThing
+ end
+
+ class Attribute < NamedThing
+ attr_reader :rw, :comment
+ def initialize(name, rw, comment)
+ super(name)
+ @rw = rw
+ @comment = comment
+ end
+ end
+
+ class Constant < NamedThing
+ attr_reader :value, :comment
+ def initialize(name, value, comment)
+ super(name)
+ @value = value
+ @comment = comment
+ end
+ end
+
+ class IncludedModule < NamedThing
+ end
+
+
+ class MethodSummary < NamedThing
+ def initialize(name="")
+ super
+ end
+ end
+
+
+
+ class Description
+ attr_accessor :name
+ attr_accessor :full_name
+ attr_accessor :comment
+
+ def serialize
+ self.to_yaml
+ end
+
+ def Description.deserialize(from)
+ YAML.load(from)
+ end
+
+ def <=>(other)
+ @name <=> other.name
+ end
+ end
+
+ class ModuleDescription < Description
+
+ attr_accessor :class_methods
+ attr_accessor :instance_methods
+ attr_accessor :attributes
+ attr_accessor :constants
+ attr_accessor :includes
+
+ # merge in another class desscription into this one
+ def merge_in(old)
+ merge(@class_methods, old.class_methods)
+ merge(@instance_methods, old.instance_methods)
+ merge(@attributes, old.attributes)
+ merge(@constants, old.constants)
+ merge(@includes, old.includes)
+ if @comment.nil? || @comment.empty?
+ @comment = old.comment
+ else
+ unless old.comment.nil? or old.comment.empty? then
+ @comment << SM::Flow::RULE.new
+ @comment.concat old.comment
+ end
+ end
+ end
+
+ def display_name
+ "Module"
+ end
+
+ # the 'ClassDescription' subclass overrides this
+ # to format up the name of a parent
+ def superclass_string
+ nil
+ end
+
+ private
+
+ def merge(into, from)
+ names = {}
+ into.each {|i| names[i.name] = i }
+ from.each {|i| names[i.name] = i }
+ into.replace(names.keys.sort.map {|n| names[n]})
+ end
+ end
+
+ class ClassDescription < ModuleDescription
+ attr_accessor :superclass
+
+ def display_name
+ "Class"
+ end
+
+ def superclass_string
+ if @superclass && @superclass != "Object"
+ @superclass
+ else
+ nil
+ end
+ end
+ end
+
+
+ class MethodDescription < Description
+
+ attr_accessor :is_class_method
+ attr_accessor :visibility
+ attr_accessor :block_params
+ attr_accessor :is_singleton
+ attr_accessor :aliases
+ attr_accessor :is_alias_for
+ attr_accessor :params
+
+ end
+
+end
diff --git a/ruby_1_8_6/lib/rdoc/ri/ri_display.rb b/ruby_1_8_6/lib/rdoc/ri/ri_display.rb
new file mode 100644
index 0000000000..67962fc2c1
--- /dev/null
+++ b/ruby_1_8_6/lib/rdoc/ri/ri_display.rb
@@ -0,0 +1,255 @@
+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.
+#
+# To access your class from the command line, you can do
+#
+# ruby -r <your source file> ../ri ....
+#
+# If folks _really_ want to do this from the command line,
+# I'll build an option in
+
+module RiDisplay
+ @@display_class = nil
+
+ def RiDisplay.append_features(display_class)
+ @@display_class = display_class
+ end
+
+ def RiDisplay.new(*args)
+ @@display_class.new(*args)
+ end
+end
+
+######################################################################
+#
+# A paging display module. Uses the ri_formatter class to do the
+# actual presentation
+#
+
+class DefaultDisplay
+
+ include RiDisplay
+
+ def initialize(options)
+ @options = options
+ @formatter = @options.formatter.new(@options, " ")
+ end
+
+
+ ######################################################################
+
+ def display_usage
+ page do
+ RI::Options::OptionList.usage(short_form=true)
+ end
+ end
+
+
+ ######################################################################
+
+ def display_method_info(method)
+ page do
+ @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
+ end
+
+ ######################################################################
+
+ def display_class_info(klass, ri_reader)
+ 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
+
+ unless klass.includes.empty?
+ @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
+ @formatter.wrap(incs.sort.join(', '))
+ end
+
+ unless klass.constants.empty?
+ @formatter.blankline
+ @formatter.display_heading("Constants:", 2, "")
+ 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.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.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.attributes.empty?
+ @formatter.blankline
+ @formatter.wrap("Attributes:", "")
+ @formatter.wrap(klass.attributes.map{|a| a.name}.sort.join(', '))
+ 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"
+ puts "your search by asking for information on one of:\n\n"
+ @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"
+ puts "your search by asking for information on one of:\n\n"
+ @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
+ @formatter.draw_line("Known classes and modules")
+ @formatter.blankline
+ @formatter.wrap(classes.sort.join(", "))
+ end
+ end
+ end
+
+ ######################################################################
+
+ def list_known_names(names)
+ if names.empty?
+ warn_no_database
+ else
+ page do
+ names.each {|n| @formatter.raw_print_line(n)}
+ end
+ end
+ end
+
+ ######################################################################
+
+ private
+
+ ######################################################################
+
+ def page
+ return yield unless pager = setup_pager
+ begin
+ save_stdout = STDOUT.clone
+ STDOUT.reopen(pager)
+ yield
+ ensure
+ STDOUT.reopen(save_stdout)
+ save_stdout.close
+ pager.close
+ end
+ end
+
+ ######################################################################
+
+ def setup_pager
+ unless @options.use_stdout
+ for pager in [ ENV['PAGER'], "less", "more", 'pager' ].compact.uniq
+ return IO.popen(pager, "w") rescue nil
+ end
+ @options.use_stdout = true
+ nil
+ end
+ 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
+ params.split(/\n/).each do |p|
+ @formatter.wrap(p)
+ @formatter.break_to_newline
+ end
+ end
+ ######################################################################
+
+ def display_flow(flow)
+ if !flow || flow.empty?
+ @formatter.wrap("(no description...)")
+ else
+ @formatter.display_flow(flow)
+ end
+ end
+
+ ######################################################################
+
+ def warn_no_database
+ puts "Before using ri, you need to generate documentation"
+ puts "using 'rdoc' with the --ri option"
+ end
+end # class RiDisplay
diff --git a/ruby_1_8_6/lib/rdoc/ri/ri_driver.rb b/ruby_1_8_6/lib/rdoc/ri/ri_driver.rb
new file mode 100644
index 0000000000..a00f20ee3b
--- /dev/null
+++ b/ruby_1_8_6/lib/rdoc/ri/ri_driver.rb
@@ -0,0 +1,143 @@
+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'
+
+
+######################################################################
+
+class RiDriver
+
+ def initialize
+ @options = RI::Options.instance
+
+ args = ARGV
+ if ENV["RI"]
+ args = ENV["RI"].split.concat(ARGV)
+ end
+
+ @options.parse(args)
+
+ path = @options.path
+ report_missing_documentation @options.raw_path if path.empty?
+
+ @ri_reader = RI::RiReader.new(RI::RiCache.new(path))
+ @display = @options.displayer
+ 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
+
+ ######################################################################
+
+ # 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
+ 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
+ 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}")
+ 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
+
+ full_class_name = desc.full_class_name
+ entries = namespaces.find_all {|m| m.full_name == full_class_name}
+ namespaces = entries if entries.size == 1
+
+ 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
+
+ ######################################################################
+
+ 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)
+ else
+ if ARGV.size.zero?
+ @display.display_usage
+ else
+ begin
+ ARGV.each do |arg|
+ get_info_for(arg)
+ end
+ rescue RiError => e
+ STDERR.puts(e.message)
+ exit(1)
+ end
+ end
+ end
+ end
+
+end # class RiDriver
diff --git a/ruby_1_8_6/lib/rdoc/ri/ri_formatter.rb b/ruby_1_8_6/lib/rdoc/ri/ri_formatter.rb
new file mode 100644
index 0000000000..34eb561ca3
--- /dev/null
+++ b/ruby_1_8_6/lib/rdoc/ri/ri_formatter.rb
@@ -0,0 +1,672 @@
+module RI
+ class TextFormatter
+
+ attr_reader :indent
+
+ def initialize(options, indent)
+ @options = options
+ @width = options.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)
+ end
+ puts
+ end
+
+ ######################################################################
+
+ def wrap(txt, prefix=@indent, linelen=@width)
+ return unless txt && !txt.empty?
+ work = conv_markup(txt)
+ textLen = linelen - prefix.length
+ patt = Regexp.new("^(.{0,#{textLen}})[ \n]")
+ next_prefix = prefix.tr("^ ", " ")
+
+ res = []
+
+ while work.length > textLen
+ if work =~ patt
+ res << $1
+ work.slice!(0, $&.length)
+ else
+ res << work.slice!(0, textLen)
+ end
+ end
+ res << work if work.length.nonzero?
+ puts(prefix + res.join("\n" + next_prefix))
+ end
+
+ ######################################################################
+
+ def blankline
+ puts
+ end
+
+ ######################################################################
+
+ # called when we want to ensure a nbew 'wrap' starts on a newline
+ # Only needed for HtmlFormatter, because the rest do their
+ # own line breaking
+
+ def break_to_newline
+ end
+
+ ######################################################################
+
+ def bold_print(txt)
+ print txt
+ end
+
+ ######################################################################
+
+ def raw_print_line(txt)
+ puts txt
+ end
+
+ ######################################################################
+
+ # convert HTML entities back to ASCII
+ def conv_html(txt)
+ txt.
+ gsub(/&gt;/, '>').
+ gsub(/&lt;/, '<').
+ gsub(/&quot;/, '"').
+ gsub(/&amp;/, '&')
+
+ end
+
+ # convert markup into display form
+ def conv_markup(txt)
+ txt.
+ gsub(%r{<tt>(.*?)</tt>}) { "+#$1+" } .
+ gsub(%r{<code>(.*?)</code>}) { "+#$1+" } .
+ gsub(%r{<b>(.*?)</b>}) { "*#$1*" } .
+ gsub(%r{<em>(.*?)</em>}) { "_#$1_" }
+ end
+
+ ######################################################################
+
+ def display_list(list)
+ case list.type
+
+ when SM::ListBase::BULLET
+ prefixer = proc { |ignored| @indent + "* " }
+
+ when SM::ListBase::NUMBER,
+ SM::ListBase::UPPERALPHA,
+ SM::ListBase::LOWERALPHA
+
+ start = case list.type
+ when SM::ListBase::NUMBER then 1
+ when SM::ListBase::UPPERALPHA then 'A'
+ when SM::ListBase::LOWERALPHA then 'a'
+ end
+ prefixer = proc do |ignored|
+ res = @indent + "#{start}.".ljust(4)
+ start = start.succ
+ res
+ end
+
+ when SM::ListBase::LABELED
+ prefixer = proc do |li|
+ li.label
+ end
+
+ when SM::ListBase::NOTE
+ longest = 0
+ list.contents.each do |item|
+ if item.kind_of?(SM::Flow::LI) && item.label.length > longest
+ longest = item.label.length
+ end
+ end
+
+ prefixer = proc do |li|
+ @indent + li.label.ljust(longest+1)
+ end
+
+ else
+ fail "unknown list type"
+
+ end
+
+ list.contents.each do |item|
+ if item.kind_of? SM::Flow::LI
+ prefix = prefixer.call(item)
+ display_flow_item(item, prefix)
+ else
+ display_flow_item(item)
+ end
+ end
+ end
+
+ ######################################################################
+
+ def display_flow_item(item, prefix=@indent)
+ case item
+ when SM::Flow::P, SM::Flow::LI
+ wrap(conv_html(item.body), prefix)
+ blankline
+
+ when SM::Flow::LIST
+ display_list(item)
+
+ when SM::Flow::VERB
+ display_verbatim_flow_item(item, @indent)
+
+ when SM::Flow::H
+ display_heading(conv_html(item.text), item.level, @indent)
+
+ when SM::Flow::RULE
+ draw_line
+
+ else
+ fail "Unknown flow element: #{item.class}"
+ end
+ end
+
+ ######################################################################
+
+ def display_verbatim_flow_item(item, prefix=@indent)
+ item.body.split(/\n/).each do |line|
+ print @indent, conv_html(line), "\n"
+ end
+ blankline
+ end
+
+ ######################################################################
+
+ def display_heading(text, level, indent)
+ text = strip_attributes(text)
+ case level
+ when 1
+ ul = "=" * text.length
+ puts
+ puts text.upcase
+ puts ul
+# puts
+
+ when 2
+ ul = "-" * text.length
+ puts
+ puts text
+ puts ul
+# puts
+ else
+ print indent, text, "\n"
+ end
+ end
+
+
+ def display_flow(flow)
+ flow.each do |f|
+ display_flow_item(f)
+ end
+ end
+
+ def strip_attributes(txt)
+ tokens = txt.split(%r{(</?(?:b|code|em|i|tt)>)})
+ text = []
+ attributes = 0
+ tokens.each do |tok|
+ case tok
+ when %r{^</(\w+)>$}, %r{^<(\w+)>$}
+ ;
+ else
+ text << tok
+ end
+ end
+ text.join
+ end
+
+
+ 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
+
+ ATTR_MAP = {
+ "b" => BOLD,
+ "code" => CODE,
+ "em" => ITALIC,
+ "i" => ITALIC,
+ "tt" => CODE
+ }
+
+ # TODO: struct?
+ class AttrChar
+ attr_reader :char
+ attr_reader :attr
+
+ def initialize(char, attr)
+ @char = char
+ @attr = attr
+ end
+ end
+
+
+ class AttributeString
+ attr_reader :txt
+
+ def initialize
+ @txt = []
+ @optr = 0
+ end
+
+ def <<(char)
+ @txt << char
+ end
+
+ def empty?
+ @optr >= @txt.length
+ end
+
+ # accept non space, then all following spaces
+ def next_word
+ start = @optr
+ len = @txt.length
+
+ while @optr < len && @txt[@optr].char != " "
+ @optr += 1
+ end
+
+ while @optr < len && @txt[@optr].char == " "
+ @optr += 1
+ end
+
+ @txt[start...@optr]
+ end
+ end
+
+ ######################################################################
+ # overrides base class. Looks for <tt>...</tt> etc sequences
+ # and generates an array of AttrChars. This array is then used
+ # as the basis for the split
+
+ def wrap(txt, prefix=@indent, linelen=@width)
+ return unless txt && !txt.empty?
+
+ txt = add_attributes_to(txt)
+ next_prefix = prefix.tr("^ ", " ")
+ linelen -= prefix.size
+
+ line = []
+
+ until txt.empty?
+ word = txt.next_word
+ if word.size + line.size > linelen
+ write_attribute_text(prefix, line)
+ prefix = next_prefix
+ line = []
+ end
+ line.concat(word)
+ end
+
+ write_attribute_text(prefix, line) if line.length > 0
+ end
+
+ protected
+
+ # overridden in specific formatters
+
+ def write_attribute_text(prefix, line)
+ print prefix
+ line.each do |achar|
+ print achar.char
+ end
+ puts
+ end
+
+ # again, overridden
+
+ def bold_print(txt)
+ print txt
+ end
+
+ private
+
+ def add_attributes_to(txt)
+ tokens = txt.split(%r{(</?(?:b|code|em|i|tt)>)})
+ text = AttributeString.new
+ attributes = 0
+ tokens.each do |tok|
+ case tok
+ when %r{^</(\w+)>$} then attributes &= ~(ATTR_MAP[$1]||0)
+ when %r{^<(\w+)>$} then attributes |= (ATTR_MAP[$1]||0)
+ else
+ tok.split(//).each {|ch| text << AttrChar.new(ch, attributes)}
+ end
+ end
+ text
+ end
+
+ end
+
+
+ ##################################################
+
+ # This formatter generates overstrike-style formatting, which
+ # works with pagers such as man and less.
+
+ class OverstrikeFormatter < AttributeFormatter
+
+ BS = "\C-h"
+
+ def write_attribute_text(prefix, line)
+ print prefix
+ line.each do |achar|
+ attr = achar.attr
+ if (attr & (ITALIC+CODE)) != 0
+ print "_", BS
+ end
+ if (attr & BOLD) != 0
+ print achar.char, BS
+ end
+ print achar.char
+ end
+ puts
+ end
+
+ # draw a string in bold
+ def bold_print(text)
+ text.split(//).each do |ch|
+ print ch, BS, ch
+ end
+ end
+ end
+
+ ##################################################
+
+ # This formatter uses ANSI escape sequences
+ # to colorize stuff
+ # works with pages such as man and less.
+
+ class AnsiFormatter < AttributeFormatter
+
+ def initialize(*args)
+ print "\033[0m"
+ super
+ end
+
+ def write_attribute_text(prefix, line)
+ print prefix
+ curr_attr = 0
+ line.each do |achar|
+ attr = achar.attr
+ if achar.attr != curr_attr
+ update_attributes(achar.attr)
+ curr_attr = achar.attr
+ end
+ print achar.char
+ end
+ update_attributes(0) unless curr_attr.zero?
+ puts
+ end
+
+
+ def bold_print(txt)
+ print "\033[1m#{txt}\033[m"
+ end
+
+ HEADINGS = {
+ 1 => [ "\033[1;32m", "\033[m" ] ,
+ 2 => ["\033[4;32m", "\033[m" ],
+ 3 => ["\033[32m", "\033[m" ]
+ }
+
+ def display_heading(text, level, indent)
+ level = 3 if level > 3
+ heading = HEADINGS[level]
+ print indent
+ print heading[0]
+ print strip_attributes(text)
+ puts heading[1]
+ end
+
+ private
+
+ ATTR_MAP = {
+ BOLD => "1",
+ ITALIC => "33",
+ CODE => "36"
+ }
+
+ def update_attributes(attr)
+ str = "\033["
+ for quality in [ BOLD, ITALIC, CODE]
+ unless (attr & quality).zero?
+ str << ATTR_MAP[quality]
+ end
+ end
+ print str, "m"
+ end
+ end
+
+ ##################################################
+
+ # This formatter uses HTML.
+
+ class HtmlFormatter < AttributeFormatter
+
+ def initialize(*args)
+ super
+ end
+
+ def write_attribute_text(prefix, line)
+ curr_attr = 0
+ line.each do |achar|
+ attr = achar.attr
+ if achar.attr != curr_attr
+ update_attributes(curr_attr, achar.attr)
+ curr_attr = achar.attr
+ end
+ print(escape(achar.char))
+ end
+ update_attributes(curr_attr, 0) unless curr_attr.zero?
+ end
+
+ def draw_line(label=nil)
+ if label != nil
+ bold_print(label)
+ end
+ puts("<hr>")
+ end
+
+ def bold_print(txt)
+ tag("b") { txt }
+ end
+
+ def blankline()
+ puts("<p>")
+ end
+
+ def break_to_newline
+ puts("<br>")
+ end
+
+ def display_heading(text, level, indent)
+ level = 4 if level > 4
+ tag("h#{level}") { text }
+ puts
+ end
+
+ ######################################################################
+
+ def display_list(list)
+
+ case list.type
+ when SM::ListBase::BULLET
+ list_type = "ul"
+ prefixer = proc { |ignored| "<li>" }
+
+ when SM::ListBase::NUMBER,
+ SM::ListBase::UPPERALPHA,
+ SM::ListBase::LOWERALPHA
+ list_type = "ol"
+ prefixer = proc { |ignored| "<li>" }
+
+ when SM::ListBase::LABELED
+ list_type = "dl"
+ prefixer = proc do |li|
+ "<dt><b>" + escape(li.label) + "</b><dd>"
+ end
+
+ when SM::ListBase::NOTE
+ list_type = "table"
+ prefixer = proc do |li|
+ %{<tr valign="top"><td>#{li.label.gsub(/ /, '&nbsp;')}</td><td>}
+ end
+ else
+ fail "unknown list type"
+ end
+
+ print "<#{list_type}>"
+ list.contents.each do |item|
+ if item.kind_of? SM::Flow::LI
+ prefix = prefixer.call(item)
+ print prefix
+ display_flow_item(item, prefix)
+ else
+ display_flow_item(item)
+ end
+ end
+ print "</#{list_type}>"
+ end
+
+ def display_verbatim_flow_item(item, prefix=@indent)
+ print("<pre>")
+ puts item.body
+ puts("</pre>")
+ end
+
+ private
+
+ ATTR_MAP = {
+ BOLD => "b>",
+ ITALIC => "i>",
+ CODE => "tt>"
+ }
+
+ def update_attributes(current, wanted)
+ str = ""
+ # first turn off unwanted ones
+ off = current & ~wanted
+ for quality in [ BOLD, ITALIC, CODE]
+ if (off & quality) > 0
+ str << "</" + ATTR_MAP[quality]
+ end
+ end
+
+ # now turn on wanted
+ for quality in [ BOLD, ITALIC, CODE]
+ unless (wanted & quality).zero?
+ str << "<" << ATTR_MAP[quality]
+ end
+ end
+ print str
+ end
+
+ def tag(code)
+ print("<#{code}>")
+ print(yield)
+ print("</#{code}>")
+ end
+
+ def escape(str)
+ str.
+ gsub(/&/n, '&amp;').
+ gsub(/\"/n, '&quot;').
+ gsub(/>/n, '&gt;').
+ gsub(/</n, '&lt;')
+ end
+
+ end
+
+ ##################################################
+
+ # This formatter reduces extra lines for a simpler output.
+ # It improves way output looks for tools like IRC bots.
+
+ class SimpleFormatter < TextFormatter
+
+ ######################################################################
+
+ # No extra blank lines
+
+ def blankline
+ end
+
+ ######################################################################
+
+ # Display labels only, no lines
+
+ def draw_line(label=nil)
+ unless label.nil? then
+ bold_print(label)
+ puts
+ end
+ end
+
+ ######################################################################
+
+ # Place heading level indicators inline with heading.
+
+ def display_heading(text, level, indent)
+ text = strip_attributes(text)
+ case level
+ when 1
+ puts "= " + text.upcase
+ when 2
+ puts "-- " + text
+ else
+ print indent, text, "\n"
+ end
+ end
+
+ end
+
+
+ # Finally, fill in the list of known formatters
+
+ class TextFormatter
+
+ FORMATTERS = {
+ "ansi" => AnsiFormatter,
+ "bs" => OverstrikeFormatter,
+ "html" => HtmlFormatter,
+ "plain" => TextFormatter,
+ "simple" => SimpleFormatter,
+ }
+
+ def TextFormatter.list
+ FORMATTERS.keys.sort.join(", ")
+ end
+
+ def TextFormatter.for(name)
+ FORMATTERS[name.downcase]
+ end
+
+ end
+
+end
+
+
diff --git a/ruby_1_8_6/lib/rdoc/ri/ri_options.rb b/ruby_1_8_6/lib/rdoc/ri/ri_options.rb
new file mode 100644
index 0000000000..db9f4afecf
--- /dev/null
+++ b/ruby_1_8_6/lib/rdoc/ri/ri_options.rb
@@ -0,0 +1,313 @@
+# 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}/doc/*/ri" :
+ "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
+ $stderr.puts "\nFor help on options, try 'ri --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
+ ]
+
+ directories << "#{Gem.path}/doc/*/ri" if RI::Paths::GEMDIRS
+
+ 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:
+
+ ri File
+ ri File.new
+ ri F.n
+ ri zip
+
+ Note that shell quoting may be required for method names
+ containing punctuation:
+
+ ri 'Array.[]'
+ ri 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 'ri -h'"
+ puts "For a list of classes I know about, type 'ri -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/ruby_1_8_6/lib/rdoc/ri/ri_paths.rb b/ruby_1_8_6/lib/rdoc/ri/ri_paths.rb
new file mode 100644
index 0000000000..32363bf70a
--- /dev/null
+++ b/ruby_1_8_6/lib/rdoc/ri/ri_paths.rb
@@ -0,0 +1,80 @@
+module RI
+
+ # Encapsulate all the strangeness to do with finding out
+ # where to find RDoc files
+ #
+ # We basically deal with three directories:
+ #
+ # 1. The 'system' documentation directory, which holds
+ # the documentation distributed with Ruby, and which
+ # is managed by the Ruby install process
+ # 2. The 'site' directory, which contains site-wide
+ # documentation added locally.
+ # 3. The 'user' documentation directory, stored under the
+ # user's own home directory.
+ #
+ # There's contention about all this, but for now:
+ #
+ # system:: $datadir/ri/<ver>/system/...
+ # site:: $datadir/ri/<ver>/site/...
+ # user:: ~/.rdoc
+
+ module Paths
+
+ #:stopdoc:
+ require 'rbconfig'
+
+ DOC_DIR = "doc/rdoc"
+
+ version = Config::CONFIG['ruby_version']
+
+ base = File.join(Config::CONFIG['datadir'], "ri", version)
+ SYSDIR = File.join(base, "system")
+ SITEDIR = File.join(base, "site")
+ homedir = ENV['HOME'] || ENV['USERPROFILE'] || ENV['HOMEPATH']
+
+ if homedir
+ HOMEDIR = File.join(homedir, ".rdoc")
+ else
+ HOMEDIR = nil
+ end
+
+ # This is the search path for 'ri'
+ PATH = [ SYSDIR, SITEDIR, HOMEDIR ].find_all {|p| p && File.directory?(p)}
+
+ begin
+ require 'rubygems'
+ GEMDIRS = Dir["#{Gem.path}/doc/*/ri"]
+ GEMDIRS.each { |path| RI::Paths::PATH << path }
+ rescue LoadError
+ GEMDIRS = nil
+ end
+
+ # Returns the selected documentation directories as an Array, or PATH if no
+ # overriding directories were given.
+
+ def self.path(use_system, use_site, use_home, use_gems, *extra_dirs)
+ path = raw_path(use_system, use_site, use_home, use_gems, *extra_dirs)
+ return path.select { |path| File.directory? path }
+ end
+
+ # Returns the selected documentation directories including nonexistent
+ # directories. Used to print out what paths were searched if no ri was
+ # 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 << RI::Paths::SYSDIR if use_system
+ path << RI::Paths::SITEDIR if use_site
+ path << RI::Paths::HOMEDIR if use_home
+ path << RI::Paths::GEMDIRS if use_gems
+
+ return path.flatten.compact
+ end
+
+ end
+end
diff --git a/ruby_1_8_6/lib/rdoc/ri/ri_reader.rb b/ruby_1_8_6/lib/rdoc/ri/ri_reader.rb
new file mode 100644
index 0000000000..fb2c373e38
--- /dev/null
+++ b/ruby_1_8_6/lib/rdoc/ri/ri_reader.rb
@@ -0,0 +1,100 @@
+require 'rdoc/ri/ri_descriptions'
+require 'rdoc/ri/ri_writer'
+require 'rdoc/markup/simple_markup/to_flow'
+
+module RI
+ class RiReader
+
+ def initialize(ri_cache)
+ @cache = ri_cache
+ end
+
+ def top_level_namespace
+ [ @cache.toplevel ]
+ end
+
+ def lookup_namespace_in(target, namespaces)
+ result = []
+ for n in namespaces
+ result.concat(n.contained_modules_matching(target))
+ end
+ result
+ end
+
+ def find_class_by_name(full_name)
+ names = full_name.split(/::/)
+ ns = @cache.toplevel
+ for name in names
+ ns = ns.contained_class_named(name)
+ return nil if ns.nil?
+ end
+ get_class(ns)
+ end
+
+ def find_methods(name, is_class_method, namespaces)
+ result = []
+ namespaces.each do |ns|
+ result.concat ns.methods_matching(name, is_class_method)
+ end
+ result
+ end
+
+ # return the MethodDescription for a given MethodEntry
+ # by deserializing the YAML
+ def get_method(method_entry)
+ path = method_entry.path_name
+ File.open(path) { |f| RI::Description.deserialize(f) }
+ end
+
+ # Return a class description
+ 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) }
+ if result
+ result.merge_in(desc)
+ else
+ result = desc
+ end
+ end
+ result
+ end
+
+ # return the names of all classes and modules
+ def full_class_names
+ res = []
+ find_classes_in(res, @cache.toplevel)
+ end
+
+ # return a list of all classes, modules, and methods
+ def all_names
+ res = []
+ find_names_in(res, @cache.toplevel)
+ end
+
+ # ----
+ private
+ # ----
+
+ def find_classes_in(res, klass)
+ classes = klass.classes_and_modules
+ for c in classes
+ res << c.full_name
+ find_classes_in(res, c)
+ end
+ res
+ end
+
+ def find_names_in(res, klass)
+ classes = klass.classes_and_modules
+ for c in classes
+ res << c.full_name
+ res.concat c.all_method_names
+ find_names_in(res, c)
+ end
+ res
+ end
+
+ end
+end
diff --git a/ruby_1_8_6/lib/rdoc/ri/ri_util.rb b/ruby_1_8_6/lib/rdoc/ri/ri_util.rb
new file mode 100644
index 0000000000..8a01255897
--- /dev/null
+++ b/ruby_1_8_6/lib/rdoc/ri/ri_util.rb
@@ -0,0 +1,75 @@
+######################################################################
+
+class RiError < Exception; end
+#
+# Break argument into its constituent class or module names, an
+# optional method type, and a method name
+
+class NameDescriptor
+
+ attr_reader :class_names
+ attr_reader :method_name
+
+ # true and false have the obvious meaning. nil means we don't care
+ attr_reader :is_class_method
+
+ # arg may be
+ # 1. a class or module name (optionally qualified with other class
+ # or module names (Kernel, File::Stat etc)
+ # 2. a method name
+ # 3. a method name qualified by a optionally fully qualified class
+ # or module name
+ #
+ # We're fairly casual about delimiters: folks can say Kernel::puts,
+ # Kernel.puts, or Kernel\#puts for example. There's one exception:
+ # if you say IO::read, we look for a class method, but if you
+ # say IO.read, we look for an instance method
+
+ def initialize(arg)
+ @class_names = []
+ separator = nil
+
+ tokens = arg.split(/(\.|::|#)/)
+
+ # Skip leading '::', '#' or '.', but remember it might
+ # be a method name qualifier
+ separator = tokens.shift if tokens[0] =~ /^(\.|::|#)/
+
+ # Skip leading '::', but remember we potentially have an inst
+
+ # leading stuff must be class names
+
+ while tokens[0] =~ /^[A-Z]/
+ @class_names << tokens.shift
+ unless tokens.empty?
+ separator = tokens.shift
+ break unless separator == "::"
+ end
+ end
+
+ # Now must have a single token, the method name, or an empty
+ # array
+ unless tokens.empty?
+ @method_name = tokens.shift
+ # We may now have a trailing !, ?, or = to roll into
+ # the method name
+ if !tokens.empty? && tokens[0] =~ /^[!?=]$/
+ @method_name << tokens.shift
+ end
+
+ if @method_name =~ /::|\.|#/ or !tokens.empty?
+ raise RiError.new("Bad argument: #{arg}")
+ end
+ if separator && separator != '.'
+ @is_class_method = separator == "::"
+ end
+ end
+ end
+
+ # Return the full class name (with '::' between the components)
+ # or "" if there's no class name
+
+ def full_class_name
+ @class_names.join("::")
+ end
+end
diff --git a/ruby_1_8_6/lib/rdoc/ri/ri_writer.rb b/ruby_1_8_6/lib/rdoc/ri/ri_writer.rb
new file mode 100644
index 0000000000..78c68e8409
--- /dev/null
+++ b/ruby_1_8_6/lib/rdoc/ri/ri_writer.rb
@@ -0,0 +1,62 @@
+require 'fileutils'
+
+module RI
+ class RiWriter
+
+ def RiWriter.class_desc_path(dir, class_desc)
+ File.join(dir, "cdesc-" + class_desc.name + ".yaml")
+ end
+
+
+ # Convert a name from internal form (containing punctuation)
+ # to an external form (where punctuation is replaced
+ # by %xx)
+
+ def RiWriter.internal_to_external(name)
+ name.gsub(/\W/) { sprintf("%%%02x", $&[0]) }
+ end
+
+ # And the reverse operation
+ def RiWriter.external_to_internal(name)
+ name.gsub(/%([0-9a-f]{2,2})/) { $1.to_i(16).chr }
+ end
+
+ def initialize(base_dir)
+ @base_dir = base_dir
+ end
+
+ def remove_class(class_desc)
+ FileUtils.rm_rf(path_to_dir(class_desc.full_name))
+ end
+
+ def add_class(class_desc)
+ dir = path_to_dir(class_desc.full_name)
+ FileUtils.mkdir_p(dir)
+ class_file_name = RiWriter.class_desc_path(dir, class_desc)
+ File.open(class_file_name, "w") do |f|
+ f.write(class_desc.serialize)
+ end
+ end
+
+ def add_method(class_desc, method_desc)
+ dir = path_to_dir(class_desc.full_name)
+ file_name = RiWriter.internal_to_external(method_desc.name)
+ meth_file_name = File.join(dir, file_name)
+ if method_desc.is_singleton
+ meth_file_name += "-c.yaml"
+ else
+ meth_file_name += "-i.yaml"
+ end
+
+ File.open(meth_file_name, "w") do |f|
+ f.write(method_desc.serialize)
+ end
+ end
+
+ private
+
+ def path_to_dir(class_name)
+ File.join(@base_dir, *class_name.split('::'))
+ end
+ end
+end