[前][次][番号順一覧][スレッド一覧]

ruby-changes:3460

From: ko1@a...
Date: 8 Jan 2008 19:19:00 +0900
Subject: [ruby-changes:3460] drbrain - Ruby:r14953 (trunk): Clean up namespacing of RI's classes

drbrain	2008-01-08 19:18:41 +0900 (Tue, 08 Jan 2008)

  New Revision: 14953

  Added files:
    trunk/lib/rdoc/ri/cache.rb
    trunk/lib/rdoc/ri/descriptions.rb
    trunk/lib/rdoc/ri/display.rb
    trunk/lib/rdoc/ri/driver.rb
    trunk/lib/rdoc/ri/formatter.rb
    trunk/lib/rdoc/ri/paths.rb
    trunk/lib/rdoc/ri/reader.rb
    trunk/lib/rdoc/ri/util.rb
    trunk/lib/rdoc/ri/writer.rb
  Removed files:
    trunk/lib/rdoc/ri/ri_cache.rb
    trunk/lib/rdoc/ri/ri_descriptions.rb
    trunk/lib/rdoc/ri/ri_display.rb
    trunk/lib/rdoc/ri/ri_driver.rb
    trunk/lib/rdoc/ri/ri_formatter.rb
    trunk/lib/rdoc/ri/ri_paths.rb
    trunk/lib/rdoc/ri/ri_reader.rb
    trunk/lib/rdoc/ri/ri_util.rb
    trunk/lib/rdoc/ri/ri_writer.rb
  Modified files:
    trunk/ChangeLog
    trunk/bin/ri
    trunk/lib/rdoc/generators/ri_generator.rb
    trunk/lib/rdoc/options.rb
    trunk/lib/rdoc/rdoc.rb

  Log:
    Clean up namespacing of RI's classes

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/ri/writer.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/ri/ri_util.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/ri/reader.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/ri/ri_driver.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/ri/descriptions.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/ri/cache.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/ri/util.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/ri/paths.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/ri/display.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/ChangeLog?r1=14953&r2=14952&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/ri/ri_paths.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/ri/driver.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/bin/ri?r1=14953&r2=14952&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/ri/ri_writer.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/ri/ri_cache.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/ri/ri_reader.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/ri/formatter.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/ri/ri_formatter.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/ri/ri_descriptions.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/options.rb?r1=14953&r2=14952&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/generators/ri_generator.rb?r1=14953&r2=14952&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/ri/ri_display.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/rdoc.rb?r1=14953&r2=14952&diff_format=u

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 14952)
+++ ChangeLog	(revision 14953)
@@ -1,3 +1,7 @@
+Tue Jan  8 19:17:29 2008  Eric Hodel  <drbrain@s...>
+
+	* lib/rdoc/*: Clean up namespacing of RI's classes.
+
 Tue Jan  8 18:05:35 2008  Eric Hodel  <drbrain@s...>
 
 	* bin/ri, lib/rdoc/ri/*: Replace with Ryan Davis' cached ri.
Index: lib/rdoc/generators/ri_generator.rb
===================================================================
--- lib/rdoc/generators/ri_generator.rb	(revision 14952)
+++ lib/rdoc/generators/ri_generator.rb	(revision 14953)
@@ -1,10 +1,10 @@
 require 'rdoc/generators'
 require 'rdoc/markup/simple_markup/to_flow'
 
-require 'rdoc/ri/ri_cache'
-require 'rdoc/ri/ri_reader'
-require 'rdoc/ri/ri_writer'
-require 'rdoc/ri/ri_descriptions'
+require 'rdoc/ri/cache'
+require 'rdoc/ri/reader'
+require 'rdoc/ri/writer'
+require 'rdoc/ri/descriptions'
 
 class RDoc::Generators::RIGenerator
 
@@ -25,7 +25,7 @@
 
   def initialize(options) #:not-new:
     @options   = options
-    @ri_writer = RI::RiWriter.new(".")
+    @ri_writer = RDoc::RI::Writer.new "."
     @markup    = SM::SimpleMarkup.new
     @to_flow   = SM::ToFlow.new
 
@@ -53,34 +53,35 @@
 
   def generate_class_info(cls)
     if cls === RDoc::NormalModule
-      cls_desc = RI::ModuleDescription.new
+      cls_desc = RDoc::RI::ModuleDescription.new
     else
-      cls_desc = RI::ClassDescription.new
+      cls_desc = RDoc::RI::ClassDescription.new
       cls_desc.superclass  = cls.superclass
     end
     cls_desc.name        = cls.name
     cls_desc.full_name   = cls.full_name
     cls_desc.comment     = markup(cls.comment)
 
-    cls_desc.attributes =cls.attributes.sort.map do |a|
-      RI::Attribute.new(a.name, a.rw, markup(a.comment))
+    cls_desc.attributes = cls.attributes.sort.map do |a|
+      RDoc::RI::Attribute.new(a.name, a.rw, markup(a.comment))
     end
 
     cls_desc.constants = cls.constants.map do |c|
-      RI::Constant.new(c.name, c.value, markup(c.comment))
+      RDoc::RI::Constant.new(c.name, c.value, markup(c.comment))
     end
 
     cls_desc.includes = cls.includes.map do |i|
-      RI::IncludedModule.new(i.name)
+      RDoc::RI::IncludedModule.new(i.name)
     end
 
     class_methods, instance_methods = method_list(cls)
 
     cls_desc.class_methods = class_methods.map do |m|
-      RI::MethodSummary.new(m.name)
+      RDoc::RI::MethodSummary.new(m.name)
     end
+
     cls_desc.instance_methods = instance_methods.map do |m|
-      RI::MethodSummary.new(m.name)
+      RDoc::RI::MethodSummary.new(m.name)
     end
 
     update_or_replace(cls_desc)
@@ -94,9 +95,8 @@
     end
   end
 
-
   def generate_method_info(cls_desc, method)
-    meth_desc = RI::MethodDescription.new
+    meth_desc = RDoc::RI::MethodDescription.new
     meth_desc.name = method.name
     meth_desc.full_name = cls_desc.full_name
     if method.singleton
@@ -113,7 +113,7 @@
     meth_desc.block_params = method.block_params
 
     meth_desc.aliases = method.aliases.map do |a|
-      RI::AliasName.new(a.name)
+      RDoc::RI::AliasName.new(a.name)
     end
 
     @ri_writer.add_method(cls_desc, meth_desc)
@@ -190,7 +190,7 @@
     old_cls = nil
 
     if @options.merge
-      rdr = RI::RiReader.new(RI::RiCache.new(@options.op_dir))
+      rdr = RDoc::RI::Reader.new RDoc::RI::Cache.new(@options.op_dir)
 
       namespace = rdr.top_level_namespace
       namespace = rdr.lookup_namespace_in(cls_desc.name, namespace)
Index: lib/rdoc/rdoc.rb
===================================================================
--- lib/rdoc/rdoc.rb	(revision 14952)
+++ lib/rdoc/rdoc.rb	(revision 14953)
@@ -36,7 +36,7 @@
   ##
   # Exception thrown by any rdoc error.
 
-  class Error < StandardError; end
+  class Error < RuntimeError; end
 
   RDocError = Error # :nodoc:
 
Index: lib/rdoc/ri/ri_cache.rb
===================================================================
--- lib/rdoc/ri/ri_cache.rb	(revision 14952)
+++ lib/rdoc/ri/ri_cache.rb	(revision 14953)
@@ -1,187 +0,0 @@
-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
Index: lib/rdoc/ri/ri_formatter.rb
===================================================================
--- lib/rdoc/ri/ri_formatter.rb	(revision 14952)
+++ lib/rdoc/ri/ri_formatter.rb	(revision 14953)
@@ -1,673 +0,0 @@
-module RI
-  class TextFormatter
-
-    attr_reader :indent
-
-    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)
-      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>")
-        item.body.split(/\n/).each do |line|
-          puts conv_html(line)
-        end
-        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
-
-
Index: lib/rdoc/ri/ri_display.rb
===================================================================
--- lib/rdoc/ri/ri_display.rb	(revision 14952)
+++ lib/rdoc/ri/ri_display.rb	(revision 14953)
@@ -1,275 +0,0 @@
-# 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(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)
-    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.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:", "")
-        @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
-    if pager = setup_pager then
-      begin
-        orig_stdout = $stdout
-        $stdout = pager
-        yield
-      ensure
-        $stdout = orig_stdout
-        pager.close
-      end
-    else
-      yield
-    end
-  rescue Errno::EPIPE
-  end
-
-  ######################################################################
-
-  def setup_pager
-    unless @use_stdout then
-      for pager in [ ENV['PAGER'], "less", "more", 'pager' ].compact.uniq
-        return IO.popen(pager, "w") rescue nil
-      end
-      @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
-    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...)")
-    else
-      @formatter.display_flow(flow)
-    end
-  end
-
-  ######################################################################
-
-  def warn_no_database
-    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
Index: lib/rdoc/ri/ri_descriptions.rb
===================================================================
--- lib/rdoc/ri/ri_descriptions.rb	(revision 14952)
+++ lib/rdoc/ri/ri_descriptions.rb	(revision 14953)
@@ -1,154 +0,0 @@
-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
Index: lib/rdoc/ri/ri_driver.rb
===================================================================
--- lib/rdoc/ri/ri_driver.rb	(revision 14952)
+++ lib/rdoc/ri/ri_driver.rb	(revision 14953)
@@ -1,424 +0,0 @@
-require 'optparse'
-require 'yaml'
-
-require 'rdoc/ri'
-require 'rdoc/ri/ri_paths'
-require 'rdoc/ri/ri_formatter'
-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    "}
-
-Specifying the --system, --site, --home, --gems or --doc-dir options will
-limit ri to searching only the specified directories.
-
-Options may also be set in the 'RI' environment variable.
-      EOT
-
-      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
-
-    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)
-
-    options
-
-  rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e
-    puts opts
-    puts
-    puts e
-    exit 1
-  end
-
-  def self.run(argv = ARGV)
-    options = process_args argv
-    ri = new options
-    ri.run
-  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 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 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
-
-  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
-  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 read_yaml(path)
-    YAML.load File.read(path).gsub(/ \!ruby\/(object|struct):RI.*/, '')
-  end
-
-  def run
-    if @names.empty? then
-      @display.list_known_classes select_classes
-    else
-      @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
-        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
-
Index: lib/rdoc/ri/ri_writer.rb
===================================================================
--- lib/rdoc/ri/ri_writer.rb	(revision 14952)
+++ lib/rdoc/ri/ri_writer.rb	(revision 14953)
@@ -1,62 +0,0 @@
-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/) { "%%%02x" % $&[0].ord }
-    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
Index: lib/rdoc/ri/ri_util.rb
===================================================================
--- lib/rdoc/ri/ri_util.rb	(revision 14952)
+++ lib/rdoc/ri/ri_util.rb	(revision 14953)
@@ -1,75 +0,0 @@
-######################################################################
-
-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
Index: lib/rdoc/ri/ri_paths.rb
===================================================================
--- lib/rdoc/ri/ri_paths.rb	(revision 14952)
+++ lib/rdoc/ri/ri_paths.rb	(revision 14953)
@@ -1,97 +0,0 @@
-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 = RbConfig::CONFIG['ruby_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']
-
-    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)}
-
-    require 'rubygems' unless defined?(Gem) and Gem::Enable
-
-    # HACK dup'd from Gem.latest_partials and friends
-    all_paths = []
-
-    all_paths = Gem.path.map do |dir|
-      Dir[File.join(dir, 'doc', '*', 'ri')]
-    end.flatten
-
-    ri_paths = {}
-
-    all_paths.each do |dir|
-      base = File.basename File.dirname(dir)
-      if base =~ /(.*)-((\d+\.)*\d+)/ then
-        name, version = $1, $2
-        ver = Gem::Version.new version
-        if ri_paths[name].nil? or ver > ri_paths[name][0] then
-          ri_paths[name] = [ver, dir]
-        end
-      end
-    end
-
-    GEMDIRS = ri_paths.map { |k,v| v.last }.sort
-    GEMDIRS.each { |dir| RI::Paths::PATH << dir }
-
-    # 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 { |directory| File.directory? directory }
-    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
Index: lib/rdoc/ri/ri_reader.rb
===================================================================
--- lib/rdoc/ri/ri_reader.rb	(revision 14952)
+++ lib/rdoc/ri/ri_reader.rb	(revision 14953)
@@ -1,100 +0,0 @@
-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
Index: lib/rdoc/ri/util.rb
===================================================================
--- lib/rdoc/ri/util.rb	(revision 0)
+++ lib/rdoc/ri/util.rb	(revision 14953)
@@ -0,0 +1,81 @@
+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
+
+class RDoc::RI::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
+

