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

ruby-changes:4718

From: ko1@a...
Date: Sun, 27 Apr 2008 01:14:51 +0900 (JST)
Subject: [ruby-changes:4718] drbrain - Ruby:r16212 (trunk): Import RDoc 2.0.0 r56.

drbrain	2008-04-27 01:14:19 +0900 (Sun, 27 Apr 2008)

  New Revision: 16212

  Added files:
    trunk/lib/rdoc/markup/attribute_manager.rb
    trunk/test/rdoc/test_rdoc_ri_default_display.rb
  Modified files:
    trunk/ChangeLog
    trunk/lib/rdoc/markup/inline.rb
    trunk/lib/rdoc/markup/to_html.rb
    trunk/lib/rdoc/markup.rb
    trunk/lib/rdoc/parsers/parse_rb.rb
    trunk/lib/rdoc/rdoc.rb
    trunk/lib/rdoc/ri/descriptions.rb
    trunk/lib/rdoc/ri/display.rb
    trunk/lib/rdoc/ri/driver.rb
    trunk/lib/rdoc/ri/formatter.rb
    trunk/lib/rdoc/template.rb
    trunk/lib/rdoc.rb
    trunk/test/rdoc/test_rdoc_c_parser.rb
    trunk/test/rdoc/test_rdoc_markup_attribute_manager.rb
    trunk/test/rdoc/test_rdoc_ri_formatter.rb

  Log:
    Import RDoc 2.0.0 r56.

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/ri/formatter.rb?r1=16212&r2=16211&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/test/rdoc/test_rdoc_ri_formatter.rb?r1=16212&r2=16211&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/ri/driver.rb?r1=16212&r2=16211&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/parsers/parse_rb.rb?r1=16212&r2=16211&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/ChangeLog?r1=16212&r2=16211&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/template.rb?r1=16212&r2=16211&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/markup/attribute_manager.rb?revision=16212&view=markup
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/test/rdoc/test_rdoc_markup_attribute_manager.rb?r1=16212&r2=16211&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/markup/inline.rb?r1=16212&r2=16211&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/markup.rb?r1=16212&r2=16211&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/markup/to_html.rb?r1=16212&r2=16211&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/test/rdoc/test_rdoc_ri_default_display.rb?revision=16212&view=markup
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc.rb?r1=16212&r2=16211&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/ri/descriptions.rb?r1=16212&r2=16211&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/test/rdoc/test_rdoc_c_parser.rb?r1=16212&r2=16211&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/ri/display.rb?r1=16212&r2=16211&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/rdoc/rdoc.rb?r1=16212&r2=16211&diff_format=u

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 16211)
+++ ChangeLog	(revision 16212)
@@ -1,3 +1,7 @@
+Sun Apr 27 01:13:05 2008  Eric Hodel  <drbrain@s...>
+
+	* lib/rdoc, test/rdoc:  Update to RDoc 2.0.0 r56.
+
 Sat Apr 26 21:30:40 2008  Tanaka Akira  <akr@f...>
 
 	* include/ruby/intern.h (rb_hash_dup): declared.
Index: lib/rdoc.rb
===================================================================
--- lib/rdoc.rb	(revision 16211)
+++ lib/rdoc.rb	(revision 16212)
@@ -1,5 +1,246 @@
+$DEBUG_RDOC = nil
+
 ##
-# :include: rdoc/README
+# = 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
+# to JavaDoc, parsing the source, and extracting the definition for classes,
+# modules, and methods (along with includes and requires).  We associate with
+# these optional documentation contained in the immediately preceding comment
+# block, and then render 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.
+# 
+# == Roadmap
+# 
+# * 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::C_Parser
+# * For information on the various markups available in comment blocks, see
+#   RDoc::Markup.
+# * If you want to drive RDoc programatically, see RDoc::RDoc.
+# * If you want to use the library to format text blocks into HTML, have a look
+#   at RDoc::Markup.
+# * If you want to try writing your own HTML output template, see
+#   RDoc::Generator::HTML
+# 
+# == Summary
+# 
+# Once installed, you can create documentation using the 'rdoc' command
+# (the command is 'rdoc.bat' under Windows)
+# 
+#   % rdoc [options] [names...]
+# 
+# Type "rdoc --help" for an up-to-date option summary.
+# 
+# A typical use might be to generate documentation for a package of Ruby
+# 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'.
+# 
+# You can make this slightly more useful for your readers by having the
+# index page contain the documentation for the primary file.  In our
+# case, we could type
+# 
+#   % rdoc --main rdoc.rb
+# 
+# You'll find information on the various formatting tricks you can use
+# 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 +.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
+# 
+# For information on how to make lists, hyperlinks, etc. with RDoc, see
+# RDoc::Markup.
+# 
+# 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
+# flagged with an RDoc tag:
+# 
+#   =begin rdoc
+#   Documentation to be processed by RDoc.
+#   
+#   ...
+#   =end
+# 
+# RDoc stops processing comments if it finds a comment line containing
+# a <tt>--</tt>.  This can be used to separate external from internal
+# comments, or to stop a comment being associated with a method, class, or
+# module.  Commenting can be turned back on with a line that starts with a
+# <tt>++</tt>.
+# 
+#   ##
+#   # Extract the age and calculate the date-of-birth.
+#   #--
+#   # FIXME: fails if the birthday falls on February 29th
+#   #++
+#   # The DOB is returned as a Time object.
+#   
+#   def get_dob(person)
+#     # ...
+#   end
+# 
+# Names of classes, source files, and any method names containing an
+# underscore or preceded by a hash character are automatically hyperlinked
+# from comment text to their description. 
+# 
+# Method parameter lists are extracted and displayed with the method
+# description.  If a method calls +yield+, then the parameters passed to yield
+# will also be displayed:
+# 
+#   def fred
+#     ...
+#     yield line, address
+# 
+# This will get documented as:
+# 
+#   fred() { |line, address| ... }
+# 
+# You can override this using a comment containing ':yields: ...' immediately
+# after the method definition
+# 
+#   def fred # :yields: index, position
+#     # ...
+#   
+#     yield line, address
+# 
+# which will get documented as
+# 
+#    fred() { |index, position| ... }
+# 
+# +:yields:+ is an example of a documentation directive.  These appear
+# immediately after the start of the document element they are modifying.
+# 
+# == 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.
+#   
+#     module MyModule # :nodoc:
+#       class Input
+#       end
+#     end
+#     
+#     module OtherModule # :nodoc: all
+#       class Output
+#       end
+#     end
+#   
+#   In the above code, only class +MyModule::Input+ will be documented.
+#   :nodoc: 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.
+# 
+# [+: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
+#   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
+#   option.
+# 
+# Comment blocks can contain other directives:
+# 
+# [<tt>:section: title</tt>]
+#   Starts a new section in the output.  The title following +:section:+ is
+#   used as the section heading, and the remainder of the comment containing
+#   the section is used as introductory text.  Subsequent methods, aliases,
+#   attributes, and classes will be documented in this section.  A :section:
+#   comment block may have one or more lines before the :section: directive.
+#   These will be removed, and any identical lines at the end of the block are
+#   also removed.  This allows you to add visual cues such as:
+#     
+#     # ----------------------------------------
+#     # :section: My Section
+#     # This is the section that I wrote.
+#     # See it glisten in the noon-day sun.
+#     # ----------------------------------------
+# 
+# [+:call-seq:+]
+#   Lines up to the next blank line in the comment are treated as the method's
+#   calling sequence, overriding the default parsing of method parameters and
+#   yield arguments.
+# 
+# [+:include:+ _filename_]
+#   \Include the contents of the named file at this point.  The file will be
+#   searched for in the directories listed by the +--include+ option, or in
+#   the current directory by default.  The contents of the file will be
+#   shifted to have the same indentation as the ':' at the start of the
+#   :include: directive.
+# 
+# [+:title:+ _text_]
+#   Sets the title for the document.  Equivalent to the <tt>--title</tt>
+#   command line parameter.  (The command line parameter overrides any :title:
+#   directive in the source).
+# 
+# [+:enddoc:+]
+#   Document nothing further at the current level.
+# 
+# [+:main:+ _name_]
+#   Equivalent to the <tt>--main</tt> command line parameter.
+# 
+# [+:stopdoc:+ / +:startdoc:+]
+#   Stop and start adding new documentation elements to the current container.
+#   For example, if a class has a number of constants that you don't want to
+#   document, put a +:stopdoc:+ before the first, and a +:startdoc:+ after the
+#   last.  If you don't specifiy a +:startdoc:+ by the end of the container,
+#   disables documentation for the entire class or module.
+# 
+# = Other stuff
+# 
+# RDoc is currently being maintained by Eric Hodel <drbrain@s...>
+#
+# Dave Thomas <dave@p...> is the original author of RDoc.
+# 
+# == Credits
+# 
+# * The Ruby parser in rdoc/parse.rb is based heavily on the outstanding
+#   work of Keiju ISHITSUKA of Nippon Rational Inc, who produced the Ruby
+#   parser for irb and the rtags package.
+# 
+# * Code to diagram classes and modules was written by Sergey A Yanovitsky
+#   (Jah) of Enticla.
+# 
+# * Charset patch from MoonWolf.
+# 
+# * Rich Kilmer wrote the kilmer.rb output template.
+# 
+# * Dan Brickley led the design of the RDF format.
+# 
+# == License
+# 
+# RDoc is Copyright (c) 2001-2003 Dave Thomas, The Pragmatic Programmers.  It
+# is free software, and may be redistributed under the terms specified
+# in the README file of the Ruby distribution.
+# 
+# == Warranty
+# 
+# This software is provided "as is" and without any express or implied
+# warranties, including, without limitation, the implied warranties of
+# merchantibility and fitness for a particular purpose.
 
 module RDoc
 
