summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordrbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-04-01 07:45:16 +0000
committerdrbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-04-01 07:45:16 +0000
commit46580b51477355fece514573c88cb67030f4a502 (patch)
tree779c1a64466643461b3daa4cd9a3548b84f0fd55
parent9b40cdfe8c973a061c5683ad78c283b9ddb8b2e9 (diff)
Import RDoc 2.5
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@27147 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog4
-rwxr-xr-xbin/rdoc23
-rw-r--r--lib/rdoc.rb100
-rw-r--r--lib/rdoc/README232
-rw-r--r--lib/rdoc/alias.rb54
-rw-r--r--lib/rdoc/anon_class.rb10
-rw-r--r--lib/rdoc/any_method.rb282
-rw-r--r--lib/rdoc/attr.rb165
-rw-r--r--lib/rdoc/class_module.rb213
-rw-r--r--lib/rdoc/code_object.rb175
-rw-r--r--lib/rdoc/code_objects.rb1074
-rw-r--r--lib/rdoc/constant.rb58
-rw-r--r--lib/rdoc/context.rb755
-rw-r--r--lib/rdoc/diagram.rb340
-rw-r--r--lib/rdoc/dot.rb249
-rw-r--r--lib/rdoc/generator.rb1080
-rw-r--r--lib/rdoc/generator/chm.rb113
-rw-r--r--lib/rdoc/generator/chm/chm.rb100
-rw-r--r--lib/rdoc/generator/darkfish.rb459
-rw-r--r--lib/rdoc/generator/html.rb449
-rw-r--r--lib/rdoc/generator/html/common.rb24
-rw-r--r--lib/rdoc/generator/html/frameless.rb92
-rw-r--r--lib/rdoc/generator/html/hefss.rb150
-rw-r--r--lib/rdoc/generator/html/html.rb769
-rw-r--r--lib/rdoc/generator/html/kilmer.rb151
-rw-r--r--lib/rdoc/generator/html/kilmerfactory.rb427
-rw-r--r--lib/rdoc/generator/html/one_page_html.rb122
-rw-r--r--lib/rdoc/generator/markup.rb171
-rw-r--r--lib/rdoc/generator/ri.rb226
-rw-r--r--lib/rdoc/generator/template/darkfish/.document (renamed from test/rdoc/empty.dat)0
-rw-r--r--lib/rdoc/generator/template/darkfish/classpage.rhtml297
-rw-r--r--lib/rdoc/generator/template/darkfish/filepage.rhtml124
-rw-r--r--lib/rdoc/generator/template/darkfish/images/brick.pngbin0 -> 452 bytes
-rw-r--r--lib/rdoc/generator/template/darkfish/images/brick_link.pngbin0 -> 764 bytes
-rw-r--r--lib/rdoc/generator/template/darkfish/images/bug.pngbin0 -> 774 bytes
-rw-r--r--lib/rdoc/generator/template/darkfish/images/bullet_black.pngbin0 -> 211 bytes
-rw-r--r--lib/rdoc/generator/template/darkfish/images/bullet_toggle_minus.pngbin0 -> 207 bytes
-rw-r--r--lib/rdoc/generator/template/darkfish/images/bullet_toggle_plus.pngbin0 -> 209 bytes
-rw-r--r--lib/rdoc/generator/template/darkfish/images/date.pngbin0 -> 626 bytes
-rw-r--r--lib/rdoc/generator/template/darkfish/images/find.pngbin0 -> 659 bytes
-rw-r--r--lib/rdoc/generator/template/darkfish/images/loadingAnimation.gifbin0 -> 5886 bytes
-rw-r--r--lib/rdoc/generator/template/darkfish/images/macFFBgHack.pngbin0 -> 207 bytes
-rw-r--r--lib/rdoc/generator/template/darkfish/images/package.pngbin0 -> 853 bytes
-rw-r--r--lib/rdoc/generator/template/darkfish/images/page_green.pngbin0 -> 621 bytes
-rw-r--r--lib/rdoc/generator/template/darkfish/images/page_white_text.pngbin0 -> 342 bytes
-rw-r--r--lib/rdoc/generator/template/darkfish/images/page_white_width.pngbin0 -> 309 bytes
-rw-r--r--lib/rdoc/generator/template/darkfish/images/plugin.pngbin0 -> 591 bytes
-rw-r--r--lib/rdoc/generator/template/darkfish/images/ruby.pngbin0 -> 592 bytes
-rw-r--r--lib/rdoc/generator/template/darkfish/images/tag_green.pngbin0 -> 613 bytes
-rw-r--r--lib/rdoc/generator/template/darkfish/images/wrench.pngbin0 -> 610 bytes
-rw-r--r--lib/rdoc/generator/template/darkfish/images/wrench_orange.pngbin0 -> 584 bytes
-rw-r--r--lib/rdoc/generator/template/darkfish/images/zoom.pngbin0 -> 692 bytes
-rw-r--r--lib/rdoc/generator/template/darkfish/index.rhtml64
-rw-r--r--lib/rdoc/generator/template/darkfish/js/darkfish.js116
-rw-r--r--lib/rdoc/generator/template/darkfish/js/jquery.js32
-rw-r--r--lib/rdoc/generator/template/darkfish/js/quicksearch.js114
-rw-r--r--lib/rdoc/generator/template/darkfish/js/thickbox-compressed.js10
-rw-r--r--lib/rdoc/generator/template/darkfish/rdoc.css701
-rw-r--r--lib/rdoc/generator/texinfo.rb81
-rw-r--r--lib/rdoc/generator/texinfo/class.texinfo.erb44
-rw-r--r--lib/rdoc/generator/texinfo/file.texinfo.erb6
-rw-r--r--lib/rdoc/generator/texinfo/method.texinfo.erb6
-rw-r--r--lib/rdoc/generator/texinfo/texinfo.erb28
-rw-r--r--lib/rdoc/generator/xml.rb117
-rw-r--r--lib/rdoc/generator/xml/rdf.rb113
-rw-r--r--lib/rdoc/generator/xml/xml.rb123
-rw-r--r--lib/rdoc/ghost_method.rb8
-rw-r--r--lib/rdoc/include.rb61
-rw-r--r--lib/rdoc/markup.rb286
-rw-r--r--lib/rdoc/markup/attribute_manager.rb141
-rw-r--r--lib/rdoc/markup/blank_line.rb19
-rw-r--r--lib/rdoc/markup/document.rb72
-rw-r--r--lib/rdoc/markup/formatter.rb129
-rw-r--r--lib/rdoc/markup/formatter_test_case.rb341
-rw-r--r--lib/rdoc/markup/fragments.rb337
-rw-r--r--lib/rdoc/markup/heading.rb17
-rw-r--r--lib/rdoc/markup/inline.rb42
-rw-r--r--lib/rdoc/markup/lines.rb152
-rw-r--r--lib/rdoc/markup/list.rb78
-rw-r--r--lib/rdoc/markup/list_item.rb83
-rw-r--r--lib/rdoc/markup/paragraph.rb66
-rw-r--r--lib/rdoc/markup/parser.rb528
-rw-r--r--lib/rdoc/markup/preprocess.rb11
-rw-r--r--lib/rdoc/markup/rule.rb17
-rw-r--r--lib/rdoc/markup/to_ansi.rb72
-rw-r--r--lib/rdoc/markup/to_bs.rb74
-rw-r--r--lib/rdoc/markup/to_flow.rb185
-rw-r--r--lib/rdoc/markup/to_html.rb327
-rw-r--r--lib/rdoc/markup/to_html_crossref.rb84
-rw-r--r--lib/rdoc/markup/to_latex.rb328
-rw-r--r--lib/rdoc/markup/to_rdoc.rb243
-rw-r--r--lib/rdoc/markup/to_test.rb46
-rw-r--r--lib/rdoc/markup/to_texinfo.rb69
-rw-r--r--lib/rdoc/markup/verbatim.rb42
-rw-r--r--lib/rdoc/meta_method.rb8
-rw-r--r--lib/rdoc/normal_class.rb55
-rw-r--r--lib/rdoc/normal_module.rb64
-rw-r--r--lib/rdoc/options.rb422
-rw-r--r--lib/rdoc/parser.rb64
-rw-r--r--lib/rdoc/parser/c.rb288
-rw-r--r--lib/rdoc/parser/f95.rb1835
-rw-r--r--lib/rdoc/parser/perl.rb16
-rw-r--r--lib/rdoc/parser/ruby.rb2240
-rw-r--r--lib/rdoc/parser/ruby_tools.rb157
-rw-r--r--lib/rdoc/parser/simple.rb5
-rw-r--r--lib/rdoc/rdoc.rb543
-rw-r--r--lib/rdoc/require.rb32
-rw-r--r--lib/rdoc/ri.rb10
-rw-r--r--lib/rdoc/ri/cache.rb187
-rw-r--r--lib/rdoc/ri/descriptions.rb156
-rw-r--r--lib/rdoc/ri/display.rb392
-rw-r--r--lib/rdoc/ri/driver.rb1155
-rw-r--r--lib/rdoc/ri/formatter.rb615
-rw-r--r--lib/rdoc/ri/gemdirs.rb28
-rw-r--r--lib/rdoc/ri/paths.rb148
-rw-r--r--lib/rdoc/ri/reader.rb106
-rw-r--r--lib/rdoc/ri/store.rb248
-rw-r--r--lib/rdoc/ri/util.rb79
-rw-r--r--lib/rdoc/ri/writer.rb68
-rw-r--r--lib/rdoc/ruby_lex.rb1284
-rw-r--r--lib/rdoc/ruby_token.rb416
-rw-r--r--lib/rdoc/single_class.rb13
-rw-r--r--lib/rdoc/stats.rb216
-rw-r--r--lib/rdoc/task.rb254
-rw-r--r--lib/rdoc/template.rb64
-rw-r--r--lib/rdoc/text.rb130
-rw-r--r--lib/rdoc/tokenstream.rb37
-rw-r--r--lib/rdoc/top_level.rb248
-rw-r--r--test/rdoc/hidden.zip.txt1
-rw-r--r--test/rdoc/rdoc_markup_to_html_crossref_reference.rb31
-rw-r--r--test/rdoc/test.ja.rdoc8
-rw-r--r--test/rdoc/test.ja.txt8
-rw-r--r--test/rdoc/test.txt1
-rw-r--r--test/rdoc/test_attribute_manager.rb25
-rw-r--r--test/rdoc/test_rdoc_any_method.rb33
-rw-r--r--test/rdoc/test_rdoc_attr.rb40
-rw-r--r--test/rdoc/test_rdoc_class_module.rb100
-rw-r--r--test/rdoc/test_rdoc_code_object.rb96
-rw-r--r--test/rdoc/test_rdoc_constant.rb15
-rw-r--r--test/rdoc/test_rdoc_context.rb291
-rw-r--r--test/rdoc/test_rdoc_generator_ri.rb56
-rw-r--r--test/rdoc/test_rdoc_include.rb17
-rw-r--r--test/rdoc/test_rdoc_info_formatting.rb179
-rw-r--r--test/rdoc/test_rdoc_info_sections.rb139
-rw-r--r--test/rdoc/test_rdoc_markup.rb620
-rw-r--r--test/rdoc/test_rdoc_markup_attribute_manager.rb40
-rw-r--r--test/rdoc/test_rdoc_markup_document.rb51
-rw-r--r--test/rdoc/test_rdoc_markup_paragraph.rb27
-rw-r--r--test/rdoc/test_rdoc_markup_parser.rb1327
-rw-r--r--test/rdoc/test_rdoc_markup_to_ansi.rb426
-rw-r--r--test/rdoc/test_rdoc_markup_to_bs.rb443
-rw-r--r--test/rdoc/test_rdoc_markup_to_html.rb225
-rw-r--r--test/rdoc/test_rdoc_markup_to_html_crossref.rb408
-rw-r--r--test/rdoc/test_rdoc_markup_to_rdoc.rb426
-rw-r--r--test/rdoc/test_rdoc_normal_class.rb17
-rw-r--r--test/rdoc/test_rdoc_normal_module.rb26
-rw-r--r--test/rdoc/test_rdoc_options.rb41
-rw-r--r--test/rdoc/test_rdoc_parser.rb79
-rw-r--r--test/rdoc/test_rdoc_parser_c.rb253
-rw-r--r--test/rdoc/test_rdoc_parser_perl.rb5
-rw-r--r--test/rdoc/test_rdoc_parser_ruby.rb672
-rw-r--r--test/rdoc/test_rdoc_parser_simple.rb48
-rw-r--r--test/rdoc/test_rdoc_rdoc.rb66
-rw-r--r--test/rdoc/test_rdoc_require.rb25
-rw-r--r--test/rdoc/test_rdoc_ri_attribute_formatter.rb44
-rw-r--r--test/rdoc/test_rdoc_ri_default_display.rb301
-rw-r--r--test/rdoc/test_rdoc_ri_driver.rb790
-rw-r--r--test/rdoc/test_rdoc_ri_formatter.rb320
-rw-r--r--test/rdoc/test_rdoc_ri_overstrike_formatter.rb71
-rw-r--r--test/rdoc/test_rdoc_ri_paths.rb43
-rw-r--r--test/rdoc/test_rdoc_ri_store.rb309
-rw-r--r--test/rdoc/test_rdoc_task.rb64
-rw-r--r--test/rdoc/test_rdoc_text.rb157
-rw-r--r--test/rdoc/test_rdoc_top_level.rb111
-rw-r--r--test/rdoc/xref_data.rb54
-rw-r--r--test/rdoc/xref_test_case.rb53
176 files changed, 17725 insertions, 16341 deletions
diff --git a/ChangeLog b/ChangeLog
index dca654a..2a3b3c9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+Thu Apr 1 16:44:00 2010 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rdoc, test/rdoc: Imported RDoc 2.5
+
Thu Apr 1 14:30:16 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
* enc/utf_16{be,le}.c (utf16{be,le}_mbc_to_code): simplified.
diff --git a/bin/rdoc b/bin/rdoc
index e502854..8fafd01 100755
--- a/bin/rdoc
+++ b/bin/rdoc
@@ -13,10 +13,23 @@ require 'rdoc/rdoc'
begin
r = RDoc::RDoc.new
r.document ARGV
-rescue Interrupt
- $stderr.puts
- $stderr.puts "Interrupted"
-rescue RDoc::Error => e
- $stderr.puts e.message
+rescue SystemExit
+ raise
+rescue Exception => e
+ if $DEBUG_RDOC then
+ $stderr.puts e.message
+ $stderr.puts "#{e.backtrace.join "\n\t"}"
+ $stderr.puts
+ elsif Interrupt === e then
+ $stderr.puts
+ $stderr.puts 'Interrupted'
+ else
+ $stderr.puts "uh-oh! RDoc had a problem:"
+ $stderr.puts e.message
+ $stderr.puts
+ $stderr.puts "run with --debug for full backtrace"
+ end
+
exit 1
end
+
diff --git a/lib/rdoc.rb b/lib/rdoc.rb
index 043d342..fb83932 100644
--- a/lib/rdoc.rb
+++ b/lib/rdoc.rb
@@ -1,5 +1,7 @@
$DEBUG_RDOC = nil
+# :main: README.txt
+
##
# = \RDoc - Ruby Documentation System
#
@@ -17,7 +19,8 @@ $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
+# * If you want to generate documentation for extensions written in C, see
+# RDoc::Parser::C
# * 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.
@@ -31,6 +34,7 @@ $DEBUG_RDOC = nil
# % rdoc [options] [names...]
#
# For an up-to-date option summary, type
+#
# % rdoc --help
#
# A typical use might be to generate documentation for a package of Ruby
@@ -59,6 +63,7 @@ $DEBUG_RDOC = nil
# recursively for C and Ruby source files only.
#
# == \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.
@@ -68,35 +73,22 @@ $DEBUG_RDOC = nil
# will make rdoc default to inline method source code. Command-line options
# always will override those in +RDOCOPT+.
#
-# Run
+# Run:
#
-# % rdoc --help
+# 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
+# Comment blocks can be written fairly naturally, either using <tt>#</tt> on
# successive lines of the comment, or by including the comment in
# a =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
#
@@ -112,7 +104,7 @@ $DEBUG_RDOC = nil
# # FIXME: fails if the birthday falls on February 29th
# #++
# # The DOB is returned as a Time object.
-#
+#
# def get_dob(person)
# # ...
# end
@@ -138,7 +130,7 @@ $DEBUG_RDOC = nil
#
# def fred # :yields: index, position
# # ...
-#
+#
# yield line, address
#
# which will get documented as
@@ -148,6 +140,11 @@ $DEBUG_RDOC = nil
# +:yields:+ is an example of a documentation directive. These appear
# immediately after the start of the document element they are modifying.
#
+# RDoc automatically cross-references words with underscores or camel-case.
+# To suppress cross-references, prefix the word with a \\ character. To
+# include special characters like "\\n", you'll need to use two \\
+# characters like "\\\\\\n".
+#
# == \Markup
#
# * The markup engine looks for a document's natural left margin. This is
@@ -214,17 +211,17 @@ $DEBUG_RDOC = nil
#
# 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
+# [<tt>\*word*</tt>] displays word in a *bold* font
+# [<tt>\_word_</tt>] displays word in an _emphasized_ font
+# [<tt>\+word+</tt>] 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
+# [<tt>\<b>text...</b></tt>] displays word in a *bold* font
+# [<tt>\<em>text...</em></tt>] displays word in an _emphasized_ font
+# [<tt>\<i>text...</i></tt>] displays word in an <i>italicized</i> font
+# [<tt>\<tt>text...\</tt></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
@@ -233,7 +230,7 @@ $DEBUG_RDOC = nil
#
# * 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
+# converted into an inline \<IMG..>. Hyperlinks starting 'link:' are
# assumed to refer to local files whose path is relative to the --op
# directory.
#
@@ -242,6 +239,14 @@ $DEBUG_RDOC = nil
# used as the target. If +label+ contains multiple words,
# put it in braces: <em>{multi word label}[</em>url<em>]</em>.
#
+# Example hyperlinks:
+#
+# link:RDoc.html
+# http://rdoc.rubyforge.org
+# mailto:user@example.com
+# {RDoc Documentation}[http://rdoc.rubyforge.org]
+# {RDoc Markup}[link:RDoc/Markup.html]
+#
# == Directives
#
# [+:nodoc:+ / +:nodoc:+ all]
@@ -251,12 +256,12 @@ $DEBUG_RDOC = nil
# 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
# end
# end
-#
+#
# module OtherModule # :nodoc: all
# class Output
# end
@@ -290,7 +295,7 @@ $DEBUG_RDOC = nil
# 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.
@@ -327,6 +332,8 @@ $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.
#
+# Further directives can be found in RDoc::Parser::Ruby and RDoc::Parser::C
+#
# == Other stuff
#
# RDoc is currently being maintained by Eric Hodel <drbrain@segment7.net>
@@ -339,9 +346,6 @@ $DEBUG_RDOC = nil
# 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.
@@ -367,12 +371,19 @@ module RDoc
class Error < RuntimeError; end
- RDocError = Error # :nodoc:
+ def self.const_missing const_name # :nodoc:
+ if const_name.to_s == 'RDocError' then
+ warn "RDoc::RDocError is deprecated"
+ return Error
+ end
+
+ super
+ end
##
# RDoc version you are using
- VERSION = "2.2.2"
+ VERSION = '2.5'
##
# Name of the dotfile that contains the description of files to be processed
@@ -380,14 +391,29 @@ module RDoc
DOT_DOC_FILENAME = ".document"
+ ##
+ # General RDoc modifiers
+
GENERAL_MODIFIERS = %w[nodoc].freeze
+ ##
+ # RDoc modifiers for classes
+
CLASS_MODIFIERS = GENERAL_MODIFIERS
- ATTR_MODIFIERS = GENERAL_MODIFIERS
+ ##
+ # RDoc modifiers for attributes
+
+ ATTR_MODIFIERS = GENERAL_MODIFIERS
+
+ ##
+ # RDoc modifiers for constants
CONSTANT_MODIFIERS = GENERAL_MODIFIERS
+ ##
+ # RDoc modifiers for methods
+
METHOD_MODIFIERS = GENERAL_MODIFIERS +
%w[arg args yield yields notnew not-new not_new doc]
diff --git a/lib/rdoc/README b/lib/rdoc/README
deleted file mode 100644
index f183c61..0000000
--- a/lib/rdoc/README
+++ /dev/null
@@ -1,232 +0,0 @@
-= 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 programmatically, 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 '+#--+'.
-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 '+#+++'.
-
- ##
- # 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.
-
-[+: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:
-
-[+:section: title+]
- 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 --title 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 --main 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 specify a +:startdoc:+ by the end of the container,
- disables documentation for the entire class or module.
-
-= Other stuff
-
-Author:: Dave Thomas <dave@pragmaticprogrammer.com>
-
-== 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.
-
diff --git a/lib/rdoc/alias.rb b/lib/rdoc/alias.rb
new file mode 100644
index 0000000..6cd9af0
--- /dev/null
+++ b/lib/rdoc/alias.rb
@@ -0,0 +1,54 @@
+require 'rdoc/code_object'
+
+##
+# Represent an alias, which is an old_name/new_name pair associated with a
+# particular context
+
+class RDoc::Alias < RDoc::CodeObject
+
+ ##
+ # Allow comments to be overridden
+
+ attr_writer :comment
+
+ ##
+ # Aliased name
+
+ attr_accessor :new_name
+
+ ##
+ # Aliasee's name
+
+ attr_accessor :old_name
+
+ ##
+ # Source file token stream
+
+ attr_accessor :text
+
+ ##
+ # Creates a new Alias with a token stream of +text+ that aliases +old_name+
+ # to +new_name+ and has +comment+
+
+ def initialize(text, old_name, new_name, comment)
+ super()
+ @text = text
+ @old_name = old_name
+ @new_name = new_name
+ self.comment = comment
+ end
+
+ def inspect # :nodoc:
+ parent_name = parent ? parent.name : '(unknown)'
+ "#<%s:0x%x %s.alias_method %s, %s>" % [
+ self.class, object_id,
+ parent_name, @old_name, @new_name,
+ ]
+ end
+
+ def to_s # :nodoc:
+ "alias: #{self.old_name} -> #{self.new_name}\n#{self.comment}"
+ end
+
+end
+
diff --git a/lib/rdoc/anon_class.rb b/lib/rdoc/anon_class.rb
new file mode 100644
index 0000000..0a684f2
--- /dev/null
+++ b/lib/rdoc/anon_class.rb
@@ -0,0 +1,10 @@
+require 'rdoc/class_module'
+
+##
+# An anonymous class like:
+#
+# c = Class.new do end
+
+class RDoc::AnonClass < RDoc::ClassModule
+end
+
diff --git a/lib/rdoc/any_method.rb b/lib/rdoc/any_method.rb
new file mode 100644
index 0000000..5d291e8
--- /dev/null
+++ b/lib/rdoc/any_method.rb
@@ -0,0 +1,282 @@
+require 'rdoc/code_object'
+require 'rdoc/tokenstream'
+
+##
+# AnyMethod is the base class for objects representing methods
+
+class RDoc::AnyMethod < RDoc::CodeObject
+
+ MARSHAL_VERSION = 0 # :nodoc:
+
+ include Comparable
+
+ ##
+ # Method name
+
+ attr_writer :name
+
+ ##
+ # public, protected, private
+
+ attr_accessor :visibility
+
+ ##
+ # Parameters yielded by the called block
+
+ attr_accessor :block_params
+
+ ##
+ # Don't rename \#initialize to \::new
+
+ attr_accessor :dont_rename_initialize
+
+ ##
+ # Is this a singleton method?
+
+ attr_accessor :singleton
+
+ ##
+ # Source file token stream
+
+ attr_reader :text
+
+ ##
+ # Array of other names for this method
+
+ attr_reader :aliases
+
+ ##
+ # Fragment reference for this method
+
+ attr_reader :aref
+
+ ##
+ # The method we're aliasing
+
+ attr_accessor :is_alias_for
+
+ ##
+ # Parameters for this method
+
+ attr_overridable :params, :param, :parameters, :parameter
+
+ ##
+ # Different ways to call this method
+
+ attr_accessor :call_seq
+
+ include RDoc::TokenStream
+
+ ##
+ # Resets method fragment reference counter
+
+ def self.reset
+ @@aref = 'M000000'
+ end
+
+ reset
+
+ def initialize(text, name)
+ super()
+
+ @text = text
+ @name = name
+
+ @aliases = []
+ @block_params = nil
+ @call_seq = nil
+ @dont_rename_initialize = false
+ @is_alias_for = nil
+ @parent_name = nil
+ @singleton = nil
+ @token_stream = nil
+ @visibility = :public
+
+ @aref = @@aref
+ @@aref = @@aref.succ
+ end
+
+ ##
+ # Order by #singleton then #name
+
+ def <=>(other)
+ [@singleton ? 0 : 1, @name] <=> [other.singleton ? 0 : 1, other.name]
+ end
+
+ ##
+ # Adds +method+ as an alias for this method
+
+ def add_alias(method)
+ @aliases << method
+ end
+
+ ##
+ # HTML id-friendly method name
+
+ def html_name
+ @name.gsub(/[^a-z]+/, '-')
+ end
+
+ def inspect # :nodoc:
+ alias_for = @is_alias_for ? " (alias for #{@is_alias_for.name})" : nil
+ "#<%s:0x%x %s (%s)%s>" % [
+ self.class, object_id,
+ full_name,
+ visibility,
+ alias_for,
+ ]
+ end
+
+ ##
+ # Full method name including namespace
+
+ def full_name
+ @full_name ||= "#{@parent ? @parent.full_name : '(unknown)'}#{pretty_name}"
+ end
+
+ ##
+ # Dumps this AnyMethod for use by ri. See also #marshal_load
+
+ def marshal_dump
+ aliases = @aliases.map do |a|
+ [a.full_name, parse(a.comment)]
+ end
+
+ [ MARSHAL_VERSION,
+ @name,
+ full_name,
+ @singleton,
+ @visibility,
+ parse(@comment),
+ @call_seq,
+ @block_params,
+ aliases,
+ ]
+ end
+
+ ##
+ # Loads this AnyMethod from +array+. For a loaded AnyMethod the following
+ # methods will return cached values:
+ #
+ # * #full_name
+ # * #parent_name
+
+ def marshal_load(array)
+ @aliases = []
+ @dont_rename_initialize = nil
+ @is_alias_for = nil
+ @token_stream = nil
+
+ @name = array[1]
+ @full_name = array[2]
+ @singleton = array[3]
+ @visibility = array[4]
+ @comment = array[5]
+ @call_seq = array[6]
+ @block_params = array[7]
+
+ @parent_name = if @full_name =~ /#/ then
+ $`
+ else
+ name = @full_name.split('::')
+ name.pop
+ name.join '::'
+ end
+
+ array[8].each do |old_name, new_name, comment|
+ add_alias RDoc::Alias.new(nil, old_name, new_name, comment)
+ end
+ end
+
+ ##
+ # Method name
+
+ def name
+ return @name if @name
+
+ @name = @call_seq[/^.*?\.(\w+)/, 1] || @call_seq if @call_seq
+ end
+
+ ##
+ # Pretty parameter list for this method
+
+ def param_seq
+ params = params.gsub(/\s*\#.*/, '')
+ params = params.tr("\n", " ").squeeze(" ")
+ params = "(#{params})" unless p[0] == ?(
+
+ if block = block_params then # yes, =
+ # If this method has explicit block parameters, remove any explicit
+ # &block
+ params.sub!(/,?\s*&\w+/)
+
+ block.gsub!(/\s*\#.*/, '')
+ block = block.tr("\n", " ").squeeze(" ")
+ if block[0] == ?(
+ block.sub!(/^\(/, '').sub!(/\)/, '')
+ end
+ params << " { |#{block}| ... }"
+ end
+
+ params
+ end
+
+ ##
+ # Name of our parent with special handling for un-marshaled methods
+
+ def parent_name
+ @parent_name || super
+ end
+
+ ##
+ # Path to this method
+
+ def path
+ "#{@parent.path}##{@aref}"
+ end
+
+ ##
+ # Method name with class/instance indicator
+
+ def pretty_name
+ "#{singleton ? '::' : '#'}#{@name}"
+ end
+
+ def pretty_print q # :nodoc:
+ alias_for = @is_alias_for ? "alias for #{@is_alias_for.name}" : nil
+
+ q.group 2, "[#{self.class.name} #{full_name} #{visibility}", "]" do
+ if alias_for then
+ q.breakable
+ q.text alias_for
+ end
+
+ if text then
+ q.breakable
+ q.text "text:"
+ q.breakable
+ q.pp @text
+ end
+
+ unless comment.empty? then
+ q.breakable
+ q.text "comment:"
+ q.breakable
+ q.pp @comment
+ end
+ end
+ end
+
+ def to_s # :nodoc:
+ "#{self.class.name}: #{full_name} (#{@text})\n#{@comment}"
+ end
+
+ ##
+ # Type of method (class or instance)
+
+ def type
+ singleton ? 'class' : 'instance'
+ end
+
+end
+
diff --git a/lib/rdoc/attr.rb b/lib/rdoc/attr.rb
new file mode 100644
index 0000000..43ded8e
--- /dev/null
+++ b/lib/rdoc/attr.rb
@@ -0,0 +1,165 @@
+require 'rdoc/code_object'
+
+##
+# An attribute created by \#attr, \#attr_reader, \#attr_writer or
+# \#attr_accessor
+
+class RDoc::Attr < RDoc::CodeObject
+
+ MARSHAL_VERSION = 0 # :nodoc:
+
+ ##
+ # Name of the attribute
+
+ attr_accessor :name
+
+ ##
+ # Is the attribute readable, writable or both?
+
+ attr_accessor :rw
+
+ ##
+ # Source file token stream
+
+ attr_accessor :text
+
+ ##
+ # public, protected, private
+
+ attr_accessor :visibility
+
+ def initialize(text, name, rw, comment)
+ super()
+ @text = text
+ @name = name
+ @rw = rw
+ @visibility = :public
+ self.comment = comment
+ end
+
+ ##
+ # Attributes are ordered by name
+
+ def <=>(other)
+ self.name <=> other.name
+ end
+
+ ##
+ # Attributes are equal when their names and rw is identical
+
+ def == other
+ self.class == other.class and
+ self.name == other.name and
+ self.rw == other.rw
+ end
+
+ ##
+ # Returns nil, for duck typing with RDoc::AnyMethod
+
+ def block_params
+ end
+
+ ##
+ # Returns nil, for duck typing with RDoc::AnyMethod
+
+ def call_seq
+ end
+
+ ##
+ # Partially bogus as Attr has no parent. For duck typing with
+ # RDoc::AnyMethod.
+
+ def full_name
+ @full_name ||= "#{@parent ? @parent.full_name : '(unknown)'}##{name}"
+ end
+
+ ##
+ # An HTML id-friendly representation of #name
+
+ def html_name
+ @name.gsub(/[^a-z]+/, '-')
+ end
+
+ def inspect # :nodoc:
+ attr = case rw
+ when 'RW' then :attr_accessor
+ when 'R' then :attr_reader
+ when 'W' then :attr_writer
+ else
+ " (#{rw})"
+ end
+
+ "#<%s:0x%x %s.%s :%s>" % [
+ self.class, object_id,
+ parent_name, attr, @name,
+ ]
+ end
+
+ ##
+ # Dumps this Attr for use by ri. See also #marshal_load
+
+ def marshal_dump
+ [ MARSHAL_VERSION,
+ @name,
+ full_name,
+ @rw,
+ @visibility,
+ parse(@comment),
+ ]
+ end
+
+ ##
+ # Loads this AnyMethod from +array+. For a loaded AnyMethod the following
+ # methods will return cached values:
+ #
+ # * #full_name
+ # * #parent_name
+
+ def marshal_load array
+ @name = array[1]
+ @full_name = array[2]
+ @rw = array[3]
+ @visibility = array[4]
+ @comment = array[5]
+
+ @parent_name = @full_name
+ end
+
+ ##
+ # Name of our parent with special handling for un-marshaled methods
+
+ def parent_name
+ @parent_name || super
+ end
+
+ ##
+ # URL path for this attribute
+
+ def path
+ "#{@parent.path}##{@name}"
+ end
+
+ ##
+ # For duck typing with RDoc::AnyMethod
+
+ def singleton
+ false
+ end
+
+ def to_s # :nodoc:
+ "#{type} #{name}\n#{comment}"
+ end
+
+ ##
+ # Returns attr_reader, attr_writer or attr_accessor as appropriate
+
+ def type
+ case @rw
+ when 'RW' then 'attr_accessor'
+ when 'R' then 'attr_reader'
+ when 'W' then 'attr_writer'
+ end
+ end
+
+end
+
diff --git a/lib/rdoc/class_module.rb b/lib/rdoc/class_module.rb
new file mode 100644
index 0000000..c3029bf
--- /dev/null
+++ b/lib/rdoc/class_module.rb
@@ -0,0 +1,213 @@
+require 'rdoc/context'
+
+##
+# ClassModule is the base class for objects representing either a class or a
+# module.
+
+class RDoc::ClassModule < RDoc::Context
+
+ MARSHAL_VERSION = 0 # :nodoc:
+
+ attr_accessor :diagram
+
+ ##
+ # Creates a new ClassModule with +name+ with optional +superclass+
+
+ def initialize(name, superclass = 'Object')
+ @diagram = nil
+ @full_name = nil
+ @name = name
+ @superclass = superclass
+ super()
+ end
+
+ ##
+ # Ancestors list for this ClassModule (abstract)
+
+ def ancestors
+ raise NotImplementedError
+ end
+
+ ##
+ # Appends +comment+ to the current comment, but separated by a rule. Works
+ # more like <tt>+=</tt>.
+
+ def comment=(comment)
+ return if comment.empty?
+
+ comment = "#{@comment}\n---\n#{normalize_comment comment}" unless
+ @comment.empty?
+
+ super
+ end
+
+ ##
+ # Finds a class or module with +name+ in this namespace or its descendents
+
+ def find_class_named(name)
+ return self if full_name == name
+ return self if @name == name
+
+ @classes.values.find do |klass|
+ next if klass == self
+ klass.find_class_named name
+ end
+ end
+
+ ##
+ # Return the fully qualified name of this class or module
+
+ def full_name
+ @full_name ||= if RDoc::ClassModule === @parent then
+ "#{@parent.full_name}::#{@name}"
+ else
+ @name
+ end
+ end
+
+ ##
+ # 'module' or 'class'
+
+ def type
+ module? ? 'module' : 'class'
+ end
+
+ def marshal_dump # :nodoc:
+ attrs = attributes.sort.map do |attr|
+ [attr.name, attr.rw]
+ end
+
+ method_types = methods_by_type.map do |type, visibilities|
+ visibilities = visibilities.map do |visibility, methods|
+ method_names = methods.map do |method|
+ method.name
+ end
+
+ [visibility, method_names.uniq]
+ end
+
+ [type, visibilities]
+ end
+
+ [ MARSHAL_VERSION,
+ @name,
+ full_name,
+ @superclass,
+ parse(@comment),
+ attrs,
+ constants.map do |const|
+ [const.name, parse(const.comment)]
+ end,
+ includes.map do |incl|
+ [incl.name, parse(incl.comment)]
+ end,
+ method_types,
+ ]
+ end
+
+ def marshal_load array # :nodoc:
+ initialize_methods_etc
+ @document_self = true
+ @done_documenting = false
+ @current_section = nil
+
+ @name = array[1]
+ @full_name = array[2]
+ @superclass = array[3]
+ @comment = array[4]
+
+ array[5].each do |name, rw|
+ add_attribute RDoc::Attr.new(nil, name, rw, nil)
+ end
+
+ array[6].each do |name, comment|
+ add_constant RDoc::Constant.new(name, nil, comment)
+ end
+
+ array[7].each do |name, comment|
+ add_include RDoc::Include.new(name, comment)
+ end
+
+ array[8].each do |type, visibilities|
+ visibilities.each do |visibility, methods|
+ @visibility = visibility
+
+ methods.each do |name|
+ method = RDoc::AnyMethod.new nil, name
+ method.singleton = true if type == 'class'
+ add_method method
+ end
+ end
+ end
+ end
+
+ ##
+ # Merges +class_module+ into this ClassModule
+
+ def merge class_module
+ if class_module.comment then
+ document = parse @comment
+
+ class_module.comment.parts.push(*document.parts)
+
+ @comment = class_module.comment
+ end
+
+ class_module.each_attribute do |attr|
+ if match = attributes.find { |a| a.name == attr.name } then
+ match.rw = [match.rw, attr.rw].compact.join
+ else
+ add_attribute attr
+ end
+ end
+
+ class_module.each_constant do |const|
+ add_constant const
+ end
+
+ class_module.each_include do |incl|
+ add_include incl
+ end
+
+ class_module.each_method do |meth|
+ add_method meth
+ end
+ end
+
+ ##
+ # Does this object represent a module?
+
+ def module?
+ false
+ end
+
+ ##
+ # Path to this class or module
+
+ def path
+ http_url RDoc::RDoc.current.generator.class_dir
+ end
+
+ ##
+ # Get the superclass of this class. Attempts to retrieve the superclass
+ # object, returns the name if it is not known.
+
+ def superclass
+ RDoc::TopLevel.find_class_named_from(@superclass, parent) || @superclass
+ end
+
+ ##
+ # Set the superclass of this class to +superclass+
+
+ def superclass=(superclass)
+ raise NoMethodError, "#{full_name} is a module" if module?
+
+ @superclass = superclass if @superclass.nil? or @superclass == 'Object'
+ end
+
+ def to_s # :nodoc:
+ "#{self.class}: #{full_name} #{@comment} #{super}"
+ end
+
+end
+
diff --git a/lib/rdoc/code_object.rb b/lib/rdoc/code_object.rb
new file mode 100644
index 0000000..2fcc92e
--- /dev/null
+++ b/lib/rdoc/code_object.rb
@@ -0,0 +1,175 @@
+require 'rdoc'
+require 'rdoc/text'
+
+##
+# Base class for the RDoc code tree.
+#
+# We contain the common stuff for contexts (which are containers) and other
+# elements (methods, attributes and so on)
+
+class RDoc::CodeObject
+
+ include RDoc::Text
+
+ ##
+ # Our comment
+
+ attr_reader :comment
+
+ ##
+ # Do we document our children?
+
+ attr_reader :document_children
+
+ ##
+ # Do we document ourselves?
+
+ attr_reader :document_self
+
+ ##
+ # Are we done documenting (ie, did we come across a :enddoc:)?
+
+ attr_accessor :done_documenting
+
+ ##
+ # Force documentation of this CodeObject
+
+ attr_accessor :force_documentation
+
+ ##
+ # Our parent CodeObject
+
+ attr_accessor :parent
+
+ ##
+ # Which section are we in
+
+ attr_accessor :section
+
+ ##
+ # We are the model of the code, but we know that at some point we will be
+ # worked on by viewers. By implementing the Viewable protocol, viewers can
+ # associated themselves with these objects.
+
+ attr_accessor :viewer
+
+ ##
+ # There's a wee trick we pull. Comment blocks can have directives that
+ # override the stuff we extract during the parse. So, we have a special
+ # class method, attr_overridable, that lets code objects list those
+ # directives. When a comment is assigned, we then extract out any matching
+ # directives and update our object
+
+ def self.attr_overridable(name, *aliases)
+ @overridables ||= {}
+
+ attr_accessor name
+
+ aliases.unshift name
+
+ aliases.each do |directive_name|
+ @overridables[directive_name.to_s] = name
+ end
+ end
+
+ ##
+ # Creates a new CodeObject that will document itself and its children
+
+ def initialize
+ @comment = ''
+
+ @document_children = true
+ @document_self = true
+ @done_documenting = false
+ @force_documentation = false
+
+ @parent = nil
+ end
+
+ ##
+ # Replaces our comment with +comment+, unless it is empty.
+
+ def comment=(comment)
+ @comment = case comment
+ when NilClass then ''
+ when RDoc::Markup::Document then comment
+ else
+ if comment and not comment.empty? then
+ normalize_comment comment
+ else
+ @comment
+ end
+ end
+ end
+
+ ##
+ # Enables or disables documentation of this CodeObject's children. Calls
+ # remove_classes_and_modules when disabling.
+
+ def document_children=(document_children)
+ @document_children = document_children
+ remove_classes_and_modules unless document_children
+ end
+
+ ##
+ # Enables or disables documentation of this CodeObject. Calls
+ # remove_methods_etc when disabling.
+
+ def document_self=(document_self)
+ @document_self = document_self
+ remove_methods_etc unless document_self
+ end
+
+ ##
+ # Does this class have a comment with content or is document_self false.
+
+ def documented?
+ !(@document_self and @comment.empty?)
+ end
+
+ ##
+ # File name of our parent
+
+ def parent_file_name
+ @parent ? @parent.base_name : '(unknown)'
+ end
+
+ ##
+ # Name of our parent
+
+ def parent_name
+ @parent ? @parent.full_name : '(unknown)'
+ end
+
+ ##
+ # Callback called upon disabling documentation of children. See
+ # #document_children=
+
+ def remove_classes_and_modules
+ end
+
+ ##
+ # Callback called upon disabling documentation of ourself. See
+ # #document_self=
+
+ def remove_methods_etc
+ end
+
+ ##
+ # Enable capture of documentation
+
+ def start_doc
+ @document_self = true
+ @document_children = true
+ end
+
+ ##
+ # Disable capture of documentation
+
+ def stop_doc
+ @document_self = false
+ @document_children = false
+ end
+
+end
+
diff --git a/lib/rdoc/code_objects.rb b/lib/rdoc/code_objects.rb
index 3fdd863..c60dad9 100644
--- a/lib/rdoc/code_objects.rb
+++ b/lib/rdoc/code_objects.rb
@@ -1,1061 +1,23 @@
-# We represent the various high-level code constructs that appear
-# in Ruby programs: classes, modules, methods, and so on.
+# We represent the various high-level code constructs that appear in Ruby
+# programs: classes, modules, methods, and so on.
-require 'rdoc/tokenstream'
+require 'rdoc/code_object'
+require 'rdoc/context'
+require 'rdoc/top_level'
-module RDoc
+require 'rdoc/class_module'
+require 'rdoc/normal_class'
+require 'rdoc/normal_module'
+require 'rdoc/anon_class'
+require 'rdoc/single_class'
- ##
- # We contain the common stuff for contexts (which are containers) and other
- # elements (methods, attributes and so on)
+require 'rdoc/any_method'
+require 'rdoc/alias'
+require 'rdoc/ghost_method'
+require 'rdoc/meta_method'
- class CodeObject
+require 'rdoc/attr'
+require 'rdoc/constant'
+require 'rdoc/require'
+require 'rdoc/include'
- attr_accessor :parent
-
- # We are the model of the code, but we know that at some point
- # we will be worked on by viewers. By implementing the Viewable
- # protocol, viewers can associated themselves with these objects.
-
- attr_accessor :viewer
-
- # are we done documenting (ie, did we come across a :enddoc:)?
-
- attr_accessor :done_documenting
-
- # Which section are we in
-
- attr_accessor :section
-
- # do we document ourselves?
-
- attr_reader :document_self
-
- def initialize
- @document_self = true
- @document_children = true
- @force_documentation = false
- @done_documenting = false
- end
-
- def document_self=(val)
- @document_self = val
- if !val
- remove_methods_etc
- end
- end
-
- # set and cleared by :startdoc: and :enddoc:, this is used to toggle
- # the capturing of documentation
- def start_doc
- @document_self = true
- @document_children = true
- end
-
- def stop_doc
- @document_self = false
- @document_children = false
- end
-
- # do we document ourselves and our children
-
- attr_reader :document_children
-
- def document_children=(val)
- @document_children = val
- if !val
- remove_classes_and_modules
- end
- end
-
- # Do we _force_ documentation, even is we wouldn't normally show the entity
- attr_accessor :force_documentation
-
- def parent_file_name
- @parent ? @parent.file_base_name : '(unknown)'
- end
-
- def parent_name
- @parent ? @parent.name : '(unknown)'
- end
-
- # Default callbacks to nothing, but this is overridden for classes
- # and modules
- def remove_classes_and_modules
- end
-
- def remove_methods_etc
- end
-
- # Access the code object's comment
- attr_reader :comment
-
- # Update the comment, but don't overwrite a real comment with an empty one
- def comment=(comment)
- @comment = comment unless comment.empty?
- end
-
- # There's a wee trick we pull. Comment blocks can have directives that
- # override the stuff we extract during the parse. So, we have a special
- # class method, attr_overridable, that lets code objects list
- # those directives. Wehn a comment is assigned, we then extract
- # out any matching directives and update our object
-
- def self.attr_overridable(name, *aliases)
- @overridables ||= {}
-
- attr_accessor name
-
- aliases.unshift name
- aliases.each do |directive_name|
- @overridables[directive_name.to_s] = name
- end
- end
-
- end
-
- ##
- # A Context is something that can hold modules, classes, methods,
- # attributes, aliases, requires, and includes. Classes, modules, and files
- # are all Contexts.
-
- class Context < CodeObject
-
- attr_reader :aliases
- attr_reader :attributes
- attr_reader :constants
- attr_reader :current_section
- attr_reader :in_files
- attr_reader :includes
- attr_reader :method_list
- attr_reader :name
- attr_reader :requires
- attr_reader :sections
- attr_reader :visibility
-
- class Section
- attr_reader :title, :comment, :sequence
-
- @@sequence = "SEC00000"
-
- def initialize(title, comment)
- @title = title
- @@sequence.succ!
- @sequence = @@sequence.dup
- @comment = nil
- set_comment(comment)
- end
-
- def ==(other)
- self.class === other and @sequence == other.sequence
- end
-
- def inspect
- "#<%s:0x%x %s %p>" % [
- self.class, object_id,
- @sequence, title
- ]
- end
-
- ##
- # Set the comment for this section from the original comment block If
- # the first line contains :section:, strip it and use the rest.
- # Otherwise remove lines up to the line containing :section:, and look
- # for those lines again at the end and remove them. This lets us write
- #
- # # ---------------------
- # # :SECTION: The title
- # # The body
- # # ---------------------
-
- def set_comment(comment)
- return unless comment
-
- if comment =~ /^#[ \t]*:section:.*\n/
- start = $`
- rest = $'
-
- if start.empty?
- @comment = rest
- else
- @comment = rest.sub(/#{start.chomp}\Z/, '')
- end
- else
- @comment = comment
- end
- @comment = nil if @comment.empty?
- end
-
- end
-
- def initialize
- super
-
- @in_files = []
-
- @name ||= "unknown"
- @comment ||= ""
- @parent = nil
- @visibility = :public
-
- @current_section = Section.new(nil, nil)
- @sections = [ @current_section ]
-
- initialize_methods_etc
- initialize_classes_and_modules
- end
-
- ##
- # map the class hash to an array externally
-
- def classes
- @classes.values
- end
-
- ##
- # map the module hash to an array externally
-
- def modules
- @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
-
- def ongoing_visibility=(vis)
- @visibility = vis
- end
-
- ##
- # Yields Method and Attr entries matching the list of names in +methods+.
- # Attributes are only returned when +singleton+ is false.
-
- def methods_matching(methods, singleton = false)
- count = 0
-
- @method_list.each do |m|
- if methods.include? m.name and m.singleton == singleton then
- yield m
- count += 1
- end
- end
-
- return if count == methods.size || singleton
-
- # perhaps we need to look at attributes
-
- @attributes.each do |a|
- yield a if methods.include? a.name
- end
- end
-
- ##
- # Given an array +methods+ of method names, set the visibility of the
- # corresponding AnyMethod object
-
- def set_visibility_for(methods, vis, singleton = false)
- methods_matching methods, singleton do |m|
- m.visibility = vis
- end
- end
-
- ##
- # Record the file that we happen to find it in
-
- def record_location(toplevel)
- @in_files << toplevel unless @in_files.include?(toplevel)
- end
-
- # Return true if at least part of this thing was defined in +file+
- def defined_in?(file)
- @in_files.include?(file)
- end
-
- def add_class(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)
- add_class_or_module(@modules, class_type, name, nil)
- end
-
- 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
- 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
- end
-
- def add_include(an_include)
- add_to(@includes, an_include)
- end
-
- def add_constant(const)
- add_to(@constants, const)
- end
-
- # Requires always get added to the top-level (file) context
- def add_require(a_require)
- if TopLevel === self then
- add_to @requires, a_require
- else
- parent.add_require a_require
- end
- end
-
- def add_class_or_module(collection, class_type, name, superclass=nil)
- cls = collection[name]
-
- if cls then
- cls.superclass = superclass unless cls.module?
- puts "Reusing class/module #{name}" if $DEBUG_RDOC
- else
- cls = class_type.new(name, superclass)
-# collection[name] = cls if @document_self && !@done_documenting
- collection[name] = cls if !@done_documenting
- cls.parent = self
- cls.section = @current_section
- end
- cls
- end
-
- def add_to(array, thing)
- array << thing if @document_self and not @done_documenting
- thing.parent = self
- thing.section = @current_section
- end
-
- # If a class's documentation is turned off after we've started
- # collecting methods etc., we need to remove the ones
- # we have
-
- def remove_methods_etc
- initialize_methods_etc
- end
-
- def initialize_methods_etc
- @method_list = []
- @attributes = []
- @aliases = []
- @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
- def remove_classes_and_modules
- initialize_classes_and_modules
- end
-
- def initialize_classes_and_modules
- @classes = {}
- @modules = {}
- end
-
- # Find a named module
- def find_module_named(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
-
- # find a module at a higher scope
- def find_enclosing_module_named(name)
- parent && parent.find_module_named(name)
- end
-
- # Iterate over all the classes and modules in
- # this object
-
- def each_classmodule
- @modules.each_value {|m| yield m}
- @classes.each_value {|c| yield c}
- end
-
- def each_method
- @method_list.each {|m| yield m}
- end
-
- def each_attribute
- @attributes.each {|a| yield a}
- end
-
- def each_constant
- @constants.each {|c| yield c}
- end
-
- # Return the toplevel that owns us
-
- def toplevel
- return @toplevel if defined? @toplevel
- @toplevel = self
- @toplevel = @toplevel.parent until TopLevel === @toplevel
- @toplevel
- end
-
- # allow us to sort modules by name
- def <=>(other)
- name <=> other.name
- end
-
- ##
- # Look up +symbol+. If +method+ is non-nil, then we assume the symbol
- # references a module that contains that method.
-
- def find_symbol(symbol, method = nil)
- result = nil
-
- case symbol
- when /^::(.*)/ then
- result = toplevel.find_symbol($1)
- when /::/ then
- modules = symbol.split(/::/)
-
- 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)
- break unless result
- end
- end
- end
-
- else
- # if a method is specified, then we're definitely looking for
- # a module, otherwise it could be any symbol
- if method
- result = find_module_named(symbol)
- else
- result = find_local_symbol(symbol)
- if result.nil?
- if symbol =~ /^[A-Z]/
- result = parent
- while result && result.name != symbol
- result = result.parent
- end
- end
- end
- end
- end
-
- if result and method then
- fail unless result.respond_to? :find_local_symbol
- result = result.find_local_symbol(method)
- end
-
- result
- end
-
- def find_local_symbol(symbol)
- res = find_method_named(symbol) ||
- find_constant_named(symbol) ||
- find_attribute_named(symbol) ||
- find_module_named(symbol) ||
- find_file_named(symbol)
- end
-
- # Handle sections
-
- def set_current_section(title, comment)
- @current_section = Section.new(title, comment)
- @sections << @current_section
- end
-
- private
-
- # Find a named method, or return nil
- def find_method_named(name)
- @method_list.find {|meth| meth.name == name}
- end
-
- # Find a named instance method, or return nil
- def find_instance_method_named(name)
- @method_list.find {|meth| meth.name == name && !meth.singleton}
- end
-
- # Find a named constant, or return nil
- def find_constant_named(name)
- @constants.find {|m| m.name == name}
- end
-
- # Find a named attribute, or return nil
- def find_attribute_named(name)
- @attributes.find {|m| m.name == name}
- end
-
- ##
- # Find a named file, or return nil
-
- def find_file_named(name)
- toplevel.class.find_file_named(name)
- end
-
- end
-
- ##
- # A TopLevel context is a source file
-
- class TopLevel < Context
- attr_accessor :file_stat
- attr_accessor :file_relative_name
- attr_accessor :file_absolute_name
- attr_accessor :diagram
-
- @@all_classes = {}
- @@all_modules = {}
- @@all_files = {}
-
- def self.reset
- @@all_classes = {}
- @@all_modules = {}
- @@all_files = {}
- end
-
- def initialize(file_name)
- super()
- @name = "TopLevel"
- @file_relative_name = file_name
- @file_absolute_name = file_name
- @file_stat = File.stat(file_name)
- @diagram = nil
- @@all_files[file_name] = self
- end
-
- def file_base_name
- File.basename @file_absolute_name
- end
-
- def full_name
- nil
- end
-
- ##
- # Adding a class or module to a TopLevel is special, as we only want one
- # copy of a particular top-level class. For example, if both file A and
- # file B implement class C, we only want one ClassModule object for C.
- # This code arranges to share classes and modules between files.
-
- def add_class_or_module(collection, class_type, name, superclass)
- cls = collection[name]
-
- if cls then
- cls.superclass = superclass unless cls.module?
- puts "Reusing class/module #{cls.full_name}" if $DEBUG_RDOC
- else
- if class_type == NormalModule then
- all = @@all_modules
- else
- all = @@all_classes
- end
-
- cls = all[name]
-
- 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
-
- cls.parent = self
- end
-
- cls
- end
-
- def self.all_classes_and_modules
- @@all_classes.values + @@all_modules.values
- end
-
- def self.find_class_named(name)
- @@all_classes.each_value do |c|
- res = c.find_class_named(name)
- return res if res
- end
- nil
- end
-
- def self.find_file_named(name)
- @@all_files[name]
- end
-
- def find_local_symbol(symbol)
- find_class_or_module_named(symbol) || super
- end
-
- def find_class_or_module_named(symbol)
- @@all_classes.each_value {|c| return c if c.name == symbol}
- @@all_modules.each_value {|m| return m if m.name == symbol}
- nil
- end
-
- ##
- # Find a named module
-
- def find_module_named(name)
- find_class_or_module_named(name) || find_enclosing_module_named(name)
- end
-
- def inspect
- "#<%s:0x%x %p modules: %p classes: %p>" % [
- self.class, object_id,
- file_base_name,
- @modules.map { |n,m| m },
- @classes.map { |n,c| c }
- ]
- end
-
- end
-
- ##
- # ClassModule is the base class for objects representing either a class or a
- # module.
-
- class ClassModule < Context
-
- attr_accessor :diagram
-
- def initialize(name, superclass = nil)
- @name = name
- @diagram = nil
- @superclass = superclass
- @comment = ""
- super()
- end
-
- def find_class_named(name)
- return self if full_name == name
- @classes.each_value {|c| return c if c.find_class_named(name) }
- nil
- end
-
- ##
- # Return the fully qualified name of this class or module
-
- def full_name
- if @parent && @parent.full_name
- @parent.full_name + "::" + @name
- else
- @name
- end
- end
-
- def http_url(prefix)
- path = full_name.split("::")
- File.join(prefix, *path) + ".html"
- end
-
- ##
- # Does this object represent a module?
-
- def module?
- false
- end
-
- ##
- # Get the superclass of this class. Attempts to retrieve the superclass'
- # real name by following module nesting.
-
- def superclass
- raise NoMethodError, "#{full_name} is a module" if module?
-
- scope = self
-
- begin
- superclass = scope.classes.find { |c| c.name == @superclass }
-
- return superclass.full_name if superclass
- scope = scope.parent
- end until scope.nil? or TopLevel === scope
-
- @superclass
- end
-
- ##
- # Set the superclass of this class
-
- def superclass=(superclass)
- raise NoMethodError, "#{full_name} is a module" if module?
-
- if @superclass.nil? or @superclass == 'Object' then
- @superclass = superclass
- end
- end
-
- def to_s
- "#{self.class}: #{@name} #{@comment} #{super}"
- end
-
- end
-
- ##
- # Anonymous classes
-
- class AnonClass < ClassModule
- end
-
- ##
- # Normal classes
-
- class NormalClass < ClassModule
-
- def inspect
- superclass = @superclass ? " < #{@superclass}" : nil
- "<%s:0x%x class %s%s includes: %p attributes: %p methods: %p aliases: %p>" % [
- self.class, object_id,
- @name, superclass, @includes, @attributes, @method_list, @aliases
- ]
- end
-
- end
-
- ##
- # Singleton classes
-
- class SingleClass < ClassModule
- end
-
- ##
- # Module
-
- class NormalModule < ClassModule
-
- def comment=(comment)
- return if comment.empty?
- comment = @comment << "# ---\n" << comment unless @comment.empty?
-
- super
- end
-
- def inspect
- "#<%s:0x%x module %s includes: %p attributes: %p methods: %p aliases: %p>" % [
- self.class, object_id,
- @name, @includes, @attributes, @method_list, @aliases
- ]
- end
-
- def module?
- true
- end
-
- end
-
- ##
- # AnyMethod is the base class for objects representing methods
-
- class AnyMethod < CodeObject
-
- attr_accessor :name
- attr_accessor :visibility
- attr_accessor :block_params
- attr_accessor :dont_rename_initialize
- attr_accessor :singleton
- attr_reader :text
-
- # list of other names for this method
- attr_reader :aliases
-
- # method we're aliasing
- attr_accessor :is_alias_for
-
- attr_overridable :params, :param, :parameters, :parameter
-
- attr_accessor :call_seq
-
- include TokenStream
-
- def initialize(text, name)
- super()
- @text = text
- @name = name
- @token_stream = nil
- @visibility = :public
- @dont_rename_initialize = false
- @block_params = nil
- @aliases = []
- @is_alias_for = nil
- @comment = ""
- @call_seq = nil
- end
-
- def <=>(other)
- @name <=> other.name
- end
-
- def add_alias(method)
- @aliases << method
- end
-
- def inspect
- alias_for = @is_alias_for ? " (alias for #{@is_alias_for.name})" : nil
- "#<%s:0x%x %s%s%s (%s)%s>" % [
- self.class, object_id,
- parent_name,
- singleton ? '::' : '#',
- name,
- visibility,
- alias_for,
- ]
- end
-
- def param_seq
- params = params.gsub(/\s*\#.*/, '')
- params = params.tr("\n", " ").squeeze(" ")
- params = "(#{params})" unless p[0] == ?(
-
- if block = block_params then # yes, =
- # If this method has explicit block parameters, remove any explicit
- # &block
- params.sub!(/,?\s*&\w+/)
-
- block.gsub!(/\s*\#.*/, '')
- block = block.tr("\n", " ").squeeze(" ")
- if block[0] == ?(
- block.sub!(/^\(/, '').sub!(/\)/, '')
- end
- params << " { |#{block}| ... }"
- end
-
- params
- end
-
- def to_s
- res = self.class.name + ": " + @name + " (" + @text + ")\n"
- res << @comment.to_s
- res
- end
-
- end
-
- ##
- # GhostMethod represents a method referenced only by a comment
-
- class GhostMethod < AnyMethod
- end
-
- ##
- # MetaMethod represents a meta-programmed method
-
- class MetaMethod < AnyMethod
- end
-
- ##
- # Represent an alias, which is an old_name/ new_name pair associated with a
- # particular context
-
- class Alias < CodeObject
-
- attr_accessor :text, :old_name, :new_name, :comment
-
- def initialize(text, old_name, new_name, comment)
- super()
- @text = text
- @old_name = old_name
- @new_name = new_name
- self.comment = comment
- end
-
- def inspect
- "#<%s:0x%x %s.alias_method %s, %s>" % [
- self.class, object_id,
- parent.name, @old_name, @new_name,
- ]
- end
-
- def to_s
- "alias: #{self.old_name} -> #{self.new_name}\n#{self.comment}"
- end
-
- end
-
- ##
- # Represent a constant
-
- class Constant < CodeObject
- attr_accessor :name, :value
-
- def initialize(name, value, comment)
- super()
- @name = name
- @value = value
- self.comment = comment
- end
- end
-
- ##
- # Represent attributes
-
- class Attr < CodeObject
- attr_accessor :text, :name, :rw, :visibility
-
- def initialize(text, name, rw, comment)
- super()
- @text = text
- @name = name
- @rw = rw
- @visibility = :public
- self.comment = comment
- end
-
- def <=>(other)
- self.name <=> other.name
- end
-
- def inspect
- attr = case rw
- when 'RW' then :attr_accessor
- when 'R' then :attr_reader
- when 'W' then :attr_writer
- else
- " (#{rw})"
- end
-
- "#<%s:0x%x %s.%s :%s>" % [
- self.class, object_id,
- parent_name, attr, @name,
- ]
- end
-
- def to_s
- "attr: #{self.name} #{self.rw}\n#{self.comment}"
- end
-
- end
-
- ##
- # A required file
-
- class Require < CodeObject
- attr_accessor :name
-
- def initialize(name, comment)
- super()
- @name = name.gsub(/'|"/, "") #'
- self.comment = comment
- end
-
- def inspect
- "#<%s:0x%x require '%s' in %s>" % [
- self.class,
- object_id,
- @name,
- parent_file_name,
- ]
- end
-
- end
-
- ##
- # An included module
-
- class Include < CodeObject
-
- attr_accessor :name
-
- def initialize(name, comment)
- super()
- @name = name
- self.comment = comment
-
- end
-
- def inspect
- "#<%s:0x%x %s.include %s>" % [
- self.class,
- object_id,
- parent_name, @name,
- ]
- end
-
- end
-
-end
diff --git a/lib/rdoc/constant.rb b/lib/rdoc/constant.rb
new file mode 100644
index 0000000..9089908
--- /dev/null
+++ b/lib/rdoc/constant.rb
@@ -0,0 +1,58 @@
+require 'rdoc/code_object'
+
+##
+# A constant
+
+class RDoc::Constant < RDoc::CodeObject
+
+ ##
+ # The constant's name
+
+ attr_accessor :name
+
+ ##
+ # The constant's value
+
+ attr_accessor :value
+
+ ##
+ # Creates a new constant with +name+, +value+ and +comment+
+
+ def initialize(name, value, comment)
+ super()
+ @name = name
+ @value = value
+ self.comment = comment
+ end
+
+ ##
+ # Constants are ordered by name
+
+ def <=> other
+ return unless self.class === other
+
+ [parent_name, name] <=> [other.parent_name, other.name]
+ end
+
+ def == other
+ self.class == other.class and
+ @parent == other.parent and
+ @name == other.name
+ end
+
+ def inspect # :nodoc:
+ "#<%s:0x%x %s::%s>" % [
+ self.class, object_id,
+ parent_name, @name,
+ ]
+ end
+
+ ##
+ # Path to this constant
+
+ def path
+ "#{@parent.path}##{@name}"
+ end
+
+end
+
diff --git a/lib/rdoc/context.rb b/lib/rdoc/context.rb
new file mode 100644
index 0000000..4cf0c19
--- /dev/null
+++ b/lib/rdoc/context.rb
@@ -0,0 +1,755 @@
+require 'rdoc/code_object'
+
+##
+# A Context is something that can hold modules, classes, methods, attributes,
+# aliases, requires, and includes. Classes, modules, and files are all
+# Contexts.
+
+class RDoc::Context < RDoc::CodeObject
+
+ include Comparable
+
+ ##
+ # Types of methods
+
+ TYPES = %w[class instance]
+
+ ##
+ # Method visibilities
+
+ VISIBILITIES = [:public, :protected, :private]
+
+ ##
+ # Aliased methods
+
+ attr_reader :aliases
+
+ ##
+ # attr* methods
+
+ attr_reader :attributes
+
+ ##
+ # Constants defined
+
+ attr_reader :constants
+
+ ##
+ # Current section of documentation
+
+ attr_reader :current_section
+
+ ##
+ # Files this context is found in
+
+ attr_reader :in_files
+
+ ##
+ # Modules this context includes
+
+ attr_reader :includes
+
+ ##
+ # Methods defined in this context
+
+ attr_reader :method_list
+
+ ##
+ # Name of this class excluding namespace. See also full_name
+
+ attr_reader :name
+
+ ##
+ # Files this context requires
+
+ attr_reader :requires
+
+ ##
+ # Sections in this context
+
+ attr_reader :sections
+
+ ##
+ # Aliases that haven't been resolved to a method
+
+ attr_accessor :unmatched_alias_lists
+
+ ##
+ # Current visibility of this context
+
+ attr_reader :visibility
+
+ ##
+ # A per-comment section of documentation like:
+ #
+ # # :SECTION: The title
+ # # The body
+
+ class Section
+
+ ##
+ # Section comment
+
+ attr_reader :comment
+
+ ##
+ # Context this Section lives in
+
+ attr_reader :parent
+
+ ##
+ # Section sequence number (for linking)
+
+ attr_reader :sequence
+
+ ##
+ # Section title
+
+ attr_reader :title
+
+ @@sequence = "SEC00000"
+
+ ##
+ # Creates a new section with +title+ and +comment+
+
+ def initialize(parent, title, comment)
+ @parent = parent
+ @title = title
+
+ @@sequence.succ!
+ @sequence = @@sequence.dup
+
+ set_comment comment
+ end
+
+ ##
+ # Sections are equal when they have the same #sequence
+
+ def ==(other)
+ self.class === other and @sequence == other.sequence
+ end
+
+ def inspect # :nodoc:
+ "#<%s:0x%x %s %p>" % [
+ self.class, object_id,
+ @sequence, title
+ ]
+ end
+
+ ##
+ # Set the comment for this section from the original comment block If
+ # the first line contains :section:, strip it and use the rest.
+ # Otherwise remove lines up to the line containing :section:, and look
+ # for those lines again at the end and remove them. This lets us write
+ #
+ # # blah blah blah
+ # #
+ # # :SECTION: The title
+ # # The body
+
+ def set_comment(comment)
+ return unless comment
+
+ if comment =~ /^#[ \t]*:section:.*\n/ then
+ start = $`
+ rest = $'
+
+ if start.empty?
+ @comment = rest
+ else
+ @comment = rest.sub(/#{start.chomp}\Z/, '')
+ end
+ else
+ @comment = comment
+ end
+
+ @comment = nil if @comment.empty?
+ end
+
+ end
+
+ ##
+ # Creates an unnamed empty context with public visibility
+
+ def initialize
+ super
+
+ @in_files = []
+
+ @name ||= "unknown"
+ @comment ||= ""
+ @parent = nil
+ @visibility = :public
+
+ @current_section = Section.new self, nil, nil
+ @sections = [@current_section]
+
+ initialize_methods_etc
+ initialize_classes_and_modules
+ end
+
+ ##
+ # Sets the defaults for classes and modules
+
+ def initialize_classes_and_modules
+ @classes = {}
+ @modules = {}
+ end
+
+ ##
+ # Sets the defaults for methods and so-forth
+
+ def initialize_methods_etc
+ @method_list = []
+ @attributes = []
+ @aliases = []
+ @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
+
+ ##
+ # Contexts are sorted by full_name
+
+ def <=>(other)
+ full_name <=> other.full_name
+ end
+
+ ##
+ # Adds +an_alias+ that is automatically resolved
+
+ def add_alias(an_alias)
+ meth = find_instance_method_named(an_alias.old_name)
+
+ if meth then
+ 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
+ end
+
+ ##
+ # Turns +an_alias+ into an AnyMethod that points to +meth+
+
+ def add_alias_impl(an_alias, meth)
+ new_meth = RDoc::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 = an_alias.comment
+
+ meth.add_alias new_meth
+
+ add_method new_meth
+
+ # aliases don't use ongoing visibility
+ new_meth.visibility = meth.visibility
+
+ new_meth
+ end
+
+ ##
+ # Adds +attribute+
+
+ def add_attribute(attribute)
+ add_to @attributes, attribute
+ end
+
+ ##
+ # Adds a class named +name+ with +superclass+.
+ #
+ # Given <tt>class Container::Item</tt> RDoc assumes +Container+ is a module
+ # unless it later sees <tt>class Container</tt>. add_class automatically
+ # upgrades +name+ to a class in this case.
+
+ def add_class(class_type, name, superclass = 'Object')
+ klass = add_class_or_module @classes, class_type, name, superclass
+
+ existing = klass.superclass
+ existing = existing.name if existing and not String === existing
+
+ if superclass != existing and superclass != 'Object' then
+ klass.superclass = superclass
+ end
+
+ # 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 = RDoc::TopLevel.modules_hash.delete klass.full_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
+
+ @modules.delete klass.name
+ end
+
+ RDoc::TopLevel.classes_hash[klass.full_name] = klass
+
+ klass
+ end
+
+ ##
+ # Instantiates a +class_type+ named +name+ and adds it the modules or
+ # classes Hash +collection+.
+
+ def add_class_or_module(collection, class_type, name, superclass = nil)
+ full_name = child_name name
+
+ mod = collection[name]
+
+ if mod then
+ mod.superclass = superclass unless mod.module?
+ else
+ all = if class_type == RDoc::NormalModule then
+ RDoc::TopLevel.modules_hash
+ else
+ RDoc::TopLevel.classes_hash
+ end
+
+ mod = all[full_name]
+
+ unless mod then
+ mod = class_type.new name, superclass
+ 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 == RDoc::NormalClass then
+ mod.superclass = superclass unless mod.superclass
+ end
+ end
+
+ unless @done_documenting then
+ all[full_name] = mod
+ collection[name] = mod
+ end
+
+ mod.section = @current_section
+ mod.parent = self
+ end
+
+ mod
+ end
+
+ ##
+ # Adds +constant+
+
+ def add_constant(constant)
+ add_to @constants, constant
+ end
+
+ ##
+ # Adds included module +include+
+
+ def add_include(include)
+ add_to @includes, include
+ end
+
+ ##
+ # Adds +method+
+
+ def add_method(method)
+ method.visibility = @visibility
+ add_to @method_list, method
+
+ unmatched_alias_list = @unmatched_alias_lists[method.name]
+ if unmatched_alias_list then
+ unmatched_alias_list.each do |unmatched_alias|
+ add_alias_impl unmatched_alias, method
+ @aliases.delete unmatched_alias
+ end
+
+ @unmatched_alias_lists.delete method.name
+ end
+ end
+
+ ##
+ # Adds a module named +name+. If RDoc already knows +name+ is a class then
+ # that class is returned instead. See also #add_class
+
+ def add_module(class_type, name)
+ return @classes[name] if @classes.key? name
+
+ add_class_or_module @modules, class_type, name, nil
+ end
+
+ ##
+ # Adds an alias from +from+ to +name+
+
+ def add_module_alias from, name
+ to_name = child_name name
+
+ unless @done_documenting then
+ if from.module? then
+ RDoc::TopLevel.modules_hash
+ else
+ RDoc::TopLevel.classes_hash
+ end[to_name] = from
+
+ if from.module? then
+ @modules
+ else
+ @classes
+ end[name] = from
+ end
+
+ from
+ end
+
+ ##
+ # Adds +require+ to this context's top level
+
+ def add_require(require)
+ if RDoc::TopLevel === self then
+ add_to @requires, require
+ else
+ parent.add_require require
+ end
+ end
+
+ ##
+ # Adds +thing+ to the collection +array+
+
+ def add_to(array, thing)
+ array << thing if @document_self and not @done_documenting
+ thing.parent = self
+ thing.section = @current_section
+ end
+
+ ##
+ # Creates the full name for a child with +name+
+
+ def child_name name
+ if RDoc::TopLevel === self then
+ name
+ else
+ "#{self.full_name}::#{name}"
+ end
+ end
+
+ ##
+ # Array of classes in this context
+
+ def classes
+ @classes.values
+ end
+
+ ##
+ # All classes and modules in this namespace
+
+ def classes_and_modules
+ classes + modules
+ end
+
+ ##
+ # Hash of classes keyed by class name
+
+ def classes_hash
+ @classes
+ end
+
+ ##
+ # Is part of this thing was defined in +file+?
+
+ def defined_in?(file)
+ @in_files.include?(file)
+ end
+
+ ##
+ # Iterator for attributes
+
+ def each_attribute # :yields: attribute
+ @attributes.each { |a| yield a }
+ end
+
+ ##
+ # Iterator for classes and modules
+
+ def each_classmodule(&block) # :yields: module
+ classes_and_modules.sort.each(&block)
+ end
+
+ ##
+ # Iterator for constants
+
+ def each_constant # :yields: constant
+ @constants.each {|c| yield c}
+ end
+
+ ##
+ # Iterator for included modules
+
+ def each_include # :yields: include
+ @includes.each do |i| yield i end
+ end
+
+ ##
+ # Iterator for methods
+
+ def each_method # :yields: method
+ @method_list.sort.each {|m| yield m}
+ end
+
+ ##
+ # Finds an attribute with +name+ in this context
+
+ def find_attribute_named(name)
+ @attributes.find { |m| m.name == name }
+ end
+
+ ##
+ # Finds a constant with +name+ in this context
+
+ def find_constant_named(name)
+ @constants.find {|m| m.name == name}
+ end
+
+ ##
+ # Find a module at a higher scope
+
+ def find_enclosing_module_named(name)
+ parent && parent.find_module_named(name)
+ end
+
+ ##
+ # Finds a file with +name+ in this context
+
+ def find_file_named(name)
+ top_level.class.find_file_named(name)
+ end
+
+ ##
+ # Finds an instance method with +name+ in this context
+
+ def find_instance_method_named(name)
+ @method_list.find { |meth| meth.name == name && !meth.singleton }
+ end
+
+ ##
+ # Finds a method, constant, attribute, module or files named +symbol+ in
+ # this context
+
+ def find_local_symbol(symbol)
+ find_method_named(symbol) or
+ find_constant_named(symbol) or
+ find_attribute_named(symbol) or
+ find_module_named(symbol) or
+ find_file_named(symbol)
+ end
+
+ ##
+ # Finds a instance or module method with +name+ in this context
+
+ def find_method_named(name)
+ @method_list.find { |meth| meth.name == name }
+ end
+
+ ##
+ # Find a module with +name+ using ruby's scoping rules
+
+ def find_module_named(name)
+ res = @modules[name] || @classes[name]
+ return res if res
+ return self if self.name == name
+ find_enclosing_module_named name
+ end
+
+ ##
+ # Look up +symbol+. If +method+ is non-nil, then we assume the symbol
+ # references a module that contains that method.
+
+ def find_symbol(symbol, method = nil)
+ result = nil
+
+ case symbol
+ when /^::(.*)/ then
+ result = top_level.find_symbol($1)
+ when /::/ then
+ modules = symbol.split(/::/)
+
+ 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
+ break unless result
+ end
+ end
+ end
+
+ else
+ # if a method is specified, then we're definitely looking for
+ # a module, otherwise it could be any symbol
+ if method then
+ result = find_module_named symbol
+ else
+ result = find_local_symbol symbol
+ if result.nil? then
+ if symbol =~ /^[A-Z]/ then
+ result = parent
+ while result && result.name != symbol do
+ result = result.parent
+ end
+ end
+ end
+ end
+ end
+
+ if result and method then
+ fail unless result.respond_to? :find_local_symbol
+ result = result.find_local_symbol(method)
+ end
+
+ result
+ end
+
+ ##
+ # The full name for this context. This method is overridden by subclasses.
+
+ def full_name
+ '(unknown)'
+ end
+
+ ##
+ # URL for this with a +prefix+
+
+ def http_url(prefix)
+ path = full_name
+ path = path.gsub(/<<\s*(\w*)/, 'from-\1') if path =~ /<</
+ path = [prefix] + path.split('::')
+
+ File.join(*path.compact) + '.html'
+ end
+
+ ##
+ # Breaks method_list into a nested hash by type (class or instance) and
+ # visibility (public, protected private)
+
+ def methods_by_type
+ methods = {}
+
+ TYPES.each do |type|
+ visibilities = {}
+ VISIBILITIES.each do |vis|
+ visibilities[vis] = []
+ end
+
+ methods[type] = visibilities
+ end
+
+ each_method do |method|
+ methods[method.type][method.visibility] << method
+ end
+
+ methods
+ end
+
+ ##
+ # Yields Method and Attr entries matching the list of names in +methods+.
+ # Attributes are only returned when +singleton+ is false.
+
+ def methods_matching(methods, singleton = false)
+ count = 0
+
+ @method_list.each do |m|
+ if methods.include? m.name and m.singleton == singleton then
+ yield m
+ count += 1
+ end
+ end
+
+ return if count == methods.size || singleton
+
+ @attributes.each do |a|
+ yield a if methods.include? a.name
+ end
+ end
+
+ ##
+ # Array of modules in this context
+
+ def modules
+ @modules.values
+ end
+
+ ##
+ # Hash of modules keyed by module name
+
+ def modules_hash
+ @modules
+ end
+
+ ##
+ # Changes the visibility for new methods to +visibility+
+
+ def ongoing_visibility=(visibility)
+ @visibility = visibility
+ end
+
+ ##
+ # Record which file +top_level+ is in
+
+ def record_location(top_level)
+ @in_files << top_level unless @in_files.include?(top_level)
+ end
+
+ ##
+ # If a class's documentation is turned off after we've started collecting
+ # methods etc., we need to remove the ones we have
+
+ def remove_methods_etc
+ initialize_methods_etc
+ end
+
+ ##
+ # Given an array +methods+ of method names, set the visibility of each to
+ # +visibility+
+
+ def set_visibility_for(methods, visibility, singleton = false)
+ methods_matching methods, singleton do |m|
+ m.visibility = visibility
+ end
+ end
+
+ ##
+ # Removes classes and modules when we see a :nodoc: all
+
+ def remove_classes_and_modules
+ initialize_classes_and_modules
+ end
+
+ ##
+ # Creates a new section with +title+ and +comment+
+
+ def set_current_section(title, comment)
+ @current_section = Section.new self, title, comment
+ @sections << @current_section
+ end
+
+ ##
+ # Return the TopLevel that owns us
+
+ def top_level
+ return @top_level if defined? @top_level
+ @top_level = self
+ @top_level = @top_level.parent until RDoc::TopLevel === @top_level
+ @top_level
+ end
+
+end
+
diff --git a/lib/rdoc/diagram.rb b/lib/rdoc/diagram.rb
deleted file mode 100644
index d308d36..0000000
--- a/lib/rdoc/diagram.rb
+++ /dev/null
@@ -1,340 +0,0 @@
-# A wonderful hack by to draw package diagrams using the dot package.
-# Originally written by Jah, team Enticla.
-#
-# You must have the V1.7 or later in your path
-# http://www.research.att.com/sw/tools/graphviz/
-
-require 'rdoc/dot'
-
-module RDoc
-
- ##
- # Draw a set of diagrams representing the modules and classes in the
- # system. We draw one diagram for each file, and one for each toplevel
- # class or module. This means there will be overlap. However, it also
- # means that you'll get better context for objects.
- #
- # To use, simply
- #
- # d = Diagram.new(info) # pass in collection of top level infos
- # d.draw
- #
- # The results will be written to the +dot+ subdirectory. The process
- # also sets the +diagram+ attribute in each object it graphs to
- # the name of the file containing the image. This can be used
- # by output generators to insert images.
-
- class Diagram
-
- FONT = "Arial"
-
- DOT_PATH = "dot"
-
- ##
- # Pass in the set of top level objects. The method also creates the
- # subdirectory to hold the images
-
- def initialize(info, options)
- @info = info
- @options = options
- @counter = 0
- FileUtils.mkdir_p(DOT_PATH)
- @diagram_cache = {}
- end
-
- ##
- # Draw the diagrams. We traverse the files, drawing a diagram for each. We
- # also traverse each top-level class and module in that file drawing a
- # diagram for these too.
-
- def draw
- unless @options.quiet
- $stderr.print "Diagrams: "
- $stderr.flush
- end
-
- @info.each_with_index do |i, file_count|
- @done_modules = {}
- @local_names = find_names(i)
- @global_names = []
- @global_graph = graph = DOT::Digraph.new('name' => 'TopLevel',
- 'fontname' => FONT,
- 'fontsize' => '8',
- 'bgcolor' => 'lightcyan1',
- 'compound' => 'true')
-
- # it's a little hack %) i'm too lazy to create a separate class
- # for default node
- graph << DOT::Node.new('name' => 'node',
- 'fontname' => FONT,
- 'color' => 'black',
- 'fontsize' => 8)
-
- i.modules.each do |mod|
- draw_module(mod, graph, true, i.file_relative_name)
- end
- add_classes(i, graph, i.file_relative_name)
-
- i.diagram = convert_to_png("f_#{file_count}", graph)
-
- # now go through and document each top level class and
- # module independently
- i.modules.each_with_index do |mod, count|
- @done_modules = {}
- @local_names = find_names(mod)
- @global_names = []
-
- @global_graph = graph = DOT::Digraph.new('name' => 'TopLevel',
- 'fontname' => FONT,
- 'fontsize' => '8',
- 'bgcolor' => 'lightcyan1',
- 'compound' => 'true')
-
- graph << DOT::Node.new('name' => 'node',
- 'fontname' => FONT,
- 'color' => 'black',
- 'fontsize' => 8)
- draw_module(mod, graph, true)
- mod.diagram = convert_to_png("m_#{file_count}_#{count}",
- graph)
- end
- end
- $stderr.puts unless @options.quiet
- end
-
- private
-
- def find_names(mod)
- return [mod.full_name] + mod.classes.collect{|cl| cl.full_name} +
- mod.modules.collect{|m| find_names(m)}.flatten
- end
-
- def find_full_name(name, mod)
- full_name = name.dup
- return full_name if @local_names.include?(full_name)
- mod_path = mod.full_name.split('::')[0..-2]
- unless mod_path.nil?
- until mod_path.empty?
- full_name = mod_path.pop + '::' + full_name
- return full_name if @local_names.include?(full_name)
- end
- end
- return name
- end
-
- def draw_module(mod, graph, toplevel = false, file = nil)
- return if @done_modules[mod.full_name] and not toplevel
-
- @counter += 1
- url = mod.http_url("classes")
- m = DOT::Subgraph.new('name' => "cluster_#{mod.full_name.gsub( /:/,'_' )}",
- 'label' => mod.name,
- 'fontname' => FONT,
- 'color' => 'blue',
- 'style' => 'filled',
- 'URL' => %{"#{url}"},
- 'fillcolor' => toplevel ? 'palegreen1' : 'palegreen3')
-
- @done_modules[mod.full_name] = m
- add_classes(mod, m, file)
- graph << m
-
- unless mod.includes.empty?
- mod.includes.each do |inc|
- m_full_name = find_full_name(inc.name, mod)
- if @local_names.include?(m_full_name)
- @global_graph << DOT::Edge.new('from' => "#{m_full_name.gsub( /:/,'_' )}",
- 'to' => "#{mod.full_name.gsub( /:/,'_' )}",
- 'ltail' => "cluster_#{m_full_name.gsub( /:/,'_' )}",
- 'lhead' => "cluster_#{mod.full_name.gsub( /:/,'_' )}")
- else
- unless @global_names.include?(m_full_name)
- path = m_full_name.split("::")
- url = File.join('classes', *path) + ".html"
- @global_graph << DOT::Node.new('name' => "#{m_full_name.gsub( /:/,'_' )}",
- 'shape' => 'box',
- 'label' => "#{m_full_name}",
- 'URL' => %{"#{url}"})
- @global_names << m_full_name
- end
- @global_graph << DOT::Edge.new('from' => "#{m_full_name.gsub( /:/,'_' )}",
- 'to' => "#{mod.full_name.gsub( /:/,'_' )}",
- 'lhead' => "cluster_#{mod.full_name.gsub( /:/,'_' )}")
- end
- end
- end
- end
-
- def add_classes(container, graph, file = nil )
-
- use_fileboxes = @options.fileboxes
-
- files = {}
-
- # create dummy node (needed if empty and for module includes)
- if container.full_name
- graph << DOT::Node.new('name' => "#{container.full_name.gsub( /:/,'_' )}",
- 'label' => "",
- 'width' => (container.classes.empty? and
- container.modules.empty?) ?
- '0.75' : '0.01',
- 'height' => '0.01',
- 'shape' => 'plaintext')
- end
-
- container.classes.each_with_index do |cl, cl_index|
- last_file = cl.in_files[-1].file_relative_name
-
- if use_fileboxes && !files.include?(last_file)
- @counter += 1
- files[last_file] =
- DOT::Subgraph.new('name' => "cluster_#{@counter}",
- 'label' => "#{last_file}",
- 'fontname' => FONT,
- 'color'=>
- last_file == file ? 'red' : 'black')
- end
-
- next if cl.name == 'Object' || cl.name[0,2] == "<<"
-
- url = cl.http_url("classes")
-
- label = cl.name.dup
- if use_fileboxes && cl.in_files.length > 1
- label << '\n[' +
- cl.in_files.collect {|i|
- i.file_relative_name
- }.sort.join( '\n' ) +
- ']'
- end
-
- attrs = {
- 'name' => "#{cl.full_name.gsub( /:/, '_' )}",
- 'fontcolor' => 'black',
- 'style'=>'filled',
- 'color'=>'palegoldenrod',
- 'label' => label,
- 'shape' => 'ellipse',
- 'URL' => %{"#{url}"}
- }
-
- c = DOT::Node.new(attrs)
-
- if use_fileboxes
- files[last_file].push c
- else
- graph << c
- end
- end
-
- if use_fileboxes
- files.each_value do |val|
- graph << val
- end
- end
-
- unless container.classes.empty?
- container.classes.each_with_index do |cl, cl_index|
- cl.includes.each do |m|
- m_full_name = find_full_name(m.name, cl)
- if @local_names.include?(m_full_name)
- @global_graph << DOT::Edge.new('from' => "#{m_full_name.gsub( /:/,'_' )}",
- 'to' => "#{cl.full_name.gsub( /:/,'_' )}",
- 'ltail' => "cluster_#{m_full_name.gsub( /:/,'_' )}")
- else
- unless @global_names.include?(m_full_name)
- path = m_full_name.split("::")
- url = File.join('classes', *path) + ".html"
- @global_graph << DOT::Node.new('name' => "#{m_full_name.gsub( /:/,'_' )}",
- 'shape' => 'box',
- 'label' => "#{m_full_name}",
- 'URL' => %{"#{url}"})
- @global_names << m_full_name
- end
- @global_graph << DOT::Edge.new('from' => "#{m_full_name.gsub( /:/,'_' )}",
- 'to' => "#{cl.full_name.gsub( /:/, '_')}")
- end
- end
-
- sclass = cl.superclass
- next if sclass.nil? || sclass == 'Object'
- sclass_full_name = find_full_name(sclass,cl)
- unless @local_names.include?(sclass_full_name) or @global_names.include?(sclass_full_name)
- path = sclass_full_name.split("::")
- url = File.join('classes', *path) + ".html"
- @global_graph << DOT::Node.new('name' => "#{sclass_full_name.gsub( /:/, '_' )}",
- 'label' => sclass_full_name,
- 'URL' => %{"#{url}"})
- @global_names << sclass_full_name
- end
- @global_graph << DOT::Edge.new('from' => "#{sclass_full_name.gsub( /:/,'_' )}",
- 'to' => "#{cl.full_name.gsub( /:/, '_')}")
- end
- end
-
- container.modules.each do |submod|
- draw_module(submod, graph)
- end
-
- end
-
- def convert_to_png(file_base, graph)
- str = graph.to_s
- return @diagram_cache[str] if @diagram_cache[str]
- op_type = @options.image_format
- dotfile = File.join(DOT_PATH, file_base)
- src = dotfile + ".dot"
- dot = dotfile + "." + op_type
-
- unless @options.quiet
- $stderr.print "."
- $stderr.flush
- end
-
- File.open(src, 'w+' ) do |f|
- f << str << "\n"
- end
-
- system "dot", "-T#{op_type}", src, "-o", dot
-
- # Now construct the imagemap wrapper around
- # that png
-
- ret = wrap_in_image_map(src, dot)
- @diagram_cache[str] = ret
- return ret
- end
-
- ##
- # Extract the client-side image map from dot, and use it to generate the
- # imagemap proper. Return the whole <map>..<img> combination, suitable for
- # inclusion on the page
-
- def wrap_in_image_map(src, dot)
- res = ""
- dot_map = `dot -Tismap #{src}`
-
- 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
- res << "</map>\n"
- end
-
- res << %{<img src="#{dot}" usemap="#map" alt="#{dot}" />}
- return res
- end
-
- end
-
-end
diff --git a/lib/rdoc/dot.rb b/lib/rdoc/dot.rb
deleted file mode 100644
index fbd2cfb..0000000
--- a/lib/rdoc/dot.rb
+++ /dev/null
@@ -1,249 +0,0 @@
-module RDoc; end
-
-module RDoc::DOT
-
- TAB = ' '
- TAB2 = TAB * 2
-
- # options for node declaration
- NODE_OPTS = [
- 'bgcolor',
- 'color',
- 'fontcolor',
- 'fontname',
- 'fontsize',
- 'height',
- 'width',
- 'label',
- 'layer',
- 'rank',
- 'shape',
- 'shapefile',
- 'style',
- 'URL',
- ]
-
- # options for edge declaration
- EDGE_OPTS = [
- 'color',
- 'decorate',
- 'dir',
- 'fontcolor',
- 'fontname',
- 'fontsize',
- 'id',
- 'label',
- 'layer',
- 'lhead',
- 'ltail',
- 'minlen',
- 'style',
- 'weight'
- ]
-
- # options for graph declaration
- GRAPH_OPTS = [
- 'bgcolor',
- 'center',
- 'clusterrank',
- 'color',
- 'compound',
- 'concentrate',
- 'fillcolor',
- 'fontcolor',
- 'fontname',
- 'fontsize',
- 'label',
- 'layerseq',
- 'margin',
- 'mclimit',
- 'nodesep',
- 'nslimit',
- 'ordering',
- 'orientation',
- 'page',
- 'rank',
- 'rankdir',
- 'ranksep',
- 'ratio',
- 'size',
- 'style',
- 'URL'
- ]
-
- # a root class for any element in dot notation
- class SimpleElement
- attr_accessor :name
-
- def initialize( params = {} )
- @label = params['name'] ? params['name'] : ''
- end
-
- def to_s
- @name
- end
- end
-
- # an element that has options ( node, edge or graph )
- class Element < SimpleElement
- #attr_reader :parent
- attr_accessor :name, :options
-
- def initialize( params = {}, option_list = [] )
- super( params )
- @name = params['name'] ? params['name'] : nil
- @parent = params['parent'] ? params['parent'] : nil
- @options = {}
- option_list.each{ |i|
- @options[i] = params[i] if params[i]
- }
- @options['label'] ||= @name if @name != 'node'
- end
-
- def each_option
- @options.each{ |i| yield i }
- end
-
- def each_option_pair
- @options.each_pair{ |key, val| yield key, val }
- end
-
- #def parent=( thing )
- # @parent.delete( self ) if defined?( @parent ) and @parent
- # @parent = thing
- #end
- end
-
-
- # this is used when we build nodes that have shape=record
- # ports don't have options :)
- class Port < SimpleElement
- attr_accessor :label
-
- def initialize( params = {} )
- super( params )
- @name = params['label'] ? params['label'] : ''
- end
- def to_s
- ( @name && @name != "" ? "<#{@name}>" : "" ) + "#{@label}"
- end
- end
-
- # node element
- class Node < Element
-
- def initialize( params = {}, option_list = NODE_OPTS )
- super( params, option_list )
- @ports = params['ports'] ? params['ports'] : []
- end
-
- def each_port
- @ports.each{ |i| yield i }
- end
-
- def << ( thing )
- @ports << thing
- end
-
- def push ( thing )
- @ports.push( thing )
- end
-
- def pop
- @ports.pop
- end
-
- def to_s( t = '' )
-
- label = @options['shape'] != 'record' && @ports.length == 0 ?
- @options['label'] ?
- t + TAB + "label = \"#{@options['label']}\"\n" :
- '' :
- t + TAB + 'label = "' + " \\\n" +
- t + TAB2 + "#{@options['label']}| \\\n" +
- @ports.collect{ |i|
- t + TAB2 + i.to_s
- }.join( "| \\\n" ) + " \\\n" +
- t + TAB + '"' + "\n"
-
- t + "#{@name} [\n" +
- @options.to_a.collect{ |i|
- i[1] && i[0] != 'label' ?
- t + TAB + "#{i[0]} = #{i[1]}" : nil
- }.compact.join( ",\n" ) + ( label != '' ? ",\n" : "\n" ) +
- label +
- t + "]\n"
- end
- end
-
- # subgraph element is the same to graph, but has another header in dot
- # notation
- class Subgraph < Element
-
- def initialize( params = {}, option_list = GRAPH_OPTS )
- super( params, option_list )
- @nodes = params['nodes'] ? params['nodes'] : []
- @dot_string = 'subgraph'
- end
-
- def each_node
- @nodes.each{ |i| yield i }
- end
-
- def << ( thing )
- @nodes << thing
- end
-
- def push( thing )
- @nodes.push( thing )
- end
-
- def pop
- @nodes.pop
- end
-
- def to_s( t = '' )
- hdr = t + "#{@dot_string} #{@name} {\n"
-
- options = @options.to_a.collect{ |name, val|
- val && name != 'label' ?
- t + TAB + "#{name} = #{val}" :
- name ? t + TAB + "#{name} = \"#{val}\"" : nil
- }.compact.join( "\n" ) + "\n"
-
- nodes = @nodes.collect{ |i|
- i.to_s( t + TAB )
- }.join( "\n" ) + "\n"
- hdr + options + nodes + t + "}\n"
- end
- end
-
- # this is graph
- class Digraph < Subgraph
- def initialize( params = {}, option_list = GRAPH_OPTS )
- super( params, option_list )
- @dot_string = 'digraph'
- end
- end
-
- # this is edge
- class Edge < Element
- attr_accessor :from, :to
- def initialize( params = {}, option_list = EDGE_OPTS )
- super( params, option_list )
- @from = params['from'] ? params['from'] : nil
- @to = params['to'] ? params['to'] : nil
- end
-
- def to_s( t = '' )
- t + "#{@from} -> #{to} [\n" +
- @options.to_a.collect{ |i|
- i[1] && i[0] != 'label' ?
- t + TAB + "#{i[0]} = #{i[1]}" :
- i[1] ? t + TAB + "#{i[0]} = \"#{i[1]}\"" : nil
- }.compact.join( "\n" ) + "\n" + t + "]\n"
- end
- end
-
-end
-
diff --git a/lib/rdoc/generator.rb b/lib/rdoc/generator.rb
index 86196b4..b650029 100644
--- a/lib/rdoc/generator.rb
+++ b/lib/rdoc/generator.rb
@@ -1,1082 +1,8 @@
-require 'cgi'
require 'rdoc'
-require 'rdoc/options'
-require 'rdoc/markup/to_html_crossref'
-require 'rdoc/template'
-module RDoc::Generator
-
- ##
- # Name of sub-directory that holds file descriptions
-
- FILE_DIR = "files"
-
- ##
- # Name of sub-directory that holds class descriptions
-
- CLASS_DIR = "classes"
-
- ##
- # Name of the RDoc CSS file
-
- CSS_NAME = "rdoc-style.css"
-
- ##
- # Build a hash of all items that can be cross-referenced. This is used when
- # we output required and included names: if the names appear in this hash,
- # we can generate an html cross reference to the appropriate description.
- # We also use this when parsing comment blocks: any decorated words matching
- # an entry in this list are hyperlinked.
-
- class AllReferences
- @@refs = {}
-
- def AllReferences::reset
- @@refs = {}
- end
-
- def AllReferences.add(name, html_class)
- @@refs[name] = html_class
- end
-
- def AllReferences.[](name)
- @@refs[name]
- end
-
- def AllReferences.keys
- @@refs.keys
- end
- end
-
- ##
- # Handle common markup tasks for the various Context subclasses
-
- module MarkUp
-
- ##
- # Convert a string in markup format into HTML.
-
- def markup(str, remove_para = false)
- return '' unless str
-
- # Convert leading comment markers to spaces, but only if all non-blank
- # lines have them
- if str =~ /^(?>\s*)[^\#]/ then
- content = str
- else
- content = str.gsub(/^\s*(#+)/) { $1.tr '#', ' ' }
- end
-
- res = formatter.convert content
-
- if remove_para then
- res.sub!(/^<p>/, '')
- res.sub!(/<\/p>$/, '')
- end
-
- res
- end
-
- ##
- # Qualify a stylesheet URL; if if +css_name+ does not begin with '/' or
- # 'http[s]://', prepend a prefix relative to +path+. Otherwise, return it
- # unmodified.
-
- def style_url(path, css_name=nil)
-# $stderr.puts "style_url( #{path.inspect}, #{css_name.inspect} )"
- css_name ||= CSS_NAME
- if %r{^(https?:/)?/} =~ css_name
- css_name
- else
- RDoc::Markup::ToHtml.gen_relative_url path, css_name
- end
- end
-
- ##
- # Build a webcvs URL with the given 'url' argument. URLs with a '%s' in them
- # get the file's path sprintfed into them; otherwise they're just catenated
- # together.
-
- def cvs_url(url, full_path)
- if /%s/ =~ url
- return sprintf( url, full_path )
- else
- return url + full_path
- end
- end
-
- end
-
- ##
- # A Context is built by the parser to represent a container: contexts hold
- # classes, modules, methods, require lists and include lists. ClassModule
- # and TopLevel are the context objects we process here
-
- class Context
-
- include MarkUp
-
- attr_reader :context
-
- ##
- # Generate:
- #
- # * a list of RDoc::Generator::File objects for each TopLevel object
- # * a list of RDoc::Generator::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 self.build_indices(toplevels, options)
- files = []
- classes = []
-
- toplevels.each do |toplevel|
- files << RDoc::Generator::File.new(toplevel, options,
- RDoc::Generator::FILE_DIR)
- end
-
- RDoc::TopLevel.all_classes_and_modules.each do |cls|
- build_class_list(classes, options, cls, files[0],
- RDoc::Generator::CLASS_DIR)
- end
-
- return files, classes
- end
-
- def self.build_class_list(classes, options, from, html_file, class_dir)
- classes << RDoc::Generator::Class.new(from, html_file, class_dir, options)
-
- from.each_classmodule do |mod|
- build_class_list(classes, options, mod, html_file, class_dir)
- end
- end
-
- def initialize(context, options)
- @context = context
- @options = options
-
- # HACK ugly
- @template = options.template_class
- end
-
- def formatter
- @formatter ||= @options.formatter ||
- RDoc::Markup::ToHtmlCrossref.new(path, self, @options.show_hash)
- end
-
- ##
- # convenience method to build a hyperlink
-
- def href(link, cls, name)
- %{<a href="#{link}" class="#{cls}">#{name}</a>} #"
- end
-
- ##
- # Returns a reference to outselves to be used as an href= the form depends
- # on whether we're all in one file or in multiple files
-
- def as_href(from_path)
- if @options.all_one_file
- "#" + path
- else
- RDoc::Markup::ToHtml.gen_relative_url from_path, path
- end
- end
-
- ##
- # Create a list of Method objects for each method in the corresponding
- # context object. If the @options.show_all variable is set (corresponding
- # to the <tt>--all</tt> option, we include all methods, otherwise just the
- # public ones.
-
- def collect_methods
- list = @context.method_list
-
- unless @options.show_all then
- list = list.select do |m|
- m.visibility == :public or
- m.visibility == :protected or
- m.force_documentation
- end
- end
-
- @methods = list.collect do |m|
- RDoc::Generator::Method.new m, self, @options
- end
- end
-
- ##
- # Build a summary list of all the methods in this context
-
- def build_method_summary_list(path_prefix = "")
- collect_methods unless @methods
-
- @methods.sort.map do |meth|
- {
- "name" => CGI.escapeHTML(meth.name),
- "aref" => "##{meth.aref}"
- }
- end
- end
-
- ##
- # Build a list of aliases for which we couldn't find a
- # corresponding method
-
- def build_alias_summary_list(section)
- @context.aliases.map do |al|
- next unless al.section == section
-
- res = {
- 'old_name' => al.old_name,
- 'new_name' => al.new_name,
- }
-
- if al.comment and not al.comment.empty? then
- res['desc'] = markup al.comment, true
- end
-
- res
- end.compact
- end
-
- ##
- # Build a list of constants
-
- def build_constants_summary_list(section)
- @context.constants.map do |co|
- next unless co.section == section
-
- res = {
- 'name' => co.name,
- 'value' => CGI.escapeHTML(co.value)
- }
-
- if co.comment and not co.comment.empty? then
- res['desc'] = markup co.comment, true
- end
-
- res
- end.compact
- end
-
- def build_requires_list(context)
- potentially_referenced_list(context.requires) {|fn| [fn + ".rb"] }
- end
-
- def build_include_list(context)
- potentially_referenced_list(context.includes)
- end
-
- ##
- # Build a list from an array of Context items. Look up each in the
- # AllReferences hash: if we find a corresponding entry, we generate a
- # hyperlink to it, otherwise just output the name. However, some names
- # potentially need massaging. For example, you may require a Ruby file
- # without the .rb extension, but the file names we know about may have it.
- # To deal with this, we pass in a block which performs the massaging,
- # returning an array of alternative names to match
-
- def potentially_referenced_list(array)
- res = []
- array.each do |i|
- ref = AllReferences[i.name]
-# if !ref
-# container = @context.parent
-# while !ref && container
-# name = container.name + "::" + i.name
-# ref = AllReferences[name]
-# container = container.parent
-# end
-# end
-
- ref = @context.find_symbol(i.name)
- ref = ref.viewer if ref
-
- if !ref && block_given?
- possibles = yield(i.name)
- while !ref and !possibles.empty?
- ref = AllReferences[possibles.shift]
- end
- end
- h_name = CGI.escapeHTML(i.name)
- if ref and ref.document_self
- path = url(ref.path)
- res << { "name" => h_name, "aref" => path }
- else
- res << { "name" => h_name }
- end
- end
- res
- end
-
- ##
- # Build an array of arrays of method details. The outer array has up
- # to six entries, public, private, and protected for both class
- # methods, the other for instance methods. The inner arrays contain
- # a hash for each method
-
- def build_method_detail_list(section)
- outer = []
-
- methods = @methods.sort.select do |m|
- m.document_self and m.section == section
- end
-
- for singleton in [true, false]
- for vis in [ :public, :protected, :private ]
- res = []
- methods.each do |m|
- next unless m.visibility == vis and m.singleton == singleton
-
- row = {}
-
- if m.call_seq then
- row["callseq"] = m.call_seq.gsub(/->/, '&rarr;')
- else
- row["name"] = CGI.escapeHTML(m.name)
- row["params"] = m.params
- end
-
- desc = m.description.strip
- row["m_desc"] = desc unless desc.empty?
- row["aref"] = m.aref
- row["visibility"] = m.visibility.to_s
-
- alias_names = []
-
- m.aliases.each do |other|
- if other.viewer then # won't be if the alias is private
- alias_names << {
- 'name' => other.name,
- 'aref' => other.viewer.as_href(path)
- }
- end
- end
-
- row["aka"] = alias_names unless alias_names.empty?
-
- if @options.inline_source then
- code = m.source_code
- row["sourcecode"] = code if code
- else
- code = m.src_url
- if code then
- row["codeurl"] = code
- row["imgurl"] = m.img_url
- end
- end
-
- res << row
- end
-
- if res.size > 0 then
- outer << {
- "type" => vis.to_s.capitalize,
- "category" => singleton ? "Class" : "Instance",
- "methods" => res
- }
- end
- end
- end
-
- outer
- end
-
- ##
- # Build the structured list of classes and modules contained
- # in this context.
-
- def build_class_list(level, from, section, infile=nil)
- prefix = '&nbsp;&nbsp;::' * level;
- res = ''
-
- from.modules.sort.each do |mod|
- next unless mod.section == section
- next if infile && !mod.defined_in?(infile)
- if mod.document_self
- res <<
- prefix <<
- 'Module ' <<
- href(url(mod.viewer.path), 'link', mod.full_name) <<
- "<br />\n" <<
- build_class_list(level + 1, mod, section, infile)
- end
- end
-
- from.classes.sort.each do |cls|
- next unless cls.section == section
- next if infile and not cls.defined_in?(infile)
-
- if cls.document_self
- res <<
- prefix <<
- 'Class ' <<
- href(url(cls.viewer.path), 'link', cls.full_name) <<
- "<br />\n" <<
- build_class_list(level + 1, cls, section, infile)
- end
- end
-
- res
- end
-
- def url(target)
- RDoc::Markup::ToHtml.gen_relative_url path, target
- end
-
- def aref_to(target)
- if @options.all_one_file
- "#" + target
- else
- url(target)
- end
- end
-
- def document_self
- @context.document_self
- end
-
- def diagram_reference(diagram)
- res = diagram.gsub(/((?:src|href)=")(.*?)"/) {
- $1 + url($2) + '"'
- }
- res
- end
-
- ##
- # Find a symbol in ourselves or our parent
-
- def find_symbol(symbol, method=nil)
- res = @context.find_symbol(symbol, method)
- if res
- res = res.viewer
- end
- res
- end
-
- ##
- # create table of contents if we contain sections
-
- def add_table_of_sections
- toc = []
- @context.sections.each do |section|
- if section.title then
- toc << {
- 'secname' => section.title,
- 'href' => section.sequence
- }
- end
- end
-
- @values['toc'] = toc unless toc.empty?
- end
-
- end
-
- ##
- # Wrap a ClassModule context
-
- class Class < Context
-
- attr_reader :methods
- attr_reader :path
- attr_reader :values
-
- def initialize(context, html_file, prefix, options)
- super context, options
-
- @html_file = html_file
- @html_class = self
- @is_module = context.module?
- @values = {}
-
- context.viewer = self
-
- if options.all_one_file
- @path = context.full_name
- else
- @path = http_url(context.full_name, prefix)
- end
-
- collect_methods
-
- AllReferences.add(name, self)
- end
-
- ##
- # Returns the relative file name to store this class in, which is also its
- # url
-
- def http_url(full_name, prefix)
- path = full_name.dup
-
- path.gsub!(/<<\s*(\w*)/, 'from-\1') if path['<<']
-
- ::File.join(prefix, path.split("::")) + ".html"
- end
-
- def name
- @context.full_name
- end
-
- def parent_name
- @context.parent.full_name
- end
-
- def index_name
- name
- end
-
- def write_on(f, file_list, class_list, method_list, overrides = {})
- value_hash
-
- @values['file_list'] = file_list
- @values['class_list'] = class_list
- @values['method_list'] = method_list
-
- @values.update overrides
-
- template = RDoc::TemplatePage.new(@template::BODY,
- @template::CLASS_PAGE,
- @template::METHOD_LIST)
-
- template.write_html_on(f, @values)
- end
-
- def value_hash
- class_attribute_values
- add_table_of_sections
-
- @values["charset"] = @options.charset
- @values["style_url"] = style_url(path, @options.css)
-
- d = markup(@context.comment)
- @values["description"] = d unless d.empty?
-
- ml = build_method_summary_list @path
- @values["methods"] = ml unless ml.empty?
-
- il = build_include_list @context
- @values["includes"] = il unless il.empty?
-
- @values["sections"] = @context.sections.map do |section|
- secdata = {
- "sectitle" => section.title,
- "secsequence" => section.sequence,
- "seccomment" => markup(section.comment),
- }
-
- al = build_alias_summary_list section
- secdata["aliases"] = al unless al.empty?
-
- co = build_constants_summary_list section
- secdata["constants"] = co unless co.empty?
-
- al = build_attribute_list section
- secdata["attributes"] = al unless al.empty?
-
- cl = build_class_list 0, @context, section
- secdata["classlist"] = cl unless cl.empty?
-
- mdl = build_method_detail_list section
- secdata["method_list"] = mdl unless mdl.empty?
-
- secdata
- end
-
- @values
- end
-
- def build_attribute_list(section)
- @context.attributes.sort.map do |att|
- next unless att.section == section
-
- if att.visibility == :public or att.visibility == :protected or
- @options.show_all then
-
- entry = {
- "name" => CGI.escapeHTML(att.name),
- "rw" => att.rw,
- "a_desc" => markup(att.comment, true)
- }
-
- unless att.visibility == :public or att.visibility == :protected then
- entry["rw"] << "-"
- end
-
- entry
- end
- end.compact
- end
-
- def class_attribute_values
- h_name = CGI.escapeHTML(name)
-
- @values["href"] = @path
- @values["classmod"] = @is_module ? "Module" : "Class"
- @values["title"] = "#{@values['classmod']}: #{h_name} [#{@options.title}]"
-
- c = @context
- c = c.parent while c and not c.diagram
-
- if c and c.diagram then
- @values["diagram"] = diagram_reference(c.diagram)
- end
-
- @values["full_name"] = h_name
-
- if not @context.module? and @context.superclass then
- parent_class = @context.superclass
- @values["parent"] = CGI.escapeHTML(parent_class)
-
- if parent_name
- lookup = parent_name + "::" + parent_class
- else
- lookup = parent_class
- end
-
- parent_url = AllReferences[lookup] || AllReferences[parent_class]
-
- if parent_url and parent_url.document_self
- @values["par_url"] = aref_to(parent_url.path)
- end
- end
-
- files = []
- @context.in_files.each do |f|
- res = {}
- full_path = CGI.escapeHTML(f.file_absolute_name)
-
- res["full_path"] = full_path
- res["full_path_url"] = aref_to(f.viewer.path) if f.document_self
-
- if @options.webcvs
- res["cvsurl"] = cvs_url( @options.webcvs, full_path )
- end
-
- files << res
- end
-
- @values['infiles'] = files
- end
-
- def <=>(other)
- self.name <=> other.name
- end
-
- end
-
- ##
- # Handles the mapping of a file's information to HTML. In reality, a file
- # corresponds to a +TopLevel+ object, containing modules, classes, and
- # top-level methods. In theory it _could_ contain attributes and aliases,
- # but we ignore these for now.
-
- class File < Context
-
- attr_reader :path
- attr_reader :name
- attr_reader :values
-
- def initialize(context, options, file_dir)
- super context, options
-
- @values = {}
-
- if options.all_one_file
- @path = filename_to_label
- else
- @path = http_url(file_dir)
- end
-
- @name = @context.file_relative_name
-
- collect_methods
- AllReferences.add(name, self)
- context.viewer = self
- end
-
- def http_url(file_dir)
- ::File.join file_dir, "#{@context.file_relative_name.tr '.', '_'}.html"
- end
-
- def filename_to_label
- @context.file_relative_name.gsub(/%|\/|\?|\#/) do
- ('%%%x' % $&[0]).unpack('C')
- end
- end
-
- def index_name
- name
- end
-
- def parent_name
- nil
- end
-
- def value_hash
- file_attribute_values
- add_table_of_sections
-
- @values["charset"] = @options.charset
- @values["href"] = path
- @values["style_url"] = style_url(path, @options.css)
-
- if @context.comment
- d = markup(@context.comment)
- @values["description"] = d if d.size > 0
- end
-
- ml = build_method_summary_list
- @values["methods"] = ml unless ml.empty?
-
- il = build_include_list(@context)
- @values["includes"] = il unless il.empty?
-
- rl = build_requires_list(@context)
- @values["requires"] = rl unless rl.empty?
-
- if @options.promiscuous
- file_context = nil
- else
- file_context = @context
- end
-
-
- @values["sections"] = @context.sections.map do |section|
-
- secdata = {
- "sectitle" => section.title,
- "secsequence" => section.sequence,
- "seccomment" => markup(section.comment)
- }
-
- cl = build_class_list(0, @context, section, file_context)
- secdata["classlist"] = cl unless cl.empty?
-
- mdl = build_method_detail_list(section)
- secdata["method_list"] = mdl unless mdl.empty?
-
- al = build_alias_summary_list(section)
- secdata["aliases"] = al unless al.empty?
-
- co = build_constants_summary_list(section)
- secdata["constants"] = co unless co.empty?
-
- secdata
- end
-
- @values
- end
-
- def write_on(f, file_list, class_list, method_list, overrides = {})
- value_hash
-
- @values['file_list'] = file_list
- @values['class_list'] = class_list
- @values['method_list'] = method_list
-
- @values.update overrides
-
- template = RDoc::TemplatePage.new(@template::BODY,
- @template::FILE_PAGE,
- @template::METHOD_LIST)
-
- template.write_html_on(f, @values)
- end
-
- def file_attribute_values
- full_path = @context.file_absolute_name
- short_name = ::File.basename full_path
-
- @values["title"] = CGI.escapeHTML("File: #{short_name} [#{@options.title}]")
-
- if @context.diagram then
- @values["diagram"] = diagram_reference(@context.diagram)
- end
-
- @values["short_name"] = CGI.escapeHTML(short_name)
- @values["full_path"] = CGI.escapeHTML(full_path)
- @values["dtm_modified"] = @context.file_stat.mtime.to_s
-
- if @options.webcvs then
- @values["cvsurl"] = cvs_url @options.webcvs, @values["full_path"]
- end
- end
-
- def <=>(other)
- self.name <=> other.name
- end
-
- end
-
- class Method
-
- include MarkUp
-
- attr_reader :context
- attr_reader :src_url
- attr_reader :img_url
- attr_reader :source_code
-
- 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
- @html_class = html_class
- @options = options
-
- @@seq = @@seq.succ
- @seq = @@seq
-
- # HACK ugly
- @template = options.template_class
-
- @@all_methods << self
-
- context.viewer = self
-
- if (ts = @context.token_stream)
- @source_code = markup_code(ts)
- unless @options.inline_source
- @src_url = create_source_code_file(@source_code)
- @img_url = RDoc::Markup::ToHtml.gen_relative_url path, 'source.png'
- end
- end
-
- AllReferences.add(name, self)
- end
-
- ##
- # Returns a reference to outselves to be used as an href= the form depends
- # on whether we're all in one file or in multiple files
-
- def as_href(from_path)
- if @options.all_one_file
- "#" + path
- else
- RDoc::Markup::ToHtml.gen_relative_url from_path, path
- end
- end
-
- def formatter
- @formatter ||= @options.formatter ||
- RDoc::Markup::ToHtmlCrossref.new(path, self, @options.show_hash)
- end
-
- def inspect
- alias_for = if @context.is_alias_for then
- " (alias_for #{@context.is_alias_for})"
- else
- nil
- end
-
- "#<%s:0x%x %s%s%s (%s)%s>" % [
- self.class, object_id,
- @context.parent.name,
- @context.singleton ? '::' : '#',
- name,
- @context.visibility,
- alias_for
- ]
- end
-
- def name
- @context.name
- end
-
- def section
- @context.section
- end
-
- def index_name
- "#{@context.name} (#{@html_class.name})"
- end
-
- def parent_name
- if @context.parent.parent
- @context.parent.parent.full_name
- else
- nil
- end
- end
-
- def aref
- @seq
- end
-
- def path
- if @options.all_one_file
- aref
- else
- @html_class.path + "#" + aref
- end
- end
-
- def description
- markup(@context.comment)
- end
-
- def visibility
- @context.visibility
- end
-
- def singleton
- @context.singleton
- end
-
- def call_seq
- cs = @context.call_seq
- if cs
- cs.gsub(/\n/, "<br />\n")
- else
- nil
- end
- end
-
- def params
- # params coming from a call-seq in 'C' will start with the
- # method name
- params = @context.params
- if params !~ /^\w/
- params = @context.params.gsub(/\s*\#.*/, '')
- params = params.tr("\n", " ").squeeze(" ")
- params = "(" + params + ")" unless params[0] == ?(
-
- if (block = @context.block_params)
- # If this method has explicit block parameters, remove any
- # explicit &block
-
- params.sub!(/,?\s*&\w+/, '')
-
- block.gsub!(/\s*\#.*/, '')
- block = block.tr("\n", " ").squeeze(" ")
- if block[0] == ?(
- block.sub!(/^\(/, '').sub!(/\)/, '')
- end
- params << " {|#{block.strip}| ...}"
- end
- end
- CGI.escapeHTML(params)
- end
-
- def create_source_code_file(code_body)
- meth_path = @html_class.path.sub(/\.html$/, '.src')
- FileUtils.mkdir_p(meth_path)
- file_path = ::File.join meth_path, "#{@seq}.html"
-
- template = RDoc::TemplatePage.new(@template::SRC_PAGE)
-
- open file_path, 'w' do |f|
- values = {
- 'title' => CGI.escapeHTML(index_name),
- 'code' => code_body,
- 'style_url' => style_url(file_path, @options.css),
- 'charset' => @options.charset
- }
- template.write_html_on(f, values)
- end
-
- RDoc::Markup::ToHtml.gen_relative_url path, file_path
- end
-
- def <=>(other)
- @context <=> other.context
- end
-
- ##
- # Given a sequence of source tokens, mark up the source code
- # to make it look purty.
-
- def markup_code(tokens)
- src = ""
- tokens.each do |t|
- next unless t
-# style = STYLE_MAP[t.class]
- style = case t
- when RDoc::RubyToken::TkCONSTANT then "ruby-constant"
- when RDoc::RubyToken::TkKW then "ruby-keyword kw"
- when RDoc::RubyToken::TkIVAR then "ruby-ivar"
- when RDoc::RubyToken::TkOp then "ruby-operator"
- when RDoc::RubyToken::TkId then "ruby-identifier"
- when RDoc::RubyToken::TkNode then "ruby-node"
- when RDoc::RubyToken::TkCOMMENT then "ruby-comment cmt"
- when RDoc::RubyToken::TkREGEXP then "ruby-regexp re"
- when RDoc::RubyToken::TkSTRING then "ruby-value str"
- when RDoc::RubyToken::TkVal then "ruby-value"
- else
- nil
- end
-
- text = CGI.escapeHTML(t.text)
-
- if style
- src << "<span class=\"#{style}\">#{text}</span>"
- else
- src << text
- end
- end
-
- add_line_numbers(src) if @options.include_line_numbers
- src
- end
-
- ##
- # We rely on the fact that the first line of a source code listing has
- # # File xxxxx, line dddd
-
- def add_line_numbers(src)
- if src =~ /\A.*, line (\d+)/
- first = $1.to_i - 1
- last = first + src.count("\n")
- size = last.to_s.length
- fmt = "%#{size}d: "
- is_first_line = true
- line_num = first
- src.gsub!(/^/) do
- 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
- end
-
- def document_self
- @context.document_self
- end
-
- def aliases
- @context.aliases
- end
-
- def find_symbol(symbol, method=nil)
- res = @context.parent.find_symbol(symbol, method)
- if res
- res = res.viewer
- end
- res
- end
-
- end
+##
+# Namespace for generators
+module RDoc::Generator
end
diff --git a/lib/rdoc/generator/chm.rb b/lib/rdoc/generator/chm.rb
deleted file mode 100644
index 7537365..0000000
--- a/lib/rdoc/generator/chm.rb
+++ /dev/null
@@ -1,113 +0,0 @@
-require 'rdoc/generator/html'
-
-class RDoc::Generator::CHM < RDoc::Generator::HTML
-
- HHC_PATH = "c:/Program Files/HTML Help Workshop/hhc.exe"
-
- ##
- # Standard generator factory
-
- def self.for(options)
- new(options)
- end
-
- def initialize(*args)
- super
- @op_name = @options.op_name || "rdoc"
- check_for_html_help_workshop
- end
-
- def check_for_html_help_workshop
- stat = File.stat(HHC_PATH)
- rescue
- $stderr <<
- "\n.chm output generation requires that Microsoft's Html Help\n" <<
- "Workshop is installed. RDoc looks for it in:\n\n " <<
- HHC_PATH <<
- "\n\nYou can download a copy for free from:\n\n" <<
- " http://msdn.microsoft.com/library/default.asp?" <<
- "url=/library/en-us/htmlhelp/html/hwMicrosoftHTMLHelpDownloads.asp\n\n"
- end
-
- ##
- # Generate the html as normal, then wrap it in a help project
-
- def generate(info)
- super
- @project_name = @op_name + ".hhp"
- create_help_project
- end
-
- ##
- # The project contains the project file, a table of contents and an index
-
- def create_help_project
- create_project_file
- create_contents_and_index
- compile_project
- end
-
- ##
- # The project file links together all the various
- # files that go to make up the help.
-
- def create_project_file
- template = RDoc::TemplatePage.new @template::HPP_FILE
- values = { "title" => @options.title, "opname" => @op_name }
- files = []
- @files.each do |f|
- files << { "html_file_name" => f.path }
- end
-
- values['all_html_files'] = files
-
- File.open(@project_name, "w") do |f|
- template.write_html_on(f, values)
- end
- end
-
- ##
- # The contents is a list of all files and modules.
- # For each we include as sub-entries the list
- # of methods they contain. As we build the contents
- # we also build an index file
-
- def create_contents_and_index
- contents = []
- index = []
-
- (@files+@classes).sort.each do |entry|
- content_entry = { "c_name" => entry.name, "ref" => entry.path }
- index << { "name" => entry.name, "aref" => entry.path }
-
- internals = []
-
- methods = entry.build_method_summary_list(entry.path)
-
- content_entry["methods"] = methods unless methods.empty?
- contents << content_entry
- index.concat methods
- end
-
- values = { "contents" => contents }
- template = RDoc::TemplatePage.new @template::CONTENTS
- File.open("contents.hhc", "w") do |f|
- template.write_html_on(f, values)
- end
-
- values = { "index" => index }
- template = RDoc::TemplatePage.new @template::CHM_INDEX
- File.open("index.hhk", "w") do |f|
- template.write_html_on(f, values)
- end
- end
-
- ##
- # Invoke the windows help compiler to compiler the project
-
- def compile_project
- system(HHC_PATH, @project_name)
- end
-
-end
-
diff --git a/lib/rdoc/generator/chm/chm.rb b/lib/rdoc/generator/chm/chm.rb
deleted file mode 100644
index c362318..0000000
--- a/lib/rdoc/generator/chm/chm.rb
+++ /dev/null
@@ -1,100 +0,0 @@
-require 'rdoc/generator/chm'
-require 'rdoc/generator/html/html'
-
-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
- FILE_INDEX = HTML::FILE_INDEX
- FILE_PAGE = HTML::FILE_PAGE
- METHOD_INDEX = HTML::METHOD_INDEX
- METHOD_LIST = HTML::METHOD_LIST
-
- FR_INDEX_BODY = HTML::FR_INDEX_BODY
-
- # This is a nasty little hack, but hhc doesn't support the <?xml tag, so...
- BODY = HTML::BODY.sub!(/<\?xml.*\?>/, '')
- SRC_PAGE = HTML::SRC_PAGE.sub!(/<\?xml.*\?>/, '')
-
- HPP_FILE = <<-EOF
-[OPTIONS]
-Auto Index = Yes
-Compatibility=1.1 or later
-Compiled file=<%= values["opname"] %>.chm
-Contents file=contents.hhc
-Full-text search=Yes
-Index file=index.hhk
-Language=0x409 English(United States)
-Title=<%= values["title"] %>
-
-[FILES]
-<% values["all_html_files"].each do |all_html_files| %>
-<%= all_html_files["html_file_name"] %>
-<% end # values["all_html_files"] %>
- EOF
-
- CONTENTS = <<-EOF
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<HTML>
-<HEAD>
-<meta name="GENERATOR" content="Microsoft&reg; HTML Help Workshop 4.1">
-<!-- Sitemap 1.0 -->
-</HEAD><BODY>
-<OBJECT type="text/site properties">
- <param name="Foreground" value="0x80">
- <param name="Window Styles" value="0x800025">
- <param name="ImageType" value="Folder">
-</OBJECT>
-<UL>
-<% values["contents"].each do |contents| %>
- <LI> <OBJECT type="text/sitemap">
- <param name="Name" value="<%= contents["c_name"] %>">
- <param name="Local" value="<%= contents["ref"] %>">
- </OBJECT>
-<% if contents["methods"] then %>
-<ul>
-<% contents["methods"].each do |methods| %>
- <LI> <OBJECT type="text/sitemap">
- <param name="Name" value="<%= methods["name"] %>">
- <param name="Local" value="<%= methods["aref"] %>">
- </OBJECT>
-<% end # contents["methods"] %>
-</ul>
-<% end %>
- </LI>
-<% end # values["contents"] %>
-</UL>
-</BODY></HTML>
- EOF
-
- CHM_INDEX = <<-EOF
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<HTML>
-<HEAD>
-<meta name="GENERATOR" content="Microsoft&reg; HTML Help Workshop 4.1">
-<!-- Sitemap 1.0 -->
-</HEAD><BODY>
-<OBJECT type="text/site properties">
- <param name="Foreground" value="0x80">
- <param name="Window Styles" value="0x800025">
- <param name="ImageType" value="Folder">
-</OBJECT>
-<UL>
-<% values["index"].each do |index| %>
- <LI> <OBJECT type="text/sitemap">
- <param name="Name" value="<%= index["name"] %>">
- <param name="Local" value="<%= index["aref"] %>">
- </OBJECT>
-<% end # values["index"] %>
-</UL>
-</BODY></HTML>
- EOF
-
-end
-
diff --git a/lib/rdoc/generator/darkfish.rb b/lib/rdoc/generator/darkfish.rb
new file mode 100644
index 0000000..a25475d
--- /dev/null
+++ b/lib/rdoc/generator/darkfish.rb
@@ -0,0 +1,459 @@
+#!ruby
+# vim: noet ts=2 sts=8 sw=2
+
+unless File.exist? File.expand_path('../.svn', __FILE__) then
+ require 'rubygems'
+ gem 'rdoc', '>= 2.4'
+end
+
+require 'pp'
+require 'pathname'
+require 'fileutils'
+require 'erb'
+
+require 'rdoc/generator/markup'
+
+$DARKFISH_DRYRUN = false # TODO make me non-global
+
+#
+# Darkfish RDoc HTML Generator
+#
+# $Id: darkfish.rb 52 2009-01-07 02:08:11Z deveiant $
+#
+# == Author/s
+# * Michael Granger (ged@FaerieMUD.org)
+#
+# == Contributors
+# * Mahlon E. Smith (mahlon@martini.nu)
+# * Eric Hodel (drbrain@segment7.net)
+#
+# == License
+#
+# Copyright (c) 2007, 2008, Michael Granger. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of the author/s, nor the names of the project's
+# contributors may be used to endorse or promote products derived from this
+# software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+class RDoc::Generator::Darkfish
+
+ RDoc::RDoc.add_generator( self )
+
+ include ERB::Util
+
+ # Subversion rev
+ SVNRev = %$Rev: 52 $
+
+ # Subversion ID
+ SVNId = %$Id: darkfish.rb 52 2009-01-07 02:08:11Z deveiant $
+
+ # Path to this file's parent directory. Used to find templates and other
+ # resources.
+ GENERATOR_DIR = File.join 'rdoc', 'generator'
+
+ # Release Version
+ VERSION = '1.1.6'
+
+ # Directory where generated classes live relative to the root
+ CLASS_DIR = nil
+
+ # Directory where generated files live relative to the root
+ FILE_DIR = nil
+
+
+ #################################################################
+ ### C L A S S M E T H O D S
+ #################################################################
+
+ ### Standard generator factory method
+ def self::for( options )
+ new( options )
+ end
+
+
+ #################################################################
+ ### I N S T A N C E M E T H O D S
+ #################################################################
+
+ ### Initialize a few instance variables before we start
+ def initialize( options )
+ @options = options
+
+ template = @options.template || 'darkfish'
+
+ template_dir = $LOAD_PATH.map do |path|
+ File.join File.expand_path(path), GENERATOR_DIR, 'template', template
+ end.find do |dir|
+ File.directory? dir
+ end
+
+ raise RDoc::Error, "could not find template #{template.inspect}" unless
+ template_dir
+
+ @template_dir = Pathname.new File.expand_path(template_dir)
+
+ @files = nil
+ @classes = nil
+
+ @basedir = Pathname.pwd.expand_path
+ end
+
+ ######
+ public
+ ######
+
+ # The output directory
+ attr_reader :outputdir
+
+
+ ### Output progress information if debugging is enabled
+ def debug_msg( *msg )
+ return unless $DEBUG_RDOC
+ $stderr.puts( *msg )
+ end
+
+ def class_dir
+ CLASS_DIR
+ end
+
+ def file_dir
+ FILE_DIR
+ end
+
+ ### Create the directories the generated docs will live in if
+ ### they don't already exist.
+ def gen_sub_directories
+ @outputdir.mkpath
+ end
+
+ ### Copy over the stylesheet into the appropriate place in the output
+ ### directory.
+ def write_style_sheet
+ debug_msg "Copying static files"
+ options = { :verbose => $DEBUG_RDOC, :noop => $DARKFISH_DRYRUN }
+
+ FileUtils.cp @template_dir + 'rdoc.css', '.', options
+
+ Dir[(@template_dir + "{js,images}/**/*").to_s].each do |path|
+ next if File.directory? path
+ next if path =~ /#{File::SEPARATOR}\./
+
+ dst = Pathname.new(path).relative_path_from @template_dir
+
+ # I suck at glob
+ dst_dir = dst.dirname
+ FileUtils.mkdir_p dst_dir, options unless File.exist? dst_dir
+
+ FileUtils.cp @template_dir + path, dst, options
+ end
+ end
+
+ ### Build the initial indices and output objects
+ ### based on an array of TopLevel objects containing
+ ### the extracted information.
+ def generate( top_levels )
+ @outputdir = Pathname.new( @options.op_dir ).expand_path( @basedir )
+
+ @files = top_levels.sort
+ @classes = RDoc::TopLevel.all_classes_and_modules.sort
+ @methods = @classes.map { |m| m.method_list }.flatten.sort
+ @modsort = get_sorted_module_list( @classes )
+
+ # Now actually write the output
+ write_style_sheet
+ generate_index
+ generate_class_files
+ generate_file_files
+
+ rescue StandardError => err
+ debug_msg "%s: %s\n %s" % [ err.class.name, err.message, err.backtrace.join("\n ") ]
+ raise
+ end
+
+ #########
+ protected
+ #########
+
+ ### Return a list of the documented modules sorted by salience first, then
+ ### by name.
+ def get_sorted_module_list( classes )
+ nscounts = classes.inject({}) do |counthash, klass|
+ top_level = klass.full_name.gsub( /::.*/, '' )
+ counthash[top_level] ||= 0
+ counthash[top_level] += 1
+
+ counthash
+ end
+
+ # Sort based on how often the top level namespace occurs, and then on the
+ # name of the module -- this works for projects that put their stuff into
+ # a namespace, of course, but doesn't hurt if they don't.
+ classes.sort_by do |klass|
+ top_level = klass.full_name.gsub( /::.*/, '' )
+ [
+ nscounts[ top_level ] * -1,
+ klass.full_name
+ ]
+ end.select do |klass|
+ klass.document_self
+ end
+ end
+
+ ### Generate an index page which lists all the classes which
+ ### are documented.
+ def generate_index
+ template_file = @template_dir + 'index.rhtml'
+ return unless template_file.exist?
+
+ debug_msg "Rendering the index page..."
+
+ template_src = template_file.read
+ template = ERB.new( template_src, nil, '<>' )
+ template.filename = template_file.to_s
+ context = binding()
+
+ output = nil
+
+ begin
+ output = template.result( context )
+ rescue NoMethodError => err
+ raise RDoc::Error, "Error while evaluating %s: %s (at %p)" % [
+ template_file,
+ err.message,
+ eval( "_erbout[-50,50]", context )
+ ], err.backtrace
+ end
+
+ outfile = @basedir + @options.op_dir + 'index.html'
+ unless $DARKFISH_DRYRUN
+ debug_msg "Outputting to %s" % [outfile.expand_path]
+ outfile.open( 'w', 0644 ) do |fh|
+ fh.print( output )
+ end
+ else
+ debug_msg "Would have output to %s" % [outfile.expand_path]
+ end
+ end
+
+ ### Generate a documentation file for each class
+ def generate_class_files
+ template_file = @template_dir + 'classpage.rhtml'
+ return unless template_file.exist?
+ debug_msg "Generating class documentation in #@outputdir"
+
+ @classes.each do |klass|
+ debug_msg " working on %s (%s)" % [ klass.full_name, klass.path ]
+ outfile = @outputdir + klass.path
+ rel_prefix = @outputdir.relative_path_from( outfile.dirname )
+ svninfo = self.get_svninfo( klass )
+
+ debug_msg " rendering #{outfile}"
+ self.render_template( template_file, binding(), outfile )
+ end
+ end
+
+ ### Generate a documentation file for each file
+ def generate_file_files
+ template_file = @template_dir + 'filepage.rhtml'
+ return unless template_file.exist?
+ debug_msg "Generating file documentation in #@outputdir"
+
+ @files.each do |file|
+ outfile = @outputdir + file.path
+ debug_msg " working on %s (%s)" % [ file.full_name, outfile ]
+ rel_prefix = @outputdir.relative_path_from( outfile.dirname )
+ context = binding()
+
+ debug_msg " rendering #{outfile}"
+ self.render_template( template_file, binding(), outfile )
+ end
+ end
+
+
+ ### Return a string describing the amount of time in the given number of
+ ### seconds in terms a human can understand easily.
+ def time_delta_string( seconds )
+ return 'less than a minute' if seconds < 1.minute
+ return (seconds / 1.minute).to_s + ' minute' + (seconds/60 == 1 ? '' : 's') if seconds < 50.minutes
+ return 'about one hour' if seconds < 90.minutes
+ return (seconds / 1.hour).to_s + ' hours' if seconds < 18.hours
+ return 'one day' if seconds < 1.day
+ return 'about one day' if seconds < 2.days
+ return (seconds / 1.day).to_s + ' days' if seconds < 1.week
+ return 'about one week' if seconds < 2.week
+ return (seconds / 1.week).to_s + ' weeks' if seconds < 3.months
+ return (seconds / 1.month).to_s + ' months' if seconds < 1.year
+ return (seconds / 1.year).to_s + ' years'
+ end
+
+
+ # %q$Id: darkfish.rb 52 2009-01-07 02:08:11Z deveiant $"
+ SVNID_PATTERN = /
+ \$Id:\s
+ (\S+)\s # filename
+ (\d+)\s # rev
+ (\d{4}-\d{2}-\d{2})\s # Date (YYYY-MM-DD)
+ (\d{2}:\d{2}:\d{2}Z)\s # Time (HH:MM:SSZ)
+ (\w+)\s # committer
+ \$$
+ /x
+
+ ### Try to extract Subversion information out of the first constant whose value looks like
+ ### a subversion Id tag. If no matching constant is found, and empty hash is returned.
+ def get_svninfo( klass )
+ constants = klass.constants or return {}
+
+ constants.find {|c| c.value =~ SVNID_PATTERN } or return {}
+
+ filename, rev, date, time, committer = $~.captures
+ commitdate = Time.parse( date + ' ' + time )
+
+ return {
+ :filename => filename,
+ :rev => Integer( rev ),
+ :commitdate => commitdate,
+ :commitdelta => time_delta_string( Time.now.to_i - commitdate.to_i ),
+ :committer => committer,
+ }
+ end
+
+
+ ### Load and render the erb template in the given +template_file+ within the
+ ### specified +context+ (a Binding object) and write it out to +outfile+.
+ ### Both +template_file+ and +outfile+ should be Pathname-like objects.
+
+ def render_template( template_file, context, outfile )
+ template_src = template_file.read
+ template = ERB.new( template_src, nil, '<>' )
+ template.filename = template_file.to_s
+
+ output = begin
+ template.result( context )
+ rescue NoMethodError => err
+ raise RDoc::Error, "Error while evaluating %s: %s (at %p)" % [
+ template_file.to_s,
+ err.message,
+ eval( "_erbout[-50,50]", context )
+ ], err.backtrace
+ end
+
+ unless $DARKFISH_DRYRUN
+ outfile.dirname.mkpath
+ outfile.open( 'w', 0644 ) do |ofh|
+ ofh.print( output )
+ end
+ else
+ debug_msg " would have written %d bytes to %s" %
+ [ output.length, outfile ]
+ end
+ end
+
+end # Roc::Generator::Darkfish
+
+# :stopdoc:
+
+### Time constants
+module TimeConstantMethods # :nodoc:
+
+ ### Number of seconds (returns receiver unmodified)
+ def seconds
+ return self
+ end
+ alias_method :second, :seconds
+
+ ### Returns number of seconds in <receiver> minutes
+ def minutes
+ return self * 60
+ end
+ alias_method :minute, :minutes
+
+ ### Returns the number of seconds in <receiver> hours
+ def hours
+ return self * 60.minutes
+ end
+ alias_method :hour, :hours
+
+ ### Returns the number of seconds in <receiver> days
+ def days
+ return self * 24.hours
+ end
+ alias_method :day, :days
+
+ ### Return the number of seconds in <receiver> weeks
+ def weeks
+ return self * 7.days
+ end
+ alias_method :week, :weeks
+
+ ### Returns the number of seconds in <receiver> fortnights
+ def fortnights
+ return self * 2.weeks
+ end
+ alias_method :fortnight, :fortnights
+
+ ### Returns the number of seconds in <receiver> months (approximate)
+ def months
+ return self * 30.days
+ end
+ alias_method :month, :months
+
+ ### Returns the number of seconds in <receiver> years (approximate)
+ def years
+ return (self * 365.25.days).to_i
+ end
+ alias_method :year, :years
+
+
+ ### Returns the Time <receiver> number of seconds before the
+ ### specified +time+. E.g., 2.hours.before( header.expiration )
+ def before( time )
+ return time - self
+ end
+
+
+ ### Returns the Time <receiver> number of seconds ago. (e.g.,
+ ### expiration > 2.hours.ago )
+ def ago
+ return self.before( ::Time.now )
+ end
+
+
+ ### Returns the Time <receiver> number of seconds after the given +time+.
+ ### E.g., 10.minutes.after( header.expiration )
+ def after( time )
+ return time + self
+ end
+
+ # Reads best without arguments: 10.minutes.from_now
+ def from_now
+ return self.after( ::Time.now )
+ end
+end # module TimeConstantMethods
+
+
+# Extend Numeric with time constants
+class Numeric # :nodoc:
+ include TimeConstantMethods
+end
+
diff --git a/lib/rdoc/generator/html.rb b/lib/rdoc/generator/html.rb
deleted file mode 100644
index 3bce7b2..0000000
--- a/lib/rdoc/generator/html.rb
+++ /dev/null
@@ -1,449 +0,0 @@
-require 'fileutils'
-
-require 'rdoc/generator'
-require 'rdoc/markup/to_html'
-
-##
-# We're responsible for generating all the HTML files from the object tree
-# defined in code_objects.rb. We generate:
-#
-# [files] an html file for each input file given. These
-# input files appear as objects of class
-# TopLevel
-#
-# [classes] an html file for each class or module encountered.
-# These classes are not grouped by file: if a file
-# contains four classes, we'll generate an html
-# file for the file itself, and four html files
-# for the individual classes.
-#
-# [indices] we generate three indices for files, classes,
-# and methods. These are displayed in a browser
-# like window with three index panes across the
-# top and the selected description below
-#
-# Method descriptions appear in whatever entity (file, class, or module) that
-# contains them.
-#
-# We generate files in a structure below a specified subdirectory, normally
-# +doc+.
-#
-# opdir
-# |
-# |___ files
-# | |__ per file summaries
-# |
-# |___ classes
-# |__ per class/module descriptions
-#
-# HTML is generated using the Template class.
-
-class RDoc::Generator::HTML
-
- include RDoc::Generator::MarkUp
-
- ##
- # Generator may need to return specific subclasses depending on the
- # options they are passed. Because of this we create them using a factory
-
- def self.for(options)
- RDoc::Generator::AllReferences.reset
- RDoc::Generator::Method.reset
-
- if options.all_one_file
- RDoc::Generator::HTMLInOne.new options
- else
- new options
- end
- end
-
- class << self
- protected :new
- end
-
- ##
- # Set up a new HTML generator. Basically all we do here is load up the
- # correct output temlate
-
- def initialize(options) #:not-new:
- @options = options
- load_html_template
- end
-
- ##
- # Build the initial indices and output objects
- # based on an array of TopLevel objects containing
- # the extracted information.
-
- def generate(toplevels)
- @toplevels = toplevels
- @files = []
- @classes = []
-
- write_style_sheet
- gen_sub_directories
- build_indices
- generate_html
- end
-
- private
-
- ##
- # Load up the HTML template specified in the options.
- # 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
- template = File.join('rdoc', 'generator', @options.generator.key,
- template)
- end
-
- begin
- require 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
-
- $stderr.puts "Could not find HTML template '#{template}': #{e.message}"
- exit 99
- end
- end
-
- ##
- # Write out the style sheet used by the main frames
-
- def write_style_sheet
- return unless @template.constants.include? :STYLE or
- @template.constants.include? 'STYLE'
-
- template = RDoc::TemplatePage.new @template::STYLE
-
- unless @options.css then
- open RDoc::Generator::CSS_NAME, 'w' do |f|
- values = {}
-
- if @template.constants.include? :FONTS or
- @template.constants.include? 'FONTS' then
- values["fonts"] = @template::FONTS
- end
-
- template.write_html_on(f, values)
- end
- end
- end
-
- ##
- # See the comments at the top for a description of the directory structure
-
- def gen_sub_directories
- FileUtils.mkdir_p RDoc::Generator::FILE_DIR
- FileUtils.mkdir_p RDoc::Generator::CLASS_DIR
- rescue
- $stderr.puts $!.message
- exit 1
- end
-
- def build_indices
- @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)
-
- # and the index files
- gen_file_index
- gen_class_index
- gen_method_index
- gen_main_index
-
- # this method is defined in the template file
- 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)
- #
- # 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)
-
- 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
- end
-
- file_list.clear
- class_list.clear
- method_list.clear
- end
- end
-
- def gen_file_index
- gen_an_index @files, 'Files', @template::FILE_INDEX, "fr_file_index.html"
- end
-
- def gen_class_index
- gen_an_index(@classes, 'Classes', @template::CLASS_INDEX,
- "fr_class_index.html")
- end
-
- def gen_method_index
- gen_an_index(RDoc::Generator::Method.all_methods, 'Methods',
- @template::METHOD_INDEX, "fr_method_index.html")
- end
-
- def gen_an_index(collection, title, template, filename)
- template = RDoc::TemplatePage.new @template::FR_INDEX_BODY, template
- res = []
- collection.sort.each do |f|
- if f.document_self
- res << { "href" => f.path, "name" => f.index_name }
- end
- end
-
- values = {
- "entries" => res,
- 'title' => CGI.escapeHTML("#{title} [#{@options.title}]"),
- 'list_title' => CGI.escapeHTML(title),
- 'index_url' => @main_url,
- 'charset' => @options.charset,
- 'style_url' => style_url('', @options.css),
- }
-
- open filename, 'w' do |f|
- template.write_html_on(f, values)
- end
- end
-
- ##
- # The main index page is mostly a template frameset, but includes the
- # initial page. If the <tt>--main</tt> option was given, we use this as
- # our main page, otherwise we use the first file specified on the command
- # line.
-
- def gen_main_index
- if @template.const_defined? :FRAMELESS then
- #
- # 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
-
- 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
-
- main.write_html_on f, values
- end
- end
- end
-
- def index_to_links(output_path, collection)
- collection.sort.map do |f|
- next unless f.document_self
- { "href" => RDoc::Markup::ToHtml.gen_relative_url(output_path, f.path),
- "name" => f.index_name }
- end.compact
- end
-
- ##
- # Returns the url of the main page
-
- def main_url
- main_page = @options.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
- return main_page_ref.path
- else
- $stderr.puts "Could not find main page #{main_page}"
- end
- end
-
- #
- # 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
-
- #
- # 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
-
- #
- # 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
-
-class RDoc::Generator::HTMLInOne < RDoc::Generator::HTML
-
- def initialize(*args)
- super
- end
-
- ##
- # Build the initial indices and output objects
- # based on an array of TopLevel objects containing
- # the extracted information.
-
- def generate(info)
- @toplevels = info
- @hyperlinks = {}
-
- build_indices
- generate_xml
- end
-
- ##
- # Generate:
- #
- # * a list of RDoc::Generator::File objects for each TopLevel object.
- # * a list of RDoc::Generator::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
- @files, @classes = RDoc::Generator::Context.build_indices(@toplevels,
- @options)
- end
-
- ##
- # Generate all the HTML. For the one-file case, we generate
- # all the information in to one big hash
-
- def generate_xml
- values = {
- 'charset' => @options.charset,
- 'files' => gen_into(@files),
- 'classes' => gen_into(@classes),
- 'title' => CGI.escapeHTML(@options.title),
- }
-
- template = RDoc::TemplatePage.new @template::ONE_PAGE
-
- if @options.op_name
- opfile = open @options.op_name, 'w'
- else
- opfile = $stdout
- end
- template.write_html_on(opfile, values)
- end
-
- def gen_into(list)
- res = []
- list.each do |item|
- res << item.value_hash
- end
- res
- end
-end
diff --git a/lib/rdoc/generator/html/common.rb b/lib/rdoc/generator/html/common.rb
deleted file mode 100644
index b25f009..0000000
--- a/lib/rdoc/generator/html/common.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-#
-# 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
deleted file mode 100644
index 0375fee..0000000
--- a/lib/rdoc/generator/html/frameless.rb
+++ /dev/null
@@ -1,92 +0,0 @@
-require 'rdoc/generator/html/html'
-
-##
-# = CSS2 RDoc HTML template
-#
-# 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>
-#
-# Copyright (c) 2002, 2003 The FaerieMUD Consortium. Some rights reserved.
-#
-# This work is licensed under the Creative Commons Attribution License. To view
-# a copy of this license, visit http://creativecommons.org/licenses/by/1.0/ or
-# send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California
-# 94305, USA.
-
-module RDoc::Generator::HTML::FRAMELESS
-
- FRAMELESS = true
-
- FONTS = RDoc::Generator::HTML::HTML::FONTS
-
- STYLE = RDoc::Generator::HTML::HTML::STYLE
-
- HEADER = RDoc::Generator::HTML::HTML::HEADER
-
- FOOTER = <<-EOF
- <div id="popupmenu" class="index">
- <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>
-<% end %>
- </ul>
-
- <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 = RDoc::Generator::HTML::HTML::FILE_PAGE
-
- CLASS_PAGE = RDoc::Generator::HTML::HTML::CLASS_PAGE
-
- METHOD_LIST = RDoc::Generator::HTML::HTML::METHOD_LIST
-
- BODY = HEADER + %{
-
-<%= template_include %> <!-- banner header -->
-
- <div id="bodyContent">
-
-} + METHOD_LIST + %{
-
- </div>
-
-} + FOOTER
-
- SRC_PAGE = RDoc::Generator::HTML::HTML::SRC_PAGE
-
- FR_INDEX_BODY = RDoc::Generator::HTML::HTML::FR_INDEX_BODY
-
- FILE_INDEX = RDoc::Generator::HTML::HTML::FILE_INDEX
-
- 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
deleted file mode 100644
index 01425a4..0000000
--- a/lib/rdoc/generator/html/hefss.rb
+++ /dev/null
@@ -1,150 +0,0 @@
-require 'rdoc/generator/html'
-require 'rdoc/generator/html/kilmerfactory'
-
-module RDoc::Generator::HTML::HEFSS
-
- FONTS = "Verdana, Arial, Helvetica, sans-serif"
-
- CENTRAL_STYLE = <<-EOF
-body,p { font-family: <%= values["fonts"] %>;
- color: #000040; background: #BBBBBB;
-}
-
-td { font-family: <%= values["fonts"] %>;
- color: #000040;
-}
-
-.attr-rw { font-size: small; color: #444488 }
-
-.title-row {color: #eeeeff;
- background: #BBBBDD;
-}
-
-.big-title-font { color: white;
- font-family: <%= values["fonts"] %>;
- font-size: large;
- height: 50px}
-
-.small-title-font { color: purple;
- font-family: <%= values["fonts"] %>;
- font-size: small; }
-
-.aqua { color: purple }
-
-#diagram img {
- border: 0;
-}
-
-.method-name, attr-name {
- font-family: monospace; font-weight: bold;
-}
-
-.tablesubtitle {
- width: 100%;
- margin-top: 1ex;
- margin-bottom: .5ex;
- padding: 5px 0px 5px 20px;
- font-size: large;
- color: purple;
- background: #BBBBCC;
-}
-
-.tablesubsubtitle {
- width: 100%;
- margin-top: 1ex;
- margin-bottom: .5ex;
- padding: 5px 0px 5px 20px;
- font-size: medium;
- color: white;
- background: #BBBBCC;
-}
-
-.name-list {
- font-family: monospace;
- margin-left: 40px;
- margin-bottom: 2ex;
- line-height: 140%;
-}
-
-.description {
- margin-left: 40px;
- margin-bottom: 2ex;
- line-height: 140%;
-}
-
-.methodtitle {
- font-size: medium;
- text_decoration: none;
- padding: 3px 3px 3px 20px;
- color: #0000AA;
-}
-
-.ruby-comment { color: green; font-style: italic }
-.ruby-constant { color: #4433aa; font-weight: bold; }
-.ruby-identifier { color: #222222; }
-.ruby-ivar { color: #2233dd; }
-.ruby-keyword { color: #3333FF; font-weight: bold }
-.ruby-node { color: #777777; }
-.ruby-operator { color: #111111; }
-.ruby-regexp { color: #662222; }
-.ruby-value { color: #662222; font-style: italic }
-
-.srcbut { float: right }
- EOF
-
- INDEX_STYLE = <<-EOF
-body {
- background-color: #bbbbbb;
- font-family: #{FONTS};
- font-size: 11px;
- font-style: normal;
- line-height: 14px;
- color: #000040;
-}
-
-div.banner {
- background: #bbbbcc;
- color: white;
- padding: 1;
- margin: 0;
- font-size: 90%;
- font-weight: bold;
- line-height: 1.1;
- text-align: center;
- width: 100%;
-}
-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")
-
- STYLE = FACTORY.get_STYLE()
-
- METHOD_LIST = FACTORY.get_METHOD_LIST()
-
- BODY = FACTORY.get_BODY()
-
- FILE_PAGE = FACTORY.get_FILE_PAGE()
-
- CLASS_PAGE = FACTORY.get_CLASS_PAGE()
-
- SRC_PAGE = FACTORY.get_SRC_PAGE()
-
- FR_INDEX_BODY = FACTORY.get_FR_INDEX_BODY()
-
- 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
deleted file mode 100644
index 5e5b4d5..0000000
--- a/lib/rdoc/generator/html/html.rb
+++ /dev/null
@@ -1,769 +0,0 @@
-require 'rdoc/generator/html'
-require 'rdoc/generator/html/common'
-
-##
-# = CSS2 RDoc HTML template
-#
-# 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>
-#
-# Copyright (c) 2002, 2003 The FaerieMUD Consortium. Some rights reserved.
-#
-# This work is licensed under the Creative Commons Attribution License. To
-# view a copy of this license, visit
-# http://creativecommons.org/licenses/by/1.0/ or send a letter to Creative
-# Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
-
-module RDoc::Generator::HTML::HTML
-
- include RDoc::Generator::HTML::Common
-
- FONTS = "Verdana,Arial,Helvetica,sans-serif"
-
- STYLE = <<-EOF
-body {
- font-family: #{FONTS};
- font-size: 90%;
- margin: 0;
- margin-left: 40px;
- padding: 0;
- background: white;
- color: black;
-}
-
-h1, h2, h3, h4 {
- margin: 0;
- 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;
-}
-
-#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;
-}
-
-.type-note {
- font-size: small;
- color: #dedede;
-}
-
-.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
-}
-
-#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;
-}
-
-/* --- 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: auto;
-}
-
-div.method-source-code pre {
- color: #ffdead;
-}
-
-/* --- Ruby keyword styles --------------------- */
-
-.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;
-}
-EOF
-
-
-#####################################################################
-### H E A D E R T E M P L A T E
-#####################################################################
-
- HEADER = XHTML_STRICT_PREAMBLE + HTML_ELEMENT + <<-EOF
-<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
-
-#####################################################################
-### F O O T E R T E M P L A T E
-#####################################################################
-
- FOOTER = <<-EOF
-<div id="validator-badges">
- <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
-</div>
-
-</body>
-</html>
- EOF
-
-
-#####################################################################
-### F I L E P A G E H E A D E R T E M P L A T E
-#####################################################################
-
- FILE_PAGE = <<-EOF
- <div id="fileHeader">
- <h1><%= values["short_name"] %></h1>
- <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
-
-#####################################################################
-### C L A S S P A G E H E A D E R T E M P L A T E
-#####################################################################
-
- 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
-
-#####################################################################
-### M E T H O D L I S T T E M P L A T E
-#####################################################################
-
- 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="#<%= toc["href"] %>"><%= toc["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 sections["classlist"] then %>
- <div id="class-list">
- <h3 class="section-bar">Classes and Modules</h3>
-
- <%= sections["classlist"] %>
- </div>
-<% end
-
- if sections["constants"] then %>
- <div id="constants-list">
- <h3 class="section-bar">Constants</h3>
-
- <div class="name-list">
- <table summary="Constants">
-<% sections["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 constants["desc"] then %>
- <td>&nbsp;</td>
- <td class="context-item-desc"><%= constants["desc"] %></td>
-<% end %>
- </tr>
-<% end %><%# sections["constants"] %>
- </table>
- </div>
- </div>
-<% end
-
- if sections["aliases"] then %>
- <div id="aliases-list">
- <h3 class="section-bar">External Aliases</h3>
-
- <div class="name-list">
- <table summary="aliases">
-<% sections["aliases"].each do |aliases| %>
- <tr class="top-aligned-row context-row">
- <td class="context-item-name"><%= aliases["old_name"] %></td>
- <td>-&gt;</td>
- <td class="context-item-value"><%= aliases["new_name"] %></td>
- </tr>
-<% if aliases["desc"] then %>
- <tr class="top-aligned-row context-row">
- <td>&nbsp;</td>
- <td colspan="2" class="context-item-desc"><%= aliases["desc"] %></td>
- </tr>
-<% end
- end %><%# sections["aliases"] %>
- </table>
- </div>
- </div>
-<% end %>
-
-<% if sections["attributes"] then %>
- <div id="attribute-list">
- <h3 class="section-bar">Attributes</h3>
-
- <div class="name-list">
- <table>
-<% sections["attributes"].each do |attribute| %>
- <tr class="top-aligned-row context-row">
- <td class="context-item-name"><%= attribute["name"] %></td>
-<% if attribute["rw"] then %>
- <td class="context-item-value">&nbsp;[<%= attribute["rw"] %>]&nbsp;</td>
-<% end
- unless attribute["rw"] then %>
- <td class="context-item-value">&nbsp;&nbsp;</td>
-<% end %>
- <td class="context-item-desc"><%= attribute["a_desc"] %></td>
- </tr>
-<% end %><%# sections["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
-
-#####################################################################
-### B O D Y T E M P L A T E
-#####################################################################
-
- BODY = HEADER + %{
-
-<%= template_include %> <!-- banner header -->
-
- <div id="bodyContent">
-
-} + METHOD_LIST + %{
-
- </div>
-
-} + FOOTER
-
-#####################################################################
-### S O U R C E C O D E T E M P L A T E
-#####################################################################
-
- SRC_PAGE = XHTML_STRICT_PREAMBLE + HTML_ELEMENT + <<-EOF
-<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
-
-
-#####################################################################
-### I N D E X F I L E T E M P L A T E S
-#####################################################################
-
- FR_INDEX_BODY = %{<%= template_include %>}
-
- FILE_INDEX = XHTML_STRICT_PREAMBLE + HTML_ELEMENT + <<-EOF
-<!--
-
- <%= values["title"] %>
-
- -->
-<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" />
- <base target="docwin" />
-</head>
-<body>
-<div class="index">
- <h1 class="section-bar"><%= values["list_title"] %></h1>
- <div id="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 = XHTML_FRAME_PREAMBLE + HTML_ELEMENT + <<-EOF
-<!--
-
- <%= values["title"] %>
-
- -->
-<head>
- <title><%= values["title"] %></title>
- <meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
-</head>
-<frameset rows="20%, 80%">
- <frameset cols="25%,35%,45%">
- <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>
- <frame src="<%= values["initial_page"] %>" name="docwin" />
-</frameset>
-</html>
- EOF
-
-end
-
diff --git a/lib/rdoc/generator/html/kilmer.rb b/lib/rdoc/generator/html/kilmer.rb
deleted file mode 100644
index 233a925..0000000
--- a/lib/rdoc/generator/html/kilmer.rb
+++ /dev/null
@@ -1,151 +0,0 @@
-require 'rdoc/generator/html'
-require 'rdoc/generator/html/kilmerfactory'
-
-module RDoc::Generator::HTML::KILMER
-
- FONTS = "Verdana, Arial, Helvetica, sans-serif"
-
- CENTRAL_STYLE = <<-EOF
-body,td,p { font-family: <%= values["fonts"] %>;
- color: #000040;
-}
-
-.attr-rw { font-size: xx-small; color: #444488 }
-
-.title-row { background-color: #CCCCFF;
- color: #000010;
-}
-
-.big-title-font {
- color: black;
- font-weight: bold;
- font-family: <%= values["fonts"] %>;
- font-size: large;
- height: 60px;
- padding: 10px 3px 10px 3px;
-}
-
-.small-title-font { color: black;
- font-family: <%= values["fonts"] %>;
- font-size:10; }
-
-.aqua { color: black }
-
-#diagram img {
- border: 0;
-}
-
-.method-name, .attr-name {
- font-family: font-family: <%= values["fonts"] %>;
- font-weight: bold;
- font-size: small;
- margin-left: 20px;
- color: #000033;
-}
-
-.tablesubtitle, .tablesubsubtitle {
- width: 100%;
- margin-top: 1ex;
- margin-bottom: .5ex;
- padding: 5px 0px 5px 3px;
- font-size: large;
- color: black;
- background-color: #CCCCFF;
- border: thin;
-}
-
-.name-list {
- margin-left: 5px;
- margin-bottom: 2ex;
- line-height: 105%;
-}
-
-.description {
- margin-left: 5px;
- margin-bottom: 2ex;
- line-height: 105%;
- font-size: small;
-}
-
-.methodtitle {
- font-size: small;
- font-weight: bold;
- text-decoration: none;
- color: #000033;
- background: #ccc;
-}
-
-.srclink {
- font-size: small;
- font-weight: bold;
- text-decoration: none;
- color: #0000DD;
- background-color: white;
-}
-
-.srcbut { float: right }
-
-.ruby-comment { color: green; font-style: italic }
-.ruby-constant { color: #4433aa; font-weight: bold; }
-.ruby-identifier { color: #222222; }
-.ruby-ivar { color: #2233dd; }
-.ruby-keyword { color: #3333FF; font-weight: bold }
-.ruby-node { color: #777777; }
-.ruby-operator { color: #111111; }
-.ruby-regexp { color: #662222; }
-.ruby-value { color: #662222; font-style: italic }
- EOF
-
- INDEX_STYLE = <<-EOF
-body {
- background-color: #ddddff;
- font-family: #{FONTS};
- font-size: 11px;
- font-style: normal;
- line-height: 14px;
- color: #000040;
-}
-
-div.banner {
- background: #0000aa;
- color: white;
- padding: 1;
- margin: 0;
- font-size: 90%;
- font-weight: bold;
- line-height: 1.1;
- text-align: center;
- width: 100%;
-}
-EOF
-
- FACTORY = RDoc::Generator::HTML::
- KilmerFactory.new(:central_css => CENTRAL_STYLE,
- :index_css => INDEX_STYLE)
-
- STYLE = FACTORY.get_STYLE()
-
- METHOD_LIST = FACTORY.get_METHOD_LIST()
-
- BODY = FACTORY.get_BODY()
-
- FILE_PAGE = FACTORY.get_FILE_PAGE()
-
- CLASS_PAGE = FACTORY.get_CLASS_PAGE()
-
- SRC_PAGE = FACTORY.get_SRC_PAGE()
-
- FR_INDEX_BODY = FACTORY.get_FR_INDEX_BODY()
-
- 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
deleted file mode 100644
index 1407840..0000000
--- a/lib/rdoc/generator/html/kilmerfactory.rb
+++ /dev/null
@@ -1,427 +0,0 @@
-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
deleted file mode 100644
index 5bae2f3..0000000
--- a/lib/rdoc/generator/html/one_page_html.rb
+++ /dev/null
@@ -1,122 +0,0 @@
-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"] %>
-<% end %>
-
-<% if defined? files and files["requires"] then %>
-<h4>Requires:</h4>
-<ul>
-<% files["requires"].each do |requires| %>
-<% if requires["aref"] then %>
-<li><a href="<%= requires["aref"] %>"><%= requires["name"] %></a></li>
-<% end %>
-<% unless requires["aref"] then %>
-<li><%= requires["name"] %></li>
-<% end %>
-<% end %><%# files["requires"] %>
-</ul>
-<% end %>
-
-<% if defined? classes and classes["includes"] then %>
-<h4>Includes</h4>
-<ul>
-<% classes["includes"].each do |includes| %>
-<% if includes["aref"] then %>
-<li><a href="<%= includes["aref"] %>"><%= includes["name"] %></a></li>
-<% end %>
-<% unless includes["aref"] then %>
-<li><%= includes["name"] %></li>
-<% end %>
-<% end %><%# classes["includes"] %>
-</ul>
-<% end %>
-
-<% if defined? classes and classes["sections"] then %>
-<% classes["sections"].each do |sections| %>
-<% if sections["attributes"] then %>
-<h4>Attributes</h4>
-<table>
-<% sections["attributes"].each do |attributes| %>
-<tr><td><%= attributes["name"] %></td><td><%= attributes["rw"] %></td><td><%= attributes["a_desc"] %></td></tr>
-<% end %><%# sections["attributes"] %>
-</table>
-<% end %>
-
-<% if sections["method_list"] then %>
-<h3>Methods</h3>
-<% sections["method_list"].each do |method_list| %>
-<% if method_list["methods"] then %>
-<% method_list["methods"].each do |methods| %>
-<h4><%= methods["type"] %> <%= methods["category"] %> method:
-<% if methods["callseq"] then %>
-<a name="<%= methods["aref"] %>"><%= methods["callseq"] %></a>
-<% end %>
-<% unless methods["callseq"] then %>
-<a name="<%= methods["aref"] %>"><%= methods["name"] %><%= methods["params"] %></a></h4>
-<% end %>
-
-<% if methods["m_desc"] then %>
-<%= methods["m_desc"] %>
-<% end %>
-
-<% if methods["sourcecode"] then %>
-<blockquote><pre>
-<%= methods["sourcecode"] %>
-</pre></blockquote>
-<% end %>
-<% end %><%# method_list["methods"] %>
-<% end %>
-<% end %><%# sections["method_list"] %>
-<% end %>
-<% end %><%# classes["sections"] %>
-<% end %>
- EOF
-
- 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: <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>
-</table>
-} + CONTENTS_XML + %{
-<% end %><%# values["files"] %>
-
-<% if values["classes"] then %>
-<h2>Classes</h2>
-<% values["classes"].each do |classes| %>
-<% if classes["parent"] then %>
-<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>
-<% end %>
-
-<% if classes["infiles"] then %>
-(in files
-<% classes["infiles"].each do |infiles| %>
-<%= href infiles["full_path_url"], infiles["full_path"] %>
-<% end %><%# classes["infiles"] %>
-)
-<% end %>
-} + CONTENTS_XML + %{
-<% end %><%# values["classes"] %>
-<% end %>
-</body>
-</html>
-}
-
-end
-
diff --git a/lib/rdoc/generator/markup.rb b/lib/rdoc/generator/markup.rb
new file mode 100644
index 0000000..a90b15a
--- /dev/null
+++ b/lib/rdoc/generator/markup.rb
@@ -0,0 +1,171 @@
+require 'rdoc/text'
+require 'rdoc/code_objects'
+require 'rdoc/generator'
+require 'rdoc/markup/to_html_crossref'
+
+##
+# Handle common RDoc::Markup tasks for various CodeObjects
+
+module RDoc::Generator::Markup
+
+ ##
+ # Generates a relative URL from this object's path to +target_path+
+
+ def aref_to(target_path)
+ RDoc::Markup::ToHtml.gen_relative_url path, target_path
+ end
+
+ ##
+ # Generates a relative URL from +from_path+ to this object's path
+
+ def as_href(from_path)
+ RDoc::Markup::ToHtml.gen_relative_url from_path, path
+ end
+
+ ##
+ # Handy wrapper for marking up this object's comment
+
+ def description
+ markup @comment
+ end
+
+ ##
+ # Creates an RDoc::Markup::ToHtmlCrossref formatter
+
+ def formatter
+ return @formatter if defined? @formatter
+
+ show_hash = RDoc::RDoc.current.options.show_hash
+ this = RDoc::Context === self ? self : @parent
+ @formatter = RDoc::Markup::ToHtmlCrossref.new this.path, this, show_hash
+ end
+
+ ##
+ # Build a webcvs URL starting for the given +url+ with +full_path+ appended
+ # as the destination path. If +url+ contains '%s' +full_path+ will be
+ # sprintf'd into +url+ instead.
+
+ def cvs_url(url, full_path)
+ if /%s/ =~ url then
+ sprintf url, full_path
+ else
+ url + full_path
+ end
+ end
+
+end
+
+class RDoc::AnyMethod
+
+ include RDoc::Generator::Markup
+
+ ##
+ # Prepend +src+ with line numbers. Relies on the first line of a source
+ # code listing having:
+ #
+ # # File xxxxx, line dddd
+
+ def add_line_numbers(src)
+ if src =~ /\A.*, line (\d+)/ then
+ first = $1.to_i - 1
+ last = first + src.count("\n")
+ size = last.to_s.length
+
+ line = first
+ src.gsub!(/^/) do
+ res = if line == first then
+ " " * (size + 2)
+ else
+ "%2$*1$d: " % [size, line]
+ end
+
+ line += 1
+ res
+ end
+ end
+ end
+
+ ##
+ # Turns the method's token stream into HTML
+
+ def markup_code
+ return '' unless @token_stream
+
+ src = ""
+
+ @token_stream.each do |t|
+ next unless t
+ # style = STYLE_MAP[t.class]
+ style = case t
+ when RDoc::RubyToken::TkCONSTANT then "ruby-constant"
+ when RDoc::RubyToken::TkKW then "ruby-keyword kw"
+ when RDoc::RubyToken::TkIVAR then "ruby-ivar"
+ when RDoc::RubyToken::TkOp then "ruby-operator"
+ when RDoc::RubyToken::TkId then "ruby-identifier"
+ when RDoc::RubyToken::TkNode then "ruby-node"
+ when RDoc::RubyToken::TkCOMMENT then "ruby-comment cmt"
+ when RDoc::RubyToken::TkREGEXP then "ruby-regexp re"
+ when RDoc::RubyToken::TkSTRING then "ruby-value str"
+ when RDoc::RubyToken::TkVal then "ruby-value"
+ else
+ nil
+ end
+
+ text = CGI.escapeHTML t.text
+
+ if style
+ src << "<span class=\"#{style}\">#{text}</span>"
+ else
+ src << text
+ end
+ end
+
+ add_line_numbers src
+
+ src
+ end
+
+end
+
+class RDoc::Attr
+
+ include RDoc::Generator::Markup
+
+end
+
+class RDoc::Constant
+
+ include RDoc::Generator::Markup
+
+end
+
+class RDoc::Context
+
+ include RDoc::Generator::Markup
+
+end
+
+class RDoc::Context::Section
+
+ include RDoc::Generator::Markup
+
+end
+
+class RDoc::TopLevel
+
+ ##
+ # Returns a URL for this source file on some web repository. Use the -W
+ # command line option to set.
+
+ def cvs_url
+ url = RDoc::RDoc.current.options.webcvs
+
+ if /%s/ =~ url then
+ url % @absolute_name
+ else
+ url + @absolute_name
+ end
+ end
+
+end
+
diff --git a/lib/rdoc/generator/ri.rb b/lib/rdoc/generator/ri.rb
index 6b7a593..ad9932a 100644
--- a/lib/rdoc/generator/ri.rb
+++ b/lib/rdoc/generator/ri.rb
@@ -1,225 +1,79 @@
require 'rdoc/generator'
-require 'rdoc/markup/to_flow'
+require 'rdoc/ri'
-require 'rdoc/ri/cache'
-require 'rdoc/ri/reader'
-require 'rdoc/ri/writer'
-require 'rdoc/ri/descriptions'
+##
+# Generates ri data files
class RDoc::Generator::RI
- ##
- # Generator may need to return specific subclasses depending on the
- # options they are passed. Because of this we create them using a factory
+ RDoc::RDoc.add_generator self
- def self.for(options)
- new(options)
+ def self.for options
+ new options
end
##
# Set up a new ri generator
- def initialize(options) #:not-new:
- @options = options
- @ri_writer = RDoc::RI::Writer.new "."
- @markup = RDoc::Markup.new
- @to_flow = RDoc::Markup::ToFlow.new
-
- @generated = {}
+ def initialize options #:not-new:
+ @options = options
+ @store = RDoc::RI::Store.new '.'
+ @old_siginfo = nil
+ @current = nil
end
##
- # Build the initial indices and output objects based on an array of
- # TopLevel objects containing the extracted information.
-
- def generate(toplevels)
- RDoc::TopLevel.all_classes_and_modules.each do |cls|
- process_class cls
- end
- end
-
- def process_class(from_class)
- generate_class_info(from_class)
+ # Build the initial indices and output objects based on an array of TopLevel
+ # objects containing the extracted information.
- # now recurse into this class' constituent classes
- from_class.each_classmodule do |mod|
- process_class(mod)
- end
- end
-
- def generate_class_info(cls)
- case cls
- when RDoc::NormalModule then
- cls_desc = RDoc::RI::ModuleDescription.new
- else
- cls_desc = RDoc::RI::ClassDescription.new
- cls_desc.superclass = cls.superclass
- end
+ def generate top_levels
+ install_siginfo_handler
- cls_desc.name = cls.name
- cls_desc.full_name = cls.full_name
- cls_desc.comment = markup(cls.comment)
+ RDoc::TopLevel.all_classes_and_modules.each do |klass|
+ @current = "#{klass.class}: #{klass.full_name}"
- cls_desc.attributes = cls.attributes.sort.map do |a|
- RDoc::RI::Attribute.new(a.name, a.rw, markup(a.comment))
- end
+ @store.save_class klass
- cls_desc.constants = cls.constants.map do |c|
- RDoc::RI::Constant.new(c.name, c.value, markup(c.comment))
- end
-
- cls_desc.includes = cls.includes.map do |i|
- RDoc::RI::IncludedModule.new(i.name)
- end
-
- class_methods, instance_methods = method_list(cls)
-
- cls_desc.class_methods = class_methods.map do |m|
- RDoc::RI::MethodSummary.new(m.name)
- end
-
- cls_desc.instance_methods = instance_methods.map do |m|
- RDoc::RI::MethodSummary.new(m.name)
- end
-
- update_or_replace(cls_desc)
-
- class_methods.each do |m|
- generate_method_info(cls_desc, m)
- end
+ klass.each_method do |method|
+ @current = "#{method.class}: #{method.full_name}"
+ @store.save_method klass, method
+ end
- instance_methods.each do |m|
- generate_method_info(cls_desc, m)
+ klass.each_attribute do |attribute|
+ @store.save_method klass, attribute
+ end
end
- end
- def generate_method_info(cls_desc, method)
- meth_desc = RDoc::RI::MethodDescription.new
- meth_desc.name = method.name
- meth_desc.full_name = cls_desc.full_name
- if method.singleton
- meth_desc.full_name += "::"
- else
- meth_desc.full_name += "#"
- end
- meth_desc.full_name << method.name
+ @current = 'saving cache'
- meth_desc.comment = markup(method.comment)
- meth_desc.params = params_of(method)
- meth_desc.visibility = method.visibility.to_s
- meth_desc.is_singleton = method.singleton
- meth_desc.block_params = method.block_params
+ @store.save_cache
- meth_desc.aliases = method.aliases.map do |a|
- RDoc::RI::AliasName.new(a.name)
- end
+ ensure
+ @current = nil
- @ri_writer.add_method(cls_desc, meth_desc)
+ remove_siginfo_handler
end
- private
-
##
- # Returns a list of class and instance methods that we'll be documenting
-
- def method_list(cls)
- list = cls.method_list
- unless @options.show_all
- list = list.find_all do |m|
- m.visibility == :public || m.visibility == :protected || m.force_documentation
- end
- end
+ # Installs a siginfo handler that prints the current filename.
- c = []
- i = []
- list.sort.each do |m|
- if m.singleton
- c << m
- else
- i << m
- end
- end
- return c,i
- end
+ def install_siginfo_handler
+ return unless Signal.list.key? 'INFO'
- def params_of(method)
- if method.call_seq
- method.call_seq
- else
- params = method.params || ""
-
- p = params.gsub(/\s*\#.*/, '')
- p = p.tr("\n", " ").squeeze(" ")
- p = "(" + p + ")" unless p[0] == ?(
-
- if (block = method.block_params)
- block.gsub!(/\s*\#.*/, '')
- block = block.tr("\n", " ").squeeze(" ")
- if block[0] == ?(
- block.sub!(/^\(/, '').sub!(/\)/, '')
- end
- p << " {|#{block.strip}| ...}"
- end
- p
+ @old_siginfo = trap 'INFO' do
+ puts @current if @current
end
end
- def markup(comment)
- return nil if !comment || comment.empty?
-
- # Convert leading comment markers to spaces, but only
- # if all non-blank lines have them
-
- if comment =~ /^(?>\s*)[^\#]/
- content = comment
- else
- content = comment.gsub(/^\s*(#+)/) { $1.tr('#',' ') }
- end
- @markup.convert(content, @to_flow)
- end
-
##
- # By default we replace existing classes with the same name. If the
- # --merge option was given, we instead merge this definition into an
- # existing class. We add our methods, aliases, etc to that class, but do
- # not change the class's description.
-
- def update_or_replace(cls_desc)
- old_cls = nil
-
- if @options.merge
- rdr = RDoc::RI::Reader.new RDoc::RI::Cache.new(@options.op_dir)
-
- namespace = rdr.top_level_namespace
- namespace = rdr.lookup_namespace_in(cls_desc.name, namespace)
- if namespace.empty?
- $stderr.puts "You asked me to merge this source into existing "
- $stderr.puts "documentation. This file references a class or "
- $stderr.puts "module called #{cls_desc.name} which I don't"
- $stderr.puts "have existing documentation for."
- $stderr.puts
- $stderr.puts "Perhaps you need to generate its documentation first"
- exit 1
- else
- old_cls = namespace[0]
- end
- end
-
- prev_cls = @generated[cls_desc.full_name]
+ # Removes a siginfo handler and replaces the previous
- if old_cls and not prev_cls then
- old_desc = rdr.get_class old_cls
- cls_desc.merge_in old_desc
- end
-
- if prev_cls then
- cls_desc.merge_in prev_cls
- end
+ def remove_siginfo_handler
+ return unless Signal.list.key? 'INFO'
- @generated[cls_desc.full_name] = cls_desc
+ handler = @old_siginfo || 'DEFAULT'
- @ri_writer.remove_class cls_desc
- @ri_writer.add_class cls_desc
+ trap 'INFO', handler
end
end
diff --git a/test/rdoc/empty.dat b/lib/rdoc/generator/template/darkfish/.document
index e69de29..e69de29 100644
--- a/test/rdoc/empty.dat
+++ b/lib/rdoc/generator/template/darkfish/.document
diff --git a/lib/rdoc/generator/template/darkfish/classpage.rhtml b/lib/rdoc/generator/template/darkfish/classpage.rhtml
new file mode 100644
index 0000000..58e87e6
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/classpage.rhtml
@@ -0,0 +1,297 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <meta content="text/html; charset=<%= @options.charset %>" http-equiv="Content-Type" />
+
+ <title><%= klass.type.capitalize %>: <%= klass.full_name %></title>
+
+ <link rel="stylesheet" href="<%= rel_prefix %>/rdoc.css" type="text/css" media="screen" />
+
+ <script src="<%= rel_prefix %>/js/jquery.js" type="text/javascript"
+ charset="utf-8"></script>
+ <script src="<%= rel_prefix %>/js/thickbox-compressed.js" type="text/javascript"
+ charset="utf-8"></script>
+ <script src="<%= rel_prefix %>/js/quicksearch.js" type="text/javascript"
+ charset="utf-8"></script>
+ <script src="<%= rel_prefix %>/js/darkfish.js" type="text/javascript"
+ charset="utf-8"></script>
+
+</head>
+<body class="<%= klass.type %>">
+
+ <div id="metadata">
+ <div id="home-metadata">
+ <div id="home-section" class="section">
+ <h3 class="section-header">
+ <a href="<%= rel_prefix %>/index.html">Home</a>
+ <a href="<%= rel_prefix %>/index.html#classes">Classes</a>
+ <a href="<%= rel_prefix %>/index.html#methods">Methods</a>
+ </h3>
+ </div>
+ </div>
+
+ <div id="file-metadata">
+ <div id="file-list-section" class="section">
+ <h3 class="section-header">In Files</h3>
+ <div class="section-body">
+ <ul>
+ <% klass.in_files.each do |tl| %>
+ <li><a href="<%= rel_prefix %>/<%= h tl.path %>?TB_iframe=true&amp;height=550&amp;width=785"
+ class="thickbox" title="<%= h tl.absolute_name %>"><%= h tl.absolute_name %></a></li>
+ <% end %>
+ </ul>
+ </div>
+ </div>
+
+ <% if !svninfo.empty? %>
+ <div id="file-svninfo-section" class="section">
+ <h3 class="section-header">Subversion Info</h3>
+ <div class="section-body">
+ <dl class="svninfo">
+ <dt>Rev</dt>
+ <dd><%= svninfo[:rev] %></dd>
+
+ <dt>Last Checked In</dt>
+ <dd><%= svninfo[:commitdate].strftime('%Y-%m-%d %H:%M:%S') %>
+ (<%= svninfo[:commitdelta] %> ago)</dd>
+
+ <dt>Checked in by</dt>
+ <dd><%= svninfo[:committer] %></dd>
+ </dl>
+ </div>
+ </div>
+ <% end %>
+ </div>
+
+ <div id="class-metadata">
+
+ <!-- Parent Class -->
+ <% if klass.type == 'class' %>
+ <div id="parent-class-section" class="section">
+ <h3 class="section-header">Parent</h3>
+ <% unless String === klass.superclass %>
+ <p class="link"><a href="<%= klass.aref_to klass.superclass.path %>"><%= klass.superclass.full_name %></a></p>
+ <% else %>
+ <p class="link"><%= klass.superclass %></p>
+ <% end %>
+ </div>
+ <% end %>
+
+ <!-- Namespace Contents -->
+ <% unless klass.classes_and_modules.empty? %>
+ <div id="namespace-list-section" class="section">
+ <h3 class="section-header">Namespace</h3>
+ <ul class="link-list">
+ <% (klass.modules.sort + klass.classes.sort).each do |mod| %>
+ <li><span class="type"><%= mod.type.upcase %></span> <a href="<%= klass.aref_to mod.path %>"><%= mod.full_name %></a></li>
+ <% end %>
+ </ul>
+ </div>
+ <% end %>
+
+ <!-- Method Quickref -->
+ <% unless klass.method_list.empty? %>
+ <div id="method-list-section" class="section">
+ <h3 class="section-header">Methods</h3>
+ <ul class="link-list">
+ <% klass.each_method do |meth| %>
+ <li><a href="#<%= meth.aref %>"><%= meth.singleton ? '::' : '#' %><%= meth.name %></a></li>
+ <% end %>
+ </ul>
+ </div>
+ <% end %>
+
+ <!-- Included Modules -->
+ <% unless klass.includes.empty? %>
+ <div id="includes-section" class="section">
+ <h3 class="section-header">Included Modules</h3>
+ <ul class="link-list">
+ <% klass.each_include do |inc| %>
+ <% unless String === inc.module %>
+ <li><a class="include" href="<%= klass.aref_to inc.module.path %>"><%= inc.module.full_name %></a></li>
+ <% else %>
+ <li><span class="include"><%= inc.name %></span></li>
+ <% end %>
+ <% end %>
+ </ul>
+ </div>
+ <% end %>
+ </div>
+
+ <div id="project-metadata">
+ <% simple_files = @files.select {|tl| tl.parser == RDoc::Parser::Simple } %>
+ <% unless simple_files.empty? then %>
+ <div id="fileindex-section" class="section project-section">
+ <h3 class="section-header">Files</h3>
+ <ul>
+ <% simple_files.each do |file| %>
+ <li class="file"><a href="<%= rel_prefix %>/<%= file.path %>"><%= h file.base_name %></a></li>
+ <% end %>
+ </ul>
+ </div>
+ <% end %>
+
+ <div id="classindex-section" class="section project-section">
+ <h3 class="section-header">Class Index
+ <span class="search-toggle"><img src="<%= rel_prefix %>/images/find.png"
+ height="16" width="16" alt="[+]"
+ title="show/hide quicksearch" /></span></h3>
+ <form action="#" method="get" accept-charset="utf-8" class="initially-hidden">
+ <fieldset>
+ <legend>Quicksearch</legend>
+ <input type="text" name="quicksearch" value=""
+ class="quicksearch-field" />
+ </fieldset>
+ </form>
+
+ <ul class="link-list">
+ <% @modsort.each do |index_klass| %>
+ <li><a href="<%= rel_prefix %>/<%= index_klass.path %>"><%= index_klass.full_name %></a></li>
+ <% end %>
+ </ul>
+ <div id="no-class-search-results" style="display: none;">No matching classes.</div>
+ </div>
+
+ <% if $DEBUG_RDOC %>
+ <div id="debugging-toggle"><img src="<%= rel_prefix %>/images/bug.png"
+ alt="toggle debugging" height="16" width="16" /></div>
+ <% end %>
+ </div>
+ </div>
+
+ <div id="documentation">
+ <h1 class="<%= klass.type %>"><%= klass.full_name %></h1>
+
+ <div id="description">
+ <%= klass.description %>
+ </div>
+
+ <!-- Constants -->
+ <% unless klass.constants.empty? %>
+ <div id="constants-list" class="section">
+ <h3 class="section-header">Constants</h3>
+ <dl>
+ <% klass.each_constant do |const| %>
+ <dt><a name="<%= const.name %>"><%= const.name %></a></dt>
+ <% if const.comment %>
+ <dd class="description"><%= const.description.strip %></dd>
+ <% else %>
+ <dd class="description missing-docs">(Not documented)</dd>
+ <% end %>
+ <% end %>
+ </dl>
+ </div>
+ <% end %>
+
+ <!-- Attributes -->
+ <% unless klass.attributes.empty? %>
+ <div id="attribute-method-details" class="method-section section">
+ <h3 class="section-header">Attributes</h3>
+
+ <% klass.each_attribute do |attrib| %>
+ <div id="<%= attrib.html_name %>-attribute-method" class="method-detail">
+ <a name="<%= h attrib.name %>"></a>
+ <% if attrib.rw =~ /w/i %>
+ <a name="<%= h attrib.name %>="></a>
+ <% end %>
+ <div class="method-heading attribute-method-heading">
+ <span class="method-name"><%= h attrib.name %></span><span
+ class="attribute-access-type">[<%= attrib.rw %>]</span>
+ </div>
+
+ <div class="method-description">
+ <% if attrib.comment %>
+ <%= attrib.description.strip %>
+ <% else %>
+ <p class="missing-docs">(Not documented)</p>
+ <% end %>
+ </div>
+ </div>
+ <% end %>
+ </div>
+ <% end %>
+
+ <!-- Methods -->
+ <% klass.methods_by_type.each do |type, visibilities|
+ next if visibilities.empty?
+ visibilities.each do |visibility, methods|
+ next if methods.empty? %>
+ <div id="<%= visibility %>-<%= type %>-method-details" class="method-section section">
+ <h3 class="section-header"><%= visibility.to_s.capitalize %> <%= type.capitalize %> Methods</h3>
+
+ <% methods.each do |method| %>
+ <div id="<%= method.html_name %>-method" class="method-detail <%= method.is_alias_for ? "method-alias" : '' %>">
+ <a name="<%= h method.aref %>"></a>
+
+ <div class="method-heading">
+ <% if method.call_seq %>
+ <span class="method-callseq"><%= method.call_seq.strip.gsub(/->/, '&rarr;').gsub( /^\w.+\./m, '') %></span>
+ <span class="method-click-advice">click to toggle source</span>
+ <% else %>
+ <span class="method-name"><%= h method.name %></span><span
+ class="method-args"><%= method.params %></span>
+ <span class="method-click-advice">click to toggle source</span>
+ <% end %>
+ </div>
+
+ <div class="method-description">
+ <% if method.comment %>
+ <%= method.description.strip %>
+ <% else %>
+ <p class="missing-docs">(Not documented)</p>
+ <% end %>
+
+ <% if method.token_stream %>
+ <div class="method-source-code"
+ id="<%= method.html_name %>-source">
+<pre>
+<%= method.markup_code %>
+</pre>
+ </div>
+ <% end %>
+ </div>
+
+ <% unless method.aliases.empty? %>
+ <div class="aliases">
+ Also aliased as: <%= method.aliases.map do |aka|
+ %{<a href="#{ klass.aref_to aka.path}">#{h aka.name}</a>}
+ end.join(", ") %>
+ </div>
+ <% end %>
+
+ <% if method.is_alias_for then %>
+ <div class="aliases">
+ Alias for: <a href="<%= klass.aref_to method.is_alias_for.path %>"><%= h method.is_alias_for.name %></a>
+ </div>
+ <% end %>
+ </div>
+
+ <% end %>
+ </div>
+ <% end
+ end %>
+
+ </div>
+
+
+ <div id="rdoc-debugging-section-dump" class="debugging-section">
+ <% if $DEBUG_RDOC
+ require 'pp' %>
+<pre><%= h PP.pp(klass, _erbout) %></pre>
+ </div>
+ <% else %>
+ <p>Disabled; run with --debug to generate this.</p>
+ <% end %>
+ </div>
+
+ <div id="validator-badges">
+ <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
+ <p><small>Generated with the <a href="http://deveiate.org/projects/Darkfish-Rdoc/">Darkfish
+ Rdoc Generator</a> <%= RDoc::Generator::Darkfish::VERSION %></small>.</p>
+ </div>
+
+</body>
+</html>
+
diff --git a/lib/rdoc/generator/template/darkfish/filepage.rhtml b/lib/rdoc/generator/template/darkfish/filepage.rhtml
new file mode 100644
index 0000000..33216dc
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/filepage.rhtml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <meta content="text/html; charset=<%= @options.charset %>" http-equiv="Content-Type" />
+
+ <title>File: <%= file.base_name %> [<%= @options.title %>]</title>
+
+ <link type="text/css" media="screen" href="<%= rel_prefix %>/rdoc.css" rel="stylesheet" />
+
+ <script src="<%= rel_prefix %>/js/jquery.js" type="text/javascript"
+ charset="utf-8"></script>
+ <script src="<%= rel_prefix %>/js/thickbox-compressed.js" type="text/javascript"
+ charset="utf-8"></script>
+ <script src="<%= rel_prefix %>/js/quicksearch.js" type="text/javascript"
+ charset="utf-8"></script>
+ <script src="<%= rel_prefix %>/js/darkfish.js" type="text/javascript"
+ charset="utf-8"></script>
+</head>
+
+<% if file.parser == RDoc::Parser::Simple %>
+<body class="file">
+ <div id="metadata">
+ <div id="home-metadata">
+ <div id="home-section" class="section">
+ <h3 class="section-header">
+ <a href="<%= rel_prefix %>/index.html">Home</a>
+ <a href="<%= rel_prefix %>/index.html#classes">Classes</a>
+ <a href="<%= rel_prefix %>/index.html#methods">Methods</a>
+ </h3>
+ </div>
+ </div>
+
+ <div id="project-metadata">
+ <% simple_files = @files.select { |f| f.parser == RDoc::Parser::Simple } %>
+ <% unless simple_files.empty? then %>
+ <div id="fileindex-section" class="section project-section">
+ <h3 class="section-header">Files</h3>
+ <ul>
+ <% simple_files.each do |f| %>
+ <li class="file"><a href="<%= rel_prefix %>/<%= f.path %>"><%= h f.base_name %></a></li>
+ <% end %>
+ </ul>
+ </div>
+ <% end %>
+
+ <div id="classindex-section" class="section project-section">
+ <h3 class="section-header">Class Index
+ <span class="search-toggle"><img src="<%= rel_prefix %>/images/find.png"
+ height="16" width="16" alt="[+]"
+ title="show/hide quicksearch" /></span></h3>
+ <form action="#" method="get" accept-charset="utf-8" class="initially-hidden">
+ <fieldset>
+ <legend>Quicksearch</legend>
+ <input type="text" name="quicksearch" value=""
+ class="quicksearch-field" />
+ </fieldset>
+ </form>
+
+ <ul class="link-list">
+ <% @modsort.each do |index_klass| %>
+ <li><a href="<%= rel_prefix %>/<%= index_klass.path %>"><%= index_klass.full_name %></a></li>
+ <% end %>
+ </ul>
+ <div id="no-class-search-results" style="display: none;">No matching classes.</div>
+ </div>
+
+ <% if $DEBUG_RDOC %>
+ <div id="debugging-toggle"><img src="<%= rel_prefix %>/images/bug.png"
+ alt="toggle debugging" height="16" width="16" /></div>
+ <% end %>
+ </div>
+ </div>
+
+ <div id="documentation">
+ <%= file.description %>
+ </div>
+
+ <div id="validator-badges">
+ <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
+ <p><small>Generated with the <a href="http://deveiate.org/projects/Darkfish-Rdoc/">Darkfish
+ Rdoc Generator</a> <%= RDoc::Generator::Darkfish::VERSION %></small>.</p>
+ </div>
+</body>
+<% else %>
+<body class="file file-popup">
+ <div id="metadata">
+ <dl>
+ <dt class="modified-date">Last Modified</dt>
+ <dd class="modified-date"><%= file.last_modified %></dd>
+
+ <% if file.requires %>
+ <dt class="requires">Requires</dt>
+ <dd class="requires">
+ <ul>
+ <% file.requires.each do |require| %>
+ <li><%= require.name %></li>
+ <% end %>
+ </ul>
+ </dd>
+ <% end %>
+
+ <% if @options.webcvs %>
+ <dt class="scs-url">Trac URL</dt>
+ <dd class="scs-url"><a target="_top"
+ href="<%= file.cvs_url %>"><%= file.cvs_url %></a></dd>
+ <% end %>
+ </dl>
+ </div>
+
+ <div id="documentation">
+ <% if file.comment %>
+ <div class="description">
+ <h2>Description</h2>
+ <%= file.description %>
+ </div>
+ <% end %>
+ </div>
+</body>
+<% end %>
+</html>
+
diff --git a/lib/rdoc/generator/template/darkfish/images/brick.png b/lib/rdoc/generator/template/darkfish/images/brick.png
new file mode 100644
index 0000000..7851cf3
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/images/brick.png
Binary files differ
diff --git a/lib/rdoc/generator/template/darkfish/images/brick_link.png b/lib/rdoc/generator/template/darkfish/images/brick_link.png
new file mode 100644
index 0000000..9ebf013
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/images/brick_link.png
Binary files differ
diff --git a/lib/rdoc/generator/template/darkfish/images/bug.png b/lib/rdoc/generator/template/darkfish/images/bug.png
new file mode 100644
index 0000000..2d5fb90
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/images/bug.png
Binary files differ
diff --git a/lib/rdoc/generator/template/darkfish/images/bullet_black.png b/lib/rdoc/generator/template/darkfish/images/bullet_black.png
new file mode 100644
index 0000000..5761970
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/images/bullet_black.png
Binary files differ
diff --git a/lib/rdoc/generator/template/darkfish/images/bullet_toggle_minus.png b/lib/rdoc/generator/template/darkfish/images/bullet_toggle_minus.png
new file mode 100644
index 0000000..b47ce55
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/images/bullet_toggle_minus.png
Binary files differ
diff --git a/lib/rdoc/generator/template/darkfish/images/bullet_toggle_plus.png b/lib/rdoc/generator/template/darkfish/images/bullet_toggle_plus.png
new file mode 100644
index 0000000..9ab4a89
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/images/bullet_toggle_plus.png
Binary files differ
diff --git a/lib/rdoc/generator/template/darkfish/images/date.png b/lib/rdoc/generator/template/darkfish/images/date.png
new file mode 100644
index 0000000..783c833
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/images/date.png
Binary files differ
diff --git a/lib/rdoc/generator/template/darkfish/images/find.png b/lib/rdoc/generator/template/darkfish/images/find.png
new file mode 100644
index 0000000..1547479
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/images/find.png
Binary files differ
diff --git a/lib/rdoc/generator/template/darkfish/images/loadingAnimation.gif b/lib/rdoc/generator/template/darkfish/images/loadingAnimation.gif
new file mode 100644
index 0000000..82290f4
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/images/loadingAnimation.gif
Binary files differ
diff --git a/lib/rdoc/generator/template/darkfish/images/macFFBgHack.png b/lib/rdoc/generator/template/darkfish/images/macFFBgHack.png
new file mode 100644
index 0000000..c6473b3
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/images/macFFBgHack.png
Binary files differ
diff --git a/lib/rdoc/generator/template/darkfish/images/package.png b/lib/rdoc/generator/template/darkfish/images/package.png
new file mode 100644
index 0000000..da3c2a2
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/images/package.png
Binary files differ
diff --git a/lib/rdoc/generator/template/darkfish/images/page_green.png b/lib/rdoc/generator/template/darkfish/images/page_green.png
new file mode 100644
index 0000000..de8e003
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/images/page_green.png
Binary files differ
diff --git a/lib/rdoc/generator/template/darkfish/images/page_white_text.png b/lib/rdoc/generator/template/darkfish/images/page_white_text.png
new file mode 100644
index 0000000..813f712
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/images/page_white_text.png
Binary files differ
diff --git a/lib/rdoc/generator/template/darkfish/images/page_white_width.png b/lib/rdoc/generator/template/darkfish/images/page_white_width.png
new file mode 100644
index 0000000..1eb8809
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/images/page_white_width.png
Binary files differ
diff --git a/lib/rdoc/generator/template/darkfish/images/plugin.png b/lib/rdoc/generator/template/darkfish/images/plugin.png
new file mode 100644
index 0000000..6187b15
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/images/plugin.png
Binary files differ
diff --git a/lib/rdoc/generator/template/darkfish/images/ruby.png b/lib/rdoc/generator/template/darkfish/images/ruby.png
new file mode 100644
index 0000000..f763a16
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/images/ruby.png
Binary files differ
diff --git a/lib/rdoc/generator/template/darkfish/images/tag_green.png b/lib/rdoc/generator/template/darkfish/images/tag_green.png
new file mode 100644
index 0000000..83ec984
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/images/tag_green.png
Binary files differ
diff --git a/lib/rdoc/generator/template/darkfish/images/wrench.png b/lib/rdoc/generator/template/darkfish/images/wrench.png
new file mode 100644
index 0000000..5c8213f
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/images/wrench.png
Binary files differ
diff --git a/lib/rdoc/generator/template/darkfish/images/wrench_orange.png b/lib/rdoc/generator/template/darkfish/images/wrench_orange.png
new file mode 100644
index 0000000..565a933
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/images/wrench_orange.png
Binary files differ
diff --git a/lib/rdoc/generator/template/darkfish/images/zoom.png b/lib/rdoc/generator/template/darkfish/images/zoom.png
new file mode 100644
index 0000000..908612e
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/images/zoom.png
Binary files differ
diff --git a/lib/rdoc/generator/template/darkfish/index.rhtml b/lib/rdoc/generator/template/darkfish/index.rhtml
new file mode 100644
index 0000000..e853235
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/index.rhtml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+ <meta content="text/html; charset=<%= @options.charset %>" http-equiv="Content-Type" />
+
+ <title><%= h @options.title %></title>
+
+ <link type="text/css" media="screen" href="rdoc.css" rel="stylesheet" />
+
+ <script src="js/jquery.js" type="text/javascript" charset="utf-8"></script>
+ <script src="js/thickbox-compressed.js" type="text/javascript" charset="utf-8"></script>
+ <script src="js/quicksearch.js" type="text/javascript" charset="utf-8"></script>
+ <script src="js/darkfish.js" type="text/javascript" charset="utf-8"></script>
+
+</head>
+<body class="indexpage">
+
+ <% $stderr.sync = true %>
+ <h1><%= h @options.title %></h1>
+
+ <% if @options.main_page && main_page = @files.find { |f| f.full_name == @options.main_page } %>
+ <div id="main">
+ <%= main_page.description.sub(%r{^\s*<h1.*?/h1>}i, '') %>
+ </div>
+ <% else %>
+ <p>This is the API documentation for '<%= @options.title %>'.</p>
+ <% end %>
+
+ <% simple_files = @files.select {|tl| tl.parser == RDoc::Parser::Simple } %>
+ <% unless simple_files.empty? then %>
+ <h2>Files</h2>
+ <ul>
+ <% simple_files.sort.each do |file| %>
+ <li class="file"><a href="<%= file.path %>"><%= h file.base_name %></a></li>
+ <% end %>
+ </ul>
+ <% end %>
+
+ <h2 id="classes">Classes/Modules</h2>
+ <ul>
+ <% @modsort.each do |klass| %>
+ <li class="<%= klass.type %>"><a href="<%= klass.path %>"><%= klass.full_name %></a></li>
+ <% end %>
+ </ul>
+
+ <h2 id="methods">Methods</h2>
+ <ul>
+ <% RDoc::TopLevel.all_classes_and_modules.map do |mod|
+ mod.method_list
+ end.flatten.sort.each do |method| %>
+ <li><a href="<%= method.path %>"><%= method.pretty_name %> &mdash; <%= method.parent.full_name %></a></li>
+ <% end %>
+ </ul>
+
+ <div id="validator-badges">
+ <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
+ <p><small>Generated with the <a href="http://deveiate.org/projects/Darkfish-Rdoc/">Darkfish
+ Rdoc Generator</a> <%= RDoc::Generator::Darkfish::VERSION %></small>.</p>
+ </div>
+</body>
+</html>
diff --git a/lib/rdoc/generator/template/darkfish/js/darkfish.js b/lib/rdoc/generator/template/darkfish/js/darkfish.js
new file mode 100644
index 0000000..43528fd
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/js/darkfish.js
@@ -0,0 +1,116 @@
+/**
+ *
+ * Darkfish Page Functions
+ * $Id: darkfish.js 53 2009-01-07 02:52:03Z deveiant $
+ *
+ * Author: Michael Granger <mgranger@laika.com>
+ *
+ */
+
+/* Provide console simulation for firebug-less environments */
+if (!("console" in window) || !("firebug" in console)) {
+ var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
+ "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
+
+ window.console = {};
+ for (var i = 0; i < names.length; ++i)
+ window.console[names[i]] = function() {};
+};
+
+
+/**
+ * Unwrap the first element that matches the given @expr@ from the targets and return them.
+ */
+$.fn.unwrap = function( expr ) {
+ return this.each( function() {
+ $(this).parents( expr ).eq( 0 ).after( this ).remove();
+ });
+};
+
+
+function showSource( e ) {
+ var target = e.target;
+ var codeSections = $(target).
+ parents('.method-detail').
+ find('.method-source-code');
+
+ $(target).
+ parents('.method-detail').
+ find('.method-source-code').
+ slideToggle();
+};
+
+function hookSourceViews() {
+ $('.method-description,.method-heading').click( showSource );
+};
+
+function toggleDebuggingSection() {
+ $('.debugging-section').slideToggle();
+};
+
+function hookDebuggingToggle() {
+ $('#debugging-toggle img').click( toggleDebuggingSection );
+};
+
+function hookQuickSearch() {
+ $('.quicksearch-field').each( function() {
+ var searchElems = $(this).parents('.section').find( 'li' );
+ var toggle = $(this).parents('.section').find('h3 .search-toggle');
+ // console.debug( "Toggle is: %o", toggle );
+ var qsbox = $(this).parents('form').get( 0 );
+
+ $(this).quicksearch( this, searchElems, {
+ noSearchResultsIndicator: 'no-class-search-results',
+ focusOnLoad: false
+ });
+ $(toggle).click( function() {
+ // console.debug( "Toggling qsbox: %o", qsbox );
+ $(qsbox).toggle();
+ });
+ });
+};
+
+function highlightTarget( anchor ) {
+ console.debug( "Highlighting target '%s'.", anchor );
+
+ $("a[name=" + anchor + "]").each( function() {
+ if ( !$(this).parent().parent().hasClass('target-section') ) {
+ console.debug( "Wrapping the target-section" );
+ $('div.method-detail').unwrap( 'div.target-section' );
+ $(this).parent().wrap( '<div class="target-section"></div>' );
+ } else {
+ console.debug( "Already wrapped." );
+ }
+ });
+};
+
+function highlightLocationTarget() {
+ console.debug( "Location hash: %s", window.location.hash );
+ if ( ! window.location.hash || window.location.hash.length == 0 ) return;
+
+ var anchor = window.location.hash.substring(1);
+ console.debug( "Found anchor: %s; matching %s", anchor, "a[name=" + anchor + "]" );
+
+ highlightTarget( anchor );
+};
+
+function highlightClickTarget( event ) {
+ console.debug( "Highlighting click target for event %o", event.target );
+ try {
+ var anchor = $(event.target).attr( 'href' ).substring(1);
+ console.debug( "Found target anchor: %s", anchor );
+ highlightTarget( anchor );
+ } catch ( err ) {
+ console.error( "Exception while highlighting: %o", err );
+ };
+};
+
+
+$(document).ready( function() {
+ hookSourceViews();
+ hookDebuggingToggle();
+ hookQuickSearch();
+ highlightLocationTarget();
+
+ $('ul.link-list a').bind( "click", highlightClickTarget );
+});
diff --git a/lib/rdoc/generator/template/darkfish/js/jquery.js b/lib/rdoc/generator/template/darkfish/js/jquery.js
new file mode 100644
index 0000000..afe9e74
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/js/jquery.js
@@ -0,0 +1,32 @@
+/*
+ * jQuery 1.2.6 - New Wave Javascript
+ *
+ * Copyright (c) 2008 John Resig (jquery.com)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * $Date: 2008-09-25 09:50:52 -0700 (Thu, 25 Sep 2008) $
+ * $Rev: 38 $
+ */
+(function(){var _jQuery=window.jQuery,_$=window.$;var jQuery=window.jQuery=window.$=function(selector,context){return new jQuery.fn.init(selector,context);};var quickExpr=/^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/,isSimple=/^.[^:#\[\.]*$/,undefined;jQuery.fn=jQuery.prototype={init:function(selector,context){selector=selector||document;if(selector.nodeType){this[0]=selector;this.length=1;return this;}if(typeof selector=="string"){var match=quickExpr.exec(selector);if(match&&(match[1]||!context)){if(match[1])selector=jQuery.clean([match[1]],context);else{var elem=document.getElementById(match[3]);if(elem){if(elem.id!=match[3])return jQuery().find(selector);return jQuery(elem);}selector=[];}}else
+return jQuery(context).find(selector);}else if(jQuery.isFunction(selector))return jQuery(document)[jQuery.fn.ready?"ready":"load"](selector);return this.setArray(jQuery.makeArray(selector));},jquery:"1.2.6",size:function(){return this.length;},length:0,get:function(num){return num==undefined?jQuery.makeArray(this):this[num];},pushStack:function(elems){var ret=jQuery(elems);ret.prevObject=this;return ret;},setArray:function(elems){this.length=0;Array.prototype.push.apply(this,elems);return this;},each:function(callback,args){return jQuery.each(this,callback,args);},index:function(elem){var ret=-1;return jQuery.inArray(elem&&elem.jquery?elem[0]:elem,this);},attr:function(name,value,type){var options=name;if(name.constructor==String)if(value===undefined)return this[0]&&jQuery[type||"attr"](this[0],name);else{options={};options[name]=value;}return this.each(function(i){for(name in options)jQuery.attr(type?this.style:this,name,jQuery.prop(this,options[name],type,i,name));});},css:function(key,value){if((key=='width'||key=='height')&&parseFloat(value)<0)value=undefined;return this.attr(key,value,"curCSS");},text:function(text){if(typeof text!="object"&&text!=null)return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(text));var ret="";jQuery.each(text||this,function(){jQuery.each(this.childNodes,function(){if(this.nodeType!=8)ret+=this.nodeType!=1?this.nodeValue:jQuery.fn.text([this]);});});return ret;},wrapAll:function(html){if(this[0])jQuery(html,this[0].ownerDocument).clone().insertBefore(this[0]).map(function(){var elem=this;while(elem.firstChild)elem=elem.firstChild;return elem;}).append(this);return this;},wrapInner:function(html){return this.each(function(){jQuery(this).contents().wrapAll(html);});},wrap:function(html){return this.each(function(){jQuery(this).wrapAll(html);});},append:function(){return this.domManip(arguments,true,false,function(elem){if(this.nodeType==1)this.appendChild(elem);});},prepend:function(){return this.domManip(arguments,true,true,function(elem){if(this.nodeType==1)this.insertBefore(elem,this.firstChild);});},before:function(){return this.domManip(arguments,false,false,function(elem){this.parentNode.insertBefore(elem,this);});},after:function(){return this.domManip(arguments,false,true,function(elem){this.parentNode.insertBefore(elem,this.nextSibling);});},end:function(){return this.prevObject||jQuery([]);},find:function(selector){var elems=jQuery.map(this,function(elem){return jQuery.find(selector,elem);});return this.pushStack(/[^+>] [^+>]/.test(selector)||selector.indexOf("..")>-1?jQuery.unique(elems):elems);},clone:function(events){var ret=this.map(function(){if(jQuery.browser.msie&&!jQuery.isXMLDoc(this)){var clone=this.cloneNode(true),container=document.createElement("div");container.appendChild(clone);return jQuery.clean([container.innerHTML])[0];}else
+return this.cloneNode(true);});var clone=ret.find("*").andSelf().each(function(){if(this[expando]!=undefined)this[expando]=null;});if(events===true)this.find("*").andSelf().each(function(i){if(this.nodeType==3)return;var events=jQuery.data(this,"events");for(var type in events)for(var handler in events[type])jQuery.event.add(clone[i],type,events[type][handler],events[type][handler].data);});return ret;},filter:function(selector){return this.pushStack(jQuery.isFunction(selector)&&jQuery.grep(this,function(elem,i){return selector.call(elem,i);})||jQuery.multiFilter(selector,this));},not:function(selector){if(selector.constructor==String)if(isSimple.test(selector))return this.pushStack(jQuery.multiFilter(selector,this,true));else
+selector=jQuery.multiFilter(selector,this);var isArrayLike=selector.length&&selector[selector.length-1]!==undefined&&!selector.nodeType;return this.filter(function(){return isArrayLike?jQuery.inArray(this,selector)<0:this!=selector;});},add:function(selector){return this.pushStack(jQuery.unique(jQuery.merge(this.get(),typeof selector=='string'?jQuery(selector):jQuery.makeArray(selector))));},is:function(selector){return!!selector&&jQuery.multiFilter(selector,this).length>0;},hasClass:function(selector){return this.is("."+selector);},val:function(value){if(value==undefined){if(this.length){var elem=this[0];if(jQuery.nodeName(elem,"select")){var index=elem.selectedIndex,values=[],options=elem.options,one=elem.type=="select-one";if(index<0)return null;for(var i=one?index:0,max=one?index+1:options.length;i<max;i++){var option=options[i];if(option.selected){value=jQuery.browser.msie&&!option.attributes.value.specified?option.text:option.value;if(one)return value;values.push(value);}}return values;}else
+return(this[0].value||"").replace(/\r/g,"");}return undefined;}if(value.constructor==Number)value+='';return this.each(function(){if(this.nodeType!=1)return;if(value.constructor==Array&&/radio|checkbox/.test(this.type))this.checked=(jQuery.inArray(this.value,value)>=0||jQuery.inArray(this.name,value)>=0);else if(jQuery.nodeName(this,"select")){var values=jQuery.makeArray(value);jQuery("option",this).each(function(){this.selected=(jQuery.inArray(this.value,values)>=0||jQuery.inArray(this.text,values)>=0);});if(!values.length)this.selectedIndex=-1;}else
+this.value=value;});},html:function(value){return value==undefined?(this[0]?this[0].innerHTML:null):this.empty().append(value);},replaceWith:function(value){return this.after(value).remove();},eq:function(i){return this.slice(i,i+1);},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments));},map:function(callback){return this.pushStack(jQuery.map(this,function(elem,i){return callback.call(elem,i,elem);}));},andSelf:function(){return this.add(this.prevObject);},data:function(key,value){var parts=key.split(".");parts[1]=parts[1]?"."+parts[1]:"";if(value===undefined){var data=this.triggerHandler("getData"+parts[1]+"!",[parts[0]]);if(data===undefined&&this.length)data=jQuery.data(this[0],key);return data===undefined&&parts[1]?this.data(parts[0]):data;}else
+return this.trigger("setData"+parts[1]+"!",[parts[0],value]).each(function(){jQuery.data(this,key,value);});},removeData:function(key){return this.each(function(){jQuery.removeData(this,key);});},domManip:function(args,table,reverse,callback){var clone=this.length>1,elems;return this.each(function(){if(!elems){elems=jQuery.clean(args,this.ownerDocument);if(reverse)elems.reverse();}var obj=this;if(table&&jQuery.nodeName(this,"table")&&jQuery.nodeName(elems[0],"tr"))obj=this.getElementsByTagName("tbody")[0]||this.appendChild(this.ownerDocument.createElement("tbody"));var scripts=jQuery([]);jQuery.each(elems,function(){var elem=clone?jQuery(this).clone(true)[0]:this;if(jQuery.nodeName(elem,"script"))scripts=scripts.add(elem);else{if(elem.nodeType==1)scripts=scripts.add(jQuery("script",elem).remove());callback.call(obj,elem);}});scripts.each(evalScript);});}};jQuery.fn.init.prototype=jQuery.fn;function evalScript(i,elem){if(elem.src)jQuery.ajax({url:elem.src,async:false,dataType:"script"});else
+jQuery.globalEval(elem.text||elem.textContent||elem.innerHTML||"");if(elem.parentNode)elem.parentNode.removeChild(elem);}function now(){return+new Date;}jQuery.extend=jQuery.fn.extend=function(){var target=arguments[0]||{},i=1,length=arguments.length,deep=false,options;if(target.constructor==Boolean){deep=target;target=arguments[1]||{};i=2;}if(typeof target!="object"&&typeof target!="function")target={};if(length==i){target=this;--i;}for(;i<length;i++)if((options=arguments[i])!=null)for(var name in options){var src=target[name],copy=options[name];if(target===copy)continue;if(deep&&copy&&typeof copy=="object"&&!copy.nodeType)target[name]=jQuery.extend(deep,src||(copy.length!=null?[]:{}),copy);else if(copy!==undefined)target[name]=copy;}return target;};var expando="jQuery"+now(),uuid=0,windowData={},exclude=/z-?index|font-?weight|opacity|zoom|line-?height/i,defaultView=document.defaultView||{};jQuery.extend({noConflict:function(deep){window.$=_$;if(deep)window.jQuery=_jQuery;return jQuery;},isFunction:function(fn){return!!fn&&typeof fn!="string"&&!fn.nodeName&&fn.constructor!=Array&&/^[\s[]?function/.test(fn+"");},isXMLDoc:function(elem){return elem.documentElement&&!elem.body||elem.tagName&&elem.ownerDocument&&!elem.ownerDocument.body;},globalEval:function(data){data=jQuery.trim(data);if(data){var head=document.getElementsByTagName("head")[0]||document.documentElement,script=document.createElement("script");script.type="text/javascript";if(jQuery.browser.msie)script.text=data;else
+script.appendChild(document.createTextNode(data));head.insertBefore(script,head.firstChild);head.removeChild(script);}},nodeName:function(elem,name){return elem.nodeName&&elem.nodeName.toUpperCase()==name.toUpperCase();},cache:{},data:function(elem,name,data){elem=elem==window?windowData:elem;var id=elem[expando];if(!id)id=elem[expando]=++uuid;if(name&&!jQuery.cache[id])jQuery.cache[id]={};if(data!==undefined)jQuery.cache[id][name]=data;return name?jQuery.cache[id][name]:id;},removeData:function(elem,name){elem=elem==window?windowData:elem;var id=elem[expando];if(name){if(jQuery.cache[id]){delete jQuery.cache[id][name];name="";for(name in jQuery.cache[id])break;if(!name)jQuery.removeData(elem);}}else{try{delete elem[expando];}catch(e){if(elem.removeAttribute)elem.removeAttribute(expando);}delete jQuery.cache[id];}},each:function(object,callback,args){var name,i=0,length=object.length;if(args){if(length==undefined){for(name in object)if(callback.apply(object[name],args)===false)break;}else
+for(;i<length;)if(callback.apply(object[i++],args)===false)break;}else{if(length==undefined){for(name in object)if(callback.call(object[name],name,object[name])===false)break;}else
+for(var value=object[0];i<length&&callback.call(value,i,value)!==false;value=object[++i]){}}return object;},prop:function(elem,value,type,i,name){if(jQuery.isFunction(value))value=value.call(elem,i);return value&&value.constructor==Number&&type=="curCSS"&&!exclude.test(name)?value+"px":value;},className:{add:function(elem,classNames){jQuery.each((classNames||"").split(/\s+/),function(i,className){if(elem.nodeType==1&&!jQuery.className.has(elem.className,className))elem.className+=(elem.className?" ":"")+className;});},remove:function(elem,classNames){if(elem.nodeType==1)elem.className=classNames!=undefined?jQuery.grep(elem.className.split(/\s+/),function(className){return!jQuery.className.has(classNames,className);}).join(" "):"";},has:function(elem,className){return jQuery.inArray(className,(elem.className||elem).toString().split(/\s+/))>-1;}},swap:function(elem,options,callback){var old={};for(var name in options){old[name]=elem.style[name];elem.style[name]=options[name];}callback.call(elem);for(var name in options)elem.style[name]=old[name];},css:function(elem,name,force){if(name=="width"||name=="height"){var val,props={position:"absolute",visibility:"hidden",display:"block"},which=name=="width"?["Left","Right"]:["Top","Bottom"];function getWH(){val=name=="width"?elem.offsetWidth:elem.offsetHeight;var padding=0,border=0;jQuery.each(which,function(){padding+=parseFloat(jQuery.curCSS(elem,"padding"+this,true))||0;border+=parseFloat(jQuery.curCSS(elem,"border"+this+"Width",true))||0;});val-=Math.round(padding+border);}if(jQuery(elem).is(":visible"))getWH();else
+jQuery.swap(elem,props,getWH);return Math.max(0,val);}return jQuery.curCSS(elem,name,force);},curCSS:function(elem,name,force){var ret,style=elem.style;function color(elem){if(!jQuery.browser.safari)return false;var ret=defaultView.getComputedStyle(elem,null);return!ret||ret.getPropertyValue("color")=="";}if(name=="opacity"&&jQuery.browser.msie){ret=jQuery.attr(style,"opacity");return ret==""?"1":ret;}if(jQuery.browser.opera&&name=="display"){var save=style.outline;style.outline="0 solid black";style.outline=save;}if(name.match(/float/i))name=styleFloat;if(!force&&style&&style[name])ret=style[name];else if(defaultView.getComputedStyle){if(name.match(/float/i))name="float";name=name.replace(/([A-Z])/g,"-$1").toLowerCase();var computedStyle=defaultView.getComputedStyle(elem,null);if(computedStyle&&!color(elem))ret=computedStyle.getPropertyValue(name);else{var swap=[],stack=[],a=elem,i=0;for(;a&&color(a);a=a.parentNode)stack.unshift(a);for(;i<stack.length;i++)if(color(stack[i])){swap[i]=stack[i].style.display;stack[i].style.display="block";}ret=name=="display"&&swap[stack.length-1]!=null?"none":(computedStyle&&computedStyle.getPropertyValue(name))||"";for(i=0;i<swap.length;i++)if(swap[i]!=null)stack[i].style.display=swap[i];}if(name=="opacity"&&ret=="")ret="1";}else if(elem.currentStyle){var camelCase=name.replace(/\-(\w)/g,function(all,letter){return letter.toUpperCase();});ret=elem.currentStyle[name]||elem.currentStyle[camelCase];if(!/^\d+(px)?$/i.test(ret)&&/^\d/.test(ret)){var left=style.left,rsLeft=elem.runtimeStyle.left;elem.runtimeStyle.left=elem.currentStyle.left;style.left=ret||0;ret=style.pixelLeft+"px";style.left=left;elem.runtimeStyle.left=rsLeft;}}return ret;},clean:function(elems,context){var ret=[];context=context||document;if(typeof context.createElement=='undefined')context=context.ownerDocument||context[0]&&context[0].ownerDocument||document;jQuery.each(elems,function(i,elem){if(!elem)return;if(elem.constructor==Number)elem+='';if(typeof elem=="string"){elem=elem.replace(/(<(\w+)[^>]*?)\/>/g,function(all,front,tag){return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?all:front+"></"+tag+">";});var tags=jQuery.trim(elem).toLowerCase(),div=context.createElement("div");var wrap=!tags.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!tags.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||tags.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!tags.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!tags.indexOf("<td")||!tags.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!tags.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||jQuery.browser.msie&&[1,"div<div>","</div>"]||[0,"",""];div.innerHTML=wrap[1]+elem+wrap[2];while(wrap[0]--)div=div.lastChild;if(jQuery.browser.msie){var tbody=!tags.indexOf("<table")&&tags.indexOf("<tbody")<0?div.firstChild&&div.firstChild.childNodes:wrap[1]=="<table>"&&tags.indexOf("<tbody")<0?div.childNodes:[];for(var j=tbody.length-1;j>=0;--j)if(jQuery.nodeName(tbody[j],"tbody")&&!tbody[j].childNodes.length)tbody[j].parentNode.removeChild(tbody[j]);if(/^\s/.test(elem))div.insertBefore(context.createTextNode(elem.match(/^\s*/)[0]),div.firstChild);}elem=jQuery.makeArray(div.childNodes);}if(elem.length===0&&(!jQuery.nodeName(elem,"form")&&!jQuery.nodeName(elem,"select")))return;if(elem[0]==undefined||jQuery.nodeName(elem,"form")||elem.options)ret.push(elem);else
+ret=jQuery.merge(ret,elem);});return ret;},attr:function(elem,name,value){if(!elem||elem.nodeType==3||elem.nodeType==8)return undefined;var notxml=!jQuery.isXMLDoc(elem),set=value!==undefined,msie=jQuery.browser.msie;name=notxml&&jQuery.props[name]||name;if(elem.tagName){var special=/href|src|style/.test(name);if(name=="selected"&&jQuery.browser.safari)elem.parentNode.selectedIndex;if(name in elem&&notxml&&!special){if(set){if(name=="type"&&jQuery.nodeName(elem,"input")&&elem.parentNode)throw"type property can't be changed";elem[name]=value;}if(jQuery.nodeName(elem,"form")&&elem.getAttributeNode(name))return elem.getAttributeNode(name).nodeValue;return elem[name];}if(msie&&notxml&&name=="style")return jQuery.attr(elem.style,"cssText",value);if(set)elem.setAttribute(name,""+value);var attr=msie&&notxml&&special?elem.getAttribute(name,2):elem.getAttribute(name);return attr===null?undefined:attr;}if(msie&&name=="opacity"){if(set){elem.zoom=1;elem.filter=(elem.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(value)+''=="NaN"?"":"alpha(opacity="+value*100+")");}return elem.filter&&elem.filter.indexOf("opacity=")>=0?(parseFloat(elem.filter.match(/opacity=([^)]*)/)[1])/100)+'':"";}name=name.replace(/-([a-z])/ig,function(all,letter){return letter.toUpperCase();});if(set)elem[name]=value;return elem[name];},trim:function(text){return(text||"").replace(/^\s+|\s+$/g,"");},makeArray:function(array){var ret=[];if(array!=null){var i=array.length;if(i==null||array.split||array.setInterval||array.call)ret[0]=array;else
+while(i)ret[--i]=array[i];}return ret;},inArray:function(elem,array){for(var i=0,length=array.length;i<length;i++)if(array[i]===elem)return i;return-1;},merge:function(first,second){var i=0,elem,pos=first.length;if(jQuery.browser.msie){while(elem=second[i++])if(elem.nodeType!=8)first[pos++]=elem;}else
+while(elem=second[i++])first[pos++]=elem;return first;},unique:function(array){var ret=[],done={};try{for(var i=0,length=array.length;i<length;i++){var id=jQuery.data(array[i]);if(!done[id]){done[id]=true;ret.push(array[i]);}}}catch(e){ret=array;}return ret;},grep:function(elems,callback,inv){var ret=[];for(var i=0,length=elems.length;i<length;i++)if(!inv!=!callback(elems[i],i))ret.push(elems[i]);return ret;},map:function(elems,callback){var ret=[];for(var i=0,length=elems.length;i<length;i++){var value=callback(elems[i],i);if(value!=null)ret[ret.length]=value;}return ret.concat.apply([],ret);}});var userAgent=navigator.userAgent.toLowerCase();jQuery.browser={version:(userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[])[1],safari:/webkit/.test(userAgent),opera:/opera/.test(userAgent),msie:/msie/.test(userAgent)&&!/opera/.test(userAgent),mozilla:/mozilla/.test(userAgent)&&!/(compatible|webkit)/.test(userAgent)};var styleFloat=jQuery.browser.msie?"styleFloat":"cssFloat";jQuery.extend({boxModel:!jQuery.browser.msie||document.compatMode=="CSS1Compat",props:{"for":"htmlFor","class":"className","float":styleFloat,cssFloat:styleFloat,styleFloat:styleFloat,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing"}});jQuery.each({parent:function(elem){return elem.parentNode;},parents:function(elem){return jQuery.dir(elem,"parentNode");},next:function(elem){return jQuery.nth(elem,2,"nextSibling");},prev:function(elem){return jQuery.nth(elem,2,"previousSibling");},nextAll:function(elem){return jQuery.dir(elem,"nextSibling");},prevAll:function(elem){return jQuery.dir(elem,"previousSibling");},siblings:function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},children:function(elem){return jQuery.sibling(elem.firstChild);},contents:function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}},function(name,fn){jQuery.fn[name]=function(selector){var ret=jQuery.map(this,fn);if(selector&&typeof selector=="string")ret=jQuery.multiFilter(selector,ret);return this.pushStack(jQuery.unique(ret));};});jQuery.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(name,original){jQuery.fn[name]=function(){var args=arguments;return this.each(function(){for(var i=0,length=args.length;i<length;i++)jQuery(args[i])[original](this);});};});jQuery.each({removeAttr:function(name){jQuery.attr(this,name,"");if(this.nodeType==1)this.removeAttribute(name);},addClass:function(classNames){jQuery.className.add(this,classNames);},removeClass:function(classNames){jQuery.className.remove(this,classNames);},toggleClass:function(classNames){jQuery.className[jQuery.className.has(this,classNames)?"remove":"add"](this,classNames);},remove:function(selector){if(!selector||jQuery.filter(selector,[this]).r.length){jQuery("*",this).add(this).each(function(){jQuery.event.remove(this);jQuery.removeData(this);});if(this.parentNode)this.parentNode.removeChild(this);}},empty:function(){jQuery(">*",this).remove();while(this.firstChild)this.removeChild(this.firstChild);}},function(name,fn){jQuery.fn[name]=function(){return this.each(fn,arguments);};});jQuery.each(["Height","Width"],function(i,name){var type=name.toLowerCase();jQuery.fn[type]=function(size){return this[0]==window?jQuery.browser.opera&&document.body["client"+name]||jQuery.browser.safari&&window["inner"+name]||document.compatMode=="CSS1Compat"&&document.documentElement["client"+name]||document.body["client"+name]:this[0]==document?Math.max(Math.max(document.body["scroll"+name],document.documentElement["scroll"+name]),Math.max(document.body["offset"+name],document.documentElement["offset"+name])):size==undefined?(this.length?jQuery.css(this[0],type):null):this.css(type,size.constructor==String?size:size+"px");};});function num(elem,prop){return elem[0]&&parseInt(jQuery.curCSS(elem[0],prop,true),10)||0;}var chars=jQuery.browser.safari&&parseInt(jQuery.browser.version)<417?"(?:[\\w*_-]|\\\\.)":"(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",quickChild=new RegExp("^>\\s*("+chars+"+)"),quickID=new RegExp("^("+chars+"+)(#)("+chars+"+)"),quickClass=new RegExp("^([#.]?)("+chars+"*)");jQuery.extend({expr:{"":function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},"#":function(a,i,m){return a.getAttribute("id")==m[2];},":":{lt:function(a,i,m){return i<m[3]-0;},gt:function(a,i,m){return i>m[3]-0;},nth:function(a,i,m){return m[3]-0==i;},eq:function(a,i,m){return m[3]-0==i;},first:function(a,i){return i==0;},last:function(a,i,m,r){return i==r.length-1;},even:function(a,i){return i%2==0;},odd:function(a,i){return i%2;},"first-child":function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},"last-child":function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;},"only-child":function(a){return!jQuery.nth(a.parentNode.lastChild,2,"previousSibling");},parent:function(a){return a.firstChild;},empty:function(a){return!a.firstChild;},contains:function(a,i,m){return(a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;},visible:function(a){return"hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";},hidden:function(a){return"hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";},enabled:function(a){return!a.disabled;},disabled:function(a){return a.disabled;},checked:function(a){return a.checked;},selected:function(a){return a.selected||jQuery.attr(a,"selected");},text:function(a){return"text"==a.type;},radio:function(a){return"radio"==a.type;},checkbox:function(a){return"checkbox"==a.type;},file:function(a){return"file"==a.type;},password:function(a){return"password"==a.type;},submit:function(a){return"submit"==a.type;},image:function(a){return"image"==a.type;},reset:function(a){return"reset"==a.type;},button:function(a){return"button"==a.type||jQuery.nodeName(a,"button");},input:function(a){return/input|select|textarea|button/i.test(a.nodeName);},has:function(a,i,m){return jQuery.find(m[3],a).length;},header:function(a){return/h\d/i.test(a.nodeName);},animated:function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length;}}},parse:[/^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,/^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,new RegExp("^([:.#]*)("+chars+"+)")],multiFilter:function(expr,elems,not){var old,cur=[];while(expr&&expr!=old){old=expr;var f=jQuery.filter(expr,elems,not);expr=f.t.replace(/^\s*,\s*/,"");cur=not?elems=f.r:jQuery.merge(cur,f.r);}return cur;},find:function(t,context){if(typeof t!="string")return[t];if(context&&context.nodeType!=1&&context.nodeType!=9)return[];context=context||document;var ret=[context],done=[],last,nodeName;while(t&&last!=t){var r=[];last=t;t=jQuery.trim(t);var foundToken=false,re=quickChild,m=re.exec(t);if(m){nodeName=m[1].toUpperCase();for(var i=0;ret[i];i++)for(var c=ret[i].firstChild;c;c=c.nextSibling)if(c.nodeType==1&&(nodeName=="*"||c.nodeName.toUpperCase()==nodeName))r.push(c);ret=r;t=t.replace(re,"");if(t.indexOf(" ")==0)continue;foundToken=true;}else{re=/^([>+~])\s*(\w*)/i;if((m=re.exec(t))!=null){r=[];var merge={};nodeName=m[2].toUpperCase();m=m[1];for(var j=0,rl=ret.length;j<rl;j++){var n=m=="~"||m=="+"?ret[j].nextSibling:ret[j].firstChild;for(;n;n=n.nextSibling)if(n.nodeType==1){var id=jQuery.data(n);if(m=="~"&&merge[id])break;if(!nodeName||n.nodeName.toUpperCase()==nodeName){if(m=="~")merge[id]=true;r.push(n);}if(m=="+")break;}}ret=r;t=jQuery.trim(t.replace(re,""));foundToken=true;}}if(t&&!foundToken){if(!t.indexOf(",")){if(context==ret[0])ret.shift();done=jQuery.merge(done,ret);r=ret=[context];t=" "+t.substr(1,t.length);}else{var re2=quickID;var m=re2.exec(t);if(m){m=[0,m[2],m[3],m[1]];}else{re2=quickClass;m=re2.exec(t);}m[2]=m[2].replace(/\\/g,"");var elem=ret[ret.length-1];if(m[1]=="#"&&elem&&elem.getElementById&&!jQuery.isXMLDoc(elem)){var oid=elem.getElementById(m[2]);if((jQuery.browser.msie||jQuery.browser.opera)&&oid&&typeof oid.id=="string"&&oid.id!=m[2])oid=jQuery('[@id="'+m[2]+'"]',elem)[0];ret=r=oid&&(!m[3]||jQuery.nodeName(oid,m[3]))?[oid]:[];}else{for(var i=0;ret[i];i++){var tag=m[1]=="#"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];if(tag=="*"&&ret[i].nodeName.toLowerCase()=="object")tag="param";r=jQuery.merge(r,ret[i].getElementsByTagName(tag));}if(m[1]==".")r=jQuery.classFilter(r,m[2]);if(m[1]=="#"){var tmp=[];for(var i=0;r[i];i++)if(r[i].getAttribute("id")==m[2]){tmp=[r[i]];break;}r=tmp;}ret=r;}t=t.replace(re2,"");}}if(t){var val=jQuery.filter(t,r);ret=r=val.r;t=jQuery.trim(val.t);}}if(t)ret=[];if(ret&&context==ret[0])ret.shift();done=jQuery.merge(done,ret);return done;},classFilter:function(r,m,not){m=" "+m+" ";var tmp=[];for(var i=0;r[i];i++){var pass=(" "+r[i].className+" ").indexOf(m)>=0;if(!not&&pass||not&&!pass)tmp.push(r[i]);}return tmp;},filter:function(t,r,not){var last;while(t&&t!=last){last=t;var p=jQuery.parse,m;for(var i=0;p[i];i++){m=p[i].exec(t);if(m){t=t.substring(m[0].length);m[2]=m[2].replace(/\\/g,"");break;}}if(!m)break;if(m[1]==":"&&m[2]=="not")r=isSimple.test(m[3])?jQuery.filter(m[3],r,true).r:jQuery(r).not(m[3]);else if(m[1]==".")r=jQuery.classFilter(r,m[2],not);else if(m[1]=="["){var tmp=[],type=m[3];for(var i=0,rl=r.length;i<rl;i++){var a=r[i],z=a[jQuery.props[m[2]]||m[2]];if(z==null||/href|src|selected/.test(m[2]))z=jQuery.attr(a,m[2])||'';if((type==""&&!!z||type=="="&&z==m[5]||type=="!="&&z!=m[5]||type=="^="&&z&&!z.indexOf(m[5])||type=="$="&&z.substr(z.length-m[5].length)==m[5]||(type=="*="||type=="~=")&&z.indexOf(m[5])>=0)^not)tmp.push(a);}r=tmp;}else if(m[1]==":"&&m[2]=="nth-child"){var merge={},tmp=[],test=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(m[3]=="even"&&"2n"||m[3]=="odd"&&"2n+1"||!/\D/.test(m[3])&&"0n+"+m[3]||m[3]),first=(test[1]+(test[2]||1))-0,last=test[3]-0;for(var i=0,rl=r.length;i<rl;i++){var node=r[i],parentNode=node.parentNode,id=jQuery.data(parentNode);if(!merge[id]){var c=1;for(var n=parentNode.firstChild;n;n=n.nextSibling)if(n.nodeType==1)n.nodeIndex=c++;merge[id]=true;}var add=false;if(first==0){if(node.nodeIndex==last)add=true;}else if((node.nodeIndex-last)%first==0&&(node.nodeIndex-last)/first>=0)add=true;if(add^not)tmp.push(node);}r=tmp;}else{var fn=jQuery.expr[m[1]];if(typeof fn=="object")fn=fn[m[2]];if(typeof fn=="string")fn=eval("false||function(a,i){return "+fn+";}");r=jQuery.grep(r,function(elem,i){return fn(elem,i,m,r);},not);}}return{r:r,t:t};},dir:function(elem,dir){var matched=[],cur=elem[dir];while(cur&&cur!=document){if(cur.nodeType==1)matched.push(cur);cur=cur[dir];}return matched;},nth:function(cur,result,dir,elem){result=result||1;var num=0;for(;cur;cur=cur[dir])if(cur.nodeType==1&&++num==result)break;return cur;},sibling:function(n,elem){var r=[];for(;n;n=n.nextSibling){if(n.nodeType==1&&n!=elem)r.push(n);}return r;}});jQuery.event={add:function(elem,types,handler,data){if(elem.nodeType==3||elem.nodeType==8)return;if(jQuery.browser.msie&&elem.setInterval)elem=window;if(!handler.guid)handler.guid=this.guid++;if(data!=undefined){var fn=handler;handler=this.proxy(fn,function(){return fn.apply(this,arguments);});handler.data=data;}var events=jQuery.data(elem,"events")||jQuery.data(elem,"events",{}),handle=jQuery.data(elem,"handle")||jQuery.data(elem,"handle",function(){if(typeof jQuery!="undefined"&&!jQuery.event.triggered)return jQuery.event.handle.apply(arguments.callee.elem,arguments);});handle.elem=elem;jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];handler.type=parts[1];var handlers=events[type];if(!handlers){handlers=events[type]={};if(!jQuery.event.special[type]||jQuery.event.special[type].setup.call(elem)===false){if(elem.addEventListener)elem.addEventListener(type,handle,false);else if(elem.attachEvent)elem.attachEvent("on"+type,handle);}}handlers[handler.guid]=handler;jQuery.event.global[type]=true;});elem=null;},guid:1,global:{},remove:function(elem,types,handler){if(elem.nodeType==3||elem.nodeType==8)return;var events=jQuery.data(elem,"events"),ret,index;if(events){if(types==undefined||(typeof types=="string"&&types.charAt(0)=="."))for(var type in events)this.remove(elem,type+(types||""));else{if(types.type){handler=types.handler;types=types.type;}jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];if(events[type]){if(handler)delete events[type][handler.guid];else
+for(handler in events[type])if(!parts[1]||events[type][handler].type==parts[1])delete events[type][handler];for(ret in events[type])break;if(!ret){if(!jQuery.event.special[type]||jQuery.event.special[type].teardown.call(elem)===false){if(elem.removeEventListener)elem.removeEventListener(type,jQuery.data(elem,"handle"),false);else if(elem.detachEvent)elem.detachEvent("on"+type,jQuery.data(elem,"handle"));}ret=null;delete events[type];}}});}for(ret in events)break;if(!ret){var handle=jQuery.data(elem,"handle");if(handle)handle.elem=null;jQuery.removeData(elem,"events");jQuery.removeData(elem,"handle");}}},trigger:function(type,data,elem,donative,extra){data=jQuery.makeArray(data);if(type.indexOf("!")>=0){type=type.slice(0,-1);var exclusive=true;}if(!elem){if(this.global[type])jQuery("*").add([window,document]).trigger(type,data);}else{if(elem.nodeType==3||elem.nodeType==8)return undefined;var val,ret,fn=jQuery.isFunction(elem[type]||null),event=!data[0]||!data[0].preventDefault;if(event){data.unshift({type:type,target:elem,preventDefault:function(){},stopPropagation:function(){},timeStamp:now()});data[0][expando]=true;}data[0].type=type;if(exclusive)data[0].exclusive=true;var handle=jQuery.data(elem,"handle");if(handle)val=handle.apply(elem,data);if((!fn||(jQuery.nodeName(elem,'a')&&type=="click"))&&elem["on"+type]&&elem["on"+type].apply(elem,data)===false)val=false;if(event)data.shift();if(extra&&jQuery.isFunction(extra)){ret=extra.apply(elem,val==null?data:data.concat(val));if(ret!==undefined)val=ret;}if(fn&&donative!==false&&val!==false&&!(jQuery.nodeName(elem,'a')&&type=="click")){this.triggered=true;try{elem[type]();}catch(e){}}this.triggered=false;}return val;},handle:function(event){var val,ret,namespace,all,handlers;event=arguments[0]=jQuery.event.fix(event||window.event);namespace=event.type.split(".");event.type=namespace[0];namespace=namespace[1];all=!namespace&&!event.exclusive;handlers=(jQuery.data(this,"events")||{})[event.type];for(var j in handlers){var handler=handlers[j];if(all||handler.type==namespace){event.handler=handler;event.data=handler.data;ret=handler.apply(this,arguments);if(val!==false)val=ret;if(ret===false){event.preventDefault();event.stopPropagation();}}}return val;},fix:function(event){if(event[expando]==true)return event;var originalEvent=event;event={originalEvent:originalEvent};var props="altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target timeStamp toElement type view wheelDelta which".split(" ");for(var i=props.length;i;i--)event[props[i]]=originalEvent[props[i]];event[expando]=true;event.preventDefault=function(){if(originalEvent.preventDefault)originalEvent.preventDefault();originalEvent.returnValue=false;};event.stopPropagation=function(){if(originalEvent.stopPropagation)originalEvent.stopPropagation();originalEvent.cancelBubble=true;};event.timeStamp=event.timeStamp||now();if(!event.target)event.target=event.srcElement||document;if(event.target.nodeType==3)event.target=event.target.parentNode;if(!event.relatedTarget&&event.fromElement)event.relatedTarget=event.fromElement==event.target?event.toElement:event.fromElement;if(event.pageX==null&&event.clientX!=null){var doc=document.documentElement,body=document.body;event.pageX=event.clientX+(doc&&doc.scrollLeft||body&&body.scrollLeft||0)-(doc.clientLeft||0);event.pageY=event.clientY+(doc&&doc.scrollTop||body&&body.scrollTop||0)-(doc.clientTop||0);}if(!event.which&&((event.charCode||event.charCode===0)?event.charCode:event.keyCode))event.which=event.charCode||event.keyCode;if(!event.metaKey&&event.ctrlKey)event.metaKey=event.ctrlKey;if(!event.which&&event.button)event.which=(event.button&1?1:(event.button&2?3:(event.button&4?2:0)));return event;},proxy:function(fn,proxy){proxy.guid=fn.guid=fn.guid||proxy.guid||this.guid++;return proxy;},special:{ready:{setup:function(){bindReady();return;},teardown:function(){return;}},mouseenter:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseover",jQuery.event.special.mouseenter.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseover",jQuery.event.special.mouseenter.handler);return true;},handler:function(event){if(withinElement(event,this))return true;event.type="mouseenter";return jQuery.event.handle.apply(this,arguments);}},mouseleave:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseout",jQuery.event.special.mouseleave.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseout",jQuery.event.special.mouseleave.handler);return true;},handler:function(event){if(withinElement(event,this))return true;event.type="mouseleave";return jQuery.event.handle.apply(this,arguments);}}}};jQuery.fn.extend({bind:function(type,data,fn){return type=="unload"?this.one(type,data,fn):this.each(function(){jQuery.event.add(this,type,fn||data,fn&&data);});},one:function(type,data,fn){var one=jQuery.event.proxy(fn||data,function(event){jQuery(this).unbind(event,one);return(fn||data).apply(this,arguments);});return this.each(function(){jQuery.event.add(this,type,one,fn&&data);});},unbind:function(type,fn){return this.each(function(){jQuery.event.remove(this,type,fn);});},trigger:function(type,data,fn){return this.each(function(){jQuery.event.trigger(type,data,this,true,fn);});},triggerHandler:function(type,data,fn){return this[0]&&jQuery.event.trigger(type,data,this[0],false,fn);},toggle:function(fn){var args=arguments,i=1;while(i<args.length)jQuery.event.proxy(fn,args[i++]);return this.click(jQuery.event.proxy(fn,function(event){this.lastToggle=(this.lastToggle||0)%i;event.preventDefault();return args[this.lastToggle++].apply(this,arguments)||false;}));},hover:function(fnOver,fnOut){return this.bind('mouseenter',fnOver).bind('mouseleave',fnOut);},ready:function(fn){bindReady();if(jQuery.isReady)fn.call(document,jQuery);else
+jQuery.readyList.push(function(){return fn.call(this,jQuery);});return this;}});jQuery.extend({isReady:false,readyList:[],ready:function(){if(!jQuery.isReady){jQuery.isReady=true;if(jQuery.readyList){jQuery.each(jQuery.readyList,function(){this.call(document);});jQuery.readyList=null;}jQuery(document).triggerHandler("ready");}}});var readyBound=false;function bindReady(){if(readyBound)return;readyBound=true;if(document.addEventListener&&!jQuery.browser.opera)document.addEventListener("DOMContentLoaded",jQuery.ready,false);if(jQuery.browser.msie&&window==top)(function(){if(jQuery.isReady)return;try{document.documentElement.doScroll("left");}catch(error){setTimeout(arguments.callee,0);return;}jQuery.ready();})();if(jQuery.browser.opera)document.addEventListener("DOMContentLoaded",function(){if(jQuery.isReady)return;for(var i=0;i<document.styleSheets.length;i++)if(document.styleSheets[i].disabled){setTimeout(arguments.callee,0);return;}jQuery.ready();},false);if(jQuery.browser.safari){var numStyles;(function(){if(jQuery.isReady)return;if(document.readyState!="loaded"&&document.readyState!="complete"){setTimeout(arguments.callee,0);return;}if(numStyles===undefined)numStyles=jQuery("style, link[rel=stylesheet]").length;if(document.styleSheets.length!=numStyles){setTimeout(arguments.callee,0);return;}jQuery.ready();})();}jQuery.event.add(window,"load",jQuery.ready);}jQuery.each(("blur,focus,load,resize,scroll,unload,click,dblclick,"+"mousedown,mouseup,mousemove,mouseover,mouseout,change,select,"+"submit,keydown,keypress,keyup,error").split(","),function(i,name){jQuery.fn[name]=function(fn){return fn?this.bind(name,fn):this.trigger(name);};});var withinElement=function(event,elem){var parent=event.relatedTarget;while(parent&&parent!=elem)try{parent=parent.parentNode;}catch(error){parent=elem;}return parent==elem;};jQuery(window).bind("unload",function(){jQuery("*").add(document).unbind();});jQuery.fn.extend({_load:jQuery.fn.load,load:function(url,params,callback){if(typeof url!='string')return this._load(url);var off=url.indexOf(" ");if(off>=0){var selector=url.slice(off,url.length);url=url.slice(0,off);}callback=callback||function(){};var type="GET";if(params)if(jQuery.isFunction(params)){callback=params;params=null;}else{params=jQuery.param(params);type="POST";}var self=this;jQuery.ajax({url:url,type:type,dataType:"html",data:params,complete:function(res,status){if(status=="success"||status=="notmodified")self.html(selector?jQuery("<div/>").append(res.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(selector):res.responseText);self.each(callback,[res.responseText,status,res]);}});return this;},serialize:function(){return jQuery.param(this.serializeArray());},serializeArray:function(){return this.map(function(){return jQuery.nodeName(this,"form")?jQuery.makeArray(this.elements):this;}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password/i.test(this.type));}).map(function(i,elem){var val=jQuery(this).val();return val==null?null:val.constructor==Array?jQuery.map(val,function(val,i){return{name:elem.name,value:val};}):{name:elem.name,value:val};}).get();}});jQuery.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(i,o){jQuery.fn[o]=function(f){return this.bind(o,f);};});var jsc=now();jQuery.extend({get:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data=null;}return jQuery.ajax({type:"GET",url:url,data:data,success:callback,dataType:type});},getScript:function(url,callback){return jQuery.get(url,null,callback,"script");},getJSON:function(url,data,callback){return jQuery.get(url,data,callback,"json");},post:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data={};}return jQuery.ajax({type:"POST",url:url,data:data,success:callback,dataType:type});},ajaxSetup:function(settings){jQuery.extend(jQuery.ajaxSettings,settings);},ajaxSettings:{url:location.href,global:true,type:"GET",timeout:0,contentType:"application/x-www-form-urlencoded",processData:true,async:true,data:null,username:null,password:null,accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(s){s=jQuery.extend(true,s,jQuery.extend(true,{},jQuery.ajaxSettings,s));var jsonp,jsre=/=\?(&|$)/g,status,data,type=s.type.toUpperCase();if(s.data&&s.processData&&typeof s.data!="string")s.data=jQuery.param(s.data);if(s.dataType=="jsonp"){if(type=="GET"){if(!s.url.match(jsre))s.url+=(s.url.match(/\?/)?"&":"?")+(s.jsonp||"callback")+"=?";}else if(!s.data||!s.data.match(jsre))s.data=(s.data?s.data+"&":"")+(s.jsonp||"callback")+"=?";s.dataType="json";}if(s.dataType=="json"&&(s.data&&s.data.match(jsre)||s.url.match(jsre))){jsonp="jsonp"+jsc++;if(s.data)s.data=(s.data+"").replace(jsre,"="+jsonp+"$1");s.url=s.url.replace(jsre,"="+jsonp+"$1");s.dataType="script";window[jsonp]=function(tmp){data=tmp;success();complete();window[jsonp]=undefined;try{delete window[jsonp];}catch(e){}if(head)head.removeChild(script);};}if(s.dataType=="script"&&s.cache==null)s.cache=false;if(s.cache===false&&type=="GET"){var ts=now();var ret=s.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+ts+"$2");s.url=ret+((ret==s.url)?(s.url.match(/\?/)?"&":"?")+"_="+ts:"");}if(s.data&&type=="GET"){s.url+=(s.url.match(/\?/)?"&":"?")+s.data;s.data=null;}if(s.global&&!jQuery.active++)jQuery.event.trigger("ajaxStart");var remote=/^(?:\w+:)?\/\/([^\/?#]+)/;if(s.dataType=="script"&&type=="GET"&&remote.test(s.url)&&remote.exec(s.url)[1]!=location.host){var head=document.getElementsByTagName("head")[0];var script=document.createElement("script");script.src=s.url;if(s.scriptCharset)script.charset=s.scriptCharset;if(!jsonp){var done=false;script.onload=script.onreadystatechange=function(){if(!done&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){done=true;success();complete();head.removeChild(script);}};}head.appendChild(script);return undefined;}var requestDone=false;var xhr=window.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest();if(s.username)xhr.open(type,s.url,s.async,s.username,s.password);else
+xhr.open(type,s.url,s.async);try{if(s.data)xhr.setRequestHeader("Content-Type",s.contentType);if(s.ifModified)xhr.setRequestHeader("If-Modified-Since",jQuery.lastModified[s.url]||"Thu, 01 Jan 1970 00:00:00 GMT");xhr.setRequestHeader("X-Requested-With","XMLHttpRequest");xhr.setRequestHeader("Accept",s.dataType&&s.accepts[s.dataType]?s.accepts[s.dataType]+", */*":s.accepts._default);}catch(e){}if(s.beforeSend&&s.beforeSend(xhr,s)===false){s.global&&jQuery.active--;xhr.abort();return false;}if(s.global)jQuery.event.trigger("ajaxSend",[xhr,s]);var onreadystatechange=function(isTimeout){if(!requestDone&&xhr&&(xhr.readyState==4||isTimeout=="timeout")){requestDone=true;if(ival){clearInterval(ival);ival=null;}status=isTimeout=="timeout"&&"timeout"||!jQuery.httpSuccess(xhr)&&"error"||s.ifModified&&jQuery.httpNotModified(xhr,s.url)&&"notmodified"||"success";if(status=="success"){try{data=jQuery.httpData(xhr,s.dataType,s.dataFilter);}catch(e){status="parsererror";}}if(status=="success"){var modRes;try{modRes=xhr.getResponseHeader("Last-Modified");}catch(e){}if(s.ifModified&&modRes)jQuery.lastModified[s.url]=modRes;if(!jsonp)success();}else
+jQuery.handleError(s,xhr,status);complete();if(s.async)xhr=null;}};if(s.async){var ival=setInterval(onreadystatechange,13);if(s.timeout>0)setTimeout(function(){if(xhr){xhr.abort();if(!requestDone)onreadystatechange("timeout");}},s.timeout);}try{xhr.send(s.data);}catch(e){jQuery.handleError(s,xhr,null,e);}if(!s.async)onreadystatechange();function success(){if(s.success)s.success(data,status);if(s.global)jQuery.event.trigger("ajaxSuccess",[xhr,s]);}function complete(){if(s.complete)s.complete(xhr,status);if(s.global)jQuery.event.trigger("ajaxComplete",[xhr,s]);if(s.global&&!--jQuery.active)jQuery.event.trigger("ajaxStop");}return xhr;},handleError:function(s,xhr,status,e){if(s.error)s.error(xhr,status,e);if(s.global)jQuery.event.trigger("ajaxError",[xhr,s,e]);},active:0,httpSuccess:function(xhr){try{return!xhr.status&&location.protocol=="file:"||(xhr.status>=200&&xhr.status<300)||xhr.status==304||xhr.status==1223||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return false;},httpNotModified:function(xhr,url){try{var xhrRes=xhr.getResponseHeader("Last-Modified");return xhr.status==304||xhrRes==jQuery.lastModified[url]||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return false;},httpData:function(xhr,type,filter){var ct=xhr.getResponseHeader("content-type"),xml=type=="xml"||!type&&ct&&ct.indexOf("xml")>=0,data=xml?xhr.responseXML:xhr.responseText;if(xml&&data.documentElement.tagName=="parsererror")throw"parsererror";if(filter)data=filter(data,type);if(type=="script")jQuery.globalEval(data);if(type=="json")data=eval("("+data+")");return data;},param:function(a){var s=[];if(a.constructor==Array||a.jquery)jQuery.each(a,function(){s.push(encodeURIComponent(this.name)+"="+encodeURIComponent(this.value));});else
+for(var j in a)if(a[j]&&a[j].constructor==Array)jQuery.each(a[j],function(){s.push(encodeURIComponent(j)+"="+encodeURIComponent(this));});else
+s.push(encodeURIComponent(j)+"="+encodeURIComponent(jQuery.isFunction(a[j])?a[j]():a[j]));return s.join("&").replace(/%20/g,"+");}});jQuery.fn.extend({show:function(speed,callback){return speed?this.animate({height:"show",width:"show",opacity:"show"},speed,callback):this.filter(":hidden").each(function(){this.style.display=this.oldblock||"";if(jQuery.css(this,"display")=="none"){var elem=jQuery("<"+this.tagName+" />").appendTo("body");this.style.display=elem.css("display");if(this.style.display=="none")this.style.display="block";elem.remove();}}).end();},hide:function(speed,callback){return speed?this.animate({height:"hide",width:"hide",opacity:"hide"},speed,callback):this.filter(":visible").each(function(){this.oldblock=this.oldblock||jQuery.css(this,"display");this.style.display="none";}).end();},_toggle:jQuery.fn.toggle,toggle:function(fn,fn2){return jQuery.isFunction(fn)&&jQuery.isFunction(fn2)?this._toggle.apply(this,arguments):fn?this.animate({height:"toggle",width:"toggle",opacity:"toggle"},fn,fn2):this.each(function(){jQuery(this)[jQuery(this).is(":hidden")?"show":"hide"]();});},slideDown:function(speed,callback){return this.animate({height:"show"},speed,callback);},slideUp:function(speed,callback){return this.animate({height:"hide"},speed,callback);},slideToggle:function(speed,callback){return this.animate({height:"toggle"},speed,callback);},fadeIn:function(speed,callback){return this.animate({opacity:"show"},speed,callback);},fadeOut:function(speed,callback){return this.animate({opacity:"hide"},speed,callback);},fadeTo:function(speed,to,callback){return this.animate({opacity:to},speed,callback);},animate:function(prop,speed,easing,callback){var optall=jQuery.speed(speed,easing,callback);return this[optall.queue===false?"each":"queue"](function(){if(this.nodeType!=1)return false;var opt=jQuery.extend({},optall),p,hidden=jQuery(this).is(":hidden"),self=this;for(p in prop){if(prop[p]=="hide"&&hidden||prop[p]=="show"&&!hidden)return opt.complete.call(this);if(p=="height"||p=="width"){opt.display=jQuery.css(this,"display");opt.overflow=this.style.overflow;}}if(opt.overflow!=null)this.style.overflow="hidden";opt.curAnim=jQuery.extend({},prop);jQuery.each(prop,function(name,val){var e=new jQuery.fx(self,opt,name);if(/toggle|show|hide/.test(val))e[val=="toggle"?hidden?"show":"hide":val](prop);else{var parts=val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),start=e.cur(true)||0;if(parts){var end=parseFloat(parts[2]),unit=parts[3]||"px";if(unit!="px"){self.style[name]=(end||1)+unit;start=((end||1)/e.cur(true))*start;self.style[name]=start+unit;}if(parts[1])end=((parts[1]=="-="?-1:1)*end)+start;e.custom(start,end,unit);}else
+e.custom(start,val,"");}});return true;});},queue:function(type,fn){if(jQuery.isFunction(type)||(type&&type.constructor==Array)){fn=type;type="fx";}if(!type||(typeof type=="string"&&!fn))return queue(this[0],type);return this.each(function(){if(fn.constructor==Array)queue(this,type,fn);else{queue(this,type).push(fn);if(queue(this,type).length==1)fn.call(this);}});},stop:function(clearQueue,gotoEnd){var timers=jQuery.timers;if(clearQueue)this.queue([]);this.each(function(){for(var i=timers.length-1;i>=0;i--)if(timers[i].elem==this){if(gotoEnd)timers[i](true);timers.splice(i,1);}});if(!gotoEnd)this.dequeue();return this;}});var queue=function(elem,type,array){if(elem){type=type||"fx";var q=jQuery.data(elem,type+"queue");if(!q||array)q=jQuery.data(elem,type+"queue",jQuery.makeArray(array));}return q;};jQuery.fn.dequeue=function(type){type=type||"fx";return this.each(function(){var q=queue(this,type);q.shift();if(q.length)q[0].call(this);});};jQuery.extend({speed:function(speed,easing,fn){var opt=speed&&speed.constructor==Object?speed:{complete:fn||!fn&&easing||jQuery.isFunction(speed)&&speed,duration:speed,easing:fn&&easing||easing&&easing.constructor!=Function&&easing};opt.duration=(opt.duration&&opt.duration.constructor==Number?opt.duration:jQuery.fx.speeds[opt.duration])||jQuery.fx.speeds.def;opt.old=opt.complete;opt.complete=function(){if(opt.queue!==false)jQuery(this).dequeue();if(jQuery.isFunction(opt.old))opt.old.call(this);};return opt;},easing:{linear:function(p,n,firstNum,diff){return firstNum+diff*p;},swing:function(p,n,firstNum,diff){return((-Math.cos(p*Math.PI)/2)+0.5)*diff+firstNum;}},timers:[],timerId:null,fx:function(elem,options,prop){this.options=options;this.elem=elem;this.prop=prop;if(!options.orig)options.orig={};}});jQuery.fx.prototype={update:function(){if(this.options.step)this.options.step.call(this.elem,this.now,this);(jQuery.fx.step[this.prop]||jQuery.fx.step._default)(this);if(this.prop=="height"||this.prop=="width")this.elem.style.display="block";},cur:function(force){if(this.elem[this.prop]!=null&&this.elem.style[this.prop]==null)return this.elem[this.prop];var r=parseFloat(jQuery.css(this.elem,this.prop,force));return r&&r>-10000?r:parseFloat(jQuery.curCSS(this.elem,this.prop))||0;},custom:function(from,to,unit){this.startTime=now();this.start=from;this.end=to;this.unit=unit||this.unit||"px";this.now=this.start;this.pos=this.state=0;this.update();var self=this;function t(gotoEnd){return self.step(gotoEnd);}t.elem=this.elem;jQuery.timers.push(t);if(jQuery.timerId==null){jQuery.timerId=setInterval(function(){var timers=jQuery.timers;for(var i=0;i<timers.length;i++)if(!timers[i]())timers.splice(i--,1);if(!timers.length){clearInterval(jQuery.timerId);jQuery.timerId=null;}},13);}},show:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.show=true;this.custom(0,this.cur());if(this.prop=="width"||this.prop=="height")this.elem.style[this.prop]="1px";jQuery(this.elem).show();},hide:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0);},step:function(gotoEnd){var t=now();if(gotoEnd||t>this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var done=true;for(var i in this.options.curAnim)if(this.options.curAnim[i]!==true)done=false;if(done){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(jQuery.css(this.elem,"display")=="none")this.elem.style.display="block";}if(this.options.hide)this.elem.style.display="none";if(this.options.hide||this.options.show)for(var p in this.options.curAnim)jQuery.attr(this.elem.style,p,this.options.orig[p]);}if(done)this.options.complete.call(this.elem);return false;}else{var n=t-this.startTime;this.state=n/this.options.duration;this.pos=jQuery.easing[this.options.easing||(jQuery.easing.swing?"swing":"linear")](this.state,n,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update();}return true;}};jQuery.extend(jQuery.fx,{speeds:{slow:600,fast:200,def:400},step:{scrollLeft:function(fx){fx.elem.scrollLeft=fx.now;},scrollTop:function(fx){fx.elem.scrollTop=fx.now;},opacity:function(fx){jQuery.attr(fx.elem.style,"opacity",fx.now);},_default:function(fx){fx.elem.style[fx.prop]=fx.now+fx.unit;}}});jQuery.fn.offset=function(){var left=0,top=0,elem=this[0],results;if(elem)with(jQuery.browser){var parent=elem.parentNode,offsetChild=elem,offsetParent=elem.offsetParent,doc=elem.ownerDocument,safari2=safari&&parseInt(version)<522&&!/adobeair/i.test(userAgent),css=jQuery.curCSS,fixed=css(elem,"position")=="fixed";if(elem.getBoundingClientRect){var box=elem.getBoundingClientRect();add(box.left+Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),box.top+Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));add(-doc.documentElement.clientLeft,-doc.documentElement.clientTop);}else{add(elem.offsetLeft,elem.offsetTop);while(offsetParent){add(offsetParent.offsetLeft,offsetParent.offsetTop);if(mozilla&&!/^t(able|d|h)$/i.test(offsetParent.tagName)||safari&&!safari2)border(offsetParent);if(!fixed&&css(offsetParent,"position")=="fixed")fixed=true;offsetChild=/^body$/i.test(offsetParent.tagName)?offsetChild:offsetParent;offsetParent=offsetParent.offsetParent;}while(parent&&parent.tagName&&!/^body|html$/i.test(parent.tagName)){if(!/^inline|table.*$/i.test(css(parent,"display")))add(-parent.scrollLeft,-parent.scrollTop);if(mozilla&&css(parent,"overflow")!="visible")border(parent);parent=parent.parentNode;}if((safari2&&(fixed||css(offsetChild,"position")=="absolute"))||(mozilla&&css(offsetChild,"position")!="absolute"))add(-doc.body.offsetLeft,-doc.body.offsetTop);if(fixed)add(Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));}results={top:top,left:left};}function border(elem){add(jQuery.curCSS(elem,"borderLeftWidth",true),jQuery.curCSS(elem,"borderTopWidth",true));}function add(l,t){left+=parseInt(l,10)||0;top+=parseInt(t,10)||0;}return results;};jQuery.fn.extend({position:function(){var left=0,top=0,results;if(this[0]){var offsetParent=this.offsetParent(),offset=this.offset(),parentOffset=/^body|html$/i.test(offsetParent[0].tagName)?{top:0,left:0}:offsetParent.offset();offset.top-=num(this,'marginTop');offset.left-=num(this,'marginLeft');parentOffset.top+=num(offsetParent,'borderTopWidth');parentOffset.left+=num(offsetParent,'borderLeftWidth');results={top:offset.top-parentOffset.top,left:offset.left-parentOffset.left};}return results;},offsetParent:function(){var offsetParent=this[0].offsetParent;while(offsetParent&&(!/^body|html$/i.test(offsetParent.tagName)&&jQuery.css(offsetParent,'position')=='static'))offsetParent=offsetParent.offsetParent;return jQuery(offsetParent);}});jQuery.each(['Left','Top'],function(i,name){var method='scroll'+name;jQuery.fn[method]=function(val){if(!this[0])return;return val!=undefined?this.each(function(){this==window||this==document?window.scrollTo(!i?val:jQuery(window).scrollLeft(),i?val:jQuery(window).scrollTop()):this[method]=val;}):this[0]==window||this[0]==document?self[i?'pageYOffset':'pageXOffset']||jQuery.boxModel&&document.documentElement[method]||document.body[method]:this[0][method];};});jQuery.each(["Height","Width"],function(i,name){var tl=i?"Left":"Top",br=i?"Right":"Bottom";jQuery.fn["inner"+name]=function(){return this[name.toLowerCase()]()+num(this,"padding"+tl)+num(this,"padding"+br);};jQuery.fn["outer"+name]=function(margin){return this["inner"+name]()+num(this,"border"+tl+"Width")+num(this,"border"+br+"Width")+(margin?num(this,"margin"+tl)+num(this,"margin"+br):0);};});})(); \ No newline at end of file
diff --git a/lib/rdoc/generator/template/darkfish/js/quicksearch.js b/lib/rdoc/generator/template/darkfish/js/quicksearch.js
new file mode 100644
index 0000000..332772a
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/js/quicksearch.js
@@ -0,0 +1,114 @@
+/**
+ *
+ * JQuery QuickSearch - Hook up a form field to hide non-matching elements.
+ * $Id: quicksearch.js 53 2009-01-07 02:52:03Z deveiant $
+ *
+ * Author: Michael Granger <mgranger@laika.com>
+ *
+ */
+jQuery.fn.quicksearch = function( target, searchElems, options ) {
+ // console.debug( "Quicksearch fn" );
+
+ var settings = {
+ delay: 250,
+ clearButton: false,
+ highlightMatches: false,
+ focusOnLoad: false,
+ noSearchResultsIndicator: null
+ };
+ if ( options ) $.extend( settings, options );
+
+ return jQuery(this).each( function() {
+ // console.debug( "Creating a new quicksearch on %o for %o", this, searchElems );
+ new jQuery.quicksearch( this, searchElems, settings );
+ });
+};
+
+
+jQuery.quicksearch = function( searchBox, searchElems, settings ) {
+ var timeout;
+ var boxdiv = $(searchBox).parents('div').eq(0);
+
+ function init() {
+ setupKeyEventHandlers();
+ focusOnLoad();
+ };
+
+ function setupKeyEventHandlers() {
+ // console.debug( "Hooking up the 'keypress' event to %o", searchBox );
+ $(searchBox).
+ unbind( 'keyup' ).
+ keyup( function(e) { return onSearchKey( e.keyCode ); });
+ $(searchBox).
+ unbind( 'keypress' ).
+ keypress( function(e) {
+ switch( e.which ) {
+ // Execute the search on Enter, Tab, or Newline
+ case 9:
+ case 13:
+ case 10:
+ clearTimeout( timeout );
+ e.preventDefault();
+ doQuickSearch();
+ break;
+
+ // Allow backspace
+ case 8:
+ return true;
+ break;
+
+ // Only allow valid search characters
+ default:
+ return validQSChar( e.charCode );
+ }
+ });
+ };
+
+ function focusOnLoad() {
+ if ( !settings.focusOnLoad ) return false;
+ $(searchBox).focus();
+ };
+
+ function onSearchKey ( code ) {
+ clearTimeout( timeout );
+ // console.debug( "...scheduling search." );
+ timeout = setTimeout( doQuickSearch, settings.delay );
+ };
+
+ function validQSChar( code ) {
+ var c = String.fromCharCode( code );
+ return (
+ (c == ':') ||
+ (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z')
+ );
+ };
+
+ function doQuickSearch() {
+ var searchText = searchBox.value;
+ var pat = new RegExp( searchText, "im" );
+ var shownCount = 0;
+
+ if ( settings.noSearchResultsIndicator ) {
+ $('#' + settings.noSearchResultsIndicator).hide();
+ }
+
+ // All elements start out hidden
+ $(searchElems).each( function(index) {
+ var str = $(this).text();
+
+ if ( pat.test(str) ) {
+ shownCount += 1;
+ $(this).fadeIn();
+ } else {
+ $(this).hide();
+ }
+ });
+
+ if ( shownCount == 0 && settings.noSearchResultsIndicator ) {
+ $('#' + settings.noSearchResultsIndicator).slideDown();
+ }
+ };
+
+ init();
+};
diff --git a/lib/rdoc/generator/template/darkfish/js/thickbox-compressed.js b/lib/rdoc/generator/template/darkfish/js/thickbox-compressed.js
new file mode 100644
index 0000000..3a3fdae
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/js/thickbox-compressed.js
@@ -0,0 +1,10 @@
+/*
+ * Thickbox 3 - One Box To Rule Them All.
+ * By Cody Lindley (http://www.codylindley.com)
+ * Copyright (c) 2007 cody lindley
+ * Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php
+*/
+
+var tb_pathToImage = "../images/loadingAnimation.gif";
+
+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('$(o).2S(9(){1u(\'a.18, 3n.18, 3i.18\');1w=1p 1t();1w.L=2H});9 1u(b){$(b).s(9(){6 t=X.Q||X.1v||M;6 a=X.u||X.23;6 g=X.1N||P;19(t,a,g);X.2E();H P})}9 19(d,f,g){3m{3(2t o.v.J.2i==="2g"){$("v","11").r({A:"28%",z:"28%"});$("11").r("22","2Z");3(o.1Y("1F")===M){$("v").q("<U 5=\'1F\'></U><4 5=\'B\'></4><4 5=\'8\'></4>");$("#B").s(G)}}n{3(o.1Y("B")===M){$("v").q("<4 5=\'B\'></4><4 5=\'8\'></4>");$("#B").s(G)}}3(1K()){$("#B").1J("2B")}n{$("#B").1J("2z")}3(d===M){d=""}$("v").q("<4 5=\'K\'><1I L=\'"+1w.L+"\' /></4>");$(\'#K\').2y();6 h;3(f.O("?")!==-1){h=f.3l(0,f.O("?"))}n{h=f}6 i=/\\.2s$|\\.2q$|\\.2m$|\\.2l$|\\.2k$/;6 j=h.1C().2h(i);3(j==\'.2s\'||j==\'.2q\'||j==\'.2m\'||j==\'.2l\'||j==\'.2k\'){1D="";1G="";14="";1z="";1x="";R="";1n="";1r=P;3(g){E=$("a[@1N="+g+"]").36();25(D=0;((D<E.1c)&&(R===""));D++){6 k=E[D].u.1C().2h(i);3(!(E[D].u==f)){3(1r){1z=E[D].Q;1x=E[D].u;R="<1e 5=\'1X\'>&1d;&1d;<a u=\'#\'>2T &2R;</a></1e>"}n{1D=E[D].Q;1G=E[D].u;14="<1e 5=\'1U\'>&1d;&1d;<a u=\'#\'>&2O; 2N</a></1e>"}}n{1r=1b;1n="1t "+(D+1)+" 2L "+(E.1c)}}}S=1p 1t();S.1g=9(){S.1g=M;6 a=2x();6 x=a[0]-1M;6 y=a[1]-1M;6 b=S.z;6 c=S.A;3(b>x){c=c*(x/b);b=x;3(c>y){b=b*(y/c);c=y}}n 3(c>y){b=b*(y/c);c=y;3(b>x){c=c*(x/b);b=x}}13=b+30;1a=c+2G;$("#8").q("<a u=\'\' 5=\'1L\' Q=\'1o\'><1I 5=\'2F\' L=\'"+f+"\' z=\'"+b+"\' A=\'"+c+"\' 23=\'"+d+"\'/></a>"+"<4 5=\'2D\'>"+d+"<4 5=\'2C\'>"+1n+14+R+"</4></4><4 5=\'2A\'><a u=\'#\' 5=\'Z\' Q=\'1o\'>1l</a> 1k 1j 1s</4>");$("#Z").s(G);3(!(14==="")){9 12(){3($(o).N("s",12)){$(o).N("s",12)}$("#8").C();$("v").q("<4 5=\'8\'></4>");19(1D,1G,g);H P}$("#1U").s(12)}3(!(R==="")){9 1i(){$("#8").C();$("v").q("<4 5=\'8\'></4>");19(1z,1x,g);H P}$("#1X").s(1i)}o.1h=9(e){3(e==M){I=2w.2v}n{I=e.2u}3(I==27){G()}n 3(I==3k){3(!(R=="")){o.1h="";1i()}}n 3(I==3j){3(!(14=="")){o.1h="";12()}}};16();$("#K").C();$("#1L").s(G);$("#8").r({Y:"T"})};S.L=f}n{6 l=f.2r(/^[^\\?]+\\??/,\'\');6 m=2p(l);13=(m[\'z\']*1)+30||3h;1a=(m[\'A\']*1)+3g||3f;W=13-30;V=1a-3e;3(f.O(\'2j\')!=-1){1E=f.1B(\'3d\');$("#15").C();3(m[\'1A\']!="1b"){$("#8").q("<4 5=\'2f\'><4 5=\'1H\'>"+d+"</4><4 5=\'2e\'><a u=\'#\' 5=\'Z\' Q=\'1o\'>1l</a> 1k 1j 1s</4></4><U 1W=\'0\' 2d=\'0\' L=\'"+1E[0]+"\' 5=\'15\' 1v=\'15"+1f.2c(1f.1y()*2b)+"\' 1g=\'1m()\' J=\'z:"+(W+29)+"p;A:"+(V+17)+"p;\' > </U>")}n{$("#B").N();$("#8").q("<U 1W=\'0\' 2d=\'0\' L=\'"+1E[0]+"\' 5=\'15\' 1v=\'15"+1f.2c(1f.1y()*2b)+"\' 1g=\'1m()\' J=\'z:"+(W+29)+"p;A:"+(V+17)+"p;\'> </U>")}}n{3($("#8").r("Y")!="T"){3(m[\'1A\']!="1b"){$("#8").q("<4 5=\'2f\'><4 5=\'1H\'>"+d+"</4><4 5=\'2e\'><a u=\'#\' 5=\'Z\'>1l</a> 1k 1j 1s</4></4><4 5=\'F\' J=\'z:"+W+"p;A:"+V+"p\'></4>")}n{$("#B").N();$("#8").q("<4 5=\'F\' 3c=\'3b\' J=\'z:"+W+"p;A:"+V+"p;\'></4>")}}n{$("#F")[0].J.z=W+"p";$("#F")[0].J.A=V+"p";$("#F")[0].3a=0;$("#1H").11(d)}}$("#Z").s(G);3(f.O(\'37\')!=-1){$("#F").q($(\'#\'+m[\'26\']).1T());$("#8").24(9(){$(\'#\'+m[\'26\']).q($("#F").1T())});16();$("#K").C();$("#8").r({Y:"T"})}n 3(f.O(\'2j\')!=-1){16();3($.1q.35){$("#K").C();$("#8").r({Y:"T"})}}n{$("#F").34(f+="&1y="+(1p 33().32()),9(){16();$("#K").C();1u("#F a.18");$("#8").r({Y:"T"})})}}3(!m[\'1A\']){o.21=9(e){3(e==M){I=2w.2v}n{I=e.2u}3(I==27){G()}}}}31(e){}}9 1m(){$("#K").C();$("#8").r({Y:"T"})}9 G(){$("#2Y").N("s");$("#Z").N("s");$("#8").2X("2W",9(){$(\'#8,#B,#1F\').2V("24").N().C()});$("#K").C();3(2t o.v.J.2i=="2g"){$("v","11").r({A:"1Z",z:"1Z"});$("11").r("22","")}o.1h="";o.21="";H P}9 16(){$("#8").r({2U:\'-\'+20((13/2),10)+\'p\',z:13+\'p\'});3(!(1V.1q.2Q&&1V.1q.2P<7)){$("#8").r({38:\'-\'+20((1a/2),10)+\'p\'})}}9 2p(a){6 b={};3(!a){H b}6 c=a.1B(/[;&]/);25(6 i=0;i<c.1c;i++){6 d=c[i].1B(\'=\');3(!d||d.1c!=2){39}6 e=2a(d[0]);6 f=2a(d[1]);f=f.2r(/\\+/g,\' \');b[e]=f}H b}9 2x(){6 a=o.2M;6 w=1S.2o||1R.2o||(a&&a.1Q)||o.v.1Q;6 h=1S.1P||1R.1P||(a&&a.2n)||o.v.2n;1O=[w,h];H 1O}9 1K(){6 a=2K.2J.1C();3(a.O(\'2I\')!=-1&&a.O(\'3o\')!=-1){H 1b}}',62,211,'|||if|div|id|var||TB_window|function||||||||||||||else|document|px|append|css|click||href|body||||width|height|TB_overlay|remove|TB_Counter|TB_TempArray|TB_ajaxContent|tb_remove|return|keycode|style|TB_load|src|null|unbind|indexOf|false|title|TB_NextHTML|imgPreloader|block|iframe|ajaxContentH|ajaxContentW|this|display|TB_closeWindowButton||html|goPrev|TB_WIDTH|TB_PrevHTML|TB_iframeContent|tb_position||thickbox|tb_show|TB_HEIGHT|true|length|nbsp|span|Math|onload|onkeydown|goNext|Esc|or|close|tb_showIframe|TB_imageCount|Close|new|browser|TB_FoundURL|Key|Image|tb_init|name|imgLoader|TB_NextURL|random|TB_NextCaption|modal|split|toLowerCase|TB_PrevCaption|urlNoQuery|TB_HideSelect|TB_PrevURL|TB_ajaxWindowTitle|img|addClass|tb_detectMacXFF|TB_ImageOff|150|rel|arrayPageSize|innerHeight|clientWidth|self|window|children|TB_prev|jQuery|frameborder|TB_next|getElementById|auto|parseInt|onkeyup|overflow|alt|unload|for|inlineId||100||unescape|1000|round|hspace|TB_closeAjaxWindow|TB_title|undefined|match|maxHeight|TB_iframe|bmp|gif|png|clientHeight|innerWidth|tb_parseQuery|jpeg|replace|jpg|typeof|which|keyCode|event|tb_getPageSize|show|TB_overlayBG|TB_closeWindow|TB_overlayMacFFBGHack|TB_secondLine|TB_caption|blur|TB_Image|60|tb_pathToImage|mac|userAgent|navigator|of|documentElement|Prev|lt|version|msie|gt|ready|Next|marginLeft|trigger|fast|fadeOut|TB_imageOff|hidden||catch|getTime|Date|load|safari|get|TB_inline|marginTop|continue|scrollTop|TB_modal|class|TB_|45|440|40|630|input|188|190|substr|try|area|firefox'.split('|'),0,{})) \ No newline at end of file
diff --git a/lib/rdoc/generator/template/darkfish/rdoc.css b/lib/rdoc/generator/template/darkfish/rdoc.css
new file mode 100644
index 0000000..e836c66
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/rdoc.css
@@ -0,0 +1,701 @@
+/*
+ * "Darkfish" Rdoc CSS
+ * $Id: rdoc.css 54 2009-01-27 01:09:48Z deveiant $
+ *
+ * Author: Michael Granger <ged@FaerieMUD.org>
+ *
+ */
+
+/* Base Green is: #6C8C22 */
+
+*{ padding: 0; margin: 0; }
+
+body {
+ background: #efefef;
+ font: 14px "Helvetica Neue", Helvetica, Tahoma, sans-serif;
+}
+body.class, body.module, body.file {
+ margin-left: 40px;
+}
+body.file-popup {
+ font-size: 90%;
+ margin-left: 0;
+}
+
+h1 {
+ font-size: 300%;
+ text-shadow: rgba(135,145,135,0.65) 2px 2px 3px;
+ color: #6C8C22;
+}
+h2,h3,h4 { margin-top: 1.5em; }
+
+:link,
+:visited {
+ color: #6C8C22;
+ text-decoration: none;
+}
+:link:hover,
+:visited:hover {
+ border-bottom: 1px dotted #6C8C22;
+}
+
+pre {
+ background: #ddd;
+ padding: 0.5em 0;
+}
+
+
+/* @group Generic Classes */
+
+.initially-hidden {
+ display: none;
+}
+
+.quicksearch-field {
+ width: 98%;
+ background: #ddd;
+ border: 1px solid #aaa;
+ height: 1.5em;
+ -webkit-border-radius: 4px;
+}
+.quicksearch-field:focus {
+ background: #f1edba;
+}
+
+.missing-docs {
+ font-size: 120%;
+ background: white url(images/wrench_orange.png) no-repeat 4px center;
+ color: #ccc;
+ line-height: 2em;
+ border: 1px solid #d00;
+ opacity: 1;
+ padding-left: 20px;
+ text-indent: 24px;
+ letter-spacing: 3px;
+ font-weight: bold;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+}
+
+.target-section {
+ border: 2px solid #dcce90;
+ border-left-width: 8px;
+ padding: 0 1em;
+ background: #fff3c2;
+}
+
+/* @end */
+
+
+/* @group Index Page, Standalone file pages */
+body.indexpage {
+ margin: 1em 3em;
+}
+body.indexpage p,
+body.indexpage div,
+body.file p {
+ margin: 1em 0;
+}
+
+.indexpage ul,
+.file #documentation ul {
+ line-height: 160%;
+ list-style: none;
+}
+.indexpage ul :link,
+.indexpage ul :visited,
+.file #documentation ul :link,
+.file #documentation ul :visited {
+ font-size: 16px;
+}
+
+.indexpage li,
+.file #documentation li {
+ padding-left: 20px;
+ background: url(images/bullet_black.png) no-repeat left 4px;
+}
+.indexpage li.module {
+ background: url(images/package.png) no-repeat left 4px;
+}
+.indexpage li.class {
+ background: url(images/ruby.png) no-repeat left 4px;
+}
+.indexpage li.file {
+ background: url(images/page_white_text.png) no-repeat left 4px;
+}
+.file li p,
+.indexpage li p {
+ margin: 0 0;
+}
+
+/* @end */
+
+/* @group Top-Level Structure */
+
+.class #metadata,
+.file #metadata,
+.module #metadata {
+ float: left;
+ width: 260px;
+}
+
+.class #documentation,
+.file #documentation,
+.module #documentation {
+ margin: 2em 1em 5em 300px;
+ min-width: 340px;
+}
+
+.file #metadata {
+ margin: 0.8em;
+}
+
+#validator-badges {
+ clear: both;
+ margin: 1em 1em 2em;
+}
+
+/* @end */
+
+/* @group Metadata Section */
+#metadata .section {
+ background-color: #dedede;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ border: 1px solid #aaa;
+ margin: 0 8px 16px;
+ font-size: 90%;
+ overflow: hidden;
+}
+#metadata h3.section-header {
+ margin: 0;
+ padding: 2px 8px;
+ background: #ccc;
+ color: #666;
+ -moz-border-radius-topleft: 4px;
+ -moz-border-radius-topright: 4px;
+ -webkit-border-top-left-radius: 4px;
+ -webkit-border-top-right-radius: 4px;
+ border-bottom: 1px solid #aaa;
+}
+#metadata #home-section h3.section-header {
+ border-bottom: 0;
+}
+
+#metadata ul,
+#metadata dl,
+#metadata p {
+ padding: 8px;
+ list-style: none;
+}
+
+#file-metadata ul {
+ padding-left: 28px;
+ list-style-image: url(images/page_green.png);
+}
+
+dl.svninfo {
+ color: #666;
+ margin: 0;
+}
+dl.svninfo dt {
+ font-weight: bold;
+}
+
+ul.link-list li {
+ white-space: nowrap;
+}
+ul.link-list .type {
+ font-size: 8px;
+ text-transform: uppercase;
+ color: white;
+ background: #969696;
+ padding: 2px 4px;
+ -webkit-border-radius: 5px;
+}
+
+/* @end */
+
+
+/* @group Project Metadata Section */
+#project-metadata {
+ margin-top: 3em;
+}
+
+.file #project-metadata {
+ margin-top: 0em;
+}
+
+#project-metadata .section {
+ border: 1px solid #aaa;
+}
+#project-metadata h3.section-header {
+ border-bottom: 1px solid #aaa;
+ position: relative;
+}
+#project-metadata h3.section-header .search-toggle {
+ position: absolute;
+ right: 5px;
+}
+
+
+#project-metadata form {
+ color: #777;
+ background: #ccc;
+ padding: 8px 8px 16px;
+ border-bottom: 1px solid #bbb;
+}
+#project-metadata fieldset {
+ border: 0;
+}
+
+#no-class-search-results {
+ margin: 0 auto 1em;
+ text-align: center;
+ font-size: 14px;
+ font-weight: bold;
+ color: #aaa;
+}
+
+/* @end */
+
+
+/* @group Documentation Section */
+#description {
+ font-size: 100%;
+ color: #333;
+}
+
+#description p {
+ margin: 1em 0.4em;
+}
+
+#description ul {
+ margin-left: 2em;
+}
+#description ul li {
+ line-height: 1.4em;
+}
+
+#description dl,
+#documentation dl {
+ margin: 8px 1.5em;
+ border: 1px solid #ccc;
+}
+#description dl {
+ font-size: 14px;
+}
+
+#description dt,
+#documentation dt {
+ padding: 2px 4px;
+ font-weight: bold;
+ background: #ddd;
+}
+#description dd,
+#documentation dd {
+ padding: 2px 12px;
+}
+#description dd + dt,
+#documentation dd + dt {
+ margin-top: 0.7em;
+}
+
+#documentation .section {
+ font-size: 90%;
+}
+#documentation h3.section-header {
+ margin-top: 2em;
+ padding: 0.75em 0.5em;
+ background-color: #dedede;
+ color: #333;
+ font-size: 150%;
+ border: 1px solid #bbb;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+}
+
+#constants-list > dl,
+#attributes-list > dl {
+ margin: 1em 0 2em;
+ border: 0;
+}
+#constants-list > dl dt,
+#attributes-list > dl dt {
+ padding-left: 0;
+ font-weight: bold;
+ font-family: Monaco, "Andale Mono";
+ background: inherit;
+}
+#constants-list > dl dt a,
+#attributes-list > dl dt a {
+ color: inherit;
+}
+#constants-list > dl dd,
+#attributes-list > dl dd {
+ margin: 0 0 1em 0;
+ padding: 0;
+ color: #666;
+}
+
+/* @group Method Details */
+
+#documentation .method-source-code {
+ display: none;
+}
+
+#documentation .method-detail {
+ margin: 0.5em 0;
+ padding: 0.5em 0;
+ cursor: pointer;
+}
+#documentation .method-detail:hover {
+ background-color: #f1edba;
+}
+#documentation .method-heading {
+ position: relative;
+ padding: 2px 4px 0 20px;
+ font-size: 125%;
+ font-weight: bold;
+ color: #333;
+ background: url(images/brick.png) no-repeat left bottom;
+}
+#documentation .method-heading :link,
+#documentation .method-heading :visited {
+ color: inherit;
+}
+#documentation .method-click-advice {
+ position: absolute;
+ top: 2px;
+ right: 5px;
+ font-size: 10px;
+ color: #9b9877;
+ visibility: hidden;
+ padding-right: 20px;
+ line-height: 20px;
+ background: url(images/zoom.png) no-repeat right top;
+}
+#documentation .method-detail:hover .method-click-advice {
+ visibility: visible;
+}
+
+#documentation .method-alias .method-heading {
+ color: #666;
+ background: url(images/brick_link.png) no-repeat left bottom;
+}
+
+#documentation .method-description,
+#documentation .aliases {
+ margin: 0 20px;
+ line-height: 1.2em;
+ color: #666;
+}
+#documentation .aliases {
+ padding-top: 4px;
+ font-style: italic;
+ cursor: default;
+}
+#documentation .method-description p {
+ padding: 0;
+}
+#documentation .method-description p + p {
+ margin-bottom: 0.5em;
+}
+
+#documentation .attribute-method-heading {
+ background: url(images/tag_green.png) no-repeat left bottom;
+}
+#documentation #attribute-method-details .method-detail:hover {
+ background-color: transparent;
+ cursor: default;
+}
+#documentation .attribute-access-type {
+ font-size: 60%;
+ text-transform: uppercase;
+ vertical-align: super;
+ padding: 0 2px;
+}
+/* @end */
+
+/* @end */
+
+
+
+/* @group Source Code */
+
+div.method-source-code {
+ background: #262626;
+ color: #efefef;
+ margin: 1em;
+ padding: 0.5em;
+ border: 1px dashed #999;
+ overflow: hidden;
+}
+
+div.method-source-code pre {
+ background: inherit;
+ padding: 0;
+ color: white;
+ overflow: auto;
+}
+
+/* @group Ruby keyword styles */
+
+.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; }
+
+/* @end */
+/* @end */
+
+
+/* @group File Popup Contents */
+
+.file #metadata,
+.file-popup #metadata {
+}
+
+.file-popup dl {
+ font-size: 80%;
+ padding: 0.75em;
+ background-color: #dedede;
+ color: #333;
+ border: 1px solid #bbb;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+}
+.file dt {
+ font-weight: bold;
+ padding-left: 22px;
+ line-height: 20px;
+ background: url(images/page_white_width.png) no-repeat left top;
+}
+.file dt.modified-date {
+ background: url(images/date.png) no-repeat left top;
+}
+.file dt.requires {
+ background: url(images/plugin.png) no-repeat left top;
+}
+.file dt.scs-url {
+ background: url(images/wrench.png) no-repeat left top;
+}
+
+.file dl dd {
+ margin: 0 0 1em 0;
+}
+.file #metadata dl dd ul {
+ list-style: circle;
+ margin-left: 20px;
+ padding-top: 0;
+}
+.file #metadata dl dd ul li {
+}
+
+
+.file h2 {
+ margin-top: 2em;
+ padding: 0.75em 0.5em;
+ background-color: #dedede;
+ color: #333;
+ font-size: 120%;
+ border: 1px solid #bbb;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+}
+
+/* @end */
+
+
+
+
+/* @group ThickBox Styles */
+#TB_window {
+ font: 12px Arial, Helvetica, sans-serif;
+ color: #333333;
+}
+
+#TB_secondLine {
+ font: 10px Arial, Helvetica, sans-serif;
+ color:#666666;
+}
+
+#TB_window :link,
+#TB_window :visited { color: #666666; }
+#TB_window :link:hover,
+#TB_window :visited:hover { color: #000; }
+#TB_window :link:active,
+#TB_window :visited:active { color: #666666; }
+#TB_window :link:focus,
+#TB_window :visited:focus { color: #666666; }
+
+#TB_overlay {
+ position: fixed;
+ z-index:100;
+ top: 0px;
+ left: 0px;
+ height:100%;
+ width:100%;
+}
+
+.TB_overlayMacFFBGHack {background: url(images/macFFBgHack.png) repeat;}
+.TB_overlayBG {
+ background-color:#000;
+ filter:alpha(opacity=75);
+ -moz-opacity: 0.75;
+ opacity: 0.75;
+}
+
+* html #TB_overlay { /* ie6 hack */
+ position: absolute;
+ height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
+}
+
+#TB_window {
+ position: fixed;
+ background: #ffffff;
+ z-index: 102;
+ color:#000000;
+ display:none;
+ border: 4px solid #525252;
+ text-align:left;
+ top:50%;
+ left:50%;
+}
+
+* html #TB_window { /* ie6 hack */
+position: absolute;
+margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px');
+}
+
+#TB_window img#TB_Image {
+ display:block;
+ margin: 15px 0 0 15px;
+ border-right: 1px solid #ccc;
+ border-bottom: 1px solid #ccc;
+ border-top: 1px solid #666;
+ border-left: 1px solid #666;
+}
+
+#TB_caption{
+ height:25px;
+ padding:7px 30px 10px 25px;
+ float:left;
+}
+
+#TB_closeWindow{
+ height:25px;
+ padding:11px 25px 10px 0;
+ float:right;
+}
+
+#TB_closeAjaxWindow{
+ padding:7px 10px 5px 0;
+ margin-bottom:1px;
+ text-align:right;
+ float:right;
+}
+
+#TB_ajaxWindowTitle{
+ float:left;
+ padding:7px 0 5px 10px;
+ margin-bottom:1px;
+ font-size: 22px;
+}
+
+#TB_title{
+ background-color: #6C8C22;
+ color: #dedede;
+ height:40px;
+}
+#TB_title :link,
+#TB_title :visited {
+ color: white !important;
+ border-bottom: 1px dotted #dedede;
+}
+
+#TB_ajaxContent{
+ clear:both;
+ padding:2px 15px 15px 15px;
+ overflow:auto;
+ text-align:left;
+ line-height:1.4em;
+}
+
+#TB_ajaxContent.TB_modal{
+ padding:15px;
+}
+
+#TB_ajaxContent p{
+ padding:5px 0px 5px 0px;
+}
+
+#TB_load{
+ position: fixed;
+ display:none;
+ height:13px;
+ width:208px;
+ z-index:103;
+ top: 50%;
+ left: 50%;
+ margin: -6px 0 0 -104px; /* -height/2 0 0 -width/2 */
+}
+
+* html #TB_load { /* ie6 hack */
+position: absolute;
+margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px');
+}
+
+#TB_HideSelect{
+ z-index:99;
+ position:fixed;
+ top: 0;
+ left: 0;
+ background-color:#fff;
+ border:none;
+ filter:alpha(opacity=0);
+ -moz-opacity: 0;
+ opacity: 0;
+ height:100%;
+ width:100%;
+}
+
+* html #TB_HideSelect { /* ie6 hack */
+ position: absolute;
+ height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
+}
+
+#TB_iframeContent{
+ clear:both;
+ border:none;
+ margin-bottom:-1px;
+ margin-top:1px;
+ _margin-bottom:1px;
+}
+
+/* @end */
+
+/* @group Debugging Section */
+
+#debugging-toggle {
+ text-align: center;
+}
+#debugging-toggle img {
+ cursor: pointer;
+}
+
+#rdoc-debugging-section-dump {
+ display: none;
+ margin: 0 2em 2em;
+ background: #ccc;
+ border: 1px solid #999;
+}
+
+
+
+/* @end */
diff --git a/lib/rdoc/generator/texinfo.rb b/lib/rdoc/generator/texinfo.rb
deleted file mode 100644
index 99a1452..0000000
--- a/lib/rdoc/generator/texinfo.rb
+++ /dev/null
@@ -1,81 +0,0 @@
-require 'rdoc/rdoc'
-require 'rdoc/generator'
-require 'rdoc/markup/to_texinfo'
-
-module RDoc
- module Generator
- # This generates Texinfo files for viewing with GNU Info or Emacs
- # from RDoc extracted from Ruby source files.
- class TEXINFO
- # What should the .info file be named by default?
- DEFAULT_INFO_FILENAME = 'rdoc.info'
-
- include Generator::MarkUp
-
- # Accept some options
- def initialize(options)
- @options = options
- @options.inline_source = true
- @options.op_name ||= 'rdoc.texinfo'
- @options.formatter = ::RDoc::Markup::ToTexInfo.new
- end
-
- # Generate the +texinfo+ files
- def generate(toplevels)
- @toplevels = toplevels
- @files, @classes = ::RDoc::Generator::Context.build_indices(@toplevels,
- @options)
-
- (@files + @classes).each { |x| x.value_hash }
-
- open(@options.op_name, 'w') do |f|
- f.puts TexinfoTemplate.new('files' => @files,
- 'classes' => @classes,
- 'filename' => @options.op_name.gsub(/texinfo/, 'info'),
- 'title' => @options.title).render
- end
- # TODO: create info files and install?
- end
-
- class << self
- # Factory? We don't need no stinkin' factory!
- alias_method :for, :new
- end
- end
-
- # Basically just a wrapper around ERB.
- # Should probably use RDoc::TemplatePage instead
- class TexinfoTemplate
- BASE_DIR = ::File.expand_path(::File.dirname(__FILE__)) # have to calculate this when the file's loaded.
-
- def initialize(values, file = 'texinfo.erb')
- @v, @file = [values, file]
- end
-
- def template
- ::File.read(::File.join(BASE_DIR, 'texinfo', @file))
- end
-
- # Go!
- def render
- ERB.new(template).result binding
- end
-
- def href(location, text)
- text # TODO: how does texinfo do hyperlinks?
- end
-
- def target(name, text)
- text # TODO: how do hyperlink targets work?
- end
-
- # TODO: this is probably implemented elsewhere?
- def method_prefix(section)
- { 'Class' => '.',
- 'Module' => '::',
- 'Instance' => '#',
- }[section['category']]
- end
- end
- end
-end
diff --git a/lib/rdoc/generator/texinfo/class.texinfo.erb b/lib/rdoc/generator/texinfo/class.texinfo.erb
deleted file mode 100644
index 74ecc59..0000000
--- a/lib/rdoc/generator/texinfo/class.texinfo.erb
+++ /dev/null
@@ -1,44 +0,0 @@
-@node <%= @v['class']['full_name'].gsub(/::/, '-') %>
-@chapter <%= @v['class']["classmod"] %> <%= @v['class']['full_name'] %>
-
-<% if @v['class']["parent"] and @v['class']['par_url'] %>
-Inherits <%= href @v['class']["par_url"], @v['class']["parent"] %><% end %>
-
-<%= @v['class']["description"] %>
-
-<% if @v['class']["includes"] %>
-Includes
-<% @v['class']["includes"].each do |include| %>
-* <%= href include["aref"], include["name"] %>
-<% end # @v['class']["includes"] %>
-<% end %>
-
-<% if @v['class']["sections"] %>
-<% @v['class']["sections"].each do |section| %>
-<% if section["attributes"] %>
-Attributes
-<% section["attributes"].each do |attributes| %>
-* <%= attributes["name"] %> <%= attributes["rw"] %> <%= attributes["a_desc"] %>
-<% end # section["attributes"] %>
-<% end %>
-<% end %>
-
-<% @v['class']["sections"].each do |section| %>
-<% if section["method_list"] %>
-Methods
-@menu
-<% section["method_list"].each_with_index do |method_list, i| %>
-<%= i %>
-<% (method_list["methods"] || []).each do |method| %>
-* <%= @v['class']['full_name'].gsub(/::/, '-') %><%= method_prefix method_list %><%= method['name'] %>::<% end %>
-<% end %>
-@end menu
-
-<% section["method_list"].each do |method_list| %>
-<% (method_list["methods"] || []).uniq.each do |method| %>
-<%= TexinfoTemplate.new(@v.merge({'method' => method, 'list' => method_list}),
- 'method.texinfo.erb').render %><% end %>
-<% end %>
-<% end # if section["method_list"] %>
-<% end # @v['class']["sections"] %>
-<% end %>
diff --git a/lib/rdoc/generator/texinfo/file.texinfo.erb b/lib/rdoc/generator/texinfo/file.texinfo.erb
deleted file mode 100644
index b619b94..0000000
--- a/lib/rdoc/generator/texinfo/file.texinfo.erb
+++ /dev/null
@@ -1,6 +0,0 @@
-<% if false %>
-<h2>File: <%= @v['file']["short_name"] %></h2>
-Path: <%= @v['file']["full_path"] %>
-
-<%= TexinfoTemplate.new(@v, 'content.texinfo.erb').render %>
-<% end %>
diff --git a/lib/rdoc/generator/texinfo/method.texinfo.erb b/lib/rdoc/generator/texinfo/method.texinfo.erb
deleted file mode 100644
index f5c2b73..0000000
--- a/lib/rdoc/generator/texinfo/method.texinfo.erb
+++ /dev/null
@@ -1,6 +0,0 @@
-@node <%= @v['class']['full_name'].gsub(/::/, '-') %><%= method_prefix @v['list'] %><%= @v['method']['name'] %>
-@section <%= @v['class']["classmod"] %> <%= @v['class']['full_name'] %><%= method_prefix @v['list'] %><%= @v['method']['name'] %>
-<%= @v['method']["type"] %> <%= @v['method']["category"] %> method:
-<%= target @v['method']["aref"], @v['method']['callseq'] ||
- @v['method']["name"] + @v['method']["params"] %>
-<%= @v['method']["m_desc"] %>
diff --git a/lib/rdoc/generator/texinfo/texinfo.erb b/lib/rdoc/generator/texinfo/texinfo.erb
deleted file mode 100644
index 235f63d..0000000
--- a/lib/rdoc/generator/texinfo/texinfo.erb
+++ /dev/null
@@ -1,28 +0,0 @@
-\input texinfo @c -*-texinfo-*-
-@c %**start of header
-@setfilename <%= @v['filename'] %>
-@settitle <%= @v['title'] %>
-@c %**end of header
-
-@contents @c TODO: whitespace is a mess... =\
-
-@ifnottex
-@node Top
-
-@top <%= @v['title'] %>
-@end ifnottex
-
-<% if @f = @v['files'].detect { |f| f.name =~ /Readme/i } %>
-<%= @f.values['description'] %><% end %>
-
-@menu
-<% @v['classes'].each do |klass| %>
-* <%= klass.name.gsub(/::/, '-') %>::<% end %>
-@c TODO: add files
-@end menu
-
-<% (@v['classes'] || []).each_with_index do |klass, i| %>
-<%= TexinfoTemplate.new(@v.merge('class' => klass.values),
- 'class.texinfo.erb').render %><% end %>
-
-@bye
diff --git a/lib/rdoc/generator/xml.rb b/lib/rdoc/generator/xml.rb
deleted file mode 100644
index 0d4c5a7..0000000
--- a/lib/rdoc/generator/xml.rb
+++ /dev/null
@@ -1,117 +0,0 @@
-require 'rdoc/generator/html'
-
-##
-# Generate XML output as one big file
-
-class RDoc::Generator::XML < RDoc::Generator::HTML
-
- ##
- # Standard generator factory
-
- def self.for(options)
- new(options)
- end
-
- def initialize(*args)
- super
- end
-
- ##
- # Build the initial indices and output objects
- # based on an array of TopLevel objects containing
- # the extracted information.
-
- def generate(info)
- @info = info
- @files = []
- @classes = []
- @hyperlinks = {}
-
- build_indices
- generate_xml
- end
-
- ##
- # Generate:
- #
- # * 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::File.new(toplevel, @options, RDoc::Generator::FILE_DIR)
- end
-
- RDoc::TopLevel.all_classes_and_modules.each do |cls|
- build_class_list(cls, @files[0], RDoc::Generator::CLASS_DIR)
- end
- end
-
- def build_class_list(from, html_file, class_dir)
- @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
- end
-
- ##
- # Generate all the HTML. For the one-file case, we generate
- # all the information in to one big hash
-
- def generate_xml
- values = {
- 'charset' => @options.charset,
- 'files' => gen_into(@files),
- 'classes' => gen_into(@classes)
- }
-
- template = RDoc::TemplatePage.new @template::ONE_PAGE
-
- if @options.op_name
- opfile = File.open(@options.op_name, "w")
- else
- opfile = $stdout
- end
- template.write_html_on(opfile, values)
- end
-
- def gen_into(list)
- res = []
- list.each do |item|
- res << item.value_hash
- 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::HtmlMethod.all_methods, 'Methods')
- end
-
- def gen_an_index(collection, title)
- res = []
- collection.sort.each do |f|
- if f.document_self
- res << { "href" => f.path, "name" => f.index_name }
- end
- end
-
- return {
- "entries" => res,
- 'list_title' => title,
- 'index_url' => main_url,
- }
- end
-
-end
-
diff --git a/lib/rdoc/generator/xml/rdf.rb b/lib/rdoc/generator/xml/rdf.rb
deleted file mode 100644
index 7b15c69..0000000
--- a/lib/rdoc/generator/xml/rdf.rb
+++ /dev/null
@@ -1,113 +0,0 @@
-require 'rdoc/generator/xml'
-
-module RDoc::Generator::XML::RDF
-
- CONTENTS_RDF = <<-EOF
-<% if defined? classes and classes["description"] then %>
- <description rd:parseType="Literal">
-<%= classes["description"] %>
- </description>
-<% end %>
-
-<% if defined? files and files["requires"] then %>
-<% files["requires"].each do |requires| %>
- <rd:required-file rd:name="<%= requires["name"] %>" />
-<% end # files["requires"] %>
-<% end %>
-
-<% if defined? classes and classes["includes"] then %>
- <IncludedModuleList>
-<% classes["includes"].each do |includes| %>
- <included-module rd:name="<%= includes["name"] %>" />
-<% end # includes["includes"] %>
- </IncludedModuleList>
-<% end %>
-
-<% if defined? classes and classes["sections"] then %>
-<% classes["sections"].each do |sections| %>
-<% if sections["attributes"] then %>
-<% sections["attributes"].each do |attributes| %>
- <contents>
- <Attribute rd:name="<%= attributes["name"] %>">
-<% if attributes["rw"] then %>
- <attribute-rw><%= attributes["rw"] %></attribute-rw>
-<% end %>
- <description rdf:parseType="Literal"><%= attributes["a_desc"] %></description>
- </Attribute>
- </contents>
-<% end # sections["attributes"] %>
-<% end %>
-
-<% if sections["method_list"] then %>
-<% sections["method_list"].each do |method_list| %>
-<% if method_list["methods"] then %>
-<% method_list["methods"].each do |methods| %>
- <contents>
- <Method rd:name="<%= methods["name"] %>" rd:visibility="<%= methods["type"] %>"
- rd:category="<%= methods["category"] %>" rd:id="<%= methods["aref"] %>">
- <parameters><%= methods["params"] %></parameters>
-<% if methods["m_desc"] then %>
- <description rdf:parseType="Literal">
-<%= methods["m_desc"] %>
- </description>
-<% end %>
-<% if methods["sourcecode"] then %>
- <source-code-listing rdf:parseType="Literal">
-<%= methods["sourcecode"] %>
- </source-code-listing>
-<% end %>
- </Method>
- </contents>
-<% end # method_list["methods"] %>
-<% end %>
-<% end # sections["method_list"] %>
-<% end %>
- <!-- end method list -->
-<% end # classes["sections"] %>
-<% end %>
- EOF
-
-########################################################################
-
- ONE_PAGE = %{<?xml version="1.0" encoding="utf-8"?>
-<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns="http://pragprog.com/rdoc/rdoc.rdf#"
- xmlns:rd="http://pragprog.com/rdoc/rdoc.rdf#">
-
-<!-- RDoc -->
-<% values["files"].each do |files| %>
- <rd:File rd:name="<%= files["short_name"] %>" rd:id="<%= files["href"] %>">
- <path><%= files["full_path"] %></path>
- <dtm-modified><%= files["dtm_modified"] %></dtm-modified>
-} + CONTENTS_RDF + %{
- </rd:File>
-<% end # values["files"] %>
-<% values["classes"].each do |classes| %>
- <<%= values["classmod"] %> rd:name="<%= classes["full_name"] %>" rd:id="<%= classes["full_name"] %>">
- <classmod-info>
-<% if classes["infiles"] then %>
- <InFiles>
-<% classes["infiles"].each do |infiles| %>
- <infile>
- <File rd:name="<%= infiles["full_path"] %>"
-<% if infiles["full_path_url"] then %>
- rdf:about="<%= infiles["full_path_url"] %>"
-<% end %>
- />
- </infile>
-<% end # classes["infiles"] %>
- </InFiles>
-<% end %>
-<% if classes["parent"] then %>
- <superclass><%= href classes["par_url"], classes["parent"] %></superclass>
-<% end %>
- </classmod-info>
-} + CONTENTS_RDF + %{
- </<%= classes["classmod"] %>>
-<% end # values["classes"] %>
-<!-- /RDoc -->
-</rdf:RDF>
-}
-
-end
-
diff --git a/lib/rdoc/generator/xml/xml.rb b/lib/rdoc/generator/xml/xml.rb
deleted file mode 100644
index 4b54e73..0000000
--- a/lib/rdoc/generator/xml/xml.rb
+++ /dev/null
@@ -1,123 +0,0 @@
-require 'rdoc/generator/xml'
-
-module RDoc::Generator::XML::XML
-
- CONTENTS_XML = <<-EOF
-<% if defined? classes and classes["description"] then %>
- <description>
-<%= classes["description"] %>
- </description>
-<% end %>
- <contents>
-<% if defined? files and files["requires"] then %>
- <required-file-list>
-<% files["requires"].each do |requires| %>
- <required-file name="<%= requires["name"] %>"
-<% if requires["aref"] then %>
- href="<%= requires["aref"] %>"
-<% end %>
- />
-<% 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| %>
- <attribute name="<%= attributes["name"] %>">
-<% if attributes["rw"] then %>
- <attribute-rw><%= attributes["rw"] %></attribute-rw>
-<% end %>
- <description><%= attributes["a_desc"] %></description>
- </attribute>
-<% end %><%# sections["attributes"] %>
- </attribute-list>
-<% end %>
-<% if sections["method_list"] then %>
- <method-list>
-<% sections["method_list"].each do |method_list| %>
-<% if method_list["methods"] then %>
-<% method_list["methods"].each do |methods| %>
- <method name="<%= methods["name"] %>" type="<%= methods["type"] %>" category="<%= methods["category"] %>" id="<%= methods["aref"] %>">
- <parameters><%= methods["params"] %></parameters>
-<% if methods["m_desc"] then %>
- <description>
-<%= methods["m_desc"] %>
- </description>
-<% end %>
-<% if methods["sourcecode"] then %>
- <source-code-listing>
-<%= methods["sourcecode"] %>
- </source-code-listing>
-<% end %>
- </method>
-<% end %><%# method_list["methods"] %>
-<% end %>
-<% end %><%# sections["method_list"] %>
- </method-list>
-<% end %>
-<% end %><%# classes["sections"] %>
-<% end %>
-<% if defined? classes and classes["includes"] then %>
- <included-module-list>
-<% classes["includes"].each do |includes| %>
- <included-module name="<%= includes["name"] %>"
-<% if includes["aref"] then %>
- href="<%= includes["aref"] %>"
-<% end %>
- />
-<% end %><%# classes["includes"] %>
- </included-module-list>
-<% end %>
- </contents>
- EOF
-
- ONE_PAGE = %{<?xml version="1.0" encoding="utf-8"?>
-<rdoc>
-<file-list>
-<% values["files"].each do |files| %>
- <file name="<%= files["short_name"] %>" id="<%= files["href"] %>">
- <file-info>
- <path><%= files["full_path"] %></path>
- <dtm-modified><%= files["dtm_modified"] %></dtm-modified>
- </file-info>
-} + CONTENTS_XML + %{
- </file>
-<% end %><%# values["files"] %>
-</file-list>
-<class-module-list>
-<% values["classes"].each do |classes| %>
- <<%= classes["classmod"] %> name="<%= classes["full_name"] %>" id="<%= classes["full_name"] %>">
- <classmod-info>
-<% if classes["infiles"] then %>
- <infiles>
-<% classes["infiles"].each do |infiles| %>
- <infile><%= href infiles["full_path_url"], infiles["full_path"] %></infile>
-<% end %><%# classes["infiles"] %>
- </infiles>
-<% end %>
-<% if classes["parent"] then %>
- <superclass><%= href classes["par_url"], classes["parent"] %></superclass>
-<% end %>
- </classmod-info>
-} + CONTENTS_XML + %{
- </<%= classes["classmod"] %>>
-<% end %><%# values["classes"] %>
-</class-module-list>
-</rdoc>
-}
-
-end
diff --git a/lib/rdoc/ghost_method.rb b/lib/rdoc/ghost_method.rb
new file mode 100644
index 0000000..192b46f
--- /dev/null
+++ b/lib/rdoc/ghost_method.rb
@@ -0,0 +1,8 @@
+require 'rdoc/any_method'
+
+##
+# GhostMethod represents a method referenced only by a comment
+
+class RDoc::GhostMethod < RDoc::AnyMethod
+end
+
diff --git a/lib/rdoc/include.rb b/lib/rdoc/include.rb
new file mode 100644
index 0000000..11a9bdc
--- /dev/null
+++ b/lib/rdoc/include.rb
@@ -0,0 +1,61 @@
+require 'rdoc/code_object'
+
+##
+# A Module include in a class with \#include
+
+class RDoc::Include < RDoc::CodeObject
+
+ ##
+ # Name of included module
+
+ attr_accessor :name
+
+ ##
+ # Creates a new Include for +name+ with +comment+
+
+ def initialize(name, comment)
+ super()
+ @name = name
+ self.comment = comment
+ end
+
+ ##
+ # Includes are sorted by name
+
+ def <=> other
+ return unless self.class === other
+
+ name <=> other.name
+ end
+
+ def == other # :nodoc:
+ self.class == other.class and
+ self.name == other.name
+ end
+
+ ##
+ # Full name based on #module
+
+ def full_name
+ m = self.module
+ RDoc::ClassModule === m ? m.full_name : @name
+ end
+
+ def inspect # :nodoc:
+ "#<%s:0x%x %s.include %s>" % [
+ self.class,
+ object_id,
+ parent_name, @name,
+ ]
+ end
+
+ ##
+ # Attempts to locate the included module object. Returns the name if not
+ # known.
+
+ def module
+ RDoc::TopLevel.find_module_named(@name) || @name
+ end
+
+end
+
diff --git a/lib/rdoc/markup.rb b/lib/rdoc/markup.rb
index a584a79..c3c5213 100644
--- a/lib/rdoc/markup.rb
+++ b/lib/rdoc/markup.rb
@@ -27,9 +27,9 @@ require 'rdoc'
# convert multiple input strings.
#
# require 'rdoc/markup/to_html'
-#
+#
# h = RDoc::Markup::ToHtml.new
-#
+#
# puts h.convert(input_string)
#
# You can extend the RDoc::Markup parser to recognise new markup
@@ -41,22 +41,22 @@ require 'rdoc'
#
# require 'rdoc/markup'
# require 'rdoc/markup/to_html'
-#
+#
# class WikiHtml < RDoc::Markup::ToHtml
# def handle_special_WIKIWORD(special)
# "<font color=red>" + special.text + "</font>"
# end
# end
-#
+#
# m = RDoc::Markup.new
# m.add_word_pair("{", "}", :STRIKE)
# m.add_html("no", :STRIKE)
-#
+#
# m.add_special(/\b([A-Z][a-z]+[A-Z]\w+)/, :WIKIWORD)
-#
+#
# wh = WikiHtml.new
# wh.add_tag(:STRIKE, "<strike>", "</strike>")
-#
+#
# puts "<body>#{wh.convert ARGF.read}</body>"
#
#--
@@ -65,30 +65,7 @@ require 'rdoc'
class RDoc::Markup
- SPACE = ?\s
-
- # List entries look like:
- # * text
- # 1. text
- # [label] text
- # label:: text
- #
- # Flag it as a list entry, and work out the indent for subsequent lines
-
- SIMPLE_LIST_RE = /^(
- ( \* (?# bullet)
- |- (?# bullet)
- |\d+\. (?# numbered )
- |[A-Za-z]\. (?# alphabetically numbered )
- )
- \s+
- )\S/x
-
- LABEL_LIST_RE = /^(
- ( \[.*?\] (?# labeled )
- |\S.*:: (?# note )
- )(?:\s+|$)
- )/x
+ attr_reader :attribute_manager
##
# Take a block of text and use various heuristics to determine it's
@@ -96,7 +73,7 @@ class RDoc::Markup
# identify significant chunks.
def initialize
- @am = RDoc::Markup::AttributeManager.new
+ @attribute_manager = RDoc::Markup::AttributeManager.new
@output = nil
end
@@ -106,14 +83,14 @@ class RDoc::Markup
# formatters can recognize by their +name+.
def add_word_pair(start, stop, name)
- @am.add_word_pair(start, stop, name)
+ @attribute_manager.add_word_pair(start, stop, name)
end
##
# Add to the sequences recognized as general markup.
def add_html(tag, name)
- @am.add_html(tag, name)
+ @attribute_manager.add_html(tag, name)
end
##
@@ -126,7 +103,7 @@ class RDoc::Markup
# accept_special method.
def add_special(pattern, name)
- @am.add_special(pattern, name)
+ @attribute_manager.add_special(pattern, name)
end
##
@@ -136,243 +113,14 @@ class RDoc::Markup
# display the result.
def convert(str, op)
- lines = str.split(/\r?\n/).map { |line| Line.new line }
- @lines = Lines.new lines
-
- return "" if @lines.empty?
- @lines.normalize
- assign_types_to_lines
- group = group_lines
- # call the output formatter to handle the result
- #group.each { |line| p line }
- group.accept @am, op
- end
-
- private
-
- ##
- # Look through the text at line indentation. We flag each line as being
- # Blank, a paragraph, a list element, or verbatim text.
-
- def assign_types_to_lines(margin = 0, level = 0)
- while line = @lines.next
- if line.blank? then
- line.stamp :BLANK, level
- next
- end
-
- # if a line contains non-blanks before the margin, then it must belong
- # to an outer level
-
- text = line.text
-
- for i in 0...margin
- if text[i] != SPACE
- @lines.unget
- return
- end
- end
-
- active_line = text[margin..-1]
-
- # Rules (horizontal lines) look like
- #
- # --- (three or more hyphens)
- #
- # The more hyphens, the thicker the rule
- #
-
- if /^(---+)\s*$/ =~ active_line
- line.stamp :RULE, level, $1.length-2
- next
- end
-
- # Then look for list entries. First the ones that have to have
- # text following them (* xxx, - xxx, and dd. xxx)
-
- if SIMPLE_LIST_RE =~ active_line
- offset = margin + $1.length
- prefix = $2
- prefix_length = prefix.length
-
- flag = case prefix
- when "*","-" then :BULLET
- when /^\d/ then :NUMBER
- when /^[A-Z]/ then :UPPERALPHA
- when /^[a-z]/ then :LOWERALPHA
- else raise "Invalid List Type: #{self.inspect}"
- end
-
- line.stamp :LIST, level+1, prefix, flag
- text[margin, prefix_length] = " " * prefix_length
- assign_types_to_lines(offset, level + 1)
- next
- end
-
- if LABEL_LIST_RE =~ active_line
- offset = margin + $1.length
- prefix = $2
- prefix_length = prefix.length
-
- next if handled_labeled_list(line, level, margin, offset, prefix)
- end
-
- # Headings look like
- # = Main heading
- # == Second level
- # === Third
- #
- # Headings reset the level to 0
-
- if active_line[0] == ?= and active_line =~ /^(=+)\s*(.*)/
- prefix_length = $1.length
- prefix_length = 6 if prefix_length > 6
- line.stamp :HEADING, 0, prefix_length
- line.strip_leading(margin + prefix_length)
- next
- end
-
- # If the character's a space, then we have verbatim text,
- # otherwise
-
- if active_line[0] == SPACE
- line.strip_leading(margin) if margin > 0
- line.stamp :VERBATIM, level
- else
- line.stamp :PARAGRAPH, level
- end
- end
- end
-
- ##
- # Handle labeled list entries, We have a special case to deal with.
- # Because the labels can be long, they force the remaining block of text
- # over the to right:
- #
- # this is a long label that I wrote:: and here is the
- # block of text with
- # a silly margin
- #
- # So we allow the special case. If the label is followed by nothing, and
- # if the following line is indented, then we take the indent of that line
- # as the new margin.
- #
- # this is a long label that I wrote::
- # here is a more reasonably indented block which
- # will be attached to the label.
- #
-
- def handled_labeled_list(line, level, margin, offset, prefix)
- prefix_length = prefix.length
- text = line.text
- flag = nil
-
- case prefix
- when /^\[/ then
- flag = :LABELED
- prefix = prefix[1, prefix.length-2]
- when /:$/ then
- flag = :NOTE
- prefix.chop!
- else
- raise "Invalid List Type: #{self.inspect}"
- end
+ document = RDoc::Markup::Parser.parse str
- # body is on the next line
- if text.length <= offset then
- original_line = line
- line = @lines.next
- return false unless line
- text = line.text
-
- for i in 0..margin
- if text[i] != SPACE
- @lines.unget
- return false
- end
- end
-
- i = margin
- i += 1 while text[i] == SPACE
-
- if i >= text.length then
- @lines.unget
- return false
- else
- offset = i
- prefix_length = 0
-
- if text[offset..-1] =~ SIMPLE_LIST_RE then
- @lines.unget
- line = original_line
- line.text = ''
- else
- @lines.delete original_line
- end
- end
- end
-
- line.stamp :LIST, level+1, prefix, flag
- text[margin, prefix_length] = " " * prefix_length
- assign_types_to_lines(offset, level + 1)
- return true
+ document.accept op
end
- ##
- # Return a block consisting of fragments which are paragraphs, list
- # entries or verbatim text. We merge consecutive lines of the same type
- # and level together. We are also slightly tricky with lists: the lines
- # following a list introduction look like paragraph lines at the next
- # level, and we remap them into list entries instead.
-
- def group_lines
- @lines.rewind
-
- in_list = false
- wanted_type = wanted_level = nil
-
- block = LineCollection.new
- group = nil
-
- while line = @lines.next
- if line.level == wanted_level and line.type == wanted_type
- group.add_text(line.text)
- else
- group = block.fragment_for(line)
- block.add(group)
-
- if line.type == :LIST
- wanted_type = :PARAGRAPH
- else
- wanted_type = line.type
- end
-
- wanted_level = line.type == :HEADING ? line.param : line.level
- end
- end
-
- block.normalize
- block
- end
-
- ##
- # For debugging, we allow access to our line contents as text.
-
- def content
- @lines.as_text
- end
- public :content
-
- ##
- # For debugging, return the list of line types.
-
- def get_line_types
- @lines.line_types
- end
- public :get_line_types
-
end
-require 'rdoc/markup/fragments'
+require 'rdoc/markup/parser'
+require 'rdoc/markup/attribute_manager'
require 'rdoc/markup/inline'
-require 'rdoc/markup/lines'
+
diff --git a/lib/rdoc/markup/attribute_manager.rb b/lib/rdoc/markup/attribute_manager.rb
index d13b793..5b9e070 100644
--- a/lib/rdoc/markup/attribute_manager.rb
+++ b/lib/rdoc/markup/attribute_manager.rb
@@ -1,41 +1,76 @@
-require 'rdoc/markup/inline'
+##
+# Manages changes of attributes in a block of text
class RDoc::Markup::AttributeManager
+ ##
+ # The NUL character
+
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
+ A_PROTECT = 004 # :nodoc:
+
+ PROTECT_ATTR = A_PROTECT.chr # :nodoc:
##
# 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 = {}
+ attr_reader :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 = {}
+ attr_reader :word_pair_map
##
# This maps HTML tags to the corresponding attribute char
- HTML_TAGS = {}
+ attr_reader :html_tags
+
+ ##
+ # A \ in front of a character that would normally be processed turns off
+ # processing. We do this by turning \< into <#{PROTECT}
+
+ attr_reader :protectable
##
# And this maps _special_ sequences to a name. A special sequence is
# something like a WikiWord
- SPECIAL = {}
+ attr_reader :special
+
+ ##
+ # Creates a new attribute manager that understands bold, emphasized and
+ # teletype text.
+
+ def initialize
+ @html_tags = {}
+ @matching_word_pairs = {}
+ @protectable = %w[<\\]
+ @special = {}
+ @word_pair_map = {}
+
+ 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
+ end
+
##
# Return an attribute object with the given turn_on and turn_off bits set
@@ -75,19 +110,19 @@ class RDoc::Markup::AttributeManager
def convert_attrs(str, attrs)
# first do matching ones
- tags = MATCHING_WORD_PAIRS.keys.join("")
+ tags = @matching_word_pairs.keys.join("")
re = /(^|\W)([#{tags}])([#:\\]?[\w.\/-]+?\S?)\2(\W|$)/
1 while str.gsub!(re) do
- attr = MATCHING_WORD_PAIRS[$2]
+ 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|
+ 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
@@ -96,11 +131,14 @@ class RDoc::Markup::AttributeManager
end
end
+ ##
+ # Converts HTML tags to RDoc attributes
+
def convert_html(str, attrs)
- tags = HTML_TAGS.keys.join '|'
+ tags = @html_tags.keys.join '|'
1 while str.gsub!(/<(#{tags})>(.*?)<\/\1>/i) {
- attr = HTML_TAGS[$1.downcase]
+ attr = @html_tags[$1.downcase]
html_length = $1.length + 2
seq = NULL * html_length
attrs.set_attrs($`.length + html_length, $2.length, attr)
@@ -108,9 +146,12 @@ class RDoc::Markup::AttributeManager
}
end
+ ##
+ # Converts special sequences to RDoc attributes
+
def convert_specials(str, attrs)
- unless SPECIAL.empty?
- SPECIAL.each do |regexp, attr|
+ unless @special.empty?
+ @special.each do |regexp, attr|
str.scan(regexp) do
attrs.set_attrs($`.length, $&.length,
attr | RDoc::Markup::Attribute::SPECIAL)
@@ -120,31 +161,25 @@ class RDoc::Markup::AttributeManager
end
##
- # A \ in front of a character that would normally be processed turns off
- # processing. We do this by turning \< into <#{PROTECT}
-
- PROTECTABLE = %w[<\\]
+ # Escapes special sequences of text to prevent conversion to RDoc
def mask_protected_sequences
- protect_pattern = Regexp.new("\\\\([#{Regexp.escape(PROTECTABLE.join(''))}])")
- @str.gsub!(protect_pattern, "\\1#{PROTECT_ATTR}")
+ @str.gsub!(/\\([#{Regexp.escape @protectable.join('')}])/,
+ "\\1#{PROTECT_ATTR}")
end
+ ##
+ # Unescapes special sequences of text
+
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)
- end
+ ##
+ # Adds a markup class with +name+ for words wrapped in the +start+ and
+ # +stop+ character. To make words wrapped with "*" bold:
+ #
+ # am.add_word_pair '*', '*', :BOLD
def add_word_pair(start, stop, name)
raise ArgumentError, "Word flags may not start with '<'" if
@@ -153,24 +188,39 @@ class RDoc::Markup::AttributeManager
bitmap = RDoc::Markup::Attribute.bitmap_for name
if start == stop then
- MATCHING_WORD_PAIRS[start] = bitmap
+ @matching_word_pairs[start] = bitmap
else
pattern = /(#{Regexp.escape start})(\S+)(#{Regexp.escape stop})/
- WORD_PAIR_MAP[pattern] = bitmap
+ @word_pair_map[pattern] = bitmap
end
- PROTECTABLE << start[0,1]
- PROTECTABLE.uniq!
+ @protectable << start[0,1]
+ @protectable.uniq!
end
+ ##
+ # Adds a markup class with +name+ for words surrounded by HTML tag +tag+.
+ # To process emphasis tags:
+ #
+ # am.add_html 'em', :EM
+
def add_html(tag, name)
- HTML_TAGS[tag.downcase] = RDoc::Markup::Attribute.bitmap_for name
+ @html_tags[tag.downcase] = RDoc::Markup::Attribute.bitmap_for name
end
+ ##
+ # Adds a special handler for +pattern+ with +name+. A simple URL handler
+ # would be:
+ #
+ # @am.add_special(/((https?:)\S+\w)/, :HYPERLINK)
+
def add_special(pattern, name)
- SPECIAL[pattern] = RDoc::Markup::Attribute.bitmap_for name
+ @special[pattern] = RDoc::Markup::Attribute.bitmap_for name
end
+ ##
+ # Processes +str+ converting attributes, HTML and specials
+
def flow(str)
@str = str
@@ -178,15 +228,18 @@ class RDoc::Markup::AttributeManager
@attrs = RDoc::Markup::AttrSpan.new @str.length
- convert_attrs(@str, @attrs)
- convert_html(@str, @attrs)
- convert_specials(str, @attrs)
+ convert_attrs @str, @attrs
+ convert_html @str, @attrs
+ convert_specials @str, @attrs
unmask_protected_sequences
- return split_into_flow
+ split_into_flow
end
+ ##
+ # Debug method that prints a string along with its attributes
+
def display_attributes
puts
puts @str.tr(NULL, "!")
@@ -258,7 +311,7 @@ class RDoc::Markup::AttributeManager
# and reset to all attributes off
res << change_attribute(current_attr, 0) if current_attr != 0
- return res
+ res
end
end
diff --git a/lib/rdoc/markup/blank_line.rb b/lib/rdoc/markup/blank_line.rb
new file mode 100644
index 0000000..a8c07c8
--- /dev/null
+++ b/lib/rdoc/markup/blank_line.rb
@@ -0,0 +1,19 @@
+##
+# An empty line
+
+class RDoc::Markup::BlankLine
+
+ def == other # :nodoc:
+ self.class == other.class
+ end
+
+ def accept visitor
+ visitor.accept_blank_line self
+ end
+
+ def pretty_print q # :nodoc:
+ q.text 'blankline'
+ end
+
+end
+
diff --git a/lib/rdoc/markup/document.rb b/lib/rdoc/markup/document.rb
new file mode 100644
index 0000000..7963e9a
--- /dev/null
+++ b/lib/rdoc/markup/document.rb
@@ -0,0 +1,72 @@
+##
+# A Document containing lists, headings, paragraphs, etc.
+
+class RDoc::Markup::Document
+
+ ##
+ # The parts of the Document
+
+ attr_reader :parts
+
+ ##
+ # Creates a new Document with +parts+
+
+ def initialize *parts
+ @parts = []
+ @parts.push(*parts)
+ end
+
+ ##
+ # Appends +part+ to the document
+
+ def << part
+ case part
+ when RDoc::Markup::Document then
+ unless part.empty? then
+ parts.push(*part.parts)
+ parts << RDoc::Markup::BlankLine.new
+ end
+ when String then
+ raise ArgumentError,
+ "expected RDoc::Markup::Document and friends, got String" unless
+ part.empty?
+ else
+ parts << part
+ end
+ end
+
+ def == other # :nodoc:
+ self.class == other.class and @parts == other.parts
+ end
+
+ def accept visitor
+ visitor.start_accepting
+
+ @parts.each do |item|
+ item.accept visitor
+ end
+
+ visitor.end_accepting
+ end
+
+ def empty?
+ @parts.empty?
+ end
+
+ def pretty_print q # :nodoc:
+ q.group 2, '[doc: ', ']' do
+ q.seplist @parts do |part|
+ q.pp part
+ end
+ end
+ end
+
+ ##
+ # Appends +parts+ to the document
+
+ def push *parts
+ self.parts.push(*parts)
+ end
+
+end
+
diff --git a/lib/rdoc/markup/formatter.rb b/lib/rdoc/markup/formatter.rb
index 14cbae5..993e523 100644
--- a/lib/rdoc/markup/formatter.rb
+++ b/lib/rdoc/markup/formatter.rb
@@ -1,14 +1,143 @@
require 'rdoc/markup'
+##
+# Base class for RDoc markup formatters
+#
+# Formatters use a visitor pattern to convert content into output.
+
class RDoc::Markup::Formatter
+ InlineTag = Struct.new(:bit, :on, :off)
+
+ ##
+ # Creates a new Formatter
+
def initialize
@markup = RDoc::Markup.new
+ @am = @markup.attribute_manager
+ @attr_tags = []
+
+ @in_tt = 0
+ @tt_bit = RDoc::Markup::Attribute.bitmap_for :TT
+ end
+
+ ##
+ # Add a new set of tags for an attribute. We allow separate start and end
+ # tags for flexibility
+
+ def add_tag(name, start, stop)
+ attr = RDoc::Markup::Attribute.bitmap_for name
+ @attr_tags << InlineTag.new(attr, start, stop)
+ end
+
+ ##
+ # Allows +tag+ to be decorated with additional information.
+
+ def annotate(tag)
+ tag
end
+ ##
+ # Marks up +content+
+
def convert(content)
@markup.convert content, self
end
+ ##
+ # Converts flow items +flow+
+
+ def convert_flow(flow)
+ res = []
+
+ flow.each do |item|
+ case item
+ when String then
+ res << convert_string(item)
+ when RDoc::Markup::AttrChanger then
+ off_tags res, item
+ on_tags res, item
+ when RDoc::Markup::Special then
+ res << convert_special(item)
+ else
+ raise "Unknown flow element: #{item.inspect}"
+ end
+ end
+
+ res.join
+ end
+
+ ##
+ # Converts added specials. See RDoc::Markup#add_special
+
+ def convert_special(special)
+ handled = false
+
+ RDoc::Markup::Attribute.each_name_of special.type do |name|
+ method_name = "handle_special_#{name}"
+
+ if respond_to? method_name then
+ special.text = send method_name, special
+ handled = true
+ end
+ end
+
+ raise "Unhandled special: #{special}" unless handled
+
+ special.text
+ end
+
+ ##
+ # Converts a string to be fancier if desired
+
+ def convert_string string
+ string
+ end
+
+ ##
+ # Are we currently inside tt tags?
+
+ def in_tt?
+ @in_tt > 0
+ end
+
+ def on_tags res, item
+ attr_mask = item.turn_on
+ return if attr_mask.zero?
+
+ @attr_tags.each do |tag|
+ if attr_mask & tag.bit != 0 then
+ res << annotate(tag.on)
+ @in_tt += 1 if tt? tag
+ end
+ end
+ end
+
+ def off_tags res, item
+ attr_mask = item.turn_off
+ return if attr_mask.zero?
+
+ @attr_tags.reverse_each do |tag|
+ if attr_mask & tag.bit != 0 then
+ @in_tt -= 1 if tt? tag
+ res << annotate(tag.off)
+ end
+ end
+ end
+
+ ##
+ # Is +tag+ a tt tag?
+
+ def tt? tag
+ tag.bit == @tt_bit
+ end
+
end
+class RDoc::Markup
+ autoload :ToAnsi, 'rdoc/markup/to_ansi'
+ autoload :ToBs, 'rdoc/markup/to_bs'
+ autoload :ToHtml, 'rdoc/markup/to_html'
+ autoload :ToHtmlCrossref, 'rdoc/markup/to_html_crossref'
+ autoload :ToRdoc, 'rdoc/markup/to_rdoc'
+end
diff --git a/lib/rdoc/markup/formatter_test_case.rb b/lib/rdoc/markup/formatter_test_case.rb
new file mode 100644
index 0000000..9b9d7cf
--- /dev/null
+++ b/lib/rdoc/markup/formatter_test_case.rb
@@ -0,0 +1,341 @@
+require 'minitest/unit'
+require 'rdoc/markup/formatter'
+
+##
+# Test case for creating new RDoc::Markup formatters. See
+# test/test_rdoc_markup_to_*.rb for examples.
+
+class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
+
+ def setup
+ super
+
+ @m = RDoc::Markup.new
+ @am = RDoc::Markup::AttributeManager.new
+ @RM = RDoc::Markup
+
+ @bullet_list = @RM::List.new(:BULLET,
+ @RM::ListItem.new(nil, @RM::Paragraph.new('l1')),
+ @RM::ListItem.new(nil, @RM::Paragraph.new('l2')))
+
+ @label_list = @RM::List.new(:LABEL,
+ @RM::ListItem.new('cat', @RM::Paragraph.new('cats are cool')),
+ @RM::ListItem.new('dog', @RM::Paragraph.new('dogs are cool too')))
+
+ @lalpha_list = @RM::List.new(:LALPHA,
+ @RM::ListItem.new(nil, @RM::Paragraph.new('l1')),
+ @RM::ListItem.new(nil, @RM::Paragraph.new('l2')))
+
+ @note_list = @RM::List.new(:NOTE,
+ @RM::ListItem.new('cat', @RM::Paragraph.new('cats are cool')),
+ @RM::ListItem.new('dog', @RM::Paragraph.new('dogs are cool too')))
+
+ @number_list = @RM::List.new(:NUMBER,
+ @RM::ListItem.new(nil, @RM::Paragraph.new('l1')),
+ @RM::ListItem.new(nil, @RM::Paragraph.new('l2')))
+
+ @ualpha_list = @RM::List.new(:UALPHA,
+ @RM::ListItem.new(nil, @RM::Paragraph.new('l1')),
+ @RM::ListItem.new(nil, @RM::Paragraph.new('l2')))
+ end
+
+ def self.add_visitor_tests
+ self.class_eval do
+ def test_start_accepting
+ @to.start_accepting
+
+ start_accepting
+ end
+
+ def test_end_accepting
+ @to.start_accepting
+ @to.res << 'hi'
+
+ end_accepting
+ end
+
+ def test_accept_blank_line
+ @to.start_accepting
+
+ @to.accept_blank_line @RM::BlankLine.new
+
+ accept_blank_line
+ end
+
+ def test_accept_heading
+ @to.start_accepting
+
+ @to.accept_heading @RM::Heading.new(5, 'Hello')
+
+ accept_heading
+ end
+
+ def test_accept_paragraph
+ @to.start_accepting
+
+ @to.accept_paragraph @RM::Paragraph.new('hi')
+
+ accept_paragraph
+ end
+
+ def test_accept_verbatim
+ @to.start_accepting
+
+ @to.accept_verbatim @RM::Verbatim.new(' ', 'hi', "\n",
+ ' ', 'world', "\n")
+
+ accept_verbatim
+ end
+
+ def test_accept_rule
+ @to.start_accepting
+
+ @to.accept_rule @RM::Rule.new(4)
+
+ accept_rule
+ end
+
+ def test_accept_list_item_start_bullet
+ @to.start_accepting
+
+ @to.accept_list_start @bullet_list
+
+ @to.accept_list_item_start @bullet_list.items.first
+
+ accept_list_item_start_bullet
+ end
+
+ def test_accept_list_item_start_label
+ @to.start_accepting
+
+ @to.accept_list_start @label_list
+
+ @to.accept_list_item_start @label_list.items.first
+
+ accept_list_item_start_label
+ end
+
+ def test_accept_list_item_start_lalpha
+ @to.start_accepting
+
+ @to.accept_list_start @lalpha_list
+
+ @to.accept_list_item_start @lalpha_list.items.first
+
+ accept_list_item_start_lalpha
+ end
+
+ def test_accept_list_item_start_note
+ @to.start_accepting
+
+ @to.accept_list_start @note_list
+
+ @to.accept_list_item_start @note_list.items.first
+
+ accept_list_item_start_note
+ end
+
+ def test_accept_list_item_start_number
+ @to.start_accepting
+
+ @to.accept_list_start @number_list
+
+ @to.accept_list_item_start @number_list.items.first
+
+ accept_list_item_start_number
+ end
+
+ def test_accept_list_item_start_ualpha
+ @to.start_accepting
+
+ @to.accept_list_start @ualpha_list
+
+ @to.accept_list_item_start @ualpha_list.items.first
+
+ accept_list_item_start_ualpha
+ end
+
+ def test_accept_list_item_end_bullet
+ @to.start_accepting
+
+ @to.accept_list_start @bullet_list
+
+ @to.accept_list_item_start @bullet_list.items.first
+
+ @to.accept_list_item_end @bullet_list.items.first
+
+ accept_list_item_end_bullet
+ end
+
+ def test_accept_list_item_end_label
+ @to.start_accepting
+
+ @to.accept_list_start @label_list
+
+ @to.accept_list_item_start @label_list.items.first
+
+ @to.accept_list_item_end @label_list.items.first
+
+ accept_list_item_end_label
+ end
+
+ def test_accept_list_item_end_lalpha
+ @to.start_accepting
+
+ @to.accept_list_start @lalpha_list
+
+ @to.accept_list_item_start @lalpha_list.items.first
+
+ @to.accept_list_item_end @lalpha_list.items.first
+
+ accept_list_item_end_lalpha
+ end
+
+ def test_accept_list_item_end_note
+ @to.start_accepting
+
+ @to.accept_list_start @note_list
+
+ @to.accept_list_item_start @note_list.items.first
+
+ @to.accept_list_item_end @note_list.items.first
+
+ accept_list_item_end_note
+ end
+
+ def test_accept_list_item_end_number
+ @to.start_accepting
+
+ @to.accept_list_start @number_list
+
+ @to.accept_list_item_start @number_list.items.first
+
+ @to.accept_list_item_end @number_list.items.first
+
+ accept_list_item_end_number
+ end
+
+ def test_accept_list_item_end_ualpha
+ @to.start_accepting
+
+ @to.accept_list_start @ualpha_list
+
+ @to.accept_list_item_start @ualpha_list.items.first
+
+ @to.accept_list_item_end @ualpha_list.items.first
+
+ accept_list_item_end_ualpha
+ end
+
+ def test_accept_list_start_bullet
+ @to.start_accepting
+
+ @to.accept_list_start @bullet_list
+
+ accept_list_start_bullet
+ end
+
+ def test_accept_list_start_label
+ @to.start_accepting
+
+ @to.accept_list_start @label_list
+
+ accept_list_start_label
+ end
+
+ def test_accept_list_start_lalpha
+ @to.start_accepting
+
+ @to.accept_list_start @lalpha_list
+
+ accept_list_start_lalpha
+ end
+
+ def test_accept_list_start_note
+ @to.start_accepting
+
+ @to.accept_list_start @note_list
+
+ accept_list_start_note
+ end
+
+ def test_accept_list_start_number
+ @to.start_accepting
+
+ @to.accept_list_start @number_list
+
+ accept_list_start_number
+ end
+
+ def test_accept_list_start_ualpha
+ @to.start_accepting
+
+ @to.accept_list_start @ualpha_list
+
+ accept_list_start_ualpha
+ end
+
+ def test_accept_list_end_bullet
+ @to.start_accepting
+
+ @to.accept_list_start @bullet_list
+
+ @to.accept_list_end @bullet_list
+
+ accept_list_end_bullet
+ end
+
+ def test_accept_list_end_label
+ @to.start_accepting
+
+ @to.accept_list_start @label_list
+
+ @to.accept_list_end @label_list
+
+ accept_list_end_label
+ end
+
+ def test_accept_list_end_lalpha
+ @to.start_accepting
+
+ @to.accept_list_start @lalpha_list
+
+ @to.accept_list_end @lalpha_list
+
+ accept_list_end_lalpha
+ end
+
+ def test_accept_list_end_number
+ @to.start_accepting
+
+ @to.accept_list_start @number_list
+
+ @to.accept_list_end @number_list
+
+ accept_list_end_number
+ end
+
+ def test_accept_list_end_note
+ @to.start_accepting
+
+ @to.accept_list_start @note_list
+
+ @to.accept_list_end @note_list
+
+ accept_list_end_note
+ end
+
+ def test_accept_list_end_ualpha
+ @to.start_accepting
+
+ @to.accept_list_start @ualpha_list
+
+ @to.accept_list_end @ualpha_list
+
+ accept_list_end_ualpha
+ end
+ end
+ end
+
+end
+
diff --git a/lib/rdoc/markup/fragments.rb b/lib/rdoc/markup/fragments.rb
deleted file mode 100644
index 0031b80..0000000
--- a/lib/rdoc/markup/fragments.rb
+++ /dev/null
@@ -1,337 +0,0 @@
-require 'rdoc/markup'
-require 'rdoc/markup/lines'
-
-class RDoc::Markup
-
- ##
- # A Fragment is a chunk of text, subclassed as a paragraph, a list
- # entry, or verbatim text.
-
- class Fragment
- attr_reader :level, :param, :txt
- attr_accessor :type
-
- ##
- # This is a simple factory system that lets us associate fragement
- # types (a string) with a subclass of fragment
-
- TYPE_MAP = {}
-
- def self.type_name(name)
- TYPE_MAP[name] = self
- end
-
- def self.for(line)
- klass = TYPE_MAP[line.type] ||
- raise("Unknown line type: '#{line.type.inspect}:' '#{line.text}'")
- return klass.new(line.level, line.param, line.flag, line.text)
- end
-
- def initialize(level, param, type, txt)
- @level = level
- @param = param
- @type = type
- @txt = ""
- add_text(txt) if txt
- end
-
- def add_text(txt)
- @txt << " " if @txt.length > 0
- @txt << txt.tr_s("\n ", " ").strip
- end
-
- def to_s
- "L#@level: #{self.class.name.split('::')[-1]}\n#@txt"
- end
-
- end
-
- ##
- # A paragraph is a fragment which gets wrapped to fit. We remove all
- # newlines when we're created, and have them put back on output.
-
- class Paragraph < Fragment
- type_name :PARAGRAPH
- end
-
- class BlankLine < Paragraph
- type_name :BLANK
- end
-
- class Heading < Paragraph
- type_name :HEADING
-
- def head_level
- @param.to_i
- end
- end
-
- ##
- # A List is a fragment with some kind of label
-
- class ListBase < Paragraph
- LIST_TYPES = [
- :BULLET,
- :NUMBER,
- :UPPERALPHA,
- :LOWERALPHA,
- :LABELED,
- :NOTE,
- ]
- end
-
- class ListItem < ListBase
- type_name :LIST
-
- def to_s
- text = if [:NOTE, :LABELED].include? type then
- "#{@param}: #{@txt}"
- else
- @txt
- end
-
- "L#@level: #{type} #{self.class.name.split('::')[-1]}\n#{text}"
- end
-
- end
-
- class ListStart < ListBase
- def initialize(level, param, type)
- super(level, param, type, nil)
- end
- end
-
- class ListEnd < ListBase
- def initialize(level, type)
- super(level, "", type, nil)
- end
- end
-
- ##
- # Verbatim code contains lines that don't get wrapped.
-
- class Verbatim < Fragment
- type_name :VERBATIM
-
- def add_text(txt)
- @txt << txt.chomp << "\n"
- end
-
- end
-
- ##
- # A horizontal rule
-
- class Rule < Fragment
- type_name :RULE
- end
-
- ##
- # Collect groups of lines together. Each group will end up containing a flow
- # of text.
-
- class LineCollection
-
- def initialize
- @fragments = []
- end
-
- def add(fragment)
- @fragments << fragment
- end
-
- def each(&b)
- @fragments.each(&b)
- end
-
- def to_a # :nodoc:
- @fragments.map {|fragment| fragment.to_s}
- end
-
- ##
- # Factory for different fragment types
-
- def fragment_for(*args)
- Fragment.for(*args)
- end
-
- ##
- # Tidy up at the end
-
- def normalize
- change_verbatim_blank_lines
- add_list_start_and_ends
- add_list_breaks
- tidy_blank_lines
- end
-
- def to_s
- @fragments.join("\n----\n")
- end
-
- def accept(am, visitor)
- visitor.start_accepting
-
- @fragments.each do |fragment|
- case fragment
- when Verbatim
- visitor.accept_verbatim(am, fragment)
- when Rule
- visitor.accept_rule(am, fragment)
- when ListStart
- visitor.accept_list_start(am, fragment)
- when ListEnd
- visitor.accept_list_end(am, fragment)
- when ListItem
- visitor.accept_list_item(am, fragment)
- when BlankLine
- visitor.accept_blank_line(am, fragment)
- when Heading
- visitor.accept_heading(am, fragment)
- when Paragraph
- visitor.accept_paragraph(am, fragment)
- end
- end
-
- visitor.end_accepting
- end
-
- private
-
- # If you have:
- #
- # normal paragraph text.
- #
- # this is code
- #
- # and more code
- #
- # You'll end up with the fragments Paragraph, BlankLine, Verbatim,
- # BlankLine, Verbatim, BlankLine, etc.
- #
- # The BlankLine in the middle of the verbatim chunk needs to be changed to
- # a real verbatim newline, and the two verbatim blocks merged
-
- def change_verbatim_blank_lines
- frag_block = nil
- blank_count = 0
- @fragments.each_with_index do |frag, i|
- if frag_block.nil?
- frag_block = frag if Verbatim === frag
- else
- case frag
- when Verbatim
- blank_count.times { frag_block.add_text("\n") }
- blank_count = 0
- frag_block.add_text(frag.txt)
- @fragments[i] = nil # remove out current fragment
- when BlankLine
- if frag_block
- blank_count += 1
- @fragments[i] = nil
- end
- else
- frag_block = nil
- blank_count = 0
- end
- end
- end
- @fragments.compact!
- end
-
- ##
- # List nesting is implicit given the level of indentation. Make it
- # explicit, just to make life a tad easier for the output processors
-
- def add_list_start_and_ends
- level = 0
- res = []
- type_stack = []
-
- @fragments.each do |fragment|
- # $stderr.puts "#{level} : #{fragment.class.name} : #{fragment.level}"
- new_level = fragment.level
- while (level < new_level)
- level += 1
- type = fragment.type
- res << ListStart.new(level, fragment.param, type) if type
- type_stack.push type
- # $stderr.puts "Start: #{level}"
- end
-
- while level > new_level
- type = type_stack.pop
- res << ListEnd.new(level, type) if type
- level -= 1
- # $stderr.puts "End: #{level}, #{type}"
- end
-
- res << fragment
- level = fragment.level
- end
- level.downto(1) do |i|
- type = type_stack.pop
- res << ListEnd.new(i, type) if type
- end
-
- @fragments = res
- end
-
- ##
- # Inserts start/ends between list entries at the same level that have
- # different element types
-
- def add_list_breaks
- res = @fragments
-
- @fragments = []
- list_stack = []
-
- res.each do |fragment|
- case fragment
- when ListStart
- list_stack.push fragment
- when ListEnd
- start = list_stack.pop
- fragment.type = start.type
- when ListItem
- l = list_stack.last
- if fragment.type != l.type
- @fragments << ListEnd.new(l.level, l.type)
- start = ListStart.new(l.level, fragment.param, fragment.type)
- @fragments << start
- list_stack.pop
- list_stack.push start
- end
- else
- ;
- end
- @fragments << fragment
- end
- end
-
- ##
- # Tidy up the blank lines:
- # * change Blank/ListEnd into ListEnd/Blank
- # * remove blank lines at the front
-
- def tidy_blank_lines
- (@fragments.size - 1).times do |i|
- if BlankLine === @fragments[i] and ListEnd === @fragments[i+1] then
- @fragments[i], @fragments[i+1] = @fragments[i+1], @fragments[i]
- end
- end
-
- # remove leading blanks
- @fragments.each_with_index do |f, i|
- break unless f.kind_of? BlankLine
- @fragments[i] = nil
- end
-
- @fragments.compact!
- end
-
- end
-
-end
-
diff --git a/lib/rdoc/markup/heading.rb b/lib/rdoc/markup/heading.rb
new file mode 100644
index 0000000..21e2574
--- /dev/null
+++ b/lib/rdoc/markup/heading.rb
@@ -0,0 +1,17 @@
+##
+# A heading with a level (1-6) and text
+
+class RDoc::Markup::Heading < Struct.new :level, :text
+
+ def accept visitor
+ visitor.accept_heading self
+ end
+
+ def pretty_print q # :nodoc:
+ q.group 2, "[head: #{level} ", ']' do
+ q.pp text
+ end
+ end
+
+end
+
diff --git a/lib/rdoc/markup/inline.rb b/lib/rdoc/markup/inline.rb
index 46c9b58..1b5eac4 100644
--- a/lib/rdoc/markup/inline.rb
+++ b/lib/rdoc/markup/inline.rb
@@ -1,5 +1,3 @@
-require 'rdoc/markup'
-
class RDoc::Markup
##
@@ -7,6 +5,10 @@ class RDoc::Markup
# value.
class Attribute
+
+ ##
+ # Special attribute type. See RDoc::Markup#add_special
+
SPECIAL = 1
@@name_to_bitmap = { :_SPECIAL_ => SPECIAL }
@@ -37,17 +39,18 @@ class RDoc::Markup
yield name.to_s if (bitmap & bit) != 0
end
end
+
end
- AttrChanger = Struct.new(:turn_on, :turn_off)
+ AttrChanger = Struct.new :turn_on, :turn_off # :nodoc:
##
# 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.
class AttrChanger
- def to_s
- "Attr: +#{Attribute.as_string(turn_on)}/-#{Attribute.as_string(turn_on)}"
+ def to_s # :nodoc:
+ "Attr: +#{Attribute.as_string turn_on}/-#{Attribute.as_string turn_on}"
end
end
@@ -55,42 +58,66 @@ class RDoc::Markup
# An array of attributes which parallels the characters in a string.
class AttrSpan
+
+ ##
+ # Creates a new AttrSpan for +length+ characters
+
def initialize(length)
@attrs = Array.new(length, 0)
end
+ ##
+ # Toggles +bits+ from +start+ to +length+
def set_attrs(start, length, bits)
for i in start ... (start+length)
@attrs[i] |= bits
end
end
+ ##
+ # Acccesses flags for character +n+
+
def [](n)
@attrs[n]
end
+
end
##
# Hold details of a special sequence
class Special
+
+ ##
+ # Special type
+
attr_reader :type
+
+ ##
+ # Special text
+
attr_accessor :text
+ ##
+ # Creates a new special sequence of +type+ with +text+
+
def initialize(type, text)
@type, @text = type, text
end
+ ##
+ # Specials are equal when the have the same text and type
+
def ==(o)
self.text == o.text && self.type == o.type
end
- def inspect
+ def inspect # :nodoc:
"#<RDoc::Markup::Special:0x%x @type=%p, name=%p @text=%p>" % [
object_id, @type, RDoc::Markup::Attribute.as_string(type), text.dump]
end
- def to_s
+ def to_s # :nodoc:
"Special: type=#{type}, name=#{RDoc::Markup::Attribute.as_string type}, text=#{text.dump}"
end
@@ -98,4 +125,3 @@ class RDoc::Markup
end
-require 'rdoc/markup/attribute_manager'
diff --git a/lib/rdoc/markup/lines.rb b/lib/rdoc/markup/lines.rb
deleted file mode 100644
index 0694921..0000000
--- a/lib/rdoc/markup/lines.rb
+++ /dev/null
@@ -1,152 +0,0 @@
-class RDoc::Markup
-
- ##
- # We store the lines we're working on as objects of class Line. These
- # contain the text of the line, along with a flag indicating the line type,
- # and an indentation level.
-
- class Line
- INFINITY = 9999
-
- LINE_TYPES = [
- :BLANK,
- :HEADING,
- :LIST,
- :PARAGRAPH,
- :RULE,
- :VERBATIM,
- ]
-
- # line type
- attr_accessor :type
-
- # The indentation nesting level
- attr_accessor :level
-
- # The contents
- attr_accessor :text
-
- # A prefix or parameter. For LIST lines, this is
- # the text that introduced the list item (the label)
- attr_accessor :param
-
- # A flag. For list lines, this is the type of the list
- attr_accessor :flag
-
- # the number of leading spaces
- attr_accessor :leading_spaces
-
- # true if this line has been deleted from the list of lines
- attr_accessor :deleted
-
- def initialize(text)
- @text = text.dup
- @deleted = false
-
- # expand tabs
- 1 while @text.gsub!(/\t+/) { ' ' * (8*$&.length - $`.length % 8)} && $~ #`
-
- # Strip trailing whitespace
- @text.sub!(/\s+$/, '')
-
- # and look for leading whitespace
- if @text.length > 0
- @text =~ /^(\s*)/
- @leading_spaces = $1.length
- else
- @leading_spaces = INFINITY
- end
- end
-
- # Return true if this line is blank
- def blank?
- @text.empty?
- end
-
- # stamp a line with a type, a level, a prefix, and a flag
- def stamp(type, level, param="", flag=nil)
- @type, @level, @param, @flag = type, level, param, flag
- end
-
- ##
- # Strip off the leading margin
-
- def strip_leading(size)
- if @text.size > size
- @text[0,size] = ""
- else
- @text = ""
- end
- end
-
- def to_s
- "#@type#@level: #@text"
- end
- end
-
- ##
- # A container for all the lines.
-
- class Lines
-
- include Enumerable
-
- attr_reader :lines # :nodoc:
-
- def initialize(lines)
- @lines = lines
- rewind
- end
-
- def empty?
- @lines.size.zero?
- end
-
- def each
- @lines.each do |line|
- yield line unless line.deleted
- end
- end
-
-# def [](index)
-# @lines[index]
-# end
-
- def rewind
- @nextline = 0
- end
-
- def next
- begin
- res = @lines[@nextline]
- @nextline += 1 if @nextline < @lines.size
- end while res and res.deleted and @nextline < @lines.size
- res
- end
-
- def unget
- @nextline -= 1
- end
-
- def delete(a_line)
- a_line.deleted = true
- end
-
- def normalize
- margin = @lines.collect{|l| l.leading_spaces}.min
- margin = 0 if margin == :INFINITY
- @lines.each {|line| line.strip_leading(margin) } if margin > 0
- end
-
- def as_text
- @lines.map {|l| l.text}.join("\n")
- end
-
- def line_types
- @lines.map {|l| l.type }
- end
-
- end
-
-end
-
diff --git a/lib/rdoc/markup/list.rb b/lib/rdoc/markup/list.rb
new file mode 100644
index 0000000..75326ed
--- /dev/null
+++ b/lib/rdoc/markup/list.rb
@@ -0,0 +1,78 @@
+##
+# A List of ListItems
+
+class RDoc::Markup::List
+
+ ##
+ # The list's type
+
+ attr_accessor :type
+
+ ##
+ # Items in the list
+
+ attr_reader :items
+
+ ##
+ # Creates a new list of +type+ with +items+
+
+ def initialize type = nil, *items
+ @type = type
+ @items = []
+ @items.push(*items)
+ end
+
+ ##
+ # Appends +item+ to the list
+
+ def << item
+ @items << item
+ end
+
+ def == other # :nodoc:
+ self.class == other.class and
+ @type == other.type and
+ @items == other.items
+ end
+
+ def accept visitor
+ visitor.accept_list_start self
+
+ @items.each do |item|
+ item.accept visitor
+ end
+
+ visitor.accept_list_end self
+ end
+
+ ##
+ # Is the list empty?
+
+ def empty?
+ @items.empty?
+ end
+
+ ##
+ # Returns the last item in the list
+
+ def last
+ @items.last
+ end
+
+ def pretty_print q # :nodoc:
+ q.group 2, "[list: #{@type} ", ']' do
+ q.seplist @items do |item|
+ q.pp item
+ end
+ end
+ end
+
+ ##
+ # Appends +items+ to the list
+
+ def push *items
+ @items.push(*items)
+ end
+
+end
+
diff --git a/lib/rdoc/markup/list_item.rb b/lib/rdoc/markup/list_item.rb
new file mode 100644
index 0000000..500e814
--- /dev/null
+++ b/lib/rdoc/markup/list_item.rb
@@ -0,0 +1,83 @@
+##
+# An item within a List that contains paragraphs, headings, etc.
+
+class RDoc::Markup::ListItem
+
+ ##
+ # The label for the ListItem
+
+ attr_accessor :label
+
+ ##
+ # Parts of the ListItem
+
+ attr_reader :parts
+
+ ##
+ # Creates a new ListItem with an optional +label+ containing +parts+
+
+ def initialize label = nil, *parts
+ @label = label
+ @parts = []
+ @parts.push(*parts)
+ end
+
+ ##
+ # Appends +part+ to the ListItem
+
+ def << part
+ @parts << part
+ end
+
+ def == other # :nodoc:
+ self.class == other.class and
+ @label == other.label and
+ @parts == other.parts
+ end
+
+ def accept visitor
+ visitor.accept_list_item_start self
+
+ @parts.each do |part|
+ part.accept visitor
+ end
+
+ visitor.accept_list_item_end self
+ end
+
+ ##
+ # Is the ListItem empty?
+
+ def empty?
+ @parts.empty?
+ end
+
+ ##
+ # Length of parts in the ListItem
+
+ def length
+ @parts.length
+ end
+
+ def pretty_print q # :nodoc:
+ q.group 2, '[item: ', ']' do
+ if @label then
+ q.text @label
+ q.breakable
+ end
+
+ q.seplist @parts do |part|
+ q.pp part
+ end
+ end
+ end
+
+ ##
+ # Adds +parts+ to the ListItem
+
+ def push *parts
+ @parts.push(*parts)
+ end
+
+end
+
diff --git a/lib/rdoc/markup/paragraph.rb b/lib/rdoc/markup/paragraph.rb
new file mode 100644
index 0000000..bc23423
--- /dev/null
+++ b/lib/rdoc/markup/paragraph.rb
@@ -0,0 +1,66 @@
+##
+# A Paragraph of text
+
+class RDoc::Markup::Paragraph
+
+ ##
+ # The component parts of the list
+
+ attr_reader :parts
+
+ ##
+ # Creates a new Paragraph containing +parts+
+
+ def initialize *parts
+ @parts = []
+ @parts.push(*parts)
+ end
+
+ ##
+ # Appends +text+ to the Paragraph
+
+ def << text
+ @parts << text
+ end
+
+ def == other # :nodoc:
+ self.class == other.class and text == other.text
+ end
+
+ def accept visitor
+ visitor.accept_paragraph self
+ end
+
+ ##
+ # Appends +other+'s parts into this Paragraph
+
+ def merge other
+ @parts.push(*other.parts)
+ end
+
+ def pretty_print q # :nodoc:
+ self.class.name =~ /.*::(\w{4})/i
+
+ q.group 2, "[#{$1.downcase}: ", ']' do
+ q.seplist @parts do |part|
+ q.pp part
+ end
+ end
+ end
+
+ ##
+ # Appends +texts+ onto this Paragraph
+
+ def push *texts
+ self.parts.push(*texts)
+ end
+
+ ##
+ # The text of this paragraph
+
+ def text
+ @parts.join ' '
+ end
+
+end
+
diff --git a/lib/rdoc/markup/parser.rb b/lib/rdoc/markup/parser.rb
new file mode 100644
index 0000000..c0d6519
--- /dev/null
+++ b/lib/rdoc/markup/parser.rb
@@ -0,0 +1,528 @@
+require 'strscan'
+require 'rdoc/text'
+
+##
+# A recursive-descent parser for RDoc markup.
+#
+# The parser tokenizes an input string then parses the tokens into a Document.
+# Documents can be converted into output formats by writing a visitor like
+# RDoc::Markup::ToHTML.
+#
+# The parser only handles the block-level constructs Paragraph, List,
+# ListItem, Heading, Verbatim, BlankLine and Rule. Inline markup such as
+# <tt>\+blah\+</tt> is handled separately by RDoc::Markup::AttributeManager.
+#
+# To see what markup the Parser implements read RDoc. To see how to use
+# RDoc markup to format text in your program read RDoc::Markup.
+
+class RDoc::Markup::Parser
+
+ include RDoc::Text
+
+ ##
+ # List token types
+
+ LIST_TOKENS = [
+ :BULLET,
+ :LABEL,
+ :LALPHA,
+ :NOTE,
+ :NUMBER,
+ :UALPHA,
+ ]
+
+ ##
+ # Parser error subclass
+
+ class Error < RuntimeError; end
+
+ ##
+ # Raised when the parser is unable to handle the given markup
+
+ class ParseError < Error; end
+
+ ##
+ # Enables display of debugging information
+
+ attr_accessor :debug
+
+ ##
+ # Token accessor
+
+ attr_reader :tokens
+
+ ##
+ # Parsers +str+ into a Document
+
+ def self.parse str
+ parser = new
+ #parser.debug = true
+ parser.tokenize str
+ RDoc::Markup::Document.new(*parser.parse)
+ end
+
+ ##
+ # Returns a token stream for +str+, for testing
+
+ def self.tokenize str
+ parser = new
+ parser.tokenize str
+ parser.tokens
+ end
+
+ ##
+ # Creates a new Parser. See also ::parse
+
+ def initialize
+ @tokens = []
+ @current_token = nil
+ @debug = false
+
+ @line = 0
+ @line_pos = 0
+ end
+
+ ##
+ # Builds a Heading of +level+
+
+ def build_heading level
+ heading = RDoc::Markup::Heading.new level, text
+ skip :NEWLINE
+
+ heading
+ end
+
+ ##
+ # Builds a List flush to +margin+
+
+ def build_list margin
+ p :list_start => margin if @debug
+
+ list = RDoc::Markup::List.new
+
+ until @tokens.empty? do
+ type, data, column, = get
+
+ case type
+ when :BULLET, :LABEL, :LALPHA, :NOTE, :NUMBER, :UALPHA then
+ list_type = type
+
+ if column < margin then
+ unget
+ break
+ end
+
+ if list.type and list.type != list_type then
+ unget
+ break
+ end
+
+ list.type = list_type
+
+ case type
+ when :NOTE, :LABEL then
+ _, indent, = get # SPACE
+ if :NEWLINE == peek_token.first then
+ get
+ peek_type, new_indent, peek_column, = peek_token
+ indent = new_indent if
+ peek_type == :INDENT and peek_column >= column
+ unget
+ end
+ else
+ data = nil
+ _, indent, = get
+ end
+
+ list_item = build_list_item(margin + indent, data)
+
+ list << list_item if list_item
+ else
+ unget
+ break
+ end
+ end
+
+ p :list_end => margin if @debug
+
+ return nil if list.empty?
+
+ list
+ end
+
+ ##
+ # Builds a ListItem that is flush to +indent+ with type +item_type+
+
+ def build_list_item indent, item_type = nil
+ p :list_item_start => [indent, item_type] if @debug
+
+ list_item = RDoc::Markup::ListItem.new item_type
+
+ until @tokens.empty? do
+ type, data, column = get
+
+ if column < indent and
+ not type == :NEWLINE and
+ (type != :INDENT or data < indent) then
+ unget
+ break
+ end
+
+ case type
+ when :INDENT then
+ unget
+ list_item.push(*parse(indent))
+ when :TEXT then
+ unget
+ list_item << build_paragraph(indent)
+ when :HEADER then
+ list_item << build_heading(data)
+ when :NEWLINE then
+ list_item << RDoc::Markup::BlankLine.new
+ when *LIST_TOKENS then
+ unget
+ list_item << build_list(column)
+ else
+ raise ParseError, "Unhandled token #{@current_token.inspect}"
+ end
+ end
+
+ p :list_item_end => [indent, item_type] if @debug
+
+ return nil if list_item.empty?
+
+ list_item.parts.shift if
+ RDoc::Markup::BlankLine === list_item.parts.first and
+ list_item.length > 1
+
+ list_item
+ end
+
+ ##
+ # Builds a Paragraph that is flush to +margin+
+
+ def build_paragraph margin
+ p :paragraph_start => margin if @debug
+
+ paragraph = RDoc::Markup::Paragraph.new
+
+ until @tokens.empty? do
+ type, data, column, = get
+
+ case type
+ when :INDENT then
+ next if data == margin and peek_token[0] == :TEXT
+
+ unget
+ break
+ when :TEXT then
+ if column != margin then
+ unget
+ break
+ end
+
+ paragraph << data
+ skip :NEWLINE
+ else
+ unget
+ break
+ end
+ end
+
+ p :paragraph_end => margin if @debug
+
+ paragraph
+ end
+
+ ##
+ # Builds a Verbatim that is flush to +margin+
+
+ def build_verbatim margin
+ p :verbatim_begin => margin if @debug
+ verbatim = RDoc::Markup::Verbatim.new
+
+ until @tokens.empty? do
+ type, data, column, = get
+
+ case type
+ when :INDENT then
+ if margin >= data then
+ unget
+ break
+ end
+
+ indent = data - margin
+
+ verbatim << ' ' * indent
+ when :HEADER then
+ verbatim << '=' * data
+
+ _, _, peek_column, = peek_token
+ peek_column ||= column + data
+ verbatim << ' ' * (peek_column - column - data)
+ when :RULE then
+ width = 2 + data
+ verbatim << '-' * width
+
+ _, _, peek_column, = peek_token
+ peek_column ||= column + data + 2
+ verbatim << ' ' * (peek_column - column - width)
+ when :TEXT then
+ verbatim << data
+ when *LIST_TOKENS then
+ if column <= margin then
+ unget
+ break
+ end
+
+ list_marker = case type
+ when :BULLET then '*'
+ when :LABEL then "[#{data}]"
+ when :LALPHA, :NUMBER, :UALPHA then "#{data}."
+ when :NOTE then "#{data}::"
+ end
+
+ verbatim << list_marker
+
+ _, data, = get
+
+ verbatim << ' ' * (data - list_marker.length)
+ when :NEWLINE then
+ verbatim << data
+ break unless [:INDENT, :NEWLINE].include? peek_token[0]
+ else
+ unget
+ break
+ end
+ end
+
+ verbatim.normalize
+
+ p :verbatim_end => margin if @debug
+
+ verbatim
+ end
+
+ ##
+ # Pulls the next token from the stream.
+
+ def get
+ @current_token = @tokens.shift
+ p :get => @current_token if @debug
+ @current_token
+ end
+
+ ##
+ # Parses the tokens into a Document
+
+ def parse indent = 0
+ p :parse_start => indent if @debug
+
+ document = []
+
+ until @tokens.empty? do
+ type, data, column, = get
+
+ if type != :INDENT and column < indent then
+ unget
+ break
+ end
+
+ case type
+ when :HEADER then
+ document << build_heading(data)
+ when :INDENT then
+ if indent > data then
+ unget
+ break
+ elsif indent == data then
+ next
+ end
+
+ unget
+ document << build_verbatim(indent)
+ when :NEWLINE then
+ document << RDoc::Markup::BlankLine.new
+ skip :NEWLINE, false
+ when :RULE then
+ document << RDoc::Markup::Rule.new(data)
+ skip :NEWLINE
+ when :TEXT then
+ unget
+ document << build_paragraph(indent)
+
+ # we're done with this paragraph (indent mismatch)
+ break if peek_token[0] == :TEXT
+ when *LIST_TOKENS then
+ unget
+
+ list = build_list(indent)
+
+ document << list if list
+
+ # we're done with this list (indent mismatch)
+ break if LIST_TOKENS.include? peek_token.first and indent > 0
+ else
+ type, data, column, line = @current_token
+ raise ParseError,
+ "Unhandled token #{type} (#{data.inspect}) at #{line}:#{column}"
+ end
+ end
+
+ p :parse_end => indent if @debug
+
+ document
+ end
+
+ ##
+ # Returns the next token on the stream without modifying the stream
+
+ def peek_token
+ token = @tokens.first || []
+ p :peek => token if @debug
+ token
+ end
+
+ ##
+ # Skips a token of +token_type+, optionally raising an error.
+
+ def skip token_type, error = true
+ type, data, = get
+
+ return unless type # end of stream
+
+ return @current_token if token_type == type
+
+ unget
+
+ raise ParseError, "expected #{token_type} got #{@current_token.inspect}" if
+ error
+ end
+
+ ##
+ # Consumes tokens until NEWLINE and turns them back into text
+
+ def text
+ text = ''
+
+ loop do
+ type, data, = get
+
+ text << case type
+ when :BULLET then
+ _, space, = get # SPACE
+ "*#{' ' * (space - 1)}"
+ when :LABEL then
+ _, space, = get # SPACE
+ "[#{data}]#{' ' * (space - data.length - 2)}"
+ when :LALPHA, :NUMBER, :UALPHA then
+ _, space, = get # SPACE
+ "#{data}.#{' ' * (space - 2)}"
+ when :NOTE then
+ _, space = get # SPACE
+ "#{data}::#{' ' * (space - data.length - 2)}"
+ when :TEXT then
+ data
+ when :NEWLINE then
+ unget
+ break
+ when nil then
+ break
+ else
+ raise ParseError, "unhandled token #{@current_token.inspect}"
+ end
+ end
+
+ text
+ end
+
+ ##
+ # Calculates the column and line of the current token based on +offset+.
+
+ def token_pos offset
+ [offset - @line_pos, @line]
+ end
+
+ ##
+ # Turns text +input+ into a stream of tokens
+
+ def tokenize input
+ s = StringScanner.new input
+
+ @line = 0
+ @line_pos = 0
+
+ until s.eos? do
+ pos = s.pos
+
+ @tokens << case
+ when s.scan(/\r?\n/) then
+ token = [:NEWLINE, s.matched, *token_pos(pos)]
+ @line_pos = s.pos
+ @line += 1
+ token
+ when s.scan(/ +/) then
+ [:INDENT, s.matched_size, *token_pos(pos)]
+ when s.scan(/(=+)\s+/) then
+ level = s[1].length
+ level = 6 if level > 6
+ @tokens << [:HEADER, level, *token_pos(pos)]
+
+ pos = s.pos
+ s.scan(/.*/)
+ [:TEXT, s.matched, *token_pos(pos)]
+ when s.scan(/^(-{3,}) *$/) then
+ [:RULE, s[1].length - 2, *token_pos(pos)]
+ when s.scan(/([*-])\s+/) then
+ @tokens << [:BULLET, :BULLET, *token_pos(pos)]
+ [:SPACE, s.matched_size, *token_pos(pos)]
+ when s.scan(/([a-z]|\d+)\.[ \t]+\S/i) then
+ list_label = s[1]
+ width = s.matched_size - 1
+
+ s.pos -= 1 # unget \S
+
+ list_type = case list_label
+ when /[a-z]/ then :LALPHA
+ when /[A-Z]/ then :UALPHA
+ when /\d/ then :NUMBER
+ else
+ raise ParseError, "BUG token #{list_label}"
+ end
+
+ @tokens << [list_type, list_label, *token_pos(pos)]
+ [:SPACE, width, *token_pos(pos)]
+ when s.scan(/\[(.*?)\]( +|$)/) then
+ @tokens << [:LABEL, s[1], *token_pos(pos)]
+ [:SPACE, s.matched_size, *token_pos(pos)]
+ when s.scan(/(.*?)::( +|$)/) then
+ @tokens << [:NOTE, s[1], *token_pos(pos)]
+ [:SPACE, s.matched_size, *token_pos(pos)]
+ else s.scan(/.*/)
+ [:TEXT, s.matched, *token_pos(pos)]
+ end
+ end
+
+ self
+ end
+
+ ##
+ # Returns the current token or +token+ to the token stream
+
+ def unget token = @current_token
+ p :unget => token if @debug
+ raise Error, 'too many #ungets' if token == @tokens.first
+ @tokens.unshift token if token
+ end
+
+end
+
+require 'rdoc/markup/blank_line'
+require 'rdoc/markup/document'
+require 'rdoc/markup/heading'
+require 'rdoc/markup/list'
+require 'rdoc/markup/list_item'
+require 'rdoc/markup/paragraph'
+require 'rdoc/markup/rule'
+require 'rdoc/markup/verbatim'
+
diff --git a/lib/rdoc/markup/preprocess.rb b/lib/rdoc/markup/preprocess.rb
index 00dd4be..a175d17 100644
--- a/lib/rdoc/markup/preprocess.rb
+++ b/lib/rdoc/markup/preprocess.rb
@@ -7,6 +7,10 @@ require 'rdoc/markup'
class RDoc::Markup::PreProcess
+ ##
+ # Creates a new pre-processor for +input_file_name+ that will look for
+ # included files in +include_path+
+
def initialize(input_file_name, include_path)
@input_file_name = input_file_name
@include_path = include_path
@@ -44,15 +48,16 @@ class RDoc::Markup::PreProcess
def include_file(name, indent)
if full_name = find_include_file(name) then
- content = File.open(full_name) {|f| f.read}
+ content = File.read full_name
+
# strip leading '#'s, but only if all lines start with them
- if content =~ /^[^#]/
+ if content =~ /^[^#]/ then
content.gsub(/^/, indent)
else
content.gsub(/^#?/, indent)
end
else
- $stderr.puts "Couldn't find file to include: '#{name}'"
+ $stderr.puts "Couldn't find file to include '#{name}' from #{@input_file_name}"
''
end
end
diff --git a/lib/rdoc/markup/rule.rb b/lib/rdoc/markup/rule.rb
new file mode 100644
index 0000000..4fcd040
--- /dev/null
+++ b/lib/rdoc/markup/rule.rb
@@ -0,0 +1,17 @@
+##
+# A horizontal rule with a weight
+
+class RDoc::Markup::Rule < Struct.new :weight
+
+ def accept visitor
+ visitor.accept_rule self
+ end
+
+ def pretty_print q # :nodoc:
+ q.group 2, '[rule:', ']' do
+ q.pp weight
+ end
+ end
+
+end
+
diff --git a/lib/rdoc/markup/to_ansi.rb b/lib/rdoc/markup/to_ansi.rb
new file mode 100644
index 0000000..9a5be8b
--- /dev/null
+++ b/lib/rdoc/markup/to_ansi.rb
@@ -0,0 +1,72 @@
+require 'rdoc/markup/inline'
+
+##
+# Outputs RDoc markup with vibrant ANSI color!
+
+class RDoc::Markup::ToAnsi < RDoc::Markup::ToRdoc
+
+ def initialize
+ super
+
+ @headings.clear
+ @headings[1] = ["\e[1;32m", "\e[m"]
+ @headings[2] = ["\e[4;32m", "\e[m"]
+ @headings[3] = ["\e[32m", "\e[m"]
+ end
+
+ ##
+ # Maps attributes to ANSI sequences
+
+ def init_tags
+ add_tag :BOLD, "\e[1m", "\e[m"
+ add_tag :TT, "\e[7m", "\e[m"
+ add_tag :EM, "\e[4m", "\e[m"
+ end
+
+ def accept_list_item_end list_item
+ width = case @list_type.last
+ when :BULLET then
+ 2
+ when :NOTE, :LABEL then
+ @res << "\n"
+ 2
+ else
+ bullet = @list_index.last.to_s
+ @list_index[-1] = @list_index.last.succ
+ bullet.length + 2
+ end
+
+ @indent -= width
+ end
+
+ def accept_list_item_start list_item
+ bullet = case @list_type.last
+ when :BULLET then
+ '*'
+ when :NOTE, :LABEL then
+ attributes(list_item.label) + ":\n"
+ else
+ @list_index.last.to_s + '.'
+ end
+
+ case @list_type.last
+ when :NOTE, :LABEL then
+ @indent += 2
+ @prefix = bullet + (' ' * @indent)
+ else
+ @prefix = (' ' * @indent) + bullet.ljust(bullet.length + 1)
+
+ width = bullet.gsub(/\e\[[\d;]*m/, '').length + 1
+
+ @indent += width
+ end
+ end
+
+ def start_accepting
+ super
+
+ @res = ["\e[0m"]
+ end
+
+end
+
diff --git a/lib/rdoc/markup/to_bs.rb b/lib/rdoc/markup/to_bs.rb
new file mode 100644
index 0000000..e7af129
--- /dev/null
+++ b/lib/rdoc/markup/to_bs.rb
@@ -0,0 +1,74 @@
+require 'rdoc/markup/inline'
+
+##
+# Outputs RDoc markup with hot backspace action! You will probably need a
+# pager to use this output format.
+#
+# This formatter won't work on 1.8.6 because it lacks String#chars.
+
+class RDoc::Markup::ToBs < RDoc::Markup::ToRdoc
+
+ def initialize
+ super
+
+ @in_b = false
+ @in_em = false
+ end
+
+ ##
+ # Sets a flag that is picked up by #annotate to do the right thing in
+ # #convert_string
+
+ def init_tags
+ add_tag :BOLD, '+b', '-b'
+ add_tag :EM, '+_', '-_'
+ end
+
+ def accept_heading heading
+ use_prefix or @res << ' ' * @indent
+ @res << @headings[heading.level][0]
+ @in_b = true
+ @res << attributes(heading.text)
+ @in_b = false
+ @res << @headings[heading.level][1]
+ @res << "\n"
+ end
+
+ ##
+ # Turns on or off special handling for +convert_string+
+
+ def annotate tag
+ case tag
+ when '+b' then @in_b = true
+ when '-b' then @in_b = false
+ when '+_' then @in_em = true
+ when '-_' then @in_em = false
+ end
+
+ ''
+ end
+
+ ##
+ # Calls convert_string on the result of convert_special
+
+ def convert_special special
+ convert_string super
+ end
+
+ ##
+ # Adds bold or underline mixed with backspaces
+
+ def convert_string string
+ return string unless string.respond_to? :chars # your ruby is lame
+ return string unless @in_b or @in_em
+ chars = if @in_b then
+ string.chars.map do |char| "#{char}\b#{char}" end
+ elsif @in_em then
+ string.chars.map do |char| "_\b#{char}" end
+ end
+
+ chars.join
+ end
+
+end
+
diff --git a/lib/rdoc/markup/to_flow.rb b/lib/rdoc/markup/to_flow.rb
deleted file mode 100644
index 3d87b3e..0000000
--- a/lib/rdoc/markup/to_flow.rb
+++ /dev/null
@@ -1,185 +0,0 @@
-require 'rdoc/markup/formatter'
-require 'rdoc/markup/fragments'
-require 'rdoc/markup/inline'
-require 'cgi'
-
-class RDoc::Markup
-
- module Flow
- P = Struct.new(:body)
- VERB = Struct.new(:body)
- RULE = Struct.new(:width)
- class LIST
- attr_reader :type, :contents
- def initialize(type)
- @type = type
- @contents = []
- end
- def <<(stuff)
- @contents << stuff
- end
- end
- LI = Struct.new(:label, :body)
- H = Struct.new(:level, :text)
- end
-
- class ToFlow < RDoc::Markup::Formatter
- LIST_TYPE_TO_HTML = {
- :BULLET => [ "<ul>", "</ul>" ],
- :NUMBER => [ "<ol>", "</ol>" ],
- :UPPERALPHA => [ "<ol>", "</ol>" ],
- :LOWERALPHA => [ "<ol>", "</ol>" ],
- :LABELED => [ "<dl>", "</dl>" ],
- :NOTE => [ "<table>", "</table>" ],
- }
-
- InlineTag = Struct.new(:bit, :on, :off)
-
- def initialize
- super
-
- init_tags
- end
-
- ##
- # Set up the standard mapping of attributes to HTML tags
-
- def init_tags
- @attr_tags = [
- InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:BOLD), "<b>", "</b>"),
- InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:TT), "<tt>", "</tt>"),
- InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:EM), "<em>", "</em>"),
- ]
- end
-
- ##
- # Add a new set of HTML tags for an attribute. We allow separate start and
- # end tags for flexibility
-
- def add_tag(name, start, stop)
- @attr_tags << InlineTag.new(RDoc::Markup::Attribute.bitmap_for(name), start, stop)
- end
-
- ##
- # Given an HTML tag, decorate it with class information and the like if
- # required. This is a no-op in the base class, but is overridden in HTML
- # output classes that implement style sheets
-
- def annotate(tag)
- tag
- end
-
- ##
- # Here's the client side of the visitor pattern
-
- def start_accepting
- @res = []
- @list_stack = []
- end
-
- def end_accepting
- @res
- end
-
- def accept_paragraph(am, fragment)
- @res << Flow::P.new((convert_flow(am.flow(fragment.txt))))
- end
-
- def accept_verbatim(am, fragment)
- @res << Flow::VERB.new((convert_flow(am.flow(fragment.txt))))
- end
-
- def accept_rule(am, fragment)
- size = fragment.param
- size = 10 if size > 10
- @res << Flow::RULE.new(size)
- end
-
- def accept_list_start(am, fragment)
- @list_stack.push(@res)
- list = Flow::LIST.new(fragment.type)
- @res << list
- @res = list
- end
-
- def accept_list_end(am, fragment)
- @res = @list_stack.pop
- end
-
- def accept_list_item(am, fragment)
- @res << Flow::LI.new(fragment.param, convert_flow(am.flow(fragment.txt)))
- end
-
- def accept_blank_line(am, fragment)
- # @res << annotate("<p />") << "\n"
- end
-
- def accept_heading(am, fragment)
- @res << Flow::H.new(fragment.head_level, convert_flow(am.flow(fragment.txt)))
- end
-
- private
-
- def on_tags(res, item)
- attr_mask = item.turn_on
- return if attr_mask.zero?
-
- @attr_tags.each do |tag|
- if attr_mask & tag.bit != 0
- res << annotate(tag.on)
- end
- end
- end
-
- def off_tags(res, item)
- attr_mask = item.turn_off
- return if attr_mask.zero?
-
- @attr_tags.reverse_each do |tag|
- if attr_mask & tag.bit != 0
- res << annotate(tag.off)
- end
- end
- end
-
- def convert_flow(flow)
- res = ""
- flow.each do |item|
- case item
- when String
- res << convert_string(item)
- when AttrChanger
- off_tags(res, item)
- on_tags(res, item)
- when Special
- res << convert_special(item)
- else
- raise "Unknown flow element: #{item.inspect}"
- end
- end
- res
- end
-
- def convert_string(item)
- CGI.escapeHTML(item)
- end
-
- def convert_special(special)
- handled = false
- Attribute.each_name_of(special.type) do |name|
- method_name = "handle_special_#{name}"
- if self.respond_to? method_name
- special.text = send(method_name, special)
- handled = true
- end
- end
-
- raise "Unhandled special: #{special}" unless handled
-
- special.text
- end
-
- end
-
-end
-
diff --git a/lib/rdoc/markup/to_html.rb b/lib/rdoc/markup/to_html.rb
index 0165042..f060fd1 100644
--- a/lib/rdoc/markup/to_html.rb
+++ b/lib/rdoc/markup/to_html.rb
@@ -1,38 +1,28 @@
require 'rdoc/markup/formatter'
-require 'rdoc/markup/fragments'
require 'rdoc/markup/inline'
require 'cgi'
+##
+# Outputs RDoc markup as HTML
+
class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
+ ##
+ # Maps RDoc::Markup::Parser::LIST_TOKENS types to HTML tags
+
LIST_TYPE_TO_HTML = {
- :BULLET => %w[<ul> </ul>],
- :NUMBER => %w[<ol> </ol>],
- :UPPERALPHA => %w[<ol> </ol>],
- :LOWERALPHA => %w[<ol> </ol>],
- :LABELED => %w[<dl> </dl>],
- :NOTE => %w[<table> </table>],
+ :BULLET => ['<ul>', '</ul>'],
+ :LABEL => ['<dl>', '</dl>'],
+ :LALPHA => ['<ol style="display: lower-alpha">', '</ol>'],
+ :NOTE => ['<table>', '</table>'],
+ :NUMBER => ['<ol>', '</ol>'],
+ :UALPHA => ['<ol style="display: upper-alpha">', '</ol>'],
}
- InlineTag = Struct.new(:bit, :on, :off)
-
- def initialize
- super
-
- # @in_tt - tt nested levels count
- # @tt_bit - cache
- @in_tt = 0
- @tt_bit = RDoc::Markup::Attribute.bitmap_for :TT
-
- # external hyperlinks
- @markup.add_special(/((link:|https?:|mailto:|ftp:|www\.)\S+\w)/, :HYPERLINK)
-
- # and links of the form <text>[<url>]
- @markup.add_special(/(((\{.*?\})|\b\S+?)\[\S+?\.\S+?\])/, :TIDYLINK)
-
- init_tags
- end
+ attr_reader :res # :nodoc:
+ attr_reader :in_list_entry # :nodoc:
+ attr_reader :list # :nodoc:
##
# Converts a target url to one that is relative to a given path
@@ -44,6 +34,9 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
from = from.split "/"
to = to.split "/"
+ from.delete '.'
+ to.delete '.'
+
while from.size > 0 and to.size > 0 and from[0] == to[0] do
from.shift
to.shift
@@ -55,6 +48,31 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
File.join(*from)
end
+ def initialize
+ super
+
+ @th = nil
+ @in_list_entry = nil
+ @list = nil
+
+ # external hyperlinks
+ @markup.add_special(/((link:|https?:|mailto:|ftp:|www\.)\S+\w)/, :HYPERLINK)
+
+ # and links of the form <text>[<url>]
+ @markup.add_special(/(((\{.*?\})|\b\S+?)\[\S+?\.\S+?\])/, :TIDYLINK)
+
+ init_tags
+ end
+
+ ##
+ # Maps attributes to HTML tags
+
+ def init_tags
+ add_tag :BOLD, "<b>", "</b>"
+ add_tag :TT, "<tt>", "</tt>"
+ add_tag :EM, "<em>", "</em>"
+ end
+
##
# Generate a hyperlink for url, labeled with text. Handle the
# special cases for img: and link: described under handle_special_HYPERLINK
@@ -113,195 +131,121 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
end
##
- # are we currently inside <tt> tags?
-
- def in_tt?
- @in_tt > 0
- end
-
- ##
- # is +tag+ a <tt> tag?
-
- def tt?(tag)
- tag.bit == @tt_bit
- end
-
- ##
- # Set up the standard mapping of attributes to HTML tags
-
- def init_tags
- @attr_tags = [
- InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:BOLD), "<b>", "</b>"),
- InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:TT), "<tt>", "</tt>"),
- InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:EM), "<em>", "</em>"),
- ]
- end
-
- ##
- # Add a new set of HTML tags for an attribute. We allow separate start and
- # end tags for flexibility.
+ # This is a higher speed (if messier) version of wrap
- def add_tag(name, start, stop)
- @attr_tags << InlineTag.new(RDoc::Markup::Attribute.bitmap_for(name), start, stop)
- end
+ def wrap(txt, line_len = 76)
+ res = []
+ sp = 0
+ ep = txt.length
- ##
- # Given an HTML tag, decorate it with class information and the like if
- # required. This is a no-op in the base class, but is overridden in HTML
- # output classes that implement style sheets.
+ while sp < ep
+ # scan back for a space
+ p = sp + line_len - 1
+ if p >= ep
+ p = ep
+ else
+ while p > sp and txt[p] != ?\s
+ p -= 1
+ end
+ if p <= sp
+ p = sp + line_len
+ while p < ep and txt[p] != ?\s
+ p += 1
+ end
+ end
+ end
+ res << txt[sp...p] << "\n"
+ sp = p
+ sp += 1 while sp < ep and txt[sp] == ?\s
+ end
- def annotate(tag)
- tag
+ res.join
end
##
- # Here's the client side of the visitor pattern
+ # :section: Visitor
def start_accepting
- @res = ""
+ @res = []
@in_list_entry = []
+ @list = []
end
def end_accepting
- @res
+ @res.join
end
- def accept_paragraph(am, fragment)
+ def accept_paragraph(paragraph)
@res << annotate("<p>") + "\n"
- @res << wrap(convert_flow(am.flow(fragment.txt)))
+ @res << wrap(convert_flow(@am.flow(paragraph.text)))
@res << annotate("</p>") + "\n"
end
- def accept_verbatim(am, fragment)
- @res << annotate("<pre>") + "\n"
- @res << CGI.escapeHTML(fragment.txt)
+ def accept_verbatim(verbatim)
+ @res << annotate("<pre>") << "\n"
+ @res << CGI.escapeHTML(verbatim.text)
@res << annotate("</pre>") << "\n"
end
- def accept_rule(am, fragment)
- size = fragment.param
+ def accept_rule(rule)
+ size = rule.weight
size = 10 if size > 10
- @res << "<hr size=\"#{size}\"></hr>"
+ @res << "<hr style=\"height: #{size}px\"></hr>"
end
- def accept_list_start(am, fragment)
- @res << html_list_name(fragment.type, true) << "\n"
+ def accept_list_start(list)
+ @list << list.type
+ @res << html_list_name(list.type, true) << "\n"
@in_list_entry.push false
end
- def accept_list_end(am, fragment)
+ def accept_list_end(list)
+ @list.pop
if tag = @in_list_entry.pop
@res << annotate(tag) << "\n"
end
- @res << html_list_name(fragment.type, false) << "\n"
+ @res << html_list_name(list.type, false) << "\n"
end
- def accept_list_item(am, fragment)
+ def accept_list_item_start(list_item)
if tag = @in_list_entry.last
@res << annotate(tag) << "\n"
end
- @res << list_item_start(am, fragment)
-
- @res << wrap(convert_flow(am.flow(fragment.txt))) << "\n"
+ @res << list_item_start(list_item, @list.last)
+ end
- @in_list_entry[-1] = list_end_for(fragment.type)
+ def accept_list_item_end(list_item)
+ @in_list_entry[-1] = list_end_for(@list.last)
end
- def accept_blank_line(am, fragment)
+ def accept_blank_line(blank_line)
# @res << annotate("<p />") << "\n"
end
- def accept_heading(am, fragment)
- @res << convert_heading(fragment.head_level, am.flow(fragment.txt))
- end
-
- ##
- # This is a higher speed (if messier) version of wrap
-
- def wrap(txt, line_len = 76)
- res = ""
- sp = 0
- ep = txt.length
- while sp < ep
- # scan back for a space
- p = sp + line_len - 1
- if p >= ep
- p = ep
- else
- while p > sp and txt[p] != ?\s
- p -= 1
- end
- if p <= sp
- p = sp + line_len
- while p < ep and txt[p] != ?\s
- p += 1
- end
- end
- end
- res << txt[sp...p] << "\n"
- sp = p
- sp += 1 while sp < ep and txt[sp] == ?\s
- end
- res
+ def accept_heading(heading)
+ @res << convert_heading(heading.level, @am.flow(heading.text))
end
private
- def on_tags(res, item)
- attr_mask = item.turn_on
- return if attr_mask.zero?
-
- @attr_tags.each do |tag|
- if attr_mask & tag.bit != 0
- res << annotate(tag.on)
- @in_tt += 1 if tt?(tag)
- end
- end
- end
-
- def off_tags(res, item)
- attr_mask = item.turn_off
- return if attr_mask.zero?
-
- @attr_tags.reverse_each do |tag|
- if attr_mask & tag.bit != 0
- @in_tt -= 1 if tt?(tag)
- res << annotate(tag.off)
- end
- end
- end
-
- def convert_flow(flow)
- res = ""
-
- flow.each do |item|
- case item
- when String
- res << convert_string(item)
- when RDoc::Markup::AttrChanger
- off_tags(res, item)
- on_tags(res, item)
- when RDoc::Markup::Special
- res << convert_special(item)
- else
- raise "Unknown flow element: #{item.inspect}"
- end
- end
-
- res
- end
+ ##
+ # Converts string +item+
def convert_string(item)
in_tt? ? convert_string_simple(item) : convert_string_fancy(item)
end
+ ##
+ # Escapes HTML in +item+
+
def convert_string_simple(item)
CGI.escapeHTML item
end
##
- # some of these patterns are taken from SmartyPants...
+ # Converts ampersand, dashes, elipsis, quotes, copyright and registered
+ # trademark symbols to HTML escaped Unicode.
def convert_string_fancy(item)
# convert ampersand before doing anything else
@@ -333,69 +277,62 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
gsub(/\(r\)/, '&#174;')
end
- def convert_special(special)
- handled = false
- RDoc::Markup::Attribute.each_name_of(special.type) do |name|
- method_name = "handle_special_#{name}"
- if self.respond_to? method_name
- special.text = send(method_name, special)
- handled = true
- end
- end
- raise "Unhandled special: #{special}" unless handled
- special.text
- end
+ ##
+ # Converts headings to hN elements
def convert_heading(level, flow)
- res =
- annotate("<h#{level}>") +
- convert_flow(flow) +
- annotate("</h#{level}>\n")
+ [annotate("<h#{level}>"),
+ convert_flow(flow),
+ annotate("</h#{level}>\n")].join
end
- def html_list_name(list_type, is_open_tag)
- tags = LIST_TYPE_TO_HTML[list_type] || raise("Invalid list type: #{list_type.inspect}")
- annotate(tags[ is_open_tag ? 0 : 1])
- end
+ ##
+ # Determins the HTML list element for +list_type+ and +open_tag+
- def list_item_start(am, fragment)
- case fragment.type
- when :BULLET, :NUMBER then
- annotate("<li>")
+ def html_list_name(list_type, open_tag)
+ tags = LIST_TYPE_TO_HTML[list_type]
+ raise RDoc::Error, "Invalid list type: #{list_type.inspect}" unless tags
+ annotate tags[open_tag ? 0 : 1]
+ end
- when :UPPERALPHA then
- annotate("<li type=\"A\">")
+ ##
+ # Starts a list item
- when :LOWERALPHA then
- annotate("<li type=\"a\">")
+ def list_item_start(list_item, list_type)
+ case list_type
+ when :BULLET, :LALPHA, :NUMBER, :UALPHA then
+ annotate("<li>")
- when :LABELED then
+ when :LABEL then
annotate("<dt>") +
- convert_flow(am.flow(fragment.param)) +
+ convert_flow(@am.flow(list_item.label)) +
annotate("</dt>") +
annotate("<dd>")
when :NOTE then
annotate("<tr>") +
annotate("<td valign=\"top\">") +
- convert_flow(am.flow(fragment.param)) +
+ convert_flow(@am.flow(list_item.label)) +
annotate("</td>") +
annotate("<td>")
else
- raise "Invalid list type"
+ raise RDoc::Error, "Invalid list type: #{list_type.inspect}"
end
end
- def list_end_for(fragment_type)
- case fragment_type
- when :BULLET, :NUMBER, :UPPERALPHA, :LOWERALPHA then
+ ##
+ # Ends a list item
+
+ def list_end_for(list_type)
+ case list_type
+ when :BULLET, :LALPHA, :NUMBER, :UALPHA then
"</li>"
- when :LABELED then
+ when :LABEL then
"</dd>"
when :NOTE then
"</td></tr>"
else
- raise "Invalid list type"
+ raise RDoc::Error, "Invalid list type: #{list_type.inspect}"
end
end
diff --git a/lib/rdoc/markup/to_html_crossref.rb b/lib/rdoc/markup/to_html_crossref.rb
index 930218b..1f62ee0 100644
--- a/lib/rdoc/markup/to_html_crossref.rb
+++ b/lib/rdoc/markup/to_html_crossref.rb
@@ -1,44 +1,35 @@
require 'rdoc/markup/to_html'
##
-# Subclass of the RDoc::Markup::ToHtml class that supports looking up words in
-# the AllReferences list. Those that are found (like AllReferences in this
-# comment) will be hyperlinked
+# Subclass of the RDoc::Markup::ToHtml class that supports looking up words
+# from a context. Those that are found will be hyperlinked.
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.
+ ##
+ # Regular expression to match class references
#
- # The markup/cross-referencing engine needs a rewrite for
- # Fortran 95 to be supported properly.
+ # 1) There can be a '\' in front of text to suppress any cross-references
+ # 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
+
CLASS_REGEXP_STR = '\\\\?((?:\:{2})?[A-Z]\w*(?:\:\:\w+)*)'
- METHOD_REGEXP_STR = '(\w+[!?=]?)(?:\([\.\w+\*\/\+\-\=\<\>]*\))?'
+ ##
+ # Regular expression to match method references.
+ #
+ # See CLASS_REGEXP_STR
+
+ 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.
+ # 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}
@@ -72,8 +63,14 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
)/x
##
- # We need to record the html path of our caller so we can generate
- # correct relative paths for any hyperlinks that we find
+ # RDoc::CodeObject for generating references
+
+ attr_accessor :context
+
+ ##
+ # Creates a new crossref resolver that generates links relative to +context+
+ # which lives at +from_path+ in the generated files. '#' characters on
+ # references are removed unless +show_hash+ is true.
def initialize(from_path, context, show_hash)
raise ArgumentError, 'from_path cannot be nil' if from_path.nil?
@@ -89,19 +86,18 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
end
##
- # We're invoked when any text matches the CROSSREF pattern
- # (defined in MarkUp). If we fine the corresponding reference,
- # generate a hyperlink. If the name we're looking for contains
- # no punctuation, we look for it up the module/class chain. For
- # example, HyperlinkHtml is found, even without the Generator::
- # prefix, because we look for it in module Generator first.
+ # We're invoked when any text matches the CROSSREF pattern (defined in
+ # MarkUp). If we find the corresponding reference, generate a hyperlink.
+ # If the name we're looking for contains no punctuation, we look for it up
+ # the module/class chain. For example, HyperlinkHtml is found, even without
+ # the Generator:: prefix, because we look for it in module Generator first.
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)
+ # 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
@@ -113,7 +109,6 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
lookup = name
end
-
# Find class, module, or method in class or module.
#
# Do not, however, use an if/elsif/else chain to do so. Instead, test
@@ -132,7 +127,9 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
ref = @context.find_symbol lookup unless ref
- out = if lookup =~ /^\\/ then
+ out = if lookup == '\\' then
+ lookup
+ elsif lookup =~ /^\\/ then
$'
elsif ref and ref.document_self then
"<a href=\"#{ref.as_href(@from_path)}\">#{name}</a>"
@@ -146,3 +143,4 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
end
end
+
diff --git a/lib/rdoc/markup/to_latex.rb b/lib/rdoc/markup/to_latex.rb
deleted file mode 100644
index bbf958f..0000000
--- a/lib/rdoc/markup/to_latex.rb
+++ /dev/null
@@ -1,328 +0,0 @@
-require 'rdoc/markup/formatter'
-require 'rdoc/markup/fragments'
-require 'rdoc/markup/inline'
-
-require 'cgi'
-
-##
-# Convert SimpleMarkup to basic LaTeX report format.
-
-class RDoc::Markup::ToLaTeX < RDoc::Markup::Formatter
-
- BS = "\020" # \
- OB = "\021" # {
- CB = "\022" # }
- DL = "\023" # Dollar
-
- BACKSLASH = "#{BS}symbol#{OB}92#{CB}"
- HAT = "#{BS}symbol#{OB}94#{CB}"
- BACKQUOTE = "#{BS}symbol#{OB}0#{CB}"
- TILDE = "#{DL}#{BS}sim#{DL}"
- LESSTHAN = "#{DL}<#{DL}"
- GREATERTHAN = "#{DL}>#{DL}"
-
- def self.l(str)
- str.tr('\\', BS).tr('{', OB).tr('}', CB).tr('$', DL)
- end
-
- def l(arg)
- RDoc::Markup::ToLaTeX.l(arg)
- end
-
- LIST_TYPE_TO_LATEX = {
- :BULLET => [ l("\\begin{itemize}"), l("\\end{itemize}") ],
- :NUMBER => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\arabic" ],
- :UPPERALPHA => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\Alph" ],
- :LOWERALPHA => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\alph" ],
- :LABELED => [ l("\\begin{description}"), l("\\end{description}") ],
- :NOTE => [
- l("\\begin{tabularx}{\\linewidth}{@{} l X @{}}"),
- l("\\end{tabularx}") ],
- }
-
- InlineTag = Struct.new(:bit, :on, :off)
-
- def initialize
- init_tags
- @list_depth = 0
- @prev_list_types = []
- end
-
- ##
- # Set up the standard mapping of attributes to LaTeX
-
- def init_tags
- @attr_tags = [
- InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:BOLD), l("\\textbf{"), l("}")),
- InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:TT), l("\\texttt{"), l("}")),
- InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:EM), l("\\emph{"), l("}")),
- ]
- end
-
- ##
- # Escape a LaTeX string
-
- def escape(str)
- $stderr.print "FE: ", str if $DEBUG_RDOC
- s = str.
- sub(/\s+$/, '').
- gsub(/([_\${}&%#])/, "#{BS}\\1").
- gsub(/\\/, BACKSLASH).
- gsub(/\^/, HAT).
- gsub(/~/, TILDE).
- gsub(/</, LESSTHAN).
- gsub(/>/, GREATERTHAN).
- gsub(/,,/, ",{},").
- gsub(/\`/, BACKQUOTE)
- $stderr.print "-> ", s, "\n" if $DEBUG_RDOC
- s
- end
-
- ##
- # Add a new set of LaTeX tags for an attribute. We allow
- # separate start and end tags for flexibility
-
- def add_tag(name, start, stop)
- @attr_tags << InlineTag.new(RDoc::Markup::Attribute.bitmap_for(name), start, stop)
- end
-
- ##
- # Here's the client side of the visitor pattern
-
- def start_accepting
- @res = ""
- @in_list_entry = []
- end
-
- def end_accepting
- @res.tr(BS, '\\').tr(OB, '{').tr(CB, '}').tr(DL, '$')
- end
-
- def accept_paragraph(am, fragment)
- @res << wrap(convert_flow(am.flow(fragment.txt)))
- @res << "\n"
- end
-
- def accept_verbatim(am, fragment)
- @res << "\n\\begin{code}\n"
- @res << fragment.txt.sub(/[\n\s]+\Z/, '')
- @res << "\n\\end{code}\n\n"
- end
-
- def accept_rule(am, fragment)
- size = fragment.param
- size = 10 if size > 10
- @res << "\n\n\\rule{\\linewidth}{#{size}pt}\n\n"
- end
-
- def accept_list_start(am, fragment)
- @res << list_name(fragment.type, true) << "\n"
- @in_list_entry.push false
- end
-
- def accept_list_end(am, fragment)
- if tag = @in_list_entry.pop
- @res << tag << "\n"
- end
- @res << list_name(fragment.type, false) << "\n"
- end
-
- def accept_list_item(am, fragment)
- if tag = @in_list_entry.last
- @res << tag << "\n"
- end
- @res << list_item_start(am, fragment)
- @res << wrap(convert_flow(am.flow(fragment.txt))) << "\n"
- @in_list_entry[-1] = list_end_for(fragment.type)
- end
-
- def accept_blank_line(am, fragment)
- # @res << "\n"
- end
-
- def accept_heading(am, fragment)
- @res << convert_heading(fragment.head_level, am.flow(fragment.txt))
- end
-
- ##
- # This is a higher speed (if messier) version of wrap
-
- def wrap(txt, line_len = 76)
- res = ""
- sp = 0
- ep = txt.length
- while sp < ep
- # scan back for a space
- p = sp + line_len - 1
- if p >= ep
- p = ep
- else
- while p > sp and txt[p] != ?\s
- p -= 1
- end
- if p <= sp
- p = sp + line_len
- while p < ep and txt[p] != ?\s
- p += 1
- end
- end
- end
- res << txt[sp...p] << "\n"
- sp = p
- sp += 1 while sp < ep and txt[sp] == ?\s
- end
- res
- end
-
- private
-
- def on_tags(res, item)
- attr_mask = item.turn_on
- return if attr_mask.zero?
-
- @attr_tags.each do |tag|
- if attr_mask & tag.bit != 0
- res << tag.on
- end
- end
- end
-
- def off_tags(res, item)
- attr_mask = item.turn_off
- return if attr_mask.zero?
-
- @attr_tags.reverse_each do |tag|
- if attr_mask & tag.bit != 0
- res << tag.off
- end
- end
- end
-
- def convert_flow(flow)
- res = ""
- flow.each do |item|
- case item
- when String
- $stderr.puts "Converting '#{item}'" if $DEBUG_RDOC
- res << convert_string(item)
- when AttrChanger
- off_tags(res, item)
- on_tags(res, item)
- when Special
- res << convert_special(item)
- else
- raise "Unknown flow element: #{item.inspect}"
- end
- end
- res
- end
-
- ##
- # some of these patterns are taken from SmartyPants...
-
- def convert_string(item)
- escape(item).
-
- # convert ... to elipsis (and make sure .... becomes .<elipsis>)
- gsub(/\.\.\.\./, '.\ldots{}').gsub(/\.\.\./, '\ldots{}').
-
- # convert single closing quote
- gsub(%r{([^ \t\r\n\[\{\(])\'}, '\1\'').
- gsub(%r{\'(?=\W|s\b)}, "'" ).
-
- # convert single opening quote
- gsub(/'/, '`').
-
- # convert double closing quote
- gsub(%r{([^ \t\r\n\[\{\(])\"(?=\W)}, "\\1''").
-
- # convert double opening quote
- gsub(/"/, "``").
-
- # convert copyright
- gsub(/\(c\)/, '\copyright{}')
-
- end
-
- def convert_special(special)
- handled = false
- Attribute.each_name_of(special.type) do |name|
- method_name = "handle_special_#{name}"
- if self.respond_to? method_name
- special.text = send(method_name, special)
- handled = true
- end
- end
- raise "Unhandled special: #{special}" unless handled
- special.text
- end
-
- def convert_heading(level, flow)
- res =
- case level
- when 1 then "\\chapter{"
- when 2 then "\\section{"
- when 3 then "\\subsection{"
- when 4 then "\\subsubsection{"
- else "\\paragraph{"
- end +
- convert_flow(flow) +
- "}\n"
- end
-
- def list_name(list_type, is_open_tag)
- tags = LIST_TYPE_TO_LATEX[list_type] || raise("Invalid list type: #{list_type.inspect}")
- if tags[2] # enumerate
- if is_open_tag
- @list_depth += 1
- if @prev_list_types[@list_depth] != tags[2]
- case @list_depth
- when 1
- roman = "i"
- when 2
- roman = "ii"
- when 3
- roman = "iii"
- when 4
- roman = "iv"
- else
- raise("Too deep list: level #{@list_depth}")
- end
- @prev_list_types[@list_depth] = tags[2]
- return l("\\renewcommand{\\labelenum#{roman}}{#{tags[2]}{enum#{roman}}}") + "\n" + tags[0]
- end
- else
- @list_depth -= 1
- end
- end
- tags[ is_open_tag ? 0 : 1]
- end
-
- def list_item_start(am, fragment)
- case fragment.type
- when :BULLET, :NUMBER, :UPPERALPHA, :LOWERALPHA then
- "\\item "
-
- when :LABELED then
- "\\item[" + convert_flow(am.flow(fragment.param)) + "] "
-
- when :NOTE then
- convert_flow(am.flow(fragment.param)) + " & "
- else
- raise "Invalid list type"
- end
- end
-
- def list_end_for(fragment_type)
- case fragment_type
- when :BULLET, :NUMBER, :UPPERALPHA, :LOWERALPHA, :LABELED then
- ""
- when :NOTE
- "\\\\\n"
- else
- raise "Invalid list type"
- end
- end
-
-end
-
diff --git a/lib/rdoc/markup/to_rdoc.rb b/lib/rdoc/markup/to_rdoc.rb
new file mode 100644
index 0000000..97c7d0c
--- /dev/null
+++ b/lib/rdoc/markup/to_rdoc.rb
@@ -0,0 +1,243 @@
+require 'rdoc/markup/inline'
+
+##
+# Outputs RDoc markup as RDoc markup! (mostly)
+
+class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
+
+ attr_accessor :indent
+ attr_reader :list_index
+ attr_reader :list_type
+ attr_reader :list_width
+ attr_reader :prefix
+ attr_reader :res
+
+ def initialize
+ super
+
+ @markup.add_special(/\\[^\s]/, :SUPPRESSED_CROSSREF)
+
+ @width = 78
+ @prefix = ''
+
+ init_tags
+
+ @headings = {}
+ @headings.default = []
+
+ @headings[1] = ['= ', '']
+ @headings[2] = ['== ', '']
+ @headings[3] = ['=== ', '']
+ @headings[4] = ['==== ', '']
+ @headings[5] = ['===== ', '']
+ @headings[6] = ['====== ', '']
+ end
+
+ ##
+ # Maps attributes to ANSI sequences
+
+ def init_tags
+ add_tag :BOLD, "<b>", "</b>"
+ add_tag :TT, "<tt>", "</tt>"
+ add_tag :EM, "<em>", "</em>"
+ end
+
+ def accept_blank_line blank_line
+ @res << "\n"
+ end
+
+ def accept_heading heading
+ use_prefix or @res << ' ' * @indent
+ @res << @headings[heading.level][0]
+ @res << attributes(heading.text)
+ @res << @headings[heading.level][1]
+ @res << "\n"
+ end
+
+ def accept_list_end list
+ @list_index.pop
+ @list_type.pop
+ @list_width.pop
+ end
+
+ def accept_list_item_end list_item
+ width = case @list_type.last
+ when :BULLET then
+ 2
+ when :NOTE, :LABEL then
+ @res << "\n"
+ 2
+ else
+ bullet = @list_index.last.to_s
+ @list_index[-1] = @list_index.last.succ
+ bullet.length + 2
+ end
+
+ @indent -= width
+ end
+
+ def accept_list_item_start list_item
+ bullet = case @list_type.last
+ when :BULLET then
+ '*'
+ when :NOTE, :LABEL then
+ attributes(list_item.label) + ":\n"
+ else
+ @list_index.last.to_s + '.'
+ end
+
+ case @list_type.last
+ when :NOTE, :LABEL then
+ @indent += 2
+ @prefix = bullet + (' ' * @indent)
+ else
+ @prefix = (' ' * @indent) + bullet.ljust(bullet.length + 1)
+
+ width = bullet.length + 1
+
+ @indent += width
+ end
+ end
+
+ def accept_list_start list
+ case list.type
+ when :BULLET then
+ @list_index << nil
+ @list_width << 1
+ when :LABEL, :NOTE then
+ @list_index << nil
+ @list_width << 2
+ when :LALPHA then
+ @list_index << 'a'
+ @list_width << list.items.length.to_s.length
+ when :NUMBER then
+ @list_index << 1
+ @list_width << list.items.length.to_s.length
+ when :UALPHA then
+ @list_index << 'A'
+ @list_width << list.items.length.to_s.length
+ else
+ raise RDoc::Error, "invalid list type #{list.type}"
+ end
+
+ @list_type << list.type
+ end
+
+ def accept_paragraph paragraph
+ wrap attributes(paragraph.text)
+ end
+
+ def accept_rule rule
+ use_prefix or @res << ' ' * @indent
+ @res << '-' * (@width - @indent)
+ @res << "\n"
+ end
+
+ ##
+ # Outputs +verbatim+ flush left and indented 2 columns
+
+ def accept_verbatim verbatim
+ indent = ' ' * (@indent + 2)
+
+ lines = []
+ current_line = []
+
+ # split into lines
+ verbatim.parts.each do |part|
+ current_line << part
+
+ if part == "\n" then
+ lines << current_line
+ current_line = []
+ end
+ end
+
+ lines << current_line unless current_line.empty?
+
+ # calculate margin
+ indented = lines.select { |line| line != ["\n"] }
+ margin = indented.map { |line| line.first.length }.min
+
+ # flush left
+ indented.each { |line| line[0][0...margin] = '' }
+
+ # output
+ use_prefix or @res << indent # verbatim is unlikely to have prefix
+ @res << lines.shift.join
+
+ lines.each do |line|
+ @res << indent unless line == ["\n"]
+ @res << line.join
+ end
+
+ @res << "\n"
+ end
+
+ def attributes text
+ flow = @am.flow text.dup
+ convert_flow flow
+ end
+
+ def end_accepting
+ @res.join
+ end
+
+ def handle_special_SUPPRESSED_CROSSREF special
+ special.text.sub(/\\/, '')
+ end
+
+ def start_accepting
+ @res = [""]
+ @indent = 0
+ @prefix = nil
+
+ @list_index = []
+ @list_type = []
+ @list_width = []
+ end
+
+ def use_prefix
+ prefix = @prefix
+ @prefix = nil
+ @res << prefix if prefix
+
+ prefix
+ end
+
+ def wrap text
+ return unless text && !text.empty?
+
+ text_len = @width - @indent
+
+ text_len = 20 if text_len < 20
+
+ re = /^(.{0,#{text_len}})[ \n]/
+ next_prefix = ' ' * @indent
+
+ prefix = @prefix || next_prefix
+ @prefix = nil
+
+ @res << prefix
+
+ while text.length > text_len
+ if text =~ re then
+ @res << $1
+ text.slice!(0, $&.length)
+ else
+ @res << text.slice!(0, text_len)
+ end
+
+ @res << "\n" << next_prefix
+ end
+
+ if text.empty? then
+ @res.pop
+ @res.pop
+ else
+ @res << text
+ @res << "\n"
+ end
+ end
+
+end
+
diff --git a/lib/rdoc/markup/to_test.rb b/lib/rdoc/markup/to_test.rb
index ce6aff6..0afdb96 100644
--- a/lib/rdoc/markup/to_test.rb
+++ b/lib/rdoc/markup/to_test.rb
@@ -6,44 +6,58 @@ require 'rdoc/markup/formatter'
class RDoc::Markup::ToTest < RDoc::Markup::Formatter
+ ##
+ # :section: Visitor
+
def start_accepting
@res = []
+ @list = []
end
def end_accepting
@res
end
- def accept_paragraph(am, fragment)
- @res << fragment.to_s
+ def accept_paragraph(paragraph)
+ @res << paragraph.text
+ end
+
+ def accept_verbatim(verbatim)
+ @res << verbatim.text
end
- def accept_verbatim(am, fragment)
- @res << fragment.to_s
+ def accept_list_start(list)
+ @list << case list.type
+ when :BULLET then
+ '*'
+ when :NUMBER then
+ '1'
+ else
+ list.type
+ end
end
- def accept_list_start(am, fragment)
- @res << fragment.to_s
+ def accept_list_end(list)
+ @list.pop
end
- def accept_list_end(am, fragment)
- @res << fragment.to_s
+ def accept_list_item_start(list_item)
+ @res << "#{' ' * (@list.size - 1)}#{@list.last}: "
end
- def accept_list_item(am, fragment)
- @res << fragment.to_s
+ def accept_list_item_end(list_item)
end
- def accept_blank_line(am, fragment)
- @res << fragment.to_s
+ def accept_blank_line(blank_line)
+ @res << "\n"
end
- def accept_heading(am, fragment)
- @res << fragment.to_s
+ def accept_heading(heading)
+ @res << "#{'=' * heading.level} #{heading.text}"
end
- def accept_rule(am, fragment)
- @res << fragment.to_s
+ def accept_rule(rule)
+ @res << '-' * rule.weight
end
end
diff --git a/lib/rdoc/markup/to_texinfo.rb b/lib/rdoc/markup/to_texinfo.rb
deleted file mode 100644
index 65a1608..0000000
--- a/lib/rdoc/markup/to_texinfo.rb
+++ /dev/null
@@ -1,69 +0,0 @@
-require 'rdoc/markup/formatter'
-require 'rdoc/markup/fragments'
-require 'rdoc/markup/inline'
-
-require 'rdoc/markup'
-require 'rdoc/markup/formatter'
-
-##
-# Convert SimpleMarkup to basic TexInfo format
-#
-# TODO: WTF is AttributeManager for?
-#
-class RDoc::Markup::ToTexInfo < RDoc::Markup::Formatter
-
- def start_accepting
- @text = []
- end
-
- def end_accepting
- @text.join("\n")
- end
-
- def accept_paragraph(attributes, text)
- @text << format(text)
- end
-
- def accept_verbatim(attributes, text)
- @text << "@verb{|#{format(text)}|}"
- end
-
- def accept_heading(attributes, text)
- heading = ['@majorheading', '@chapheading'][text.head_level - 1] || '@heading'
- @text << "#{heading} #{format(text)}"
- end
-
- def accept_list_start(attributes, text)
- @text << '@itemize @bullet'
- end
-
- def accept_list_end(attributes, text)
- @text << '@end itemize'
- end
-
- def accept_list_item(attributes, text)
- @text << "@item\n#{format(text)}"
- end
-
- def accept_blank_line(attributes, text)
- @text << "\n"
- end
-
- def accept_rule(attributes, text)
- @text << '-----'
- end
-
- def format(text)
- text.txt.
- gsub(/@/, "@@").
- gsub(/\{/, "@{").
- gsub(/\}/, "@}").
- # gsub(/,/, "@,"). # technically only required in cross-refs
- gsub(/\+([\w]+)\+/, "@code{\\1}").
- gsub(/\<tt\>([^<]+)\<\/tt\>/, "@code{\\1}").
- gsub(/\*([\w]+)\*/, "@strong{\\1}").
- gsub(/\<b\>([^<]+)\<\/b\>/, "@strong{\\1}").
- gsub(/_([\w]+)_/, "@emph{\\1}").
- gsub(/\<em\>([^<]+)\<\/em\>/, "@emph{\\1}")
- end
-end
diff --git a/lib/rdoc/markup/verbatim.rb b/lib/rdoc/markup/verbatim.rb
new file mode 100644
index 0000000..faf539a
--- /dev/null
+++ b/lib/rdoc/markup/verbatim.rb
@@ -0,0 +1,42 @@
+##
+# A section of verbatim text
+
+class RDoc::Markup::Verbatim < RDoc::Markup::Paragraph
+
+ def accept visitor
+ visitor.accept_verbatim self
+ end
+
+ ##
+ # Collapses 3+ newlines into two newlines
+
+ def normalize
+ parts = []
+
+ newlines = 0
+
+ @parts.each do |part|
+ case part
+ when /\n/ then
+ newlines += 1
+ parts << part if newlines <= 2
+ else
+ newlines = 0
+ parts << part
+ end
+ end
+
+ parts.slice!(-1) if parts[-2..-1] == ["\n", "\n"]
+
+ @parts = parts
+ end
+
+ ##
+ # The text of the section
+
+ def text
+ @parts.join
+ end
+
+end
+
diff --git a/lib/rdoc/meta_method.rb b/lib/rdoc/meta_method.rb
new file mode 100644
index 0000000..e0c065c
--- /dev/null
+++ b/lib/rdoc/meta_method.rb
@@ -0,0 +1,8 @@
+require 'rdoc/any_method'
+
+##
+# MetaMethod represents a meta-programmed method
+
+class RDoc::MetaMethod < RDoc::AnyMethod
+end
+
diff --git a/lib/rdoc/normal_class.rb b/lib/rdoc/normal_class.rb
new file mode 100644
index 0000000..e7ca6ff
--- /dev/null
+++ b/lib/rdoc/normal_class.rb
@@ -0,0 +1,55 @@
+require 'rdoc/class_module'
+
+##
+# A normal class, neither singleton nor anonymous
+
+class RDoc::NormalClass < RDoc::ClassModule
+
+ ##
+ # Ancestor ClassModules
+
+ def ancestors
+ includes + [superclass]
+ end
+
+ def inspect # :nodoc:
+ superclass = @superclass ? " < #{@superclass}" : nil
+ "<%s:0x%x class %s%s includes: %p attributes: %p methods: %p aliases: %p>" % [
+ self.class, object_id,
+ full_name, superclass, @includes, @attributes, @method_list, @aliases
+ ]
+ end
+
+ def pretty_print q # :nodoc:
+ superclass = @superclass ? " < #{@superclass}" : nil
+
+ q.group 2, "[class #{full_name}#{superclass} ", "]" do
+ q.breakable
+ q.text "includes:"
+ q.breakable
+ q.seplist @includes do |inc| q.pp inc end
+
+ q.breakable
+ q.text "attributes:"
+ q.breakable
+ q.seplist @attributes do |inc| q.pp inc end
+
+ q.breakable
+ q.text "methods:"
+ q.breakable
+ q.seplist @method_list do |inc| q.pp inc end
+
+ q.breakable
+ q.text "aliases:"
+ q.breakable
+ q.seplist @aliases do |inc| q.pp inc end
+
+ q.breakable
+ q.text "comment:"
+ q.breakable
+ q.pp comment
+ end
+ end
+
+end
+
diff --git a/lib/rdoc/normal_module.rb b/lib/rdoc/normal_module.rb
new file mode 100644
index 0000000..92abe6b
--- /dev/null
+++ b/lib/rdoc/normal_module.rb
@@ -0,0 +1,64 @@
+require 'rdoc/class_module'
+
+##
+# A normal module, like NormalClass
+
+class RDoc::NormalModule < RDoc::ClassModule
+
+ ##
+ # Included NormalModules
+
+ alias ancestors includes
+
+ def inspect # :nodoc:
+ "#<%s:0x%x module %s includes: %p attributes: %p methods: %p aliases: %p>" % [
+ self.class, object_id,
+ full_name, @includes, @attributes, @method_list, @aliases
+ ]
+ end
+
+ ##
+ # This is a module, returns true
+
+ def module?
+ true
+ end
+
+ def pretty_print q # :nodoc:
+ q.group 2, "[module #{full_name}: ", "]" do
+ q.breakable
+ q.text "includes:"
+ q.breakable
+ q.seplist @includes do |inc| q.pp inc end
+ q.breakable
+
+ q.text "attributes:"
+ q.breakable
+ q.seplist @attributes do |inc| q.pp inc end
+ q.breakable
+
+ q.text "methods:"
+ q.breakable
+ q.seplist @method_list do |inc| q.pp inc end
+ q.breakable
+
+ q.text "aliases:"
+ q.breakable
+ q.seplist @aliases do |inc| q.pp inc end
+ q.breakable
+
+ q.text "comment:"
+ q.breakable
+ q.pp comment
+ end
+ end
+
+ ##
+ # Modules don't have one, raises NoMethodError
+
+ def superclass
+ raise NoMethodError, "#{full_name} is a module"
+ end
+
+end
+
diff --git a/lib/rdoc/options.rb b/lib/rdoc/options.rb
index 2b069f4..e4616f2 100644
--- a/lib/rdoc/options.rb
+++ b/lib/rdoc/options.rb
@@ -1,15 +1,11 @@
-# We handle the parsing of options, and subsequently as a singleton
-# object to be queried for option values
-
-require "rdoc/ri/paths"
require 'optparse'
-class RDoc::Options
+require 'rdoc/ri/paths'
- ##
- # Should the output be placed into a single file
+##
+# RDoc::Options handles the parsing and storage of options
- attr_reader :all_one_file
+class RDoc::Options
##
# Character-set
@@ -17,36 +13,11 @@ class RDoc::Options
attr_reader :charset
##
- # URL of stylesheet
-
- attr_reader :css
-
- ##
- # Should diagrams be drawn
-
- attr_reader :diagram
-
- ##
# Files matching this pattern will be excluded
attr_accessor :exclude
##
- # Additional attr_... style method flags
-
- attr_reader :extra_accessor_flags
-
- ##
- # Pattern for additional attr_... style methods
-
- attr_accessor :extra_accessors
-
- ##
- # Should we draw fileboxes in diagrams
-
- attr_reader :fileboxes
-
- ##
# The list of files to be processed
attr_accessor :files
@@ -67,45 +38,20 @@ class RDoc::Options
attr_accessor :formatter
##
- # image format for diagrams
-
- attr_reader :image_format
-
- ##
- # Include line numbers in the source listings
-
- attr_reader :include_line_numbers
-
- ##
- # Should source code be included inline, or displayed in a popup
-
- attr_accessor :inline_source
-
- ##
# Name of the file, class or module to display in the initial index page (if
# not specified the first file we encounter is used)
attr_accessor :main_page
##
- # Merge into classes of the same name when generating ri
-
- attr_reader :merge
-
- ##
# The name of the output directory
attr_accessor :op_dir
##
- # The name to use for the output
-
- attr_accessor :op_name
-
- ##
- # Are we promiscuous about showing module contents across multiple files
+ # Is RDoc in pipe mode?
- attr_reader :promiscuous
+ attr_accessor :pipe
##
# Array of directories to search for files to satisfy an :include:
@@ -113,7 +59,7 @@ class RDoc::Options
attr_reader :rdoc_include
##
- # Include private and protected methods in the output
+ # Include private and protected methods in the output?
attr_accessor :show_all
@@ -128,18 +74,11 @@ class RDoc::Options
attr_reader :tab_width
##
- # template to be used when generating output
+ # Template to be used when generating output
attr_reader :template
##
- # Template class for file generation
- #--
- # HACK around dependencies in lib/rdoc/generator/html.rb
-
- attr_accessor :template_class # :nodoc:
-
- ##
# Documentation title
attr_reader :title
@@ -154,34 +93,24 @@ class RDoc::Options
attr_reader :webcvs
- def initialize(generators = {}) # :nodoc:
- @op_dir = "doc"
- @op_name = nil
+ def initialize # :nodoc:
+ require 'rdoc/rdoc'
+ @op_dir = nil
@show_all = false
@main_page = nil
- @merge = false
@exclude = []
- @generators = generators
- @generator_name = 'html'
- @generator = @generators[@generator_name]
+ @generators = RDoc::RDoc::GENERATORS
+ @generator = RDoc::Generator::Darkfish
+ @generator_name = nil
@rdoc_include = []
@title = nil
@template = nil
- @template_class = nil
- @diagram = false
- @fileboxes = false
@show_hash = false
- @image_format = 'png'
- @inline_source = false
- @all_one_file = false
@tab_width = 8
- @include_line_numbers = false
- @extra_accessor_flags = {}
- @promiscuous = false
- @force_update = false
+ @force_update = true
@verbosity = 1
+ @pipe = false
- @css = nil
@webcvs = nil
@charset = 'utf-8'
@@ -191,7 +120,7 @@ class RDoc::Options
# Parse command line options.
def parse(argv)
- accessors = []
+ ignore_invalid = true
opts = OptionParser.new do |opt|
opt.program_name = File.basename $0
@@ -210,44 +139,26 @@ Usage: #{opt.program_name} [options] [names...]
How RDoc generates output depends on the output formatter being used, and on
the options you give.
- - HTML output is normally produced into a number of separate files
- (one per class, module, and file, along with various indices).
- These files will appear in the directory given by the --op
- option (doc/ by default).
+ - Darkfish creates frameless HTML output by Michael Granger.
+ - ri creates ri data files
- - XML output by default is written to standard output. If a
- --opname option is given, the output will instead be written
- to a file with that name in the output directory.
+ RDoc understands the following file formats:
- - .chm files (Windows help files) are written in the --op directory.
- If an --opname parameter is present, that name is used, otherwise
- the file will be called rdoc.chm.
EOF
- opt.separator nil
- opt.separator "Options:"
- opt.separator nil
+ parsers = Hash.new { |h,parser| h[parser] = [] }
- opt.on("--accessor=ACCESSORS", "-A", Array,
- "A comma separated list of additional class",
- "methods that should be treated like",
- "'attr_reader' and friends.",
- " ",
- "Option may be repeated.",
- " ",
- "Each accessorname may have '=text'",
- "appended, in which case that text appears",
- "where the r/w/rw appears for normal.",
- "accessors") do |value|
- value.each do |accessor|
- if accessor =~ /^(\w+)(=(.*))?$/
- accessors << $1
- @extra_accessor_flags[$1] = $3
- end
- end
+ RDoc::Parser.parsers.each do |regexp, parser|
+ parsers[parser.name.sub('RDoc::Parser::', '')] << regexp.source
+ end
+
+ parsers.sort.each do |parser, regexp|
+ opt.banner << " - #{parser}: #{regexp.join ', '}\n"
end
opt.separator nil
+ opt.separator "Parsing Options:"
+ opt.separator nil
opt.on("--all", "-a",
"Include all methods (not just public) in",
@@ -257,31 +168,6 @@ Usage: #{opt.program_name} [options] [names...]
opt.separator nil
- opt.on("--charset=CHARSET", "-c",
- "Specifies the output HTML character-set.") do |value|
- @charset = value
- end
-
- opt.separator nil
-
- opt.on("--debug", "-D",
- "Displays lots on internal stuff.") do |value|
- $DEBUG_RDOC = value
- end
-
- opt.separator nil
-
- opt.on("--diagram", "-d",
- "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") do |value|
- check_diagram
- @diagram = true
- end
-
- opt.separator nil
-
opt.on("--exclude=PATTERN", "-x", Regexp,
"Do not process files or directories",
"matching PATTERN.") do |value|
@@ -300,25 +186,13 @@ Usage: #{opt.program_name} [options] [names...]
raise OptionParser::InvalidArgument, "Invalid parameter to '-E'"
end
- unless RDoc::ParserFactory.alias_extension old, new then
+ unless RDoc::Parser.alias_extension old, new then
raise OptionParser::InvalidArgument, "Unknown extension .#{old} to -E"
end
end
opt.separator nil
- opt.on("--fileboxes", "-F",
- "Classes are put in boxes which represents",
- "files, where these classes reside. Classes",
- "shared between more than one file are",
- "shown with list of files that are sharing",
- "them. Silently discarded if --diagram is",
- "not given.") do |value|
- @fileboxes = value
- end
-
- opt.separator nil
-
opt.on("--force-update", "-U",
"Forces rdoc to scan all sources even if",
"newer than the flag file.") do |value|
@@ -327,45 +201,37 @@ Usage: #{opt.program_name} [options] [names...]
opt.separator nil
- opt.on("--fmt=FORMAT", "--format=FORMAT", "-f", @generators.keys,
- "Set the output formatter.") do |value|
- @generator_name = value.downcase
- setup_generator
+ opt.on("--pipe",
+ "Convert RDoc on stdin to HTML") do
+ @pipe = true
end
opt.separator nil
-
- image_formats = %w[gif png jpg jpeg]
- opt.on("--image-format=FORMAT", "-I", image_formats,
- "Sets output image format for diagrams. Can",
- "be #{image_formats.join ', '}. If this option",
- "is omitted, png is used. Requires",
- "diagrams.") do |value|
- @image_format = value
- end
-
+ opt.separator "Generator Options:"
opt.separator nil
- opt.on("--include=DIRECTORIES", "-i", Array,
- "set (or add to) the list of directories to",
- "be searched when satisfying :include:",
- "requests. Can be used more than once.") do |value|
- @rdoc_include.concat value.map { |dir| dir.strip }
+ opt.on("--charset=CHARSET", "-c",
+ "Specifies the output HTML character-set.") do |value|
+ @charset = value
end
opt.separator nil
- opt.on("--inline-source", "-S",
- "Show method source code inline, rather than",
- "via a popup link.") do |value|
- @inline_source = value
+ generator_text = @generators.keys.map { |name| " #{name}" }.sort
+
+ opt.on("--fmt=FORMAT", "--format=FORMAT", "-f", @generators.keys,
+ "Set the output formatter. One of:", *generator_text) do |value|
+ @generator_name = value.downcase
+ setup_generator
end
opt.separator nil
- opt.on("--line-numbers", "-N",
- "Include line numbers in the source code.") do |value|
- @include_line_numbers = value
+ opt.on("--include=DIRECTORIES", "-i", Array,
+ "Set (or add to) the list of directories to",
+ "be searched when satisfying :include:",
+ "requests. Can be used more than once.") do |value|
+ @rdoc_include.concat value.map { |dir| dir.strip }
end
opt.separator nil
@@ -377,62 +243,61 @@ Usage: #{opt.program_name} [options] [names...]
opt.separator nil
- opt.on("--merge", "-M",
- "When creating ri output, merge previously",
- "processed classes into previously",
- "documented classes of the same name.") do |value|
- @merge = value
+ opt.on("--output=DIR", "--op", "-o",
+ "Set the output directory.") do |value|
+ @op_dir = value
end
opt.separator nil
- opt.on("--one-file", "-1",
- "Put all the output into a single file.") do |value|
- @all_one_file = value
- @inline_source = value if value
- @template = 'one_page_html'
+ opt.on("--show-hash", "-H",
+ "A name of the form #name in a comment is a",
+ "possible hyperlink to an instance method",
+ "name. When displayed, the '#' is removed",
+ "unless this option is specified.") do |value|
+ @show_hash = value
end
opt.separator nil
- opt.on("--op=DIR", "-o",
- "Set the output directory.") do |value|
- @op_dir = value
+ opt.on("--tab-width=WIDTH", "-w", OptionParser::DecimalInteger,
+ "Set the width of tab characters.") do |value|
+ @tab_width = value
end
opt.separator nil
- opt.on("--opname=NAME", "-n",
- "Set the NAME of the output. Has no effect",
- "for HTML.") do |value|
- @op_name = value
+ opt.on("--template=NAME", "-T",
+ "Set the template used when generating",
+ "output.") do |value|
+ @template = value
end
opt.separator nil
- opt.on("--promiscuous", "-p",
- "When documenting a file that contains a",
- "module or class also defined in other",
- "files, show all stuff for that module or",
- "class in each files page. By default, only",
- "show stuff defined in that particular file.") do |value|
- @promiscuous = value
+ opt.on("--title=TITLE", "-t",
+ "Set TITLE as the title for HTML output.") do |value|
+ @title = value
end
opt.separator nil
- opt.on("--quiet", "-q",
- "Don't show progress as we parse.") do |value|
- @verbosity = 0
+ opt.on("--webcvs=URL", "-W",
+ "Specify a URL for linking to a web frontend",
+ "to CVS. If the URL contains a '\%s', the",
+ "name of the current file will be",
+ "substituted; if the URL doesn't contain a",
+ "'\%s', the filename will be appended to it.") do |value|
+ @webcvs = value
end
- opt.on("--verbose", "-v",
- "Display extra progress as we parse.") do |value|
- @verbosity = 2
- end
+ opt.separator nil
+ opt.on("-d", "--diagram", "Prevents -d from tripping --debug")
opt.separator nil
+ opt.separator "ri Generator Options:"
+ opt.separator nil
opt.on("--ri", "-r",
"Generate output for use by `ri`. The files",
@@ -441,7 +306,7 @@ Usage: #{opt.program_name} [options] [names...]
"subsequent --op parameter, so no special",
"privileges are needed.") do |value|
@generator_name = "ri"
- @op_dir = RDoc::RI::Paths::HOMEDIR
+ @op_dir ||= RDoc::RI::Paths::HOMEDIR
setup_generator
end
@@ -458,74 +323,49 @@ Usage: #{opt.program_name} [options] [names...]
end
opt.separator nil
-
- opt.on("--ri-system", "-Y",
- "Generate output for use by `ri`. The files",
- "are stored in a site-wide directory,",
- "making them accessible to others, so",
- "special privileges are needed. This",
- "option is intended to be used during Ruby",
- "installation.") do |value|
- @generator_name = "ri"
- @op_dir = RDoc::RI::Paths::SYSDIR
- setup_generator
- end
-
- opt.separator nil
-
- opt.on("--show-hash", "-H",
- "A name of the form #name in a comment is a",
- "possible hyperlink to an instance method",
- "name. When displayed, the '#' is removed",
- "unless this option is specified.") do |value|
- @show_hash = value
- end
-
+ opt.separator "Generic Options:"
opt.separator nil
- opt.on("--style=URL", "-s",
- "Specifies the URL of a separate stylesheet.") do |value|
- @css = value
+ opt.on("-D", "--[no-]debug",
+ "Displays lots on internal stuff.") do |value|
+ $DEBUG_RDOC = value
end
- opt.separator nil
-
- opt.on("--tab-width=WIDTH", "-w", OptionParser::DecimalInteger,
- "Set the width of tab characters.") do |value|
- @tab_width = value
+ opt.on("--[no-]ignore-invalid",
+ "Ignore invalid options and continue.") do |value|
+ ignore_invalid = value
end
- opt.separator nil
-
- opt.on("--template=NAME", "-T",
- "Set the template used when generating",
- "output.") do |value|
- @template = value
+ opt.on("--quiet", "-q",
+ "Don't show progress as we parse.") do |value|
+ @verbosity = 0
end
- opt.separator nil
-
- opt.on("--title=TITLE", "-t",
- "Set TITLE as the title for HTML output.") do |value|
- @title = value
+ opt.on("--verbose", "-v",
+ "Display extra progress as we parse.") do |value|
+ @verbosity = 2
end
opt.separator nil
-
- opt.on("--webcvs=URL", "-W",
- "Specify a URL for linking to a web frontend",
- "to CVS. If the URL contains a '\%s', the",
- "name of the current file will be",
- "substituted; if the URL doesn't contain a",
- "'\%s', the filename will be appended to it.") do |value|
- @webcvs = value
- end
end
argv.insert(0, *ENV['RDOCOPT'].split) if ENV['RDOCOPT']
- opts.parse! argv
+ begin
+ opts.parse! argv
+ rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e
+ if ignore_invalid and not quiet then
+ $stderr.puts e
+ $stderr.puts '(invalid options are ignored)'
+ else
+ $stderr.puts opts
+ $stderr.puts
+ $stderr.puts e
+ exit 1
+ end
+ end
+ @op_dir ||= 'doc'
@files = argv.dup
@rdoc_include << "." if @rdoc_include.empty?
@@ -542,18 +382,6 @@ Usage: #{opt.program_name} [options] [names...]
# formatter
@template ||= @generator_name
-
- # Generate a regexp from the accessors
- unless accessors.empty? then
- re = '^(' + accessors.map { |a| Regexp.quote a }.join('|') + ')$'
- @extra_accessors = Regexp.new re
- end
-
- rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e
- puts opts
- puts
- puts e
- exit 1
end
##
@@ -586,42 +414,6 @@ Usage: #{opt.program_name} [options] [names...]
unless @generator then
raise OptionParser::InvalidArgument, "Invalid output formatter"
end
-
- if @generator_name == "xml" then
- @all_one_file = true
- @inline_source = true
- end
- end
-
- # Check that the right version of 'dot' is available. Unfortunately this
- # doesn't work correctly under Windows NT, so we'll bypass the test under
- # Windows.
-
- def check_diagram
- return if RUBY_PLATFORM =~ /mswin|cygwin|mingw|bccwin/
-
- ok = false
- ver = nil
-
- IO.popen "dot -V 2>&1" do |io|
- ver = io.read
- if ver =~ /dot.+version(?:\s+gviz)?\s+(\d+)\.(\d+)/ then
- ok = ($1.to_i > 1) || ($1.to_i == 1 && $2.to_i >= 8)
- end
- end
-
- unless ok then
- if ver =~ /^dot.+version/ then
- $stderr.puts "Warning: You may need dot V1.8.6 or later to use\n",
- "the --diagram option correctly. You have:\n\n ",
- ver,
- "\nDiagrams might have strange background colors.\n\n"
- else
- $stderr.puts "You need the 'dot' program to produce diagrams.",
- "(see http://www.research.att.com/sw/tools/graphviz/)\n\n"
- exit
- end
- end
end
##
@@ -629,7 +421,7 @@ Usage: #{opt.program_name} [options] [names...]
def check_files
@files.each do |f|
- stat = File.stat f
+ stat = File.stat f rescue next
raise RDoc::Error, "file '#{f}' not readable" unless stat.readable?
end
end
diff --git a/lib/rdoc/parser.rb b/lib/rdoc/parser.rb
index 3798734..d29599c 100644
--- a/lib/rdoc/parser.rb
+++ b/lib/rdoc/parser.rb
@@ -22,14 +22,14 @@ require 'rdoc/stats'
# following incantation
#
# require "rdoc/parser"
-#
+#
# class RDoc::Parser::Xyz < RDoc::Parser
# parse_files_matching /\.xyz$/ # <<<<
-#
+#
# def initialize(file_name, body, options)
# ...
# end
-#
+#
# def scan
# ...
# end
@@ -63,13 +63,37 @@ class RDoc::Parser
end
##
- # Return _true_ if the +file+ seems like binary.
+ # Determines if the file is a "binary" file which basically means it has
+ # content that an RDoc parser shouldn't try to consume.
def self.binary?(file)
- s = File.read(file, 1024) or return false
- s.count("^ -~\t\r\n").fdiv(s.size) > 0.3 || s.index("\x00")
+ s = File.read(file, File.stat(file).blksize) || ""
+
+ if s[0, 2] == Marshal.dump('')[0, 2] then
+ true
+ elsif file =~ /erb\.rb$/ then
+ false
+ elsif s.scan(/<%|%>/).length >= 4 then
+ true
+ else
+ # From ptools under the Artistic License 2.0, (c) Daniel Berger.
+ s = s.split(//)
+
+ ((s.size - s.grep(" ".."~").size) / s.size.to_f) > 0.30
+ end
+ end
+
+ ##
+ # Checks if +file+ is a zip file in disguise. Signatures from
+ # http://www.garykessler.net/library/file_sigs.html
+
+ def self.zip? file
+ zip_signature = File.read file, 4
+
+ zip_signature == "PK\x03\x04" or
+ zip_signature == "PK\x05\x06" or
+ zip_signature == "PK\x07\x08"
end
- private_class_method :binary?
##
# Return a parser that can handle a particular extension
@@ -77,16 +101,13 @@ class RDoc::Parser
def self.can_parse(file_name)
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
+ # HACK Selenium hides a jar file using a .txt extension
+ return if parser == RDoc::Parser::Simple and zip? file_name
- return parser
+ # The default parser must not parse binary files
+ return if parser == RDoc::Parser::Simple and file_name !~ /\.(txt|rdoc)$/
+
+ parser
end
##
@@ -94,6 +115,8 @@ class RDoc::Parser
# for ones that we don't know
def self.for(top_level, file_name, body, options, stats)
+ return if binary? file_name
+
# If no extension, look for shebang
if file_name !~ /\.\w+$/ && body =~ %r{\A#!(.+)} then
shebang = $1
@@ -105,18 +128,15 @@ class RDoc::Parser
parser = can_parse file_name
- #
- # This method must return a parser.
- #
- if !parser then
- parser = RDoc::Parser::Simple
- end
+ return unless parser
parser.new top_level, file_name, body, options, stats
end
##
# Record which file types this parser can understand.
+ #
+ # It is ok to call this multiple times.
def self.parse_files_matching(regexp)
RDoc::Parser.parsers.unshift [regexp, self]
diff --git a/lib/rdoc/parser/c.rb b/lib/rdoc/parser/c.rb
index a2c3eef..f2d460b 100644
--- a/lib/rdoc/parser/c.rb
+++ b/lib/rdoc/parser/c.rb
@@ -14,32 +14,32 @@ require 'rdoc/known_classes'
# method, that is to say the method whose name is given in the
# <tt>rb_define_method</tt> call. For example, you might write:
#
-# /*
-# * Returns a new array that is a one-dimensional flattening of this
-# * array (recursively). That is, for every element that is an array,
-# * extract its elements into the new array.
-# *
-# * s = [ 1, 2, 3 ] #=> [1, 2, 3]
-# * t = [ 4, 5, 6, [7, 8] ] #=> [4, 5, 6, [7, 8]]
-# * a = [ s, t, 9, 10 ] #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10]
-# * a.flatten #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
-# */
-# static VALUE
-# rb_ary_flatten(ary)
-# VALUE ary;
-# {
-# ary = rb_obj_dup(ary);
-# rb_ary_flatten_bang(ary);
-# return ary;
-# }
+# /*
+# * Returns a new array that is a one-dimensional flattening of this
+# * array (recursively). That is, for every element that is an array,
+# * extract its elements into the new array.
+# *
+# * s = [ 1, 2, 3 ] #=> [1, 2, 3]
+# * t = [ 4, 5, 6, [7, 8] ] #=> [4, 5, 6, [7, 8]]
+# * a = [ s, t, 9, 10 ] #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10]
+# * a.flatten #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+# */
+# static VALUE
+# rb_ary_flatten(ary)
+# VALUE ary;
+# {
+# ary = rb_obj_dup(ary);
+# rb_ary_flatten_bang(ary);
+# return ary;
+# }
#
-# ...
+# ...
#
-# void
-# Init_Array()
-# {
-# ...
-# rb_define_method(rb_cArray, "flatten", rb_ary_flatten, 0);
+# void
+# Init_Array()
+# {
+# ...
+# rb_define_method(rb_cArray, "flatten", rb_ary_flatten, 0);
#
# Here RDoc will determine from the rb_define_method line that there's a
# method called "flatten" in class Array, and will look for the implementation
@@ -47,9 +47,6 @@ require 'rdoc/known_classes'
# method in the HTML output. This method must be in the same source file
# as the rb_define_method.
#
-# C classes can be diagrammed (see /tc/dl/ruby/ruby/error.c), and RDoc
-# integrates C and Ruby source into one tree
-#
# The comment blocks may include special directives:
#
# [Document-class: <i>name</i>]
@@ -68,7 +65,7 @@ require 'rdoc/known_classes'
# Ruby function is in the same source file as the rb_define_method call.
# If this isn't the case, add the comment:
#
-# rb_define_method(....); // in filename
+# rb_define_method(....); // in: filename
#
# As an example, we might have an extension that defines multiple classes
# in its Init_xxx method. We could document them using
@@ -79,7 +76,7 @@ require 'rdoc/known_classes'
# * Encapsulate the writing and reading of the configuration
# * file. ...
# */
-#
+#
# /*
# * Document-method: read_value
# *
@@ -96,8 +93,23 @@ class RDoc::Parser::C < RDoc::Parser
parse_files_matching(/\.(?:([CcHh])\1?|c([+xp])\2|y)\z/)
- @@enclosure_classes = {}
- @@known_bodies = {}
+ include RDoc::Text
+
+ ##
+ # C file the parser is parsing
+
+ attr_accessor :content
+
+ ##
+ # Resets cross-file state. Call when parsing different projects that need
+ # separate documentation.
+
+ def self.reset
+ @@enclosure_classes = {}
+ @@known_bodies = {}
+ end
+
+ reset
##
# Prepare to parse a C file
@@ -164,19 +176,17 @@ class RDoc::Parser::C < RDoc::Parser
def do_constants
@content.scan(%r{\Wrb_define_
- (
- variable |
- readonly_variable |
- const |
- global_const |
- )
+ ( variable |
+ readonly_variable |
+ const |
+ global_const | )
\s*\(
(?:\s*(\w+),)?
\s*"(\w+)",
\s*(.*?)\s*\)\s*;
}xm) do |type, var_name, const_name, definition|
var_name = "rb_cObject" if !var_name or var_name == "rb_mKernel"
- handle_constants(type, var_name, const_name, definition)
+ handle_constants type, var_name, const_name, definition
end
end
@@ -270,12 +280,13 @@ class RDoc::Parser::C < RDoc::Parser
def find_body(class_name, meth_name, meth_obj, body, quiet = false)
case body
- when %r"((?>/\*.*?\*/\s*))(?:(?:static|SWIGINTERN)\s+)?(?:intern\s+)?VALUE\s+#{meth_name}
- \s*(\([^)]*\))([^;]|$)"xm
- comment, params = $1, $2
- body_text = $&
+ when %r"((?>/\*.*?\*/\s*))((?:(?:static|SWIGINTERN)\s+)?(?:intern\s+)?VALUE\s+#{meth_name}
+ \s*(\([^)]*\))([^;]|$))"xm
+ comment = $1
+ body_text = $2
+ params = $3
- remove_private_comments(comment) if comment
+ remove_private_comments comment if comment
# see if we can find the whole body
@@ -288,33 +299,40 @@ class RDoc::Parser::C < RDoc::Parser
# distinct (for example Kernel.hash and Kernel.object_id share the same
# implementation
- override_comment = find_override_comment(class_name, 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
+ find_modifiers comment, meth_obj if comment
# meth_obj.params = params
meth_obj.start_collecting_tokens
- meth_obj.add_token(RDoc::RubyToken::Token.new(1,1).set_text(body_text))
- meth_obj.comment = mangle_comment(comment)
- when %r{((?>/\*.*?\*/\s*))^\s*\#\s*define\s+#{meth_name}\s+(\w+)}m
+ tk = RDoc::RubyToken::Token.new nil, 1, 1
+ tk.set_text body_text
+ meth_obj.add_token tk
+ meth_obj.comment = strip_stars comment
+ when %r{((?>/\*.*?\*/\s*))^\s*(\#\s*define\s+#{meth_name}\s+(\w+))}m
comment = $1
- find_body(class_name, $2, meth_obj, body, true)
- find_modifiers(comment, meth_obj)
- meth_obj.comment = mangle_comment(comment) + meth_obj.comment
+ body_text = $2
+ find_body class_name, $3, meth_obj, body, true
+ find_modifiers comment, meth_obj
+
+ meth_obj.start_collecting_tokens
+ tk = RDoc::RubyToken::Token.new nil, 1, 1
+ tk.set_text body_text
+ meth_obj.add_token tk
+ meth_obj.comment = strip_stars(comment) + meth_obj.comment.to_s
when %r{^\s*\#\s*define\s+#{meth_name}\s+(\w+)}m
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(class_name, meth_obj.name)
if comment
find_modifiers(comment, meth_obj)
- meth_obj.comment = mangle_comment(comment)
+ meth_obj.comment = strip_stars comment
else
warn "No definition for #{meth_name}" unless @options.quiet
return false
@@ -328,7 +346,7 @@ class RDoc::Parser::C < RDoc::Parser
if raw_name =~ /^rb_m/
container = @top_level.add_module RDoc::NormalModule, name
else
- container = @top_level.add_class RDoc::NormalClass, name, nil
+ container = @top_level.add_class RDoc::NormalClass, name
end
container.record_location @top_level
@@ -363,27 +381,23 @@ class RDoc::Parser::C < RDoc::Parser
# */
# VALUE cFoo = rb_define_class("Foo", rb_cObject);
- def find_class_comment(class_name, class_meth)
+ def find_class_comment(class_name, class_mod)
comment = nil
- if @content =~ %r{((?>/\*.*?\*/\s+))
- (static\s+)?void\s+Init_#{class_name}\s*(?:_\(\s*)?\(\s*(?:void\s*)\)}xmi then
+
+ if @content =~ %r{
+ ((?>/\*.*?\*/\s+))
+ (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
+ elsif @content =~ %r{Document-(?:class|module):\s+#{class_name}\s*?(?:<\s+[:,\w]+)?\n((?>.*?\*/))}m then
+ comment = $1
+ elsif @content =~ %r{((?>/\*.*?\*/\s+))
+ ([\w\.\s]+\s* = \s+)?rb_define_(class|module).*?"(#{class_name})"}xm then
comment = $1
- else
- if @content =~ /rb_define_(class|module)/m then
- class_name = class_name.split("::").last
- comments = []
- @content.split(/(\/\*.*?\*\/)\s*?\n/m).each_with_index do |chunk, index|
- comments[index] = chunk
- if chunk =~ /rb_define_(class|module).*?"(#{class_name})"/m then
- comment = comments[index-1]
- break
- end
- end
- end
end
- class_meth.comment = mangle_comment(comment) if comment
+
+ class_mod.comment = strip_stars comment if comment
end
##
@@ -434,67 +448,67 @@ class RDoc::Parser::C < RDoc::Parser
def handle_attr(var_name, attr_name, reader, writer)
rw = ''
- if reader
- #@stats.num_methods += 1
- rw << 'R'
- end
- if writer
- #@stats.num_methods += 1
- rw << 'W'
- end
+ rw << 'R' if reader
+ rw << 'W' if writer
class_name = @known_classes[var_name]
return unless class_name
- class_obj = find_class(var_name, class_name)
+ class_obj = find_class(var_name, class_name)
if class_obj
comment = find_attr_comment(attr_name)
- unless comment.empty?
- comment = mangle_comment(comment)
- end
+ comment = strip_stars comment
att = RDoc::Attr.new '', attr_name, rw, comment
+ @stats.add_method att
class_obj.add_attribute(att)
end
end
- def handle_class_module(var_name, class_mod, class_name, parent, in_module)
+ def handle_class_module(var_name, type, class_name, parent, in_module)
parent_name = @known_classes[parent] || parent
- if in_module
+ if in_module then
enclosure = @classes[in_module] || @@enclosure_classes[in_module]
- unless enclosure
- if enclosure = @known_classes[in_module]
- handle_class_module(in_module, (/^rb_m/ =~ in_module ? "module" : "class"),
- enclosure, nil, nil)
- enclosure = @classes[in_module]
- end
+
+ if enclosure.nil? and enclosure = @known_classes[in_module] then
+ type = /^rb_m/ =~ in_module ? "module" : "class"
+ handle_class_module in_module, type, enclosure, nil, nil
+ enclosure = @classes[in_module]
end
- unless enclosure
- warn("Enclosing class/module '#{in_module}' for " +
- "#{class_mod} #{class_name} not known")
+
+ unless enclosure then
+ warn("Enclosing class/module '#{in_module}' for #{type} #{class_name} not known")
return
end
else
enclosure = @top_level
end
- if class_mod == "class" then
- full_name = enclosure.full_name.to_s + "::#{class_name}"
+ if type == "class" then
+ full_name = if RDoc::ClassModule === enclosure then
+ enclosure.full_name + "::#{class_name}"
+ else
+ class_name
+ end
+
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
cm = enclosure.add_module RDoc::NormalModule, class_name
@stats.add_module cm
end
- cm.record_location(enclosure.toplevel)
+ cm.record_location enclosure.top_level
+
+ find_class_comment cm.full_name, cm
- find_class_comment(cm.full_name, cm)
@classes[var_name] = cm
@@enclosure_classes[var_name] = cm
@known_classes[var_name] = cm.full_name
@@ -512,46 +526,55 @@ class RDoc::Parser::C < RDoc::Parser
# Values may include quotes and escaped colons (\:).
def handle_constants(type, var_name, const_name, definition)
- #@stats.num_constants += 1
class_name = @known_classes[var_name]
return unless class_name
- class_obj = find_class(var_name, class_name)
+ class_obj = find_class var_name, class_name
- unless class_obj
- warn("Enclosing class/module '#{const_name}' for not known")
+ unless class_obj then
+ warn "Enclosing class/module #{const_name.inspect} not known"
return
end
- comment = find_const_comment(type, const_name)
+ comment = find_const_comment type, const_name
+ comment = strip_stars comment
+ comment = normalize_comment comment
# In the case of rb_define_const, the definition and comment are in
# "/* definition: comment */" form. The literal ':' and '\' characters
# can be escaped with a backslash.
if type.downcase == 'const' then
- elements = mangle_comment(comment).split(':')
- if elements.nil? or elements.empty? then
- con = RDoc::Constant.new(const_name, definition,
- mangle_comment(comment))
- else
- new_definition = elements[0..-2].join(':')
- if new_definition.empty? then # Default to literal C definition
- new_definition = definition
- else
- new_definition.gsub!("\:", ":")
- new_definition.gsub!("\\", '\\')
- end
- new_definition.sub!(/\A(\s+)/, '')
- new_comment = $1.nil? ? elements.last : "#{$1}#{elements.last.lstrip}"
- con = RDoc::Constant.new(const_name, new_definition,
- mangle_comment(new_comment))
- end
+ elements = comment.split ':'
+
+ if elements.nil? or elements.empty? then
+ con = RDoc::Constant.new const_name, definition, comment
+ else
+ new_definition = elements[0..-2].join(':')
+
+ if new_definition.empty? then # Default to literal C definition
+ new_definition = definition
+ else
+ new_definition.gsub!("\:", ":")
+ new_definition.gsub!("\\", '\\')
+ end
+
+ new_definition.sub!(/\A(\s+)/, '')
+
+ new_comment = if $1.nil? then
+ elements.last.lstrip
+ else
+ "#{$1}#{elements.last.lstrip}"
+ end
+
+ con = RDoc::Constant.new const_name, new_definition, new_comment
+ end
else
- con = RDoc::Constant.new const_name, definition, mangle_comment(comment)
+ con = RDoc::Constant.new const_name, definition, comment
end
- class_obj.add_constant(con)
+ @stats.add_constant con
+ class_obj.add_constant con
end
##
@@ -588,9 +611,11 @@ class RDoc::Parser::C < RDoc::Parser
meth_obj.params = "(" + (1..p_count).map{|i| "p#{i}"}.join(", ") + ")"
end
- if source_file then
+ if source_file and File.exist? source_file then
file_name = File.join(@file_dir, source_file)
body = (@@known_bodies[source_file] ||= File.read(file_name))
+ elsif source_file then
+ warn "unknown source file #{source_file}"
else
body = @content
end
@@ -598,6 +623,7 @@ class RDoc::Parser::C < RDoc::Parser
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
+ meth_obj.visibility = :private if 'private_method' == type
end
end
end
@@ -615,16 +641,6 @@ class RDoc::Parser::C < RDoc::Parser
end
##
- # Remove the /*'s and leading asterisks from C comments
-
- def mangle_comment(comment)
- comment.sub!(%r{/\*+}) { " " * $&.length }
- comment.sub!(%r{\*+/}) { " " * $&.length }
- comment.gsub!(/^[ \t]*\*/m) { " " * $&.length }
- comment
- end
-
- ##
# Removes lines that are commented out that might otherwise get picked up
# when scanning for classes and methods
@@ -651,11 +667,5 @@ class RDoc::Parser::C < RDoc::Parser
@top_level
end
- def warn(msg)
- $stderr.puts
- $stderr.puts msg
- $stderr.flush
- end
-
end
diff --git a/lib/rdoc/parser/f95.rb b/lib/rdoc/parser/f95.rb
deleted file mode 100644
index 0959db4..0000000
--- a/lib/rdoc/parser/f95.rb
+++ /dev/null
@@ -1,1835 +0,0 @@
-require 'rdoc/parser'
-
-##
-# = Fortran95 RDoc Parser
-#
-# == Overview
-#
-# This parser parses Fortran95 files with suffixes "f90", "F90", "f95" and
-# "F95". Fortran95 files are expected to be conformed to Fortran95 standards.
-#
-# == Rules
-#
-# Fundamental rules are same as that of the Ruby parser. But comment markers
-# are '!' not '#'.
-#
-# === Correspondence between RDoc documentation and Fortran95 programs
-#
-# F95 parses main programs, modules, subroutines, functions, derived-types,
-# public variables, public constants, defined operators and defined
-# assignments. These components are described in items of RDoc documentation,
-# as follows.
-#
-# Files :: Files (same as Ruby)
-# Classes:: Modules
-# Methods:: Subroutines, functions, variables, constants, derived-types,
-# defined operators, defined assignments
-# Required files:: Files in which imported modules, external subroutines and
-# external functions are defined.
-# Included Modules:: List of imported modules
-# Attributes:: List of derived-types, List of imported modules all of whose
-# components are published again
-#
-# Components listed in 'Methods' (subroutines, functions, ...) defined in
-# modules are described in the item of 'Classes'. On the other hand,
-# components defined in main programs or as external procedures are described
-# in the item of 'Files'.
-#
-# === Components parsed by default
-#
-# By default, documentation on public components (subroutines, functions,
-# variables, constants, derived-types, defined operators, defined assignments)
-# are generated.
-#
-# With "--all" option, documentation on all components are generated (almost
-# same as the Ruby parser).
-#
-# === Information parsed automatically
-#
-# The following information is automatically parsed.
-#
-# * Types of arguments
-# * Types of variables and constants
-# * Types of variables in the derived types, and initial values
-# * NAMELISTs and types of variables in them, and initial values
-#
-# Aliases by interface statement are described in the item of 'Methods'.
-#
-# Components which are imported from other modules and published again are
-# described in the item of 'Methods'.
-#
-# === Format of comment blocks
-#
-# Comment blocks should be written as follows.
-#
-# Comment blocks are considered to be ended when the line without '!' appears.
-#
-# The indentation is not necessary.
-#
-# ! (Top of file)
-# !
-# ! Comment blocks for the files.
-# !
-# !--
-# ! The comment described in the part enclosed by
-# ! "!--" and "!++" is ignored.
-# !++
-# !
-# module hogehoge
-# !
-# ! Comment blocks for the modules (or the programs).
-# !
-#
-# private
-#
-# logical :: a ! a private variable
-# real, public :: b ! a public variable
-# integer, parameter :: c = 0 ! a public constant
-#
-# public :: c
-# public :: MULTI_ARRAY
-# public :: hoge, foo
-#
-# type MULTI_ARRAY
-# !
-# ! Comment blocks for the derived-types.
-# !
-# real, pointer :: var(:) =>null() ! Comments block for the variables.
-# integer :: num = 0
-# end type MULTI_ARRAY
-#
-# contains
-#
-# subroutine hoge( in, & ! Comment blocks between continuation lines are ignored.
-# & out )
-# !
-# ! Comment blocks for the subroutines or functions
-# !
-# character(*),intent(in):: in ! Comment blocks for the arguments.
-# character(*),intent(out),allocatable,target :: in
-# ! Comment blocks can be
-# ! written under Fortran statements.
-#
-# character(32) :: file ! This comment parsed as a variable in below NAMELIST.
-# integer :: id
-#
-# namelist /varinfo_nml/ file, id
-# !
-# ! Comment blocks for the NAMELISTs.
-# ! Information about variables are described above.
-# !
-#
-# ....
-#
-# end subroutine hoge
-#
-# integer function foo( in )
-# !
-# ! This part is considered as comment block.
-#
-# ! Comment blocks under blank lines are ignored.
-# !
-# integer, intent(in):: inA ! This part is considered as comment block.
-#
-# ! This part is ignored.
-#
-# end function foo
-#
-# subroutine hide( in, &
-# & out ) !:nodoc:
-# !
-# ! If "!:nodoc:" is described at end-of-line in subroutine
-# ! statement as above, the subroutine is ignored.
-# ! This assignment can be used to modules, subroutines,
-# ! functions, variables, constants, derived-types,
-# ! defined operators, defined assignments,
-# ! list of imported modules ("use" statement).
-# !
-#
-# ....
-#
-# end subroutine hide
-#
-# end module hogehoge
-
-class RDoc::Parser::F95 < RDoc::Parser
-
- parse_files_matching(/\.((f|F)9(0|5)|F)$/)
-
- class Token
-
- NO_TEXT = "??".freeze
-
- def initialize(line_no, char_no)
- @line_no = line_no
- @char_no = char_no
- @text = NO_TEXT
- end
- # Because we're used in contexts that expect to return a token,
- # we set the text string and then return ourselves
- def set_text(text)
- @text = text
- self
- end
-
- attr_reader :line_no, :char_no, :text
-
- end
-
- @@external_aliases = []
- @@public_methods = []
-
- ##
- # "false":: Comments are below source code
- # "true" :: Comments are upper source code
-
- COMMENTS_ARE_UPPER = false
-
- ##
- # Internal alias message
-
- INTERNAL_ALIAS_MES = "Alias for"
-
- ##
- # External alias message
-
- EXTERNAL_ALIAS_MES = "The entity is"
-
- ##
- # Define code constructs
-
- def scan
- # remove private comment
- remaining_code = remove_private_comments(@content)
-
- # continuation lines are united to one line
- remaining_code = united_to_one_line(remaining_code)
-
- # semicolons are replaced to line feed
- remaining_code = semicolon_to_linefeed(remaining_code)
-
- # collect comment for file entity
- whole_comment, remaining_code = collect_first_comment(remaining_code)
- @top_level.comment = whole_comment
-
- # String "remaining_code" is converted to Array "remaining_lines"
- remaining_lines = remaining_code.split("\n")
-
- # "module" or "program" parts are parsed (new)
- #
- level_depth = 0
- block_searching_flag = nil
- block_searching_lines = []
- pre_comment = []
- module_program_trailing = ""
- module_program_name = ""
- other_block_level_depth = 0
- other_block_searching_flag = nil
- remaining_lines.collect!{|line|
- if !block_searching_flag && !other_block_searching_flag
- if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i
- block_searching_flag = :module
- block_searching_lines << line
- module_program_name = $1
- module_program_trailing = find_comments($2)
- next false
- elsif line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i ||
- line =~ /^\s*?\w/ && !block_start?(line)
- block_searching_flag = :program
- block_searching_lines << line
- module_program_name = $1 || ""
- module_program_trailing = find_comments($2)
- next false
-
- elsif block_start?(line)
- other_block_searching_flag = true
- next line
-
- elsif line =~ /^\s*?!\s?(.*)/
- pre_comment << line
- next line
- else
- pre_comment = []
- next line
- end
- elsif other_block_searching_flag
- other_block_level_depth += 1 if block_start?(line)
- other_block_level_depth -= 1 if block_end?(line)
- if other_block_level_depth < 0
- other_block_level_depth = 0
- other_block_searching_flag = nil
- end
- next line
- end
-
- block_searching_lines << line
- level_depth += 1 if block_start?(line)
- level_depth -= 1 if block_end?(line)
- if level_depth >= 0
- next false
- end
-
- # "module_program_code" is formatted.
- # ":nodoc:" flag is checked.
- #
- module_program_code = block_searching_lines.join("\n")
- module_program_code = remove_empty_head_lines(module_program_code)
- if module_program_trailing =~ /^:nodoc:/
- # next loop to search next block
- level_depth = 0
- block_searching_flag = false
- block_searching_lines = []
- pre_comment = []
- next false
- end
-
- # NormalClass is created, and added to @top_level
- #
- if block_searching_flag == :module
- module_name = module_program_name
- module_code = module_program_code
- module_trailing = module_program_trailing
-
- f9x_module = @top_level.add_module NormalClass, module_name
- f9x_module.record_location @top_level
-
- @stats.add_module f9x_module
-
- f9x_comment = COMMENTS_ARE_UPPER ?
- find_comments(pre_comment.join("\n")) + "\n" + module_trailing :
- module_trailing + "\n" + find_comments(module_code.sub(/^.*$\n/i, ''))
- f9x_module.comment = f9x_comment
- parse_program_or_module(f9x_module, module_code)
-
- TopLevel.all_files.each do |name, toplevel|
- if toplevel.include_includes?(module_name, @options.ignore_case)
- if !toplevel.include_requires?(@file_name, @options.ignore_case)
- toplevel.add_require(Require.new(@file_name, ""))
- end
- end
- toplevel.each_classmodule{|m|
- if m.include_includes?(module_name, @options.ignore_case)
- if !m.include_requires?(@file_name, @options.ignore_case)
- m.add_require(Require.new(@file_name, ""))
- end
- end
- }
- end
- elsif block_searching_flag == :program
- program_name = module_program_name
- program_code = module_program_code
- program_trailing = module_program_trailing
- # progress "p" # HACK what stats thingy does this correspond to?
- program_comment = COMMENTS_ARE_UPPER ?
- find_comments(pre_comment.join("\n")) + "\n" + program_trailing :
- program_trailing + "\n" + find_comments(program_code.sub(/^.*$\n/i, ''))
- program_comment = "\n\n= <i>Program</i> <tt>#{program_name}</tt>\n\n" \
- + program_comment
- @top_level.comment << program_comment
- parse_program_or_module(@top_level, program_code, :private)
- end
-
- # next loop to search next block
- level_depth = 0
- block_searching_flag = false
- block_searching_lines = []
- pre_comment = []
- next false
- }
-
- remaining_lines.delete_if{ |line|
- line == false
- }
-
- # External subprograms and functions are parsed
- #
- parse_program_or_module(@top_level, remaining_lines.join("\n"),
- :public, true)
-
- @top_level
- end # End of scan
-
- private
-
- def parse_program_or_module(container, code,
- visibility=:public, external=nil)
- return unless container
- return unless code
- remaining_lines = code.split("\n")
- remaining_code = "#{code}"
-
- #
- # Parse variables before "contains" in module
- #
- level_depth = 0
- before_contains_lines = []
- before_contains_code = nil
- before_contains_flag = nil
- remaining_lines.each{ |line|
- if !before_contains_flag
- if line =~ /^\s*?module\s+\w+\s*?(!.*?)?$/i
- before_contains_flag = true
- end
- else
- break if line =~ /^\s*?contains\s*?(!.*?)?$/i
- level_depth += 1 if block_start?(line)
- level_depth -= 1 if block_end?(line)
- break if level_depth < 0
- before_contains_lines << line
- end
- }
- before_contains_code = before_contains_lines.join("\n")
- if before_contains_code
- before_contains_code.gsub!(/^\s*?interface\s+.*?\s+end\s+interface.*?$/im, "")
- before_contains_code.gsub!(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
- end
-
- #
- # Parse global "use"
- #
- use_check_code = "#{before_contains_code}"
- cascaded_modules_list = []
- while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i
- use_check_code = $~.pre_match
- use_check_code << $~.post_match
- used_mod_name = $1.strip.chomp
- used_list = $2 || ""
- used_trailing = $3 || ""
- next if used_trailing =~ /!:nodoc:/
- if !container.include_includes?(used_mod_name, @options.ignore_case)
- # progress "." # HACK what stats thingy does this correspond to?
- container.add_include Include.new(used_mod_name, "")
- end
- if ! (used_list =~ /\,\s*?only\s*?:/i )
- cascaded_modules_list << "\#" + used_mod_name
- end
- end
-
- #
- # Parse public and private, and store information.
- # This information is used when "add_method" and
- # "set_visibility_for" are called.
- #
- visibility_default, visibility_info =
- parse_visibility(remaining_lines.join("\n"), visibility, container)
- @@public_methods.concat visibility_info
- if visibility_default == :public
- if !cascaded_modules_list.empty?
- cascaded_modules =
- Attr.new("Cascaded Modules",
- "Imported modules all of whose components are published again",
- "",
- cascaded_modules_list.join(", "))
- container.add_attribute(cascaded_modules)
- end
- end
-
- #
- # Check rename elements
- #
- use_check_code = "#{before_contains_code}"
- while use_check_code =~ /^\s*?use\s+(\w+)\s*?\,(.+)$/i
- use_check_code = $~.pre_match
- use_check_code << $~.post_match
- used_mod_name = $1.strip.chomp
- used_elements = $2.sub(/\s*?only\s*?:\s*?/i, '')
- used_elements.split(",").each{ |used|
- if /\s*?(\w+)\s*?=>\s*?(\w+)\s*?/ =~ used
- local = $1
- org = $2
- @@public_methods.collect!{ |pub_meth|
- if local == pub_meth["name"] ||
- local.upcase == pub_meth["name"].upcase &&
- @options.ignore_case
- pub_meth["name"] = org
- pub_meth["local_name"] = local
- end
- pub_meth
- }
- end
- }
- end
-
- #
- # Parse private "use"
- #
- use_check_code = remaining_lines.join("\n")
- while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i
- use_check_code = $~.pre_match
- use_check_code << $~.post_match
- used_mod_name = $1.strip.chomp
- used_trailing = $3 || ""
- next if used_trailing =~ /!:nodoc:/
- if !container.include_includes?(used_mod_name, @options.ignore_case)
- # progress "." # HACK what stats thingy does this correspond to?
- container.add_include Include.new(used_mod_name, "")
- end
- end
-
- container.each_includes{ |inc|
- TopLevel.all_files.each do |name, toplevel|
- indicated_mod = toplevel.find_symbol(inc.name,
- nil, @options.ignore_case)
- if indicated_mod
- indicated_name = indicated_mod.parent.file_relative_name
- if !container.include_requires?(indicated_name, @options.ignore_case)
- container.add_require(Require.new(indicated_name, ""))
- end
- break
- end
- end
- }
-
- #
- # Parse derived-types definitions
- #
- derived_types_comment = ""
- remaining_code = remaining_lines.join("\n")
- while remaining_code =~ /^\s*?
- type[\s\,]+(public|private)?\s*?(::)?\s*?
- (\w+)\s*?(!.*?)?$
- (.*?)
- ^\s*?end\s+type.*?$
- /imx
- remaining_code = $~.pre_match
- remaining_code << $~.post_match
- typename = $3.chomp.strip
- type_elements = $5 || ""
- type_code = remove_empty_head_lines($&)
- type_trailing = find_comments($4)
- next if type_trailing =~ /^:nodoc:/
- type_visibility = $1
- type_comment = COMMENTS_ARE_UPPER ?
- find_comments($~.pre_match) + "\n" + type_trailing :
- type_trailing + "\n" + find_comments(type_code.sub(/^.*$\n/i, ''))
- type_element_visibility_public = true
- type_code.split("\n").each{ |line|
- if /^\s*?private\s*?$/ =~ line
- type_element_visibility_public = nil
- break
- end
- } if type_code
-
- args_comment = ""
- type_args_info = nil
-
- if @options.show_all
- args_comment = find_arguments(nil, type_code, true)
- else
- type_public_args_list = []
- type_args_info = definition_info(type_code)
- type_args_info.each{ |arg|
- arg_is_public = type_element_visibility_public
- arg_is_public = true if arg.include_attr?("public")
- arg_is_public = nil if arg.include_attr?("private")
- type_public_args_list << arg.varname if arg_is_public
- }
- args_comment = find_arguments(type_public_args_list, type_code)
- end
-
- type = AnyMethod.new("type #{typename}", typename)
- type.singleton = false
- type.params = ""
- type.comment = "<b><em> Derived Type </em></b> :: <tt></tt>\n"
- type.comment << args_comment if args_comment
- type.comment << type_comment if type_comment
-
- @stats.add_method type
-
- container.add_method type
-
- set_visibility(container, typename, visibility_default, @@public_methods)
-
- if type_visibility
- type_visibility.gsub!(/\s/,'')
- type_visibility.gsub!(/\,/,'')
- type_visibility.gsub!(/:/,'')
- type_visibility.downcase!
- if type_visibility == "public"
- container.set_visibility_for([typename], :public)
- elsif type_visibility == "private"
- container.set_visibility_for([typename], :private)
- end
- end
-
- check_public_methods(type, container.name)
-
- if @options.show_all
- derived_types_comment << ", " unless derived_types_comment.empty?
- derived_types_comment << typename
- else
- if type.visibility == :public
- derived_types_comment << ", " unless derived_types_comment.empty?
- derived_types_comment << typename
- end
- end
-
- end
-
- if !derived_types_comment.empty?
- derived_types_table =
- Attr.new("Derived Types", "Derived_Types", "",
- derived_types_comment)
- container.add_attribute(derived_types_table)
- end
-
- #
- # move interface scope
- #
- interface_code = ""
- while remaining_code =~ /^\s*?
- interface(
- \s+\w+ |
- \s+operator\s*?\(.*?\) |
- \s+assignment\s*?\(\s*?=\s*?\)
- )?\s*?$
- (.*?)
- ^\s*?end\s+interface.*?$
- /imx
- interface_code << remove_empty_head_lines($&) + "\n"
- remaining_code = $~.pre_match
- remaining_code << $~.post_match
- end
-
- #
- # Parse global constants or variables in modules
- #
- const_var_defs = definition_info(before_contains_code)
- const_var_defs.each{|defitem|
- next if defitem.nodoc
- const_or_var_type = "Variable"
- const_or_var_progress = "v"
- if defitem.include_attr?("parameter")
- const_or_var_type = "Constant"
- const_or_var_progress = "c"
- end
- const_or_var = AnyMethod.new(const_or_var_type, defitem.varname)
- const_or_var.singleton = false
- const_or_var.params = ""
- self_comment = find_arguments([defitem.varname], before_contains_code)
- const_or_var.comment = "<b><em>" + const_or_var_type + "</em></b> :: <tt></tt>\n"
- const_or_var.comment << self_comment if self_comment
-
- @stats.add_method const_or_var_progress
-
- container.add_method const_or_var
-
- set_visibility(container, defitem.varname, visibility_default, @@public_methods)
-
- if defitem.include_attr?("public")
- container.set_visibility_for([defitem.varname], :public)
- elsif defitem.include_attr?("private")
- container.set_visibility_for([defitem.varname], :private)
- end
-
- check_public_methods(const_or_var, container.name)
-
- } if const_var_defs
-
- remaining_lines = remaining_code.split("\n")
-
- # "subroutine" or "function" parts are parsed (new)
- #
- level_depth = 0
- block_searching_flag = nil
- block_searching_lines = []
- pre_comment = []
- procedure_trailing = ""
- procedure_name = ""
- procedure_params = ""
- procedure_prefix = ""
- procedure_result_arg = ""
- procedure_type = ""
- contains_lines = []
- contains_flag = nil
- remaining_lines.collect!{|line|
- if !block_searching_flag
- # subroutine
- if line =~ /^\s*?
- (recursive|pure|elemental)?\s*?
- subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
- /ix
- block_searching_flag = :subroutine
- block_searching_lines << line
-
- procedure_name = $2.chomp.strip
- procedure_params = $3 || ""
- procedure_prefix = $1 || ""
- procedure_trailing = $4 || "!"
- next false
-
- # function
- elsif line =~ /^\s*?
- (recursive|pure|elemental)?\s*?
- (
- character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
- | type\s*?\([\w\s]+?\)\s+
- | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
- | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
- | double\s+precision\s+
- | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
- | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
- )?
- function\s+(\w+)\s*?
- (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
- /ix
- block_searching_flag = :function
- block_searching_lines << line
-
- procedure_prefix = $1 || ""
- procedure_type = $2 ? $2.chomp.strip : nil
- procedure_name = $8.chomp.strip
- procedure_params = $9 || ""
- procedure_result_arg = $11 ? $11.chomp.strip : procedure_name
- procedure_trailing = $12 || "!"
- next false
- elsif line =~ /^\s*?!\s?(.*)/
- pre_comment << line
- next line
- else
- pre_comment = []
- next line
- end
- end
- contains_flag = true if line =~ /^\s*?contains\s*?(!.*?)?$/
- block_searching_lines << line
- contains_lines << line if contains_flag
-
- level_depth += 1 if block_start?(line)
- level_depth -= 1 if block_end?(line)
- if level_depth >= 0
- next false
- end
-
- # "procedure_code" is formatted.
- # ":nodoc:" flag is checked.
- #
- procedure_code = block_searching_lines.join("\n")
- procedure_code = remove_empty_head_lines(procedure_code)
- if procedure_trailing =~ /^!:nodoc:/
- # next loop to search next block
- level_depth = 0
- block_searching_flag = nil
- block_searching_lines = []
- pre_comment = []
- procedure_trailing = ""
- procedure_name = ""
- procedure_params = ""
- procedure_prefix = ""
- procedure_result_arg = ""
- procedure_type = ""
- contains_lines = []
- contains_flag = nil
- next false
- end
-
- # AnyMethod is created, and added to container
- #
- subroutine_function = nil
- if block_searching_flag == :subroutine
- subroutine_prefix = procedure_prefix
- subroutine_name = procedure_name
- subroutine_params = procedure_params
- subroutine_trailing = procedure_trailing
- subroutine_code = procedure_code
-
- subroutine_comment = COMMENTS_ARE_UPPER ?
- pre_comment.join("\n") + "\n" + subroutine_trailing :
- subroutine_trailing + "\n" + subroutine_code.sub(/^.*$\n/i, '')
- subroutine = AnyMethod.new("subroutine", subroutine_name)
- parse_subprogram(subroutine, subroutine_params,
- subroutine_comment, subroutine_code,
- before_contains_code, nil, subroutine_prefix)
-
- @stats.add_method subroutine
-
- container.add_method subroutine
- subroutine_function = subroutine
-
- elsif block_searching_flag == :function
- function_prefix = procedure_prefix
- function_type = procedure_type
- function_name = procedure_name
- function_params_org = procedure_params
- function_result_arg = procedure_result_arg
- function_trailing = procedure_trailing
- function_code_org = procedure_code
-
- function_comment = COMMENTS_ARE_UPPER ?
- pre_comment.join("\n") + "\n" + function_trailing :
- function_trailing + "\n " + function_code_org.sub(/^.*$\n/i, '')
-
- function_code = "#{function_code_org}"
- if function_type
- function_code << "\n" + function_type + " :: " + function_result_arg
- end
-
- function_params =
- function_params_org.sub(/^\(/, "\(#{function_result_arg}, ")
-
- function = AnyMethod.new("function", function_name)
- parse_subprogram(function, function_params,
- function_comment, function_code,
- before_contains_code, true, function_prefix)
-
- # Specific modification due to function
- function.params.sub!(/\(\s*?#{function_result_arg}\s*?,\s*?/, "\( ")
- function.params << " result(" + function_result_arg + ")"
- function.start_collecting_tokens
- function.add_token Token.new(1,1).set_text(function_code_org)
-
- @stats.add_method function
-
- container.add_method function
- subroutine_function = function
-
- end
-
- # The visibility of procedure is specified
- #
- set_visibility(container, procedure_name,
- visibility_default, @@public_methods)
-
- # The alias for this procedure from external modules
- #
- check_external_aliases(procedure_name,
- subroutine_function.params,
- subroutine_function.comment, subroutine_function) if external
- check_public_methods(subroutine_function, container.name)
-
-
- # contains_lines are parsed as private procedures
- if contains_flag
- parse_program_or_module(container,
- contains_lines.join("\n"), :private)
- end
-
- # next loop to search next block
- level_depth = 0
- block_searching_flag = nil
- block_searching_lines = []
- pre_comment = []
- procedure_trailing = ""
- procedure_name = ""
- procedure_params = ""
- procedure_prefix = ""
- procedure_result_arg = ""
- contains_lines = []
- contains_flag = nil
- next false
- } # End of remaining_lines.collect!{|line|
-
- # Array remains_lines is converted to String remains_code again
- #
- remaining_code = remaining_lines.join("\n")
-
- #
- # Parse interface
- #
- interface_scope = false
- generic_name = ""
- interface_code.split("\n").each{ |line|
- if /^\s*?
- interface(
- \s+\w+|
- \s+operator\s*?\(.*?\)|
- \s+assignment\s*?\(\s*?=\s*?\)
- )?
- \s*?(!.*?)?$
- /ix =~ line
- generic_name = $1 ? $1.strip.chomp : nil
- interface_trailing = $2 || "!"
- interface_scope = true
- interface_scope = false if interface_trailing =~ /!:nodoc:/
-# if generic_name =~ /operator\s*?\((.*?)\)/i
-# operator_name = $1
-# if operator_name && !operator_name.empty?
-# generic_name = "#{operator_name}"
-# end
-# end
-# if generic_name =~ /assignment\s*?\((.*?)\)/i
-# assignment_name = $1
-# if assignment_name && !assignment_name.empty?
-# generic_name = "#{assignment_name}"
-# end
-# end
- end
- if /^\s*?end\s+interface/i =~ line
- interface_scope = false
- generic_name = nil
- end
- # internal alias
- if interface_scope && /^\s*?module\s+procedure\s+(.*?)(!.*?)?$/i =~ line
- procedures = $1.strip.chomp
- procedures_trailing = $2 || "!"
- next if procedures_trailing =~ /!:nodoc:/
- procedures.split(",").each{ |proc|
- proc.strip!
- proc.chomp!
- next if generic_name == proc || !generic_name
- old_meth = container.find_symbol(proc, nil, @options.ignore_case)
- next if !old_meth
- nolink = old_meth.visibility == :private ? true : nil
- nolink = nil if @options.show_all
- new_meth =
- initialize_external_method(generic_name, proc,
- old_meth.params, nil,
- old_meth.comment,
- old_meth.clone.token_stream[0].text,
- true, nolink)
- new_meth.singleton = old_meth.singleton
-
- @stats.add_method new_meth
-
- container.add_method new_meth
-
- set_visibility(container, generic_name, visibility_default, @@public_methods)
-
- check_public_methods(new_meth, container.name)
-
- }
- end
-
- # external aliases
- if interface_scope
- # subroutine
- proc = nil
- params = nil
- procedures_trailing = nil
- if line =~ /^\s*?
- (recursive|pure|elemental)?\s*?
- subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
- /ix
- proc = $2.chomp.strip
- generic_name = proc unless generic_name
- params = $3 || ""
- procedures_trailing = $4 || "!"
-
- # function
- elsif line =~ /^\s*?
- (recursive|pure|elemental)?\s*?
- (
- character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
- | type\s*?\([\w\s]+?\)\s+
- | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
- | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
- | double\s+precision\s+
- | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
- | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
- )?
- function\s+(\w+)\s*?
- (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
- /ix
- proc = $8.chomp.strip
- generic_name = proc unless generic_name
- params = $9 || ""
- procedures_trailing = $12 || "!"
- else
- next
- end
- next if procedures_trailing =~ /!:nodoc:/
- indicated_method = nil
- indicated_file = nil
- TopLevel.all_files.each do |name, toplevel|
- indicated_method = toplevel.find_local_symbol(proc, @options.ignore_case)
- indicated_file = name
- break if indicated_method
- end
-
- if indicated_method
- external_method =
- initialize_external_method(generic_name, proc,
- indicated_method.params,
- indicated_file,
- indicated_method.comment)
-
- @stats.add_method external_method
-
- container.add_method external_method
- set_visibility(container, generic_name, visibility_default, @@public_methods)
- if !container.include_requires?(indicated_file, @options.ignore_case)
- container.add_require(Require.new(indicated_file, ""))
- end
- check_public_methods(external_method, container.name)
-
- else
- @@external_aliases << {
- "new_name" => generic_name,
- "old_name" => proc,
- "file_or_module" => container,
- "visibility" => find_visibility(container, generic_name, @@public_methods) || visibility_default
- }
- end
- end
-
- } if interface_code # End of interface_code.split("\n").each ...
-
- #
- # Already imported methods are removed from @@public_methods.
- # Remainders are assumed to be imported from other modules.
- #
- @@public_methods.delete_if{ |method| method["entity_is_discovered"]}
-
- @@public_methods.each{ |pub_meth|
- next unless pub_meth["file_or_module"].name == container.name
- pub_meth["used_modules"].each{ |used_mod|
- TopLevel.all_classes_and_modules.each{ |modules|
- if modules.name == used_mod ||
- modules.name.upcase == used_mod.upcase &&
- @options.ignore_case
- modules.method_list.each{ |meth|
- if meth.name == pub_meth["name"] ||
- meth.name.upcase == pub_meth["name"].upcase &&
- @options.ignore_case
- new_meth = initialize_public_method(meth,
- modules.name)
- if pub_meth["local_name"]
- new_meth.name = pub_meth["local_name"]
- end
-
- @stats.add_method new_meth
-
- container.add_method new_meth
- end
- }
- end
- }
- }
- }
-
- container
- end # End of parse_program_or_module
-
- ##
- # Parse arguments, comment, code of subroutine and function. Return
- # AnyMethod object.
-
- def parse_subprogram(subprogram, params, comment, code,
- before_contains=nil, function=nil, prefix=nil)
- subprogram.singleton = false
- prefix = "" if !prefix
- arguments = params.sub(/\(/, "").sub(/\)/, "").split(",") if params
- args_comment, params_opt =
- find_arguments(arguments, code.sub(/^s*?contains\s*?(!.*?)?$.*/im, ""),
- nil, nil, true)
- params_opt = "( " + params_opt + " ) " if params_opt
- subprogram.params = params_opt || ""
- namelist_comment = find_namelists(code, before_contains)
-
- block_comment = find_comments comment
- if function
- subprogram.comment = "<b><em> Function </em></b> :: <em>#{prefix}</em>\n"
- else
- subprogram.comment = "<b><em> Subroutine </em></b> :: <em>#{prefix}</em>\n"
- end
- subprogram.comment << args_comment if args_comment
- subprogram.comment << block_comment if block_comment
- subprogram.comment << namelist_comment if namelist_comment
-
- # For output source code
- subprogram.start_collecting_tokens
- subprogram.add_token Token.new(1,1).set_text(code)
-
- subprogram
- end
-
- ##
- # Collect comment for file entity
-
- def collect_first_comment(body)
- comment = ""
- not_comment = ""
- comment_start = false
- comment_end = false
- body.split("\n").each{ |line|
- if comment_end
- not_comment << line
- not_comment << "\n"
- elsif /^\s*?!\s?(.*)$/i =~ line
- comment_start = true
- comment << $1
- comment << "\n"
- elsif /^\s*?$/i =~ line
- comment_end = true if comment_start && COMMENTS_ARE_UPPER
- else
- comment_end = true
- not_comment << line
- not_comment << "\n"
- end
- }
- return comment, not_comment
- end
-
-
- ##
- # Return comments of definitions of arguments
- #
- # If "all" argument is true, information of all arguments are returned.
- #
- # If "modified_params" is true, list of arguments are decorated, for
- # example, optional arguments are parenthetic as "[arg]".
-
- def find_arguments(args, text, all=nil, indent=nil, modified_params=nil)
- return unless args || all
- indent = "" unless indent
- args = ["all"] if all
- params = "" if modified_params
- comma = ""
- return unless text
- args_rdocforms = "\n"
- remaining_lines = "#{text}"
- definitions = definition_info(remaining_lines)
- args.each{ |arg|
- arg.strip!
- arg.chomp!
- definitions.each { |defitem|
- if arg == defitem.varname.strip.chomp || all
- args_rdocforms << <<-"EOF"
-
-#{indent}<tt><b>#{defitem.varname.chomp.strip}#{defitem.arraysuffix}</b> #{defitem.inivalue}</tt> ::
-#{indent} <tt>#{defitem.types.chomp.strip}</tt>
-EOF
- if !defitem.comment.chomp.strip.empty?
- comment = ""
- defitem.comment.split("\n").each{ |line|
- comment << " " + line + "\n"
- }
- args_rdocforms << <<-"EOF"
-
-#{indent} <tt></tt> ::
-#{indent} <tt></tt>
-#{indent} #{comment.chomp.strip}
-EOF
- end
-
- if modified_params
- if defitem.include_attr?("optional")
- params << "#{comma}[#{arg}]"
- else
- params << "#{comma}#{arg}"
- end
- comma = ", "
- end
- end
- }
- }
- if modified_params
- return args_rdocforms, params
- else
- return args_rdocforms
- end
- end
-
- ##
- # Return comments of definitions of namelists
-
- def find_namelists(text, before_contains=nil)
- return nil if !text
- result = ""
- lines = "#{text}"
- before_contains = "" if !before_contains
- while lines =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)$/i
- lines = $~.post_match
- nml_comment = COMMENTS_ARE_UPPER ?
- find_comments($~.pre_match) : find_comments($~.post_match)
- nml_name = $1
- nml_args = $2.split(",")
- result << "\n\n=== NAMELIST <tt><b>" + nml_name + "</tt></b>\n\n"
- result << nml_comment + "\n" if nml_comment
- if lines.split("\n")[0] =~ /^\//i
- lines = "namelist " + lines
- end
- result << find_arguments(nml_args, "#{text}" + "\n" + before_contains)
- end
- return result
- end
-
- ##
- # Comments just after module or subprogram, or arguments are returned. If
- # "COMMENTS_ARE_UPPER" is true, comments just before modules or subprograms
- # are returnd
-
- def find_comments text
- return "" unless text
- lines = text.split("\n")
- lines.reverse! if COMMENTS_ARE_UPPER
- comment_block = Array.new
- lines.each do |line|
- break if line =~ /^\s*?\w/ || line =~ /^\s*?$/
- if COMMENTS_ARE_UPPER
- comment_block.unshift line.sub(/^\s*?!\s?/,"")
- else
- comment_block.push line.sub(/^\s*?!\s?/,"")
- end
- end
- nice_lines = comment_block.join("\n").split "\n\s*?\n"
- nice_lines[0] ||= ""
- nice_lines.shift
- end
-
- ##
- # Create method for internal alias
-
- def initialize_public_method(method, parent)
- return if !method || !parent
-
- new_meth = AnyMethod.new("External Alias for module", method.name)
- new_meth.singleton = method.singleton
- new_meth.params = method.params.clone
- new_meth.comment = remove_trailing_alias(method.comment.clone)
- new_meth.comment << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}"
-
- return new_meth
- end
-
- ##
- # Create method for external alias
- #
- # If argument "internal" is true, file is ignored.
-
- def initialize_external_method(new, old, params, file, comment, token=nil,
- internal=nil, nolink=nil)
- return nil unless new || old
-
- if internal
- external_alias_header = "#{INTERNAL_ALIAS_MES} "
- external_alias_text = external_alias_header + old
- elsif file
- external_alias_header = "#{EXTERNAL_ALIAS_MES} "
- external_alias_text = external_alias_header + file + "#" + old
- else
- return nil
- end
- external_meth = AnyMethod.new(external_alias_text, new)
- external_meth.singleton = false
- external_meth.params = params
- external_comment = remove_trailing_alias(comment) + "\n\n" if comment
- external_meth.comment = external_comment || ""
- if nolink && token
- external_meth.start_collecting_tokens
- external_meth.add_token Token.new(1,1).set_text(token)
- else
- external_meth.comment << external_alias_text
- end
-
- return external_meth
- end
-
- ##
- # Parse visibility
-
- def parse_visibility(code, default, container)
- result = []
- visibility_default = default || :public
-
- used_modules = []
- container.includes.each{|i| used_modules << i.name} if container
-
- remaining_code = code.gsub(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
- remaining_code.split("\n").each{ |line|
- if /^\s*?private\s*?$/ =~ line
- visibility_default = :private
- break
- end
- } if remaining_code
-
- remaining_code.split("\n").each{ |line|
- if /^\s*?private\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
- methods = $2.sub(/!.*$/, '')
- methods.split(",").each{ |meth|
- meth.sub!(/!.*$/, '')
- meth.gsub!(/:/, '')
- result << {
- "name" => meth.chomp.strip,
- "visibility" => :private,
- "used_modules" => used_modules.clone,
- "file_or_module" => container,
- "entity_is_discovered" => nil,
- "local_name" => nil
- }
- }
- elsif /^\s*?public\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
- methods = $2.sub(/!.*$/, '')
- methods.split(",").each{ |meth|
- meth.sub!(/!.*$/, '')
- meth.gsub!(/:/, '')
- result << {
- "name" => meth.chomp.strip,
- "visibility" => :public,
- "used_modules" => used_modules.clone,
- "file_or_module" => container,
- "entity_is_discovered" => nil,
- "local_name" => nil
- }
- }
- end
- } if remaining_code
-
- if container
- result.each{ |vis_info|
- vis_info["parent"] = container.name
- }
- end
-
- return visibility_default, result
- end
-
- ##
- # Set visibility
- #
- # "subname" element of "visibility_info" is deleted.
-
- def set_visibility(container, subname, visibility_default, visibility_info)
- return unless container || subname || visibility_default || visibility_info
- not_found = true
- visibility_info.collect!{ |info|
- if info["name"] == subname ||
- @options.ignore_case && info["name"].upcase == subname.upcase
- if info["file_or_module"].name == container.name
- container.set_visibility_for([subname], info["visibility"])
- info["entity_is_discovered"] = true
- not_found = false
- end
- end
- info
- }
- if not_found
- return container.set_visibility_for([subname], visibility_default)
- else
- return container
- end
- end
-
- ##
- # Find visibility
-
- def find_visibility(container, subname, visibility_info)
- return nil if !subname || !visibility_info
- visibility_info.each{ |info|
- if info["name"] == subname ||
- @options.ignore_case && info["name"].upcase == subname.upcase
- if info["parent"] == container.name
- return info["visibility"]
- end
- end
- }
- return nil
- end
-
- ##
- # Check external aliases
-
- def check_external_aliases(subname, params, comment, test=nil)
- @@external_aliases.each{ |alias_item|
- if subname == alias_item["old_name"] ||
- subname.upcase == alias_item["old_name"].upcase &&
- @options.ignore_case
-
- new_meth = initialize_external_method(alias_item["new_name"],
- subname, params, @file_name,
- comment)
- new_meth.visibility = alias_item["visibility"]
-
- @stats.add_method new_meth
-
- alias_item["file_or_module"].add_method(new_meth)
-
- if !alias_item["file_or_module"].include_requires?(@file_name, @options.ignore_case)
- alias_item["file_or_module"].add_require(Require.new(@file_name, ""))
- end
- end
- }
- end
-
- ##
- # Check public_methods
-
- def check_public_methods(method, parent)
- return if !method || !parent
- @@public_methods.each{ |alias_item|
- parent_is_used_module = nil
- alias_item["used_modules"].each{ |used_module|
- if used_module == parent ||
- used_module.upcase == parent.upcase &&
- @options.ignore_case
- parent_is_used_module = true
- end
- }
- next if !parent_is_used_module
-
- if method.name == alias_item["name"] ||
- method.name.upcase == alias_item["name"].upcase &&
- @options.ignore_case
-
- new_meth = initialize_public_method(method, parent)
- if alias_item["local_name"]
- new_meth.name = alias_item["local_name"]
- end
-
- @stats.add_method new_meth
-
- alias_item["file_or_module"].add_method new_meth
- end
- }
- end
-
- ##
- # Continuous lines are united.
- #
- # Comments in continuous lines are removed.
-
- def united_to_one_line(f90src)
- return "" unless f90src
- lines = f90src.split("\n")
- previous_continuing = false
- now_continuing = false
- body = ""
- lines.each{ |line|
- words = line.split("")
- next if words.empty? && previous_continuing
- commentout = false
- brank_flag = true ; brank_char = ""
- squote = false ; dquote = false
- ignore = false
- words.collect! { |char|
- if previous_continuing && brank_flag
- now_continuing = true
- ignore = true
- case char
- when "!" ; break
- when " " ; brank_char << char ; next ""
- when "&"
- brank_flag = false
- now_continuing = false
- next ""
- else
- brank_flag = false
- now_continuing = false
- ignore = false
- next brank_char + char
- end
- end
- ignore = false
-
- if now_continuing
- next ""
- elsif !(squote) && !(dquote) && !(commentout)
- case char
- when "!" ; commentout = true ; next char
- when "\""; dquote = true ; next char
- when "\'"; squote = true ; next char
- when "&" ; now_continuing = true ; next ""
- else next char
- end
- elsif commentout
- next char
- elsif squote
- case char
- when "\'"; squote = false ; next char
- else next char
- end
- elsif dquote
- case char
- when "\""; dquote = false ; next char
- else next char
- end
- end
- }
- if !ignore && !previous_continuing || !brank_flag
- if previous_continuing
- body << words.join("")
- else
- body << "\n" + words.join("")
- end
- end
- previous_continuing = now_continuing ? true : nil
- now_continuing = nil
- }
- return body
- end
-
-
- ##
- # Continuous line checker
-
- def continuous_line?(line)
- continuous = false
- if /&\s*?(!.*)?$/ =~ line
- continuous = true
- if comment_out?($~.pre_match)
- continuous = false
- end
- end
- return continuous
- end
-
- ##
- # Comment out checker
-
- def comment_out?(line)
- return nil unless line
- commentout = false
- squote = false ; dquote = false
- line.split("").each { |char|
- if !(squote) && !(dquote)
- case char
- when "!" ; commentout = true ; break
- when "\""; dquote = true
- when "\'"; squote = true
- else next
- end
- elsif squote
- case char
- when "\'"; squote = false
- else next
- end
- elsif dquote
- case char
- when "\""; dquote = false
- else next
- end
- end
- }
- return commentout
- end
-
- ##
- # Semicolons are replaced to line feed.
-
- def semicolon_to_linefeed(text)
- return "" unless text
- lines = text.split("\n")
- lines.collect!{ |line|
- words = line.split("")
- commentout = false
- squote = false ; dquote = false
- words.collect! { |char|
- if !(squote) && !(dquote) && !(commentout)
- case char
- when "!" ; commentout = true ; next char
- when "\""; dquote = true ; next char
- when "\'"; squote = true ; next char
- when ";" ; "\n"
- else next char
- end
- elsif commentout
- next char
- elsif squote
- case char
- when "\'"; squote = false ; next char
- else next char
- end
- elsif dquote
- case char
- when "\""; dquote = false ; next char
- else next char
- end
- end
- }
- words.join("")
- }
- return lines.join("\n")
- end
-
- ##
- # Which "line" is start of block (module, program, block data, subroutine,
- # function) statement ?
-
- def block_start?(line)
- return nil if !line
-
- if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i ||
- line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i ||
- line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i ||
- line =~ \
- /^\s*?
- (recursive|pure|elemental)?\s*?
- subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
- /ix ||
- line =~ \
- /^\s*?
- (recursive|pure|elemental)?\s*?
- (
- character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
- | type\s*?\([\w\s]+?\)\s+
- | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
- | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
- | double\s+precision\s+
- | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
- | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
- )?
- function\s+(\w+)\s*?
- (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
- /ix
- return true
- end
-
- return nil
- end
-
- ##
- # Which "line" is end of block (module, program, block data, subroutine,
- # function) statement ?
-
- def block_end?(line)
- return nil if !line
-
- if line =~ /^\s*?end\s*?(!.*?)?$/i ||
- line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i ||
- line =~ /^\s*?end\s+program(\s+\w+)?\s*?(!.*?)?$/i ||
- line =~ /^\s*?end\s+block\s+data(\s+\w+)?\s*?(!.*?)?$/i ||
- line =~ /^\s*?end\s+subroutine(\s+\w+)?\s*?(!.*?)?$/i ||
- line =~ /^\s*?end\s+function(\s+\w+)?\s*?(!.*?)?$/i
- return true
- end
-
- return nil
- end
-
- ##
- # Remove "Alias for" in end of comments
-
- def remove_trailing_alias(text)
- return "" if !text
- lines = text.split("\n").reverse
- comment_block = Array.new
- checked = false
- lines.each do |line|
- if !checked
- if /^\s?#{INTERNAL_ALIAS_MES}/ =~ line ||
- /^\s?#{EXTERNAL_ALIAS_MES}/ =~ line
- checked = true
- next
- end
- end
- comment_block.unshift line
- end
- nice_lines = comment_block.join("\n")
- nice_lines ||= ""
- return nice_lines
- end
-
- ##
- # Empty lines in header are removed
-
- def remove_empty_head_lines(text)
- return "" unless text
- lines = text.split("\n")
- header = true
- lines.delete_if{ |line|
- header = false if /\S/ =~ line
- header && /^\s*?$/ =~ line
- }
- lines.join("\n")
- end
-
- ##
- # header marker "=", "==", ... are removed
-
- def remove_header_marker(text)
- return text.gsub(/^\s?(=+)/, '<tt></tt>\1')
- end
-
- def remove_private_comments(body)
- body.gsub!(/^\s*!--\s*?$.*?^\s*!\+\+\s*?$/m, '')
- return body
- end
-
- ##
- # Information of arguments of subroutines and functions in Fortran95
-
- class Fortran95Definition
-
- # Name of variable
- #
- attr_reader :varname
-
- # Types of variable
- #
- attr_reader :types
-
- # Initial Value
- #
- attr_reader :inivalue
-
- # Suffix of array
- #
- attr_reader :arraysuffix
-
- # Comments
- #
- attr_accessor :comment
-
- # Flag of non documentation
- #
- attr_accessor :nodoc
-
- def initialize(varname, types, inivalue, arraysuffix, comment,
- nodoc=false)
- @varname = varname
- @types = types
- @inivalue = inivalue
- @arraysuffix = arraysuffix
- @comment = comment
- @nodoc = nodoc
- end
-
- def to_s
- return <<-EOF
-<Fortran95Definition:
-varname=#{@varname}, types=#{types},
-inivalue=#{@inivalue}, arraysuffix=#{@arraysuffix}, nodoc=#{@nodoc},
-comment=
-#{@comment}
->
-EOF
- end
-
- #
- # If attr is included, true is returned
- #
- def include_attr?(attr)
- return if !attr
- @types.split(",").each{ |type|
- return true if type.strip.chomp.upcase == attr.strip.chomp.upcase
- }
- return nil
- end
-
- end # End of Fortran95Definition
-
- ##
- # Parse string argument "text", and Return Array of Fortran95Definition
- # object
-
- def definition_info(text)
- return nil unless text