Property changes on: lib/rdoc/ri/util.rb
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + LF

Index: lib/rdoc/ri/paths.rb
===================================================================
--- lib/rdoc/ri/paths.rb	(revision 0)
+++ lib/rdoc/ri/paths.rb	(revision 14953)
@@ -0,0 +1,97 @@
+require 'rdoc/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 RDoc::RI::Paths
+
+  #:stopdoc:
+  require 'rbconfig'
+
+  DOC_DIR  = "doc/rdoc"
+
+  version = RbConfig::CONFIG['ruby_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']
+
+  if homedir then
+    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)}
+
+  require 'rubygems' unless defined?(Gem) and Gem::Enable
+
+  # HACK dup'd from Gem.latest_partials and friends
+  all_paths = []
+
+  all_paths = Gem.path.map do |dir|
+    Dir[File.join(dir, 'doc', '*', 'ri')]
+  end.flatten
+
+  ri_paths = {}
+
+  all_paths.each do |dir|
+    base = File.basename File.dirname(dir)
+    if base =~ /(.*)-((\d+\.)*\d+)/ then
+      name, version = $1, $2
+      ver = Gem::Version.new version
+      if ri_paths[name].nil? or ver > ri_paths[name][0] then
+        ri_paths[name] = [ver, dir]
+      end
+    end
+  end
+
+  GEMDIRS = ri_paths.map { |k,v| v.last }.sort
+  GEMDIRS.each { |dir| PATH << dir }
+
+  # 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 { |directory| File.directory? directory }
+  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 << SYSDIR if use_system
+    path << SITEDIR if use_site
+    path << HOMEDIR if use_home
+    path << GEMDIRS if use_gems
+
+    return path.flatten.compact
+  end
+
+end
+