Index: lib/rdoc/parsers/parse_rb.rb
===================================================================
--- lib/rdoc/parsers/parse_rb.rb	(revision 16211)
+++ lib/rdoc/parsers/parse_rb.rb	(revision 16212)
@@ -2316,7 +2316,7 @@
 
       when "section"
         context.set_current_section(param, comment)
-        comment.clear
+        comment.replace ''
         break
 
       else
Index: lib/rdoc/rdoc.rb
===================================================================
--- lib/rdoc/rdoc.rb	(revision 16211)
+++ lib/rdoc/rdoc.rb	(revision 16212)
@@ -228,37 +228,37 @@
     def document(argv)
       TopLevel::reset
 
-      options = Options.new GENERATORS
-      options.parse argv
+      @options = Options.new GENERATORS
+      @options.parse argv
 
       @last_created = nil
 
-      unless options.all_one_file
-        @last_created = setup_output_dir(options.op_dir, options.force_update)
+      unless @options.all_one_file then
+        @last_created = setup_output_dir @options.op_dir, @options.force_update
       end
 
       start_time = Time.now
 
-      file_info = parse_files(options)
+      file_info = parse_files @options
 
       if file_info.empty?
-        $stderr.puts "\nNo newer files." unless options.quiet
+        $stderr.puts "\nNo newer files." unless @options.quiet
       else
-        gen = options.generator
+        gen = @options.generator
 
-        $stderr.puts "\nGenerating #{gen.key.upcase}..." unless options.quiet
+        $stderr.puts "\nGenerating #{gen.key.upcase}..." unless @options.quiet
 
         require gen.file_name
 
         gen_class = ::RDoc::Generator.const_get gen.class_name
-        gen = gen_class.for(options)
+        gen = gen_class.for @options
 
         pwd = Dir.pwd
 
-        Dir.chdir(options.op_dir)  unless options.all_one_file
+        Dir.chdir @options.op_dir unless @options.all_one_file
 
         begin
-          Diagram.new(file_info, options).draw if options.diagram
+          Diagram.new(file_info, @options).draw if @options.diagram
           gen.generate(file_info)
           update_output_dir(".", start_time)
         ensure
@@ -266,7 +266,7 @@
         end
       end
 
-      unless options.quiet
+      unless @options.quiet
         puts
         @stats.print
       end
