From 858362e761a41e7d96efbcb9b38ae815b1e388d7 Mon Sep 17 00:00:00 2001
From: drbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
Date: Thu, 25 Sep 2008 02:43:03 +0000
Subject: [PATCH] Import RDoc 2.2.1 r185

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@19537 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
---
 ChangeLog                                     |   4 +
 bin/ri                                        |   3 +-
 lib/rdoc.rb                                   | 190 ++++-
 lib/rdoc/code_objects.rb                      |  86 +-
 lib/rdoc/diagram.rb                           |  34 +-
 lib/rdoc/generator.rb                         |  36 +-
 lib/rdoc/generator/chm/chm.rb                 |   2 +
 lib/rdoc/generator/html.rb                    | 220 +++--
 lib/rdoc/generator/html/common.rb             |  24 +
 lib/rdoc/generator/html/frameless.rb          | 771 +-----------------
 lib/rdoc/generator/html/hefss.rb              | 358 ++------
 lib/rdoc/generator/html/html.rb               | 389 +++++----
 lib/rdoc/generator/html/kilmer.rb             | 329 +-------
 lib/rdoc/generator/html/kilmerfactory.rb      | 427 ++++++++++
 lib/rdoc/generator/html/one_page_html.rb      |  11 +-
 lib/rdoc/generator/texinfo.rb                 |   9 +-
 lib/rdoc/generator/texinfo/class.texinfo.erb  |   4 +-
 lib/rdoc/generator/xml.rb                     |  11 +-
 lib/rdoc/generator/xml/xml.rb                 |  30 +-
 lib/rdoc/markup.rb                            |  95 ---
 lib/rdoc/markup/inline.rb                     |   2 +-
 lib/rdoc/markup/to_html.rb                    |  15 +-
 lib/rdoc/markup/to_html_crossref.rb           |  88 +-
 lib/rdoc/markup/to_texinfo.rb                 |   2 +-
 lib/rdoc/options.rb                           |   9 +-
 lib/rdoc/parser.rb                            |  23 +-
 lib/rdoc/parser/c.rb                          |  64 +-
 lib/rdoc/parser/perl.rb                       | 165 ++++
 lib/rdoc/parser/ruby.rb                       |  12 +-
 lib/rdoc/parser/simple.rb                     |   2 +-
 lib/rdoc/rdoc.rb                              |   6 +-
 lib/rdoc/ri/cache.rb                          |  11 +-
 lib/rdoc/ri/descriptions.rb                   |   3 +
 lib/rdoc/ri/display.rb                        | 203 ++++-
 lib/rdoc/ri/driver.rb                         | 660 +++++++++------
 lib/rdoc/ri/formatter.rb                      |   2 +-
 lib/rdoc/ri/paths.rb                          |  13 +-
 lib/rdoc/ri/reader.rb                         |   6 +-
 lib/rdoc/ri/util.rb                           |   2 -
 test/rdoc/binary.dat                          | Bin 0 -> 1024 bytes
 .../rdoc_markup_to_html_crossref_reference.rb |  31 +
 test/rdoc/test_attribute_manager.rb           |  73 ++
 test/rdoc/test_rdoc_info_formatting.rb        |  12 +-
 test/rdoc/test_rdoc_info_sections.rb          |   4 +-
 .../test_rdoc_markup_attribute_manager.rb     |  28 +-
 test/rdoc/test_rdoc_markup_to_html.rb         |  18 +-
 .../rdoc/test_rdoc_markup_to_html_crossref.rb | 284 ++++++-
 test/rdoc/test_rdoc_parser.rb                 |  18 +
 test/rdoc/test_rdoc_parser_c.rb               |  31 +-
 test/rdoc/test_rdoc_parser_perl.rb            |  72 ++
 test/rdoc/test_rdoc_parser_ruby.rb            | 212 ++++-
 test/rdoc/test_rdoc_ri_default_display.rb     |  53 +-
 test/rdoc/test_rdoc_ri_driver.rb              |   2 +-
 test/rdoc/test_rdoc_ri_formatter.rb           |   2 +-
 54 files changed, 2893 insertions(+), 2268 deletions(-)
 create mode 100644 lib/rdoc/generator/html/common.rb
 create mode 100644 lib/rdoc/generator/html/kilmerfactory.rb
 create mode 100644 lib/rdoc/parser/perl.rb
 create mode 100644 test/rdoc/binary.dat
 create mode 100644 test/rdoc/rdoc_markup_to_html_crossref_reference.rb
 create mode 100644 test/rdoc/test_attribute_manager.rb
 create mode 100644 test/rdoc/test_rdoc_parser.rb
 create mode 100644 test/rdoc/test_rdoc_parser_perl.rb

diff --git a/ChangeLog b/ChangeLog
index e3ec2b2294..b9f6fcdac8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+Thu Sep 25 11:22:51 2008
+
+	* lib/rdoc*: Update to RDoc 2.2.1 r185.
+
 Thu Sep 25 02:08:47 2008  Tanaka Akira  <akr@fsij.org>
 
 	* io.c (rb_io_mode_enc): make it static.
diff --git a/bin/ri b/bin/ri
index 0d4e3304d8..243557403c 100755
--- a/bin/ri
+++ b/bin/ri
@@ -1,6 +1,5 @@
-#!/usr//bin/env ruby
+#!/usr/bin/env ruby
 
 require 'rdoc/ri/driver'
 
 RDoc::RI::Driver.run ARGV
-
diff --git a/lib/rdoc.rb b/lib/rdoc.rb
index 53b72241f8..797b119fbf 100644
--- a/lib/rdoc.rb
+++ b/lib/rdoc.rb
@@ -1,14 +1,14 @@
 $DEBUG_RDOC = nil
 
 ##
-# RDoc - Ruby Documentation System
+# = \RDoc - Ruby Documentation System
 #
 # This package contains RDoc and RDoc::Markup.  RDoc is an application that
-# produces documentation for one or more Ruby source files.  We work similarly
+# produces documentation for one or more Ruby source files.  It works similarly
 # to JavaDoc, parsing the source, and extracting the definition for classes,
-# modules, and methods (along with includes and requires).  We associate with
+# modules, and methods (along with includes and requires).  It associates with
 # these optional documentation contained in the immediately preceding comment
-# block, and then render the result using a pluggable output formatter.
+# block, and then renders the result using a pluggable output formatter.
 # RDoc::Markup is a library that converts plain text into various output
 # formats.  The markup library is used to interpret the comment blocks that
 # RDoc uses to document methods, classes, and so on.
@@ -18,8 +18,6 @@ $DEBUG_RDOC = nil
 # * If you want to use RDoc to create documentation for your Ruby source files,
 #   read on.
 # * If you want to include extensions written in C, see RDoc::Parser::C
-# * For information on the various markups available in comment blocks, see
-#   RDoc::Markup.
 # * If you want to drive RDoc programmatically, see RDoc::RDoc.
 # * If you want to use the library to format text blocks into HTML, have a look
 #   at RDoc::Markup.
@@ -28,21 +26,21 @@ $DEBUG_RDOC = nil
 #
 # == Summary
 #
-# Once installed, you can create documentation using the 'rdoc' command
-# (the command is 'rdoc.bat' under Windows)
+# Once installed, you can create documentation using the +rdoc+ command
 #
 #   % rdoc [options] [names...]
 #
-# Type "rdoc --help" for an up-to-date option summary.
+# For an up-to-date option summary, type
+#   % rdoc --help
 #
 # A typical use might be to generate documentation for a package of Ruby
-# source (such as rdoc itself).
+# source (such as RDoc itself).
 #
 #   % rdoc
 #
 # This command generates documentation for all the Ruby and C source
 # files in and below the current directory.  These will be stored in a
-# documentation tree starting in the subdirectory 'doc'.
+# documentation tree starting in the subdirectory +doc+.
 #
 # You can make this slightly more useful for your readers by having the
 # index page contain the documentation for the primary file.  In our
@@ -54,20 +52,46 @@ $DEBUG_RDOC = nil
 # in comment blocks in the documentation this generates.
 #
 # RDoc uses file extensions to determine how to process each file.  File names
-# ending +.rb+ and <tt>.rbw</tt> are assumed to be Ruby source.  Files
+# ending +.rb+ and +.rbw+ are assumed to be Ruby source.  Files
 # ending +.c+ are parsed as C files.  All other files are assumed to
 # contain just Markup-style markup (with or without leading '#' comment
 # markers).  If directory names are passed to RDoc, they are scanned
 # recursively for C and Ruby source files only.
 #
-# = Markup
+# == \Options
+# rdoc can be passed a variety of command-line options.  In addition,
+# options can be specified via the +RDOCOPT+ environment variable, which
+# functions similarly to the +RUBYOPT+ environment variable.
 #
-# For information on how to make lists, hyperlinks, etc. with RDoc, see
-# RDoc::Markup.
+#   % export RDOCOPT="-S"
 #
-# Comment blocks can be written fairly naturally, either using '#' on
+# will make rdoc default to inline method source code.  Command-line options
+# always will override those in +RDOCOPT+.
+#
+# Run
+# 
+#   % rdoc --help
+#
+# for full details on rdoc's options.
+#
+# Here are some of the most commonly used options.
+# [-d, --diagram]
+#   Generate diagrams showing modules and
+#   classes. You need dot V1.8.6 or later to
+#   use the --diagram option correctly. Dot is
+#   available from http://graphviz.org
+#
+# [-S, --inline-source]
+#   Show method source code inline, rather than via a popup link.
+#
+# [-T, --template=NAME]
+#   Set the template used when generating output.
+#
+# == Documenting Source Code
+#
+# Comment blocks can be written fairly naturally, either using +#+ on
 # successive lines of the comment, or by including the comment in
-# an =begin/=end block.  If you use the latter form, the =begin line must be
+# a =begin/=end block.  If you use the latter form, the =begin line must be
 # flagged with an RDoc tag:
 #
 #   =begin rdoc
@@ -93,7 +117,7 @@ $DEBUG_RDOC = nil
 #     # ...
 #   end
 #
-# Names of classes, source files, and any method names containing an
+# Names of classes, files, and any method names containing an
 # underscore or preceded by a hash character are automatically hyperlinked
 # from comment text to their description.
 #
@@ -124,15 +148,109 @@ $DEBUG_RDOC = nil
 # +:yields:+ is an example of a documentation directive.  These appear
 # immediately after the start of the document element they are modifying.
 #
+# == \Markup
+#
+# * The markup engine looks for a document's natural left margin.  This is
+#   used as the initial margin for the document.
+#
+# * Consecutive lines starting at this margin are considered to be a
+#   paragraph.
+#
+# * If a paragraph starts with a "*", "-", or with "<digit>.", then it is
+#   taken to be the start of a list.  The margin in increased to be the first
+#   non-space following the list start flag.  Subsequent lines should be
+#   indented to this new margin until the list ends.  For example:
+#
+#      * this is a list with three paragraphs in
+#        the first item.  This is the first paragraph.
+#
+#        And this is the second paragraph.
+#
+#        1. This is an indented, numbered list.
+#        2. This is the second item in that list
+#
+#        This is the third conventional paragraph in the
+#        first list item.
+#
+#      * This is the second item in the original list
+#
+# * You can also construct labeled lists, sometimes called description
+#   or definition lists.  Do this by putting the label in square brackets
+#   and indenting the list body:
+#
+#       [cat]  a small furry mammal
+#              that seems to sleep a lot
+#
+#       [ant]  a little insect that is known
+#              to enjoy picnics
+#
+#   A minor variation on labeled lists uses two colons to separate the
+#   label from the list body:
+#
+#       cat::  a small furry mammal
+#              that seems to sleep a lot
+#
+#       ant::  a little insect that is known
+#              to enjoy picnics
+#
+#   This latter style guarantees that the list bodies' left margins are
+#   aligned: think of them as a two column table.
+#
+# * Any line that starts to the right of the current margin is treated
+#   as verbatim text.  This is useful for code listings.  The example of a
+#   list above is also verbatim text.
+#
+# * A line starting with an equals sign (=) is treated as a
+#   heading.  Level one headings have one equals sign, level two headings
+#   have two,and so on.
+#
+# * A line starting with three or more hyphens (at the current indent)
+#   generates a horizontal rule.  The more hyphens, the thicker the rule
+#   (within reason, and if supported by the output device)
+#
+# * You can use markup within text (except verbatim) to change the
+#   appearance of parts of that text.  Out of the box, RDoc::Markup
+#   supports word-based and general markup.
+#
+#   Word-based markup uses flag characters around individual words:
+#
+#   [\*word*]  displays word in a *bold* font
+#   [\_word_]  displays word in an _emphasized_ font
+#   [\+word+]  displays word in a +code+ font
+#
+#   General markup affects text between a start delimiter and and end
+#   delimiter.  Not surprisingly, these delimiters look like HTML markup.
+#
+#   [\<b>text...</b>]    displays word in a *bold* font
+#   [\<em>text...</em>]  displays word in an _emphasized_ font
+#   [\\<i>text...</i>]    displays word in an <i>italicized</i> font
+#   [\<tt>text...</tt>]  displays word in a +code+ font
+#
+#   Unlike conventional Wiki markup, general markup can cross line
+#   boundaries.  You can turn off the interpretation of markup by
+#   preceding the first character with a backslash.  This only works for
+#   simple markup, not HTML-style markup.
+#
+# * Hyperlinks to the web starting http:, mailto:, ftp:, or www. are
+#   recognized.  An HTTP url that references an external image file is
+#   converted into an inline <IMG..>.  Hyperlinks starting 'link:' are
+#   assumed to refer to local files whose path is relative to the --op
+#   directory.
+#
+#   Hyperlinks can also be of the form <tt>label</tt>[url], in which
+#   case the label is used in the displayed text, and +url+ is
+#   used as the target.  If +label+ contains multiple words,
+#   put it in braces: <em>{multi word label}[</em>url<em>]</em>.
+#
 # == Directives
 #
 # [+:nodoc:+ / +:nodoc:+ all]
-#   Don't include this element in the documentation.  For classes
-#   and modules, the methods, aliases, constants, and attributes
-#   directly within the affected class or module will also be
-#   omitted.  By default, though, modules and classes within that
-#   class of module _will_ be documented.  This is turned off by
-#   adding the +all+ modifier.
+#   This directive prevents documentation for the element from
+#   being generated.  For classes and modules, the methods, aliases,
+#   constants, and attributes directly within the affected class or
+#   module also will be omitted.  By default, though, modules and
+#   classes within that class of module _will_ be documented.  This is
+#   turned off by adding the +all+ modifier.
 #   
 #     module MyModule # :nodoc:
 #       class Input
@@ -144,22 +262,22 @@ $DEBUG_RDOC = nil
 #       end
 #     end
 #
-#   In the above code, only class +MyModule::Input+ will be documented.The
-#   The :nodoc: directive is global across all files the class or module
-#   appears in, so use :stopdoc:/:startdoc: to only omit documentation for a
-#   particular set of methods, etc.
+#   In the above code, only class <tt>MyModule::Input</tt> will be documented.
+#   The +:nodoc:+ directive is global across all files for the class or module
+#   to which it applies, so use +:stopdoc:+/+:startdoc:+ to suppress
+#   documentation only for a particular set of methods, etc.
 #
 # [+:doc:+]
-#   Force a method or attribute to be documented even if it wouldn't otherwise
-#   be.  Useful if, for example, you want to include documentation of a
+#   Forces a method or attribute to be documented even if it wouldn't be
+#   otherwise.  Useful if, for example, you want to include documentation of a
 #   particular private method.
 #
 # [+:notnew:+]
 #   Only applicable to the +initialize+ instance method.  Normally RDoc
-#   assumes that the documentation and parameters for #initialize are
-#   actually for the ::new method, and so fakes out a ::new for the class.
-#   The :notnew: modifier stops this.  Remember that #initialize is protected,
-#   so you won't see the documentation unless you use the -a command line
+#   assumes that the documentation and parameters for +initialize+ are
+#   actually for the +new+ method, and so fakes out a +new+ for the class.
+#   The +:notnew:+ modifier stops this.  Remember that +initialize+ is private,
+#   so you won't see the documentation unless you use the +-a+ command line
 #   option.
 #
 # Comment blocks can contain other directives:
@@ -209,7 +327,7 @@ $DEBUG_RDOC = nil
 #   last.  If you don't specify a +:startdoc:+ by the end of the container,
 #   disables documentation for the entire class or module.
 #
-# = Other stuff
+# == Other stuff
 #
 # RDoc is currently being maintained by Eric Hodel <drbrain@segment7.net>
 #
@@ -254,7 +372,7 @@ module RDoc
   ##
   # RDoc version you are using
 
-  VERSION = "2.1.0"
+  VERSION = "2.2.1"
 
   ##
   # Name of the dotfile that contains the description of files to be processed
diff --git a/lib/rdoc/code_objects.rb b/lib/rdoc/code_objects.rb
index fbdb612b92..0916b03398 100644
--- a/lib/rdoc/code_objects.rb
+++ b/lib/rdoc/code_objects.rb
@@ -219,6 +219,22 @@ module RDoc
       @modules.values
     end
 
+    ##
+    # return the classes Hash (only to be used internally)
+
+    def classes_hash
+      @classes
+    end
+    protected :classes_hash
+
+    ##
+    # return the modules Hash (only to be used internally)
+
+    def modules_hash
+      @modules
+    end
+    protected :modules_hash
+
     ##
     # Change the default visibility for new methods
 
@@ -272,7 +288,24 @@ module RDoc
     end
 
     def add_class(class_type, name, superclass)
-      add_class_or_module @classes, class_type, name, superclass
+      klass = add_class_or_module @classes, class_type, name, superclass
+
+      #
+      # If the parser encounters Container::Item before encountering
+      # Container, then it assumes that Container is a module.  This
+      # may not be the case, so remove Container from the module list
+      # if present and transfer any contained classes and modules to
+      # the new class.
+      #
+      mod = @modules.delete(name)
+
+      if mod then
+        klass.classes_hash.update(mod.classes_hash)
+        klass.modules_hash.update(mod.modules_hash)
+        klass.method_list.concat(mod.method_list)
+      end
+
+      return klass
     end
 
     def add_module(class_type, name)
@@ -282,25 +315,41 @@ module RDoc
     def add_method(a_method)
       a_method.visibility = @visibility
       add_to(@method_list, a_method)
+
+      unmatched_alias_list = @unmatched_alias_lists[a_method.name]
+      if unmatched_alias_list then
+        unmatched_alias_list.each do |unmatched_alias|
+          add_alias_impl unmatched_alias, a_method
+          @aliases.delete unmatched_alias
+        end
+
+        @unmatched_alias_lists.delete a_method.name
+      end
     end
 
     def add_attribute(an_attribute)
       add_to(@attributes, an_attribute)
     end
 
+    def add_alias_impl(an_alias, meth)
+      new_meth = AnyMethod.new(an_alias.text, an_alias.new_name)
+      new_meth.is_alias_for = meth
+      new_meth.singleton    = meth.singleton
+      new_meth.params       = meth.params
+      new_meth.comment = "Alias for \##{meth.name}"
+      meth.add_alias(new_meth)
+      add_method(new_meth)
+    end
+    
     def add_alias(an_alias)
       meth = find_instance_method_named(an_alias.old_name)
 
       if meth then
-        new_meth = AnyMethod.new(an_alias.text, an_alias.new_name)
-        new_meth.is_alias_for = meth
-        new_meth.singleton    = meth.singleton
-        new_meth.params       = meth.params
-        new_meth.comment = "Alias for \##{meth.name}"
-        meth.add_alias(new_meth)
-        add_method(new_meth)
+        add_alias_impl(an_alias, meth)
       else
         add_to(@aliases, an_alias)
+        unmatched_alias_list = @unmatched_alias_lists[an_alias.old_name] ||= []
+        unmatched_alias_list.push(an_alias)
       end
 
       an_alias
@@ -360,6 +409,10 @@ module RDoc
       @requires    = []
       @includes    = []
       @constants   = []
+
+      # This Hash maps a method name to a list of unmatched
+      # aliases (aliases of a method not yet encountered).
+      @unmatched_alias_lists = {}
     end
 
     # and remove classes and modules when we see a :nodoc: all
@@ -374,9 +427,12 @@ module RDoc
 
     # Find a named module
     def find_module_named(name)
-      return self if self.name == name
+      # First check the enclosed modules, then check the module itself,
+      # then check the enclosing modules (this mirrors the check done by
+      # the Ruby parser)
       res = @modules[name] || @classes[name]
       return res if res
+      return self if self.name == name
       find_enclosing_module_named(name)
     end
 
@@ -435,6 +491,7 @@ module RDoc
         unless modules.empty? then
           module_name = modules.shift
           result = find_module_named(module_name)
+
           if result then
             modules.each do |name|
               result = result.find_module_named(name)
@@ -573,9 +630,18 @@ module RDoc
 
         cls = all[name]
 
-        unless cls then
+        if !cls then
           cls = class_type.new name, superclass
           all[name] = cls unless @done_documenting
+        else
+          # If the class has been encountered already, check that its
+          # superclass has been set (it may not have been, depending on
+          # the context in which it was encountered).
+          if class_type == NormalClass
+            if !cls.superclass then
+              cls.superclass = superclass
+            end
+          end
         end
 
         collection[name] = cls unless @done_documenting
diff --git a/lib/rdoc/diagram.rb b/lib/rdoc/diagram.rb
index e235e043dc..4aa2ec5656 100644
--- a/lib/rdoc/diagram.rb
+++ b/lib/rdoc/diagram.rb
@@ -311,28 +311,30 @@ module RDoc
     # inclusion on the page
 
     def wrap_in_image_map(src, dot)
-      res = %{<map id="map" name="map">\n}
+      res = ""
       dot_map = `dot -Tismap #{src}`
-      dot_map.split($/).each do |area|
-        unless area =~ /^rectangle \((\d+),(\d+)\) \((\d+),(\d+)\) ([\/\w.]+)\s*(.*)/
-          $stderr.puts "Unexpected output from dot:\n#{area}"
-          return nil
+      
+      if(!dot_map.empty?)
+        res << %{<map id="map" name="map">\n}
+        dot_map.split($/).each do |area|
+          unless area =~ /^rectangle \((\d+),(\d+)\) \((\d+),(\d+)\) ([\/\w.]+)\s*(.*)/
+            $stderr.puts "Unexpected output from dot:\n#{area}"
+            return nil
+          end
+
+          xs, ys = [$1.to_i, $3.to_i], [$2.to_i, $4.to_i]
+          url, area_name = $5, $6
+
+          res <<  %{  <area shape="rect" coords="#{xs.min},#{ys.min},#{xs.max},#{ys.max}" }
+          res <<  %{     href="#{url}" alt="#{area_name}" />\n}
         end
-
-        xs, ys = [$1.to_i, $3.to_i], [$2.to_i, $4.to_i]
-        url, area_name = $5, $6
-
-        res <<  %{  <area shape="rect" coords="#{xs.min},#{ys.min},#{xs.max},#{ys.max}" }
-        res <<  %{     href="#{url}" alt="#{area_name}" />\n}
+        res << "</map>\n"
       end
-      res << "</map>\n"
-#      map_file = src.sub(/.dot/, '.map')
-#      system("dot -Timap #{src} -o #{map_file}")
-      res << %{<img src="#{dot}" usemap="#map" border="0" alt="#{dot}">}
+
+      res << %{<img src="#{dot}" usemap="#map" alt="#{dot}" />}
       return res
     end
 
   end
 
 end
-
diff --git a/lib/rdoc/generator.rb b/lib/rdoc/generator.rb
index fbc08c4e20..d695e661d1 100644
--- a/lib/rdoc/generator.rb
+++ b/lib/rdoc/generator.rb
@@ -127,7 +127,7 @@ module RDoc::Generator
     # * a complete list of all hyperlinkable terms (file, class, module, and
     #   method names)
 
-    def self.build_indicies(toplevels, options)
+    def self.build_indices(toplevels, options)
       files = []
       classes = []
 
@@ -215,7 +215,7 @@ module RDoc::Generator
       @methods.sort.map do |meth|
         {
           "name" => CGI.escapeHTML(meth.name),
-          "aref" => "#{path_prefix}\##{meth.aref}"
+          "aref" => "##{meth.aref}"
         }
       end
     end
@@ -614,9 +614,9 @@ module RDoc::Generator
     def class_attribute_values
       h_name = CGI.escapeHTML(name)
 
-      @values["path"]      = @path
+      @values["href"]      = @path
       @values["classmod"]  = @is_module ? "Module" : "Class"
-      @values["title"]     = "#{@values['classmod']}: #{h_name}"
+      @values["title"]     = "#{@values['classmod']}: #{h_name} [#{@options.title}]"
 
       c = @context
       c = c.parent while c and not c.diagram
@@ -704,7 +704,7 @@ module RDoc::Generator
 
     def filename_to_label
       @context.file_relative_name.gsub(/%|\/|\?|\#/) do
-        '%%%x' % $&[0].unpack('C')
+        ('%%%x' % $&[0]).unpack('C')
       end
     end
 
@@ -791,7 +791,7 @@ module RDoc::Generator
       full_path = @context.file_absolute_name
       short_name = ::File.basename full_path
 
-      @values["title"] = CGI.escapeHTML("File: #{short_name}")
+      @values["title"] = CGI.escapeHTML("File: #{short_name} [#{@options.title}]")
 
       if @context.diagram then
         @values["diagram"] = diagram_reference(@context.diagram)
@@ -821,18 +821,18 @@ module RDoc::Generator
     attr_reader :img_url
     attr_reader :source_code
 
-    @@seq = "M000000"
-
-    @@all_methods = []
-
     def self.all_methods
       @@all_methods
     end
 
     def self.reset
       @@all_methods = []
+      @@seq = "M000000"
     end
 
+    # Initialize the class variables.
+    self.reset
+
     def initialize(context, html_class, options)
       # TODO: rethink the class hierarchy here...
       @context    = context
@@ -1043,12 +1043,18 @@ module RDoc::Generator
         first = $1.to_i - 1
         last  = first + src.count("\n")
         size = last.to_s.length
-        real_fmt = "%#{size}d: "
-        fmt = " " * (size+2)
+        fmt = "%#{size}d: "
+        is_first_line = true
+        line_num = first
         src.gsub!(/^/) do
-          res = sprintf(fmt, first)
-          first += 1
-          fmt = real_fmt
+          if is_first_line then
+            is_first_line = false
+            res = " " * (size+2)
+          else
+            res = sprintf(fmt, line_num)
+          end
+
+          line_num += 1
           res
         end
       end
diff --git a/lib/rdoc/generator/chm/chm.rb b/lib/rdoc/generator/chm/chm.rb
index 0a17a9e1ea..cceeca5dfc 100644
--- a/lib/rdoc/generator/chm/chm.rb
+++ b/lib/rdoc/generator/chm/chm.rb
@@ -6,6 +6,8 @@ module RDoc::Generator::CHM::CHM
   HTML = RDoc::Generator::HTML::HTML
 
   INDEX = HTML::INDEX
+  
+  STYLE = HTML::STYLE
 
   CLASS_INDEX = HTML::CLASS_INDEX
   CLASS_PAGE = HTML::CLASS_PAGE
diff --git a/lib/rdoc/generator/html.rb b/lib/rdoc/generator/html.rb
index a9e030a896..d136de7b00 100644
--- a/lib/rdoc/generator/html.rb
+++ b/lib/rdoc/generator/html.rb
@@ -68,7 +68,6 @@ class RDoc::Generator::HTML
   def initialize(options) #:not-new:
     @options = options
     load_html_template
-    @main_page_path = nil
   end
 
   ##
@@ -94,6 +93,15 @@ class RDoc::Generator::HTML
   # If the template name contains a slash, use it literally
 
   def load_html_template
+    #
+    # If the template is not a path, first look for it
+    # in rdoc's HTML template directory.  Perhaps this behavior should
+    # be reversed (first try to include the template and, only if that
+    # fails, try to include it in the default template directory).
+    # One danger with reversing the behavior, however, is that
+    # if something like require 'html' could load up an
+    # unrelated file in the standard library or in a gem.
+    #
     template = @options.template
 
     unless template =~ %r{/|\\} then
@@ -101,14 +109,25 @@ class RDoc::Generator::HTML
                            template)
     end
 
-    require template
+    begin
+      require template
 
-    @template = self.class.const_get @options.template.upcase
-    @options.template_class = @template
+      @template = self.class.const_get @options.template.upcase
+      @options.template_class = @template
+    rescue LoadError => e
+      #
+      # The template did not exist in the default template directory, so
+      # see if require can find the template elsewhere (in a gem, for
+      # instance).
+      #
+      if(e.message[template] && template != @options.template)
+        template = @options.template
+        retry
+      end
 
-  rescue LoadError
-    $stderr.puts "Could not find HTML template '#{template}'"
-    exit 99
+      $stderr.puts "Could not find HTML template '#{template}': #{e.message}"
+      exit 99
+    end
   end
 
   ##
@@ -146,14 +165,16 @@ class RDoc::Generator::HTML
   end
 
   def build_indices
-    @files, @classes = RDoc::Generator::Context.build_indicies(@toplevels,
-                                                               @options)
+    @files, @classes = RDoc::Generator::Context.build_indices(@toplevels,
+                                                              @options)
   end
 
   ##
   # Generate all the HTML
 
   def generate_html
+    @main_url = main_url
+
     # the individual descriptions for files and classes
     gen_into(@files)
     gen_into(@classes)
@@ -165,23 +186,50 @@ class RDoc::Generator::HTML
     gen_main_index
 
     # this method is defined in the template file
-    write_extra_pages if defined? write_extra_pages
+    values = {
+      'title_suffix' => CGI.escapeHTML("[#{@options.title}]"),
+      'charset'      => @options.charset,
+      'style_url'    => style_url('', @options.css),
+    }
+
+    @template.write_extra_pages(values) if @template.respond_to?(:write_extra_pages)
   end
 
   def gen_into(list)