Property changes on: lib/rdoc/ri/paths.rb
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + LF

Index: lib/rdoc/ri/reader.rb
===================================================================
--- lib/rdoc/ri/reader.rb	(revision 0)
+++ lib/rdoc/ri/reader.rb	(revision 14953)
@@ -0,0 +1,106 @@
+require 'rdoc/ri'
+require 'rdoc/ri/descriptions'
+require 'rdoc/ri/writer'
+require 'rdoc/markup/simple_markup/to_flow'
+
+class RDoc::RI::Reader
+
+  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
+

Property changes on: lib/rdoc/ri/reader.rb
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + LF

Index: lib/rdoc/ri/cache.rb
===================================================================
--- lib/rdoc/ri/cache.rb	(revision 0)
+++ lib/rdoc/ri/cache.rb	(revision 14953)
@@ -0,0 +1,188 @@
+require 'rdoc/ri'
+
+class RDoc::RI::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 RDoc::RI::TopLevelEntry < RDoc::RI::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 RDoc::RI::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 RDoc::RI::Cache
+
+  attr_reader :toplevel
+
+  def initialize(dirs)
+    # At the top level we have a dummy module holding the
+    # overall namespace
+    @toplevel = RDoc::RI::TopLevelEntry.new('', '::', nil)
+
+    dirs.each do |dir|
+      @toplevel.load_from(dir)
+    end
+  end
+
+end
+