Index: lib/rdoc/markup/attribute_manager.rb
===================================================================
--- lib/rdoc/markup/attribute_manager.rb	(revision 0)
+++ lib/rdoc/markup/attribute_manager.rb	(revision 16212)
@@ -0,0 +1,274 @@
+require 'rdoc/markup/inline'
+
+class RDoc::Markup::AttributeManager
+
+  NULL = "\000".freeze
+
+  ##
+  # We work by substituting non-printing characters in to the text. For now
+  # I'm assuming that I can substitute a character in the range 0..8 for a 7
+  # bit character without damaging the encoded string, but this might be
+  # optimistic
+
+  A_PROTECT  = 004
+  PROTECT_ATTR  = A_PROTECT.chr
+
+  ##
+  # This maps delimiters that occur around words (such as *bold* or +tt+)
+  # where the start and end delimiters and the same. This lets us optimize
+  # the regexp
+
+  MATCHING_WORD_PAIRS = {}
+
+  ##
+  # And this is used when the delimiters aren't the same. In this case the
+  # hash maps a pattern to the attribute character
+
+  WORD_PAIR_MAP = {}
+
+  ##
+  # This maps HTML tags to the corresponding attribute char
+
+  HTML_TAGS = {}
+
+  ##
+  # And this maps _special_ sequences to a name. A special sequence is
+  # something like a WikiWord
+
+  SPECIAL = {}
+
+  ##
+  # Return an attribute object with the given turn_on and turn_off bits set
+
+  def attribute(turn_on, turn_off)
+    RDoc::Markup::AttrChanger.new turn_on, turn_off
+  end
+
+  def change_attribute(current, new)
+    diff = current ^ new
+    attribute(new & diff, current & diff)
+  end
+
+  def changed_attribute_by_name(current_set, new_set)
+    current = new = 0
+    current_set.each do |name|
+      current |= RDoc::Markup::Attribute.bitmap_for(name)
+    end
+
+    new_set.each do |name|
+      new |= RDoc::Markup::Attribute.bitmap_for(name)
+    end
+
+    change_attribute(current, new)
+  end
+
+  def copy_string(start_pos, end_pos)
+    res = @str[start_pos...end_pos]
+    res.gsub!(/\000/, '')
+    res
+  end
+
+  ##
+  # Map attributes like <b>text</b>to the sequence
+  # \001\002<char>\001\003<char>, where <char> is a per-attribute specific
+  # character
+
+  def convert_attrs(str, attrs)
+    # first do matching ones
+    tags = MATCHING_WORD_PAIRS.keys.join("")
+
+    re = /(^|\W)([#{tags}])([#:\\]?[\w.\/-]+?\S?)\2(\W|$)/
+
+    1 while str.gsub!(re) do
+      attr = MATCHING_WORD_PAIRS[$2]
+      attrs.set_attrs($`.length + $1.length + $2.length, $3.length, attr)
+      $1 + NULL * $2.length + $3 + NULL * $2.length + $4
+    end
+
+    # then non-matching
+    unless WORD_PAIR_MAP.empty? then
+      WORD_PAIR_MAP.each do |regexp, attr|
+        str.gsub!(regexp) {
+          attrs.set_attrs($`.length + $1.length, $2.length, attr)
+          NULL * $1.length + $2 + NULL * $3.length
+        }
+      end
+    end
+  end
+
+  def convert_html(str, attrs)
+    tags = HTML_TAGS.keys.join '|'
+
+    1 while str.gsub!(/<(#{tags})>(.*?)<\/\1>/i) {
+      attr = HTML_TAGS[$1.downcase]
+      html_length = $1.length + 2
+      seq = NULL * html_length
+      attrs.set_attrs($`.length + html_length, $2.length, attr)
+      seq + $2 + seq + NULL
+    }
+  end
+
+  def convert_specials(str, attrs)
+    unless SPECIAL.empty?
+      SPECIAL.each do |regexp, attr|
+        str.scan(regexp) do
+          attrs.set_attrs($`.length, $&.length,
+                          attr | RDoc::Markup::Attribute::SPECIAL)
+        end
+      end
+    end
+  end
+
+  ##
+  # A \ in front of a character that would normally be processed turns off
+  # processing. We do this by turning \< into <#{PROTECT}
+
+  PROTECTABLE = %w[<\\]
+
+  def mask_protected_sequences
+    protect_pattern = Regexp.new("\\\\([#{Regexp.escape(PROTECTABLE.join(''))}])")
+    @str.gsub!(protect_pattern, "\\1#{PROTECT_ATTR}")
+  end
+
+  def unmask_protected_sequences
+    @str.gsub!(/(.)#{PROTECT_ATTR}/, "\\1\000")
+  end
+
+  def initialize
+    add_word_pair("*", "*", :BOLD)
+    add_word_pair("_", "_", :EM)
+    add_word_pair("+", "+", :TT)
+
+    add_html("em", :EM)
+    add_html("i",  :EM)
+    add_html("b",  :BOLD)
+    add_html("tt",   :TT)
+    add_html("code", :TT)
+
+    add_special(/<!--(.*?)-->/, :COMMENT)
+  end
+
+  def add_word_pair(start, stop, name)
+    raise ArgumentError, "Word flags may not start with '<'" if
+      start[0,1] == '<'
+
+    bitmap = RDoc::Markup::Attribute.bitmap_for name
+
+    if start == stop then
+      MATCHING_WORD_PAIRS[start] = bitmap
+    else
+      pattern = /(#{Regexp.escape start})(\S+)(#{Regexp.escape stop})/
+      WORD_PAIR_MAP[pattern] = bitmap
+    end
+
+    PROTECTABLE << start[0,1]
+    PROTECTABLE.uniq!
+  end
+
+  def add_html(tag, name)
+    HTML_TAGS[tag.downcase] = RDoc::Markup::Attribute.bitmap_for name
+  end
+
+  def add_special(pattern, name)
+    SPECIAL[pattern] = RDoc::Markup::Attribute.bitmap_for name
+  end
+
+  def flow(str)
+    @str = str
+
+    puts("Before flow, str='#{@str.dump}'") if $DEBUG_RDOC
+    mask_protected_sequences
+
+    @attrs = RDoc::Markup::AttrSpan.new @str.length
+
+    puts("After protecting, str='#{@str.dump}'") if $DEBUG_RDOC
+
+    convert_attrs(@str, @attrs)
+    convert_html(@str, @attrs)
+    convert_specials(str, @attrs)
+
+    unmask_protected_sequences
+
+    puts("After flow, str='#{@str.dump}'") if $DEBUG_RDOC
+
+    return split_into_flow
+  end
+
+  def display_attributes
+    puts
+    puts @str.tr(NULL, "!")
+    bit = 1
+    16.times do |bno|
+      line = ""
+      @str.length.times do |i|
+        if (@attrs[i] & bit) == 0
+          line << " "
+        else
+          if bno.zero?
+            line << "S"
+          else
+            line << ("%d" % (bno+1))
+          end
+        end
+      end
+      puts(line) unless line =~ /^ *$/
+      bit <<= 1
+    end
+  end
+
+  def split_into_flow
+    display_attributes if $DEBUG_RDOC
+
+    res = []
+    current_attr = 0
+    str = ""
+
+    str_len = @str.length
+
+    # skip leading invisible text
+    i = 0
+    i += 1 while i < str_len and @str[i].chr == "\0"
+    start_pos = i
+
+    # then scan the string, chunking it on attribute changes
+    while i < str_len
+      new_attr = @attrs[i]
+      if new_attr != current_attr
+        if i > start_pos
+          res << copy_string(start_pos, i)
+          start_pos = i
+        end
+
+        res << change_attribute(current_attr, new_attr)
+        current_attr = new_attr
+
+        if (current_attr & RDoc::Markup::Attribute::SPECIAL) != 0 then
+          i += 1 while
+            i < str_len and (@attrs[i] & RDoc::Markup::Attribute::SPECIAL) != 0
+
+          res << RDoc::Markup::Special.new(current_attr,
+                                           copy_string(start_pos, i))
+          start_pos = i
+          next
+        end
+      end
+
+      # move on, skipping any invisible characters
+      begin
+        i += 1
+      end while i < str_len and @str[i].chr == "\0"
+    end
+
+    # tidy up trailing text
+    if start_pos < str_len
+      res << copy_string(start_pos, str_len)
+    end
+
+    # and reset to all attributes off
+    res << change_attribute(current_attr, 0) if current_attr != 0
+
+    return res
+  end
+
+end
+
Index: lib/rdoc/markup/inline.rb
===================================================================
--- lib/rdoc/markup/inline.rb	(revision 16211)
+++ lib/rdoc/markup/inline.rb	(revision 16212)
@@ -39,12 +39,12 @@
     end
   end
 
+  AttrChanger = Struct.new(:turn_on, :turn_off)
+
   ##
   # An AttrChanger records a change in attributes. It contains a bitmap of the
   # attributes to turn on, and a bitmap of those to turn off.
 
-  AttrChanger = Struct.new(:turn_on, :turn_off)
-
   class AttrChanger
     def to_s
       "Attr: +#{Attribute.as_string(@turn_on)}/-#{Attribute.as_string(@turn_on)}"
@@ -96,266 +96,6 @@
 
   end
 
-  class AttributeManager
-
-    NULL = "\000".freeze
-
-    ##
-    # We work by substituting non-printing characters in to the text. For now
-    # I'm assuming that I can substitute a character in the range 0..8 for a 7
-    # bit character without damaging the encoded string, but this might be
-    # optimistic
-
-    A_PROTECT  = 004
-    PROTECT_ATTR  = A_PROTECT.chr
-
-    ##
-    # This maps delimiters that occur around words (such as *bold* or +tt+)
-    # where the start and end delimiters and the same. This lets us optimize
-    # the regexp
-
-    MATCHING_WORD_PAIRS = {}
-
-    ##
-    # And this is used when the delimiters aren't the same. In this case the
-    # hash maps a pattern to the attribute character
-
-    WORD_PAIR_MAP = {}
-
-    ##
-    # This maps HTML tags to the corresponding attribute char
-
-    HTML_TAGS = {}
-
-    ##
-    # And this maps _special_ sequences to a name. A special sequence is
-    # something like a WikiWord
-
-    SPECIAL = {}
-
-    ##
-    # Return an attribute object with the given turn_on and turn_off bits set
-
-    def attribute(turn_on, turn_off)
-      AttrChanger.new(turn_on, turn_off)
-    end
-
-    def change_attribute(current, new)
-      diff = current ^ new
-      attribute(new & diff, current & diff)
-    end
-
-    def changed_attribute_by_name(current_set, new_set)
-      current = new = 0
-      current_set.each {|name| current |= Attribute.bitmap_for(name) }
-      new_set.each {|name| new |= Attribute.bitmap_for(name) }
-      change_attribute(current, new)
-    end
-
-    def copy_string(start_pos, end_pos)
-      res = @str[start_pos...end_pos]
-      res.gsub!(/\000/, '')
-      res
-    end
-
-    ##
-    # Map attributes like <b>text</b>to the sequence
-    # \001\002<char>\001\003<char>, where <char> is a per-attribute specific
-    # character
-
-    def convert_attrs(str, attrs)
-      # first do matching ones
-      tags = MATCHING_WORD_PAIRS.keys.join("")
-
-      re = /(^|\W)([#{tags}])([#\\]?[\w.\/]+?\S?)\2(\W|$)/
-
-      1 while str.gsub!(re) do
-        attr = MATCHING_WORD_PAIRS[$2]
-        attrs.set_attrs($`.length + $1.length + $2.length, $3.length, attr)
-        $1 + NULL * $2.length + $3 + NULL * $2.length + $4
-      end
-
-      # then non-matching
-      unless WORD_PAIR_MAP.empty? then
-        WORD_PAIR_MAP.each do |regexp, attr|
-          str.gsub!(regexp) {
-            attrs.set_attrs($`.length + $1.length, $2.length, attr)
-            NULL * $1.length + $2 + NULL * $3.length
-          }
-        end
-      end
-    end
-
-    def convert_html(str, attrs)
-      tags = HTML_TAGS.keys.join '|'
-
-      1 while str.gsub!(/<(#{tags})>(.*?)<\/\1>/i) {
-        attr = HTML_TAGS[$1.downcase]
-        html_length = $1.length + 2
-        seq = NULL * html_length
-        attrs.set_attrs($`.length + html_length, $2.length, attr)
-        seq + $2 + seq + NULL
-      }
-    end
-
-    def convert_specials(str, attrs)
-      unless SPECIAL.empty?
-        SPECIAL.each do |regexp, attr|
-          str.scan(regexp) do
-            attrs.set_attrs($`.length, $&.length, attr | Attribute::SPECIAL)
-          end
-        end
-      end
-    end
-
-    ##
-    # A \ in front of a character that would normally be processed turns off
-    # processing. We do this by turning \< into <#{PROTECT}
-
-    PROTECTABLE = %w[<\\]
-
-    def mask_protected_sequences
-      protect_pattern = Regexp.new("\\\\([#{Regexp.escape(PROTECTABLE.join(''))}])")
-      @str.gsub!(protect_pattern, "\\1#{PROTECT_ATTR}")
-    end
-
-    def unmask_protected_sequences
-      @str.gsub!(/(.)#{PROTECT_ATTR}/, "\\1\000")
-    end
-
-    def initialize
-      add_word_pair("*", "*", :BOLD)
-      add_word_pair("_", "_", :EM)
-      add_word_pair("+", "+", :TT)
-
-      add_html("em", :EM)
-      add_html("i",  :EM)
-      add_html("b",  :BOLD)
-      add_html("tt",   :TT)
-      add_html("code", :TT)
-
-      add_special(/<!--(.*?)-->/, :COMMENT)
-    end
-
-    def add_word_pair(start, stop, name)
-      raise "Word flags may not start '<'" if start[0] == ?<
-      bitmap = Attribute.bitmap_for(name)
-      if start == stop
-        MATCHING_WORD_PAIRS[start] = bitmap
-      else
-        pattern = Regexp.new("(" + Regexp.escape(start) + ")" +
-#                             "([A-Za-z]+)" +
-                             "(\\S+)" +
-                             "(" + Regexp.escape(stop) +")")
-        WORD_PAIR_MAP[pattern] = bitmap
-      end
-      PROTECTABLE << start[0,1]
-      PROTECTABLE.uniq!
-    end
-
-    def add_html(tag, name)
-      HTML_TAGS[tag.downcase] = Attribute.bitmap_for(name)
-    end
-
-    def add_special(pattern, name)
-      SPECIAL[pattern] = Attribute.bitmap_for(name)
-    end
-
-    def flow(str)
-      @str = str
-
-      puts("Before flow, str='#{@str.dump}'") if $DEBUG_RDOC
-      mask_protected_sequences
-
-      @attrs = AttrSpan.new(@str.length)
-
-      puts("After protecting, str='#{@str.dump}'") if $DEBUG_RDOC
-
-      convert_attrs(@str, @attrs)
-      convert_html(@str, @attrs)
-      convert_specials(str, @attrs)
-
-      unmask_protected_sequences
-
-      puts("After flow, str='#{@str.dump}'") if $DEBUG_RDOC
-
-      return split_into_flow
-    end
-
-    def display_attributes
-      puts
-      puts @str.tr(NULL, "!")
-      bit = 1
-      16.times do |bno|
-        line = ""
-        @str.length.times do |i|
-          if (@attrs[i] & bit) == 0
-            line << " "
-          else
-            if bno.zero?
-              line << "S"
-            else
-              line << ("%d" % (bno+1))
-            end
-          end
-        end
-        puts(line) unless line =~ /^ *$/
-        bit <<= 1
-      end
-    end
-
-    def split_into_flow
-      display_attributes if $DEBUG_RDOC
-
-      res = []
-      current_attr = 0
-      str = ""
-
-      str_len = @str.length
-
-      # skip leading invisible text
-      i = 0
-      i += 1 while i < str_len and @str[i] == "\0"
-      start_pos = i
-
-      # then scan the string, chunking it on attribute changes
-      while i < str_len
-        new_attr = @attrs[i]
-        if new_attr != current_attr
-          if i > start_pos
-            res << copy_string(start_pos, i)
-            start_pos = i
-          end
-
-          res << change_attribute(current_attr, new_attr)
-          current_attr = new_attr
-
-          if (current_attr & Attribute::SPECIAL) != 0
-            i += 1 while i < str_len and (@attrs[i] & Attribute::SPECIAL) != 0
-            res << Special.new(current_attr, copy_string(start_pos, i))
-            start_pos = i
-            next
-          end
-        end
-
-        # move on, skipping any invisible characters
-        begin
-          i += 1
-        end while i < str_len and @str[i] == "\0"
-      end
-
-      # tidy up trailing text
-      if start_pos < str_len
-        res << copy_string(start_pos, str_len)
-      end
-
-      # and reset to all attributes off
-      res << change_attribute(current_attr, 0) if current_attr != 0
-
-      return res
-    end
-
-  end
-
 end
 
+require 'rdoc/markup/attribute_manager'
Index: lib/rdoc/markup/to_html.rb
===================================================================
--- lib/rdoc/markup/to_html.rb	(revision 16211)
+++ lib/rdoc/markup/to_html.rb	(revision 16212)
@@ -1,6 +1,7 @@
 require 'rdoc/markup/formatter'
 require 'rdoc/markup/fragments'
 require 'rdoc/markup/inline'
+require 'rdoc/generator'
 
 require 'cgi'
 
@@ -47,7 +48,7 @@
       url = if path[0, 1] == '#' then # is this meaningful?
               path
             else
-              HTML.gen_url @from_path, path
+              RDoc::Generator.gen_url @from_path, path
             end
     end
 
Index: lib/rdoc/markup.rb
===================================================================
--- lib/rdoc/markup.rb	(revision 16211)
+++ lib/rdoc/markup.rb	(revision 16212)
@@ -11,8 +11,8 @@
 # RDoc::Markup itself does no output formatting: this is left to a different
 # set of classes.
 #
-# RDoc::Markup is extendable at runtime: you can add new markup elements to be
-# recognised in the documents that RDoc::Markup parses.
+# RDoc::Markup is extendable at runtime: you can add \new markup elements to
+# be recognised in the documents that RDoc::Markup parses.
 #
 # RDoc::Markup is intended to be the basis for a family of tools which share
 # the common requirement that simple, plain-text should be rendered in a
@@ -29,10 +29,9 @@
 #   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:
+#   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.
@@ -102,7 +101,7 @@
 #   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
+#   text</b> and \\\*bold* produce \<b>bold text</b> and \*bold*
 #   respectively.
 #
 # * Hyperlinks to the web starting http:, mailto:, ftp:, or www. are
@@ -118,17 +117,15 @@
 #
 # == Synopsis
 #
-# This code converts <tt>input_string</tt> to HTML.  The conversion
-# takes place in the +convert+ method, so you can use the same
-# RDoc::Markup object to convert multiple input strings.
+# This code converts +input_string+ to HTML.  The conversion takes place in
+# the +convert+ method, so you can use the same RDoc::Markup converter to
+# convert multiple input strings.
 #
-#   require 'rdoc/markup'
 #   require 'rdoc/markup/to_html'
 #   
-#   p = RDoc::Markup.new
 #   h = RDoc::Markup::ToHtml.new
 #   
-#   puts p.convert(input_string, h)
+#   puts h.convert(input_string)
 #
 # You can extend the RDoc::Markup parser to recognise new markup
 # sequences, and to add special processing for text that matches a
@@ -152,10 +149,10 @@
 #   
 #   m.add_special(/\b([A-Z][a-z]+[A-Z]\w+)/, :WIKIWORD)
 #   
-#   h = WikiHtml.new
-#   h.add_tag(:STRIKE, "<strike>", "</strike>")
+#   wh = WikiHtml.new
+#   wh.add_tag(:STRIKE, "<strike>", "</strike>")
 #   
-#   puts "<body>" + m.convert(ARGF.read, h) + "</body>"
+#   puts "<body>#{wh.convert ARGF.read}</body>"
 #
 #--
 # Author::   Dave Thomas,  dave@p...
Index: lib/rdoc/ri/formatter.rb
===================================================================
--- lib/rdoc/ri/formatter.rb	(revision 16211)
+++ lib/rdoc/ri/formatter.rb	(revision 16212)
@@ -3,7 +3,7 @@
 
 class RDoc::RI::Formatter
 
-  attr_reader :indent
+  attr_writer :indent
   attr_accessor :output
 
   FORMATTERS = { }
@@ -20,6 +20,7 @@
     @output = output
     @width  = width
     @indent = indent
+    @original_indent = indent.dup
   end
 
   def draw_line(label=nil)
@@ -42,6 +43,18 @@
     end
   end
 
+  def indent
+    return @indent unless block_given?
+
+    begin
+      indent = @indent.dup
+      @indent += @original_indent
+      yield
+    ensure
+      @indent = indent
+    end
+  end
+
   def wrap(txt, prefix=@indent, linelen=@width)
     return unless txt && !txt.empty?
 
@@ -481,13 +494,13 @@
     when :LABELED then
       list_type = "dl"
       prefixer = proc do |li|
-          "<dt><b>" + escape(li.label) + "</b><dd>"
+        "<dt><b>" + escape(li.label) + "</b><dd>"
       end
 
     when :NOTE then
       list_type = "table"
       prefixer = proc do |li|
-          %{<tr valign="top"><td>#{li.label.gsub(/ /, '&nbsp;')}</td><td>}
+        %{<tr valign="top"><td>#{li.label.gsub(/ /, '&nbsp;')}</td><td>}
       end
     else
       fail "unknown list type"
Index: lib/rdoc/ri/display.rb
===================================================================
--- lib/rdoc/ri/display.rb	(revision 16211)
+++ lib/rdoc/ri/display.rb	(revision 16212)
@@ -2,9 +2,9 @@
 
 ##
 # This is a kind of 'flag' module. If you want to write your own 'ri' display
-# module (perhaps because you'r writing an IDE or somesuch beast), you simply
-# write a class which implements the various 'display' methods in
-# 'DefaultDisplay', and include the 'RiDisplay' module in that class.
+# module (perhaps because you're writing an IDE), you write a class which
+# implements the various 'display' methods in RDoc::RI::DefaultDisplay, and
+# include the RDoc::RI::Display module in that class.
 #
 # To access your class from the command line, you can do
 #
@@ -32,26 +32,14 @@
 
   include RDoc::RI::Display
 
-  def initialize(formatter, width, use_stdout)
+  def initialize(formatter, width, use_stdout, output = $stdout)
     @use_stdout = use_stdout
-    @formatter = formatter.new $stdout, width, "     "
+    @formatter = formatter.new output, width, "     "
   end
 
-  def display_method_info(method)
-    page do
-      @formatter.draw_line(method.full_name)
-      display_params(method)
-      @formatter.draw_line
-      display_flow(method.comment)
-      if method.aliases && !method.aliases.empty?
-        @formatter.blankline
-        aka = "(also known as "
-        aka << method.aliases.map {|a| a.name }.join(", ")
-        aka << ")"
-        @formatter.wrap(aka)
-      end
-    end
-  end
+  ##
+  # Display information about +klass+.  Fetches additional information from
+  # +ri_reader+ as necessary.
 
   def display_class_info(klass, ri_reader)
     page do
@@ -90,89 +78,150 @@
       unless klass.constants.empty?
         @formatter.blankline
         @formatter.display_heading("Constants:", 2, "")
-        len = 0
-        klass.constants.each { |c| len = c.name.length if c.name.length > len }
-        len += 2
-        klass.constants.each do |c|
-          @formatter.wrap(c.value,
-                          @formatter.indent+((c.name+":").ljust(len)))
+
+        constants = klass.constants.sort_by { |constant| constant.name }
+
+        constants.each do |constant|
+          if constant.comment then
+            @formatter.wrap "#{constant.name}:"
+
+            @formatter.indent do
+              @formatter.display_flow constant.comment
+            end
+          else
+            @formatter.wrap constant.name
+          end
         end
       end
 
-      unless klass.class_methods.empty?
-        @formatter.blankline
-        @formatter.display_heading("Class methods:", 2, "")
-        @formatter.wrap(klass.class_methods.map{|m| m.name}.sort.join(', '))
-      end
+      class_data = [
+        :class_methods,
+        :class_method_extensions,
+        :instance_methods,
+        :instance_method_extensions,
+      ]
 
-      unless klass.class_method_extensions.empty?
-        @formatter.blankline
-        @formatter.display_heading("Class Method Extensions:", 2, "")
-        @formatter.wrap(klass.class_method_extensions.map{|m| m.name}.sort.join(', '))
+      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.instance_methods.empty?
+      unless klass.attributes.empty? then
         @formatter.blankline
-        @formatter.display_heading("Instance methods:", 2, "")
-        @formatter.wrap(klass.instance_methods.map{|m| m.name}.sort.join(', '))
-      end
 
-      unless klass.instance_method_extensions.empty?
-        @formatter.blankline
-        @formatter.display_heading("Instance Method Extensions:", 2, "")
-        @formatter.wrap(klass.instance_method_extensions.map{|m| m.name}.sort.join(', '))
+        @formatter.display_heading 'Attributes:', 2, ''
+
+        attributes = klass.attributes.sort_by { |attribute| attribute.name }
+
+        attributes.each do |attribute|
+          if attribute.comment then
+            @formatter.wrap "#{attribute.name} (#{attribute.rw}):"
+            @formatter.indent do
+              @formatter.display_flow attribute.comment
+            end
+          else
+            @formatter.wrap "#{attribute.name} (#{attribute.rw})"
+          end
+        end
       end
+    end
+  end
 
-      unless klass.attributes.empty?
+  ##
+  # Display an Array of RDoc::Markup::Flow objects, +flow+.
+
+  def display_flow(flow)
+    if flow and not flow.empty? then
+      @formatter.display_flow flow
+    else
+      @formatter.wrap '[no description]'
+    end
+  end
+
+  ##
+  # Display information about +method+.
+
+  def display_method_info(method)
+    page do
+      @formatter.draw_line(method.full_name)
+      display_params(method)
+
+      @formatter.draw_line
+      display_flow(method.comment)
+
+      if method.aliases and not method.aliases.empty? then
         @formatter.blankline
-        @formatter.wrap("Attributes:", "")
-        @formatter.wrap(klass.attributes.map{|a| a.name}.sort.join(', '))
+        aka = "(also known as #{method.aliases.map { |a| a.name }.join(', ')})"
+        @formatter.wrap aka
       end
     end
   end
 
   ##
-  # Display a list of method names
+  # Display the list of +methods+.
 
   def display_method_list(methods)
     page do
-      @formatter.raw_print_line("More than one method matched your request. You can refine")
-      @formatter.raw_print_line("your search by asking for information on one of:\n\n")
-      @formatter.wrap(methods.map {|m| m.full_name} .join(", "))
+      @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(", ")
     end
   end
 
-  def display_class_list(namespaces)
-    page do
-      @formatter.raw_print_line("More than one class or module matched your request. You can refine")
-      @formatter.raw_print_line("your search by asking for information on one of:\n\n")
-      @formatter.wrap(namespaces.map {|m| m.full_name}.join(", "))
+  ##
+  # Display the params for +method+.
+
+  def display_params(method)
+    params = method.params
+
+    if params[0,1] == "(" then
+      if method.is_singleton
+        params = method.full_name + params
+      else
+        params = method.name + params
+      end
     end
+
+    params.split(/\n/).each do |param|
+      @formatter.wrap param
+      @formatter.break_to_newline
+    end
+
+    if method.source_path then
+      @formatter.blankline
+      @formatter.wrap("Extension from #{method.source_path}")
+    end
   end
 
+  ##
+  # List the classes in +classes+.
+
   def list_known_classes(classes)
     if classes.empty?
       warn_no_database
     else
       page do
-        @formatter.draw_line("Known classes and modules")
+        @formatter.draw_line "Known classes and modules"
         @formatter.blankline
-        @formatter.wrap(classes.sort.join(", "))
-      end
-    end
-  end
 
-  def list_known_names(names)
-    if names.empty?
-      warn_no_database
-    else
-      page do
-        names.each {|n| @formatter.raw_print_line(n)}
+        @formatter.wrap classes.sort.join(', ')
       end
     end
   end
 
-  private
+  ##
+  # Paginates output through a pager program.
 
   def page
     if pager = setup_pager then
@@ -190,6 +239,9 @@
   rescue Errno::EPIPE
   end
 
+  ##
+  # Sets up a pager program to pass output through.
+
   def setup_pager
     unless @use_stdout then
       for pager in [ ENV['PAGER'], "less", "more", 'pager' ].compact.uniq
@@ -200,45 +252,23 @@
     end
   end
 
-  def display_params(method)
-    params = method.params
+  ##
+  # Displays a message that describes how to build RI data.
 
-    if params[0,1] == "("
-      if method.is_singleton
-        params = method.full_name + params
-      else
-        params = method.name + params
-      end
-    end
-    params.split(/\n/).each do |p|
-      @formatter.wrap(p)
-      @formatter.break_to_newline
-    end
-    if method.source_path then
-      @formatter.blankline
-      @formatter.wrap("Extension from #{method.source_path}")
-    end
-  end
+  def warn_no_database
+    output = @formatter.output
 
-  def display_flow(flow)
-    if !flow || flow.empty?
-      @formatter.wrap("(no description...)")
-    else
-      @formatter.display_flow(flow)
-    end
+    output.puts "No ri data found"
+    output.puts
+    output.puts "If you've installed Ruby yourself, you need to generate documentation using:"
+    output.puts
+    output.puts "  make install-doc"
+    output.puts
+    output.puts "from the same place you ran `make` to build ruby."
+    output.puts
+    output.puts "If you installed Ruby from a packaging system, then you may need to"
+    output.puts "install an additional package, or ask the packager to enable ri generation."
   end
 
-  def warn_no_database
-    puts "No ri data found"
-    puts
-    puts "If you've installed Ruby yourself, you need to generate documentation using:"
-    puts
-    puts "  make install-doc"
-    puts
-    puts "from the same place you ran `make` to build ruby."
-    puts
-    puts "If you installed Ruby from a packaging system, then you may need to"
-    puts "install an additional package, or ask the packager to enable ri generation."
-  end
 end
 
Index: lib/rdoc/ri/descriptions.rb
===================================================================
--- lib/rdoc/ri/descriptions.rb	(revision 16211)
+++ lib/rdoc/ri/descriptions.rb	(revision 16212)
@@ -13,6 +13,7 @@
   def initialize(name)
     @name = name
   end
+
   def <=>(other)
     @name <=> other.name
   end
@@ -30,6 +31,7 @@
 
 class RDoc::RI::Attribute < RDoc::RI::NamedThing
   attr_reader :rw, :comment
+
   def initialize(name, rw, comment)
     super(name)
     @rw = rw
@@ -39,6 +41,7 @@
 
 class RDoc::RI::Constant < RDoc::RI::NamedThing
   attr_reader :value, :comment
+
   def initialize(name, value, comment)
     super(name)
     @value = value
Index: lib/rdoc/ri/driver.rb
===================================================================
--- lib/rdoc/ri/driver.rb	(revision 16211)
+++ lib/rdoc/ri/driver.rb	(revision 16212)
@@ -344,7 +344,11 @@
   end
 
   def read_yaml(path)
-    YAML.load File.read(path).gsub(/ \!ruby\/(object|struct):(RDoc::RI|RI|SM).*/, '')
+    data = File.read path
+    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
   end
 
   def get_info_for(arg)
@@ -418,7 +422,7 @@
 
 end
 
-class Hash
+class Hash # HACK don't add stuff to Hash.
   def method_missing method, *args
     self[method.to_s]
   end
@@ -428,7 +432,12 @@
       if self[k] then
         case v
         when Array then
-          self[k] += v
+          # HACK dunno
+          if String === self[k] and self[k].empty? then
+            self[k] = v
+          else
+            self[k] += v
+          end
         when Hash then
           self[k].merge! v
         else
Index: lib/rdoc/template.rb
===================================================================
--- lib/rdoc/template.rb	(revision 16211)
+++ lib/rdoc/template.rb	(revision 16212)
@@ -1,10 +1,12 @@
 require 'erb'
 
+module RDoc; end
+
 ##
-# An ERB wrapper.
+# An ERb wrapper that allows nesting of one ERb template inside another.
 #
 # This TemplatePage operates similarly to RDoc 1.x's TemplatePage, but uses
-# ERB instead of a custom template language.
+# ERb instead of a custom template language.
 #
 # Converting from a RDoc 1.x template to an RDoc 2.x template is fairly easy.
 #
@@ -24,8 +26,6 @@
 #
 # So you can see what is being used inside which loop.
 
-module RDoc
-end
 class RDoc::TemplatePage
 
   ##
Index: test/rdoc/test_rdoc_markup_attribute_manager.rb
===================================================================
--- test/rdoc/test_rdoc_markup_attribute_manager.rb	(revision 16211)
+++ test/rdoc/test_rdoc_markup_attribute_manager.rb	(revision 16212)
@@ -43,6 +43,29 @@
     #assert_equal(["cat {and} dog" ], @am.flow("cat \\{and} dog"))
   end
 
+  def test_add_word_pair
+    @am.add_word_pair '%', '&', 'percent and'
+
+    assert RDoc::Markup::AttributeManager::WORD_PAIR_MAP.include?(/(%)(\S+)(&)/)
+    assert RDoc::Markup::AttributeManager::PROTECTABLE.include?('%')
+    assert !RDoc::Markup::AttributeManager::PROTECTABLE.include?('&')
+  end
+
+  def test_add_word_pair_angle
+    e = assert_raise ArgumentError do
+      @am.add_word_pair '<', '>', 'angles'
+    end
+
+    assert_equal "Word flags may not start with '<'", e.message
+  end
+
+  def test_add_word_pair_matching
+    @am.add_word_pair '^', '^', 'caret'
+
+    assert RDoc::Markup::AttributeManager::MATCHING_WORD_PAIRS.include?('^')
+    assert RDoc::Markup::AttributeManager::PROTECTABLE.include?('^')
+  end
+
   def test_basic
     assert_equal(["cat"], @am.flow("cat"))
 
@@ -79,7 +102,6 @@
 
     assert_equal(["cat ", @em_on, "_", @em_off, " dog"],
                   @am.flow("cat ___ dog"))
-
   end
 
   def test_bold
@@ -101,6 +123,29 @@
                   @am.flow("cat _a__nd_ *dog*"))
   end
 
+  def test_convert_attrs
+    str = '+foo+'
+    attrs = RDoc::Markup::AttrSpan.new str.length
+
+    @am.convert_attrs str, attrs
+
+    assert_equal "\000foo\000", str
+
+    str = '+:foo:+'
+    attrs = RDoc::Markup::AttrSpan.new str.length
+
+    @am.convert_attrs str, attrs
+
+    assert_equal "\000:foo:\000", str
+
+    str = '+x-y+'
+    attrs = RDoc::Markup::AttrSpan.new str.length
+
+    @am.convert_attrs str, attrs
+
+    assert_equal "\000x-y\000", str
+  end
+
   def test_html_like_em_bold
     assert_equal ["cat ", @em_on, "and ", @em_to_bold, "dog", @bold_off],
                   @am.flow("cat <i>and </i><b>dog</b>")
Index: test/rdoc/test_rdoc_ri_formatter.rb
===================================================================
--- test/rdoc/test_rdoc_ri_formatter.rb	(revision 16211)
+++ test/rdoc/test_rdoc_ri_formatter.rb	(revision 16212)
@@ -149,43 +149,6 @@
     assert_equal "  *   a b c\n\n", @output.string
   end
 
-  def test_display_heading_1
-    @f.display_heading 'heading', 1, '  '
-
-    assert_equal "\nHEADING\n=======\n\n", @output.string
-  end
-
-  def test_display_heading_2
-    @f.display_heading 'heading', 2, '  '
-
-    assert_equal "\nheading\n-------\n\n", @output.string
-  end
-
-  def test_display_heading_3
-    @f.display_heading 'heading', 3, '  '
-
-    assert_equal "  heading\n\n", @output.string
-  end
-
-  def test_display_list
-    list = RDoc::Markup::Flow::LIST.new :NUMBER
-    list << RDoc::Markup::Flow::LI.new(nil, 'a b c')
-    list << RDoc::Markup::Flow::LI.new(nil, 'd e f')
-
-    @f.display_list list
-
-    assert_equal "  1.  a b c\n\n  2.  d e f\n\n", @output.string
-  end
-
-  def test_display_list_bullet
-    list = RDoc::Markup::Flow::LIST.new :BULLET
-    list << RDoc::Markup::Flow::LI.new(nil, 'a b c')
-
-    @f.display_list list
-
-    assert_equal "  *   a b c\n\n", @output.string
-  end
-
   def test_display_list_labeled
     list = RDoc::Markup::Flow::LIST.new :LABELED
     list << RDoc::Markup::Flow::LI.new('label', 'a b c')
Index: test/rdoc/test_rdoc_c_parser.rb
===================================================================
--- test/rdoc/test_rdoc_c_parser.rb	(revision 16211)
+++ test/rdoc/test_rdoc_c_parser.rb	(revision 16212)
@@ -226,7 +226,7 @@
     assert_equal "  \n   a comment for class Foo\n   ", klass.comment
   end
 
-  def test_find_class_comment_define_class
+  def test_find_class_comment_define_class_Init_Foo
     content = <<-EOF
 /*
  * a comment for class Foo on Init
Index: test/rdoc/test_rdoc_ri_default_display.rb
===================================================================
--- test/rdoc/test_rdoc_ri_default_display.rb	(revision 0)
+++ test/rdoc/test_rdoc_ri_default_display.rb	(revision 16212)
@@ -0,0 +1,295 @@
+require 'stringio'
+require 'test/unit'
+require 'rdoc/ri/formatter'
+require 'rdoc/ri/display'
+require 'rdoc/ri/driver'
+
+class TestRDocRIDefaultDisplay < Test::Unit::TestCase
+
+  def setup
+    @output = StringIO.new
+    @width = 78
+    @indent = '  '
+
+    @dd = RDoc::RI::DefaultDisplay.new RDoc::RI::Formatter, @width, true,
+                                       @output
+
+    @some_method = {
+      'aliases' => [{'name' => 'some_method_alias'}],
+      'block_params' => 'block_param',
+      'comment' => [RDoc::Markup::Flow::P.new('some comment')],
+      'full_name' => 'SomeClass#some_method',
+      'is_singleton' => false,
+      'name' => 'some_method',
+      'params' => '(arg1, arg2) {|block_param| ...}',
+      'source_path' => '/nonexistent',
+      'visibility' => 'public',
+    }
+  end
+
+  def test_display_class_info
+    ri_reader = nil
+    klass = {
+      'attributes' => [
+        { 'name' => 'attribute', 'rw' => 'RW',
+          'comment' => [RDoc::Markup::Flow::P.new('attribute comment')] },
+        { 'name' => 'attribute_no_comment', 'rw' => 'RW',
+          'comment' => nil },
+      ],
+      'class_methods' => [
+        { 'name' => 'class_method' },
+      ],
+      'class_method_extensions' => [
+        { 'name' => 'class_method_extension' },
+      ],
+      'comment' => [RDoc::Markup::Flow::P.new('SomeClass comment')],
+      'constants' => [
+        { 'name' => 'CONSTANT', 'value' => '"value"',
+          'comment' => [RDoc::Markup::Flow::P.new('CONSTANT value')] },
+        { 'name' => 'CONSTANT_NOCOMMENT', 'value' => '"value"',
+          'comment' => nil },
+      ],
+      'display_name' => 'Class',
+      'full_name' => 'SomeClass',
+      'includes' => [],
+      'instance_methods' => [
+        { 'name' => 'instance_method' },
+      ],
+      'instance_method_extensions' => [
+        { 'name' => 'instance_method_extension' },
+      ],
+      'superclass_string' => 'Object',
+    }
+
+    @dd.display_class_info klass, ri_reader
+
+    expected = <<-EOF
+---------------------------------------------------- Class: SomeClass < Object
+     SomeClass comment
+
+------------------------------------------------------------------------------
+
+
+Constants:
+----------
+
+     CONSTANT:
+          CONSTANT value
+
+     CONSTANT_NOCOMMENT
+
+
+Class methods:
+--------------
+
+     class_method
+
+
+Class method extensions:
+------------------------
+
+     class_method_extension
+
+
+Instance methods:
+-----------------
+
+     instance_method
+
+
+Instance method extensions:
+---------------------------
+
+     instance_method_extension
+
+
+Attributes:
+-----------
+
+     attribute (RW):
+          attribute comment
+
+     attribute_no_comment (RW)
+    EOF
+
+    assert_equal expected, @output.string
+  end
+
+  def test_display_flow
+    flow = [RDoc::Markup::Flow::P.new('flow')]
+
+    @dd.display_flow flow
+
+    assert_equal "     flow\n\n", @output.string
+  end
+
+  def test_display_flow_empty
+    @dd.display_flow []
+
+    assert_equal "     [no description]\n", @output.string
+  end
+
+  def test_display_flow_nil
+    @dd.display_flow nil
+
+    assert_equal "     [no description]\n", @output.string
+  end
+
+  def test_display_method_info
+    @dd.display_method_info @some_method
+
+    expected = <<-EOF
+-------------------------------------------------------- SomeClass#some_method
+     some_method(arg1, arg2) {|block_param| ...}
+
+     Extension from /nonexistent
+------------------------------------------------------------------------------
+     some comment
+
+
+     (also known as some_method_alias)
+    EOF
+
+    assert_equal expected, @output.string
+  end
+
+  def test_display_method_info_singleton
+    method = {
+      'aliases' => [],
+      'block_params' => nil,
+      'comment' => nil,
+      'full_name' => 'SomeClass::some_method',
+      'is_singleton' => true,
+      'name' => 'some_method',
+      'params' => '(arg1, arg2)',
+      'visibility' => 'public',
+    }
+
+    @dd.display_method_info method
+
+    expected = <<-EOF
+------------------------------------------------------- SomeClass::some_method
+     SomeClass::some_method(arg1, arg2)
+------------------------------------------------------------------------------
+     [no description]
+    EOF
+
+    assert_equal expected, @output.string
+  end
+
+  def test_display_method_list
+    methods = [
+      {
+        "aliases" => [],
+        "block_params" => nil,
+        "comment" =>  nil,
+        "full_name" => "SomeClass#some_method",
+        "is_singleton" => false,
+        "name" => "some_method",
+        "params" => "()",
+        "visibility" => "public",
+      },
+      {
+        "aliases" => [],
+        "block_params" => nil,
+        "comment" => nil,
+        "full_name" => "SomeClass#some_other_method",
+        "is_singleton" => false,
+        "name" => "some_other_method",
+        "params" => "()",
+        "visibility" => "public",
+      },
+    ]
+
+    @dd.display_method_list methods
+
+    expected = <<-EOF
+     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
+    EOF
+
+    assert_equal expected, @output.string
+  end
+
+  def test_display_params
+    @dd.display_params @some_method
+
+    expected = <<-EOF
+     some_method(arg1, arg2) {|block_param| ...}
+
+     Extension from /nonexistent
+    EOF
+
+    assert_equal expected, @output.string
+  end
+
+  def test_display_params_multiple
+    @some_method['params'] = <<-EOF
+some_method(index)
+some_method(start, length)
+    EOF
+
+    @dd.display_params @some_method
+
+    expected = <<-EOF
+     some_method(index)
+     some_method(start, length)
+
+     Extension from /nonexistent
+    EOF
+
+    assert_equal expected, @output.string
+  end
+
+  def test_display_params_singleton
+    @some_method['is_singleton'] = true
+    @some_method['full_name'] = 'SomeClass::some_method'
+
+    @dd.display_params @some_method
+
+    expected = <<-EOF
+     SomeClass::some_method(arg1, arg2) {|block_param| ...}
+
+     Extension from /nonexistent
+    EOF
+
+    assert_equal expected, @output.string
+  end
+
+  def test_list_known_classes
+    klasses = %w[SomeClass SomeModule]
+
+    @dd.list_known_classes klasses
+
+    expected = <<-EOF
+---------------------------------------------------- Known classes and modules
+
+     SomeClass, SomeModule
+    EOF
+
+    assert_equal expected, @output.string
+  end
+
+  def test_list_known_classes_empty
+    @dd.list_known_classes []
+
+    expected = <<-EOF
+No ri data found
+
+If you've installed Ruby yourself, you need to generate documentation using:
+
+  make install-doc
+
+from the same place you ran `make` to build ruby.
+
+If you installed Ruby from a packaging system, then you may need to
+install an additional package, or ask the packager to enable ri generation.
+    EOF
+
+    assert_equal expected, @output.string
+  end
+
+end
+

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

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