-    @file_list ||= index_to_links @files
-    @class_list ||= index_to_links @classes
-    @method_list ||= index_to_links RDoc::Generator::Method.all_methods
+    #
+    # The file, class, and method lists technically should be regenerated
+    # for every output file, in order that the relative links be correct
+    # (we are worried here about frameless templates, which need this
+    # information for every generated page).  Doing this is a bit slow,
+    # however.  For a medium-sized gem, this increased rdoc's runtime by
+    # about 5% (using the 'time' command-line utility).  While this is not
+    # necessarily a problem, I do not want to pessimize rdoc for large
+    # projects, however, and so we only regenerate the lists when the
+    # directory of the output file changes, which seems like a reasonable
+    # optimization.
+    #
+    file_list = {}
+    class_list = {}
+    method_list = {}
+    prev_op_dir = nil
 
     list.each do |item|
       next unless item.document_self
 
       op_file = item.path
+      op_dir = File.dirname(op_file)
 
-      FileUtils.mkdir_p File.dirname(op_file)
+      if(op_dir != prev_op_dir)
+        file_list = index_to_links op_file, @files
+        class_list = index_to_links op_file, @classes
+        method_list = index_to_links op_file, RDoc::Generator::Method.all_methods
+      end
+      prev_op_dir = op_dir
+
+      FileUtils.mkdir_p op_dir
 
       open op_file, 'w' do |io|
-        item.write_on io, @file_list, @class_list, @method_list
+        item.write_on io, file_list, class_list, method_list
       end
     end
   end
@@ -211,8 +259,9 @@ class RDoc::Generator::HTML
 
     values = {
       "entries"    => res,
+      'title'      => CGI.escapeHTML("#{title} [#{@options.title}]"),
       'list_title' => CGI.escapeHTML(title),
-      'index_url'  => main_url,
+      'index_url'  => @main_url,
       'charset'    => @options.charset,
       'style_url'  => style_url('', @options.css),
     }
@@ -230,47 +279,55 @@ class RDoc::Generator::HTML
 
   def gen_main_index
     if @template.const_defined? :FRAMELESS then
-      main = @files.find do |file|
-        @main_page == file.name
-      end
-
-      if main.nil? then
-        main = @classes.find do |klass|
-          main_page == klass.context.full_name
-        end
+      #
+      # If we're using a template without frames, then just redirect
+      # to it from index.html.
+      #
+      # One alternative to this, expanding the main page's template into
+      # index.html, is tricky because the relative URLs will be different
+      # (since index.html is located in at the site's root,
+      # rather than within a files or a classes subdirectory).
+      #
+      open 'index.html', 'w'  do |f|
+        f.puts(%{<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+               "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">})
+        f.puts(%{<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
+                lang="en">})
+        f.puts(%{<head>})
+        f.puts(%{<title>#{CGI.escapeHTML(@options.title)}</title>})
+        f.puts(%{<meta http-equiv="refresh" content="0; url=#{@main_url}" />})
+        f.puts(%{</head>})
+        f.puts(%{<body></body>})
+        f.puts(%{</html>})
       end
     else
       main = RDoc::TemplatePage.new @template::INDEX
-    end
 
-    open 'index.html', 'w'  do |f|
-      style_url = style_url '', @options.css
+      open 'index.html', 'w'  do |f|
+        style_url = style_url '', @options.css
+        
+        classes = @classes.sort.map { |klass| klass.value_hash }
+        
+        values = {
+          'initial_page'  => @main_url,
+          'style_url'     => style_url('', @options.css),
+          'title'         => CGI.escapeHTML(@options.title),
+          'charset'       => @options.charset,
+          'classes'       => classes,
+        }
+        
+        values['inline_source'] = @options.inline_source
 
-      classes = @classes.sort.map { |klass| klass.value_hash }
-
-      values = {
-        'main_page'     => @main_page,
-        'initial_page'  => main_url,
-        'style_url'     => style_url('', @options.css),
-        'title'         => CGI.escapeHTML(@options.title),
-        'charset'       => @options.charset,
-        'classes'       => classes,
-      }
-
-      values['inline_source'] = @options.inline_source
-
-      if main.respond_to? :write_on then
-        main.write_on f, @file_list, @class_list, @method_list, values
-      else
         main.write_html_on f, values
       end
     end
   end
 
-  def index_to_links(collection)
+  def index_to_links(output_path, collection)
     collection.sort.map do |f|
       next unless f.document_self
-      { "href" => f.path, "name" => f.index_name }
+      { "href" => RDoc::Markup::ToHtml.gen_relative_url(output_path, f.path),
+        "name" => f.index_name }
     end.compact
   end
 
@@ -278,32 +335,48 @@ class RDoc::Generator::HTML
   # Returns the url of the main page
 
   def main_url
-    @main_page = @options.main_page
-    @main_page_ref = nil
+    main_page = @options.main_page
 
-    if @main_page then
-      @main_page_ref = RDoc::Generator::AllReferences[@main_page]
+    #
+    # If a main page has been specified (--main), then search for it
+    # in the AllReferences array.  This allows either files or classes
+    # to be used for the main page.
+    #
+    if main_page then
+      main_page_ref = RDoc::Generator::AllReferences[main_page]
 
-      if @main_page_ref then
-        @main_page_path = @main_page_ref.path
+      if main_page_ref then
+        return main_page_ref.path
       else
-        $stderr.puts "Could not find main page #{@main_page}"
+        $stderr.puts "Could not find main page #{main_page}"
       end
     end
 
-    unless @main_page_path then
-      file = @files.find { |context| context.document_self }
-      @main_page_path = file.path if file
+    #
+    # No main page has been specified, so just use the README.
+    #
+    @files.each do |file|
+      if file.name =~ /^README/ then
+        return file.path
+      end
     end
 
-    unless @main_page_path then
-      $stderr.puts "Couldn't find anything to document"
-      $stderr.puts "Perhaps you've used :stopdoc: in all classes"
-      exit 1
+    #
+    # There's no README (shame! shame!).  Just use the first file
+    # that will be documented.
+    #
+    @files.each do |file|
+      if file.document_self then
+        return file.path
+      end
     end
 
-    @main_page_path
+    #
+    # There are no files to be documented...  Something seems very wrong.
+    #
+    raise RDoc::Error, "Couldn't find anything to document (perhaps :stopdoc: has been used in all classes)!"
   end
+  private :main_url
 
 end
 
@@ -349,12 +422,9 @@ class RDoc::Generator::HTMLInOne < RDoc::Generator::HTML
       'charset' => @options.charset,
       'files'   => gen_into(@files),
       'classes' => gen_into(@classes),
-      'title'        => CGI.escapeHTML(@options.title),
+      'title'   => CGI.escapeHTML(@options.title),
     }
 
-    # this method is defined in the template file
-    write_extra_pages if defined? write_extra_pages
-
     template = RDoc::TemplatePage.new @template::ONE_PAGE
 
     if @options.op_name
@@ -372,26 +442,4 @@ class RDoc::Generator::HTMLInOne < RDoc::Generator::HTML
     end
     res
   end
-
-  def gen_file_index
-    gen_an_index(@files, 'Files')
-  end
-
-  def gen_class_index
-    gen_an_index(@classes, 'Classes')
-  end
-
-  def gen_method_index
-    gen_an_index(RDoc::Generator::Method.all_methods, 'Methods')
-  end
-
-  def gen_an_index(collection, title)
-    return {
-      "entries" => index_to_links(collection),
-      'list_title' => title,
-      'index_url'  => main_url,
-    }
-  end
-
 end
-
diff --git a/lib/rdoc/generator/html/common.rb b/lib/rdoc/generator/html/common.rb
new file mode 100644
index 0000000000..b25f009a72
--- /dev/null
+++ b/lib/rdoc/generator/html/common.rb
@@ -0,0 +1,24 @@
+#
+# The templates require further refactoring.  In particular,
+# * Some kind of HTML generation library should be used.
+#
+# Also, all of the templates require some TLC from a designer.
+#
+# Right now, this file contains some constants that are used by all
+# of the templates.
+#
+module RDoc::Generator::HTML::Common
+  XHTML_STRICT_PREAMBLE = <<-EOF
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+EOF
+
+  XHTML_FRAME_PREAMBLE = <<-EOF
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
+EOF
+
+  HTML_ELEMENT = <<-EOF
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+EOF
+end
diff --git a/lib/rdoc/generator/html/frameless.rb b/lib/rdoc/generator/html/frameless.rb
index 2af890ce04..0375fee313 100644
--- a/lib/rdoc/generator/html/frameless.rb
+++ b/lib/rdoc/generator/html/frameless.rb
@@ -1,15 +1,16 @@
-require 'rdoc/generator/html'
-require 'rdoc/generator/html/one_page_html'
+require 'rdoc/generator/html/html'
 
 ##
 # = CSS2 RDoc HTML template
 #
-# This is a template for RDoc that uses XHTML 1.0 Transitional and dictates a
+# This is a template for RDoc that uses XHTML 1.0 Strict and dictates a
 # bit more of the appearance of the output to cascading stylesheets than the
 # default. It was designed for clean inline code display, and uses DHTMl to
 # toggle the visbility of each method's source with each click on the '[source]'
 # link.
 #
+# Frameless basically is the html template without frames.
+#
 # == Authors
 #
 # * Michael Granger <ged@FaerieMUD.org>
@@ -25,692 +26,47 @@ module RDoc::Generator::HTML::FRAMELESS
 
   FRAMELESS = true
 
-  FONTS = "Verdana,Arial,Helvetica,sans-serif"
+  FONTS = RDoc::Generator::HTML::HTML::FONTS
 
-  STYLE = <<-EOF
-body {
-  font-family: #{FONTS};
-  font-size: 90%;
-  margin: 0;
-  margin-left: 40px;
-  padding: 0;
-  background: white;
-}
+  STYLE = RDoc::Generator::HTML::HTML::STYLE
 
-h1, h2, h3, h4 {
-  margin: 0;
-  color: #efefef;
-  background: transparent;
-}
-
-h1 {
-  font-size: 150%;
-}
-
-h2,h3,h4 {
-  margin-top: 1em;
-}
-
-:link, :visited {
-  background: #eef;
-  color: #039;
-  text-decoration: none;
-}
-
-:link:hover, :visited:hover {
-  background: #039;
-  color: #eef;
-}
-
-/* Override the base stylesheet's Anchor inside a table cell */
-td > :link, td > :visited {
-  background: transparent;
-  color: #039;
-  text-decoration: none;
-}
-
-/* and inside a section title */
-.section-title > :link, .section-title > :visited {
-  background: transparent;
-  color: #eee;
-  text-decoration: none;
-}
-
-/* === Structural elements =================================== */
-
-.index {
-  margin: 0;
-  margin-left: -40px;
-  padding: 0;
-  font-size: 90%;
-}
-
-.index :link, .index :visited {
-  margin-left: 0.7em;
-}
-
-.index .section-bar {
-  margin-left: 0px;
-  padding-left: 0.7em;
-  background: #ccc;
-  font-size: small;
-}
-
-#classHeader, #fileHeader {
-  width: auto;
-  color: white;
-  padding: 0.5em 1.5em 0.5em 1.5em;
-  margin: 0;
-  margin-left: -40px;
-  border-bottom: 3px solid #006;
-}
-
-#classHeader :link, #fileHeader :link,
-#classHeader :visited, #fileHeader :visited {
-  background: inherit;
-  color: white;
-}
-
-#classHeader td, #fileHeader td {
-  background: inherit;
-  color: white;
-}
-
-#fileHeader {
-  background: #057;
-}
-
-#classHeader {
-  background: #048;
-}
-
-.class-name-in-header {
-  font-size:  180%;
-  font-weight: bold;
-}
-
-#bodyContent {
-  padding: 0 1.5em 0 1.5em;
-}
-
-#description {
-  padding: 0.5em 1.5em;
-  background: #efefef;
-  border: 1px dotted #999;
-}
-
-#description h1, #description h2, #description h3,
-#description h4, #description h5, #description h6 {
-  color: #125;
-  background: transparent;
-}
-
-#copyright {
-  color: #333;
-  background: #efefef;
-  font: 0.75em sans-serif;
-  margin-top: 5em;
-  margin-bottom: 0;
-  padding: 0.5em 2em;
-}
-
-/* === Classes =================================== */
-
-table.header-table {
-  color: white;
-  font-size: small;
-}
-
-.type-note {
-  font-size: small;
-  color: #dedede;
-}
-
-.xxsection-bar {
-  background: #eee;
-  color: #333;
-  padding: 3px;
-}
-
-.section-bar {
-  color: #333;
-  border-bottom: 1px solid #999;
-  margin-left: -20px;
-}
-
-.section-title {
-  background: #79a;
-  color: #eee;
-  padding: 3px;
-  margin-top: 2em;
-  margin-left: -30px;
-  border: 1px solid #999;
-}
-
-.top-aligned-row {
-  vertical-align: top
-}
-
-.bottom-aligned-row {
-  vertical-align: bottom
-}
-
-/* --- Context section classes ----------------------- */
-
-.context-row { }
-
-.context-item-name {
-  font-family: monospace;
-  font-weight: bold;
-  color: black;
-}
-
-.context-item-value {
-  font-size: small;
-  color: #448;
-}
-
-.context-item-desc {
-  color: #333;
-  padding-left: 2em;
-}
-
-/* --- Method classes -------------------------- */
-
-.method-detail {
-  background: #efefef;
-  padding: 0;
-  margin-top: 0.5em;
-  margin-bottom: 1em;
-  border: 1px dotted #ccc;
-}
-
-.method-heading {
-  color: black;
-  background: #ccc;
-  border-bottom: 1px solid #666;
-  padding: 0.2em 0.5em 0 0.5em;
-}
-
-.method-signature {
-  color: black;
-  background: inherit;
-}
-
-.method-name {
-  font-weight: bold;
-}
-
-.method-args {
-  font-style: italic;
-}
-
-.method-description {
-  padding: 0 0.5em 0 0.5em;
-}
-
-/* --- Source code sections -------------------- */
-
-:link.source-toggle, :visited.source-toggle {
-  font-size: 90%;
-}
-
-div.method-source-code {
-  background: #262626;
-  color: #ffdead;
-  margin: 1em;
-  padding: 0.5em;
-  border: 1px dashed #999;
-  overflow: hidden;
-}
-
-div.method-source-code pre {
-  color: #ffdead;
-  overflow: hidden;
-}
-
-/* --- Ruby keyword styles --------------------- */
-
-.standalone-code {
-  background: #221111;
-  color: #ffdead;
-  overflow: hidden;
-}
-
-.ruby-constant {
-  color: #7fffd4;
-  background: transparent;
-}
-
-.ruby-keyword {
-  color: #00ffff;
-  background: transparent;
-}
-
-.ruby-ivar {
-  color: #eedd82;
-  background: transparent;
-}
-
-.ruby-operator {
-  color: #00ffee;
-  background: transparent;
-}
-
-.ruby-identifier {
-  color: #ffdead;
-  background: transparent;
-}
-
-.ruby-node {
-  color: #ffa07a;
-  background: transparent;
-}
-
-.ruby-comment {
-  color: #b22222;
-  font-weight: bold;
-  background: transparent;
-}
-
-.ruby-regexp {
-  color: #ffa07a;
-  background: transparent;
-}
-
-.ruby-value {
-  color: #7fffd4;
-  background: transparent;
-}
-
-EOF
-
-  ##
-  # Header template
-
-  XHTML_PREAMBLE = <<-EOF
-<?xml version="1.0" encoding="<%= values["charset"] %>"?>
-<!DOCTYPE html
-     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-  EOF
-
-  HEADER = XHTML_PREAMBLE + <<-EOF
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head>
-  <title><%= values["title"] %></title>
-  <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
-  <meta http-equiv="Content-Script-Type" content="text/javascript" />
-  <link rel="stylesheet" href="<%= values["style_url"] %>" type="text/css" media="screen" />
-  <script type="text/javascript">
-  // <![CDATA[
-
-  function popupCode( url ) {
-    window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
-  }
-
-  function toggleCode( id ) {
-    if ( document.getElementById )
-      elem = document.getElementById( id );
-    else if ( document.all )
-      elem = eval( "document.all." + id );
-    else
-      return false;
-
-    elemStyle = elem.style;
-
-    if ( elemStyle.display != "block" ) {
-      elemStyle.display = "block"
-    } else {
-      elemStyle.display = "none"
-    }
-
-    return true;
-  }
-
-  // Make codeblocks hidden by default
-  document.writeln( "<style type=\\"text/css\\">div.method-source-code { display: none }</style>" )
-
-  // ]]>
-  </script>
-
-</head>
-<body>
-EOF
-
-  ##
-  # Context content template
-
-  CONTEXT_CONTENT = %{
-}
-
-  ##
-  # Footer template
+  HEADER = RDoc::Generator::HTML::HTML::HEADER
 
   FOOTER = <<-EOF
   <div id="popupmenu" class="index">
-    <ul>
-    <li class="index-entries section-bar">Classes
-      <ul>
-<% values["class_list"].each do |klass| %>
-        <li><a href="<%= klass["href"] %>"><%= klass["name"] %></a>
-<% end %>
-      </ul>
-    </li>
-
-    <li class="index-entries section-bar">Methods
-      <ul>
-<% values["method_list"].each do |file| %>
-        <li><a href="<%= file["href"] %>"><%= file["name"] %></a>
-<% end %>
-      </ul>
-    </li>
-
-    <li class="index-entries section-bar">Files
+    <br />
+    <h1 class="index-entries section-bar">Files</h1>
       <ul>
 <% values["file_list"].each do |file| %>
-        <li><a href="<%= file["href"] %>"><%= file["name"] %></a>
+        <li><a href="<%= file["href"] %>"><%= file["name"] %></a></li>
 <% end %>
       </ul>
-    </li>
-    </ul>
-  </li>
 
+    <br />
+    <h1 class="index-entries section-bar">Classes</h1>
+      <ul>
+<% values["class_list"].each do |klass| %>
+        <li><a href="<%= klass["href"] %>"><%= klass["name"] %></a></li>
+<% end %>
+      </ul>
+
+    <br />
+    <h1 class="index-entries section-bar">Methods</h1>
+      <ul>
+<% values["method_list"].each do |method| %>
+        <li><a href="<%= method["href"] %>"><%= method["name"] %></a></li>
+<% end %>
+      </ul>
+  </div>
 </body>
 </html>
   EOF
 
-  ##
-  # File page header template
+  FILE_PAGE = RDoc::Generator::HTML::HTML::FILE_PAGE
 
-  FILE_PAGE = <<-EOF
-  <div id="fileHeader">
-    <h1><%= values["short_name"] %></h1>
+  CLASS_PAGE = RDoc::Generator::HTML::HTML::CLASS_PAGE
 
-    <table class="header-table">
-    <tr class="top-aligned-row">
-      <td><strong>Path:</strong></td>
-      <td><%= values["full_path"] %>
-<% if values["cvsurl"] then %>
-        &nbsp;(<a href="<%= values["cvsurl"] %>"><acronym title="Concurrent Versioning System">CVS</acronym></a>)
-<% end %>
-      </td>
-    </tr>
-
-    <tr class="top-aligned-row">
-      <td><strong>Last Update:</strong></td>
-      <td><%= values["dtm_modified"] %></td>
-    </tr>
-    </table>
-  </div>
-  EOF
-
-  ##
-  # Class page header template
-
-  CLASS_PAGE = <<-EOF
-    <div id="classHeader">
-      <table class="header-table">
-      <tr class="top-aligned-row">
-        <td><strong><%= values["classmod"] %></strong></td>
-        <td class="class-name-in-header"><%= values["full_name"] %></td>
-      </tr>
-
-      <tr class="top-aligned-row">
-        <td><strong>In:</strong></td>
-        <td>
-<% values["infiles"].each do |infiles| %>
-<% if infiles["full_path_url"] then %>
-          <a href="<%= infiles["full_path_url"] %>">
-<% end %>
-            <%= infiles["full_path"] %>
-<% if infiles["full_path_url"] then %>
-          </a>
-<% end %>
-<% if infiles["cvsurl"] then %>
-          &nbsp;(<a href="<%= infiles["cvsurl"] %>"><acronym title="Concurrent Versioning System">CVS</acronym></a>)
-<% end %>
-          <br />
-<% end %><%# values["infiles"] %>
-        </td>
-      </tr>
-
-<% if values["parent"] then %>
-      <tr class="top-aligned-row">
-        <td><strong>Parent:</strong></td>
-        <td>
-<% if values["par_url"] then %>
-          <a href="<%= values["par_url"] %>">
-<% end %>
-            <%= values["parent"] %>
-<% if values["par_url"] then %>
-          </a>
-<% end %>
-        </td>
-      </tr>
-<% end %>
-    </table>
-  </div>
-  EOF
-
-  ##
-  # Method list template
-
-  METHOD_LIST = <<-EOF
-
-  <div id="contextContent">
-<% if values["diagram"] then %>
-    <div id="diagram">
-      <%= values["diagram"] %>
-    </div>
-<% end %>
-
-<% if values["description"] then %>
-    <div id="description">
-      <%= values["description"] %>
-    </div>
-<% end %>
-
-<% if values["requires"] then %>
-    <div id="requires-list">
-      <h3 class="section-bar">Required files</h3>
-
-      <div class="name-list">
-<% values["requires"].each do |requires| %>
-        <%= href requires["aref"], requires["name"] %>&nbsp;&nbsp;
-<% end %><%# values["requires"] %>
-      </div>
-    </div>
-<% end %>
-
-<% if values["toc"] then %>
-    <div id="contents-list">
-      <h3 class="section-bar">Contents</h3>
-      <ul>
-<% values["toc"].each do |toc| %>
-      <li><a href="#<%= values["href"] %>"><%= values["secname"] %></a></li>
-<% end %><%# values["toc"] %>
-     </ul>
-<% end %>
-   </div>
-
-<% if values["methods"] then %>
-    <div id="method-list">
-      <h3 class="section-bar">Methods</h3>
-
-      <div class="name-list">
-<% values["methods"].each do |methods| %>
-        <%= href methods["aref"], methods["name"] %>&nbsp;&nbsp;
-<% end %><%# values["methods"] %>
-      </div>
-    </div>
-<% end %>
-
-  </div>
-
-
-    <!-- if includes -->
-<% if values["includes"] then %>
-    <div id="includes">
-      <h3 class="section-bar">Included Modules</h3>
-
-      <div id="includes-list">
-<% values["includes"].each do |includes| %>
-        <span class="include-name"><%= href includes["aref"], includes["name"] %></span>
-<% end %><%# values["includes"] %>
-      </div>
-    </div>
-<% end %>
-
-<% values["sections"].each do |sections| %>
-    <div id="section">
-<% if sections["sectitle"] then %>
-      <h2 class="section-title"><a name="<%= sections["secsequence"] %>"><%= sections["sectitle"] %></a></h2>
-<% if sections["seccomment"] then %>
-      <div class="section-comment">
-        <%= sections["seccomment"] %>
-      </div>
-<% end %>
-<% end %>
-
-<% if values["classlist"] then %>
-    <div id="class-list">
-      <h3 class="section-bar">Classes and Modules</h3>
-
-      <%= values["classlist"] %>
-    </div>
-<% end %>
-
-<% if values["constants"] then %>
-    <div id="constants-list">
-      <h3 class="section-bar">Constants</h3>
-
-      <div class="name-list">
-        <table summary="Constants">
-<% values["constants"].each do |constants| %>
-        <tr class="top-aligned-row context-row">
-          <td class="context-item-name"><%= constants["name"] %></td>
-          <td>=</td>
-          <td class="context-item-value"><%= constants["value"] %></td>
-<% if values["desc"] then %>
-          <td width="3em">&nbsp;</td>
-          <td class="context-item-desc"><%= constants["desc"] %></td>
-<% end %>
-        </tr>
-<% end %><%# values["constants"] %>
-        </table>
-      </div>
-    </div>
-<% end %>
-
-<% if values["aliases"] then %>
-    <div id="aliases-list">
-      <h3 class="section-bar">External Aliases</h3>
-
-      <div class="name-list">
-                        <table summary="aliases">
-<% values["aliases"].each do |aliases| $stderr.puts({ :aliases => aliases }.inspect) %>
-        <tr class="top-aligned-row context-row">
-          <td class="context-item-name"><%= values["old_name"] %></td>
-          <td>-&gt;</td>
-          <td class="context-item-value"><%= values["new_name"] %></td>
-        </tr>
-<% if values["desc"] then %>
-      <tr class="top-aligned-row context-row">
-        <td>&nbsp;</td>
-        <td colspan="2" class="context-item-desc"><%= values["desc"] %></td>
-      </tr>
-<% end %>
-<% end %><%# values["aliases"] %>
-        </table>
-      </div>
-    </div>
-<% end %>
-
-
-<% if values["attributes"] then %>
-    <div id="attribute-list">
-      <h3 class="section-bar">Attributes</h3>
-
-      <div class="name-list">
-        <table>
-<% values["attributes"].each do |attributes| $stderr.puts({ :attributes => attributes }.inspect) %>
-        <tr class="top-aligned-row context-row">
-          <td class="context-item-name"><%= values["name"] %></td>
-<% if values["rw"] then %>
-          <td class="context-item-value">&nbsp;[<%= values["rw"] %>]&nbsp;</td>
-<% end %>
-<% unless values["rw"] then %>
-          <td class="context-item-value">&nbsp;&nbsp;</td>
-<% end %>
-          <td class="context-item-desc"><%= values["a_desc"] %></td>
-        </tr>
-<% end %><%# values["attributes"] %>
-        </table>
-      </div>
-    </div>
-<% end %>
-
-    <!-- if method_list -->
-<% if sections["method_list"] then %>
-    <div id="methods">
-<% sections["method_list"].each do |method_list| %>
-<% if method_list["methods"] then %>
-      <h3 class="section-bar"><%= method_list["type"] %> <%= method_list["category"] %> methods</h3>
-
-<% method_list["methods"].each do |methods| %>
-      <div id="method-<%= methods["aref"] %>" class="method-detail">
-        <a name="<%= methods["aref"] %>"></a>
-
-        <div class="method-heading">
-<% if methods["codeurl"] then %>
-          <a href="<%= methods["codeurl"] %>" target="Code" class="method-signature"
-            onclick="popupCode('<%= methods["codeurl"] %>');return false;">
-<% end %>
-<% if methods["sourcecode"] then %>
-          <a href="#<%= methods["aref"] %>" class="method-signature">
-<% end %>
-<% if methods["callseq"] then %>
-          <span class="method-name"><%= methods["callseq"] %></span>
-<% end %>
-<% unless methods["callseq"] then %>
-          <span class="method-name"><%= methods["name"] %></span><span class="method-args"><%= methods["params"] %></span>
-<% end %>
-<% if methods["codeurl"] then %>
-          </a>
-<% end %>
-<% if methods["sourcecode"] then %>
-          </a>
-<% end %>
-        </div>
-
-        <div class="method-description">
-<% if methods["m_desc"] then %>
-          <%= methods["m_desc"] %>
-<% end %>
-<% if methods["sourcecode"] then %>
-          <p><a class="source-toggle" href="#"
-            onclick="toggleCode('<%= methods["aref"] %>-source');return false;">[Source]</a></p>
-          <div class="method-source-code" id="<%= methods["aref"] %>-source">
-<pre>
-<%= methods["sourcecode"] %>
-</pre>
-          </div>
-<% end %>
-        </div>
-      </div>
-
-<% end %><%# method_list["methods"] %>
-<% end %>
-<% end %><%# sections["method_list"] %>
-
-    </div>
-<% end %>
-<% end %><%# values["sections"] %>
-  EOF
-
-  ##
-  # Body template
+  METHOD_LIST = RDoc::Generator::HTML::HTML::METHOD_LIST
 
   BODY = HEADER + %{
 
@@ -724,72 +80,13 @@ EOF
 
 } + FOOTER
 
-  ##
-  # Source code template
+  SRC_PAGE = RDoc::Generator::HTML::HTML::SRC_PAGE
 
-  SRC_PAGE = XHTML_PREAMBLE + <<-EOF
-<html>
-<head>
-  <title><%= values["title"] %></title>
-  <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
-  <link rel="stylesheet" href="<%= values["style_url"] %>" type="text/css" media="screen" />
-</head>
-<body class="standalone-code">
-  <pre><%= values["code"] %></pre>
-</body>
-</html>
-  EOF
+  FR_INDEX_BODY = RDoc::Generator::HTML::HTML::FR_INDEX_BODY
 
-  ##
-  # Index file templates
+  FILE_INDEX = RDoc::Generator::HTML::HTML::FILE_INDEX
 
-  FR_INDEX_BODY = %{
-<%= template_include %>
-}
-
-  FILE_INDEX = XHTML_PREAMBLE + <<-EOF
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head>
-  <title><%= values["list_title"] %></title>
-  <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
-  <link rel="stylesheet" href="<%= values["style_url"] %>" type="text/css" />
-  <base target="docwin" />
-</head>
-<body>
-<div class="index">
-  <h1 class="section-bar"><%= values["list_title"] %></h1>
-  <div class="index-entries">
-<% values["entries"].each do |entries| %>
-    <a href="<%= entries["href"] %>"><%= entries["name"] %></a><br />
-<% end %><%# values["entries"] %>
-  </div>
-</div>
-</body>
-</html>
-  EOF
-
-  CLASS_INDEX = FILE_INDEX
-  METHOD_INDEX = FILE_INDEX
-
-  INDEX = <<-EOF
-<?xml version="1.0" encoding="<%= values["charset"] %>"?>
-<!DOCTYPE html
-     PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
-     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head>
-  <title><%= values["title"] %></title>
-  <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
-</head>
-<frameset rows="20%, 80%">
-  <frameset cols="45%,55%">
-    <frame src="fr_class_index.html"  name="Classes" />
-    <frame src="fr_method_index.html" name="Methods" />
-  </frameset>
-  <frame src="<%= values["initial_page"] %>" name="docwin" />
-</frameset>
-</html>
-  EOF
+  CLASS_INDEX = RDoc::Generator::HTML::HTML::CLASS_INDEX
 