Property changes on: lib/rdoc/ri/cache.rb
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + LF

Index: lib/rdoc/ri/formatter.rb
===================================================================
--- lib/rdoc/ri/formatter.rb	(revision 0)
+++ lib/rdoc/ri/formatter.rb	(revision 14953)
@@ -0,0 +1,662 @@
+require 'rdoc/ri'
+
+class RDoc::RI::Formatter
+
+  attr_reader :indent
+
+  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)
+    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 RDoc::RI::AttributeFormatter < RDoc::RI::Formatter
+
+  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 RDoc::RI::OverstrikeFormatter < RDoc::RI::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
+# pagers such as man and less.
+
+class RDoc::RI::AnsiFormatter < RDoc::RI::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 RDoc::RI::HtmlFormatter < RDoc::RI::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>")
+    item.body.split(/\n/).each do |line|
+      puts conv_html(line)
+    end
+    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 RDoc::RI::SimpleFormatter < RDoc::RI::Formatter
+
+  ##
+  # 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 RDoc::RI::Formatter
+
+  FORMATTERS = {
+    "plain"  => RDoc::RI::Formatter,
+    "simple" => RDoc::RI::SimpleFormatter,
+    "bs"     => RDoc::RI::OverstrikeFormatter,
+    "ansi"   => RDoc::RI::AnsiFormatter,
+    "html"   => RDoc::RI::HtmlFormatter,
+  }
+
+  def self.list
+    FORMATTERS.keys.sort.join(", ")
+  end
+
+  def self.for(name)
+    FORMATTERS[name.downcase]
+  end
+
+end
+

Property changes on: lib/rdoc/ri/formatter.rb
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + LF

Index: lib/rdoc/ri/display.rb
===================================================================
--- lib/rdoc/ri/display.rb	(revision 0)
+++ lib/rdoc/ri/display.rb	(revision 14953)
@@ -0,0 +1,244 @@
+require 'rdoc/ri'
+
+##
+# 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 ....
+
+module RDoc::RI::Display
+
+  @@display_class = nil
+
+  def self.append_features(display_class)
+    @@display_class = display_class
+  end
+
+  def self.new(*args)
+    @@display_class.new(*args)
+  end
+
+end
+
+##
+# A paging display module. Uses the RDoc::RI::Formatter class to do the actual
+# presentation
+
+class RDoc::RI::DefaultDisplay
+
+  include RDoc::RI::Display
+
+  def initialize(formatter, width, use_stdout)
+    @use_stdout = use_stdout
+    @formatter = formatter.new width, "     "
+  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.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:", "")
+        @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
+    if pager = setup_pager then
+      begin
+        orig_stdout = $stdout
+        $stdout = pager
+        yield
+      ensure
+        $stdout = orig_stdout
+        pager.close
+      end
+    else
+      yield
+    end
+  rescue Errno::EPIPE
+  end
+
+  def setup_pager
+    unless @use_stdout then
+      for pager in [ ENV['PAGER'], "less", "more", 'pager' ].compact.uniq
+        return IO.popen(pager, "w") rescue nil
+      end
+      @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
+    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...)")
+    else
+      @formatter.display_flow(flow)
+    end
+  end
+
+  def warn_no_database
+    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
+

Property changes on: lib/rdoc/ri/display.rb
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + LF

Index: lib/rdoc/ri/descriptions.rb
===================================================================
--- lib/rdoc/ri/descriptions.rb	(revision 0)
+++ lib/rdoc/ri/descriptions.rb	(revision 14953)
@@ -0,0 +1,147 @@
+require 'yaml'
+require 'rdoc/markup/simple_markup/fragments'
+require 'rdoc/ri'
+
+#--
+# 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
+#++
+
+class RDoc::RI::RDoc::RI::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
+
+class RDoc::RI::AliasName < RDoc::RI::RDoc::RI::NamedThing; end
+
+class RDoc::RI::Attribute < RDoc::RI::RDoc::RI::NamedThing
+  attr_reader :rw, :comment
+  def initialize(name, rw, comment)
+    super(name)
+    @rw = rw
+    @comment = comment
+  end
+end
+
+class RDoc::RI::Constant < RDoc::RI::NamedThing
+  attr_reader :value, :comment
+  def initialize(name, value, comment)
+    super(name)
+    @value = value
+    @comment = comment
+  end
+end
+
+class RDoc::RI::IncludedModule < RDoc::RI::NamedThing; end
+
+class RDoc::RI::MethodSummary < RDoc::RI::NamedThing
+  def initialize(name="")
+    super
+  end
+end
+
+class RDoc::RI::Description
+  attr_accessor :name
+  attr_accessor :full_name
+  attr_accessor :comment
+
+  def serialize
+    self.to_yaml
+  end
+
+  def self.deserialize(from)
+    YAML.load(from)
+  end
+
+  def <=>(other)
+    @name <=> other.name
+  end
+end
+
+class RDoc::RI::ModuleDescription < RDoc::RI::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 RDoc::RI::ClassDescription < RDoc::RI::ModuleDescription
+  attr_accessor :superclass
+
+  def display_name
+      "Class"
+  end
+
+  def superclass_string
+    if @superclass && @superclass != "Object"
+      @superclass
+    else
+      nil
+    end
+  end
+end
+
+class RDoc::RI::MethodDescription < RDoc::RI::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
+

Property changes on: lib/rdoc/ri/descriptions.rb
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + LF