+  METHOD_INDEX = RDoc::Generator::HTML::HTML::METHOD_INDEX
 end
-
diff --git a/lib/rdoc/generator/html/hefss.rb b/lib/rdoc/generator/html/hefss.rb
index e186a40384..540c23d869 100644
--- a/lib/rdoc/generator/html/hefss.rb
+++ b/lib/rdoc/generator/html/hefss.rb
@@ -1,16 +1,16 @@
 require 'rdoc/generator/html'
-require 'rdoc/generator/html/html'
+require 'rdoc/generator/html/kilmerfactory'
 
 module RDoc::Generator::HTML::HEFSS
 
   FONTS = "Verdana, Arial, Helvetica, sans-serif"
 
-STYLE = <<-EOF
-body,p { font-family: Verdana, Arial, Helvetica, sans-serif;
+  CENTRAL_STYLE = <<-EOF
+body,p { font-family: <%= values["fonts"] %>;
        color: #000040; background: #BBBBBB;
 }
 
-td { font-family: Verdana, Arial, Helvetica, sans-serif;
+td { font-family: <%= values["fonts"] %>;
        color: #000040;
 }
 
@@ -21,16 +21,20 @@ td { font-family: Verdana, Arial, Helvetica, sans-serif;
 }
 
 .big-title-font { color: white;
-                  font-family: Verdana, Arial, Helvetica, sans-serif;
+                  font-family: <%= values["fonts"] %>;
                   font-size: large;
                   height: 50px}
 
 .small-title-font { color: purple;
-                    font-family: Verdana, Arial, Helvetica, sans-serif;
+                    font-family: <%= values["fonts"] %>;
                     font-size: small; }
 
 .aqua { color: purple }
 
+#diagram img {
+  border: 0;
+}
+
 .method-name, attr-name {
       font-family: monospace; font-weight: bold;
 }
@@ -75,241 +79,6 @@ td { font-family: Verdana, Arial, Helvetica, sans-serif;
   color: #0000AA;
 }
 
-.column-title {
-  font-size: medium;
-  font-weight: bold;
-  text_decoration: none;
-  padding: 3px 3px 3px 20px;
-  color: #3333CC;
-  }
-
-.variable-name {
-  font-family: monospace;
-  font-size: medium;
-  text_decoration: none;
-  padding: 3px 3px 3px 20px;
-  color: #0000AA;
-}
-
-.row-name {
-  font-size: medium;
-  font-weight: medium;
-  font-family: monospace;
-  text_decoration: none;
-  padding: 3px 3px 3px 20px;
-}
-
-.paramsig {
-   font-size: small;
-}
-
-.srcbut { float: right }
-
-  EOF
-
-  BODY = <<-EOF
-<html><head>
-  <title><%= values["title"] %></title>
-  <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>">
-  <link rel="stylesheet" href="<%= values["style_url"] %>" type="text/css" media="screen" />
-  <script type="text/javascript" language="JavaScript">
-  <!--
-  function popCode(url) {
-    parent.frames.source.location = url
-  }
-  //-->
-  </script>
-</head>
-<body bgcolor="#BBBBBB">
-
-<%= template_include %>  <!-- banner header -->
-
-<% if values["diagram"] then %>
-<table width="100%"><tr><td align="center">
-<%= values["diagram"] %>
-</td></tr></table>
-<% end %>
-
-<% if values["description"] then %>
-<div class="description"><%= values["description"] %></div>
-<% end %>
-
-<% if values["requires"] then %>
-<table cellpadding="5" width="100%">
-<tr><td class="tablesubtitle">Required files</td></tr>
-</table><br />
-<div class="name-list">
-<% values["requires"].each do |requires| %>
-<%= href requires["aref"], requires["name"] %>
-<% end %><%# values["requires"] %>
-<% end %>
-</div>
-
-<% if values["sections"] then %>
-<% values["sections"].each do |sections| %>
-<% if sections["method_list"] then %>
-<% sections["method_list"].each do |method_list| %>
-<% if method_list["methods"] then %>
-<table cellpadding="5" width="100%">
-<tr><td class="tablesubtitle">Subroutines and Functions</td></tr>
-</table><br />
-<div class="name-list">
-<% method_list["methods"].each do |methods| %>
-<a href="<%= methods["codeurl"] %>" target="source"><%= methods["name"] %></a>
-<% end %><%# values["methods"] %>
-</div>
-<% end %>
-<% end %><%# values["method_list"] %>
-<% end %>
-
-<% if sections["attributes"] then %>
-<table cellpadding="5" width="100%">
-<tr><td class="tablesubtitle">Arguments</td></tr>
-</table><br />
-<table cellspacing="5">
-<% sections["attributes"].each do |attributes| %>
-     <tr valign="top">
-<% if attributes["rw"] then %>
-       <td align="center" class="attr-rw">&nbsp;[<%= attributes["rw"] %>]&nbsp;</td>
-<% end %>
-<% unless attributes["rw"] then %>
-       <td></td>
-<% end %>
-       <td class="attr-name"><%= attributes["name"] %></td>
-       <td><%= attributes["a_desc"] %></td>
-     </tr>
-<% end %><%# values["attributes"] %>
-</table>
-<% end %>
-<% end %><%# values["sections"] %>
-<% end %>
-
-<% if values["classlist"] then %>
-<table cellpadding="5" width="100%">
-<tr><td class="tablesubtitle">Modules</td></tr>
-</table><br />
-<%= values["classlist"] %><br />
-<% end %>
-
-  <%= template_include %>  <!-- method descriptions -->
-
-</body>
-</html>
-  EOF
-
-  FILE_PAGE = <<-EOF
-<table width="100%">
- <tr class="title-row">
- <td><table width="100%"><tr>
-   <td class="big-title-font" colspan="2"><font size="-3"><b>File</b><br /></font><%= values["short_name"] %></td>
-   <td align="right"><table cellspacing="0" cellpadding="2">
-         <tr>
-           <td  class="small-title-font">Path:</td>
-           <td class="small-title-font"><%= values["full_path"] %>
-<% if values["cvsurl"] then %>
-				&nbsp;(<a href="<%= values["cvsurl"] %>"><acronym title="Concurrent Versioning System">CVS</acronym></a>)
-<% end %>
-           </td>
-         </tr>
-         <tr>
-           <td class="small-title-font">Modified:</td>
-           <td class="small-title-font"><%= values["dtm_modified"] %></td>
-         </tr>
-        </table>
-    </td></tr></table></td>
-  </tr>
-</table><br />
-  EOF
-
-  CLASS_PAGE = <<-EOF
-<table width="100%" border="0" cellspacing="0">
- <tr class="title-row">
- <td class="big-title-font">
-   <font size="-3"><b><%= values["classmod"] %></b><br /></font><%= values["full_name"] %>
- </td>
- <td align="right">
-   <table cellspacing="0" cellpadding="2">
-     <tr valign="top">
-      <td class="small-title-font">In:</td>
-      <td class="small-title-font">
-<% values["infiles"].each do |infiles| %>
-<%= href infiles["full_path_url"], infiles["full_path"] %>
-<% if infiles["cvsurl"] then %>
-&nbsp;(<a href="<%= infiles["cvsurl"] %>"><acronym title="Concurrent Versioning System">CVS</acronym></a>)
-<% end %>
-<% end %><%# values["infiles"] %>
-      </td>
-     </tr>
-<% if values["parent"] then %>
-     <tr>
-      <td class="small-title-font">Parent:</td>
-      <td class="small-title-font">
-<% if values["par_url"] then %>
-        <a href="<%= values["par_url"] %>" class="cyan">
-<% end %>
-<%= values["parent"] %>
-<% if values["par_url"] then %>
-         </a>
-<% end %>
-      </td>
-     </tr>
-<% end %>
-   </table>
-  </td>
-  </tr>
-</table><br />
-  EOF
-
-  METHOD_LIST = <<-EOF
-<% if values["includes"] then %>
-<div class="tablesubsubtitle">Uses</div><br />
-<div class="name-list">
-<% values["includes"].each do |includes| %>
-    <span class="method-name"><%= href includes["aref"], includes["name"] %></span>
-<% end %><%# values["includes"] %>
-</div>
-<% end %>
-
-<% if values["sections"] then %>
-<% values["sections"].each do |sections| %>
-<% if sections["method_list"] then %>
-<% sections["method_list"].each do |method_list| %>
-<% if method_list["methods"] then %>
-<table cellpadding="5" width="100%">
-<tr><td class="tablesubtitle"><%= method_list["type"] %> <%= method_list["category"] %> methods</td></tr>
-</table>
-<% method_list["methods"].each do |methods| %>
-<table width="100%" cellspacing="0" cellpadding="5" border="0">
-<tr><td class="methodtitle">
-<a name="<%= methods["aref"] %>">
-<b><%= methods["name"] %></b><%= methods["params"] %>
-<% if methods["codeurl"] then %>
-<a href="<%= methods["codeurl"] %>" target="source" class="srclink">src</a>
-<% end %>
-</a></td></tr>
-</table>
-<% if method_list["m_desc"] then %>
-<div class="description">
-<%= method_list["m_desc"] %>
-</div>
-<% end %>
-<% end %><%# method_list["methods"] %>
-<% end %>
-<% end %><%# sections["method_list"] %>
-<% end %>
-<% end %><%# values["sections"] %>
-<% end %>
-  EOF
-
-  SRC_PAGE = <<-EOF
-<html>
-<head><title><%= values["title"] %></title>
-<meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>">
-<style type="text/css">
-  .kw { color: #3333FF; font-weight: bold }
-  .cmt { color: green; font-style: italic }
-  .str { color: #662222; font-style: italic }
-  .re  { color: #662222; }
 .ruby-comment    { color: green; font-style: italic }
 .ruby-constant   { color: #4433aa; font-weight: bold; }
 .ruby-identifier { color: #222222;  }
@@ -319,35 +88,23 @@ td { font-family: Verdana, Arial, Helvetica, sans-serif;
 .ruby-operator   { color: #111111;  }
 .ruby-regexp     { color: #662222; }
 .ruby-value      { color: #662222; font-style: italic }
-</style>
-</head>
-<body bgcolor="#BBBBBB">
-<pre><%= values["code"] %></pre>
-</body>
-</html>
+
+.srcbut { float: right }
   EOF
 
-  FR_INDEX_BODY = %{
-<%= template_include %>
+  INDEX_STYLE = <<-EOF
+body {
+  background-color: #bbbbbb;
+  font-family: #{FONTS};
+  font-size: 11px;
+  font-style: normal;
+  line-height: 14px;
+  color: #000040;
 }
 
-  FILE_INDEX = <<-EOF
-<html>
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>">
-<style type="text/css">
-<!--
-  body {
-background-color: #bbbbbb;
-     font-family: #{FONTS};
-       font-size: 11px;
-      font-style: normal;
-     line-height: 14px;
-           color: #000040;
-  }
 div.banner {
   background: #bbbbcc;
-  color:      white;
+  color: white;
   padding: 1;
   margin: 0;
   font-size: 90%;
@@ -356,59 +113,38 @@ div.banner {
   text-align: center;
   width: 100%;
 }
+EOF
 
--->
-</style>
-<base target="docwin">
-</head>
-<body>
-<div class="banner"><%= values["list_title"] %></div>
-<% values["entries"].each do |entries| %>
-<a href="<%= entries["href"] %>"><%= entries["name"] %></a><br />
-<% end %><%# values["entries"] %>
-</body></html>
-  EOF
+  FACTORY = RDoc::Generator::HTML::
+    KilmerFactory.new(:central_css => CENTRAL_STYLE,
+                      :index_css => INDEX_STYLE,
+                      :method_list_heading => "Subroutines and Functions",
+                      :class_and_module_list_heading => "Classes and Modules",
+                      :attribute_list_heading => "Arguments")
 
-  CLASS_INDEX = FILE_INDEX
-  METHOD_INDEX = FILE_INDEX
+  STYLE = FACTORY.get_STYLE()
 
-  INDEX = <<-EOF
-<html>
-<head>
-  <title><%= values["title"] %></title>
-  <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>">
-</head>
+  METHOD_LIST = FACTORY.get_METHOD_LIST()
+  
+  BODY = FACTORY.get_BODY()
+  
+  FILE_PAGE = FACTORY.get_FILE_PAGE()
 
-<frameset cols="20%,*">
-    <frameset rows="15%,35%,50%">
-        <frame src="fr_file_index.html"   title="Files" name="Files">
-        <frame src="fr_class_index.html"  name="Modules">
-        <frame src="fr_method_index.html" name="Subroutines and Functions">
-    </frameset>
-    <frameset rows="80%,20%">
-      <frame  src="<%= values["initial_page"] %>" name="docwin">
-      <frame  src="blank.html" name="source">
-    </frameset>
-    <noframes>
-          <body bgcolor="#BBBBBB">
-            Click <a href="html/index.html">here</a> for a non-frames
-            version of this page.
-          </body>
-    </noframes>
-</frameset>
+  CLASS_PAGE = FACTORY.get_CLASS_PAGE()
 
-</html>
-  EOF
+  SRC_PAGE = FACTORY.get_SRC_PAGE()
 
-  # Blank page to use as a target
-  BLANK = %{
-<html><body bgcolor="#BBBBBB"></body></html>
-}
+  FR_INDEX_BODY = FACTORY.get_FR_INDEX_BODY()
 
-  def write_extra_pages
-    template = TemplatePage.new(BLANK)
-    File.open("blank.html", "w") { |f| template.write_html_on(f, {}) }
+  FILE_INDEX = FACTORY.get_FILE_INDEX()
+
+  CLASS_INDEX = FACTORY.get_CLASS_INDEX()
+
+  METHOD_INDEX = FACTORY.get_METHOD_INDEX()
+
+  INDEX = FACTORY.get_INDEX()
+
+  def self.write_extra_pages(values)
+    FACTORY.write_extra_pages(values)
   end
-
 end
-
diff --git a/lib/rdoc/generator/html/html.rb b/lib/rdoc/generator/html/html.rb
index 1ab90c6264..823d8056e7 100644
--- a/lib/rdoc/generator/html/html.rb
+++ b/lib/rdoc/generator/html/html.rb
@@ -1,15 +1,17 @@
 require 'rdoc/generator/html'
-require 'rdoc/generator/html/one_page_html'
+require 'rdoc/generator/html/common'
 
 ##
 # = CSS2 RDoc HTML template
 #
-# This is a template for RDoc that uses XHTML 1.0 Transitional and dictates a
+# This is a template for RDoc that uses XHTML 1.0 Strict and dictates a
 # bit more of the appearance of the output to cascading stylesheets than the
 # default. It was designed for clean inline code display, and uses DHTMl to
 # toggle the visibility of each method's source with each click on the
 # '[source]' link.
 #
+# This template *also* forms the basis of the frameless template.
+# 
 # == Authors
 #
 # * Michael Granger <ged@FaerieMUD.org>
@@ -23,34 +25,54 @@ require 'rdoc/generator/html/one_page_html'
 
 module RDoc::Generator::HTML::HTML
 
+  include RDoc::Generator::HTML::Common
+
   FONTS = "Verdana,Arial,Helvetica,sans-serif"
 
   STYLE = <<-EOF
 body {
-    font-family: Verdana,Arial,Helvetica,sans-serif;
-    font-size:   90%;
-    margin: 0;
-    margin-left: 40px;
-    padding: 0;
-    background: white;
+  font-family: #{FONTS};
+  font-size: 90%;
+  margin: 0;
+  margin-left: 40px;
+  padding: 0;
+  background: white;
+  color: black;
 }
 
-h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
-h1 { font-size: 150%; }
-h2,h3,h4 { margin-top: 1em; }
+h1, h2, h3, h4 {
+  margin: 0;
+  background: transparent;
+}
 
-a { background: #eef; color: #039; text-decoration: none; }
-a:hover { background: #039; color: #eef; }
+h1 {
+  font-size: 150%;
+}
+
+h2,h3,h4 {
+  margin-top: 1em;
+}
+
+:link, :visited {
+  background: #eef;
+  color: #039;
+  text-decoration: none;
+}
+
+:link:hover, :visited:hover {
+  background: #039;
+  color: #eef;
+}
 
 /* Override the base stylesheet's Anchor inside a table cell */
-td > a {
+td > :link, td > :visited {
   background: transparent;
   color: #039;
   text-decoration: none;
 }
 
 /* and inside a section title */
-.section-title > a {
+.section-title > :link, .section-title > :visited {
   background: transparent;
   color: #eee;
   text-decoration: none;
@@ -58,181 +80,255 @@ td > a {
 
 /* === Structural elements =================================== */
 
-div#index {
-    margin: 0;
-    margin-left: -40px;
-    padding: 0;
-    font-size: 90%;
+.index {
+  margin: 0;
+  margin-left: -40px;
+  padding: 0;
+  font-size: 90%;
 }
 
-
-div#index a {
-    margin-left: 0.7em;
+.index :link, .index :visited {
+  margin-left: 0.7em;
 }
 
-div#index .section-bar {
-   margin-left: 0px;
-   padding-left: 0.7em;
-   background: #ccc;
-   font-size: small;
+.index .section-bar {
+  margin-left: 0px;
+  padding-left: 0.7em;
+  background: #ccc;
+  font-size: small;
 }
 
-
-div#classHeader, div#fileHeader {
-    width: auto;
-    color: white;
-    padding: 0.5em 1.5em 0.5em 1.5em;
-    margin: 0;
-    margin-left: -40px;
-    border-bottom: 3px solid #006;
+#classHeader, #fileHeader {
+  width: auto;
+  color: white;
+  padding: 0.5em 1.5em 0.5em 1.5em;
+  margin: 0;
+  margin-left: -40px;
+  border-bottom: 3px solid #006;
 }
 
-div#classHeader a, div#fileHeader a {
-    background: inherit;
-    color: white;
+#classHeader :link, #fileHeader :link,
+#classHeader :visited, #fileHeader :visited {
+  background: inherit;
+  color: white;
 }
 
-div#classHeader td, div#fileHeader td {
-    background: inherit;
-    color: white;
+#classHeader td, #fileHeader td {
+  background: inherit;
+  color: white;
 }
 
-
-div#fileHeader {
-    background: #057;
+#fileHeader {
+  background: #057;
 }
 
-div#classHeader {
-    background: #048;
+#classHeader {
+  background: #048;
 }
 
-
 .class-name-in-header {
   font-size:  180%;
   font-weight: bold;
 }
 
-
-div#bodyContent {
-    padding: 0 1.5em 0 1.5em;
+#bodyContent {
+  padding: 0 1.5em 0 1.5em;
 }
 
-div#description {
-    padding: 0.5em 1.5em;
-    background: #efefef;
-    border: 1px dotted #999;
+#description {
+  padding: 0.5em 1.5em;
+  background: #efefef;
+  border: 1px dotted #999;
 }
 
-div#description h1,h2,h3,h4,h5,h6 {
-    color: #125;;
-    background: transparent;
+#description h1, #description h2, #description h3,
+#description h4, #description h5, #description h6 {
+  color: #125;
+  background: transparent;
 }
 
-div#validator-badges {
-    text-align: center;
-}
-div#validator-badges img { border: 0; }
-
-div#copyright {
-    color: #333;
-    background: #efefef;
-    font: 0.75em sans-serif;
-    margin-top: 5em;
-    margin-bottom: 0;
-    padding: 0.5em 2em;
+#validator-badges {
+  text-align: center;
 }
 
+#validator-badges img {
+  border: 0;
+}
+
+#copyright {
+  color: #333;
+  background: #efefef;
+  font: 0.75em sans-serif;
+  margin-top: 5em;
+  margin-bottom: 0;
+  padding: 0.5em 2em;
+}
 
 /* === Classes =================================== */
 
 table.header-table {
-    color: white;
-    font-size: small;
+  color: white;
+  font-size: small;
 }
 
 .type-note {
-    font-size: small;
-    color: #DEDEDE;
-}
-
-.xxsection-bar {
-    background: #eee;
-    color: #333;
-    padding: 3px;
+  font-size: small;
+  color: #dedede;
 }
 
 .section-bar {
-   color: #333;
-   border-bottom: 1px solid #999;
-    margin-left: -20px;
+  color: #333;
+  border-bottom: 1px solid #999;
+  margin-left: -20px;
 }
 
-
 .section-title {
-    background: #79a;
-    color: #eee;
-    padding: 3px;
-    margin-top: 2em;
-    margin-left: -30px;
-    border: 1px solid #999;
+  background: #79a;
+  color: #eee;
+  padding: 3px;
+  margin-top: 2em;
+  margin-left: -30px;
+  border: 1px solid #999;
 }
 
-.top-aligned-row {  vertical-align: top }
-.bottom-aligned-row { vertical-align: bottom }
+.top-aligned-row {
+  vertical-align: top
+}
+
+.bottom-aligned-row {
+  vertical-align: bottom
+}
+
+#diagram img {
+  border: 0;
+}
 
 /* --- Context section classes ----------------------- */
 
 .context-row { }
-.context-item-name { font-family: monospace; font-weight: bold; color: black; }
-.context-item-value { font-size: small; color: #448; }
-.context-item-desc { color: #333; padding-left: 2em; }
+
+.context-item-name {
+  font-family: monospace;
+  font-weight: bold;
+  color: black;
+}
+
+.context-item-value {
+  font-size: small;
+  color: #448;
+}
+
+.context-item-desc {
+  color: #333;
+  padding-left: 2em;
+}
 
 /* --- Method classes -------------------------- */
+
 .method-detail {
-    background: #efefef;
-    padding: 0;
-    margin-top: 0.5em;
-    margin-bottom: 1em;
-    border: 1px dotted #ccc;
+  background: #efefef;
+  padding: 0;
+  margin-top: 0.5em;
+  margin-bottom: 1em;
+  border: 1px dotted #ccc;
 }
+
 .method-heading {
   color: black;
   background: #ccc;
   border-bottom: 1px solid #666;
   padding: 0.2em 0.5em 0 0.5em;
 }
-.method-signature { color: black; background: inherit; }
-.method-name { font-weight: bold; }
-.method-args { font-style: italic; }
-.method-description { padding: 0 0.5em 0 0.5em; }
+
+.method-signature {
+  color: black;
+  background: inherit;
+}
+
+.method-name {
+  font-weight: bold;
+}
+
+.method-args {
+  font-style: italic;
+}
+
+.method-description {
+  padding: 0 0.5em 0 0.5em;
+}
 
 /* --- Source code sections -------------------- */
 
-a.source-toggle { font-size: 90%; }
-div.method-source-code {
-    background: #262626;
-    color: #ffdead;
-    margin: 1em;
-    padding: 0.5em;
-    border: 1px dashed #999;
-    overflow: hidden;
+:link.source-toggle, :visited.source-toggle {
+  font-size: 90%;
 }
 
-div.method-source-code pre { color: #ffdead; overflow: hidden; }
+div.method-source-code {
+  background: #262626;
+  color: #ffdead;
+  margin: 1em;
+  padding: 0.5em;
+  border: 1px dashed #999;
+  overflow: auto;
+}
+
+div.method-source-code pre {
+  color: #ffdead;
+}
 
 /* --- Ruby keyword styles --------------------- */
 
-.standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
+.standalone-code {
+  background: #221111;
+  color: #ffdead;
+  overflow: auto;
+}
 
-.ruby-constant  { color: #7fffd4; background: transparent; }
-.ruby-keyword { color: #00ffff; background: transparent; }
-.ruby-ivar    { color: #eedd82; background: transparent; }
-.ruby-operator  { color: #00ffee; background: transparent; }
-.ruby-identifier { color: #ffdead; background: transparent; }
-.ruby-node    { color: #ffa07a; background: transparent; }
-.ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
-.ruby-regexp  { color: #ffa07a; background: transparent; }
-.ruby-value   { color: #7fffd4; background: transparent; }
+.ruby-constant {
+  color: #7fffd4;
+  background: transparent;
+}
+
+.ruby-keyword {
+  color: #00ffff;
+  background: transparent;
+}
+
+.ruby-ivar {
+  color: #eedd82;
+  background: transparent;
+}
+
+.ruby-operator {
+  color: #00ffee;
+  background: transparent;
+}
+
+.ruby-identifier {
+  color: #ffdead;
+  background: transparent;
+}
+
+.ruby-node {
+  color: #ffa07a;
+  background: transparent;
+}
+
+.ruby-comment {
+  color: #b22222;
+  font-weight: bold;
+  background: transparent;
+}
+
+.ruby-regexp {
+  color: #ffa07a;
+  background: transparent;
+}
+
+.ruby-value {
+  color: #7fffd4;
+  background: transparent;
+}
 EOF
 
 
@@ -240,15 +336,7 @@ EOF
 ### H E A D E R   T E M P L A T E
 #####################################################################
 
-  XHTML_PREAMBLE = <<-EOF
-<?xml version="1.0" encoding="<%= values["charset"] %>"?>
-<!DOCTYPE html
-     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-  EOF
-
-  HEADER = XHTML_PREAMBLE + <<-EOF
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+  HEADER = XHTML_STRICT_PREAMBLE + HTML_ELEMENT + <<-EOF
 <head>
   <title><%= values["title"] %></title>
   <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
@@ -281,7 +369,7 @@ EOF
   }
 
   // Make codeblocks hidden by default
-  document.writeln( "<style type=\\"text/css\\">div.method-source-code { display: none }</style>" )
+  document.writeln( "<style type=\\"text/css\\">div.method-source-code { display: none }<\\/style>" )
 
   // ]]>
   </script>
@@ -290,13 +378,6 @@ EOF
 <body>
 EOF
 
-#####################################################################
-### C O N T E X T   C O N T E N T   T E M P L A T E
-#####################################################################
-
-  CONTEXT_CONTENT = %{
-}
-
 #####################################################################
 ### F O O T E R   T E M P L A T E
 #####################################################################
@@ -480,8 +561,8 @@ EOF
           <td class="context-item-name"><%= constants["name"] %></td>
           <td>=</td>
           <td class="context-item-value"><%= constants["value"] %></td>
-<%       if sections["desc"] then %>
-          <td width="3em">&nbsp;</td>
+<%       if constants["desc"] then %>
+          <td>&nbsp;</td>
           <td class="context-item-desc"><%= constants["desc"] %></td>
 <%       end %>
         </tr>
@@ -616,8 +697,7 @@ EOF
 ### S O U R C E   C O D E   T E M P L A T E
 #####################################################################
 
-  SRC_PAGE = XHTML_PREAMBLE + <<-EOF
-<html>
+  SRC_PAGE = XHTML_STRICT_PREAMBLE + HTML_ELEMENT + <<-EOF
 <head>
   <title><%= values["title"] %></title>
   <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
@@ -634,25 +714,22 @@ EOF
 ### I N D E X   F I L E   T E M P L A T E S
 #####################################################################
 
-  FR_INDEX_BODY = %{
-<%= template_include %>
-}
+  FR_INDEX_BODY = %{<%= template_include %>}
 
-  FILE_INDEX = XHTML_PREAMBLE + <<-EOF
+  FILE_INDEX = XHTML_STRICT_PREAMBLE + HTML_ELEMENT + <<-EOF
 <!--
 
-    <%= values["list_title"] %>
+    <%= values["title"] %>
 
   -->
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 <head>
-  <title><%= values["list_title"] %></title>
+  <title><%= values["title"] %></title>
   <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
   <link rel="stylesheet" href="<%= values["style_url"] %>" type="text/css" />
   <base target="docwin" />
 </head>
 <body>
-<div id="index">
+<div class="index">
   <h1 class="section-bar"><%= values["list_title"] %></h1>
   <div id="index-entries">
 <% values["entries"].each do |entries| %>
@@ -667,18 +744,12 @@ EOF
   CLASS_INDEX = FILE_INDEX
   METHOD_INDEX = FILE_INDEX
 
-  INDEX = <<-EOF
-<?xml version="1.0" encoding="<%= values["charset"] %>"?>
-<!DOCTYPE html
-     PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
-     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
-
+  INDEX = XHTML_FRAME_PREAMBLE + HTML_ELEMENT + <<-EOF
 <!--
 
     <%= values["title"] %>
 
   -->
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 <head>
   <title><%= values["title"] %></title>
   <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
diff --git a/lib/rdoc/generator/html/kilmer.rb b/lib/rdoc/generator/html/kilmer.rb
index 6479abaf8b..4c5a9ee8b0 100644
--- a/lib/rdoc/generator/html/kilmer.rb
+++ b/lib/rdoc/generator/html/kilmer.rb
@@ -1,10 +1,11 @@
 require 'rdoc/generator/html'
+require 'rdoc/generator/html/kilmerfactory'
 
 module RDoc::Generator::HTML::KILMER
 
   FONTS = "Verdana, Arial, Helvetica, sans-serif"
 
-  STYLE = <<-EOF
+  CENTRAL_STYLE = <<-EOF
 body,td,p { font-family: <%= values["fonts"] %>;
        color: #000040;
 }
@@ -30,6 +31,10 @@ body,td,p { font-family: <%= values["fonts"] %>;
 
 .aqua { color: black }
 
+#diagram img {
+  border: 0;
+}
+
 .method-name, .attr-name {
       font-family: font-family: <%= values["fonts"] %>;
       font-weight: bold;
@@ -67,7 +72,7 @@ body,td,p { font-family: <%= values["fonts"] %>;
   font-weight: bold;
   text-decoration: none;
   color: #000033;
-  background-color: white;
+  background: #ccc;
 }
 
 .srclink {
@@ -78,232 +83,8 @@ body,td,p { font-family: <%= values["fonts"] %>;
   background-color: white;
 }
 
-.paramsig {
-   font-size: small;
-}
-
 .srcbut { float: right }
-  EOF
 
-  BODY = <<-EOF
-<html><head>
-  <title><%= values["title"] %></title>
-  <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>">
-  <link rel="stylesheet" href="<%= values["style_url"] %>" type="text/css" media="screen" />
-  <script type="text/javascript" language="JavaScript">
-  <!--
-  function popCode(url) {
-    parent.frames.source.location = url
-  }
-  //-->
-  </script>
-</head>
-<body bgcolor="white">
-
-<%= template_include %>  <!-- banner header -->
-
-<% if values["diagram"] then %>
-<table width="100%"><tr><td align="center">
-<%= values["diagram"] %>
-</td></tr></table>
-<% end %>
-
-<% if values["description"] then %>
-<div class="description"><%= values["description"] %></div>
-<% end %>
-
-<% if values["requires"] then %>
-<table cellpadding="5" width="100%">
-<tr><td class="tablesubtitle">Required files</td></tr>
-</table><br />
-<div class="name-list">
-<% values["requires"].each do |requires| %>
-<%= href requires["aref"], requires["name"] %>
-<% end %><%# values["requires"] %>
-<% end %>
-</div>
-
-<% if values["methods"] then %>
-<table cellpadding="5" width="100%">
-<tr><td class="tablesubtitle">Methods</td></tr>
-</table><br />
-<div class="name-list">
-<% values["methods"].each do |methods| %>
-<%= href methods["aref"], methods["name"] %>,
-<% end %><%# values["methods"] %>
-</div>
-<% end %>
-
-
-<% values["sections"].each do |sections| %>
-    <div id="section">
-<% if sections["sectitle"] then %>
-      <h2 class="section-title"><a name="<%= sections["secsequence"] %>"><%= sections["sectitle"] %></a></h2>
-<% if sections["seccomment"] then %>
-      <div class="section-comment">
-        <%= sections["seccomment"] %>
-      </div>
-<% end %>
-<% end %>
-
-<% if sections["attributes"] then %>
-<table cellpadding="5" width="100%">
-<tr><td class="tablesubtitle">Attributes</td></tr>
-</table><br />
-<table cellspacing="5">
-<% sections["attributes"].each do |attributes| %>
-     <tr valign="top">
-<% if attributes["rw"] then %>
-       <td align="center" class="attr-rw">&nbsp;[<%= attributes["rw"] %>]&nbsp;</td>
-<% end %>
-<% unless attributes["rw"] then %>
-       <td></td>
-<% end %>
-       <td class="attr-name"><%= attributes["name"] %></td>
-       <td><%= attributes["a_desc"] %></td>
-     </tr>
-<% end %><%# sections["attributes"] %>
-</table>
-<% end %>
-
-<% if sections["classlist"] then %>
-<table cellpadding="5" width="100%">
-<tr><td class="tablesubtitle">Classes and Modules</td></tr>
-</table><br />
-<%= sections["classlist"] %><br />
-<% end %>
-
-  <%= template_include %>  <!-- method descriptions -->
-
-<% end %><%# values["sections"] %>
-
-</body>
-</html>
-  EOF
-
-  FILE_PAGE = <<-EOF
-<table width="100%">
- <tr class="title-row">
- <td><table width="100%"><tr>
-   <td class="big-title-font" colspan="2"><font size="-3"><b>File</b><br /></font><%= values["short_name"] %></td>
-   <td align="right"><table cellspacing="0" cellpadding="2">
-         <tr>
-           <td  class="small-title-font">Path:</td>
-           <td class="small-title-font"><%= values["full_path"] %>
-<% if values["cvsurl"] then %>
-				&nbsp;(<a href="<%= values["cvsurl"] %>"><acronym title="Concurrent Versioning System">CVS</acronym></a>)
-<% end %>
-           </td>
-         </tr>
-         <tr>
-           <td class="small-title-font">Modified:</td>
-           <td class="small-title-font"><%= values["dtm_modified"] %></td>
-         </tr>
-        </table>
-    </td></tr></table></td>
-  </tr>
-</table><br />
-  EOF
-
-  CLASS_PAGE = <<-EOF
-<table width="100%" border="0" cellspacing="0">
- <tr class="title-row">
- <td class="big-title-font">
-   <font size="-3"><b><%= values["classmod"] %></b><br /></font><%= values["full_name"] %>
- </td>
- <td align="right">
-   <table cellspacing="0" cellpadding="2">
-     <tr valign="top">
-      <td class="small-title-font">In:</td>
-      <td class="small-title-font">
-<% values["infiles"].each do |infiles| %>
-<%= href infiles["full_path_url"], infiles["full_path"] %>
-<% if infiles["cvsurl"] then %>
-&nbsp;(<a href="<%= infiles["cvsurl"] %>"><acronym title="Concurrent Versioning System">CVS</acronym></a>)
-<% end %>
-<% end %><%# values["infiles"] %>
-      </td>
-     </tr>
-<% if values["parent"] then %>
-     <tr>
-      <td class="small-title-font">Parent:</td>
-      <td class="small-title-font">
-<% if values["par_url"] then %>
-        <a href="<%= values["par_url"] %>" class="cyan">
-<% end %>
-<%= values["parent"] %>
-<% if values["par_url"] then %>
-         </a>
-<% end %>
-      </td>
-     </tr>
-<% end %>
-   </table>
-  </td>
-  </tr>
-</table><br />
-  EOF
-
-  METHOD_LIST = <<-EOF
-<% if values["includes"] then %>
-<div class="tablesubsubtitle">Included modules</div><br />
-<div class="name-list">
-<% values["includes"].each do |includes| %>
-    <span class="method-name"><%= href includes["aref"], includes["name"] %></span>
-<% end %><%# values["includes"] %>
-</div>
-<% end %>
-
-<% if values["method_list"] then %>
-<% values["method_list"].each do |method_list| $stderr.puts({ :method_list => method_list }.inspect) %>
-<% if values["methods"] then %>
-<table cellpadding=5 width="100%">
-<tr><td class="tablesubtitle"><%= values["type"] %> <%= values["category"] %> methods</td></tr>
-</table>
-<% values["methods"].each do |methods| $stderr.puts({ :methods => methods }.inspect) %>
-<table width="100%" cellspacing="0" cellpadding="5" border="0">
-<tr><td class="methodtitle">
-<a name="<%= values["aref"] %>">
-<% if values["callseq"] then %>
-<b><%= values["callseq"] %></b>
-<% end %>
-<% unless values["callseq"] then %>
- <b><%= values["name"] %></b><%= values["params"] %>
-<% end %>
-<% if values["codeurl"] then %>
-<a href="<%= values["codeurl"] %>" target="source" class="srclink">src</a>
-<% end %>
-</a></td></tr>
-</table>
-<% if values["m_desc"] then %>
-<div class="description">
-<%= values["m_desc"] %>
-</div>
-<% end %>
-<% if values["aka"] then %>
-<div class="aka">
-This method is also aliased as
-<% values["aka"].each do |aka| $stderr.puts({ :aka => aka }.inspect) %>
-<a href="<%= values["aref"] %>"><%= values["name"] %></a>
-<% end %><%# values["aka"] %>
-</div>
-<% end %>
-<% if values["sourcecode"] then %>
-<pre class="source">
-<%= values["sourcecode"] %>
-</pre>
-<% end %>
-<% end %><%# values["methods"] %>
-<% end %>
-<% end %><%# values["method_list"] %>
-<% end %>
-  EOF
-
-  SRC_PAGE = <<-EOF
-<html>
-<head><title><%= values["title"] %></title>
-<meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>">
-<style type="text/css">
 .ruby-comment    { color: green; font-style: italic }
 .ruby-constant   { color: #4433aa; font-weight: bold; }
 .ruby-identifier { color: #222222;  }
@@ -313,28 +94,9 @@ This method is also aliased as
 .ruby-operator   { color: #111111;  }
 .ruby-regexp     { color: #662222; }
 .ruby-value      { color: #662222; font-style: italic }
-  .kw { color: #3333FF; font-weight: bold }
-  .cmt { color: green; font-style: italic }
-  .str { color: #662222; font-style: italic }
-  .re  { color: #662222; }
-</style>
-</head>
-<body bgcolor="white">
-<pre><%= values["code"] %></pre>
-</body>
-</html>
   EOF
 
-  FR_INDEX_BODY = %{
-<%= template_include %>
-}
-
-  FILE_INDEX = <<-EOF
-<html>
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>">
-<style>
-<!--
+  INDEX_STYLE = <<-EOF
 body {
   background-color: #ddddff;
   font-family: #{FONTS};
@@ -355,64 +117,35 @@ div.banner {
   text-align: center;
   width: 100%;
 }
+EOF
 
--->
-</style>
-<base target="docwin">
-</head>
-<body>
-<div class="banner"><%= values["list_title"] %></div>
-<% values["entries"].each do |entries| %>
-<a href="<%= entries["href"] %>"><%= entries["name"] %></a><br />
-<% end %><%# values["entries"] %>
-</body></html>
-  EOF
+  FACTORY = RDoc::Generator::HTML::
+    KilmerFactory.new(:central_css => CENTRAL_STYLE,
+                      :index_css => INDEX_STYLE)
 
-  CLASS_INDEX = FILE_INDEX
-  METHOD_INDEX = FILE_INDEX
+  STYLE = FACTORY.get_STYLE()
 
-  INDEX = <<-EOF
-<html>
-<head>
-  <title><%= values["title"] %></title>
-  <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>">
-</head>
+  METHOD_LIST = FACTORY.get_METHOD_LIST()
+  
+  BODY = FACTORY.get_BODY()
+  
+  FILE_PAGE = FACTORY.get_FILE_PAGE()
 
-<frameset cols="20%,*">
-    <frameset rows="15%,35%,50%">
-        <frame src="fr_file_index.html"   title="Files" name="Files">
-        <frame src="fr_class_index.html"  name="Classes">
-        <frame src="fr_method_index.html" name="Methods">
-    </frameset>
-<% if values["inline_source"] then %>
-      <frame  src="<%= values["initial_page"] %>" name="docwin">
-<% end %>
-<% unless values["inline_source"] then %>
-    <frameset rows="80%,20%">
-      <frame  src="<%= values["initial_page"] %>" name="docwin">
-      <frame  src="blank.html" name="source">
-    </frameset>
-<% end %>
-    <noframes>
-          <body bgcolor="white">
-            Click <a href="html/index.html">here</a> for a non-frames
-            version of this page.
-          </body>
-    </noframes>
-</frameset>
+  CLASS_PAGE = FACTORY.get_CLASS_PAGE()
 
-</html>
-  EOF
+  SRC_PAGE = FACTORY.get_SRC_PAGE()
 
-  # A blank page to use as a target
-  BLANK = %{
-<html><body bgcolor="white"></body></html>
-}
+  FR_INDEX_BODY = FACTORY.get_FR_INDEX_BODY()
 
-  def write_extra_pages
-    template = TemplatePage.new(BLANK)
-    File.open("blank.html", "w") { |f| template.write_html_on(f, {}) }
+  FILE_INDEX = FACTORY.get_FILE_INDEX()
+
+  CLASS_INDEX = FACTORY.get_CLASS_INDEX()
+
+  METHOD_INDEX = FACTORY.get_METHOD_INDEX()
+
+  INDEX = FACTORY.get_INDEX()
+
+  def self.write_extra_pages(values)
+    FACTORY.write_extra_pages(values)
   end
-
 end
-
diff --git a/lib/rdoc/generator/html/kilmerfactory.rb b/lib/rdoc/generator/html/kilmerfactory.rb
new file mode 100644
index 0000000000..ef6f3f3b4d
--- /dev/null
+++ b/lib/rdoc/generator/html/kilmerfactory.rb
@@ -0,0 +1,427 @@
+require 'rdoc/generator/html'
+require 'rdoc/generator/html/common'
+
+#
+# This class generates Kilmer-style templates.  Right now,
+# rdoc is shipped with two such templates:
+# * kilmer
+# * hefss
+#
+# Kilmer-style templates use frames.  The left side of the page has
+# three frames stacked on top of each other: one lists
+# files, one lists classes, and one lists methods.  If source code
+# is not inlined, an additional frame runs across the bottom of
+# the page and will be used to display method source code.
+# The central (and largest frame) display class and file
+# pages.
+#
+# The constructor of this class accepts a Hash containing stylistic
+# attributes.  Then, a get_BLAH instance method of this class returns a
+# value for the template's BLAH constant.  get_BODY, for instance, returns
+# the value of the template's BODY constant.
+#
+class RDoc::Generator::HTML::KilmerFactory
+
+  include RDoc::Generator::HTML::Common
+
+  #
+  # The contents of the stylesheet that should be used for the
+  # central frame (for the class and file pages).
+  #
+  # This must be specified in the Hash passed to the constructor.
+  #
+  attr_reader :central_css
+
+  #
+  # The contents of the stylesheet that should be used for the
+  # index pages.
+  #
+  # This must be specified in the Hash passed to the constructor.
+  #
+  attr_reader :index_css
+
+  #
+  # The heading that should be displayed before listing methods.
+  #
+  # If not supplied, this defaults to "Methods".
+  #
+  attr_reader :method_list_heading
+
+  #
+  # The heading that should be displayed before listing classes and
+  # modules.
+  #
+  # If not supplied, this defaults to "Classes and Modules".
+  #
+  attr_reader :class_and_module_list_heading
+
+  #
+  # The heading that should be displayed before listing attributes.
+  #
+  # If not supplied, this defaults to "Attributes".
+  #
+  attr_reader :attribute_list_heading
+  
+  # 
+  # ====Description:
+  # This method constructs a KilmerFactory instance, which
+  # can be used to build Kilmer-style template classes.
+  # The +style_attributes+ argument is a Hash that contains the
+  # values of the classes attributes (Symbols mapped to Strings).
+  #
+  # ====Parameters:
+  # [style_attributes]
+  #      A Hash describing the appearance of the Kilmer-style.
+  # 
+  def initialize(style_attributes)
+    @central_css = style_attributes[:central_css]
+    if(!@central_css)
+      raise ArgumentError, "did not specify a value for :central_css"
+    end
+
+    @index_css = style_attributes[:index_css]
+    if(!@index_css)
+      raise ArgumentError, "did not specify a value for :index_css"
+    end
+
+    @method_list_heading = style_attributes[:method_list_heading]
+    if(!@method_list_heading)
+      @method_list_heading = "Methods"
+    end
+
+    @class_and_module_list_heading = style_attributes[:class_and_module_list_heading]
+    if(!@class_and_module_list_heading)
+      @class_and_module_list_heading = "Classes and Modules"
+    end
+
+    @attribute_list_heading = style_attributes[:attribute_list_heading]
+    if(!@attribute_list_heading)
+      @attribute_list_heading = "Attributes"
+    end
+  end
+
+  def get_STYLE
+    return @central_css
+  end
+  
+  def get_METHOD_LIST
+    return %{
+<% if values["diagram"] then %>
+<div id="diagram">
+<table width="100%"><tr><td align="center">
+<%= values["diagram"] %>
+</td></tr></table>
+</div>
+<% end %>
+
+<% if values["description"] then %>
+<div class="description"><%= values["description"] %></div>
+<% end %>
+
+<% if values["requires"] then %>
+<table cellpadding="5" width="100%">
+<tr><td class="tablesubtitle">Required files</td></tr>
+</table><br />
+<div class="name-list">
+<% values["requires"].each do |requires| %>
+<%= href requires["aref"], requires["name"] %>
+<% end %><%# values["requires"] %>
+</div>
+<% end %>
+
+<% if values["methods"] then %>
+<table cellpadding="5" width="100%">
+<tr><td class="tablesubtitle">#{@method_list_heading}</td></tr>
+</table><br />
+<div class="name-list">
+<% values["methods"].each do |methods| %>
+<%= href methods["aref"], methods["name"] %>,
+<% end %><%# values["methods"] %>
+</div>
+<% end %>
+
+<% if values["includes"] then %>
+<div class="tablesubsubtitle">Included modules</div><br />
+<div class="name-list">
+<% values["includes"].each do |includes| %>
+    <span class="method-name"><%= href includes["aref"], includes["name"] %></span>
+<% end %><%# values["includes"] %>
+</div>
+<% end %>
+
+<% values["sections"].each do |sections| %>
+    <div id="section">
+<% if sections["sectitle"] then %>
+      <h2 class="section-title"><a name="<%= sections["secsequence"] %>"><%= sections["sectitle"] %></a></h2>
+<% if sections["seccomment"] then %>
+      <div class="section-comment">
+        <%= sections["seccomment"] %>
+      </div>
+<% end %>
+<% end %>
+<% if sections["attributes"] then %>
+<table cellpadding="5" width="100%">
+<tr><td class="tablesubtitle">#{@attribute_list_heading}</td></tr>
+</table><br />
+<table cellspacing="5">
+<% sections["attributes"].each do |attributes| %>
+     <tr valign="top">
+<% if attributes["rw"] then %>
+       <td align="center" class="attr-rw">&nbsp;[<%= attributes["rw"] %>]&nbsp;</td>
+<% end %>
+<% unless attributes["rw"] then %>
+       <td></td>
+<% end %>
+       <td class="attr-name"><%= attributes["name"] %></td>
+       <td><%= attributes["a_desc"] %></td>
+     </tr>
+<% end %><%# sections["attributes"] %>
+</table>
+<% end %>
+
+<% if sections["classlist"] then %>
+<table cellpadding="5" width="100%">
+<tr><td class="tablesubtitle">#{@class_and_module_list_heading}</td></tr>
+</table><br />
+<%= sections["classlist"] %><br />
+<% end %>
+
+<% if sections["method_list"] then %>
+<% sections["method_list"].each do |method_list| %>
+<% if method_list["methods"] then %>
+<table cellpadding="5" width="100%">
+<tr><td class="tablesubtitle"><%= method_list["type"] %> <%= method_list["category"] %> methods</td></tr>
+</table>
+<% method_list["methods"].each do |methods| %>
+<table width="100%" cellspacing="0" cellpadding="5" border="0">
+<tr><td class="methodtitle">
+<a name="<%= methods["aref"] %>">
+<% if methods["callseq"] then %>
+<b><%= methods["callseq"] %></b>
+<% end %>
+<% unless methods["callseq"] then %>
+ <b><%= methods["name"] %></b><%= methods["params"] %>
+<% end %>
+</a>
+<% if methods["codeurl"] then %>
+<a href="<%= methods["codeurl"] %>" target="source" class="srclink">src</a>
+<% end %>
+</td></tr>
+</table>
+<% if methods["m_desc"] then %>
+<div class="description">
+<%= methods["m_desc"] %>
+</div>
+<% end %>
+<% if methods["aka"] then %>
+<div class="aka">
+This method is also aliased as
+<% methods["aka"].each do |aka| %>
+<a href="<%= methods["aref"] %>"><%= methods["name"] %></a>
+<% end %><%# methods["aka"] %>
+</div>
+<% end %>
+<% if methods["sourcecode"] then %>
+<pre class="source">
+<%= methods["sourcecode"] %>
+</pre>
+<% end %>
+<% end %><%# method_list["methods"] %>
+<% end %>
+<% end %><%# sections["method_list"] %>
+<% end %>
+
+<% end %><%# values["sections"] %>
+</div>
+}
+  end
+
+  def get_BODY
+    return XHTML_STRICT_PREAMBLE + HTML_ELEMENT + %{
+<head>
+  <title><%= values["title"] %></title>
+  <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
+  <link rel="stylesheet" href="<%= values["style_url"] %>" type="text/css" media="screen" />
+  <script type="text/javascript">
+  <!--
+  function popCode(url) {
+    parent.frames.source.location = url
+  }
+  //-->
+  </script>
+</head>
+<body>
+<div class="bodyContent">
+<%= template_include %>  <!-- banner header -->
+
+#{get_METHOD_LIST()}
+</div>
+</body>
+</html>
+}
+  end
+
+def get_FILE_PAGE
+  return %{
+<table width="100%">
+ <tr class="title-row">
+ <td><table width="100%"><tr>
+   <td class="big-title-font" colspan="2">File<br /><%= values["short_name"] %></td>
+   <td align="right"><table cellspacing="0" cellpadding="2">
+         <tr>
+           <td class="small-title-font">Path:</td>
+           <td class="small-title-font"><%= values["full_path"] %>
+<% if values["cvsurl"] then %>
+				&nbsp;(<a href="<%= values["cvsurl"] %>"><acronym title="Concurrent Versioning System">CVS</acronym></a>)
+<% end %>
+           </td>
+         </tr>
+         <tr>
+           <td class="small-title-font">Modified:</td>
+           <td class="small-title-font"><%= values["dtm_modified"] %></td>
+         </tr>
+        </table>
+    </td></tr></table></td>
+  </tr>
+</table><br />
+}
+end
+
+def get_CLASS_PAGE
+  return %{
+<table width="100%" border="0" cellspacing="0">
+ <tr class="title-row">
+ <td class="big-title-font">
+   <%= values["classmod"] %><br /><%= values["full_name"] %>
+ </td>
+ <td align="right">
+   <table cellspacing="0" cellpadding="2">
+     <tr valign="top">
+      <td class="small-title-font">In:</td>
+      <td class="small-title-font">
+<% values["infiles"].each do |infiles| %>
+<%= href infiles["full_path_url"], infiles["full_path"] %>
+<% if infiles["cvsurl"] then %>
+&nbsp;(<a href="<%= infiles["cvsurl"] %>"><acronym title="Concurrent Versioning System">CVS</acronym></a>)
+<% end %>
+<% end %><%# values["infiles"] %>
+      </td>
+     </tr>
+<% if values["parent"] then %>
+     <tr>
+      <td class="small-title-font">Parent:</td>
+      <td class="small-title-font">
+<% if values["par_url"] then %>
+        <a href="<%= values["par_url"] %>" class="cyan">
+<% end %>
+<%= values["parent"] %>
+<% if values["par_url"] then %>
+         </a>
+<% end %>
+      </td>
+     </tr>
+<% end %>
+   </table>
+  </td>
+  </tr>
+</table><br />
+}
+end
+
+def get_SRC_PAGE
+  return XHTML_STRICT_PREAMBLE + HTML_ELEMENT + %{
+<head><title><%= values["title"] %></title>
+<meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
+<link rel="stylesheet" href="<%= values["style_url"] %>" type="text/css" media="screen" />
+</head>
+<body>
+<pre><%= values["code"] %></pre>
+</body>
+</html>
+}
+end
+
+def get_FR_INDEX_BODY
+  return %{<%= template_include %>}
+end
+
+def get_FILE_INDEX
+  return XHTML_STRICT_PREAMBLE + HTML_ELEMENT + %{
+<head>
+<title><%= values["title"] %></title>
+<meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
+<style type="text/css">
+<!--
+#{@index_css}
+-->
+</style>
+<base target="docwin" />
+</head>
+<body>
+<div class="index">
+<div class="banner"><%= values["list_title"] %></div>
+<% values["entries"].each do |entries| %>
+<a href="<%= entries["href"] %>"><%= entries["name"] %></a><br />
+<% end %><%# values["entries"] %>
+</div>
+</body></html>
+}
+end
+
+def get_CLASS_INDEX
+  return get_FILE_INDEX
+end
+
+def get_METHOD_INDEX
+  return get_FILE_INDEX
+end
+
+def get_INDEX
+  return XHTML_FRAME_PREAMBLE + HTML_ELEMENT + %{
+<head>
+  <title><%= values["title"] %></title>
+  <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
+</head>
+
+<frameset cols="20%,*">
+    <frameset rows="15%,35%,50%">
+        <frame src="fr_file_index.html"   title="Files" name="Files" />
+        <frame src="fr_class_index.html"  name="Classes" />
+        <frame src="fr_method_index.html" name="Methods" />
+    </frameset>
+<% if values["inline_source"] then %>
+      <frame  src="<%= values["initial_page"] %>" name="docwin" />
+<% end %>
+<% unless values["inline_source"] then %>
+    <frameset rows="80%,20%">
+      <frame  src="<%= values["initial_page"] %>" name="docwin" />
+      <frame  src="blank.html" name="source" />
+    </frameset>
+<% end %>
+</frameset>
+
+</html>
+}
+end
+
+def get_BLANK
+  # This will be displayed in the source code frame before
+  # any source code has been selected.
+  return XHTML_STRICT_PREAMBLE + HTML_ELEMENT + %{
+<head>
+  <title>Source Code Frame <%= values["title_suffix"] %></title>
+  <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
+  <link rel="stylesheet" href="<%= values["style_url"] %>" type="text/css" media="screen" />
+</head>
+<body>
+</body>
+</html>
+}
+end
+
+def write_extra_pages(values)
+  template = RDoc::TemplatePage.new(get_BLANK())
+  File.open("blank.html", "w") { |f| template.write_html_on(f, values) }
+end
+
+end
diff --git a/lib/rdoc/generator/html/one_page_html.rb b/lib/rdoc/generator/html/one_page_html.rb
index c4dd95529d..51ae32351a 100644
--- a/lib/rdoc/generator/html/one_page_html.rb
+++ b/lib/rdoc/generator/html/one_page_html.rb
@@ -1,7 +1,10 @@
 require 'rdoc/generator/html'
+require 'rdoc/generator/html/common'
 
 module RDoc::Generator::HTML::ONE_PAGE_HTML
 
+  include RDoc::Generator::HTML::Common
+
   CONTENTS_XML = <<-EOF
 <% if defined? classes and classes["description"] then %>
 <%= classes["description"] %>
@@ -76,16 +79,14 @@ module RDoc::Generator::HTML::ONE_PAGE_HTML
 <% end %>
   EOF
 
-  ONE_PAGE = %{
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html>
+  ONE_PAGE = XHTML_STRICT_PREAMBLE + HTML_ELEMENT + %{
 <head>
   <title><%= values["title"] %></title>
   <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
 </head>
 <body>
 <% values["files"].each do |files| %>
-<h2>File: <%= files["short_name"] %></h2>
+<h2>File: <a name="<%= files["href"] %>"><%= files["short_name"] %></a></h2>
 <table>
   <tr><td>Path:</td><td><%= files["full_path"] %></td></tr>
   <tr><td>Modified:</td><td><%= files["dtm_modified"] %></td></tr>
@@ -97,7 +98,7 @@ module RDoc::Generator::HTML::ONE_PAGE_HTML
 <h2>Classes</h2>
 <% values["classes"].each do |classes| %>
 <% if classes["parent"] then %>
-<h3><%= classes["classmod"] %> <%= classes["full_name"] %> &lt; <%= href classes["par_url"], classes["parent"] %></h3>
+<h3><%= classes["classmod"] %> <a name="<%= classes["href"] %>"><%= classes["full_name"] %></a> &lt; <%= href classes["par_url"], classes["parent"] %></h3>
 <% end %>
 <% unless classes["parent"] then %>
 <h3><%= classes["classmod"] %> <%= classes["full_name"] %></h3>
diff --git a/lib/rdoc/generator/texinfo.rb b/lib/rdoc/generator/texinfo.rb
index 0b79820228..70db875af9 100644
--- a/lib/rdoc/generator/texinfo.rb
+++ b/lib/rdoc/generator/texinfo.rb
@@ -3,13 +3,10 @@ require 'rdoc/generator'
 require 'rdoc/markup/to_texinfo'
 
 module RDoc
-  RDoc::GENERATORS['texinfo'] = RDoc::Generator.new("rdoc/generator/texinfo",
-                                                    :Texinfo,
-                                                    'texinfo')
   module Generator
     # This generates Texinfo files for viewing with GNU Info or Emacs
     # from RDoc extracted from Ruby source files.
-    class Texinfo
+    class TEXINFO
       # What should the .info file be named by default?
       DEFAULT_INFO_FILENAME = 'rdoc.info'
 
@@ -26,8 +23,8 @@ module RDoc
       # Generate the +texinfo+ files
       def generate(toplevels)
         @toplevels = toplevels
-        @files, @classes = ::RDoc::Generator::Context.build_indicies(@toplevels,
-                                                                     @options)
+        @files, @classes = ::RDoc::Generator::Context.build_indices(@toplevels,
+                                                                    @options)
 
         (@files + @classes).each { |x| x.value_hash }
 
diff --git a/lib/rdoc/generator/texinfo/class.texinfo.erb b/lib/rdoc/generator/texinfo/class.texinfo.erb
index 07f17eaef2..74ecc59f7d 100644
--- a/lib/rdoc/generator/texinfo/class.texinfo.erb
+++ b/lib/rdoc/generator/texinfo/class.texinfo.erb
@@ -38,7 +38,7 @@ Methods
 <%       (method_list["methods"] || []).uniq.each do |method| %>
 <%=        TexinfoTemplate.new(@v.merge({'method' => method, 'list' => method_list}),
                                'method.texinfo.erb').render %><% end %>
-<%     end # section["method_list"] %>
-<%   end %>
+<%       end %>
+<%     end # if section["method_list"] %>
 <% end # @v['class']["sections"] %>
 <% end %>
diff --git a/lib/rdoc/generator/xml.rb b/lib/rdoc/generator/xml.rb
index 3335f2ce7c..0d4c5a7ea1 100644
--- a/lib/rdoc/generator/xml.rb
+++ b/lib/rdoc/generator/xml.rb
@@ -34,15 +34,15 @@ class RDoc::Generator::XML < RDoc::Generator::HTML
   ##
   # Generate:
   #
-  # * a list of HtmlFile objects for each TopLevel object.
-  # * a list of HtmlClass objects for each first level
+  # * a list of File objects for each TopLevel object.
+  # * a list of Class objects for each first level
   #   class or module in the TopLevel objects
   # * a complete list of all hyperlinkable terms (file,
   #   class, module, and method names)
 
   def build_indices
     @info.each do |toplevel|
-      @files << RDoc::Generator::HtmlFile.new(toplevel, @options, RDoc::Generator::FILE_DIR)
+      @files << RDoc::Generator::File.new(toplevel, @options, RDoc::Generator::FILE_DIR)
     end
 
     RDoc::TopLevel.all_classes_and_modules.each do |cls|
@@ -51,7 +51,7 @@ class RDoc::Generator::XML < RDoc::Generator::HTML
   end
 
   def build_class_list(from, html_file, class_dir)
-    @classes << RDoc::Generator::HtmlClass.new(from, html_file, class_dir, @options)
+    @classes << RDoc::Generator::Class.new(from, html_file, class_dir, @options)
     from.each_classmodule do |mod|
       build_class_list(mod, html_file, class_dir)
     end
@@ -68,9 +68,6 @@ class RDoc::Generator::XML < RDoc::Generator::HTML
       'classes' => gen_into(@classes)
     }
 
-    # this method is defined in the template file
-    write_extra_pages if defined? write_extra_pages
-
     template = RDoc::TemplatePage.new @template::ONE_PAGE
 
     if @options.op_name
diff --git a/lib/rdoc/generator/xml/xml.rb b/lib/rdoc/generator/xml/xml.rb
index ffb1329c4e..4b54e7350f 100644
--- a/lib/rdoc/generator/xml/xml.rb
+++ b/lib/rdoc/generator/xml/xml.rb
@@ -17,11 +17,23 @@ module RDoc::Generator::XML::XML
                         href="<%= requires["aref"] %>"
 <% end %>
          />
-<% end # files["requires"] %>
+<% end %><%# files["requires"] %>
       </required-file-list>
 <% end %>
 <% if defined? classes and classes["sections"] then %>
 <% classes["sections"].each do |sections| %>
+<% if sections["constants"] then %>
+      <constant-list>
+<% sections["constants"].each do |constant| %>
+        <constant name="<%= constant["name"] %>">
+<% if constant["value"] then %>
+          <value><%= constant["value"] %></value>
+<% end %>
+          <description><%= constant["a_desc"] %></description>
+        </constant>
+<% end %><%# sections["constants"] %>
+      </constant-list>
+<% end %>
 <% if sections["attributes"] then %>
       <attribute-list>
 <% sections["attributes"].each do |attributes| %>
@@ -31,7 +43,7 @@ module RDoc::Generator::XML::XML
 <% end %>
           <description><%= attributes["a_desc"] %></description>
         </attribute>
-<% end # sections["attributes"] %>
+<% end %><%# sections["attributes"] %>
       </attribute-list>
 <% end %>
 <% if sections["method_list"] then %>
@@ -52,12 +64,12 @@ module RDoc::Generator::XML::XML
           </source-code-listing>
 <% end %>
         </method>
-<% end # method_list["methods"] %>
+<% end %><%# method_list["methods"] %>
 <% end %>
-<% end # sections["method_list"] %>
+<% end %><%# sections["method_list"] %>
       </method-list>
 <% end %>
-<% end # classes["sections"] %>
+<% end %><%# classes["sections"] %>
 <% end %>
 <% if defined? classes and classes["includes"] then %>
       <included-module-list>
@@ -67,7 +79,7 @@ module RDoc::Generator::XML::XML
                          href="<%= includes["aref"] %>"
 <% end %>
         />
-<% end # classes["includes"] %>
+<% end %><%# classes["includes"] %>
       </included-module-list>
 <% end %>
     </contents>
@@ -84,7 +96,7 @@ module RDoc::Generator::XML::XML
     </file-info>
 } + CONTENTS_XML + %{
   </file>
-<% end # values["files"] %>
+<% end %><%# values["files"] %>
 </file-list>
 <class-module-list>
 <% values["classes"].each do |classes| %>
@@ -94,7 +106,7 @@ module RDoc::Generator::XML::XML
       <infiles>
 <% classes["infiles"].each do |infiles|  %>
         <infile><%= href infiles["full_path_url"], infiles["full_path"] %></infile>
-<% end # classes["infiles"] %>
+<% end %><%# classes["infiles"] %>
       </infiles>
 <% end %>
 <% if classes["parent"] then %>
@@ -103,7 +115,7 @@ module RDoc::Generator::XML::XML
     </classmod-info>
 } + CONTENTS_XML + %{
   </<%= classes["classmod"] %>>
-<% end # values["classes"] %>
+<% end %><%# values["classes"] %>
 </class-module-list>
 </rdoc>
 }
diff --git a/lib/rdoc/markup.rb b/lib/rdoc/markup.rb
index 0e1b596255..9d22b38946 100644
--- a/lib/rdoc/markup.rb
+++ b/lib/rdoc/markup.rb
@@ -20,101 +20,6 @@ require 'rdoc'
 # RDoc::Markup could be the basis for formatting RDoc style comment blocks,
 # Wiki entries, and online FAQs.
 #
-# = Basic Formatting
-#
-# * RDoc::Markup looks for a document's natural left margin.  This is
-#   used as the initial margin for the document.
-#
-# * Consecutive lines starting at this margin are considered to be a
-#   paragraph.
-#
-# * If a paragraph starts with a "*", "-", or with "<digit>.", then it is
-#   taken to be the start of a list.  The margin in increased to be the first
-#   non-space following the list start flag.  Subsequent lines should be
-#   indented to this \new margin until the list ends.  For example:
-#
-#      * this is a list with three paragraphs in
-#        the first item.  This is the first paragraph.
-#
-#        And this is the second paragraph.
-#
-#        1. This is an indented, numbered list.
-#        2. This is the second item in that list
-#
-#        This is the third conventional paragraph in the
-#        first list item.
-#
-#      * This is the second item in the original list
-#
-# * You can also construct labeled lists, sometimes called description
-#   or definition lists.  Do this by putting the label in square brackets
-#   and indenting the list body:
-#
-#       [cat]  a small furry mammal
-#              that seems to sleep a lot
-#
-#       [ant]  a little insect that is known
-#              to enjoy picnics
-#
-#   A minor variation on labeled lists uses two colons to separate the
-#   label from the list body:
-#
-#       cat::  a small furry mammal
-#              that seems to sleep a lot
-#
-#       ant::  a little insect that is known
-#              to enjoy picnics
-#
-#   This latter style guarantees that the list bodies' left margins are
-#   aligned: think of them as a two column table.
-#
-# * Any line that starts to the right of the current margin is treated
-#   as verbatim text.  This is useful for code listings.  The example of a
-#   list above is also verbatim text.
-#
-# * A line starting with an equals sign (=) is treated as a
-#   heading.  Level one headings have one equals sign, level two headings
-#   have two,and so on.
-#
-# * A line starting with three or more hyphens (at the current indent)
-#   generates a horizontal rule.  The more hyphens, the thicker the rule
-#   (within reason, and if supported by the output device)
-#
-# * You can use markup within text (except verbatim) to change the
-#   appearance of parts of that text.  Out of the box, RDoc::Markup
-#   supports word-based and general markup.
-#
-#   Word-based markup uses flag characters around individual words:
-#
-#   [\*word*]  displays word in a *bold* font
-#   [\_word_]  displays word in an _emphasized_ font
-#   [\+word+]  displays word in a +code+ font
-#
-#   General markup affects text between a start delimiter and and end
-#   delimiter.  Not surprisingly, these delimiters look like HTML markup.
-#
-#   [\<b>text...</b>]    displays word in a *bold* font
-#   [\<em>text...</em>]  displays word in an _emphasized_ font
-#   [\<i>text...</i>]    displays word in an _emphasized_ font
-#   [\<tt>text...</tt>]  displays word in a +code+ font
-#
-#   Unlike conventional Wiki markup, general markup can cross line
-#   boundaries.  You can turn off the interpretation of markup by
-#   preceding the first character with a backslash, so \\\<b>bold
-#   text</b> and \\\*bold* produce \<b>bold text</b> and \*bold*
-#   respectively.
-#
-# * Hyperlinks to the web starting http:, mailto:, ftp:, or www. are
-#   recognized.  An HTTP url that references an external image file is
-#   converted into an inline <IMG..>.  Hyperlinks starting 'link:' are
-#   assumed to refer to local files whose path is relative to the --op
-#   directory.
-#
-#   Hyperlinks can also be of the form <tt>label</tt>[url], in which
-#   case the label is used in the displayed text, and <tt>url</tt> is
-#   used as the target.  If <tt>label</tt> contains multiple words,
-#   put it in braces: <em>{multi word label}[</em>url<em>]</em>.
-#
 # == Synopsis
 #
 # This code converts +input_string+ to HTML.  The conversion takes place in
diff --git a/lib/rdoc/markup/inline.rb b/lib/rdoc/markup/inline.rb
index ee77679a11..46c9b5822c 100644
--- a/lib/rdoc/markup/inline.rb
+++ b/lib/rdoc/markup/inline.rb
@@ -47,7 +47,7 @@ class RDoc::Markup
 
   class AttrChanger
     def to_s
-      "Attr: +#{Attribute.as_string(@turn_on)}/-#{Attribute.as_string(@turn_on)}"
+      "Attr: +#{Attribute.as_string(turn_on)}/-#{Attribute.as_string(turn_on)}"
     end
   end
 
diff --git a/lib/rdoc/markup/to_html.rb b/lib/rdoc/markup/to_html.rb
index ca29373db1..dce7a69b12 100644
--- a/lib/rdoc/markup/to_html.rb
+++ b/lib/rdoc/markup/to_html.rb
@@ -57,7 +57,7 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
 
   ##
   # Generate a hyperlink for url, labeled with text. Handle the
-  # special cases for img: and link: described under handle_special_HYPEDLINK
+  # special cases for img: and link: described under handle_special_HYPERLINK
 
   def gen_url(url, text)
     if url =~ /([A-Za-z]+):(.*)/ then
@@ -304,9 +304,12 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
   # some of these patterns are taken from SmartyPants...
 
   def convert_string_fancy(item)
-    # convert -- to em-dash, (-- to en-dash)
-    item.gsub(/---?/, '&#8212;'). #gsub(/--/, '&#8211;').
+    # convert ampersand before doing anything else
+    item.gsub(/&/, '&amp;').
 
+    # convert -- to em-dash, (-- to en-dash)
+      gsub(/---?/, '&#8212;'). #gsub(/--/, '&#8211;').
+      
     # convert ... to elipsis (and make sure .... becomes .<elipsis>)
       gsub(/\.\.\.\./, '.&#8230;').gsub(/\.\.\./, '&#8230;').
 
@@ -318,15 +321,15 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
       gsub(/'/, '&#8216;').
 
     # convert double closing quote
-      gsub(%r{([^ \t\r\n\[\{\(])\'(?=\W)}, '\1&#8221;'). # }
+      gsub(%r{([^ \t\r\n\[\{\(])\"(?=\W)}, '\1&#8221;'). # }
 
     # convert double opening quote
-      gsub(/'/, '&#8220;').
+      gsub(/"/, '&#8220;').
 
     # convert copyright
       gsub(/\(c\)/, '&#169;').
 
-    # convert and registered trademark
+    # convert registered trademark
       gsub(/\(r\)/, '&#174;')
   end
 
diff --git a/lib/rdoc/markup/to_html_crossref.rb b/lib/rdoc/markup/to_html_crossref.rb
index a6f29c5c2c..dc64b30da1 100644
--- a/lib/rdoc/markup/to_html_crossref.rb
+++ b/lib/rdoc/markup/to_html_crossref.rb
@@ -9,6 +9,68 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
 
   attr_accessor :context
 
+  # Regular expressions to match class and method references.
+  # 
+  # 1.) There can be a '\' in front of text to suppress
+  #     any cross-references (note, however, that the single '\'
+  #     is written as '\\\\' in order to escape it twice, once
+  #     in the Ruby String literal and once in the regexp).
+  # 2.) There can be a '::' in front of class names to reference
+  #     from the top-level namespace.
+  # 3.) The method can be followed by parenthesis,
+  #     which may or may not have things inside (this
+  #     apparently is allowed for Fortran 95, but I also think that this
+  #     is a good idea for Ruby, as it is very reasonable to want to
+  #     reference a call with arguments).
+  #
+  # NOTE: In order to support Fortran 95 properly, the [A-Z] below
+  # should be changed to [A-Za-z].  This slows down rdoc significantly,
+  # however, and the Fortran 95 support is broken in any case due to
+  # the return in handle_special_CROSSREF if the token consists
+  # entirely of lowercase letters.
+  #
+  # The markup/cross-referencing engine needs a rewrite for
+  # Fortran 95 to be supported properly.
+  CLASS_REGEXP_STR = '\\\\?((?:\:{2})?[A-Z]\w*(?:\:\:\w+)*)'
+  METHOD_REGEXP_STR = '(\w+[!?=]?)(?:\([\.\w+\*\/\+\-\=\<\>]*\))?'
+
+  # Regular expressions matching text that should potentially have
+  # cross-reference links generated are passed to add_special.
+  # Note that these expressions are meant to pick up text for which
+  # cross-references have been suppressed, since the suppression
+  # characters are removed by the code that is triggered.
+  CROSSREF_REGEXP = /(
+                      # A::B::C.meth
+                      #{CLASS_REGEXP_STR}[\.\#]#{METHOD_REGEXP_STR}
+
+                      # Stand-alone method (proceeded by a #)
+                      | \\?\##{METHOD_REGEXP_STR}
+
+                      # A::B::C
+                      # The stuff after CLASS_REGEXP_STR is a
+                      # nasty hack.  CLASS_REGEXP_STR unfortunately matches
+                      # words like dog and cat (these are legal "class"
+                      # names in Fortran 95).  When a word is flagged as a
+                      # potential cross-reference, limitations in the markup
+                      # engine suppress other processing, such as typesetting.
+                      # This is particularly noticeable for contractions.
+                      # In order that words like "can't" not
+                      # be flagged as potential cross-references, only
+                      # flag potential class cross-references if the character
+                      # after the cross-referece is a space or sentence
+                      # punctuation.
+                      | #{CLASS_REGEXP_STR}(?=[\s\)\.\?\!\,\;]|\z)
+
+                      # Things that look like filenames
+                      # The key thing is that there must be at least
+                      # one special character (period, slash, or
+                      # underscore).
+                      | [\/\w]+[_\/\.][\w\/\.]+
+
+                      # Things that have markup suppressed
+                      | \\[^\s]
+                      )/x
+
   ##
   # We need to record the html path of our caller so we can generate
   # correct relative paths for any hyperlinks that we find
@@ -17,18 +79,7 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
     raise ArgumentError, 'from_path cannot be nil' if from_path.nil?
     super()
 
-    # class names, variable names, or instance variables
-    @markup.add_special(/(
-                           # A::B.meth(**) (for operator in Fortran95)
-                           \w+(::\w+)*[.\#]\w+(\([\.\w+\*\/\+\-\=\<\>]+\))?
-                           # meth(**) (for operator in Fortran95)
-                         | \#\w+(\([.\w\*\/\+\-\=\<\>]+\))?
-                         | \b([A-Z]\w*(::\w+)*[.\#]\w+)  #    A::B.meth
-                         | \b([A-Z]\w+(::\w+)*)          #    A::B
-                         | \#\w+[!?=]?                   #    #meth_name
-                         | \\?\b\w+([_\/\.]+\w+)*[!?=]?  #    meth_name
-                         )/x,
-                        :CROSSREF)
+    @markup.add_special(CROSSREF_REGEXP, :CROSSREF)
 
     @from_path = from_path
     @context = context
@@ -48,6 +99,9 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
   def handle_special_CROSSREF(special)
     name = special.text
 
+    # This ensures that words entirely consisting of lowercase letters will
+    # not have cross-references generated (to suppress lots of
+    # erroneous cross-references to "new" in text, for instance)
     return name if name =~ /\A[a-z]*\z/
 
     return @seen[name] if @seen.include? name
@@ -70,14 +124,7 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
     # (in which case it would match the last pattern, which just checks
     # whether the string as a whole is a known symbol).
 
-    if /([A-Z][\w:]*)[.\#](\w+[!?=]?)/ =~ lookup then
-      container = $1
-      method = $2
-      ref = @context.find_symbol container, method
-    end
-
-    if !ref and
-       /([A-Za-z][\w:]*)[.\#](\w+(\([\.\w+\*\/\+\-\=\<\>]+\))?)/ =~ lookup then
+    if /#{CLASS_REGEXP_STR}[\.\#]#{METHOD_REGEXP_STR}/ =~ lookup then
       container = $1
       method = $2
       ref = @context.find_symbol container, method
@@ -99,4 +146,3 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
   end
 
 end
-
diff --git a/lib/rdoc/markup/to_texinfo.rb b/lib/rdoc/markup/to_texinfo.rb
index 533d3e34a0..65a1608c4d 100644
--- a/lib/rdoc/markup/to_texinfo.rb
+++ b/lib/rdoc/markup/to_texinfo.rb
@@ -30,7 +30,7 @@ class RDoc::Markup::ToTexInfo < RDoc::Markup::Formatter
 
   def accept_heading(attributes, text)
     heading = ['@majorheading', '@chapheading'][text.head_level - 1] || '@heading'
-    @text << "#{heading}{#{format(text)}}"
+    @text << "#{heading} #{format(text)}"
   end
 
   def accept_list_start(attributes, text)
diff --git a/lib/rdoc/options.rb b/lib/rdoc/options.rb
index d683a14022..1d92bd4748 100644
--- a/lib/rdoc/options.rb
+++ b/lib/rdoc/options.rb
@@ -184,7 +184,7 @@ class RDoc::Options
     @css = nil
     @webcvs = nil
 
-    @charset = 'iso-8859-1'
+    @charset = 'utf-8'
   end
 
   ##
@@ -196,6 +196,7 @@ class RDoc::Options
     opts = OptionParser.new do |opt|
       opt.program_name = File.basename $0
       opt.version = RDoc::VERSION
+      opt.release = nil
       opt.summary_indent = ' ' * 4
       opt.banner = <<-EOF
 Usage: #{opt.program_name} [options] [names...]
@@ -257,7 +258,7 @@ Usage: #{opt.program_name} [options] [names...]
       opt.separator nil
 
       opt.on("--charset=CHARSET", "-c",
-             "Specifies the HTML character-set.") do |value|
+             "Specifies the output HTML character-set.") do |value|
         @charset = value
       end
 
@@ -283,9 +284,7 @@ Usage: #{opt.program_name} [options] [names...]
 
       opt.on("--exclude=PATTERN", "-x", Regexp,
              "Do not process files or directories",
-             "matching PATTERN. Files given explicitly",
-             "on the command line will never be",
-             "excluded.") do |value|
+             "matching PATTERN.") do |value|
         @exclude << value
       end
 
diff --git a/lib/rdoc/parser.rb b/lib/rdoc/parser.rb
index 794fad00e9..6855cfcfc5 100644
--- a/lib/rdoc/parser.rb
+++ b/lib/rdoc/parser.rb
@@ -62,11 +62,32 @@ class RDoc::Parser
     true
   end
 
+  ##
+  # Shamelessly stolen from the ptools gem (since RDoc cannot depend on
+  # the gem).
+
+  def self.binary?(file)
+    s = (File.read(file, File.stat(file).blksize) || "").split(//)
+    ((s.size - s.grep(" ".."~").size) / s.size.to_f) > 0.30
+  end
+  private_class_method :binary?
+
   ##
   # Return a parser that can handle a particular extension
 
   def self.can_parse(file_name)
-    RDoc::Parser.parsers.find { |regexp, parser| regexp =~ file_name }.last
+    parser = RDoc::Parser.parsers.find { |regexp,| regexp =~ file_name }.last
+
+    #
+    # The default parser should *NOT* parse binary files.
+    #
+    if parser == RDoc::Parser::Simple then
+      if binary? file_name then
+        return nil
+      end
+    end
+
+    return parser
   end
 
   ##
diff --git a/lib/rdoc/parser/c.rb b/lib/rdoc/parser/c.rb
index 43bb767da9..a5b06c2b04 100644
--- a/lib/rdoc/parser/c.rb
+++ b/lib/rdoc/parser/c.rb
@@ -120,7 +120,7 @@ class RDoc::Parser::C < RDoc::Parser
 
       @stats.add_alias as
     end
- end
+  end
 
   def do_classes
     @content.scan(/(\w+)\s* = \s*rb_define_module\s*\(\s*"(\w+)"\s*\)/mx) do 
@@ -155,7 +155,7 @@ class RDoc::Parser::C < RDoc::Parser
               \(
                  \s*(\w+),
                  \s*"(\w+)",
-                 \s*(\w+)\s*
+                 \s*([\w\*\s\(\)\.\->]+)\s*  # for SWIG
               \s*\)/mx) do |var_name, in_module, class_name, parent|
       handle_class_module(var_name, "class", class_name, parent, in_module)
     end
@@ -251,7 +251,7 @@ class RDoc::Parser::C < RDoc::Parser
       handle_method("method", "rb_mFileTest", meth_name, meth_body, param_count)
       handle_method("singleton_method", "rb_cFile", meth_name, meth_body, param_count)
     end
- end
+  end
 
   def find_attr_comment(attr_name)
     if @content =~ %r{((?>/\*.*?\*/\s+))
@@ -267,10 +267,10 @@ class RDoc::Parser::C < RDoc::Parser
   ##
   # Find the C code corresponding to a Ruby method
 
-  def find_body(meth_name, meth_obj, body, quiet = false)
+  def find_body(class_name, meth_name, meth_obj, body, quiet = false)
     case body
-    when %r"((?>/\*.*?\*/\s*))(?:static\s+)?VALUE\s+#{meth_name}
-            \s*(\([^)]*\))\s*\{.*?^\}"xm
+    when %r"((?>/\*.*?\*/\s*)*)(?:(?:static|SWIGINTERN)\s+)?(?:intern\s+)?VALUE\s+#{meth_name}
+            \s*(\([^)]*\))([^;]|$)"xm
       comment, params = $1, $2
       body_text = $&
 
@@ -279,9 +279,7 @@ class RDoc::Parser::C < RDoc::Parser
       # see if we can find the whole body
 
       re = Regexp.escape(body_text) + '[^(]*^\{.*?^\}'
-      if Regexp.new(re, Regexp::MULTILINE).match(body)
-        body_text = $&
-      end
+      body_text = $& if /#{re}/m =~ body
 
       # The comment block may have been overridden with a 'Document-method'
       # block. This happens in the interpreter when multiple methods are
@@ -289,7 +287,7 @@ class RDoc::Parser::C < RDoc::Parser
       # distinct (for example Kernel.hash and Kernel.object_id share the same
       # implementation
 
-      override_comment = find_override_comment(meth_obj.name)
+      override_comment = find_override_comment(class_name, meth_obj.name)
       comment = override_comment if override_comment
 
       find_modifiers(comment, meth_obj) if comment
@@ -300,18 +298,18 @@ class RDoc::Parser::C < RDoc::Parser
       meth_obj.comment = mangle_comment(comment)
     when %r{((?>/\*.*?\*/\s*))^\s*\#\s*define\s+#{meth_name}\s+(\w+)}m
       comment = $1
-      find_body($2, meth_obj, body, true)
+      find_body(class_name, $2, meth_obj, body, true)
       find_modifiers(comment, meth_obj)
       meth_obj.comment = mangle_comment(comment) + meth_obj.comment
     when %r{^\s*\#\s*define\s+#{meth_name}\s+(\w+)}m
-      unless find_body($1, meth_obj, body, true)
+      unless find_body(class_name, $1, meth_obj, body, true)
         warn "No definition for #{meth_name}" unless @options.quiet
         return false
       end
     else
 
       # No body, but might still have an override comment
-      comment = find_override_comment(meth_obj.name)
+      comment = find_override_comment(class_name, meth_obj.name)
 
       if comment
         find_modifiers(comment, meth_obj)
@@ -367,10 +365,10 @@ class RDoc::Parser::C < RDoc::Parser
   def find_class_comment(class_name, class_meth)
     comment = nil
     if @content =~ %r{((?>/\*.*?\*/\s+))
-                   (static\s+)?void\s+Init_#{class_name}\s*(?:_\(\s*)?\(\s*(?:void\s*)\)}xmi
+                   (static\s+)?void\s+Init_#{class_name}\s*(?:_\(\s*)?\(\s*(?:void\s*)\)}xmi then
+      comment = $1
+    elsif @content =~ %r{Document-(?:class|module):\s#{class_name}\s*?(?:<\s+[:,\w]+)?\n((?>.*?\*/))}m
       comment = $1
-    elsif @content =~ %r{Document-(class|module):\s#{class_name}\s*?\n((?>.*?\*/))}m
-      comment = $2
     else
       if @content =~ /rb_define_(class|module)/m then
         class_name = class_name.split("::").last
@@ -424,9 +422,11 @@ class RDoc::Parser::C < RDoc::Parser
     end
   end
 
-  def find_override_comment(meth_name)
+  def find_override_comment(class_name, meth_name)
     name = Regexp.escape(meth_name)
-    if @content =~ %r{Document-method:\s#{name}\s*?\n((?>.*?\*/))}m
+    if @content =~ %r{Document-method:\s+#{class_name}(?:\.|::)#{name}\s*?\n((?>.*?\*/))}m then
+      $1
+    elsif @content =~ %r{Document-method:\s#{name}\s*?\n((?>.*?\*/))}m then
       $1
     end
   end
@@ -480,6 +480,10 @@ class RDoc::Parser::C < RDoc::Parser
     end
 
     if class_mod == "class" then
+      full_name = enclosure.full_name.to_s + "::#{class_name}"
+      if @content =~ %r{Document-class:\s+#{full_name}\s*<\s+([:,\w]+)} then
+        parent_name = $1
+      end
       cm = enclosure.add_class RDoc::NormalClass, class_name, parent_name
       @stats.add_class cm
     else
@@ -562,18 +566,16 @@ class RDoc::Parser::C < RDoc::Parser
 
     return unless class_name
 
-    class_obj  = find_class(var_name, class_name)
+    class_obj = find_class var_name, class_name
 
-    if class_obj
-      if meth_name == "initialize"
+    if class_obj then
+      if meth_name == "initialize" then
         meth_name = "new"
         type = "singleton_method"
       end
-      meth_obj = RDoc::AnyMethod.new("", meth_name)
-      meth_obj.singleton =
-  %w{singleton_method module_function}.include?(type)
 
-      @stats.add_method meth_obj
+      meth_obj = RDoc::AnyMethod.new '', meth_name
+      meth_obj.singleton = %w[singleton_method module_function].include? type
 
       p_count = (Integer(param_count) rescue -1)
 
@@ -585,14 +587,16 @@ class RDoc::Parser::C < RDoc::Parser
         meth_obj.params = "(" + (1..p_count).map{|i| "p#{i}"}.join(", ") + ")"
       end
 
-      if source_file
+      if source_file then
         file_name = File.join(@file_dir, source_file)
         body = (@@known_bodies[source_file] ||= File.read(file_name))
       else
         body = @content
       end
-      if find_body(meth_body, meth_obj, body) and meth_obj.document_self
-        class_obj.add_method(meth_obj)
+
+      if find_body(class_name, meth_body, meth_obj, body) and meth_obj.document_self then
+        class_obj.add_method meth_obj
+        @stats.add_method meth_obj
       end
     end
   end
@@ -628,8 +632,8 @@ class RDoc::Parser::C < RDoc::Parser
   end
 
   def remove_private_comments(comment)
-     comment.gsub!(/\/?\*--(.*?)\/?\*\+\+/m, '')
-     comment.sub!(/\/?\*--.*/m, '')
+     comment.gsub!(/\/?\*--\n(.*?)\/?\*\+\+/m, '')
+     comment.sub!(/\/?\*--\n.*/m, '')
   end
 
   ##
diff --git a/lib/rdoc/parser/perl.rb b/lib/rdoc/parser/perl.rb
new file mode 100644
index 0000000000..43d1e9ff69
--- /dev/null
+++ b/lib/rdoc/parser/perl.rb
@@ -0,0 +1,165 @@
+require 'rdoc/parser'
+
+##
+#
+# This is an attamept to write a basic parser for Perl's
+# POD (Plain old Documentation) format.  Ruby code must
+# co-exist with Perl, and some tasks are easier in Perl
+# than Ruby because of existing libraries.
+#
+# One difficult is that Perl POD has no means of identifying
+# the classes (packages) and methods (subs) with which it
+# is associated, it is more like literate programming in so
+# far as it just happens to be in the same place as the code,
+# but need not be.
+#
+# We would like to support all the markup the POD provides
+# so that it will convert happily to HTML.  At the moment
+# I don't think I can do that: time constraints. 
+#
+
+class RDoc::Parser::PerlPOD < RDoc::Parser
+
+  parse_files_matching(/.p[lm]$/)
+
+  ##
+  # Prepare to parse a perl file
+
+  def initialize(top_level, file_name, content, options, stats)
+    super
+
+    preprocess = RDoc::Markup::PreProcess.new @file_name, @options.rdoc_include
+
+    preprocess.handle @content do |directive, param|
+      warn "Unrecognized directive '#{directive}' in #{@file_name}"
+    end
+  end
+
+  ##
+  # Extract the Pod(-like) comments from the code.
+  # At its most basic there will ne no need to distinguish
+  # between the different types of header, etc.
+  #
+  # This uses a simple finite state machine, in a very
+  # procedural pattern. I could "replace case with polymorphism"
+  # but I think it would obscure the intent, scatter the
+  # code all over tha place.  This machine is necessary
+  # because POD requires that directives be preceded by
+  # blank lines, so reading line by line is necessary, 
+  # and preserving state about what is seen is necesary.
+
+  def scan
+
+    @top_level.comment ||= ""
+    state=:code_blank    
+    line_number = 0
+    line = nil
+
+    # This started out as a really long nested case statement,
+    # which also led to repetitive code.  I'd like to avoid that
+    # so I'm using a "table" instead.
+    
+    # Firstly we need some procs to do the transition and processing
+    # work.  Because these are procs they are closures, and they can
+    # use variables in the local scope.
+    #
+    # First, the "nothing to see here" stuff.
+    code_noop = lambda do 
+      if line =~ /^\s+$/
+	state = :code_blank
+      end
+    end
+
+    pod_noop = lambda do 
+      if line =~ /^\s+$/
+	state = :pod_blank
+      end
+      @top_level.comment += filter(line)
+    end
+
+    begin_noop = lambda do 
+      if line =~ /^\s+$/
+	state = :begin_blank
+      end
+      @top_level.comment += filter(line)
+    end
+
+    # Now for the blocks that process code and comments...
+
+    transit_to_pod = lambda do
+      case line
+      when /^=(?:pod|head\d+)/
+	state = :pod_no_blank
+	@top_level.comment += filter(line)
+      when /^=over/
+	state = :over_no_blank
+	@top_level.comment += filter(line)
+      when /^=(?:begin|for)/
+	state = :begin_no_blank
+      end
+    end
+
+    process_pod = lambda do
+      case line
+      when  /^\s*$/
+	state = :pod_blank
+	@top_level.comment += filter(line)
+      when /^=cut/
+	state = :code_no_blank
+      when /^=end/
+	$stderr.puts "'=end' unexpected at #{line_number} in #{@file_name}"
+      else
+	@top_level.comment += filter(line)
+      end
+    end
+
+
+    process_begin = lambda do
+      case line
+      when  /^\s*$/
+	state = :begin_blank
+	@top_level.comment += filter(line)
+      when /^=end/
+	state = :code_no_blank
+      when /^=cut/
+	$stderr.puts "'=cut' unexpected at #{line_number} in #{@file_name}"
+      else
+	@top_level.comment += filter(line)
+      end
+
+    end
+
+
+    transitions = { :code_no_blank => code_noop,
+                    :code_blank => transit_to_pod,
+		    :pod_no_blank => pod_noop,
+		    :pod_blank => process_pod,
+		    :begin_no_blank => begin_noop,
+		    :begin_blank => process_begin}
+    @content.each_line do |l|
+      line = l
+      line_number += 1
+      transitions[state].call
+    end # each line
+
+    @top_level
+  end
+
+  # Filter the perl markup that does the same as the rdoc
+  # filtering.  Only basic for now. Will probably need a
+  # proper parser to cope with C<<...>> etc
+  def filter(comment)
+    return '' if comment =~ /^=pod\s*$/
+    comment.gsub!(/^=pod/, '==')
+    comment.gsub!(/^=head(\d+)/) do 
+      "=" * $1.to_i
+    end
+    comment.gsub!(/=item/, '');
+    comment.gsub!(/C<(.*?)>/, '<tt>\1</tt>');
+    comment.gsub!(/I<(.*?)>/, '<i>\1</i>');
+    comment.gsub!(/B<(.*?)>/, '<b>\1</b>');
+    comment
+  end
+
+end
+
diff --git a/lib/rdoc/parser/ruby.rb b/lib/rdoc/parser/ruby.rb
index abbc85bde7..865cb79d39 100644
--- a/lib/rdoc/parser/ruby.rb
+++ b/lib/rdoc/parser/ruby.rb
@@ -134,7 +134,7 @@ module RDoc::RubyToken
 
   TokenDefinitions = [
     [:TkCLASS,      TkKW,  "class",  EXPR_CLASS],
-    [:TkMODULE,     TkKW,  "module", EXPR_BEG],
+    [:TkMODULE,     TkKW,  "module", EXPR_CLASS],
     [:TkDEF,        TkKW,  "def",    EXPR_FNAME],
     [:TkUNDEF,      TkKW,  "undef",  EXPR_FNAME],
     [:TkBEGIN,      TkKW,  "begin",  EXPR_BEG],
@@ -1945,9 +1945,9 @@ class RDoc::Parser::Ruby < RDoc::Parser
         case tk
         when TkSEMICOLON
           break
-        when TkLPAREN, TkfLPAREN
+        when TkLPAREN, TkfLPAREN, TkLBRACE, TkLBRACK, TkDO
           nest += 1
-        when TkRPAREN
+        when TkRPAREN, TkRBRACE, TkRBRACK, TkEND
           nest -= 1
         when TkCOMMENT
           if nest <= 0 && @scanner.lex_state == EXPR_END
@@ -1955,7 +1955,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
             break
           end
         when TkNL
-          if (@scanner.lex_state == EXPR_END and nest <= 0) || !@scanner.continue
+          if (nest <= 0) && ((@scanner.lex_state == EXPR_END) || (!@scanner.continue))
             unget_tk(tk)
             break
           end
@@ -2683,8 +2683,8 @@ class RDoc::Parser::Ruby < RDoc::Parser
   end
 
   def remove_private_comments(comment)
-    comment.gsub!(/^#--.*?^#\+\+/m, '')
-    comment.sub!(/^#--.*/m, '')
+    comment.gsub!(/^#--\n.*?^#\+\+/m, '')
+    comment.sub!(/^#--\n.*/m, '')
   end
 
   def remove_token_listener(obj)
diff --git a/lib/rdoc/parser/simple.rb b/lib/rdoc/parser/simple.rb
index 6e123a4655..cdfe686718 100644
--- a/lib/rdoc/parser/simple.rb
+++ b/lib/rdoc/parser/simple.rb
@@ -31,7 +31,7 @@ class RDoc::Parser::Simple < RDoc::Parser
   end
 
   def remove_private_comments(comment)
-    comment.gsub(/^--[^-].*?^\+\+/m, '').sub(/^--.*/m, '')
+    comment.gsub(/^--\n.*?^\+\+/m, '').sub(/^--\n.*/m, '')
   end
 
 end
diff --git a/lib/rdoc/rdoc.rb b/lib/rdoc/rdoc.rb
index bc0a32f407..ce1cb1a93f 100644
--- a/lib/rdoc/rdoc.rb
+++ b/lib/rdoc/rdoc.rb
@@ -7,6 +7,7 @@ require 'rdoc/parser/simple'
 require 'rdoc/parser/ruby'
 require 'rdoc/parser/c'
 require 'rdoc/parser/f95'
+require 'rdoc/parser/perl'
 
 require 'rdoc/stats'
 require 'rdoc/options'
@@ -189,11 +190,11 @@ module RDoc
 
     def parse_files(options)
       @stats = Stats.new options.verbosity
-      
+
       files = options.files
       files = ["."] if files.empty?
 
-      file_list = normalized_file_list(options, files, true)
+      file_list = normalized_file_list(options, files, true, options.exclude)
 
       return [] if file_list.empty?
 
@@ -288,6 +289,5 @@ module RDoc
       end
     end
   end
-
 end
 
diff --git a/lib/rdoc/ri/cache.rb b/lib/rdoc/ri/cache.rb
index 2e267d95fb..06177a00de 100644
--- a/lib/rdoc/ri/cache.rb
+++ b/lib/rdoc/ri/cache.rb
@@ -14,7 +14,7 @@ class RDoc::RI::ClassEntry
     @inferior_classes = []
   end
 
-  # We found this class in more tha one place, so add
+  # We found this class in more than one place, so add
   # in the name from there.
   def add_path(path)
     @path_names << path
@@ -37,10 +37,10 @@ class RDoc::RI::ClassEntry
       if name =~ /^(.*?)-(c|i).yaml$/
         external_name = $1
         is_class_method = $2 == "c"
-        internal_name = RiWriter.external_to_internal(external_name)
+        internal_name = RDoc::RI::Writer.external_to_internal(external_name)
         list = is_class_method ? @class_methods : @instance_methods
         path = File.join(dir, name)
-        list << MethodEntry.new(path, internal_name, is_class_method, self)
+        list << RDoc::RI::MethodEntry.new(path, internal_name, is_class_method, self)
       else
         full_name = File.join(dir, name)
         if File.directory?(full_name)
@@ -48,7 +48,7 @@ class RDoc::RI::ClassEntry
           if inf_class
             inf_class.add_path(full_name)
           else
-            inf_class = ClassEntry.new(full_name, name, self)
+            inf_class = RDoc::RI::ClassEntry.new(full_name, name, self)
             @inferior_classes << inf_class
           end
           inf_class.load_from(full_name)
@@ -168,7 +168,7 @@ class RDoc::RI::MethodEntry
 end
 
 ##
-# We represent everything know about all 'ri' files accessible to this program
+# We represent everything known about all 'ri' files accessible to this program
 
 class RDoc::RI::Cache
 
@@ -185,4 +185,3 @@ class RDoc::RI::Cache
   end
 
 end
-
diff --git a/lib/rdoc/ri/descriptions.rb b/lib/rdoc/ri/descriptions.rb
index 0d8560323a..467b7de2a9 100644
--- a/lib/rdoc/ri/descriptions.rb
+++ b/lib/rdoc/ri/descriptions.rb
@@ -77,7 +77,9 @@ end
 class RDoc::RI::ModuleDescription < RDoc::RI::Description
 
   attr_accessor :class_methods
+  attr_accessor :class_method_extensions
   attr_accessor :instance_methods
+  attr_accessor :instance_method_extensions
   attr_accessor :attributes
   attr_accessor :constants
   attr_accessor :includes
@@ -148,6 +150,7 @@ class RDoc::RI::MethodDescription < RDoc::RI::Description
   attr_accessor :aliases
   attr_accessor :is_alias_for
   attr_accessor :params
+  attr_accessor :source_path
 
 end
 
diff --git a/lib/rdoc/ri/display.rb b/lib/rdoc/ri/display.rb
index 379cef11b3..05a7cf253d 100644
--- a/lib/rdoc/ri/display.rb
+++ b/lib/rdoc/ri/display.rb
@@ -1,5 +1,15 @@
 require 'rdoc/ri'
 
+# readline support might not be present, so be careful
+# when requiring it.
+begin
+  require('readline')
+  require('abbrev')
+  CAN_USE_READLINE = true
+rescue
+  CAN_USE_READLINE = false
+end
+
 ##
 # This is a kind of 'flag' module. If you want to write your own 'ri' display
 # module (perhaps because you're writing an IDE), you write a class which
@@ -41,7 +51,7 @@ class RDoc::RI::DefaultDisplay
   # Display information about +klass+.  Fetches additional information from
   # +ri_reader+ as necessary.
 
-  def display_class_info(klass, ri_reader)
+  def display_class_info(klass)
     page do
       superclass = klass.superclass_string
 
@@ -61,17 +71,11 @@ class RDoc::RI::DefaultDisplay
         @formatter.blankline
         @formatter.display_heading("Includes:", 2, "")
         incs = []
+
         klass.includes.each do |inc|
-          inc_desc = ri_reader.find_class_by_name(inc.name)
-          if inc_desc
-            str = inc.name + "("
-            str << inc_desc.instance_methods.map{|m| m.name}.join(", ")
-            str << ")"
-            incs << str
-          else
-            incs << inc.name
-          end
-      end
+          incs << inc.name
+        end
+
         @formatter.wrap(incs.sort.join(', '))
       end
 
@@ -82,42 +86,19 @@ class RDoc::RI::DefaultDisplay
         constants = klass.constants.sort_by { |constant| constant.name }
 
         constants.each do |constant|
+          @formatter.wrap "#{constant.name} = #{constant.value}"
           if constant.comment then
-            @formatter.wrap "#{constant.name}:"
-
             @formatter.indent do
               @formatter.display_flow constant.comment
             end
           else
-            @formatter.wrap constant.name
+            @formatter.break_to_newline
           end
         end
       end
 
-      class_data = [
-        :class_methods,
-        :class_method_extensions,
-        :instance_methods,
-        :instance_method_extensions,
-      ]
-
-      class_data.each do |data_type|
-        data = klass.send data_type
-
-        unless data.empty? then
-          @formatter.blankline
-
-          heading = data_type.to_s.split('_').join(' ').capitalize << ':'
-          @formatter.display_heading heading, 2, ''
-
-          data = data.map { |item| item.name }.sort.join ', '
-          @formatter.wrap data
-        end
-      end
-
       unless klass.attributes.empty? then
         @formatter.blankline
-
         @formatter.display_heading 'Attributes:', 2, ''
 
         attributes = klass.attributes.sort_by { |attribute| attribute.name }
@@ -130,11 +111,119 @@ class RDoc::RI::DefaultDisplay
             end
           else
             @formatter.wrap "#{attribute.name} (#{attribute.rw})"
+            @formatter.break_to_newline
           end
         end
       end
+
+      return display_class_method_list(klass)
     end
   end
+  
+  ##
+  # Given a Hash mapping a class' methods to method types (returned by
+  # display_class_method_list), this method allows the user to
+  # choose one of the methods.
+  
+  def get_class_method_choice(method_map)
+    if CAN_USE_READLINE
+      # prepare abbreviations for tab completion
+      abbreviations = method_map.keys.abbrev
+      Readline.completion_proc = proc do |string| 
+        abbreviations.values.uniq.grep(/^#{string}/)
+      end
+    end
+    
+    @formatter.raw_print_line "\nEnter the method name you want.\n"
+    @formatter.raw_print_line "Class methods can be preceeded by '::' and instance methods by '#'.\n"
+
+    if CAN_USE_READLINE
+      @formatter.raw_print_line "You can use tab to autocomplete.\n"
+      @formatter.raw_print_line "Enter a blank line to exit.\n"
+      
+      choice_string = Readline.readline(">> ").strip
+    else
+      @formatter.raw_print_line "Enter a blank line to exit.\n"
+      @formatter.raw_print_line ">> "
+      choice_string = $stdin.gets.strip
+    end
+    
+    if choice_string == ''
+      return nil
+    else
+      class_or_instance = method_map[choice_string]
+
+      if class_or_instance
+        # If the user's choice is not preceeded by a '::' or a '#', figure
+        # out whether they want a class or an instance method and decorate
+        # the choice appropriately.
+        if(choice_string =~ /^[a-zA-Z]/)
+          if(class_or_instance == :class)
+            choice_string = "::#{choice_string}"
+          else
+            choice_string = "##{choice_string}"
+          end
+        end
+
+        return choice_string
+      else
+        @formatter.raw_print_line "No method matched '#{choice_string}'.\n"
+        return nil
+      end
+    end
+  end
+  
+
+  ##
+  # Display methods on +klass+
+  # Returns a hash mapping method name to method contents (HACK?)
+
+  def display_class_method_list(klass)
+    method_map = {}
+
+    class_data = [
+                  :class_methods,
+                  :class_method_extensions,
+                  :instance_methods,
+                  :instance_method_extensions,
+                 ]
+    
+    class_data.each do |data_type|
+      data = klass.send data_type
+      
+      unless data.nil? or data.empty? then
+        @formatter.blankline
+        
+        heading = data_type.to_s.split('_').join(' ').capitalize << ':'
+        @formatter.display_heading heading, 2, ''
+        
+        method_names = []
+        data.each do |item|
+          method_names << item.name
+
+          if(data_type == :class_methods ||
+             data_type == :class_method_extensions) then
+            method_map["::#{item.name}"] = :class
+            method_map[item.name] = :class
+          else
+            #
+            # Since we iterate over instance methods after class methods,
+            # an instance method always will overwrite the unqualified
+            # class method entry for a class method of the same name.
+            #
+            method_map["##{item.name}"] = :instance
+            method_map[item.name] = :instance
+          end
+        end
+        method_names.sort!
+
+        @formatter.wrap method_names.join(',')
+      end
+    end
+
+    method_map
+  end
+  private :display_class_method_list
 
   ##
   # Display an Array of RDoc::Markup::Flow objects, +flow+.
@@ -172,10 +261,42 @@ class RDoc::RI::DefaultDisplay
   def display_method_list(methods)
     page do
       @formatter.wrap "More than one method matched your request.  You can refine your search by asking for information on one of:"
-
       @formatter.blankline
 
-      @formatter.wrap methods.map { |m| m.full_name }.join(", ")
+      methods.each do |method|
+        @formatter.raw_print_line "#{method.full_name} [#{method.source_path}]\n"
+      end
+    end
+  end
+  
+  ##
+  # Display a list of +methods+ and allow the user to select one of them.
+
+  def display_method_list_choice(methods)
+    page do
+      @formatter.wrap "More than one method matched your request.  Please choose one of the possible matches."
+      @formatter.blankline
+
+      methods.each_with_index do |method, index|
+        @formatter.raw_print_line "%3d %s [%s]\n" % [index + 1, method.full_name, method.source_path]
+      end
+      
+      @formatter.raw_print_line ">> "
+      
+      choice = $stdin.gets.strip!
+
+      if(choice == '')
+        return
+      end
+
+      choice = choice.to_i
+
+      if ((choice == 0) || (choice > methods.size)) then
+        @formatter.raw_print_line "Invalid choice!\n"
+      else
+        method = methods[choice - 1] 
+        display_method_info(method)
+      end
     end
   end
 
@@ -198,10 +319,8 @@ class RDoc::RI::DefaultDisplay
       @formatter.break_to_newline
     end
 
-    if method.source_path then
-      @formatter.blankline
-      @formatter.wrap("Extension from #{method.source_path}")
-    end
+    @formatter.blankline
+    @formatter.wrap("From #{method.source_path}")
   end
 
   ##
diff --git a/lib/rdoc/ri/driver.rb b/lib/rdoc/ri/driver.rb
index dfc5f2f98a..0c91232b70 100644
--- a/lib/rdoc/ri/driver.rb
+++ b/lib/rdoc/ri/driver.rb
@@ -11,29 +11,33 @@ require 'rdoc/markup/to_flow'
 
 class RDoc::RI::Driver
 
-  class Hash < ::Hash
-    def self.convert(hash)
-      hash = new.update hash
+  #
+  # This class offers both Hash and OpenStruct functionality.
+  # We convert from the Core Hash to this before calling any of
+  # the display methods, in order to give the display methods
+  # a cleaner API for accessing the data.
+  #
+  class OpenStructHash < Hash
+    #
+    # This method converts from a Hash to an OpenStructHash.
+    #
+    def self.convert(object)
+      case object
+      when Hash then
+        new_hash = new # Convert Hash -> OpenStructHash
 
-      hash.each do |key, value|
-        hash[key] = case value
-                    when ::Hash then
-                      convert value
-                    when Array then
-                      value = value.map do |v|
-                        ::Hash === v ? convert(v) : v
-                      end
-                      value
-                    else
-                      value
-                    end
+        object.each do |key, value|
+          new_hash[key] = convert(value)
+        end
+
+        new_hash
+      when Array then
+        object.map do |element|
+          convert(element)
+        end
+      else
+        object
       end
-
-      hash
-    end
-
-    def method_missing method, *args
-      self[method.to_s]
     end
 
     def merge_enums(other)
@@ -57,6 +61,10 @@ class RDoc::RI::Driver
         end
       end
     end
+
+    def method_missing method, *args
+      self[method.to_s]
+    end
   end
 
   class Error < RDoc::RI::Error; end
@@ -69,25 +77,31 @@ class RDoc::RI::Driver
 
   attr_accessor :homepath # :nodoc:
 
-  def self.process_args(argv)
+  def self.default_options
     options = {}
     options[:use_stdout] = !$stdout.tty?
     options[:width] = 72
     options[:formatter] = RDoc::RI::Formatter.for 'plain'
-    options[:list_classes] = false
-    options[:list_names] = false
+    options[:interactive] = false
+    options[:use_cache] = true
 
-    # By default all 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 = []
+    # By default all standard paths are used.
+    options[:use_system] = true
+    options[:use_site] = true
+    options[:use_home] = true
+    options[:use_gems] = true
+    options[:extra_doc_dirs] = []
+
+    return options
+  end
+
+  def self.process_args(argv)
+    options = default_options
 
     opts = OptionParser.new do |opt|
       opt.program_name = File.basename $0
       opt.version = RDoc::VERSION
+      opt.release = nil
       opt.summary_indent = ' ' * 4
 
       directories = [
@@ -142,30 +156,6 @@ Options may also be set in the 'RI' environment variable.
       opt.separator "Options:"
       opt.separator nil
 
-      opt.on("--classes", "-c",
-             "Display the names of classes and modules we",
-             "know about.") do |value|
-        options[:list_classes] = value
-      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:",
@@ -179,49 +169,101 @@ Options may also be set in the 'RI' environment variable.
 
       opt.separator nil
 
-      unless RDoc::RI::Paths::GEMDIRS.empty? then
-        opt.on("--[no-]gems",
-               "Include documentation from RubyGems.") do |value|
-          use_gems = value
+      opt.on("--doc-dir=DIRNAME", "-d", Array,
+             "List of directories from which to source",
+             "documentation in addition to the standard",
+             "directories.  May be repeated.") do |value|
+        value.each do |dir|
+          unless File.directory? dir then
+            raise OptionParser::InvalidArgument, "#{dir} is not a directory"
+          end
+
+          options[:extra_doc_dirs] << File.expand_path(dir)
         end
       end
 
       opt.separator nil
 
-      opt.on("--[no-]home",
-             "Include documentation stored in ~/.rdoc.") do |value|
-        use_home = value
+      opt.on("--[no-]use-cache",
+             "Whether or not to use ri's cache.",
+             "True by default.") do |value|
+        options[:use_cache] = value
       end
 
       opt.separator nil
 
-      opt.on("--[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
+      opt.on("--no-standard-docs",
+             "Do not include documentation from",
+             "the Ruby standard library, site_lib,",
+             "installed gems, or ~/.rdoc.",
+             "Equivalent to specifying",
+             "the options --no-system, --no-site, --no-gems,",
+             "and --no-home") do
+        options[:use_system] = false
+        options[:use_site] = false
+        options[:use_gems] = false
+        options[:use_home] = false
       end
 
       opt.separator nil
 
       opt.on("--[no-]system",
              "Include documentation from Ruby's standard",
-             "library.") do |value|
-        use_system = value
+             "library.  Defaults to true.") do |value|
+        options[:use_system] = value
+      end
+
+      opt.separator nil
+
+      opt.on("--[no-]site",
+             "Include documentation from libraries",
+             "installed in site_lib.",
+             "Defaults to true.") do |value|
+        options[:use_site] = value
+      end
+
+      opt.separator nil
+
+      opt.on("--[no-]gems",
+             "Include documentation from RubyGems.",
+             "Defaults to true.") do |value|
+        options[:use_gems] = value
+      end
+
+      opt.separator nil
+
+      opt.on("--[no-]home",
+             "Include documentation stored in ~/.rdoc.",
+             "Defaults to true.") do |value|
+        options[:use_home] = value
+      end
+
+      opt.separator nil
+
+      opt.on("--list-doc-dirs",
+             "List the directories from which ri will",
+             "source documentation on stdout and exit.") do
+        options[:list_doc_dirs] = true
+      end
+
+      opt.separator nil
+
+      opt.on("--no-pager", "-T",
+             "Send output directly to stdout,",
+             "rather than to a pager.") do
+        options[:use_stdout] = true
+      end
+
+      opt.on("--interactive", "-i",
+             "This makes ri go into interactive mode.",
+             "When ri is in interactive mode it will",
+             "allow the user to disambiguate lists of",
+             "methods in case multiple methods match",
+             "against a method search string.  It also",
+             "will allow the user to enter in a method",
+             "name (with auto-completion, if readline",
+             "is supported) when viewing a class.") do
+        options[:interactive] = true
       end
 
       opt.separator nil
@@ -238,10 +280,10 @@ Options may also be set in the 'RI' environment variable.
 
     options[:names] = argv
 
-    options[:path] = RDoc::RI::Paths.path(use_system, use_site, use_home,
-                                          use_gems, *doc_dirs)
-    options[:raw_path] = RDoc::RI::Paths.raw_path(use_system, use_site,
-                                                  use_home, use_gems, *doc_dirs)
+    options[:formatter] ||= RDoc::RI::Formatter.for('plain')
+    options[:use_stdout] ||= !$stdout.tty?
+    options[:use_stdout] ||= options[:interactive]
+    options[:width] ||= 72
 
     options
 
@@ -258,22 +300,30 @@ Options may also be set in the 'RI' environment variable.
     ri.run
   end
 
-  def initialize(options={})
-    options[:formatter] ||= RDoc::RI::Formatter.for('plain')
-    options[:use_stdout] ||= !$stdout.tty?
-    options[:width] ||= 72
-    @names = options[:names]
+  def initialize(initial_options={})
+    options = self.class.default_options.update(initial_options)
 
+    @names = options[:names]
     @class_cache_name = 'classes'
-    @all_dirs = RDoc::RI::Paths.path(true, true, true, true)
+
+    @doc_dirs = RDoc::RI::Paths.path(options[:use_system],
+                                     options[:use_site],
+                                     options[:use_home],
+                                     options[:use_gems],
+                                     options[:extra_doc_dirs])
+
     @homepath = RDoc::RI::Paths.raw_path(false, false, true, false).first
     @homepath = @homepath.sub(/\.rdoc/, '.ri')
-    @sys_dirs = RDoc::RI::Paths.raw_path(true, false, false, false)
+    @sys_dir = RDoc::RI::Paths.raw_path(true, false, false, false).first
+    @list_doc_dirs = options[:list_doc_dirs]
 
     FileUtils.mkdir_p cache_file_path unless File.directory? cache_file_path
+    @cache_doc_dirs_path = File.join cache_file_path, ".doc_dirs"
 
+    @use_cache = options[:use_cache]
     @class_cache = nil
 
+    @interactive = options[:interactive]
     @display = RDoc::RI::DefaultDisplay.new(options[:formatter],
                                             options[:width],
                                             options[:use_stdout])
@@ -282,158 +332,67 @@ Options may also be set in the 'RI' environment variable.
   def class_cache
     return @class_cache if @class_cache
 
-    newest = map_dirs('created.rid', :all) do |f|
+    # Get the documentation directories used to make the cache in order to see
+    # whether the cache is valid for the current ri instantiation.
+    if(File.readable?(@cache_doc_dirs_path))
+      cache_doc_dirs = IO.read(@cache_doc_dirs_path).split("\n")
+    else
+      cache_doc_dirs = []
+    end
+
+    newest = map_dirs('created.rid') do |f|
       File.mtime f if test ?f, f
     end.max
 
+    # An up to date cache file must have been created more recently than
+    # the last modification of any of the documentation directories.  It also
+    # must have been created with the same documentation directories
+    # as those from which ri currently is sourcing documentation.
     up_to_date = (File.exist?(class_cache_file_path) and
-                  newest and newest < File.mtime(class_cache_file_path))
+                  newest and newest < File.mtime(class_cache_file_path) and
+                  (cache_doc_dirs == @doc_dirs))
 
-    @class_cache = if up_to_date then
-                     load_cache_for @class_cache_name
-                   else
-                     class_cache = RDoc::RI::Driver::Hash.new
+    if up_to_date and @use_cache then
+      open class_cache_file_path, 'rb' do |fp|
+        begin
+          @class_cache = Marshal.load fp.read
+        rescue
+          #
+          # This shouldn't be necessary, since the up_to_date logic above
+          # should force the cache to be recreated when a new version of
+          # rdoc is installed.  This seems like a worthwhile enhancement
+          # to ri's robustness, however.
+          #
+          $stderr.puts "Error reading the class cache; recreating the class cache!"
+          @class_cache = create_class_cache
+        end
+      end
+    else
+      @class_cache = create_class_cache
+    end
 
-                     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
-
-    @class_cache = RDoc::RI::Driver::Hash.convert @class_cache
     @class_cache
   end
 
-  def class_cache_file_path
-    File.join cache_file_path, @class_cache_name
-  end
+  def create_class_cache
+    class_cache = OpenStructHash.new
 
-  def cache_file_for(klassname)
-    File.join cache_file_path, klassname.gsub(/:+/, "-")
-  end
-
-  def cache_file_path
-    File.join @homepath, 'cache'
-  end
-
-  def display_class(name)
-    klass = class_cache[name]
-    klass = RDoc::RI::Driver::Hash.convert klass
-    @display.display_class_info klass, class_cache
-  end
-
-  def get_info_for(arg)
-    @names = [arg]
-    run
-  end
-
-  def load_cache_for(klassname)
-    path = cache_file_for klassname
-
-    cache = nil
-
-    if File.exist? path and
-       File.mtime(path) >= File.mtime(class_cache_file_path) then
-      open path, 'rb' do |fp|
-        cache = Marshal.load fp.read
+    if(@use_cache)
+      # Dump the documentation directories to a file in the cache, so that
+      # we only will use the cache for future instantiations with identical
+      # documentation directories.
+      File.open @cache_doc_dirs_path, "wb" do |fp|
+        fp << @doc_dirs.join("\n")
       end
-    else
-      class_cache = nil
-
-      open class_cache_file_path, 'rb' do |fp|
-        class_cache = Marshal.load fp.read
-      end
-
-      klass = class_cache[klassname]
-      return nil unless klass
-
-      method_files = klass["sources"]
-      cache = RDoc::RI::Driver::Hash.new
-
-      sys_dir = @sys_dirs.first
-      method_files.each do |f|
-        system_file = f.index(sys_dir) == 0
-        Dir[File.join(File.dirname(f), "*")].each do |yaml|
-          next unless yaml =~ /yaml$/
-          next if yaml =~ /cdesc-[^\/]+yaml$/
-          method = read_yaml yaml
-          name = method["full_name"]
-          ext_path = f
-          ext_path = "gem #{$1}" if f =~ %r%gems/[\d.]+/doc/([^/]+)%
-          method["source_path"] = ext_path unless system_file
-          cache[name] = RDoc::RI::Driver::Hash.convert method
-        end
-      end
-
-      write_cache cache, path
     end
 
-    RDoc::RI::Driver::Hash.convert cache
-  end
+    classes = map_dirs('**/cdesc*.yaml') { |f| Dir[f] }
+    warn "Updating class cache with #{classes.size} classes..."
+    populate_class_cache class_cache, classes
 
-  ##
-  # Finds the next ancestor of +orig_klass+ after +klass+.
+    write_cache class_cache, class_cache_file_path
 
-  def lookup_ancestor(klass, orig_klass)
-    cache = class_cache[orig_klass]
-
-    return nil unless cache
-
-    ancestors = [orig_klass]
-    ancestors.push(*cache.includes.map { |inc| inc['name'] })
-    ancestors << cache.superclass
-
-    ancestor = ancestors[ancestors.index(klass) + 1]
-
-    return ancestor if ancestor
-
-    lookup_ancestor klass, cache.superclass
-  end
-
-  ##
-  # Finds the method
-
-  def lookup_method(name, klass)
-    cache = load_cache_for klass
-    return nil unless cache
-
-    method = cache[name.gsub('.', '#')]
-    method = cache[name.gsub('.', '::')] unless method
-    method
-  end
-
-  def map_dirs(file_name, system=false)
-    dirs = if system == :all then
-             @all_dirs
-           else
-             if system then
-               @sys_dirs
-             else
-               @all_dirs - @sys_dirs
-             end
-           end
-
-    dirs.map { |dir| yield File.join(dir, file_name) }.flatten.compact
-  end
-
-  ##
-  # Extract the class and method name parts from +name+ like Foo::Bar#baz
-
-  def parse_name(name)
-    parts = name.split(/(::|\#|\.)/)
-
-    if parts[-2] != '::' or parts.last !~ /^[A-Z]/ then
-      meth = parts.pop
-      parts.pop
-    end
-
-    klass = parts.join
-
-    [klass, meth]
+    class_cache
   end
 
   def populate_class_cache(class_cache, classes, extension = false)
@@ -455,64 +414,222 @@ Options may also be set in the 'RI' environment variable.
           desc["class_method_extensions"] = desc.delete "class_methods"
         end
 
-        klass = RDoc::RI::Driver::Hash.convert klass
-
         klass.merge_enums desc
         klass["sources"] << cdesc
       end
     end
   end
 
+  def class_cache_file_path
+    File.join cache_file_path, @class_cache_name
+  end
+
+  def cache_file_for(klassname)
+    File.join cache_file_path, klassname.gsub(/:+/, "-")
+  end
+
+  def cache_file_path
+    File.join @homepath, 'cache'
+  end
+
+  def display_class(name)
+    klass = class_cache[name]
+    @display.display_class_info klass
+  end
+
+  def display_method(method)
+    @display.display_method_info method
+  end
+
+  def get_info_for(arg)
+    @names = [arg]
+    run
+  end
+
+  def load_cache_for(klassname)
+    path = cache_file_for klassname
+
+    cache = nil
+
+    if File.exist? path and
+       File.mtime(path) >= File.mtime(class_cache_file_path) and
+       @use_cache then
+      open path, 'rb' do |fp|
+        begin
+          cache = Marshal.load fp.read
+        rescue
+          #
+          # The cache somehow is bad.  Recreate the cache.
+          #
+          $stderr.puts "Error reading the cache for #{klassname}; recreating the cache!"
+          cache = create_cache_for klassname, path
+        end
+      end
+    else
+      cache = create_cache_for klassname, path
+    end
+
+    cache
+  end
+
+  def create_cache_for(klassname, path)
+    klass = class_cache[klassname]
+    return nil unless klass
+
+    method_files = klass["sources"]
+    cache = OpenStructHash.new
+
+    method_files.each do |f|
+      system_file = f.index(@sys_dir) == 0
+      Dir[File.join(File.dirname(f), "*")].each do |yaml|
+        next unless yaml =~ /yaml$/
+        next if yaml =~ /cdesc-[^\/]+yaml$/
+
+        method = read_yaml yaml
+
+        if system_file then
+          method["source_path"] = "Ruby #{RDoc::RI::Paths::VERSION}"
+        else
+          if(f =~ %r%gems/[\d.]+/doc/([^/]+)%) then
+            ext_path = "gem #{$1}"
+          else
+            ext_path = f
+          end
+
+          method["source_path"] = ext_path
+        end
+
+        name = method["full_name"]
+        cache[name] = method
+      end
+    end
+
+    write_cache cache, path
+  end
+
+  ##
+  # Finds the next ancestor of +orig_klass+ after +klass+.
+
+  def lookup_ancestor(klass, orig_klass)
+    # This is a bit hacky, but ri will go into an infinite
+    # loop otherwise, since Object has an Object ancestor
+    # for some reason.  Depending on the documentation state, I've seen
+    # Kernel as an ancestor of Object and not as an ancestor of Object.
+    if ((orig_klass == "Object") &&
+        ((klass == "Kernel") || (klass == "Object")))
+      return nil
+    end
+
+    cache = class_cache[orig_klass]
+
+    return nil unless cache
+
+    ancestors = [orig_klass]
+    ancestors.push(*cache.includes.map { |inc| inc['name'] })
+    ancestors << cache.superclass
+    
+    ancestor_index = ancestors.index(klass)
+
+    if ancestor_index
+      ancestor = ancestors[ancestors.index(klass) + 1]
+      return ancestor if ancestor
+    end
+
+    lookup_ancestor klass, cache.superclass
+  end
+
+  ##
+  # Finds the method
+
+  def lookup_method(name, klass)
+    cache = load_cache_for klass
+    return nil unless cache
+
+    method = cache[name.gsub('.', '#')]
+    method = cache[name.gsub('.', '::')] unless method
+    method
+  end
+
+  def map_dirs(file_name)
+    @doc_dirs.map { |dir| yield File.join(dir, file_name) }.flatten.compact
+  end
+
+  ##
+  # Extract the class and method name parts from +name+ like Foo::Bar#baz
+
+  def parse_name(name)
+    parts = name.split(/(::|\#|\.)/)
+
+    if parts[-2] != '::' or parts.last !~ /^[A-Z]/ then
+      meth = parts.pop
+      parts.pop
+    end
+
+    klass = parts.join
+
+    [klass, meth]
+  end
+
   def read_yaml(path)
     data = File.read path
+
+    # Necessary to be backward-compatible with documentation generated
+    # by earliar RDoc versions.
     data = data.gsub(/ \!ruby\/(object|struct):(RDoc::RI|RI).*/, '')
     data = data.gsub(/ \!ruby\/(object|struct):SM::(\S+)/,
                      ' !ruby/\1:RDoc::Markup::\2')
-    YAML.load data
+    OpenStructHash.convert(YAML.load(data))
   end
 
   def run
-    if @names.empty? then
+    if(@list_doc_dirs)
+      puts @doc_dirs.join("\n")
+    elsif @names.empty? then
       @display.list_known_classes class_cache.keys.sort
     else
       @names.each do |name|
-        case name
-        when /::|\#|\./ then
-          if class_cache.key? name then
-            display_class name
-          else
-            klass, = parse_name name
+        if class_cache.key? name then
+          method_map = display_class name
+          if(@interactive)
+            method_name = @display.get_class_method_choice(method_map)
 
-            orig_klass = klass
-            orig_name = name
-
-            until klass == 'Kernel' do
-              method = lookup_method name, klass
-
-              break method if method
-
-              ancestor = lookup_ancestor klass, orig_klass
-
-              break unless ancestor
-
-              name = name.sub klass, ancestor
-              klass = ancestor
+            if(method_name != nil)
+              method = lookup_method "#{name}#{method_name}", name
+              display_method method
             end
-
-            raise NotFoundError, orig_name unless method
-
-            @display.display_method_info method
           end
-        else
-          if class_cache.key? name then
-            display_class name
-          else
-            methods = select_methods(/^#{name}/)
+        elsif name =~ /::|\#|\./ then
+          klass, = parse_name name
 
-            if methods.size == 0
-              raise NotFoundError, name
-            elsif methods.size == 1
-              @display.display_method_info methods.first
+          orig_klass = klass
+          orig_name = name
+
+          loop do
+            method = lookup_method name, klass
+
+            break method if method
+
+            ancestor = lookup_ancestor klass, orig_klass
+
+            break unless ancestor
+
+            name = name.sub klass, ancestor
+            klass = ancestor
+          end
+
+          raise NotFoundError, orig_name unless method
+
+          display_method method
+        else
+          methods = select_methods(/#{name}/)
+
+          if methods.size == 0
+            raise NotFoundError, name
+          elsif methods.size == 1
+            display_method methods[0]
+          else
+            if(@interactive)
+              @display.display_method_list_choice methods
             else
               @display.display_method_list methods
             end
@@ -540,12 +657,13 @@ Options may also be set in the 'RI' environment variable.
   end
 
   def write_cache(cache, path)
-    File.open path, "wb" do |cache_file|
-      Marshal.dump cache, cache_file
+    if(@use_cache)
+      File.open path, "wb" do |cache_file|
+        Marshal.dump cache, cache_file
+      end
     end
 
     cache
   end
 
 end
-
diff --git a/lib/rdoc/ri/formatter.rb b/lib/rdoc/ri/formatter.rb
index 0a0c3f7380..933882abc4 100644
--- a/lib/rdoc/ri/formatter.rb
+++ b/lib/rdoc/ri/formatter.rb
@@ -93,7 +93,7 @@ class RDoc::RI::Formatter
   end
 
   def raw_print_line(txt)
-    @output.puts txt
+    @output.print txt
   end
 
   ##
diff --git a/lib/rdoc/ri/paths.rb b/lib/rdoc/ri/paths.rb
index b4b6c64925..2f72b9dfd5 100644
--- a/lib/rdoc/ri/paths.rb
+++ b/lib/rdoc/ri/paths.rb
@@ -26,9 +26,9 @@ module RDoc::RI::Paths
 
   DOC_DIR  = "doc/rdoc"
 
-  version = RbConfig::CONFIG['ruby_version']
+  VERSION = RbConfig::CONFIG['ruby_version']
 
-  base    = File.join(RbConfig::CONFIG['datadir'], "ri", version)
+  base    = File.join(RbConfig::CONFIG['datadir'], "ri", VERSION)
   SYSDIR  = File.join(base, "system")
   SITEDIR = File.join(base, "site")
   homedir = ENV['HOME'] || ENV['USERPROFILE'] || ENV['HOMEPATH']
@@ -39,9 +39,6 @@ module RDoc::RI::Paths
     HOMEDIR = nil
   end
 
-  # This is the search path for 'ri'
-  PATH = [ SYSDIR, SITEDIR, HOMEDIR ].find_all {|p| p && File.directory?(p)}
-
   begin
     require 'rubygems' unless defined?(Gem) and defined?(Gem::Enable) and
                               Gem::Enable
@@ -67,7 +64,6 @@ module RDoc::RI::Paths
     end
 
     GEMDIRS = ri_paths.map { |k,v| v.last }.sort
-    GEMDIRS.each { |dir| PATH << dir }
   rescue LoadError
     GEMDIRS = []
   end
@@ -85,9 +81,6 @@ module RDoc::RI::Paths
   # found.
 
   def self.raw_path(use_system, use_site, use_home, use_gems, *extra_dirs)
-    return PATH unless use_system or use_site or use_home or use_gems or
-                       not extra_dirs.empty?
-
     path = []
     path << extra_dirs unless extra_dirs.empty?
     path << SYSDIR if use_system
@@ -97,6 +90,4 @@ module RDoc::RI::Paths
 
     return path.flatten.compact
   end
-
 end
-
diff --git a/lib/rdoc/ri/reader.rb b/lib/rdoc/ri/reader.rb
index 986bb75954..de3c8d9afa 100644
--- a/lib/rdoc/ri/reader.rb
+++ b/lib/rdoc/ri/reader.rb
@@ -45,7 +45,7 @@ class RDoc::RI::Reader
 
   def get_method(method_entry)
     path = method_entry.path_name
-    File.open(path) { |f| RI::Description.deserialize(f) }
+    File.open(path) { |f| RDoc::RI::Description.deserialize(f) }
   end
 
   ##
@@ -54,8 +54,8 @@ class RDoc::RI::Reader
   def get_class(class_entry)
     result = nil
     for path in class_entry.path_names
-      path = RiWriter.class_desc_path(path, class_entry)
-      desc = File.open(path) {|f| RI::Description.deserialize(f) }
+      path = RDoc::RI::Writer.class_desc_path(path, class_entry)
+      desc = File.open(path) {|f| RDoc::RI::Description.deserialize(f) }
       if result
         result.merge_in(desc)
       else
diff --git a/lib/rdoc/ri/util.rb b/lib/rdoc/ri/util.rb
index 34277f2594..4e91eb978d 100644
--- a/lib/rdoc/ri/util.rb
+++ b/lib/rdoc/ri/util.rb
@@ -1,7 +1,5 @@
 require 'rdoc/ri'
 
-class RDoc::RI::Error < RuntimeError; end
-
 ##
 # Break argument into its constituent class or module names, an
 # optional method type, and a method name
diff --git a/test/rdoc/binary.dat b/test/rdoc/binary.dat
new file mode 100644
index 0000000000000000000000000000000000000000..371950efe69506c3af56982f99feaacb8645773a
GIT binary patch
literal 1024
zcmV+b1poUViwFP?8!t!z1MEF(ciT3y{TluXG)a4{#CqDY8+nzpv_#w7>Q#|SoNo5$
zP!w!)E0J1~@?*QbzkO!_kOV2omJ>hPu6PogoWaZhGlRhZAmOoheREFTe7R69>=nOx
zl&b{SeznSf@1=i>>zi`9RNmPuS9i;M-@sjIfA<?weVpo~uXzw!J|W+Xov9Q0&dPFk
z;s2o5IAwopJoelN_k#P|AAXiM_J4|Nnf(Daoy;shp#FpS!dmt(?e6XFmn-{~U9kUN
zb*Hki|5IFd*}n<+GiO4-Mg|&qZ+CZv{ma$L?ta?-l~Sb&{lD~3jlAvpAGiN25?Pp(
z3zb5-lCOYC%9YYPMR}EfxJ!9Oj;Tw1YeH<#J#)_Iz7;y2OS~EW3LaKiuiyQf)-Z=1
zwXKolsuRhzlR|^`q1KlQDcynD8<@kU-UocQ|4AaZBV<eM91qlEEg{p~^NAB&DB7vn
zSAnnEYLS%iPnr=Udwu<bYHG`ohN+r*V+Cca+fZA>MoTpe&4`dEdQ%$?I?Zll*w(N)
zhM??pWn4@Z;ST${b|grKP0eV?68l<DQ_UeOv(ON=^-=v~0F9~YEv-2;v_{NT@3i!e
zHq<*OT3<H-i2?-fXwYg6d#ZWDjAJBB0cV(fy*E7SciXIlWD&h%YW)th8(Lw=Rf(w@
zU1(*a+iq(e(@3h>Pz??0)`6e0JdQL@x_vWUkF?f|Mz@zG1l$L$e+U+84^K3;8R=SL
z`VpGmXbphD5$MK{kbhG@sAvdvV0I<F3av49Wtu1mW0f9t7oEz$W<*9zs5!E!qk;|x
zrZzn8cLzNz5s5U_!=a)7EcX#k_=9q+b+kTs=+NvoyDi`$^GuMMVXj0T4vrIC>^8b;
zq}44<taa2w;Yg<5?Iev*+UhAZTsL(f{u!ExnqZ#4Q&PG;umeDcqFWwy`@=@$7-)%s
z0X!2k#1(nq;I=fV5uZ-1kd8^{kt@r09rv7A?wHJc@7$+BK&J4+I;RgD{eBwgnwizG
z(8))&-_bkASp#sLAabZ5@nA8)o}@L?NKkKEHPe(F)9N0hmeZK0R&sbjiQ~@ZA;A&t
zfz_&az`>TO)p6~~d`uN=KL#!gRjDBLrf>nlv@z%#`Ufpb4Mx#US+rQzDL5v}m0{F&
zkIOsB(!`h*G?}{a=+lP5EXz&AUe>YnmMM*r48vhVqdVv~q*%xJJ+<irZ|>WajC}7Z
zfPVI{@<j^|``wR5Dpim|GcRLENYFxGJJR}ErvWkO@Du30rDAN0$5(+g5)65+_=H`@
un#?Y&5e*$1)3k{N5z2AL^!i~dqqce{>Y)Z14vgn|r>UJL`f7Ar2Ec{_-2&<W

literal 0
HcmV?d00001

diff --git a/test/rdoc/rdoc_markup_to_html_crossref_reference.rb b/test/rdoc/rdoc_markup_to_html_crossref_reference.rb
new file mode 100644
index 0000000000..cbf6734b28
--- /dev/null
+++ b/test/rdoc/rdoc_markup_to_html_crossref_reference.rb
@@ -0,0 +1,31 @@
+#
+# This file is parsed by test_rdoc_markup_to_html_crossref.rb
+# during its tests.
+#
+class Ref_Class1
+end
+
+class Ref_Class2
+  class Ref_Class3
+    def method
+    end
+
+    class Helper1
+      def method?
+      end
+    end
+  end
+end
+
+class Ref_Class3
+  class Helper1
+  end
+
+  class Helper2
+  end
+end
+
+class Ref_Class4
+  class Ref_Class4
+  end
+end
diff --git a/test/rdoc/test_attribute_manager.rb b/test/rdoc/test_attribute_manager.rb
new file mode 100644
index 0000000000..298eca0141
--- /dev/null
+++ b/test/rdoc/test_attribute_manager.rb
@@ -0,0 +1,73 @@
+require 'test/unit'
+require 'rdoc/markup/attribute_manager'
+
+class TestAttributeManager < Test::Unit::TestCase
+
+  def setup
+    @am = RDoc::Markup::AttributeManager.new
+    @klass = RDoc::Markup::AttributeManager
+  end
+  
+  def teardown
+    silently do 
+      @klass.const_set(:MATCHING_WORD_PAIRS, {})
+      @klass.const_set(:WORD_PAIR_MAP, {})
+      @klass.const_set(:HTML_TAGS, {})
+    end
+  end
+
+  def test_initial_word_pairs
+    word_pairs = @klass::MATCHING_WORD_PAIRS
+    assert word_pairs.is_a?(Hash)
+    assert_equal(3, word_pairs.size)
+  end
+
+  def test_initial_html
+    html_tags = @klass::HTML_TAGS
+    assert html_tags.is_a?(Hash)
+    assert_equal(5, html_tags.size)
+  end
+
+  def test_add_matching_word_pair
+    @am.add_word_pair("x","x", :TEST)
+    word_pairs = @klass::MATCHING_WORD_PAIRS
+    assert_equal(4,word_pairs.size)
+    assert(word_pairs.has_key?("x"))
+  end
+  
+  def test_add_invalid_word_pair
+    assert_raise ArgumentError do
+      @am.add_word_pair("<", "<", :TEST)
+    end
+  end
+
+  def test_add_word_pair_map
+    @am.add_word_pair("x", "y", :TEST)
+    word_pair_map = @klass::WORD_PAIR_MAP
+    assert_equal(1,word_pair_map.size)
+    assert_equal(word_pair_map. keys.first.source, "(x)(\\S+)(y)")
+  end
+
+  def test_add_html_tag
+    @am.add_html("Test", :TEST)
+    tags = @klass::HTML_TAGS
+    assert_equal(6, tags.size)
+    assert(tags.has_key?("test"))
+  end
+
+  def test_add_special
+    @am.add_special("WikiWord", :WIKIWORD)
+    specials = @klass::SPECIAL
+    assert_equal(1,specials.size)
+    assert(specials.has_key?("WikiWord"))
+  end
+
+  def silently(&block)
+    warn_level = $VERBOSE
+    $VERBOSE = nil
+    result = block.call
+    $VERBOSE = warn_level
+    result
+  end
+
+end
diff --git a/test/rdoc/test_rdoc_info_formatting.rb b/test/rdoc/test_rdoc_info_formatting.rb
index 6c024f7454..b18cdf2931 100644
--- a/test/rdoc/test_rdoc_info_formatting.rb
+++ b/test/rdoc/test_rdoc_info_formatting.rb
@@ -5,7 +5,7 @@ require 'test/unit'
 require 'rdoc/generator/texinfo'
 
 # From chapter 18 of the Pickaxe 3rd ed. and the TexInfo manual.
-class TestRdocInfoFormatting < Test::Unit::TestCase
+class TestRDocInfoFormatting < Test::Unit::TestCase
   def setup
     @output_dir = File.join Dir.tmpdir, "test_rdoc_info_formatting_#{$$}"
     @output_file = File.join @output_dir, 'rdoc.texinfo'
@@ -19,7 +19,7 @@ class TestRdocInfoFormatting < Test::Unit::TestCase
   end
 
   def teardown
-    FileUtils.rm_rf @output_dir
+    # FileUtils.rm_rf @output_dir
   end
 
   # Make sure tags like *this* do not make HTML
@@ -73,10 +73,10 @@ class TestRdocInfoFormatting < Test::Unit::TestCase
   # === Everything deeper becomes a regular @heading
   # ====== Regardless of its nesting level
   def test_headings
-    assert_match(/@majorheading\{Huge heading should be a @@majorheading\}/)
-    assert_match(/@chapheading\{There is also @@chapheading\}/)
-    assert_match(/@heading\{Everything deeper becomes a regular @@heading\}/)
-    assert_match(/@heading\{Regardless of its nesting level\}/)
+    assert_match(/@majorheading Huge heading should be a @@majorheading/)
+    assert_match(/@chapheading There is also @@chapheading/)
+    assert_match(/@heading Everything deeper becomes a regular @@heading/)
+    assert_match(/@heading Regardless of its nesting level/)
   end
 
   # * list item
diff --git a/test/rdoc/test_rdoc_info_sections.rb b/test/rdoc/test_rdoc_info_sections.rb
index cceba186c1..6825d37a7d 100644
--- a/test/rdoc/test_rdoc_info_sections.rb
+++ b/test/rdoc/test_rdoc_info_sections.rb
@@ -6,10 +6,10 @@ require 'tmpdir'
 require 'rdoc/generator/texinfo'
 
 # give us access to check this stuff before it's rendered
-class RDoc::Generator::Texinfo; attr_reader :files, :classes; end
+class RDoc::Generator::TEXINFO; attr_reader :files, :classes; end
 class RDoc::RDoc; attr_reader :options; attr_reader :gen; end
 
-class TestRdocInfoSections < Test::Unit::TestCase
+class TestRDocInfoSections < Test::Unit::TestCase
 
   def setup
     @output_dir = File.join Dir.tmpdir, "test_rdoc_info_sections_#{$$}"
diff --git a/test/rdoc/test_rdoc_markup_attribute_manager.rb b/test/rdoc/test_rdoc_markup_attribute_manager.rb
index 8ba9d7440a..eea87822a8 100644
--- a/test/rdoc/test_rdoc_markup_attribute_manager.rb
+++ b/test/rdoc/test_rdoc_markup_attribute_manager.rb
@@ -1,5 +1,6 @@
 require "test/unit"
 require "rdoc/markup/inline"
+require "rdoc/markup/to_html_crossref"
 
 class TestRDocMarkupAttributeManager < Test::Unit::TestCase
 
@@ -201,24 +202,23 @@ class TestRDocMarkupAttributeManager < Test::Unit::TestCase
   end
 
   def test_special
-    # class names, variable names, file names, or instance variables
-    @am.add_special(/(
-                       \b([A-Z]\w+(::\w+)*)
-                       | \#\w+[!?=]?
-                       | \b\w+([_\/\.]+\w+)+[!?=]?
-                      )/x,
-                    :CROSSREF)
+    @am.add_special(RDoc::Markup::ToHtmlCrossref::CROSSREF_REGEXP, :CROSSREF)
 
-    assert_equal(["cat"], @am.flow("cat"))
+    #
+    # The apostrophes in "cats'" and "dogs'" suppress the flagging of these
+    # words as potential cross-references, which is necessary for the unit
+    # tests.  Unfortunately, the markup engine right now does not actually
+    # check whether a cross-reference is valid before flagging it.
+    #
+    assert_equal(["cats'"], @am.flow("cats'"))
 
-    assert_equal(["cat ", crossref("#fred"), " dog"].flatten,
-                  @am.flow("cat #fred dog"))
+    assert_equal(["cats' ", crossref("#fred"), " dogs'"].flatten,
+                  @am.flow("cats' #fred dogs'"))
 
-    assert_equal([crossref("#fred"), " dog"].flatten,
-                  @am.flow("#fred dog"))
+    assert_equal([crossref("#fred"), " dogs'"].flatten,
+                  @am.flow("#fred dogs'"))
 
-    assert_equal(["cat ", crossref("#fred")].flatten, @am.flow("cat #fred"))
+    assert_equal(["cats' ", crossref("#fred")].flatten, @am.flow("cats' #fred"))
   end
 
 end
-
diff --git a/test/rdoc/test_rdoc_markup_to_html.rb b/test/rdoc/test_rdoc_markup_to_html.rb
index 463228cc4a..05fb9f2375 100644
--- a/test/rdoc/test_rdoc_markup_to_html.rb
+++ b/test/rdoc/test_rdoc_markup_to_html.rb
@@ -2,7 +2,7 @@ require 'test/unit'
 require 'rdoc/markup'
 require 'rdoc/markup/to_html'
 
-class TestRdocMarkupToHtml < Test::Unit::TestCase
+class TestRDocMarkupToHtml < Test::Unit::TestCase
 
   def setup
     @am = RDoc::Markup::AttributeManager.new
@@ -10,11 +10,23 @@ class TestRdocMarkupToHtml < Test::Unit::TestCase
   end
 
   def test_tt_formatting
-    assert_equal "<p>\n<tt>--</tt> &#8212; <tt>(c)</tt> &#169;\n</p>\n",
-                 util_format("<tt>--</tt> -- <tt>(c)</tt> (c)")
+    assert_equal "<p>\n<tt>--</tt> &#8212; <tt>cats'</tt> cats&#8217;\n</p>\n",
+                 util_format("<tt>--</tt> -- <tt>cats'</tt> cats'")
     assert_equal "<p>\n<b>&#8212;</b>\n</p>\n", util_format("<b>--</b>")
   end
 
+  def test_convert_string_fancy
+    #
+    # The HTML typesetting is broken in a number of ways, but I have fixed
+    # the most glaring issues for single and double quotes.  Note that
+    # "strange" symbols (periods or dashes) need to be at the end of the
+    # test case strings in order to suppress cross-references.
+    #
+    assert_equal "<p>\n&#8220;cats&#8221;.\n</p>\n", util_format("\"cats\".")
+    assert_equal "<p>\n&#8216;cats&#8217;.\n</p>\n", util_format("\'cats\'.")
+    assert_equal "<p>\ncat&#8217;s-\n</p>\n", util_format("cat\'s-")
+  end
+
   def util_fragment(text)
     RDoc::Markup::Fragment.new 0, nil, nil, text
   end
diff --git a/test/rdoc/test_rdoc_markup_to_html_crossref.rb b/test/rdoc/test_rdoc_markup_to_html_crossref.rb
index ab4c3e7e9c..de99a58b75 100644
--- a/test/rdoc/test_rdoc_markup_to_html_crossref.rb
+++ b/test/rdoc/test_rdoc_markup_to_html_crossref.rb
@@ -2,17 +2,287 @@ require 'test/unit'
 require 'rdoc/generator'
 require 'rdoc/markup/to_html_crossref'
 
-class TestRdocMarkupToHtmlCrossref < Test::Unit::TestCase
+require 'pathname'
 
-  def setup
-    @xref = RDoc::Markup::ToHtmlCrossref.new 'from_path', nil, nil
+class TestRDocMarkupToHtmlCrossref < Test::Unit::TestCase
+
+  #
+  # This method parses a source file and returns a Hash mapping
+  # class names (Strings) to RDoc::Generator::Class instances
+  # (classes), which can be used to create RDoc::Markup::ToHtmlCrossref
+  # instances.  The unit tests only test against classes starting with
+  # Ref_, so this method only includes such classes in the Hash.
+  #
+  def create_class_hash
+    # The relative gem would help here...
+    # @source_file_name must be cleaned because rdoc does not deal
+    # well with paths containing "." or "..".
+    curr_file = Pathname.new(__FILE__)
+    @source_file_name = curr_file.dirname + "rdoc_markup_to_html_crossref_reference.rb"
+    @source_file_name = @source_file_name.cleanpath.to_s
+
+    RDoc::TopLevel.reset
+
+    # Reset RDoc::Generator::Method so that the method sequence number starts
+    # at 1, making the method sequence numbers for the methods in the Ref_
+    # predicable.
+    RDoc::Generator::Method.reset
+    top_level = RDoc::TopLevel.new @source_file_name
+    
+    options = RDoc::Options.new
+    options.quiet = true
+
+    # If this is false, then RDoc::Generator::Method will attempt to create
+    # an HTML file containing the method source code when being instantiated,
+    # which does not work in the context of this unit test.
+    #
+    # RDoc::Generator::Method needs to be refactored so that this does *not*
+    # happen as part of instantiation.
+    options.inline_source = true
+
+    stats = RDoc::Stats.new 0
+
+    parser = RDoc::Parser::Ruby.new(top_level,
+                                    @source_file_name,
+                                    IO.read(@source_file_name),
+                                    options,
+                                    stats)
+    top_levels = []
+    top_levels.push(parser.scan())
+
+    files, classes = RDoc::Generator::Context.build_indices(top_levels, options)
+
+    class_hash = {}
+    classes.each do |klass|
+      if(klass.name.include?("Ref_"))
+        class_hash[klass.name] = klass
+      end
+    end
+
+    return class_hash
+  end
+
+  #
+  # This method uses xref to cross-reference String reference and
+  # asserts that xref.convert(reference) is equal
+  # to String expected_result.
+  #
+  def verify_convert(xref, reference, expected_result)
+    # Everything converted in the tests will be within paragraph markup, so
+    # add paragraph markup to the expected result.
+    actual_expected_result = "<p>\n#{expected_result}\n</p>\n"
+
+    result = xref.convert(reference)
+
+    # RDoc::Markup::ToHtml word-wraps lines.  It is tricky to predict where
+    # a line will be wrapped except that it will happen on a space, so replace
+    # all newlines with spaces in order to not have to worry about this.
+    actual_expected_result.gsub!(/\n/, " ")
+    result.gsub!(/\n/, " ")
+
+    assert_equal actual_expected_result, result
+  end
+
+  #
+  # This method verifies that xref generates no cross-reference link for
+  # String reference.
+  #
+  def verify_no_crossref(xref, reference)
+    if(reference[0, 1] == "\\") # Remove the markup suppression character
+      expected_result = reference[1, reference.length() - 1]
+    else
+      expected_result = reference
+    end
+
+    verify_convert(xref, reference, expected_result)
+  end
+
+  #
+  # This method verifies that xref generates a cross-reference link to
+  # class_name (String) for String reference.
+  #
+  def verify_class_crossref(xref, reference, class_name)
+    class_file_name = class_name.gsub(/::/, "/")
+    
+    result = "<a href=\"../classes/#{class_file_name}.html\">#{reference}</a>"
+
+    verify_convert xref, reference, result
+  end
+
+  #
+  # This method verifies that xref generates a cross-reference link to method
+  # method_seq (String, e.g, "M000001") in class_name (String) for
+  # String reference.
+  #
+  def verify_method_crossref(xref, reference, class_name, method_seq)
+    class_file_name = class_name.gsub(/::/, "/")
+    
+    result = "<a href=\"../classes/#{class_file_name}.html##{method_seq}\">#{reference}</a>"
+
+    verify_convert xref, reference, result
+  end
+
+  #
+  # This method verifies that xref generates a cross-reference link to
+  # file_name (String) for String reference.
+  #
+  def verify_file_crossref(xref, reference, file_name)
+    generated_document_path = Pathname.new("../files/#{file_name.gsub(/\./, '_')}.html").cleanpath.to_s
+    result = "<a href=\"#{generated_document_path}\">#{reference}</a>"
+
+    verify_convert xref, reference, result
+  end
+
+  #
+  # This method verifies that several invariant cross-references are
+  # (or are not) generated.
+  #
+  def verify_invariant_crossrefs(xref)
+    # bogus does not exist and so no cross-reference should be generated.
+    verify_no_crossref xref, "bogus"
+    verify_no_crossref xref, "\\bogus"
+    
+    # Ref_Class1 is in the top-level namespace, and so a cross-reference always
+    # should be generated, unless markup is suppressed.
+    verify_class_crossref xref, "Ref_Class1", "Ref_Class1"
+    verify_no_crossref xref, "\\Ref_Class1"
+
+    # Ref_Class2 is in the top-level namespace, and so a cross-reference always
+    # should be generated for it and for its nested classes.
+    verify_class_crossref xref, "Ref_Class2", "Ref_Class2"
+    verify_class_crossref xref, "Ref_Class2::Ref_Class3", "Ref_Class2::Ref_Class3"
+    verify_method_crossref xref, "Ref_Class2::Ref_Class3#method", "Ref_Class2::Ref_Class3", "M000001"
+    verify_method_crossref xref, "Ref_Class2::Ref_Class3#method()", "Ref_Class2::Ref_Class3", "M000001"
+    verify_method_crossref xref, "Ref_Class2::Ref_Class3.method()", "Ref_Class2::Ref_Class3", "M000001"
+    verify_method_crossref xref, "Ref_Class2::Ref_Class3.method(*)", "Ref_Class2::Ref_Class3", "M000001"
+    verify_class_crossref xref, "Ref_Class2::Ref_Class3::Helper1", "Ref_Class2::Ref_Class3::Helper1"
+    verify_method_crossref xref, "Ref_Class2::Ref_Class3::Helper1#method?", "Ref_Class2::Ref_Class3::Helper1", "M000002"
+
+    # The hyphen character is not a valid class/method separator character, so
+    # rdoc just generates a class cross-reference (perhaps it should not
+    # generate anything?).
+    result = "<a href=\"../classes/Ref_Class2/Ref_Class3.html\">Ref_Class2::Ref_Class3</a>;method(*)"
+    verify_convert xref, "Ref_Class2::Ref_Class3;method(*)", result
+
+    # There is one Ref_Class3 nested in Ref_Class2 and one defined in the
+    # top-level namespace; regardless, ::Ref_Class3 (Ref_Class3 relative
+    # to the top-level namespace) always should generate a link to the
+    # top-level Ref_Class3 (unless of course cross-references are suppressed).
+    verify_class_crossref xref, "::Ref_Class3", "Ref_Class3"
+    verify_no_crossref xref, "\\::Ref_Class3"
+    verify_class_crossref xref, "::Ref_Class3::Helper1", "Ref_Class3::Helper1"
+    verify_class_crossref xref, "::Ref_Class3::Helper2", "Ref_Class3::Helper2"
+
+    #
+    # Ref_Class3::Helper1 does not have method method.
+    #
+    verify_no_crossref xref, "::Ref_Class3::Helper1#method"
+    verify_no_crossref xref, "\\::Ref_Class3::Helper1#method"
+
+    # References to Ref_Class2 relative to the top-level namespace always should
+    # generate links to Ref_Class2.
+    verify_method_crossref xref, "::Ref_Class2::Ref_Class3#method", "Ref_Class2::Ref_Class3", "M000001"
+    verify_method_crossref xref, "::Ref_Class2::Ref_Class3#method()", "Ref_Class2::Ref_Class3", "M000001"
+    verify_method_crossref xref, "::Ref_Class2::Ref_Class3#method(*)", "Ref_Class2::Ref_Class3", "M000001"
+    verify_class_crossref xref, "::Ref_Class2::Ref_Class3::Helper1", "Ref_Class2::Ref_Class3::Helper1"
+    verify_no_crossref xref, "\\::Ref_Class2::Ref_Class3#method(*)"
+
+    # Suppressing cross-references always should suppress the generation of
+    # links.
+    verify_no_crossref xref, "\\#method"
+    verify_no_crossref xref, "\\#method()"
+    verify_no_crossref xref, "\\#method(*)"
+
+    # Links never should be generated for words solely consisting of lowercase
+    # letters, because too many links would get generated by mistake (i.e., the
+    # word "new" always would be a link).
+    verify_no_crossref xref, "method"
+
+    # A link always should be generated for a file name.
+    verify_file_crossref xref, @source_file_name, @source_file_name
+
+    # References should be generated correctly for a class scoped within
+    # a class of the same name.
+    verify_class_crossref xref, "Ref_Class4::Ref_Class4", "Ref_Class4::Ref_Class4"
   end
 
   def test_handle_special_CROSSREF_no_underscore
-    out = @xref.convert 'foo'
+    class_hash = create_class_hash
 
-    assert_equal "<p>\nfoo\n</p>\n", out
+    # Note that we instruct the ToHtmlCrossref instance to show hashes so that
+    # an exception won't have to be made for words starting with a '#'.
+    # I'm also not convinced that the current behavior of the rdoc code
+    # is correct since, without this, it strips the leading # from all
+    # words, whether or not they end up as cross-references.
+    #
+    # After the behavior has been sorted out, this can be changed.
+    #
+    # Create a variety of RDoc::Markup::ToHtmlCrossref instances, for
+    # different classes, and test the cross-references generated by
+    # each.
+    klass = class_hash["Ref_Class1"]
+    xref = RDoc::Markup::ToHtmlCrossref.new 'from_path', klass, true
+    verify_invariant_crossrefs xref
+    verify_class_crossref xref, "Ref_Class3", "Ref_Class3"
+    verify_no_crossref xref, "Ref_Class3#method"
+    verify_no_crossref xref, "#method"
+    verify_class_crossref xref, "Ref_Class3::Helper1", "Ref_Class3::Helper1"
+    verify_class_crossref xref, "Ref_Class3::Helper2", "Ref_Class3::Helper2"
+    verify_no_crossref xref, "Helper1"
+    verify_class_crossref xref, "Ref_Class4", "Ref_Class4"
+
+    klass = class_hash["Ref_Class2"]
+    xref = RDoc::Markup::ToHtmlCrossref.new 'from_path', klass, true
+    verify_invariant_crossrefs xref
+    verify_class_crossref xref, "Ref_Class3", "Ref_Class2::Ref_Class3"
+    verify_method_crossref xref, "Ref_Class3#method", "Ref_Class2::Ref_Class3", "M000001"
+    verify_no_crossref xref, "#method"
+    verify_class_crossref xref, "Ref_Class3::Helper1", "Ref_Class2::Ref_Class3::Helper1"
+    verify_class_crossref xref, "Ref_Class4", "Ref_Class4"
+
+    # This one possibly is an rdoc bug...
+    # Ref_Class2 has a nested Ref_Class3, but
+    # Ref_Class2::Ref_Class3::Helper2 does not exist.
+    # On the other hand, there is a Ref_Class3::Helper2
+    # in the top-level namespace...  Should rdoc stop
+    # looking if it finds one class match?
+    verify_no_crossref xref, "Ref_Class3::Helper2"
+    verify_no_crossref xref, "Helper1"
+
+    klass = class_hash["Ref_Class2::Ref_Class3"]
+    xref = RDoc::Markup::ToHtmlCrossref.new 'from_path', klass, true
+    verify_invariant_crossrefs xref
+    verify_class_crossref xref, "Ref_Class3", "Ref_Class2::Ref_Class3"
+    verify_method_crossref xref, "Ref_Class3#method", "Ref_Class2::Ref_Class3", "M000001"
+    verify_method_crossref xref, "#method", "Ref_Class2::Ref_Class3", "M000001"
+    verify_class_crossref xref, "Ref_Class3::Helper1", "Ref_Class2::Ref_Class3::Helper1"
+    verify_no_crossref xref, "Ref_Class3::Helper2"
+    verify_class_crossref xref, "Helper1", "Ref_Class2::Ref_Class3::Helper1"
+    verify_class_crossref xref, "Ref_Class4", "Ref_Class4"
+
+    klass = class_hash["Ref_Class3"]
+    xref = RDoc::Markup::ToHtmlCrossref.new 'from_path', klass, true
+    verify_invariant_crossrefs xref
+    verify_class_crossref xref, "Ref_Class3", "Ref_Class3"
+    verify_no_crossref xref, "Ref_Class3#method"
+    verify_no_crossref xref, "#method"
+    verify_class_crossref xref, "Ref_Class3::Helper1", "Ref_Class3::Helper1"
+    verify_class_crossref xref, "Ref_Class3::Helper2", "Ref_Class3::Helper2"
+    verify_class_crossref xref, "Helper1", "Ref_Class3::Helper1"
+    verify_class_crossref xref, "Ref_Class4", "Ref_Class4"
+
+    klass = class_hash["Ref_Class4"]
+    xref = RDoc::Markup::ToHtmlCrossref.new 'from_path', klass, true
+    verify_invariant_crossrefs xref
+    # A Ref_Class4 reference inside a Ref_Class4 class containing a
+    # Ref_Class4 class should resolve to the contained class.
+    verify_class_crossref xref, "Ref_Class4", "Ref_Class4::Ref_Class4"
+
+    klass = class_hash["Ref_Class4::Ref_Class4"]
+    xref = RDoc::Markup::ToHtmlCrossref.new 'from_path', klass, true
+    verify_invariant_crossrefs xref
+    # A Ref_Class4 reference inside a Ref_Class4 class contained within
+    # a Ref_Class4 class should resolve to the inner Ref_Class4 class.
+    verify_class_crossref xref, "Ref_Class4", "Ref_Class4::Ref_Class4"
   end
-
 end
-
diff --git a/test/rdoc/test_rdoc_parser.rb b/test/rdoc/test_rdoc_parser.rb
new file mode 100644
index 0000000000..4f71974a5f
--- /dev/null
+++ b/test/rdoc/test_rdoc_parser.rb
@@ -0,0 +1,18 @@
+require 'rdoc/parser'
+
+class TestRDocParser < Test::Unit::TestCase
+  def test_can_parse
+    assert_equal(RDoc::Parser.can_parse(__FILE__), RDoc::Parser::Ruby)
+
+    readme_file_name = File.join(File.dirname(__FILE__), "..", "README.txt")
+
+    unless File.exist? readme_file_name then
+      readme_file_name = File.join File.dirname(__FILE__), '..', '..', 'README'
+    end
+
+    assert_equal(RDoc::Parser.can_parse(readme_file_name), RDoc::Parser::Simple)
+
+    binary_file_name = File.join(File.dirname(__FILE__), "binary.dat")
+    assert_equal(RDoc::Parser.can_parse(binary_file_name), nil)
+  end
+end
diff --git a/test/rdoc/test_rdoc_parser_c.rb b/test/rdoc/test_rdoc_parser_c.rb
index fd750070d8..9387a030c0 100644
--- a/test/rdoc/test_rdoc_parser_c.rb
+++ b/test/rdoc/test_rdoc_parser_c.rb
@@ -10,7 +10,7 @@ class RDoc::Parser::C
   public :do_classes, :do_constants
 end
 
-class TestRdocParserC < Test::Unit::TestCase
+class TestRDocParserC < Test::Unit::TestCase
 
   def setup
     @tempfile = Tempfile.new self.class.name
@@ -244,9 +244,36 @@ Init_Foo(void) {
     assert_equal "  \n   a comment for class Foo on Init\n   \n", klass.comment
   end
 
+  def test_define_method
+    content = <<-EOF
+/*Method Comment! */
+static VALUE
+rb_io_s_read(argc, argv, io)
+    int argc;
+    VALUE *argv;
+    VALUE io;
+{
+}
+
+void
+Init_IO(void) {
+    /*
+     * a comment for class Foo on rb_define_class
+     */
+    VALUE rb_cIO = rb_define_class("IO", rb_cObject);
+    rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
+}
+    EOF
+
+    klass = util_get_class content, 'rb_cIO'
+    read_method = klass.method_list.first
+    assert_equal "read", read_method.name
+    assert_equal "  Method Comment!   \n", read_method.comment
+  end
+
   def util_get_class(content, name)
     parser = util_parser content
-    parser.do_classes
+    parser.scan
     parser.classes[name]
   end
 
diff --git a/test/rdoc/test_rdoc_parser_perl.rb b/test/rdoc/test_rdoc_parser_perl.rb
new file mode 100644
index 0000000000..458e32745e
--- /dev/null
+++ b/test/rdoc/test_rdoc_parser_perl.rb
@@ -0,0 +1,72 @@
+require 'stringio'
+require 'tempfile'
+require 'test/unit'
+require 'rdoc/options'
+require 'rdoc/parser/perl'
+
+class TestRdocParserPerlPOD < Test::Unit::TestCase
+
+  def setup
+    @tempfile = Tempfile.new self.class.name
+    filename = @tempfile.path
+
+    @top_level = RDoc::TopLevel.new filename
+    @fn = filename
+    @options = RDoc::Options.new
+    @stats = RDoc::Stats.new 0
+  end
+
+  def teardown
+    @tempfile.close
+  end
+
+  def test_uncommented_perl
+    content = <<-EOF
+while (<>) {
+  tr/a-z/A-Z;
+  print
+}
+    EOF
+
+    comment =  util_get_comment content
+    assert_equal "", comment
+  end
+
+  def test_perl_without_pod
+    content = <<-EOF
+#!/usr/local/bin/perl
+#
+#This is a pointless perl program because it does -p.
+#
+while(<>) {print;}:
+    EOF
+
+    comment = util_get_comment content
+    assert_equal "", comment
+  end
+
+  def test_simple_pod_no_structure
+    content = <<-EOF
+=begin pod
+
+This just contains plain old documentation
+
+=end
+    EOF
+    comment = util_get_comment content
+    assert_equal "\nThis just contains plain old documentation\n\n", comment
+  end
+
+  # Get the comment of the @top_level when it has processed the input.
+  def util_get_comment(content)
+    parser = util_parser content
+    parser.scan.comment
+  end
+
+  # create a new parser with the supplied content.
+  def util_parser(content)
+    RDoc::Parser::PerlPOD.new @top_level, @fn, content, @options, @stats
+  end
+
+end
+
diff --git a/test/rdoc/test_rdoc_parser_ruby.rb b/test/rdoc/test_rdoc_parser_ruby.rb
index 77d8bd24fc..30ab3f84f5 100644
--- a/test/rdoc/test_rdoc_parser_ruby.rb
+++ b/test/rdoc/test_rdoc_parser_ruby.rb
@@ -6,12 +6,16 @@ require 'rdoc/options'
 require 'rdoc/parser/ruby'
 require 'rdoc/stats'
 
-class TestRdocParserRuby < Test::Unit::TestCase
+class TestRDocParserRuby < Test::Unit::TestCase
 
   def setup
     @tempfile = Tempfile.new self.class.name
     @filename = @tempfile.path
 
+    # Some tests need two paths.
+    @tempfile2 = Tempfile.new self.class.name
+    @filename2 = @tempfile2.path
+
     util_toplevel
     @options = RDoc::Options.new
     @options.quiet = true
@@ -20,6 +24,7 @@ class TestRdocParserRuby < Test::Unit::TestCase
 
   def teardown
     @tempfile.close
+    @tempfile2.close
   end
 
   def test_look_for_directives_in_commented
@@ -158,6 +163,105 @@ class TestRdocParserRuby < Test::Unit::TestCase
     assert_equal 'Super', bar.superclass
   end
 
+  def test_parse_module
+    comment = "##\n# my module\n"
+
+    util_parser 'module Foo; end'
+
+    tk = @parser.get_tk
+
+    @parser.parse_module @top_level, RDoc::Parser::Ruby::NORMAL, tk, comment
+
+    foo = @top_level.modules.first
+    assert_equal 'Foo', foo.full_name
+    assert_equal comment, foo.comment
+  end
+  
+  def test_parse_class_mistaken_for_module
+#
+# The code below is not strictly legal Ruby (Foo must have been defined
+# before Foo::Bar is encountered), but RDoc might encounter Foo::Bar before
+# Foo if they live in different files.
+#
+    code = <<-EOF
+class Foo::Bar
+end
+
+module Foo::Baz
+end
+
+class Foo
+end
+EOF
+
+    util_parser code
+
+    @parser.scan()
+
+    assert(@top_level.modules.empty?)
+    foo = @top_level.classes.first
+    assert_equal 'Foo', foo.full_name
+
+    bar = foo.classes.first
+    assert_equal 'Foo::Bar', bar.full_name
+
+    baz = foo.modules.first
+    assert_equal 'Foo::Baz', baz.full_name
+  end
+
+  def test_parse_class_definition_encountered_after_class_reference
+#
+# The code below is not strictly legal Ruby (Foo must have been defined
+# before Foo.bar is encountered), but RDoc might encounter Foo.bar before
+# Foo if they live in different files.
+#
+    code = <<-EOF
+def Foo.bar
+end
+
+class Foo < IO
+end
+EOF
+
+    util_parser code
+
+    @parser.scan()
+
+    assert(@top_level.modules.empty?)
+
+    foo = @top_level.classes.first
+    assert_equal 'Foo', foo.full_name
+    assert_equal 'IO', foo.superclass
+
+    bar = foo.method_list.first
+    assert_equal 'bar', bar.name
+  end
+
+  def test_parse_module_relative_to_top_level_namespace
+    comment = <<-EOF
+#
+# Weirdly named module
+#
+EOF
+
+    code = comment + <<-EOF
+module ::Foo
+  class Helper
+  end
+end
+EOF
+
+    util_parser code
+    @parser.scan()
+
+    foo = @top_level.modules.first
+    assert_equal 'Foo', foo.full_name
+    assert_equal comment, foo.comment
+
+    helper = foo.classes.first
+    assert_equal 'Foo::Helper', helper.full_name
+  end
+
   def test_parse_comment
     content = <<-EOF
 class Foo
@@ -416,9 +520,107 @@ end
 
     @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, ''
 
+    foo = @top_level.classes.first.method_list[0]
+    assert_equal 'foo', foo.name
+
     foo2 = @top_level.classes.first.method_list.last
     assert_equal 'foo2', foo2.name
     assert_equal 'foo', foo2.is_alias_for.name
+    assert @top_level.classes.first.aliases.empty?
+  end
+
+  def test_parse_statements_identifier_alias_method_before_original_method
+    # This is not strictly legal Ruby code, but it simulates finding an alias
+    # for a method before finding the original method, which might happen
+    # to rdoc if the alias is in a different file than the original method
+    # and rdoc processes the alias' file first.
+    content = <<-EOF
+class Foo
+  alias_method :foo2, :foo
+
+  alias_method :foo3, :foo
+
+  def foo()
+  end
+
+  alias_method :foo4, :foo
+
+  alias_method :foo5, :unknown
+end
+EOF
+
+    util_parser content
+
+    @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, ''
+
+    foo = @top_level.classes.first.method_list[0]
+    assert_equal 'foo', foo.name
+
+    foo2 = @top_level.classes.first.method_list[1]
+    assert_equal 'foo2', foo2.name
+    assert_equal 'foo', foo2.is_alias_for.name
+
+    foo3 = @top_level.classes.first.method_list[2]
+    assert_equal 'foo3', foo3.name
+    assert_equal 'foo', foo3.is_alias_for.name
+
+    foo4 = @top_level.classes.first.method_list.last
+    assert_equal 'foo4', foo4.name
+    assert_equal 'foo', foo4.is_alias_for.name
+
+    assert_equal 'unknown', @top_level.classes.first.aliases[0].old_name
+  end
+
+  def test_parse_statements_identifier_constant
+    content = <<-EOF
+class Foo
+  FIRST_CONSTANT = 5
+
+  SECOND_CONSTANT = [
+     1,
+     2,
+     3
+  ]
+
+  THIRD_CONSTANT = {
+     :foo => 'bar',
+     :x => 'y'
+  }
+
+  FOURTH_CONSTANT = SECOND_CONSTANT.map do |element|
+    element + 1
+    element + 2
+  end
+
+  FIFTH_CONSTANT = SECOND_CONSTANT.map { |element| element + 1 }
+end
+EOF
+
+    util_parser content
+
+    @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, ''
+
+    constants = @top_level.classes.first.constants
+
+    constant = constants[0]
+    assert_equal 'FIRST_CONSTANT', constant.name
+    assert_equal '5', constant.value
+
+    constant = constants[1]
+    assert_equal 'SECOND_CONSTANT', constant.name
+    assert_equal '[      1,      2,      3   ]', constant.value
+
+    constant = constants[2]
+    assert_equal 'THIRD_CONSTANT', constant.name
+    assert_equal "{      :foo => 'bar',      :x => 'y'   }", constant.value
+
+    constant = constants[3]
+    assert_equal 'FOURTH_CONSTANT', constant.name
+    assert_equal 'SECOND_CONSTANT.map do |element|     element + 1     element + 2   end', constant.value
+
+    constant = constants.last
+    assert_equal 'FIFTH_CONSTANT', constant.name
+    assert_equal 'SECOND_CONSTANT.map { |element| element + 1 }', constant.value
   end
 
   def test_parse_statements_identifier_attr
@@ -530,9 +732,17 @@ end
                                      @stats
   end
 
+  def util_two_parsers(first_file_content, second_file_content)
+    util_parser first_file_content
+
+    @parser2 = RDoc::Parser::Ruby.new @top_level2, @filename,
+                                      second_file_content, @options, @stats
+  end
+
   def util_toplevel
     RDoc::TopLevel.reset
     @top_level = RDoc::TopLevel.new @filename
+    @top_level2 = RDoc::TopLevel.new @filename2
   end
 
 end
diff --git a/test/rdoc/test_rdoc_ri_default_display.rb b/test/rdoc/test_rdoc_ri_default_display.rb
index 97fa6c94ae..266b501ebb 100644
--- a/test/rdoc/test_rdoc_ri_default_display.rb
+++ b/test/rdoc/test_rdoc_ri_default_display.rb
@@ -4,7 +4,7 @@ require 'rdoc/ri/formatter'
 require 'rdoc/ri/display'
 require 'rdoc/ri/driver'
 
-class TestRdocRiDefaultDisplay < Test::Unit::TestCase
+class TestRDocRiDefaultDisplay < Test::Unit::TestCase
 
   def setup
     @output = StringIO.new
@@ -27,7 +27,6 @@ class TestRdocRiDefaultDisplay < Test::Unit::TestCase
   end
 
   def test_display_class_info
-    ri_reader = nil
     klass = h \
       'attributes' => [
         { 'name' => 'attribute', 'rw' => 'RW',
@@ -43,9 +42,9 @@ class TestRdocRiDefaultDisplay < Test::Unit::TestCase
       ],
       'comment' => [RDoc::Markup::Flow::P.new('SomeClass comment')],
       'constants' => [
-        { 'name' => 'CONSTANT', 'value' => '"value"',
+        { 'name' => 'CONSTANT', 'value' => '"value1"',
           'comment' => [RDoc::Markup::Flow::P.new('CONSTANT value')] },
-        { 'name' => 'CONSTANT_NOCOMMENT', 'value' => '"value"',
+        { 'name' => 'CONSTANT_NOCOMMENT', 'value' => '"value2"',
           'comment' => nil },
       ],
       'display_name' => 'Class',
@@ -59,7 +58,7 @@ class TestRdocRiDefaultDisplay < Test::Unit::TestCase
       ],
       'superclass_string' => 'Object'
 
-    @dd.display_class_info klass, ri_reader
+    @dd.display_class_info klass
 
     expected = <<-EOF
 ---------------------------------------------------- Class: SomeClass < Object
@@ -71,10 +70,19 @@ class TestRdocRiDefaultDisplay < Test::Unit::TestCase
 Constants:
 ----------
 
-     CONSTANT:
+     CONSTANT = "value1"
           CONSTANT value
 
-     CONSTANT_NOCOMMENT
+     CONSTANT_NOCOMMENT = "value2"
+
+
+Attributes:
+-----------
+
+     attribute (RW):
+          attribute comment
+
+     attribute_no_comment (RW)
 
 
 Class methods:
@@ -99,15 +107,6 @@ Instance method extensions:
 ---------------------------
 
      instance_method_extension
-
-
-Attributes:
------------
-
-     attribute (RW):
-          attribute comment
-
-     attribute_no_comment (RW)
     EOF
 
     assert_equal expected, @output.string
@@ -140,7 +139,7 @@ Attributes:
 -------------------------------------------------------- SomeClass#some_method
      some_method(arg1, arg2) {|block_param| ...}
 
-     Extension from /nonexistent
+     From /nonexistent
 ------------------------------------------------------------------------------
      some comment
 
@@ -152,7 +151,7 @@ Attributes:
   end
 
   def test_display_method_info_singleton
-    method = RDoc::RI::Driver::Hash.new.update \
+    method = RDoc::RI::Driver::OpenStructHash.new.update \
       'aliases' => [],
       'block_params' => nil,
       'comment' => nil,
@@ -167,6 +166,8 @@ Attributes:
     expected = <<-EOF
 ------------------------------------------------------- SomeClass::some_method
      SomeClass::some_method(arg1, arg2)
+
+     From 
 ------------------------------------------------------------------------------
      [no description]
     EOF
@@ -176,7 +177,7 @@ Attributes:
 
   def test_display_method_list
     methods = [
-      RDoc::RI::Driver::Hash.new.update(
+      RDoc::RI::Driver::OpenStructHash.new.update(
         "aliases" => [],
         "block_params" => nil,
         "comment" =>  nil,
@@ -186,7 +187,7 @@ Attributes:
         "params" => "()",
         "visibility" => "public"
       ),
-      RDoc::RI::Driver::Hash.new.update(
+      RDoc::RI::Driver::OpenStructHash.new.update(
         "aliases" => [],
         "block_params" => nil,
         "comment" => nil,
@@ -204,7 +205,8 @@ Attributes:
      More than one method matched your request.  You can refine your search by
      asking for information on one of:
 
-     SomeClass#some_method, SomeClass#some_other_method
+SomeClass#some_method []
+SomeClass#some_other_method []
     EOF
 
     assert_equal expected, @output.string
@@ -216,7 +218,7 @@ Attributes:
     expected = <<-EOF
      some_method(arg1, arg2) {|block_param| ...}
 
-     Extension from /nonexistent
+     From /nonexistent
     EOF
 
     assert_equal expected, @output.string
@@ -234,7 +236,7 @@ some_method(start, length)
      some_method(index)
      some_method(start, length)
 
-     Extension from /nonexistent
+     From /nonexistent
     EOF
 
     assert_equal expected, @output.string
@@ -249,7 +251,7 @@ some_method(start, length)
     expected = <<-EOF
      SomeClass::some_method(arg1, arg2) {|block_param| ...}
 
-     Extension from /nonexistent
+     From /nonexistent
     EOF
 
     assert_equal expected, @output.string
@@ -289,8 +291,7 @@ install an additional package, or ask the packager to enable ri generation.
   end
 
   def h(hash)
-    RDoc::RI::Driver::Hash.convert hash
+    RDoc::RI::Driver::OpenStructHash.convert hash
   end
 
 end
-
diff --git a/test/rdoc/test_rdoc_ri_driver.rb b/test/rdoc/test_rdoc_ri_driver.rb
index cddd4e60d1..22643d61d3 100644
--- a/test/rdoc/test_rdoc_ri_driver.rb
+++ b/test/rdoc/test_rdoc_ri_driver.rb
@@ -14,7 +14,7 @@ class TestRDocRIDriver < Test::Unit::TestCase
     FileUtils.mkdir_p @home_ri
     FileUtils.mkdir_p @cache_dir
 
-    @driver = RDoc::RI::Driver.new
+    @driver = RDoc::RI::Driver.new(RDoc::RI::Driver.process_args([]))
     @driver.homepath = @home_ri
   end
 
diff --git a/test/rdoc/test_rdoc_ri_formatter.rb b/test/rdoc/test_rdoc_ri_formatter.rb
index ed2ccba22d..539359033e 100644
--- a/test/rdoc/test_rdoc_ri_formatter.rb
+++ b/test/rdoc/test_rdoc_ri_formatter.rb
@@ -245,7 +245,7 @@ class TestRDocRIFormatter < Test::Unit::TestCase
   def test_raw_print_line
     @f.raw_print_line 'a b c'
 
-    assert_equal "a b c\n", @output.string
+    assert_equal "a b c", @output.string
   end
 
   def test_strip_attributes_b