Index: lib/rdoc/ri/driver.rb
===================================================================
--- lib/rdoc/ri/driver.rb	(revision 0)
+++ lib/rdoc/ri/driver.rb	(revision 14953)
@@ -0,0 +1,414 @@
+require 'optparse'
+require 'yaml'
+
+require 'rdoc/ri'
+require 'rdoc/ri/paths'
+require 'rdoc/ri/formatter'
+require 'rdoc/ri/display'
+require 'fileutils'
+require 'rdoc/markup/simple_markup'
+require 'rdoc/markup/simple_markup/to_flow'
+
+class RDoc::RI::Driver
+
+  def self.process_args(argv)
+    options = {}
+    options[:use_stdout] = !$stdout.tty?
+    options[:width] = 72
+    options[:formatter] = RDoc::RI::Formatter.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 = [
+        RDoc::RI::Paths::SYSDIR,
+        RDoc::RI::Paths::SITEDIR,
+        RDoc::RI::Paths::HOMEDIR
+      ]
+
+      if RDoc::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    "}
+
+Specifying the --system, --site, --home, --gems or --doc-dir options will
+limit ri to searching only the specified directories.
+
+Options may also be set in the 'RI' environment variable.
+      EOT
+
+      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",
+             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
+
+      unless RDoc::RI::Paths::GEMDIRS.empty? 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
+
+    argv = ENV['RI'].to_s.split.concat argv
+
+    opts.parse! argv
+
+    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
+
+  rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e
+    puts opts
+    puts
+    puts e
+    exit 1
+  end
+
+  def self.run(argv = ARGV)
+    options = process_args argv
+    ri = new options
+    ri.run
+  end
+
+  def initialize(options)
+    @names = options[:names]
+
+    @class_cache_name = 'classes'
+    @all_dirs = RDoc::RI::Paths.path(true, true, true, true)
+    @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)
+
+    FileUtils.mkdir_p cache_file_path unless File.directory? cache_file_path
+
+    @class_cache = nil
+
+    @display = RDoc::RI::DefaultDisplay.new(options[:formatter],
+                                            options[:width],
+                                            options[:use_stdout])
+  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 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
+
+  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
+  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 read_yaml(path)
+    YAML.load File.read(path).gsub(/ \!ruby\/(object|struct):RI.*/, '')
+  end
+
+  def run
+    if @names.empty? then
+      @display.list_known_classes select_classes
+    else
+      @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
+        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
+
+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
+

Property changes on: lib/rdoc/ri/driver.rb
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + LF

Index: lib/rdoc/ri/writer.rb
===================================================================
--- lib/rdoc/ri/writer.rb	(revision 0)
+++ lib/rdoc/ri/writer.rb	(revision 14953)
@@ -0,0 +1,64 @@
+require 'fileutils'
+require 'rdoc/ri'
+
+class RDoc::RI::Writer
+
+  def self.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 self.internal_to_external(name)
+    name.gsub(/\W/) { "%%%02x" % $&[0].ord }
+  end
+
+  ##
+  # And the reverse operation
+
+  def self.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 = self.class.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 = self.class.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
+

Property changes on: lib/rdoc/ri/writer.rb
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + LF

Index: lib/rdoc/options.rb
===================================================================
--- lib/rdoc/options.rb	(revision 14952)
+++ lib/rdoc/options.rb	(revision 14953)
@@ -1,7 +1,7 @@
 # We handle the parsing of options, and subsequently as a singleton
 # object to be queried for option values
 
-require "rdoc/ri/ri_paths"
+require "rdoc/ri/paths"
 require 'optparse'
 
 class RDoc::Options
@@ -423,7 +423,7 @@
              "subsequent --op parameter, so no special",
              "privileges are needed.") do |value|
         @generator_name = "ri"
-        @op_dir = RI::Paths::HOMEDIR
+        @op_dir = RDoc::RI::Paths::HOMEDIR
         setup_generator
       end
 
@@ -435,7 +435,7 @@
              "making them accessible to others, so",
              "special privileges are needed.") do |value|
         @generator_name = "ri"
-        @op_dir = RI::Paths::SITEDIR
+        @op_dir = RDoc::RI::Paths::SITEDIR
         setup_generator
       end
 
@@ -449,7 +449,7 @@
              "option is intended to be used during Ruby",
              "installation.") do |value|
         @generator_name = "ri"
-        @op_dir = RI::Paths::SYSDIR
+        @op_dir = RDoc::RI::Paths::SYSDIR
         setup_generator
       end
 
Index: bin/ri
===================================================================
--- bin/ri	(revision 14952)
+++ bin/ri	(revision 14953)
@@ -1,6 +1,6 @@
 #!/usr//bin/env ruby
 
-require 'rdoc/ri/ri_driver'
+require 'rdoc/ri/driver'
 
-RDoc::RI::RiDriver.run ARGV
+RDoc::RI::Driver.run ARGV
 

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml

[前][次][番号順一覧][スレッド一覧]