summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordrbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-11-27 04:28:14 +0000
committerdrbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-11-27 04:28:14 +0000
commit1c279a7d2753949c725754e1302f791b76358114 (patch)
tree36aa3bdde250e564445eba5f2e25fcb96bcb6cef
parentc72f0daa877808e4fa5018b3191ca09d4b97c03d (diff)
* lib/rdoc*: Updated to RDoc 4.0 (pre-release)
* bin/rdoc: ditto * test/rdoc: ditto * NEWS: Updated with RDoc 4.0 information git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37889 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog7
-rw-r--r--NEWS11
-rwxr-xr-xbin/rdoc6
-rw-r--r--ext/nkf/nkf-utf8/utf8tbl.c2
-rw-r--r--lib/rdoc.rb171
-rw-r--r--lib/rdoc/alias.rb2
-rw-r--r--lib/rdoc/anon_class.rb2
-rw-r--r--lib/rdoc/any_method.rb105
-rw-r--r--lib/rdoc/attr.rb59
-rw-r--r--lib/rdoc/class_module.rb267
-rw-r--r--lib/rdoc/code_object.rb70
-rw-r--r--lib/rdoc/code_objects.rb24
-rw-r--r--lib/rdoc/comment.rb232
-rw-r--r--lib/rdoc/constant.rb108
-rw-r--r--lib/rdoc/context.rb323
-rw-r--r--lib/rdoc/context/section.rb238
-rw-r--r--lib/rdoc/cross_reference.rb136
-rw-r--r--lib/rdoc/encoding.rb65
-rw-r--r--lib/rdoc/erb_partial.rb18
-rw-r--r--lib/rdoc/extend.rb117
-rw-r--r--lib/rdoc/generator.rb32
-rw-r--r--lib/rdoc/generator/darkfish.rb466
-rw-r--r--lib/rdoc/generator/json_index.rb248
-rw-r--r--lib/rdoc/generator/markup.rb87
-rw-r--r--lib/rdoc/generator/ri.rb70
-rw-r--r--lib/rdoc/generator/template/darkfish/_footer.rhtml5
-rw-r--r--lib/rdoc/generator/template/darkfish/_head.rhtml16
-rw-r--r--lib/rdoc/generator/template/darkfish/_sidebar_VCS_info.rhtml18
-rw-r--r--lib/rdoc/generator/template/darkfish/_sidebar_classes.rhtml9
-rw-r--r--lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtml16
-rw-r--r--lib/rdoc/generator/template/darkfish/_sidebar_in_files.rhtml8
-rw-r--r--lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtml16
-rw-r--r--lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtml14
-rw-r--r--lib/rdoc/generator/template/darkfish/_sidebar_methods.rhtml12
-rw-r--r--lib/rdoc/generator/template/darkfish/_sidebar_navigation.rhtml7
-rw-r--r--lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml12
-rw-r--r--lib/rdoc/generator/template/darkfish/_sidebar_parent.rhtml10
-rw-r--r--lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml10
-rw-r--r--lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtml10
-rw-r--r--lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml13
-rw-r--r--lib/rdoc/generator/template/darkfish/class.rhtml179
-rw-r--r--lib/rdoc/generator/template/darkfish/classpage.rhtml321
-rw-r--r--lib/rdoc/generator/template/darkfish/filepage.rhtml124
-rwxr-xr-xlib/rdoc/generator/template/darkfish/images/add.pngbin0 -> 733 bytes
-rwxr-xr-xlib/rdoc/generator/template/darkfish/images/arrow_up.pngbin0 -> 372 bytes
-rwxr-xr-xlib/rdoc/generator/template/darkfish/images/delete.pngbin0 -> 715 bytes
-rwxr-xr-xlib/rdoc/generator/template/darkfish/images/tag_blue.pngbin0 -> 1880 bytes
-rw-r--r--lib/rdoc/generator/template/darkfish/images/transparent.pngbin0 -> 97 bytes
-rw-r--r--lib/rdoc/generator/template/darkfish/index.rhtml77
-rw-r--r--lib/rdoc/generator/template/darkfish/js/darkfish.js161
-rw-r--r--lib/rdoc/generator/template/darkfish/js/jquery.js44
-rw-r--r--lib/rdoc/generator/template/darkfish/js/quicksearch.js114
-rw-r--r--lib/rdoc/generator/template/darkfish/js/search.js94
-rw-r--r--lib/rdoc/generator/template/darkfish/js/thickbox-compressed.js10
-rw-r--r--lib/rdoc/generator/template/darkfish/page.rhtml18
-rw-r--r--lib/rdoc/generator/template/darkfish/rdoc.css487
-rw-r--r--lib/rdoc/generator/template/darkfish/servlet_not_found.rhtml18
-rw-r--r--lib/rdoc/generator/template/darkfish/servlet_root.rhtml37
-rw-r--r--lib/rdoc/generator/template/darkfish/table_of_contents.rhtml55
-rw-r--r--lib/rdoc/generator/template/json_index/js/navigation.js142
-rw-r--r--lib/rdoc/generator/template/json_index/js/searcher.js228
-rw-r--r--lib/rdoc/ghost_method.rb2
-rw-r--r--lib/rdoc/include.rb43
-rw-r--r--lib/rdoc/markdown.rb16372
-rw-r--r--lib/rdoc/markdown/entities.rb2128
-rw-r--r--lib/rdoc/markdown/literals_1_9.rb417
-rw-r--r--lib/rdoc/markup.rb316
-rw-r--r--lib/rdoc/markup/attr_changer.rb22
-rw-r--r--lib/rdoc/markup/attr_span.rb29
-rw-r--r--lib/rdoc/markup/attribute_manager.rb37
-rw-r--r--lib/rdoc/markup/attributes.rb70
-rw-r--r--lib/rdoc/markup/block_quote.rb14
-rw-r--r--lib/rdoc/markup/document.rb45
-rw-r--r--lib/rdoc/markup/formatter.rb47
-rw-r--r--lib/rdoc/markup/formatter_test_case.rb120
-rw-r--r--lib/rdoc/markup/hard_break.rb31
-rw-r--r--lib/rdoc/markup/heading.rb44
-rw-r--r--lib/rdoc/markup/include.rb42
-rw-r--r--lib/rdoc/markup/indented_paragraph.rb14
-rw-r--r--lib/rdoc/markup/inline.rb145
-rw-r--r--lib/rdoc/markup/list.rb28
-rw-r--r--lib/rdoc/markup/list_item.rb21
-rw-r--r--lib/rdoc/markup/paragraph.rb14
-rw-r--r--lib/rdoc/markup/parser.rb189
-rw-r--r--lib/rdoc/markup/pre_process.rb88
-rw-r--r--lib/rdoc/markup/raw.rb10
-rw-r--r--lib/rdoc/markup/special.rb40
-rw-r--r--lib/rdoc/markup/text_formatter_test_case.rb2
-rw-r--r--lib/rdoc/markup/to_ansi.rb15
-rw-r--r--lib/rdoc/markup/to_bs.rb2
-rw-r--r--lib/rdoc/markup/to_html.rb178
-rw-r--r--lib/rdoc/markup/to_html_crossref.rb63
-rw-r--r--lib/rdoc/markup/to_html_snippet.rb284
-rw-r--r--lib/rdoc/markup/to_joined_paragraph.rb68
-rw-r--r--lib/rdoc/markup/to_label.rb74
-rw-r--r--lib/rdoc/markup/to_markdown.rb134
-rw-r--r--lib/rdoc/markup/to_rdoc.rb52
-rw-r--r--lib/rdoc/markup/to_table_of_contents.rb61
-rw-r--r--lib/rdoc/markup/to_test.rb3
-rw-r--r--lib/rdoc/markup/to_tt_only.rb16
-rw-r--r--lib/rdoc/markup/verbatim.rb38
-rw-r--r--lib/rdoc/meta_method.rb2
-rw-r--r--lib/rdoc/method_attr.rb81
-rw-r--r--lib/rdoc/normal_class.rb35
-rw-r--r--lib/rdoc/normal_module.rb17
-rw-r--r--lib/rdoc/options.rb341
-rw-r--r--lib/rdoc/parser.rb146
-rw-r--r--lib/rdoc/parser/c.rb494
-rw-r--r--lib/rdoc/parser/markdown.rb23
-rw-r--r--lib/rdoc/parser/rd.rb22
-rw-r--r--lib/rdoc/parser/ruby.rb312
-rw-r--r--lib/rdoc/parser/ruby_tools.rb11
-rw-r--r--lib/rdoc/parser/simple.rb30
-rw-r--r--lib/rdoc/parser/text.rb11
-rw-r--r--lib/rdoc/rd.rb99
-rw-r--r--lib/rdoc/rd/block_parser.rb1054
-rw-r--r--lib/rdoc/rd/inline.rb71
-rw-r--r--lib/rdoc/rd/inline_parser.rb1207
-rw-r--r--lib/rdoc/rdoc.rb172
-rw-r--r--lib/rdoc/require.rb2
-rw-r--r--lib/rdoc/ri.rb6
-rw-r--r--lib/rdoc/ri/driver.rb404
-rw-r--r--lib/rdoc/ri/paths.rb121
-rw-r--r--lib/rdoc/ri/store.rb356
-rw-r--r--lib/rdoc/ruby_lex.rb125
-rw-r--r--lib/rdoc/ruby_token.rb50
-rw-r--r--lib/rdoc/rubygems_hook.rb9
-rw-r--r--lib/rdoc/servlet.rb298
-rw-r--r--lib/rdoc/single_class.rb2
-rw-r--r--lib/rdoc/stats.rb58
-rw-r--r--lib/rdoc/store.rb881
-rw-r--r--lib/rdoc/task.rb30
-rw-r--r--lib/rdoc/test_case.rb162
-rw-r--r--lib/rdoc/text.rb75
-rw-r--r--lib/rdoc/token_stream.rb45
-rw-r--r--lib/rdoc/tom_doc.rb233
-rw-r--r--lib/rdoc/top_level.rb345
-rw-r--r--test/rdoc/MarkdownTest_1.0.3/Amps and angle encoding.text21
-rw-r--r--test/rdoc/MarkdownTest_1.0.3/Auto links.text13
-rw-r--r--test/rdoc/MarkdownTest_1.0.3/Backslash escapes.text120
-rw-r--r--test/rdoc/MarkdownTest_1.0.3/Blockquotes with code blocks.text11
-rw-r--r--test/rdoc/MarkdownTest_1.0.3/Code Blocks.text14
-rw-r--r--test/rdoc/MarkdownTest_1.0.3/Code Spans.text6
-rw-r--r--test/rdoc/MarkdownTest_1.0.3/Hard-wrapped paragraphs with list-like lines.text8
-rw-r--r--test/rdoc/MarkdownTest_1.0.3/Horizontal rules.text67
-rw-r--r--test/rdoc/MarkdownTest_1.0.3/Inline HTML (Advanced).text15
-rw-r--r--test/rdoc/MarkdownTest_1.0.3/Inline HTML (Simple).text69
-rw-r--r--test/rdoc/MarkdownTest_1.0.3/Inline HTML comments.text13
-rw-r--r--test/rdoc/MarkdownTest_1.0.3/Links, inline style.text12
-rw-r--r--test/rdoc/MarkdownTest_1.0.3/Links, reference style.text71
-rw-r--r--test/rdoc/MarkdownTest_1.0.3/Links, shortcut references.text20
-rw-r--r--test/rdoc/MarkdownTest_1.0.3/Literal quotes in titles.text7
-rw-r--r--test/rdoc/MarkdownTest_1.0.3/Markdown Documentation - Basics.text306
-rw-r--r--test/rdoc/MarkdownTest_1.0.3/Markdown Documentation - Syntax.text888
-rw-r--r--test/rdoc/MarkdownTest_1.0.3/Nested blockquotes.text5
-rw-r--r--test/rdoc/MarkdownTest_1.0.3/Ordered and unordered lists.text131
-rw-r--r--test/rdoc/MarkdownTest_1.0.3/Strong and em together.text7
-rw-r--r--test/rdoc/MarkdownTest_1.0.3/Tabs.text21
-rw-r--r--test/rdoc/MarkdownTest_1.0.3/Tidyness.text5
-rw-r--r--test/rdoc/test.ja.large.rdoc (renamed from test/rdoc/test.ja.largedoc)0
-rw-r--r--test/rdoc/test_attribute_manager.rb66
-rw-r--r--test/rdoc/test_rdoc_any_method.rb134
-rw-r--r--test/rdoc/test_rdoc_attr.rb85
-rw-r--r--test/rdoc/test_rdoc_class_module.rb855
-rw-r--r--test/rdoc/test_rdoc_code_object.rb35
-rw-r--r--test/rdoc/test_rdoc_comment.rb504
-rw-r--r--test/rdoc/test_rdoc_constant.rb132
-rw-r--r--test/rdoc/test_rdoc_context.rb230
-rw-r--r--test/rdoc/test_rdoc_context_section.rb123
-rw-r--r--test/rdoc/test_rdoc_cross_reference.rb28
-rw-r--r--test/rdoc/test_rdoc_encoding.rb27
-rw-r--r--test/rdoc/test_rdoc_extend.rb94
-rw-r--r--test/rdoc/test_rdoc_generator_darkfish.rb110
-rw-r--r--test/rdoc/test_rdoc_generator_json_index.rb275
-rw-r--r--test/rdoc/test_rdoc_generator_markup.rb56
-rw-r--r--test/rdoc/test_rdoc_generator_ri.rb39
-rw-r--r--test/rdoc/test_rdoc_include.rb12
-rw-r--r--test/rdoc/test_rdoc_markdown.rb977
-rw-r--r--test/rdoc/test_rdoc_markdown_test.rb1891
-rw-r--r--test/rdoc/test_rdoc_markup.rb16
-rw-r--r--test/rdoc/test_rdoc_markup_attribute_manager.rb17
-rw-r--r--test/rdoc/test_rdoc_markup_attributes.rb39
-rw-r--r--test/rdoc/test_rdoc_markup_document.rb55
-rw-r--r--test/rdoc/test_rdoc_markup_formatter.rb29
-rw-r--r--test/rdoc/test_rdoc_markup_hard_break.rb31
-rw-r--r--test/rdoc/test_rdoc_markup_heading.rb20
-rw-r--r--test/rdoc/test_rdoc_markup_include.rb19
-rw-r--r--test/rdoc/test_rdoc_markup_indented_paragraph.rb23
-rw-r--r--test/rdoc/test_rdoc_markup_paragraph.rb23
-rw-r--r--test/rdoc/test_rdoc_markup_parser.rb381
-rw-r--r--test/rdoc/test_rdoc_markup_pre_process.rb69
-rw-r--r--test/rdoc/test_rdoc_markup_raw.rb14
-rw-r--r--test/rdoc/test_rdoc_markup_to_ansi.rb49
-rw-r--r--test/rdoc/test_rdoc_markup_to_bs.rb33
-rw-r--r--test/rdoc/test_rdoc_markup_to_html.rb259
-rw-r--r--test/rdoc/test_rdoc_markup_to_html_crossref.rb142
-rw-r--r--test/rdoc/test_rdoc_markup_to_html_snippet.rb710
-rw-r--r--test/rdoc/test_rdoc_markup_to_joined_paragraph.rb32
-rw-r--r--test/rdoc/test_rdoc_markup_to_label.rb112
-rw-r--r--test/rdoc/test_rdoc_markup_to_markdown.rb352
-rw-r--r--test/rdoc/test_rdoc_markup_to_rdoc.rb48
-rw-r--r--test/rdoc/test_rdoc_markup_to_table_of_contents.rb95
-rw-r--r--test/rdoc/test_rdoc_markup_to_tt_only.rb25
-rw-r--r--test/rdoc/test_rdoc_markup_verbatim.rb29
-rw-r--r--test/rdoc/test_rdoc_method_attr.rb35
-rw-r--r--test/rdoc/test_rdoc_normal_class.rb29
-rw-r--r--test/rdoc/test_rdoc_normal_module.rb2
-rw-r--r--test/rdoc/test_rdoc_options.rb232
-rw-r--r--test/rdoc/test_rdoc_parser.rb121
-rw-r--r--test/rdoc/test_rdoc_parser_c.rb377
-rw-r--r--test/rdoc/test_rdoc_parser_markdown.rb55
-rw-r--r--test/rdoc/test_rdoc_parser_rd.rb52
-rw-r--r--test/rdoc/test_rdoc_parser_ruby.rb1152
-rw-r--r--test/rdoc/test_rdoc_parser_simple.rb54
-rw-r--r--test/rdoc/test_rdoc_rd.rb30
-rw-r--r--test/rdoc/test_rdoc_rd_block_parser.rb523
-rw-r--r--test/rdoc/test_rdoc_rd_inline.rb63
-rw-r--r--test/rdoc/test_rdoc_rd_inline_parser.rb173
-rw-r--r--test/rdoc/test_rdoc_rdoc.rb203
-rw-r--r--test/rdoc/test_rdoc_ri_driver.rb489
-rw-r--r--test/rdoc/test_rdoc_ri_paths.rb150
-rw-r--r--test/rdoc/test_rdoc_ruby_lex.rb222
-rw-r--r--test/rdoc/test_rdoc_ruby_token.rb19
-rw-r--r--test/rdoc/test_rdoc_rubygems_hook.rb7
-rw-r--r--test/rdoc/test_rdoc_servlet.rb408
-rw-r--r--test/rdoc/test_rdoc_stats.rb352
-rw-r--r--test/rdoc/test_rdoc_store.rb (renamed from test/rdoc/test_rdoc_ri_store.rb)415
-rw-r--r--test/rdoc/test_rdoc_task.rb17
-rw-r--r--test/rdoc/test_rdoc_text.rb193
-rw-r--r--test/rdoc/test_rdoc_token_stream.rb42
-rw-r--r--test/rdoc/test_rdoc_tom_doc.rb455
-rw-r--r--test/rdoc/test_rdoc_top_level.rb227
-rw-r--r--test/rdoc/xref_test_case.rb24
233 files changed, 44982 insertions, 5063 deletions
diff --git a/ChangeLog b/ChangeLog
index 8c76752ac4..7f79bfc25e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Tue Nov 27 13:27:46 2012 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rdoc*: Updated to RDoc 4.0 (pre-release)
+ * bin/rdoc: ditto
+ * test/rdoc*: ditto
+ * NEWS: Updated with RDoc 4.0 information
+
Tue Nov 27 12:17:11 2012 Koichi Sasada <ko1@atdot.net>
* thread.c (rb_thread_terminate_all): retry broadcast only when
diff --git a/NEWS b/NEWS
index 269fcbe2b6..267c52db19 100644
--- a/NEWS
+++ b/NEWS
@@ -272,6 +272,17 @@ with all sufficient information, see the ChangeLog file.
http://rake.rubyforge.org/doc/release_notes/rake-0_9_4_rdoc.html for a list
of changes in rake 0.9.3 and 0.9.4.
+* rdoc
+ * rdoc has been updated to version 4.0
+
+ This version is largely backwards-compatible with previous rdoc versions.
+ The most notable change is an update to the ri data format (ri data must
+ be regenerated for gems shared across rdoc versions). Further API changes
+ are internal and won't affect most users.
+
+ See https://github.com/rdoc/rdoc/blob/master/History.rdoc for a list of
+ changes in rdoc 4.0.
+
* resolv
* new methods:
* Resolv::DNS#timeouts=
diff --git a/bin/rdoc b/bin/rdoc
index 64601a819e..aaa23292df 100755
--- a/bin/rdoc
+++ b/bin/rdoc
@@ -5,8 +5,6 @@
#
# Copyright (c) 2003 Dave Thomas
# Released under the same terms as Ruby
-#
-# $Revision$
begin
gem 'rdoc'
@@ -20,6 +18,10 @@ require 'rdoc/rdoc'
begin
r = RDoc::RDoc.new
r.document ARGV
+rescue Errno::ENOSPC
+ $stderr.puts 'Ran out of space creating documentation'
+ $stderr.puts
+ $stderr.puts 'Please free up some space and try again'
rescue SystemExit
raise
rescue Exception => e
diff --git a/ext/nkf/nkf-utf8/utf8tbl.c b/ext/nkf/nkf-utf8/utf8tbl.c
index 7a1cacaf9f..bbf5c5f109 100644
--- a/ext/nkf/nkf-utf8/utf8tbl.c
+++ b/ext/nkf/nkf-utf8/utf8tbl.c
@@ -1,7 +1,7 @@
/*
* utf8tbl.c - Convertion Table for nkf
*
- * $Id: utf8tbl.c,v 1.23 2008/02/07 19:25:29 naruse Exp $
+ * $Id$
*/
#include "config.h"
diff --git a/lib/rdoc.rb b/lib/rdoc.rb
index aaa1aaa092..5c2df18a0d 100644
--- a/lib/rdoc.rb
+++ b/lib/rdoc.rb
@@ -1,86 +1,55 @@
$DEBUG_RDOC = nil
-# :main: README.txt
+# :main: README.rdoc
##
-# RDoc is a Ruby documentation system which contains RDoc::RDoc for generating
-# documentation, RDoc::RI for interactive documentation and RDoc::Markup for
-# text markup.
+# RDoc produces documentation for Ruby source files by parsing the source and
+# extracting the definition for classes, modules, methods, includes and
+# requires. It associates these with optional documentation contained in an
+# immediately preceding comment block then renders the result using an output
+# formatter.
#
-# RDoc::RDoc produces documentation for Ruby source files. It works similarly
-# to JavaDoc, parsing the source and extracting the definition for classes,
-# modules, methods, includes and requires. It associates these with optional
-# documentation contained in an immediately preceding comment block then
-# renders the result using an output formatter.
-#
-# RDoc::Markup 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.
-#
-# RDoc::RI implements the +ri+ command-line tool which displays on-line
-# documentation for ruby classes, methods, etc. +ri+ features several output
-# formats and an interactive mode (<tt>ri -i</tt>). See <tt>ri --help</tt>
-# for further details.
+# For a simple introduction to writing or generating documentation using RDoc
+# see the README.
#
# == Roadmap
#
-# * If you want to use RDoc to create documentation for your Ruby source files,
-# see RDoc::Markup and refer to <tt>rdoc --help</tt> for command line
-# usage.
-# * If you want to write documentation for Ruby files see RDoc::Parser::Ruby
-# * If you want to write documentation for extensions written in C see
-# RDoc::Parser::C
-# * If you want to generate documentation using <tt>rake</tt> see RDoc::Task.
-# * If you want to drive RDoc programmatically, see RDoc::RDoc.
-# * If you want to use the library to format text blocks into HTML, look at
-# RDoc::Markup.
-# * If you want to make an RDoc plugin such as a generator or directive
-# handler see RDoc::RDoc.
-# * If you want to write your own output generator see RDoc::Generator.
-#
-# == Summary
+# If you think you found a bug in RDoc see DEVELOPERS@Bugs
#
-# Once installed, you can create documentation using the +rdoc+ command
+# If you want to use RDoc to create documentation for your Ruby source files,
+# see RDoc::Markup and refer to <tt>rdoc --help</tt> for command line usage.
#
-# % rdoc [options] [names...]
+# If you want to set the default markup format see
+# RDoc::Markup@Supported+Formats
#
-# For an up-to-date option summary, type
+# If you want to store rdoc configuration in your gem (such as the default
+# markup format) see RDoc::Options@Saved+Options
#
-# % rdoc --help
+# If you want to write documentation for Ruby files see RDoc::Parser::Ruby
#
-# A typical use might be to generate documentation for a package of Ruby
-# source (such as RDoc itself).
+# If you want to write documentation for extensions written in C see
+# RDoc::Parser::C
#
-# % rdoc
+# If you want to generate documentation using <tt>rake</tt> see RDoc::Task.
#
-# 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+.
+# If you want to drive RDoc programmatically, see RDoc::RDoc.
#
-# 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
+# If you want to use the library to format text blocks into HTML or other
+# formats, look at RDoc::Markup.
#
-# % rdoc --main README.txt
+# If you want to make an RDoc plugin such as a generator or directive handler
+# see RDoc::RDoc.
#
-# You'll find information on the various formatting tricks you can use
-# in comment blocks in the documentation this generates.
+# If you want to write your own output generator see RDoc::Generator.
#
-# RDoc uses file extensions to determine how to process each file. File names
-# ending +.rb+ and +.rbw+ are assumed to be Ruby source. Files
-# ending +.c+ are parsed as C files. All other files are assumed to
-# contain just Markup-style markup (with or without leading '#' comment
-# markers). If directory names are passed to RDoc, they are scanned
-# recursively for C and Ruby source files only.
+# If you want an overview of how RDoc works see DEVELOPERS
#
-# == Other stuff
+# == Credits
#
# RDoc is currently being maintained by Eric Hodel <drbrain@segment7.net>.
#
# Dave Thomas <dave@pragmaticprogrammer.com> is the original author of RDoc.
#
-# == Credits
-#
# * The Ruby parser in rdoc/parse.rb is based heavily on the outstanding
# work of Keiju ISHITSUKA of Nippon Rational Inc, who produced the Ruby
# parser for irb and the rtags package.
@@ -92,19 +61,10 @@ module RDoc
class Error < RuntimeError; end
- 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 = '3.9.4'
+ VERSION = '4.0'
##
# Method visibilities
@@ -143,5 +103,80 @@ module RDoc
METHOD_MODIFIERS = GENERAL_MODIFIERS +
%w[arg args yield yields notnew not-new not_new doc]
+ ##
+ # Loads the best available YAML library.
+
+ def self.load_yaml
+ begin
+ gem 'psych'
+ rescue Gem::LoadError
+ end
+
+ begin
+ require 'psych'
+ rescue ::LoadError
+ ensure
+ require 'yaml'
+ end
+ end
+
+ autoload :RDoc, 'rdoc/rdoc'
+
+ autoload :TestCase, 'rdoc/test_case'
+
+ autoload :CrossReference, 'rdoc/cross_reference'
+ autoload :ERBIO, 'rdoc/erbio'
+ autoload :ERBPartial, 'rdoc/erb_partial'
+ autoload :Encoding, 'rdoc/encoding'
+ autoload :Generator, 'rdoc/generator'
+ autoload :Options, 'rdoc/options'
+ autoload :Parser, 'rdoc/parser'
+ autoload :Servlet, 'rdoc/servlet'
+ autoload :RI, 'rdoc/ri'
+ autoload :Stats, 'rdoc/stats'
+ autoload :Store, 'rdoc/store'
+ autoload :Task, 'rdoc/task'
+ autoload :Text, 'rdoc/text'
+
+ autoload :Markdown, 'rdoc/markdown'
+ autoload :Markup, 'rdoc/markup'
+ autoload :RD, 'rdoc/rd'
+ autoload :TomDoc, 'rdoc/tom_doc'
+
+ autoload :KNOWN_CLASSES, 'rdoc/known_classes'
+
+ autoload :RubyLex, 'rdoc/ruby_lex'
+ autoload :RubyToken, 'rdoc/ruby_token'
+ autoload :TokenStream, 'rdoc/token_stream'
+
+ autoload :Comment, 'rdoc/comment'
+
+ # code objects
+ #
+ # We represent the various high-level code constructs that appear in Ruby
+ # programs: classes, modules, methods, and so on.
+ autoload :CodeObject, 'rdoc/code_object'
+
+ autoload :Context, 'rdoc/context'
+ autoload :TopLevel, 'rdoc/top_level'
+
+ autoload :AnonClass, 'rdoc/anon_class'
+ autoload :ClassModule, 'rdoc/class_module'
+ autoload :NormalClass, 'rdoc/normal_class'
+ autoload :NormalModule, 'rdoc/normal_module'
+ autoload :SingleClass, 'rdoc/single_class'
+
+ autoload :Alias, 'rdoc/alias'
+ autoload :AnyMethod, 'rdoc/any_method'
+ autoload :MethodAttr, 'rdoc/method_attr'
+ autoload :GhostMethod, 'rdoc/ghost_method'
+ autoload :MetaMethod, 'rdoc/meta_method'
+ autoload :Attr, 'rdoc/attr'
+
+ autoload :Constant, 'rdoc/constant'
+ autoload :Include, 'rdoc/include'
+ autoload :Extend, 'rdoc/extend'
+ autoload :Require, 'rdoc/require'
+
end
diff --git a/lib/rdoc/alias.rb b/lib/rdoc/alias.rb
index fa433dc0a9..39d2694817 100644
--- a/lib/rdoc/alias.rb
+++ b/lib/rdoc/alias.rb
@@ -1,5 +1,3 @@
-require 'rdoc/code_object'
-
##
# Represent an alias, which is an old_name/new_name pair associated with a
# particular context
diff --git a/lib/rdoc/anon_class.rb b/lib/rdoc/anon_class.rb
index 63c09e11f1..c23d8e5d96 100644
--- a/lib/rdoc/anon_class.rb
+++ b/lib/rdoc/anon_class.rb
@@ -1,5 +1,3 @@
-require 'rdoc/class_module'
-
##
# An anonymous class like:
#
diff --git a/lib/rdoc/any_method.rb b/lib/rdoc/any_method.rb
index c008edfe95..c3d68e87b4 100644
--- a/lib/rdoc/any_method.rb
+++ b/lib/rdoc/any_method.rb
@@ -1,12 +1,16 @@
-require 'rdoc/method_attr'
-require 'rdoc/token_stream'
-
##
# AnyMethod is the base class for objects representing methods
class RDoc::AnyMethod < RDoc::MethodAttr
- MARSHAL_VERSION = 1 # :nodoc:
+ ##
+ # 2::
+ # RDoc 4
+ # Added calls_super
+ # Added parent name and class
+ # Added section title
+
+ MARSHAL_VERSION = 2 # :nodoc:
##
# Don't rename \#initialize to \::new
@@ -28,6 +32,11 @@ class RDoc::AnyMethod < RDoc::MethodAttr
attr_accessor :params
+ ##
+ # If true this method uses +super+ to call a superclass version
+
+ attr_accessor :calls_super
+
include RDoc::TokenStream
##
@@ -39,6 +48,8 @@ class RDoc::AnyMethod < RDoc::MethodAttr
@c_function = nil
@dont_rename_initialize = false
@token_stream = nil
+ @calls_super = false
+ @superclass_method = nil
end
##
@@ -97,6 +108,10 @@ class RDoc::AnyMethod < RDoc::MethodAttr
aliases,
@params,
@file.absolute_name,
+ @calls_super,
+ @parent.name,
+ @parent.class,
+ @section.title,
]
end
@@ -107,34 +122,44 @@ class RDoc::AnyMethod < RDoc::MethodAttr
# * #full_name
# * #parent_name
- def marshal_load(array)
+ def marshal_load array
@dont_rename_initialize = nil
@is_alias_for = nil
@token_stream = nil
@aliases = []
-
- version = array[0]
- @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 = nil
+ @parent_name = nil
+ @parent_class = nil
+ @section = nil
+ @file = nil
+
+ version = array[0]
+ @name = array[1]
+ @full_name = array[2]
+ @singleton = array[3]
+ @visibility = array[4]
+ @comment = array[5]
+ @call_seq = array[6]
+ @block_params = array[7]
+ # 8 handled below
+ @params = array[9]
+ # 10 handled below
+ @calls_super = array[11]
+ @parent_name = array[12]
+ @parent_title = array[13]
+ @section_title = array[14]
array[8].each do |new_name, comment|
add_alias RDoc::Alias.new(nil, @name, new_name, comment, @singleton)
end
- @params = array[9]
-
- @parent_name = if @full_name =~ /#/ then
- $`
- else
- name = @full_name.split('::')
- name.pop
- name.join '::'
- end
+ @parent_name ||= if @full_name =~ /#/ then
+ $`
+ else
+ name = @full_name.split('::')
+ name.pop
+ name.join '::'
+ end
@file = RDoc::TopLevel.new array[10] if version > 0
end
@@ -169,7 +194,9 @@ class RDoc::AnyMethod < RDoc::MethodAttr
return []
end
- params.gsub(/\s+/, '').split ','
+ params = params.gsub(/\s+/, '').split ','
+
+ params.map { |param| param.sub(/=.*/, '') }
end
##
@@ -181,10 +208,12 @@ class RDoc::AnyMethod < RDoc::MethodAttr
params = @call_seq.split("\n").last
params = params.sub(/[^( ]+/, '')
params = params.sub(/(\|[^|]+\|)\s*\.\.\.\s*(end|\})/, '\1 \2')
- else
+ elsif @params then
params = @params.gsub(/\s*\#.*/, '')
params = params.tr("\n", " ").squeeze(" ")
params = "(#{params})" unless params[0] == ?(
+ else
+ params = ''
end
if @block_params then
@@ -203,5 +232,31 @@ class RDoc::AnyMethod < RDoc::MethodAttr
params
end
+ ##
+ # Sets the store for this method and its referenced code objects.
+
+ def store= store
+ super
+
+ @file = @store.add_file @file.full_name if @file
+ end
+
+ ##
+ # For methods that +super+, find the superclass method that would be called.
+
+ def superclass_method
+ return unless @calls_super
+ return @superclass_method if @superclass_method
+
+ parent.each_ancestor do |ancestor|
+ if method = ancestor.method_list.find { |m| m.name == @name } then
+ @superclass_method = method
+ break
+ end
+ end
+
+ @superclass_method
+ end
+
end
diff --git a/lib/rdoc/attr.rb b/lib/rdoc/attr.rb
index 5d9bc17831..0eb1c0d79b 100644
--- a/lib/rdoc/attr.rb
+++ b/lib/rdoc/attr.rb
@@ -1,12 +1,16 @@
-require 'rdoc/method_attr'
-
##
# An attribute created by \#attr, \#attr_reader, \#attr_writer or
# \#attr_accessor
class RDoc::Attr < RDoc::MethodAttr
- MARSHAL_VERSION = 2 # :nodoc:
+ ##
+ # 3::
+ # RDoc 4
+ # Added parent name and class
+ # Added section title
+
+ MARSHAL_VERSION = 3 # :nodoc:
##
# Is the attribute readable ('R'), writable ('W') or both ('RW')?
@@ -58,6 +62,16 @@ class RDoc::Attr < RDoc::MethodAttr
end
##
+ # Attributes never call super. See RDoc::AnyMethod#calls_super
+ #
+ # An RDoc::Attr can show up in the method list in some situations (see
+ # Gem::ConfigFile)
+
+ def calls_super # :nodoc:
+ false
+ end
+
+ ##
# Returns attr_reader, attr_writer or attr_accessor as appropriate.
def definition
@@ -93,6 +107,9 @@ class RDoc::Attr < RDoc::MethodAttr
parse(@comment),
singleton,
@file.absolute_name,
+ @parent.full_name,
+ @parent.class,
+ @section.title
]
end
@@ -104,17 +121,28 @@ class RDoc::Attr < RDoc::MethodAttr
# * #parent_name
def marshal_load array
- version = array[0]
- @name = array[1]
- @full_name = array[2]
- @rw = array[3]
- @visibility = array[4]
- @comment = array[5]
- @singleton = array[6] || false # MARSHAL_VERSION == 0
+ @aliases = []
+ @parent = nil
+ @parent_name = nil
+ @parent_class = nil
+ @section = nil
+ @file = nil
+
+ version = array[0]
+ @name = array[1]
+ @full_name = array[2]
+ @rw = array[3]
+ @visibility = array[4]
+ @comment = array[5]
+ @singleton = array[6] || false # MARSHAL_VERSION == 0
+ # 7 handled below
+ @parent_name = array[8]
+ @parent_class = array[9]
+ @section_title = array[10]
@file = RDoc::TopLevel.new array[7] if version > 1
- @parent_name = @full_name
+ @parent_name ||= @full_name.split('#', 2).first
end
def pretty_print q # :nodoc:
@@ -132,5 +160,14 @@ class RDoc::Attr < RDoc::MethodAttr
"#{definition} #{name} in: #{parent}"
end
+ ##
+ # Attributes do not have token streams.
+ #
+ # An RDoc::Attr can show up in the method list in some situations (see
+ # Gem::ConfigFile)
+
+ def token_stream # :nodoc:
+ end
+
end
diff --git a/lib/rdoc/class_module.rb b/lib/rdoc/class_module.rb
index 27066d8bd7..04f0132b7d 100644
--- a/lib/rdoc/class_module.rb
+++ b/lib/rdoc/class_module.rb
@@ -1,5 +1,3 @@
-require 'rdoc/context'
-
##
# ClassModule is the base class for objects representing either a class or a
# module.
@@ -13,8 +11,17 @@ class RDoc::ClassModule < RDoc::Context
# * Added file to constants
# * Added file to includes
# * Added file to methods
-
- MARSHAL_VERSION = 1 # :nodoc:
+ # 2::
+ # RDoc 3.13
+ # * Added extends
+ # 3::
+ # RDoc 4.0
+ # * Added sections
+ # * Added in_files
+ # * Added parent name
+ # * Complete Constant dump
+
+ MARSHAL_VERSION = 3 # :nodoc:
##
# Constants that are aliases for this class or module
@@ -56,6 +63,7 @@ class RDoc::ClassModule < RDoc::Context
klass.external_aliases.concat mod.external_aliases
klass.constants.concat mod.constants
klass.includes.concat mod.includes
+ klass.extends.concat mod.extends
klass.methods_hash.update mod.methods_hash
klass.constants_hash.update mod.constants_hash
@@ -84,6 +92,7 @@ class RDoc::ClassModule < RDoc::Context
klass.external_aliases +
klass.constants +
klass.includes +
+ klass.extends +
klass.classes +
klass.modules).each do |obj|
obj.parent = klass
@@ -115,16 +124,32 @@ class RDoc::ClassModule < RDoc::Context
# across multiple runs.
def add_comment comment, location
- return if comment.empty? or not document_self
+ return unless document_self
original = comment
- comment = normalize_comment comment
+ comment = case comment
+ when RDoc::Comment then
+ comment.normalize
+ else
+ normalize_comment comment
+ end
@comment_location << [comment, location]
self.comment = original
end
+ def add_things my_things, other_things # :nodoc:
+ other_things.each do |group, things|
+ my_things[group].each { |thing| yield false, thing } if
+ my_things.include? group
+
+ things.each do |thing|
+ yield true, thing
+ end
+ end
+ end
+
##
# Ancestors list for this ClassModule: the list of included modules
# (classes will add their superclass if any).
@@ -142,6 +167,11 @@ class RDoc::ClassModule < RDoc::Context
end
##
+ # Ancestors of this class or module only
+
+ alias direct_ancestors ancestors
+
+ ##
# Clears the comment. Used by the ruby parser.
def clear_comment
@@ -155,9 +185,13 @@ class RDoc::ClassModule < RDoc::Context
# more like <tt>+=</tt>.
def comment= comment
- return if comment.empty?
+ comment = case comment
+ when RDoc::Comment then
+ comment.normalize
+ else
+ normalize_comment comment
+ end
- comment = normalize_comment comment
comment = "#{@comment}\n---\n#{comment}" unless @comment.empty?
super comment
@@ -166,7 +200,7 @@ class RDoc::ClassModule < RDoc::Context
##
# Prepares this ClassModule for use by a generator.
#
- # See RDoc::TopLevel::complete
+ # See RDoc::Store#complete
def complete min_visibility
update_aliases
@@ -176,12 +210,22 @@ class RDoc::ClassModule < RDoc::Context
end
##
+ # Does this ClassModule or any of its methods have document_self set?
+
+ def document_self_or_methods
+ document_self || method_list.any?{ |m| m.document_self }
+ end
+
+ ##
# Iterates the ancestors of this class or module for which an
# RDoc::ClassModule exists.
def each_ancestor # :yields: module
+ return enum_for __method__ unless block_given?
+
ancestors.each do |mod|
next if String === mod
+ next if self == mod
yield mod
end
end
@@ -215,8 +259,8 @@ class RDoc::ClassModule < RDoc::Context
# Return the fully qualified name of this class or module
def full_name
- @full_name ||= if RDoc::ClassModule === @parent then
- "#{@parent.full_name}::#{@name}"
+ @full_name ||= if RDoc::ClassModule === parent then
+ "#{parent.full_name}::#{@name}"
else
@name
end
@@ -250,13 +294,20 @@ class RDoc::ClassModule < RDoc::Context
@superclass,
parse(@comment_location),
attrs,
- constants.map do |const|
- [const.name, parse(const.comment), const.file_name]
- end,
+ constants,
includes.map do |incl|
[incl.name, parse(incl.comment), incl.file_name]
end,
method_types,
+ extends.map do |ext|
+ [ext.name, parse(ext.comment), ext.file_name]
+ end,
+ @sections.values,
+ @in_files.map do |tl|
+ tl.absolute_name
+ end,
+ parent.full_name,
+ parent.class,
]
end
@@ -268,6 +319,8 @@ class RDoc::ClassModule < RDoc::Context
@parent = nil
@temporary_section = nil
@visibility = nil
+ @classes = {}
+ @modules = {}
@name = array[1]
@full_name = array[2]
@@ -291,9 +344,14 @@ class RDoc::ClassModule < RDoc::Context
attr.record_location RDoc::TopLevel.new file
end
- array[6].each do |name, comment, file|
- const = add_constant RDoc::Constant.new(name, nil, comment)
- const.record_location RDoc::TopLevel.new file
+ array[6].each do |constant, comment, file|
+ case constant
+ when RDoc::Constant then
+ add_constant constant
+ else
+ constant = add_constant RDoc::Constant.new(constant, nil, comment)
+ constant.record_location RDoc::TopLevel.new file
+ end
end
array[7].each do |name, comment, file|
@@ -313,6 +371,27 @@ class RDoc::ClassModule < RDoc::Context
end
end
end
+
+ array[9].each do |name, comment, file|
+ ext = add_extend RDoc::Extend.new(name, comment)
+ ext.record_location RDoc::TopLevel.new file
+ end if array[9] # Support Marshal version 1
+
+ sections = (array[10] || []).map do |section|
+ [section.title, section]
+ end
+
+ @sections = Hash[*sections.flatten]
+ @current_section = add_section nil
+
+ @in_files = []
+
+ (array[11] || []).each do |filename|
+ record_location RDoc::TopLevel.new filename
+ end
+
+ @parent_name = array[12]
+ @parent_class = array[13]
end
##
@@ -321,6 +400,9 @@ class RDoc::ClassModule < RDoc::Context
# The data in +class_module+ is preferred over the receiver.
def merge class_module
+ @parent = class_module.parent
+ @parent_name = class_module.parent_name
+
other_document = parse class_module.comment_location
if other_document then
@@ -360,6 +442,18 @@ class RDoc::ClassModule < RDoc::Context
end
end
+ @includes.uniq! # clean up
+
+ merge_collections extends, cm.extends, other_files do |add, ext|
+ if add then
+ add_extend ext
+ else
+ @extends.delete ext
+ end
+ end
+
+ @extends.uniq! # clean up
+
merge_collections method_list, cm.method_list, other_files do |add, meth|
if add then
add_method meth
@@ -369,6 +463,8 @@ class RDoc::ClassModule < RDoc::Context
end
end
+ merge_sections cm
+
self
end
@@ -391,22 +487,46 @@ class RDoc::ClassModule < RDoc::Context
my_things = mine. group_by { |thing| thing.file }
other_things = other.group_by { |thing| thing.file }
- my_things.delete_if do |file, things|
- next false unless other_files.include? file
+ remove_things my_things, other_files, &block
+ add_things my_things, other_things, &block
+ end
- things.each do |thing|
- yield false, thing
- end
+ ##
+ # Merges the comments in this ClassModule with the comments in the other
+ # ClassModule +cm+.
- true
+ def merge_sections cm # :nodoc:
+ my_sections = sections.group_by { |section| section.title }
+ other_sections = cm.sections.group_by { |section| section.title }
+
+ other_files = cm.in_files
+
+ remove_things my_sections, other_files do |_, section|
+ @sections.delete section.title
end
- other_things.each do |file, things|
- my_things[file].each { |thing| yield false, thing } if
- my_things.include?(file)
+ other_sections.each do |group, sections|
+ if my_sections.include? group
+ my_sections[group].each do |my_section|
+ other_section = cm.sections_hash[group]
- things.each do |thing|
- yield true, thing
+ my_comments = my_section.comments
+ other_comments = other_section.comments
+
+ other_files = other_section.in_files
+
+ merge_collections my_comments, other_comments, other_files do |add, comment|
+ if add then
+ my_section.add_comment comment
+ else
+ my_section.remove_comment comment
+ end
+ end
+ end
+ else
+ sections.each do |section|
+ add_section group, section.comments
+ end
end
end
end
@@ -438,11 +558,15 @@ class RDoc::ClassModule < RDoc::Context
when Array then
docs = comment_location.map do |comment, location|
doc = super comment
- doc.file = location.absolute_name
+ doc.file = location
doc
end
RDoc::Markup::Document.new(*docs)
+ when RDoc::Comment then
+ doc = super comment_location.text, comment_location.format
+ doc.file = comment_location.location
+ doc
when RDoc::Markup::Document then
return comment_location
else
@@ -451,10 +575,10 @@ class RDoc::ClassModule < RDoc::Context
end
##
- # Path to this class or module
+ # Path to this class or module for use with HTML generator output.
def path
- http_url RDoc::RDoc.current.generator.class_dir
+ http_url @store.rdoc.generator.class_dir
end
##
@@ -488,21 +612,61 @@ class RDoc::ClassModule < RDoc::Context
modules_hash.each_key do |name|
full_name = prefix + name
- modules_hash.delete name unless RDoc::TopLevel.all_modules_hash[full_name]
+ modules_hash.delete name unless @store.modules_hash[full_name]
end
classes_hash.each_key do |name|
full_name = prefix + name
- classes_hash.delete name unless RDoc::TopLevel.all_classes_hash[full_name]
+ classes_hash.delete name unless @store.classes_hash[full_name]
end
end
+ def remove_things my_things, other_files # :nodoc:
+ my_things.delete_if do |file, things|
+ next false unless other_files.include? file
+
+ things.each do |thing|
+ yield false, thing
+ end
+
+ true
+ end
+ end
+
+ ##
+ # Search record used by RDoc::Generator::JsonIndex
+
+ def search_record
+ [
+ name,
+ full_name,
+ full_name,
+ '',
+ path,
+ '',
+ snippet(@comment_location),
+ ]
+ end
+
+ ##
+ # Sets the store for this class or module and its contained code objects.
+
+ def store= store
+ super
+
+ @attributes .each do |attr| attr.store = store end
+ @constants .each do |const| const.store = store end
+ @includes .each do |incl| incl.store = store end
+ @extends .each do |ext| ext.store = store end
+ @method_list.each do |meth| meth.store = store end
+ 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(@superclass) || @superclass
+ @store.find_class_named(@superclass) || @superclass
end
##
@@ -533,7 +697,7 @@ class RDoc::ClassModule < RDoc::Context
# aliases through a constant.
#
# The aliased module/class is replaced in the children and in
- # RDoc::TopLevel::all_modules_hash or RDoc::TopLevel::all_classes_hash
+ # RDoc::Store#modules_hash or RDoc::Store#classes_hash
# by a copy that has <tt>RDoc::ClassModule#is_alias_for</tt> set to
# the aliased module/class, and this copy is added to <tt>#aliases</tt>
# of the aliased module/class.
@@ -548,16 +712,21 @@ class RDoc::ClassModule < RDoc::Context
next unless cm = const.is_alias_for
cm_alias = cm.dup
cm_alias.name = const.name
- cm_alias.parent = self
- cm_alias.full_name = nil # force update for new parent
+
+ # Don't move top-level aliases under Object, they look ugly there
+ unless RDoc::TopLevel === cm_alias.parent then
+ cm_alias.parent = self
+ cm_alias.full_name = nil # force update for new parent
+ end
+
cm_alias.aliases.clear
cm_alias.is_alias_for = cm
if cm.module? then
- RDoc::TopLevel.all_modules_hash[cm_alias.full_name] = cm_alias
+ @store.modules_hash[cm_alias.full_name] = cm_alias
modules_hash[const.name] = cm_alias
else
- RDoc::TopLevel.all_classes_hash[cm_alias.full_name] = cm_alias
+ @store.classes_hash[cm_alias.full_name] = cm_alias
classes_hash[const.name] = cm_alias
end
@@ -574,8 +743,26 @@ class RDoc::ClassModule < RDoc::Context
def update_includes
includes.reject! do |include|
mod = include.module
- !(String === mod) && RDoc::TopLevel.all_modules_hash[mod.full_name].nil?
+ !(String === mod) && @store.modules_hash[mod.full_name].nil?
end
+
+ includes.uniq!
+ end
+
+ ##
+ # Deletes from #extends those whose module has been removed from the
+ # documentation.
+ #--
+ # FIXME: like update_includes, extends are not reliably removed
+
+ def update_extends
+ extends.reject! do |ext|
+ mod = ext.module
+
+ !(String === mod) && @store.modules_hash[mod.full_name].nil?
+ end
+
+ extends.uniq!
end
end
diff --git a/lib/rdoc/code_object.rb b/lib/rdoc/code_object.rb
index 54826fffbd..e2d9d909da 100644
--- a/lib/rdoc/code_object.rb
+++ b/lib/rdoc/code_object.rb
@@ -1,6 +1,3 @@
-require 'rdoc'
-require 'rdoc/text'
-
##
# Base class for the RDoc code tree.
#
@@ -78,9 +75,9 @@ class RDoc::CodeObject
attr_accessor :offset
##
- # Our parent CodeObject
+ # Sets the parent CodeObject
- attr_accessor :parent
+ attr_writer :parent
##
# Did we ever receive a +:nodoc:+ directive?
@@ -88,9 +85,14 @@ class RDoc::CodeObject
attr_reader :received_nodoc
##
- # Which section are we in
+ # Set the section this CodeObject is in
- attr_accessor :section
+ attr_writer :section
+
+ ##
+ # The RDoc::Store for this object.
+
+ attr_accessor :store
##
# We are the model of the code, but we know that at some point we will be
@@ -103,11 +105,16 @@ class RDoc::CodeObject
# Creates a new CodeObject that will document itself and its children
def initialize
- @metadata = {}
- @comment = ''
- @parent = nil
- @file = nil
- @full_name = nil
+ @metadata = {}
+ @comment = ''
+ @parent = nil
+ @parent_name = nil # for loading
+ @parent_class = nil # for loading
+ @section = nil
+ @section_title = nil # for loading
+ @file = nil
+ @full_name = nil
+ @store = nil
@document_children = true
@document_self = true
@@ -124,11 +131,11 @@ class RDoc::CodeObject
@comment = case comment
when NilClass then ''
when RDoc::Markup::Document then comment
+ when RDoc::Comment then comment.normalize
else
if comment and not comment.empty? then
normalize_comment comment
else
- # TODO is this sufficient?
# HACK correct fix is to have #initialize create @comment
# with the correct encoding
if String === @comment and
@@ -216,7 +223,7 @@ class RDoc::CodeObject
##
# Force the documentation of this object unless documentation
- # has been turned off by :endoc:
+ # has been turned off by :enddoc:
#--
# HACK untested, was assigning to an ivar
@@ -262,6 +269,29 @@ class RDoc::CodeObject
end
##
+ # Our parent CodeObject. The parent may be missing for classes loaded from
+ # legacy RI data stores.
+
+ def parent
+ return @parent if @parent
+ return nil unless @parent_name
+
+ if @parent_class == RDoc::TopLevel then
+ @parent = @store.add_file @parent_name
+ else
+ @parent = @store.find_class_or_module @parent_name
+
+ return @parent if @parent
+
+ begin
+ @parent = @store.load_class @parent_name
+ rescue RDoc::Store::MissingFileError
+ nil
+ end
+ end
+ end
+
+ ##
# File name of our parent
def parent_file_name
@@ -284,8 +314,18 @@ class RDoc::CodeObject
end
##
+ # The section this CodeObject is in. Sections allow grouping of constants,
+ # attributes and methods inside a class or module.
+
+ def section
+ return @section if @section
+
+ @section = parent.add_section @section_title if parent
+ end
+
+ ##
# Enable capture of documentation unless documentation has been
- # turned off by :endoc:
+ # turned off by :enddoc:
def start_doc
return if @done_documenting
diff --git a/lib/rdoc/code_objects.rb b/lib/rdoc/code_objects.rb
index c60dad92df..f1a626cd2e 100644
--- a/lib/rdoc/code_objects.rb
+++ b/lib/rdoc/code_objects.rb
@@ -1,23 +1,5 @@
-# We represent the various high-level code constructs that appear in Ruby
-# programs: classes, modules, methods, and so on.
+# This file was used to load all the RDoc::CodeObject subclasses at once. Now
+# autoload handles this.
-require 'rdoc/code_object'
-require 'rdoc/context'
-require 'rdoc/top_level'
-
-require 'rdoc/class_module'
-require 'rdoc/normal_class'
-require 'rdoc/normal_module'
-require 'rdoc/anon_class'
-require 'rdoc/single_class'
-
-require 'rdoc/any_method'
-require 'rdoc/alias'
-require 'rdoc/ghost_method'
-require 'rdoc/meta_method'
-
-require 'rdoc/attr'
-require 'rdoc/constant'
-require 'rdoc/require'
-require 'rdoc/include'
+require 'rdoc'
diff --git a/lib/rdoc/comment.rb b/lib/rdoc/comment.rb
new file mode 100644
index 0000000000..25e7c966c8
--- /dev/null
+++ b/lib/rdoc/comment.rb
@@ -0,0 +1,232 @@
+##
+# A comment holds the text comment for a RDoc::CodeObject and provides a
+# unified way of cleaning it up and parsing it into an RDoc::Markup::Document.
+#
+# Each comment may have a different markup format set by #format=. By default
+# 'rdoc' is used. The :markup: directive tells RDoc which format to use.
+#
+# See RDoc::Markup@Other+directives for instructions on adding an alternate
+# format.
+
+class RDoc::Comment
+
+ include RDoc::Text
+
+ ##
+ # The format of this comment. Defaults to RDoc::Markup
+
+ attr_reader :format
+
+ ##
+ # The RDoc::TopLevel this comment was found in
+
+ attr_accessor :location
+
+ ##
+ # For duck-typing when merging classes at load time
+
+ alias file location # :nodoc:
+
+ ##
+ # The text for this comment
+
+ attr_reader :text
+
+ ##
+ # Overrides the content returned by #parse. Use when there is no #text
+ # source for this comment
+
+ attr_writer :document
+
+ ##
+ # Creates a new comment with +text+ that is found in the RDoc::TopLevel
+ # +location+.
+
+ def initialize text = nil, location = nil
+ @location = location
+ @text = text
+
+ @document = nil
+ @format = 'rdoc'
+ @normalized = false
+ end
+
+ ##
+ #--
+ # TODO deep copy @document
+
+ def initialize_copy copy # :nodoc:
+ @text = copy.text.dup
+ end
+
+ def == other # :nodoc:
+ self.class === other and
+ other.text == @text and other.location == @location
+ end
+
+ ##
+ # Look for a 'call-seq' in the comment to override the normal parameter
+ # handling. The :call-seq: is indented from the baseline. All lines of the
+ # same indentation level and prefix are consumed.
+ #
+ # For example, all of the following will be used as the :call-seq:
+ #
+ # # :call-seq:
+ # # ARGF.readlines(sep=$/) -> array
+ # # ARGF.readlines(limit) -> array
+ # # ARGF.readlines(sep, limit) -> array
+ # #
+ # # ARGF.to_a(sep=$/) -> array
+ # # ARGF.to_a(limit) -> array
+ # # ARGF.to_a(sep, limit) -> array
+
+ def extract_call_seq method
+ # we must handle situations like the above followed by an unindented first
+ # comment. The difficulty is to make sure not to match lines starting
+ # with ARGF at the same indent, but that are after the first description
+ # paragraph.
+ if @text =~ /^\s*:?call-seq:(.*?(?:\S).*?)^\s*$/m then
+ all_start, all_stop = $~.offset(0)
+ seq_start, seq_stop = $~.offset(1)
+
+ # we get the following lines that start with the leading word at the
+ # same indent, even if they have blank lines before
+ if $1 =~ /(^\s*\n)+^(\s*\w+)/m then
+ leading = $2 # ' * ARGF' in the example above
+ re = %r%
+ \A(
+ (^\s*\n)+
+ (^#{Regexp.escape leading}.*?\n)+
+ )+
+ ^\s*$
+ %xm
+
+ if @text[seq_stop..-1] =~ re then
+ all_stop = seq_stop + $~.offset(0).last
+ seq_stop = seq_stop + $~.offset(1).last
+ end
+ end
+
+ seq = @text[seq_start..seq_stop]
+ seq.gsub!(/^\s*(\S|\n)/m, '\1')
+ @text.slice! all_start...all_stop
+
+ method.call_seq = seq.chomp
+
+ elsif @text.sub!(/^\s*:?call-seq:(.*?)(^\s*$|\z)/m, '') then
+ seq = $1
+ seq.gsub!(/^\s*/, '')
+ method.call_seq = seq
+ end
+ #elsif @text.sub!(/\A\/\*\s*call-seq:(.*?)\*\/\Z/, '') then
+ # method.call_seq = $1.strip
+ #end
+
+ method
+ end
+
+ ##
+ # A comment is empty if its text String is empty.
+
+ def empty?
+ @text.empty?
+ end
+
+ ##
+ # HACK dubious
+
+ def force_encoding encoding
+ @text.force_encoding encoding
+ end
+
+ ##
+ # Sets the format of this comment and resets any parsed document
+
+ def format= format
+ @format = format
+ @document = nil
+ end
+
+ def inspect # :nodoc:
+ location = @location ? @location.absolute_name : '(unknown)'
+
+ "#<%s:%x %s %p>" % [self.class, object_id, location, @text]
+ end
+
+ ##
+ # Normalizes the text. See RDoc::Text#normalize_comment for details
+
+ def normalize
+ return self unless @text
+ return self if @normalized # TODO eliminate duplicate normalization
+
+ @text = normalize_comment @text
+
+ @normalized = true
+
+ self
+ end
+
+ ##
+ # Was this text normalized?
+
+ def normalized? # :nodoc:
+ @normalized
+ end
+
+ ##
+ # Parses the comment into an RDoc::Markup::Document. The parsed document is
+ # cached until the text is changed.
+
+ def parse
+ return @document if @document
+
+ @document = super @text, @format
+ @document.file = @location
+ @document
+ end
+
+ ##
+ # Removes private sections from this comment. Private sections are flush to
+ # the comment marker and start with <tt>--</tt> and end with <tt>++</tt>.
+ # For C-style comments, a private marker may not start at the opening of the
+ # comment.
+ #
+ # /*
+ # *--
+ # * private
+ # *++
+ # * public
+ # */
+
+ def remove_private
+ # Workaround for gsub encoding for Ruby 1.9.2 and earlier
+ empty = ''
+ empty.force_encoding @text.encoding if Object.const_defined? :Encoding
+
+ @text = @text.gsub(%r%^\s*([#*]?)--.*?^\s*(\1)\+\+\n?%m, empty)
+ @text = @text.sub(%r%^\s*[#*]?--.*%m, '')
+ end
+
+ ##
+ # Replaces this comment's text with +text+ and resets the parsed document.
+ #
+ # An error is raised if the comment contains a document but no text.
+
+ def text= text
+ raise RDoc::Error, 'replacing document-only comment is not allowed' if
+ @text.nil? and @document
+
+ @document = nil
+ @text = text
+ end
+
+ ##
+ # Returns true if this comment is in TomDoc format.
+
+ def tomdoc?
+ @format == 'tomdoc'
+ end
+
+end
+
diff --git a/lib/rdoc/constant.rb b/lib/rdoc/constant.rb
index 056ce130be..d9fcf021ed 100644
--- a/lib/rdoc/constant.rb
+++ b/lib/rdoc/constant.rb
@@ -1,16 +1,14 @@
-require 'rdoc/code_object'
-
##
# A constant
class RDoc::Constant < RDoc::CodeObject
+ MARSHAL_VERSION = 0 # :nodoc:
+
##
- # If this constant is an alias for a module or class,
- # this is the RDoc::ClassModule it is an alias for.
- # +nil+ otherwise.
+ # Sets the module or class this is constant is an alias for.
- attr_accessor :is_alias_for
+ attr_writer :is_alias_for
##
# The constant's name
@@ -23,13 +21,22 @@ class RDoc::Constant < RDoc::CodeObject
attr_accessor :value
##
+ # The constant's visibility
+
+ attr_accessor :visibility
+
+ ##
# Creates a new constant with +name+, +value+ and +comment+
def initialize(name, value, comment)
super()
- @name = name
+
+ @name = name
@value = value
+
@is_alias_for = nil
+ @visibility = nil
+
self.comment = comment
end
@@ -59,6 +66,27 @@ class RDoc::Constant < RDoc::CodeObject
super or is_alias_for && is_alias_for.documented?
end
+ ##
+ # Full constant name including namespace
+
+ def full_name
+ @full_name ||= "#{parent_name}::#{@name}"
+ end
+
+ ##
+ # The module or class this constant is an alias for
+
+ def is_alias_for
+ case @is_alias_for
+ when String then
+ found = @store.find_class_or_module @is_alias_for
+ @is_alias_for = found if found
+ @is_alias_for
+ else
+ @is_alias_for
+ end
+ end
+
def inspect # :nodoc:
"#<%s:0x%x %s::%s>" % [
self.class, object_id,
@@ -67,12 +95,76 @@ class RDoc::Constant < RDoc::CodeObject
end
##
- # Path to this constant
+ # Dumps this Constant for use by ri. See also #marshal_load
+
+ def marshal_dump
+ alias_name = case found = is_alias_for
+ when RDoc::CodeObject then found.full_name
+ else found
+ end
+
+ [ MARSHAL_VERSION,
+ @name,
+ full_name,
+ @visibility,
+ alias_name,
+ parse(@comment),
+ @file.absolute_name,
+ parent.name,
+ parent.class,
+ section.title,
+ ]
+ end
+
+ ##
+ # Loads this Constant from +array+. For a loaded Constant the following
+ # methods will return cached values:
+ #
+ # * #full_name
+ # * #parent_name
+
+ def marshal_load array
+ initialize array[1], nil, array[5]
+
+ @full_name = array[2]
+ @visibility = array[3]
+ @is_alias_for = array[4]
+ # 5 handled above
+ # 6 handled below
+ @parent_name = array[7]
+ @parent_class = array[8]
+ @section_title = array[9]
+
+ @file = RDoc::TopLevel.new array[6]
+ end
+
+ ##
+ # Path to this constant for use with HTML generator output.
def path
"#{@parent.path}##{@name}"
end
+ def pretty_print q # :nodoc:
+ q.group 2, "[#{self.class.name} #{full_name}", "]" do
+ unless comment.empty? then
+ q.breakable
+ q.text "comment:"
+ q.breakable
+ q.pp @comment
+ end
+ end
+ end
+
+ ##
+ # Sets the store for this class or module and its contained code objects.
+
+ def store= store
+ super
+
+ @file = @store.add_file @file.full_name if @file
+ end
+
def to_s # :nodoc:
parent_name = parent ? parent.full_name : '(unknown)'
if is_alias_for
diff --git a/lib/rdoc/context.rb b/lib/rdoc/context.rb
index abdab2026d..6f9deae4a8 100644
--- a/lib/rdoc/context.rb
+++ b/lib/rdoc/context.rb
@@ -1,4 +1,4 @@
-require 'rdoc/code_object'
+require 'cgi'
##
# A Context is something that can hold modules, classes, methods, attributes,
@@ -15,6 +15,12 @@ class RDoc::Context < RDoc::CodeObject
TYPES = %w[class instance]
##
+ # If a context has these titles it will be sorted in this order.
+
+ TOMDOC_TITLES = [nil, 'Public', 'Internal', 'Deprecated'] # :nodoc:
+ TOMDOC_TITLES_SORT = TOMDOC_TITLES.sort_by { |title| title.to_s } # :nodoc:
+
+ ##
# Class/module aliases
attr_reader :aliases
@@ -25,6 +31,11 @@ class RDoc::Context < RDoc::CodeObject
attr_reader :attributes
##
+ # Block params to be used in the next MethodAttr parsed under this context
+
+ attr_accessor :block_params
+
+ ##
# Constants defined
attr_reader :constants
@@ -45,6 +56,11 @@ class RDoc::Context < RDoc::CodeObject
attr_reader :includes
##
+ # Modules this context is extended with
+
+ attr_reader :extends
+
+ ##
# Methods defined in this context
attr_reader :method_list
@@ -72,7 +88,7 @@ class RDoc::Context < RDoc::CodeObject
attr_accessor :unmatched_alias_lists
##
- # Aliases that could not eventually be resolved.
+ # Aliases that could not be resolved.
attr_reader :external_aliases
@@ -88,121 +104,14 @@ class RDoc::Context < RDoc::CodeObject
attr_reader :methods_hash
##
- # Hash of registered constants.
+ # Params to be used in the next MethodAttr parsed under this context
- attr_reader :constants_hash
+ attr_accessor :params
##
- # A section of documentation like:
- #
- # # :section: The title
- # # The body
- #
- # Sections can be referenced multiple times and will be collapsed into a
- # single section.
-
- class Section
-
- include RDoc::Text
-
- ##
- # Section comment
-
- attr_reader :comment
-
- ##
- # Context this Section lives in
-
- attr_reader :parent
-
- ##
- # Section title
-
- attr_reader :title
-
- @@sequence = "SEC00000"
-
- ##
- # Creates a new section with +title+ and +comment+
-
- def initialize parent, title, comment
- @parent = parent
- @title = title ? title.strip : title
-
- @@sequence.succ!
- @sequence = @@sequence.dup
-
- @comment = extract_comment comment
- end
-
- ##
- # Sections are equal when they have the same #title
-
- def == other
- self.class === other and @title == other.title
- end
-
- ##
- # Anchor reference for linking to this section
-
- def aref
- title = @title || '[untitled]'
-
- CGI.escape(title).gsub('%', '-').sub(/^-/, '')
- end
-
- ##
- # Appends +comment+ to the current comment separated by a rule.
-
- def comment= comment
- comment = extract_comment comment
-
- return if comment.empty?
-
- if @comment then
- @comment += "\n# ---\n#{comment}"
- else
- @comment = comment
- end
- end
-
- ##
- # Extracts 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 extract_comment comment
- if comment =~ /^#[ \t]*:section:.*\n/ then
- start = $`
- rest = $'
-
- if start.empty? then
- rest
- else
- rest.sub(/#{start.chomp}\Z/, '')
- end
- else
- comment
- end
- end
-
- def inspect # :nodoc:
- "#<%s:0x%x %p>" % [self.class, object_id, title]
- end
-
- ##
- # Section sequence number (deprecated)
-
- def sequence
- warn "RDoc::Context::Section#sequence is deprecated, use #aref"
- @sequence
- end
+ # Hash of registered constants.
- end
+ attr_reader :constants_hash
##
# Creates an unnamed empty context with public current visibility
@@ -235,6 +144,7 @@ class RDoc::Context < RDoc::CodeObject
@aliases = []
@requires = []
@includes = []
+ @extends = []
@constants = []
@external_aliases = []
@@ -242,8 +152,12 @@ class RDoc::Context < RDoc::CodeObject
# a method not yet encountered).
@unmatched_alias_lists = {}
- @methods_hash = {}
+ @methods_hash = {}
@constants_hash = {}
+
+ @params = nil
+
+ @store ||= nil
end
##
@@ -366,12 +280,12 @@ class RDoc::Context < RDoc::CodeObject
if full_name =~ /^(.+)::(\w+)$/ then
name = $2
ename = $1
- enclosing = RDoc::TopLevel.classes_hash[ename] ||
- RDoc::TopLevel.modules_hash[ename]
+ enclosing = @store.classes_hash[ename] || @store.modules_hash[ename]
# HACK: crashes in actionpack/lib/action_view/helpers/form_helper.rb (metaprogramming)
unless enclosing then
# try the given name at top level (will work for the above example)
- enclosing = RDoc::TopLevel.classes_hash[given_name] || RDoc::TopLevel.modules_hash[given_name]
+ enclosing = @store.classes_hash[given_name] ||
+ @store.modules_hash[given_name]
return enclosing if enclosing
# not found: create the parent(s)
names = ename.split('::')
@@ -410,7 +324,7 @@ class RDoc::Context < RDoc::CodeObject
end
# did we believe it was a module?
- mod = RDoc::TopLevel.modules_hash.delete superclass
+ mod = @store.modules_hash.delete superclass
upgrade_to_class mod, RDoc::NormalClass, mod.parent if mod
@@ -418,7 +332,7 @@ class RDoc::Context < RDoc::CodeObject
superclass = nil if superclass == full_name
end
- klass = RDoc::TopLevel.classes_hash[full_name]
+ klass = @store.classes_hash[full_name]
if klass then
# if TopLevel, it may not be registered in the classes:
@@ -435,7 +349,7 @@ class RDoc::Context < RDoc::CodeObject
end
else
# this is a new class
- mod = RDoc::TopLevel.modules_hash.delete full_name
+ mod = @store.modules_hash.delete full_name
if mod then
klass = upgrade_to_class mod, RDoc::NormalClass, enclosing
@@ -445,10 +359,12 @@ class RDoc::Context < RDoc::CodeObject
klass = class_type.new name, superclass
enclosing.add_class_or_module(klass, enclosing.classes_hash,
- RDoc::TopLevel.classes_hash)
+ @store.classes_hash)
end
end
+ klass.parent = self
+
klass
end
@@ -463,6 +379,7 @@ class RDoc::Context < RDoc::CodeObject
mod.section = current_section # TODO declaring context? something is
# wrong here...
mod.parent = self
+ mod.store = @store
unless @done_documenting then
self_hash[mod.name] = mod
@@ -504,13 +421,21 @@ class RDoc::Context < RDoc::CodeObject
# Adds included module +include+ which should be an RDoc::Include
def add_include include
- add_to @includes, include unless
- @includes.map { |i| i.full_name }.include? include.full_name
+ add_to @includes, include
include
end
##
+ # Adds extension module +ext+ which should be an RDoc::Extend
+
+ def add_extend ext
+ add_to @extends, ext
+
+ ext
+ end
+
+ ##
# Adds +method+ if not already there. If it is (as method or attribute),
# updates the comment if it was empty.
@@ -523,6 +448,10 @@ class RDoc::Context < RDoc::CodeObject
if known then
known.comment = method.comment if known.comment.empty?
+ previously = ", previously in #{known.file}" unless
+ method.file == known.file
+ @store.rdoc.options.warn \
+ "Duplicate method #{known.full_name} in #{method.file}#{previously}"
else
@methods_hash[key] = method
method.visibility = @visibility
@@ -542,9 +471,9 @@ class RDoc::Context < RDoc::CodeObject
return mod if mod
full_name = child_name name
- mod = RDoc::TopLevel.modules_hash[full_name] || class_type.new(name)
+ mod = @store.modules_hash[full_name] || class_type.new(name)
- add_class_or_module(mod, @modules, RDoc::TopLevel.modules_hash)
+ add_class_or_module mod, @modules, @store.modules_hash
end
##
@@ -554,31 +483,34 @@ class RDoc::Context < RDoc::CodeObject
def add_module_alias from, name, file
return from if @done_documenting
- to_name = child_name(name)
+ to_name = child_name name
# if we already know this name, don't register an alias:
# see the metaprogramming in lib/active_support/basic_object.rb,
- # where we already know BasicObject as a class when we find
+ # where we already know BasicObject is a class when we find
# BasicObject = BlankSlate
- return from if RDoc::TopLevel.find_class_or_module(to_name)
+ return from if @store.find_class_or_module to_name
- if from.module? then
- RDoc::TopLevel.modules_hash[to_name] = from
- @modules[name] = from
+ to = from.dup
+ to.name = name
+ to.full_name = nil
+
+ if to.module? then
+ @store.modules_hash[to_name] = to
+ @modules[name] = to
else
- RDoc::TopLevel.classes_hash[to_name] = from
- @classes[name] = from
+ @store.classes_hash[to_name] = to
+ @classes[name] = to
end
- # HACK: register a constant for this alias:
- # constant value and comment will be updated after,
- # when the Ruby parser adds the constant
- const = RDoc::Constant.new name, nil, ''
+ # Registers a constant for this alias. The constant value and comment
+ # will be updated later, when the Ruby parser adds the constant
+ const = RDoc::Constant.new name, nil, to.comment
const.record_location file
const.is_alias_for = from
add_constant const
- from
+ to
end
##
@@ -602,9 +534,9 @@ class RDoc::Context < RDoc::CodeObject
#
# See also RDoc::Context::Section
- def add_section title, comment
+ def add_section title, comment = nil
if section = @sections[title] then
- section.comment = comment
+ section.add_comment comment if comment
else
section = Section.new self, title, comment
@sections[title] = section
@@ -616,9 +548,11 @@ class RDoc::Context < RDoc::CodeObject
##
# Adds +thing+ to the collection +array+
- def add_to(array, thing)
+ def add_to array, thing
array << thing if @document_self
- thing.parent = self
+
+ thing.parent = self
+ thing.store = @store if @store
thing.section = current_section
end
@@ -628,7 +562,7 @@ class RDoc::Context < RDoc::CodeObject
# This means any of: comment, aliases, methods, attributes, external
# aliases, require, constant.
#
- # Includes are also checked unless <tt>includes == false</tt>.
+ # Includes and extends are also checked unless <tt>includes == false</tt>.
def any_content(includes = true)
@any_content ||= !(
@@ -640,7 +574,7 @@ class RDoc::Context < RDoc::CodeObject
@requires.empty? &&
@constants.empty?
)
- @any_content || (includes && !@includes.empty?)
+ @any_content || (includes && !(@includes + @extends).empty? )
end
##
@@ -723,6 +657,9 @@ class RDoc::Context < RDoc::CodeObject
##
# Iterator for ancestors for duck-typing. Does nothing. See
# RDoc::ClassModule#each_ancestor.
+ #
+ # This method exists to make it easy to work with Context subclasses that
+ # aren't part of RDoc.
def each_ancestor # :nodoc:
end
@@ -756,10 +693,19 @@ class RDoc::Context < RDoc::CodeObject
end
##
+ # Iterator for extension modules
+
+ def each_extend # :yields: extend
+ @extends.each do |e| yield e end
+ end
+
+ ##
# Iterator for methods
def each_method # :yields: method
- @method_list.sort.each {|m| yield m}
+ return enum_for __method__ unless block_given?
+
+ @method_list.sort.each { |m| yield m }
end
##
@@ -773,13 +719,15 @@ class RDoc::Context < RDoc::CodeObject
# NOTE: Do not edit collections yielded by this method
def each_section # :yields: section, constants, attributes
- constants = @constants.group_by do |constant| constant.section end
- constants.default = []
+ return enum_for __method__ unless block_given?
+ constants = @constants.group_by do |constant| constant.section end
attributes = @attributes.group_by do |attribute| attribute.section end
+
+ constants.default = []
attributes.default = []
- @sections.sort_by { |title, _| title.to_s }.each do |_, section|
+ sort_sections.each do |section|
yield section, constants[section].sort, attributes[section].sort
end
end
@@ -851,8 +799,8 @@ class RDoc::Context < RDoc::CodeObject
##
# Finds a file with +name+ in this context
- def find_file_named(name)
- top_level.class.find_file_named(name)
+ def find_file_named name
+ @store.find_file_named name
end
##
@@ -922,21 +870,21 @@ class RDoc::Context < RDoc::CodeObject
# look for a class or module 'symbol'
case symbol
when /^::/ then
- result = RDoc::TopLevel.find_class_or_module(symbol)
+ result = @store.find_class_or_module symbol
when /^(\w+):+(.+)$/
suffix = $2
top = $1
searched = self
- loop do
+ while searched do
mod = searched.find_module_named(top)
break unless mod
- result = RDoc::TopLevel.find_class_or_module(mod.full_name + '::' + suffix)
+ result = @store.find_class_or_module "#{mod.full_name}::#{suffix}"
break if result || searched.is_a?(RDoc::TopLevel)
searched = searched.parent
end
else
searched = self
- loop do
+ while searched do
result = searched.find_module_named(symbol)
break if result || searched.is_a?(RDoc::TopLevel)
searched = searched.parent
@@ -985,6 +933,8 @@ class RDoc::Context < RDoc::CodeObject
##
# Instance methods
+ #--
+ # TODO rename to instance_methods
def instance_method_list
@instance_method_list ||= method_list.reject { |a| a.singleton }
@@ -1098,24 +1048,23 @@ class RDoc::Context < RDoc::CodeObject
##
# Only called when min_visibility == :public or :private
- def remove_invisible_in(array, min_visibility) # :nodoc:
- if min_visibility == :public
+ def remove_invisible_in array, min_visibility # :nodoc:
+ if min_visibility == :public then
array.reject! { |e|
e.visibility != :public and not e.force_documentation
}
else
array.reject! { |e|
- e.visibility == :private and
- not e.force_documentation
+ e.visibility == :private and not e.force_documentation
}
end
end
##
- # Tries to resolve unmatched aliases when a method
- # or attribute has just been added.
+ # Tries to resolve unmatched aliases when a method or attribute has just
+ # been added.
- def resolve_aliases(added)
+ def resolve_aliases added
# resolve any pending unmatched aliases
key = added.pretty_name
unmatched_alias_list = @unmatched_alias_lists[key]
@@ -1128,6 +1077,31 @@ class RDoc::Context < RDoc::CodeObject
end
##
+ # Returns RDoc::Context::Section objects referenced in this context for use
+ # in a table of contents.
+
+ def section_contents
+ used_sections = {}
+
+ each_method do |method|
+ next unless method.display?
+
+ used_sections[method.section] = true
+ end
+
+ # order found sections
+ sections = sort_sections.select do |section|
+ used_sections[section]
+ end
+
+ # only the default section is used
+ return [] if
+ sections.length == 1 and not sections.first.title
+
+ sections
+ end
+
+ ##
# Sections in this context
def sections
@@ -1155,6 +1129,26 @@ class RDoc::Context < RDoc::CodeObject
end
end
+ ##
+ # Sorts sections alphabetically (default) or in TomDoc fashion (none,
+ # Public, Internal, Deprecated)
+
+ def sort_sections
+ titles = @sections.map { |title, _| title }
+
+ if titles.length > 1 and
+ TOMDOC_TITLES_SORT ==
+ (titles | TOMDOC_TITLES).sort_by { |title| title.to_s } then
+ @sections.values_at(*TOMDOC_TITLES).compact
+ else
+ @sections.sort_by { |title, _|
+ title.to_s
+ }.map { |_, section|
+ section
+ }
+ end
+ end
+
def to_s # :nodoc:
"#{self.class.name} #{self.full_name}"
end
@@ -1179,13 +1173,16 @@ class RDoc::Context < RDoc::CodeObject
enclosing.modules_hash.delete mod.name
klass = RDoc::ClassModule.from_module class_type, mod
+ klass.store = @store
# if it was there, then we keep it even if done_documenting
- RDoc::TopLevel.classes_hash[mod.full_name] = klass
- enclosing.classes_hash[mod.name] = klass
+ @store.classes_hash[mod.full_name] = klass
+ enclosing.classes_hash[mod.name] = klass
klass
end
+ autoload :Section, 'rdoc/context/section'
+
end
diff --git a/lib/rdoc/context/section.rb b/lib/rdoc/context/section.rb
new file mode 100644
index 0000000000..580f07deff
--- /dev/null
+++ b/lib/rdoc/context/section.rb
@@ -0,0 +1,238 @@
+##
+# A section of documentation like:
+#
+# # :section: The title
+# # The body
+#
+# Sections can be referenced multiple times and will be collapsed into a
+# single section.
+
+class RDoc::Context::Section
+
+ include RDoc::Text
+
+ MARSHAL_VERSION = 0 # :nodoc:
+
+ ##
+ # Section comment
+
+ attr_reader :comment
+
+ ##
+ # Section comments
+
+ attr_reader :comments
+
+ ##
+ # Context this Section lives in
+
+ attr_reader :parent
+
+ ##
+ # Section title
+
+ attr_reader :title
+
+ @@sequence = "SEC00000"
+
+ ##
+ # Creates a new section with +title+ and +comment+
+
+ def initialize parent, title, comment
+ @parent = parent
+ @title = title ? title.strip : title
+
+ @@sequence.succ!
+ @sequence = @@sequence.dup
+
+ @comments = []
+
+ add_comment comment
+ end
+
+ ##
+ # Sections are equal when they have the same #title
+
+ def == other
+ self.class === other and @title == other.title
+ end
+
+ ##
+ # Adds +comment+ to this section
+
+ def add_comment comment
+ comment = extract_comment comment
+
+ return if comment.empty?
+
+ case comment
+ when RDoc::Comment then
+ @comments << comment
+ when RDoc::Markup::Document then
+ @comments.concat comment.parts
+ when Array then
+ @comments.concat comment
+ else
+ raise TypeError, "unknown comment type: #{comment.inspect}"
+ end
+ end
+
+ ##
+ # Anchor reference for linking to this section
+
+ def aref
+ title = @title || '[untitled]'
+
+ CGI.escape(title).gsub('%', '-').sub(/^-/, '')
+ end
+
+ ##
+ # Extracts 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 extract_comment comment
+ case comment
+ when Array then
+ comment.map do |c|
+ extract_comment c
+ end
+ when nil
+ RDoc::Comment.new ''
+ when RDoc::Comment then
+ if comment.text =~ /^#[ \t]*:section:.*\n/ then
+ start = $`
+ rest = $'
+
+ comment.text = if start.empty? then
+ rest
+ else
+ rest.sub(/#{start.chomp}\Z/, '')
+ end
+ end
+
+ comment
+ when RDoc::Markup::Document then
+ comment
+ else
+ raise TypeError, "unknown comment #{comment.inspect}"
+ end
+ end
+
+ def inspect # :nodoc:
+ "#<%s:0x%x %p>" % [self.class, object_id, title]
+ end
+
+ ##
+ # The files comments in this section come from
+
+ def in_files
+ return [] if @comments.empty?
+
+ case @comments
+ when Array then
+ @comments.map do |comment|
+ comment.file
+ end
+ when RDoc::Markup::Document then
+ @comment.parts.map do |document|
+ document.file
+ end
+ else
+ raise RDoc::Error, "BUG: unknown comment class #{@comments.class}"
+ end
+ end
+
+ ##
+ # Serializes this Section. The title and parsed comment are saved, but not
+ # the section parent which must be restored manually.
+
+ def marshal_dump
+ [
+ MARSHAL_VERSION,
+ @title,
+ parse,
+ ]
+ end
+
+ ##
+ # De-serializes this Section. The section parent must be restored manually.
+
+ def marshal_load array
+ @parent = nil
+
+ @title = array[1]
+ @comments = array[2]
+ end
+
+ ##
+ # Parses +comment_location+ into an RDoc::Markup::Document composed of
+ # multiple RDoc::Markup::Documents with their file set.
+
+ def parse
+ case @comments
+ when String then
+ super
+ when Array then
+ docs = @comments.map do |comment, location|
+ doc = super comment
+ doc.file = location if location
+ doc
+ end
+
+ RDoc::Markup::Document.new(*docs)
+ when RDoc::Comment then
+ doc = super @comments.text, comments.format
+ doc.file = @comments.location
+ doc
+ when RDoc::Markup::Document then
+ return @comments
+ else
+ raise ArgumentError, "unknown comment class #{comments.class}"
+ end
+ end
+
+ ##
+ # The section's title, or 'Top Section' if the title is nil.
+ #
+ # This is used by the table of contents template so the name is silly.
+
+ def plain_html
+ @title || 'Top Section'
+ end
+
+ ##
+ # Removes a comment from this section if it is from the same file as
+ # +comment+
+
+ def remove_comment comment
+ return if @comments.empty?
+
+ case @comments
+ when Array then
+ @comments.delete_if do |my_comment|
+ my_comment.file == comment.file
+ end
+ when RDoc::Markup::Document then
+ @comments.parts.delete_if do |document|
+ document.file == comment.file.name
+ end
+ else
+ raise RDoc::Error, "BUG: unknown comment class #{@comments.class}"
+ end
+ end
+
+ ##
+ # Section sequence number (deprecated)
+
+ def sequence
+ warn "RDoc::Context::Section#sequence is deprecated, use #aref"
+ @sequence
+ end
+
+end
+
diff --git a/lib/rdoc/cross_reference.rb b/lib/rdoc/cross_reference.rb
index adeef2661a..c6f127387c 100644
--- a/lib/rdoc/cross_reference.rb
+++ b/lib/rdoc/cross_reference.rb
@@ -18,7 +18,7 @@ class RDoc::CrossReference
#
# See CLASS_REGEXP_STR
- METHOD_REGEXP_STR = '([a-z]\w*[!?=]?)(?:\([\w.+*/=<>-]*\))?'
+ METHOD_REGEXP_STR = '([a-z]\w*[!?=]?|%)(?:\([\w.+*/=<>-]*\))?'
##
# Regular expressions matching text that should potentially have
@@ -27,63 +27,79 @@ class RDoc::CrossReference
# have been suppressed, since the suppression characters are removed by the
# code that is triggered.
- CROSSREF_REGEXP = /(
- # A::B::C.meth
- #{CLASS_REGEXP_STR}(?:[.#]|::)#{METHOD_REGEXP_STR}
-
- # Stand-alone method (preceded by a #)
- | \\?\##{METHOD_REGEXP_STR}
-
- # Stand-alone method (preceded by ::)
- | ::#{METHOD_REGEXP_STR}
-
- # A::B::C
- # The stuff after CLASS_REGEXP_STR is a
- # nasty hack. CLASS_REGEXP_STR unfortunately matches
- # words like dog and cat (these are legal "class"
- # names in Fortran 95). When a word is flagged as a
- # potential cross-reference, limitations in the markup
- # engine suppress other processing, such as typesetting.
- # This is particularly noticeable for contractions.
- # In order that words like "can't" not
- # be flagged as potential cross-references, only
- # flag potential class cross-references if the character
- # after the cross-reference is a space, sentence
- # punctuation, tag start character, or attribute
- # marker.
- | #{CLASS_REGEXP_STR}(?=[\s\)\.\?\!\,\;<\000]|\z)
-
- # Things that look like filenames
- # The key thing is that there must be at least
- # one special character (period, slash, or
- # underscore).
- | (?:\.\.\/)*[-\/\w]+[_\/\.][-\w\/\.]+
-
- # Things that have markup suppressed
- # Don't process things like '\<' in \<tt>, though.
- # TODO: including < is a hack, not very satisfying.
- | \\[^\s<]
- )/x
+ CROSSREF_REGEXP = /(?:^|\s)
+ (
+ (?:
+ # A::B::C.meth
+ #{CLASS_REGEXP_STR}(?:[.#]|::)#{METHOD_REGEXP_STR}
+
+ # Stand-alone method (preceded by a #)
+ | \\?\##{METHOD_REGEXP_STR}
+
+ # Stand-alone method (preceded by ::)
+ | ::#{METHOD_REGEXP_STR}
+
+ # A::B::C
+ # The stuff after CLASS_REGEXP_STR is a
+ # nasty hack. CLASS_REGEXP_STR unfortunately matches
+ # words like dog and cat (these are legal "class"
+ # names in Fortran 95). When a word is flagged as a
+ # potential cross-reference, limitations in the markup
+ # engine suppress other processing, such as typesetting.
+ # This is particularly noticeable for contractions.
+ # In order that words like "can't" not
+ # be flagged as potential cross-references, only
+ # flag potential class cross-references if the character
+ # after the cross-reference is a space, sentence
+ # punctuation, tag start character, or attribute
+ # marker.
+ | #{CLASS_REGEXP_STR}(?=[@\s).?!,;<\000]|\z)
+
+ # Things that look like filenames
+ # The key thing is that there must be at least
+ # one special character (period, slash, or
+ # underscore).
+ | (?:\.\.\/)*[-\/\w]+[_\/.][-\w\/.]+
+
+ # Things that have markup suppressed
+ # Don't process things like '\<' in \<tt>, though.
+ # TODO: including < is a hack, not very satisfying.
+ | \\[^\s<]
+ )
+
+ # labels for headings
+ (?:@[\w+%-]+(?:\.[\w|%-]+)?)?
+ )/x
##
# Version of CROSSREF_REGEXP used when <tt>--hyperlink-all</tt> is specified.
- ALL_CROSSREF_REGEXP = /(
- # A::B::C.meth
- #{CLASS_REGEXP_STR}(?:[.#]|::)#{METHOD_REGEXP_STR}
+ ALL_CROSSREF_REGEXP = /
+ (?:^|\s)
+ (
+ (?:
+ # A::B::C.meth
+ #{CLASS_REGEXP_STR}(?:[.#]|::)#{METHOD_REGEXP_STR}
- # Stand-alone method
- | \\?#{METHOD_REGEXP_STR}
+ # Stand-alone method
+ | \\?#{METHOD_REGEXP_STR}
- # A::B::C
- | #{CLASS_REGEXP_STR}(?=[\s\)\.\?\!\,\;<\000]|\z)
+ # A::B::C
+ | #{CLASS_REGEXP_STR}(?=[@\s).?!,;<\000]|\z)
- # Things that look like filenames
- | (?:\.\.\/)*[-\/\w]+[_\/\.][-\w\/\.]+
+ # Things that look like filenames
+ | (?:\.\.\/)*[-\/\w]+[_\/.][-\w\/.]+
- # Things that have markup suppressed
- | \\[^\s<]
- )/x
+ # Things that have markup suppressed
+ | \\[^\s<]
+ )
+
+ # labels for headings
+ (?:@[\w+%-]+)?
+ )/x
+
+ ##
+ # Hash of references that have been looked-up to their replacements
attr_accessor :seen
@@ -93,6 +109,7 @@ class RDoc::CrossReference
def initialize context
@context = context
+ @store = context.store
@seen = {}
end
@@ -107,16 +124,6 @@ class RDoc::CrossReference
def resolve name, text
return @seen[name] if @seen.include? name
- # Find class, module, or method in class or module.
- #
- # Do not, however, use an if/elsif/else chain to do so. Instead, test
- # each possible pattern until one matches. The reason for this is that a
- # string like "YAML.txt" could be the txt() class method of class YAML (in
- # which case it would match the first pattern, which splits the string
- # into container and method components and looks up both) or a filename
- # (in which case it would match the last pattern, which just checks
- # whether the string as a whole is a known symbol).
-
if /#{CLASS_REGEXP_STR}([.#]|::)#{METHOD_REGEXP_STR}/o =~ name then
type = $2
type = '' if type == '.' # will find either #method or ::method
@@ -141,12 +148,15 @@ class RDoc::CrossReference
ref = case name
when /^\\(#{CLASS_REGEXP_STR})$/o then
- ref = @context.find_symbol $1
+ @context.find_symbol $1
else
- ref = @context.find_symbol name
+ @context.find_symbol name
end unless ref
- ref = nil if RDoc::Alias === ref # external alias: can't link to it
+ # Try a page name
+ ref = @store.page name if not ref and name =~ /^\w+$/
+
+ ref = nil if RDoc::Alias === ref # external alias, can't link to it
out = if name == '\\' then
name
diff --git a/lib/rdoc/encoding.rb b/lib/rdoc/encoding.rb
index ab752ee665..0b1ec6728e 100644
--- a/lib/rdoc/encoding.rb
+++ b/lib/rdoc/encoding.rb
@@ -1,7 +1,5 @@
# coding: US-ASCII
-require 'rdoc'
-
##
# This class is a wrapper around File IO and Encoding that helps RDoc load
# files and convert them to the correct encoding.
@@ -27,26 +25,40 @@ module RDoc::Encoding
RDoc::Encoding.set_encoding content
if Object.const_defined? :Encoding then
- encoding ||= Encoding.default_external
- orig_encoding = content.encoding
-
- if utf8 then
- content.force_encoding Encoding::UTF_8
- content.encode! encoding
- else
- # assume the content is in our output encoding
- content.force_encoding encoding
- end
-
- unless content.valid_encoding? then
- # revert and try to transcode
- content.force_encoding orig_encoding
- content.encode! encoding
- end
-
- unless content.valid_encoding? then
- warn "unable to convert #{filename} to #{encoding}, skipping"
- content = nil
+ begin
+ encoding ||= Encoding.default_external
+ orig_encoding = content.encoding
+
+ if utf8 then
+ content.force_encoding Encoding::UTF_8
+ content.encode! encoding
+ else
+ # assume the content is in our output encoding
+ content.force_encoding encoding
+ end
+
+ unless content.valid_encoding? then
+ # revert and try to transcode
+ content.force_encoding orig_encoding
+ content.encode! encoding
+ end
+
+ unless content.valid_encoding? then
+ warn "unable to convert #{filename} to #{encoding}, skipping"
+ content = nil
+ end
+ rescue Encoding::InvalidByteSequenceError,
+ Encoding::UndefinedConversionError => e
+ if force_transcode then
+ content.force_encoding orig_encoding
+ content.encode!(encoding,
+ :invalid => :replace, :undef => :replace,
+ :replace => '?')
+ return content
+ else
+ warn "unable to convert #{e.message} for #{filename}, skipping"
+ return nil
+ end
end
end
@@ -55,15 +67,6 @@ module RDoc::Encoding
raise unless e.message =~ /unknown encoding name - (.*)/
warn "unknown encoding name \"#{$1}\" for #{filename}, skipping"
nil
- rescue Encoding::UndefinedConversionError => e
- if force_transcode then
- content.force_encoding orig_encoding
- content.encode! encoding, :undef => :replace, :replace => '?'
- content
- else
- warn "unable to convert #{e.message} for #{filename}, skipping"
- nil
- end
rescue Errno::EISDIR, Errno::ENOENT
nil
end
diff --git a/lib/rdoc/erb_partial.rb b/lib/rdoc/erb_partial.rb
new file mode 100644
index 0000000000..910d1e0351
--- /dev/null
+++ b/lib/rdoc/erb_partial.rb
@@ -0,0 +1,18 @@
+##
+# Allows an ERB template to be rendered in the context (binding) of an
+# existing ERB template evaluation.
+
+class RDoc::ERBPartial < ERB
+
+ ##
+ # Overrides +compiler+ startup to set the +eoutvar+ to an empty string only
+ # if it isn't already set.
+
+ def set_eoutvar compiler, eoutvar = '_erbout'
+ super
+
+ compiler.pre_cmd = ["#{eoutvar} ||= ''"]
+ end
+
+end
+
diff --git a/lib/rdoc/extend.rb b/lib/rdoc/extend.rb
new file mode 100644
index 0000000000..2bccfba084
--- /dev/null
+++ b/lib/rdoc/extend.rb
@@ -0,0 +1,117 @@
+##
+# A Module extension in a class with \#extend
+
+class RDoc::Extend < RDoc::CodeObject
+
+ ##
+ # Name of extension module
+
+ attr_accessor :name
+
+ ##
+ # Creates a new Extend for +name+ with +comment+
+
+ def initialize(name, comment)
+ super()
+ @name = name
+ self.comment = comment
+ @module = nil # cache for module if found
+ end
+
+ ##
+ # Extends are sorted by name
+
+ def <=> other
+ return unless self.class === other
+
+ name <=> other.name
+ end
+
+ def == other # :nodoc:
+ self.class === other and @name == other.name
+ end
+
+ alias eql? ==
+
+ ##
+ # Full name based on #module
+
+ def full_name
+ m = self.module
+ RDoc::ClassModule === m ? m.full_name : @name
+ end
+
+ def hash # :nodoc:
+ [@name, self.module].hash
+ end
+
+ def inspect # :nodoc:
+ "#<%s:0x%x %s.extend %s>" % [
+ self.class,
+ object_id,
+ parent_name, @name,
+ ]
+ end
+
+ ##
+ # Attempts to locate the extend module object. Returns the name if not
+ # known.
+ #
+ # The scoping rules of Ruby to resolve the name of an extension module are:
+ # - first look into the children of the current context;
+ # - if not found, look into the children of extension modules,
+ # in reverse extend order;
+ # - if still not found, go up the hierarchy of names.
+ #
+ # This method has <code>O(n!)</code> behavior when the module calling
+ # extend is referencing nonexistent modules. Avoid calling #module until
+ # after all the files are parsed. This behavior is due to ruby's constant
+ # lookup behavior.
+
+ def module
+ return @module if @module
+
+ # search the current context
+ return @name unless parent
+ full_name = parent.child_name(@name)
+ @module = @store.modules_hash[full_name]
+ return @module if @module
+ return @name if @name =~ /^::/
+
+ # search the includes before this one, in reverse order
+ searched = parent.extends.take_while { |i| i != self }.reverse
+ searched.each do |i|
+ ext = i.module
+ next if String === ext
+ full_name = ext.child_name(@name)
+ @module = @store.modules_hash[full_name]
+ return @module if @module
+ end
+
+ # go up the hierarchy of names
+ up = parent.parent
+ while up
+ full_name = up.child_name(@name)
+ @module = @store.modules_hash[full_name]
+ return @module if @module
+ up = up.parent
+ end
+
+ @name
+ end
+
+ ##
+ # Sets the store for this class or module and its contained code objects.
+
+ def store= store
+ super
+
+ @file = @store.add_file @file.full_name if @file
+ end
+
+ def to_s # :nodoc:
+ "extend #@name in: #{parent}"
+ end
+
+end
+
diff --git a/lib/rdoc/generator.rb b/lib/rdoc/generator.rb
index 2fa891f533..9051f8a658 100644
--- a/lib/rdoc/generator.rb
+++ b/lib/rdoc/generator.rb
@@ -1,12 +1,10 @@
-require 'rdoc'
-
##
# RDoc uses generators to turn parsed source code in the form of an
# RDoc::CodeObject tree into some form of output. RDoc comes with the HTML
# generator RDoc::Generator::Darkfish and an ri data generator
# RDoc::Generator::RI.
#
-# = Registering a Generator
+# == Registering a Generator
#
# Generators are registered by calling RDoc::RDoc.add_generator with the class
# of the generator:
@@ -15,26 +13,38 @@ require 'rdoc'
# RDoc::RDoc.add_generator self
# end
#
-# = Adding Options to +rdoc+
+# == Adding Options to +rdoc+
#
# Before option processing in +rdoc+, RDoc::Options will call ::setup_options
# on the generator class with an RDoc::Options instance. The generator can
# use RDoc::Options#option_parser to add command-line options to the +rdoc+
-# tool. See OptionParser for details on how to add options.
+# tool. See RDoc::Options@Custom+Options for an example and see OptionParser
+# for details on how to add options.
#
# You can extend the RDoc::Options instance with additional accessors for your
# generator.
#
-# = Generator Instantiation
+# == Generator Instantiation
#
# After parsing, RDoc::RDoc will instantiate a generator by calling
-# #initialize with an RDoc::Options instance.
+# #initialize with an RDoc::Store instance and an RDoc::Options instance.
+#
+# The RDoc::Store instance holds documentation for parsed source code. In
+# RDoc 3 and earlier the RDoc::TopLevel class held this data. When upgrading
+# a generator from RDoc 3 and earlier you should only need to replace
+# RDoc::TopLevel with the store instance.
#
-# RDoc will then call #generate on the generator instance and pass in an Array
-# of RDoc::TopLevel instances, each representing a parsed file. You can use
-# the various class methods on RDoc::TopLevel and in the RDoc::CodeObject tree
-# to create your desired output format.
+# RDoc will then call #generate on the generator instance. You can use the
+# various methods on RDoc::Store and in the RDoc::CodeObject tree to create
+# your desired output format.
module RDoc::Generator
+
+ autoload :Markup, 'rdoc/generator/markup'
+
+ autoload :Darkfish, 'rdoc/generator/darkfish'
+ autoload :JsonIndex, 'rdoc/generator/json_index'
+ autoload :RI, 'rdoc/generator/ri'
+
end
diff --git a/lib/rdoc/generator/darkfish.rb b/lib/rdoc/generator/darkfish.rb
index a3ffea0ce8..bd0f617d84 100644
--- a/lib/rdoc/generator/darkfish.rb
+++ b/lib/rdoc/generator/darkfish.rb
@@ -1,9 +1,8 @@
# -*- mode: ruby; ruby-indent-level: 2; tab-width: 2 -*-
-require 'pathname'
+require 'erb'
require 'fileutils'
-require 'rdoc/erbio'
-
+require 'pathname'
require 'rdoc/generator/markup'
##
@@ -46,6 +45,11 @@ require 'rdoc/generator/markup'
# 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.
+#
+# == Attributions
+#
+# Darkfish uses the {Silk Icons}[http://www.famfamfam.com/lab/icons/silk/] set
+# by Mark James.
class RDoc::Generator::Darkfish
@@ -53,6 +57,7 @@ class RDoc::Generator::Darkfish
include ERB::Util
+ ##
# Path to this file's parent directory. Used to find templates and other
# resources.
@@ -61,7 +66,7 @@ class RDoc::Generator::Darkfish
##
# Release Version
- VERSION = '2'
+ VERSION = '3'
##
# Description of this generator
@@ -69,19 +74,58 @@ class RDoc::Generator::Darkfish
DESCRIPTION = 'HTML generator, written by Michael Granger'
##
- # Initialize a few instance variables before we start
+ # The relative path to style sheets and javascript. By default this is set
+ # the same as the rel_prefix.
- def initialize options
- @options = options
+ attr_accessor :asset_rel_path
- @template_dir = Pathname.new options.template_dir
- @template_cache = {}
+ ##
+ # The path to generate files into, combined with <tt>--op</tt> from the
+ # options for a full path.
- @files = nil
- @classes = nil
+ attr_reader :base_dir
- @basedir = Pathname.pwd.expand_path
- end
+ ##
+ # Classes and modules to be used by this generator, not necessarily
+ # displayed. See also #modsort
+
+ attr_reader :classes
+
+ ##
+ # No files will be written when dry_run is true.
+
+ attr_accessor :dry_run
+
+ ##
+ # When false the generate methods return a String instead of writing to a
+ # file. The default is true.
+
+ attr_accessor :file_output
+
+ ##
+ # Files to be displayed by this generator
+
+ attr_reader :files
+
+ ##
+ # The JSON index generator for this Darkfish generator
+
+ attr_reader :json_index
+
+ ##
+ # Methods to be displayed by this generator
+
+ attr_reader :methods
+
+ ##
+ # Sorted list of classes and modules to be displayed by this generator
+
+ attr_reader :modsort
+
+ ##
+ # The RDoc::Store that is the source of the generated content
+
+ attr_reader :store
##
# The output directory
@@ -89,6 +133,29 @@ class RDoc::Generator::Darkfish
attr_reader :outputdir
##
+ # Initialize a few instance variables before we start
+
+ def initialize store, options
+ @store = store
+ @options = options
+
+ @asset_rel_path = ''
+ @base_dir = Pathname.pwd.expand_path
+ @dry_run = @options.dry_run
+ @file_output = true
+ @template_dir = Pathname.new options.template_dir
+ @template_cache = {}
+
+ @classes = nil
+ @context = nil
+ @files = nil
+ @methods = nil
+ @modsort = nil
+
+ @json_index = RDoc::Generator::JsonIndex.new self, options
+ end
+
+ ##
# Output progress information if debugging is enabled
def debug_msg *msg
@@ -126,7 +193,7 @@ class RDoc::Generator::Darkfish
def write_style_sheet
debug_msg "Copying static files"
- options = { :verbose => $DEBUG_RDOC, :noop => @options.dry_run }
+ options = { :verbose => $DEBUG_RDOC, :noop => @dry_run }
FileUtils.cp @template_dir + 'rdoc.css', '.', options
@@ -134,7 +201,7 @@ class RDoc::Generator::Darkfish
next if File.directory? path
next if File.basename(path) =~ /^\./
- dst = Pathname.new(path).relative_path_from @template_dir
+ dst = Pathname.new(path).relative_path_from @template_dir
# I suck at glob
dst_dir = dst.dirname
@@ -148,19 +215,17 @@ class RDoc::Generator::Darkfish
# 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)
+ def generate
+ setup
- # Now actually write the output
write_style_sheet
generate_index
generate_class_files
generate_file_files
+ generate_table_of_contents
+ @json_index.generate
+
+ copy_static
rescue => e
debug_msg "%s: %s\n %s" % [
@@ -170,42 +235,64 @@ class RDoc::Generator::Darkfish
raise
end
- protected
-
##
- # Return a list of the documented modules sorted by salience first, then
- # by name.
+ # Copies static files from the static_path into the output directory
+
+ def copy_static
+ return if @options.static_path.empty?
- 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
+ fu_options = { :verbose => $DEBUG_RDOC, :noop => @dry_run }
- counthash
+ @options.static_path.each do |path|
+ unless File.directory? path then
+ FileUtils.install path, @outputdir, fu_options.merge(:mode => 0644)
+ next
+ end
+
+ Dir.chdir path do
+ Dir[File.join('**', '*')].each do |entry|
+ dest_file = @outputdir + entry
+
+ if File.directory? entry then
+ FileUtils.mkdir_p entry, fu_options
+ else
+ FileUtils.install entry, dest_file, fu_options.merge(:mode => 0644)
+ end
+ end
+ end
end
+ 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|
+ ##
+ # Return a list of the documented modules sorted by salience first, then
+ # by name.
+
+ def get_sorted_module_list classes
+ classes.select do |klass|
klass.display?
- end
+ end.sort
end
##
# Generate an index page which lists all the classes which are documented.
def generate_index
+ setup
+
template_file = @template_dir + 'index.rhtml'
return unless template_file.exist?
debug_msg "Rendering the index page..."
- out_file = @basedir + @options.op_dir + 'index.html'
+ out_file = @base_dir + @options.op_dir + 'index.html'
+ rel_prefix = @outputdir.relative_path_from out_file.dirname
+ search_index_rel_prefix = rel_prefix
+ search_index_rel_prefix += @asset_rel_path if @file_output
+
+ # suppress 1.9.3 warning
+ asset_rel_prefix = asset_rel_prefix = rel_prefix + @asset_rel_path
+
+ @title = @options.title
render_template template_file, out_file do |io| binding end
rescue => e
@@ -217,10 +304,40 @@ class RDoc::Generator::Darkfish
end
##
- # Generate a documentation file for each class
+ # Generates a class file for +klass+
+
+ def generate_class klass, template_file = nil
+ setup
+
+ current = klass
+
+ template_file ||= @template_dir + 'class.rhtml'
+
+ debug_msg " working on %s (%s)" % [klass.full_name, klass.path]
+ out_file = @outputdir + klass.path
+ rel_prefix = @outputdir.relative_path_from out_file.dirname
+ search_index_rel_prefix = rel_prefix
+ search_index_rel_prefix += @asset_rel_path if @file_output
+
+ # suppress 1.9.3 warning
+ asset_rel_prefix = asset_rel_prefix = rel_prefix + @asset_rel_path
+ svninfo = svninfo = get_svninfo(current)
+
+ @title = "#{klass.type} #{klass.full_name} - #{@options.title}"
+
+ debug_msg " rendering #{out_file}"
+ render_template template_file, out_file do |io| binding end
+ end
+
+ ##
+ # Generate a documentation file for each class and module
def generate_class_files
- template_file = @template_dir + 'classpage.rhtml'
+ setup
+
+ template_file = @template_dir + 'class.rhtml'
+ template_file = @template_dir + 'classpage.rhtml' unless
+ template_file.exist?
return unless template_file.exist?
debug_msg "Generating class documentation in #{@outputdir}"
@@ -228,14 +345,8 @@ class RDoc::Generator::Darkfish
@classes.each do |klass|
current = klass
- debug_msg " working on %s (%s)" % [klass.full_name, klass.path]
- out_file = @outputdir + klass.path
- # suppress 1.9.3 warning
- rel_prefix = rel_prefix = @outputdir.relative_path_from(out_file.dirname)
- svninfo = svninfo = self.get_svninfo(klass)
- debug_msg " rendering #{out_file}"
- render_template template_file, out_file do |io| binding end
+ generate_class klass, template_file
end
rescue => e
error = RDoc::Error.new \
@@ -249,19 +360,56 @@ class RDoc::Generator::Darkfish
# Generate a documentation file for each file
def generate_file_files
- template_file = @template_dir + 'filepage.rhtml'
- return unless template_file.exist?
+ setup
+
+ page_file = @template_dir + 'page.rhtml'
+ fileinfo_file = @template_dir + 'fileinfo.rhtml'
+
+ # for legacy templates
+ filepage_file = @template_dir + 'filepage.rhtml' unless
+ page_file.exist? or fileinfo_file.exist?
+
+ return unless
+ page_file.exist? or fileinfo_file.exist? or filepage_file.exist?
+
debug_msg "Generating file documentation in #{@outputdir}"
out_file = nil
+ current = nil
@files.each do |file|
- out_file = @outputdir + file.path
+ current = file
+
+ if file.text? and page_file.exist? then
+ generate_page file
+ next
+ end
+
+ template_file = nil
+ out_file = @outputdir + file.path
debug_msg " working on %s (%s)" % [file.full_name, out_file]
+ rel_prefix = @outputdir.relative_path_from out_file.dirname
+ search_index_rel_prefix = rel_prefix
+ search_index_rel_prefix += @asset_rel_path if @file_output
+
# suppress 1.9.3 warning
- rel_prefix = rel_prefix = @outputdir.relative_path_from(out_file.dirname)
+ asset_rel_prefix = asset_rel_prefix = rel_prefix + @asset_rel_path
+
+ unless filepage_file then
+ if file.text? then
+ next unless page_file.exist?
+ template_file = page_file
+ @title = file.page_name
+ else
+ next unless fileinfo_file.exist?
+ template_file = fileinfo_file
+ @title = "File: #{file.base_name}"
+ end
+ end
+
+ @title += " - #{@options.title}"
+ template_file ||= filepage_file
- debug_msg " rendering #{out_file}"
render_template template_file, out_file do |io| binding end
end
rescue => e
@@ -273,6 +421,134 @@ class RDoc::Generator::Darkfish
end
##
+ # Generate a page file for +file+
+
+ def generate_page file
+ setup
+
+ template_file = @template_dir + 'page.rhtml'
+
+ out_file = @outputdir + file.path
+ debug_msg " working on %s (%s)" % [file.full_name, out_file]
+ rel_prefix = @outputdir.relative_path_from out_file.dirname
+ search_index_rel_prefix = rel_prefix
+ search_index_rel_prefix += @asset_rel_path if @file_output
+
+ # suppress 1.9.3 warning
+ current = current = file
+ asset_rel_prefix = asset_rel_prefix = rel_prefix + @asset_rel_path
+
+ @title = "#{file.page_name} - #{@options.title}"
+
+ debug_msg " rendering #{out_file}"
+ render_template template_file, out_file do |io| binding end
+ end
+
+ ##
+ # Generates the 404 page for the RDoc servlet
+
+ def generate_servlet_not_found path
+ setup
+
+ template_file = @template_dir + 'servlet_not_found.rhtml'
+ return unless template_file.exist?
+
+ debug_msg "Rendering the servlet root page..."
+
+ rel_prefix = rel_prefix = ''
+ search_index_rel_prefix = rel_prefix
+ search_index_rel_prefix += @asset_rel_path if @file_output
+
+ # suppress 1.9.3 warning
+ asset_rel_prefix = asset_rel_prefix = ''
+
+ @title = 'Not Found'
+
+ render_template template_file do |io| binding end
+ rescue => e
+ error = RDoc::Error.new \
+ "error generating servlet_root: #{e.message} (#{e.class})"
+ error.set_backtrace e.backtrace
+
+ raise error
+ end
+
+ ##
+ # Generates the servlet root page for the RDoc servlet
+
+ def generate_servlet_root installed
+ setup
+
+ template_file = @template_dir + 'servlet_root.rhtml'
+ return unless template_file.exist?
+
+ debug_msg 'Rendering the servlet root page...'
+
+ rel_prefix = rel_prefix = ''
+ search_index_rel_prefix = rel_prefix
+ search_index_rel_prefix += @asset_rel_path if @file_output
+
+ # suppress 1.9.3 warning
+ asset_rel_prefix = asset_rel_prefix = ''
+
+ @title = 'Local RDoc Documentation'
+
+ render_template template_file do |io| binding end
+ rescue => e
+ error = RDoc::Error.new \
+ "error generating servlet_root: #{e.message} (#{e.class})"
+ error.set_backtrace e.backtrace
+
+ raise error
+ end
+
+ ##
+ # Generate an index page which lists all the classes which are documented.
+
+ def generate_table_of_contents
+ setup
+
+ template_file = @template_dir + 'table_of_contents.rhtml'
+ return unless template_file.exist?
+
+ debug_msg "Rendering the Table of Contents..."
+
+ out_file = @outputdir + 'table_of_contents.html'
+ rel_prefix = @outputdir.relative_path_from out_file.dirname
+ search_index_rel_prefix = rel_prefix
+ search_index_rel_prefix += @asset_rel_path if @file_output
+
+ # suppress 1.9.3 warning
+ asset_rel_prefix = asset_rel_prefix = rel_prefix + @asset_rel_path
+
+ @title = "Table of Contents - #{@options.title}"
+
+ render_template template_file, out_file do |io| binding end
+ rescue => e
+ error = RDoc::Error.new \
+ "error generating table_of_contents.html: #{e.message} (#{e.class})"
+ error.set_backtrace e.backtrace
+
+ raise error
+ end
+
+ ##
+ # Prepares for generation of output from the current directory
+
+ def setup
+ return if instance_variable_defined? :@outputdir
+
+ @outputdir = Pathname.new(@options.op_dir).expand_path @base_dir
+
+ return unless @store
+
+ @classes = @store.all_classes_and_modules.sort
+ @files = @store.all_files.sort
+ @methods = @classes.map { |m| m.method_list }.flatten.sort
+ @modsort = get_sorted_module_list @classes
+ end
+
+ ##
# Return a string describing the amount of time in the given number of
# seconds in terms a human can understand easily.
@@ -325,6 +601,46 @@ class RDoc::Generator::Darkfish
end
##
+ # Creates a template from its components and the +body_file+.
+ #
+ # For backwards compatibility, if +body_file+ contains "<html" the body is
+ # used directly.
+
+ def assemble_template body_file
+ body = body_file.read
+ return body if body =~ /<html/
+
+ head_file = @template_dir + '_head.rhtml'
+ footer_file = @template_dir + '_footer.rhtml'
+
+ <<-TEMPLATE
+<!DOCTYPE html>
+
+<html>
+<head>
+#{head_file.read}
+
+#{body}
+
+#{footer_file.read}
+ TEMPLATE
+ end
+
+ ##
+ # Renders the ERb contained in +file_name+ relative to the template
+ # directory and returns the result based on the current context.
+
+ def render file_name
+ template_file = @template_dir + file_name
+
+ template = template_for template_file, false, RDoc::ERBPartial
+
+ template.filename = template_file.to_s
+
+ template.result @context
+ end
+
+ ##
# Load and render the erb template in the given +template_file+ and write
# it out to +out_file+.
#
@@ -332,28 +648,33 @@ class RDoc::Generator::Darkfish
#
# An io will be yielded which must be captured by binding in the caller.
- def render_template template_file, out_file # :yield: io
- template = template_for template_file
+ def render_template template_file, out_file = nil # :yield: io
+ io_output = out_file && !@dry_run && @file_output
+ erb_klass = io_output ? RDoc::ERBIO : ERB
+
+ template = template_for template_file, true, erb_klass
- unless @options.dry_run then
+ if io_output then
debug_msg "Outputting to %s" % [out_file.expand_path]
out_file.dirname.mkpath
out_file.open 'w', 0644 do |io|
io.set_encoding @options.encoding if Object.const_defined? :Encoding
- context = yield io
+ @context = yield io
- template_result template, context, template_file
+ template_result template, @context, template_file
end
else
- context = yield nil
+ @context = yield nil
- output = template_result template, context, template_file
+ output = template_result template, @context, template_file
debug_msg " would have written %d characters to %s" % [
output.length, out_file.expand_path
- ]
+ ] if @dry_run
+
+ output
end
end
@@ -374,14 +695,25 @@ class RDoc::Generator::Darkfish
##
# Retrieves a cache template for +file+, if present, or fills the cache.
- def template_for file
+ def template_for file, page = true, klass = ERB
template = @template_cache[file]
return template if template
- klass = @options.dry_run ? ERB : RDoc::ERBIO
+ template = if page then
+ assemble_template file
+ else
+ file.read
+ end
+
+ erbout = if page then
+ 'io'
+ else
+ file_var = File.basename(file).sub(/\..*/, '')
+ "_erbout_#{file_var}"
+ end
- template = klass.new file.read, nil, '<>'
+ template = klass.new template, nil, '<>', erbout
@template_cache[file] = template
template
end
diff --git a/lib/rdoc/generator/json_index.rb b/lib/rdoc/generator/json_index.rb
new file mode 100644
index 0000000000..c303b2effb
--- /dev/null
+++ b/lib/rdoc/generator/json_index.rb
@@ -0,0 +1,248 @@
+require 'json'
+
+##
+# The JsonIndex generator is designed to complement an HTML generator and
+# produces a JSON search index. This generator is derived from sdoc by
+# Vladimir Kolesnikov and contains verbatim code written by him.
+#
+# This generator is designed to be used with a regular HTML generator:
+#
+# class RDoc::Generator::Darkfish
+# def initialize options
+# # ...
+# @base_dir = Pathname.pwd.expand_path
+#
+# @json_index = RDoc::Generator::JsonIndex.new self, options
+# end
+#
+# def generate
+# # ...
+# @json_index.generate
+# end
+# end
+#
+# == Index Format
+#
+# The index is output as a JSON file assigned to the global variable
+# +search_data+. The structure is:
+#
+# var search_data = {
+# "index": {
+# "searchIndex":
+# ["a", "b", ...],
+# "longSearchIndex":
+# ["a", "a::b", ...],
+# "info": [
+# ["A", "A", "A.html", "", ""],
+# ["B", "A::B", "A::B.html", "", ""],
+# ...
+# ]
+# }
+# }
+#
+# The same item is described across the +searchIndex+, +longSearchIndex+ and
+# +info+ fields. The +searchIndex+ field contains the item's short name, the
+# +longSearchIndex+ field contains the full_name (when appropriate) and the
+# +info+ field contains the item's name, full_name, path, parameters and a
+# snippet of the item's comment.
+#
+# == LICENSE
+#
+# Copyright (c) 2009 Vladimir Kolesnikov
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+class RDoc::Generator::JsonIndex
+
+ include RDoc::Text
+
+ ##
+ # Where the search index lives in the generated output
+
+ SEARCH_INDEX_FILE = File.join 'js', 'search_index.js'
+
+ attr_reader :index # :nodoc:
+
+ ##
+ # Creates a new generator. +parent_generator+ is used to determine the
+ # class_dir and file_dir of links in the output index.
+ #
+ # +options+ are the same options passed to the parent generator.
+
+ def initialize parent_generator, options
+ @parent_generator = parent_generator
+ @store = parent_generator.store
+ @options = options
+
+ @template_dir = File.expand_path '../template/json_index', __FILE__
+ @base_dir = @parent_generator.base_dir
+
+ @classes = nil
+ @files = nil
+ @index = nil
+ end
+
+ ##
+ # Builds the JSON index as a Hash.
+
+ def build_index
+ reset @store.all_files.sort, @store.all_classes_and_modules.sort
+
+ index_classes
+ index_methods
+ index_pages
+
+ { :index => @index }
+ end
+
+ ##
+ # Output progress information if debugging is enabled
+
+ def debug_msg *msg
+ return unless $DEBUG_RDOC
+ $stderr.puts(*msg)
+ end
+
+ ##
+ # Writes the JSON index to disk
+
+ def generate
+ debug_msg "Generating JSON index"
+
+ debug_msg " writing search index to %s" % SEARCH_INDEX_FILE
+ data = build_index
+
+ return if @options.dry_run
+
+ out_dir = @base_dir + @options.op_dir
+ index_file = out_dir + SEARCH_INDEX_FILE
+
+ FileUtils.mkdir_p index_file.dirname, :verbose => $DEBUG_RDOC
+
+ index_file.open 'w', 0644 do |io|
+ io.set_encoding Encoding::UTF_8 if Object.const_defined? :Encoding
+ io.write 'var search_data = '
+
+ JSON.dump data, io, 0
+ end
+
+ Dir.chdir @template_dir do
+ Dir['**/*.js'].each do |source|
+ dest = File.join out_dir, source
+
+ FileUtils.install source, dest, :mode => 0644, :verbose => $DEBUG_RDOC
+ end
+ end
+ end
+
+ ##
+ # Adds classes and modules to the index
+
+ def index_classes
+ debug_msg " generating class search index"
+
+ documented = @classes.uniq.select do |klass|
+ klass.document_self_or_methods
+ end
+
+ documented.each do |klass|
+ debug_msg " #{klass.full_name}"
+ record = klass.search_record
+ @index[:searchIndex] << search_string(record.shift)
+ @index[:longSearchIndex] << search_string(record.shift)
+ @index[:info] << record
+ end
+ end
+
+ ##
+ # Adds methods to the index
+
+ def index_methods
+ debug_msg " generating method search index"
+
+ list = @classes.uniq.map do |klass|
+ klass.method_list
+ end.flatten.sort_by do |method|
+ [method.name, method.parent.full_name]
+ end
+
+ list.each do |method|
+ debug_msg " #{method.full_name}"
+ record = method.search_record
+ @index[:searchIndex] << "#{search_string record.shift}()"
+ @index[:longSearchIndex] << "#{search_string record.shift}()"
+ @index[:info] << record
+ end
+ end
+
+ ##
+ # Adds pages to the index
+
+ def index_pages
+ debug_msg " generating pages search index"
+
+ pages = @files.select do |file|
+ file.text?
+ end
+
+ pages.each do |page|
+ debug_msg " #{page.page_name}"
+ record = page.search_record
+ @index[:searchIndex] << search_string(record.shift)
+ @index[:longSearchIndex] << ''
+ record.shift
+ @index[:info] << record
+ end
+ end
+
+ ##
+ # The directory classes are written to
+
+ def class_dir
+ @parent_generator.class_dir
+ end
+
+ ##
+ # The directory files are written to
+
+ def file_dir
+ @parent_generator.file_dir
+ end
+
+ def reset files, classes # :nodoc:
+ @files = files
+ @classes = classes
+
+ @index = {
+ :searchIndex => [],
+ :longSearchIndex => [],
+ :info => []
+ }
+ end
+
+ ##
+ # Removes whitespace and downcases +string+
+
+ def search_string string
+ string.downcase.gsub(/\s/, '')
+ end
+
+end
+
diff --git a/lib/rdoc/generator/markup.rb b/lib/rdoc/generator/markup.rb
index c267bb1c13..3b3546690e 100644
--- a/lib/rdoc/generator/markup.rb
+++ b/lib/rdoc/generator/markup.rb
@@ -1,14 +1,8 @@
-# This file is loaded by generators. It allows RDoc's CodeObject tree to
-# avoid loading generator code to increase startup time (for ri).
-
-require 'rdoc/text'
-require 'rdoc/code_objects'
-require 'rdoc/generator'
-require 'rdoc/markup/to_html_crossref'
-require 'rdoc/ruby_token'
-
##
# Handle common RDoc::Markup tasks for various CodeObjects
+#
+# This module is loaded by generators. It allows RDoc's CodeObject tree to
+# avoid loading generator code to improve startup time for +ri+.
module RDoc::Generator::Markup
@@ -39,18 +33,18 @@ module RDoc::Generator::Markup
def formatter
return @formatter if defined? @formatter
- show_hash = RDoc::RDoc.current.options.show_hash
- hyperlink_all = RDoc::RDoc.current.options.hyperlink_all
+ options = @store.rdoc.options
this = RDoc::Context === self ? self : @parent
- @formatter = RDoc::Markup::ToHtmlCrossref.new(this.path, this, show_hash,
- hyperlink_all)
+ @formatter = RDoc::Markup::ToHtmlCrossref.new options, this.path, this
+ @formatter.code_object = self
+ @formatter
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.
+ # will replace the %s using sprintf on the +url+.
def cvs_url(url, full_path)
if /%s/ =~ url then
@@ -62,10 +56,14 @@ module RDoc::Generator::Markup
end
-class RDoc::AnyMethod
+class RDoc::CodeObject
include RDoc::Generator::Markup
+end
+
+class RDoc::MethodAttr
+
@add_line_numbers = false
class << self
@@ -82,7 +80,8 @@ class RDoc::AnyMethod
#
# # File xxxxx, line dddd
#
- # If it has, line numbers are added an ', line dddd' is removed.
+ # If it has this comment then line numbers are added to +src+ and the <tt>,
+ # line dddd</tt> portion of the comment is removed.
def add_line_numbers(src)
return unless src.sub!(/\A(.*)(, line (\d+))/, '\1')
@@ -111,32 +110,7 @@ class RDoc::AnyMethod
def markup_code
return '' unless @token_stream
- src = ""
-
- @token_stream.each do |t|
- next unless t
-
- style = case t
- when RDoc::RubyToken::TkCONSTANT then 'ruby-constant'
- when RDoc::RubyToken::TkKW then 'ruby-keyword'
- 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'
- when RDoc::RubyToken::TkREGEXP then 'ruby-regexp'
- when RDoc::RubyToken::TkSTRING then 'ruby-string'
- when RDoc::RubyToken::TkVal then 'ruby-value'
- end
-
- text = CGI.escapeHTML t.text
-
- if style then
- src << "<span class=\"#{style}\">#{text}</span>"
- else
- src << text
- end
- end
+ src = RDoc::TokenStream.to_html @token_stream
# dedent the source
indent = src.length
@@ -151,34 +125,21 @@ class RDoc::AnyMethod
end
src.gsub!(/^#{' ' * indent}/, '') if indent > 0
- add_line_numbers(src) if self.class.add_line_numbers
+ add_line_numbers(src) if RDoc::MethodAttr.add_line_numbers
src
end
end
-class RDoc::Attr
+class RDoc::ClassModule
- include RDoc::Generator::Markup
-
-end
-
-class RDoc::Alias
-
- include RDoc::Generator::Markup
-
-end
-
-class RDoc::Constant
-
- include RDoc::Generator::Markup
-
-end
-
-class RDoc::Context
+ ##
+ # Handy wrapper for marking up this class or module's comment
- include RDoc::Generator::Markup
+ def description
+ markup @comment_location
+ end
end
@@ -195,7 +156,7 @@ class RDoc::TopLevel
# command line option to set.
def cvs_url
- url = RDoc::RDoc.current.options.webcvs
+ url = @store.rdoc.options.webcvs
if /%s/ =~ url then
url % @absolute_name
diff --git a/lib/rdoc/generator/ri.rb b/lib/rdoc/generator/ri.rb
index 939a165cfb..b9c4141a5e 100644
--- a/lib/rdoc/generator/ri.rb
+++ b/lib/rdoc/generator/ri.rb
@@ -1,6 +1,3 @@
-require 'rdoc/generator'
-require 'rdoc/ri'
-
##
# Generates ri data files
@@ -16,70 +13,17 @@ class RDoc::Generator::RI
##
# Set up a new ri generator
- def initialize options #:not-new:
- @options = options
- @old_siginfo = nil
- @current = nil
-
- @store = RDoc::RI::Store.new '.'
- @store.dry_run = @options.dry_run
- @store.encoding = @options.encoding if @options.respond_to? :encoding
- end
-
- ##
- # Build the initial indices and output objects based on an array of TopLevel
- # objects containing the extracted information.
-
- def generate top_levels
- install_siginfo_handler
-
- @store.load_cache
-
- RDoc::TopLevel.all_classes_and_modules.each do |klass|
- @current = "#{klass.class}: #{klass.full_name}"
-
- @store.save_class klass
-
- klass.each_method do |method|
- @current = "#{method.class}: #{method.full_name}"
- @store.save_method klass, method
- end
-
- klass.each_attribute do |attribute|
- @store.save_method klass, attribute
- end
- end
-
- @current = 'saving cache'
-
- @store.save_cache
-
- ensure
- @current = nil
-
- remove_siginfo_handler
+ def initialize store, options #:not-new:
+ @options = options
+ @store = store
+ @store.path = '.'
end
##
- # Installs a siginfo handler that prints the current filename.
-
- def install_siginfo_handler
- return unless Signal.list.key? 'INFO'
-
- @old_siginfo = trap 'INFO' do
- puts @current if @current
- end
- end
-
- ##
- # Removes a siginfo handler and replaces the previous
-
- def remove_siginfo_handler
- return unless Signal.list.key? 'INFO'
-
- handler = @old_siginfo || 'DEFAULT'
+ # Writes the parsed data store to disk for use by ri.
- trap 'INFO', handler
+ def generate
+ @store.save
end
end
diff --git a/lib/rdoc/generator/template/darkfish/_footer.rhtml b/lib/rdoc/generator/template/darkfish/_footer.rhtml
new file mode 100644
index 0000000000..0736c335ba
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/_footer.rhtml
@@ -0,0 +1,5 @@
+<footer id="validator-badges">
+ <p><a href="http://validator.w3.org/check/referer">[Validate]</a>
+ <p>Generated by <a href="https://github.com/rdoc/rdoc">RDoc</a> <%= RDoc::VERSION %>.
+ <p>Generated with the <a href="http://deveiate.org/projects/Darkfish-Rdoc/">Darkfish Rdoc Generator</a> <%= RDoc::Generator::Darkfish::VERSION %>.
+</footer>
diff --git a/lib/rdoc/generator/template/darkfish/_head.rhtml b/lib/rdoc/generator/template/darkfish/_head.rhtml
new file mode 100644
index 0000000000..f3d82a37f6
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/_head.rhtml
@@ -0,0 +1,16 @@
+<meta content="text/html; charset=<%= @options.charset %>" http-equiv="Content-Type">
+
+<title><%= h @title %></title>
+
+<link type="text/css" media="screen" href="<%= asset_rel_prefix %>/rdoc.css" rel="stylesheet">
+
+<script type="text/javascript">
+ var rdoc_rel_prefix = "<%= rel_prefix %>/";
+</script>
+
+<script type="text/javascript" charset="utf-8" src="<%= asset_rel_prefix %>/js/jquery.js"></script>
+<script type="text/javascript" charset="utf-8" src="<%= asset_rel_prefix %>/js/navigation.js"></script>
+<script type="text/javascript" charset="utf-8" src="<%= search_index_rel_prefix %>/js/search_index.js"></script>
+<script type="text/javascript" charset="utf-8" src="<%= asset_rel_prefix %>/js/search.js"></script>
+<script type="text/javascript" charset="utf-8" src="<%= asset_rel_prefix %>/js/searcher.js"></script>
+<script type="text/javascript" charset="utf-8" src="<%= asset_rel_prefix %>/js/darkfish.js"></script>
diff --git a/lib/rdoc/generator/template/darkfish/_sidebar_VCS_info.rhtml b/lib/rdoc/generator/template/darkfish/_sidebar_VCS_info.rhtml
new file mode 100644
index 0000000000..93d57f39f6
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/_sidebar_VCS_info.rhtml
@@ -0,0 +1,18 @@
+<% if !svninfo.empty? then %>
+<nav id="file-svninfo-section" class="section">
+ <h3 class="section-header">VCS Info</h3>
+ <div class="section-body">
+ <dl class="svninfo">
+ <dt>Rev
+ <dd><%= svninfo[:rev] %>
+
+ <dt>Last Checked In
+ <dd><%= svninfo[:commitdate].strftime('%Y-%m-%d %H:%M:%S') %>
+ (<%= svninfo[:commitdelta] %> ago)
+
+ <dt>Checked in by
+ <dd><%= svninfo[:committer] %>
+ </dl>
+ </div>
+</nav>
+<% end %>
diff --git a/lib/rdoc/generator/template/darkfish/_sidebar_classes.rhtml b/lib/rdoc/generator/template/darkfish/_sidebar_classes.rhtml
new file mode 100644
index 0000000000..efa202fa18
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/_sidebar_classes.rhtml
@@ -0,0 +1,9 @@
+<nav id="classindex-section" class="section project-section">
+ <h3 class="section-header">Class and Module Index</h3>
+
+ <ul class="link-list">
+ <% @modsort.each do |index_klass| %>
+ <li><a href="<%= rel_prefix %>/<%= index_klass.path %>"><%= index_klass.full_name %></a>
+ <% end %>
+ </ul>
+</nav>
diff --git a/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtml b/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtml
new file mode 100644
index 0000000000..19273829a0
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtml
@@ -0,0 +1,16 @@
+<% unless klass.extends.empty? then %>
+<!-- Extension Modules -->
+<nav id="extends-section" class="section">
+ <h3 class="section-header">Extended With Modules</h3>
+
+ <ul class="link-list">
+ <% klass.each_extend do |ext| %>
+ <% unless String === ext.module then %>
+ <li><a class="extend" href="<%= klass.aref_to ext.module.path %>"><%= ext.module.full_name %></a>
+ <% else %>
+ <li><span class="extend"><%= ext.name %></span>
+ <% end %>
+ <% end %>
+ </ul>
+</nav>
+<% end %>
diff --git a/lib/rdoc/generator/template/darkfish/_sidebar_in_files.rhtml b/lib/rdoc/generator/template/darkfish/_sidebar_in_files.rhtml
new file mode 100644
index 0000000000..c4ae216a14
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/_sidebar_in_files.rhtml
@@ -0,0 +1,8 @@
+<nav id="file-list-section" class="section">
+ <h3 class="section-header">Defined In</h3>
+ <ul>
+<% klass.in_files.each do |tl| %>
+ <li><%= h tl.absolute_name %>
+<% end %>
+ </ul>
+</nav>
diff --git a/lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtml b/lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtml
new file mode 100644
index 0000000000..5494f1f5f8
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtml
@@ -0,0 +1,16 @@
+<% unless klass.includes.empty? then %>
+<!-- Included Modules -->
+<nav 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 then %>
+ <li><a class="include" href="<%= klass.aref_to inc.module.path %>"><%= inc.module.full_name %></a>
+ <% else %>
+ <li><span class="include"><%= inc.name %></span>
+ <% end %>
+ <% end %>
+ </ul>
+</nav>
+<% end %>
diff --git a/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtml b/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtml
new file mode 100644
index 0000000000..45a3048e84
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtml
@@ -0,0 +1,14 @@
+<nav id="home-section" class="section">
+ <h3 class="section-header">Documentation</h3>
+
+ <ul>
+ <% installed.each do |name, href, exists| %>
+ <li class="folder">
+ <% if exists then %>
+ <a href="<%= href %>"><%= h name %></a>
+ <% else %>
+ <%= h name %>
+ <% end %>
+ <% end %>
+ </ul>
+</nav>
diff --git a/lib/rdoc/generator/template/darkfish/_sidebar_methods.rhtml b/lib/rdoc/generator/template/darkfish/_sidebar_methods.rhtml
new file mode 100644
index 0000000000..88e2734819
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/_sidebar_methods.rhtml
@@ -0,0 +1,12 @@
+<% unless klass.method_list.empty? then %>
+<!-- Method Quickref -->
+<nav id="method-list-section" class="section">
+ <h3 class="section-header">Methods</h3>
+
+ <ul class="link-list">
+ <% klass.each_method do |meth| %>
+ <li <% if meth.calls_super %>class="calls-super" <% end %>><a href="#<%= meth.aref %>"><%= meth.singleton ? '::' : '#' %><%= h meth.name %></a>
+ <% end %>
+ </ul>
+</nav>
+<% end %>
diff --git a/lib/rdoc/generator/template/darkfish/_sidebar_navigation.rhtml b/lib/rdoc/generator/template/darkfish/_sidebar_navigation.rhtml
new file mode 100644
index 0000000000..fdeb6aed9f
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/_sidebar_navigation.rhtml
@@ -0,0 +1,7 @@
+<nav id="home-section" class="section">
+ <h3 class="section-header">
+ <a href="<%= rel_prefix %>/index.html">Home</a>
+ <a href="<%= rel_prefix %>/table_of_contents.html#classes">Classes</a>
+ <a href="<%= rel_prefix %>/table_of_contents.html#methods">Methods</a>
+ </h3>
+</nav>
diff --git a/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml b/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml
new file mode 100644
index 0000000000..2089387c51
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml
@@ -0,0 +1,12 @@
+<% simple_files = @files.select { |f| f.text? } %>
+<% unless simple_files.empty? then %>
+<nav id="fileindex-section" class="section project-section">
+ <h3 class="section-header">Pages</h3>
+
+ <ul>
+ <% simple_files.each do |f| %>
+ <li class="file"><a href="<%= rel_prefix %>/<%= f.path %>"><%= h f.page_name %></a>
+ <% end %>
+ </ul>
+</nav>
+<% end %>
diff --git a/lib/rdoc/generator/template/darkfish/_sidebar_parent.rhtml b/lib/rdoc/generator/template/darkfish/_sidebar_parent.rhtml
new file mode 100644
index 0000000000..463f05a8d9
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/_sidebar_parent.rhtml
@@ -0,0 +1,10 @@
+<% if klass.type == 'class' then %>
+<nav id="parent-class-section" class="section">
+ <h3 class="section-header">Parent</h3>
+ <% if klass.superclass and not String === klass.superclass then %>
+ <p class="link"><a href="<%= klass.aref_to klass.superclass.path %>"><%= klass.superclass.full_name %></a>
+ <% else %>
+ <p class="link"><%= klass.superclass %>
+ <% end %>
+</nav>
+<% end %>
diff --git a/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml b/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml
new file mode 100644
index 0000000000..f3275783d0
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml
@@ -0,0 +1,10 @@
+<nav id="search-section" class="section project-section" class="initially-hidden">
+ <form action="#" method="get" accept-charset="utf-8">
+ <h3 class="section-header">
+ <input type="text" name="search" placeholder="Search" id="search-field"
+ title="Type to search, Up and Down to navigate, Enter to load">
+ </h3>
+ </form>
+
+ <ul id="search-results" class="initially-hidden"></ul>
+</nav>
diff --git a/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtml b/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtml
new file mode 100644
index 0000000000..726423a341
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtml
@@ -0,0 +1,10 @@
+<% unless klass.sections.length == 1 then %>
+<nav id="sections-section" class="section">
+ <h3 class="section-header">Sections</h3>
+ <ul class="link-list">
+ <% klass.sort_sections.each do |section| %>
+ <li><a href="#<%= section.aref %>"><%= h section.title %></a></li>
+ <% end %>
+ </ul>
+</nav>
+<% end %>
diff --git a/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml b/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml
new file mode 100644
index 0000000000..225f811f0e
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml
@@ -0,0 +1,13 @@
+<% table = current.parse(current.comment).table_of_contents
+ if table.length > 1 then %>
+<div id="table-of-contents">
+ <nav class="section">
+ <h3 class="section-header">Table of Contents</h3>
+ <ul>
+<% table.each do |heading| %>
+ <li><a href="#<%= heading.aref %>"><%= heading.plain_html %></a>
+<% end %>
+ </ul>
+ </nav>
+</div>
+<% end %>
diff --git a/lib/rdoc/generator/template/darkfish/class.rhtml b/lib/rdoc/generator/template/darkfish/class.rhtml
new file mode 100644
index 0000000000..c7e52e6808
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/class.rhtml
@@ -0,0 +1,179 @@
+<body id="top" class="<%= klass.type %>">
+<nav id="metadata">
+ <%= render '_sidebar_navigation.rhtml' %>
+
+ <%= render '_sidebar_search.rhtml' %>
+
+ <%= render '_sidebar_table_of_contents.rhtml' %>
+
+ <div id="file-metadata">
+ <%= render '_sidebar_in_files.rhtml' %>
+ <%= render '_sidebar_VCS_info.rhtml' %>
+ </div>
+
+ <div id="class-metadata">
+ <%= render '_sidebar_sections.rhtml' %>
+ <%= render '_sidebar_parent.rhtml' %>
+ <%= render '_sidebar_includes.rhtml' %>
+ <%= render '_sidebar_extends.rhtml' %>
+ <%= render '_sidebar_methods.rhtml' %>
+ </div>
+
+ <div id="project-metadata">
+ <%= render '_sidebar_pages.rhtml' %>
+ <%= render '_sidebar_classes.rhtml' %>
+ </div>
+</nav>
+
+<div id="documentation">
+ <h1 class="<%= klass.type %>"><%= klass.type %> <%= klass.full_name %></h1>
+
+ <div id="description" class="description">
+ <%= klass.description %>
+ </div><!-- description -->
+
+ <% klass.each_section do |section, constants, attributes| %>
+ <% constants = constants.select { |const| const.display? } %>
+ <% attributes = attributes.select { |attr| attr.display? } %>
+ <section id="<%= section.aref %>" class="documentation-section">
+ <% if section.title then %>
+ <div class="documentation-section-title">
+ <h2 class="section-header">
+ <%= section.title %>
+ </h2>
+ <span class="section-click-top">
+ <a href="#top">&uarr; top</a>
+ </span>
+ </div>
+ <% end %>
+
+ <% if section.comment then %>
+ <div class="description">
+ <%= section.description %>
+ </div>
+ <% end %>
+
+ <% unless constants.empty? then %>
+ <!-- Constants -->
+ <section id="constants-list" class="section">
+ <h3 class="section-header">Constants</h3>
+ <dl>
+ <% constants.each do |const| %>
+ <dt id="<%= const.name %>"><%= const.name %>
+ <% if const.comment then %>
+ <dd class="description"><%= const.description.strip %>
+ <% else %>
+ <dd class="description missing-docs">(Not documented)
+ <% end %>
+ <% end %>
+ </dl>
+ </section>
+ <% end %>
+
+ <% unless attributes.empty? then %>
+ <!-- Attributes -->
+ <section id="attribute-method-details" class="method-section section">
+ <h3 class="section-header">Attributes</h3>
+
+ <% attributes.each do |attrib| %>
+ <div id="<%= attrib.aref %>" class="method-detail">
+ <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 then %>
+ <%= attrib.description.strip %>
+ <% else %>
+ <p class="missing-docs">(Not documented)
+ <% end %>
+ </div>
+ </div>
+ <% end %>
+ </section><!-- attribute-method-details -->
+ <% end %>
+
+ <!-- Methods -->
+ <% klass.methods_by_type(section).each do |type, visibilities|
+ next if visibilities.empty?
+ visibilities.each do |visibility, methods|
+ next if methods.empty? %>
+ <section id="<%= visibility %>-<%= type %>-<%= section.aref %>-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.aref %>" class="method-detail <%= method.is_alias_for ? "method-alias" : '' %>">
+ <% if method.call_seq then %>
+ <% method.call_seq.strip.split("\n").each_with_index do |call_seq, i| %>
+ <div class="method-heading">
+ <span class="method-callseq">
+ <%= h(call_seq.strip.
+ gsub( /^\w+\./m, '')).
+ gsub(/(.*)[-=]&gt;/, '\1&rarr;') %>
+ </span>
+ <% if i == 0 and method.token_stream then %>
+ <span class="method-click-advice">click to toggle source</span>
+ <% end %>
+ </div>
+ <% end %>
+ <% else %>
+ <div class="method-heading">
+ <span class="method-name"><%= h method.name %></span><span
+ class="method-args"><%= method.param_seq %></span>
+ <% if method.token_stream then %>
+ <span class="method-click-advice">click to toggle source</span>
+ <% end %>
+ </div>
+ <% end %>
+
+ <div class="method-description">
+ <% if method.comment then %>
+ <%= method.description.strip %>
+ <% else %>
+ <p class="missing-docs">(Not documented)
+ <% end %>
+ <% if method.calls_super then %>
+ <div class="method-calls-super">
+ Calls superclass method
+ <%=
+ method.superclass_method ?
+ method.formatter.link(method.superclass_method.full_name, method.superclass_method.full_name) : nil
+ %>
+ </div>
+ <% end %>
+
+ <% if method.token_stream then %>
+ <div class="method-source-code" id="<%= method.html_name %>-source">
+ <pre><%= method.markup_code %></pre>
+ </div><!-- <%= method.html_name %>-source -->
+ <% end %>
+ </div>
+
+ <% unless method.aliases.empty? then %>
+ <div class="aliases">
+ Also aliased as: <%= method.aliases.map do |aka|
+ if aka.parent then # HACK lib/rexml/encodings
+ %{<a href="#{klass.aref_to aka.path}">#{h aka.name}</a>}
+ else
+ h aka.name
+ end
+ 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><!-- <%= method.html_name %>-method -->
+
+ <% end %>
+ </section><!-- <%= visibility %>-<%= type %>-method-details -->
+ <% end
+ end %>
+ </section><!-- <%= section.aref %> -->
+<% end %>
+
+</div><!-- documentation -->
diff --git a/lib/rdoc/generator/template/darkfish/classpage.rhtml b/lib/rdoc/generator/template/darkfish/classpage.rhtml
deleted file mode 100644
index 9c74cacf0f..0000000000
--- a/lib/rdoc/generator/template/darkfish/classpage.rhtml
+++ /dev/null
@@ -1,321 +0,0 @@
-<?xml version="1.0" encoding="<%= @options.charset %>"?>
-<!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 id="top" 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? then %>
- <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">
- <% if klass.type == 'class' then %>
- <!-- Parent Class -->
- <div id="parent-class-section" class="section">
- <h3 class="section-header">Parent</h3>
- <% if klass.superclass and not String === klass.superclass then %>
- <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 %>
-
- <% unless klass.sections.length == 1 then %>
- <!-- Sections -->
- <div id="sections-section" class="section">
- <h3 class="section-header">Sections</h3>
- <ul class="link-list">
- <% klass.sections.sort_by { |s| s.title.to_s }.each do |section| %>
- <li><a href="#<%= section.aref %>"><%= h section.title %></a></li>
- <% end %>
- </ul>
- </div>
- <% end %>
-
- <% unless klass.classes_and_modules.empty? then %>
- <!-- Namespace Contents -->
- <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 %>
-
- <% unless klass.method_list.empty? then %>
- <!-- Method Quickref -->
- <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 %>
-
- <% unless klass.includes.empty? then %>
- <!-- Included Modules -->
- <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 then %>
- <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/Module 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 then %>
- <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" class="description">
- <%= klass.description %>
- </div><!-- description -->
-
- <% klass.each_section do |section, constants, attributes| %>
- <% constants = constants.select { |const| const.display? } %>
- <% attributes = attributes.select { |attr| attr.display? } %>
- <div id="<%= section.aref %>" class="documentation-section">
- <% if section.title then %>
- <h2 class="section-header">
- <%= section.title %>
- <a href="#top">&uarr; top</a>
- </h2>
- <% end %>
-
- <% if section.comment then %>
- <div class="description">
- <%= section.description %>
- </div>
- <% end %>
-
- <% unless constants.empty? then %>
- <!-- Constants -->
- <div id="constants-list" class="section">
- <h3 class="section-header">Constants</h3>
- <dl>
- <% constants.each do |const| %>
- <dt><a name="<%= const.name %>"><%= const.name %></a></dt>
- <% if const.comment then %>
- <dd class="description"><%= const.description.strip %></dd>
- <% else %>
- <dd class="description missing-docs">(Not documented)</dd>
- <% end %>
- <% end %>
- </dl>
- </div>
- <% end %>
-
- <% unless attributes.empty? then %>
- <!-- Attributes -->
- <div id="attribute-method-details" class="method-section section">
- <h3 class="section-header">Attributes</h3>
-
- <% attributes.each do |attrib| %>
- <div id="<%= attrib.html_name %>-attribute-method" class="method-detail">
- <a name="<%= h attrib.name %>"></a>
- <% if attrib.rw =~ /w/i then %>
- <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 then %>
- <%= attrib.description.strip %>
- <% else %>
- <p class="missing-docs">(Not documented)</p>
- <% end %>
- </div>
- </div>
- <% end %>
- </div><!-- attribute-method-details -->
- <% end %>
-
- <!-- Methods -->
- <% klass.methods_by_type(section).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>
-
- <% if method.call_seq then %>
- <% method.call_seq.strip.split("\n").each_with_index do |call_seq, i| %>
- <div class="method-heading">
- <span class="method-callseq"><%= call_seq.strip.gsub(/->/, '&rarr;').gsub( /^\w+\./m, '') %></span>
- <% if i == 0 then %>
- <span class="method-click-advice">click to toggle source</span>
- <% end %>
- </div>
- <% end %>
- <% else %>
- <div class="method-heading">
- <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>
- </div>
- <% end %>
-
- <div class="method-description">
- <% if method.comment then %>
- <%= method.description.strip %>
- <% else %>
- <p class="missing-docs">(Not documented)</p>
- <% end %>
-
- <% if method.token_stream then %>
- <div class="method-source-code" id="<%= method.html_name %>-source">
-<pre>
-<%= method.markup_code %>
-</pre>
- </div><!-- <%= method.html_name %>-source -->
- <% end %>
- </div>
-
- <% unless method.aliases.empty? then %>
- <div class="aliases">
- Also aliased as: <%= method.aliases.map do |aka|
- if aka.parent then # HACK lib/rexml/encodings
- %{<a href="#{klass.aref_to aka.path}">#{h aka.name}</a>}
- else
- h aka.name
- end
- 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><!-- <%= method.html_name %>-method -->
-
- <% end %>
- </div><!-- <%= visibility %>-<%= type %>-method-details -->
- <% end
- end %>
- </div><!-- <%= section.aref %> -->
- <% end %>
-
- </div><!-- documentation -->
-
- <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
deleted file mode 100644
index b230a456a3..0000000000
--- a/lib/rdoc/generator/template/darkfish/filepage.rhtml
+++ /dev/null
@@ -1,124 +0,0 @@
-<?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/add.png b/lib/rdoc/generator/template/darkfish/images/add.png
new file mode 100755
index 0000000000..6332fefea4
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/images/add.png
Binary files differ
diff --git a/lib/rdoc/generator/template/darkfish/images/arrow_up.png b/lib/rdoc/generator/template/darkfish/images/arrow_up.png
new file mode 100755
index 0000000000..1ebb193243
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/images/arrow_up.png
Binary files differ
diff --git a/lib/rdoc/generator/template/darkfish/images/delete.png b/lib/rdoc/generator/template/darkfish/images/delete.png
new file mode 100755
index 0000000000..08f249365a
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/images/delete.png
Binary files differ
diff --git a/lib/rdoc/generator/template/darkfish/images/tag_blue.png b/lib/rdoc/generator/template/darkfish/images/tag_blue.png
new file mode 100755
index 0000000000..3f02b5f8f8
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/images/tag_blue.png
Binary files differ
diff --git a/lib/rdoc/generator/template/darkfish/images/transparent.png b/lib/rdoc/generator/template/darkfish/images/transparent.png
new file mode 100644
index 0000000000..d665e179ef
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/images/transparent.png
Binary files differ
diff --git a/lib/rdoc/generator/template/darkfish/index.rhtml b/lib/rdoc/generator/template/darkfish/index.rhtml
index 3198246f8a..d076c2a252 100644
--- a/lib/rdoc/generator/template/darkfish/index.rhtml
+++ b/lib/rdoc/generator/template/darkfish/index.rhtml
@@ -1,64 +1,19 @@
-<?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">
+<body>
+<nav id="metadata">
+ <%= render '_sidebar_navigation.rhtml' %>
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
-<head>
- <meta content="text/html; charset=<%= @options.charset %>" http-equiv="Content-Type" />
+ <%= render '_sidebar_search.rhtml' %>
- <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 } then %>
- <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 id="project-metadata">
+ <%= render '_sidebar_pages.rhtml' %>
+ <%= render '_sidebar_classes.rhtml' %>
</div>
-</body>
-</html>
+</nav>
+
+<div id="documentation" class="description">
+<% if @options.main_page && main_page = @files.find { |f| f.full_name == @options.main_page } then %>
+<%= main_page.description %>
+<% else %>
+<p>This is the API documentation for <%= @title %>.
+<% end %>
+</div>
diff --git a/lib/rdoc/generator/template/darkfish/js/darkfish.js b/lib/rdoc/generator/template/darkfish/js/darkfish.js
index 84565c1e2d..4be722fac3 100644
--- a/lib/rdoc/generator/template/darkfish/js/darkfish.js
+++ b/lib/rdoc/generator/template/darkfish/js/darkfish.js
@@ -9,12 +9,12 @@
/* Provide console simulation for firebug-less environments */
if (!("console" in window) || !("firebug" in console)) {
- var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
+ 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() {};
+ window.console = {};
+ for (var i = 0; i < names.length; ++i)
+ window.console[names[i]] = function() {};
};
@@ -23,94 +23,131 @@ if (!("console" in window) || !("firebug" in console)) {
*/
$.fn.unwrap = function( expr ) {
return this.each( function() {
- $(this).parents( expr ).eq( 0 ).after( this ).remove();
+ $(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();
+ 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 );
+ $('.method-heading').click( showSource );
};
function toggleDebuggingSection() {
- $('.debugging-section').slideToggle();
+ $('.debugging-section').slideToggle();
};
function hookDebuggingToggle() {
- $('#debugging-toggle img').click( toggleDebuggingSection );
+ $('#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 hookTableOfContentsToggle() {
+ $('.indexpage li .toc-toggle').each( function() {
+ $(this).click( function() {
+ $(this).toggleClass('open');
+ });
+
+ var section = $(this).next();
+
+ $(this).click( function() {
+ section.slideToggle();
+ });
+ });
+}
+
+function hookSearch() {
+ var input = $('#search-field').eq(0);
+ var result = $('#search-results').eq(0);
+ $(result).show();
+
+ var search_section = $('#search-section').get(0);
+ $(search_section).show();
+
+ var search = new Search(search_data, input, result);
+
+ search.renderItem = function(result) {
+ var li = document.createElement('li');
+ var html = '';
+
+ // TODO add relative path to <script> per-page
+ html += '<p class="search-match"><a href="' + rdoc_rel_prefix + result.path + '">' + this.hlt(result.title);
+ if (result.params)
+ html += '<span class="params">' + result.params + '</span>';
+ html += '</a>';
+
+
+ if (result.namespace)
+ html += '<p class="search-namespace">' + this.hlt(result.namespace);
+
+ if (result.snippet)
+ html += '<div class="search-snippet">' + result.snippet + '</div>';
+
+ li.innerHTML = html;
+
+ return li;
+ }
+
+ search.select = function(result) {
+ var result_element = result.get(0);
+ window.location.href = result_element.firstChild.firstChild.href;
+ }
+
+ search.scrollIntoView = search.scrollInWindow;
};
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." );
- }
- });
+ 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;
+ 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 + "]" );
+ var anchor = window.location.hash.substring(1);
+ console.debug( "Found anchor: %s; matching %s", anchor, "a[name=" + anchor + "]" );
- highlightTarget( 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 );
- };
+ 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();
+ hookSourceViews();
+ hookDebuggingToggle();
+ hookSearch();
+ highlightLocationTarget();
+ hookTableOfContentsToggle();
- $('ul.link-list a').bind( "click", highlightClickTarget );
+ $('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
index afe9e74c90..48590ecb96 100644
--- a/lib/rdoc/generator/template/darkfish/js/jquery.js
+++ b/lib/rdoc/generator/template/darkfish/js/jquery.js
@@ -1,32 +1,18 @@
-/*
- * jQuery 1.2.6 - New Wave Javascript
+/*!
+ * jQuery JavaScript Library v1.6.2
+ * http://jquery.com/
*
- * Copyright (c) 2008 John Resig (jquery.com)
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
+ * Copyright 2011, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
*
- * $Date: 2008-09-25 09:50:52 -0700 (Thu, 25 Sep 2008) $
- * $Rev: 38 $
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2011, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Thu Jun 30 14:16:56 2011 -0400
*/
-(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
+(function(a,b){function cv(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cs(a){if(!cg[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ch||(ch=c.createElement("iframe"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode==="CSS1Compat"?"<!doctype html>":"")+"<html><body>"),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cr(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cq(){cn=b}function cp(){setTimeout(cq,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h=="string"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=e[m]||e["* "+k];if(!n){p=b;for(o in e){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=e[j[1]+" "+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function bZ(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function bY(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bC.test(a)?d(a,e):bY(a+"["+(typeof e=="object"||f.isArray(e)?b:"")+"]",e,c,d)});else if(!c&&b!=null&&typeof b=="object")for(var e in b)bY(a+"["+e+"]",b[e],c,d);else d(a,b)}function bX(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bR,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l=="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=bX(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=bX(a,c,d,e,"*",g));return l}function bW(a){return function(b,c){typeof b!="string"&&(c=b,b="*");if(f.isFunction(c)){var d=b.toLowerCase().split(bN),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bA(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=b==="width"?bv:bw;if(d>0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bx(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function bm(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(be,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bl(a){f.nodeName(a,"input")?bk(a):"getElementsByTagName"in a&&f.grep(a.getElementsByTagName("input"),bk)}function bk(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bj(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bi(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bh(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i<j;i++)f.event.add(b,h+(g[h][i].namespace?".":"")+g[h][i].namespace,g[h][i],g[h][i].data)}}}}function bg(a,b){return f.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function W(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=f.grep(a,function(a){return a.nodeType===1});if(R.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function V(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function N(a,b){return(a&&a!=="*"?a+".":"")+b.replace(z,"`").replace(A,"&")}function M(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;i<s.length;i++)g=s[i],g.origType.replace(x,"")===a.type?q.push(g.selector):s.splice(i--,1);e=f(a.target).closest(q,a.currentTarget);for(j=0,k=e.length;j<k;j++){m=e[j];for(i=0;i<s.length;i++){g=s[i];if(m.selector===g.selector&&(!n||n.test(g.namespace))&&!m.elem.disabled){h=m.elem,d=null;if(g.preType==="mouseenter"||g.preType==="mouseleave")a.type=g.preType,d=f(a.relatedTarget).closest(g.selector)[0],d&&f.contains(h,d)&&(d=h);(!d||d!==h)&&p.push({elem:h,handleObj:g,level:m.level})}}}for(j=0,k=p.length;j<k;j++){e=p[j];if(c&&e.level>c)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function K(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function E(){return!0}function D(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"$1-$2").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z])/ig,x=function(a,b){return b.toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;A.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!A){A=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a);return c===b||D.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(b,c,d){a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),d=c.documentElement,(!d||!d.nodeName||d.nodeName==="parsererror")&&e.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:G?function(a){return a==null?"":G.call(a)}:function(a){return a==null?"":(a+"").replace(k,"").replace(l,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d==="string"||d==="function"||d==="regexp"||e.isWindow(a)?E.call(c,a):e.merge(c,a)}return c},inArray:function(a,b){if(H)return H.call(b,a);for(var c=0,d=b.length;c<d;c++)if(b[c]===a)return c;return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length=="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j=="number"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c=="string"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=F.call(arguments,2),g=function(){return a.apply(c,f.concat(F.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h){var i=a.length;if(typeof c=="object"){for(var j in c)e.access(a,j,c[j],f,g,d);return a}if(d!==b){f=!h&&f&&e.isFunction(d);for(var k=0;k<i;k++)g(a[k],c,f?d.call(a[k],k,g(a[k],c)):d,h);return a}return i?g(a[0],c):b},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=s.exec(a)||t.exec(a)||u.exec(a)||a.indexOf("compatible")<0&&v.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){I["[object "+b+"]"]=b.toLowerCase()}),z=e.uaMatch(y),z.browser&&(e.browser[z.browser]=!0,e.browser.version=z.version),e.browser.webkit&&(e.browser.safari=!0),j.test(" ")&&(k=/^[\s\xA0]+/,l=/[\s\xA0]+$/),h=e(c),c.addEventListener?B=function(){c.removeEventListener("DOMContentLoaded",B,!1),e.ready()}:c.attachEvent&&(B=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",B),e.ready())});return e}(),g="done fail isResolved isRejected promise then always pipe".split(" "),h=[].slice;f.extend({_Deferred:function(){var a=[],b,c,d,e={done:function(){if(!d){var c=arguments,g,h,i,j,k;b&&(k=b,b=0);for(g=0,h=c.length;g<h;g++)i=c[g],j=f.type(i),j==="array"?e.done.apply(e,i):j==="function"&&a.push(i);k&&e.resolveWith(k[0],k[1])}return this},resolveWith:function(e,f){if(!d&&!b&&!c){f=f||[],c=1;try{while(a[0])a.shift().apply(e,f)}finally{b=[e,f],c=0}}return this},resolve:function(){e.resolveWith(this,arguments);return this},isResolved:function(){return!!c||!!b},cancel:function(){d=1,a=[];return this}};return e},Deferred:function(a){var b=f._Deferred(),c=f._Deferred(),d;f.extend(b,{then:function(a,c){b.done(a).fail(c);return this},always:function(){return b.done.apply(b,arguments).fail.apply(this,arguments)},fail:c.done,rejectWith:c.resolveWith,reject:c.resolve,isRejected:c.isResolved,pipe:function(a,c){return f.Deferred(function(d){f.each({done:[a,"resolve"],fail:[c,"reject"]},function(a,c){var e=c[0],g=c[1],h;f.isFunction(e)?b[a](function(){h=e.apply(this,arguments),h&&f.isFunction(h.promise)?h.promise().then(d.resolve,d.reject):d[g](h)}):b[a](d[g])})}).promise()},promise:function(a){if(a==null){if(d)return d;d=a={}}var c=g.length;while(c--)a[g[c]]=b[g[c]];return a}}),b.done(c.cancel).fail(b.cancel),delete b.cancel,a&&a.call(b,b);return b},when:function(a){function i(a){return function(c){b[a]=arguments.length>1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c<d;c++)b[c]&&f.isFunction(b[c].promise)?b[c].promise().then(i(c),g.reject):--e;e||g.resolveWith(g,b)}else g!==a&&g.resolveWith(g,d?[a]:[]);return g.promise()}}),f.support=function(){var a=c.createElement("div"),b=c.documentElement,d,e,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u;a.setAttribute("className","t"),a.innerHTML=" <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.firstChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0},m&&f.extend(p,{position:"absolute",left:-1e3,top:-1e3});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="<div style='width:4px;'></div>",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>",q=a.getElementsByTagName("td"),u=q[0].offsetHeight===0,q[0].style.display="",q[1].style.display="none",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0),o.innerHTML="",n.removeChild(o);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s="on"+t,u=s in a,u||(a.setAttribute(s,"return;"),u=typeof a[s]=="function"),k[t+"Bubbles"]=u;o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([a-z])([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g=f.expando,h=typeof c=="string",i,j=a.nodeType,k=j?f.cache:a,l=j?a[f.expando]:a[f.expando]&&f.expando;if((!l||e&&l&&!k[l][g])&&h&&d===b)return;l||(j?a[f.expando]=l=++f.uuid:l=f.expando),k[l]||(k[l]={},j||(k[l].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?k[l][g]=f.extend(k[l][g],c):k[l]=f.extend(k[l],c);i=k[l],e&&(i[g]||(i[g]={}),i=i[g]),d!==b&&(i[f.camelCase(c)]=d);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[f.camelCase(c)]||i[c]:i}},removeData:function(b,c,d){if(!!f.acceptData(b)){var e=f.expando,g=b.nodeType,h=g?f.cache:b,i=g?b[f.expando]:f.expando;if(!h[i])return;if(c){var j=d?h[i][e]:h[i];if(j){delete j[c];if(!l(j))return}}if(d){delete h[i][e];if(!l(h[i]))return}var k=h[i][e];f.support.deleteExpando||h!=a?delete h[i]:h[i]=null,k?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=k):g&&(f.support.deleteExpando?delete b[f.expando]:b.removeAttribute?b.removeAttribute(f.expando):b[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h<i;h++)g=e[h].name,g.indexOf("data-")===0&&(g=f.camelCase(g.substring(5)),k(this[0],g,d[g]))}}return d}if(typeof a=="object")return this.each(function(){f.data(this,a)});var j=a.split(".");j[1]=j[1]?"."+j[1]:"";if(c===b){d=this.triggerHandler("getData"+j[1]+"!",[j[0]]),d===b&&this.length&&(d=f.data(this[0],a),d=k(this[0],a,d));return d===b&&j[1]?this.data(j[0]):d}return this.each(function(){var b=f(this),d=[j[0],c];b.triggerHandler("setData"+j[1]+"!",d),f.data(this,a,c),b.triggerHandler("changeData"+j[1]+"!",d)})},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,c){a&&(c=(c||"fx")+"mark",f.data(a,c,(f.data(a,c,b,!0)||0)+1,!0))},_unmark:function(a,c,d){a!==!0&&(d=c,c=a,a=!1);if(c){d=d||"fx";var e=d+"mark",g=a?0:(f.data(c,e,b,!0)||1)-1;g?f.data(c,e,g,!0):(f.removeData(c,e,!0),m(c,d,"mark"))}},queue:function(a,c,d){if(a){c=(c||"fx")+"queue";var e=f.data(a,c,b,!0);d&&(!e||f.isArray(d)?e=f.data(a,c,f.makeArray(d),!0):e.push(d));return e||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e;d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),d.call(a,function(){f.dequeue(a,b)})),c.length||(f.removeData(a,b+"queue",!0),m(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){typeof a!="string"&&(c=a,a="fx");if(c===b)return f.queue(this[0],a);return this.each(function(){var b=f.queue(this,a,c);a==="fx"&&b[0]!=="inprogress"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(){var c=this;setTimeout(function(){f.dequeue(c,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!="string"&&(c=a,a=b),a=a||"fx";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+"defer",j=a+"queue",k=a+"mark",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f._Deferred(),!0))h++,l.done(m);m();return d.promise()}});var n=/[\n\t\r]/g,o=/\s+/,p=/\r/g,q=/^(?:button|input)$/i,r=/^(?:button|input|object|select|textarea)$/i,s=/^a(?:rea)?$/i,t=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,u=/\:|^on/,v,w;f.fn.extend({attr:function(a,b){return f.access(this,a,b,!0,f.attr)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,a,b,!0,f.prop)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(o);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{g=" "+e.className+" ";for(h=0,i=b.length;h<i;h++)~g.indexOf(" "+b[h]+" ")||(g+=b[h]+" ");e.className=f.trim(g)}}}return this},removeClass:function(a){var c,d,e,g,h,i,j;if(f.isFunction(a))return this.each(function(b){f(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(o);for(d=0,e=this.length;d<e;d++){g=this[d];if(g.nodeType===1&&g.className)if(a){h=(" "+g.className+" ").replace(n," ");for(i=0,j=c.length;i<j;i++)h=h.replace(" "+c[i]+" "," ");g.className=f.trim(h)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";if(f.isFunction(a))return this.each(function(c){f(this).toggleClass(a.call(this,c,this.className,b),b)});return this.each(function(){if(c==="string"){var e,g=0,h=f(this),i=b,j=a.split(o);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&f._data(this,"__className__",this.className),this.className=this.className||a===!1?"":f._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ";for(var c=0,d=this.length;c<d;c++)if((" "+this[c].className+" ").replace(n," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;d=e.value;return typeof d=="string"?d.replace(p,""):d==null?"":d}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h<i;h++){var j=e[h];if(j.selected&&(f.support.optDisabled?!j.disabled:j.getAttribute("disabled")===null)&&(!j.parentNode.disabled||!f.nodeName(j.parentNode,"optgroup"))){b=f(j).val();if(g)return b;d.push(b)}}if(g&&!d.length&&e.length)return f(e[c]).val();return d},set:function(a,b){var c=f.makeArray(b);f(a).find("option").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);j&&(c=f.attrFix[c]||c,i=f.attrHooks[c],i||(t.test(c)?i=w:v&&c!=="className"&&(f.nodeName(a,"form")||u.test(c))&&(i=v)));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j&&(h=i.get(a,c))!==null)return h;h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.support.getSetAttribute?a.removeAttribute(b):(f.attr(a,b,""),a.removeAttributeNode(a.getAttributeNode(b))),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},tabIndex:{get:function(a){var c=a.getAttributeNode("tabIndex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}},value:{get:function(a,b){if(v&&f.nodeName(a,"button"))return v.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(v&&f.nodeName(a,"button"))return v.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);i&&(c=f.propFix[c]||c,h=f.propHooks[c]);return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==b?g:a[c]},propHooks:{}}),w={get:function(a,c){return f.prop(a,c)?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},f.support.getSetAttribute||(f.attrFix=f.propFix,v=f.attrHooks.name=f.attrHooks.title=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,c){var d=a.getAttributeNode(c);if(d){d.nodeValue=b;return b}}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var x=/\.(.*)$/,y=/^(?:textarea|input|select)$/i,z=/\./g,A=/ /g,B=/[^\w\s.|`]/g,C=function(a){return a.replace(B,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=D;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=D);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),C).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j<p.length;j++){q=p[j];if(l||n.test(q.namespace))f.event.remove(a,r,q.handler,j),p.splice(j--,1)}continue}o=f.event.special[h]||{};for(j=e||0;j<p.length;j++){q=p[j];if(d.guid===q.guid){if(l||n.test(q.namespace))e==null&&p.splice(j--,1),o.remove&&o.remove.call(a,q);if(e!=null)break}}if(p.length===0||e!=null&&p.length===1)(!o.teardown||o.teardown.call(a,m)===!1)&&f.removeEvent(a,h,s.handle),g=null,delete t[h]}if(f.isEmptyObject(t)){var u=s.handle;u&&(u.elem=null),delete s.events,delete s.handle,f.isEmptyObject(s)&&f.removeData(a,b,!0)}}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){var h=c.type||c,i=[],j;h.indexOf("!")>=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.
+shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d!=null?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h<i;h++){var j=d[h];if(e||c.namespace_re.test(j.namespace)){c.handler=j.handler,c.data=j.data,c.handleObj=j;var k=j.handler.apply(this,g);k!==b&&(c.result=k,k===!1&&(c.preventDefault(),c.stopPropagation()));if(c.isImmediatePropagationStopped())break}}return c.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(a){if(a[f.expando])return a;var d=a;a=f.Event(d);for(var e=this.props.length,g;e;)g=this.props[--e],a[g]=d[g];a.target||(a.target=a.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),!a.relatedTarget&&a.fromElement&&(a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement);if(a.pageX==null&&a.clientX!=null){var h=a.target.ownerDocument||c,i=h.documentElement,j=h.body;a.pageX=a.clientX+(i&&i.scrollLeft||j&&j.scrollLeft||0)-(i&&i.clientLeft||j&&j.clientLeft||0),a.pageY=a.clientY+(i&&i.scrollTop||j&&j.scrollTop||0)-(i&&i.clientTop||j&&j.clientTop||0)}a.which==null&&(a.charCode!=null||a.keyCode!=null)&&(a.which=a.charCode!=null?a.charCode:a.keyCode),!a.metaKey&&a.ctrlKey&&(a.metaKey=a.ctrlKey),!a.which&&a.button!==b&&(a.which=a.button&1?1:a.button&2?3:a.button&4?2:0);return a},guid:1e8,proxy:f.proxy,special:{ready:{setup:f.bindReady,teardown:f.noop},live:{add:function(a){f.event.add(this,N(a.origType,a.selector),f.extend({},a,{handler:M,guid:a.handler.guid}))},remove:function(a){f.event.remove(this,N(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}}},f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},f.Event=function(a,b){if(!this.preventDefault)return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?E:D):this.type=a,b&&f.extend(this,b),this.timeStamp=f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=E;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=E;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=E,this.stopPropagation()},isDefaultPrevented:D,isPropagationStopped:D,isImmediatePropagationStopped:D};var F=function(a){var b=a.relatedTarget,c=!1,d=a.type;a.type=a.data,b!==this&&(b&&(c=f.contains(this,b)),c||(f.event.handle.apply(this,arguments),a.type=d))},G=function(a){a.type=a.data,f.event.handle.apply(this,arguments)};f.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){f.event.special[a]={setup:function(c){f.event.add(this,b,c&&c.selector?G:F,a)},teardown:function(a){f.event.remove(this,b,a&&a.selector?G:F)}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(a,b){if(!f.nodeName(this,"form"))f.event.add(this,"click.specialSubmit",function(a){var b=a.target,c=b.type;(c==="submit"||c==="image")&&f(b).closest("form").length&&K("submit",this,arguments)}),f.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,c=b.type;(c==="text"||c==="password")&&f(b).closest("form").length&&a.keyCode===13&&K("submit",this,arguments)});else return!1},teardown:function(a){f.event.remove(this,".specialSubmit")}});if(!f.support.changeBubbles){var H,I=function(a){var b=a.type,c=a.value;b==="radio"||b==="checkbox"?c=a.checked:b==="select-multiple"?c=a.selectedIndex>-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},J=function(c){var d=c.target,e,g;if(!!y.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=I(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:J,beforedeactivate:J,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&J.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&J.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",I(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in H)f.event.add(this,c+".specialChange",H[c]);return y.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return y.test(this.nodeName)}},H=f.event.special.change.filters,H.focus=H.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i<j;i++)f.event.add(this[i],a,g,d);return this}}),f.fn.extend({unbind:function(a,b){if(typeof a=="object"&&!a.preventDefault)for(var c in a)this.unbind(c,a[c]);else for(var d=0,e=this.length;d<e;d++)f.event.remove(this[d],a,b);return this},delegate:function(a,b,c,d){return this.live(b,c,d,a)},undelegate:function(a,b,c){return arguments.length===0?this.unbind("live"):this.die(b,null,c,a)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f.data(this,"lastToggle"+a.guid)||0)%d;f.data(this,"lastToggle"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var L={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};f.each(["live","die"],function(a,c){f.fn[c]=function(a,d,e,g){var h,i=0,j,k,l,m=g||this.selector,n=g?this:f(this.context);if(typeof a=="object"&&!a.preventDefault){for(var o in a)n[c](o,d,a[o],m);return this}if(c==="die"&&!a&&g&&g.charAt(0)==="."){n.unbind(g);return this}if(d===!1||f.isFunction(d))e=d||D,d=b;a=(a||"").split(" ");while((h=a[i++])!=null){j=x.exec(h),k="",j&&(k=j[0],h=h.replace(x,""));if(h==="hover"){a.push("mouseenter"+k,"mouseleave"+k);continue}l=h,L[h]?(a.push(L[h]+k),h=h+k):h=(L[h]||h)+k;if(c==="live")for(var p=0,q=n.length;p<q;p++)f.event.add(n[p],"live."+N(h,m),{data:d,selector:m,handler:e,origType:h,origHandler:e,preType:l});else n.unbind("live."+N(h,m),e)}return this}}),f.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}if(i.nodeType===1){f||(i.sizcache=c,i.sizset=g);if(typeof b!="string"){if(i===b){j=!0;break}}else if(k.filter(b,[i]).length>0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}i.nodeType===1&&!f&&(i.sizcache=c,i.sizset=g);if(i.nodeName.toLowerCase()===b){j=i;break}i=i[a]}d[g]=j}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},k.matches=function(a,b){return k(a,null,null,b)},k.matchesSelector=function(a,b){return k(b,null,null,[a]).length>0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e<f;e++){var g,h=l.order[e];if(g=l.leftMatch[h].exec(a)){var j=g[1];g.splice(1,1);if(j.substr(j.length-1)!=="\\"){g[1]=(g[1]||"").replace(i,""),d=l.find[h](g,b,c);if(d!=null){a=a.replace(l.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},k.filter=function(a,c,d,e){var f,g,h=a,i=[],j=c,m=c&&c[0]&&k.isXML(c[0]);while(a&&c.length){for(var n in l.filter)if((f=l.leftMatch[n].exec(a))!=null&&f[2]){var o,p,q=l.filter[n],r=f[1];g=!1,f.splice(1,1);if(r.substr(r.length-1)==="\\")continue;j===i&&(i=[]);if(l.preFilter[n]){f=l.preFilter[n](f,j,d,i,e,m);if(!f)g=o=!0;else if(f===!0)continue}if(f)for(var s=0;(p=j[s])!=null;s++)if(p){o=q(p,f,s,j);var t=e^!!o;d&&o!=null?t?g=!0:j[s]=!1:t&&(i.push(p),g=!0)}if(o!==b){d||(j=i),a=a.replace(l.match[n],"");if(!g)return[];break}}if(a===h)if(g==null)k.error(a);else break;h=a}return j},k.error=function(a){throw"Syntax error, unrecognized expression: "+a};var l=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b=="string",d=c&&!j.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&k.filter(b,a,!0)},">":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&k.filter(b,a,!0)}},"":function(a,b,c){var e,f=d++,g=u;typeof b=="string"&&!j.test(b)&&(b=b.toLowerCase(),e=b,g=t),g("parentNode",b,f,a,e,c)},"~":function(a,b,c){var e,f=d++,g=u;typeof b=="string"&&!j.test(b)&&(b=b.toLowerCase(),e=b,g=t),g("previousSibling",b,f,a,e,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(i,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}k.error(e)},CHILD:function(a,b){var c=b[1],d=a;switch(c){case"only":case"first":while(d=d.previousSibling)if(d.nodeType===1)return!1;if(c==="first")return!0;d=a;case"last":while(d=d.nextSibling)if(d.nodeType===1)return!1;return!0;case"nth":var e=b[2],f=b[3];if(e===1&&f===0)return!0;var g=b[0],h=a.parentNode;if(h&&(h.sizcache!==g||!a.nodeIndex)){var i=0;for(d=h.firstChild;d;d=d.nextSibling)d.nodeType===1&&(d.nodeIndex=++i);h.sizcache=g}var j=a.nodeIndex-f;return e===0?j===0:j%e===0&&j/e>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c<f;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var r,s;c.documentElement.compareDocumentPosition?r=function(a,b){if(a===b){g=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(r=function(a,b){if(a===b){g=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],h=a.parentNode,i=b.parentNode,j=h;if(h===i)return s(a,b);if(!h)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return s(e[k],f[k]);return k===c?s(a,f[k],-1):s(e[k],b,1)},s=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),k.getText=function(a){var b="",c;for(var d=0;a[d];d++)c=a[d],c.nodeType===3||c.nodeType===4?b+=c.nodeValue:c.nodeType!==8&&(b+=k.getText(c.childNodes));return b},function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g<h;g++)k(a,f[g],d);return k.filter(e,d)};f.find=k,f.expr=k.selectors,f.expr[":"]=f.expr.filters,f.unique=k.uniqueSort,f.text=k.getText,f.isXMLDoc=k.isXML,f.contains=k.contains}();var O=/Until$/,P=/^(?:parents|prevUntil|prevAll)/,Q=/,/,R=/^.[^:#\[\.,]*$/,S=Array.prototype.slice,T=f.expr.match.POS,U={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!="string")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack("","find",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(W(this,a,!1),"not",a)},filter:function(a){return this.pushStack(W(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d<e;d++)i=a[d],j[i]||(j[i]=T.test(i)?f(i,b||this.context):i);while(g&&g.ownerDocument&&g!==b){for(i in j)h=j[i],(h.jquery?h.index(g)>-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=T.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(l?l.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a=="string")return f.inArray(this[0],a?f(a):this.parent().children());return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(V(c[0])||V(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=S.call(arguments);O.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!U[a]?f.unique(e):e,(this.length>1||Q.test(d))&&P.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var X=/ jQuery\d+="(?:\d+|null)"/g,Y=/^\s+/,Z=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,$=/<([\w:]+)/,_=/<tbody/i,ba=/<|&#?\w+;/,bb=/<(?:script|object|embed|option|style)/i,bc=/checked\s*(?:[^=]|=\s*.checked.)/i,bd=/\/(java|ecma)script/i,be=/^\s*<!(?:\[CDATA\[|\-\-)/,bf={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};bf.optgroup=bf.option,bf.tbody=bf.tfoot=bf.colgroup=bf.caption=bf.thead,bf.th=bf.td,f.support.htmlSerialize||(bf._default=[1,"div<div>","</div>"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(X,""):null;if(typeof a=="string"&&!bb.test(a)&&(f.support.leadingWhitespace||!Y.test(a))&&!bf[($.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Z,"<$1></$2>");try{for(var c=0,d=this.length;c<d;c++)this[c].nodeType===1&&(f.cleanData(this[c].getElementsByTagName("*")),this[c].innerHTML=a)}catch(e){this.empty().append(a)}}else f.isFunction(a)?this.each(function(b){var c=f(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!="string"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j=="string"&&bc.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bg(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,bm)}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i;b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof a[0]=="string"&&a[0].length<512&&i===c&&a[0].charAt(0)==="<"&&!bb.test(a[0])&&(f.support.checkClone||!bc.test(a[0]))&&(g=!0,h=f.fragments[a[0]],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean(a,i,e,d)),g&&(f.fragments[a[0]]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j
+)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bi(a,d),e=bj(a),g=bj(d);for(h=0;e[h];++h)bi(e[h],g[h])}if(b){bh(a,d);if(c){e=bj(a),g=bj(d);for(h=0;e[h];++h)bh(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!ba.test(k))k=b.createTextNode(k);else{k=k.replace(Z,"<$1></$2>");var l=($.exec(k)||["",""])[1].toLowerCase(),m=bf[l]||bf._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=_.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]==="<table>"&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&Y.test(k)&&o.insertBefore(b.createTextNode(Y.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i<r;i++)bl(k[i]);else bl(k);k.nodeType?h.push(k):h=f.merge(h,k)}if(d){g=function(a){return!a.type||bd.test(a.type)};for(j=0;h[j];j++)if(e&&f.nodeName(h[j],"script")&&(!h[j].type||h[j].type.toLowerCase()==="text/javascript"))e.push(h[j].parentNode?h[j].parentNode.removeChild(h[j]):h[j]);else{if(h[j].nodeType===1){var s=f.grep(h[j].getElementsByTagName("script"),g);h.splice.apply(h,[j+1,0].concat(s))}d.appendChild(h[j])}}return h},cleanData:function(a){var b,c,d=f.cache,e=f.expando,g=f.event.special,h=f.support.deleteExpando;for(var i=0,j;(j=a[i])!=null;i++){if(j.nodeName&&f.noData[j.nodeName.toLowerCase()])continue;c=j[f.expando];if(c){b=d[c]&&d[c][e];if(b&&b.events){for(var k in b.events)g[k]?f.event.remove(j,k):f.removeEvent(j,k,b.handle);b.handle&&(b.handle.elem=null)}h?delete j[f.expando]:j.removeAttribute&&j.removeAttribute(f.expando),delete d[c]}}}});var bn=/alpha\([^)]*\)/i,bo=/opacity=([^)]*)/,bp=/([A-Z]|^ms)/g,bq=/^-?\d+(?:px)?$/i,br=/^-?\d/,bs=/^[+\-]=/,bt=/[^+\-\.\de]+/g,bu={position:"absolute",visibility:"hidden",display:"block"},bv=["Left","Right"],bw=["Top","Bottom"],bx,by,bz;f.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return f.access(this,a,c,!0,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)})},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bx(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d;if(h==="number"&&isNaN(d)||d==null)return;h==="string"&&bs.test(d)&&(d=+d.replace(bt,"")+parseFloat(f.css(a,c)),h="number"),h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(bx)return bx(a,c)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]}}),f.curCSS=f.css,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){var e;if(c){if(a.offsetWidth!==0)return bA(a,b,d);f.swap(a,bu,function(){e=bA(a,b,d)});return e}},set:function(a,b){if(!bq.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bo.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle;c.zoom=1;var e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.filter=bn.test(g)?g.replace(bn,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bx(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(by=function(a,c){var d,e,g;c=c.replace(bp,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bz=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bq.test(d)&&br.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bx=by||bz,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bB=/%20/g,bC=/\[\]$/,bD=/\r?\n/g,bE=/#.*$/,bF=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bG=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bH=/^(?:about|app|app\-storage|.+\-extension|file|widget):$/,bI=/^(?:GET|HEAD)$/,bJ=/^\/\//,bK=/\?/,bL=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bM=/^(?:select|textarea)/i,bN=/\s+/,bO=/([?&])_=[^&]*/,bP=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bQ=f.fn.load,bR={},bS={},bT,bU;try{bT=e.href}catch(bV){bT=c.createElement("a"),bT.href="",bT=bT.href}bU=bP.exec(bT.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bQ)return bQ.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("<div>").append(c.replace(bL,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bM.test(this.nodeName)||bG.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bD,"\r\n")}}):{name:b.name,value:c.replace(bD,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?f.extend(!0,a,f.ajaxSettings,b):(b=a,a=f.extend(!0,f.ajaxSettings,b));for(var c in{context:1,url:1})c in b?a[c]=b[c]:c in f.ajaxSettings&&(a[c]=f.ajaxSettings[c]);return a},ajaxSettings:{url:bT,isLocal:bH.test(bU[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML}},ajaxPrefilter:bW(bR),ajaxTransport:bW(bS),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a?4:0;var o,r,u,w=l?bZ(d,v,l):b,x,y;if(a>=200&&a<300||a===304){if(d.ifModified){if(x=v.getResponseHeader("Last-Modified"))f.lastModified[k]=x;if(y=v.getResponseHeader("Etag"))f.etag[k]=y}if(a===304)c="notmodified",o=!0;else try{r=b$(d,w),c="success",o=!0}catch(z){c="parsererror",u=z}}else{u=c;if(!c||a)c="error",a<0&&(a=0)}v.status=a,v.statusText=c,o?h.resolveWith(e,[r,c,v]):h.rejectWith(e,[v,c,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,c]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bF.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bE,"").replace(bJ,bU[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bN),d.crossDomain==null&&(r=bP.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bU[1]&&r[2]==bU[2]&&(r[3]||(r[1]==="http:"?80:443))==(bU[3]||(bU[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bX(bR,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bI.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bK.test(d.url)?"&":"?")+d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bO,"$1_="+x);d.url=y+(y===d.url?(bK.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", */*; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bX(bS,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){status<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)bY(g,a[g],c,e);return d.join("&").replace(bB,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var b_=f.now(),ca=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+b_++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ca.test(b.url)||e&&ca.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ca,l),b.url===j&&(e&&(k=k.replace(ca,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cb=a.ActiveXObject?function(){for(var a in cd)cd[a](0,1)}:!1,cc=0,cd;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ce()||cf()}:ce,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cb&&delete cd[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cc,cb&&(cd||(cd={},f(a).unload(cb)),cd[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cg={},ch,ci,cj=/^(?:toggle|show|hide)$/,ck=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cl,cm=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cn,co=a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cr("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,"olddisplay")&&e==="none"&&(e=d.style.display=""),e===""&&f.css(d,"display")==="none"&&f._data(d,"olddisplay",cs(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===""||e==="none")d.style.display=f._data(d,"olddisplay")||""}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(cr("hide",3),a,b,c);for(var d=0,e=this.length;d<e;d++)if(this[d].style){var g=f.css(this[d],"display");g!=="none"&&!f._data(this[d],"olddisplay")&&f._data(this[d],"olddisplay",g)}for(d=0;d<e;d++)this[d].style&&(this[d].style.display="none");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a=="boolean";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(":hidden");f(this)[b?"show":"hide"]()}):this.animate(cr("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return this[e.queue===!1?"each":"queue"](function(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(":hidden"),g,h,i,j,k,l,m,n,o;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]),h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||"swing";if(h==="hide"&&d||h==="show"&&!d)return b.complete.call(this);c&&(g==="height"||g==="width")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,"display")==="inline"&&f.css(this,"float")==="none"&&(f.support.inlineBlockNeedsLayout?(j=cs(this.nodeName),j==="inline"?this.style.display="inline-block":(this.style.display="inline",this.style.zoom=1)):this.style.display="inline-block"))}b.overflow!=null&&(this.style.overflow="hidden");for(i in a)k=new f.fx(this,b,i),h=a[i],cj.test(h)?k[h==="toggle"?d?"show":"hide":h]():(l=ck.exec(h),m=k.cur(),l?(n=parseFloat(l[2]),o=l[3]||(f.cssNumber[i]?"":"px"),o!=="px"&&(f.style(this,i,(n||1)+o),m=(n||1)/k.cur()*m,f.style(this,i,m+o)),l[1]&&(n=(l[1]==="-="?-1:1)*n+m),k.custom(m,n,o)):k.custom(m,h,""));return!0})},stop:function(a,b){a&&this.queue([]),this.each(function(){var a=f.timers,c=a.length;b||f._unmark(!0,this);while(c--)a[c].elem===this&&(b&&a[c](!0),a.splice(c,1))}),b||this.dequeue();return this}}),f.each({slideDown:cr("show",1),slideUp:cr("hide",1),slideToggle:cr("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a=="object"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default,d.old=d.complete,d.complete=function(a){f.isFunction(d.old)&&d.old.call(this),d.queue!==!1?f.dequeue(this):a!==!1&&f._unmark(this)};return d},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,b,c){function h(a){return d.step(a)}var d=this,e=f.fx,g;this.startTime=cn||cp(),this.start=a,this.end=b,this.unit=c||this.unit||(f.cssNumber[this.prop]?"":"px"),this.now=this.start,this.pos=this.state=0,h.elem=this.elem,h()&&f.timers.push(h)&&!cl&&(co?(cl=!0,g=function(){cl&&(co(g),e.tick())},co(g)):cl=setInterval(e.tick,e.interval))},show:function(){this.options.orig[this.prop]=f.style(this.elem,this.prop),this.options.show=!0,this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b=cn||cp(),c=!0,d=this.elem,e=this.options,g,h;if(a||b>=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b<a.length;++b)a[b]()||a.splice(b--,1);a.length||f.fx.stop()},interval:13,stop:function(){clearInterval(cl),cl=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit:a.elem[a.prop]=a.now}}}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var ct=/^t(?:able|d|h)$/i,cu=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?f.fn.offset=function(a){var b=this[0],c;if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);try{c=b.getBoundingClientRect()}catch(d){}var e=b.ownerDocument,g=e.documentElement;if(!c||!f.contains(g,b))return c?{top:c.top,left:c.left}:{top:0,left:0};var h=e.body,i=cv(e),j=g.clientTop||h.clientTop||0,k=g.clientLeft||h.clientLeft||0,l=i.pageYOffset||f.support.boxModel&&g.scrollTop||h.scrollTop,m=i.pageXOffset||f.support.boxModel&&g.scrollLeft||h.scrollLeft,n=c.top+l-j,o=c.left+m-k;return{top:n,left:o}}:f.fn.offset=function(a){var b=this[0];if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);f.offset.initialize();var c,d=b.offsetParent,e=b,g=b.ownerDocument,h=g.documentElement,i=g.body,j=g.defaultView,k=j?j.getComputedStyle(b,null):b.currentStyle,l=b.offsetTop,m=b.offsetLeft;while((b=b.parentNode)&&b!==i&&b!==h){if(f.offset.supportsFixedPosition&&k.position==="fixed")break;c=j?j.getComputedStyle(b,null):b.currentStyle,l-=b.scrollTop,m-=b.scrollLeft,b===d&&(l+=b.offsetTop,m+=b.offsetLeft,f.offset.doesNotAddBorder&&(!f.offset.doesAddBorderForTableAndCells||!ct.test(b.nodeName))&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),e=d,d=b.offsetParent),f.offset.subtractsBorderForOverflowNotVisible&&c.overflow!=="visible"&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),k=c}if(k.position==="relative"||k.position==="static")l+=i.offsetTop,m+=i.offsetLeft;f.offset.supportsFixedPosition&&k.position==="fixed"&&(l+=Math.max(h.scrollTop,i.scrollTop),m+=Math.max(h.scrollLeft,i.scrollLeft));return{top:l,left:m}},f.offset={initialize:function(){var a=c.body,b=c.createElement("div"),d,e,g,h,i=parseFloat(f.css(a,"marginTop"))||0,j="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cu.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cu.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cv(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cv(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a&&a.style?parseFloat(f.css(a,d,"padding")):null},f.fn["outer"+c]=function(a){var b=this[0];return b&&b.style?parseFloat(f.css(b,d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c];return e.document.compatMode==="CSS1Compat"&&g||e.document.body["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var h=f.css(e,d),i=parseFloat(h);return f.isNaN(i)?h:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window); \ 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
deleted file mode 100644
index 70dbd33cd9..0000000000
--- a/lib/rdoc/generator/template/darkfish/js/quicksearch.js
+++ /dev/null
@@ -1,114 +0,0 @@
-/**
- *
- * 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/search.js b/lib/rdoc/generator/template/darkfish/js/search.js
new file mode 100644
index 0000000000..dbdfdcbc4c
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/js/search.js
@@ -0,0 +1,94 @@
+Search = function(data, input, result) {
+ this.data = data;
+ this.$input = $(input);
+ this.$result = $(result);
+
+ this.$current = null;
+ this.$view = this.$result.parent();
+ this.searcher = new Searcher(data.index);
+ this.init();
+}
+
+Search.prototype = $.extend({}, Navigation, new function() {
+ var suid = 1;
+
+ this.init = function() {
+ var _this = this;
+ var observer = function() {
+ _this.search(_this.$input[0].value);
+ };
+ this.$input.keyup(observer);
+ this.$input.click(observer); // mac's clear field
+
+ this.searcher.ready(function(results, isLast) {
+ _this.addResults(results, isLast);
+ })
+
+ this.initNavigation();
+ this.setNavigationActive(false);
+ }
+
+ this.search = function(value, selectFirstMatch) {
+ value = jQuery.trim(value).toLowerCase();
+ if (value) {
+ this.setNavigationActive(true);
+ } else {
+ this.setNavigationActive(false);
+ }
+
+ if (value == '') {
+ this.lastQuery = value;
+ this.$result.empty();
+ this.setNavigationActive(false);
+ } else if (value != this.lastQuery) {
+ this.lastQuery = value;
+ this.firstRun = true;
+ this.searcher.find(value);
+ }
+ }
+
+ this.addResults = function(results, isLast) {
+ var target = this.$result.get(0);
+ if (this.firstRun && (results.length > 0 || isLast)) {
+ this.$current = null;
+ this.$result.empty();
+ }
+
+ for (var i=0, l = results.length; i < l; i++) {
+ target.appendChild(this.renderItem.call(this, results[i]));
+ };
+
+ if (this.firstRun && results.length > 0) {
+ this.firstRun = false;
+ this.$current = $(target.firstChild);
+ this.$current.addClass('current');
+ }
+ if (jQuery.browser.msie) this.$element[0].className += '';
+ }
+
+ this.move = function(isDown) {
+ if (!this.$current) return;
+ var $next = this.$current[isDown ? 'next' : 'prev']();
+ if ($next.length) {
+ this.$current.removeClass('current');
+ $next.addClass('current');
+ this.scrollIntoView($next[0], this.$view[0]);
+ this.$current = $next;
+ }
+ return true;
+ }
+
+ this.hlt = function(html) {
+ return this.escapeHTML(html).
+ replace(/\u0001/g, '<em>').
+ replace(/\u0002/g, '</em>');
+ }
+
+ this.escapeHTML = function(html) {
+ return html.replace(/[&<>]/g, function(c) {
+ return '&#' + c.charCodeAt(0) + ';';
+ });
+ }
+
+});
+
diff --git a/lib/rdoc/generator/template/darkfish/js/thickbox-compressed.js b/lib/rdoc/generator/template/darkfish/js/thickbox-compressed.js
deleted file mode 100644
index 3a3fdae1fb..0000000000
--- a/lib/rdoc/generator/template/darkfish/js/thickbox-compressed.js
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * 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/page.rhtml b/lib/rdoc/generator/template/darkfish/page.rhtml
new file mode 100644
index 0000000000..942172919b
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/page.rhtml
@@ -0,0 +1,18 @@
+<body class="file">
+<nav id="metadata">
+ <%= render '_sidebar_navigation.rhtml' %>
+
+ <%= render '_sidebar_search.rhtml' %>
+
+ <%= render '_sidebar_table_of_contents.rhtml' %>
+
+ <div id="project-metadata">
+ <%= render '_sidebar_pages.rhtml' %>
+ <%= render '_sidebar_classes.rhtml' %>
+ </div>
+</nav>
+
+<div id="documentation" class="description">
+ <%= file.description %>
+</div>
+
diff --git a/lib/rdoc/generator/template/darkfish/rdoc.css b/lib/rdoc/generator/template/darkfish/rdoc.css
index ea91421837..b965e604e6 100644
--- a/lib/rdoc/generator/template/darkfish/rdoc.css
+++ b/lib/rdoc/generator/template/darkfish/rdoc.css
@@ -6,15 +6,14 @@
*
*/
+/* vim: ft=css et sw=2 ts=2 sts=2 */
/* Base Green is: #6C8C22 */
-*{ padding: 0; margin: 0; }
+* { 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 {
@@ -44,6 +43,15 @@ pre {
padding: 0.5em 0;
}
+blockquote {
+ background: #ddd;
+ margin: 1em;
+ padding: 0.25em;
+}
+
+blockquote > :first-child {
+ margin-top: 0 !important;
+}
/* @group Generic Classes */
@@ -51,16 +59,21 @@ pre {
display: none;
}
-.quicksearch-field {
+#search-field {
width: 98%;
- background: #ddd;
- border: 1px solid #aaa;
+ background: #eee;
+ border: none;
height: 1.5em;
-webkit-border-radius: 4px;
}
-.quicksearch-field:focus {
+#search-field:focus {
background: #f1edba;
}
+#search-field:-moz-placeholder,
+#search-field::-webkit-input-placeholder {
+ font-weight: bold;
+ color: #666;
+}
.missing-docs {
font-size: 120%;
@@ -86,28 +99,8 @@ pre {
/* @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 .rdoc-list p, .file .rdoc-list p {
- margin: 0em 0;
-}
-
-.indexpage ol,
-.file #documentation ol {
- line-height: 160%;
-}
-
-.indexpage ul,
-.file #documentation ul {
+.indexpage ul {
line-height: 160%;
list-style: none;
}
@@ -116,25 +109,16 @@ body.file p {
font-size: 16px;
}
-.indexpage li,
-.file #documentation li {
+.indexpage li {
padding-left: 20px;
}
-.indexpage ol,
-.file #documentation ol {
- margin-left: 20px;
-}
-
-.indexpage ol > li,
-.file #documentation ol > li {
- padding-left: 0;
-}
-
-.indexpage ul > li,
-.file #documentation ul > li {
+.indexpage ul > li {
background: url(images/bullet_black.png) no-repeat left 4px;
}
+.indexpage li.method {
+ background: url(images/plugin.png) no-repeat left 4px;
+}
.indexpage li.module {
background: url(images/package.png) no-repeat left 4px;
}
@@ -144,36 +128,37 @@ body.file p {
.indexpage li.file {
background: url(images/page_white_text.png) no-repeat left 4px;
}
-.file li p,
-.indexpage li p {
- margin: 0 0;
+.indexpage li li {
+ background: url(images/tag_blue.png) no-repeat left 4px;
+}
+.indexpage li .toc-toggle {
+ width: 16px;
+ height: 16px;
+ background: url(images/add.png) no-repeat;
+}
+
+.indexpage li .toc-toggle.open {
+ background: url(images/delete.png) no-repeat;
}
/* @end */
/* @group Top-Level Structure */
-.class #metadata,
-.file #metadata,
-.module #metadata {
+#metadata {
float: left;
width: 260px;
}
-.class #documentation,
-.file #documentation,
-.module #documentation {
+#documentation {
margin: 2em 1em 5em 300px;
min-width: 340px;
}
-.file #metadata {
- margin: 0.8em;
-}
-
#validator-badges {
clear: both;
margin: 1em 1em 2em;
+ font-size: smaller;
}
/* @end */
@@ -184,7 +169,7 @@ body.file p {
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border: 1px solid #aaa;
- margin: 0 8px 16px;
+ margin: 0 8px 8px;
font-size: 90%;
overflow: hidden;
}
@@ -210,11 +195,24 @@ body.file p {
list-style: none;
}
+#file-metadata {
+ margin-top: 2em;
+}
+
#file-metadata ul {
padding-left: 28px;
list-style-image: url(images/page_green.png);
}
+#table-of-contents {
+ margin-top: 2em;
+}
+
+#table-of-contents ul {
+ padding-left: 28px;
+ list-style-image: url(images/tag_blue.png);
+}
+
dl.svninfo {
color: #666;
margin: 0;
@@ -225,7 +223,9 @@ dl.svninfo dt {
ul.link-list li {
white-space: nowrap;
+ line-height: 20px;
}
+
ul.link-list .type {
font-size: 8px;
text-transform: uppercase;
@@ -235,16 +235,21 @@ ul.link-list .type {
-webkit-border-radius: 5px;
}
+.calls-super {
+ background: url(images/arrow_up.png) no-repeat right center;
+}
+
/* @end */
+/* @group Class Metadata Section */
+#class-metadata {
+ margin-top: 2em;
+}
+/* @end */
/* @group Project Metadata Section */
#project-metadata {
- margin-top: 3em;
-}
-
-.file #project-metadata {
- margin-top: 0em;
+ margin-top: 2em;
}
#project-metadata .section {
@@ -254,33 +259,14 @@ ul.link-list .type {
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%;
@@ -295,34 +281,44 @@ ul.link-list .type {
margin: 0;
}
+.description ol,
.description ul {
margin-left: 1.5em;
}
+.description ol li,
.description ul li {
line-height: 1.4em;
}
-.description dl,
-#documentation dl {
+.note-list {
+ margin: 8px 0;
+}
+
+.label-list {
margin: 8px 1.5em;
border: 1px solid #ccc;
}
-.description dl {
+.description .label-list {
font-size: 14px;
}
-.description dt,
-#documentation dt {
+.note-list dt {
+ font-weight: bold;
+}
+.note-list dd {
+ padding: 0 12px;
+}
+
+.label-list dt {
padding: 2px 4px;
font-weight: bold;
background: #ddd;
}
-.description dd,
-#documentation dd {
+.label-list dd {
padding: 2px 12px;
}
-.description dd + dt,
-#documentation dd + dt {
+.label-list dd + dt,
+.note-list dd + dt {
margin-top: 0.7em;
}
@@ -331,8 +327,8 @@ ul.link-list .type {
}
#documentation h2.section-header {
- margin-top: 2em;
- padding: 0.75em 0.5em;
+ margin-top: 1em;
+ padding: 0.25em 0.5em;
background: #ccc;
color: #333;
font-size: 175%;
@@ -341,8 +337,25 @@ ul.link-list .type {
-webkit-border-radius: 3px;
}
+.documentation-section-title {
+ position: relative;
+}
+.documentation-section-title .section-click-top {
+ position: absolute;
+ top: 6px;
+ right: 12px;
+ font-size: 10px;
+ color: #9b9877;
+ visibility: hidden;
+ padding-right: 0.5px;
+}
+
+.documentation-section-title:hover .section-click-top {
+ visibility: visible;
+}
+
#documentation h3.section-header {
- margin-top: 2em;
+ margin-top: 1em;
padding: 0.25em 0.5em;
background-color: #dedede;
color: #333;
@@ -398,6 +411,11 @@ ul.link-list .type {
display: none;
}
+#documentation .method-description .method-calls-super {
+ color: #333;
+ font-weight: bolder;
+}
+
#documentation .method-detail {
margin: 0.5em 0;
padding: 0.5em 0;
@@ -429,7 +447,7 @@ ul.link-list .type {
line-height: 20px;
background: url(images/zoom.png) no-repeat right top;
}
-#documentation .method-detail:hover .method-click-advice {
+#documentation .method-heading:hover .method-click-advice {
visibility: visible;
}
@@ -455,14 +473,14 @@ ul.link-list .type {
cursor: default;
}
#documentation .method-description p {
- padding: 0;
-}
-#documentation .method-description p + p {
margin-bottom: 0.5em;
}
#documentation .method-description ul {
margin-left: 1.5em;
}
+pre {
+ margin: 0.5em 0;
+}
#documentation .attribute-method-heading {
background: url(images/tag_green.png) no-repeat left bottom;
@@ -481,283 +499,76 @@ ul.link-list .type {
/* @end */
-
-
/* @group Source Code */
-div.method-source-code {
+pre {
+ overflow: auto;
background: #262626;
- color: #efefef;
- margin: 1em;
- padding: 0.5em;
+ color: white;
border: 1px dashed #999;
- overflow: hidden;
+ padding: 0.5em;
}
-div.method-source-code pre {
- background: inherit;
- padding: 0;
- color: white;
- overflow: auto;
+.description pre {
+ margin: 0 0.4em;
}
-/* @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-comment { color: #dc0000; 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;
+/* @group search results */
+#search-results h1 {
+ font-size: 1em;
+ font-weight: normal;
+ text-shadow: none;
}
-#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;
+#search-results .current {
+ background: #ccc;
+ border-bottom: 1px solid transparent;
}
-#TB_ajaxContent p{
- padding:5px 0px 5px 0px;
+#search-results li {
+ list-style: none;
+ border-bottom: 1px solid #aaa;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ border-radius: 4px;
+ margin-bottom: 0.5em;
}
-#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 */
+#search-results li:last-child {
+ border-bottom: none;
+ margin-bottom: 0;
}
-* 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');
+#search-results li p {
+ padding: 0;
+ margin: 0.5em;
}
-#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%;
+#search-results .search-namespace {
+ font-weight: bold;
}
-* html #TB_HideSelect { /* ie6 hack */
- position: absolute;
- height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
+#search-results li em {
+ background: yellow;
+ font-style: normal;
}
-#TB_iframeContent{
- clear:both;
- border:none;
- margin-bottom:-1px;
- margin-top:1px;
- _margin-bottom:1px;
+#search-results pre {
+ margin: 0.5em;
}
/* @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/template/darkfish/servlet_not_found.rhtml b/lib/rdoc/generator/template/darkfish/servlet_not_found.rhtml
new file mode 100644
index 0000000000..24c9ba8eaa
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/servlet_not_found.rhtml
@@ -0,0 +1,18 @@
+<body>
+<nav id="metadata">
+ <%= render '_sidebar_navigation.rhtml' %>
+
+ <%= render '_sidebar_search.rhtml' %>
+
+ <div id="project-metadata">
+ <%= render '_sidebar_pages.rhtml' %>
+ <%= render '_sidebar_classes.rhtml' %>
+ </div>
+</nav>
+
+<div id="documentation" class="description">
+ <h1>Not Found</h1>
+
+ <p>The page <kbd><%=h path %></kbd> was not found
+</div>
+
diff --git a/lib/rdoc/generator/template/darkfish/servlet_root.rhtml b/lib/rdoc/generator/template/darkfish/servlet_root.rhtml
new file mode 100644
index 0000000000..63b4ee8ff7
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/servlet_root.rhtml
@@ -0,0 +1,37 @@
+<body>
+<nav id="metadata">
+<%= render '_sidebar_search.rhtml' %>
+
+<%= render '_sidebar_installed.rhtml' %>
+</nav>
+
+<div id="documentation" class="description">
+ <h1>Local RDoc Documentation</h1>
+
+ <p>Here you can browse local documentation from the ruby standard library and
+ your installed gems.
+
+<% gems = installed.select { |_, _, _, type,| type == :gem } %>
+<% missing = gems.reject { |_, _, exists,| exists } %>
+<% unless missing.empty? then %>
+ <h2>Missing Gem Documentation</h2>
+
+ <p>You are missing documentation for some of your installed gems.
+ You can install missing documentation for gems by running
+ <kbd>gem rdoc --all</kbd>. After installing the missing documentation you
+ only need to reload this page. The newly created documentation will
+ automatically appear.
+
+ <p>You can also install documentation for a specific gem by running one of
+ the following commands.
+
+ <ul>
+ <% names = missing.map { |name,| name.sub(/-([^-]*)$/, '') }.uniq %>
+ <% names.each do |name| %>
+ <li><kbd>gem rdoc <%=h name %></kbd>
+ <% end %>
+ </ul>
+<% end %>
+
+</div>
+
diff --git a/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml b/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml
new file mode 100644
index 0000000000..8f19085bb4
--- /dev/null
+++ b/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml
@@ -0,0 +1,55 @@
+<body class="indexpage">
+<h1><%= h @title %></h1>
+
+<% simple_files = @files.select { |f| f.text? } %>
+<% unless simple_files.empty? then %>
+<h2>Pages</h2>
+<ul>
+<% simple_files.sort.each do |file| %>
+ <li class="file">
+ <a href="<%= file.path %>"><%= h file.page_name %></a>
+<%
+ # HACK table_of_contents should not exist on Document
+ table = file.parse(file.comment).table_of_contents
+ unless table.empty? then %>
+ <img class="toc-toggle" src="images/transparent.png" alt="" title="toggle headings">
+ <ul class="initially-hidden">
+<% table.each do |heading| %>
+ <li><a href="<%= file.path %>#<%= heading.aref %>"><%= heading.plain_html %></a>
+<% end %>
+ </ul>
+<% end %>
+ </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>
+<% table = []
+ table.concat klass.parse(klass.comment).table_of_contents
+ table.concat klass.section_contents
+
+ unless table.empty? then %>
+ <img class="toc-toggle" src="images/transparent.png" alt="" title="toggle headings">
+ <ul class="initially-hidden">
+<% table.each do |item| %>
+ <li><a href="<%= klass.path %>#<%= item.aref %>"><%= item.plain_html %></a>
+<% end %>
+ </ul>
+<% end %>
+ </li>
+ <% end %>
+</ul>
+
+<h2 id="methods">Methods</h2>
+<ul>
+ <% @store.all_classes_and_modules.map do |mod|
+ mod.method_list
+ end.flatten.sort.each do |method| %>
+ <li class="method"><a href="<%= method.path %>"><%= method.pretty_name %> &mdash; <%= method.parent.full_name %></a>
+ <% end %>
+</ul>
diff --git a/lib/rdoc/generator/template/json_index/js/navigation.js b/lib/rdoc/generator/template/json_index/js/navigation.js
new file mode 100644
index 0000000000..e41268123e
--- /dev/null
+++ b/lib/rdoc/generator/template/json_index/js/navigation.js
@@ -0,0 +1,142 @@
+/*
+ * Navigation allows movement using the arrow keys through the search results.
+ *
+ * When using this library you will need to set scrollIntoView to the
+ * appropriate function for your layout. Use scrollInWindow if the container
+ * is not scrollable and scrollInElement if the container is a separate
+ * scrolling region.
+ */
+Navigation = new function() {
+ this.initNavigation = function() {
+ var _this = this;
+
+ $(document).keydown(function(e) {
+ _this.onkeydown(e);
+ }).keyup(function(e) {
+ _this.onkeyup(e);
+ });
+
+ this.navigationActive = true;
+ }
+
+ this.setNavigationActive = function(state) {
+ this.navigationActive = state;
+ this.clearMoveTimeout();
+ }
+
+ this.onkeyup = function(e) {
+ if (!this.navigationActive) return;
+
+ switch(e.keyCode) {
+ case 37: //Event.KEY_LEFT:
+ case 38: //Event.KEY_UP:
+ case 39: //Event.KEY_RIGHT:
+ case 40: //Event.KEY_DOWN:
+ this.clearMoveTimeout();
+ break;
+ }
+ }
+
+ this.onkeydown = function(e) {
+ if (!this.navigationActive) return;
+ switch(e.keyCode) {
+ case 37: //Event.KEY_LEFT:
+ if (this.moveLeft()) e.preventDefault();
+ break;
+ case 38: //Event.KEY_UP:
+ if (e.keyCode == 38 || e.ctrlKey) {
+ if (this.moveUp()) e.preventDefault();
+ this.startMoveTimeout(false);
+ }
+ break;
+ case 39: //Event.KEY_RIGHT:
+ if (this.moveRight()) e.preventDefault();
+ break;
+ case 40: //Event.KEY_DOWN:
+ if (e.keyCode == 40 || e.ctrlKey) {
+ if (this.moveDown()) e.preventDefault();
+ this.startMoveTimeout(true);
+ }
+ break;
+ case 13: //Event.KEY_RETURN:
+ if (this.$current)
+ e.preventDefault();
+ this.select(this.$current);
+ break;
+ }
+ if (e.ctrlKey && e.shiftKey) this.select(this.$current);
+ }
+
+ this.clearMoveTimeout = function() {
+ clearTimeout(this.moveTimeout);
+ this.moveTimeout = null;
+ }
+
+ this.startMoveTimeout = function(isDown) {
+ if (!$.browser.mozilla && !$.browser.opera) return;
+ if (this.moveTimeout) this.clearMoveTimeout();
+ var _this = this;
+
+ var go = function() {
+ if (!_this.moveTimeout) return;
+ _this[isDown ? 'moveDown' : 'moveUp']();
+ _this.moveTimout = setTimeout(go, 100);
+ }
+ this.moveTimeout = setTimeout(go, 200);
+ }
+
+ this.moveRight = function() {
+ }
+
+ this.moveLeft = function() {
+ }
+
+ this.move = function(isDown) {
+ }
+
+ this.moveUp = function() {
+ return this.move(false);
+ }
+
+ this.moveDown = function() {
+ return this.move(true);
+ }
+
+ /*
+ * Scrolls to the given element in the scrollable element view.
+ */
+ this.scrollInElement = function(element, view) {
+ var offset, viewHeight, viewScroll, height;
+ offset = element.offsetTop;
+ height = element.offsetHeight;
+ viewHeight = view.offsetHeight;
+ viewScroll = view.scrollTop;
+
+ if (offset - viewScroll + height > viewHeight) {
+ view.scrollTop = offset - viewHeight + height;
+ }
+ if (offset < viewScroll) {
+ view.scrollTop = offset;
+ }
+ }
+
+ /*
+ * Scrolls to the given element in the window. The second argument is
+ * ignored
+ */
+ this.scrollInWindow = function(element, ignored) {
+ var offset, viewHeight, viewScroll, height;
+ offset = element.offsetTop;
+ height = element.offsetHeight;
+ viewHeight = window.innerHeight;
+ viewScroll = window.scrollY;
+
+ if (offset - viewScroll + height > viewHeight) {
+ window.scrollTo(window.scrollX, offset - viewHeight + height);
+ }
+ if (offset < viewScroll) {
+ window.scrollTo(window.scrollX, offset);
+ }
+ }
+}
+
diff --git a/lib/rdoc/generator/template/json_index/js/searcher.js b/lib/rdoc/generator/template/json_index/js/searcher.js
new file mode 100644
index 0000000000..f854b541d0
--- /dev/null
+++ b/lib/rdoc/generator/template/json_index/js/searcher.js
@@ -0,0 +1,228 @@
+Searcher = function(data) {
+ this.data = data;
+ this.handlers = [];
+}
+
+Searcher.prototype = new function() {
+ // search is performed in chunks of 1000 for non-blocking user input
+ var CHUNK_SIZE = 1000;
+ // do not try to find more than 100 results
+ var MAX_RESULTS = 100;
+ var huid = 1;
+ var suid = 1;
+ var runs = 0;
+
+ this.find = function(query) {
+ var queries = splitQuery(query);
+ var regexps = buildRegexps(queries);
+ var highlighters = buildHilighters(queries);
+ var state = { from: 0, pass: 0, limit: MAX_RESULTS, n: suid++};
+ var _this = this;
+
+ this.currentSuid = state.n;
+
+ if (!query) return;
+
+ var run = function() {
+ // stop current search thread if new search started
+ if (state.n != _this.currentSuid) return;
+
+ var results =
+ performSearch(_this.data, regexps, queries, highlighters, state);
+ var hasMore = (state.limit > 0 && state.pass < 4);
+
+ triggerResults.call(_this, results, !hasMore);
+ if (hasMore) {
+ setTimeout(run, 2);
+ }
+ runs++;
+ };
+ runs = 0;
+
+ // start search thread
+ run();
+ }
+
+ /* ----- Events ------ */
+ this.ready = function(fn) {
+ fn.huid = huid;
+ this.handlers.push(fn);
+ }
+
+ /* ----- Utilities ------ */
+ function splitQuery(query) {
+ return jQuery.grep(query.split(/(\s+|::?|\(\)?)/), function(string) {
+ return string.match(/\S/)
+ });
+ }
+
+ function buildRegexps(queries) {
+ return jQuery.map(queries, function(query) {
+ return new RegExp(query.replace(/(.)/g, '([$1])([^$1]*?)'), 'i')
+ });
+ }
+
+ function buildHilighters(queries) {
+ return jQuery.map(queries, function(query) {
+ return jQuery.map(query.split(''), function(l, i) {
+ return '\u0001$' + (i*2+1) + '\u0002$' + (i*2+2);
+ }).join('');
+ });
+ }
+
+ // function longMatchRegexp(index, longIndex, regexps) {
+ // for (var i = regexps.length - 1; i >= 0; i--){
+ // if (!index.match(regexps[i]) && !longIndex.match(regexps[i])) return false;
+ // };
+ // return true;
+ // }
+
+
+ /* ----- Mathchers ------ */
+
+ /*
+ * This record matches if the index starts with queries[0] and the record
+ * matches all of the regexps
+ */
+ function matchPassBeginning(index, longIndex, queries, regexps) {
+ if (index.indexOf(queries[0]) != 0) return false;
+ for (var i=1, l = regexps.length; i < l; i++) {
+ if (!index.match(regexps[i]) && !longIndex.match(regexps[i]))
+ return false;
+ };
+ return true;
+ }
+
+ /*
+ * This record matches if the longIndex starts with queries[0] and the
+ * longIndex matches all of the regexps
+ */
+ function matchPassLongIndex(index, longIndex, queries, regexps) {
+ if (longIndex.indexOf(queries[0]) != 0) return false;
+ for (var i=1, l = regexps.length; i < l; i++) {
+ if (!longIndex.match(regexps[i]))
+ return false;
+ };
+ return true;
+ }
+
+ /*
+ * This record matches if the index contains queries[0] and the record
+ * matches all of the regexps
+ */
+ function matchPassContains(index, longIndex, queries, regexps) {
+ if (index.indexOf(queries[0]) == -1) return false;
+ for (var i=1, l = regexps.length; i < l; i++) {
+ if (!index.match(regexps[i]) && !longIndex.match(regexps[i]))
+ return false;
+ };
+ return true;
+ }
+
+ /*
+ * This record matches if regexps[0] matches the index and the record
+ * matches all of the regexps
+ */
+ function matchPassRegexp(index, longIndex, queries, regexps) {
+ if (!index.match(regexps[0])) return false;
+ for (var i=1, l = regexps.length; i < l; i++) {
+ if (!index.match(regexps[i]) && !longIndex.match(regexps[i]))
+ return false;
+ };
+ return true;
+ }
+
+
+ /* ----- Highlighters ------ */
+ function highlightRegexp(info, queries, regexps, highlighters) {
+ var result = createResult(info);
+ for (var i=0, l = regexps.length; i < l; i++) {
+ result.title = result.title.replace(regexps[i], highlighters[i]);
+ result.namespace = result.namespace.replace(regexps[i], highlighters[i]);
+ };
+ return result;
+ }
+
+ function hltSubstring(string, pos, length) {
+ return string.substring(0, pos) + '\u0001' + string.substring(pos, pos + length) + '\u0002' + string.substring(pos + length);
+ }
+
+ function highlightQuery(info, queries, regexps, highlighters) {
+ var result = createResult(info);
+ var pos = 0;
+ var lcTitle = result.title.toLowerCase();
+
+ pos = lcTitle.indexOf(queries[0]);
+ if (pos != -1) {
+ result.title = hltSubstring(result.title, pos, queries[0].length);
+ }
+
+ result.namespace = result.namespace.replace(regexps[0], highlighters[0]);
+ for (var i=1, l = regexps.length; i < l; i++) {
+ result.title = result.title.replace(regexps[i], highlighters[i]);
+ result.namespace = result.namespace.replace(regexps[i], highlighters[i]);
+ };
+ return result;
+ }
+
+ function createResult(info) {
+ var result = {};
+ result.title = info[0];
+ result.namespace = info[1];
+ result.path = info[2];
+ result.params = info[3];
+ result.snippet = info[4];
+ return result;
+ }
+
+ /* ----- Searching ------ */
+ function performSearch(data, regexps, queries, highlighters, state) {
+ var searchIndex = data.searchIndex;
+ var longSearchIndex = data.longSearchIndex;
+ var info = data.info;
+ var result = [];
+ var i = state.from;
+ var l = searchIndex.length;
+ var togo = CHUNK_SIZE;
+ var matchFunc, hltFunc;
+
+ while (state.pass < 4 && state.limit > 0 && togo > 0) {
+ if (state.pass == 0) {
+ matchFunc = matchPassBeginning;
+ hltFunc = highlightQuery;
+ } else if (state.pass == 1) {
+ matchFunc = matchPassLongIndex;
+ hltFunc = highlightQuery;
+ } else if (state.pass == 2) {
+ matchFunc = matchPassContains;
+ hltFunc = highlightQuery;
+ } else if (state.pass == 3) {
+ matchFunc = matchPassRegexp;
+ hltFunc = highlightRegexp;
+ }
+
+ for (; togo > 0 && i < l && state.limit > 0; i++, togo--) {
+ if (info[i].n == state.n) continue;
+ if (matchFunc(searchIndex[i], longSearchIndex[i], queries, regexps)) {
+ info[i].n = state.n;
+ result.push(hltFunc(info[i], queries, regexps, highlighters));
+ state.limit--;
+ }
+ };
+ if (searchIndex.length <= i) {
+ state.pass++;
+ i = state.from = 0;
+ } else {
+ state.from = i;
+ }
+ }
+ return result;
+ }
+
+ function triggerResults(results, isLast) {
+ jQuery.each(this.handlers, function(i, fn) {
+ fn.call(this, results, isLast)
+ })
+ }
+}
+
diff --git a/lib/rdoc/ghost_method.rb b/lib/rdoc/ghost_method.rb
index 192b46f51f..7eb2d93167 100644
--- a/lib/rdoc/ghost_method.rb
+++ b/lib/rdoc/ghost_method.rb
@@ -1,5 +1,3 @@
-require 'rdoc/any_method'
-
##
# GhostMethod represents a method referenced only by a comment
diff --git a/lib/rdoc/include.rb b/lib/rdoc/include.rb
index 9cebd3d8ef..1e9ff5a464 100644
--- a/lib/rdoc/include.rb
+++ b/lib/rdoc/include.rb
@@ -1,5 +1,3 @@
-require 'rdoc/code_object'
-
##
# A Module include in a class with \#include
@@ -17,7 +15,7 @@ class RDoc::Include < RDoc::CodeObject
super()
@name = name
self.comment = comment
- @module = nil # cache for module if found
+ @module = nil # cache for module if found
end
##
@@ -30,10 +28,11 @@ class RDoc::Include < RDoc::CodeObject
end
def == other # :nodoc:
- self.class == other.class and
- self.name == other.name
+ self.class === other and @name == other.name
end
+ alias eql? ==
+
##
# Full name based on #module
@@ -42,6 +41,10 @@ class RDoc::Include < RDoc::CodeObject
RDoc::ClassModule === m ? m.full_name : @name
end
+ def hash # :nodoc:
+ [@name, self.module].hash
+ end
+
def inspect # :nodoc:
"#<%s:0x%x %s.include %s>" % [
self.class,
@@ -59,6 +62,13 @@ class RDoc::Include < RDoc::CodeObject
# - if not found, look into the children of included modules,
# in reverse inclusion order;
# - if still not found, go up the hierarchy of names.
+ #
+ # This method has <code>O(n!)</code> behavior when the module calling
+ # include is referencing nonexistent modules. Avoid calling #module until
+ # after all the files are parsed. This behavior is due to ruby's constant
+ # lookup behavior.
+ #
+ # As of the beginning of October, 2011, no gem includes nonexistent modules.
def module
return @module if @module
@@ -66,7 +76,7 @@ class RDoc::Include < RDoc::CodeObject
# search the current context
return @name unless parent
full_name = parent.child_name(@name)
- @module = RDoc::TopLevel.modules_hash[full_name]
+ @module = @store.modules_hash[full_name]
return @module if @module
return @name if @name =~ /^::/
@@ -76,22 +86,31 @@ class RDoc::Include < RDoc::CodeObject
inc = i.module
next if String === inc
full_name = inc.child_name(@name)
- @module = RDoc::TopLevel.modules_hash[full_name]
+ @module = @store.modules_hash[full_name]
return @module if @module
end
# go up the hierarchy of names
- p = parent.parent
- while p
- full_name = p.child_name(@name)
- @module = RDoc::TopLevel.modules_hash[full_name]
+ up = parent.parent
+ while up
+ full_name = up.child_name(@name)
+ @module = @store.modules_hash[full_name]
return @module if @module
- p = p.parent
+ up = up.parent
end
@name
end
+ ##
+ # Sets the store for this class or module and its contained code objects.
+
+ def store= store
+ super
+
+ @file = @store.add_file @file.full_name if @file
+ end
+
def to_s # :nodoc:
"include #@name in: #{parent}"
end
diff --git a/lib/rdoc/markdown.rb b/lib/rdoc/markdown.rb
new file mode 100644
index 0000000000..f1fa2cf17b
--- /dev/null
+++ b/lib/rdoc/markdown.rb
@@ -0,0 +1,16372 @@
+# coding: UTF-8
+# :markup: markdown
+
+##
+# RDoc::Markdown as described by the [markdown syntax][syntax].
+#
+# To choose Markdown as your only default format see
+# RDoc::Options@Saved+Options for instructions on setting up a `.doc_options`
+# file to store your project default.
+#
+# ## Extensions
+#
+# The following markdown extensions are supported by the parser, but not all
+# are used in RDoc output by default.
+#
+# ### RDoc
+#
+# The RDoc Markdown parser has the following built-in behaviors that cannot be
+# disabled.
+#
+# Underscores embedded in words are never interpreted as emphasis. (While the
+# [markdown dingus][dingus] emphasizes in-word underscores, neither the
+# Markdown syntax nor MarkdownTest mention this behavior.)
+#
+# For HTML output, RDoc always auto-links bare URLs.
+#
+# ### Break on Newline
+#
+# The break_on_newline extension converts all newlines into hard line breaks
+# as in [Github Flavored Markdown][GFM]. This extension is disabled by
+# default.
+#
+# ### CSS
+#
+# The #css extension enables CSS blocks to be included in the output, but they
+# are not used for any built-in RDoc output format. This extension is disabled
+# by default.
+#
+# Example:
+#
+# <style type="text/css">
+# h1 { font-size: 3em }
+# </style>
+#
+# ### Definition Lists
+#
+# The definition_lists extension allows definition lists using the [PHP
+# Markdown Extra syntax][PHPE], but only one label and definition are supported
+# at this time. This extension is enabled by default.
+#
+# Example:
+#
+# ```
+# cat
+# : A small furry mammal
+# that seems to sleep a lot
+#
+# ant
+# : A little insect that is known
+# to enjoy picnics
+#
+# ```
+#
+# Produces:
+#
+# cat
+# : A small furry mammal
+# that seems to sleep a lot
+#
+# ant
+# : A little insect that is known
+# to enjoy picnics
+#
+# ### Github
+#
+# The #github extension enables a partial set of [Github Flavored Markdown]
+# [GFM]. This extension is enabled by default.
+#
+# Supported github extensions include:
+#
+# #### Fenced code blocks
+#
+# Use ` ``` ` around a block of code instead of indenting it four spaces.
+#
+# #### Syntax highlighting
+#
+# Use ` ``` ruby ` as the start of a code fence to add syntax highlighting.
+# (Currently only `ruby` syntax is supported).
+#
+# ### HTML
+#
+# Enables raw HTML to be included in the output. This extension is enabled by
+# default.
+#
+# Example:
+#
+# <table>
+# ...
+# </table>
+#
+# ### Notes
+#
+# The #notes extension enables footnote support. This extension is enabled by
+# default.
+#
+# Example:
+#
+# Here is some text[^1] including an inline footnote ^[for short footnotes]
+#
+# ...
+#
+# [^1]: With the footnote text down at the bottom
+#
+# Produces:
+#
+# Here is some text[^1] including an inline footnote ^[for short footnotes]
+#
+# [^1]: With the footnote text down at the bottom
+#
+# ## Limitations
+#
+# * Link titles are not used
+# * Image links are not generated correctly
+# * Footnotes are collapsed into a single paragraph
+#
+# ## Author
+#
+# This markdown parser is a port to kpeg from [peg-markdown][pegmarkdown] by
+# John MacFarlane.
+#
+# It is used under the MIT license:
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# The port to kpeg was performed by Eric Hodel and Evan Phoenix
+#
+# [dingus]: http://daringfireball.net/projects/markdown/dingus
+# [GFM]: http://github.github.com/github-flavored-markdown/
+# [pegmarkdown]: https://github.com/jgm/peg-markdown
+# [PHPE]: http://michelf.com/projects/php-markdown/extra/#def-list
+# [syntax]: http://daringfireball.net/projects/markdown/syntax
+#--
+# Last updated to jgm/peg-markdown commit 8f8fc22ef0
+class RDoc::Markdown
+ # :stopdoc:
+
+ # This is distinct from setup_parser so that a standalone parser
+ # can redefine #initialize and still have access to the proper
+ # parser setup code.
+ def initialize(str, debug=false)
+ setup_parser(str, debug)
+ end
+
+
+
+ # Prepares for parsing +str+. If you define a custom initialize you must
+ # call this method before #parse
+ def setup_parser(str, debug=false)
+ @string = str
+ @pos = 0
+ @memoizations = Hash.new { |h,k| h[k] = {} }
+ @result = nil
+ @failed_rule = nil
+ @failing_rule_offset = -1
+
+ setup_foreign_grammar
+ end
+
+ attr_reader :string
+ attr_reader :failing_rule_offset
+ attr_accessor :result, :pos
+
+
+ def current_column(target=pos)
+ if c = string.rindex("\n", target-1)
+ return target - c - 1
+ end
+
+ target + 1
+ end
+
+ def current_line(target=pos)
+ cur_offset = 0
+ cur_line = 0
+
+ string.each_line do |line|
+ cur_line += 1
+ cur_offset += line.size
+ return cur_line if cur_offset >= target
+ end
+
+ -1
+ end
+
+ def lines
+ lines = []
+ string.each_line { |l| lines << l }
+ lines
+ end
+
+
+
+ def get_text(start)
+ @string[start..@pos-1]
+ end
+
+ def show_pos
+ width = 10
+ if @pos < width
+ "#{@pos} (\"#{@string[0,@pos]}\" @ \"#{@string[@pos,width]}\")"
+ else
+ "#{@pos} (\"... #{@string[@pos - width, width]}\" @ \"#{@string[@pos,width]}\")"
+ end
+ end
+
+ def failure_info
+ l = current_line @failing_rule_offset
+ c = current_column @failing_rule_offset
+
+ if @failed_rule.kind_of? Symbol
+ info = self.class::Rules[@failed_rule]
+ "line #{l}, column #{c}: failed rule '#{info.name}' = '#{info.rendered}'"
+ else
+ "line #{l}, column #{c}: failed rule '#{@failed_rule}'"
+ end
+ end
+
+ def failure_caret
+ l = current_line @failing_rule_offset
+ c = current_column @failing_rule_offset
+
+ line = lines[l-1]
+ "#{line}\n#{' ' * (c - 1)}^"
+ end
+
+ def failure_character
+ l = current_line @failing_rule_offset
+ c = current_column @failing_rule_offset
+ lines[l-1][c-1, 1]
+ end
+
+ def failure_oneline
+ l = current_line @failing_rule_offset
+ c = current_column @failing_rule_offset
+
+ char = lines[l-1][c-1, 1]
+
+ if @failed_rule.kind_of? Symbol
+ info = self.class::Rules[@failed_rule]
+ "@#{l}:#{c} failed rule '#{info.name}', got '#{char}'"
+ else
+ "@#{l}:#{c} failed rule '#{@failed_rule}', got '#{char}'"
+ end
+ end
+
+ class ParseError < RuntimeError
+ end
+
+ def raise_error
+ raise ParseError, failure_oneline
+ end
+
+ def show_error(io=STDOUT)
+ error_pos = @failing_rule_offset
+ line_no = current_line(error_pos)
+ col_no = current_column(error_pos)
+
+ io.puts "On line #{line_no}, column #{col_no}:"
+
+ if @failed_rule.kind_of? Symbol
+ info = self.class::Rules[@failed_rule]
+ io.puts "Failed to match '#{info.rendered}' (rule '#{info.name}')"
+ else
+ io.puts "Failed to match rule '#{@failed_rule}'"
+ end
+
+ io.puts "Got: #{string[error_pos,1].inspect}"
+ line = lines[line_no-1]
+ io.puts "=> #{line}"
+ io.print(" " * (col_no + 3))
+ io.puts "^"
+ end
+
+ def set_failed_rule(name)
+ if @pos > @failing_rule_offset
+ @failed_rule = name
+ @failing_rule_offset = @pos
+ end
+ end
+
+ attr_reader :failed_rule
+
+ def match_string(str)
+ len = str.size
+ if @string[pos,len] == str
+ @pos += len
+ return str
+ end
+
+ return nil
+ end
+
+ def scan(reg)
+ if m = reg.match(@string[@pos..-1])
+ width = m.end(0)
+ @pos += width
+ return true
+ end
+
+ return nil
+ end
+
+ if "".respond_to? :getbyte
+ def get_byte
+ if @pos >= @string.size
+ return nil
+ end
+
+ s = @string.getbyte @pos
+ @pos += 1
+ s
+ end
+ else
+ def get_byte
+ if @pos >= @string.size
+ return nil
+ end
+
+ s = @string[@pos]
+ @pos += 1
+ s
+ end
+ end
+
+ def parse(rule=nil)
+ # We invoke the rules indirectly via apply
+ # instead of by just calling them as methods because
+ # if the rules use left recursion, apply needs to
+ # manage that.
+
+ if !rule
+ apply(:_root)
+ else
+ method = rule.gsub("-","_hyphen_")
+ apply :"_#{method}"
+ end
+ end
+
+ class MemoEntry
+ def initialize(ans, pos)
+ @ans = ans
+ @pos = pos
+ @result = nil
+ @set = false
+ @left_rec = false
+ end
+
+ attr_reader :ans, :pos, :result, :set
+ attr_accessor :left_rec
+
+ def move!(ans, pos, result)
+ @ans = ans
+ @pos = pos
+ @result = result
+ @set = true
+ @left_rec = false
+ end
+ end
+
+ def external_invoke(other, rule, *args)
+ old_pos = @pos
+ old_string = @string
+
+ @pos = other.pos
+ @string = other.string
+
+ begin
+ if val = __send__(rule, *args)
+ other.pos = @pos
+ other.result = @result
+ else
+ other.set_failed_rule "#{self.class}##{rule}"
+ end
+ val
+ ensure
+ @pos = old_pos
+ @string = old_string
+ end
+ end
+
+ def apply_with_args(rule, *args)
+ memo_key = [rule, args]
+ if m = @memoizations[memo_key][@pos]
+ @pos = m.pos
+ if !m.set
+ m.left_rec = true
+ return nil
+ end
+
+ @result = m.result
+
+ return m.ans
+ else
+ m = MemoEntry.new(nil, @pos)
+ @memoizations[memo_key][@pos] = m
+ start_pos = @pos
+
+ ans = __send__ rule, *args
+
+ lr = m.left_rec
+
+ m.move! ans, @pos, @result
+
+ # Don't bother trying to grow the left recursion
+ # if it's failing straight away (thus there is no seed)
+ if ans and lr
+ return grow_lr(rule, args, start_pos, m)
+ else
+ return ans
+ end
+
+ return ans
+ end
+ end
+
+ def apply(rule)
+ if m = @memoizations[rule][@pos]
+ @pos = m.pos
+ if !m.set
+ m.left_rec = true
+ return nil
+ end
+
+ @result = m.result
+
+ return m.ans
+ else
+ m = MemoEntry.new(nil, @pos)
+ @memoizations[rule][@pos] = m
+ start_pos = @pos
+
+ ans = __send__ rule
+
+ lr = m.left_rec
+
+ m.move! ans, @pos, @result
+
+ # Don't bother trying to grow the left recursion
+ # if it's failing straight away (thus there is no seed)
+ if ans and lr
+ return grow_lr(rule, nil, start_pos, m)
+ else
+ return ans
+ end
+
+ return ans
+ end
+ end
+
+ def grow_lr(rule, args, start_pos, m)
+ while true
+ @pos = start_pos
+ @result = m.result
+
+ if args
+ ans = __send__ rule, *args
+ else
+ ans = __send__ rule
+ end
+ return nil unless ans
+
+ break if @pos <= m.pos
+
+ m.move! ans, @pos, @result
+ end
+
+ @result = m.result
+ @pos = m.pos
+ return m.ans
+ end
+
+ class RuleInfo
+ def initialize(name, rendered)
+ @name = name
+ @rendered = rendered
+ end
+
+ attr_reader :name, :rendered
+ end
+
+ def self.rule_info(name, rendered)
+ RuleInfo.new(name, rendered)
+ end
+
+
+ # :startdoc:
+
+
+
+ require 'rubygems'
+ require 'rdoc'
+ require 'rdoc/markup/to_joined_paragraph'
+ require 'rdoc/markdown/entities'
+
+ if RUBY_VERSION > '1.9' then
+ require 'rdoc/markdown/literals_1_9'
+ else
+ require 'rdoc/markdown/literals_1_8'
+ end
+
+ ##
+ # Supported extensions
+
+ EXTENSIONS = []
+
+ ##
+ # Extensions enabled by default
+
+ DEFAULT_EXTENSIONS = [
+ :definition_lists,
+ :github,
+ :html,
+ :notes,
+ ]
+
+ # :section: Extensions
+
+ ##
+ # Creates extension methods for the `name` extension to enable and disable
+ # the extension and to query if they are active.
+
+ def self.extension name
+ EXTENSIONS << name
+
+ eval <<-RUBY
+ def #{name}?
+ extension? __method__
+ end
+
+ def #{name}= enable
+ extension __method__, enable
+ end
+ RUBY
+ end
+
+ ##
+ # Converts all newlines into hard breaks
+
+ extension :break_on_newline
+
+ ##
+ # Allow style blocks
+
+ extension :css
+
+ ##
+ # Allow PHP Markdown Extras style definition lists
+
+ extension :definition_lists
+
+ ##
+ # Allow Github Flavored Markdown
+
+ extension :github
+
+ ##
+ # Allow HTML
+
+ extension :html
+
+ ##
+ # Enables the notes extension
+
+ extension :notes
+
+ # :section:
+
+ ##
+ # Parses the `markdown` document into an RDoc::Document using the default
+ # extensions.
+
+ def self.parse markdown
+ parser = new
+
+ parser.parse markdown
+ end
+
+ # TODO remove when kpeg 0.10 is released
+ alias orig_initialize initialize # :nodoc:
+
+ ##
+ # Creates a new markdown parser that enables the given +extensions+.
+
+ def initialize extensions = DEFAULT_EXTENSIONS, debug = false
+ @debug = debug
+ @formatter = RDoc::Markup::ToJoinedParagraph.new
+ @extensions = extensions
+
+ @references = nil
+ @unlinked_references = nil
+
+ @footnotes = nil
+ @note_order = nil
+ end
+
+ ##
+ # Wraps `text` in emphasis for rdoc inline formatting
+
+ def emphasis text
+ if text =~ /\A[a-z\d.\/]+\z/i then
+ "_#{text}_"
+ else
+ "<em>#{text}</em>"
+ end
+ end
+
+ ##
+ # :category: Extensions
+ #
+ # Is the extension `name` enabled?
+
+ def extension? name
+ name = name.to_s.delete('?').intern
+
+ @extensions.include? name
+ end
+
+ ##
+ # :category: Extensions
+ #
+ # Enables or disables the extension with `name`
+
+ def extension name, enable
+ name = name.to_s.delete('=').intern
+
+ if enable then
+ @extensions |= [name]
+ else
+ @extensions -= [name]
+ end
+ end
+
+ ##
+ # Parses `text` in a clone of this parser. This is used for handling nested
+ # lists the same way as markdown_parser.
+
+ def inner_parse text # :nodoc:
+ parser = clone
+
+ parser.setup_parser text, @debug
+
+ parser.peg_parse
+
+ doc = parser.result
+
+ doc.accept @formatter
+
+ doc.parts
+ end
+
+ ##
+ # Finds a link reference for `label` and creates a new link to it with
+ # `content` as the link text. If `label` was not encountered in the
+ # reference-gathering parser pass the label and content are reconstructed
+ # with the linking `text` (usually whitespace).
+
+ def link_to content, label = content, text = nil
+ raise 'enable notes extension' if
+ content.start_with? '^' and label.equal? content
+
+ if ref = @references[label] then
+ "{#{content}}[#{ref}]"
+ elsif label.equal? content then
+ "[#{content}]#{text}"
+ else
+ "[#{content}]#{text}[#{label}]"
+ end
+ end
+
+ ##
+ # Creates an RDoc::Markup::ListItem by parsing the `unparsed` content from
+ # the first parsing pass.
+
+ def list_item_from unparsed
+ parsed = inner_parse unparsed.join
+ RDoc::Markup::ListItem.new nil, *parsed
+ end
+
+ ##
+ # Stores `label` as a note and fills in previously unknown note references.
+
+ def note label
+ #foottext = "rdoc-label:foottext-#{label}:footmark-#{label}"
+
+ #ref.replace foottext if ref = @unlinked_notes.delete(label)
+
+ @notes[label] = foottext
+
+ #"{^1}[rdoc-label:footmark-#{label}:foottext-#{label}] "
+ end
+
+ ##
+ # Creates a new link for the footnote `reference` and adds the reference to
+ # the note order list for proper display at the end of the document.
+
+ def note_for ref
+ @note_order << ref
+
+ label = @note_order.length
+
+ "{*#{label}}[rdoc-label:foottext-#{label}:footmark-#{label}]"
+ end
+
+ ##
+ # The internal kpeg parse method
+
+ alias peg_parse parse # :nodoc:
+
+ ##
+ # Creates an RDoc::Markup::Paragraph from `parts` and including
+ # extension-specific behavior
+
+ def paragraph parts
+ parts = parts.map do |part|
+ if "\n" == part then
+ RDoc::Markup::HardBreak.new
+ else
+ part
+ end
+ end if break_on_newline?
+
+ RDoc::Markup::Paragraph.new(*parts)
+ end
+
+ ##
+ # Parses `markdown` into an RDoc::Document
+
+ def parse markdown
+ @references = {}
+ @unlinked_references = {}
+
+ markdown += "\n\n"
+
+ setup_parser markdown, @debug
+ peg_parse 'References'
+
+ if notes? then
+ @footnotes = {}
+
+ setup_parser markdown, @debug
+ peg_parse 'Notes'
+
+ # using note_order on the first pass would be a bug
+ @note_order = []
+ end
+
+ setup_parser markdown, @debug
+ peg_parse
+
+ doc = result
+
+ if notes? and not @footnotes.empty? then
+ doc << RDoc::Markup::Rule.new(1)
+
+ @note_order.each_with_index do |ref, index|
+ label = index + 1
+ note = @footnotes[ref]
+
+ link = "{^#{label}}[rdoc-label:footmark-#{label}:foottext-#{label}] "
+ note.parts.unshift link
+
+ doc << note
+ end
+ end
+
+ doc.accept @formatter
+
+ doc
+ end
+
+ ##
+ # Stores `label` as a reference to `link` and fills in previously unknown
+ # link references.
+
+ def reference label, link
+ if ref = @unlinked_references.delete(label) then
+ ref.replace link
+ end
+
+ @references[label] = link
+ end
+
+ ##
+ # Wraps `text` in strong markup for rdoc inline formatting
+
+ def strong text
+ if text =~ /\A[a-z\d.\/-]+\z/i then
+ "*#{text}*"
+ else
+ "<b>#{text}</b>"
+ end
+ end
+
+
+ # :stopdoc:
+ def setup_foreign_grammar
+ @_grammar_literals = RDoc::Markdown::Literals.new(nil)
+ end
+
+ # root = Doc
+ def _root
+ _tmp = apply(:_Doc)
+ set_failed_rule :_root unless _tmp
+ return _tmp
+ end
+
+ # Doc = BOM? Block*:a { RDoc::Markup::Document.new(*a.compact) }
+ def _Doc
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = apply(:_BOM)
+ unless _tmp
+ _tmp = true
+ self.pos = _save1
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _ary = []
+ while true
+ _tmp = apply(:_Block)
+ _ary << @result if _tmp
+ break unless _tmp
+ end
+ _tmp = true
+ @result = _ary
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; RDoc::Markup::Document.new(*a.compact) ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Doc unless _tmp
+ return _tmp
+ end
+
+ # Block = BlankLine* (BlockQuote | Verbatim | CodeFence | Note | Reference | HorizontalRule | Heading | OrderedList | BulletList | DefinitionList | HtmlBlock | StyleBlock | Para | Plain)
+ def _Block
+
+ _save = self.pos
+ while true # sequence
+ while true
+ _tmp = apply(:_BlankLine)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_BlockQuote)
+ break if _tmp
+ self.pos = _save2
+ _tmp = apply(:_Verbatim)
+ break if _tmp
+ self.pos = _save2
+ _tmp = apply(:_CodeFence)
+ break if _tmp
+ self.pos = _save2
+ _tmp = apply(:_Note)
+ break if _tmp
+ self.pos = _save2
+ _tmp = apply(:_Reference)
+ break if _tmp
+ self.pos = _save2
+ _tmp = apply(:_HorizontalRule)
+ break if _tmp
+ self.pos = _save2
+ _tmp = apply(:_Heading)
+ break if _tmp
+ self.pos = _save2
+ _tmp = apply(:_OrderedList)
+ break if _tmp
+ self.pos = _save2
+ _tmp = apply(:_BulletList)
+ break if _tmp
+ self.pos = _save2
+ _tmp = apply(:_DefinitionList)
+ break if _tmp
+ self.pos = _save2
+ _tmp = apply(:_HtmlBlock)
+ break if _tmp
+ self.pos = _save2
+ _tmp = apply(:_StyleBlock)
+ break if _tmp
+ self.pos = _save2
+ _tmp = apply(:_Para)
+ break if _tmp
+ self.pos = _save2
+ _tmp = apply(:_Plain)
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Block unless _tmp
+ return _tmp
+ end
+
+ # Para = NonindentSpace Inlines:a BlankLine+ { paragraph a }
+ def _Para
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_NonindentSpace)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Inlines)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save1 = self.pos
+ _tmp = apply(:_BlankLine)
+ if _tmp
+ while true
+ _tmp = apply(:_BlankLine)
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save1
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; paragraph a ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Para unless _tmp
+ return _tmp
+ end
+
+ # Plain = Inlines:a { paragraph a }
+ def _Plain
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_Inlines)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; paragraph a ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Plain unless _tmp
+ return _tmp
+ end
+
+ # AtxInline = !Newline !(Sp? "#"* Sp Newline) Inline
+ def _AtxInline
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = apply(:_Newline)
+ _tmp = _tmp ? nil : true
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save2 = self.pos
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_Sp)
+ unless _tmp
+ _tmp = true
+ self.pos = _save4
+ end
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ while true
+ _tmp = match_string("#")
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ _tmp = _tmp ? nil : true
+ self.pos = _save2
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Inline)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_AtxInline unless _tmp
+ return _tmp
+ end
+
+ # AtxStart = < ("######" | "#####" | "####" | "###" | "##" | "#") > { text.length }
+ def _AtxStart
+
+ _save = self.pos
+ while true # sequence
+ _text_start = self.pos
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("######")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("#####")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("####")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("###")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("##")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("#")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; text.length ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_AtxStart unless _tmp
+ return _tmp
+ end
+
+ # AtxHeading = AtxStart:s Sp? AtxInline+:a (Sp? "#"* Sp)? Newline { RDoc::Markup::Heading.new(s, a.join) }
+ def _AtxHeading
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_AtxStart)
+ s = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save1 = self.pos
+ _tmp = apply(:_Sp)
+ unless _tmp
+ _tmp = true
+ self.pos = _save1
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save2 = self.pos
+ _ary = []
+ _tmp = apply(:_AtxInline)
+ if _tmp
+ _ary << @result
+ while true
+ _tmp = apply(:_AtxInline)
+ _ary << @result if _tmp
+ break unless _tmp
+ end
+ _tmp = true
+ @result = _ary
+ else
+ self.pos = _save2
+ end
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save3 = self.pos
+
+ _save4 = self.pos
+ while true # sequence
+ _save5 = self.pos
+ _tmp = apply(:_Sp)
+ unless _tmp
+ _tmp = true
+ self.pos = _save5
+ end
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+ while true
+ _tmp = match_string("#")
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save4
+ end
+ break
+ end # end sequence
+
+ unless _tmp
+ _tmp = true
+ self.pos = _save3
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; RDoc::Markup::Heading.new(s, a.join) ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_AtxHeading unless _tmp
+ return _tmp
+ end
+
+ # SetextHeading = (SetextHeading1 | SetextHeading2)
+ def _SetextHeading
+
+ _save = self.pos
+ while true # choice
+ _tmp = apply(:_SetextHeading1)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_SetextHeading2)
+ break if _tmp
+ self.pos = _save
+ break
+ end # end choice
+
+ set_failed_rule :_SetextHeading unless _tmp
+ return _tmp
+ end
+
+ # SetextBottom1 = "===" "="* Newline
+ def _SetextBottom1
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("===")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = match_string("=")
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_SetextBottom1 unless _tmp
+ return _tmp
+ end
+
+ # SetextBottom2 = "---" "-"* Newline
+ def _SetextBottom2
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("---")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = match_string("-")
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_SetextBottom2 unless _tmp
+ return _tmp
+ end
+
+ # SetextHeading1 = &(RawLine SetextBottom1) StartList:a (!Endline Inline:b { a << b })+ Sp? Newline SetextBottom1 { a; RDoc::Markup::Heading.new(1, a.join) }
+ def _SetextHeading1
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+
+ _save2 = self.pos
+ while true # sequence
+ _tmp = apply(:_RawLine)
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = apply(:_SetextBottom1)
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_StartList)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save3 = self.pos
+
+ _save4 = self.pos
+ while true # sequence
+ _save5 = self.pos
+ _tmp = apply(:_Endline)
+ _tmp = _tmp ? nil : true
+ self.pos = _save5
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+ _tmp = apply(:_Inline)
+ b = @result
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+ @result = begin; a << b ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save4
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ while true
+
+ _save6 = self.pos
+ while true # sequence
+ _save7 = self.pos
+ _tmp = apply(:_Endline)
+ _tmp = _tmp ? nil : true
+ self.pos = _save7
+ unless _tmp
+ self.pos = _save6
+ break
+ end
+ _tmp = apply(:_Inline)
+ b = @result
+ unless _tmp
+ self.pos = _save6
+ break
+ end
+ @result = begin; a << b ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save6
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save3
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save8 = self.pos
+ _tmp = apply(:_Sp)
+ unless _tmp
+ _tmp = true
+ self.pos = _save8
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_SetextBottom1)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; a; RDoc::Markup::Heading.new(1, a.join) ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_SetextHeading1 unless _tmp
+ return _tmp
+ end
+
+ # SetextHeading2 = &(RawLine SetextBottom2) StartList:a (!Endline Inline:b { a << b })+ Sp? Newline SetextBottom2 { RDoc::Markup::Heading.new(2, a.join) }
+ def _SetextHeading2
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+
+ _save2 = self.pos
+ while true # sequence
+ _tmp = apply(:_RawLine)
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = apply(:_SetextBottom2)
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_StartList)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save3 = self.pos
+
+ _save4 = self.pos
+ while true # sequence
+ _save5 = self.pos
+ _tmp = apply(:_Endline)
+ _tmp = _tmp ? nil : true
+ self.pos = _save5
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+ _tmp = apply(:_Inline)
+ b = @result
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+ @result = begin; a << b ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save4
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ while true
+
+ _save6 = self.pos
+ while true # sequence
+ _save7 = self.pos
+ _tmp = apply(:_Endline)
+ _tmp = _tmp ? nil : true
+ self.pos = _save7
+ unless _tmp
+ self.pos = _save6
+ break
+ end
+ _tmp = apply(:_Inline)
+ b = @result
+ unless _tmp
+ self.pos = _save6
+ break
+ end
+ @result = begin; a << b ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save6
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save3
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save8 = self.pos
+ _tmp = apply(:_Sp)
+ unless _tmp
+ _tmp = true
+ self.pos = _save8
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_SetextBottom2)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; RDoc::Markup::Heading.new(2, a.join) ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_SetextHeading2 unless _tmp
+ return _tmp
+ end
+
+ # Heading = (SetextHeading | AtxHeading)
+ def _Heading
+
+ _save = self.pos
+ while true # choice
+ _tmp = apply(:_SetextHeading)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_AtxHeading)
+ break if _tmp
+ self.pos = _save
+ break
+ end # end choice
+
+ set_failed_rule :_Heading unless _tmp
+ return _tmp
+ end
+
+ # BlockQuote = BlockQuoteRaw:a { RDoc::Markup::BlockQuote.new(*a) }
+ def _BlockQuote
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_BlockQuoteRaw)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; RDoc::Markup::BlockQuote.new(*a) ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_BlockQuote unless _tmp
+ return _tmp
+ end
+
+ # BlockQuoteRaw = StartList:a (">" " "? Line:l { a << l } (!">" !BlankLine Line:c { a << c })* (BlankLine:n { a << n })*)+ { inner_parse a.join }
+ def _BlockQuoteRaw
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_StartList)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save1 = self.pos
+
+ _save2 = self.pos
+ while true # sequence
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _save3 = self.pos
+ _tmp = match_string(" ")
+ unless _tmp
+ _tmp = true
+ self.pos = _save3
+ end
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = apply(:_Line)
+ l = @result
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ @result = begin; a << l ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ while true
+
+ _save5 = self.pos
+ while true # sequence
+ _save6 = self.pos
+ _tmp = match_string(">")
+ _tmp = _tmp ? nil : true
+ self.pos = _save6
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ _save7 = self.pos
+ _tmp = apply(:_BlankLine)
+ _tmp = _tmp ? nil : true
+ self.pos = _save7
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ _tmp = apply(:_Line)
+ c = @result
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ @result = begin; a << c ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save5
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ while true
+
+ _save9 = self.pos
+ while true # sequence
+ _tmp = apply(:_BlankLine)
+ n = @result
+ unless _tmp
+ self.pos = _save9
+ break
+ end
+ @result = begin; a << n ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save9
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ while true
+
+ _save10 = self.pos
+ while true # sequence
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save10
+ break
+ end
+ _save11 = self.pos
+ _tmp = match_string(" ")
+ unless _tmp
+ _tmp = true
+ self.pos = _save11
+ end
+ unless _tmp
+ self.pos = _save10
+ break
+ end
+ _tmp = apply(:_Line)
+ l = @result
+ unless _tmp
+ self.pos = _save10
+ break
+ end
+ @result = begin; a << l ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save10
+ break
+ end
+ while true
+
+ _save13 = self.pos
+ while true # sequence
+ _save14 = self.pos
+ _tmp = match_string(">")
+ _tmp = _tmp ? nil : true
+ self.pos = _save14
+ unless _tmp
+ self.pos = _save13
+ break
+ end
+ _save15 = self.pos
+ _tmp = apply(:_BlankLine)
+ _tmp = _tmp ? nil : true
+ self.pos = _save15
+ unless _tmp
+ self.pos = _save13
+ break
+ end
+ _tmp = apply(:_Line)
+ c = @result
+ unless _tmp
+ self.pos = _save13
+ break
+ end
+ @result = begin; a << c ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save13
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save10
+ break
+ end
+ while true
+
+ _save17 = self.pos
+ while true # sequence
+ _tmp = apply(:_BlankLine)
+ n = @result
+ unless _tmp
+ self.pos = _save17
+ break
+ end
+ @result = begin; a << n ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save17
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save10
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save1
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; inner_parse a.join ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_BlockQuoteRaw unless _tmp
+ return _tmp
+ end
+
+ # NonblankIndentedLine = !BlankLine IndentedLine
+ def _NonblankIndentedLine
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = apply(:_BlankLine)
+ _tmp = _tmp ? nil : true
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_IndentedLine)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_NonblankIndentedLine unless _tmp
+ return _tmp
+ end
+
+ # VerbatimChunk = BlankLine*:a NonblankIndentedLine+:b { a.concat b }
+ def _VerbatimChunk
+
+ _save = self.pos
+ while true # sequence
+ _ary = []
+ while true
+ _tmp = apply(:_BlankLine)
+ _ary << @result if _tmp
+ break unless _tmp
+ end
+ _tmp = true
+ @result = _ary
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save2 = self.pos
+ _ary = []
+ _tmp = apply(:_NonblankIndentedLine)
+ if _tmp
+ _ary << @result
+ while true
+ _tmp = apply(:_NonblankIndentedLine)
+ _ary << @result if _tmp
+ break unless _tmp
+ end
+ _tmp = true
+ @result = _ary
+ else
+ self.pos = _save2
+ end
+ b = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; a.concat b ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_VerbatimChunk unless _tmp
+ return _tmp
+ end
+
+ # Verbatim = VerbatimChunk+:a { RDoc::Markup::Verbatim.new(*a.flatten) }
+ def _Verbatim
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _ary = []
+ _tmp = apply(:_VerbatimChunk)
+ if _tmp
+ _ary << @result
+ while true
+ _tmp = apply(:_VerbatimChunk)
+ _ary << @result if _tmp
+ break unless _tmp
+ end
+ _tmp = true
+ @result = _ary
+ else
+ self.pos = _save1
+ end
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; RDoc::Markup::Verbatim.new(*a.flatten) ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Verbatim unless _tmp
+ return _tmp
+ end
+
+ # HorizontalRule = NonindentSpace ("*" Sp "*" Sp "*" (Sp "*")* | "-" Sp "-" Sp "-" (Sp "-")* | "_" Sp "_" Sp "_" (Sp "_")*) Sp Newline BlankLine+ { RDoc::Markup::Rule.new 1 }
+ def _HorizontalRule
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_NonindentSpace)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+
+ _save2 = self.pos
+ while true # sequence
+ _tmp = match_string("*")
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = match_string("*")
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = match_string("*")
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ while true
+
+ _save4 = self.pos
+ while true # sequence
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+ _tmp = match_string("*")
+ unless _tmp
+ self.pos = _save4
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save1
+
+ _save5 = self.pos
+ while true # sequence
+ _tmp = match_string("-")
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ _tmp = match_string("-")
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ _tmp = match_string("-")
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ while true
+
+ _save7 = self.pos
+ while true # sequence
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save7
+ break
+ end
+ _tmp = match_string("-")
+ unless _tmp
+ self.pos = _save7
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save5
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save1
+
+ _save8 = self.pos
+ while true # sequence
+ _tmp = match_string("_")
+ unless _tmp
+ self.pos = _save8
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save8
+ break
+ end
+ _tmp = match_string("_")
+ unless _tmp
+ self.pos = _save8
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save8
+ break
+ end
+ _tmp = match_string("_")
+ unless _tmp
+ self.pos = _save8
+ break
+ end
+ while true
+
+ _save10 = self.pos
+ while true # sequence
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save10
+ break
+ end
+ _tmp = match_string("_")
+ unless _tmp
+ self.pos = _save10
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save8
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save11 = self.pos
+ _tmp = apply(:_BlankLine)
+ if _tmp
+ while true
+ _tmp = apply(:_BlankLine)
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save11
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; RDoc::Markup::Rule.new 1 ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HorizontalRule unless _tmp
+ return _tmp
+ end
+
+ # Bullet = !HorizontalRule NonindentSpace ("+" | "*" | "-") Spacechar+
+ def _Bullet
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = apply(:_HorizontalRule)
+ _tmp = _tmp ? nil : true
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_NonindentSpace)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = match_string("+")
+ break if _tmp
+ self.pos = _save2
+ _tmp = match_string("*")
+ break if _tmp
+ self.pos = _save2
+ _tmp = match_string("-")
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save3 = self.pos
+ _tmp = apply(:_Spacechar)
+ if _tmp
+ while true
+ _tmp = apply(:_Spacechar)
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save3
+ end
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Bullet unless _tmp
+ return _tmp
+ end
+
+ # BulletList = &Bullet (ListTight | ListLoose):a { RDoc::Markup::List.new(:BULLET, *a) }
+ def _BulletList
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = apply(:_Bullet)
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_ListTight)
+ break if _tmp
+ self.pos = _save2
+ _tmp = apply(:_ListLoose)
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; RDoc::Markup::List.new(:BULLET, *a) ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_BulletList unless _tmp
+ return _tmp
+ end
+
+ # ListTight = ListItemTight+:a BlankLine* !(Bullet | Enumerator) { a }
+ def _ListTight
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _ary = []
+ _tmp = apply(:_ListItemTight)
+ if _tmp
+ _ary << @result
+ while true
+ _tmp = apply(:_ListItemTight)
+ _ary << @result if _tmp
+ break unless _tmp
+ end
+ _tmp = true
+ @result = _ary
+ else
+ self.pos = _save1
+ end
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_BlankLine)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save3 = self.pos
+
+ _save4 = self.pos
+ while true # choice
+ _tmp = apply(:_Bullet)
+ break if _tmp
+ self.pos = _save4
+ _tmp = apply(:_Enumerator)
+ break if _tmp
+ self.pos = _save4
+ break
+ end # end choice
+
+ _tmp = _tmp ? nil : true
+ self.pos = _save3
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; a ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_ListTight unless _tmp
+ return _tmp
+ end
+
+ # ListLoose = StartList:a (ListItem:b BlankLine* { a << b })+ { a }
+ def _ListLoose
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_StartList)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save1 = self.pos
+
+ _save2 = self.pos
+ while true # sequence
+ _tmp = apply(:_ListItem)
+ b = @result
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ while true
+ _tmp = apply(:_BlankLine)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ @result = begin; a << b ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ while true
+
+ _save4 = self.pos
+ while true # sequence
+ _tmp = apply(:_ListItem)
+ b = @result
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+ while true
+ _tmp = apply(:_BlankLine)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+ @result = begin; a << b ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save4
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save1
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; a ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_ListLoose unless _tmp
+ return _tmp
+ end
+
+ # ListItem = (Bullet | Enumerator) StartList:a ListBlock:b { a << b } (ListContinuationBlock:c { a.push(*c) })* { list_item_from a }
+ def _ListItem
+
+ _save = self.pos
+ while true # sequence
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = apply(:_Bullet)
+ break if _tmp
+ self.pos = _save1
+ _tmp = apply(:_Enumerator)
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_StartList)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_ListBlock)
+ b = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; a << b ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save3 = self.pos
+ while true # sequence
+ _tmp = apply(:_ListContinuationBlock)
+ c = @result
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ @result = begin; a.push(*c) ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; list_item_from a ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_ListItem unless _tmp
+ return _tmp
+ end
+
+ # ListItemTight = (Bullet | Enumerator) ListBlock:a (!BlankLine ListContinuationBlock:b { a.push(*b) })* !ListContinuationBlock { list_item_from a }
+ def _ListItemTight
+
+ _save = self.pos
+ while true # sequence
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = apply(:_Bullet)
+ break if _tmp
+ self.pos = _save1
+ _tmp = apply(:_Enumerator)
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_ListBlock)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_BlankLine)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = apply(:_ListContinuationBlock)
+ b = @result
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ @result = begin; a.push(*b) ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save5 = self.pos
+ _tmp = apply(:_ListContinuationBlock)
+ _tmp = _tmp ? nil : true
+ self.pos = _save5
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; list_item_from a ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_ListItemTight unless _tmp
+ return _tmp
+ end
+
+ # ListBlock = !BlankLine Line:a ListBlockLine*:c { [a, *c] }
+ def _ListBlock
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = apply(:_BlankLine)
+ _tmp = _tmp ? nil : true
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Line)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _ary = []
+ while true
+ _tmp = apply(:_ListBlockLine)
+ _ary << @result if _tmp
+ break unless _tmp
+ end
+ _tmp = true
+ @result = _ary
+ c = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; [a, *c] ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_ListBlock unless _tmp
+ return _tmp
+ end
+
+ # ListContinuationBlock = StartList:a < BlankLine* > { a << "\n" } (Indent ListBlock:b { a.concat b })+ { a }
+ def _ListContinuationBlock
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_StartList)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _text_start = self.pos
+ while true
+ _tmp = apply(:_BlankLine)
+ break unless _tmp
+ end
+ _tmp = true
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; a << "\n" ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save2 = self.pos
+
+ _save3 = self.pos
+ while true # sequence
+ _tmp = apply(:_Indent)
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = apply(:_ListBlock)
+ b = @result
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ @result = begin; a.concat b ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ while true
+
+ _save4 = self.pos
+ while true # sequence
+ _tmp = apply(:_Indent)
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+ _tmp = apply(:_ListBlock)
+ b = @result
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+ @result = begin; a.concat b ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save4
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save2
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; a ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_ListContinuationBlock unless _tmp
+ return _tmp
+ end
+
+ # Enumerator = NonindentSpace [0-9]+ "." Spacechar+
+ def _Enumerator
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_NonindentSpace)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save1 = self.pos
+ _save2 = self.pos
+ _tmp = get_byte
+ if _tmp
+ unless _tmp >= 48 and _tmp <= 57
+ self.pos = _save2
+ _tmp = nil
+ end
+ end
+ if _tmp
+ while true
+ _save3 = self.pos
+ _tmp = get_byte
+ if _tmp
+ unless _tmp >= 48 and _tmp <= 57
+ self.pos = _save3
+ _tmp = nil
+ end
+ end
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save1
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(".")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save4 = self.pos
+ _tmp = apply(:_Spacechar)
+ if _tmp
+ while true
+ _tmp = apply(:_Spacechar)
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save4
+ end
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Enumerator unless _tmp
+ return _tmp
+ end
+
+ # OrderedList = &Enumerator (ListTight | ListLoose):a { RDoc::Markup::List.new(:NUMBER, *a) }
+ def _OrderedList
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = apply(:_Enumerator)
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_ListTight)
+ break if _tmp
+ self.pos = _save2
+ _tmp = apply(:_ListLoose)
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; RDoc::Markup::List.new(:NUMBER, *a) ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_OrderedList unless _tmp
+ return _tmp
+ end
+
+ # ListBlockLine = !BlankLine !(Indent? (Bullet | Enumerator)) !HorizontalRule OptionallyIndentedLine
+ def _ListBlockLine
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = apply(:_BlankLine)
+ _tmp = _tmp ? nil : true
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save2 = self.pos
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_Indent)
+ unless _tmp
+ _tmp = true
+ self.pos = _save4
+ end
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+
+ _save5 = self.pos
+ while true # choice
+ _tmp = apply(:_Bullet)
+ break if _tmp
+ self.pos = _save5
+ _tmp = apply(:_Enumerator)
+ break if _tmp
+ self.pos = _save5
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ _tmp = _tmp ? nil : true
+ self.pos = _save2
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save6 = self.pos
+ _tmp = apply(:_HorizontalRule)
+ _tmp = _tmp ? nil : true
+ self.pos = _save6
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_OptionallyIndentedLine)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_ListBlockLine unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenAddress = "<" Spnl ("address" | "ADDRESS") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenAddress
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("address")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("ADDRESS")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenAddress unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseAddress = "<" Spnl "/" ("address" | "ADDRESS") Spnl ">"
+ def _HtmlBlockCloseAddress
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("address")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("ADDRESS")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseAddress unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockAddress = HtmlBlockOpenAddress (HtmlBlockAddress | !HtmlBlockCloseAddress .)* HtmlBlockCloseAddress
+ def _HtmlBlockAddress
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenAddress)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockAddress)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseAddress)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseAddress)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockAddress unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenBlockquote = "<" Spnl ("blockquote" | "BLOCKQUOTE") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenBlockquote
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("blockquote")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("BLOCKQUOTE")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenBlockquote unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseBlockquote = "<" Spnl "/" ("blockquote" | "BLOCKQUOTE") Spnl ">"
+ def _HtmlBlockCloseBlockquote
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("blockquote")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("BLOCKQUOTE")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseBlockquote unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockBlockquote = HtmlBlockOpenBlockquote (HtmlBlockBlockquote | !HtmlBlockCloseBlockquote .)* HtmlBlockCloseBlockquote
+ def _HtmlBlockBlockquote
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenBlockquote)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockBlockquote)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseBlockquote)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseBlockquote)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockBlockquote unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenCenter = "<" Spnl ("center" | "CENTER") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenCenter
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("center")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("CENTER")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenCenter unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseCenter = "<" Spnl "/" ("center" | "CENTER") Spnl ">"
+ def _HtmlBlockCloseCenter
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("center")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("CENTER")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseCenter unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCenter = HtmlBlockOpenCenter (HtmlBlockCenter | !HtmlBlockCloseCenter .)* HtmlBlockCloseCenter
+ def _HtmlBlockCenter
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenCenter)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockCenter)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseCenter)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseCenter)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCenter unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenDir = "<" Spnl ("dir" | "DIR") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenDir
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("dir")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("DIR")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenDir unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseDir = "<" Spnl "/" ("dir" | "DIR") Spnl ">"
+ def _HtmlBlockCloseDir
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("dir")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("DIR")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseDir unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockDir = HtmlBlockOpenDir (HtmlBlockDir | !HtmlBlockCloseDir .)* HtmlBlockCloseDir
+ def _HtmlBlockDir
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenDir)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockDir)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseDir)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseDir)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockDir unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenDiv = "<" Spnl ("div" | "DIV") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenDiv
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("div")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("DIV")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenDiv unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseDiv = "<" Spnl "/" ("div" | "DIV") Spnl ">"
+ def _HtmlBlockCloseDiv
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("div")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("DIV")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseDiv unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockDiv = HtmlBlockOpenDiv (HtmlBlockDiv | !HtmlBlockCloseDiv .)* HtmlBlockCloseDiv
+ def _HtmlBlockDiv
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenDiv)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockDiv)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseDiv)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseDiv)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockDiv unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenDl = "<" Spnl ("dl" | "DL") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenDl
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("dl")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("DL")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenDl unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseDl = "<" Spnl "/" ("dl" | "DL") Spnl ">"
+ def _HtmlBlockCloseDl
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("dl")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("DL")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseDl unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockDl = HtmlBlockOpenDl (HtmlBlockDl | !HtmlBlockCloseDl .)* HtmlBlockCloseDl
+ def _HtmlBlockDl
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenDl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockDl)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseDl)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseDl)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockDl unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenFieldset = "<" Spnl ("fieldset" | "FIELDSET") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenFieldset
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("fieldset")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("FIELDSET")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenFieldset unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseFieldset = "<" Spnl "/" ("fieldset" | "FIELDSET") Spnl ">"
+ def _HtmlBlockCloseFieldset
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("fieldset")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("FIELDSET")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseFieldset unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockFieldset = HtmlBlockOpenFieldset (HtmlBlockFieldset | !HtmlBlockCloseFieldset .)* HtmlBlockCloseFieldset
+ def _HtmlBlockFieldset
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenFieldset)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockFieldset)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseFieldset)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseFieldset)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockFieldset unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenForm = "<" Spnl ("form" | "FORM") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenForm
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("form")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("FORM")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenForm unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseForm = "<" Spnl "/" ("form" | "FORM") Spnl ">"
+ def _HtmlBlockCloseForm
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("form")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("FORM")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseForm unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockForm = HtmlBlockOpenForm (HtmlBlockForm | !HtmlBlockCloseForm .)* HtmlBlockCloseForm
+ def _HtmlBlockForm
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenForm)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockForm)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseForm)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseForm)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockForm unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenH1 = "<" Spnl ("h1" | "H1") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenH1
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("h1")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("H1")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenH1 unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseH1 = "<" Spnl "/" ("h1" | "H1") Spnl ">"
+ def _HtmlBlockCloseH1
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("h1")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("H1")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseH1 unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockH1 = HtmlBlockOpenH1 (HtmlBlockH1 | !HtmlBlockCloseH1 .)* HtmlBlockCloseH1
+ def _HtmlBlockH1
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenH1)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockH1)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseH1)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseH1)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockH1 unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenH2 = "<" Spnl ("h2" | "H2") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenH2
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("h2")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("H2")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenH2 unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseH2 = "<" Spnl "/" ("h2" | "H2") Spnl ">"
+ def _HtmlBlockCloseH2
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("h2")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("H2")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseH2 unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockH2 = HtmlBlockOpenH2 (HtmlBlockH2 | !HtmlBlockCloseH2 .)* HtmlBlockCloseH2
+ def _HtmlBlockH2
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenH2)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockH2)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseH2)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseH2)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockH2 unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenH3 = "<" Spnl ("h3" | "H3") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenH3
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("h3")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("H3")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenH3 unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseH3 = "<" Spnl "/" ("h3" | "H3") Spnl ">"
+ def _HtmlBlockCloseH3
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("h3")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("H3")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseH3 unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockH3 = HtmlBlockOpenH3 (HtmlBlockH3 | !HtmlBlockCloseH3 .)* HtmlBlockCloseH3
+ def _HtmlBlockH3
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenH3)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockH3)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseH3)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseH3)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockH3 unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenH4 = "<" Spnl ("h4" | "H4") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenH4
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("h4")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("H4")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenH4 unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseH4 = "<" Spnl "/" ("h4" | "H4") Spnl ">"
+ def _HtmlBlockCloseH4
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("h4")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("H4")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseH4 unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockH4 = HtmlBlockOpenH4 (HtmlBlockH4 | !HtmlBlockCloseH4 .)* HtmlBlockCloseH4
+ def _HtmlBlockH4
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenH4)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockH4)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseH4)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseH4)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockH4 unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenH5 = "<" Spnl ("h5" | "H5") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenH5
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("h5")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("H5")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenH5 unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseH5 = "<" Spnl "/" ("h5" | "H5") Spnl ">"
+ def _HtmlBlockCloseH5
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("h5")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("H5")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseH5 unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockH5 = HtmlBlockOpenH5 (HtmlBlockH5 | !HtmlBlockCloseH5 .)* HtmlBlockCloseH5
+ def _HtmlBlockH5
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenH5)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockH5)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseH5)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseH5)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockH5 unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenH6 = "<" Spnl ("h6" | "H6") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenH6
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("h6")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("H6")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenH6 unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseH6 = "<" Spnl "/" ("h6" | "H6") Spnl ">"
+ def _HtmlBlockCloseH6
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("h6")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("H6")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseH6 unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockH6 = HtmlBlockOpenH6 (HtmlBlockH6 | !HtmlBlockCloseH6 .)* HtmlBlockCloseH6
+ def _HtmlBlockH6
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenH6)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockH6)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseH6)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseH6)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockH6 unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenMenu = "<" Spnl ("menu" | "MENU") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenMenu
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("menu")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("MENU")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenMenu unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseMenu = "<" Spnl "/" ("menu" | "MENU") Spnl ">"
+ def _HtmlBlockCloseMenu
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("menu")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("MENU")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseMenu unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockMenu = HtmlBlockOpenMenu (HtmlBlockMenu | !HtmlBlockCloseMenu .)* HtmlBlockCloseMenu
+ def _HtmlBlockMenu
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenMenu)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockMenu)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseMenu)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseMenu)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockMenu unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenNoframes = "<" Spnl ("noframes" | "NOFRAMES") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenNoframes
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("noframes")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("NOFRAMES")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenNoframes unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseNoframes = "<" Spnl "/" ("noframes" | "NOFRAMES") Spnl ">"
+ def _HtmlBlockCloseNoframes
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("noframes")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("NOFRAMES")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseNoframes unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockNoframes = HtmlBlockOpenNoframes (HtmlBlockNoframes | !HtmlBlockCloseNoframes .)* HtmlBlockCloseNoframes
+ def _HtmlBlockNoframes
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenNoframes)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockNoframes)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseNoframes)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseNoframes)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockNoframes unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenNoscript = "<" Spnl ("noscript" | "NOSCRIPT") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenNoscript
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("noscript")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("NOSCRIPT")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenNoscript unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseNoscript = "<" Spnl "/" ("noscript" | "NOSCRIPT") Spnl ">"
+ def _HtmlBlockCloseNoscript
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("noscript")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("NOSCRIPT")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseNoscript unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockNoscript = HtmlBlockOpenNoscript (HtmlBlockNoscript | !HtmlBlockCloseNoscript .)* HtmlBlockCloseNoscript
+ def _HtmlBlockNoscript
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenNoscript)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockNoscript)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseNoscript)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseNoscript)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockNoscript unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenOl = "<" Spnl ("ol" | "OL") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenOl
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("ol")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("OL")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenOl unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseOl = "<" Spnl "/" ("ol" | "OL") Spnl ">"
+ def _HtmlBlockCloseOl
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("ol")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("OL")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseOl unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOl = HtmlBlockOpenOl (HtmlBlockOl | !HtmlBlockCloseOl .)* HtmlBlockCloseOl
+ def _HtmlBlockOl
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenOl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockOl)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseOl)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseOl)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOl unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenP = "<" Spnl ("p" | "P") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenP
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("p")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("P")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenP unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseP = "<" Spnl "/" ("p" | "P") Spnl ">"
+ def _HtmlBlockCloseP
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("p")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("P")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseP unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockP = HtmlBlockOpenP (HtmlBlockP | !HtmlBlockCloseP .)* HtmlBlockCloseP
+ def _HtmlBlockP
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenP)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockP)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseP)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseP)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockP unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenPre = "<" Spnl ("pre" | "PRE") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenPre
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("pre")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("PRE")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenPre unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockClosePre = "<" Spnl "/" ("pre" | "PRE") Spnl ">"
+ def _HtmlBlockClosePre
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("pre")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("PRE")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockClosePre unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockPre = HtmlBlockOpenPre (HtmlBlockPre | !HtmlBlockClosePre .)* HtmlBlockClosePre
+ def _HtmlBlockPre
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenPre)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockPre)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockClosePre)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockClosePre)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockPre unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenTable = "<" Spnl ("table" | "TABLE") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenTable
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("table")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("TABLE")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenTable unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseTable = "<" Spnl "/" ("table" | "TABLE") Spnl ">"
+ def _HtmlBlockCloseTable
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("table")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("TABLE")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseTable unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockTable = HtmlBlockOpenTable (HtmlBlockTable | !HtmlBlockCloseTable .)* HtmlBlockCloseTable
+ def _HtmlBlockTable
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenTable)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockTable)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseTable)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseTable)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockTable unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenUl = "<" Spnl ("ul" | "UL") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenUl
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("ul")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("UL")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenUl unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseUl = "<" Spnl "/" ("ul" | "UL") Spnl ">"
+ def _HtmlBlockCloseUl
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("ul")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("UL")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseUl unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockUl = HtmlBlockOpenUl (HtmlBlockUl | !HtmlBlockCloseUl .)* HtmlBlockCloseUl
+ def _HtmlBlockUl
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenUl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockUl)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseUl)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseUl)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockUl unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenDd = "<" Spnl ("dd" | "DD") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenDd
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("dd")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("DD")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenDd unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseDd = "<" Spnl "/" ("dd" | "DD") Spnl ">"
+ def _HtmlBlockCloseDd
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("dd")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("DD")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseDd unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockDd = HtmlBlockOpenDd (HtmlBlockDd | !HtmlBlockCloseDd .)* HtmlBlockCloseDd
+ def _HtmlBlockDd
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenDd)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockDd)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseDd)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseDd)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockDd unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenDt = "<" Spnl ("dt" | "DT") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenDt
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("dt")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("DT")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenDt unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseDt = "<" Spnl "/" ("dt" | "DT") Spnl ">"
+ def _HtmlBlockCloseDt
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("dt")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("DT")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseDt unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockDt = HtmlBlockOpenDt (HtmlBlockDt | !HtmlBlockCloseDt .)* HtmlBlockCloseDt
+ def _HtmlBlockDt
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenDt)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockDt)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseDt)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseDt)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockDt unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenFrameset = "<" Spnl ("frameset" | "FRAMESET") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenFrameset
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("frameset")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("FRAMESET")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenFrameset unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseFrameset = "<" Spnl "/" ("frameset" | "FRAMESET") Spnl ">"
+ def _HtmlBlockCloseFrameset
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("frameset")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("FRAMESET")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseFrameset unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockFrameset = HtmlBlockOpenFrameset (HtmlBlockFrameset | !HtmlBlockCloseFrameset .)* HtmlBlockCloseFrameset
+ def _HtmlBlockFrameset
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenFrameset)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockFrameset)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseFrameset)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseFrameset)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockFrameset unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenLi = "<" Spnl ("li" | "LI") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenLi
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("li")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("LI")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenLi unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseLi = "<" Spnl "/" ("li" | "LI") Spnl ">"
+ def _HtmlBlockCloseLi
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("li")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("LI")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseLi unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockLi = HtmlBlockOpenLi (HtmlBlockLi | !HtmlBlockCloseLi .)* HtmlBlockCloseLi
+ def _HtmlBlockLi
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenLi)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockLi)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseLi)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseLi)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockLi unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenTbody = "<" Spnl ("tbody" | "TBODY") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenTbody
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("tbody")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("TBODY")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenTbody unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseTbody = "<" Spnl "/" ("tbody" | "TBODY") Spnl ">"
+ def _HtmlBlockCloseTbody
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("tbody")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("TBODY")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseTbody unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockTbody = HtmlBlockOpenTbody (HtmlBlockTbody | !HtmlBlockCloseTbody .)* HtmlBlockCloseTbody
+ def _HtmlBlockTbody
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenTbody)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockTbody)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseTbody)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseTbody)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockTbody unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenTd = "<" Spnl ("td" | "TD") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenTd
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("td")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("TD")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenTd unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseTd = "<" Spnl "/" ("td" | "TD") Spnl ">"
+ def _HtmlBlockCloseTd
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("td")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("TD")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseTd unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockTd = HtmlBlockOpenTd (HtmlBlockTd | !HtmlBlockCloseTd .)* HtmlBlockCloseTd
+ def _HtmlBlockTd
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenTd)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockTd)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseTd)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseTd)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockTd unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenTfoot = "<" Spnl ("tfoot" | "TFOOT") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenTfoot
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("tfoot")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("TFOOT")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenTfoot unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseTfoot = "<" Spnl "/" ("tfoot" | "TFOOT") Spnl ">"
+ def _HtmlBlockCloseTfoot
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("tfoot")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("TFOOT")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseTfoot unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockTfoot = HtmlBlockOpenTfoot (HtmlBlockTfoot | !HtmlBlockCloseTfoot .)* HtmlBlockCloseTfoot
+ def _HtmlBlockTfoot
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenTfoot)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockTfoot)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseTfoot)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseTfoot)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockTfoot unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenTh = "<" Spnl ("th" | "TH") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenTh
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("th")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("TH")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenTh unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseTh = "<" Spnl "/" ("th" | "TH") Spnl ">"
+ def _HtmlBlockCloseTh
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("th")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("TH")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseTh unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockTh = HtmlBlockOpenTh (HtmlBlockTh | !HtmlBlockCloseTh .)* HtmlBlockCloseTh
+ def _HtmlBlockTh
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenTh)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockTh)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseTh)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseTh)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockTh unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenThead = "<" Spnl ("thead" | "THEAD") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenThead
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("thead")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("THEAD")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenThead unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseThead = "<" Spnl "/" ("thead" | "THEAD") Spnl ">"
+ def _HtmlBlockCloseThead
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("thead")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("THEAD")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseThead unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockThead = HtmlBlockOpenThead (HtmlBlockThead | !HtmlBlockCloseThead .)* HtmlBlockCloseThead
+ def _HtmlBlockThead
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenThead)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockThead)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseThead)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseThead)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockThead unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenTr = "<" Spnl ("tr" | "TR") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenTr
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("tr")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("TR")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenTr unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseTr = "<" Spnl "/" ("tr" | "TR") Spnl ">"
+ def _HtmlBlockCloseTr
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("tr")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("TR")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseTr unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockTr = HtmlBlockOpenTr (HtmlBlockTr | !HtmlBlockCloseTr .)* HtmlBlockCloseTr
+ def _HtmlBlockTr
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenTr)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockTr)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_HtmlBlockCloseTr)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseTr)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockTr unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockOpenScript = "<" Spnl ("script" | "SCRIPT") Spnl HtmlAttribute* ">"
+ def _HtmlBlockOpenScript
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("script")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("SCRIPT")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockOpenScript unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockCloseScript = "<" Spnl "/" ("script" | "SCRIPT") Spnl ">"
+ def _HtmlBlockCloseScript
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("script")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("SCRIPT")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockCloseScript unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockScript = HtmlBlockOpenScript (!HtmlBlockCloseScript .)* HtmlBlockCloseScript
+ def _HtmlBlockScript
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_HtmlBlockOpenScript)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # sequence
+ _save3 = self.pos
+ _tmp = apply(:_HtmlBlockCloseScript)
+ _tmp = _tmp ? nil : true
+ self.pos = _save3
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockCloseScript)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockScript unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockInTags = (HtmlBlockAddress | HtmlBlockBlockquote | HtmlBlockCenter | HtmlBlockDir | HtmlBlockDiv | HtmlBlockDl | HtmlBlockFieldset | HtmlBlockForm | HtmlBlockH1 | HtmlBlockH2 | HtmlBlockH3 | HtmlBlockH4 | HtmlBlockH5 | HtmlBlockH6 | HtmlBlockMenu | HtmlBlockNoframes | HtmlBlockNoscript | HtmlBlockOl | HtmlBlockP | HtmlBlockPre | HtmlBlockTable | HtmlBlockUl | HtmlBlockDd | HtmlBlockDt | HtmlBlockFrameset | HtmlBlockLi | HtmlBlockTbody | HtmlBlockTd | HtmlBlockTfoot | HtmlBlockTh | HtmlBlockThead | HtmlBlockTr | HtmlBlockScript)
+ def _HtmlBlockInTags
+
+ _save = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockAddress)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockBlockquote)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockCenter)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockDir)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockDiv)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockDl)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockFieldset)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockForm)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockH1)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockH2)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockH3)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockH4)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockH5)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockH6)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockMenu)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockNoframes)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockNoscript)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockOl)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockP)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockPre)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockTable)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockUl)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockDd)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockDt)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockFrameset)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockLi)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockTbody)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockTd)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockTfoot)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockTh)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockThead)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockTr)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_HtmlBlockScript)
+ break if _tmp
+ self.pos = _save
+ break
+ end # end choice
+
+ set_failed_rule :_HtmlBlockInTags unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlock = < (HtmlBlockInTags | HtmlComment | HtmlBlockSelfClosing | HtmlUnclosed) > BlankLine+ { if html? then RDoc::Markup::Raw.new text end }
+ def _HtmlBlock
+
+ _save = self.pos
+ while true # sequence
+ _text_start = self.pos
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlockInTags)
+ break if _tmp
+ self.pos = _save1
+ _tmp = apply(:_HtmlComment)
+ break if _tmp
+ self.pos = _save1
+ _tmp = apply(:_HtmlBlockSelfClosing)
+ break if _tmp
+ self.pos = _save1
+ _tmp = apply(:_HtmlUnclosed)
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save2 = self.pos
+ _tmp = apply(:_BlankLine)
+ if _tmp
+ while true
+ _tmp = apply(:_BlankLine)
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save2
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; if html? then
+ RDoc::Markup::Raw.new text
+ end ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlock unless _tmp
+ return _tmp
+ end
+
+ # HtmlUnclosed = "<" Spnl HtmlUnclosedType Spnl HtmlAttribute* Spnl ">"
+ def _HtmlUnclosed
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlUnclosedType)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlUnclosed unless _tmp
+ return _tmp
+ end
+
+ # HtmlUnclosedType = ("HR" | "hr")
+ def _HtmlUnclosedType
+
+ _save = self.pos
+ while true # choice
+ _tmp = match_string("HR")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("hr")
+ break if _tmp
+ self.pos = _save
+ break
+ end # end choice
+
+ set_failed_rule :_HtmlUnclosedType unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockSelfClosing = "<" Spnl HtmlBlockType Spnl HtmlAttribute* "/" Spnl ">"
+ def _HtmlBlockSelfClosing
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_HtmlBlockType)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlBlockSelfClosing unless _tmp
+ return _tmp
+ end
+
+ # HtmlBlockType = ("ADDRESS" | "BLOCKQUOTE" | "CENTER" | "DD" | "DIR" | "DIV" | "DL" | "DT" | "FIELDSET" | "FORM" | "FRAMESET" | "H1" | "H2" | "H3" | "H4" | "H5" | "H6" | "HR" | "ISINDEX" | "LI" | "MENU" | "NOFRAMES" | "NOSCRIPT" | "OL" | "P" | "PRE" | "SCRIPT" | "TABLE" | "TBODY" | "TD" | "TFOOT" | "TH" | "THEAD" | "TR" | "UL" | "address" | "blockquote" | "center" | "dd" | "dir" | "div" | "dl" | "dt" | "fieldset" | "form" | "frameset" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "hr" | "isindex" | "li" | "menu" | "noframes" | "noscript" | "ol" | "p" | "pre" | "script" | "table" | "tbody" | "td" | "tfoot" | "th" | "thead" | "tr" | "ul")
+ def _HtmlBlockType
+
+ _save = self.pos
+ while true # choice
+ _tmp = match_string("ADDRESS")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("BLOCKQUOTE")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("CENTER")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("DD")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("DIR")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("DIV")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("DL")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("DT")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("FIELDSET")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("FORM")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("FRAMESET")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("H1")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("H2")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("H3")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("H4")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("H5")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("H6")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("HR")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("ISINDEX")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("LI")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("MENU")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("NOFRAMES")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("NOSCRIPT")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("OL")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("P")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("PRE")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("SCRIPT")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("TABLE")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("TBODY")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("TD")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("TFOOT")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("TH")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("THEAD")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("TR")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("UL")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("address")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("blockquote")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("center")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("dd")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("dir")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("div")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("dl")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("dt")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("fieldset")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("form")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("frameset")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("h1")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("h2")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("h3")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("h4")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("h5")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("h6")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("hr")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("isindex")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("li")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("menu")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("noframes")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("noscript")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("ol")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("p")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("pre")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("script")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("table")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("tbody")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("td")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("tfoot")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("th")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("thead")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("tr")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("ul")
+ break if _tmp
+ self.pos = _save
+ break
+ end # end choice
+
+ set_failed_rule :_HtmlBlockType unless _tmp
+ return _tmp
+ end
+
+ # StyleOpen = "<" Spnl ("style" | "STYLE") Spnl HtmlAttribute* ">"
+ def _StyleOpen
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("style")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("STYLE")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_StyleOpen unless _tmp
+ return _tmp
+ end
+
+ # StyleClose = "<" Spnl "/" ("style" | "STYLE") Spnl ">"
+ def _StyleClose
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("/")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = match_string("style")
+ break if _tmp
+ self.pos = _save1
+ _tmp = match_string("STYLE")
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_StyleClose unless _tmp
+ return _tmp
+ end
+
+ # InStyleTags = StyleOpen (!StyleClose .)* StyleClose
+ def _InStyleTags
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_StyleOpen)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # sequence
+ _save3 = self.pos
+ _tmp = apply(:_StyleClose)
+ _tmp = _tmp ? nil : true
+ self.pos = _save3
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_StyleClose)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_InStyleTags unless _tmp
+ return _tmp
+ end
+
+ # StyleBlock = < InStyleTags > BlankLine* { if css? then RDoc::Markup::Raw.new text end }
+ def _StyleBlock
+
+ _save = self.pos
+ while true # sequence
+ _text_start = self.pos
+ _tmp = apply(:_InStyleTags)
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_BlankLine)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; if css? then
+ RDoc::Markup::Raw.new text
+ end ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_StyleBlock unless _tmp
+ return _tmp
+ end
+
+ # Inlines = (!Endline Inline:i { i } | Endline:c &Inline { c })+:chunks Endline? { chunks }
+ def _Inlines
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _ary = []
+
+ _save2 = self.pos
+ while true # choice
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_Endline)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = apply(:_Inline)
+ i = @result
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ @result = begin; i ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+
+ _save5 = self.pos
+ while true # sequence
+ _tmp = apply(:_Endline)
+ c = @result
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ _save6 = self.pos
+ _tmp = apply(:_Inline)
+ self.pos = _save6
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ @result = begin; c ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save5
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ if _tmp
+ _ary << @result
+ while true
+
+ _save7 = self.pos
+ while true # choice
+
+ _save8 = self.pos
+ while true # sequence
+ _save9 = self.pos
+ _tmp = apply(:_Endline)
+ _tmp = _tmp ? nil : true
+ self.pos = _save9
+ unless _tmp
+ self.pos = _save8
+ break
+ end
+ _tmp = apply(:_Inline)
+ i = @result
+ unless _tmp
+ self.pos = _save8
+ break
+ end
+ @result = begin; i ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save8
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save7
+
+ _save10 = self.pos
+ while true # sequence
+ _tmp = apply(:_Endline)
+ c = @result
+ unless _tmp
+ self.pos = _save10
+ break
+ end
+ _save11 = self.pos
+ _tmp = apply(:_Inline)
+ self.pos = _save11
+ unless _tmp
+ self.pos = _save10
+ break
+ end
+ @result = begin; c ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save10
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save7
+ break
+ end # end choice
+
+ _ary << @result if _tmp
+ break unless _tmp
+ end
+ _tmp = true
+ @result = _ary
+ else
+ self.pos = _save1
+ end
+ chunks = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save12 = self.pos
+ _tmp = apply(:_Endline)
+ unless _tmp
+ _tmp = true
+ self.pos = _save12
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; chunks ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Inlines unless _tmp
+ return _tmp
+ end
+
+ # Inline = (Str | Endline | UlOrStarLine | Space | Strong | Emph | Image | Link | NoteReference | InlineNote | Code | RawHtml | Entity | EscapedChar | Symbol)
+ def _Inline
+
+ _save = self.pos
+ while true # choice
+ _tmp = apply(:_Str)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_Endline)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_UlOrStarLine)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_Space)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_Strong)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_Emph)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_Image)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_Link)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_NoteReference)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_InlineNote)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_Code)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_RawHtml)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_Entity)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_EscapedChar)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_Symbol)
+ break if _tmp
+ self.pos = _save
+ break
+ end # end choice
+
+ set_failed_rule :_Inline unless _tmp
+ return _tmp
+ end
+
+ # Space = Spacechar+ { " " }
+ def _Space
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = apply(:_Spacechar)
+ if _tmp
+ while true
+ _tmp = apply(:_Spacechar)
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save1
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; " " ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Space unless _tmp
+ return _tmp
+ end
+
+ # Str = StartList:a < NormalChar+ > { a = text } (StrChunk:c { a << c })* { a }
+ def _Str
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_StartList)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _text_start = self.pos
+ _save1 = self.pos
+ _tmp = apply(:_NormalChar)
+ if _tmp
+ while true
+ _tmp = apply(:_NormalChar)
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save1
+ end
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; a = text ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save3 = self.pos
+ while true # sequence
+ _tmp = apply(:_StrChunk)
+ c = @result
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ @result = begin; a << c ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; a ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Str unless _tmp
+ return _tmp
+ end
+
+ # StrChunk = < (NormalChar | "_"+ &Alphanumeric)+ > { text }
+ def _StrChunk
+
+ _save = self.pos
+ while true # sequence
+ _text_start = self.pos
+ _save1 = self.pos
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_NormalChar)
+ break if _tmp
+ self.pos = _save2
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = match_string("_")
+ if _tmp
+ while true
+ _tmp = match_string("_")
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save4
+ end
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _save5 = self.pos
+ _tmp = apply(:_Alphanumeric)
+ self.pos = _save5
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ if _tmp
+ while true
+
+ _save6 = self.pos
+ while true # choice
+ _tmp = apply(:_NormalChar)
+ break if _tmp
+ self.pos = _save6
+
+ _save7 = self.pos
+ while true # sequence
+ _save8 = self.pos
+ _tmp = match_string("_")
+ if _tmp
+ while true
+ _tmp = match_string("_")
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save8
+ end
+ unless _tmp
+ self.pos = _save7
+ break
+ end
+ _save9 = self.pos
+ _tmp = apply(:_Alphanumeric)
+ self.pos = _save9
+ unless _tmp
+ self.pos = _save7
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save6
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save1
+ end
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; text ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_StrChunk unless _tmp
+ return _tmp
+ end
+
+ # EscapedChar = "\\" !Newline < /[:\\`|*_{}\[\]()#+.!><-]/ > { text }
+ def _EscapedChar
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("\\")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save1 = self.pos
+ _tmp = apply(:_Newline)
+ _tmp = _tmp ? nil : true
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _text_start = self.pos
+ _tmp = scan(/\A(?-mix:[:\\`|*_{}\[\]()#+.!><-])/)
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; text ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_EscapedChar unless _tmp
+ return _tmp
+ end
+
+ # Entity = (HexEntity | DecEntity | CharEntity):a { a }
+ def _Entity
+
+ _save = self.pos
+ while true # sequence
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = apply(:_HexEntity)
+ break if _tmp
+ self.pos = _save1
+ _tmp = apply(:_DecEntity)
+ break if _tmp
+ self.pos = _save1
+ _tmp = apply(:_CharEntity)
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; a ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Entity unless _tmp
+ return _tmp
+ end
+
+ # Endline = (LineBreak | TerminalEndline | NormalEndline)
+ def _Endline
+
+ _save = self.pos
+ while true # choice
+ _tmp = apply(:_LineBreak)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_TerminalEndline)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_NormalEndline)
+ break if _tmp
+ self.pos = _save
+ break
+ end # end choice
+
+ set_failed_rule :_Endline unless _tmp
+ return _tmp
+ end
+
+ # NormalEndline = Sp Newline !BlankLine !">" !AtxStart !(Line ("===" "="* | "---" "-"*) Newline) { "\n" }
+ def _NormalEndline
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save1 = self.pos
+ _tmp = apply(:_BlankLine)
+ _tmp = _tmp ? nil : true
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save2 = self.pos
+ _tmp = match_string(">")
+ _tmp = _tmp ? nil : true
+ self.pos = _save2
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save3 = self.pos
+ _tmp = apply(:_AtxStart)
+ _tmp = _tmp ? nil : true
+ self.pos = _save3
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save4 = self.pos
+
+ _save5 = self.pos
+ while true # sequence
+ _tmp = apply(:_Line)
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+
+ _save6 = self.pos
+ while true # choice
+
+ _save7 = self.pos
+ while true # sequence
+ _tmp = match_string("===")
+ unless _tmp
+ self.pos = _save7
+ break
+ end
+ while true
+ _tmp = match_string("=")
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save7
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save6
+
+ _save9 = self.pos
+ while true # sequence
+ _tmp = match_string("---")
+ unless _tmp
+ self.pos = _save9
+ break
+ end
+ while true
+ _tmp = match_string("-")
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save9
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save6
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save5
+ end
+ break
+ end # end sequence
+
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; "\n" ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_NormalEndline unless _tmp
+ return _tmp
+ end
+
+ # TerminalEndline = Sp Newline Eof
+ def _TerminalEndline
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Eof)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_TerminalEndline unless _tmp
+ return _tmp
+ end
+
+ # LineBreak = < " " NormalEndline > { RDoc::Markup::HardBreak.new }
+ def _LineBreak
+
+ _save = self.pos
+ while true # sequence
+ _text_start = self.pos
+
+ _save1 = self.pos
+ while true # sequence
+ _tmp = match_string(" ")
+ unless _tmp
+ self.pos = _save1
+ break
+ end
+ _tmp = apply(:_NormalEndline)
+ unless _tmp
+ self.pos = _save1
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; RDoc::Markup::HardBreak.new ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_LineBreak unless _tmp
+ return _tmp
+ end
+
+ # Symbol = < SpecialChar > { text }
+ def _Symbol
+
+ _save = self.pos
+ while true # sequence
+ _text_start = self.pos
+ _tmp = apply(:_SpecialChar)
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; text ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Symbol unless _tmp
+ return _tmp
+ end
+
+ # UlOrStarLine = (UlLine | StarLine):a { a }
+ def _UlOrStarLine
+
+ _save = self.pos
+ while true # sequence
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = apply(:_UlLine)
+ break if _tmp
+ self.pos = _save1
+ _tmp = apply(:_StarLine)
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; a ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_UlOrStarLine unless _tmp
+ return _tmp
+ end
+
+ # StarLine = (< "****" "*"* > { text } | < Spacechar "*"+ &Spacechar > { text })
+ def _StarLine
+
+ _save = self.pos
+ while true # choice
+
+ _save1 = self.pos
+ while true # sequence
+ _text_start = self.pos
+
+ _save2 = self.pos
+ while true # sequence
+ _tmp = match_string("****")
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ while true
+ _tmp = match_string("*")
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save1
+ break
+ end
+ @result = begin; text ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save1
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save
+
+ _save4 = self.pos
+ while true # sequence
+ _text_start = self.pos
+
+ _save5 = self.pos
+ while true # sequence
+ _tmp = apply(:_Spacechar)
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ _save6 = self.pos
+ _tmp = match_string("*")
+ if _tmp
+ while true
+ _tmp = match_string("*")
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save6
+ end
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ _save7 = self.pos
+ _tmp = apply(:_Spacechar)
+ self.pos = _save7
+ unless _tmp
+ self.pos = _save5
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+ @result = begin; text ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save4
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save
+ break
+ end # end choice
+
+ set_failed_rule :_StarLine unless _tmp
+ return _tmp
+ end
+
+ # UlLine = (< "____" "_"* > { text } | < Spacechar "_"+ &Spacechar > { text })
+ def _UlLine
+
+ _save = self.pos
+ while true # choice
+
+ _save1 = self.pos
+ while true # sequence
+ _text_start = self.pos
+
+ _save2 = self.pos
+ while true # sequence
+ _tmp = match_string("____")
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ while true
+ _tmp = match_string("_")
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save1
+ break
+ end
+ @result = begin; text ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save1
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save
+
+ _save4 = self.pos
+ while true # sequence
+ _text_start = self.pos
+
+ _save5 = self.pos
+ while true # sequence
+ _tmp = apply(:_Spacechar)
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ _save6 = self.pos
+ _tmp = match_string("_")
+ if _tmp
+ while true
+ _tmp = match_string("_")
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save6
+ end
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ _save7 = self.pos
+ _tmp = apply(:_Spacechar)
+ self.pos = _save7
+ unless _tmp
+ self.pos = _save5
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+ @result = begin; text ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save4
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save
+ break
+ end # end choice
+
+ set_failed_rule :_UlLine unless _tmp
+ return _tmp
+ end
+
+ # Emph = (EmphStar | EmphUl)
+ def _Emph
+
+ _save = self.pos
+ while true # choice
+ _tmp = apply(:_EmphStar)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_EmphUl)
+ break if _tmp
+ self.pos = _save
+ break
+ end # end choice
+
+ set_failed_rule :_Emph unless _tmp
+ return _tmp
+ end
+
+ # OneStarOpen = !StarLine "*" !Spacechar !Newline
+ def _OneStarOpen
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = apply(:_StarLine)
+ _tmp = _tmp ? nil : true
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("*")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save2 = self.pos
+ _tmp = apply(:_Spacechar)
+ _tmp = _tmp ? nil : true
+ self.pos = _save2
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save3 = self.pos
+ _tmp = apply(:_Newline)
+ _tmp = _tmp ? nil : true
+ self.pos = _save3
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_OneStarOpen unless _tmp
+ return _tmp
+ end
+
+ # OneStarClose = !Spacechar !Newline Inline:a "*" { a }
+ def _OneStarClose
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = apply(:_Spacechar)
+ _tmp = _tmp ? nil : true
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save2 = self.pos
+ _tmp = apply(:_Newline)
+ _tmp = _tmp ? nil : true
+ self.pos = _save2
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Inline)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("*")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; a ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_OneStarClose unless _tmp
+ return _tmp
+ end
+
+ # EmphStar = OneStarOpen StartList:a (!OneStarClose Inline:l { a << l })* OneStarClose:l { a << l } { emphasis a.join }
+ def _EmphStar
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_OneStarOpen)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_StartList)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # sequence
+ _save3 = self.pos
+ _tmp = apply(:_OneStarClose)
+ _tmp = _tmp ? nil : true
+ self.pos = _save3
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = apply(:_Inline)
+ l = @result
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ @result = begin; a << l ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_OneStarClose)
+ l = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; a << l ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; emphasis a.join ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_EmphStar unless _tmp
+ return _tmp
+ end
+
+ # OneUlOpen = !UlLine "_" !Spacechar !Newline
+ def _OneUlOpen
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = apply(:_UlLine)
+ _tmp = _tmp ? nil : true
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("_")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save2 = self.pos
+ _tmp = apply(:_Spacechar)
+ _tmp = _tmp ? nil : true
+ self.pos = _save2
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save3 = self.pos
+ _tmp = apply(:_Newline)
+ _tmp = _tmp ? nil : true
+ self.pos = _save3
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_OneUlOpen unless _tmp
+ return _tmp
+ end
+
+ # OneUlClose = !Spacechar !Newline Inline:a "_" { a }
+ def _OneUlClose
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = apply(:_Spacechar)
+ _tmp = _tmp ? nil : true
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save2 = self.pos
+ _tmp = apply(:_Newline)
+ _tmp = _tmp ? nil : true
+ self.pos = _save2
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Inline)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("_")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; a ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_OneUlClose unless _tmp
+ return _tmp
+ end
+
+ # EmphUl = OneUlOpen StartList:a (!OneUlClose Inline:l { a << l })* OneUlClose:l { a << l } { emphasis a.join }
+ def _EmphUl
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_OneUlOpen)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_StartList)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # sequence
+ _save3 = self.pos
+ _tmp = apply(:_OneUlClose)
+ _tmp = _tmp ? nil : true
+ self.pos = _save3
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = apply(:_Inline)
+ l = @result
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ @result = begin; a << l ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_OneUlClose)
+ l = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; a << l ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; emphasis a.join ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_EmphUl unless _tmp
+ return _tmp
+ end
+
+ # Strong = (StrongStar | StrongUl)
+ def _Strong
+
+ _save = self.pos
+ while true # choice
+ _tmp = apply(:_StrongStar)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_StrongUl)
+ break if _tmp
+ self.pos = _save
+ break
+ end # end choice
+
+ set_failed_rule :_Strong unless _tmp
+ return _tmp
+ end
+
+ # TwoStarOpen = !StarLine "**" !Spacechar !Newline
+ def _TwoStarOpen
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = apply(:_StarLine)
+ _tmp = _tmp ? nil : true
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("**")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save2 = self.pos
+ _tmp = apply(:_Spacechar)
+ _tmp = _tmp ? nil : true
+ self.pos = _save2
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save3 = self.pos
+ _tmp = apply(:_Newline)
+ _tmp = _tmp ? nil : true
+ self.pos = _save3
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_TwoStarOpen unless _tmp
+ return _tmp
+ end
+
+ # TwoStarClose = !Spacechar !Newline Inline:a "**" { a }
+ def _TwoStarClose
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = apply(:_Spacechar)
+ _tmp = _tmp ? nil : true
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save2 = self.pos
+ _tmp = apply(:_Newline)
+ _tmp = _tmp ? nil : true
+ self.pos = _save2
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Inline)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("**")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; a ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_TwoStarClose unless _tmp
+ return _tmp
+ end
+
+ # StrongStar = TwoStarOpen StartList:a (!TwoStarClose Inline:l { a << l })* TwoStarClose:l { a << l } { strong a.join }
+ def _StrongStar
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_TwoStarOpen)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_StartList)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # sequence
+ _save3 = self.pos
+ _tmp = apply(:_TwoStarClose)
+ _tmp = _tmp ? nil : true
+ self.pos = _save3
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = apply(:_Inline)
+ l = @result
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ @result = begin; a << l ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_TwoStarClose)
+ l = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; a << l ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; strong a.join ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_StrongStar unless _tmp
+ return _tmp
+ end
+
+ # TwoUlOpen = !UlLine "__" !Spacechar !Newline
+ def _TwoUlOpen
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = apply(:_UlLine)
+ _tmp = _tmp ? nil : true
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("__")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save2 = self.pos
+ _tmp = apply(:_Spacechar)
+ _tmp = _tmp ? nil : true
+ self.pos = _save2
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save3 = self.pos
+ _tmp = apply(:_Newline)
+ _tmp = _tmp ? nil : true
+ self.pos = _save3
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_TwoUlOpen unless _tmp
+ return _tmp
+ end
+
+ # TwoUlClose = !Spacechar !Newline Inline:a "__" { a }
+ def _TwoUlClose
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = apply(:_Spacechar)
+ _tmp = _tmp ? nil : true
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save2 = self.pos
+ _tmp = apply(:_Newline)
+ _tmp = _tmp ? nil : true
+ self.pos = _save2
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Inline)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("__")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; a ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_TwoUlClose unless _tmp
+ return _tmp
+ end
+
+ # StrongUl = TwoUlOpen StartList:a (!TwoUlClose Inline:i { a << i })* TwoUlClose:l { a << l } { strong a.join }
+ def _StrongUl
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_TwoUlOpen)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_StartList)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # sequence
+ _save3 = self.pos
+ _tmp = apply(:_TwoUlClose)
+ _tmp = _tmp ? nil : true
+ self.pos = _save3
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = apply(:_Inline)
+ i = @result
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ @result = begin; a << i ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_TwoUlClose)
+ l = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; a << l ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; strong a.join ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_StrongUl unless _tmp
+ return _tmp
+ end
+
+ # Image = "!" (ExplicitLink | ReferenceLink):a { a }
+ def _Image
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("!")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = apply(:_ExplicitLink)
+ break if _tmp
+ self.pos = _save1
+ _tmp = apply(:_ReferenceLink)
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; a ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Image unless _tmp
+ return _tmp
+ end
+
+ # Link = (ExplicitLink | ReferenceLink | AutoLink)
+ def _Link
+
+ _save = self.pos
+ while true # choice
+ _tmp = apply(:_ExplicitLink)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_ReferenceLink)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_AutoLink)
+ break if _tmp
+ self.pos = _save
+ break
+ end # end choice
+
+ set_failed_rule :_Link unless _tmp
+ return _tmp
+ end
+
+ # ReferenceLink = (ReferenceLinkDouble | ReferenceLinkSingle)
+ def _ReferenceLink
+
+ _save = self.pos
+ while true # choice
+ _tmp = apply(:_ReferenceLinkDouble)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_ReferenceLinkSingle)
+ break if _tmp
+ self.pos = _save
+ break
+ end # end choice
+
+ set_failed_rule :_ReferenceLink unless _tmp
+ return _tmp
+ end
+
+ # ReferenceLinkDouble = Label:content < Spnl > !"[]" Label:label { link_to content, label, text }
+ def _ReferenceLinkDouble
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_Label)
+ content = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _text_start = self.pos
+ _tmp = apply(:_Spnl)
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save1 = self.pos
+ _tmp = match_string("[]")
+ _tmp = _tmp ? nil : true
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Label)
+ label = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; link_to content, label, text ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_ReferenceLinkDouble unless _tmp
+ return _tmp
+ end
+
+ # ReferenceLinkSingle = Label:content < (Spnl "[]")? > { link_to content, content, text }
+ def _ReferenceLinkSingle
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_Label)
+ content = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _text_start = self.pos
+ _save1 = self.pos
+
+ _save2 = self.pos
+ while true # sequence
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = match_string("[]")
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ unless _tmp
+ _tmp = true
+ self.pos = _save1
+ end
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; link_to content, content, text ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_ReferenceLinkSingle unless _tmp
+ return _tmp
+ end
+
+ # ExplicitLink = Label:l Spnl "(" Sp Source:s Spnl Title:t Sp ")" { "{#{l}}[#{s}]" }
+ def _ExplicitLink
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_Label)
+ l = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("(")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Source)
+ s = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Title)
+ t = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(")")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; "{#{l}}[#{s}]" ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_ExplicitLink unless _tmp
+ return _tmp
+ end
+
+ # Source = ("<" < SourceContents > ">" | < SourceContents >) { text }
+ def _Source
+
+ _save = self.pos
+ while true # sequence
+
+ _save1 = self.pos
+ while true # choice
+
+ _save2 = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _text_start = self.pos
+ _tmp = apply(:_SourceContents)
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save1
+ _text_start = self.pos
+ _tmp = apply(:_SourceContents)
+ if _tmp
+ text = get_text(_text_start)
+ end
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; text ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Source unless _tmp
+ return _tmp
+ end
+
+ # SourceContents = (((!"(" !")" !">" Nonspacechar)+ | "(" SourceContents ")")* | "")
+ def _SourceContents
+
+ _save = self.pos
+ while true # choice
+ while true
+
+ _save2 = self.pos
+ while true # choice
+ _save3 = self.pos
+
+ _save4 = self.pos
+ while true # sequence
+ _save5 = self.pos
+ _tmp = match_string("(")
+ _tmp = _tmp ? nil : true
+ self.pos = _save5
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+ _save6 = self.pos
+ _tmp = match_string(")")
+ _tmp = _tmp ? nil : true
+ self.pos = _save6
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+ _save7 = self.pos
+ _tmp = match_string(">")
+ _tmp = _tmp ? nil : true
+ self.pos = _save7
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save4
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ while true
+
+ _save8 = self.pos
+ while true # sequence
+ _save9 = self.pos
+ _tmp = match_string("(")
+ _tmp = _tmp ? nil : true
+ self.pos = _save9
+ unless _tmp
+ self.pos = _save8
+ break
+ end
+ _save10 = self.pos
+ _tmp = match_string(")")
+ _tmp = _tmp ? nil : true
+ self.pos = _save10
+ unless _tmp
+ self.pos = _save8
+ break
+ end
+ _save11 = self.pos
+ _tmp = match_string(">")
+ _tmp = _tmp ? nil : true
+ self.pos = _save11
+ unless _tmp
+ self.pos = _save8
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save8
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save3
+ end
+ break if _tmp
+ self.pos = _save2
+
+ _save12 = self.pos
+ while true # sequence
+ _tmp = match_string("(")
+ unless _tmp
+ self.pos = _save12
+ break
+ end
+ _tmp = apply(:_SourceContents)
+ unless _tmp
+ self.pos = _save12
+ break
+ end
+ _tmp = match_string(")")
+ unless _tmp
+ self.pos = _save12
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("")
+ break if _tmp
+ self.pos = _save
+ break
+ end # end choice
+
+ set_failed_rule :_SourceContents unless _tmp
+ return _tmp
+ end
+
+ # Title = (TitleSingle | TitleDouble | < "" >):a { a }
+ def _Title
+
+ _save = self.pos
+ while true # sequence
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = apply(:_TitleSingle)
+ break if _tmp
+ self.pos = _save1
+ _tmp = apply(:_TitleDouble)
+ break if _tmp
+ self.pos = _save1
+ _text_start = self.pos
+ _tmp = match_string("")
+ if _tmp
+ text = get_text(_text_start)
+ end
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; a ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Title unless _tmp
+ return _tmp
+ end
+
+ # TitleSingle = "'" < (!("'" Sp (")" | Newline)) .)* > "'"
+ def _TitleSingle
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("'")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _text_start = self.pos
+ while true
+
+ _save2 = self.pos
+ while true # sequence
+ _save3 = self.pos
+
+ _save4 = self.pos
+ while true # sequence
+ _tmp = match_string("'")
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+
+ _save5 = self.pos
+ while true # choice
+ _tmp = match_string(")")
+ break if _tmp
+ self.pos = _save5
+ _tmp = apply(:_Newline)
+ break if _tmp
+ self.pos = _save5
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save4
+ end
+ break
+ end # end sequence
+
+ _tmp = _tmp ? nil : true
+ self.pos = _save3
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("'")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_TitleSingle unless _tmp
+ return _tmp
+ end
+
+ # TitleDouble = "\"" < (!("\"" Sp (")" | Newline)) .)* > "\""
+ def _TitleDouble
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("\"")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _text_start = self.pos
+ while true
+
+ _save2 = self.pos
+ while true # sequence
+ _save3 = self.pos
+
+ _save4 = self.pos
+ while true # sequence
+ _tmp = match_string("\"")
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+
+ _save5 = self.pos
+ while true # choice
+ _tmp = match_string(")")
+ break if _tmp
+ self.pos = _save5
+ _tmp = apply(:_Newline)
+ break if _tmp
+ self.pos = _save5
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save4
+ end
+ break
+ end # end sequence
+
+ _tmp = _tmp ? nil : true
+ self.pos = _save3
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("\"")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_TitleDouble unless _tmp
+ return _tmp
+ end
+
+ # AutoLink = (AutoLinkUrl | AutoLinkEmail)
+ def _AutoLink
+
+ _save = self.pos
+ while true # choice
+ _tmp = apply(:_AutoLinkUrl)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_AutoLinkEmail)
+ break if _tmp
+ self.pos = _save
+ break
+ end # end choice
+
+ set_failed_rule :_AutoLink unless _tmp
+ return _tmp
+ end
+
+ # AutoLinkUrl = "<" < /[A-Za-z]+/ "://" (!Newline !">" .)+ > ">" { text }
+ def _AutoLinkUrl
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _text_start = self.pos
+
+ _save1 = self.pos
+ while true # sequence
+ _tmp = scan(/\A(?-mix:[A-Za-z]+)/)
+ unless _tmp
+ self.pos = _save1
+ break
+ end
+ _tmp = match_string("://")
+ unless _tmp
+ self.pos = _save1
+ break
+ end
+ _save2 = self.pos
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_Newline)
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _save5 = self.pos
+ _tmp = match_string(">")
+ _tmp = _tmp ? nil : true
+ self.pos = _save5
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ while true
+
+ _save6 = self.pos
+ while true # sequence
+ _save7 = self.pos
+ _tmp = apply(:_Newline)
+ _tmp = _tmp ? nil : true
+ self.pos = _save7
+ unless _tmp
+ self.pos = _save6
+ break
+ end
+ _save8 = self.pos
+ _tmp = match_string(">")
+ _tmp = _tmp ? nil : true
+ self.pos = _save8
+ unless _tmp
+ self.pos = _save6
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save6
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save2
+ end
+ unless _tmp
+ self.pos = _save1
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; text ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_AutoLinkUrl unless _tmp
+ return _tmp
+ end
+
+ # AutoLinkEmail = "<" "mailto:"? < /[\w+_.\/!%~$-]+/i "@" (!Newline !">" .)+ > ">" { "mailto:#{text}" }
+ def _AutoLinkEmail
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save1 = self.pos
+ _tmp = match_string("mailto:")
+ unless _tmp
+ _tmp = true
+ self.pos = _save1
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _text_start = self.pos
+
+ _save2 = self.pos
+ while true # sequence
+ _tmp = scan(/\A(?i-mx:[\w+_.\/!%~$-]+)/)
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = match_string("@")
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _save3 = self.pos
+
+ _save4 = self.pos
+ while true # sequence
+ _save5 = self.pos
+ _tmp = apply(:_Newline)
+ _tmp = _tmp ? nil : true
+ self.pos = _save5
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+ _save6 = self.pos
+ _tmp = match_string(">")
+ _tmp = _tmp ? nil : true
+ self.pos = _save6
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save4
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ while true
+
+ _save7 = self.pos
+ while true # sequence
+ _save8 = self.pos
+ _tmp = apply(:_Newline)
+ _tmp = _tmp ? nil : true
+ self.pos = _save8
+ unless _tmp
+ self.pos = _save7
+ break
+ end
+ _save9 = self.pos
+ _tmp = match_string(">")
+ _tmp = _tmp ? nil : true
+ self.pos = _save9
+ unless _tmp
+ self.pos = _save7
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save7
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save3
+ end
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; "mailto:#{text}" ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_AutoLinkEmail unless _tmp
+ return _tmp
+ end
+
+ # Reference = NonindentSpace !"[]" Label:label ":" Spnl RefSrc:link RefTitle:title BlankLine+ { # TODO use title reference label, link nil }
+ def _Reference
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_NonindentSpace)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save1 = self.pos
+ _tmp = match_string("[]")
+ _tmp = _tmp ? nil : true
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Label)
+ label = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(":")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_RefSrc)
+ link = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_RefTitle)
+ title = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save2 = self.pos
+ _tmp = apply(:_BlankLine)
+ if _tmp
+ while true
+ _tmp = apply(:_BlankLine)
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save2
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; # TODO use title
+ reference label, link
+ nil
+ ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Reference unless _tmp
+ return _tmp
+ end
+
+ # Label = "[" (!"^" &{ notes? } | &. &{ !notes? }) StartList:a (!"]" Inline:l { a << l })* "]" { a.join.gsub(/\s+/, ' ') }
+ def _Label
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("[")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+
+ _save1 = self.pos
+ while true # choice
+
+ _save2 = self.pos
+ while true # sequence
+ _save3 = self.pos
+ _tmp = match_string("^")
+ _tmp = _tmp ? nil : true
+ self.pos = _save3
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _save4 = self.pos
+ _tmp = begin; notes? ; end
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save1
+
+ _save5 = self.pos
+ while true # sequence
+ _save6 = self.pos
+ _tmp = get_byte
+ self.pos = _save6
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ _save7 = self.pos
+ _tmp = begin; !notes? ; end
+ self.pos = _save7
+ unless _tmp
+ self.pos = _save5
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_StartList)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save9 = self.pos
+ while true # sequence
+ _save10 = self.pos
+ _tmp = match_string("]")
+ _tmp = _tmp ? nil : true
+ self.pos = _save10
+ unless _tmp
+ self.pos = _save9
+ break
+ end
+ _tmp = apply(:_Inline)
+ l = @result
+ unless _tmp
+ self.pos = _save9
+ break
+ end
+ @result = begin; a << l ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save9
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("]")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; a.join.gsub(/\s+/, ' ') ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Label unless _tmp
+ return _tmp
+ end
+
+ # RefSrc = < Nonspacechar+ > { text }
+ def _RefSrc
+
+ _save = self.pos
+ while true # sequence
+ _text_start = self.pos
+ _save1 = self.pos
+ _tmp = apply(:_Nonspacechar)
+ if _tmp
+ while true
+ _tmp = apply(:_Nonspacechar)
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save1
+ end
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; text ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_RefSrc unless _tmp
+ return _tmp
+ end
+
+ # RefTitle = (RefTitleSingle | RefTitleDouble | RefTitleParens | EmptyTitle)
+ def _RefTitle
+
+ _save = self.pos
+ while true # choice
+ _tmp = apply(:_RefTitleSingle)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_RefTitleDouble)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_RefTitleParens)
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_EmptyTitle)
+ break if _tmp
+ self.pos = _save
+ break
+ end # end choice
+
+ set_failed_rule :_RefTitle unless _tmp
+ return _tmp
+ end
+
+ # EmptyTitle = < "" >
+ def _EmptyTitle
+ _text_start = self.pos
+ _tmp = match_string("")
+ if _tmp
+ text = get_text(_text_start)
+ end
+ set_failed_rule :_EmptyTitle unless _tmp
+ return _tmp
+ end
+
+ # RefTitleSingle = Spnl "'" < (!("'" Sp Newline | Newline) .)* > "'" { text }
+ def _RefTitleSingle
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("'")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _text_start = self.pos
+ while true
+
+ _save2 = self.pos
+ while true # sequence
+ _save3 = self.pos
+
+ _save4 = self.pos
+ while true # choice
+
+ _save5 = self.pos
+ while true # sequence
+ _tmp = match_string("'")
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save5
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save4
+ _tmp = apply(:_Newline)
+ break if _tmp
+ self.pos = _save4
+ break
+ end # end choice
+
+ _tmp = _tmp ? nil : true
+ self.pos = _save3
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("'")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; text ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_RefTitleSingle unless _tmp
+ return _tmp
+ end
+
+ # RefTitleDouble = Spnl "\"" < (!("\"" Sp Newline | Newline) .)* > "\"" { text }
+ def _RefTitleDouble
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("\"")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _text_start = self.pos
+ while true
+
+ _save2 = self.pos
+ while true # sequence
+ _save3 = self.pos
+
+ _save4 = self.pos
+ while true # choice
+
+ _save5 = self.pos
+ while true # sequence
+ _tmp = match_string("\"")
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save5
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save4
+ _tmp = apply(:_Newline)
+ break if _tmp
+ self.pos = _save4
+ break
+ end # end choice
+
+ _tmp = _tmp ? nil : true
+ self.pos = _save3
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("\"")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; text ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_RefTitleDouble unless _tmp
+ return _tmp
+ end
+
+ # RefTitleParens = Spnl "(" < (!(")" Sp Newline | Newline) .)* > ")" { text }
+ def _RefTitleParens
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("(")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _text_start = self.pos
+ while true
+
+ _save2 = self.pos
+ while true # sequence
+ _save3 = self.pos
+
+ _save4 = self.pos
+ while true # choice
+
+ _save5 = self.pos
+ while true # sequence
+ _tmp = match_string(")")
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save5
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save4
+ _tmp = apply(:_Newline)
+ break if _tmp
+ self.pos = _save4
+ break
+ end # end choice
+
+ _tmp = _tmp ? nil : true
+ self.pos = _save3
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(")")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; text ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_RefTitleParens unless _tmp
+ return _tmp
+ end
+
+ # References = (Reference | SkipBlock)*
+ def _References
+ while true
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = apply(:_Reference)
+ break if _tmp
+ self.pos = _save1
+ _tmp = apply(:_SkipBlock)
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ set_failed_rule :_References unless _tmp
+ return _tmp
+ end
+
+ # Ticks1 = "`" !"`"
+ def _Ticks1
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("`")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save1 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Ticks1 unless _tmp
+ return _tmp
+ end
+
+ # Ticks2 = "``" !"`"
+ def _Ticks2
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("``")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save1 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Ticks2 unless _tmp
+ return _tmp
+ end
+
+ # Ticks3 = "```" !"`"
+ def _Ticks3
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("```")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save1 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Ticks3 unless _tmp
+ return _tmp
+ end
+
+ # Ticks4 = "````" !"`"
+ def _Ticks4
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("````")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save1 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Ticks4 unless _tmp
+ return _tmp
+ end
+
+ # Ticks5 = "`````" !"`"
+ def _Ticks5
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("`````")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save1 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Ticks5 unless _tmp
+ return _tmp
+ end
+
+ # Code = (Ticks1 Sp < ((!"`" Nonspacechar)+ | !Ticks1 "`"+ | !(Sp Ticks1) (Spacechar | Newline !BlankLine))+ > Sp Ticks1 | Ticks2 Sp < ((!"`" Nonspacechar)+ | !Ticks2 "`"+ | !(Sp Ticks2) (Spacechar | Newline !BlankLine))+ > Sp Ticks2 | Ticks3 Sp < ((!"`" Nonspacechar)+ | !Ticks3 "`"+ | !(Sp Ticks3) (Spacechar | Newline !BlankLine))+ > Sp Ticks3 | Ticks4 Sp < ((!"`" Nonspacechar)+ | !Ticks4 "`"+ | !(Sp Ticks4) (Spacechar | Newline !BlankLine))+ > Sp Ticks4 | Ticks5 Sp < ((!"`" Nonspacechar)+ | !Ticks5 "`"+ | !(Sp Ticks5) (Spacechar | Newline !BlankLine))+ > Sp Ticks5) { "<code>#{text}</code>" }
+ def _Code
+
+ _save = self.pos
+ while true # sequence
+
+ _save1 = self.pos
+ while true # choice
+
+ _save2 = self.pos
+ while true # sequence
+ _tmp = apply(:_Ticks1)
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _text_start = self.pos
+ _save3 = self.pos
+
+ _save4 = self.pos
+ while true # choice
+ _save5 = self.pos
+
+ _save6 = self.pos
+ while true # sequence
+ _save7 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save7
+ unless _tmp
+ self.pos = _save6
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save6
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ while true
+
+ _save8 = self.pos
+ while true # sequence
+ _save9 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save9
+ unless _tmp
+ self.pos = _save8
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save8
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save5
+ end
+ break if _tmp
+ self.pos = _save4
+
+ _save10 = self.pos
+ while true # sequence
+ _save11 = self.pos
+ _tmp = apply(:_Ticks1)
+ _tmp = _tmp ? nil : true
+ self.pos = _save11
+ unless _tmp
+ self.pos = _save10
+ break
+ end
+ _save12 = self.pos
+ _tmp = match_string("`")
+ if _tmp
+ while true
+ _tmp = match_string("`")
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save12
+ end
+ unless _tmp
+ self.pos = _save10
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save4
+
+ _save13 = self.pos
+ while true # sequence
+ _save14 = self.pos
+
+ _save15 = self.pos
+ while true # sequence
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save15
+ break
+ end
+ _tmp = apply(:_Ticks1)
+ unless _tmp
+ self.pos = _save15
+ end
+ break
+ end # end sequence
+
+ _tmp = _tmp ? nil : true
+ self.pos = _save14
+ unless _tmp
+ self.pos = _save13
+ break
+ end
+
+ _save16 = self.pos
+ while true # choice
+ _tmp = apply(:_Spacechar)
+ break if _tmp
+ self.pos = _save16
+
+ _save17 = self.pos
+ while true # sequence
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save17
+ break
+ end
+ _save18 = self.pos
+ _tmp = apply(:_BlankLine)
+ _tmp = _tmp ? nil : true
+ self.pos = _save18
+ unless _tmp
+ self.pos = _save17
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save16
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save13
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save4
+ break
+ end # end choice
+
+ if _tmp
+ while true
+
+ _save19 = self.pos
+ while true # choice
+ _save20 = self.pos
+
+ _save21 = self.pos
+ while true # sequence
+ _save22 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save22
+ unless _tmp
+ self.pos = _save21
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save21
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ while true
+
+ _save23 = self.pos
+ while true # sequence
+ _save24 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save24
+ unless _tmp
+ self.pos = _save23
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save23
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save20
+ end
+ break if _tmp
+ self.pos = _save19
+
+ _save25 = self.pos
+ while true # sequence
+ _save26 = self.pos
+ _tmp = apply(:_Ticks1)
+ _tmp = _tmp ? nil : true
+ self.pos = _save26
+ unless _tmp
+ self.pos = _save25
+ break
+ end
+ _save27 = self.pos
+ _tmp = match_string("`")
+ if _tmp
+ while true
+ _tmp = match_string("`")
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save27
+ end
+ unless _tmp
+ self.pos = _save25
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save19
+
+ _save28 = self.pos
+ while true # sequence
+ _save29 = self.pos
+
+ _save30 = self.pos
+ while true # sequence
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save30
+ break
+ end
+ _tmp = apply(:_Ticks1)
+ unless _tmp
+ self.pos = _save30
+ end
+ break
+ end # end sequence
+
+ _tmp = _tmp ? nil : true
+ self.pos = _save29
+ unless _tmp
+ self.pos = _save28
+ break
+ end
+
+ _save31 = self.pos
+ while true # choice
+ _tmp = apply(:_Spacechar)
+ break if _tmp
+ self.pos = _save31
+
+ _save32 = self.pos
+ while true # sequence
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save32
+ break
+ end
+ _save33 = self.pos
+ _tmp = apply(:_BlankLine)
+ _tmp = _tmp ? nil : true
+ self.pos = _save33
+ unless _tmp
+ self.pos = _save32
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save31
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save28
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save19
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save3
+ end
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = apply(:_Ticks1)
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save1
+
+ _save34 = self.pos
+ while true # sequence
+ _tmp = apply(:_Ticks2)
+ unless _tmp
+ self.pos = _save34
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save34
+ break
+ end
+ _text_start = self.pos
+ _save35 = self.pos
+
+ _save36 = self.pos
+ while true # choice
+ _save37 = self.pos
+
+ _save38 = self.pos
+ while true # sequence
+ _save39 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save39
+ unless _tmp
+ self.pos = _save38
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save38
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ while true
+
+ _save40 = self.pos
+ while true # sequence
+ _save41 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save41
+ unless _tmp
+ self.pos = _save40
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save40
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save37
+ end
+ break if _tmp
+ self.pos = _save36
+
+ _save42 = self.pos
+ while true # sequence
+ _save43 = self.pos
+ _tmp = apply(:_Ticks2)
+ _tmp = _tmp ? nil : true
+ self.pos = _save43
+ unless _tmp
+ self.pos = _save42
+ break
+ end
+ _save44 = self.pos
+ _tmp = match_string("`")
+ if _tmp
+ while true
+ _tmp = match_string("`")
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save44
+ end
+ unless _tmp
+ self.pos = _save42
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save36
+
+ _save45 = self.pos
+ while true # sequence
+ _save46 = self.pos
+
+ _save47 = self.pos
+ while true # sequence
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save47
+ break
+ end
+ _tmp = apply(:_Ticks2)
+ unless _tmp
+ self.pos = _save47
+ end
+ break
+ end # end sequence
+
+ _tmp = _tmp ? nil : true
+ self.pos = _save46
+ unless _tmp
+ self.pos = _save45
+ break
+ end
+
+ _save48 = self.pos
+ while true # choice
+ _tmp = apply(:_Spacechar)
+ break if _tmp
+ self.pos = _save48
+
+ _save49 = self.pos
+ while true # sequence
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save49
+ break
+ end
+ _save50 = self.pos
+ _tmp = apply(:_BlankLine)
+ _tmp = _tmp ? nil : true
+ self.pos = _save50
+ unless _tmp
+ self.pos = _save49
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save48
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save45
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save36
+ break
+ end # end choice
+
+ if _tmp
+ while true
+
+ _save51 = self.pos
+ while true # choice
+ _save52 = self.pos
+
+ _save53 = self.pos
+ while true # sequence
+ _save54 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save54
+ unless _tmp
+ self.pos = _save53
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save53
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ while true
+
+ _save55 = self.pos
+ while true # sequence
+ _save56 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save56
+ unless _tmp
+ self.pos = _save55
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save55
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save52
+ end
+ break if _tmp
+ self.pos = _save51
+
+ _save57 = self.pos
+ while true # sequence
+ _save58 = self.pos
+ _tmp = apply(:_Ticks2)
+ _tmp = _tmp ? nil : true
+ self.pos = _save58
+ unless _tmp
+ self.pos = _save57
+ break
+ end
+ _save59 = self.pos
+ _tmp = match_string("`")
+ if _tmp
+ while true
+ _tmp = match_string("`")
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save59
+ end
+ unless _tmp
+ self.pos = _save57
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save51
+
+ _save60 = self.pos
+ while true # sequence
+ _save61 = self.pos
+
+ _save62 = self.pos
+ while true # sequence
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save62
+ break
+ end
+ _tmp = apply(:_Ticks2)
+ unless _tmp
+ self.pos = _save62
+ end
+ break
+ end # end sequence
+
+ _tmp = _tmp ? nil : true
+ self.pos = _save61
+ unless _tmp
+ self.pos = _save60
+ break
+ end
+
+ _save63 = self.pos
+ while true # choice
+ _tmp = apply(:_Spacechar)
+ break if _tmp
+ self.pos = _save63
+
+ _save64 = self.pos
+ while true # sequence
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save64
+ break
+ end
+ _save65 = self.pos
+ _tmp = apply(:_BlankLine)
+ _tmp = _tmp ? nil : true
+ self.pos = _save65
+ unless _tmp
+ self.pos = _save64
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save63
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save60
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save51
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save35
+ end
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save34
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save34
+ break
+ end
+ _tmp = apply(:_Ticks2)
+ unless _tmp
+ self.pos = _save34
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save1
+
+ _save66 = self.pos
+ while true # sequence
+ _tmp = apply(:_Ticks3)
+ unless _tmp
+ self.pos = _save66
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save66
+ break
+ end
+ _text_start = self.pos
+ _save67 = self.pos
+
+ _save68 = self.pos
+ while true # choice
+ _save69 = self.pos
+
+ _save70 = self.pos
+ while true # sequence
+ _save71 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save71
+ unless _tmp
+ self.pos = _save70
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save70
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ while true
+
+ _save72 = self.pos
+ while true # sequence
+ _save73 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save73
+ unless _tmp
+ self.pos = _save72
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save72
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save69
+ end
+ break if _tmp
+ self.pos = _save68
+
+ _save74 = self.pos
+ while true # sequence
+ _save75 = self.pos
+ _tmp = apply(:_Ticks3)
+ _tmp = _tmp ? nil : true
+ self.pos = _save75
+ unless _tmp
+ self.pos = _save74
+ break
+ end
+ _save76 = self.pos
+ _tmp = match_string("`")
+ if _tmp
+ while true
+ _tmp = match_string("`")
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save76
+ end
+ unless _tmp
+ self.pos = _save74
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save68
+
+ _save77 = self.pos
+ while true # sequence
+ _save78 = self.pos
+
+ _save79 = self.pos
+ while true # sequence
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save79
+ break
+ end
+ _tmp = apply(:_Ticks3)
+ unless _tmp
+ self.pos = _save79
+ end
+ break
+ end # end sequence
+
+ _tmp = _tmp ? nil : true
+ self.pos = _save78
+ unless _tmp
+ self.pos = _save77
+ break
+ end
+
+ _save80 = self.pos
+ while true # choice
+ _tmp = apply(:_Spacechar)
+ break if _tmp
+ self.pos = _save80
+
+ _save81 = self.pos
+ while true # sequence
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save81
+ break
+ end
+ _save82 = self.pos
+ _tmp = apply(:_BlankLine)
+ _tmp = _tmp ? nil : true
+ self.pos = _save82
+ unless _tmp
+ self.pos = _save81
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save80
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save77
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save68
+ break
+ end # end choice
+
+ if _tmp
+ while true
+
+ _save83 = self.pos
+ while true # choice
+ _save84 = self.pos
+
+ _save85 = self.pos
+ while true # sequence
+ _save86 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save86
+ unless _tmp
+ self.pos = _save85
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save85
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ while true
+
+ _save87 = self.pos
+ while true # sequence
+ _save88 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save88
+ unless _tmp
+ self.pos = _save87
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save87
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save84
+ end
+ break if _tmp
+ self.pos = _save83
+
+ _save89 = self.pos
+ while true # sequence
+ _save90 = self.pos
+ _tmp = apply(:_Ticks3)
+ _tmp = _tmp ? nil : true
+ self.pos = _save90
+ unless _tmp
+ self.pos = _save89
+ break
+ end
+ _save91 = self.pos
+ _tmp = match_string("`")
+ if _tmp
+ while true
+ _tmp = match_string("`")
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save91
+ end
+ unless _tmp
+ self.pos = _save89
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save83
+
+ _save92 = self.pos
+ while true # sequence
+ _save93 = self.pos
+
+ _save94 = self.pos
+ while true # sequence
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save94
+ break
+ end
+ _tmp = apply(:_Ticks3)
+ unless _tmp
+ self.pos = _save94
+ end
+ break
+ end # end sequence
+
+ _tmp = _tmp ? nil : true
+ self.pos = _save93
+ unless _tmp
+ self.pos = _save92
+ break
+ end
+
+ _save95 = self.pos
+ while true # choice
+ _tmp = apply(:_Spacechar)
+ break if _tmp
+ self.pos = _save95
+
+ _save96 = self.pos
+ while true # sequence
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save96
+ break
+ end
+ _save97 = self.pos
+ _tmp = apply(:_BlankLine)
+ _tmp = _tmp ? nil : true
+ self.pos = _save97
+ unless _tmp
+ self.pos = _save96
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save95
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save92
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save83
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save67
+ end
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save66
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save66
+ break
+ end
+ _tmp = apply(:_Ticks3)
+ unless _tmp
+ self.pos = _save66
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save1
+
+ _save98 = self.pos
+ while true # sequence
+ _tmp = apply(:_Ticks4)
+ unless _tmp
+ self.pos = _save98
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save98
+ break
+ end
+ _text_start = self.pos
+ _save99 = self.pos
+
+ _save100 = self.pos
+ while true # choice
+ _save101 = self.pos
+
+ _save102 = self.pos
+ while true # sequence
+ _save103 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save103
+ unless _tmp
+ self.pos = _save102
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save102
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ while true
+
+ _save104 = self.pos
+ while true # sequence
+ _save105 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save105
+ unless _tmp
+ self.pos = _save104
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save104
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save101
+ end
+ break if _tmp
+ self.pos = _save100
+
+ _save106 = self.pos
+ while true # sequence
+ _save107 = self.pos
+ _tmp = apply(:_Ticks4)
+ _tmp = _tmp ? nil : true
+ self.pos = _save107
+ unless _tmp
+ self.pos = _save106
+ break
+ end
+ _save108 = self.pos
+ _tmp = match_string("`")
+ if _tmp
+ while true
+ _tmp = match_string("`")
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save108
+ end
+ unless _tmp
+ self.pos = _save106
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save100
+
+ _save109 = self.pos
+ while true # sequence
+ _save110 = self.pos
+
+ _save111 = self.pos
+ while true # sequence
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save111
+ break
+ end
+ _tmp = apply(:_Ticks4)
+ unless _tmp
+ self.pos = _save111
+ end
+ break
+ end # end sequence
+
+ _tmp = _tmp ? nil : true
+ self.pos = _save110
+ unless _tmp
+ self.pos = _save109
+ break
+ end
+
+ _save112 = self.pos
+ while true # choice
+ _tmp = apply(:_Spacechar)
+ break if _tmp
+ self.pos = _save112
+
+ _save113 = self.pos
+ while true # sequence
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save113
+ break
+ end
+ _save114 = self.pos
+ _tmp = apply(:_BlankLine)
+ _tmp = _tmp ? nil : true
+ self.pos = _save114
+ unless _tmp
+ self.pos = _save113
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save112
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save109
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save100
+ break
+ end # end choice
+
+ if _tmp
+ while true
+
+ _save115 = self.pos
+ while true # choice
+ _save116 = self.pos
+
+ _save117 = self.pos
+ while true # sequence
+ _save118 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save118
+ unless _tmp
+ self.pos = _save117
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save117
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ while true
+
+ _save119 = self.pos
+ while true # sequence
+ _save120 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save120
+ unless _tmp
+ self.pos = _save119
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save119
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save116
+ end
+ break if _tmp
+ self.pos = _save115
+
+ _save121 = self.pos
+ while true # sequence
+ _save122 = self.pos
+ _tmp = apply(:_Ticks4)
+ _tmp = _tmp ? nil : true
+ self.pos = _save122
+ unless _tmp
+ self.pos = _save121
+ break
+ end
+ _save123 = self.pos
+ _tmp = match_string("`")
+ if _tmp
+ while true
+ _tmp = match_string("`")
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save123
+ end
+ unless _tmp
+ self.pos = _save121
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save115
+
+ _save124 = self.pos
+ while true # sequence
+ _save125 = self.pos
+
+ _save126 = self.pos
+ while true # sequence
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save126
+ break
+ end
+ _tmp = apply(:_Ticks4)
+ unless _tmp
+ self.pos = _save126
+ end
+ break
+ end # end sequence
+
+ _tmp = _tmp ? nil : true
+ self.pos = _save125
+ unless _tmp
+ self.pos = _save124
+ break
+ end
+
+ _save127 = self.pos
+ while true # choice
+ _tmp = apply(:_Spacechar)
+ break if _tmp
+ self.pos = _save127
+
+ _save128 = self.pos
+ while true # sequence
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save128
+ break
+ end
+ _save129 = self.pos
+ _tmp = apply(:_BlankLine)
+ _tmp = _tmp ? nil : true
+ self.pos = _save129
+ unless _tmp
+ self.pos = _save128
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save127
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save124
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save115
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save99
+ end
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save98
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save98
+ break
+ end
+ _tmp = apply(:_Ticks4)
+ unless _tmp
+ self.pos = _save98
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save1
+
+ _save130 = self.pos
+ while true # sequence
+ _tmp = apply(:_Ticks5)
+ unless _tmp
+ self.pos = _save130
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save130
+ break
+ end
+ _text_start = self.pos
+ _save131 = self.pos
+
+ _save132 = self.pos
+ while true # choice
+ _save133 = self.pos
+
+ _save134 = self.pos
+ while true # sequence
+ _save135 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save135
+ unless _tmp
+ self.pos = _save134
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save134
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ while true
+
+ _save136 = self.pos
+ while true # sequence
+ _save137 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save137
+ unless _tmp
+ self.pos = _save136
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save136
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save133
+ end
+ break if _tmp
+ self.pos = _save132
+
+ _save138 = self.pos
+ while true # sequence
+ _save139 = self.pos
+ _tmp = apply(:_Ticks5)
+ _tmp = _tmp ? nil : true
+ self.pos = _save139
+ unless _tmp
+ self.pos = _save138
+ break
+ end
+ _save140 = self.pos
+ _tmp = match_string("`")
+ if _tmp
+ while true
+ _tmp = match_string("`")
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save140
+ end
+ unless _tmp
+ self.pos = _save138
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save132
+
+ _save141 = self.pos
+ while true # sequence
+ _save142 = self.pos
+
+ _save143 = self.pos
+ while true # sequence
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save143
+ break
+ end
+ _tmp = apply(:_Ticks5)
+ unless _tmp
+ self.pos = _save143
+ end
+ break
+ end # end sequence
+
+ _tmp = _tmp ? nil : true
+ self.pos = _save142
+ unless _tmp
+ self.pos = _save141
+ break
+ end
+
+ _save144 = self.pos
+ while true # choice
+ _tmp = apply(:_Spacechar)
+ break if _tmp
+ self.pos = _save144
+
+ _save145 = self.pos
+ while true # sequence
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save145
+ break
+ end
+ _save146 = self.pos
+ _tmp = apply(:_BlankLine)
+ _tmp = _tmp ? nil : true
+ self.pos = _save146
+ unless _tmp
+ self.pos = _save145
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save144
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save141
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save132
+ break
+ end # end choice
+
+ if _tmp
+ while true
+
+ _save147 = self.pos
+ while true # choice
+ _save148 = self.pos
+
+ _save149 = self.pos
+ while true # sequence
+ _save150 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save150
+ unless _tmp
+ self.pos = _save149
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save149
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ while true
+
+ _save151 = self.pos
+ while true # sequence
+ _save152 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save152
+ unless _tmp
+ self.pos = _save151
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save151
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save148
+ end
+ break if _tmp
+ self.pos = _save147
+
+ _save153 = self.pos
+ while true # sequence
+ _save154 = self.pos
+ _tmp = apply(:_Ticks5)
+ _tmp = _tmp ? nil : true
+ self.pos = _save154
+ unless _tmp
+ self.pos = _save153
+ break
+ end
+ _save155 = self.pos
+ _tmp = match_string("`")
+ if _tmp
+ while true
+ _tmp = match_string("`")
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save155
+ end
+ unless _tmp
+ self.pos = _save153
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save147
+
+ _save156 = self.pos
+ while true # sequence
+ _save157 = self.pos
+
+ _save158 = self.pos
+ while true # sequence
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save158
+ break
+ end
+ _tmp = apply(:_Ticks5)
+ unless _tmp
+ self.pos = _save158
+ end
+ break
+ end # end sequence
+
+ _tmp = _tmp ? nil : true
+ self.pos = _save157
+ unless _tmp
+ self.pos = _save156
+ break
+ end
+
+ _save159 = self.pos
+ while true # choice
+ _tmp = apply(:_Spacechar)
+ break if _tmp
+ self.pos = _save159
+
+ _save160 = self.pos
+ while true # sequence
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save160
+ break
+ end
+ _save161 = self.pos
+ _tmp = apply(:_BlankLine)
+ _tmp = _tmp ? nil : true
+ self.pos = _save161
+ unless _tmp
+ self.pos = _save160
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save159
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save156
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save147
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save131
+ end
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save130
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save130
+ break
+ end
+ _tmp = apply(:_Ticks5)
+ unless _tmp
+ self.pos = _save130
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; "<code>#{text}</code>" ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Code unless _tmp
+ return _tmp
+ end
+
+ # RawHtml = < (HtmlComment | HtmlBlockScript | HtmlTag) > { if html? then text else '' end }
+ def _RawHtml
+
+ _save = self.pos
+ while true # sequence
+ _text_start = self.pos
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlComment)
+ break if _tmp
+ self.pos = _save1
+ _tmp = apply(:_HtmlBlockScript)
+ break if _tmp
+ self.pos = _save1
+ _tmp = apply(:_HtmlTag)
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; if html? then text else '' end ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_RawHtml unless _tmp
+ return _tmp
+ end
+
+ # BlankLine = Sp Newline { "\n" }
+ def _BlankLine
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; "\n" ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_BlankLine unless _tmp
+ return _tmp
+ end
+
+ # Quoted = ("\"" (!"\"" .)* "\"" | "'" (!"'" .)* "'")
+ def _Quoted
+
+ _save = self.pos
+ while true # choice
+
+ _save1 = self.pos
+ while true # sequence
+ _tmp = match_string("\"")
+ unless _tmp
+ self.pos = _save1
+ break
+ end
+ while true
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = match_string("\"")
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save1
+ break
+ end
+ _tmp = match_string("\"")
+ unless _tmp
+ self.pos = _save1
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save
+
+ _save5 = self.pos
+ while true # sequence
+ _tmp = match_string("'")
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ while true
+
+ _save7 = self.pos
+ while true # sequence
+ _save8 = self.pos
+ _tmp = match_string("'")
+ _tmp = _tmp ? nil : true
+ self.pos = _save8
+ unless _tmp
+ self.pos = _save7
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save7
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ _tmp = match_string("'")
+ unless _tmp
+ self.pos = _save5
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save
+ break
+ end # end choice
+
+ set_failed_rule :_Quoted unless _tmp
+ return _tmp
+ end
+
+ # HtmlAttribute = (AlphanumericAscii | "-")+ Spnl ("=" Spnl (Quoted | (!">" Nonspacechar)+))? Spnl
+ def _HtmlAttribute
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_AlphanumericAscii)
+ break if _tmp
+ self.pos = _save2
+ _tmp = match_string("-")
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ if _tmp
+ while true
+
+ _save3 = self.pos
+ while true # choice
+ _tmp = apply(:_AlphanumericAscii)
+ break if _tmp
+ self.pos = _save3
+ _tmp = match_string("-")
+ break if _tmp
+ self.pos = _save3
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save1
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save4 = self.pos
+
+ _save5 = self.pos
+ while true # sequence
+ _tmp = match_string("=")
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+
+ _save6 = self.pos
+ while true # choice
+ _tmp = apply(:_Quoted)
+ break if _tmp
+ self.pos = _save6
+ _save7 = self.pos
+
+ _save8 = self.pos
+ while true # sequence
+ _save9 = self.pos
+ _tmp = match_string(">")
+ _tmp = _tmp ? nil : true
+ self.pos = _save9
+ unless _tmp
+ self.pos = _save8
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save8
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ while true
+
+ _save10 = self.pos
+ while true # sequence
+ _save11 = self.pos
+ _tmp = match_string(">")
+ _tmp = _tmp ? nil : true
+ self.pos = _save11
+ unless _tmp
+ self.pos = _save10
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save10
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save7
+ end
+ break if _tmp
+ self.pos = _save6
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save5
+ end
+ break
+ end # end sequence
+
+ unless _tmp
+ _tmp = true
+ self.pos = _save4
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlAttribute unless _tmp
+ return _tmp
+ end
+
+ # HtmlComment = "<!--" (!"-->" .)* "-->"
+ def _HtmlComment
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<!--")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save2 = self.pos
+ while true # sequence
+ _save3 = self.pos
+ _tmp = match_string("-->")
+ _tmp = _tmp ? nil : true
+ self.pos = _save3
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("-->")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlComment unless _tmp
+ return _tmp
+ end
+
+ # HtmlTag = "<" Spnl "/"? AlphanumericAscii+ Spnl HtmlAttribute* "/"? Spnl ">"
+ def _HtmlTag
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("<")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save1 = self.pos
+ _tmp = match_string("/")
+ unless _tmp
+ _tmp = true
+ self.pos = _save1
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save2 = self.pos
+ _tmp = apply(:_AlphanumericAscii)
+ if _tmp
+ while true
+ _tmp = apply(:_AlphanumericAscii)
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save2
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_HtmlAttribute)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save4 = self.pos
+ _tmp = match_string("/")
+ unless _tmp
+ _tmp = true
+ self.pos = _save4
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(">")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HtmlTag unless _tmp
+ return _tmp
+ end
+
+ # Eof = !.
+ def _Eof
+ _save = self.pos
+ _tmp = get_byte
+ _tmp = _tmp ? nil : true
+ self.pos = _save
+ set_failed_rule :_Eof unless _tmp
+ return _tmp
+ end
+
+ # Nonspacechar = !Spacechar !Newline .
+ def _Nonspacechar
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = apply(:_Spacechar)
+ _tmp = _tmp ? nil : true
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save2 = self.pos
+ _tmp = apply(:_Newline)
+ _tmp = _tmp ? nil : true
+ self.pos = _save2
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Nonspacechar unless _tmp
+ return _tmp
+ end
+
+ # Sp = Spacechar*
+ def _Sp
+ while true
+ _tmp = apply(:_Spacechar)
+ break unless _tmp
+ end
+ _tmp = true
+ set_failed_rule :_Sp unless _tmp
+ return _tmp
+ end
+
+ # Spnl = Sp (Newline Sp)?
+ def _Spnl
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save1 = self.pos
+
+ _save2 = self.pos
+ while true # sequence
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ unless _tmp
+ _tmp = true
+ self.pos = _save1
+ end
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Spnl unless _tmp
+ return _tmp
+ end
+
+ # SpecialChar = ("*" | "_" | "`" | "&" | "[" | "]" | "(" | ")" | "<" | "!" | "#" | "\\" | "'" | "\"" | ExtendedSpecialChar)
+ def _SpecialChar
+
+ _save = self.pos
+ while true # choice
+ _tmp = match_string("*")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("_")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("`")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("&")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("[")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("]")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("(")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string(")")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("<")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("!")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("#")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("\\")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("'")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("\"")
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_ExtendedSpecialChar)
+ break if _tmp
+ self.pos = _save
+ break
+ end # end choice
+
+ set_failed_rule :_SpecialChar unless _tmp
+ return _tmp
+ end
+
+ # NormalChar = !(SpecialChar | Spacechar | Newline) .
+ def _NormalChar
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+
+ _save2 = self.pos
+ while true # choice
+ _tmp = apply(:_SpecialChar)
+ break if _tmp
+ self.pos = _save2
+ _tmp = apply(:_Spacechar)
+ break if _tmp
+ self.pos = _save2
+ _tmp = apply(:_Newline)
+ break if _tmp
+ self.pos = _save2
+ break
+ end # end choice
+
+ _tmp = _tmp ? nil : true
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_NormalChar unless _tmp
+ return _tmp
+ end
+
+ # Digit = [0-9]
+ def _Digit
+ _save = self.pos
+ _tmp = get_byte
+ if _tmp
+ unless _tmp >= 48 and _tmp <= 57
+ self.pos = _save
+ _tmp = nil
+ end
+ end
+ set_failed_rule :_Digit unless _tmp
+ return _tmp
+ end
+
+ # Alphanumeric = %literals.Alphanumeric
+ def _Alphanumeric
+ _tmp = @_grammar_literals.external_invoke(self, :_Alphanumeric)
+ set_failed_rule :_Alphanumeric unless _tmp
+ return _tmp
+ end
+
+ # AlphanumericAscii = %literals.AlphanumericAscii
+ def _AlphanumericAscii
+ _tmp = @_grammar_literals.external_invoke(self, :_AlphanumericAscii)
+ set_failed_rule :_AlphanumericAscii unless _tmp
+ return _tmp
+ end
+
+ # BOM = %literals.BOM
+ def _BOM
+ _tmp = @_grammar_literals.external_invoke(self, :_BOM)
+ set_failed_rule :_BOM unless _tmp
+ return _tmp
+ end
+
+ # Newline = %literals.Newline
+ def _Newline
+ _tmp = @_grammar_literals.external_invoke(self, :_Newline)
+ set_failed_rule :_Newline unless _tmp
+ return _tmp
+ end
+
+ # NonAlphanumeric = %literals.NonAlphanumeric
+ def _NonAlphanumeric
+ _tmp = @_grammar_literals.external_invoke(self, :_NonAlphanumeric)
+ set_failed_rule :_NonAlphanumeric unless _tmp
+ return _tmp
+ end
+
+ # Spacechar = %literals.Spacechar
+ def _Spacechar
+ _tmp = @_grammar_literals.external_invoke(self, :_Spacechar)
+ set_failed_rule :_Spacechar unless _tmp
+ return _tmp
+ end
+
+ # HexEntity = "&" "#" /[Xx]/ < /[0-9a-fA-F]+/ > ";" { [text.to_i(16)].pack 'U' }
+ def _HexEntity
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("&")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("#")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = scan(/\A(?-mix:[Xx])/)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _text_start = self.pos
+ _tmp = scan(/\A(?-mix:[0-9a-fA-F]+)/)
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(";")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; [text.to_i(16)].pack 'U' ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_HexEntity unless _tmp
+ return _tmp
+ end
+
+ # DecEntity = "&" "#" < /[0-9]+/ > ";" { [text.to_i].pack 'U' }
+ def _DecEntity
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("&")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("#")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _text_start = self.pos
+ _tmp = scan(/\A(?-mix:[0-9]+)/)
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(";")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; [text.to_i].pack 'U' ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_DecEntity unless _tmp
+ return _tmp
+ end
+
+ # CharEntity = "&" < /[A-Za-z0-9]+/ > ";" { if entity = HTML_ENTITIES[text] then entity.pack 'U*' else "&#{text};" end }
+ def _CharEntity
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("&")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _text_start = self.pos
+ _tmp = scan(/\A(?-mix:[A-Za-z0-9]+)/)
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(";")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; if entity = HTML_ENTITIES[text] then
+ entity.pack 'U*'
+ else
+ "&#{text};"
+ end
+ ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_CharEntity unless _tmp
+ return _tmp
+ end
+
+ # NonindentSpace = (" " | " " | " " | "")
+ def _NonindentSpace
+
+ _save = self.pos
+ while true # choice
+ _tmp = match_string(" ")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string(" ")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string(" ")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string("")
+ break if _tmp
+ self.pos = _save
+ break
+ end # end choice
+
+ set_failed_rule :_NonindentSpace unless _tmp
+ return _tmp
+ end
+
+ # Indent = ("\t" | " ")
+ def _Indent
+
+ _save = self.pos
+ while true # choice
+ _tmp = match_string("\t")
+ break if _tmp
+ self.pos = _save
+ _tmp = match_string(" ")
+ break if _tmp
+ self.pos = _save
+ break
+ end # end choice
+
+ set_failed_rule :_Indent unless _tmp
+ return _tmp
+ end
+
+ # IndentedLine = Indent Line
+ def _IndentedLine
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_Indent)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Line)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_IndentedLine unless _tmp
+ return _tmp
+ end
+
+ # OptionallyIndentedLine = Indent? Line
+ def _OptionallyIndentedLine
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = apply(:_Indent)
+ unless _tmp
+ _tmp = true
+ self.pos = _save1
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Line)
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_OptionallyIndentedLine unless _tmp
+ return _tmp
+ end
+
+ # StartList = &. { [] }
+ def _StartList
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = get_byte
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; [] ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_StartList unless _tmp
+ return _tmp
+ end
+
+ # Line = RawLine:a { a }
+ def _Line
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_RawLine)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; a ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Line unless _tmp
+ return _tmp
+ end
+
+ # RawLine = (< (!" " !"\n" .)* Newline > | < .+ > Eof) { text }
+ def _RawLine
+
+ _save = self.pos
+ while true # sequence
+
+ _save1 = self.pos
+ while true # choice
+ _text_start = self.pos
+
+ _save2 = self.pos
+ while true # sequence
+ while true
+
+ _save4 = self.pos
+ while true # sequence
+ _save5 = self.pos
+ _tmp = match_string("\r")
+ _tmp = _tmp ? nil : true
+ self.pos = _save5
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+ _save6 = self.pos
+ _tmp = match_string("\n")
+ _tmp = _tmp ? nil : true
+ self.pos = _save6
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save4
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ text = get_text(_text_start)
+ end
+ break if _tmp
+ self.pos = _save1
+
+ _save7 = self.pos
+ while true # sequence
+ _text_start = self.pos
+ _save8 = self.pos
+ _tmp = get_byte
+ if _tmp
+ while true
+ _tmp = get_byte
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save8
+ end
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save7
+ break
+ end
+ _tmp = apply(:_Eof)
+ unless _tmp
+ self.pos = _save7
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; text ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_RawLine unless _tmp
+ return _tmp
+ end
+
+ # SkipBlock = (HtmlBlock | (!"#" !SetextBottom1 !SetextBottom2 !BlankLine RawLine)+ BlankLine* | BlankLine+ | RawLine)
+ def _SkipBlock
+
+ _save = self.pos
+ while true # choice
+ _tmp = apply(:_HtmlBlock)
+ break if _tmp
+ self.pos = _save
+
+ _save1 = self.pos
+ while true # sequence
+ _save2 = self.pos
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = match_string("#")
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _save5 = self.pos
+ _tmp = apply(:_SetextBottom1)
+ _tmp = _tmp ? nil : true
+ self.pos = _save5
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _save6 = self.pos
+ _tmp = apply(:_SetextBottom2)
+ _tmp = _tmp ? nil : true
+ self.pos = _save6
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _save7 = self.pos
+ _tmp = apply(:_BlankLine)
+ _tmp = _tmp ? nil : true
+ self.pos = _save7
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = apply(:_RawLine)
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ while true
+
+ _save8 = self.pos
+ while true # sequence
+ _save9 = self.pos
+ _tmp = match_string("#")
+ _tmp = _tmp ? nil : true
+ self.pos = _save9
+ unless _tmp
+ self.pos = _save8
+ break
+ end
+ _save10 = self.pos
+ _tmp = apply(:_SetextBottom1)
+ _tmp = _tmp ? nil : true
+ self.pos = _save10
+ unless _tmp
+ self.pos = _save8
+ break
+ end
+ _save11 = self.pos
+ _tmp = apply(:_SetextBottom2)
+ _tmp = _tmp ? nil : true
+ self.pos = _save11
+ unless _tmp
+ self.pos = _save8
+ break
+ end
+ _save12 = self.pos
+ _tmp = apply(:_BlankLine)
+ _tmp = _tmp ? nil : true
+ self.pos = _save12
+ unless _tmp
+ self.pos = _save8
+ break
+ end
+ _tmp = apply(:_RawLine)
+ unless _tmp
+ self.pos = _save8
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save2
+ end
+ unless _tmp
+ self.pos = _save1
+ break
+ end
+ while true
+ _tmp = apply(:_BlankLine)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save1
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save
+ _save14 = self.pos
+ _tmp = apply(:_BlankLine)
+ if _tmp
+ while true
+ _tmp = apply(:_BlankLine)
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save14
+ end
+ break if _tmp
+ self.pos = _save
+ _tmp = apply(:_RawLine)
+ break if _tmp
+ self.pos = _save
+ break
+ end # end choice
+
+ set_failed_rule :_SkipBlock unless _tmp
+ return _tmp
+ end
+
+ # ExtendedSpecialChar = &{ notes? } "^"
+ def _ExtendedSpecialChar
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = begin; notes? ; end
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("^")
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_ExtendedSpecialChar unless _tmp
+ return _tmp
+ end
+
+ # NoteReference = &{ notes? } RawNoteReference:ref { note_for ref }
+ def _NoteReference
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = begin; notes? ; end
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_RawNoteReference)
+ ref = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; note_for ref ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_NoteReference unless _tmp
+ return _tmp
+ end
+
+ # RawNoteReference = "[^" < (!Newline !"]" .)+ > "]" { text }
+ def _RawNoteReference
+
+ _save = self.pos
+ while true # sequence
+ _tmp = match_string("[^")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _text_start = self.pos
+ _save1 = self.pos
+
+ _save2 = self.pos
+ while true # sequence
+ _save3 = self.pos
+ _tmp = apply(:_Newline)
+ _tmp = _tmp ? nil : true
+ self.pos = _save3
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _save4 = self.pos
+ _tmp = match_string("]")
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ while true
+
+ _save5 = self.pos
+ while true # sequence
+ _save6 = self.pos
+ _tmp = apply(:_Newline)
+ _tmp = _tmp ? nil : true
+ self.pos = _save6
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ _save7 = self.pos
+ _tmp = match_string("]")
+ _tmp = _tmp ? nil : true
+ self.pos = _save7
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ _tmp = get_byte
+ unless _tmp
+ self.pos = _save5
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save1
+ end
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("]")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; text ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_RawNoteReference unless _tmp
+ return _tmp
+ end
+
+ # Note = &{ notes? } NonindentSpace RawNoteReference:ref ":" Sp StartList:a RawNoteBlock:l (&Indent RawNoteBlock:i { a.concat i })* { @footnotes[ref] = paragraph a nil }
+ def _Note
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = begin; notes? ; end
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_NonindentSpace)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_RawNoteReference)
+ ref = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(":")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_StartList)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_RawNoteBlock)
+ l = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = apply(:_Indent)
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = apply(:_RawNoteBlock)
+ i = @result
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ @result = begin; a.concat i ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; @footnotes[ref] = paragraph a
+
+ nil
+ ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_Note unless _tmp
+ return _tmp
+ end
+
+ # InlineNote = &{ notes? } "^[" StartList:a (!"]" Inline:l { a << l })+ "]" { ref = [:inline, @note_order.length] @footnotes[ref] = paragraph a note_for ref }
+ def _InlineNote
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = begin; notes? ; end
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("^[")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_StartList)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save2 = self.pos
+
+ _save3 = self.pos
+ while true # sequence
+ _save4 = self.pos
+ _tmp = match_string("]")
+ _tmp = _tmp ? nil : true
+ self.pos = _save4
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = apply(:_Inline)
+ l = @result
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ @result = begin; a << l ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ while true
+
+ _save5 = self.pos
+ while true # sequence
+ _save6 = self.pos
+ _tmp = match_string("]")
+ _tmp = _tmp ? nil : true
+ self.pos = _save6
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ _tmp = apply(:_Inline)
+ l = @result
+ unless _tmp
+ self.pos = _save5
+ break
+ end
+ @result = begin; a << l ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save5
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save2
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string("]")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin;
+ ref = [:inline, @note_order.length]
+ @footnotes[ref] = paragraph a
+
+ note_for ref
+ ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_InlineNote unless _tmp
+ return _tmp
+ end
+
+ # Notes = (Note | SkipBlock)*
+ def _Notes
+ while true
+
+ _save1 = self.pos
+ while true # choice
+ _tmp = apply(:_Note)
+ break if _tmp
+ self.pos = _save1
+ _tmp = apply(:_SkipBlock)
+ break if _tmp
+ self.pos = _save1
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ set_failed_rule :_Notes unless _tmp
+ return _tmp
+ end
+
+ # RawNoteBlock = StartList:a (!BlankLine OptionallyIndentedLine:l { a << l })+ < BlankLine* > { a << text } { a }
+ def _RawNoteBlock
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_StartList)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save1 = self.pos
+
+ _save2 = self.pos
+ while true # sequence
+ _save3 = self.pos
+ _tmp = apply(:_BlankLine)
+ _tmp = _tmp ? nil : true
+ self.pos = _save3
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ _tmp = apply(:_OptionallyIndentedLine)
+ l = @result
+ unless _tmp
+ self.pos = _save2
+ break
+ end
+ @result = begin; a << l ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save2
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ while true
+
+ _save4 = self.pos
+ while true # sequence
+ _save5 = self.pos
+ _tmp = apply(:_BlankLine)
+ _tmp = _tmp ? nil : true
+ self.pos = _save5
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+ _tmp = apply(:_OptionallyIndentedLine)
+ l = @result
+ unless _tmp
+ self.pos = _save4
+ break
+ end
+ @result = begin; a << l ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save4
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save1
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _text_start = self.pos
+ while true
+ _tmp = apply(:_BlankLine)
+ break unless _tmp
+ end
+ _tmp = true
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; a << text ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; a ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_RawNoteBlock unless _tmp
+ return _tmp
+ end
+
+ # CodeFence = &{ github? } Ticks3 (Sp StrChunk:format)? Spnl < ((!"`" Nonspacechar)+ | !Ticks3 "`"+ | Spacechar | Newline)+ > Ticks3 Sp Newline* { verbatim = RDoc::Markup::Verbatim.new text verbatim.format = format.intern if format verbatim }
+ def _CodeFence
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = begin; github? ; end
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Ticks3)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save2 = self.pos
+
+ _save3 = self.pos
+ while true # sequence
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save3
+ break
+ end
+ _tmp = apply(:_StrChunk)
+ format = @result
+ unless _tmp
+ self.pos = _save3
+ end
+ break
+ end # end sequence
+
+ unless _tmp
+ _tmp = true
+ self.pos = _save2
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Spnl)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _text_start = self.pos
+ _save4 = self.pos
+
+ _save5 = self.pos
+ while true # choice
+ _save6 = self.pos
+
+ _save7 = self.pos
+ while true # sequence
+ _save8 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save8
+ unless _tmp
+ self.pos = _save7
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save7
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ while true
+
+ _save9 = self.pos
+ while true # sequence
+ _save10 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save10
+ unless _tmp
+ self.pos = _save9
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save9
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save6
+ end
+ break if _tmp
+ self.pos = _save5
+
+ _save11 = self.pos
+ while true # sequence
+ _save12 = self.pos
+ _tmp = apply(:_Ticks3)
+ _tmp = _tmp ? nil : true
+ self.pos = _save12
+ unless _tmp
+ self.pos = _save11
+ break
+ end
+ _save13 = self.pos
+ _tmp = match_string("`")
+ if _tmp
+ while true
+ _tmp = match_string("`")
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save13
+ end
+ unless _tmp
+ self.pos = _save11
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save5
+ _tmp = apply(:_Spacechar)
+ break if _tmp
+ self.pos = _save5
+ _tmp = apply(:_Newline)
+ break if _tmp
+ self.pos = _save5
+ break
+ end # end choice
+
+ if _tmp
+ while true
+
+ _save14 = self.pos
+ while true # choice
+ _save15 = self.pos
+
+ _save16 = self.pos
+ while true # sequence
+ _save17 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save17
+ unless _tmp
+ self.pos = _save16
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save16
+ end
+ break
+ end # end sequence
+
+ if _tmp
+ while true
+
+ _save18 = self.pos
+ while true # sequence
+ _save19 = self.pos
+ _tmp = match_string("`")
+ _tmp = _tmp ? nil : true
+ self.pos = _save19
+ unless _tmp
+ self.pos = _save18
+ break
+ end
+ _tmp = apply(:_Nonspacechar)
+ unless _tmp
+ self.pos = _save18
+ end
+ break
+ end # end sequence
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save15
+ end
+ break if _tmp
+ self.pos = _save14
+
+ _save20 = self.pos
+ while true # sequence
+ _save21 = self.pos
+ _tmp = apply(:_Ticks3)
+ _tmp = _tmp ? nil : true
+ self.pos = _save21
+ unless _tmp
+ self.pos = _save20
+ break
+ end
+ _save22 = self.pos
+ _tmp = match_string("`")
+ if _tmp
+ while true
+ _tmp = match_string("`")
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save22
+ end
+ unless _tmp
+ self.pos = _save20
+ end
+ break
+ end # end sequence
+
+ break if _tmp
+ self.pos = _save14
+ _tmp = apply(:_Spacechar)
+ break if _tmp
+ self.pos = _save14
+ _tmp = apply(:_Newline)
+ break if _tmp
+ self.pos = _save14
+ break
+ end # end choice
+
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save4
+ end
+ if _tmp
+ text = get_text(_text_start)
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Ticks3)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ while true
+ _tmp = apply(:_Newline)
+ break unless _tmp
+ end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; verbatim = RDoc::Markup::Verbatim.new text
+ verbatim.format = format.intern if format
+ verbatim
+ ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_CodeFence unless _tmp
+ return _tmp
+ end
+
+ # DefinitionList = &{ definition_lists? } DefinitionListItem+:list { RDoc::Markup::List.new :NOTE, *list.flatten }
+ def _DefinitionList
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _tmp = begin; definition_lists? ; end
+ self.pos = _save1
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save2 = self.pos
+ _ary = []
+ _tmp = apply(:_DefinitionListItem)
+ if _tmp
+ _ary << @result
+ while true
+ _tmp = apply(:_DefinitionListItem)
+ _ary << @result if _tmp
+ break unless _tmp
+ end
+ _tmp = true
+ @result = _ary
+ else
+ self.pos = _save2
+ end
+ list = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; RDoc::Markup::List.new :NOTE, *list.flatten ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_DefinitionList unless _tmp
+ return _tmp
+ end
+
+ # DefinitionListItem = DefinitionListLabel+:label DefinitionListDefinition+:defn { list_items = [] list_items << RDoc::Markup::ListItem.new(label, defn.shift) list_items.concat defn.map { |defn| RDoc::Markup::ListItem.new nil, defn } unless list_items.empty? list_items }
+ def _DefinitionListItem
+
+ _save = self.pos
+ while true # sequence
+ _save1 = self.pos
+ _ary = []
+ _tmp = apply(:_DefinitionListLabel)
+ if _tmp
+ _ary << @result
+ while true
+ _tmp = apply(:_DefinitionListLabel)
+ _ary << @result if _tmp
+ break unless _tmp
+ end
+ _tmp = true
+ @result = _ary
+ else
+ self.pos = _save1
+ end
+ label = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save2 = self.pos
+ _ary = []
+ _tmp = apply(:_DefinitionListDefinition)
+ if _tmp
+ _ary << @result
+ while true
+ _tmp = apply(:_DefinitionListDefinition)
+ _ary << @result if _tmp
+ break unless _tmp
+ end
+ _tmp = true
+ @result = _ary
+ else
+ self.pos = _save2
+ end
+ defn = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; list_items = []
+ list_items <<
+ RDoc::Markup::ListItem.new(label, defn.shift)
+
+ list_items.concat defn.map { |defn|
+ RDoc::Markup::ListItem.new nil, defn
+ } unless list_items.empty?
+
+ list_items
+ ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_DefinitionListItem unless _tmp
+ return _tmp
+ end
+
+ # DefinitionListLabel = StrChunk:label Sp Newline { label }
+ def _DefinitionListLabel
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_StrChunk)
+ label = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Sp)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Newline)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; label ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_DefinitionListLabel unless _tmp
+ return _tmp
+ end
+
+ # DefinitionListDefinition = NonindentSpace ":" Space Inlines:a BlankLine+ { paragraph a }
+ def _DefinitionListDefinition
+
+ _save = self.pos
+ while true # sequence
+ _tmp = apply(:_NonindentSpace)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = match_string(":")
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Space)
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _tmp = apply(:_Inlines)
+ a = @result
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ _save1 = self.pos
+ _tmp = apply(:_BlankLine)
+ if _tmp
+ while true
+ _tmp = apply(:_BlankLine)
+ break unless _tmp
+ end
+ _tmp = true
+ else
+ self.pos = _save1
+ end
+ unless _tmp
+ self.pos = _save
+ break
+ end
+ @result = begin; paragraph a ; end
+ _tmp = true
+ unless _tmp
+ self.pos = _save
+ end
+ break
+ end # end sequence
+
+ set_failed_rule :_DefinitionListDefinition unless _tmp
+ return _tmp
+ end
+
+ Rules = {}
+ Rules[:_root] = rule_info("root", "Doc")
+ Rules[:_Doc] = rule_info("Doc", "BOM? Block*:a { RDoc::Markup::Document.new(*a.compact) }")
+ Rules[:_Block] = rule_info("Block", "BlankLine* (BlockQuote | Verbatim | CodeFence | Note | Reference | HorizontalRule | Heading | OrderedList | BulletList | DefinitionList | HtmlBlock | StyleBlock | Para | Plain)")
+ Rules[:_Para] = rule_info("Para", "NonindentSpace Inlines:a BlankLine+ { paragraph a }")
+ Rules[:_Plain] = rule_info("Plain", "Inlines:a { paragraph a }")
+ Rules[:_AtxInline] = rule_info("AtxInline", "!Newline !(Sp? \"\#\"* Sp Newline) Inline")
+ Rules[:_AtxStart] = rule_info("AtxStart", "< (\"\#\#\#\#\#\#\" | \"\#\#\#\#\#\" | \"\#\#\#\#\" | \"\#\#\#\" | \"\#\#\" | \"\#\") > { text.length }")
+ Rules[:_AtxHeading] = rule_info("AtxHeading", "AtxStart:s Sp? AtxInline+:a (Sp? \"\#\"* Sp)? Newline { RDoc::Markup::Heading.new(s, a.join) }")
+ Rules[:_SetextHeading] = rule_info("SetextHeading", "(SetextHeading1 | SetextHeading2)")
+ Rules[:_SetextBottom1] = rule_info("SetextBottom1", "\"===\" \"=\"* Newline")
+ Rules[:_SetextBottom2] = rule_info("SetextBottom2", "\"---\" \"-\"* Newline")
+ Rules[:_SetextHeading1] = rule_info("SetextHeading1", "&(RawLine SetextBottom1) StartList:a (!Endline Inline:b { a << b })+ Sp? Newline SetextBottom1 { a; RDoc::Markup::Heading.new(1, a.join) }")
+ Rules[:_SetextHeading2] = rule_info("SetextHeading2", "&(RawLine SetextBottom2) StartList:a (!Endline Inline:b { a << b })+ Sp? Newline SetextBottom2 { RDoc::Markup::Heading.new(2, a.join) }")
+ Rules[:_Heading] = rule_info("Heading", "(SetextHeading | AtxHeading)")
+ Rules[:_BlockQuote] = rule_info("BlockQuote", "BlockQuoteRaw:a { RDoc::Markup::BlockQuote.new(*a) }")
+ Rules[:_BlockQuoteRaw] = rule_info("BlockQuoteRaw", "StartList:a (\">\" \" \"? Line:l { a << l } (!\">\" !BlankLine Line:c { a << c })* (BlankLine:n { a << n })*)+ { inner_parse a.join }")
+ Rules[:_NonblankIndentedLine] = rule_info("NonblankIndentedLine", "!BlankLine IndentedLine")
+ Rules[:_VerbatimChunk] = rule_info("VerbatimChunk", "BlankLine*:a NonblankIndentedLine+:b { a.concat b }")
+ Rules[:_Verbatim] = rule_info("Verbatim", "VerbatimChunk+:a { RDoc::Markup::Verbatim.new(*a.flatten) }")
+ Rules[:_HorizontalRule] = rule_info("HorizontalRule", "NonindentSpace (\"*\" Sp \"*\" Sp \"*\" (Sp \"*\")* | \"-\" Sp \"-\" Sp \"-\" (Sp \"-\")* | \"_\" Sp \"_\" Sp \"_\" (Sp \"_\")*) Sp Newline BlankLine+ { RDoc::Markup::Rule.new 1 }")
+ Rules[:_Bullet] = rule_info("Bullet", "!HorizontalRule NonindentSpace (\"+\" | \"*\" | \"-\") Spacechar+")
+ Rules[:_BulletList] = rule_info("BulletList", "&Bullet (ListTight | ListLoose):a { RDoc::Markup::List.new(:BULLET, *a) }")
+ Rules[:_ListTight] = rule_info("ListTight", "ListItemTight+:a BlankLine* !(Bullet | Enumerator) { a }")
+ Rules[:_ListLoose] = rule_info("ListLoose", "StartList:a (ListItem:b BlankLine* { a << b })+ { a }")
+ Rules[:_ListItem] = rule_info("ListItem", "(Bullet | Enumerator) StartList:a ListBlock:b { a << b } (ListContinuationBlock:c { a.push(*c) })* { list_item_from a }")
+ Rules[:_ListItemTight] = rule_info("ListItemTight", "(Bullet | Enumerator) ListBlock:a (!BlankLine ListContinuationBlock:b { a.push(*b) })* !ListContinuationBlock { list_item_from a }")
+ Rules[:_ListBlock] = rule_info("ListBlock", "!BlankLine Line:a ListBlockLine*:c { [a, *c] }")
+ Rules[:_ListContinuationBlock] = rule_info("ListContinuationBlock", "StartList:a < BlankLine* > { a << \"\\n\" } (Indent ListBlock:b { a.concat b })+ { a }")
+ Rules[:_Enumerator] = rule_info("Enumerator", "NonindentSpace [0-9]+ \".\" Spacechar+")
+ Rules[:_OrderedList] = rule_info("OrderedList", "&Enumerator (ListTight | ListLoose):a { RDoc::Markup::List.new(:NUMBER, *a) }")
+ Rules[:_ListBlockLine] = rule_info("ListBlockLine", "!BlankLine !(Indent? (Bullet | Enumerator)) !HorizontalRule OptionallyIndentedLine")
+ Rules[:_HtmlBlockOpenAddress] = rule_info("HtmlBlockOpenAddress", "\"<\" Spnl (\"address\" | \"ADDRESS\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseAddress] = rule_info("HtmlBlockCloseAddress", "\"<\" Spnl \"/\" (\"address\" | \"ADDRESS\") Spnl \">\"")
+ Rules[:_HtmlBlockAddress] = rule_info("HtmlBlockAddress", "HtmlBlockOpenAddress (HtmlBlockAddress | !HtmlBlockCloseAddress .)* HtmlBlockCloseAddress")
+ Rules[:_HtmlBlockOpenBlockquote] = rule_info("HtmlBlockOpenBlockquote", "\"<\" Spnl (\"blockquote\" | \"BLOCKQUOTE\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseBlockquote] = rule_info("HtmlBlockCloseBlockquote", "\"<\" Spnl \"/\" (\"blockquote\" | \"BLOCKQUOTE\") Spnl \">\"")
+ Rules[:_HtmlBlockBlockquote] = rule_info("HtmlBlockBlockquote", "HtmlBlockOpenBlockquote (HtmlBlockBlockquote | !HtmlBlockCloseBlockquote .)* HtmlBlockCloseBlockquote")
+ Rules[:_HtmlBlockOpenCenter] = rule_info("HtmlBlockOpenCenter", "\"<\" Spnl (\"center\" | \"CENTER\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseCenter] = rule_info("HtmlBlockCloseCenter", "\"<\" Spnl \"/\" (\"center\" | \"CENTER\") Spnl \">\"")
+ Rules[:_HtmlBlockCenter] = rule_info("HtmlBlockCenter", "HtmlBlockOpenCenter (HtmlBlockCenter | !HtmlBlockCloseCenter .)* HtmlBlockCloseCenter")
+ Rules[:_HtmlBlockOpenDir] = rule_info("HtmlBlockOpenDir", "\"<\" Spnl (\"dir\" | \"DIR\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseDir] = rule_info("HtmlBlockCloseDir", "\"<\" Spnl \"/\" (\"dir\" | \"DIR\") Spnl \">\"")
+ Rules[:_HtmlBlockDir] = rule_info("HtmlBlockDir", "HtmlBlockOpenDir (HtmlBlockDir | !HtmlBlockCloseDir .)* HtmlBlockCloseDir")
+ Rules[:_HtmlBlockOpenDiv] = rule_info("HtmlBlockOpenDiv", "\"<\" Spnl (\"div\" | \"DIV\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseDiv] = rule_info("HtmlBlockCloseDiv", "\"<\" Spnl \"/\" (\"div\" | \"DIV\") Spnl \">\"")
+ Rules[:_HtmlBlockDiv] = rule_info("HtmlBlockDiv", "HtmlBlockOpenDiv (HtmlBlockDiv | !HtmlBlockCloseDiv .)* HtmlBlockCloseDiv")
+ Rules[:_HtmlBlockOpenDl] = rule_info("HtmlBlockOpenDl", "\"<\" Spnl (\"dl\" | \"DL\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseDl] = rule_info("HtmlBlockCloseDl", "\"<\" Spnl \"/\" (\"dl\" | \"DL\") Spnl \">\"")
+ Rules[:_HtmlBlockDl] = rule_info("HtmlBlockDl", "HtmlBlockOpenDl (HtmlBlockDl | !HtmlBlockCloseDl .)* HtmlBlockCloseDl")
+ Rules[:_HtmlBlockOpenFieldset] = rule_info("HtmlBlockOpenFieldset", "\"<\" Spnl (\"fieldset\" | \"FIELDSET\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseFieldset] = rule_info("HtmlBlockCloseFieldset", "\"<\" Spnl \"/\" (\"fieldset\" | \"FIELDSET\") Spnl \">\"")
+ Rules[:_HtmlBlockFieldset] = rule_info("HtmlBlockFieldset", "HtmlBlockOpenFieldset (HtmlBlockFieldset | !HtmlBlockCloseFieldset .)* HtmlBlockCloseFieldset")
+ Rules[:_HtmlBlockOpenForm] = rule_info("HtmlBlockOpenForm", "\"<\" Spnl (\"form\" | \"FORM\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseForm] = rule_info("HtmlBlockCloseForm", "\"<\" Spnl \"/\" (\"form\" | \"FORM\") Spnl \">\"")
+ Rules[:_HtmlBlockForm] = rule_info("HtmlBlockForm", "HtmlBlockOpenForm (HtmlBlockForm | !HtmlBlockCloseForm .)* HtmlBlockCloseForm")
+ Rules[:_HtmlBlockOpenH1] = rule_info("HtmlBlockOpenH1", "\"<\" Spnl (\"h1\" | \"H1\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseH1] = rule_info("HtmlBlockCloseH1", "\"<\" Spnl \"/\" (\"h1\" | \"H1\") Spnl \">\"")
+ Rules[:_HtmlBlockH1] = rule_info("HtmlBlockH1", "HtmlBlockOpenH1 (HtmlBlockH1 | !HtmlBlockCloseH1 .)* HtmlBlockCloseH1")
+ Rules[:_HtmlBlockOpenH2] = rule_info("HtmlBlockOpenH2", "\"<\" Spnl (\"h2\" | \"H2\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseH2] = rule_info("HtmlBlockCloseH2", "\"<\" Spnl \"/\" (\"h2\" | \"H2\") Spnl \">\"")
+ Rules[:_HtmlBlockH2] = rule_info("HtmlBlockH2", "HtmlBlockOpenH2 (HtmlBlockH2 | !HtmlBlockCloseH2 .)* HtmlBlockCloseH2")
+ Rules[:_HtmlBlockOpenH3] = rule_info("HtmlBlockOpenH3", "\"<\" Spnl (\"h3\" | \"H3\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseH3] = rule_info("HtmlBlockCloseH3", "\"<\" Spnl \"/\" (\"h3\" | \"H3\") Spnl \">\"")
+ Rules[:_HtmlBlockH3] = rule_info("HtmlBlockH3", "HtmlBlockOpenH3 (HtmlBlockH3 | !HtmlBlockCloseH3 .)* HtmlBlockCloseH3")
+ Rules[:_HtmlBlockOpenH4] = rule_info("HtmlBlockOpenH4", "\"<\" Spnl (\"h4\" | \"H4\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseH4] = rule_info("HtmlBlockCloseH4", "\"<\" Spnl \"/\" (\"h4\" | \"H4\") Spnl \">\"")
+ Rules[:_HtmlBlockH4] = rule_info("HtmlBlockH4", "HtmlBlockOpenH4 (HtmlBlockH4 | !HtmlBlockCloseH4 .)* HtmlBlockCloseH4")
+ Rules[:_HtmlBlockOpenH5] = rule_info("HtmlBlockOpenH5", "\"<\" Spnl (\"h5\" | \"H5\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseH5] = rule_info("HtmlBlockCloseH5", "\"<\" Spnl \"/\" (\"h5\" | \"H5\") Spnl \">\"")
+ Rules[:_HtmlBlockH5] = rule_info("HtmlBlockH5", "HtmlBlockOpenH5 (HtmlBlockH5 | !HtmlBlockCloseH5 .)* HtmlBlockCloseH5")
+ Rules[:_HtmlBlockOpenH6] = rule_info("HtmlBlockOpenH6", "\"<\" Spnl (\"h6\" | \"H6\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseH6] = rule_info("HtmlBlockCloseH6", "\"<\" Spnl \"/\" (\"h6\" | \"H6\") Spnl \">\"")
+ Rules[:_HtmlBlockH6] = rule_info("HtmlBlockH6", "HtmlBlockOpenH6 (HtmlBlockH6 | !HtmlBlockCloseH6 .)* HtmlBlockCloseH6")
+ Rules[:_HtmlBlockOpenMenu] = rule_info("HtmlBlockOpenMenu", "\"<\" Spnl (\"menu\" | \"MENU\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseMenu] = rule_info("HtmlBlockCloseMenu", "\"<\" Spnl \"/\" (\"menu\" | \"MENU\") Spnl \">\"")
+ Rules[:_HtmlBlockMenu] = rule_info("HtmlBlockMenu", "HtmlBlockOpenMenu (HtmlBlockMenu | !HtmlBlockCloseMenu .)* HtmlBlockCloseMenu")
+ Rules[:_HtmlBlockOpenNoframes] = rule_info("HtmlBlockOpenNoframes", "\"<\" Spnl (\"noframes\" | \"NOFRAMES\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseNoframes] = rule_info("HtmlBlockCloseNoframes", "\"<\" Spnl \"/\" (\"noframes\" | \"NOFRAMES\") Spnl \">\"")
+ Rules[:_HtmlBlockNoframes] = rule_info("HtmlBlockNoframes", "HtmlBlockOpenNoframes (HtmlBlockNoframes | !HtmlBlockCloseNoframes .)* HtmlBlockCloseNoframes")
+ Rules[:_HtmlBlockOpenNoscript] = rule_info("HtmlBlockOpenNoscript", "\"<\" Spnl (\"noscript\" | \"NOSCRIPT\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseNoscript] = rule_info("HtmlBlockCloseNoscript", "\"<\" Spnl \"/\" (\"noscript\" | \"NOSCRIPT\") Spnl \">\"")
+ Rules[:_HtmlBlockNoscript] = rule_info("HtmlBlockNoscript", "HtmlBlockOpenNoscript (HtmlBlockNoscript | !HtmlBlockCloseNoscript .)* HtmlBlockCloseNoscript")
+ Rules[:_HtmlBlockOpenOl] = rule_info("HtmlBlockOpenOl", "\"<\" Spnl (\"ol\" | \"OL\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseOl] = rule_info("HtmlBlockCloseOl", "\"<\" Spnl \"/\" (\"ol\" | \"OL\") Spnl \">\"")
+ Rules[:_HtmlBlockOl] = rule_info("HtmlBlockOl", "HtmlBlockOpenOl (HtmlBlockOl | !HtmlBlockCloseOl .)* HtmlBlockCloseOl")
+ Rules[:_HtmlBlockOpenP] = rule_info("HtmlBlockOpenP", "\"<\" Spnl (\"p\" | \"P\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseP] = rule_info("HtmlBlockCloseP", "\"<\" Spnl \"/\" (\"p\" | \"P\") Spnl \">\"")
+ Rules[:_HtmlBlockP] = rule_info("HtmlBlockP", "HtmlBlockOpenP (HtmlBlockP | !HtmlBlockCloseP .)* HtmlBlockCloseP")
+ Rules[:_HtmlBlockOpenPre] = rule_info("HtmlBlockOpenPre", "\"<\" Spnl (\"pre\" | \"PRE\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockClosePre] = rule_info("HtmlBlockClosePre", "\"<\" Spnl \"/\" (\"pre\" | \"PRE\") Spnl \">\"")
+ Rules[:_HtmlBlockPre] = rule_info("HtmlBlockPre", "HtmlBlockOpenPre (HtmlBlockPre | !HtmlBlockClosePre .)* HtmlBlockClosePre")
+ Rules[:_HtmlBlockOpenTable] = rule_info("HtmlBlockOpenTable", "\"<\" Spnl (\"table\" | \"TABLE\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseTable] = rule_info("HtmlBlockCloseTable", "\"<\" Spnl \"/\" (\"table\" | \"TABLE\") Spnl \">\"")
+ Rules[:_HtmlBlockTable] = rule_info("HtmlBlockTable", "HtmlBlockOpenTable (HtmlBlockTable | !HtmlBlockCloseTable .)* HtmlBlockCloseTable")
+ Rules[:_HtmlBlockOpenUl] = rule_info("HtmlBlockOpenUl", "\"<\" Spnl (\"ul\" | \"UL\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseUl] = rule_info("HtmlBlockCloseUl", "\"<\" Spnl \"/\" (\"ul\" | \"UL\") Spnl \">\"")
+ Rules[:_HtmlBlockUl] = rule_info("HtmlBlockUl", "HtmlBlockOpenUl (HtmlBlockUl | !HtmlBlockCloseUl .)* HtmlBlockCloseUl")
+ Rules[:_HtmlBlockOpenDd] = rule_info("HtmlBlockOpenDd", "\"<\" Spnl (\"dd\" | \"DD\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseDd] = rule_info("HtmlBlockCloseDd", "\"<\" Spnl \"/\" (\"dd\" | \"DD\") Spnl \">\"")
+ Rules[:_HtmlBlockDd] = rule_info("HtmlBlockDd", "HtmlBlockOpenDd (HtmlBlockDd | !HtmlBlockCloseDd .)* HtmlBlockCloseDd")
+ Rules[:_HtmlBlockOpenDt] = rule_info("HtmlBlockOpenDt", "\"<\" Spnl (\"dt\" | \"DT\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseDt] = rule_info("HtmlBlockCloseDt", "\"<\" Spnl \"/\" (\"dt\" | \"DT\") Spnl \">\"")
+ Rules[:_HtmlBlockDt] = rule_info("HtmlBlockDt", "HtmlBlockOpenDt (HtmlBlockDt | !HtmlBlockCloseDt .)* HtmlBlockCloseDt")
+ Rules[:_HtmlBlockOpenFrameset] = rule_info("HtmlBlockOpenFrameset", "\"<\" Spnl (\"frameset\" | \"FRAMESET\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseFrameset] = rule_info("HtmlBlockCloseFrameset", "\"<\" Spnl \"/\" (\"frameset\" | \"FRAMESET\") Spnl \">\"")
+ Rules[:_HtmlBlockFrameset] = rule_info("HtmlBlockFrameset", "HtmlBlockOpenFrameset (HtmlBlockFrameset | !HtmlBlockCloseFrameset .)* HtmlBlockCloseFrameset")
+ Rules[:_HtmlBlockOpenLi] = rule_info("HtmlBlockOpenLi", "\"<\" Spnl (\"li\" | \"LI\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseLi] = rule_info("HtmlBlockCloseLi", "\"<\" Spnl \"/\" (\"li\" | \"LI\") Spnl \">\"")
+ Rules[:_HtmlBlockLi] = rule_info("HtmlBlockLi", "HtmlBlockOpenLi (HtmlBlockLi | !HtmlBlockCloseLi .)* HtmlBlockCloseLi")
+ Rules[:_HtmlBlockOpenTbody] = rule_info("HtmlBlockOpenTbody", "\"<\" Spnl (\"tbody\" | \"TBODY\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseTbody] = rule_info("HtmlBlockCloseTbody", "\"<\" Spnl \"/\" (\"tbody\" | \"TBODY\") Spnl \">\"")
+ Rules[:_HtmlBlockTbody] = rule_info("HtmlBlockTbody", "HtmlBlockOpenTbody (HtmlBlockTbody | !HtmlBlockCloseTbody .)* HtmlBlockCloseTbody")
+ Rules[:_HtmlBlockOpenTd] = rule_info("HtmlBlockOpenTd", "\"<\" Spnl (\"td\" | \"TD\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseTd] = rule_info("HtmlBlockCloseTd", "\"<\" Spnl \"/\" (\"td\" | \"TD\") Spnl \">\"")
+ Rules[:_HtmlBlockTd] = rule_info("HtmlBlockTd", "HtmlBlockOpenTd (HtmlBlockTd | !HtmlBlockCloseTd .)* HtmlBlockCloseTd")
+ Rules[:_HtmlBlockOpenTfoot] = rule_info("HtmlBlockOpenTfoot", "\"<\" Spnl (\"tfoot\" | \"TFOOT\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseTfoot] = rule_info("HtmlBlockCloseTfoot", "\"<\" Spnl \"/\" (\"tfoot\" | \"TFOOT\") Spnl \">\"")
+ Rules[:_HtmlBlockTfoot] = rule_info("HtmlBlockTfoot", "HtmlBlockOpenTfoot (HtmlBlockTfoot | !HtmlBlockCloseTfoot .)* HtmlBlockCloseTfoot")
+ Rules[:_HtmlBlockOpenTh] = rule_info("HtmlBlockOpenTh", "\"<\" Spnl (\"th\" | \"TH\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseTh] = rule_info("HtmlBlockCloseTh", "\"<\" Spnl \"/\" (\"th\" | \"TH\") Spnl \">\"")
+ Rules[:_HtmlBlockTh] = rule_info("HtmlBlockTh", "HtmlBlockOpenTh (HtmlBlockTh | !HtmlBlockCloseTh .)* HtmlBlockCloseTh")
+ Rules[:_HtmlBlockOpenThead] = rule_info("HtmlBlockOpenThead", "\"<\" Spnl (\"thead\" | \"THEAD\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseThead] = rule_info("HtmlBlockCloseThead", "\"<\" Spnl \"/\" (\"thead\" | \"THEAD\") Spnl \">\"")
+ Rules[:_HtmlBlockThead] = rule_info("HtmlBlockThead", "HtmlBlockOpenThead (HtmlBlockThead | !HtmlBlockCloseThead .)* HtmlBlockCloseThead")
+ Rules[:_HtmlBlockOpenTr] = rule_info("HtmlBlockOpenTr", "\"<\" Spnl (\"tr\" | \"TR\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseTr] = rule_info("HtmlBlockCloseTr", "\"<\" Spnl \"/\" (\"tr\" | \"TR\") Spnl \">\"")
+ Rules[:_HtmlBlockTr] = rule_info("HtmlBlockTr", "HtmlBlockOpenTr (HtmlBlockTr | !HtmlBlockCloseTr .)* HtmlBlockCloseTr")
+ Rules[:_HtmlBlockOpenScript] = rule_info("HtmlBlockOpenScript", "\"<\" Spnl (\"script\" | \"SCRIPT\") Spnl HtmlAttribute* \">\"")
+ Rules[:_HtmlBlockCloseScript] = rule_info("HtmlBlockCloseScript", "\"<\" Spnl \"/\" (\"script\" | \"SCRIPT\") Spnl \">\"")
+ Rules[:_HtmlBlockScript] = rule_info("HtmlBlockScript", "HtmlBlockOpenScript (!HtmlBlockCloseScript .)* HtmlBlockCloseScript")
+ Rules[:_HtmlBlockInTags] = rule_info("HtmlBlockInTags", "(HtmlBlockAddress | HtmlBlockBlockquote | HtmlBlockCenter | HtmlBlockDir | HtmlBlockDiv | HtmlBlockDl | HtmlBlockFieldset | HtmlBlockForm | HtmlBlockH1 | HtmlBlockH2 | HtmlBlockH3 | HtmlBlockH4 | HtmlBlockH5 | HtmlBlockH6 | HtmlBlockMenu | HtmlBlockNoframes | HtmlBlockNoscript | HtmlBlockOl | HtmlBlockP | HtmlBlockPre | HtmlBlockTable | HtmlBlockUl | HtmlBlockDd | HtmlBlockDt | HtmlBlockFrameset | HtmlBlockLi | HtmlBlockTbody | HtmlBlockTd | HtmlBlockTfoot | HtmlBlockTh | HtmlBlockThead | HtmlBlockTr | HtmlBlockScript)")
+ Rules[:_HtmlBlock] = rule_info("HtmlBlock", "< (HtmlBlockInTags | HtmlComment | HtmlBlockSelfClosing | HtmlUnclosed) > BlankLine+ { if html? then RDoc::Markup::Raw.new text end }")
+ Rules[:_HtmlUnclosed] = rule_info("HtmlUnclosed", "\"<\" Spnl HtmlUnclosedType Spnl HtmlAttribute* Spnl \">\"")
+ Rules[:_HtmlUnclosedType] = rule_info("HtmlUnclosedType", "(\"HR\" | \"hr\")")
+ Rules[:_HtmlBlockSelfClosing] = rule_info("HtmlBlockSelfClosing", "\"<\" Spnl HtmlBlockType Spnl HtmlAttribute* \"/\" Spnl \">\"")
+ Rules[:_HtmlBlockType] = rule_info("HtmlBlockType", "(\"ADDRESS\" | \"BLOCKQUOTE\" | \"CENTER\" | \"DD\" | \"DIR\" | \"DIV\" | \"DL\" | \"DT\" | \"FIELDSET\" | \"FORM\" | \"FRAMESET\" | \"H1\" | \"H2\" | \"H3\" | \"H4\" | \"H5\" | \"H6\" | \"HR\" | \"ISINDEX\" | \"LI\" | \"MENU\" | \"NOFRAMES\" | \"NOSCRIPT\" | \"OL\" | \"P\" | \"PRE\" | \"SCRIPT\" | \"TABLE\" | \"TBODY\" | \"TD\" | \"TFOOT\" | \"TH\" | \"THEAD\" | \"TR\" | \"UL\" | \"address\" | \"blockquote\" | \"center\" | \"dd\" | \"dir\" | \"div\" | \"dl\" | \"dt\" | \"fieldset\" | \"form\" | \"frameset\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"hr\" | \"isindex\" | \"li\" | \"menu\" | \"noframes\" | \"noscript\" | \"ol\" | \"p\" | \"pre\" | \"script\" | \"table\" | \"tbody\" | \"td\" | \"tfoot\" | \"th\" | \"thead\" | \"tr\" | \"ul\")")
+ Rules[:_StyleOpen] = rule_info("StyleOpen", "\"<\" Spnl (\"style\" | \"STYLE\") Spnl HtmlAttribute* \">\"")
+ Rules[:_StyleClose] = rule_info("StyleClose", "\"<\" Spnl \"/\" (\"style\" | \"STYLE\") Spnl \">\"")
+ Rules[:_InStyleTags] = rule_info("InStyleTags", "StyleOpen (!StyleClose .)* StyleClose")
+ Rules[:_StyleBlock] = rule_info("StyleBlock", "< InStyleTags > BlankLine* { if css? then RDoc::Markup::Raw.new text end }")
+ Rules[:_Inlines] = rule_info("Inlines", "(!Endline Inline:i { i } | Endline:c &Inline { c })+:chunks Endline? { chunks }")
+ Rules[:_Inline] = rule_info("Inline", "(Str | Endline | UlOrStarLine | Space | Strong | Emph | Image | Link | NoteReference | InlineNote | Code | RawHtml | Entity | EscapedChar | Symbol)")
+ Rules[:_Space] = rule_info("Space", "Spacechar+ { \" \" }")
+ Rules[:_Str] = rule_info("Str", "StartList:a < NormalChar+ > { a = text } (StrChunk:c { a << c })* { a }")
+ Rules[:_StrChunk] = rule_info("StrChunk", "< (NormalChar | \"_\"+ &Alphanumeric)+ > { text }")
+ Rules[:_EscapedChar] = rule_info("EscapedChar", "\"\\\\\" !Newline < /[:\\\\`|*_{}\\[\\]()\#+.!><-]/ > { text }")
+ Rules[:_Entity] = rule_info("Entity", "(HexEntity | DecEntity | CharEntity):a { a }")
+ Rules[:_Endline] = rule_info("Endline", "(LineBreak | TerminalEndline | NormalEndline)")
+ Rules[:_NormalEndline] = rule_info("NormalEndline", "Sp Newline !BlankLine !\">\" !AtxStart !(Line (\"===\" \"=\"* | \"---\" \"-\"*) Newline) { \"\\n\" }")
+ Rules[:_TerminalEndline] = rule_info("TerminalEndline", "Sp Newline Eof")
+ Rules[:_LineBreak] = rule_info("LineBreak", "< \" \" NormalEndline > { RDoc::Markup::HardBreak.new }")
+ Rules[:_Symbol] = rule_info("Symbol", "< SpecialChar > { text }")
+ Rules[:_UlOrStarLine] = rule_info("UlOrStarLine", "(UlLine | StarLine):a { a }")
+ Rules[:_StarLine] = rule_info("StarLine", "(< \"****\" \"*\"* > { text } | < Spacechar \"*\"+ &Spacechar > { text })")
+ Rules[:_UlLine] = rule_info("UlLine", "(< \"____\" \"_\"* > { text } | < Spacechar \"_\"+ &Spacechar > { text })")
+ Rules[:_Emph] = rule_info("Emph", "(EmphStar | EmphUl)")
+ Rules[:_OneStarOpen] = rule_info("OneStarOpen", "!StarLine \"*\" !Spacechar !Newline")
+ Rules[:_OneStarClose] = rule_info("OneStarClose", "!Spacechar !Newline Inline:a \"*\" { a }")
+ Rules[:_EmphStar] = rule_info("EmphStar", "OneStarOpen StartList:a (!OneStarClose Inline:l { a << l })* OneStarClose:l { a << l } { emphasis a.join }")
+ Rules[:_OneUlOpen] = rule_info("OneUlOpen", "!UlLine \"_\" !Spacechar !Newline")
+ Rules[:_OneUlClose] = rule_info("OneUlClose", "!Spacechar !Newline Inline:a \"_\" { a }")
+ Rules[:_EmphUl] = rule_info("EmphUl", "OneUlOpen StartList:a (!OneUlClose Inline:l { a << l })* OneUlClose:l { a << l } { emphasis a.join }")
+ Rules[:_Strong] = rule_info("Strong", "(StrongStar | StrongUl)")
+ Rules[:_TwoStarOpen] = rule_info("TwoStarOpen", "!StarLine \"**\" !Spacechar !Newline")
+ Rules[:_TwoStarClose] = rule_info("TwoStarClose", "!Spacechar !Newline Inline:a \"**\" { a }")
+ Rules[:_StrongStar] = rule_info("StrongStar", "TwoStarOpen StartList:a (!TwoStarClose Inline:l { a << l })* TwoStarClose:l { a << l } { strong a.join }")
+ Rules[:_TwoUlOpen] = rule_info("TwoUlOpen", "!UlLine \"__\" !Spacechar !Newline")
+ Rules[:_TwoUlClose] = rule_info("TwoUlClose", "!Spacechar !Newline Inline:a \"__\" { a }")
+ Rules[:_StrongUl] = rule_info("StrongUl", "TwoUlOpen StartList:a (!TwoUlClose Inline:i { a << i })* TwoUlClose:l { a << l } { strong a.join }")
+ Rules[:_Image] = rule_info("Image", "\"!\" (ExplicitLink | ReferenceLink):a { a }")
+ Rules[:_Link] = rule_info("Link", "(ExplicitLink | ReferenceLink | AutoLink)")
+ Rules[:_ReferenceLink] = rule_info("ReferenceLink", "(ReferenceLinkDouble | ReferenceLinkSingle)")
+ Rules[:_ReferenceLinkDouble] = rule_info("ReferenceLinkDouble", "Label:content < Spnl > !\"[]\" Label:label { link_to content, label, text }")
+ Rules[:_ReferenceLinkSingle] = rule_info("ReferenceLinkSingle", "Label:content < (Spnl \"[]\")? > { link_to content, content, text }")
+ Rules[:_ExplicitLink] = rule_info("ExplicitLink", "Label:l Spnl \"(\" Sp Source:s Spnl Title:t Sp \")\" { \"{\#{l}}[\#{s}]\" }")
+ Rules[:_Source] = rule_info("Source", "(\"<\" < SourceContents > \">\" | < SourceContents >) { text }")
+ Rules[:_SourceContents] = rule_info("SourceContents", "(((!\"(\" !\")\" !\">\" Nonspacechar)+ | \"(\" SourceContents \")\")* | \"\")")
+ Rules[:_Title] = rule_info("Title", "(TitleSingle | TitleDouble | < \"\" >):a { a }")
+ Rules[:_TitleSingle] = rule_info("TitleSingle", "\"'\" < (!(\"'\" Sp (\")\" | Newline)) .)* > \"'\"")
+ Rules[:_TitleDouble] = rule_info("TitleDouble", "\"\\\"\" < (!(\"\\\"\" Sp (\")\" | Newline)) .)* > \"\\\"\"")
+ Rules[:_AutoLink] = rule_info("AutoLink", "(AutoLinkUrl | AutoLinkEmail)")
+ Rules[:_AutoLinkUrl] = rule_info("AutoLinkUrl", "\"<\" < /[A-Za-z]+/ \"://\" (!Newline !\">\" .)+ > \">\" { text }")
+ Rules[:_AutoLinkEmail] = rule_info("AutoLinkEmail", "\"<\" \"mailto:\"? < /[\\w+_.\\/!%~$-]+/i \"@\" (!Newline !\">\" .)+ > \">\" { \"mailto:\#{text}\" }")
+ Rules[:_Reference] = rule_info("Reference", "NonindentSpace !\"[]\" Label:label \":\" Spnl RefSrc:link RefTitle:title BlankLine+ { \# TODO use title reference label, link nil }")
+ Rules[:_Label] = rule_info("Label", "\"[\" (!\"^\" &{ notes? } | &. &{ !notes? }) StartList:a (!\"]\" Inline:l { a << l })* \"]\" { a.join.gsub(/\\s+/, ' ') }")
+ Rules[:_RefSrc] = rule_info("RefSrc", "< Nonspacechar+ > { text }")
+ Rules[:_RefTitle] = rule_info("RefTitle", "(RefTitleSingle | RefTitleDouble | RefTitleParens | EmptyTitle)")
+ Rules[:_EmptyTitle] = rule_info("EmptyTitle", "< \"\" >")
+ Rules[:_RefTitleSingle] = rule_info("RefTitleSingle", "Spnl \"'\" < (!(\"'\" Sp Newline | Newline) .)* > \"'\" { text }")
+ Rules[:_RefTitleDouble] = rule_info("RefTitleDouble", "Spnl \"\\\"\" < (!(\"\\\"\" Sp Newline | Newline) .)* > \"\\\"\" { text }")
+ Rules[:_RefTitleParens] = rule_info("RefTitleParens", "Spnl \"(\" < (!(\")\" Sp Newline | Newline) .)* > \")\" { text }")
+ Rules[:_References] = rule_info("References", "(Reference | SkipBlock)*")
+ Rules[:_Ticks1] = rule_info("Ticks1", "\"`\" !\"`\"")
+ Rules[:_Ticks2] = rule_info("Ticks2", "\"``\" !\"`\"")
+ Rules[:_Ticks3] = rule_info("Ticks3", "\"```\" !\"`\"")
+ Rules[:_Ticks4] = rule_info("Ticks4", "\"````\" !\"`\"")
+ Rules[:_Ticks5] = rule_info("Ticks5", "\"`````\" !\"`\"")
+ Rules[:_Code] = rule_info("Code", "(Ticks1 Sp < ((!\"`\" Nonspacechar)+ | !Ticks1 \"`\"+ | !(Sp Ticks1) (Spacechar | Newline !BlankLine))+ > Sp Ticks1 | Ticks2 Sp < ((!\"`\" Nonspacechar)+ | !Ticks2 \"`\"+ | !(Sp Ticks2) (Spacechar | Newline !BlankLine))+ > Sp Ticks2 | Ticks3 Sp < ((!\"`\" Nonspacechar)+ | !Ticks3 \"`\"+ | !(Sp Ticks3) (Spacechar | Newline !BlankLine))+ > Sp Ticks3 | Ticks4 Sp < ((!\"`\" Nonspacechar)+ | !Ticks4 \"`\"+ | !(Sp Ticks4) (Spacechar | Newline !BlankLine))+ > Sp Ticks4 | Ticks5 Sp < ((!\"`\" Nonspacechar)+ | !Ticks5 \"`\"+ | !(Sp Ticks5) (Spacechar | Newline !BlankLine))+ > Sp Ticks5) { \"<code>\#{text}</code>\" }")
+ Rules[:_RawHtml] = rule_info("RawHtml", "< (HtmlComment | HtmlBlockScript | HtmlTag) > { if html? then text else '' end }")
+ Rules[:_BlankLine] = rule_info("BlankLine", "Sp Newline { \"\\n\" }")
+ Rules[:_Quoted] = rule_info("Quoted", "(\"\\\"\" (!\"\\\"\" .)* \"\\\"\" | \"'\" (!\"'\" .)* \"'\")")
+ Rules[:_HtmlAttribute] = rule_info("HtmlAttribute", "(AlphanumericAscii | \"-\")+ Spnl (\"=\" Spnl (Quoted | (!\">\" Nonspacechar)+))? Spnl")
+ Rules[:_HtmlComment] = rule_info("HtmlComment", "\"<!--\" (!\"-->\" .)* \"-->\"")
+ Rules[:_HtmlTag] = rule_info("HtmlTag", "\"<\" Spnl \"/\"? AlphanumericAscii+ Spnl HtmlAttribute* \"/\"? Spnl \">\"")
+ Rules[:_Eof] = rule_info("Eof", "!.")
+ Rules[:_Nonspacechar] = rule_info("Nonspacechar", "!Spacechar !Newline .")
+ Rules[:_Sp] = rule_info("Sp", "Spacechar*")
+ Rules[:_Spnl] = rule_info("Spnl", "Sp (Newline Sp)?")
+ Rules[:_SpecialChar] = rule_info("SpecialChar", "(\"*\" | \"_\" | \"`\" | \"&\" | \"[\" | \"]\" | \"(\" | \")\" | \"<\" | \"!\" | \"\#\" | \"\\\\\" | \"'\" | \"\\\"\" | ExtendedSpecialChar)")
+ Rules[:_NormalChar] = rule_info("NormalChar", "!(SpecialChar | Spacechar | Newline) .")
+ Rules[:_Digit] = rule_info("Digit", "[0-9]")
+ Rules[:_Alphanumeric] = rule_info("Alphanumeric", "%literals.Alphanumeric")
+ Rules[:_AlphanumericAscii] = rule_info("AlphanumericAscii", "%literals.AlphanumericAscii")
+ Rules[:_BOM] = rule_info("BOM", "%literals.BOM")
+ Rules[:_Newline] = rule_info("Newline", "%literals.Newline")
+ Rules[:_NonAlphanumeric] = rule_info("NonAlphanumeric", "%literals.NonAlphanumeric")
+ Rules[:_Spacechar] = rule_info("Spacechar", "%literals.Spacechar")
+ Rules[:_HexEntity] = rule_info("HexEntity", "\"&\" \"\#\" /[Xx]/ < /[0-9a-fA-F]+/ > \";\" { [text.to_i(16)].pack 'U' }")
+ Rules[:_DecEntity] = rule_info("DecEntity", "\"&\" \"\#\" < /[0-9]+/ > \";\" { [text.to_i].pack 'U' }")
+ Rules[:_CharEntity] = rule_info("CharEntity", "\"&\" < /[A-Za-z0-9]+/ > \";\" { if entity = HTML_ENTITIES[text] then entity.pack 'U*' else \"&\#{text};\" end }")
+ Rules[:_NonindentSpace] = rule_info("NonindentSpace", "(\" \" | \" \" | \" \" | \"\")")
+ Rules[:_Indent] = rule_info("Indent", "(\"\\t\" | \" \")")
+ Rules[:_IndentedLine] = rule_info("IndentedLine", "Indent Line")
+ Rules[:_OptionallyIndentedLine] = rule_info("OptionallyIndentedLine", "Indent? Line")
+ Rules[:_StartList] = rule_info("StartList", "&. { [] }")
+ Rules[:_Line] = rule_info("Line", "RawLine:a { a }")
+ Rules[:_RawLine] = rule_info("RawLine", "(< (!\" \" !\"\\n\" .)* Newline > | < .+ > Eof) { text }")
+ Rules[:_SkipBlock] = rule_info("SkipBlock", "(HtmlBlock | (!\"\#\" !SetextBottom1 !SetextBottom2 !BlankLine RawLine)+ BlankLine* | BlankLine+ | RawLine)")
+ Rules[:_ExtendedSpecialChar] = rule_info("ExtendedSpecialChar", "&{ notes? } \"^\"")
+ Rules[:_NoteReference] = rule_info("NoteReference", "&{ notes? } RawNoteReference:ref { note_for ref }")
+ Rules[:_RawNoteReference] = rule_info("RawNoteReference", "\"[^\" < (!Newline !\"]\" .)+ > \"]\" { text }")
+ Rules[:_Note] = rule_info("Note", "&{ notes? } NonindentSpace RawNoteReference:ref \":\" Sp StartList:a RawNoteBlock:l (&Indent RawNoteBlock:i { a.concat i })* { @footnotes[ref] = paragraph a nil }")
+ Rules[:_InlineNote] = rule_info("InlineNote", "&{ notes? } \"^[\" StartList:a (!\"]\" Inline:l { a << l })+ \"]\" { ref = [:inline, @note_order.length] @footnotes[ref] = paragraph a note_for ref }")
+ Rules[:_Notes] = rule_info("Notes", "(Note | SkipBlock)*")
+ Rules[:_RawNoteBlock] = rule_info("RawNoteBlock", "StartList:a (!BlankLine OptionallyIndentedLine:l { a << l })+ < BlankLine* > { a << text } { a }")
+ Rules[:_CodeFence] = rule_info("CodeFence", "&{ github? } Ticks3 (Sp StrChunk:format)? Spnl < ((!\"`\" Nonspacechar)+ | !Ticks3 \"`\"+ | Spacechar | Newline)+ > Ticks3 Sp Newline* { verbatim = RDoc::Markup::Verbatim.new text verbatim.format = format.intern if format verbatim }")
+ Rules[:_DefinitionList] = rule_info("DefinitionList", "&{ definition_lists? } DefinitionListItem+:list { RDoc::Markup::List.new :NOTE, *list.flatten }")
+ Rules[:_DefinitionListItem] = rule_info("DefinitionListItem", "DefinitionListLabel+:label DefinitionListDefinition+:defn { list_items = [] list_items << RDoc::Markup::ListItem.new(label, defn.shift) list_items.concat defn.map { |defn| RDoc::Markup::ListItem.new nil, defn } unless list_items.empty? list_items }")
+ Rules[:_DefinitionListLabel] = rule_info("DefinitionListLabel", "StrChunk:label Sp Newline { label }")
+ Rules[:_DefinitionListDefinition] = rule_info("DefinitionListDefinition", "NonindentSpace \":\" Space Inlines:a BlankLine+ { paragraph a }")
+ # :startdoc:
+end
diff --git a/lib/rdoc/markdown/entities.rb b/lib/rdoc/markdown/entities.rb
new file mode 100644
index 0000000000..2b45f20d37
--- /dev/null
+++ b/lib/rdoc/markdown/entities.rb
@@ -0,0 +1,2128 @@
+RDoc::Markdown::HTML_ENTITIES = {
+ "AElig" => [0x000C6],
+ "AMP" => [0x00026],
+ "Aacute" => [0x000C1],
+ "Abreve" => [0x00102],
+ "Acirc" => [0x000C2],
+ "Acy" => [0x00410],
+ "Afr" => [0x1D504],
+ "Agrave" => [0x000C0],
+ "Alpha" => [0x00391],
+ "Amacr" => [0x00100],
+ "And" => [0x02A53],
+ "Aogon" => [0x00104],
+ "Aopf" => [0x1D538],
+ "ApplyFunction" => [0x02061],
+ "Aring" => [0x000C5],
+ "Ascr" => [0x1D49C],
+ "Assign" => [0x02254],
+ "Atilde" => [0x000C3],
+ "Auml" => [0x000C4],
+ "Backslash" => [0x02216],
+ "Barv" => [0x02AE7],
+ "Barwed" => [0x02306],
+ "Bcy" => [0x00411],
+ "Because" => [0x02235],
+ "Bernoullis" => [0x0212C],
+ "Beta" => [0x00392],
+ "Bfr" => [0x1D505],
+ "Bopf" => [0x1D539],
+ "Breve" => [0x002D8],
+ "Bscr" => [0x0212C],
+ "Bumpeq" => [0x0224E],
+ "CHcy" => [0x00427],
+ "COPY" => [0x000A9],
+ "Cacute" => [0x00106],
+ "Cap" => [0x022D2],
+ "CapitalDifferentialD" => [0x02145],
+ "Cayleys" => [0x0212D],
+ "Ccaron" => [0x0010C],
+ "Ccedil" => [0x000C7],
+ "Ccirc" => [0x00108],
+ "Cconint" => [0x02230],
+ "Cdot" => [0x0010A],
+ "Cedilla" => [0x000B8],
+ "CenterDot" => [0x000B7],
+ "Cfr" => [0x0212D],
+ "Chi" => [0x003A7],
+ "CircleDot" => [0x02299],
+ "CircleMinus" => [0x02296],
+ "CirclePlus" => [0x02295],
+ "CircleTimes" => [0x02297],
+ "ClockwiseContourIntegral" => [0x02232],
+ "CloseCurlyDoubleQuote" => [0x0201D],
+ "CloseCurlyQuote" => [0x02019],
+ "Colon" => [0x02237],
+ "Colone" => [0x02A74],
+ "Congruent" => [0x02261],
+ "Conint" => [0x0222F],
+ "ContourIntegral" => [0x0222E],
+ "Copf" => [0x02102],
+ "Coproduct" => [0x02210],
+ "CounterClockwiseContourIntegral" => [0x02233],
+ "Cross" => [0x02A2F],
+ "Cscr" => [0x1D49E],
+ "Cup" => [0x022D3],
+ "CupCap" => [0x0224D],
+ "DD" => [0x02145],
+ "DDotrahd" => [0x02911],
+ "DJcy" => [0x00402],
+ "DScy" => [0x00405],
+ "DZcy" => [0x0040F],
+ "Dagger" => [0x02021],
+ "Darr" => [0x021A1],
+ "Dashv" => [0x02AE4],
+ "Dcaron" => [0x0010E],
+ "Dcy" => [0x00414],
+ "Del" => [0x02207],
+ "Delta" => [0x00394],
+ "Dfr" => [0x1D507],
+ "DiacriticalAcute" => [0x000B4],
+ "DiacriticalDot" => [0x002D9],
+ "DiacriticalDoubleAcute" => [0x002DD],
+ "DiacriticalGrave" => [0x00060],
+ "DiacriticalTilde" => [0x002DC],
+ "Diamond" => [0x022C4],
+ "DifferentialD" => [0x02146],
+ "Dopf" => [0x1D53B],
+ "Dot" => [0x000A8],
+ "DotDot" => [0x020DC],
+ "DotEqual" => [0x02250],
+ "DoubleContourIntegral" => [0x0222F],
+ "DoubleDot" => [0x000A8],
+ "DoubleDownArrow" => [0x021D3],
+ "DoubleLeftArrow" => [0x021D0],
+ "DoubleLeftRightArrow" => [0x021D4],
+ "DoubleLeftTee" => [0x02AE4],
+ "DoubleLongLeftArrow" => [0x027F8],
+ "DoubleLongLeftRightArrow" => [0x027FA],
+ "DoubleLongRightArrow" => [0x027F9],
+ "DoubleRightArrow" => [0x021D2],
+ "DoubleRightTee" => [0x022A8],
+ "DoubleUpArrow" => [0x021D1],
+ "DoubleUpDownArrow" => [0x021D5],
+ "DoubleVerticalBar" => [0x02225],
+ "DownArrow" => [0x02193],
+ "DownArrowBar" => [0x02913],
+ "DownArrowUpArrow" => [0x021F5],
+ "DownBreve" => [0x00311],
+ "DownLeftRightVector" => [0x02950],
+ "DownLeftTeeVector" => [0x0295E],
+ "DownLeftVector" => [0x021BD],
+ "DownLeftVectorBar" => [0x02956],
+ "DownRightTeeVector" => [0x0295F],
+ "DownRightVector" => [0x021C1],
+ "DownRightVectorBar" => [0x02957],
+ "DownTee" => [0x022A4],
+ "DownTeeArrow" => [0x021A7],
+ "Downarrow" => [0x021D3],
+ "Dscr" => [0x1D49F],
+ "Dstrok" => [0x00110],
+ "ENG" => [0x0014A],
+ "ETH" => [0x000D0],
+ "Eacute" => [0x000C9],
+ "Ecaron" => [0x0011A],
+ "Ecirc" => [0x000CA],
+ "Ecy" => [0x0042D],
+ "Edot" => [0x00116],
+ "Efr" => [0x1D508],
+ "Egrave" => [0x000C8],
+ "Element" => [0x02208],
+ "Emacr" => [0x00112],
+ "EmptySmallSquare" => [0x025FB],
+ "EmptyVerySmallSquare" => [0x025AB],
+ "Eogon" => [0x00118],
+ "Eopf" => [0x1D53C],
+ "Epsilon" => [0x00395],
+ "Equal" => [0x02A75],
+ "EqualTilde" => [0x02242],
+ "Equilibrium" => [0x021CC],
+ "Escr" => [0x02130],
+ "Esim" => [0x02A73],
+ "Eta" => [0x00397],
+ "Euml" => [0x000CB],
+ "Exists" => [0x02203],
+ "ExponentialE" => [0x02147],
+ "Fcy" => [0x00424],
+ "Ffr" => [0x1D509],
+ "FilledSmallSquare" => [0x025FC],
+ "FilledVerySmallSquare" => [0x025AA],
+ "Fopf" => [0x1D53D],
+ "ForAll" => [0x02200],
+ "Fouriertrf" => [0x02131],
+ "Fscr" => [0x02131],
+ "GJcy" => [0x00403],
+ "GT" => [0x0003E],
+ "Gamma" => [0x00393],
+ "Gammad" => [0x003DC],
+ "Gbreve" => [0x0011E],
+ "Gcedil" => [0x00122],
+ "Gcirc" => [0x0011C],
+ "Gcy" => [0x00413],
+ "Gdot" => [0x00120],
+ "Gfr" => [0x1D50A],
+ "Gg" => [0x022D9],
+ "Gopf" => [0x1D53E],
+ "GreaterEqual" => [0x02265],
+ "GreaterEqualLess" => [0x022DB],
+ "GreaterFullEqual" => [0x02267],
+ "GreaterGreater" => [0x02AA2],
+ "GreaterLess" => [0x02277],
+ "GreaterSlantEqual" => [0x02A7E],
+ "GreaterTilde" => [0x02273],
+ "Gscr" => [0x1D4A2],
+ "Gt" => [0x0226B],
+ "HARDcy" => [0x0042A],
+ "Hacek" => [0x002C7],
+ "Hat" => [0x0005E],
+ "Hcirc" => [0x00124],
+ "Hfr" => [0x0210C],
+ "HilbertSpace" => [0x0210B],
+ "Hopf" => [0x0210D],
+ "HorizontalLine" => [0x02500],
+ "Hscr" => [0x0210B],
+ "Hstrok" => [0x00126],
+ "HumpDownHump" => [0x0224E],
+ "HumpEqual" => [0x0224F],
+ "IEcy" => [0x00415],
+ "IJlig" => [0x00132],
+ "IOcy" => [0x00401],
+ "Iacute" => [0x000CD],
+ "Icirc" => [0x000CE],
+ "Icy" => [0x00418],
+ "Idot" => [0x00130],
+ "Ifr" => [0x02111],
+ "Igrave" => [0x000CC],
+ "Im" => [0x02111],
+ "Imacr" => [0x0012A],
+ "ImaginaryI" => [0x02148],
+ "Implies" => [0x021D2],
+ "Int" => [0x0222C],
+ "Integral" => [0x0222B],
+ "Intersection" => [0x022C2],
+ "InvisibleComma" => [0x02063],
+ "InvisibleTimes" => [0x02062],
+ "Iogon" => [0x0012E],
+ "Iopf" => [0x1D540],
+ "Iota" => [0x00399],
+ "Iscr" => [0x02110],
+ "Itilde" => [0x00128],
+ "Iukcy" => [0x00406],
+ "Iuml" => [0x000CF],
+ "Jcirc" => [0x00134],
+ "Jcy" => [0x00419],
+ "Jfr" => [0x1D50D],
+ "Jopf" => [0x1D541],
+ "Jscr" => [0x1D4A5],
+ "Jsercy" => [0x00408],
+ "Jukcy" => [0x00404],
+ "KHcy" => [0x00425],
+ "KJcy" => [0x0040C],
+ "Kappa" => [0x0039A],
+ "Kcedil" => [0x00136],
+ "Kcy" => [0x0041A],
+ "Kfr" => [0x1D50E],
+ "Kopf" => [0x1D542],
+ "Kscr" => [0x1D4A6],
+ "LJcy" => [0x00409],
+ "LT" => [0x0003C],
+ "Lacute" => [0x00139],
+ "Lambda" => [0x0039B],
+ "Lang" => [0x027EA],
+ "Laplacetrf" => [0x02112],
+ "Larr" => [0x0219E],
+ "Lcaron" => [0x0013D],
+ "Lcedil" => [0x0013B],
+ "Lcy" => [0x0041B],
+ "LeftAngleBracket" => [0x027E8],
+ "LeftArrow" => [0x02190],
+ "LeftArrowBar" => [0x021E4],
+ "LeftArrowRightArrow" => [0x021C6],
+ "LeftCeiling" => [0x02308],
+ "LeftDoubleBracket" => [0x027E6],
+ "LeftDownTeeVector" => [0x02961],
+ "LeftDownVector" => [0x021C3],
+ "LeftDownVectorBar" => [0x02959],
+ "LeftFloor" => [0x0230A],
+ "LeftRightArrow" => [0x02194],
+ "LeftRightVector" => [0x0294E],
+ "LeftTee" => [0x022A3],
+ "LeftTeeArrow" => [0x021A4],
+ "LeftTeeVector" => [0x0295A],
+ "LeftTriangle" => [0x022B2],
+ "LeftTriangleBar" => [0x029CF],
+ "LeftTriangleEqual" => [0x022B4],
+ "LeftUpDownVector" => [0x02951],
+ "LeftUpTeeVector" => [0x02960],
+ "LeftUpVector" => [0x021BF],
+ "LeftUpVectorBar" => [0x02958],
+ "LeftVector" => [0x021BC],
+ "LeftVectorBar" => [0x02952],
+ "Leftarrow" => [0x021D0],
+ "Leftrightarrow" => [0x021D4],
+ "LessEqualGreater" => [0x022DA],
+ "LessFullEqual" => [0x02266],
+ "LessGreater" => [0x02276],
+ "LessLess" => [0x02AA1],
+ "LessSlantEqual" => [0x02A7D],
+ "LessTilde" => [0x02272],
+ "Lfr" => [0x1D50F],
+ "Ll" => [0x022D8],
+ "Lleftarrow" => [0x021DA],
+ "Lmidot" => [0x0013F],
+ "LongLeftArrow" => [0x027F5],
+ "LongLeftRightArrow" => [0x027F7],
+ "LongRightArrow" => [0x027F6],
+ "Longleftarrow" => [0x027F8],
+ "Longleftrightarrow" => [0x027FA],
+ "Longrightarrow" => [0x027F9],
+ "Lopf" => [0x1D543],
+ "LowerLeftArrow" => [0x02199],
+ "LowerRightArrow" => [0x02198],
+ "Lscr" => [0x02112],
+ "Lsh" => [0x021B0],
+ "Lstrok" => [0x00141],
+ "Lt" => [0x0226A],
+ "Map" => [0x02905],
+ "Mcy" => [0x0041C],
+ "MediumSpace" => [0x0205F],
+ "Mellintrf" => [0x02133],
+ "Mfr" => [0x1D510],
+ "MinusPlus" => [0x02213],
+ "Mopf" => [0x1D544],
+ "Mscr" => [0x02133],
+ "Mu" => [0x0039C],
+ "NJcy" => [0x0040A],
+ "Nacute" => [0x00143],
+ "Ncaron" => [0x00147],
+ "Ncedil" => [0x00145],
+ "Ncy" => [0x0041D],
+ "NegativeMediumSpace" => [0x0200B],
+ "NegativeThickSpace" => [0x0200B],
+ "NegativeThinSpace" => [0x0200B],
+ "NegativeVeryThinSpace" => [0x0200B],
+ "NestedGreaterGreater" => [0x0226B],
+ "NestedLessLess" => [0x0226A],
+ "NewLine" => [0x0000A],
+ "Nfr" => [0x1D511],
+ "NoBreak" => [0x02060],
+ "NonBreakingSpace" => [0x000A0],
+ "Nopf" => [0x02115],
+ "Not" => [0x02AEC],
+ "NotCongruent" => [0x02262],
+ "NotCupCap" => [0x0226D],
+ "NotDoubleVerticalBar" => [0x02226],
+ "NotElement" => [0x02209],
+ "NotEqual" => [0x02260],
+ "NotEqualTilde" => [0x02242, 0x00338],
+ "NotExists" => [0x02204],
+ "NotGreater" => [0x0226F],
+ "NotGreaterEqual" => [0x02271],
+ "NotGreaterFullEqual" => [0x02267, 0x00338],
+ "NotGreaterGreater" => [0x0226B, 0x00338],
+ "NotGreaterLess" => [0x02279],
+ "NotGreaterSlantEqual" => [0x02A7E, 0x00338],
+ "NotGreaterTilde" => [0x02275],
+ "NotHumpDownHump" => [0x0224E, 0x00338],
+ "NotHumpEqual" => [0x0224F, 0x00338],
+ "NotLeftTriangle" => [0x022EA],
+ "NotLeftTriangleBar" => [0x029CF, 0x00338],
+ "NotLeftTriangleEqual" => [0x022EC],
+ "NotLess" => [0x0226E],
+ "NotLessEqual" => [0x02270],
+ "NotLessGreater" => [0x02278],
+ "NotLessLess" => [0x0226A, 0x00338],
+ "NotLessSlantEqual" => [0x02A7D, 0x00338],
+ "NotLessTilde" => [0x02274],
+ "NotNestedGreaterGreater" => [0x02AA2, 0x00338],
+ "NotNestedLessLess" => [0x02AA1, 0x00338],
+ "NotPrecedes" => [0x02280],
+ "NotPrecedesEqual" => [0x02AAF, 0x00338],
+ "NotPrecedesSlantEqual" => [0x022E0],
+ "NotReverseElement" => [0x0220C],
+ "NotRightTriangle" => [0x022EB],
+ "NotRightTriangleBar" => [0x029D0, 0x00338],
+ "NotRightTriangleEqual" => [0x022ED],
+ "NotSquareSubset" => [0x0228F, 0x00338],
+ "NotSquareSubsetEqual" => [0x022E2],
+ "NotSquareSuperset" => [0x02290, 0x00338],
+ "NotSquareSupersetEqual" => [0x022E3],
+ "NotSubset" => [0x02282, 0x020D2],
+ "NotSubsetEqual" => [0x02288],
+ "NotSucceeds" => [0x02281],
+ "NotSucceedsEqual" => [0x02AB0, 0x00338],
+ "NotSucceedsSlantEqual" => [0x022E1],
+ "NotSucceedsTilde" => [0x0227F, 0x00338],
+ "NotSuperset" => [0x02283, 0x020D2],
+ "NotSupersetEqual" => [0x02289],
+ "NotTilde" => [0x02241],
+ "NotTildeEqual" => [0x02244],
+ "NotTildeFullEqual" => [0x02247],
+ "NotTildeTilde" => [0x02249],
+ "NotVerticalBar" => [0x02224],
+ "Nscr" => [0x1D4A9],
+ "Ntilde" => [0x000D1],
+ "Nu" => [0x0039D],
+ "OElig" => [0x00152],
+ "Oacute" => [0x000D3],
+ "Ocirc" => [0x000D4],
+ "Ocy" => [0x0041E],
+ "Odblac" => [0x00150],
+ "Ofr" => [0x1D512],
+ "Ograve" => [0x000D2],
+ "Omacr" => [0x0014C],
+ "Omega" => [0x003A9],
+ "Omicron" => [0x0039F],
+ "Oopf" => [0x1D546],
+ "OpenCurlyDoubleQuote" => [0x0201C],
+ "OpenCurlyQuote" => [0x02018],
+ "Or" => [0x02A54],
+ "Oscr" => [0x1D4AA],
+ "Oslash" => [0x000D8],
+ "Otilde" => [0x000D5],
+ "Otimes" => [0x02A37],
+ "Ouml" => [0x000D6],
+ "OverBar" => [0x0203E],
+ "OverBrace" => [0x023DE],
+ "OverBracket" => [0x023B4],
+ "OverParenthesis" => [0x023DC],
+ "PartialD" => [0x02202],
+ "Pcy" => [0x0041F],
+ "Pfr" => [0x1D513],
+ "Phi" => [0x003A6],
+ "Pi" => [0x003A0],
+ "PlusMinus" => [0x000B1],
+ "Poincareplane" => [0x0210C],
+ "Popf" => [0x02119],
+ "Pr" => [0x02ABB],
+ "Precedes" => [0x0227A],
+ "PrecedesEqual" => [0x02AAF],
+ "PrecedesSlantEqual" => [0x0227C],
+ "PrecedesTilde" => [0x0227E],
+ "Prime" => [0x02033],
+ "Product" => [0x0220F],
+ "Proportion" => [0x02237],
+ "Proportional" => [0x0221D],
+ "Pscr" => [0x1D4AB],
+ "Psi" => [0x003A8],
+ "QUOT" => [0x00022],
+ "Qfr" => [0x1D514],
+ "Qopf" => [0x0211A],
+ "Qscr" => [0x1D4AC],
+ "RBarr" => [0x02910],
+ "REG" => [0x000AE],
+ "Racute" => [0x00154],
+ "Rang" => [0x027EB],
+ "Rarr" => [0x021A0],
+ "Rarrtl" => [0x02916],
+ "Rcaron" => [0x00158],
+ "Rcedil" => [0x00156],
+ "Rcy" => [0x00420],
+ "Re" => [0x0211C],
+ "ReverseElement" => [0x0220B],
+ "ReverseEquilibrium" => [0x021CB],
+ "ReverseUpEquilibrium" => [0x0296F],
+ "Rfr" => [0x0211C],
+ "Rho" => [0x003A1],
+ "RightAngleBracket" => [0x027E9],
+ "RightArrow" => [0x02192],
+ "RightArrowBar" => [0x021E5],
+ "RightArrowLeftArrow" => [0x021C4],
+ "RightCeiling" => [0x02309],
+ "RightDoubleBracket" => [0x027E7],
+ "RightDownTeeVector" => [0x0295D],
+ "RightDownVector" => [0x021C2],
+ "RightDownVectorBar" => [0x02955],
+ "RightFloor" => [0x0230B],
+ "RightTee" => [0x022A2],
+ "RightTeeArrow" => [0x021A6],
+ "RightTeeVector" => [0x0295B],
+ "RightTriangle" => [0x022B3],
+ "RightTriangleBar" => [0x029D0],
+ "RightTriangleEqual" => [0x022B5],
+ "RightUpDownVector" => [0x0294F],
+ "RightUpTeeVector" => [0x0295C],
+ "RightUpVector" => [0x021BE],
+ "RightUpVectorBar" => [0x02954],
+ "RightVector" => [0x021C0],
+ "RightVectorBar" => [0x02953],
+ "Rightarrow" => [0x021D2],
+ "Ropf" => [0x0211D],
+ "RoundImplies" => [0x02970],
+ "Rrightarrow" => [0x021DB],
+ "Rscr" => [0x0211B],
+ "Rsh" => [0x021B1],
+ "RuleDelayed" => [0x029F4],
+ "SHCHcy" => [0x00429],
+ "SHcy" => [0x00428],
+ "SOFTcy" => [0x0042C],
+ "Sacute" => [0x0015A],
+ "Sc" => [0x02ABC],
+ "Scaron" => [0x00160],
+ "Scedil" => [0x0015E],
+ "Scirc" => [0x0015C],
+ "Scy" => [0x00421],
+ "Sfr" => [0x1D516],
+ "ShortDownArrow" => [0x02193],
+ "ShortLeftArrow" => [0x02190],
+ "ShortRightArrow" => [0x02192],
+ "ShortUpArrow" => [0x02191],
+ "Sigma" => [0x003A3],
+ "SmallCircle" => [0x02218],
+ "Sopf" => [0x1D54A],
+ "Sqrt" => [0x0221A],
+ "Square" => [0x025A1],
+ "SquareIntersection" => [0x02293],
+ "SquareSubset" => [0x0228F],
+ "SquareSubsetEqual" => [0x02291],
+ "SquareSuperset" => [0x02290],
+ "SquareSupersetEqual" => [0x02292],
+ "SquareUnion" => [0x02294],
+ "Sscr" => [0x1D4AE],
+ "Star" => [0x022C6],
+ "Sub" => [0x022D0],
+ "Subset" => [0x022D0],
+ "SubsetEqual" => [0x02286],
+ "Succeeds" => [0x0227B],
+ "SucceedsEqual" => [0x02AB0],
+ "SucceedsSlantEqual" => [0x0227D],
+ "SucceedsTilde" => [0x0227F],
+ "SuchThat" => [0x0220B],
+ "Sum" => [0x02211],
+ "Sup" => [0x022D1],
+ "Superset" => [0x02283],
+ "SupersetEqual" => [0x02287],
+ "Supset" => [0x022D1],
+ "THORN" => [0x000DE],
+ "TRADE" => [0x02122],
+ "TSHcy" => [0x0040B],
+ "TScy" => [0x00426],
+ "Tab" => [0x00009],
+ "Tau" => [0x003A4],
+ "Tcaron" => [0x00164],
+ "Tcedil" => [0x00162],
+ "Tcy" => [0x00422],
+ "Tfr" => [0x1D517],
+ "Therefore" => [0x02234],
+ "Theta" => [0x00398],
+ "ThickSpace" => [0x0205F, 0x0200A],
+ "ThinSpace" => [0x02009],
+ "Tilde" => [0x0223C],
+ "TildeEqual" => [0x02243],
+ "TildeFullEqual" => [0x02245],
+ "TildeTilde" => [0x02248],
+ "Topf" => [0x1D54B],
+ "TripleDot" => [0x020DB],
+ "Tscr" => [0x1D4AF],
+ "Tstrok" => [0x00166],
+ "Uacute" => [0x000DA],
+ "Uarr" => [0x0219F],
+ "Uarrocir" => [0x02949],
+ "Ubrcy" => [0x0040E],
+ "Ubreve" => [0x0016C],
+ "Ucirc" => [0x000DB],
+ "Ucy" => [0x00423],
+ "Udblac" => [0x00170],
+ "Ufr" => [0x1D518],
+ "Ugrave" => [0x000D9],
+ "Umacr" => [0x0016A],
+ "UnderBar" => [0x0005F],
+ "UnderBrace" => [0x023DF],
+ "UnderBracket" => [0x023B5],
+ "UnderParenthesis" => [0x023DD],
+ "Union" => [0x022C3],
+ "UnionPlus" => [0x0228E],
+ "Uogon" => [0x00172],
+ "Uopf" => [0x1D54C],
+ "UpArrow" => [0x02191],
+ "UpArrowBar" => [0x02912],
+ "UpArrowDownArrow" => [0x021C5],
+ "UpDownArrow" => [0x02195],
+ "UpEquilibrium" => [0x0296E],
+ "UpTee" => [0x022A5],
+ "UpTeeArrow" => [0x021A5],
+ "Uparrow" => [0x021D1],
+ "Updownarrow" => [0x021D5],
+ "UpperLeftArrow" => [0x02196],
+ "UpperRightArrow" => [0x02197],
+ "Upsi" => [0x003D2],
+ "Upsilon" => [0x003A5],
+ "Uring" => [0x0016E],
+ "Uscr" => [0x1D4B0],
+ "Utilde" => [0x00168],
+ "Uuml" => [0x000DC],
+ "VDash" => [0x022AB],
+ "Vbar" => [0x02AEB],
+ "Vcy" => [0x00412],
+ "Vdash" => [0x022A9],
+ "Vdashl" => [0x02AE6],
+ "Vee" => [0x022C1],
+ "Verbar" => [0x02016],
+ "Vert" => [0x02016],
+ "VerticalBar" => [0x02223],
+ "VerticalLine" => [0x0007C],
+ "VerticalSeparator" => [0x02758],
+ "VerticalTilde" => [0x02240],
+ "VeryThinSpace" => [0x0200A],
+ "Vfr" => [0x1D519],
+ "Vopf" => [0x1D54D],
+ "Vscr" => [0x1D4B1],
+ "Vvdash" => [0x022AA],
+ "Wcirc" => [0x00174],
+ "Wedge" => [0x022C0],
+ "Wfr" => [0x1D51A],
+ "Wopf" => [0x1D54E],
+ "Wscr" => [0x1D4B2],
+ "Xfr" => [0x1D51B],
+ "Xi" => [0x0039E],
+ "Xopf" => [0x1D54F],
+ "Xscr" => [0x1D4B3],
+ "YAcy" => [0x0042F],
+ "YIcy" => [0x00407],
+ "YUcy" => [0x0042E],
+ "Yacute" => [0x000DD],
+ "Ycirc" => [0x00176],
+ "Ycy" => [0x0042B],
+ "Yfr" => [0x1D51C],
+ "Yopf" => [0x1D550],
+ "Yscr" => [0x1D4B4],
+ "Yuml" => [0x00178],
+ "ZHcy" => [0x00416],
+ "Zacute" => [0x00179],
+ "Zcaron" => [0x0017D],
+ "Zcy" => [0x00417],
+ "Zdot" => [0x0017B],
+ "ZeroWidthSpace" => [0x0200B],
+ "Zeta" => [0x00396],
+ "Zfr" => [0x02128],
+ "Zopf" => [0x02124],
+ "Zscr" => [0x1D4B5],
+ "aacute" => [0x000E1],
+ "abreve" => [0x00103],
+ "ac" => [0x0223E],
+ "acE" => [0x0223E, 0x00333],
+ "acd" => [0x0223F],
+ "acirc" => [0x000E2],
+ "acute" => [0x000B4],
+ "acy" => [0x00430],
+ "aelig" => [0x000E6],
+ "af" => [0x02061],
+ "afr" => [0x1D51E],
+ "agrave" => [0x000E0],
+ "alefsym" => [0x02135],
+ "aleph" => [0x02135],
+ "alpha" => [0x003B1],
+ "amacr" => [0x00101],
+ "amalg" => [0x02A3F],
+ "amp" => [0x00026],
+ "and" => [0x02227],
+ "andand" => [0x02A55],
+ "andd" => [0x02A5C],
+ "andslope" => [0x02A58],
+ "andv" => [0x02A5A],
+ "ang" => [0x02220],
+ "ange" => [0x029A4],
+ "angle" => [0x02220],
+ "angmsd" => [0x02221],
+ "angmsdaa" => [0x029A8],
+ "angmsdab" => [0x029A9],
+ "angmsdac" => [0x029AA],
+ "angmsdad" => [0x029AB],
+ "angmsdae" => [0x029AC],
+ "angmsdaf" => [0x029AD],
+ "angmsdag" => [0x029AE],
+ "angmsdah" => [0x029AF],
+ "angrt" => [0x0221F],
+ "angrtvb" => [0x022BE],
+ "angrtvbd" => [0x0299D],
+ "angsph" => [0x02222],
+ "angst" => [0x000C5],
+ "angzarr" => [0x0237C],
+ "aogon" => [0x00105],
+ "aopf" => [0x1D552],
+ "ap" => [0x02248],
+ "apE" => [0x02A70],
+ "apacir" => [0x02A6F],
+ "ape" => [0x0224A],
+ "apid" => [0x0224B],
+ "apos" => [0x00027],
+ "approx" => [0x02248],
+ "approxeq" => [0x0224A],
+ "aring" => [0x000E5],
+ "ascr" => [0x1D4B6],
+ "ast" => [0x0002A],
+ "asymp" => [0x02248],
+ "asympeq" => [0x0224D],
+ "atilde" => [0x000E3],
+ "auml" => [0x000E4],
+ "awconint" => [0x02233],
+ "awint" => [0x02A11],
+ "bNot" => [0x02AED],
+ "backcong" => [0x0224C],
+ "backepsilon" => [0x003F6],
+ "backprime" => [0x02035],
+ "backsim" => [0x0223D],
+ "backsimeq" => [0x022CD],
+ "barvee" => [0x022BD],
+ "barwed" => [0x02305],
+ "barwedge" => [0x02305],
+ "bbrk" => [0x023B5],
+ "bbrktbrk" => [0x023B6],
+ "bcong" => [0x0224C],
+ "bcy" => [0x00431],
+ "bdquo" => [0x0201E],
+ "becaus" => [0x02235],
+ "because" => [0x02235],
+ "bemptyv" => [0x029B0],
+ "bepsi" => [0x003F6],
+ "bernou" => [0x0212C],
+ "beta" => [0x003B2],
+ "beth" => [0x02136],
+ "between" => [0x0226C],
+ "bfr" => [0x1D51F],
+ "bigcap" => [0x022C2],
+ "bigcirc" => [0x025EF],
+ "bigcup" => [0x022C3],
+ "bigodot" => [0x02A00],
+ "bigoplus" => [0x02A01],
+ "bigotimes" => [0x02A02],
+ "bigsqcup" => [0x02A06],
+ "bigstar" => [0x02605],
+ "bigtriangledown" => [0x025BD],
+ "bigtriangleup" => [0x025B3],
+ "biguplus" => [0x02A04],
+ "bigvee" => [0x022C1],
+ "bigwedge" => [0x022C0],
+ "bkarow" => [0x0290D],
+ "blacklozenge" => [0x029EB],
+ "blacksquare" => [0x025AA],
+ "blacktriangle" => [0x025B4],
+ "blacktriangledown" => [0x025BE],
+ "blacktriangleleft" => [0x025C2],
+ "blacktriangleright" => [0x025B8],
+ "blank" => [0x02423],
+ "blk12" => [0x02592],
+ "blk14" => [0x02591],
+ "blk34" => [0x02593],
+ "block" => [0x02588],
+ "bne" => [0x0003D, 0x020E5],
+ "bnequiv" => [0x02261, 0x020E5],
+ "bnot" => [0x02310],
+ "bopf" => [0x1D553],
+ "bot" => [0x022A5],
+ "bottom" => [0x022A5],
+ "bowtie" => [0x022C8],
+ "boxDL" => [0x02557],
+ "boxDR" => [0x02554],
+ "boxDl" => [0x02556],
+ "boxDr" => [0x02553],
+ "boxH" => [0x02550],
+ "boxHD" => [0x02566],
+ "boxHU" => [0x02569],
+ "boxHd" => [0x02564],
+ "boxHu" => [0x02567],
+ "boxUL" => [0x0255D],
+ "boxUR" => [0x0255A],
+ "boxUl" => [0x0255C],
+ "boxUr" => [0x02559],
+ "boxV" => [0x02551],
+ "boxVH" => [0x0256C],
+ "boxVL" => [0x02563],
+ "boxVR" => [0x02560],
+ "boxVh" => [0x0256B],
+ "boxVl" => [0x02562],
+ "boxVr" => [0x0255F],
+ "boxbox" => [0x029C9],
+ "boxdL" => [0x02555],
+ "boxdR" => [0x02552],
+ "boxdl" => [0x02510],
+ "boxdr" => [0x0250C],
+ "boxh" => [0x02500],
+ "boxhD" => [0x02565],
+ "boxhU" => [0x02568],
+ "boxhd" => [0x0252C],
+ "boxhu" => [0x02534],
+ "boxminus" => [0x0229F],
+ "boxplus" => [0x0229E],
+ "boxtimes" => [0x022A0],
+ "boxuL" => [0x0255B],
+ "boxuR" => [0x02558],
+ "boxul" => [0x02518],
+ "boxur" => [0x02514],
+ "boxv" => [0x02502],
+ "boxvH" => [0x0256A],
+ "boxvL" => [0x02561],
+ "boxvR" => [0x0255E],
+ "boxvh" => [0x0253C],
+ "boxvl" => [0x02524],
+ "boxvr" => [0x0251C],
+ "bprime" => [0x02035],
+ "breve" => [0x002D8],
+ "brvbar" => [0x000A6],
+ "bscr" => [0x1D4B7],
+ "bsemi" => [0x0204F],
+ "bsim" => [0x0223D],
+ "bsime" => [0x022CD],
+ "bsol" => [0x0005C],
+ "bsolb" => [0x029C5],
+ "bsolhsub" => [0x027C8],
+ "bull" => [0x02022],
+ "bullet" => [0x02022],
+ "bump" => [0x0224E],
+ "bumpE" => [0x02AAE],
+ "bumpe" => [0x0224F],
+ "bumpeq" => [0x0224F],
+ "cacute" => [0x00107],
+ "cap" => [0x02229],
+ "capand" => [0x02A44],
+ "capbrcup" => [0x02A49],
+ "capcap" => [0x02A4B],
+ "capcup" => [0x02A47],
+ "capdot" => [0x02A40],
+ "caps" => [0x02229, 0x0FE00],
+ "caret" => [0x02041],
+ "caron" => [0x002C7],
+ "ccaps" => [0x02A4D],
+ "ccaron" => [0x0010D],
+ "ccedil" => [0x000E7],
+ "ccirc" => [0x00109],
+ "ccups" => [0x02A4C],
+ "ccupssm" => [0x02A50],
+ "cdot" => [0x0010B],
+ "cedil" => [0x000B8],
+ "cemptyv" => [0x029B2],
+ "cent" => [0x000A2],
+ "centerdot" => [0x000B7],
+ "cfr" => [0x1D520],
+ "chcy" => [0x00447],
+ "check" => [0x02713],
+ "checkmark" => [0x02713],
+ "chi" => [0x003C7],
+ "cir" => [0x025CB],
+ "cirE" => [0x029C3],
+ "circ" => [0x002C6],
+ "circeq" => [0x02257],
+ "circlearrowleft" => [0x021BA],
+ "circlearrowright" => [0x021BB],
+ "circledR" => [0x000AE],
+ "circledS" => [0x024C8],
+ "circledast" => [0x0229B],
+ "circledcirc" => [0x0229A],
+ "circleddash" => [0x0229D],
+ "cire" => [0x02257],
+ "cirfnint" => [0x02A10],
+ "cirmid" => [0x02AEF],
+ "cirscir" => [0x029C2],
+ "clubs" => [0x02663],
+ "clubsuit" => [0x02663],
+ "colon" => [0x0003A],
+ "colone" => [0x02254],
+ "coloneq" => [0x02254],
+ "comma" => [0x0002C],
+ "commat" => [0x00040],
+ "comp" => [0x02201],
+ "compfn" => [0x02218],
+ "complement" => [0x02201],
+ "complexes" => [0x02102],
+ "cong" => [0x02245],
+ "congdot" => [0x02A6D],
+ "conint" => [0x0222E],
+ "copf" => [0x1D554],
+ "coprod" => [0x02210],
+ "copy" => [0x000A9],
+ "copysr" => [0x02117],
+ "crarr" => [0x021B5],
+ "cross" => [0x02717],
+ "cscr" => [0x1D4B8],
+ "csub" => [0x02ACF],
+ "csube" => [0x02AD1],
+ "csup" => [0x02AD0],
+ "csupe" => [0x02AD2],
+ "ctdot" => [0x022EF],
+ "cudarrl" => [0x02938],
+ "cudarrr" => [0x02935],
+ "cuepr" => [0x022DE],
+ "cuesc" => [0x022DF],
+ "cularr" => [0x021B6],
+ "cularrp" => [0x0293D],
+ "cup" => [0x0222A],
+ "cupbrcap" => [0x02A48],
+ "cupcap" => [0x02A46],
+ "cupcup" => [0x02A4A],
+ "cupdot" => [0x0228D],
+ "cupor" => [0x02A45],
+ "cups" => [0x0222A, 0x0FE00],
+ "curarr" => [0x021B7],
+ "curarrm" => [0x0293C],
+ "curlyeqprec" => [0x022DE],
+ "curlyeqsucc" => [0x022DF],
+ "curlyvee" => [0x022CE],
+ "curlywedge" => [0x022CF],
+ "curren" => [0x000A4],
+ "curvearrowleft" => [0x021B6],
+ "curvearrowright" => [0x021B7],
+ "cuvee" => [0x022CE],
+ "cuwed" => [0x022CF],
+ "cwconint" => [0x02232],
+ "cwint" => [0x02231],
+ "cylcty" => [0x0232D],
+ "dArr" => [0x021D3],
+ "dHar" => [0x02965],
+ "dagger" => [0x02020],
+ "daleth" => [0x02138],
+ "darr" => [0x02193],
+ "dash" => [0x02010],
+ "dashv" => [0x022A3],
+ "dbkarow" => [0x0290F],
+ "dblac" => [0x002DD],
+ "dcaron" => [0x0010F],
+ "dcy" => [0x00434],
+ "dd" => [0x02146],
+ "ddagger" => [0x02021],
+ "ddarr" => [0x021CA],
+ "ddotseq" => [0x02A77],
+ "deg" => [0x000B0],
+ "delta" => [0x003B4],
+ "demptyv" => [0x029B1],
+ "dfisht" => [0x0297F],
+ "dfr" => [0x1D521],
+ "dharl" => [0x021C3],
+ "dharr" => [0x021C2],
+ "diam" => [0x022C4],
+ "diamond" => [0x022C4],
+ "diamondsuit" => [0x02666],
+ "diams" => [0x02666],
+ "die" => [0x000A8],
+ "digamma" => [0x003DD],
+ "disin" => [0x022F2],
+ "div" => [0x000F7],
+ "divide" => [0x000F7],
+ "divideontimes" => [0x022C7],
+ "divonx" => [0x022C7],
+ "djcy" => [0x00452],
+ "dlcorn" => [0x0231E],
+ "dlcrop" => [0x0230D],
+ "dollar" => [0x00024],
+ "dopf" => [0x1D555],
+ "dot" => [0x002D9],
+ "doteq" => [0x02250],
+ "doteqdot" => [0x02251],
+ "dotminus" => [0x02238],
+ "dotplus" => [0x02214],
+ "dotsquare" => [0x022A1],
+ "doublebarwedge" => [0x02306],
+ "downarrow" => [0x02193],
+ "downdownarrows" => [0x021CA],
+ "downharpoonleft" => [0x021C3],
+ "downharpoonright" => [0x021C2],
+ "drbkarow" => [0x02910],
+ "drcorn" => [0x0231F],
+ "drcrop" => [0x0230C],
+ "dscr" => [0x1D4B9],
+ "dscy" => [0x00455],
+ "dsol" => [0x029F6],
+ "dstrok" => [0x00111],
+ "dtdot" => [0x022F1],
+ "dtri" => [0x025BF],
+ "dtrif" => [0x025BE],
+ "duarr" => [0x021F5],
+ "duhar" => [0x0296F],
+ "dwangle" => [0x029A6],
+ "dzcy" => [0x0045F],
+ "dzigrarr" => [0x027FF],
+ "eDDot" => [0x02A77],
+ "eDot" => [0x02251],
+ "eacute" => [0x000E9],
+ "easter" => [0x02A6E],
+ "ecaron" => [0x0011B],
+ "ecir" => [0x02256],
+ "ecirc" => [0x000EA],
+ "ecolon" => [0x02255],
+ "ecy" => [0x0044D],
+ "edot" => [0x00117],
+ "ee" => [0x02147],
+ "efDot" => [0x02252],
+ "efr" => [0x1D522],
+ "eg" => [0x02A9A],
+ "egrave" => [0x000E8],
+ "egs" => [0x02A96],
+ "egsdot" => [0x02A98],
+ "el" => [0x02A99],
+ "elinters" => [0x023E7],
+ "ell" => [0x02113],
+ "els" => [0x02A95],
+ "elsdot" => [0x02A97],
+ "emacr" => [0x00113],
+ "empty" => [0x02205],
+ "emptyset" => [0x02205],
+ "emptyv" => [0x02205],
+ "emsp" => [0x02003],
+ "emsp13" => [0x02004],
+ "emsp14" => [0x02005],
+ "eng" => [0x0014B],
+ "ensp" => [0x02002],
+ "eogon" => [0x00119],
+ "eopf" => [0x1D556],
+ "epar" => [0x022D5],
+ "eparsl" => [0x029E3],
+ "eplus" => [0x02A71],
+ "epsi" => [0x003B5],
+ "epsilon" => [0x003B5],
+ "epsiv" => [0x003F5],
+ "eqcirc" => [0x02256],
+ "eqcolon" => [0x02255],
+ "eqsim" => [0x02242],
+ "eqslantgtr" => [0x02A96],
+ "eqslantless" => [0x02A95],
+ "equals" => [0x0003D],
+ "equest" => [0x0225F],
+ "equiv" => [0x02261],
+ "equivDD" => [0x02A78],
+ "eqvparsl" => [0x029E5],
+ "erDot" => [0x02253],
+ "erarr" => [0x02971],
+ "escr" => [0x0212F],
+ "esdot" => [0x02250],
+ "esim" => [0x02242],
+ "eta" => [0x003B7],
+ "eth" => [0x000F0],
+ "euml" => [0x000EB],
+ "euro" => [0x020AC],
+ "excl" => [0x00021],
+ "exist" => [0x02203],
+ "expectation" => [0x02130],
+ "exponentiale" => [0x02147],
+ "fallingdotseq" => [0x02252],
+ "fcy" => [0x00444],
+ "female" => [0x02640],
+ "ffilig" => [0x0FB03],
+ "fflig" => [0x0FB00],
+ "ffllig" => [0x0FB04],
+ "ffr" => [0x1D523],
+ "filig" => [0x0FB01],
+ "fjlig" => [0x00066, 0x0006A],
+ "flat" => [0x0266D],
+ "fllig" => [0x0FB02],
+ "fltns" => [0x025B1],
+ "fnof" => [0x00192],
+ "fopf" => [0x1D557],
+ "forall" => [0x02200],
+ "fork" => [0x022D4],
+ "forkv" => [0x02AD9],
+ "fpartint" => [0x02A0D],
+ "frac12" => [0x000BD],
+ "frac13" => [0x02153],
+ "frac14" => [0x000BC],
+ "frac15" => [0x02155],
+ "frac16" => [0x02159],
+ "frac18" => [0x0215B],
+ "frac23" => [0x02154],
+ "frac25" => [0x02156],
+ "frac34" => [0x000BE],
+ "frac35" => [0x02157],
+ "frac38" => [0x0215C],
+ "frac45" => [0x02158],
+ "frac56" => [0x0215A],
+ "frac58" => [0x0215D],
+ "frac78" => [0x0215E],
+ "frasl" => [0x02044],
+ "frown" => [0x02322],
+ "fscr" => [0x1D4BB],
+ "gE" => [0x02267],
+ "gEl" => [0x02A8C],
+ "gacute" => [0x001F5],
+ "gamma" => [0x003B3],
+ "gammad" => [0x003DD],
+ "gap" => [0x02A86],
+ "gbreve" => [0x0011F],
+ "gcirc" => [0x0011D],
+ "gcy" => [0x00433],
+ "gdot" => [0x00121],
+ "ge" => [0x02265],
+ "gel" => [0x022DB],
+ "geq" => [0x02265],
+ "geqq" => [0x02267],
+ "geqslant" => [0x02A7E],
+ "ges" => [0x02A7E],
+ "gescc" => [0x02AA9],
+ "gesdot" => [0x02A80],
+ "gesdoto" => [0x02A82],
+ "gesdotol" => [0x02A84],
+ "gesl" => [0x022DB, 0x0FE00],
+ "gesles" => [0x02A94],
+ "gfr" => [0x1D524],
+ "gg" => [0x0226B],
+ "ggg" => [0x022D9],
+ "gimel" => [0x02137],
+ "gjcy" => [0x00453],
+ "gl" => [0x02277],
+ "glE" => [0x02A92],
+ "gla" => [0x02AA5],
+ "glj" => [0x02AA4],
+ "gnE" => [0x02269],
+ "gnap" => [0x02A8A],
+ "gnapprox" => [0x02A8A],
+ "gne" => [0x02A88],
+ "gneq" => [0x02A88],
+ "gneqq" => [0x02269],
+ "gnsim" => [0x022E7],
+ "gopf" => [0x1D558],
+ "grave" => [0x00060],
+ "gscr" => [0x0210A],
+ "gsim" => [0x02273],
+ "gsime" => [0x02A8E],
+ "gsiml" => [0x02A90],
+ "gt" => [0x0003E],
+ "gtcc" => [0x02AA7],
+ "gtcir" => [0x02A7A],
+ "gtdot" => [0x022D7],
+ "gtlPar" => [0x02995],
+ "gtquest" => [0x02A7C],
+ "gtrapprox" => [0x02A86],
+ "gtrarr" => [0x02978],
+ "gtrdot" => [0x022D7],
+ "gtreqless" => [0x022DB],
+ "gtreqqless" => [0x02A8C],
+ "gtrless" => [0x02277],
+ "gtrsim" => [0x02273],
+ "gvertneqq" => [0x02269, 0x0FE00],
+ "gvnE" => [0x02269, 0x0FE00],
+ "hArr" => [0x021D4],
+ "hairsp" => [0x0200A],
+ "half" => [0x000BD],
+ "hamilt" => [0x0210B],
+ "hardcy" => [0x0044A],
+ "harr" => [0x02194],
+ "harrcir" => [0x02948],
+ "harrw" => [0x021AD],
+ "hbar" => [0x0210F],
+ "hcirc" => [0x00125],
+ "hearts" => [0x02665],
+ "heartsuit" => [0x02665],
+ "hellip" => [0x02026],
+ "hercon" => [0x022B9],
+ "hfr" => [0x1D525],
+ "hksearow" => [0x02925],
+ "hkswarow" => [0x02926],
+ "hoarr" => [0x021FF],
+ "homtht" => [0x0223B],
+ "hookleftarrow" => [0x021A9],
+ "hookrightarrow" => [0x021AA],
+ "hopf" => [0x1D559],
+ "horbar" => [0x02015],
+ "hscr" => [0x1D4BD],
+ "hslash" => [0x0210F],
+ "hstrok" => [0x00127],
+ "hybull" => [0x02043],
+ "hyphen" => [0x02010],
+ "iacute" => [0x000ED],
+ "ic" => [0x02063],
+ "icirc" => [0x000EE],
+ "icy" => [0x00438],
+ "iecy" => [0x00435],
+ "iexcl" => [0x000A1],
+ "iff" => [0x021D4],
+ "ifr" => [0x1D526],
+ "igrave" => [0x000EC],
+ "ii" => [0x02148],
+ "iiiint" => [0x02A0C],
+ "iiint" => [0x0222D],
+ "iinfin" => [0x029DC],
+ "iiota" => [0x02129],
+ "ijlig" => [0x00133],
+ "imacr" => [0x0012B],
+ "image" => [0x02111],
+ "imagline" => [0x02110],
+ "imagpart" => [0x02111],
+ "imath" => [0x00131],
+ "imof" => [0x022B7],
+ "imped" => [0x001B5],
+ "in" => [0x02208],
+ "incare" => [0x02105],
+ "infin" => [0x0221E],
+ "infintie" => [0x029DD],
+ "inodot" => [0x00131],
+ "int" => [0x0222B],
+ "intcal" => [0x022BA],
+ "integers" => [0x02124],
+ "intercal" => [0x022BA],
+ "intlarhk" => [0x02A17],
+ "intprod" => [0x02A3C],
+ "iocy" => [0x00451],
+ "iogon" => [0x0012F],
+ "iopf" => [0x1D55A],
+ "iota" => [0x003B9],
+ "iprod" => [0x02A3C],
+ "iquest" => [0x000BF],
+ "iscr" => [0x1D4BE],
+ "isin" => [0x02208],
+ "isinE" => [0x022F9],
+ "isindot" => [0x022F5],
+ "isins" => [0x022F4],
+ "isinsv" => [0x022F3],
+ "isinv" => [0x02208],
+ "it" => [0x02062],
+ "itilde" => [0x00129],
+ "iukcy" => [0x00456],
+ "iuml" => [0x000EF],
+ "jcirc" => [0x00135],
+ "jcy" => [0x00439],
+ "jfr" => [0x1D527],
+ "jmath" => [0x00237],
+ "jopf" => [0x1D55B],
+ "jscr" => [0x1D4BF],
+ "jsercy" => [0x00458],
+ "jukcy" => [0x00454],
+ "kappa" => [0x003BA],
+ "kappav" => [0x003F0],
+ "kcedil" => [0x00137],
+ "kcy" => [0x0043A],
+ "kfr" => [0x1D528],
+ "kgreen" => [0x00138],
+ "khcy" => [0x00445],
+ "kjcy" => [0x0045C],
+ "kopf" => [0x1D55C],
+ "kscr" => [0x1D4C0],
+ "lAarr" => [0x021DA],
+ "lArr" => [0x021D0],
+ "lAtail" => [0x0291B],
+ "lBarr" => [0x0290E],
+ "lE" => [0x02266],
+ "lEg" => [0x02A8B],
+ "lHar" => [0x02962],
+ "lacute" => [0x0013A],
+ "laemptyv" => [0x029B4],
+ "lagran" => [0x02112],
+ "lambda" => [0x003BB],
+ "lang" => [0x027E8],
+ "langd" => [0x02991],
+ "langle" => [0x027E8],
+ "lap" => [0x02A85],
+ "laquo" => [0x000AB],
+ "larr" => [0x02190],
+ "larrb" => [0x021E4],
+ "larrbfs" => [0x0291F],
+ "larrfs" => [0x0291D],
+ "larrhk" => [0x021A9],
+ "larrlp" => [0x021AB],
+ "larrpl" => [0x02939],
+ "larrsim" => [0x02973],
+ "larrtl" => [0x021A2],
+ "lat" => [0x02AAB],
+ "latail" => [0x02919],
+ "late" => [0x02AAD],
+ "lates" => [0x02AAD, 0x0FE00],
+ "lbarr" => [0x0290C],
+ "lbbrk" => [0x02772],
+ "lbrace" => [0x0007B],
+ "lbrack" => [0x0005B],
+ "lbrke" => [0x0298B],
+ "lbrksld" => [0x0298F],
+ "lbrkslu" => [0x0298D],
+ "lcaron" => [0x0013E],
+ "lcedil" => [0x0013C],
+ "lceil" => [0x02308],
+ "lcub" => [0x0007B],
+ "lcy" => [0x0043B],
+ "ldca" => [0x02936],
+ "ldquo" => [0x0201C],
+ "ldquor" => [0x0201E],
+ "ldrdhar" => [0x02967],
+ "ldrushar" => [0x0294B],
+ "ldsh" => [0x021B2],
+ "le" => [0x02264],
+ "leftarrow" => [0x02190],
+ "leftarrowtail" => [0x021A2],
+ "leftharpoondown" => [0x021BD],
+ "leftharpoonup" => [0x021BC],
+ "leftleftarrows" => [0x021C7],
+ "leftrightarrow" => [0x02194],
+ "leftrightarrows" => [0x021C6],
+ "leftrightharpoons" => [0x021CB],
+ "leftrightsquigarrow" => [0x021AD],
+ "leftthreetimes" => [0x022CB],
+ "leg" => [0x022DA],
+ "leq" => [0x02264],
+ "leqq" => [0x02266],
+ "leqslant" => [0x02A7D],
+ "les" => [0x02A7D],
+ "lescc" => [0x02AA8],
+ "lesdot" => [0x02A7F],
+ "lesdoto" => [0x02A81],
+ "lesdotor" => [0x02A83],
+ "lesg" => [0x022DA, 0x0FE00],
+ "lesges" => [0x02A93],
+ "lessapprox" => [0x02A85],
+ "lessdot" => [0x022D6],
+ "lesseqgtr" => [0x022DA],
+ "lesseqqgtr" => [0x02A8B],
+ "lessgtr" => [0x02276],
+ "lesssim" => [0x02272],
+ "lfisht" => [0x0297C],
+ "lfloor" => [0x0230A],
+ "lfr" => [0x1D529],
+ "lg" => [0x02276],
+ "lgE" => [0x02A91],
+ "lhard" => [0x021BD],
+ "lharu" => [0x021BC],
+ "lharul" => [0x0296A],
+ "lhblk" => [0x02584],
+ "ljcy" => [0x00459],
+ "ll" => [0x0226A],
+ "llarr" => [0x021C7],
+ "llcorner" => [0x0231E],
+ "llhard" => [0x0296B],
+ "lltri" => [0x025FA],
+ "lmidot" => [0x00140],
+ "lmoust" => [0x023B0],
+ "lmoustache" => [0x023B0],
+ "lnE" => [0x02268],
+ "lnap" => [0x02A89],
+ "lnapprox" => [0x02A89],
+ "lne" => [0x02A87],
+ "lneq" => [0x02A87],
+ "lneqq" => [0x02268],
+ "lnsim" => [0x022E6],
+ "loang" => [0x027EC],
+ "loarr" => [0x021FD],
+ "lobrk" => [0x027E6],
+ "longleftarrow" => [0x027F5],
+ "longleftrightarrow" => [0x027F7],
+ "longmapsto" => [0x027FC],
+ "longrightarrow" => [0x027F6],
+ "looparrowleft" => [0x021AB],
+ "looparrowright" => [0x021AC],
+ "lopar" => [0x02985],
+ "lopf" => [0x1D55D],
+ "loplus" => [0x02A2D],
+ "lotimes" => [0x02A34],
+ "lowast" => [0x02217],
+ "lowbar" => [0x0005F],
+ "loz" => [0x025CA],
+ "lozenge" => [0x025CA],
+ "lozf" => [0x029EB],
+ "lpar" => [0x00028],
+ "lparlt" => [0x02993],
+ "lrarr" => [0x021C6],
+ "lrcorner" => [0x0231F],
+ "lrhar" => [0x021CB],
+ "lrhard" => [0x0296D],
+ "lrm" => [0x0200E],
+ "lrtri" => [0x022BF],
+ "lsaquo" => [0x02039],
+ "lscr" => [0x1D4C1],
+ "lsh" => [0x021B0],
+ "lsim" => [0x02272],
+ "lsime" => [0x02A8D],
+ "lsimg" => [0x02A8F],
+ "lsqb" => [0x0005B],
+ "lsquo" => [0x02018],
+ "lsquor" => [0x0201A],
+ "lstrok" => [0x00142],
+ "lt" => [0x0003C],
+ "ltcc" => [0x02AA6],
+ "ltcir" => [0x02A79],
+ "ltdot" => [0x022D6],
+ "lthree" => [0x022CB],
+ "ltimes" => [0x022C9],
+ "ltlarr" => [0x02976],
+ "ltquest" => [0x02A7B],
+ "ltrPar" => [0x02996],
+ "ltri" => [0x025C3],
+ "ltrie" => [0x022B4],
+ "ltrif" => [0x025C2],
+ "lurdshar" => [0x0294A],
+ "luruhar" => [0x02966],
+ "lvertneqq" => [0x02268, 0x0FE00],
+ "lvnE" => [0x02268, 0x0FE00],
+ "mDDot" => [0x0223A],
+ "macr" => [0x000AF],
+ "male" => [0x02642],
+ "malt" => [0x02720],
+ "maltese" => [0x02720],
+ "map" => [0x021A6],
+ "mapsto" => [0x021A6],
+ "mapstodown" => [0x021A7],
+ "mapstoleft" => [0x021A4],
+ "mapstoup" => [0x021A5],
+ "marker" => [0x025AE],
+ "mcomma" => [0x02A29],
+ "mcy" => [0x0043C],
+ "mdash" => [0x02014],
+ "measuredangle" => [0x02221],
+ "mfr" => [0x1D52A],
+ "mho" => [0x02127],
+ "micro" => [0x000B5],
+ "mid" => [0x02223],
+ "midast" => [0x0002A],
+ "midcir" => [0x02AF0],
+ "middot" => [0x000B7],
+ "minus" => [0x02212],
+ "minusb" => [0x0229F],
+ "minusd" => [0x02238],
+ "minusdu" => [0x02A2A],
+ "mlcp" => [0x02ADB],
+ "mldr" => [0x02026],
+ "mnplus" => [0x02213],
+ "models" => [0x022A7],
+ "mopf" => [0x1D55E],
+ "mp" => [0x02213],
+ "mscr" => [0x1D4C2],
+ "mstpos" => [0x0223E],
+ "mu" => [0x003BC],
+ "multimap" => [0x022B8],
+ "mumap" => [0x022B8],
+ "nGg" => [0x022D9, 0x00338],
+ "nGt" => [0x0226B, 0x020D2],
+ "nGtv" => [0x0226B, 0x00338],
+ "nLeftarrow" => [0x021CD],
+ "nLeftrightarrow" => [0x021CE],
+ "nLl" => [0x022D8, 0x00338],
+ "nLt" => [0x0226A, 0x020D2],
+ "nLtv" => [0x0226A, 0x00338],
+ "nRightarrow" => [0x021CF],
+ "nVDash" => [0x022AF],
+ "nVdash" => [0x022AE],
+ "nabla" => [0x02207],
+ "nacute" => [0x00144],
+ "nang" => [0x02220, 0x020D2],
+ "nap" => [0x02249],
+ "napE" => [0x02A70, 0x00338],
+ "napid" => [0x0224B, 0x00338],
+ "napos" => [0x00149],
+ "napprox" => [0x02249],
+ "natur" => [0x0266E],
+ "natural" => [0x0266E],
+ "naturals" => [0x02115],
+ "nbsp" => [0x000A0],
+ "nbump" => [0x0224E, 0x00338],
+ "nbumpe" => [0x0224F, 0x00338],
+ "ncap" => [0x02A43],
+ "ncaron" => [0x00148],
+ "ncedil" => [0x00146],
+ "ncong" => [0x02247],
+ "ncongdot" => [0x02A6D, 0x00338],
+ "ncup" => [0x02A42],
+ "ncy" => [0x0043D],
+ "ndash" => [0x02013],
+ "ne" => [0x02260],
+ "neArr" => [0x021D7],
+ "nearhk" => [0x02924],
+ "nearr" => [0x02197],
+ "nearrow" => [0x02197],
+ "nedot" => [0x02250, 0x00338],
+ "nequiv" => [0x02262],
+ "nesear" => [0x02928],
+ "nesim" => [0x02242, 0x00338],
+ "nexist" => [0x02204],
+ "nexists" => [0x02204],
+ "nfr" => [0x1D52B],
+ "ngE" => [0x02267, 0x00338],
+ "nge" => [0x02271],
+ "ngeq" => [0x02271],
+ "ngeqq" => [0x02267, 0x00338],
+ "ngeqslant" => [0x02A7E, 0x00338],
+ "nges" => [0x02A7E, 0x00338],
+ "ngsim" => [0x02275],
+ "ngt" => [0x0226F],
+ "ngtr" => [0x0226F],
+ "nhArr" => [0x021CE],
+ "nharr" => [0x021AE],
+ "nhpar" => [0x02AF2],
+ "ni" => [0x0220B],
+ "nis" => [0x022FC],
+ "nisd" => [0x022FA],
+ "niv" => [0x0220B],
+ "njcy" => [0x0045A],
+ "nlArr" => [0x021CD],
+ "nlE" => [0x02266, 0x00338],
+ "nlarr" => [0x0219A],
+ "nldr" => [0x02025],
+ "nle" => [0x02270],
+ "nleftarrow" => [0x0219A],
+ "nleftrightarrow" => [0x021AE],
+ "nleq" => [0x02270],
+ "nleqq" => [0x02266, 0x00338],
+ "nleqslant" => [0x02A7D, 0x00338],
+ "nles" => [0x02A7D, 0x00338],
+ "nless" => [0x0226E],
+ "nlsim" => [0x02274],
+ "nlt" => [0x0226E],
+ "nltri" => [0x022EA],
+ "nltrie" => [0x022EC],
+ "nmid" => [0x02224],
+ "nopf" => [0x1D55F],
+ "not" => [0x000AC],
+ "notin" => [0x02209],
+ "notinE" => [0x022F9, 0x00338],
+ "notindot" => [0x022F5, 0x00338],
+ "notinva" => [0x02209],
+ "notinvb" => [0x022F7],
+ "notinvc" => [0x022F6],
+ "notni" => [0x0220C],
+ "notniva" => [0x0220C],
+ "notnivb" => [0x022FE],
+ "notnivc" => [0x022FD],
+ "npar" => [0x02226],
+ "nparallel" => [0x02226],
+ "nparsl" => [0x02AFD, 0x020E5],
+ "npart" => [0x02202, 0x00338],
+ "npolint" => [0x02A14],
+ "npr" => [0x02280],
+ "nprcue" => [0x022E0],
+ "npre" => [0x02AAF, 0x00338],
+ "nprec" => [0x02280],
+ "npreceq" => [0x02AAF, 0x00338],
+ "nrArr" => [0x021CF],
+ "nrarr" => [0x0219B],
+ "nrarrc" => [0x02933, 0x00338],
+ "nrarrw" => [0x0219D, 0x00338],
+ "nrightarrow" => [0x0219B],
+ "nrtri" => [0x022EB],
+ "nrtrie" => [0x022ED],
+ "nsc" => [0x02281],
+ "nsccue" => [0x022E1],
+ "nsce" => [0x02AB0, 0x00338],
+ "nscr" => [0x1D4C3],
+ "nshortmid" => [0x02224],
+ "nshortparallel" => [0x02226],
+ "nsim" => [0x02241],
+ "nsime" => [0x02244],
+ "nsimeq" => [0x02244],
+ "nsmid" => [0x02224],
+ "nspar" => [0x02226],
+ "nsqsube" => [0x022E2],
+ "nsqsupe" => [0x022E3],
+ "nsub" => [0x02284],
+ "nsubE" => [0x02AC5, 0x00338],
+ "nsube" => [0x02288],
+ "nsubset" => [0x02282, 0x020D2],
+ "nsubseteq" => [0x02288],
+ "nsubseteqq" => [0x02AC5, 0x00338],
+ "nsucc" => [0x02281],
+ "nsucceq" => [0x02AB0, 0x00338],
+ "nsup" => [0x02285],
+ "nsupE" => [0x02AC6, 0x00338],
+ "nsupe" => [0x02289],
+ "nsupset" => [0x02283, 0x020D2],
+ "nsupseteq" => [0x02289],
+ "nsupseteqq" => [0x02AC6, 0x00338],
+ "ntgl" => [0x02279],
+ "ntilde" => [0x000F1],
+ "ntlg" => [0x02278],
+ "ntriangleleft" => [0x022EA],
+ "ntrianglelefteq" => [0x022EC],
+ "ntriangleright" => [0x022EB],
+ "ntrianglerighteq" => [0x022ED],
+ "nu" => [0x003BD],
+ "num" => [0x00023],
+ "numero" => [0x02116],
+ "numsp" => [0x02007],
+ "nvDash" => [0x022AD],
+ "nvHarr" => [0x02904],
+ "nvap" => [0x0224D, 0x020D2],
+ "nvdash" => [0x022AC],
+ "nvge" => [0x02265, 0x020D2],
+ "nvgt" => [0x0003E, 0x020D2],
+ "nvinfin" => [0x029DE],
+ "nvlArr" => [0x02902],
+ "nvle" => [0x02264, 0x020D2],
+ "nvlt" => [0x0003C, 0x020D2],
+ "nvltrie" => [0x022B4, 0x020D2],
+ "nvrArr" => [0x02903],
+ "nvrtrie" => [0x022B5, 0x020D2],
+ "nvsim" => [0x0223C, 0x020D2],
+ "nwArr" => [0x021D6],
+ "nwarhk" => [0x02923],
+ "nwarr" => [0x02196],
+ "nwarrow" => [0x02196],
+ "nwnear" => [0x02927],
+ "oS" => [0x024C8],
+ "oacute" => [0x000F3],
+ "oast" => [0x0229B],
+ "ocir" => [0x0229A],
+ "ocirc" => [0x000F4],
+ "ocy" => [0x0043E],
+ "odash" => [0x0229D],
+ "odblac" => [0x00151],
+ "odiv" => [0x02A38],
+ "odot" => [0x02299],
+ "odsold" => [0x029BC],
+ "oelig" => [0x00153],
+ "ofcir" => [0x029BF],
+ "ofr" => [0x1D52C],
+ "ogon" => [0x002DB],
+ "ograve" => [0x000F2],
+ "ogt" => [0x029C1],
+ "ohbar" => [0x029B5],
+ "ohm" => [0x003A9],
+ "oint" => [0x0222E],
+ "olarr" => [0x021BA],
+ "olcir" => [0x029BE],
+ "olcross" => [0x029BB],
+ "oline" => [0x0203E],
+ "olt" => [0x029C0],
+ "omacr" => [0x0014D],
+ "omega" => [0x003C9],
+ "omicron" => [0x003BF],
+ "omid" => [0x029B6],
+ "ominus" => [0x02296],
+ "oopf" => [0x1D560],
+ "opar" => [0x029B7],
+ "operp" => [0x029B9],
+ "oplus" => [0x02295],
+ "or" => [0x02228],
+ "orarr" => [0x021BB],
+ "ord" => [0x02A5D],
+ "order" => [0x02134],
+ "orderof" => [0x02134],
+ "ordf" => [0x000AA],
+ "ordm" => [0x000BA],
+ "origof" => [0x022B6],
+ "oror" => [0x02A56],
+ "orslope" => [0x02A57],
+ "orv" => [0x02A5B],
+ "oscr" => [0x02134],
+ "oslash" => [0x000F8],
+ "osol" => [0x02298],
+ "otilde" => [0x000F5],
+ "otimes" => [0x02297],
+ "otimesas" => [0x02A36],
+ "ouml" => [0x000F6],
+ "ovbar" => [0x0233D],
+ "par" => [0x02225],
+ "para" => [0x000B6],
+ "parallel" => [0x02225],
+ "parsim" => [0x02AF3],
+ "parsl" => [0x02AFD],
+ "part" => [0x02202],
+ "pcy" => [0x0043F],
+ "percnt" => [0x00025],
+ "period" => [0x0002E],
+ "permil" => [0x02030],
+ "perp" => [0x022A5],
+ "pertenk" => [0x02031],
+ "pfr" => [0x1D52D],
+ "phi" => [0x003C6],
+ "phiv" => [0x003D5],
+ "phmmat" => [0x02133],
+ "phone" => [0x0260E],
+ "pi" => [0x003C0],
+ "pitchfork" => [0x022D4],
+ "piv" => [0x003D6],
+ "planck" => [0x0210F],
+ "planckh" => [0x0210E],
+ "plankv" => [0x0210F],
+ "plus" => [0x0002B],
+ "plusacir" => [0x02A23],
+ "plusb" => [0x0229E],
+ "pluscir" => [0x02A22],
+ "plusdo" => [0x02214],
+ "plusdu" => [0x02A25],
+ "pluse" => [0x02A72],
+ "plusmn" => [0x000B1],
+ "plussim" => [0x02A26],
+ "plustwo" => [0x02A27],
+ "pm" => [0x000B1],
+ "pointint" => [0x02A15],
+ "popf" => [0x1D561],
+ "pound" => [0x000A3],
+ "pr" => [0x0227A],
+ "prE" => [0x02AB3],
+ "prap" => [0x02AB7],
+ "prcue" => [0x0227C],
+ "pre" => [0x02AAF],
+ "prec" => [0x0227A],
+ "precapprox" => [0x02AB7],
+ "preccurlyeq" => [0x0227C],
+ "preceq" => [0x02AAF],
+ "precnapprox" => [0x02AB9],
+ "precneqq" => [0x02AB5],
+ "precnsim" => [0x022E8],
+ "precsim" => [0x0227E],
+ "prime" => [0x02032],
+ "primes" => [0x02119],
+ "prnE" => [0x02AB5],
+ "prnap" => [0x02AB9],
+ "prnsim" => [0x022E8],
+ "prod" => [0x0220F],
+ "profalar" => [0x0232E],
+ "profline" => [0x02312],
+ "profsurf" => [0x02313],
+ "prop" => [0x0221D],
+ "propto" => [0x0221D],
+ "prsim" => [0x0227E],
+ "prurel" => [0x022B0],
+ "pscr" => [0x1D4C5],
+ "psi" => [0x003C8],
+ "puncsp" => [0x02008],
+ "qfr" => [0x1D52E],
+ "qint" => [0x02A0C],
+ "qopf" => [0x1D562],
+ "qprime" => [0x02057],
+ "qscr" => [0x1D4C6],
+ "quaternions" => [0x0210D],
+ "quatint" => [0x02A16],
+ "quest" => [0x0003F],
+ "questeq" => [0x0225F],
+ "quot" => [0x00022],
+ "rAarr" => [0x021DB],
+ "rArr" => [0x021D2],
+ "rAtail" => [0x0291C],
+ "rBarr" => [0x0290F],
+ "rHar" => [0x02964],
+ "race" => [0x0223D, 0x00331],
+ "racute" => [0x00155],
+ "radic" => [0x0221A],
+ "raemptyv" => [0x029B3],
+ "rang" => [0x027E9],
+ "rangd" => [0x02992],
+ "range" => [0x029A5],
+ "rangle" => [0x027E9],
+ "raquo" => [0x000BB],
+ "rarr" => [0x02192],
+ "rarrap" => [0x02975],
+ "rarrb" => [0x021E5],
+ "rarrbfs" => [0x02920],
+ "rarrc" => [0x02933],
+ "rarrfs" => [0x0291E],
+ "rarrhk" => [0x021AA],
+ "rarrlp" => [0x021AC],
+ "rarrpl" => [0x02945],
+ "rarrsim" => [0x02974],
+ "rarrtl" => [0x021A3],
+ "rarrw" => [0x0219D],
+ "ratail" => [0x0291A],
+ "ratio" => [0x02236],
+ "rationals" => [0x0211A],
+ "rbarr" => [0x0290D],
+ "rbbrk" => [0x02773],
+ "rbrace" => [0x0007D],
+ "rbrack" => [0x0005D],
+ "rbrke" => [0x0298C],
+ "rbrksld" => [0x0298E],
+ "rbrkslu" => [0x02990],
+ "rcaron" => [0x00159],
+ "rcedil" => [0x00157],
+ "rceil" => [0x02309],
+ "rcub" => [0x0007D],
+ "rcy" => [0x00440],
+ "rdca" => [0x02937],
+ "rdldhar" => [0x02969],
+ "rdquo" => [0x0201D],
+ "rdquor" => [0x0201D],
+ "rdsh" => [0x021B3],
+ "real" => [0x0211C],
+ "realine" => [0x0211B],
+ "realpart" => [0x0211C],
+ "reals" => [0x0211D],
+ "rect" => [0x025AD],
+ "reg" => [0x000AE],
+ "rfisht" => [0x0297D],
+ "rfloor" => [0x0230B],
+ "rfr" => [0x1D52F],
+ "rhard" => [0x021C1],
+ "rharu" => [0x021C0],
+ "rharul" => [0x0296C],
+ "rho" => [0x003C1],
+ "rhov" => [0x003F1],
+ "rightarrow" => [0x02192],
+ "rightarrowtail" => [0x021A3],
+ "rightharpoondown" => [0x021C1],
+ "rightharpoonup" => [0x021C0],
+ "rightleftarrows" => [0x021C4],
+ "rightleftharpoons" => [0x021CC],
+ "rightrightarrows" => [0x021C9],
+ "rightsquigarrow" => [0x0219D],
+ "rightthreetimes" => [0x022CC],
+ "ring" => [0x002DA],
+ "risingdotseq" => [0x02253],
+ "rlarr" => [0x021C4],
+ "rlhar" => [0x021CC],
+ "rlm" => [0x0200F],
+ "rmoust" => [0x023B1],
+ "rmoustache" => [0x023B1],
+ "rnmid" => [0x02AEE],
+ "roang" => [0x027ED],
+ "roarr" => [0x021FE],
+ "robrk" => [0x027E7],
+ "ropar" => [0x02986],
+ "ropf" => [0x1D563],
+ "roplus" => [0x02A2E],
+ "rotimes" => [0x02A35],
+ "rpar" => [0x00029],
+ "rpargt" => [0x02994],
+ "rppolint" => [0x02A12],
+ "rrarr" => [0x021C9],
+ "rsaquo" => [0x0203A],
+ "rscr" => [0x1D4C7],
+ "rsh" => [0x021B1],
+ "rsqb" => [0x0005D],
+ "rsquo" => [0x02019],
+ "rsquor" => [0x02019],
+ "rthree" => [0x022CC],
+ "rtimes" => [0x022CA],
+ "rtri" => [0x025B9],
+ "rtrie" => [0x022B5],
+ "rtrif" => [0x025B8],
+ "rtriltri" => [0x029CE],
+ "ruluhar" => [0x02968],
+ "rx" => [0x0211E],
+ "sacute" => [0x0015B],
+ "sbquo" => [0x0201A],
+ "sc" => [0x0227B],
+ "scE" => [0x02AB4],
+ "scap" => [0x02AB8],
+ "scaron" => [0x00161],
+ "sccue" => [0x0227D],
+ "sce" => [0x02AB0],
+ "scedil" => [0x0015F],
+ "scirc" => [0x0015D],
+ "scnE" => [0x02AB6],
+ "scnap" => [0x02ABA],
+ "scnsim" => [0x022E9],
+ "scpolint" => [0x02A13],
+ "scsim" => [0x0227F],
+ "scy" => [0x00441],
+ "sdot" => [0x022C5],
+ "sdotb" => [0x022A1],
+ "sdote" => [0x02A66],
+ "seArr" => [0x021D8],
+ "searhk" => [0x02925],
+ "searr" => [0x02198],
+ "searrow" => [0x02198],
+ "sect" => [0x000A7],
+ "semi" => [0x0003B],
+ "seswar" => [0x02929],
+ "setminus" => [0x02216],
+ "setmn" => [0x02216],
+ "sext" => [0x02736],
+ "sfr" => [0x1D530],
+ "sfrown" => [0x02322],
+ "sharp" => [0x0266F],
+ "shchcy" => [0x00449],
+ "shcy" => [0x00448],
+ "shortmid" => [0x02223],
+ "shortparallel" => [0x02225],
+ "shy" => [0x000AD],
+ "sigma" => [0x003C3],
+ "sigmaf" => [0x003C2],
+ "sigmav" => [0x003C2],
+ "sim" => [0x0223C],
+ "simdot" => [0x02A6A],
+ "sime" => [0x02243],
+ "simeq" => [0x02243],
+ "simg" => [0x02A9E],
+ "simgE" => [0x02AA0],
+ "siml" => [0x02A9D],
+ "simlE" => [0x02A9F],
+ "simne" => [0x02246],
+ "simplus" => [0x02A24],
+ "simrarr" => [0x02972],
+ "slarr" => [0x02190],
+ "smallsetminus" => [0x02216],
+ "smashp" => [0x02A33],
+ "smeparsl" => [0x029E4],
+ "smid" => [0x02223],
+ "smile" => [0x02323],
+ "smt" => [0x02AAA],
+ "smte" => [0x02AAC],
+ "smtes" => [0x02AAC, 0x0FE00],
+ "softcy" => [0x0044C],
+ "sol" => [0x0002F],
+ "solb" => [0x029C4],
+ "solbar" => [0x0233F],
+ "sopf" => [0x1D564],
+ "spades" => [0x02660],
+ "spadesuit" => [0x02660],
+ "spar" => [0x02225],
+ "sqcap" => [0x02293],
+ "sqcaps" => [0x02293, 0x0FE00],
+ "sqcup" => [0x02294],
+ "sqcups" => [0x02294, 0x0FE00],
+ "sqsub" => [0x0228F],
+ "sqsube" => [0x02291],
+ "sqsubset" => [0x0228F],
+ "sqsubseteq" => [0x02291],
+ "sqsup" => [0x02290],
+ "sqsupe" => [0x02292],
+ "sqsupset" => [0x02290],
+ "sqsupseteq" => [0x02292],
+ "squ" => [0x025A1],
+ "square" => [0x025A1],
+ "squarf" => [0x025AA],
+ "squf" => [0x025AA],
+ "srarr" => [0x02192],
+ "sscr" => [0x1D4C8],
+ "ssetmn" => [0x02216],
+ "ssmile" => [0x02323],
+ "sstarf" => [0x022C6],
+ "star" => [0x02606],
+ "starf" => [0x02605],
+ "straightepsilon" => [0x003F5],
+ "straightphi" => [0x003D5],
+ "strns" => [0x000AF],
+ "sub" => [0x02282],
+ "subE" => [0x02AC5],
+ "subdot" => [0x02ABD],
+ "sube" => [0x02286],
+ "subedot" => [0x02AC3],
+ "submult" => [0x02AC1],
+ "subnE" => [0x02ACB],
+ "subne" => [0x0228A],
+ "subplus" => [0x02ABF],
+ "subrarr" => [0x02979],
+ "subset" => [0x02282],
+ "subseteq" => [0x02286],
+ "subseteqq" => [0x02AC5],
+ "subsetneq" => [0x0228A],
+ "subsetneqq" => [0x02ACB],
+ "subsim" => [0x02AC7],
+ "subsub" => [0x02AD5],
+ "subsup" => [0x02AD3],
+ "succ" => [0x0227B],
+ "succapprox" => [0x02AB8],
+ "succcurlyeq" => [0x0227D],
+ "succeq" => [0x02AB0],
+ "succnapprox" => [0x02ABA],
+ "succneqq" => [0x02AB6],
+ "succnsim" => [0x022E9],
+ "succsim" => [0x0227F],
+ "sum" => [0x02211],
+ "sung" => [0x0266A],
+ "sup" => [0x02283],
+ "sup1" => [0x000B9],
+ "sup2" => [0x000B2],
+ "sup3" => [0x000B3],
+ "supE" => [0x02AC6],
+ "supdot" => [0x02ABE],
+ "supdsub" => [0x02AD8],
+ "supe" => [0x02287],
+ "supedot" => [0x02AC4],
+ "suphsol" => [0x027C9],
+ "suphsub" => [0x02AD7],
+ "suplarr" => [0x0297B],
+ "supmult" => [0x02AC2],
+ "supnE" => [0x02ACC],
+ "supne" => [0x0228B],
+ "supplus" => [0x02AC0],
+ "supset" => [0x02283],
+ "supseteq" => [0x02287],
+ "supseteqq" => [0x02AC6],
+ "supsetneq" => [0x0228B],
+ "supsetneqq" => [0x02ACC],
+ "supsim" => [0x02AC8],
+ "supsub" => [0x02AD4],
+ "supsup" => [0x02AD6],
+ "swArr" => [0x021D9],
+ "swarhk" => [0x02926],
+ "swarr" => [0x02199],
+ "swarrow" => [0x02199],
+ "swnwar" => [0x0292A],
+ "szlig" => [0x000DF],
+ "target" => [0x02316],
+ "tau" => [0x003C4],
+ "tbrk" => [0x023B4],
+ "tcaron" => [0x00165],
+ "tcedil" => [0x00163],
+ "tcy" => [0x00442],
+ "tdot" => [0x020DB],
+ "telrec" => [0x02315],
+ "tfr" => [0x1D531],
+ "there4" => [0x02234],
+ "therefore" => [0x02234],
+ "theta" => [0x003B8],
+ "thetasym" => [0x003D1],
+ "thetav" => [0x003D1],
+ "thickapprox" => [0x02248],
+ "thicksim" => [0x0223C],
+ "thinsp" => [0x02009],
+ "thkap" => [0x02248],
+ "thksim" => [0x0223C],
+ "thorn" => [0x000FE],
+ "tilde" => [0x002DC],
+ "times" => [0x000D7],
+ "timesb" => [0x022A0],
+ "timesbar" => [0x02A31],
+ "timesd" => [0x02A30],
+ "tint" => [0x0222D],
+ "toea" => [0x02928],
+ "top" => [0x022A4],
+ "topbot" => [0x02336],
+ "topcir" => [0x02AF1],
+ "topf" => [0x1D565],
+ "topfork" => [0x02ADA],
+ "tosa" => [0x02929],
+ "tprime" => [0x02034],
+ "trade" => [0x02122],
+ "triangle" => [0x025B5],
+ "triangledown" => [0x025BF],
+ "triangleleft" => [0x025C3],
+ "trianglelefteq" => [0x022B4],
+ "triangleq" => [0x0225C],
+ "triangleright" => [0x025B9],
+ "trianglerighteq" => [0x022B5],
+ "tridot" => [0x025EC],
+ "trie" => [0x0225C],
+ "triminus" => [0x02A3A],
+ "triplus" => [0x02A39],
+ "trisb" => [0x029CD],
+ "tritime" => [0x02A3B],
+ "trpezium" => [0x023E2],
+ "tscr" => [0x1D4C9],
+ "tscy" => [0x00446],
+ "tshcy" => [0x0045B],
+ "tstrok" => [0x00167],
+ "twixt" => [0x0226C],
+ "twoheadleftarrow" => [0x0219E],
+ "twoheadrightarrow" => [0x021A0],
+ "uArr" => [0x021D1],
+ "uHar" => [0x02963],
+ "uacute" => [0x000FA],
+ "uarr" => [0x02191],
+ "ubrcy" => [0x0045E],
+ "ubreve" => [0x0016D],
+ "ucirc" => [0x000FB],
+ "ucy" => [0x00443],
+ "udarr" => [0x021C5],
+ "udblac" => [0x00171],
+ "udhar" => [0x0296E],
+ "ufisht" => [0x0297E],
+ "ufr" => [0x1D532],
+ "ugrave" => [0x000F9],
+ "uharl" => [0x021BF],
+ "uharr" => [0x021BE],
+ "uhblk" => [0x02580],
+ "ulcorn" => [0x0231C],
+ "ulcorner" => [0x0231C],
+ "ulcrop" => [0x0230F],
+ "ultri" => [0x025F8],
+ "umacr" => [0x0016B],
+ "uml" => [0x000A8],
+ "uogon" => [0x00173],
+ "uopf" => [0x1D566],
+ "uparrow" => [0x02191],
+ "updownarrow" => [0x02195],
+ "upharpoonleft" => [0x021BF],
+ "upharpoonright" => [0x021BE],
+ "uplus" => [0x0228E],
+ "upsi" => [0x003C5],
+ "upsih" => [0x003D2],
+ "upsilon" => [0x003C5],
+ "upuparrows" => [0x021C8],
+ "urcorn" => [0x0231D],
+ "urcorner" => [0x0231D],
+ "urcrop" => [0x0230E],
+ "uring" => [0x0016F],
+ "urtri" => [0x025F9],
+ "uscr" => [0x1D4CA],
+ "utdot" => [0x022F0],
+ "utilde" => [0x00169],
+ "utri" => [0x025B5],
+ "utrif" => [0x025B4],
+ "uuarr" => [0x021C8],
+ "uuml" => [0x000FC],
+ "uwangle" => [0x029A7],
+ "vArr" => [0x021D5],
+ "vBar" => [0x02AE8],
+ "vBarv" => [0x02AE9],
+ "vDash" => [0x022A8],
+ "vangrt" => [0x0299C],
+ "varepsilon" => [0x003F5],
+ "varkappa" => [0x003F0],
+ "varnothing" => [0x02205],
+ "varphi" => [0x003D5],
+ "varpi" => [0x003D6],
+ "varpropto" => [0x0221D],
+ "varr" => [0x02195],
+ "varrho" => [0x003F1],
+ "varsigma" => [0x003C2],
+ "varsubsetneq" => [0x0228A, 0x0FE00],
+ "varsubsetneqq" => [0x02ACB, 0x0FE00],
+ "varsupsetneq" => [0x0228B, 0x0FE00],
+ "varsupsetneqq" => [0x02ACC, 0x0FE00],
+ "vartheta" => [0x003D1],
+ "vartriangleleft" => [0x022B2],
+ "vartriangleright" => [0x022B3],
+ "vcy" => [0x00432],
+ "vdash" => [0x022A2],
+ "vee" => [0x02228],
+ "veebar" => [0x022BB],
+ "veeeq" => [0x0225A],
+ "vellip" => [0x022EE],
+ "verbar" => [0x0007C],
+ "vert" => [0x0007C],
+ "vfr" => [0x1D533],
+ "vltri" => [0x022B2],
+ "vnsub" => [0x02282, 0x020D2],
+ "vnsup" => [0x02283, 0x020D2],
+ "vopf" => [0x1D567],
+ "vprop" => [0x0221D],
+ "vrtri" => [0x022B3],
+ "vscr" => [0x1D4CB],
+ "vsubnE" => [0x02ACB, 0x0FE00],
+ "vsubne" => [0x0228A, 0x0FE00],
+ "vsupnE" => [0x02ACC, 0x0FE00],
+ "vsupne" => [0x0228B, 0x0FE00],
+ "vzigzag" => [0x0299A],
+ "wcirc" => [0x00175],
+ "wedbar" => [0x02A5F],
+ "wedge" => [0x02227],
+ "wedgeq" => [0x02259],
+ "weierp" => [0x02118],
+ "wfr" => [0x1D534],
+ "wopf" => [0x1D568],
+ "wp" => [0x02118],
+ "wr" => [0x02240],
+ "wreath" => [0x02240],
+ "wscr" => [0x1D4CC],
+ "xcap" => [0x022C2],
+ "xcirc" => [0x025EF],
+ "xcup" => [0x022C3],
+ "xdtri" => [0x025BD],
+ "xfr" => [0x1D535],
+ "xhArr" => [0x027FA],
+ "xharr" => [0x027F7],
+ "xi" => [0x003BE],
+ "xlArr" => [0x027F8],
+ "xlarr" => [0x027F5],
+ "xmap" => [0x027FC],
+ "xnis" => [0x022FB],
+ "xodot" => [0x02A00],
+ "xopf" => [0x1D569],
+ "xoplus" => [0x02A01],
+ "xotime" => [0x02A02],
+ "xrArr" => [0x027F9],
+ "xrarr" => [0x027F6],
+ "xscr" => [0x1D4CD],
+ "xsqcup" => [0x02A06],
+ "xuplus" => [0x02A04],
+ "xutri" => [0x025B3],
+ "xvee" => [0x022C1],
+ "xwedge" => [0x022C0],
+ "yacute" => [0x000FD],
+ "yacy" => [0x0044F],
+ "ycirc" => [0x00177],
+ "ycy" => [0x0044B],
+ "yen" => [0x000A5],
+ "yfr" => [0x1D536],
+ "yicy" => [0x00457],
+ "yopf" => [0x1D56A],
+ "yscr" => [0x1D4CE],
+ "yucy" => [0x0044E],
+ "yuml" => [0x000FF],
+ "zacute" => [0x0017A],
+ "zcaron" => [0x0017E],
+ "zcy" => [0x00437],
+ "zdot" => [0x0017C],
+ "zeetrf" => [0x02128],
+ "zeta" => [0x003B6],
+ "zfr" => [0x1D537],
+ "zhcy" => [0x00436],
+ "zigrarr" => [0x021DD],
+ "zopf" => [0x1D56B],
+ "zscr" => [0x1D4CF],
+ "zwj" => [0x0200D],
+ "zwnj" => [0x0200C],
+}
+
diff --git a/lib/rdoc/markdown/literals_1_9.rb b/lib/rdoc/markdown/literals_1_9.rb
new file mode 100644
index 0000000000..01d00e41f6
--- /dev/null
+++ b/lib/rdoc/markdown/literals_1_9.rb
@@ -0,0 +1,417 @@
+# coding: UTF-8
+# :markup: markdown
+
+##
+#--
+# This set of literals is for ruby 1.9 regular expressions and gives full
+# unicode support.
+#
+# Unlike peg-markdown, this set of literals recognizes Unicode alphanumeric
+# characters, newlines and spaces.
+class RDoc::Markdown::Literals
+ # :stopdoc:
+
+ # This is distinct from setup_parser so that a standalone parser
+ # can redefine #initialize and still have access to the proper
+ # parser setup code.
+ def initialize(str, debug=false)
+ setup_parser(str, debug)
+ end
+
+
+
+ # Prepares for parsing +str+. If you define a custom initialize you must
+ # call this method before #parse
+ def setup_parser(str, debug=false)
+ @string = str
+ @pos = 0
+ @memoizations = Hash.new { |h,k| h[k] = {} }
+ @result = nil
+ @failed_rule = nil
+ @failing_rule_offset = -1
+
+ setup_foreign_grammar
+ end
+
+ attr_reader :string
+ attr_reader :failing_rule_offset
+ attr_accessor :result, :pos
+
+
+ def current_column(target=pos)
+ if c = string.rindex("\n", target-1)
+ return target - c - 1
+ end
+
+ target + 1
+ end
+
+ def current_line(target=pos)
+ cur_offset = 0
+ cur_line = 0
+
+ string.each_line do |line|
+ cur_line += 1
+ cur_offset += line.size
+ return cur_line if cur_offset >= target
+ end
+
+ -1
+ end
+
+ def lines
+ lines = []
+ string.each_line { |l| lines << l }
+ lines
+ end
+
+
+
+ def get_text(start)
+ @string[start..@pos-1]
+ end
+
+ def show_pos
+ width = 10
+ if @pos < width
+ "#{@pos} (\"#{@string[0,@pos]}\" @ \"#{@string[@pos,width]}\")"
+ else
+ "#{@pos} (\"... #{@string[@pos - width, width]}\" @ \"#{@string[@pos,width]}\")"
+ end
+ end
+
+ def failure_info
+ l = current_line @failing_rule_offset
+ c = current_column @failing_rule_offset
+
+ if @failed_rule.kind_of? Symbol
+ info = self.class::Rules[@failed_rule]
+ "line #{l}, column #{c}: failed rule '#{info.name}' = '#{info.rendered}'"
+ else
+ "line #{l}, column #{c}: failed rule '#{@failed_rule}'"
+ end
+ end
+
+ def failure_caret
+ l = current_line @failing_rule_offset
+ c = current_column @failing_rule_offset
+
+ line = lines[l-1]
+ "#{line}\n#{' ' * (c - 1)}^"
+ end
+
+ def failure_character
+ l = current_line @failing_rule_offset
+ c = current_column @failing_rule_offset
+ lines[l-1][c-1, 1]
+ end
+
+ def failure_oneline
+ l = current_line @failing_rule_offset
+ c = current_column @failing_rule_offset
+
+ char = lines[l-1][c-1, 1]
+
+ if @failed_rule.kind_of? Symbol
+ info = self.class::Rules[@failed_rule]
+ "@#{l}:#{c} failed rule '#{info.name}', got '#{char}'"
+ else
+ "@#{l}:#{c} failed rule '#{@failed_rule}', got '#{char}'"
+ end
+ end
+
+ class ParseError < RuntimeError
+ end
+
+ def raise_error
+ raise ParseError, failure_oneline
+ end
+
+ def show_error(io=STDOUT)
+ error_pos = @failing_rule_offset
+ line_no = current_line(error_pos)
+ col_no = current_column(error_pos)
+
+ io.puts "On line #{line_no}, column #{col_no}:"
+
+ if @failed_rule.kind_of? Symbol
+ info = self.class::Rules[@failed_rule]
+ io.puts "Failed to match '#{info.rendered}' (rule '#{info.name}')"
+ else
+ io.puts "Failed to match rule '#{@failed_rule}'"
+ end
+
+ io.puts "Got: #{string[error_pos,1].inspect}"
+ line = lines[line_no-1]
+ io.puts "=> #{line}"
+ io.print(" " * (col_no + 3))
+ io.puts "^"
+ end
+
+ def set_failed_rule(name)
+ if @pos > @failing_rule_offset
+ @failed_rule = name
+ @failing_rule_offset = @pos
+ end
+ end
+
+ attr_reader :failed_rule
+
+ def match_string(str)
+ len = str.size
+ if @string[pos,len] == str
+ @pos += len
+ return str
+ end
+
+ return nil
+ end
+
+ def scan(reg)
+ if m = reg.match(@string[@pos..-1])
+ width = m.end(0)
+ @pos += width
+ return true
+ end
+
+ return nil
+ end
+
+ if "".respond_to? :getbyte
+ def get_byte
+ if @pos >= @string.size
+ return nil
+ end
+
+ s = @string.getbyte @pos
+ @pos += 1
+ s
+ end
+ else
+ def get_byte
+ if @pos >= @string.size
+ return nil
+ end
+
+ s = @string[@pos]
+ @pos += 1
+ s
+ end
+ end
+
+ def parse(rule=nil)
+ # We invoke the rules indirectly via apply
+ # instead of by just calling them as methods because
+ # if the rules use left recursion, apply needs to
+ # manage that.
+
+ if !rule
+ apply(:_root)
+ else
+ method = rule.gsub("-","_hyphen_")
+ apply :"_#{method}"
+ end
+ end
+
+ class MemoEntry
+ def initialize(ans, pos)
+ @ans = ans
+ @pos = pos
+ @result = nil
+ @set = false
+ @left_rec = false
+ end
+
+ attr_reader :ans, :pos, :result, :set
+ attr_accessor :left_rec
+
+ def move!(ans, pos, result)
+ @ans = ans
+ @pos = pos
+ @result = result
+ @set = true
+ @left_rec = false
+ end
+ end
+
+ def external_invoke(other, rule, *args)
+ old_pos = @pos
+ old_string = @string
+
+ @pos = other.pos
+ @string = other.string
+
+ begin
+ if val = __send__(rule, *args)
+ other.pos = @pos
+ other.result = @result
+ else
+ other.set_failed_rule "#{self.class}##{rule}"
+ end
+ val
+ ensure
+ @pos = old_pos
+ @string = old_string
+ end
+ end
+
+ def apply_with_args(rule, *args)
+ memo_key = [rule, args]
+ if m = @memoizations[memo_key][@pos]
+ @pos = m.pos
+ if !m.set
+ m.left_rec = true
+ return nil
+ end
+
+ @result = m.result
+
+ return m.ans
+ else
+ m = MemoEntry.new(nil, @pos)
+ @memoizations[memo_key][@pos] = m
+ start_pos = @pos
+
+ ans = __send__ rule, *args
+
+ lr = m.left_rec
+
+ m.move! ans, @pos, @result
+
+ # Don't bother trying to grow the left recursion
+ # if it's failing straight away (thus there is no seed)
+ if ans and lr
+ return grow_lr(rule, args, start_pos, m)
+ else
+ return ans
+ end
+
+ return ans
+ end
+ end
+
+ def apply(rule)
+ if m = @memoizations[rule][@pos]
+ @pos = m.pos
+ if !m.set
+ m.left_rec = true
+ return nil
+ end
+
+ @result = m.result
+
+ return m.ans
+ else
+ m = MemoEntry.new(nil, @pos)
+ @memoizations[rule][@pos] = m
+ start_pos = @pos
+
+ ans = __send__ rule
+
+ lr = m.left_rec
+
+ m.move! ans, @pos, @result
+
+ # Don't bother trying to grow the left recursion
+ # if it's failing straight away (thus there is no seed)
+ if ans and lr
+ return grow_lr(rule, nil, start_pos, m)
+ else
+ return ans
+ end
+
+ return ans
+ end
+ end
+
+ def grow_lr(rule, args, start_pos, m)
+ while true
+ @pos = start_pos
+ @result = m.result
+
+ if args
+ ans = __send__ rule, *args
+ else
+ ans = __send__ rule
+ end
+ return nil unless ans
+
+ break if @pos <= m.pos
+
+ m.move! ans, @pos, @result
+ end
+
+ @result = m.result
+ @pos = m.pos
+ return m.ans
+ end
+
+ class RuleInfo
+ def initialize(name, rendered)
+ @name = name
+ @rendered = rendered
+ end
+
+ attr_reader :name, :rendered
+ end
+
+ def self.rule_info(name, rendered)
+ RuleInfo.new(name, rendered)
+ end
+
+
+ # :startdoc:
+ # :stopdoc:
+ def setup_foreign_grammar; end
+
+ # Alphanumeric = /\p{Word}/
+ def _Alphanumeric
+ _tmp = scan(/\A(?-mix:\p{Word})/)
+ set_failed_rule :_Alphanumeric unless _tmp
+ return _tmp
+ end
+
+ # AlphanumericAscii = /[A-Za-z0-9]/
+ def _AlphanumericAscii
+ _tmp = scan(/\A(?-mix:[A-Za-z0-9])/)
+ set_failed_rule :_AlphanumericAscii unless _tmp
+ return _tmp
+ end
+
+ # BOM = "uFEFF"
+ def _BOM
+ _tmp = match_string("uFEFF")
+ set_failed_rule :_BOM unless _tmp
+ return _tmp
+ end
+
+ # Newline = /\n|\r\n?|\p{Zl}|\p{Zp}/
+ def _Newline
+ _tmp = scan(/\A(?-mix:\n|\r\n?|\p{Zl}|\p{Zp})/)
+ set_failed_rule :_Newline unless _tmp
+ return _tmp
+ end
+
+ # NonAlphanumeric = /\p{^Word}/
+ def _NonAlphanumeric
+ _tmp = scan(/\A(?-mix:\p{^Word})/)
+ set_failed_rule :_NonAlphanumeric unless _tmp
+ return _tmp
+ end
+
+ # Spacechar = /\t|\p{Zs}/
+ def _Spacechar
+ _tmp = scan(/\A(?-mix:\t|\p{Zs})/)
+ set_failed_rule :_Spacechar unless _tmp
+ return _tmp
+ end
+
+ Rules = {}
+ Rules[:_Alphanumeric] = rule_info("Alphanumeric", "/\\p{Word}/")
+ Rules[:_AlphanumericAscii] = rule_info("AlphanumericAscii", "/[A-Za-z0-9]/")
+ Rules[:_BOM] = rule_info("BOM", "\"uFEFF\"")
+ Rules[:_Newline] = rule_info("Newline", "/\\n|\\r\\n?|\\p{Zl}|\\p{Zp}/")
+ Rules[:_NonAlphanumeric] = rule_info("NonAlphanumeric", "/\\p{^Word}/")
+ Rules[:_Spacechar] = rule_info("Spacechar", "/\\t|\\p{Zs}/")
+ # :startdoc:
+end
diff --git a/lib/rdoc/markup.rb b/lib/rdoc/markup.rb
index 07fd5493c8..bdd2064d6f 100644
--- a/lib/rdoc/markup.rb
+++ b/lib/rdoc/markup.rb
@@ -1,5 +1,3 @@
-require 'rdoc'
-
##
# RDoc::Markup parses plain text documents and attempts to decompose them into
# their constituent parts. Some of these parts are high-level: paragraphs,
@@ -8,11 +6,44 @@ require 'rdoc'
# is similar in spirit to that used on WikiWiki webs, where folks create web
# pages using a simple set of formatting rules.
#
-# RDoc::Markup itself does no output formatting: this is left to a different
-# set of classes.
+# RDoc::Markup and other markup formats do no output formatting, this is
+# handled by the RDoc::Markup::Formatter subclasses.
+#
+# = Supported Formats
+#
+# Besides the RDoc::Markup format, the following formats are built in to RDoc:
+#
+# markdown::
+# The markdown format as described by
+# http://daringfireball.net/projects/markdown/. See RDoc::Markdown for
+# details on the parser and supported extensions.
+# rd::
+# The rdtool format. See RDoc::RD for details on the parser and format.
+# tomdoc::
+# The TomDoc format as described by http://tomdoc.org/. See RDoc::TomDoc
+# for details on the parser and supported extensions.
+#
+# You can choose a markup format using the following methods:
+#
+# per project::
+# If you build your documentation with rake use RDoc::Task#markup.
+#
+# If you build your documentation by hand run:
#
-# RDoc::Markup is extendable at runtime: you can add \new markup elements to
-# be recognised in the documents that RDoc::Markup parses.
+# rdoc --markup your_favorite_format --write-options
+#
+# and commit <tt>.rdoc_options</tt> and ship it with your packaged gem.
+# per file::
+# At the top of the file use the <tt>:markup:</tt> directive to set the
+# default format for the rest of the file.
+# per comment::
+# Use the <tt>:markup:</tt> directive at the top of a comment you want
+# to write in a different format.
+#
+# = RDoc::Markup
+#
+# RDoc::Markup is extensible at runtime: you can add \new markup elements to
+# be recognized in the documents that RDoc::Markup parses.
#
# RDoc::Markup is intended to be the basis for a family of tools which share
# the common requirement that simple, plain-text should be rendered in a
@@ -26,21 +57,20 @@ require 'rdoc'
# the +convert+ method, so you can use the same RDoc::Markup converter to
# convert multiple input strings.
#
-# require 'rdoc/markup/to_html'
+# require 'rdoc'
#
# h = RDoc::Markup::ToHtml.new
#
# puts h.convert(input_string)
#
-# You can extend the RDoc::Markup parser to recognise new markup
+# You can extend the RDoc::Markup parser to recognize new markup
# sequences, and to add special processing for text that matches a
# regular expression. Here we make WikiWords significant to the parser,
# and also make the sequences {word} and \<no>text...</no> signify
# strike-through text. We then subclass the HTML output class to deal
# with these:
#
-# require 'rdoc/markup'
-# require 'rdoc/markup/to_html'
+# require 'rdoc'
#
# class WikiHtml < RDoc::Markup::ToHtml
# def handle_special_WIKIWORD(special)
@@ -96,7 +126,12 @@ require 'rdoc'
# have been removed. In addition, the verbatim text has been shifted
# left, so the amount of indentation of verbatim text is unimportant.
#
-# === Headers and Rules
+# For HTML output RDoc makes a small effort to determine if a verbatim section
+# contains ruby source code. If so, the verbatim block will be marked up as
+# HTML. Triggers include "def", "class", "module", "require", the "hash
+# rocket"# (=>) or a block call with a parameter.
+#
+# === Headers
#
# A line starting with an equal sign (=) is treated as a
# heading. Level one headings have one equals sign, level two headings
@@ -104,7 +139,36 @@ require 'rdoc'
# (seven hyphens or more result in a level six heading).
#
# For example, the above header was obtained with:
-# == Headers and Rules
+#
+# === Headers
+#
+# In HTML output headers have an id matching their name. The above example's
+# HTML is:
+#
+# <h3 id="label-Headers">Headers</h3>
+#
+# If a heading is inside a method body the id will be prefixed with the
+# method's id. If the above header where in the documentation for a method
+# such as:
+#
+# ##
+# # This method does fun things
+# #
+# # = Example
+# #
+# # Example of fun things goes here ...
+#
+# def do_fun_things
+# end
+#
+# The header's id would be:
+#
+# <h1 id="method-i-do_fun_things-label-Example">Example</h3>
+#
+# The label can be linked-to using <tt>SomeClass@Headers</tt>. See
+# {Links}[RDoc::Markup@Links] for further details.
+#
+# === Rules
#
# A line starting with three or more hyphens (at the current indent)
# generates a horizontal rule. The more hyphens, the thicker the rule
@@ -240,7 +304,6 @@ require 'rdoc'
# verbatim text outside of the list (the list is therefore closed)
# regular paragraph after the list
#
-#
# == Text Markup
#
# === Bold, Italic, Typewriter Text
@@ -272,15 +335,26 @@ require 'rdoc'
# === Links
#
# Links to starting with +http:+, +https:+, +mailto:+, +ftp:+ or +www.+
-# are recognized. An HTTP url that references an external image file is
-# converted into an inline image element.
-#
-# Links starting with <tt>rdoc-ref:</tt> will link to the referenced class,
-# module, method, file, etc. If the referenced item is not documented the
-# text will be and no link will be generated.
-#
-# Links starting with +link:+ refer to local files whose path is relative to
-# the <tt>--op</tt> directory.
+# are recognized. An HTTP url that references an external image is converted
+# into an inline image element.
+#
+# Classes and methods will be automatically linked to their definition. For
+# example, <tt>RDoc::Markup</tt> will link to this documentation. By default
+# methods will only be automatically linked if they contain an <tt>_</tt> (all
+# methods can be automatically linked through the <tt>--hyperlink-all</tt>
+# command line option).
+#
+# Single-word methods can be linked by using the <tt>#</tt> character for
+# instance methods or <tt>::</tt> for class methods. For example,
+# <tt>#convert</tt> links to #convert. A class or method may be combined like
+# <tt>RDoc::Markup#convert</tt>.
+#
+# A heading inside the documentation can be linked by following the class
+# or method by an <tt>@</tt> then the heading name.
+# <tt>RDoc::Markup@Links</tt> will link to this section like this:
+# RDoc::Markup@Links. Spaces in headings with multiple words must be escaped
+# with <tt>+</tt> like <tt>RDoc::Markup@Escaping+Text+Markup</tt>.
+# Punctuation and other special characters must be escaped like CGI.escape.
#
# Links can also be of the form <tt>label[url]</tt>, in which case +label+ is
# used in the displayed text, and +url+ is used as the target. If +label+
@@ -293,6 +367,11 @@ require 'rdoc'
# no link will be generated and <tt>rdoc-ref:</tt> will be removed from the
# resulting text.
#
+# Links starting with <tt>rdoc-label:label_name</tt> will link to the
+# +label_name+. You can create a label for the current link (for
+# bidirectional links) by supplying a name for the current link like
+# <tt>rdoc-label:label-other:label-mine</tt>.
+#
# Links starting with +link:+ refer to local files whose path is relative to
# the <tt>--op</tt> directory. Use <tt>rdoc-ref:</tt> instead of
# <tt>link:</tt> to link to files generated by RDoc as the link target may
@@ -492,27 +571,54 @@ require 'rdoc'
# so you won't see the documentation unless you use the +-a+ command line
# option.
#
-# === Other directives
+# === Method arguments
#
-# [+:include:+ _filename_]
-# Include the contents of the named file at this point. This directive
-# must appear alone on one line, possibly preceded by spaces. In this
-# position, it can be escaped with a \ in front of the first colon.
+# [+:arg:+ or +:args:+ _parameters_]
+# Overrides the default argument handling with exactly these parameters.
#
-# 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.
+# ##
+# # :args: a, b
#
-# [+:title:+ _text_]
-# Sets the title for the document. Equivalent to the <tt>--title</tt>
-# command line parameter. (The command line parameter overrides any :title:
-# directive in the source).
+# def some_method(*a)
+# end
#
-# [+:main:+ _name_]
-# Equivalent to the <tt>--main</tt> command line parameter.
+# [+:yield:+ or +:yields:+ _parameters_]
+# Overrides the default yield discovery with these parameters.
+#
+# ##
+# # :yields: key, value
+#
+# def each_thing &block
+# @things.each(&block)
+# end
+#
+# [+:call-seq:+]
+# Lines up to the next blank line or lines with a common prefix in the
+# comment are treated as the method's calling sequence, overriding the
+# default parsing of method parameters and yield arguments.
+#
+# Multiple lines may be used.
+#
+# # :call-seq:
+# # ARGF.readlines(sep=$/) -> array
+# # ARGF.readlines(limit) -> array
+# # ARGF.readlines(sep, limit) -> array
+# #
+# # ARGF.to_a(sep=$/) -> array
+# # ARGF.to_a(limit) -> array
+# # ARGF.to_a(sep, limit) -> array
+# #
+# # The remaining lines are documentation ...
+#
+# === Sections
#
-# [<tt>:category: section</tt>]
+# Sections allow you to group methods in a class into sensible containers. If
+# you use the sections 'Public', 'Internal' and 'Deprecated' (the three
+# allowed method statuses from TomDoc) the sections will be displayed in that
+# order placing the most useful methods at the top. Otherwise, sections will
+# be displayed in alphabetical order.
+#
+# [+:category:+ _section_]
# Adds this item to the named +section+ overriding the current section. Use
# this to group methods by section in RDoc output while maintaining a
# sensible ordering (like alphabetical).
@@ -541,7 +647,7 @@ require 'rdoc'
# Use the :section: directive to provide introductory text for a section of
# documentation.
#
-# [<tt>:section: title</tt>]
+# [+:section:+ _title_]
# Provides section introductory text in RDoc output. The title following
# +:section:+ is used as the section name and the remainder of the comment
# containing the section is used as introductory text. A section's comment
@@ -573,12 +679,60 @@ require 'rdoc'
# # ...
# end
#
-# [+: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.
+# === Other directives
+#
+# [+:markup:+ _type_]
+# Overrides the default markup type for this comment with the specified
+# markup type. For ruby files, if the first comment contains this directive
+# it is applied automatically to all comments in the file.
+#
+# Unless you are converting between markup formats you should use a
+# <code>.rdoc_options</code> file to specify the default documentation
+# format for your entire project. See RDoc::Options@Saved+Options for
+# instructions.
+#
+# At the top of a file the +:markup:+ directive applies to the entire file:
+#
+# # coding: UTF-8
+# # :markup: TomDoc
+#
+# # TomDoc comment here ...
+#
+# class MyClass
+# # ...
+#
+# For just one comment:
+#
+# # ...
+# end
+#
+# # :markup: RDoc
+# #
+# # This is a comment in RDoc markup format ...
+#
+# def some_method
+# # ...
+#
+# See Markup@DEVELOPERS for instructions on adding a new markup format.
+#
+# [+:include:+ _filename_]
+# Include the contents of the named file at this point. This directive
+# must appear alone on one line, possibly preceded by spaces. In this
+# position, it can be escaped with a \ in front of the first colon.
+#
+# The file will be searched for in the directories listed by the +--include+
+# option, or in the current directory by default. The contents of the file
+# will be shifted to have the same indentation as the ':' at the start of
+# the +:include:+ directive.
+#
+# [+:title:+ _text_]
+# Sets the title for the document. Equivalent to the <tt>--title</tt>
+# command line parameter. (The command line parameter overrides any :title:
+# directive in the source).
+#
+# [+:main:+ _name_]
+# Equivalent to the <tt>--main</tt> command line parameter.
#
-# Further directives can be found in RDoc::Parser::Ruby and RDoc::Parser::C.
#--
# Original Author:: Dave Thomas, dave@pragmaticprogrammer.com
# License:: Ruby license
@@ -591,6 +745,34 @@ class RDoc::Markup
attr_reader :attribute_manager
##
+ # Parses +str+ into an RDoc::Markup::Document.
+
+ def self.parse str
+ RDoc::Markup::Parser.parse str
+ rescue RDoc::Markup::Parser::Error => e
+ $stderr.puts <<-EOF
+While parsing markup, RDoc encountered a #{e.class}:
+
+#{e}
+\tfrom #{e.backtrace.join "\n\tfrom "}
+
+---8<---
+#{text}
+---8<---
+
+RDoc #{RDoc::VERSION}
+
+Ruby #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL} #{RUBY_RELEASE_DATE}
+
+Please file a bug report with the above information at:
+
+https://github.com/rdoc/rdoc/issues
+
+ EOF
+ raise
+ end
+
+ ##
# Take a block of text and use various heuristics to determine its
# structure (paragraphs, lists, and so on). Invoke an event handler as we
# identify significant chunks.
@@ -644,9 +826,47 @@ class RDoc::Markup
document.accept formatter
end
-end
+ autoload :Parser, 'rdoc/markup/parser'
+ autoload :PreProcess, 'rdoc/markup/pre_process'
+
+ # Inline markup classes
+ autoload :AttrChanger, 'rdoc/markup/attr_changer'
+ autoload :AttrSpan, 'rdoc/markup/attr_span'
+ autoload :Attributes, 'rdoc/markup/attributes'
+ autoload :AttributeManager, 'rdoc/markup/attribute_manager'
+ autoload :Special, 'rdoc/markup/special'
+
+ # RDoc::Markup AST
+ autoload :BlankLine, 'rdoc/markup/blank_line'
+ autoload :BlockQuote, 'rdoc/markup/block_quote'
+ autoload :Document, 'rdoc/markup/document'
+ autoload :HardBreak, 'rdoc/markup/hard_break'
+ autoload :Heading, 'rdoc/markup/heading'
+ autoload :Include, 'rdoc/markup/include'
+ autoload :IndentedParagraph, 'rdoc/markup/indented_paragraph'
+ autoload :List, 'rdoc/markup/list'
+ autoload :ListItem, 'rdoc/markup/list_item'
+ autoload :Paragraph, 'rdoc/markup/paragraph'
+ autoload :Raw, 'rdoc/markup/raw'
+ autoload :Rule, 'rdoc/markup/rule'
+ autoload :Verbatim, 'rdoc/markup/verbatim'
-require 'rdoc/markup/parser'
-require 'rdoc/markup/attribute_manager'
-require 'rdoc/markup/inline'
+ # Formatters
+ autoload :Formatter, 'rdoc/markup/formatter'
+ autoload :FormatterTestCase, 'rdoc/markup/formatter_test_case'
+ autoload :TextFormatterTestCase, 'rdoc/markup/text_formatter_test_case'
+
+ 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 :ToHtmlSnippet, 'rdoc/markup/to_html_snippet'
+ autoload :ToLabel, 'rdoc/markup/to_label'
+ autoload :ToMarkdown, 'rdoc/markup/to_markdown'
+ autoload :ToRdoc, 'rdoc/markup/to_rdoc'
+ autoload :ToTableOfContents, 'rdoc/markup/to_table_of_contents'
+ autoload :ToTest, 'rdoc/markup/to_test'
+ autoload :ToTtOnly, 'rdoc/markup/to_tt_only'
+
+end
diff --git a/lib/rdoc/markup/attr_changer.rb b/lib/rdoc/markup/attr_changer.rb
new file mode 100644
index 0000000000..1772f18b2b
--- /dev/null
+++ b/lib/rdoc/markup/attr_changer.rb
@@ -0,0 +1,22 @@
+class RDoc::Markup
+
+ AttrChanger = Struct.new :turn_on, :turn_off # :nodoc:
+
+end
+
+##
+# 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 RDoc::Markup::AttrChanger
+
+ def to_s # :nodoc:
+ "Attr: +#{turn_on}/-#{turn_off}"
+ end
+
+ def inspect # :nodoc:
+ '+%d/-%d' % [turn_on, turn_off]
+ end
+
+end
+
diff --git a/lib/rdoc/markup/attr_span.rb b/lib/rdoc/markup/attr_span.rb
new file mode 100644
index 0000000000..b5c1b3b7b7
--- /dev/null
+++ b/lib/rdoc/markup/attr_span.rb
@@ -0,0 +1,29 @@
+##
+# An array of attributes which parallels the characters in a string.
+
+class RDoc::Markup::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
+
+ ##
+ # Accesses flags for character +n+
+
+ def [](n)
+ @attrs[n]
+ end
+
+end
+
diff --git a/lib/rdoc/markup/attribute_manager.rb b/lib/rdoc/markup/attribute_manager.rb
index d2402f1b1d..71d5e2b2cc 100644
--- a/lib/rdoc/markup/attribute_manager.rb
+++ b/lib/rdoc/markup/attribute_manager.rb
@@ -23,6 +23,11 @@ class RDoc::Markup::AttributeManager
PROTECT_ATTR = A_PROTECT.chr # :nodoc:
##
+ # The attributes enabled for this markup object.
+
+ attr_reader :attributes
+
+ ##
# 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
@@ -60,8 +65,9 @@ class RDoc::Markup::AttributeManager
@html_tags = {}
@matching_word_pairs = {}
@protectable = %w[<]
- @special = {}
+ @special = []
@word_pair_map = {}
+ @attributes = RDoc::Markup::Attributes.new
add_word_pair "*", "*", :BOLD
add_word_pair "_", "_", :EM
@@ -96,11 +102,11 @@ class RDoc::Markup::AttributeManager
def changed_attribute_by_name current_set, new_set
current = new = 0
current_set.each do |name|
- current |= RDoc::Markup::Attribute.bitmap_for(name)
+ current |= @attributes.bitmap_for(name)
end
new_set.each do |name|
- new |= RDoc::Markup::Attribute.bitmap_for(name)
+ new |= @attributes.bitmap_for(name)
end
change_attribute(current, new)
@@ -161,12 +167,15 @@ class RDoc::Markup::AttributeManager
##
# Converts special sequences to RDoc attributes
- def convert_specials(str, attrs)
+ def convert_specials str, attrs
unless @special.empty?
- @special.each do |regexp, attr|
+ @special.each do |regexp, attribute|
str.scan(regexp) do
- attrs.set_attrs($`.length, $&.length,
- attr | RDoc::Markup::Attribute::SPECIAL)
+ capture = $~.size == 1 ? 0 : 1
+
+ s, e = $~.offset capture
+
+ attrs.set_attrs s, e - s, attribute | @attributes.special
end
end
end
@@ -200,7 +209,7 @@ class RDoc::Markup::AttributeManager
raise ArgumentError, "Word flags may not start with '<'" if
start[0,1] == '<'
- bitmap = RDoc::Markup::Attribute.bitmap_for name
+ bitmap = @attributes.bitmap_for name
if start == stop then
@matching_word_pairs[start] = bitmap
@@ -220,7 +229,7 @@ class RDoc::Markup::AttributeManager
# am.add_html 'em', :EM
def add_html(tag, name)
- @html_tags[tag.downcase] = RDoc::Markup::Attribute.bitmap_for name
+ @html_tags[tag.downcase] = @attributes.bitmap_for name
end
##
@@ -229,14 +238,14 @@ class RDoc::Markup::AttributeManager
#
# @am.add_special(/((https?:)\S+\w)/, :HYPERLINK)
- def add_special(pattern, name)
- @special[pattern] = RDoc::Markup::Attribute.bitmap_for name
+ def add_special pattern, name
+ @special << [pattern, @attributes.bitmap_for(name)]
end
##
# Processes +str+ converting attributes, HTML and specials
- def flow(str)
+ def flow str
@str = str
mask_protected_sequences
@@ -303,9 +312,9 @@ class RDoc::Markup::AttributeManager
res << change_attribute(current_attr, new_attr)
current_attr = new_attr
- if (current_attr & RDoc::Markup::Attribute::SPECIAL) != 0 then
+ if (current_attr & @attributes.special) != 0 then
i += 1 while
- i < str_len and (@attrs[i] & RDoc::Markup::Attribute::SPECIAL) != 0
+ i < str_len and (@attrs[i] & @attributes.special) != 0
res << RDoc::Markup::Special.new(current_attr,
copy_string(start_pos, i))
diff --git a/lib/rdoc/markup/attributes.rb b/lib/rdoc/markup/attributes.rb
new file mode 100644
index 0000000000..3423f10ca7
--- /dev/null
+++ b/lib/rdoc/markup/attributes.rb
@@ -0,0 +1,70 @@
+##
+# We manage a set of attributes. Each attribute has a symbol name and a bit
+# value.
+
+class RDoc::Markup::Attributes
+
+ ##
+ # The special attribute type. See RDoc::Markup#add_special
+
+ attr_reader :special
+
+ ##
+ # Creates a new attributes set.
+
+ def initialize
+ @special = 1
+
+ @name_to_bitmap = [
+ [:_SPECIAL_, @special],
+ ]
+
+ @next_bitmap = @special << 1
+ end
+
+ ##
+ # Returns a unique bit for +name+
+
+ def bitmap_for name
+ bitmap = @name_to_bitmap.assoc name
+
+ unless bitmap then
+ bitmap = @next_bitmap
+ @next_bitmap <<= 1
+ @name_to_bitmap << [name, bitmap]
+ else
+ bitmap = bitmap.last
+ end
+
+ bitmap
+ end
+
+ ##
+ # Returns a string representation of +bitmap+
+
+ def as_string bitmap
+ return 'none' if bitmap.zero?
+ res = []
+
+ @name_to_bitmap.each do |name, bit|
+ res << name if (bitmap & bit) != 0
+ end
+
+ res.join ','
+ end
+
+ ##
+ # yields each attribute name in +bitmap+
+
+ def each_name_of bitmap
+ return enum_for __method__, bitmap unless block_given?
+
+ @name_to_bitmap.each do |name, bit|
+ next if bit == @special
+
+ yield name.to_s if (bitmap & bit) != 0
+ end
+ end
+
+end
+
diff --git a/lib/rdoc/markup/block_quote.rb b/lib/rdoc/markup/block_quote.rb
new file mode 100644
index 0000000000..552f0c4baa
--- /dev/null
+++ b/lib/rdoc/markup/block_quote.rb
@@ -0,0 +1,14 @@
+##
+# A quoted section which contains markup items.
+
+class RDoc::Markup::BlockQuote < RDoc::Markup::Raw
+
+ ##
+ # Calls #accept_block_quote on +visitor+
+
+ def accept visitor
+ visitor.accept_block_quote self
+ end
+
+end
+
diff --git a/lib/rdoc/markup/document.rb b/lib/rdoc/markup/document.rb
index 7077f357d3..198cef9ed9 100644
--- a/lib/rdoc/markup/document.rb
+++ b/lib/rdoc/markup/document.rb
@@ -3,11 +3,13 @@
class RDoc::Markup::Document
+ include Enumerable
+
##
# The file this document was created from. See also
# RDoc::ClassModule#add_comment
- attr_accessor :file
+ attr_reader :file
##
# The parts of the Document
@@ -19,7 +21,7 @@ class RDoc::Markup::Document
def initialize *parts
@parts = []
- @parts.push(*parts)
+ @parts.concat parts
@file = nil
end
@@ -31,7 +33,7 @@ class RDoc::Markup::Document
case part
when RDoc::Markup::Document then
unless part.empty? then
- parts.push(*part.parts)
+ parts.concat part.parts
parts << RDoc::Markup::BlankLine.new
end
when String then
@@ -68,6 +70,20 @@ class RDoc::Markup::Document
end
##
+ # Concatenates the given +parts+ onto the document
+
+ def concat parts
+ self.parts.concat parts
+ end
+
+ ##
+ # Enumerator for the parts of this document
+
+ def each &block
+ @parts.each(&block)
+ end
+
+ ##
# Does this document have no parts?
def empty?
@@ -75,6 +91,18 @@ class RDoc::Markup::Document
end
##
+ # The file this Document was created from.
+
+ def file= location
+ @file = case location
+ when RDoc::TopLevel then
+ location.absolute_name
+ else
+ location
+ end
+ end
+
+ ##
# When this is a collection of documents (#file is not set and this document
# contains only other documents as its direct children) #merge replaces
# documents in this class with documents from +other+ when the file matches
@@ -120,7 +148,16 @@ class RDoc::Markup::Document
# Appends +parts+ to the document
def push *parts
- self.parts.push(*parts)
+ self.parts.concat parts
+ end
+
+ ##
+ # Returns an Array of headings in the document.
+ #
+ # Require 'rdoc/markup/formatter' before calling this method.
+
+ def table_of_contents
+ accept RDoc::Markup::ToTableOfContents.to_toc
end
end
diff --git a/lib/rdoc/markup/formatter.rb b/lib/rdoc/markup/formatter.rb
index f42b3fc6ea..ac76db3536 100644
--- a/lib/rdoc/markup/formatter.rb
+++ b/lib/rdoc/markup/formatter.rb
@@ -1,9 +1,9 @@
-require 'rdoc/markup'
-
##
# Base class for RDoc markup formatters
#
-# Formatters use a visitor pattern to convert content into output.
+# Formatters are a visitor that converts an RDoc::Markup tree (from a comment)
+# into some kind of output. RDoc ships with formatters for converting back to
+# rdoc, ANSI text, HTML, a Table of Contents and other formats.
#
# If you'd like to write your own Formatter use
# RDoc::Markup::FormatterTestCase. If you're writing a text-output formatter
@@ -20,14 +20,21 @@ class RDoc::Markup::Formatter
##
# Creates a new Formatter
- def initialize markup = nil
+ def initialize options, markup = nil
+ @options = options
+
@markup = markup || RDoc::Markup.new
@am = @markup.attribute_manager
+ @am.add_special(/<br>/, :HARD_BREAK)
+
+ @attributes = @am.attributes
@attr_tags = []
@in_tt = 0
- @tt_bit = RDoc::Markup::Attribute.bitmap_for :TT
+ @tt_bit = @attributes.bitmap_for :TT
+
+ @hard_break = ''
end
##
@@ -44,7 +51,7 @@ class RDoc::Markup::Formatter
# tags for flexibility
def add_tag(name, start, stop)
- attr = RDoc::Markup::Attribute.bitmap_for name
+ attr = @attributes.bitmap_for name
@attr_tags << InlineTag.new(attr, start, stop)
end
@@ -58,7 +65,7 @@ class RDoc::Markup::Formatter
##
# Marks up +content+
- def convert(content)
+ def convert content
@markup.convert content, self
end
@@ -93,7 +100,7 @@ class RDoc::Markup::Formatter
handled = false
- RDoc::Markup::Attribute.each_name_of special.type do |name|
+ @attributes.each_name_of special.type do |name|
method_name = "handle_special_#{name}"
if respond_to? method_name then
@@ -102,7 +109,11 @@ class RDoc::Markup::Formatter
end
end
- raise "Unhandled special: #{special}" unless handled
+ unless handled then
+ special_name = @attributes.as_string special.type
+
+ raise RDoc::Error, "Unhandled special #{special_name}: #{special}"
+ end
special.text
end
@@ -115,6 +126,17 @@ class RDoc::Markup::Formatter
end
##
+ # Use ignore in your subclass to ignore the content of a node.
+ #
+ # ##
+ # # We don't support raw nodes in ToNoRaw
+ #
+ # alias accept_raw ignore
+
+ def ignore *node
+ end
+
+ ##
# Are we currently inside tt tags?
def in_tt?
@@ -160,10 +182,3 @@ class RDoc::Markup::Formatter
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
index c739f990b3..6616a75898 100644
--- a/lib/rdoc/markup/formatter_test_case.rb
+++ b/lib/rdoc/markup/formatter_test_case.rb
@@ -1,5 +1,4 @@
require 'minitest/unit'
-require 'rdoc/markup/formatter'
##
# Test case for creating new RDoc::Markup formatters. See
@@ -35,7 +34,7 @@ require 'rdoc/markup/formatter'
#
# end
-class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
+class RDoc::Markup::FormatterTestCase < RDoc::TestCase
##
# Call #setup when inheriting from this test case.
@@ -54,8 +53,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
def setup
super
- @m = RDoc::Markup.new
- @RM = RDoc::Markup
+ @options = RDoc::Options.new
+
+ @m = @RM.new
@bullet_list = @RM::List.new(:BULLET,
@RM::ListItem.new(nil, @RM::Paragraph.new('l1')),
@@ -86,7 +86,7 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
# Call to add the visitor tests to your test case
def self.add_visitor_tests
- self.class_eval do
+ class_eval do
##
# Calls start_accepting which needs to verify startup state
@@ -120,6 +120,16 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
end
##
+ # Calls accept_block_quote
+
+ def test_accept_block_quote
+ @to.start_accepting
+
+ @to.accept_block_quote block para 'quote'
+
+ accept_block_quote
+ end
+ ##
# Test case that calls <tt>@to.accept_document</tt>
def test_accept_document
@@ -234,6 +244,29 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
end
##
+ # Calls accept_paragraph_br with a RDoc::Markup::Paragraph containing
+ # a \<br>
+
+ def test_accept_paragraph_br
+ @to.start_accepting
+
+ @to.accept_paragraph para 'one<br>two'
+
+ accept_paragraph_br
+ end
+
+ ##
+ # Calls accept_paragraph with a Paragraph containing a hard break
+
+ def test_accept_paragraph_break
+ @to.start_accepting
+
+ @to.accept_paragraph para('hello', hard_break, 'world')
+
+ accept_paragraph_break
+ end
+
+ ##
# Calls accept_paragraph_i with a RDoc::Markup::Paragraph containing
# emphasized words
@@ -374,9 +407,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
# Calls accept_list_item_start_note_2
def test_accept_list_item_start_note_2
- list = @RM::List.new(:NOTE,
- @RM::ListItem.new('<tt>teletype</tt>',
- @RM::Paragraph.new('teletype description')))
+ list = list(:NOTE,
+ item('<tt>teletype</tt>',
+ para('teletype description')))
@to.start_accepting
@@ -388,6 +421,41 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
end
##
+ # Calls accept_list_item_start_note_multi_description
+
+ def test_accept_list_item_start_note_multi_description
+ list = list(:NOTE,
+ item(%w[label],
+ para('description one')),
+ item(nil, para('description two')))
+
+ @to.start_accepting
+
+ list.accept @to
+
+ @to.end_accepting
+
+ accept_list_item_start_note_multi_description
+ end
+
+ ##
+ # Calls accept_list_item_start_note_multi_label
+
+ def test_accept_list_item_start_note_multi_label
+ list = list(:NOTE,
+ item(%w[one two],
+ para('two headers')))
+
+ @to.start_accepting
+
+ list.accept @to
+
+ @to.end_accepting
+
+ accept_list_item_start_note_multi_label
+ end
+
+ ##
# Calls accept_list_item_start_number
def test_accept_list_item_start_number
@@ -635,7 +703,7 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
end
##
- # Calls accept_list_end_ulpha
+ # Calls accept_list_end_ualpha
def test_accept_list_end_ualpha
@to.start_accepting
@@ -670,28 +738,28 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
# Calls list_verbatim with a list containing a verbatim block
def test_list_verbatim # HACK overblown
- doc = @RM::Document.new(
- @RM::List.new(:BULLET,
- @RM::ListItem.new(nil,
- @RM::Paragraph.new('list', 'stuff'),
- @RM::BlankLine.new,
- @RM::Verbatim.new("* list\n",
- " with\n",
- "\n",
- " second\n",
- "\n",
- " 1. indented\n",
- " 2. numbered\n",
- "\n",
- " third\n",
- "\n",
- "* second\n"))))
+ doc =
+ doc(
+ list(:BULLET,
+ item(nil,
+ para('list stuff'),
+ blank_line,
+ verb("* list\n",
+ " with\n",
+ "\n",
+ " second\n",
+ "\n",
+ " 1. indented\n",
+ " 2. numbered\n",
+ "\n",
+ " third\n",
+ "\n",
+ "* second\n"))))
doc.accept @to
list_verbatim
end
-
end
end
diff --git a/lib/rdoc/markup/hard_break.rb b/lib/rdoc/markup/hard_break.rb
new file mode 100644
index 0000000000..8445ad26e7
--- /dev/null
+++ b/lib/rdoc/markup/hard_break.rb
@@ -0,0 +1,31 @@
+##
+# A hard-break in the middle of a paragraph.
+
+class RDoc::Markup::HardBreak
+
+ @instance = new
+
+ ##
+ # RDoc::Markup::HardBreak is a singleton
+
+ def self.new
+ @instance
+ end
+
+ ##
+ # Calls #accept_hard_break on +visitor+
+
+ def accept visitor
+ visitor.accept_hard_break self
+ end
+
+ def == other # :nodoc:
+ self.class === other
+ end
+
+ def pretty_print q # :nodoc:
+ q.text "[break]"
+ end
+
+end
+
diff --git a/lib/rdoc/markup/heading.rb b/lib/rdoc/markup/heading.rb
index 3bda77a1e1..b72c3e2b14 100644
--- a/lib/rdoc/markup/heading.rb
+++ b/lib/rdoc/markup/heading.rb
@@ -3,6 +3,35 @@
class RDoc::Markup::Heading < Struct.new :level, :text
+ @to_html = nil
+ @to_label = nil
+
+ ##
+ # A singleton RDoc::Markup::ToLabel formatter for headings.
+
+ def self.to_label
+ @to_label ||= RDoc::Markup::ToLabel.new
+ end
+
+ ##
+ # A singleton plain HTML formatter for headings. Used for creating labels
+ # for the Table of Contents
+
+ def self.to_html
+ return @to_html if @to_html
+
+ markup = RDoc::Markup.new
+ markup.add_special RDoc::CrossReference::CROSSREF_REGEXP, :CROSSREF
+
+ @to_html = RDoc::Markup::ToHtml.new nil
+
+ def @to_html.handle_special_CROSSREF special
+ special.text.sub(/^\\/, '')
+ end
+
+ @to_html
+ end
+
##
# Calls #accept_heading on +visitor+
@@ -10,6 +39,21 @@ class RDoc::Markup::Heading < Struct.new :level, :text
visitor.accept_heading self
end
+ ##
+ # An HTML-safe anchor reference for this header.
+
+ def aref
+ "label-#{self.class.to_label.convert text.dup}"
+ end
+
+ ##
+ # HTML markup of the text of this label without the surrounding header
+ # element.
+
+ def plain_html
+ self.class.to_html.to_html(text.dup)
+ end
+
def pretty_print q # :nodoc:
q.group 2, "[head: #{level} ", ']' do
q.pp text
diff --git a/lib/rdoc/markup/include.rb b/lib/rdoc/markup/include.rb
new file mode 100644
index 0000000000..a2e8903279
--- /dev/null
+++ b/lib/rdoc/markup/include.rb
@@ -0,0 +1,42 @@
+##
+# A file included at generation time. Objects of this class are created by
+# RDoc::RD for an extension-less include.
+#
+# This implementation in incomplete.
+
+class RDoc::Markup::Include
+
+ ##
+ # The filename to be included, without extension
+
+ attr_reader :file
+
+ ##
+ # Directories to search for #file
+
+ attr_reader :include_path
+
+ ##
+ # Creates a new include that will import +file+ from +include_path+
+
+ def initialize file, include_path
+ @file = file
+ @include_path = include_path
+ end
+
+ def == other # :nodoc:
+ self.class === other and
+ @file == other.file and @include_path == other.include_path
+ end
+
+ def pretty_print q # :nodoc:
+ q.group 2, '[incl ', ']' do
+ q.text file
+ q.breakable
+ q.text 'from '
+ q.pp include_path
+ end
+ end
+
+end
+
diff --git a/lib/rdoc/markup/indented_paragraph.rb b/lib/rdoc/markup/indented_paragraph.rb
index d995c7d8ed..1b8a8c725d 100644
--- a/lib/rdoc/markup/indented_paragraph.rb
+++ b/lib/rdoc/markup/indented_paragraph.rb
@@ -29,5 +29,19 @@ class RDoc::Markup::IndentedParagraph < RDoc::Markup::Raw
visitor.accept_indented_paragraph self
end
+ ##
+ # Joins the raw paragraph text and converts inline HardBreaks to the
+ # +hard_break+ text followed by the indent.
+
+ def text hard_break = nil
+ @parts.map do |part|
+ if RDoc::Markup::HardBreak === part then
+ '%1$s%3$*2$s' % [hard_break, @indent, ' '] if hard_break
+ else
+ part
+ end
+ end.join
+ end
+
end
diff --git a/lib/rdoc/markup/inline.rb b/lib/rdoc/markup/inline.rb
index cf598d1583..fb3ab5c74d 100644
--- a/lib/rdoc/markup/inline.rb
+++ b/lib/rdoc/markup/inline.rb
@@ -1,144 +1 @@
-require 'rdoc'
-class RDoc::Markup
-
- ##
- # We manage a set of attributes. Each attribute has a symbol name and a bit
- # value.
-
- class Attribute
-
- ##
- # Special attribute type. See RDoc::Markup#add_special
-
- SPECIAL = 1
-
- @@name_to_bitmap = { :_SPECIAL_ => SPECIAL }
- @@next_bitmap = 2
-
- ##
- # Returns a unique bit for +name+
-
- def self.bitmap_for(name)
- bitmap = @@name_to_bitmap[name]
- unless bitmap then
- bitmap = @@next_bitmap
- @@next_bitmap <<= 1
- @@name_to_bitmap[name] = bitmap
- end
- bitmap
- end
-
- ##
- # Returns a string representation of +bitmap+
-
- def self.as_string(bitmap)
- return "none" if bitmap.zero?
- res = []
- @@name_to_bitmap.each do |name, bit|
- res << name if (bitmap & bit) != 0
- end
- res.join(",")
- end
-
- ##
- # yields each attribute name in +bitmap+
-
- def self.each_name_of(bitmap)
- @@name_to_bitmap.each do |name, bit|
- next if bit == SPECIAL
- yield name.to_s if (bitmap & bit) != 0
- end
- end
-
- end
-
- 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 # :nodoc:
- "Attr: +#{Attribute.as_string turn_on}/-#{Attribute.as_string turn_off}"
- end
-
- def inspect # :nodoc:
- "+%s/-%s" % [
- Attribute.as_string(turn_on),
- Attribute.as_string(turn_off),
- ]
- end
- end
-
- ##
- # 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
-
- ##
- # Accesses 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 # :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 # :nodoc:
- "Special: type=#{type}, name=#{RDoc::Markup::Attribute.as_string type}, text=#{text.dump}"
- end
-
- end
-
-end
-
+warn "requiring rdoc/markup/inline is deprecated and will be removed in RDoc 4." if $-w
diff --git a/lib/rdoc/markup/list.rb b/lib/rdoc/markup/list.rb
index 820b4c9645..86ed845634 100644
--- a/lib/rdoc/markup/list.rb
+++ b/lib/rdoc/markup/list.rb
@@ -1,5 +1,24 @@
##
-# A List of ListItems
+# A List is a homogeneous set of ListItems.
+#
+# The supported list types include:
+#
+# :BULLET::
+# An unordered list
+# :LABEL::
+# An unordered definition list, but using an alternate RDoc::Markup syntax
+# :LALPHA::
+# An ordered list using increasing lowercase English letters
+# :NOTE::
+# An unordered definition list
+# :NUMBER::
+# An ordered list using increasing Arabic numerals
+# :UALPHA::
+# An ordered list using increasing uppercase English letters
+#
+# Definition lists behave like HTML definition lists. Each list item can
+# describe multiple terms. See RDoc::Markup::ListItem for how labels and
+# definition are stored as list items.
class RDoc::Markup::List
@@ -14,12 +33,13 @@ class RDoc::Markup::List
attr_reader :items
##
- # Creates a new list of +type+ with +items+
+ # Creates a new list of +type+ with +items+. Valid list types are:
+ # +:BULLET+, +:LABEL+, +:LALPHA+, +:NOTE+, +:NUMBER+, +:UALPHA+
def initialize type = nil, *items
@type = type
@items = []
- @items.push(*items)
+ @items.concat items
end
##
@@ -74,7 +94,7 @@ class RDoc::Markup::List
# Appends +items+ to the list
def push *items
- @items.push(*items)
+ @items.concat items
end
end
diff --git a/lib/rdoc/markup/list_item.rb b/lib/rdoc/markup/list_item.rb
index d719c352ec..c5e59fe167 100644
--- a/lib/rdoc/markup/list_item.rb
+++ b/lib/rdoc/markup/list_item.rb
@@ -1,5 +1,12 @@
##
# An item within a List that contains paragraphs, headings, etc.
+#
+# For BULLET, NUMBER, LALPHA and UALPHA lists, the label will always be nil.
+# For NOTE and LABEL lists, the list label may contain:
+#
+# * a single String for a single label
+# * an Array of Strings for a list item with multiple terms
+# * nil for an extra description attached to a previously labeled list item
class RDoc::Markup::ListItem
@@ -19,7 +26,7 @@ class RDoc::Markup::ListItem
def initialize label = nil, *parts
@label = label
@parts = []
- @parts.push(*parts)
+ @parts.concat parts
end
##
@@ -64,8 +71,14 @@ class RDoc::Markup::ListItem
def pretty_print q # :nodoc:
q.group 2, '[item: ', ']' do
- if @label then
- q.text @label
+ case @label
+ when Array then
+ q.pp @label
+ q.text ';'
+ q.breakable
+ when String then
+ q.pp @label
+ q.text ';'
q.breakable
end
@@ -79,7 +92,7 @@ class RDoc::Markup::ListItem
# Adds +parts+ to the ListItem
def push *parts
- @parts.push(*parts)
+ @parts.concat parts
end
end
diff --git a/lib/rdoc/markup/paragraph.rb b/lib/rdoc/markup/paragraph.rb
index 808430d576..7180729f75 100644
--- a/lib/rdoc/markup/paragraph.rb
+++ b/lib/rdoc/markup/paragraph.rb
@@ -10,5 +10,19 @@ class RDoc::Markup::Paragraph < RDoc::Markup::Raw
visitor.accept_paragraph self
end
+ ##
+ # Joins the raw paragraph text and converts inline HardBreaks to the
+ # +hard_break+ text.
+
+ def text hard_break = ''
+ @parts.map do |part|
+ if RDoc::Markup::HardBreak === part then
+ hard_break
+ else
+ part
+ end
+ end.join
+ end
+
end
diff --git a/lib/rdoc/markup/parser.rb b/lib/rdoc/markup/parser.rb
index c18ce821fb..ca384d0639 100644
--- a/lib/rdoc/markup/parser.rb
+++ b/lib/rdoc/markup/parser.rb
@@ -1,5 +1,4 @@
require 'strscan'
-require 'rdoc/text'
##
# A recursive-descent parser for RDoc markup.
@@ -52,7 +51,9 @@ class RDoc::Markup::Parser
attr_reader :tokens
##
- # Parses +str+ into a Document
+ # Parses +str+ into a Document.
+ #
+ # Use RDoc::Markup#parse instead of this method.
def self.parse str
parser = new
@@ -74,12 +75,15 @@ class RDoc::Markup::Parser
# Creates a new Parser. See also ::parse
def initialize
- @tokens = []
- @current_token = nil
- @debug = false
-
- @line = 0
- @line_pos = 0
+ @binary_input = nil
+ @current_token = nil
+ @debug = false
+ @have_encoding = Object.const_defined? :Encoding
+ @input_encoding = nil
+ @line = 0
+ @line_pos = 0
+ @s = nil
+ @tokens = []
end
##
@@ -107,13 +111,13 @@ class RDoc::Markup::Parser
p :list_start => margin if @debug
list = RDoc::Markup::List.new
+ label = nil
until @tokens.empty? do
type, data, column, = get
case type
- when :BULLET, :LABEL, :LALPHA, :NOTE, :NUMBER, :UALPHA then
-
+ when *LIST_TOKENS then
if column < margin || (list.type && list.type != type) then
unget
break
@@ -124,6 +128,8 @@ class RDoc::Markup::Parser
case type
when :NOTE, :LABEL then
+ label = [] unless label
+
if peek_type == :NEWLINE then
# description not on the same line as LABEL/NOTE
# skip the trailing newline & any blank lines below
@@ -146,32 +152,35 @@ class RDoc::Markup::Parser
# In all cases, we have an empty description.
# In the last case only, we continue.
if peek_type.nil? || column < margin then
- empty = 1
+ empty = true
elsif column == margin then
case peek_type
when type
- empty = 2 # continue
+ empty = :continue
when *LIST_TOKENS
- empty = 1
+ empty = true
else
- empty = 0
+ empty = false
end
else
- empty = 0
+ empty = false
end
- if empty > 0 then
- item = RDoc::Markup::ListItem.new(data)
- item << RDoc::Markup::BlankLine.new
- list << item
- break if empty == 1
- next
+ if empty then
+ label << data
+ next if empty == :continue
+ break
end
end
else
data = nil
end
+ if label then
+ data = label << data
+ label = nil
+ end
+
list_item = RDoc::Markup::ListItem.new data
parse list_item, column
list << list_item
@@ -184,7 +193,13 @@ class RDoc::Markup::Parser
p :list_end => margin if @debug
- return nil if list.empty?
+ if list.empty? then
+ return nil unless label
+ return nil unless [:LABEL, :NOTE].include? list.type
+
+ list_item = RDoc::Markup::ListItem.new label, RDoc::Markup::BlankLine.new
+ list << list_item
+ end
list
end
@@ -200,15 +215,20 @@ class RDoc::Markup::Parser
until @tokens.empty? do
type, data, column, = get
- if type == :TEXT && column == margin then
+ if type == :TEXT and column == margin then
paragraph << data
- skip :NEWLINE
+
+ break if peek_token.first == :BREAK
+
+ data << ' ' if skip :NEWLINE
else
unget
break
end
end
+ paragraph.parts.last.sub!(/ \z/, '') # cleanup
+
p :paragraph_end => margin if @debug
paragraph
@@ -267,7 +287,7 @@ class RDoc::Markup::Parser
peek_column ||= column + width
indent = peek_column - column - width
line << ' ' * indent
- when :TEXT then
+ when :BREAK, :TEXT then
line << data
else # *LIST_TOKENS
list_marker = case type
@@ -298,6 +318,19 @@ class RDoc::Markup::Parser
end
##
+ # The character offset for the input string at the given +byte_offset+
+
+ def char_pos byte_offset
+ if @have_encoding then
+ matched = @binary_input[0, byte_offset]
+ matched.force_encoding @input_encoding
+ matched.length
+ else
+ byte_offset
+ end
+ end
+
+ ##
# Pulls the next token from the stream.
def get
@@ -321,7 +354,12 @@ class RDoc::Markup::Parser
until @tokens.empty? do
type, data, column, = get
- if type == :NEWLINE then
+ case type
+ when :BREAK then
+ parent << RDoc::Markup::BlankLine.new
+ skip :NEWLINE, false
+ next
+ when :NEWLINE then
# trailing newlines are skipped below, so this is a blank line
parent << RDoc::Markup::BlankLine.new
skip :NEWLINE, false
@@ -373,6 +411,21 @@ class RDoc::Markup::Parser
end
##
+ # Creates the StringScanner
+
+ def setup_scanner input
+ @line = 0
+ @line_pos = 0
+
+ if @have_encoding then
+ @input_encoding = input.encoding
+ @binary_input = input.dup.force_encoding Encoding::BINARY
+ end
+
+ @s = StringScanner.new input
+ end
+
+ ##
# Skips the next token if its type is +token_type+.
#
# Optionally raises an error if the next token is not of the expected type.
@@ -389,58 +442,55 @@ class RDoc::Markup::Parser
# Turns text +input+ into a stream of tokens
def tokenize input
- s = StringScanner.new input
+ setup_scanner input
- @line = 0
- @line_pos = 0
-
- until s.eos? do
- pos = s.pos
+ until @s.eos? do
+ pos = @s.pos
# leading spaces will be reflected by the column of the next token
# the only thing we loose are trailing spaces at the end of the file
- next if s.scan(/ +/)
+ next if @s.scan(/ +/)
# note: after BULLET, LABEL, etc.,
# indent will be the column of the next non-newline token
@tokens << case
# [CR]LF => :NEWLINE
- when s.scan(/\r?\n/) then
- token = [:NEWLINE, s.matched, *token_pos(pos)]
- @line_pos = s.pos
+ when @s.scan(/\r?\n/) then
+ token = [:NEWLINE, @s.matched, *token_pos(pos)]
+ @line_pos = char_pos @s.pos
@line += 1
token
# === text => :HEADER then :TEXT
- when s.scan(/(=+)(\s*)/) then
- level = s[1].length
+ when @s.scan(/(=+)(\s*)/) then
+ level = @s[1].length
header = [:HEADER, level, *token_pos(pos)]
- if s[2] =~ /^\r?\n/ then
- s.pos -= s[2].length
+ if @s[2] =~ /^\r?\n/ then
+ @s.pos -= @s[2].length
header
else
- pos = s.pos
- s.scan(/.*/)
+ pos = @s.pos
+ @s.scan(/.*/)
@tokens << header
- [:TEXT, s.matched.sub(/\r$/, ''), *token_pos(pos)]
+ [:TEXT, @s.matched.sub(/\r$/, ''), *token_pos(pos)]
end
# --- (at least 3) and nothing else on the line => :RULE
- when s.scan(/(-{3,}) *$/) then
- [:RULE, s[1].length - 2, *token_pos(pos)]
+ when @s.scan(/(-{3,}) *\r?$/) then
+ [:RULE, @s[1].length - 2, *token_pos(pos)]
# * or - followed by white space and text => :BULLET
- when s.scan(/([*-]) +(\S)/) then
- s.pos -= s[2].bytesize # unget \S
- [:BULLET, s[1], *token_pos(pos)]
+ when @s.scan(/([*-]) +(\S)/) then
+ @s.pos -= @s[2].bytesize # unget \S
+ [:BULLET, @s[1], *token_pos(pos)]
# A. text, a. text, 12. text => :UALPHA, :LALPHA, :NUMBER
- when s.scan(/([a-z]|\d+)\. +(\S)/i) then
+ when @s.scan(/([a-z]|\d+)\. +(\S)/i) then
# FIXME if tab(s), the column will be wrong
# either support tabs everywhere by first expanding them to
# spaces, or assume that they will have been replaced
# before (and provide a check for that at least in debug
# mode)
- list_label = s[1]
- s.pos -= s[2].bytesize # unget \S
+ list_label = @s[1]
+ @s.pos -= @s[2].bytesize # unget \S
list_type =
case list_label
when /[a-z]/ then :LALPHA
@@ -451,14 +501,21 @@ class RDoc::Markup::Parser
end
[list_type, list_label, *token_pos(pos)]
# [text] followed by spaces or end of line => :LABEL
- when s.scan(/\[(.*?)\]( +|$)/) then
- [:LABEL, s[1], *token_pos(pos)]
+ when @s.scan(/\[(.*?)\]( +|\r?$)/) then
+ [:LABEL, @s[1], *token_pos(pos)]
# text:: followed by spaces or end of line => :NOTE
- when s.scan(/(.*?)::( +|$)/) then
- [:NOTE, s[1], *token_pos(pos)]
+ when @s.scan(/(.*?)::( +|\r?$)/) then
+ [:NOTE, @s[1], *token_pos(pos)]
# anything else: :TEXT
- else s.scan(/.*/)
- [:TEXT, s.matched.sub(/\r$/, ''), *token_pos(pos)]
+ else @s.scan(/(.*?)( )?\r?$/)
+ token = [:TEXT, @s[1], *token_pos(pos)]
+
+ if @s[2] then
+ @tokens << token
+ [:BREAK, @s[2], *token_pos(pos + @s[1].length)]
+ else
+ token
+ end
end
end
@@ -466,9 +523,12 @@ class RDoc::Markup::Parser
end
##
- # Calculates the column and line of the current token based on +offset+.
+ # Calculates the column (by character) and line of the current token from
+ # +scanner+ based on +byte_offset+.
+
+ def token_pos byte_offset
+ offset = char_pos byte_offset
- def token_pos offset
[offset - @line_pos, @line]
end
@@ -484,14 +544,3 @@ class RDoc::Markup::Parser
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/raw'
-require 'rdoc/markup/paragraph'
-require 'rdoc/markup/indented_paragraph'
-require 'rdoc/markup/rule'
-require 'rdoc/markup/verbatim'
-
diff --git a/lib/rdoc/markup/pre_process.rb b/lib/rdoc/markup/pre_process.rb
index 53e8e38ec1..6024edcd27 100644
--- a/lib/rdoc/markup/pre_process.rb
+++ b/lib/rdoc/markup/pre_process.rb
@@ -1,6 +1,3 @@
-require 'rdoc/markup'
-require 'rdoc/encoding'
-
##
# Handle common directives that can occur in a block of text:
#
@@ -9,18 +6,48 @@ require 'rdoc/encoding'
# Directives can be escaped by preceding them with a backslash.
#
# RDoc plugin authors can register additional directives to be handled by
-# using RDoc::Markup::PreProcess::register
+# using RDoc::Markup::PreProcess::register.
+#
+# Any directive that is not built-in to RDoc (including those registered via
+# plugins) will be stored in the metadata hash on the CodeObject the comment
+# is attached to. See RDoc::Markup@Directives for the list of built-in
+# directives.
class RDoc::Markup::PreProcess
+ ##
+ # An RDoc::Options instance that will be filled in with overrides from
+ # directives
+
attr_accessor :options
- @registered = {}
+ ##
+ # Adds a post-process handler for directives. The handler will be called
+ # with the result RDoc::Comment (or text String) and the code object for the
+ # comment (if any).
+
+ def self.post_process &block
+ @post_processors << block
+ end
+
+ ##
+ # Registered post-processors
+
+ def self.post_processors
+ @post_processors
+ end
##
# Registers +directive+ as one handled by RDoc. If a block is given the
# directive will be replaced by the result of the block, otherwise the
# directive will be removed from the processed text.
+ #
+ # The block will be called with the directive name and the directive
+ # parameter:
+ #
+ # RDoc::Markup::PreProcess.register 'my-directive' do |directive, param|
+ # # replace text, etc.
+ # end
def self.register directive, &block
@registered[directive] = block
@@ -34,6 +61,16 @@ class RDoc::Markup::PreProcess
end
##
+ # Clears all registered directives and post-processors
+
+ def self.reset
+ @post_processors = []
+ @registered = {}
+ end
+
+ reset
+
+ ##
# Creates a new pre-processor for +input_file_name+ that will look for
# included files in +include_path+
@@ -44,7 +81,7 @@ class RDoc::Markup::PreProcess
end
##
- # Look for directives in a chunk of +text+.
+ # Look for directives in the given +text+.
#
# Options that we don't handle are yielded. If the block returns false the
# directive is restored to the text. If the block returns nil or no block
@@ -54,27 +91,56 @@ class RDoc::Markup::PreProcess
# If no matching directive was registered the directive is restored to the
# text.
#
- # If +code_object+ is given and the param is set as metadata on the
- # +code_object+. See RDoc::CodeObject#metadata
+ # If +code_object+ is given and the directive is unknown then the
+ # directive's parameter is set as metadata on the +code_object+. See
+ # RDoc::CodeObject#metadata for details.
def handle text, code_object = nil, &block
- encoding = if defined?(Encoding) then text.encoding else nil end
+ if RDoc::Comment === text then
+ comment = text
+ text = text.text
+ end
+
+ encoding = text.encoding if defined?(Encoding)
+
# regexp helper (square brackets for optional)
# $1 $2 $3 $4 $5
# [prefix][\]:directive:[spaces][param]newline
- text.gsub!(/^([ \t]*(?:#|\/?\*)?[ \t]*)(\\?):(\w+):([ \t]*)(.+)?\n/) do
+ text.gsub!(/^([ \t]*(?:#|\/?\*)?[ \t]*)(\\?):(\w+):([ \t]*)(.+)?(\r?\n|$)/) do
# skip something like ':toto::'
next $& if $4.empty? and $5 and $5[0, 1] == ':'
# skip if escaped
next "#$1:#$3:#$4#$5\n" unless $2.empty?
+ # This is not in handle_directive because I didn't want to pass another
+ # argument into it
+ if comment and $3 == 'markup' then
+ next "#{$1.strip}\n" unless $5
+ comment.format = $5.downcase
+ next "#{$1.strip}\n"
+ end
+
handle_directive $1, $3, $5, code_object, encoding, &block
end
+ comment = text unless comment
+
+ self.class.post_processors.each do |handler|
+ handler.call comment, code_object
+ end
+
text
end
+ ##
+ # Performs the actions described by +directive+ and its parameter +param+.
+ #
+ # +code_object+ is used for directives that operate on a class or module.
+ # +prefix+ is used to ensure the replacement for handled directives is
+ # correct. +encoding+ is used for the <tt>include</tt> directive.
+ #
+ # For a list of directives in RDoc see RDoc::Markup.
#--
# When 1.8.7 support is ditched prefix can be defaulted to ''
@@ -92,7 +158,7 @@ class RDoc::Markup::PreProcess
blankline
when 'category' then
if RDoc::Context === code_object then
- section = code_object.add_section param, ''
+ section = code_object.add_section param
code_object.temporary_section = section
end
diff --git a/lib/rdoc/markup/raw.rb b/lib/rdoc/markup/raw.rb
index ca877c79af..e11e8efff4 100644
--- a/lib/rdoc/markup/raw.rb
+++ b/lib/rdoc/markup/raw.rb
@@ -13,7 +13,7 @@ class RDoc::Markup::Raw
def initialize *parts
@parts = []
- @parts.push(*parts)
+ @parts.concat parts
end
##
@@ -24,7 +24,7 @@ class RDoc::Markup::Raw
end
def == other # :nodoc:
- self.class == other.class and text == other.text
+ self.class == other.class and @parts == other.parts
end
##
@@ -38,11 +38,11 @@ class RDoc::Markup::Raw
# Appends +other+'s parts
def merge other
- @parts.push(*other.parts)
+ @parts.concat other.parts
end
def pretty_print q # :nodoc:
- self.class.name =~ /.*::(\w{4})/i
+ self.class.name =~ /.*::(\w{1,4})/i
q.group 2, "[#{$1.downcase}: ", ']' do
q.seplist @parts do |part|
@@ -55,7 +55,7 @@ class RDoc::Markup::Raw
# Appends +texts+ onto this Paragraph
def push *texts
- self.parts.push(*texts)
+ self.parts.concat texts
end
##
diff --git a/lib/rdoc/markup/special.rb b/lib/rdoc/markup/special.rb
new file mode 100644
index 0000000000..1c0fc03eea
--- /dev/null
+++ b/lib/rdoc/markup/special.rb
@@ -0,0 +1,40 @@
+##
+# Hold details of a special sequence
+
+class RDoc::Markup::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 # :nodoc:
+ "#<RDoc::Markup::Special:0x%x @type=%p, @text=%p>" % [
+ object_id, @type, text.dump]
+ end
+
+ def to_s # :nodoc:
+ "Special: type=#{type} text=#{text.dump}"
+ end
+
+end
+
diff --git a/lib/rdoc/markup/text_formatter_test_case.rb b/lib/rdoc/markup/text_formatter_test_case.rb
index ba9e7c6187..4abf42563b 100644
--- a/lib/rdoc/markup/text_formatter_test_case.rb
+++ b/lib/rdoc/markup/text_formatter_test_case.rb
@@ -1,5 +1,3 @@
-require 'rdoc/markup/formatter_test_case'
-
##
# Test case for creating new plain-text RDoc::Markup formatters. See also
# RDoc::Markup::FormatterTestCase
diff --git a/lib/rdoc/markup/to_ansi.rb b/lib/rdoc/markup/to_ansi.rb
index 1e8a0289d9..4d439ce88d 100644
--- a/lib/rdoc/markup/to_ansi.rb
+++ b/lib/rdoc/markup/to_ansi.rb
@@ -1,5 +1,3 @@
-require 'rdoc/markup/to_rdoc'
-
##
# Outputs RDoc markup with vibrant ANSI color!
@@ -34,6 +32,11 @@ class RDoc::Markup::ToAnsi < RDoc::Markup::ToRdoc
when :BULLET then
2
when :NOTE, :LABEL then
+ if @prefix then
+ @res << @prefix.strip
+ @prefix = nil
+ end
+
@res << "\n" unless res.length == 1
2
else
@@ -53,7 +56,13 @@ class RDoc::Markup::ToAnsi < RDoc::Markup::ToRdoc
when :BULLET then
'*'
when :NOTE, :LABEL then
- attributes(list_item.label) + ":\n"
+ labels = Array(list_item.label).map do |label|
+ attributes(label).strip
+ end.join "\n"
+
+ labels << ":\n" unless labels.empty?
+
+ labels
else
@list_index.last.to_s + '.'
end
diff --git a/lib/rdoc/markup/to_bs.rb b/lib/rdoc/markup/to_bs.rb
index 32b1bbb9eb..10c31854d2 100644
--- a/lib/rdoc/markup/to_bs.rb
+++ b/lib/rdoc/markup/to_bs.rb
@@ -1,5 +1,3 @@
-require 'rdoc/markup/to_rdoc'
-
##
# Outputs RDoc markup with hot backspace action! You will probably need a
# pager to use this output format.
diff --git a/lib/rdoc/markup/to_html.rb b/lib/rdoc/markup/to_html.rb
index bd5fdb493e..9cd94a5945 100644
--- a/lib/rdoc/markup/to_html.rb
+++ b/lib/rdoc/markup/to_html.rb
@@ -1,10 +1,7 @@
-require 'rdoc/markup/formatter'
-require 'rdoc/markup/inline'
-
require 'cgi'
##
-# Outputs RDoc markup as HTML
+# Outputs RDoc markup as HTML.
class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
@@ -16,12 +13,12 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
# Maps RDoc::Markup::Parser::LIST_TOKENS types to HTML tags
LIST_TYPE_TO_HTML = {
- :BULLET => ['<ul>', '</ul>'],
- :LABEL => ['<dl class="rdoc-list">', '</dl>'],
- :LALPHA => ['<ol style="display: lower-alpha">', '</ol>'],
- :NOTE => ['<table class="rdoc-list">', '</table>'],
- :NUMBER => ['<ol>', '</ol>'],
- :UALPHA => ['<ol style="display: upper-alpha">', '</ol>'],
+ :BULLET => ['<ul>', '</ul>'],
+ :LABEL => ['<dl class="rdoc-list label-list">', '</dl>'],
+ :LALPHA => ['<ol style="list-style-type: lower-alpha">', '</ol>'],
+ :NOTE => ['<dl class="rdoc-list note-list">', '</dl>'],
+ :NUMBER => ['<ol>', '</ol>'],
+ :UALPHA => ['<ol style="list-style-type: upper-alpha">', '</ol>'],
}
attr_reader :res # :nodoc:
@@ -29,6 +26,12 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
attr_reader :list # :nodoc:
##
+ # The RDoc::CodeObject HTML is being generated for. This is used to
+ # generate namespaced URI fragments
+
+ attr_accessor :code_object
+
+ ##
# Path to this document for relative links
attr_accessor :from_path
@@ -62,19 +65,31 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
##
# Creates a new formatter that will output HTML
- def initialize markup = nil
+ def initialize options, markup = nil
super
- @th = nil
+ @code_object = nil
+ @from_path = ''
@in_list_entry = nil
@list = nil
- @from_path = ''
+ @th = nil
+ @hard_break = "<br>\n"
# external links
- @markup.add_special(/((link:|https?:|mailto:|ftp:|www\.)\S+\w)/, :HYPERLINK)
+ @markup.add_special(/(?:link:|https?:|mailto:|ftp:|irc:|www\.)\S+\w/,
+ :HYPERLINK)
+
+ # internal links
+ @markup.add_special(/rdoc-[a-z]+:\S+/, :RDOCLINK)
# and links of the form <text>[<url>]
- @markup.add_special(/(((\{.*?\})|\b\S+?)\[\S+?\])/, :TIDYLINK)
+ @markup.add_special(/(?:
+ \{.*?\} | # multi-word label
+ \b[^\s{}]+? # single-word label
+ )
+
+ \[\S+?\] # link target
+ /x, :TIDYLINK)
init_tags
end
@@ -84,6 +99,13 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
# These methods handle special markup added by RDoc::Markup#add_special.
##
+ # +special+ is a <code><br></code>
+
+ def handle_special_HARD_BREAK special
+ '<br>'
+ end
+
+ ##
# +special+ is a potential link. The following schemes are handled:
#
# <tt>mailto:</tt>::
@@ -102,6 +124,39 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
end
##
+ # +special+ is an rdoc-schemed link that will be converted into a hyperlink.
+ #
+ # For the +rdoc-ref+ scheme the named reference will be returned without
+ # creating a link.
+ #
+ # For the +rdoc-label+ scheme the footnote and label prefixes are stripped
+ # when creating a link. All other contents will be linked verbatim.
+
+ def handle_special_RDOCLINK special
+ url = special.text
+
+ case url
+ when /\Ardoc-ref:/
+ $'
+ when /\Ardoc-label:/
+ text = $'
+
+ text = case text
+ when /\Alabel-/ then $'
+ when /\Afootmark-/ then "^#{$'}"
+ when /\Afoottext-/ then "*#{$'}"
+ else text
+ end
+
+ gen_url url, text
+ else
+ url =~ /\Ardoc-[a-z]+:/
+
+ $'
+ end
+ end
+
+ ##
# This +special+ is a link where the label is different from the URL
# <tt>label[url]</tt> or <tt>{long label}[url]</tt>
@@ -136,21 +191,47 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
end
##
+ # Adds +block_quote+ to the output
+
+ def accept_block_quote block_quote
+ @res << "\n<blockquote>"
+
+ block_quote.parts.each do |part|
+ part.accept self
+ end
+
+ @res << "</blockquote>\n"
+ end
+
+ ##
# Adds +paragraph+ to the output
- def accept_paragraph(paragraph)
+ def accept_paragraph paragraph
@res << "\n<p>"
- @res << wrap(to_html(paragraph.text))
+ text = paragraph.text @hard_break
+ @res << wrap(to_html(text))
@res << "</p>\n"
end
##
# Adds +verbatim+ to the output
- def accept_verbatim(verbatim)
- @res << "\n<pre>"
- @res << CGI.escapeHTML(verbatim.text.rstrip)
- @res << "</pre>\n"
+ def accept_verbatim verbatim
+ text = verbatim.text.rstrip
+
+ @res << if verbatim.ruby? or parseable? text then
+ begin
+ tokens = RDoc::RubyLex.tokenize text, @options
+
+ html = RDoc::TokenStream.to_html tokens
+
+ "\n<pre class=\"ruby\">#{html}</pre>\n"
+ rescue RDoc::RubyLex::Error
+ "\n<pre>#{CGI.escapeHTML text}</pre>\n"
+ end
+ else
+ "\n<pre>#{CGI.escapeHTML text}</pre>\n"
+ end
end
##
@@ -208,12 +289,19 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
end
##
- # Adds +heading+ to the output
+ # Adds +heading+ to the output. The headings greater than 6 are trimmed to
+ # level 6.
+
+ def accept_heading heading
+ level = [6, heading.level].min
- def accept_heading(heading)
- @res << "\n<h#{heading.level}>"
+ label = heading.aref
+ label = [@code_object.aref, label].compact.join '-' if
+ @code_object and @code_object.respond_to? :aref
+
+ @res << "\n<h#{level} id=\"#{label}\">"
@res << to_html(heading.text)
- @res << "</h#{heading.level}>\n"
+ @res << "</h#{level}>\n"
end
##
@@ -226,18 +314,22 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
# :section: Utilities
##
- # CGI escapes +text+
+ # CGI-escapes +text+
def convert_string(text)
CGI.escapeHTML text
end
##
- # Generate a link for +url+, labeled with +text+. Handles the special cases
+ # Generate a link to +url+ with content +text+. Handles the special cases
# for img: and link: described under handle_special_HYPERLINK
- def gen_url(url, text)
- if url =~ /([A-Za-z]+):(.*)/ then
+ def gen_url url, text
+ if url =~ /^rdoc-label:([^:]*)(?::(.*))?/ then
+ type = "link"
+ path = "##{$1}"
+ id = " id=\"#{$2}\"" if $2
+ elsif url =~ /([A-Za-z]+):(.*)/ then
type = $1
path = $2
else
@@ -258,7 +350,7 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
url =~ /\.(gif|png|jpg|jpeg|bmp)$/ then
"<img src=\"#{url}\" />"
else
- "<a href=\"#{url}\">#{text.sub(%r{^#{type}:/*}, '')}</a>"
+ "<a#{id} href=\"#{url}\">#{text.sub(%r{^#{type}:/*}, '')}</a>"
end
end
@@ -275,9 +367,9 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
# Maps attributes to HTML tags
def init_tags
- add_tag :BOLD, "<b>", "</b>"
- add_tag :TT, "<tt>", "</tt>"
- add_tag :EM, "<em>", "</em>"
+ add_tag :BOLD, "<strong>", "</strong>"
+ add_tag :TT, "<code>", "</code>"
+ add_tag :EM, "<em>", "</em>"
end
##
@@ -288,10 +380,10 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
case list_type
when :BULLET, :LALPHA, :NUMBER, :UALPHA then
"<li>"
- when :LABEL then
- "<dt>#{to_html list_item.label}</dt>\n<dd>"
- when :NOTE then
- "<tr><td class=\"rdoc-term\"><p>#{to_html list_item.label}</p></td>\n<td>"
+ when :LABEL, :NOTE then
+ Array(list_item.label).map do |label|
+ "<dt>#{to_html label}\n"
+ end.join << "<dd>"
else
raise RDoc::Error, "Invalid list type: #{list_type.inspect}"
end
@@ -304,16 +396,22 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
case list_type
when :BULLET, :LALPHA, :NUMBER, :UALPHA then
"</li>"
- when :LABEL then
+ when :LABEL, :NOTE then
"</dd>"
- when :NOTE then
- "</td></tr>"
else
raise RDoc::Error, "Invalid list type: #{list_type.inspect}"
end
end
##
+ # Returns true if Ripper is available it can create a sexp from +text+
+
+ def parseable? text
+ text =~ /\b(def|class|module|require) |=>|\{\s?\||do \|/ and
+ text !~ /<%|%>/
+ end
+
+ ##
# Converts +item+ to HTML using RDoc::Text#to_html
def to_html item
diff --git a/lib/rdoc/markup/to_html_crossref.rb b/lib/rdoc/markup/to_html_crossref.rb
index 450ea960b5..405f68c14f 100644
--- a/lib/rdoc/markup/to_html_crossref.rb
+++ b/lib/rdoc/markup/to_html_crossref.rb
@@ -1,6 +1,3 @@
-require 'rdoc/markup/to_html'
-require 'rdoc/cross_reference'
-
##
# Subclass of the RDoc::Markup::ToHtml class that supports looking up method
# names, classes, etc to create links. RDoc::CrossReference is used to
@@ -31,21 +28,20 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
# references are removed unless +show_hash+ is true. Only method names
# preceded by '#' or '::' are linked, unless +hyperlink_all+ is true.
- def initialize(from_path, context, show_hash, hyperlink_all = false,
- markup = nil)
+ def initialize(options, from_path, context, markup = nil)
raise ArgumentError, 'from_path cannot be nil' if from_path.nil?
- super markup
- crossref_re = hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP
+ super options, markup
- @cross_reference = RDoc::CrossReference.new context
+ @context = context
+ @from_path = from_path
+ @hyperlink_all = @options.hyperlink_all
+ @show_hash = @options.show_hash
+ crossref_re = @hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP
@markup.add_special crossref_re, :CROSSREF
- @markup.add_special(/rdoc-ref:\S+\w/, :HYPERLINK)
- @from_path = from_path
- @hyperlink_all = hyperlink_all
- @show_hash = show_hash
+ @cross_reference = RDoc::CrossReference.new @context
end
##
@@ -57,6 +53,8 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
name = name[1..-1] unless @show_hash if name[0, 1] == '#'
+ name = "#{CGI.unescape $'} at #{$1}" if name =~ /(.*[^#:])@/
+
text = name unless text
link lookup, text
@@ -72,6 +70,8 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
def handle_special_CROSSREF(special)
name = special.text
+ return name if name =~ /@[\w-]+\.[\w-]/ # labels that look like emails
+
unless @hyperlink_all then
# This ensures that words entirely consisting of lowercase letters will
# not have cross-references generated (to suppress lots of erroneous
@@ -93,6 +93,25 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
end
##
+ # +special+ is an rdoc-schemed link that will be converted into a hyperlink.
+ # For the rdoc-ref scheme the cross-reference will be looked up and the
+ # given name will be used.
+ #
+ # All other contents are handled by
+ # {the superclass}[rdoc-ref:RDoc::Markup::ToHtml#handle_special_RDOCLINK]
+
+ def handle_special_RDOCLINK special
+ url = special.text
+
+ case url
+ when /\Ardoc-ref:/ then
+ cross_reference $'
+ else
+ super
+ end
+ end
+
+ ##
# Generates links for <tt>rdoc-ref:</tt> scheme URLs and allows
# RDoc::Markup::ToHtml to handle other schemes.
@@ -106,13 +125,31 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
# Creates an HTML link to +name+ with the given +text+.
def link name, text
+ original_name = name
+
+ if name =~ /(.*[^#:])@/ then
+ name = $1
+ label = $'
+ end
+
ref = @cross_reference.resolve name, text
+ text = ref.output_name @context if
+ RDoc::MethodAttr === ref and text == original_name
+
case ref
when String then
ref
else
- "<a href=\"#{ref.as_href @from_path}\">#{text}</a>"
+ path = ref.as_href @from_path
+
+ if path =~ /#/ then
+ path << "-label-#{label}"
+ else
+ path << "#label-#{label}"
+ end if label
+
+ "<a href=\"#{path}\">#{text}</a>"
end
end
diff --git a/lib/rdoc/markup/to_html_snippet.rb b/lib/rdoc/markup/to_html_snippet.rb
new file mode 100644
index 0000000000..4ad0a9a4b9
--- /dev/null
+++ b/lib/rdoc/markup/to_html_snippet.rb
@@ -0,0 +1,284 @@
+##
+# Outputs RDoc markup as paragraphs with inline markup only.
+
+class RDoc::Markup::ToHtmlSnippet < RDoc::Markup::ToHtml
+
+ ##
+ # After this many characters the input will be cut off.
+
+ attr_reader :character_limit
+
+ ##
+ # The number of characters seen so far.
+
+ attr_reader :characters # :nodoc:
+
+ ##
+ # The attribute bitmask
+
+ attr_reader :mask
+
+ ##
+ # After this many paragraphs the input will be cut off.
+
+ attr_reader :paragraph_limit
+
+ ##
+ # Count of paragraphs found
+
+ attr_reader :paragraphs
+
+ ##
+ # Creates a new ToHtmlSnippet formatter that will cut off the input on the
+ # next word boundary after the given number of +characters+ or +paragraphs+
+ # of text have been encountered.
+
+ def initialize options, characters = 100, paragraphs = 3, markup = nil
+ super options, markup
+
+ @character_limit = characters
+ @paragraph_limit = paragraphs
+
+ @characters = 0
+ @mask = 0
+ @paragraphs = 0
+
+ @markup.add_special RDoc::CrossReference::CROSSREF_REGEXP, :CROSSREF
+ end
+
+ ##
+ # Adds +heading+ to the output as a paragraph
+
+ def accept_heading heading
+ @res << "<p>#{to_html heading.text}\n"
+
+ add_paragraph
+ end
+
+ ##
+ # Raw sections are untrusted and ignored
+
+ alias accept_raw ignore
+
+ ##
+ # Rules are ignored
+
+ alias accept_rule ignore
+
+ def accept_paragraph paragraph
+ para = @in_list_entry.last || "<p>"
+
+ text = paragraph.text @hard_break
+
+ @res << "#{para}#{wrap to_html text}\n"
+
+ add_paragraph
+ end
+
+ ##
+ # Finishes consumption of +list_item+
+
+ def accept_list_item_end list_item
+ end
+
+ ##
+ # Prepares the visitor for consuming +list_item+
+
+ def accept_list_item_start list_item
+ @res << list_item_start(list_item, @list.last)
+ end
+
+ ##
+ # Prepares the visitor for consuming +list+
+
+ def accept_list_start list
+ @list << list.type
+ @res << html_list_name(list.type, true)
+ @in_list_entry.push ''
+ end
+
+ ##
+ # Adds +verbatim+ to the output
+
+ def accept_verbatim verbatim
+ throw :done if @characters >= @character_limit
+ input = verbatim.text.rstrip
+
+ text = truncate input
+ text << ' ...' unless text == input
+
+ super RDoc::Markup::Verbatim.new text
+
+ add_paragraph
+ end
+
+ ##
+ # Prepares the visitor for HTML snippet generation
+
+ def start_accepting
+ super
+
+ @characters = 0
+ end
+
+ ##
+ # Removes escaping from the cross-references in +special+
+
+ def handle_special_CROSSREF special
+ special.text.sub(/\A\\/, '')
+ end
+
+ ##
+ # +special+ is a <code><br></code>
+
+ def handle_special_HARD_BREAK special
+ @characters -= 4
+ '<br>'
+ end
+
+ ##
+ # Lists are paragraphs, but notes and labels have a separator
+
+ def list_item_start list_item, list_type
+ throw :done if @characters >= @character_limit
+
+ case list_type
+ when :BULLET, :LALPHA, :NUMBER, :UALPHA then
+ "<p>"
+ when :LABEL, :NOTE then
+ labels = Array(list_item.label).map do |label|
+ to_html label
+ end.join ', '
+
+ labels << " &mdash; " unless labels.empty?
+
+ start = "<p>#{labels}"
+ @characters += 1 # try to include the label
+ start
+ else
+ raise RDoc::Error, "Invalid list type: #{list_type.inspect}"
+ end
+ end
+
+ ##
+ # Returns just the text of +link+, +url+ is only used to determine the link
+ # type.
+
+ def gen_url url, text
+ if url =~ /^rdoc-label:([^:]*)(?::(.*))?/ then
+ type = "link"
+ elsif url =~ /([A-Za-z]+):(.*)/ then
+ type = $1
+ else
+ type = "http"
+ end
+
+ if (type == "http" or type == "https" or type == "link") and
+ url =~ /\.(gif|png|jpg|jpeg|bmp)$/ then
+ ''
+ else
+ text.sub(%r%^#{type}:/*%, '')
+ end
+ end
+
+ ##
+ # In snippets, there are no lists
+
+ def html_list_name list_type, open_tag
+ ''
+ end
+
+ ##
+ # Throws +:done+ when paragraph_limit paragraphs have been encountered
+
+ def add_paragraph
+ @paragraphs += 1
+
+ throw :done if @paragraphs >= @paragraph_limit
+ end
+
+ ##
+ # Marks up +content+
+
+ def convert content
+ catch :done do
+ return super
+ end
+
+ end_accepting
+ end
+
+ ##
+ # Converts flow items +flow+
+
+ def convert_flow flow
+ throw :done if @characters >= @character_limit
+
+ res = []
+ @mask = 0
+
+ flow.each do |item|
+ case item
+ when RDoc::Markup::AttrChanger then
+ off_tags res, item
+ on_tags res, item
+ when String then
+ text = convert_string item
+ res << truncate(text)
+ when RDoc::Markup::Special then
+ text = convert_special item
+ res << truncate(text)
+ else
+ raise "Unknown flow element: #{item.inspect}"
+ end
+
+ if @characters >= @character_limit then
+ off_tags res, RDoc::Markup::AttrChanger.new(0, @mask)
+ break
+ end
+ end
+
+ res << ' ...' if @characters >= @character_limit
+
+ res.join
+ end
+
+ ##
+ # Maintains a bitmask to allow HTML elements to be closed properly. See
+ # RDoc::Markup::Formatter.
+
+ def on_tags res, item
+ @mask ^= item.turn_on
+
+ super
+ end
+
+ ##
+ # Maintains a bitmask to allow HTML elements to be closed properly. See
+ # RDoc::Markup::Formatter.
+
+ def off_tags res, item
+ @mask ^= item.turn_off
+
+ super
+ end
+
+ ##
+ # Truncates +text+ at the end of the first word after the character_limit.
+
+ def truncate text
+ length = text.length
+ characters = @characters
+ @characters += length
+
+ return text if @characters < @character_limit
+
+ remaining = @character_limit - characters
+
+ text =~ /\A(.{#{remaining},}?)(\s|$)/m # TODO word-break instead of \s?
+
+ $1
+ end
+
+end
+
diff --git a/lib/rdoc/markup/to_joined_paragraph.rb b/lib/rdoc/markup/to_joined_paragraph.rb
new file mode 100644
index 0000000000..d91eb439f0
--- /dev/null
+++ b/lib/rdoc/markup/to_joined_paragraph.rb
@@ -0,0 +1,68 @@
+##
+# Joins the parts of an RDoc::Markup::Paragraph into a single String.
+#
+# This allows for easier maintenance and testing of Markdown support.
+#
+# This formatter only works on Paragraph instances. Attempting to process
+# other markup syntax items will not work.
+
+class RDoc::Markup::ToJoinedParagraph < RDoc::Markup::Formatter
+
+ def initialize # :nodoc:
+ super nil
+ end
+
+ def start_accepting
+ end
+
+ def end_accepting
+ end
+
+ def accept_paragraph paragraph
+ parts = []
+ string = false
+
+ paragraph.parts.each do |part|
+ if String === part then
+ if string then
+ string << part
+ else
+ parts << part
+ string = part
+ end
+ else
+ parts << part
+ string = false
+ end
+ end
+
+ parts = parts.map do |part|
+ if String === part then
+ part.rstrip
+ else
+ part
+ end
+ end
+
+ # TODO use Enumerable#chunk when ruby 1.8 support is dropped
+ #parts = paragraph.parts.chunk do |part|
+ # String === part
+ #end.map do |string, chunk|
+ # string ? chunk.join.rstrip : chunk
+ #end.flatten
+
+ paragraph.parts.replace parts
+ end
+
+ alias accept_block_quote ignore
+ alias accept_heading ignore
+ alias accept_list_end ignore
+ alias accept_list_item_end ignore
+ alias accept_list_item_start ignore
+ alias accept_list_start ignore
+ alias accept_raw ignore
+ alias accept_rule ignore
+ alias accept_verbatim ignore
+
+end
+
diff --git a/lib/rdoc/markup/to_label.rb b/lib/rdoc/markup/to_label.rb
new file mode 100644
index 0000000000..ace89c324a
--- /dev/null
+++ b/lib/rdoc/markup/to_label.rb
@@ -0,0 +1,74 @@
+require 'cgi'
+
+##
+# Creates HTML-safe labels suitable for use in id attributes. Tidylinks are
+# converted to their link part and cross-reference links have the suppression
+# marks removed (\\SomeClass is converted to SomeClass).
+
+class RDoc::Markup::ToLabel < RDoc::Markup::Formatter
+
+ attr_reader :res # :nodoc:
+
+ ##
+ # Creates a new formatter that will output HTML-safe labels
+
+ def initialize markup = nil
+ super nil, markup
+
+ @markup.add_special RDoc::CrossReference::CROSSREF_REGEXP, :CROSSREF
+ @markup.add_special(/(((\{.*?\})|\b\S+?)\[\S+?\])/, :TIDYLINK)
+
+ add_tag :BOLD, '', ''
+ add_tag :TT, '', ''
+ add_tag :EM, '', ''
+
+ @res = []
+ end
+
+ ##
+ # Converts +text+ to an HTML-safe label
+
+ def convert text
+ label = convert_flow @am.flow text
+
+ CGI.escape label
+ end
+
+ ##
+ # Converts the CROSSREF +special+ to plain text, removing the suppression
+ # marker, if any
+
+ def handle_special_CROSSREF special
+ text = special.text
+
+ text.sub(/^\\/, '')
+ end
+
+ ##
+ # Converts the TIDYLINK +special+ to just the text part
+
+ def handle_special_TIDYLINK special
+ text = special.text
+
+ return text unless text =~ /\{(.*?)\}\[(.*?)\]/ or text =~ /(\S+)\[(.*?)\]/
+
+ $1
+ end
+
+ alias accept_blank_line ignore
+ alias accept_block_quote ignore
+ alias accept_heading ignore
+ alias accept_list_end ignore
+ alias accept_list_item_end ignore
+ alias accept_list_item_start ignore
+ alias accept_list_start ignore
+ alias accept_paragraph ignore
+ alias accept_raw ignore
+ alias accept_rule ignore
+ alias accept_verbatim ignore
+ alias end_accepting ignore
+ alias handle_special_HARD_BREAK ignore
+ alias start_accepting ignore
+
+end
+
diff --git a/lib/rdoc/markup/to_markdown.rb b/lib/rdoc/markup/to_markdown.rb
new file mode 100644
index 0000000000..e984776399
--- /dev/null
+++ b/lib/rdoc/markup/to_markdown.rb
@@ -0,0 +1,134 @@
+# :markup: markdown
+
+##
+# Outputs parsed markup as Markdown
+
+class RDoc::Markup::ToMarkdown < RDoc::Markup::ToRdoc
+
+ ##
+ # Creates a new formatter that will output Markdown format text
+
+ def initialize markup = nil
+ super
+
+ @headings[1] = ['# ', '']
+ @headings[2] = ['## ', '']
+ @headings[3] = ['### ', '']
+ @headings[4] = ['#### ', '']
+ @headings[5] = ['##### ', '']
+ @headings[6] = ['###### ', '']
+
+ @hard_break = " \n"
+ end
+
+ ##
+ # Maps attributes to HTML sequences
+
+ def init_tags
+ add_tag :BOLD, '**', '**'
+ add_tag :EM, '*', '*'
+ add_tag :TT, '`', '`'
+ end
+
+ ##
+ # Adds a newline to the output
+
+ def handle_special_HARD_BREAK special
+ " \n"
+ end
+
+ ##
+ # Finishes consumption of `list`
+
+ def accept_list_end list
+ @res << "\n"
+
+ super
+ end
+
+ ##
+ # Finishes consumption of `list_item`
+
+ def accept_list_item_end list_item
+ width = case @list_type.last
+ when :BULLET then
+ 4
+ when :NOTE, :LABEL then
+ use_prefix
+
+ 4
+ else
+ @list_index[-1] = @list_index.last.succ
+ 4
+ end
+
+ @indent -= width
+ end
+
+ ##
+ # Prepares the visitor for consuming `list_item`
+
+ def accept_list_item_start list_item
+ type = @list_type.last
+
+ case type
+ when :NOTE, :LABEL then
+ bullets = Array(list_item.label).map do |label|
+ attributes(label).strip
+ end.join "\n"
+
+ bullets << "\n:"
+
+ @prefix = ' ' * @indent
+ @indent += 4
+ @prefix << bullets + (' ' * (@indent - 1))
+ else
+ bullet = type == :BULLET ? '*' : @list_index.last.to_s + '.'
+ @prefix = (' ' * @indent) + bullet.ljust(4)
+
+ @indent += 4
+ end
+ end
+
+ ##
+ # Prepares the visitor for consuming `list`
+
+ def accept_list_start list
+ case list.type
+ when :BULLET, :LABEL, :NOTE then
+ @list_index << nil
+ when :LALPHA, :NUMBER, :UALPHA then
+ @list_index << 1
+ else
+ raise RDoc::Error, "invalid list type #{list.type}"
+ end
+
+ @list_width << 4
+ @list_type << list.type
+ end
+
+ ##
+ # Adds `rule` to the output
+
+ def accept_rule rule
+ use_prefix or @res << ' ' * @indent
+ @res << '-' * 3
+ @res << "\n"
+ end
+
+ ##
+ # Outputs `verbatim` indented 4 columns
+
+ def accept_verbatim verbatim
+ indent = ' ' * (@indent + 4)
+
+ verbatim.parts.each do |part|
+ @res << indent unless part == "\n"
+ @res << part
+ end
+
+ @res << "\n" unless @res =~ /\n\z/
+ end
+
+end
+
diff --git a/lib/rdoc/markup/to_rdoc.rb b/lib/rdoc/markup/to_rdoc.rb
index 6f2faac2f6..f16b4ed5a3 100644
--- a/lib/rdoc/markup/to_rdoc.rb
+++ b/lib/rdoc/markup/to_rdoc.rb
@@ -1,6 +1,3 @@
-require 'rdoc/markup/formatter'
-require 'rdoc/markup/inline'
-
##
# Outputs RDoc markup as RDoc markup! (mostly)
@@ -45,7 +42,7 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
# Creates a new formatter that will output (mostly) \RDoc markup
def initialize markup = nil
- super
+ super nil, markup
@markup.add_special(/\\\S/, :SUPPRESSED_CROSSREF)
@width = 78
@@ -60,6 +57,8 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
@headings[4] = ['==== ', '']
@headings[5] = ['===== ', '']
@headings[6] = ['====== ', '']
+
+ @hard_break = "\n"
end
##
@@ -79,6 +78,21 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
end
##
+ # Adds +paragraph+ to the output
+
+ def accept_block_quote block_quote
+ @indent += 2
+
+ block_quote.parts.each do |part|
+ @prefix = '> '
+
+ part.accept self
+ end
+
+ @indent -= 2
+ end
+
+ ##
# Adds +heading+ to the output
def accept_heading heading
@@ -106,6 +120,11 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
when :BULLET then
2
when :NOTE, :LABEL then
+ if @prefix then
+ @res << @prefix.strip
+ @prefix = nil
+ end
+
@res << "\n"
2
else
@@ -125,10 +144,15 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
case type
when :NOTE, :LABEL then
- bullet = attributes(list_item.label) + ":\n"
+ bullets = Array(list_item.label).map do |label|
+ attributes(label).strip
+ end.join "\n"
+
+ bullets << ":\n" unless bullets.empty?
+
@prefix = ' ' * @indent
@indent += 2
- @prefix << bullet + (' ' * @indent)
+ @prefix << bullets + (' ' * @indent)
else
bullet = type == :BULLET ? '*' : @list_index.last.to_s + '.'
@prefix = (' ' * @indent) + bullet.ljust(bullet.length + 1)
@@ -168,7 +192,8 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
# Adds +paragraph+ to the output
def accept_paragraph paragraph
- wrap attributes(paragraph.text)
+ text = paragraph.text @hard_break
+ wrap attributes text
end
##
@@ -176,7 +201,8 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
def accept_indented_paragraph paragraph
@indent += paragraph.indent
- wrap attributes(paragraph.text)
+ text = paragraph.text @hard_break
+ wrap attributes text
@indent -= paragraph.indent
end
@@ -235,6 +261,13 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
end
##
+ # Adds a newline to the output
+
+ def handle_special_HARD_BREAK special
+ "\n"
+ end
+
+ ##
# Prepares the visitor for text generation
def start_accepting
@@ -252,8 +285,7 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
# prefix for later consumption.
def use_prefix
- prefix = @prefix
- @prefix = nil
+ prefix, @prefix = @prefix, nil
@res << prefix if prefix
prefix
diff --git a/lib/rdoc/markup/to_table_of_contents.rb b/lib/rdoc/markup/to_table_of_contents.rb
new file mode 100644
index 0000000000..54f2d5f64f
--- /dev/null
+++ b/lib/rdoc/markup/to_table_of_contents.rb
@@ -0,0 +1,61 @@
+##
+# Extracts just the RDoc::Markup::Heading elements from a
+# RDoc::Markup::Document to help build a table of contents
+
+class RDoc::Markup::ToTableOfContents < RDoc::Markup::Formatter
+
+ @to_toc = nil
+
+ ##
+ # Singleton for table-of-contents generation
+
+ def self.to_toc
+ @to_toc ||= new
+ end
+
+ ##
+ # Output accumulator
+
+ attr_reader :res
+
+ def initialize # :nodoc:
+ super nil
+ end
+
+ ##
+ # Adds +heading+ to the table of contents
+
+ def accept_heading heading
+ @res << heading
+ end
+
+ ##
+ # Returns the table of contents
+
+ def end_accepting
+ @res
+ end
+
+ ##
+ # Prepares the visitor for text generation
+
+ def start_accepting
+ @res = []
+ end
+
+ # :stopdoc:
+ alias accept_block_quote ignore
+ alias accept_raw ignore
+ alias accept_rule ignore
+ alias accept_blank_line ignore
+ alias accept_paragraph ignore
+ alias accept_verbatim ignore
+ alias accept_list_end ignore
+ alias accept_list_item_start ignore
+ alias accept_list_item_end ignore
+ alias accept_list_end_bullet ignore
+ alias accept_list_start ignore
+ # :startdoc:
+
+end
+
diff --git a/lib/rdoc/markup/to_test.rb b/lib/rdoc/markup/to_test.rb
index 4847fd29f7..c51f64b917 100644
--- a/lib/rdoc/markup/to_test.rb
+++ b/lib/rdoc/markup/to_test.rb
@@ -1,6 +1,3 @@
-require 'rdoc/markup'
-require 'rdoc/markup/formatter'
-
##
# This Markup outputter is used for testing purposes.
diff --git a/lib/rdoc/markup/to_tt_only.rb b/lib/rdoc/markup/to_tt_only.rb
index 078e87db98..e2da20c6f3 100644
--- a/lib/rdoc/markup/to_tt_only.rb
+++ b/lib/rdoc/markup/to_tt_only.rb
@@ -1,6 +1,3 @@
-require 'rdoc/markup/formatter'
-require 'rdoc/markup/inline'
-
##
# Extracts sections of text enclosed in plus, tt or code. Used to discover
# undocumented parameters.
@@ -21,12 +18,19 @@ class RDoc::Markup::ToTtOnly < RDoc::Markup::Formatter
# Creates a new tt-only formatter.
def initialize markup = nil
- super
+ super nil, markup
add_tag :TT, nil, nil
end
##
+ # Adds tts from +block_quote+ to the output
+
+ def accept_block_quote block_quote
+ tt_sections block_quote.text
+ end
+
+ ##
# Pops the list type for +list+ from #list_type
def accept_list_end list
@@ -46,7 +50,9 @@ class RDoc::Markup::ToTtOnly < RDoc::Markup::Formatter
def accept_list_item_start list_item
case @list_type.last
when :NOTE, :LABEL then
- tt_sections(list_item.label)
+ Array(list_item.label).map do |label|
+ tt_sections label
+ end.flatten
end
end
diff --git a/lib/rdoc/markup/verbatim.rb b/lib/rdoc/markup/verbatim.rb
index 8fe2184699..3886bbe8a5 100644
--- a/lib/rdoc/markup/verbatim.rb
+++ b/lib/rdoc/markup/verbatim.rb
@@ -4,6 +4,21 @@
class RDoc::Markup::Verbatim < RDoc::Markup::Raw
##
+ # Format of this verbatim section
+
+ attr_accessor :format
+
+ def initialize *parts # :nodoc:
+ super
+
+ @format = nil
+ end
+
+ def == other # :nodoc:
+ super and @format == other.format
+ end
+
+ ##
# Calls #accept_verbatim on +visitor+
def accept visitor
@@ -34,6 +49,29 @@ class RDoc::Markup::Verbatim < RDoc::Markup::Raw
@parts = parts
end
+ def pretty_print q # :nodoc:
+ self.class.name =~ /.*::(\w{1,4})/i
+
+ q.group 2, "[#{$1.downcase}: ", ']' do
+ if @format then
+ q.text "format: #{@format}"
+ q.breakable
+ end
+
+ q.seplist @parts do |part|
+ q.pp part
+ end
+ end
+ end
+
+ ##
+ # Is this verbatim section ruby code?
+
+ def ruby?
+ @format ||= nil # TODO for older ri data, switch the tree to marshal_dump
+ @format == :ruby
+ end
+
##
# The text of the section
diff --git a/lib/rdoc/meta_method.rb b/lib/rdoc/meta_method.rb
index e0c065c2ba..68ba8109e0 100644
--- a/lib/rdoc/meta_method.rb
+++ b/lib/rdoc/meta_method.rb
@@ -1,5 +1,3 @@
-require 'rdoc/any_method'
-
##
# MetaMethod represents a meta-programmed method
diff --git a/lib/rdoc/method_attr.rb b/lib/rdoc/method_attr.rb
index a4cd3c5fff..5021929ea0 100644
--- a/lib/rdoc/method_attr.rb
+++ b/lib/rdoc/method_attr.rb
@@ -1,5 +1,3 @@
-require 'rdoc/code_object'
-
##
# Abstract class representing either a method or an attribute.
@@ -100,7 +98,12 @@ class RDoc::MethodAttr < RDoc::CodeObject
# Order by #singleton then #name
def <=>(other)
- [@singleton ? 0 : 1, name] <=> [other.singleton ? 0 : 1, other.name]
+ [ @singleton ? 0 : 1, name] <=>
+ [other.singleton ? 0 : 1, other.name]
+ end
+
+ def == other # :nodoc:
+ super or self.class == other.class and full_name == other.full_name
end
##
@@ -135,6 +138,15 @@ class RDoc::MethodAttr < RDoc::CodeObject
@see
end
+ ##
+ # Sets the store for this class or module and its contained code objects.
+
+ def store= store
+ super
+
+ @file = @store.add_file @file.full_name if @file
+ end
+
def find_see # :nodoc:
return nil if singleton || is_alias_for
@@ -151,7 +163,7 @@ class RDoc::MethodAttr < RDoc::CodeObject
return nil unless parent.respond_to? :ancestors
searched = parent.ancestors
- kernel = RDoc::TopLevel.all_modules_hash['Kernel']
+ kernel = @store.modules_hash['Kernel']
searched << kernel if kernel &&
parent != kernel && !searched.include?(kernel)
@@ -173,10 +185,10 @@ class RDoc::MethodAttr < RDoc::CodeObject
# Abstract method. Contexts in their building phase call this
# to register a new alias for this known method/attribute.
#
- # - creates a new AnyMethod/Attribute +newa+ named an_alias.new_name;
- # - adds +self+ as +newa.is_alias_for+;
- # - adds +newa+ to #aliases
- # - adds +newa+ to the methods/attributes of +context+.
+ # - creates a new AnyMethod/Attribute named <tt>an_alias.new_name</tt>;
+ # - adds +self+ as an alias for the new method or attribute
+ # - adds the method or attribute to #aliases
+ # - adds the method or attribute to +context+.
def add_alias(an_alias, context)
raise NotImplementedError
@@ -261,6 +273,8 @@ class RDoc::MethodAttr < RDoc::CodeObject
# HTML id-friendly method/attribute name
def html_name
+ require 'cgi'
+
CGI.escape(@name.gsub('-', '-2D')).gsub('%','-').sub(/^-/, '')
end
@@ -268,14 +282,39 @@ class RDoc::MethodAttr < RDoc::CodeObject
# Full method/attribute name including namespace
def full_name
- @full_name || "#{parent_name}#{pretty_name}"
+ @full_name ||= "#{parent_name}#{pretty_name}"
+ end
+
+ def inspect # :nodoc:
+ alias_for = @is_alias_for ? " (alias for #{@is_alias_for.name})" : nil
+ visibility = self.visibility
+ visibility = "forced #{visibility}" if force_documentation
+ "#<%s:0x%x %s (%s)%s>" % [
+ self.class, object_id,
+ full_name,
+ visibility,
+ alias_for,
+ ]
end
##
# '::' for a class method/attribute, '#' for an instance method.
def name_prefix
- singleton ? '::' : '#'
+ @singleton ? '::' : '#'
+ end
+
+ ##
+ # Name for output to HTML. For class methods the full name with a "." is
+ # used like +SomeClass.method_name+. For instance methods the class name is
+ # used if +context+ does not match the parent.
+ #
+ # This is to help prevent people from using :: to call class methods.
+
+ def output_name context
+ return "#{name_prefix}#{@name}" if context == parent
+
+ "#{parent_name}#{@singleton ? '.' : '#'}#{@name}"
end
##
@@ -293,7 +332,7 @@ class RDoc::MethodAttr < RDoc::CodeObject
end
##
- # Path to this method
+ # Path to this method for use with HTML generator output.
def path
"#{@parent.path}##{aref}"
@@ -331,15 +370,19 @@ class RDoc::MethodAttr < RDoc::CodeObject
end
end
- def inspect # :nodoc:
- alias_for = @is_alias_for ? " (alias for #{@is_alias_for.name})" : nil
- visibility = self.visibility
- visibility = "forced #{visibility}" if force_documentation
- "#<%s:0x%x %s (%s)%s>" % [
- self.class, object_id,
+ ##
+ # Used by RDoc::Generator::JsonIndex to create a record for the search
+ # engine.
+
+ def search_record
+ [
+ @name,
full_name,
- visibility,
- alias_for,
+ @name,
+ @parent.full_name,
+ path,
+ params,
+ snippet(@comment),
]
end
diff --git a/lib/rdoc/normal_class.rb b/lib/rdoc/normal_class.rb
index f67380e783..dd7482c37c 100644
--- a/lib/rdoc/normal_class.rb
+++ b/lib/rdoc/normal_class.rb
@@ -1,15 +1,23 @@
-require 'rdoc/class_module'
-
##
# A normal class, neither singleton nor anonymous
class RDoc::NormalClass < RDoc::ClassModule
##
- # Appends the superclass, if any, to the included modules.
+ # The ancestors of this class including modules. Unlike Module#ancestors,
+ # this class is not included in the result. The result will contain both
+ # RDoc::ClassModules and Strings.
def ancestors
- superclass ? super + [superclass] : super
+ if String === superclass then
+ super << superclass
+ elsif superclass then
+ ancestors = super
+ ancestors << superclass
+ ancestors.concat superclass.ancestors
+ else
+ super
+ end
end
##
@@ -19,11 +27,15 @@ class RDoc::NormalClass < RDoc::ClassModule
"class #{full_name}"
end
+ def direct_ancestors
+ superclass ? super + [superclass] : super
+ end
+
def inspect # :nodoc:
superclass = @superclass ? " < #{@superclass}" : nil
- "<%s:0x%x class %s%s includes: %p attributes: %p methods: %p aliases: %p>" % [
+ "<%s:0x%x class %s%s includes: %p extends: %p attributes: %p methods: %p aliases: %p>" % [
self.class, object_id,
- full_name, superclass, @includes, @attributes, @method_list, @aliases
+ full_name, superclass, @includes, @extends, @attributes, @method_list, @aliases
]
end
@@ -46,19 +58,24 @@ class RDoc::NormalClass < RDoc::ClassModule
q.seplist @includes do |inc| q.pp inc end
q.breakable
+ q.text "constants:"
+ q.breakable
+ q.seplist @constants do |const| q.pp const end
+
+ q.breakable
q.text "attributes:"
q.breakable
- q.seplist @attributes do |inc| q.pp inc end
+ q.seplist @attributes do |attr| q.pp attr end
q.breakable
q.text "methods:"
q.breakable
- q.seplist @method_list do |inc| q.pp inc end
+ q.seplist @method_list do |meth| q.pp meth end
q.breakable
q.text "aliases:"
q.breakable
- q.seplist @aliases do |inc| q.pp inc end
+ q.seplist @aliases do |aliaz| q.pp aliaz end
q.breakable
q.text "comment:"
diff --git a/lib/rdoc/normal_module.rb b/lib/rdoc/normal_module.rb
index 0fa7223547..cd77b1e39e 100644
--- a/lib/rdoc/normal_module.rb
+++ b/lib/rdoc/normal_module.rb
@@ -1,14 +1,12 @@
-require 'rdoc/class_module'
-
##
# A normal module, like NormalClass
class RDoc::NormalModule < RDoc::ClassModule
def inspect # :nodoc:
- "#<%s:0x%x module %s includes: %p attributes: %p methods: %p aliases: %p>" % [
+ "#<%s:0x%x module %s includes: %p extends: %p attributes: %p methods: %p aliases: %p>" % [
self.class, object_id,
- full_name, @includes, @attributes, @method_list, @aliases
+ full_name, @includes, @extends, @attributes, @method_list, @aliases
]
end
@@ -34,19 +32,24 @@ class RDoc::NormalModule < RDoc::ClassModule
q.seplist @includes do |inc| q.pp inc end
q.breakable
+ q.breakable
+ q.text "constants:"
+ q.breakable
+ q.seplist @constants do |const| q.pp const end
+
q.text "attributes:"
q.breakable
- q.seplist @attributes do |inc| q.pp inc end
+ q.seplist @attributes do |attr| q.pp attr end
q.breakable
q.text "methods:"
q.breakable
- q.seplist @method_list do |inc| q.pp inc end
+ q.seplist @method_list do |meth| q.pp meth end
q.breakable
q.text "aliases:"
q.breakable
- q.seplist @aliases do |inc| q.pp inc end
+ q.seplist @aliases do |aliaz| q.pp aliaz end
q.breakable
q.text "comment:"
diff --git a/lib/rdoc/options.rb b/lib/rdoc/options.rb
index bab5463897..d862b0adf3 100644
--- a/lib/rdoc/options.rb
+++ b/lib/rdoc/options.rb
@@ -1,9 +1,62 @@
require 'optparse'
-require 'rdoc/ri/paths'
-
##
# RDoc::Options handles the parsing and storage of options
+#
+# == Saved Options
+#
+# You can save some options like the markup format in the
+# <tt>.rdoc_options</tt> file in your gem. The easiest way to do this is:
+#
+# rdoc --markup tomdoc --write-options
+#
+# Which will automatically create the file and fill it with the options you
+# specified.
+#
+# The following options will not be saved since they interfere with the user's
+# preferences or with the normal operation of RDoc:
+#
+# * +--coverage-report+
+# * +--dry-run+
+# * +--encoding+
+# * +--force-update+
+# * +--format+
+# * +--pipe+
+# * +--quiet+
+# * +--template+
+# * +--verbose+
+#
+# == Custom Options
+#
+# Generators can hook into RDoc::Options to add generator-specific command
+# line options.
+#
+# When <tt>--format</tt> is encountered in ARGV, RDoc calls ::setup_options on
+# the generator class to add extra options to the option parser. Options for
+# custom generators must occur after <tt>--format</tt>. <tt>rdoc --help</tt>
+# will list options for all installed generators.
+#
+# Example:
+#
+# class RDoc::Generator::Spellcheck
+# RDoc::RDoc.add_generator self
+#
+# def self.setup_options rdoc_options
+# op = rdoc_options.option_parser
+#
+# op.on('--spell-dictionary DICTIONARY',
+# RDoc::Options::Path) do |dictionary|
+# rdoc_options.spell_dictionary = dictionary
+# end
+# end
+# end
+#
+# == Option Validators
+#
+# OptionParser validators will validate and cast user input values. In
+# addition to the validators that ship with OptionParser (String, Integer,
+# Float, TrueClass, FalseClass, Array, Regexp, Date, Time, URI, etc.),
+# RDoc::Options adds Path, PathArray and Template.
class RDoc::Options
@@ -25,9 +78,50 @@ class RDoc::Options
}
##
- # Template option validator for OptionParser
+ # RDoc options ignored (or handled specially) by --write-options
+
+ SPECIAL = %w[
+ coverage_report
+ dry_run
+ encoding
+ files
+ force_output
+ force_update
+ generator
+ generator_name
+ generator_options
+ generators
+ op_dir
+ option_parser
+ pipe
+ rdoc_include
+ static_path
+ stylesheet_url
+ template
+ template_dir
+ update_output_dir
+ verbosity
+ write_options
+ ]
+
+ ##
+ # Option validator for OptionParser that matches a file or directory that
+ # exists on the filesystem.
+
+ Path = Object.new
+
+ ##
+ # Option validator for OptionParser that matches a comma-separated list of
+ # files or directories that exist on the filesystem.
- Template = nil
+ PathArray = Object.new
+
+ ##
+ # Option validator for OptionParser that matches a template directory for an
+ # installed generator that lives in
+ # <tt>"rdoc/generator/template/#{template_name}"</tt>
+
+ Template = Object.new
##
# Character-set for HTML output. #encoding is preferred over #charset
@@ -40,9 +134,11 @@ class RDoc::Options
attr_accessor :dry_run
##
- # Encoding of output where. This is set via --encoding.
+ # The output encoding. All input files will be transcoded to this encoding.
+ #
+ # The default encoding is UTF-8. This is set via --encoding.
- attr_accessor :encoding if Object.const_defined? :Encoding
+ attr_accessor :encoding
##
# Files matching this pattern will be excluded
@@ -71,11 +167,16 @@ class RDoc::Options
attr_accessor :formatter
##
- # Description of the output generator (set with the <tt>--fmt</tt> option)
+ # Description of the output generator (set with the <tt>--format</tt> option)
attr_accessor :generator
##
+ # For #==
+
+ attr_reader :generator_name # :nodoc:
+
+ ##
# Loaded generator options. Used to prevent --help from loading the same
# options multiple times.
@@ -99,6 +200,12 @@ class RDoc::Options
attr_accessor :main_page
##
+ # The default markup format. The default is 'rdoc'. 'markdown', 'tomdoc'
+ # and 'rd' are also built-in.
+
+ attr_accessor :markup
+
+ ##
# If true, only report on undocumented files
attr_accessor :coverage_report
@@ -129,6 +236,11 @@ class RDoc::Options
attr_accessor :show_hash
##
+ # Directory to copy static files from
+
+ attr_accessor :static_path
+
+ ##
# The number of columns in a tab
attr_accessor :tab_width
@@ -171,9 +283,13 @@ class RDoc::Options
attr_accessor :visibility
def initialize # :nodoc:
- require 'rdoc/rdoc'
+ init_ivars
+ end
+
+ def init_ivars # :nodoc:
@dry_run = false
@exclude = []
+ @files = nil
@force_output = false
@force_update = true
@generator = nil
@@ -183,12 +299,14 @@ class RDoc::Options
@hyperlink_all = false
@line_numbers = false
@main_page = nil
+ @markup = 'rdoc'
@coverage_report = false
@op_dir = nil
@pipe = false
@rdoc_include = []
@show_hash = false
- @stylesheet_url = nil
+ @static_path = []
+ @stylesheet_url = nil # TODO remove in RDoc 4
@tab_width = 8
@template = nil
@template_dir = nil
@@ -197,15 +315,67 @@ class RDoc::Options
@verbosity = 1
@visibility = :protected
@webcvs = nil
+ @write_options = false
if Object.const_defined? :Encoding then
- @encoding = Encoding.default_external
- @charset = @encoding.to_s
+ @encoding = Encoding::UTF_8
+ @charset = @encoding.name
else
+ @encoding = nil
@charset = 'UTF-8'
end
end
+ def init_with map # :nodoc:
+ init_ivars
+
+ encoding = map['encoding']
+ @encoding = if Object.const_defined? :Encoding then
+ encoding ? Encoding.find(encoding) : encoding
+ end
+
+ @charset = map['charset']
+ @exclude = map['exclude']
+ @generator_name = map['generator_name']
+ @hyperlink_all = map['hyperlink_all']
+ @line_numbers = map['line_numbers']
+ @main_page = map['main_page']
+ @markup = map['markup']
+ @op_dir = map['op_dir']
+ @show_hash = map['show_hash']
+ @tab_width = map['tab_width']
+ @template_dir = map['template_dir']
+ @title = map['title']
+ @visibility = map['visibility']
+ @webcvs = map['webcvs']
+
+ @rdoc_include = sanitize_path map['rdoc_include']
+ @static_path = sanitize_path map['static_path']
+ end
+
+ def yaml_initialize tag, map # :nodoc:
+ init_with map
+ end
+
+ def == other # :nodoc:
+ self.class === other and
+ @encoding == other.encoding and
+ @generator_name == other.generator_name and
+ @hyperlink_all == other.hyperlink_all and
+ @line_numbers == other.line_numbers and
+ @main_page == other.main_page and
+ @markup == other.markup and
+ @op_dir == other.op_dir and
+ @rdoc_include == other.rdoc_include and
+ @show_hash == other.show_hash and
+ @static_path == other.static_path and
+ @tab_width == other.tab_width and
+ @template == other.template and
+ @title == other.title and
+ @visibility == other.visibility and
+ @webcvs == other.webcvs
+ end
+
##
# Check that the files on the command line exist
@@ -247,6 +417,24 @@ class RDoc::Options
end
##
+ # For dumping YAML
+
+ def encode_with coder # :nodoc:
+ encoding = @encoding ? @encoding.name : nil
+
+ coder.add 'encoding', encoding
+ coder.add 'static_path', sanitize_path(@static_path)
+ coder.add 'rdoc_include', sanitize_path(@rdoc_include)
+
+ ivars = instance_variables.map { |ivar| ivar.to_s[1..-1] }
+ ivars -= SPECIAL
+
+ ivars.sort.each do |ivar|
+ coder.add ivar, instance_variable_get("@#{ivar}")
+ end
+ end
+
+ ##
# Completes any unfinished option setup business such as filtering for
# existent files, creating a regexp for #exclude and setting a default
# #template.
@@ -306,7 +494,7 @@ class RDoc::Options
##
# Parses command line options.
- def parse(argv)
+ def parse argv
ignore_invalid = true
argv.insert(0, *ENV['RDOCOPT'].split) if ENV['RDOCOPT']
@@ -367,13 +555,35 @@ Usage: #{opt.program_name} [options] [names...]
template_dir = template_dir_for template
unless template_dir then
- warn "could not find template #{template}"
+ $stderr.puts "could not find template #{template}"
nil
else
[template, template_dir]
end
end
+ opt.accept Path do |path|
+ path = File.expand_path path
+
+ raise OptionParser::InvalidArgument unless File.exist? path
+
+ path
+ end
+
+ opt.accept PathArray do |paths,|
+ paths = if paths then
+ paths.split(',').map { |d| d unless d.empty? }
+ end
+
+ paths.map do |path|
+ path = File.expand_path path
+
+ raise OptionParser::InvalidArgument unless File.exist? path
+
+ path
+ end
+ end
+
opt.separator nil
opt.separator "Parsing options:"
opt.separator nil
@@ -382,9 +592,10 @@ Usage: #{opt.program_name} [options] [names...]
opt.on("--encoding=ENCODING", "-e", Encoding.list.map { |e| e.name },
"Specifies the output encoding. All files",
"read will be converted to this encoding.",
- "Preferred over --charset") do |value|
+ "The default encoding is UTF-8.",
+ "--encoding is preferred over --charset") do |value|
@encoding = Encoding.find value
- @charset = @encoding.to_s # may not be valid value
+ @charset = @encoding.name # may not be valid value
end
opt.separator nil
@@ -452,6 +663,17 @@ Usage: #{opt.program_name} [options] [names...]
end
opt.separator nil
+
+ markup_formats = RDoc::Text::MARKUP_FORMAT.keys.sort
+
+ opt.on("--markup=MARKUP", markup_formats,
+ "The markup format for the named files.",
+ "The default is rdoc. Valid values are:",
+ markup_formats.join(', ')) do |value|
+ @markup = value
+ end
+
+ opt.separator nil
opt.separator "Common generator options:"
opt.separator nil
@@ -477,7 +699,7 @@ Usage: #{opt.program_name} [options] [names...]
opt.separator nil
- opt.on("--include=DIRECTORIES", "-i", Array,
+ opt.on("--include=DIRECTORIES", "-i", PathArray,
"Set (or add to) the list of directories to",
"be searched when satisfying :include:",
"requests. Can be used more than once.") do |value|
@@ -576,6 +798,18 @@ Usage: #{opt.program_name} [options] [names...]
opt.separator nil
+ opt.on("--copy-files=PATH", Path,
+ "Specify a file or directory to copy static",
+ "files from.",
+ "If a file is given it will be copied into",
+ "the output dir. If a directory is given the",
+ "entire directory will be copied.",
+ "You can use this multiple times") do |value|
+ @static_path << value
+ 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",
@@ -620,32 +854,52 @@ Usage: #{opt.program_name} [options] [names...]
opt.separator "Generic options:"
opt.separator nil
+ opt.on("--write-options",
+ "Write .rdoc_options to the current",
+ "directory with the given options. Not all",
+ "options will be used. See RDoc::Options",
+ "for details.") do |value|
+ @write_options = true
+ end
+
+ opt.separator nil
+
opt.on("--[no-]dry-run",
"Don't write any files") do |value|
@dry_run = value
end
+ opt.separator nil
+
opt.on("-D", "--[no-]debug",
"Displays lots on internal stuff.") do |value|
$DEBUG_RDOC = value
end
+ opt.separator nil
+
opt.on("--[no-]ignore-invalid",
"Ignore invalid options and continue",
"(default true).") do |value|
ignore_invalid = value
end
+ opt.separator nil
+
opt.on("--quiet", "-q",
"Don't show progress as we parse.") do |value|
@verbosity = 0
end
+ opt.separator nil
+
opt.on("--verbose", "-v",
"Display extra progress as RDoc parses") do |value|
@verbosity = 2
end
+ opt.separator nil
+
opt.on("--help",
"Display this help") do
RDoc::RDoc::GENERATORS.each_key do |generator|
@@ -711,6 +965,13 @@ Usage: #{opt.program_name} [options] [names...]
@files = argv.dup
finish
+
+ if @write_options then
+ write_options
+ exit
+ end
+
+ self
end
##
@@ -728,6 +989,20 @@ Usage: #{opt.program_name} [options] [names...]
end
##
+ # Removes directories from +path+ that are outside the current directory
+
+ def sanitize_path path
+ require 'pathname'
+ dot = Pathname.new('.').expand_path
+
+ path.reject do |item|
+ path = Pathname.new(item).expand_path
+ relative = path.relative_path_from(dot).to_s
+ relative.start_with? '..'
+ end
+ end
+
+ ##
# Set up an output generator for the named +generator_name+.
#
# If the found generator responds to :setup_options it will be called with
@@ -766,5 +1041,39 @@ Usage: #{opt.program_name} [options] [names...]
end
end
+ ##
+ # This is compatibility code for syck
+
+ def to_yaml opts = {} # :nodoc:
+ return super if YAML.const_defined?(:ENGINE) and not YAML::ENGINE.syck?
+
+ YAML.quick_emit self, opts do |out|
+ out.map taguri, to_yaml_style do |map|
+ encode_with map
+ end
+ end
+ end
+
+ ##
+ # Displays a warning using Kernel#warn if we're being verbose
+
+ def warn message
+ super message if @verbosity > 1
+ end
+
+ ##
+ # Writes the YAML file .rdoc_options to the current directory containing the
+ # parsed options.
+
+ def write_options
+ RDoc.load_yaml
+
+ open '.rdoc_options', 'w' do |io|
+ io.set_encoding Encoding::UTF_8 if Object.const_defined? :Encoding
+
+ YAML.dump self, io
+ end
+ end
+
end
diff --git a/lib/rdoc/parser.rb b/lib/rdoc/parser.rb
index 1dee485492..b51f7868ea 100644
--- a/lib/rdoc/parser.rb
+++ b/lib/rdoc/parser.rb
@@ -1,41 +1,31 @@
-require 'rdoc'
-require 'rdoc/code_objects'
-require 'rdoc/markup/pre_process'
-require 'rdoc/stats'
-
##
-# A parser is a class that subclasses RDoc::Parser and implements
-#
-# #initialize top_level, file_name, body, options, stats
-#
-# and
-#
-# #scan
+# A parser is simple a class that subclasses RDoc::Parser and implements #scan
+# to fill in an RDoc::TopLevel with parsed data.
#
-# The initialize method takes a file name to be used, the body of the file,
-# and an RDoc::Options object. The scan method is then called to return an
-# appropriately parsed TopLevel code object.
+# The initialize method takes an RDoc::TopLevel to fill with parsed content,
+# the name of the file to be parsed, the content of the file, an RDoc::Options
+# object and an RDoc::Stats object to inform the user of parsed items. The
+# scan method is then called to parse the file and must return the
+# RDoc::TopLevel object. By calling super these items will be set for you.
#
-# RDoc::Parser::for is a factory that creates the correct parser for a
-# given filename extension. Parsers have to register themselves RDoc::Parser
-# using parse_files_matching as when they are loaded:
+# In order to be used by RDoc the parser needs to register the file extensions
+# it can parse. Use ::parse_files_matching to register extensions.
#
-# require "rdoc/parser"
+# require 'rdoc'
#
# class RDoc::Parser::Xyz < RDoc::Parser
-# parse_files_matching /\.xyz$/ # <<<<
+# parse_files_matching /\.xyz$/
#
-# def initialize top_level, file_name, body, options, stats
-# ...
+# def initialize top_level, file_name, content, options, stats
+# super
+#
+# # extra initialization if needed
# end
#
# def scan
-# ...
+# # parse file and fill in @top_level
# end
# end
-#
-# If a plain text file is detected, RDoc also looks for a shebang line in case
-# the file is a shell script.
class RDoc::Parser
@@ -61,7 +51,7 @@ class RDoc::Parser
old_ext = old_ext.sub(/^\.(.*)/, '\1')
new_ext = new_ext.sub(/^\.(.*)/, '\1')
- parser = can_parse_by_name "xxx.#{old_ext}"
+ parser = can_parse "xxx.#{old_ext}"
return false unless parser
RDoc::Parser.parsers.unshift [/\.#{new_ext}$/, parser]
@@ -80,14 +70,14 @@ class RDoc::Parser
have_encoding = s.respond_to? :encoding
+ if have_encoding then
+ return false if s.encoding != Encoding::ASCII_8BIT and s.valid_encoding?
+ end
+
return true if s[0, 2] == Marshal.dump('')[0, 2] or s.index("\x00")
if have_encoding then
- mode = "r"
- s.sub!(/\A#!.*\n/, '') # assume shebang line isn't longer than 1024.
- encoding = s[/^\s*\#\s*(?:-\*-\s*)?(?:en)?coding:\s*([^\s;]+?)(?:-\*-|[\s;])/, 1]
- mode = "r:#{encoding}" if encoding
- s = File.open(file, mode) {|f| f.gets(nil, 1024)}
+ s.force_encoding Encoding.default_external
not s.valid_encoding?
else
@@ -134,54 +124,51 @@ class RDoc::Parser
zip_signature == "PK\x03\x04" or
zip_signature == "PK\x05\x06" or
zip_signature == "PK\x07\x08"
- rescue
- false
end
##
# Return a parser that can handle a particular extension
def self.can_parse(file_name)
- parser = can_parse_by_name(file_name)
+ parser = RDoc::Parser.parsers.find { |regexp,| regexp =~ file_name }.last
# HACK Selenium hides a jar file using a .txt extension
return if parser == RDoc::Parser::Simple and zip? file_name
- parser
- end
-
- def self.can_parse_by_name(file_name)
- pattern, parser = RDoc::Parser.parsers.find { |regexp,| regexp =~ file_name }
-
# The default parser must not parse binary files
ext_name = File.extname file_name
return parser if ext_name.empty?
- return if parser == RDoc::Parser::Simple and ext_name !~ /txt|rdoc/ and file_name[pattern].empty?
+ return if parser == RDoc::Parser::Simple and ext_name !~ /txt|rdoc/
parser
+ rescue Errno::EACCES
end
##
- # Find the correct parser for a particular file name. Return a SimpleParser
- # for ones that we don't know
+ # Finds and instantiates the correct parser for the given +file_name+ and
+ # +content+.
- def self.for(top_level, file_name, body, options, stats)
+ def self.for top_level, file_name, content, options, stats
return if binary? file_name
- # If no extension, look for shebang
- if file_name !~ /\.\w+$/ && body =~ %r{\A#!(.+)} then
- shebang = $1
- case shebang
- when %r{env\s+ruby}, %r{/ruby}
- file_name = "dummy.rb"
+ parser = use_markup content
+
+ unless parser then
+ # If no extension, look for shebang
+ if file_name !~ /\.\w+$/ && content =~ %r{\A#!(.+)} then
+ shebang = $1
+ case shebang
+ when %r{env\s+ruby}, %r{/ruby}
+ file_name = "dummy.rb"
+ end
end
- end
- parser = can_parse file_name
+ parser = can_parse file_name
+ end
return unless parser
- parser.new top_level, file_name, body, options, stats
+ parser.new top_level, file_name, content, options, stats
end
##
@@ -194,13 +181,48 @@ class RDoc::Parser
end
##
- # Creates a new Parser storing +top_level+, +file_name+, +content+,
- # +options+ and +stats+ in instance variables.
+ # If there is a <tt>markup: parser_name</tt> comment at the front of the
+ # file, use it to determine the parser. For example:
+ #
+ # # markup: rdoc
+ # # Class comment can go here
+ #
+ # class C
+ # end
+ #
+ # The comment should appear as the first line of the +content+.
#
- # Usually invoked by +super+
+ # If the content contains a shebang or editor modeline the comment may
+ # appear on the second or third line.
+ #
+ # Any comment style may be used to hide the markup comment.
+
+ def self.use_markup content
+ markup = content.lines.first(3).grep(/markup:\s+(\w+)/) { $1 }.first
+
+ return unless markup
+
+ # TODO Ruby should be returned only when the filename is correct
+ return RDoc::Parser::Ruby if %w[tomdoc markdown].include? markup
- def initialize(top_level, file_name, content, options, stats)
+ markup = Regexp.escape markup
+
+ RDoc::Parser.parsers.find do |_, parser|
+ /^#{markup}$/i =~ parser.name.sub(/.*:/, '')
+ end.last
+ end
+
+ ##
+ # Creates a new Parser storing +top_level+, +file_name+, +content+,
+ # +options+ and +stats+ in instance variables. In +@preprocess+ an
+ # RDoc::Markup::PreProcess object is created which allows processing of
+ # directives.
+
+ def initialize top_level, file_name, content, options, stats
@top_level = top_level
+ @top_level.parser = self.class
+ @store = @top_level.store
+
@file_name = file_name
@content = content
@options = options
@@ -210,7 +232,15 @@ class RDoc::Parser
@preprocess.options = @options
end
+ autoload :RubyTools, 'rdoc/parser/ruby_tools'
+ autoload :Text, 'rdoc/parser/text'
+
end
+# simple must come first in order to show up last in the parsers list
require 'rdoc/parser/simple'
+require 'rdoc/parser/c'
+require 'rdoc/parser/markdown'
+require 'rdoc/parser/rd'
+require 'rdoc/parser/ruby'
diff --git a/lib/rdoc/parser/c.rb b/lib/rdoc/parser/c.rb
index 3da1820c50..31be27169c 100644
--- a/lib/rdoc/parser/c.rb
+++ b/lib/rdoc/parser/c.rb
@@ -1,6 +1,4 @@
-
-require 'rdoc/parser/ruby'
-require 'rdoc/known_classes'
+require 'tsort'
##
# RDoc::Parser::C attempts to parse C extension files. It looks for
@@ -58,6 +56,13 @@ require 'rdoc/known_classes'
# [Document-const: +name+]
# Documentation for the named +rb_define_const+.
#
+# Constant values can be supplied on the first line of the comment like so:
+#
+# /* 300: The highest possible score in bowling */
+# rb_define_const(cFoo, "PERFECT", INT2FIX(300));
+#
+# The value can contain internal colons so long as they are escaped with a \
+#
# [Document-global: +name+]
# Documentation for the named +rb_define_global_const+
#
@@ -122,27 +127,27 @@ class RDoc::Parser::C < RDoc::Parser
attr_accessor :content
+ ##
+ # Dependencies from a missing enclosing class to the classes in
+ # missing_dependencies that depend upon it.
+
+ attr_reader :enclosure_dependencies
##
- # Maps C variable names to names of ruby classes (andsingleton classes)
+ # Maps C variable names to names of ruby classes (and singleton classes)
attr_reader :known_classes
##
- # Maps C variable names to names of ruby singleton classes
+ # Classes found while parsing the C file that were not yet registered due to
+ # a missing enclosing class. These are processed by do_missing
- attr_reader :singleton_classes
+ attr_reader :missing_dependencies
##
- # Resets cross-file state. Call when parsing different projects that need
- # separate documentation.
-
- def self.reset
- @@enclosure_classes = {}
- @@known_bodies = {}
- end
+ # Maps C variable names to names of ruby singleton classes
- reset
+ attr_reader :singleton_classes
##
# Prepare to parse a C file
@@ -155,6 +160,38 @@ class RDoc::Parser::C < RDoc::Parser
@classes = {}
@singleton_classes = {}
@file_dir = File.dirname(@file_name)
+
+ # missing variable => [handle_class_module arguments]
+ @missing_dependencies = {}
+
+ # missing enclosure variable => [dependent handle_class_module arguments]
+ @enclosure_dependencies = Hash.new { |h, k| h[k] = [] }
+ @enclosure_dependencies.instance_variable_set :@missing_dependencies,
+ @missing_dependencies
+
+ @enclosure_dependencies.extend TSort
+
+ def @enclosure_dependencies.tsort_each_node &block
+ each_key(&block)
+ rescue TSort::Cyclic => e
+ cycle_vars = e.message.scan(/"(.*?)"/).flatten
+
+ cycle = cycle_vars.sort.map do |var_name|
+ delete var_name
+
+ var_name, type, mod_name, = @missing_dependencies[var_name]
+
+ "#{type} #{mod_name} (#{var_name})"
+ end.join ', '
+
+ warn "Unable to create #{cycle} due to a cyclic class or module creation"
+
+ retry
+ end
+
+ def @enclosure_dependencies.tsort_each_child node, &block
+ fetch(node, []).each(&block)
+ end
end
##
@@ -169,7 +206,7 @@ class RDoc::Parser::C < RDoc::Parser
class_name = @known_classes[var_name]
unless class_name then
- warn "Enclosing class/module %p for alias %s %s not known" % [
+ @options.warn "Enclosing class or module %p for alias %s %s is not known" % [
var_name, new_name, old_name]
next
end
@@ -180,7 +217,9 @@ class RDoc::Parser::C < RDoc::Parser
al.singleton = @singleton_classes.key? var_name
comment = find_alias_comment var_name, new_name, old_name
- comment = strip_stars comment
+
+ comment.normalize
+
al.comment = comment
al.record_location @top_level
@@ -214,62 +253,26 @@ class RDoc::Parser::C < RDoc::Parser
end
##
- # Scans #content for rb_define_module, rb_define_class, boot_defclass,
- # rb_define_module_under, rb_define_class_under and rb_singleton_class
-
- def do_classes
- @content.scan(/(\w+)\s* = \s*rb_define_module\s*\(\s*"(\w+)"\s*\)/mx) do
- |var_name, class_name|
- handle_class_module(var_name, "module", class_name, nil, nil)
- end
-
- # The '.' lets us handle SWIG-generated files
- @content.scan(/([\w\.]+)\s* = \s*rb_define_class\s*
- \(
- \s*"(\w+)",
- \s*(\w+)\s*
- \)/mx) do |var_name, class_name, parent|
- handle_class_module(var_name, "class", class_name, parent, nil)
- end
+ # Scans #content for boot_defclass
+ def do_boot_defclass
@content.scan(/(\w+)\s*=\s*boot_defclass\s*\(\s*"(\w+?)",\s*(\w+?)\s*\)/) do
|var_name, class_name, parent|
parent = nil if parent == "0"
- handle_class_module(var_name, "class", class_name, parent, nil)
- end
-
- @content.scan(/(\w+)\s* = \s*rb_define_module_under\s*
- \(
- \s*(\w+),
- \s*"(\w+)"
- \s*\)/mx) do |var_name, in_module, class_name|
- handle_class_module(var_name, "module", class_name, nil, in_module)
+ handle_class_module(var_name, :class, class_name, parent, nil)
end
+ end
- @content.scan(/([\w\.]+)\s* = # var_name
- \s*rb_define_class_under\s*
- \(
- \s* (\w+), # under
- \s* "(\w+)", # class_name
- \s*
- (?:
- ([\w\*\s\(\)\.\->]+) | # parent_name
- rb_path2class\("([\w:]+)"\) # path
- )
- \s*
- \)
- /mx) do |var_name, under, class_name, parent_name, path|
- parent = path || parent_name
-
- handle_class_module var_name, 'class', class_name, parent, under
- end
+ ##
+ # Scans #content for rb_define_class, boot_defclass, rb_define_class_under
+ # and rb_singleton_class
- @content.scan(/([\w\.]+)\s* = \s*rb_singleton_class\s*
- \(
- \s*(\w+)
- \s*\)/mx) do |sclass_var, class_var|
- handle_singleton sclass_var, class_var
- end
+ def do_classes
+ do_boot_defclass
+ do_define_class
+ do_define_class_under
+ do_singleton_class
+ do_struct_define_without_accessor
end
##
@@ -300,8 +303,82 @@ class RDoc::Parser::C < RDoc::Parser
\)
\s*;%xm) do |consts|
const = consts.first
+
handle_constants 'const', 'mCurses', const, "UINT2NUM(#{const})"
end
+
+ @content.scan(%r%
+ \Wrb_file_const
+ \s*\(
+ \s*
+ "([^"]+)",
+ \s*
+ (.*?)
+ \s*
+ \)
+ \s*;%xm) do |name, value|
+ handle_constants 'const', 'rb_mFConst', name, value
+ end
+ end
+
+ ##
+ # Scans #content for rb_define_class
+
+ def do_define_class
+ # The '.' lets us handle SWIG-generated files
+ @content.scan(/([\w\.]+)\s* = \s*rb_define_class\s*
+ \(
+ \s*"(\w+)",
+ \s*(\w+)\s*
+ \)/mx) do |var_name, class_name, parent|
+ handle_class_module(var_name, :class, class_name, parent, nil)
+ end
+ end
+
+ ##
+ # Scans #content for rb_define_class_under
+
+ def do_define_class_under
+ @content.scan(/([\w\.]+)\s* = # var_name
+ \s*rb_define_class_under\s*
+ \(
+ \s* (\w+), # under
+ \s* "(\w+)", # class_name
+ \s*
+ (?:
+ ([\w\*\s\(\)\.\->]+) | # parent_name
+ rb_path2class\("([\w:]+)"\) # path
+ )
+ \s*
+ \)
+ /mx) do |var_name, under, class_name, parent_name, path|
+ parent = path || parent_name
+
+ handle_class_module var_name, :class, class_name, parent, under
+ end
+ end
+
+ ##
+ # Scans #content for rb_define_module
+
+ def do_define_module
+ @content.scan(/(\w+)\s* = \s*rb_define_module\s*\(\s*"(\w+)"\s*\)/mx) do
+ |var_name, class_name|
+ handle_class_module(var_name, :module, class_name, nil, nil)
+ end
+ end
+
+ ##
+ # Scans #content for rb_define_module_under
+
+ def do_define_module_under
+ @content.scan(/(\w+)\s* = \s*rb_define_module_under\s*
+ \(
+ \s*(\w+),
+ \s*"(\w+)"
+ \s*\)/mx) do |var_name, in_module, class_name|
+ handle_class_module(var_name, :module, class_name, nil, in_module)
+ end
end
##
@@ -311,7 +388,9 @@ class RDoc::Parser::C < RDoc::Parser
@content.scan(/rb_include_module\s*\(\s*(\w+?),\s*(\w+?)\s*\)/) do |c,m|
if cls = @classes[c]
m = @known_classes[m] || m
- incl = cls.add_include RDoc::Include.new(m, "")
+
+ comment = RDoc::Comment.new '', @top_level
+ incl = cls.add_include RDoc::Include.new(m, comment)
incl.record_location @top_level
end
end
@@ -367,6 +446,54 @@ class RDoc::Parser::C < RDoc::Parser
end
end
+ def do_missing
+ return if @missing_dependencies.empty?
+
+ @enclosure_dependencies.tsort.each do |in_module|
+ arguments = @missing_dependencies.delete in_module
+
+ next unless arguments # dependency on existing class
+
+ handle_class_module(*arguments)
+ end
+ end
+
+ ##
+ # Scans #content for rb_define_module and rb_define_module_under
+
+ def do_modules
+ do_define_module
+ do_define_module_under
+ end
+
+ ##
+ # Scans #content for rb_singleton_class
+
+ def do_singleton_class
+ @content.scan(/([\w\.]+)\s* = \s*rb_singleton_class\s*
+ \(
+ \s*(\w+)
+ \s*\)/mx) do |sclass_var, class_var|
+ handle_singleton sclass_var, class_var
+ end
+ end
+
+ ##
+ # Scans #content for struct_define_without_accessor
+
+ def do_struct_define_without_accessor
+ @content.scan(/([\w\.]+)\s* = \s*rb_struct_define_without_accessor\s*
+ \(
+ \s*"(\w+)", # Class name
+ \s*(\w+), # Parent class
+ \s*\w+, # Allocation function
+ (\s*"\w+",)* # Attributes
+ \s*NULL
+ \)/mx) do |var_name, class_name, parent|
+ handle_class_module(var_name, :class, class_name, parent, nil)
+ end
+ end
+
##
# Finds the comment for an alias on +class_name+ from +new_name+ to
# +old_name+
@@ -377,7 +504,7 @@ class RDoc::Parser::C < RDoc::Parser
\s*"#{Regexp.escape new_name}"\s*,
\s*"#{Regexp.escape old_name}"\s*\);%xm
- $1 || ''
+ RDoc::Comment.new($1 || '', @top_level)
end
##
@@ -398,22 +525,24 @@ class RDoc::Parser::C < RDoc::Parser
/.*?/m
end
- if @content =~ %r%((?>/\*.*?\*/\s+))
- rb_define_attr\((?:\s*#{var_name},)?\s*
- "#{attr_name}"\s*,
- #{rw}\)\s*;%xm then
- $1
- elsif @content =~ %r%((?>/\*.*?\*/\s+))
- rb_attr\(\s*#{var_name}\s*,
- \s*#{attr_name}\s*,
- #{rw},.*?\)\s*;%xm then
- $1
- elsif @content =~ %r%Document-attr:\s#{attr_name}\s*?\n
- ((?>.*?\*/))%xm then
- $1
- else
- ''
- end
+ comment = if @content =~ %r%((?>/\*.*?\*/\s+))
+ rb_define_attr\((?:\s*#{var_name},)?\s*
+ "#{attr_name}"\s*,
+ #{rw}\)\s*;%xm then
+ $1
+ elsif @content =~ %r%((?>/\*.*?\*/\s+))
+ rb_attr\(\s*#{var_name}\s*,
+ \s*#{attr_name}\s*,
+ #{rw},.*?\)\s*;%xm then
+ $1
+ elsif @content =~ %r%Document-attr:\s#{attr_name}\s*?\n
+ ((?>.*?\*/))%xm then
+ $1
+ else
+ ''
+ end
+
+ RDoc::Comment.new comment, @top_level
end
##
@@ -425,11 +554,11 @@ class RDoc::Parser::C < RDoc::Parser
((?:(?:static|SWIGINTERN)\s+)?
(?:intern\s+)?VALUE\s+#{meth_name}
\s*(\([^)]*\))([^;]|$))%xm then
- comment = $1
+ comment = RDoc::Comment.new $1, @top_level
body = $2
- offset = $~.offset(2).first
+ offset, = $~.offset(2)
- remove_private_comments comment if comment
+ comment.remove_private if comment
# try to find the whole body
body = $& if /#{Regexp.escape body}[^(]*?\{.*?^\}/m =~ file_content
@@ -443,6 +572,7 @@ class RDoc::Parser::C < RDoc::Parser
override_comment = find_override_comment class_name, meth_obj
comment = override_comment if override_comment
+ comment.normalize
find_modifiers comment, meth_obj if comment
#meth_obj.params = params
@@ -450,24 +580,26 @@ class RDoc::Parser::C < RDoc::Parser
tk = RDoc::RubyToken::Token.new nil, 1, 1
tk.set_text body
meth_obj.add_token tk
- meth_obj.comment = strip_stars comment
+ meth_obj.comment = comment
meth_obj.offset = offset
meth_obj.line = file_content[0, offset].count("\n") + 1
body
when %r%((?>/\*.*?\*/\s*))^\s*(\#\s*define\s+#{meth_name}\s+(\w+))%m then
- comment = $1
+ comment = RDoc::Comment.new $1, @top_level
body = $2
offset = $~.offset(2).first
find_body class_name, $3, meth_obj, file_content, true
+
+ comment.normalize
find_modifiers comment, meth_obj
meth_obj.start_collecting_tokens
tk = RDoc::RubyToken::Token.new nil, 1, 1
tk.set_text body
meth_obj.add_token tk
- meth_obj.comment = strip_stars(comment) + meth_obj.comment.to_s
+ meth_obj.comment = comment
meth_obj.offset = offset
meth_obj.line = file_content[0, offset].count("\n") + 1
@@ -480,18 +612,19 @@ class RDoc::Parser::C < RDoc::Parser
return body if body
- warn "No definition for #{meth_name}" if @options.verbosity > 1
+ @options.warn "No definition for #{meth_name}"
false
else # No body, but might still have an override comment
comment = find_override_comment class_name, meth_obj
if comment then
+ comment.normalize
find_modifiers comment, meth_obj
- meth_obj.comment = strip_stars comment
+ meth_obj.comment = comment
''
else
- warn "No definition for #{meth_name}" if @options.verbosity > 1
+ @options.warn "No definition for #{meth_name}"
false
end
end
@@ -540,7 +673,7 @@ class RDoc::Parser::C < RDoc::Parser
# */
# VALUE cFoo = rb_define_class("Foo", rb_cObject);
- def find_class_comment(class_name, class_mod)
+ def find_class_comment class_name, class_mod
comment = nil
if @content =~ %r%
@@ -551,17 +684,21 @@ class RDoc::Parser::C < RDoc::Parser
comment = $1.sub(%r%Document-(?:class|module):\s+#{class_name}%, '')
elsif @content =~ %r%Document-(?:class|module):\s+#{class_name}\s*?
(?:<\s+[:,\w]+)?\n((?>.*?\*/))%xm then
- comment = $1
- elsif @content =~ %r%((?>/\*.*?\*/\s+))
+ comment = "/*\n#{$1}"
+ elsif @content =~ %r%.*((?>/\*.*?\*/\s+))
([\w\.\s]+\s* = \s+)?rb_define_(class|module).*?"(#{class_name})"%xm then
comment = $1
+ elsif @content =~ %r%.*((?>/\*.*?\*/\s+))
+ ([\w\.\s]+\s* = \s+)?rb_define_(class|module)_under.*?"(#{class_name.split('::').last})"%xm then
+ comment = $1
+ else
+ comment = ''
end
- return unless comment
-
- comment = strip_stars comment
+ comment = RDoc::Comment.new comment, @top_level
+ comment.normalize
- comment = look_for_directives_in class_mod, comment
+ look_for_directives_in class_mod, comment
class_mod.add_comment comment, @top_level
end
@@ -571,79 +708,33 @@ class RDoc::Parser::C < RDoc::Parser
# comment or in the matching Document- section.
def find_const_comment(type, const_name, class_name = nil)
- if @content =~ %r%((?>^\s*/\*.*?\*/\s+))
- rb_define_#{type}\((?:\s*(\w+),)?\s*
- "#{const_name}"\s*,
- .*?\)\s*;%xmi then
- $1
- elsif class_name and
- @content =~ %r%Document-(?:const|global|variable):\s
- #{class_name}::#{const_name}
- \s*?\n((?>.*?\*/))%xm then
- $1
- elsif @content =~ %r%Document-(?:const|global|variable):\s#{const_name}
- \s*?\n((?>.*?\*/))%xm then
- $1
- else
- ''
- end
+ comment = if @content =~ %r%((?>^\s*/\*.*?\*/\s+))
+ rb_define_#{type}\((?:\s*(\w+),)?\s*
+ "#{const_name}"\s*,
+ .*?\)\s*;%xmi then
+ $1
+ elsif class_name and
+ @content =~ %r%Document-(?:const|global|variable):\s
+ #{class_name}::#{const_name}
+ \s*?\n((?>.*?\*/))%xm then
+ "/*\n#{$1}"
+ elsif @content =~ %r%Document-(?:const|global|variable):
+ \s#{const_name}
+ \s*?\n((?>.*?\*/))%xm then
+ "/*\n#{$1}"
+ else
+ ''
+ end
+
+ RDoc::Comment.new comment, @top_level
end
##
# Handles modifiers in +comment+ and updates +meth_obj+ as appropriate.
- #
- # If <tt>:nodoc:</tt> is found, documentation on +meth_obj+ is suppressed.
- #
- # If <tt>:yields:</tt> is followed by an argument list it is used for the
- # #block_params of +meth_obj+.
- #
- # If the comment block contains a <tt>call-seq:</tt> section like:
- #
- # call-seq:
- # ARGF.readlines(sep=$/) -> array
- # ARGF.readlines(limit) -> array
- # ARGF.readlines(sep, limit) -> array
- #
- # ARGF.to_a(sep=$/) -> array
- # ARGF.to_a(limit) -> array
- # ARGF.to_a(sep, limit) -> array
- #
- # it is used for the parameters of +meth_obj+.
def find_modifiers comment, meth_obj
- # we must handle situations like the above followed by an unindented first
- # comment. The difficulty is to make sure not to match lines starting
- # with ARGF at the same indent, but that are after the first description
- # paragraph.
-
- if comment =~ /call-seq:(.*?(?:\S|\*\/?).*?)^\s*(?:\*\/?)?\s*$/m then
- all_start, all_stop = $~.offset(0)
- seq_start, seq_stop = $~.offset(1)
-
- # we get the following lines that start with the leading word at the
- # same indent, even if they have blank lines before
- if $1 =~ /(^\s*\*?\s*\n)+^(\s*\*?\s*\w+)/m then
- leading = $2 # ' * ARGF' in the example above
- re = %r%
- \A(
- (^\s*\*?\s*\n)+
- (^#{Regexp.escape leading}.*?\n)+
- )+
- ^\s*\*?\s*$
- %xm
- if comment[seq_stop..-1] =~ re then
- all_stop = seq_stop + $~.offset(0).last
- seq_stop = seq_stop + $~.offset(1).last
- end
- end
-
- seq = comment[seq_start..seq_stop]
- seq.gsub!(/^(\s*\*?\s*?)(\S|\n)/m, '\2')
- comment.slice! all_start...all_stop
- meth_obj.call_seq = seq
- elsif comment.sub!(/\A\/\*\s*call-seq:(.*?)\*\/\Z/, '') then
- meth_obj.call_seq = $1.strip
- end
+ comment.normalize
+ comment.extract_call_seq meth_obj
look_for_directives_in meth_obj, comment
end
@@ -655,11 +746,18 @@ class RDoc::Parser::C < RDoc::Parser
name = Regexp.escape meth_obj.name
prefix = Regexp.escape meth_obj.name_prefix
- if @content =~ %r%Document-method:\s+#{class_name}#{prefix}#{name}\s*?\n((?>.*?\*/))%m then
- $1
- elsif @content =~ %r%Document-method:\s#{name}\s*?\n((?>.*?\*/))%m then
- $1
- end
+ comment = if @content =~ %r%Document-method:
+ \s+#{class_name}#{prefix}#{name}
+ \s*?\n((?>.*?\*/))%xm then
+ "/*#{$1}"
+ elsif @content =~ %r%Document-method:
+ \s#{name}\s*?\n((?>.*?\*/))%xm then
+ "/*#{$1}"
+ end
+
+ return unless comment
+
+ RDoc::Comment.new comment, @top_level
end
##
@@ -680,7 +778,7 @@ class RDoc::Parser::C < RDoc::Parser
return unless class_obj
comment = find_attr_comment var_name, attr_name
- comment = strip_stars comment
+ comment.normalize
name = attr_name.gsub(/rb_intern\("([^"]+)"\)/, '\1')
@@ -699,23 +797,26 @@ class RDoc::Parser::C < RDoc::Parser
parent_name = @known_classes[parent] || parent
if in_module then
- enclosure = @classes[in_module] || @@enclosure_classes[in_module]
+ enclosure = @classes[in_module] || @store.c_enclosure_classes[in_module]
if enclosure.nil? and enclosure = @known_classes[in_module] then
- enc_type = /^rb_m/ =~ in_module ? "module" : "class"
+ enc_type = /^rb_m/ =~ in_module ? :module : :class
handle_class_module in_module, enc_type, enclosure, nil, nil
enclosure = @classes[in_module]
end
unless enclosure then
- warn "Enclosing class/module '#{in_module}' for #{type} #{class_name} not known"
+ @enclosure_dependencies[in_module] << var_name
+ @missing_dependencies[var_name] =
+ [var_name, type, class_name, parent, in_module]
+
return
end
else
enclosure = @top_level
end
- if type == "class" then
+ if type == :class then
full_name = if RDoc::ClassModule === enclosure then
enclosure.full_name + "::#{class_name}"
else
@@ -743,7 +844,7 @@ class RDoc::Parser::C < RDoc::Parser
end
@classes[var_name] = cm
- @@enclosure_classes[var_name] = cm
+ @store.c_enclosure_classes[var_name] = cm
@known_classes[var_name] = cm.full_name
end
@@ -765,25 +866,20 @@ class RDoc::Parser::C < RDoc::Parser
class_obj = find_class var_name, class_name
unless class_obj then
- warn "Enclosing class/module #{const_name.inspect} not known"
+ @options.warn 'Enclosing class or module %p is not known' % [const_name]
return
end
comment = find_const_comment type, const_name, class_name
- comment = strip_stars comment
- comment = normalize_comment comment
+ comment.normalize
# 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 = comment.split ':'
-
- if elements.nil? or elements.empty? then
- con = RDoc::Constant.new const_name, definition, comment
- else
- new_definition = elements[0..-2].join(':')
+ no_match, new_definition, new_comment = comment.text.split(/(\A.*):/)
+ if no_match and no_match.empty? then
if new_definition.empty? then # Default to literal C definition
new_definition = definition
else
@@ -793,13 +889,13 @@ class RDoc::Parser::C < RDoc::Parser
new_definition.sub!(/\A(\s+)/, '')
- new_comment = if $1.nil? then
- elements.last.lstrip
- else
- "#{$1}#{elements.last.lstrip}"
- end
+ new_comment = "#{$1}#{new_comment.lstrip}"
+
+ new_comment = RDoc::Comment.new new_comment, @top_level
con = RDoc::Constant.new const_name, new_definition, new_comment
+ else
+ con = RDoc::Constant.new const_name, definition, comment
end
else
con = RDoc::Constant.new const_name, definition, comment
@@ -849,9 +945,9 @@ class RDoc::Parser::C < RDoc::Parser
file_name = File.join @file_dir, source_file
if File.exist? file_name then
- file_content = (@@known_bodies[file_name] ||= File.read(file_name))
+ file_content = File.read file_name
else
- warn "unknown source #{source_file} for #{meth_name} in #{@file_name}"
+ @options.warn "unknown source #{source_file} for #{meth_name} in #{@file_name}"
end
else
file_content = @content
@@ -1021,20 +1117,16 @@ class RDoc::Parser::C < RDoc::Parser
end
##
- # Removes private comments from +comment+
-
- def remove_private_comments(comment)
- comment.gsub!(/\/?\*--\n(.*?)\/?\*\+\+/m, '')
- comment.sub!(/\/?\*--\n.*/m, '')
- end
-
- ##
# Extracts the classes, modules, methods, attributes, constants and aliases
# from a C file and returns an RDoc::TopLevel for this file
def scan
remove_commented_out_lines
+
+ do_modules
do_classes
+ do_missing
+
do_constants
do_methods
do_includes
diff --git a/lib/rdoc/parser/markdown.rb b/lib/rdoc/parser/markdown.rb
new file mode 100644
index 0000000000..6fd88cf614
--- /dev/null
+++ b/lib/rdoc/parser/markdown.rb
@@ -0,0 +1,23 @@
+##
+# Parse a Markdown format file. The parsed RDoc::Markup::Document is attached
+# as a file comment.
+
+class RDoc::Parser::Markdown < RDoc::Parser
+
+ include RDoc::Parser::Text
+
+ parse_files_matching(/\.(md|markdown)(?:\.[^.]+)?$/)
+
+ ##
+ # Creates an Markdown-format TopLevel for the given file.
+
+ def scan
+ comment = RDoc::Comment.new @content, @top_level
+ comment.format = 'markdown'
+
+ @top_level.comment = comment
+ end
+
+end
+
+
diff --git a/lib/rdoc/parser/rd.rb b/lib/rdoc/parser/rd.rb
new file mode 100644
index 0000000000..09069ae297
--- /dev/null
+++ b/lib/rdoc/parser/rd.rb
@@ -0,0 +1,22 @@
+##
+# Parse a RD format file. The parsed RDoc::Markup::Document is attached as a
+# file comment.
+
+class RDoc::Parser::RD < RDoc::Parser
+
+ include RDoc::Parser::Text
+
+ parse_files_matching(/\.rd(?:\.[^.]+)?$/)
+
+ ##
+ # Creates an rd-format TopLevel for the given file.
+
+ def scan
+ comment = RDoc::Comment.new @content, @top_level
+ comment.format = 'rd'
+
+ @top_level.comment = comment
+ end
+
+end
+
diff --git a/lib/rdoc/parser/ruby.rb b/lib/rdoc/parser/ruby.rb
index c9a12a8fe8..0b207fae3b 100644
--- a/lib/rdoc/parser/ruby.rb
+++ b/lib/rdoc/parser/ruby.rb
@@ -7,15 +7,6 @@
# by Keiju ISHITSUKA (Nippon Rational Inc.)
#
-require 'rdoc/ruby_token'
-require 'rdoc/ruby_lex'
-
-require 'rdoc/code_objects'
-require 'rdoc/token_stream'
-require 'rdoc/markup/pre_process'
-require 'rdoc/parser'
-require 'rdoc/parser/ruby_tools'
-
$TOKEN_DEBUG ||= nil
##
@@ -103,7 +94,7 @@ $TOKEN_DEBUG ||= nil
# You can force the name of a method using the :method: directive:
#
# ##
-# # :method: woo_hoo!
+# # :method: some_method!
#
# By default, meta-methods are instance methods. To indicate that a method is
# a singleton method instead use the :singleton-method: directive:
@@ -114,7 +105,7 @@ $TOKEN_DEBUG ||= nil
# You can also use the :singleton-method: directive with a name:
#
# ##
-# # :singleton-method: woo_hoo!
+# # :singleton-method: some_method!
#
# Additionally you can mark a method as an attribute by
# using :attr:, :attr_reader:, :attr_writer: or :attr_accessor:. Just like
@@ -173,6 +164,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
@scanner = RDoc::RubyLex.new content, @options
@scanner.exception_on_syntax_error = false
@prev_seek = nil
+ @markup = @options.markup
@encoding = nil
@encoding = @options.encoding if Object.const_defined? :Encoding
@@ -213,7 +205,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
unget_tk tk
- comment
+ new_comment comment
end
##
@@ -226,22 +218,6 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
##
- # Look for a 'call-seq' in the comment, and override the normal parameter
- # stuff
- #--
- # TODO handle undent
-
- def extract_call_seq(comment, meth)
- if comment.sub!(/:?call-seq:(.*?)(^\s*#?\s*$|\z)/m, '') then
- seq = $1
- seq.gsub!(/^\s*\#\s*/, '')
- meth.call_seq = seq
- end
-
- meth
- end
-
- ##
# Looks for a true or false token. Returns false if TkFALSE or TkNIL are
# found.
@@ -264,7 +240,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
# with :: separated named) and return the ultimate name, the associated
# container, and the given name (with the ::).
- def get_class_or_module(container)
+ def get_class_or_module container
skip_tkspace
name_t = get_tk
given_name = ''
@@ -283,14 +259,18 @@ class RDoc::Parser::Ruby < RDoc::Parser
while TkCOLON2 === peek_tk do
prev_container = container
container = container.find_module_named name_t.name
- unless container then
- container = prev_container.add_module RDoc::NormalModule, name_t.name
- end
+ container ||= prev_container.add_module RDoc::NormalModule, name_t.name
+
+ container.ignore unless prev_container.document_children
+
get_tk
+ skip_tkspace false
name_t = get_tk
given_name << '::' << name_t.name
end
+
skip_tkspace false
+
return [container, name_t, given_name]
end
@@ -299,9 +279,10 @@ class RDoc::Parser::Ruby < RDoc::Parser
def get_class_specification
tk = get_tk
- return "self" if TkSELF === tk
+ return 'self' if TkSELF === tk
+ return '' if TkGVAR === tk
- res = ""
+ res = ''
while TkCOLON2 === tk or TkCOLON3 === tk or TkCONSTANT === tk do
res += tk.name
tk = get_tk
@@ -412,8 +393,8 @@ class RDoc::Parser::Ruby < RDoc::Parser
'attr', 'attr_accessor', 'attr_reader', 'attr_writer' then
false # handled elsewhere
when 'section' then
- context.set_current_section param, comment
- comment.replace ''
+ context.set_current_section param, comment.dup
+ comment.text = ''
break
end
end
@@ -433,6 +414,15 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
##
+ # Creates a comment with the correct format
+
+ def new_comment comment
+ c = RDoc::Comment.new comment, @top_level
+ c.format = @markup
+ c
+ end
+
+ ##
# Creates an RDoc::Attr for the name following +tk+, setting the comment to
# +comment+.
@@ -590,7 +580,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
##
# Parses a class in +context+ with +comment+
- def parse_class(container, single, tk, comment)
+ def parse_class container, single, tk, comment
offset = tk.seek
line_no = tk.line_no
@@ -602,6 +592,11 @@ class RDoc::Parser::Ruby < RDoc::Parser
name = name_t.name
superclass = '::Object'
+ if given_name =~ /^::/ then
+ declaration_context = @top_level
+ given_name = $'
+ end
+
if TkLT === peek_tk then
get_tk
skip_tkspace
@@ -626,17 +621,25 @@ class RDoc::Parser::Ruby < RDoc::Parser
parse_statements cls
when TkLSHFT
case name = get_class_specification
- when "self", container.name
+ when 'self', container.name
parse_statements container, SINGLE
else
- other = RDoc::TopLevel.find_class_named name
+ other = @store.find_class_named name
unless other then
+ if name =~ /^::/ then
+ name = $'
+ container = @top_level
+ end
+
other = container.add_module RDoc::NormalModule, name
other.record_location @top_level
other.offset = offset
other.line = line_no
+ # class << $gvar
+ other.ignore if name.empty?
+
other.add_comment comment, @top_level
end
@@ -678,6 +681,8 @@ class RDoc::Parser::Ruby < RDoc::Parser
return false
end
+ value = ''
+ con = RDoc::Constant.new name, value, comment
nest = 0
get_tkread
@@ -705,13 +710,16 @@ class RDoc::Parser::Ruby < RDoc::Parser
(@scanner.lex_state == EXPR_END || !@scanner.continue) then
unget_tk tk
break
+ else
+ unget_tk tk
+ read_documentation_modifiers con, RDoc::CONSTANT_MODIFIERS
end
when TkCONSTANT then
rhs_name << tk.name
if nest <= 0 and TkNL === peek_tk then
mod = if rhs_name =~ /^::/ then
- RDoc::TopLevel.find_class_or_module rhs_name
+ @store.find_class_or_module rhs_name
else
container.find_module_named rhs_name
end
@@ -736,14 +744,15 @@ class RDoc::Parser::Ruby < RDoc::Parser
res = get_tkread.gsub(/^[ \t]+/, '').strip
res = "" if res == ";"
- con = RDoc::Constant.new name, res, comment
+ value.replace res
con.record_location @top_level
con.offset = offset
con.line = line_no
read_documentation_modifiers con, RDoc::CONSTANT_MODIFIERS
@stats.add_constant con
- container.add_constant con
+ con = container.add_constant con
+
true
end
@@ -751,15 +760,18 @@ class RDoc::Parser::Ruby < RDoc::Parser
# Generates an RDoc::Method or RDoc::Attr from +comment+ by looking for
# :method: or :attr: directives in +comment+.
- def parse_comment(container, tk, comment)
+ def parse_comment container, tk, comment
+ return parse_comment_tomdoc container, tk, comment if @markup == 'tomdoc'
column = tk.char_no
offset = tk.seek
line_no = tk.line_no
- singleton = !!comment.sub!(/(^# +:?)(singleton-)(method:)/, '\1\3')
+ text = comment.text
+
+ singleton = !!text.sub!(/(^# +:?)(singleton-)(method:)/, '\1\3')
# REFACTOR
- if comment.sub!(/^# +:?method: *(\S*).*?\n/i, '') then
+ if text.sub!(/^# +:?method: *(\S*).*?\n/i, '') then
name = $1 unless $1.empty?
meth = RDoc::GhostMethod.new get_tkread, name
@@ -769,16 +781,17 @@ class RDoc::Parser::Ruby < RDoc::Parser
meth.line = line_no
meth.start_collecting_tokens
- indent = TkSPACE.new nil, 1, 1
+ indent = TkSPACE.new 0, 1, 1
indent.set_text " " * column
- position_comment = TkCOMMENT.new nil, line_no, 1
+ position_comment = TkCOMMENT.new 0, line_no, 1
position_comment.set_text "# File #{@top_level.absolute_name}, line #{line_no}"
meth.add_tokens [position_comment, NEWLINE_TOKEN, indent]
meth.params = ''
- extract_call_seq comment, meth
+ comment.normalize
+ comment.extract_call_seq meth
return unless meth.name
@@ -787,7 +800,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
meth.comment = comment
@stats.add_method meth
- elsif comment.sub!(/# +:?(attr(_reader|_writer|_accessor)?): *(\S*).*?\n/i, '') then
+ elsif text.sub!(/# +:?(attr(_reader|_writer|_accessor)?): *(\S*).*?\n/i, '') then
rw = case $1
when 'attr_reader' then 'R'
when 'attr_writer' then 'W'
@@ -810,6 +823,43 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
##
+ # Creates an RDoc::Method on +container+ from +comment+ if there is a
+ # Signature section in the comment
+
+ def parse_comment_tomdoc container, tk, comment
+ return unless signature = RDoc::TomDoc.signature(comment)
+ offset = tk.seek
+ line_no = tk.line_no
+
+ name, = signature.split %r%[ \(]%, 2
+
+ meth = RDoc::GhostMethod.new get_tkread, name
+ meth.record_location @top_level
+ meth.offset = offset
+ meth.line = line_no
+
+ meth.start_collecting_tokens
+ indent = TkSPACE.new 0, 1, 1
+ indent.set_text " " * offset
+
+ position_comment = TkCOMMENT.new 0, line_no, 1
+ position_comment.set_text "# File #{@top_level.absolute_name}, line #{line_no}"
+ meth.add_tokens [position_comment, NEWLINE_TOKEN, indent]
+
+ meth.call_seq = signature
+
+ comment.normalize
+
+ return unless meth.name
+
+ container.add_method meth
+
+ meth.comment = comment
+
+ @stats.add_method meth
+ end
+
+ ##
# Parses an +include+ in +context+ with +comment+
def parse_include context, comment
@@ -830,6 +880,26 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
##
+ # Parses an +extend+ in +context+ with +comment+
+
+ def parse_extend context, comment
+ loop do
+ skip_tkspace_comment
+
+ name = get_constant_with_optional_parens
+
+ unless name.empty? then
+ incl = context.add_extend RDoc::Extend.new(name, comment)
+ incl.record_location @top_level
+ end
+
+ return unless TkCOMMA === peek_tk
+
+ get_tk
+ end
+ end
+
+ ##
# Parses a meta-programmed attribute and creates an RDoc::Attr.
#
# To create foo and bar attributes on class C with comment "My attributes":
@@ -867,7 +937,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
tmp = RDoc::CodeObject.new
read_documentation_modifiers tmp, RDoc::ATTR_MODIFIERS
- if comment.sub!(/^# +:?(attr(_reader|_writer|_accessor)?): *(\S*).*?\n/i, '') then
+ if comment.text.sub!(/^# +:?(attr(_reader|_writer|_accessor)?): *(\S*).*?\n/i, '') then
rw = case $1
when 'attr_reader' then 'R'
when 'attr_writer' then 'W'
@@ -892,6 +962,8 @@ class RDoc::Parser::Ruby < RDoc::Parser
@stats.add_attribute att
end
end
+
+ att
end
##
@@ -908,9 +980,9 @@ class RDoc::Parser::Ruby < RDoc::Parser
skip_tkspace false
- singleton = !!comment.sub!(/(^# +:?)(singleton-)(method:)/, '\1\3')
+ singleton = !!comment.text.sub!(/(^# +:?)(singleton-)(method:)/, '\1\3')
- if comment.sub!(/^# +:?method: *(\S*).*?\n/i, '') then
+ if comment.text.sub!(/^# +:?method: *(\S*).*?\n/i, '') then
name = $1 unless $1.empty?
end
@@ -939,10 +1011,10 @@ class RDoc::Parser::Ruby < RDoc::Parser
remove_token_listener self
meth.start_collecting_tokens
- indent = TkSPACE.new nil, 1, 1
+ indent = TkSPACE.new 0, 1, 1
indent.set_text " " * column
- position_comment = TkCOMMENT.new nil, line_no, 1
+ position_comment = TkCOMMENT.new 0, line_no, 1
position_comment.value = "# File #{@top_level.absolute_name}, line #{line_no}"
meth.add_tokens [position_comment, NEWLINE_TOKEN, indent]
meth.add_tokens @token_stream
@@ -950,7 +1022,8 @@ class RDoc::Parser::Ruby < RDoc::Parser
token_listener meth do
meth.params = ''
- extract_call_seq comment, meth
+ comment.normalize
+ comment.extract_call_seq meth
container.add_method meth
@@ -965,7 +1038,6 @@ class RDoc::Parser::Ruby < RDoc::Parser
when TkSPACE then
# expression continues
when TkDO then
- unget_tk tk
parse_statements container, single, meth
break
else
@@ -977,6 +1049,8 @@ class RDoc::Parser::Ruby < RDoc::Parser
meth.comment = comment
@stats.add_method meth
+
+ meth
end
##
@@ -1002,15 +1076,23 @@ class RDoc::Parser::Ruby < RDoc::Parser
meth = nil
added_container = false
- dot = get_tk
- if TkDOT === dot or TkCOLON2 === dot then
+ case dot = get_tk
+ when TkDOT, TkCOLON2 then
@scanner.instance_eval do @lex_state = EXPR_FNAME end
skip_tkspace
name_t2 = get_tk
case name_t
when TkSELF, TkMOD then
- name = name_t2.name
+ name = case name_t2
+ # NOTE: work around '[' being consumed early and not being
+ # re-tokenized as a TkAREF
+ when TkfLBRACK then
+ get_tk
+ '[]'
+ else
+ name_t2.name
+ end
when TkCONSTANT then
name = name_t2.name
prev_container = container
@@ -1039,11 +1121,12 @@ class RDoc::Parser::Ruby < RDoc::Parser
when TkIDENTIFIER, TkIVAR, TkGVAR then
dummy = RDoc::Context.new
dummy.parent = container
+ dummy.store = container.store
skip_method dummy
return
when TkTRUE, TkFALSE, TkNIL then
klass_name = "#{name_t.name.capitalize}Class"
- container = RDoc::TopLevel.find_class_named klass_name
+ container = @store.find_class_named klass_name
container ||= @top_level.add_class RDoc::NormalClass, klass_name
name = name_t2.name
@@ -1084,10 +1167,10 @@ class RDoc::Parser::Ruby < RDoc::Parser
meth.line = line_no
meth.start_collecting_tokens
- indent = TkSPACE.new nil, 1, 1
+ indent = TkSPACE.new 0, 1, 1
indent.set_text " " * column
- token = TkCOMMENT.new nil, line_no, 1
+ token = TkCOMMENT.new 0, line_no, 1
token.set_text "# File #{@top_level.absolute_name}, line #{line_no}"
meth.add_tokens [token, NEWLINE_TOKEN, indent]
meth.add_tokens @token_stream
@@ -1118,7 +1201,8 @@ class RDoc::Parser::Ruby < RDoc::Parser
parse_statements container, single, meth
end
- extract_call_seq comment, meth
+ comment.normalize
+ comment.extract_call_seq meth
meth.comment = comment
@@ -1212,17 +1296,18 @@ class RDoc::Parser::Ruby < RDoc::Parser
##
# Parses an RDoc::NormalModule in +container+ with +comment+
- def parse_module(container, single, tk, comment)
+ def parse_module container, single, tk, comment
container, name_t, = get_class_or_module container
name = name_t.name
mod = container.add_module RDoc::NormalModule, name
+ mod.ignore unless container.document_children
mod.record_location @top_level
read_documentation_modifiers mod, RDoc::CLASS_MODIFIERS
mod.add_comment comment, @top_level
- parse_statements(mod)
+ parse_statements mod
@top_level.add_to_classes_or_modules mod
@stats.add_module mod
@@ -1253,7 +1338,8 @@ class RDoc::Parser::Ruby < RDoc::Parser
# The core of the ruby parser.
def parse_statements(container, single = NORMAL, current_method = nil,
- comment = '')
+ comment = new_comment(''))
+ raise 'no' unless RDoc::Comment === comment
comment.force_encoding @encoding if @encoding
nest = 1
@@ -1293,6 +1379,8 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
end
+ comment = new_comment comment
+
unless comment.empty? then
look_for_directives_in container, comment
@@ -1306,18 +1394,14 @@ class RDoc::Parser::Ruby < RDoc::Parser
non_comment_seen = true
end
- unget_tk tk # TODO peek instead of get then unget
+ unget_tk tk
keep_comment = true
when TkCLASS then
parse_class container, single, tk, comment
when TkMODULE then
- if container.document_children then
- parse_module container, single, tk, comment
- else
- nest += 1
- end
+ parse_module container, single, tk, comment
when TkDEF then
parse_method container, single, tk, comment
@@ -1354,6 +1438,9 @@ class RDoc::Parser::Ruby < RDoc::Parser
when TkCASE, TkDO, TkIF, TkUNLESS, TkBEGIN then
nest += 1
+ when TkSUPER then
+ current_method.calls_super = true if current_method
+
when TkIDENTIFIER then
if nest == 1 and current_method.nil? then
case tk.name
@@ -1370,12 +1457,16 @@ class RDoc::Parser::Ruby < RDoc::Parser
when 'require', 'include' then
# ignore
else
- if comment =~ /\A#\#$/ then
- case comment
+ if comment.text =~ /\A#\#$/ then
+ case comment.text
when /^# +:?attr(_reader|_writer|_accessor)?:/ then
parse_meta_attr container, single, tk, comment
else
- parse_meta_method container, single, tk, comment
+ method = parse_meta_method container, single, tk, comment
+ method.params = container.params if
+ container.params
+ method.block_params = container.block_params if
+ container.block_params
end
end
end
@@ -1386,6 +1477,8 @@ class RDoc::Parser::Ruby < RDoc::Parser
parse_require container, comment
when "include" then
parse_include container, comment
+ when "extend" then
+ parse_extend container, comment
end
when TkEND then
@@ -1410,8 +1503,10 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
unless keep_comment then
- comment = ''
+ comment = new_comment ''
comment.force_encoding @encoding if @encoding
+ container.params = nil
+ container.block_params = nil
end
begin
@@ -1419,6 +1514,9 @@ class RDoc::Parser::Ruby < RDoc::Parser
skip_tkspace false
end while peek_tk == TkNL
end
+
+ container.params = nil
+ container.block_params = nil
end
##
@@ -1497,8 +1595,11 @@ class RDoc::Parser::Ruby < RDoc::Parser
def parse_top_level_statements container
comment = collect_first_comment
+
look_for_directives_in container, comment
+ @markup = comment.format
+
# HACK move if to RDoc::Context#comment=
container.comment = comment if container.document_self unless comment.empty?
@@ -1604,28 +1705,44 @@ class RDoc::Parser::Ruby < RDoc::Parser
#
# class MyClass # :nodoc:
#
- # We return the directive name and any parameters as a two element array
+ # We return the directive name and any parameters as a two element array if
+ # the name is in +allowed+. A directive can be found anywhere up to the end
+ # of the current line.
def read_directive allowed
- tk = get_tk
+ tokens = []
- if TkCOMMENT === tk then
- return unless tk.text =~ /\s*:?(\w+):\s*(.*)/
+ while tk = get_tk do
+ tokens << tk
- directive = $1.downcase
+ case tk
+ when TkNL then return
+ when TkCOMMENT then
+ return unless tk.text =~ /\s*:?([\w-]+):\s*(.*)/
- return [directive, $2] if allowed.include? directive
- else
- unget_tk tk
+ directive = $1.downcase
+
+ return [directive, $2] if allowed.include? directive
+
+ return
+ end
+ end
+ ensure
+ unless tokens.length == 1 and TkCOMMENT === tokens.first then
+ tokens.reverse_each do |token|
+ unget_tk token
+ end
end
end
##
- # Handles the directive for +context+ if the directive is listed in +allow+.
- # This method is called for directives following a definition.
+ # Handles directives following the definition for +context+ (any
+ # RDoc::CodeObject) if the directives are +allowed+ at this point.
+ #
+ # See also RDoc::Markup::PreProcess#handle_directive
- def read_documentation_modifiers context, allow
- directive, value = read_directive allow
+ def read_documentation_modifiers context, allowed
+ directive, value = read_directive allowed
return unless directive
@@ -1640,13 +1757,11 @@ class RDoc::Parser::Ruby < RDoc::Parser
##
# Removes private comments from +comment+
+ #--
+ # TODO remove
- def remove_private_comments(comment)
- empty = ''
- empty.force_encoding comment.encoding if Object.const_defined? :Encoding
-
- comment.gsub!(/^#--.*?^#\+\+\n?/m, empty)
- comment.sub!(/^#--.*/m, '')
+ def remove_private_comments comment
+ comment.remove_private
end
##
@@ -1658,6 +1773,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
catch :eof do
begin
parse_top_level_statements @top_level
+
rescue StandardError => e
bytes = ''
@@ -1770,12 +1886,10 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
##
- # Prints +msg+ to +$stderr+ unless we're being quiet
+ # Prints +message+ to +$stderr+ unless we're being quiet
- def warn(msg)
- return if @options.quiet
- msg = make_message msg
- $stderr.puts msg
+ def warn message
+ @options.warn make_message message
end
end
diff --git a/lib/rdoc/parser/ruby_tools.rb b/lib/rdoc/parser/ruby_tools.rb
index 678f721624..654431ea30 100644
--- a/lib/rdoc/parser/ruby_tools.rb
+++ b/lib/rdoc/parser/ruby_tools.rb
@@ -43,8 +43,7 @@ module RDoc::Parser::RubyTools
tk = Token(TkSYMBOL).set_text(":" + tk1.text)
end
- # remove the identifier we just read (we're about to replace it with a
- # symbol)
+ # remove the identifier we just read to replace it with a symbol
@token_listeners.each do |obj|
obj.pop_token
end if @token_listeners
@@ -70,7 +69,13 @@ module RDoc::Parser::RubyTools
loop do
tk = get_tk
- case tk when *tokens then unget_tk tk; break end
+
+ case tk
+ when *tokens then
+ unget_tk tk
+ break
+ end
+
read << tk
end
diff --git a/lib/rdoc/parser/simple.rb b/lib/rdoc/parser/simple.rb
index 1e82eb5097..65cfc1b2e7 100644
--- a/lib/rdoc/parser/simple.rb
+++ b/lib/rdoc/parser/simple.rb
@@ -4,6 +4,8 @@
class RDoc::Parser::Simple < RDoc::Parser
+ include RDoc::Parser::Text
+
parse_files_matching(//)
attr_reader :content # :nodoc:
@@ -24,26 +26,36 @@ class RDoc::Parser::Simple < RDoc::Parser
def scan
comment = remove_coding_comment @content
- comment = remove_private_comments comment
+ comment = remove_private_comment comment
+
+ comment = RDoc::Comment.new comment, @top_level
@top_level.comment = comment
- @top_level.parser = self.class
@top_level
end
##
- # Removes comments wrapped in <tt>--/++</tt>
-
- def remove_private_comments text
- text.gsub(/^--\n.*?^\+\+/m, '').sub(/^--\n.*/m, '')
- end
-
- ##
# Removes the encoding magic comment from +text+
def remove_coding_comment text
text.sub(/\A# .*coding[=:].*$/, '')
end
+ ##
+ # Removes private comments.
+ #
+ # Unlike RDoc::Comment#remove_private this implementation only looks for two
+ # dashes at the beginning of the line. Three or more dashes are considered
+ # to be a rule and ignored.
+
+ def remove_private_comment comment
+ # Workaround for gsub encoding for Ruby 1.9.2 and earlier
+ empty = ''
+ empty.force_encoding comment.encoding if Object.const_defined? :Encoding
+
+ comment = comment.gsub(%r%^--\n.*?^\+\+\n?%m, empty)
+ comment.sub(%r%^--\n.*%m, empty)
+ end
+
end
diff --git a/lib/rdoc/parser/text.rb b/lib/rdoc/parser/text.rb
new file mode 100644
index 0000000000..f973313551
--- /dev/null
+++ b/lib/rdoc/parser/text.rb
@@ -0,0 +1,11 @@
+##
+# Indicates this parser is text and doesn't contain code constructs.
+#
+# Include this module in a RDoc::Parser subclass to make it show up as a file,
+# not as part of a class or module.
+#--
+# This is not named File to avoid overriding ::File
+
+module RDoc::Parser::Text
+end
+
diff --git a/lib/rdoc/rd.rb b/lib/rdoc/rd.rb
new file mode 100644
index 0000000000..28c5d286e0
--- /dev/null
+++ b/lib/rdoc/rd.rb
@@ -0,0 +1,99 @@
+##
+# RDoc::RD implements the RD format from the rdtool gem.
+#
+# To choose RD as your only default format see
+# RDoc::Options@Saved+Options for instructions on setting up a
+# <code>.doc_options</code> file to store your project default.
+#
+# == LICENSE
+#
+# The grammar that produces RDoc::RD::BlockParser and RDoc::RD::InlineParser
+# is included in RDoc under the Ruby License.
+#
+# You can find the original source for rdtool at
+# https://github.com/uwabami/rdtool/
+#
+# You can use, re-distribute or change these files under Ruby's License or GPL.
+#
+# 1. You may make and give away verbatim copies of the source form of the
+# software without restriction, provided that you duplicate all of the
+# original copyright notices and associated disclaimers.
+#
+# 2. You may modify your copy of the software in any way, provided that
+# you do at least ONE of the following:
+#
+# a. place your modifications in the Public Domain or otherwise
+# make them Freely Available, such as by posting said
+# modifications to Usenet or an equivalent medium, or by allowing
+# the author to include your modifications in the software.
+#
+# b. use the modified software only within your corporation or
+# organization.
+#
+# c. give non-standard binaries non-standard names, with
+# instructions on where to get the original software distribution.
+#
+# d. make other distribution arrangements with the author.
+#
+# 3. You may distribute the software in object code or binary form,
+# provided that you do at least ONE of the following:
+#
+# a. distribute the binaries and library files of the software,
+# together with instructions (in the manual page or equivalent)
+# on where to get the original distribution.
+#
+# b. accompany the distribution with the machine-readable source of
+# the software.
+#
+# c. give non-standard binaries non-standard names, with
+# instructions on where to get the original software distribution.
+#
+# d. make other distribution arrangements with the author.
+#
+# 4. You may modify and include the part of the software into any other
+# software (possibly commercial). But some files in the distribution
+# are not written by the author, so that they are not under these terms.
+#
+# For the list of those files and their copying conditions, see the
+# file LEGAL.
+#
+# 5. The scripts and library files supplied as input to or produced as
+# output from the software do not automatically fall under the
+# copyright of the software, but belong to whomever generated them,
+# and may be sold commercially, and may be aggregated with this
+# software.
+#
+# 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE.
+
+class RDoc::RD
+
+ ##
+ # Parses +rd+ source and returns an RDoc::Markup::Document. If the
+ # <tt>=begin</tt> or <tt>=end</tt> lines are missing they will be added.
+
+ def self.parse rd
+ rd = rd.lines.to_a
+
+ if rd.find { |i| /\S/ === i } and !rd.find{|i| /^=begin\b/ === i } then
+ rd.unshift("=begin\n").push("=end\n")
+ end
+
+ parser = RDoc::RD::BlockParser.new
+ document = parser.parse rd
+
+ # isn't this always true?
+ document.parts.shift if RDoc::Markup::BlankLine === document.parts.first
+ document.parts.pop if RDoc::Markup::BlankLine === document.parts.last
+
+ document
+ end
+
+ autoload :BlockParser, 'rdoc/rd/block_parser'
+ autoload :InlineParser, 'rdoc/rd/inline_parser'
+ autoload :Inline, 'rdoc/rd/inline'
+
+end
+
diff --git a/lib/rdoc/rd/block_parser.rb b/lib/rdoc/rd/block_parser.rb
new file mode 100644
index 0000000000..e74f3f2901
--- /dev/null
+++ b/lib/rdoc/rd/block_parser.rb
@@ -0,0 +1,1054 @@
+#
+# DO NOT MODIFY!!!!
+# This file is automatically generated by Racc 1.4.9
+# from Racc grammer file "".
+#
+
+require 'racc/parser.rb'
+
+class RDoc::RD
+
+##
+# RD format parser for headings, paragraphs, lists, verbatim sections that
+# exist as blocks.
+
+class BlockParser < Racc::Parser
+
+
+# :stopdoc:
+
+TMPFILE = ["rdtmp", $$, 0]
+
+MARK_TO_LEVEL = {
+ '=' => 1,
+ '==' => 2,
+ '===' => 3,
+ '====' => 4,
+ '+' => 5,
+ '++' => 6,
+}
+
+# :startdoc:
+
+##
+# Footnotes for this document
+
+attr_reader :footnotes
+
+##
+# Labels for items in this document
+
+attr_reader :labels
+
+##
+# Path to find included files in
+
+attr_accessor :include_path
+
+##
+# Creates a new RDoc::RD::BlockParser. Use #parse to parse an rd-format
+# document.
+
+def initialize
+ @inline_parser = RDoc::RD::InlineParser.new self
+ @include_path = []
+
+ # for testing
+ @footnotes = []
+ @labels = {}
+end
+
+##
+# Parses +src+ and returns an RDoc::Markup::Document.
+
+def parse src
+ @src = src
+ @src.push false
+
+ @footnotes = []
+ @labels = {}
+
+ # @i: index(line no.) of src
+ @i = 0
+
+ # stack for current indentation
+ @indent_stack = []
+
+ # how indented.
+ @current_indent = @indent_stack.join("")
+
+ # RDoc::RD::BlockParser for tmp src
+ @subparser = nil
+
+ # which part is in now
+ @in_part = nil
+ @part_content = []
+
+ @in_verbatim = false
+
+ @yydebug = true
+
+ document = do_parse
+
+ unless @footnotes.empty? then
+ blankline = document.parts.pop
+
+ document.parts << RDoc::Markup::Rule.new(1)
+ document.parts.concat @footnotes
+
+ document.parts.push blankline
+ end
+
+ document
+end
+
+##
+# Returns the next token from the document
+
+def next_token # :nodoc:
+ # preprocessing
+ # if it is not in RD part
+ # => method
+ while @in_part != "rd"
+ line = @src[@i]
+ @i += 1 # next line
+
+ case line
+ # src end
+ when false
+ return [false, false]
+ # RD part begin
+ when /^=begin\s*(?:\bRD\b.*)?\s*$/
+ if @in_part # if in non-RD part
+ @part_content.push(line)
+ else
+ @in_part = "rd"
+ return [:WHITELINE, "=begin\n"] # <= for textblockand
+ end
+ # non-RD part begin
+ when /^=begin\s+(\w+)/
+ part = $1
+ if @in_part # if in non-RD part
+ @part_content.push(line)
+ else
+ @in_part = part if @tree.filter[part] # if filter exists
+# p "BEGIN_PART: #{@in_part}" # DEBUG
+ end
+ # non-RD part end
+ when /^=end/
+ if @in_part # if in non-RD part
+# p "END_PART: #{@in_part}" # DEBUG
+ # make Part-in object
+ part = RDoc::RD::Part.new(@part_content.join(""), @tree, "r")
+ @part_content.clear
+ # call filter, part_out is output(Part object)
+ part_out = @tree.filter[@in_part].call(part)
+
+ if @tree.filter[@in_part].mode == :rd # if output is RD formated
+ subtree = parse_subtree(part_out.to_a)
+ else # if output is target formated
+ basename = TMPFILE.join('.')
+ TMPFILE[-1] += 1
+ tmpfile = open(@tree.tmp_dir + "/" + basename + ".#{@in_part}", "w")
+ tmpfile.print(part_out)
+ tmpfile.close
+ subtree = parse_subtree(["=begin\n", "<<< #{basename}\n", "=end\n"])
+ end
+ @in_part = nil
+ return [:SUBTREE, subtree]
+ end
+ else
+ if @in_part # if in non-RD part
+ @part_content.push(line)
+ end
+ end
+ end
+
+ @current_indent = @indent_stack.join("")
+ line = @src[@i]
+ case line
+ when false
+ if_current_indent_equal("") do
+ [false, false]
+ end
+ when /^=end/
+ if_current_indent_equal("") do
+ @in_part = nil
+ [:WHITELINE, "=end"] # MUST CHANGE??
+ end
+ when /^\s*$/
+ @i += 1 # next line
+ return [:WHITELINE, ':WHITELINE']
+ when /^\#/ # comment line
+ @i += 1 # next line
+ self.next_token()
+ when /^(={1,4})(?!=)\s*(?=\S)/, /^(\+{1,2})(?!\+)\s*(?=\S)/
+ rest = $' # '
+ rest.strip!
+ mark = $1
+ if_current_indent_equal("") do
+ return [:HEADLINE, [MARK_TO_LEVEL[mark], rest]]
+ end
+ when /^<<<\s*(\S+)/
+ file = $1
+ if_current_indent_equal("") do
+ suffix = file[-3 .. -1]
+ if suffix == ".rd" or suffix == ".rb"
+ subtree = parse_subtree(get_included(file))
+ [:SUBTREE, subtree]
+ else
+ [:INCLUDE, file]
+ end
+ end
+ when /^(\s*)\*(\s*)/
+ rest = $' # '
+ newIndent = $2
+ if_current_indent_equal($1) do
+ if @in_verbatim
+ [:STRINGLINE, line]
+ else
+ @indent_stack.push("\s" << newIndent)
+ [:ITEMLISTLINE, rest]
+ end
+ end
+ when /^(\s*)(\(\d+\))(\s*)/
+ rest = $' # '
+ mark = $2
+ newIndent = $3
+ if_current_indent_equal($1) do
+ if @in_verbatim
+ [:STRINGLINE, line]
+ else
+ @indent_stack.push("\s" * mark.size << newIndent)
+ [:ENUMLISTLINE, rest]
+ end
+ end
+ when /^(\s*):(\s*)/
+ rest = $' # '
+ newIndent = $2
+ if_current_indent_equal($1) do
+ if @in_verbatim
+ [:STRINGLINE, line]
+ else
+ @indent_stack.push("\s#{$2}")
+ [:DESCLISTLINE, rest]
+ end
+ end
+ when /^(\s*)---(?!-|\s*$)/
+ indent = $1
+ rest = $'
+ /\s*/ === rest
+ term = $'
+ new_indent = $&
+ if_current_indent_equal(indent) do
+ if @in_verbatim
+ [:STRINGLINE, line]
+ else
+ @indent_stack.push("\s\s\s" + new_indent)
+ [:METHODLISTLINE, term]
+ end
+ end
+ when /^(\s*)/
+ if_current_indent_equal($1) do
+ [:STRINGLINE, line]
+ end
+ else
+ raise "[BUG] parsing error may occured."
+ end
+end
+
+##
+# Yields to the given block if +indent+ matches the current indent, otherwise
+# an indentation token is processed.
+
+def if_current_indent_equal(indent)
+ indent = indent.sub(/\t/, "\s" * 8)
+ if @current_indent == indent
+ @i += 1 # next line
+ yield
+ elsif indent.index(@current_indent) == 0
+ @indent_stack.push(indent[@current_indent.size .. -1])
+ [:INDENT, ":INDENT"]
+ else
+ @indent_stack.pop
+ [:DEDENT, ":DEDENT"]
+ end
+end
+private :if_current_indent_equal
+
+##
+# Cuts off excess whitespace in +src+
+
+def cut_off(src)
+ ret = []
+ whiteline_buf = []
+
+ line = src.shift
+ /^\s*/ =~ line
+
+ indent = Regexp.quote($&)
+ ret.push($')
+
+ while line = src.shift
+ if /^(\s*)$/ =~ line
+ whiteline_buf.push(line)
+ elsif /^#{indent}/ =~ line
+ unless whiteline_buf.empty?
+ ret.concat(whiteline_buf)
+ whiteline_buf.clear
+ end
+ ret.push($')
+ else
+ raise "[BUG]: probably Parser Error while cutting off.\n"
+ end
+ end
+ ret
+end
+private :cut_off
+
+def set_term_to_element(parent, term)
+# parent.set_term_under_document_struct(term, @tree.document_struct)
+ parent.set_term_without_document_struct(term)
+end
+private :set_term_to_element
+
+##
+# Raises a ParseError when invalid formatting is found
+
+def on_error(et, ev, _values)
+ prv, cur, nxt = format_line_num(@i, @i+1, @i+2)
+
+ raise ParseError, <<Msg
+
+RD syntax error: line #{@i+1}:
+ #{prv} |#{@src[@i-1].chomp}
+ #{cur}=>|#{@src[@i].chomp}
+ #{nxt} |#{@src[@i+1].chomp}
+
+Msg
+end
+
+##
+# Current line number
+
+def line_index
+ @i
+end
+
+##
+# Parses subtree +src+
+
+def parse_subtree src
+ @subparser ||= RDoc::RD::BlockParser.new
+
+ @subparser.parse src
+end
+private :parse_subtree
+
+##
+# Retrieves the content for +file+ from the include_path
+
+def get_included(file)
+ included = []
+
+ @include_path.each do |dir|
+ file_name = File.join dir, file
+
+ if File.exist? file_name then
+ included = IO.readlines file_name
+ break
+ end
+ end
+
+ included
+end
+private :get_included
+
+##
+# Formats line numbers +line_numbers+ prettily
+
+def format_line_num(*line_numbers)
+ width = line_numbers.collect{|i| i.to_s.length }.max
+ line_numbers.collect{|i| sprintf("%#{width}d", i) }
+end
+private :format_line_num
+
+##
+# Retrieves the content of +values+ as a single String
+
+def content values
+ values.map { |value| value.content }.join
+end
+
+##
+# Creates a paragraph for +value+
+
+def paragraph value
+ content = cut_off(value).join(' ').rstrip
+ contents = @inline_parser.parse content
+
+ RDoc::Markup::Paragraph.new(*contents)
+end
+
+##
+# Adds footnote +content+ to the document
+
+def add_footnote content
+ index = @footnotes.length + 1
+
+ footmark_link = "{^#{index}}[rdoc-label:footmark-#{index}:foottext-#{index}]"
+
+ @footnotes << RDoc::Markup::Paragraph.new(footmark_link, *content)
+
+ index
+end
+
+##
+# Adds label +label+ to the document
+
+def add_label label
+ @labels[label] = true
+
+ label
+end
+
+# :stopdoc:
+
+##### State transition tables begin ###
+
+racc_action_table = [
+ 34, 35, 30, 33, 14, 73, 38, 33, 76, 15,
+ 88, 34, 35, 30, 33, 40, 34, 35, 30, 33,
+ 40, 65, 34, 35, 30, 33, 14, 73, 77, 14,
+ 54, 15, 34, 35, 30, 33, 14, 9, 10, 11,
+ 12, 15, 34, 35, 30, 33, 14, 73, 81, 54,
+ 38, 15, 34, 35, 30, 33, 14, 73, 40, 67,
+ 83, 15, 34, 35, 30, 33, 14, 73, 54, 30,
+ 35, 15, 34, 35, 30, 33, 34, 47, 36, 14,
+ 59, 15, 34, 35, 30, 33, 14, 73, 38, nil,
+ nil, 15, 34, 35, 30, 33, nil, 47, nil, nil,
+ nil, 15, 34, 35, 30, 33, 14, 73, nil, nil,
+ nil, 15, 34, 35, 30, 33, 14, 73, nil, nil,
+ nil, 15, 34, 35, 30, 33, 14, 9, 10, 11,
+ 12, 15, 34, 35, 30, 33, 14, 73, nil, nil,
+ nil, 15, 34, 35, 30, 33, 14, 73, 61, 63,
+ nil, 15, nil, 62, 60, 61, 63, 61, 63, 14,
+ 62, 87, 62, nil, 79, 34, 35, 30, 33 ]
+
+racc_action_check = [
+ 86, 86, 86, 86, 86, 86, 57, 31, 49, 86,
+ 86, 41, 41, 41, 41, 41, 15, 15, 15, 15,
+ 15, 41, 45, 45, 45, 45, 45, 45, 51, 34,
+ 54, 45, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 85, 85, 85, 85, 85, 85, 56, 33,
+ 58, 85, 79, 79, 79, 79, 79, 79, 62, 44,
+ 66, 79, 78, 78, 78, 78, 78, 78, 30, 28,
+ 25, 78, 24, 24, 24, 24, 22, 24, 1, 35,
+ 36, 24, 75, 75, 75, 75, 75, 75, 13, nil,
+ nil, 75, 27, 27, 27, 27, nil, 27, nil, nil,
+ nil, 27, 74, 74, 74, 74, 74, 74, nil, nil,
+ nil, 74, 68, 68, 68, 68, 68, 68, nil, nil,
+ nil, 68, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 46, 46, 46, 46, 46, 46, nil, nil,
+ nil, 46, 47, 47, 47, 47, 47, 47, 39, 39,
+ nil, 47, nil, 39, 39, 82, 82, 64, 64, 52,
+ 82, 82, 64, nil, 52, 20, 20, 20, 20 ]
+
+racc_action_pointer = [
+ 29, 78, 119, nil, nil, nil, nil, nil, nil, nil,
+ nil, nil, nil, 81, nil, 13, nil, nil, nil, nil,
+ 162, nil, 73, nil, 69, 66, nil, 89, 64, nil,
+ 60, 1, nil, 41, 22, 72, 80, nil, nil, 141,
+ nil, 8, nil, nil, 46, 19, 129, 139, nil, -5,
+ nil, 15, 152, nil, 22, nil, 35, -1, 43, nil,
+ nil, nil, 51, nil, 150, nil, 47, nil, 109, nil,
+ nil, nil, nil, nil, 99, 79, nil, nil, 59, 49,
+ nil, nil, 148, nil, nil, 39, -3, nil, nil ]
+
+racc_action_default = [
+ -2, -73, -1, -4, -5, -6, -7, -8, -9, -10,
+ -11, -12, -13, -14, -16, -73, -23, -24, -25, -26,
+ -27, -31, -32, -34, -72, -36, -38, -72, -40, -42,
+ -59, -44, -46, -59, -63, -65, -73, -3, -15, -73,
+ -22, -73, -30, -33, -73, -69, -70, -71, -37, -73,
+ -41, -73, -51, -58, -61, -45, -73, -62, -64, 89,
+ -17, -19, -73, -21, -18, -28, -73, -35, -66, -53,
+ -54, -55, -56, -57, -67, -68, -39, -43, -49, -73,
+ -60, -47, -73, -29, -52, -48, -73, -20, -50 ]
+
+racc_goto_table = [
+ 4, 39, 4, 68, 74, 75, 5, 6, 5, 6,
+ 51, 42, 44, 56, 3, 49, 37, 57, 58, 41,
+ 43, 48, 84, 50, 66, 55, 1, 64, 84, 84,
+ 45, 46, 42, 45, 46, 2, 85, 86, 80, 84,
+ 84, nil, nil, nil, nil, nil, nil, nil, 82, nil,
+ nil, nil, 78 ]
+
+racc_goto_check = [
+ 4, 10, 4, 31, 31, 31, 5, 6, 5, 6,
+ 27, 12, 21, 27, 3, 21, 3, 9, 9, 17,
+ 19, 23, 32, 26, 11, 29, 1, 10, 32, 32,
+ 5, 6, 12, 5, 6, 2, 31, 31, 33, 32,
+ 32, nil, nil, nil, nil, nil, nil, nil, 10, nil,
+ nil, nil, 4 ]
+
+racc_goto_pointer = [
+ nil, 26, 35, 14, 0, 6, 7, nil, nil, -17,
+ -14, -17, -9, nil, nil, nil, nil, 4, nil, -2,
+ nil, -12, nil, -4, nil, nil, -5, -20, nil, -6,
+ nil, -42, -46, -16 ]
+
+racc_goto_default = [
+ nil, nil, nil, nil, 70, 71, 72, 7, 8, 13,
+ nil, nil, 21, 16, 17, 18, 19, 20, 22, 23,
+ 24, nil, 25, 26, 27, 28, 29, nil, 31, 32,
+ 52, nil, 69, 53 ]
+
+racc_reduce_table = [
+ 0, 0, :racc_error,
+ 1, 15, :_reduce_1,
+ 0, 15, :_reduce_2,
+ 2, 16, :_reduce_3,
+ 1, 16, :_reduce_4,
+ 1, 17, :_reduce_5,
+ 1, 17, :_reduce_6,
+ 1, 17, :_reduce_none,
+ 1, 17, :_reduce_8,
+ 1, 17, :_reduce_9,
+ 1, 17, :_reduce_10,
+ 1, 17, :_reduce_11,
+ 1, 21, :_reduce_12,
+ 1, 22, :_reduce_13,
+ 1, 18, :_reduce_14,
+ 2, 23, :_reduce_15,
+ 1, 23, :_reduce_16,
+ 3, 19, :_reduce_17,
+ 1, 25, :_reduce_18,
+ 2, 24, :_reduce_19,
+ 4, 24, :_reduce_20,
+ 2, 24, :_reduce_21,
+ 1, 24, :_reduce_22,
+ 1, 26, :_reduce_none,
+ 1, 26, :_reduce_none,
+ 1, 26, :_reduce_none,
+ 1, 26, :_reduce_none,
+ 1, 20, :_reduce_27,
+ 3, 20, :_reduce_28,
+ 4, 20, :_reduce_29,
+ 2, 31, :_reduce_30,
+ 1, 31, :_reduce_31,
+ 1, 27, :_reduce_32,
+ 2, 32, :_reduce_33,
+ 1, 32, :_reduce_34,
+ 3, 33, :_reduce_35,
+ 1, 28, :_reduce_36,
+ 2, 36, :_reduce_37,
+ 1, 36, :_reduce_38,
+ 3, 37, :_reduce_39,
+ 1, 29, :_reduce_40,
+ 2, 39, :_reduce_41,
+ 1, 39, :_reduce_42,
+ 3, 40, :_reduce_43,
+ 1, 30, :_reduce_44,
+ 2, 42, :_reduce_45,
+ 1, 42, :_reduce_46,
+ 3, 43, :_reduce_47,
+ 3, 41, :_reduce_48,
+ 2, 41, :_reduce_49,
+ 4, 41, :_reduce_50,
+ 1, 41, :_reduce_51,
+ 2, 45, :_reduce_52,
+ 1, 45, :_reduce_none,
+ 1, 46, :_reduce_54,
+ 1, 46, :_reduce_55,
+ 1, 46, :_reduce_none,
+ 1, 46, :_reduce_57,
+ 1, 44, :_reduce_none,
+ 0, 44, :_reduce_none,
+ 2, 47, :_reduce_none,
+ 1, 47, :_reduce_none,
+ 2, 34, :_reduce_62,
+ 1, 34, :_reduce_63,
+ 2, 38, :_reduce_64,
+ 1, 38, :_reduce_65,
+ 2, 35, :_reduce_66,
+ 2, 35, :_reduce_67,
+ 2, 35, :_reduce_68,
+ 1, 35, :_reduce_69,
+ 1, 35, :_reduce_none,
+ 1, 35, :_reduce_71,
+ 0, 35, :_reduce_72 ]
+
+racc_reduce_n = 73
+
+racc_shift_n = 89
+
+racc_token_table = {
+ false => 0,
+ :error => 1,
+ :DUMMY => 2,
+ :ITEMLISTLINE => 3,
+ :ENUMLISTLINE => 4,
+ :DESCLISTLINE => 5,
+ :METHODLISTLINE => 6,
+ :STRINGLINE => 7,
+ :WHITELINE => 8,
+ :SUBTREE => 9,
+ :HEADLINE => 10,
+ :INCLUDE => 11,
+ :INDENT => 12,
+ :DEDENT => 13 }
+
+racc_nt_base = 14
+
+racc_use_result_var = true
+
+Racc_arg = [
+ racc_action_table,
+ racc_action_check,
+ racc_action_default,
+ racc_action_pointer,
+ racc_goto_table,
+ racc_goto_check,
+ racc_goto_default,
+ racc_goto_pointer,
+ racc_nt_base,
+ racc_reduce_table,
+ racc_token_table,
+ racc_shift_n,
+ racc_reduce_n,
+ racc_use_result_var ]
+
+Racc_token_to_s_table = [
+ "$end",
+ "error",
+ "DUMMY",
+ "ITEMLISTLINE",
+ "ENUMLISTLINE",
+ "DESCLISTLINE",
+ "METHODLISTLINE",
+ "STRINGLINE",
+ "WHITELINE",
+ "SUBTREE",
+ "HEADLINE",
+ "INCLUDE",
+ "INDENT",
+ "DEDENT",
+ "$start",
+ "document",
+ "blocks",
+ "block",
+ "textblock",
+ "verbatim",
+ "lists",
+ "headline",
+ "include",
+ "textblockcontent",
+ "verbatimcontent",
+ "verbatim_after_lists",
+ "list",
+ "itemlist",
+ "enumlist",
+ "desclist",
+ "methodlist",
+ "lists2",
+ "itemlistitems",
+ "itemlistitem",
+ "first_textblock_in_itemlist",
+ "other_blocks_in_list",
+ "enumlistitems",
+ "enumlistitem",
+ "first_textblock_in_enumlist",
+ "desclistitems",
+ "desclistitem",
+ "description_part",
+ "methodlistitems",
+ "methodlistitem",
+ "whitelines",
+ "blocks_in_list",
+ "block_in_list",
+ "whitelines2" ]
+
+Racc_debug_parser = false
+
+##### State transition tables end #####
+
+# reduce 0 omitted
+
+def _reduce_1(val, _values, result)
+ result = RDoc::Markup::Document.new(*val[0])
+ result
+end
+
+def _reduce_2(val, _values, result)
+ raise ParseError, "file empty"
+ result
+end
+
+def _reduce_3(val, _values, result)
+ result = val[0].concat val[1]
+ result
+end
+
+def _reduce_4(val, _values, result)
+ result = val[0]
+ result
+end
+
+def _reduce_5(val, _values, result)
+ result = val
+ result
+end
+
+def _reduce_6(val, _values, result)
+ result = val
+ result
+end
+
+# reduce 7 omitted
+
+def _reduce_8(val, _values, result)
+ result = val
+ result
+end
+
+def _reduce_9(val, _values, result)
+ result = val
+ result
+end
+
+def _reduce_10(val, _values, result)
+ result = [RDoc::Markup::BlankLine.new]
+ result
+end
+
+def _reduce_11(val, _values, result)
+ result = val[0].parts
+ result
+end
+
+def _reduce_12(val, _values, result)
+ # val[0] is like [level, title]
+ title = @inline_parser.parse(val[0][1])
+ result = RDoc::Markup::Heading.new(val[0][0], title)
+
+ result
+end
+
+def _reduce_13(val, _values, result)
+ result = RDoc::Markup::Include.new val[0], @include_path
+
+ result
+end
+
+def _reduce_14(val, _values, result)
+ # val[0] is Array of String
+ result = paragraph val[0]
+
+ result
+end
+
+def _reduce_15(val, _values, result)
+ result << val[1].rstrip
+ result
+end
+
+def _reduce_16(val, _values, result)
+ result = [val[0].rstrip]
+ result
+end
+
+def _reduce_17(val, _values, result)
+ # val[1] is Array of String
+ content = cut_off val[1]
+ result = RDoc::Markup::Verbatim.new(*content)
+
+ # imform to lexer.
+ @in_verbatim = false
+
+ result
+end
+
+def _reduce_18(val, _values, result)
+ # val[0] is Array of String
+ content = cut_off val[0]
+ result = RDoc::Markup::Verbatim.new(*content)
+
+ # imform to lexer.
+ @in_verbatim = false
+
+ result
+end
+
+def _reduce_19(val, _values, result)
+ result << val[1]
+
+ result
+end
+
+def _reduce_20(val, _values, result)
+ result.concat val[2]
+
+ result
+end
+
+def _reduce_21(val, _values, result)
+ result << "\n"
+
+ result
+end
+
+def _reduce_22(val, _values, result)
+ result = val
+ # inform to lexer.
+ @in_verbatim = true
+
+ result
+end
+
+# reduce 23 omitted
+
+# reduce 24 omitted
+
+# reduce 25 omitted
+
+# reduce 26 omitted
+
+def _reduce_27(val, _values, result)
+ result = val[0]
+
+ result
+end
+
+def _reduce_28(val, _values, result)
+ result = val[1]
+
+ result
+end
+
+def _reduce_29(val, _values, result)
+ result = val[1].push(val[2])
+
+ result
+end
+
+def _reduce_30(val, _values, result)
+ result = val[0] << val[1]
+ result
+end
+
+def _reduce_31(val, _values, result)
+ result = [val[0]]
+ result
+end
+
+def _reduce_32(val, _values, result)
+ result = RDoc::Markup::List.new :BULLET, *val[0]
+
+ result
+end
+
+def _reduce_33(val, _values, result)
+ result.push(val[1])
+ result
+end
+
+def _reduce_34(val, _values, result)
+ result = val
+ result
+end
+
+def _reduce_35(val, _values, result)
+ result = RDoc::Markup::ListItem.new nil, val[0], *val[1]
+
+ result
+end
+
+def _reduce_36(val, _values, result)
+ result = RDoc::Markup::List.new :NUMBER, *val[0]
+
+ result
+end
+
+def _reduce_37(val, _values, result)
+ result.push(val[1])
+ result
+end
+
+def _reduce_38(val, _values, result)
+ result = val
+ result
+end
+
+def _reduce_39(val, _values, result)
+ result = RDoc::Markup::ListItem.new nil, val[0], *val[1]
+
+ result
+end
+
+def _reduce_40(val, _values, result)
+ result = RDoc::Markup::List.new :NOTE, *val[0]
+
+ result
+end
+
+def _reduce_41(val, _values, result)
+ result.push(val[1])
+ result
+end
+
+def _reduce_42(val, _values, result)
+ result = val
+ result
+end
+
+def _reduce_43(val, _values, result)
+ term = @inline_parser.parse val[0].strip
+
+ result = RDoc::Markup::ListItem.new term, *val[1]
+
+ result
+end
+
+def _reduce_44(val, _values, result)
+ result = RDoc::Markup::List.new :LABEL, *val[0]
+
+ result
+end
+
+def _reduce_45(val, _values, result)
+ result.push(val[1])
+ result
+end
+
+def _reduce_46(val, _values, result)
+ result = val
+ result
+end
+
+def _reduce_47(val, _values, result)
+ result = RDoc::Markup::ListItem.new "<tt>#{val[0].strip}</tt>", *val[1]
+
+ result
+end
+
+def _reduce_48(val, _values, result)
+ result = [val[1]].concat(val[2])
+
+ result
+end
+
+def _reduce_49(val, _values, result)
+ result = [val[1]]
+
+ result
+end
+
+def _reduce_50(val, _values, result)
+ result = val[2]
+
+ result
+end
+
+def _reduce_51(val, _values, result)
+ result = []
+
+ result
+end
+
+def _reduce_52(val, _values, result)
+ result.concat val[1]
+ result
+end
+
+# reduce 53 omitted
+
+def _reduce_54(val, _values, result)
+ result = val
+ result
+end
+
+def _reduce_55(val, _values, result)
+ result = val
+ result
+end
+
+# reduce 56 omitted
+
+def _reduce_57(val, _values, result)
+ result = []
+ result
+end
+
+# reduce 58 omitted
+
+# reduce 59 omitted
+
+# reduce 60 omitted
+
+# reduce 61 omitted
+
+def _reduce_62(val, _values, result)
+ result = paragraph [val[0]].concat(val[1])
+
+ result
+end
+
+def _reduce_63(val, _values, result)
+ result = paragraph [val[0]]
+
+ result
+end
+
+def _reduce_64(val, _values, result)
+ result = paragraph [val[0]].concat(val[1])
+
+ result
+end
+
+def _reduce_65(val, _values, result)
+ result = paragraph [val[0]]
+
+ result
+end
+
+def _reduce_66(val, _values, result)
+ result = [val[0]].concat(val[1])
+
+ result
+end
+
+def _reduce_67(val, _values, result)
+ result.concat val[1]
+ result
+end
+
+def _reduce_68(val, _values, result)
+ result = val[1]
+ result
+end
+
+def _reduce_69(val, _values, result)
+ result = val
+ result
+end
+
+# reduce 70 omitted
+
+def _reduce_71(val, _values, result)
+ result = []
+ result
+end
+
+def _reduce_72(val, _values, result)
+ result = []
+ result
+end
+
+def _reduce_none(val, _values, result)
+ val[0]
+end
+
+end # class BlockParser
+
+end
diff --git a/lib/rdoc/rd/inline.rb b/lib/rdoc/rd/inline.rb
new file mode 100644
index 0000000000..ee724fb80f
--- /dev/null
+++ b/lib/rdoc/rd/inline.rb
@@ -0,0 +1,71 @@
+##
+# Inline keeps track of markup and labels to create proper links.
+
+class RDoc::RD::Inline
+
+ ##
+ # The text of the reference
+
+ attr_reader :reference
+
+ ##
+ # The markup of this reference in RDoc format
+
+ attr_reader :rdoc
+
+ ##
+ # Creates a new Inline for +rdoc+ and +reference+.
+ #
+ # +rdoc+ may be another Inline or a String. If +reference+ is not given it
+ # will use the text from +rdoc+.
+
+ def self.new rdoc, reference = rdoc
+ if self === rdoc and reference.equal? rdoc then
+ rdoc
+ else
+ super
+ end
+ end
+
+ ##
+ # Initializes the Inline with +rdoc+ and +inline+
+
+ def initialize rdoc, reference # :not-new:
+ @reference = reference.equal?(rdoc) ? reference.dup : reference
+
+ # unpack
+ @reference = @reference.reference if self.class === @reference
+ @rdoc = rdoc
+ end
+
+ def == other # :nodoc:
+ self.class === other and
+ @reference == other.reference and @rdoc == other.rdoc
+ end
+
+ ##
+ # Appends +more+ to this inline. +more+ may be a String or another Inline.
+
+ def append more
+ case more
+ when String then
+ @reference << more
+ @rdoc << more
+ when RDoc::RD::Inline then
+ @reference << more.reference
+ @rdoc << more.rdoc
+ else
+ raise "unknown thingy #{more}"
+ end
+
+ self
+ end
+
+ def inspect # :nodoc:
+ "(inline: #{self})"
+ end
+
+ alias to_s rdoc # :nodoc:
+
+end
+
diff --git a/lib/rdoc/rd/inline_parser.rb b/lib/rdoc/rd/inline_parser.rb
new file mode 100644
index 0000000000..03a1e84dea
--- /dev/null
+++ b/lib/rdoc/rd/inline_parser.rb
@@ -0,0 +1,1207 @@
+#
+# DO NOT MODIFY!!!!
+# This file is automatically generated by Racc 1.4.9
+# from Racc grammer file "".
+#
+
+require 'racc/parser.rb'
+
+require 'strscan'
+
+class RDoc::RD
+
+##
+# RD format parser for inline markup such as emphasis, links, footnotes, etc.
+
+class InlineParser < Racc::Parser
+
+
+# :stopdoc:
+
+EM_OPEN = '((*'
+EM_OPEN_RE = /\A#{Regexp.quote(EM_OPEN)}/
+EM_CLOSE = '*))'
+EM_CLOSE_RE = /\A#{Regexp.quote(EM_CLOSE)}/
+CODE_OPEN = '(({'
+CODE_OPEN_RE = /\A#{Regexp.quote(CODE_OPEN)}/
+CODE_CLOSE = '}))'
+CODE_CLOSE_RE = /\A#{Regexp.quote(CODE_CLOSE)}/
+VAR_OPEN = '((|'
+VAR_OPEN_RE = /\A#{Regexp.quote(VAR_OPEN)}/
+VAR_CLOSE = '|))'
+VAR_CLOSE_RE = /\A#{Regexp.quote(VAR_CLOSE)}/
+KBD_OPEN = '((%'
+KBD_OPEN_RE = /\A#{Regexp.quote(KBD_OPEN)}/
+KBD_CLOSE = '%))'
+KBD_CLOSE_RE = /\A#{Regexp.quote(KBD_CLOSE)}/
+INDEX_OPEN = '((:'
+INDEX_OPEN_RE = /\A#{Regexp.quote(INDEX_OPEN)}/
+INDEX_CLOSE = ':))'
+INDEX_CLOSE_RE = /\A#{Regexp.quote(INDEX_CLOSE)}/
+REF_OPEN = '((<'
+REF_OPEN_RE = /\A#{Regexp.quote(REF_OPEN)}/
+REF_CLOSE = '>))'
+REF_CLOSE_RE = /\A#{Regexp.quote(REF_CLOSE)}/
+FOOTNOTE_OPEN = '((-'
+FOOTNOTE_OPEN_RE = /\A#{Regexp.quote(FOOTNOTE_OPEN)}/
+FOOTNOTE_CLOSE = '-))'
+FOOTNOTE_CLOSE_RE = /\A#{Regexp.quote(FOOTNOTE_CLOSE)}/
+VERB_OPEN = "(('"
+VERB_OPEN_RE = /\A#{Regexp.quote(VERB_OPEN)}/
+VERB_CLOSE = "'))"
+VERB_CLOSE_RE = /\A#{Regexp.quote(VERB_CLOSE)}/
+
+BAR = "|"
+BAR_RE = /\A#{Regexp.quote(BAR)}/
+QUOTE = '"'
+QUOTE_RE = /\A#{Regexp.quote(QUOTE)}/
+SLASH = "/"
+SLASH_RE = /\A#{Regexp.quote(SLASH)}/
+BACK_SLASH = "\\"
+BACK_SLASH_RE = /\A#{Regexp.quote(BACK_SLASH)}/
+URL = "URL:"
+URL_RE = /\A#{Regexp.quote(URL)}/
+
+other_re_mode = Regexp::EXTENDED
+other_re_mode |= Regexp::MULTILINE
+
+OTHER_RE = Regexp.new(
+ "\\A.+?(?=#{Regexp.quote(EM_OPEN)}|#{Regexp.quote(EM_CLOSE)}|
+ #{Regexp.quote(CODE_OPEN)}|#{Regexp.quote(CODE_CLOSE)}|
+ #{Regexp.quote(VAR_OPEN)}|#{Regexp.quote(VAR_CLOSE)}|
+ #{Regexp.quote(KBD_OPEN)}|#{Regexp.quote(KBD_CLOSE)}|
+ #{Regexp.quote(INDEX_OPEN)}|#{Regexp.quote(INDEX_CLOSE)}|
+ #{Regexp.quote(REF_OPEN)}|#{Regexp.quote(REF_CLOSE)}|
+ #{Regexp.quote(FOOTNOTE_OPEN)}|#{Regexp.quote(FOOTNOTE_CLOSE)}|
+ #{Regexp.quote(VERB_OPEN)}|#{Regexp.quote(VERB_CLOSE)}|
+ #{Regexp.quote(BAR)}|
+ #{Regexp.quote(QUOTE)}|
+ #{Regexp.quote(SLASH)}|
+ #{Regexp.quote(BACK_SLASH)}|
+ #{Regexp.quote(URL)})", other_re_mode)
+
+# :startdoc:
+
+##
+# Creates a new parser for inline markup in the rd format. The +block_parser+
+# is used to for footnotes and labels in the inline text.
+
+def initialize block_parser
+ @block_parser = block_parser
+end
+
+##
+# Parses the +inline+ text from RD format into RDoc format.
+
+def parse inline
+ @inline = inline
+ @src = StringScanner.new inline
+ @pre = ""
+ @yydebug = true
+ do_parse.to_s
+end
+
+##
+# Returns the next token from the inline text
+
+def next_token
+ return [false, false] if @src.eos?
+# p @src.rest if @yydebug
+ if ret = @src.scan(EM_OPEN_RE)
+ @pre << ret
+ [:EM_OPEN, ret]
+ elsif ret = @src.scan(EM_CLOSE_RE)
+ @pre << ret
+ [:EM_CLOSE, ret]
+ elsif ret = @src.scan(CODE_OPEN_RE)
+ @pre << ret
+ [:CODE_OPEN, ret]
+ elsif ret = @src.scan(CODE_CLOSE_RE)
+ @pre << ret
+ [:CODE_CLOSE, ret]
+ elsif ret = @src.scan(VAR_OPEN_RE)
+ @pre << ret
+ [:VAR_OPEN, ret]
+ elsif ret = @src.scan(VAR_CLOSE_RE)
+ @pre << ret
+ [:VAR_CLOSE, ret]
+ elsif ret = @src.scan(KBD_OPEN_RE)
+ @pre << ret
+ [:KBD_OPEN, ret]
+ elsif ret = @src.scan(KBD_CLOSE_RE)
+ @pre << ret
+ [:KBD_CLOSE, ret]
+ elsif ret = @src.scan(INDEX_OPEN_RE)
+ @pre << ret
+ [:INDEX_OPEN, ret]
+ elsif ret = @src.scan(INDEX_CLOSE_RE)
+ @pre << ret
+ [:INDEX_CLOSE, ret]
+ elsif ret = @src.scan(REF_OPEN_RE)
+ @pre << ret
+ [:REF_OPEN, ret]
+ elsif ret = @src.scan(REF_CLOSE_RE)
+ @pre << ret
+ [:REF_CLOSE, ret]
+ elsif ret = @src.scan(FOOTNOTE_OPEN_RE)
+ @pre << ret
+ [:FOOTNOTE_OPEN, ret]
+ elsif ret = @src.scan(FOOTNOTE_CLOSE_RE)
+ @pre << ret
+ [:FOOTNOTE_CLOSE, ret]
+ elsif ret = @src.scan(VERB_OPEN_RE)
+ @pre << ret
+ [:VERB_OPEN, ret]
+ elsif ret = @src.scan(VERB_CLOSE_RE)
+ @pre << ret
+ [:VERB_CLOSE, ret]
+ elsif ret = @src.scan(BAR_RE)
+ @pre << ret
+ [:BAR, ret]
+ elsif ret = @src.scan(QUOTE_RE)
+ @pre << ret
+ [:QUOTE, ret]
+ elsif ret = @src.scan(SLASH_RE)
+ @pre << ret
+ [:SLASH, ret]
+ elsif ret = @src.scan(BACK_SLASH_RE)
+ @pre << ret
+ [:BACK_SLASH, ret]
+ elsif ret = @src.scan(URL_RE)
+ @pre << ret
+ [:URL, ret]
+ elsif ret = @src.scan(OTHER_RE)
+ @pre << ret
+ [:OTHER, ret]
+ else
+ ret = @src.rest
+ @pre << ret
+ @src.terminate
+ [:OTHER, ret]
+ end
+end
+
+##
+# Raises a ParseError when invalid formatting is found
+
+def on_error(et, ev, values)
+ lines_of_rest = @src.rest.lines.to_a.length
+ prev_words = prev_words_on_error(ev)
+ at = 4 + prev_words.length
+
+ message = <<-MSG
+RD syntax error: line #{@block_parser.line_index - lines_of_rest}:
+...#{prev_words} #{(ev||'')} #{next_words_on_error()} ...
+ MSG
+
+ message << " " * at + "^" * (ev ? ev.length : 0) + "\n"
+ raise ParseError, message
+end
+
+##
+# Returns words before the error
+
+def prev_words_on_error(ev)
+ pre = @pre
+ if ev and /#{Regexp.quote(ev)}$/ =~ pre
+ pre = $`
+ end
+ last_line(pre)
+end
+
+##
+# Returns the last line of +src+
+
+def last_line(src)
+ if n = src.rindex("\n")
+ src[(n+1) .. -1]
+ else
+ src
+ end
+end
+private :last_line
+
+##
+# Returns words following an error
+
+def next_words_on_error
+ if n = @src.rest.index("\n")
+ @src.rest[0 .. (n-1)]
+ else
+ @src.rest
+ end
+end
+
+##
+# Creates a new RDoc::RD::Inline for the +rdoc+ markup and the raw +reference+
+
+def inline rdoc, reference = rdoc
+ RDoc::RD::Inline.new rdoc, reference
+end
+
+# :stopdoc:
+##### State transition tables begin ###
+
+racc_action_table = [
+ 63, 64, 65, 153, 81, 62, 76, 78, 79, 87,
+ 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
+ 77, 80, 152, 63, 64, 65, 61, 81, 62, 76,
+ 78, 79, 124, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 77, 80, 149, 104, 103, 102, 100,
+ 101, 99, 115, 116, 117, 164, 105, 106, 107, 108,
+ 109, 110, 111, 112, 113, 114, 96, 118, 119, 104,
+ 103, 102, 100, 101, 99, 115, 116, 117, 89, 105,
+ 106, 107, 108, 109, 110, 111, 112, 113, 114, 88,
+ 118, 119, 104, 103, 102, 100, 101, 99, 115, 116,
+ 117, 161, 105, 106, 107, 108, 109, 110, 111, 112,
+ 113, 114, 86, 118, 119, 104, 103, 102, 100, 101,
+ 99, 115, 116, 117, 85, 105, 106, 107, 108, 109,
+ 110, 111, 112, 113, 114, 137, 118, 119, 63, 64,
+ 65, 61, 81, 62, 76, 78, 79, 84, 66, 67,
+ 68, 69, 70, 71, 72, 73, 74, 75, 77, 80,
+ 22, 23, 24, 25, 26, 21, 18, 19, 176, 177,
+ 13, 173, 14, 154, 15, 175, 16, 137, 17, 42,
+ 148, 20, 54, 38, 53, 55, 56, 57, 29, 13,
+ 177, 14, nil, 15, nil, 16, nil, 17, nil, nil,
+ 20, 22, 23, 24, 25, 26, 21, 18, 19, nil,
+ nil, 13, nil, 14, nil, 15, nil, 16, nil, 17,
+ nil, nil, 20, 22, 23, 24, 25, 26, 21, 18,
+ 19, nil, nil, 13, nil, 14, nil, 15, nil, 16,
+ nil, 17, nil, nil, 20, 22, 23, 24, 25, 26,
+ 21, 18, 19, nil, nil, 13, nil, 14, nil, 15,
+ nil, 16, nil, 17, 145, nil, 20, 54, 133, 53,
+ 55, 56, 57, nil, 13, nil, 14, nil, 15, nil,
+ 16, nil, 17, nil, nil, 20, 22, 23, 24, 25,
+ 26, 21, 18, 19, nil, nil, 13, nil, 14, nil,
+ 15, nil, 16, nil, 17, 145, nil, 20, 54, 133,
+ 53, 55, 56, 57, nil, 13, nil, 14, nil, 15,
+ nil, 16, nil, 17, nil, nil, 20, 22, 23, 24,
+ 25, 26, 21, 18, 19, nil, nil, 13, nil, 14,
+ nil, 15, nil, 16, nil, 17, 145, nil, 20, 54,
+ 133, 53, 55, 56, 57, nil, 13, nil, 14, nil,
+ 15, nil, 16, nil, 17, 145, nil, 20, 54, 133,
+ 53, 55, 56, 57, nil, 13, nil, 14, nil, 15,
+ nil, 16, nil, 17, nil, nil, 20, 22, 23, 24,
+ 25, 26, 21, 18, 19, nil, nil, 13, nil, 14,
+ nil, 15, nil, 16, 122, 17, nil, 54, 20, 53,
+ 55, 56, 57, nil, 13, nil, 14, nil, 15, nil,
+ 16, nil, 17, nil, nil, 20, 22, 23, 24, 25,
+ 26, 21, 18, 19, nil, nil, 13, nil, 14, nil,
+ 15, nil, 16, nil, 17, nil, nil, 20, 135, 136,
+ 54, 133, 53, 55, 56, 57, nil, 13, nil, 14,
+ nil, 15, nil, 16, nil, 17, nil, nil, 20, 135,
+ 136, 54, 133, 53, 55, 56, 57, nil, 13, nil,
+ 14, nil, 15, nil, 16, nil, 17, nil, nil, 20,
+ 135, 136, 54, 133, 53, 55, 56, 57, nil, 13,
+ nil, 14, nil, 15, nil, 16, nil, 17, nil, nil,
+ 20, 172, 135, 136, 54, 133, 53, 55, 56, 57,
+ 165, 135, 136, 54, 133, 53, 55, 56, 57, 95,
+ nil, nil, 54, 91, 53, 55, 56, 57, 174, 135,
+ 136, 54, 133, 53, 55, 56, 57, 158, nil, nil,
+ 54, nil, 53, 55, 56, 57, 178, 135, 136, 54,
+ 133, 53, 55, 56, 57, 145, nil, nil, 54, 133,
+ 53, 55, 56, 57, 145, nil, nil, 54, 133, 53,
+ 55, 56, 57, 135, 136, 54, 133, 53, 55, 56,
+ 57, 135, 136, 54, 133, 53, 55, 56, 57, 135,
+ 136, 54, 133, 53, 55, 56, 57, 22, 23, 24,
+ 25, 26, 21 ]
+
+racc_action_check = [
+ 61, 61, 61, 61, 61, 61, 61, 61, 61, 33,
+ 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
+ 61, 61, 61, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 41, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 97, 97, 97, 97,
+ 97, 97, 97, 97, 97, 125, 97, 97, 97, 97,
+ 97, 97, 97, 97, 97, 97, 37, 97, 97, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38, 35, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38, 38, 34,
+ 38, 38, 155, 155, 155, 155, 155, 155, 155, 155,
+ 155, 100, 155, 155, 155, 155, 155, 155, 155, 155,
+ 155, 155, 32, 155, 155, 91, 91, 91, 91, 91,
+ 91, 91, 91, 91, 31, 91, 91, 91, 91, 91,
+ 91, 91, 91, 91, 91, 43, 91, 91, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 29, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 17, 17, 17, 17, 17, 17, 17, 17, 165, 165,
+ 17, 162, 17, 90, 17, 164, 17, 94, 17, 18,
+ 58, 17, 18, 18, 18, 18, 18, 18, 1, 18,
+ 172, 18, nil, 18, nil, 18, nil, 18, nil, nil,
+ 18, 19, 19, 19, 19, 19, 19, 19, 19, nil,
+ nil, 19, nil, 19, nil, 19, nil, 19, nil, 19,
+ nil, nil, 19, 16, 16, 16, 16, 16, 16, 16,
+ 16, nil, nil, 16, nil, 16, nil, 16, nil, 16,
+ nil, 16, nil, nil, 16, 15, 15, 15, 15, 15,
+ 15, 15, 15, nil, nil, 15, nil, 15, nil, 15,
+ nil, 15, nil, 15, 45, nil, 15, 45, 45, 45,
+ 45, 45, 45, nil, 45, nil, 45, nil, 45, nil,
+ 45, nil, 45, nil, nil, 45, 14, 14, 14, 14,
+ 14, 14, 14, 14, nil, nil, 14, nil, 14, nil,
+ 14, nil, 14, nil, 14, 146, nil, 14, 146, 146,
+ 146, 146, 146, 146, nil, 146, nil, 146, nil, 146,
+ nil, 146, nil, 146, nil, nil, 146, 13, 13, 13,
+ 13, 13, 13, 13, 13, nil, nil, 13, nil, 13,
+ nil, 13, nil, 13, nil, 13, 138, nil, 13, 138,
+ 138, 138, 138, 138, 138, nil, 138, nil, 138, nil,
+ 138, nil, 138, nil, 138, 44, nil, 138, 44, 44,
+ 44, 44, 44, 44, nil, 44, nil, 44, nil, 44,
+ nil, 44, nil, 44, nil, nil, 44, 2, 2, 2,
+ 2, 2, 2, 2, 2, nil, nil, 2, nil, 2,
+ nil, 2, nil, 2, 39, 2, nil, 39, 2, 39,
+ 39, 39, 39, nil, 39, nil, 39, nil, 39, nil,
+ 39, nil, 39, nil, nil, 39, 0, 0, 0, 0,
+ 0, 0, 0, 0, nil, nil, 0, nil, 0, nil,
+ 0, nil, 0, nil, 0, nil, nil, 0, 122, 122,
+ 122, 122, 122, 122, 122, 122, nil, 122, nil, 122,
+ nil, 122, nil, 122, nil, 122, nil, nil, 122, 127,
+ 127, 127, 127, 127, 127, 127, 127, nil, 127, nil,
+ 127, nil, 127, nil, 127, nil, 127, nil, nil, 127,
+ 42, 42, 42, 42, 42, 42, 42, 42, nil, 42,
+ nil, 42, nil, 42, nil, 42, nil, 42, nil, nil,
+ 42, 159, 159, 159, 159, 159, 159, 159, 159, 159,
+ 126, 126, 126, 126, 126, 126, 126, 126, 126, 36,
+ nil, nil, 36, 36, 36, 36, 36, 36, 163, 163,
+ 163, 163, 163, 163, 163, 163, 163, 92, nil, nil,
+ 92, nil, 92, 92, 92, 92, 171, 171, 171, 171,
+ 171, 171, 171, 171, 171, 142, nil, nil, 142, 142,
+ 142, 142, 142, 142, 52, nil, nil, 52, 52, 52,
+ 52, 52, 52, 95, 95, 95, 95, 95, 95, 95,
+ 95, 168, 168, 168, 168, 168, 168, 168, 168, 158,
+ 158, 158, 158, 158, 158, 158, 158, 27, 27, 27,
+ 27, 27, 27 ]
+
+racc_action_pointer = [
+ 423, 188, 384, nil, nil, nil, nil, nil, nil, nil,
+ nil, nil, nil, 324, 283, 242, 220, 157, 176, 198,
+ 135, nil, nil, nil, nil, nil, nil, 604, nil, 147,
+ nil, 110, 96, -9, 69, 56, 526, 43, 66, 401,
+ nil, 28, 486, 130, 362, 261, nil, nil, nil, nil,
+ nil, nil, 571, nil, nil, nil, nil, nil, 169, 20,
+ nil, -3, nil, nil, nil, nil, nil, nil, nil, nil,
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
+ 150, 112, 544, nil, 172, 579, nil, 43, nil, nil,
+ 95, nil, nil, nil, nil, nil, nil, nil, nil, nil,
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
+ nil, nil, 444, nil, nil, 52, 517, 465, nil, nil,
+ nil, nil, nil, nil, nil, nil, nil, nil, 343, nil,
+ nil, nil, 562, nil, nil, nil, 302, nil, nil, nil,
+ nil, nil, nil, nil, nil, 89, nil, nil, 595, 508,
+ nil, nil, 168, 535, 171, 164, nil, nil, 587, nil,
+ nil, 553, 185, nil, nil, nil, nil, nil, nil ]
+
+racc_action_default = [
+ -138, -138, -1, -3, -4, -5, -6, -7, -8, -9,
+ -10, -11, -12, -138, -138, -138, -138, -138, -138, -138,
+ -138, -103, -104, -105, -106, -107, -108, -111, -110, -138,
+ -2, -138, -138, -138, -138, -138, -138, -138, -138, -27,
+ -26, -35, -138, -58, -41, -40, -47, -48, -49, -50,
+ -51, -52, -63, -66, -67, -68, -69, -70, -138, -138,
+ -112, -138, -116, -117, -118, -119, -120, -121, -122, -123,
+ -124, -125, -126, -127, -128, -129, -130, -131, -132, -133,
+ -134, -135, -137, -109, 179, -13, -14, -15, -16, -17,
+ -138, -138, -23, -22, -33, -138, -19, -24, -79, -80,
+ -138, -82, -83, -84, -85, -86, -87, -88, -89, -90,
+ -91, -92, -93, -94, -95, -96, -97, -98, -99, -100,
+ -25, -35, -138, -58, -28, -138, -59, -42, -46, -55,
+ -56, -65, -71, -72, -75, -76, -77, -31, -38, -44,
+ -53, -54, -57, -61, -73, -74, -39, -62, -101, -102,
+ -136, -113, -114, -115, -18, -20, -21, -33, -138, -138,
+ -78, -81, -138, -59, -36, -37, -64, -45, -59, -43,
+ -60, -138, -34, -36, -37, -29, -30, -32, -34 ]
+
+racc_goto_table = [
+ 126, 44, 125, 43, 144, 144, 160, 93, 97, 52,
+ 166, 82, 144, 41, 40, 39, 138, 146, 169, 147,
+ 167, 94, 44, 1, 123, 129, 169, 52, 36, 37,
+ 52, 90, 59, 92, 121, 120, 31, 32, 33, 34,
+ 35, 170, 58, 166, 83, 30, 170, 166, 151, nil,
+ 150, nil, 166, 159, 8, 166, 8, nil, nil, nil,
+ nil, 155, nil, 156, 160, nil, nil, 8, 8, 8,
+ 8, 8, nil, 8, 4, nil, 4, 157, nil, nil,
+ 163, nil, 162, 52, nil, 168, nil, 4, 4, 4,
+ 4, 4, nil, 4, nil, nil, nil, nil, 144, nil,
+ nil, nil, 144, nil, nil, 129, 144, 144, nil, 5,
+ 129, 5, nil, nil, nil, nil, 171, 6, nil, 6,
+ nil, nil, 5, 5, 5, 5, 5, 11, 5, 11,
+ 6, 6, 6, 6, 6, 7, 6, 7, nil, nil,
+ 11, 11, 11, 11, 11, nil, 11, nil, 7, 7,
+ 7, 7, 7, nil, 7 ]
+
+racc_goto_check = [
+ 22, 24, 21, 23, 36, 36, 37, 18, 16, 34,
+ 35, 41, 36, 20, 19, 17, 25, 25, 28, 32,
+ 29, 23, 24, 1, 23, 24, 28, 34, 13, 15,
+ 34, 14, 38, 17, 20, 19, 1, 1, 1, 1,
+ 1, 33, 1, 35, 39, 3, 33, 35, 42, nil,
+ 41, nil, 35, 22, 8, 35, 8, nil, nil, nil,
+ nil, 16, nil, 18, 37, nil, nil, 8, 8, 8,
+ 8, 8, nil, 8, 4, nil, 4, 23, nil, nil,
+ 22, nil, 21, 34, nil, 22, nil, 4, 4, 4,
+ 4, 4, nil, 4, nil, nil, nil, nil, 36, nil,
+ nil, nil, 36, nil, nil, 24, 36, 36, nil, 5,
+ 24, 5, nil, nil, nil, nil, 22, 6, nil, 6,
+ nil, nil, 5, 5, 5, 5, 5, 11, 5, 11,
+ 6, 6, 6, 6, 6, 7, 6, 7, nil, nil,
+ 11, 11, 11, 11, 11, nil, 11, nil, 7, 7,
+ 7, 7, 7, nil, 7 ]
+
+racc_goto_pointer = [
+ nil, 23, nil, 43, 74, 109, 117, 135, 54, nil,
+ nil, 127, nil, 10, -5, 11, -30, -3, -29, -4,
+ -5, -40, -42, -15, -17, -28, nil, nil, -120, -107,
+ nil, nil, -33, -101, -9, -116, -40, -91, 12, 17,
+ nil, -9, -13 ]
+
+racc_goto_default = [
+ nil, nil, 2, 3, 46, 47, 48, 49, 50, 9,
+ 10, 51, 12, nil, nil, nil, nil, nil, nil, nil,
+ nil, nil, nil, nil, 140, nil, 45, 127, 139, 128,
+ 141, 130, 142, 143, 132, 131, 134, 98, nil, 28,
+ 27, nil, 60 ]
+
+racc_reduce_table = [
+ 0, 0, :racc_error,
+ 1, 27, :_reduce_none,
+ 2, 28, :_reduce_2,
+ 1, 28, :_reduce_3,
+ 1, 29, :_reduce_none,
+ 1, 29, :_reduce_none,
+ 1, 29, :_reduce_none,
+ 1, 29, :_reduce_none,
+ 1, 29, :_reduce_none,
+ 1, 29, :_reduce_none,
+ 1, 29, :_reduce_none,
+ 1, 29, :_reduce_none,
+ 1, 29, :_reduce_none,
+ 3, 30, :_reduce_13,
+ 3, 31, :_reduce_14,
+ 3, 32, :_reduce_15,
+ 3, 33, :_reduce_16,
+ 3, 34, :_reduce_17,
+ 4, 35, :_reduce_18,
+ 3, 35, :_reduce_19,
+ 2, 40, :_reduce_20,
+ 2, 40, :_reduce_21,
+ 1, 40, :_reduce_22,
+ 1, 40, :_reduce_23,
+ 2, 41, :_reduce_24,
+ 2, 41, :_reduce_25,
+ 1, 41, :_reduce_26,
+ 1, 41, :_reduce_27,
+ 2, 39, :_reduce_none,
+ 4, 39, :_reduce_29,
+ 4, 39, :_reduce_30,
+ 2, 43, :_reduce_31,
+ 4, 43, :_reduce_32,
+ 1, 44, :_reduce_33,
+ 3, 44, :_reduce_34,
+ 1, 45, :_reduce_none,
+ 3, 45, :_reduce_36,
+ 3, 45, :_reduce_37,
+ 2, 46, :_reduce_38,
+ 2, 46, :_reduce_39,
+ 1, 46, :_reduce_40,
+ 1, 46, :_reduce_41,
+ 1, 47, :_reduce_none,
+ 2, 51, :_reduce_43,
+ 1, 51, :_reduce_44,
+ 2, 53, :_reduce_45,
+ 1, 53, :_reduce_46,
+ 1, 50, :_reduce_none,
+ 1, 50, :_reduce_none,
+ 1, 50, :_reduce_none,
+ 1, 50, :_reduce_none,
+ 1, 50, :_reduce_none,
+ 1, 50, :_reduce_none,
+ 1, 54, :_reduce_none,
+ 1, 54, :_reduce_none,
+ 1, 55, :_reduce_none,
+ 1, 55, :_reduce_none,
+ 1, 56, :_reduce_57,
+ 1, 52, :_reduce_58,
+ 1, 57, :_reduce_59,
+ 2, 58, :_reduce_60,
+ 1, 58, :_reduce_none,
+ 2, 49, :_reduce_62,
+ 1, 49, :_reduce_none,
+ 2, 48, :_reduce_64,
+ 1, 48, :_reduce_none,
+ 1, 60, :_reduce_none,
+ 1, 60, :_reduce_none,
+ 1, 60, :_reduce_none,
+ 1, 60, :_reduce_none,
+ 1, 60, :_reduce_none,
+ 1, 62, :_reduce_none,
+ 1, 62, :_reduce_none,
+ 1, 59, :_reduce_none,
+ 1, 59, :_reduce_none,
+ 1, 61, :_reduce_none,
+ 1, 61, :_reduce_none,
+ 1, 61, :_reduce_none,
+ 2, 42, :_reduce_78,
+ 1, 42, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 2, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 1, 63, :_reduce_none,
+ 3, 36, :_reduce_101,
+ 3, 37, :_reduce_102,
+ 1, 65, :_reduce_none,
+ 1, 65, :_reduce_none,
+ 1, 65, :_reduce_none,
+ 1, 65, :_reduce_none,
+ 1, 65, :_reduce_none,
+ 1, 65, :_reduce_none,
+ 2, 66, :_reduce_109,
+ 1, 66, :_reduce_none,
+ 1, 38, :_reduce_111,
+ 1, 67, :_reduce_none,
+ 2, 67, :_reduce_113,
+ 2, 67, :_reduce_114,
+ 2, 67, :_reduce_115,
+ 1, 68, :_reduce_none,
+ 1, 68, :_reduce_none,
+ 1, 68, :_reduce_none,
+ 1, 68, :_reduce_none,
+ 1, 68, :_reduce_none,
+ 1, 68, :_reduce_none,
+ 1, 68, :_reduce_none,
+ 1, 68, :_reduce_none,
+ 1, 68, :_reduce_none,
+ 1, 68, :_reduce_none,
+ 1, 68, :_reduce_none,
+ 1, 68, :_reduce_none,
+ 1, 68, :_reduce_none,
+ 1, 68, :_reduce_none,
+ 1, 68, :_reduce_none,
+ 1, 68, :_reduce_none,
+ 1, 68, :_reduce_none,
+ 1, 68, :_reduce_none,
+ 1, 68, :_reduce_none,
+ 1, 68, :_reduce_none,
+ 2, 64, :_reduce_136,
+ 1, 64, :_reduce_none ]
+
+racc_reduce_n = 138
+
+racc_shift_n = 179
+
+racc_token_table = {
+ false => 0,
+ :error => 1,
+ :EX_LOW => 2,
+ :QUOTE => 3,
+ :BAR => 4,
+ :SLASH => 5,
+ :BACK_SLASH => 6,
+ :URL => 7,
+ :OTHER => 8,
+ :REF_OPEN => 9,
+ :FOOTNOTE_OPEN => 10,
+ :FOOTNOTE_CLOSE => 11,
+ :EX_HIGH => 12,
+ :EM_OPEN => 13,
+ :EM_CLOSE => 14,
+ :CODE_OPEN => 15,
+ :CODE_CLOSE => 16,
+ :VAR_OPEN => 17,
+ :VAR_CLOSE => 18,
+ :KBD_OPEN => 19,
+ :KBD_CLOSE => 20,
+ :INDEX_OPEN => 21,
+ :INDEX_CLOSE => 22,
+ :REF_CLOSE => 23,
+ :VERB_OPEN => 24,
+ :VERB_CLOSE => 25 }
+
+racc_nt_base = 26
+
+racc_use_result_var = true
+
+Racc_arg = [
+ racc_action_table,
+ racc_action_check,
+ racc_action_default,
+ racc_action_pointer,
+ racc_goto_table,
+ racc_goto_check,
+ racc_goto_default,
+ racc_goto_pointer,
+ racc_nt_base,
+ racc_reduce_table,
+ racc_token_table,
+ racc_shift_n,
+ racc_reduce_n,
+ racc_use_result_var ]
+
+Racc_token_to_s_table = [
+ "$end",
+ "error",
+ "EX_LOW",
+ "QUOTE",
+ "BAR",
+ "SLASH",
+ "BACK_SLASH",
+ "URL",
+ "OTHER",
+ "REF_OPEN",
+ "FOOTNOTE_OPEN",
+ "FOOTNOTE_CLOSE",
+ "EX_HIGH",
+ "EM_OPEN",
+ "EM_CLOSE",
+ "CODE_OPEN",
+ "CODE_CLOSE",
+ "VAR_OPEN",
+ "VAR_CLOSE",
+ "KBD_OPEN",
+ "KBD_CLOSE",
+ "INDEX_OPEN",
+ "INDEX_CLOSE",
+ "REF_CLOSE",
+ "VERB_OPEN",
+ "VERB_CLOSE",
+ "$start",
+ "content",
+ "elements",
+ "element",
+ "emphasis",
+ "code",
+ "var",
+ "keyboard",
+ "index",
+ "reference",
+ "footnote",
+ "verb",
+ "normal_str_ele",
+ "substitute",
+ "ref_label",
+ "ref_label2",
+ "ref_url_strings",
+ "filename",
+ "element_label",
+ "element_label2",
+ "ref_subst_content",
+ "ref_subst_content_q",
+ "ref_subst_strings_q",
+ "ref_subst_strings_first",
+ "ref_subst_ele2",
+ "ref_subst_eles",
+ "ref_subst_str_ele_first",
+ "ref_subst_eles_q",
+ "ref_subst_ele",
+ "ref_subst_ele_q",
+ "ref_subst_str_ele",
+ "ref_subst_str_ele_q",
+ "ref_subst_strings",
+ "ref_subst_string3",
+ "ref_subst_string",
+ "ref_subst_string_q",
+ "ref_subst_string2",
+ "ref_url_string",
+ "verb_strings",
+ "normal_string",
+ "normal_strings",
+ "verb_string",
+ "verb_normal_string" ]
+
+Racc_debug_parser = false
+
+##### State transition tables end #####
+
+# reduce 0 omitted
+
+# reduce 1 omitted
+
+def _reduce_2(val, _values, result)
+ result.append val[1]
+ result
+end
+
+def _reduce_3(val, _values, result)
+ result = val[0]
+ result
+end
+
+# reduce 4 omitted
+
+# reduce 5 omitted
+
+# reduce 6 omitted
+
+# reduce 7 omitted
+
+# reduce 8 omitted
+
+# reduce 9 omitted
+
+# reduce 10 omitted
+
+# reduce 11 omitted
+
+# reduce 12 omitted
+
+def _reduce_13(val, _values, result)
+ content = val[1]
+ result = inline "<em>#{content}</em>", content
+
+ result
+end
+
+def _reduce_14(val, _values, result)
+ content = val[1]
+ result = inline "<code>#{content}</code>", content
+
+ result
+end
+
+def _reduce_15(val, _values, result)
+ content = val[1]
+ result = inline "+#{content}+", content
+
+ result
+end
+
+def _reduce_16(val, _values, result)
+ content = val[1]
+ result = inline "<tt>#{content}</tt>", content
+
+ result
+end
+
+def _reduce_17(val, _values, result)
+ label = val[1]
+ @block_parser.add_label label.reference
+ result = "<span id=\"label-#{label}\">#{label}</span>"
+
+ result
+end
+
+def _reduce_18(val, _values, result)
+ result = "{#{val[1]}}[#{val[2].join}]"
+
+ result
+end
+
+def _reduce_19(val, _values, result)
+ scheme, inline = val[1]
+
+ result = "{#{inline}}[#{scheme}#{inline.reference}]"
+
+ result
+end
+
+def _reduce_20(val, _values, result)
+ result = [nil, inline(val[1])]
+
+ result
+end
+
+def _reduce_21(val, _values, result)
+ result = [
+ 'rdoc-label:',
+ inline("#{val[0].reference}/#{val[1].reference}")
+ ]
+
+ result
+end
+
+def _reduce_22(val, _values, result)
+ result = ['rdoc-label:', val[0].reference]
+
+ result
+end
+
+def _reduce_23(val, _values, result)
+ result = ['rdoc-label:', "#{val[0].reference}/"]
+
+ result
+end
+
+def _reduce_24(val, _values, result)
+ result = [nil, inline(val[1])]
+
+ result
+end
+
+def _reduce_25(val, _values, result)
+ result = [
+ 'rdoc-label:',
+ inline("#{val[0].reference}/#{val[1].reference}")
+ ]
+
+ result
+end
+
+def _reduce_26(val, _values, result)
+ result = ['rdoc-label:', val[0]]
+
+ result
+end
+
+def _reduce_27(val, _values, result)
+ ref = val[0].reference
+ result = ['rdoc-label:', inline(ref, "#{ref}/")]
+
+ result
+end
+
+# reduce 28 omitted
+
+def _reduce_29(val, _values, result)
+ result = val[1]
+ result
+end
+
+def _reduce_30(val, _values, result)
+ result = val[1]
+ result
+end
+
+def _reduce_31(val, _values, result)
+ result = inline val[0]
+
+ result
+end
+
+def _reduce_32(val, _values, result)
+ result = inline "\"#{val[1]}\""
+
+ result
+end
+
+def _reduce_33(val, _values, result)
+ result = inline val[0]
+
+ result
+end
+
+def _reduce_34(val, _values, result)
+ result = inline "\"#{val[1]}\""
+
+ result
+end
+
+# reduce 35 omitted
+
+def _reduce_36(val, _values, result)
+ result = val[1]
+ result
+end
+
+def _reduce_37(val, _values, result)
+ result = inline val[1]
+ result
+end
+
+def _reduce_38(val, _values, result)
+ result = val[0].append val[1]
+
+ result
+end
+
+def _reduce_39(val, _values, result)
+ result = val[0].append val[1]
+
+ result
+end
+
+def _reduce_40(val, _values, result)
+ result = val[0]
+
+ result
+end
+
+def _reduce_41(val, _values, result)
+ result = inline val[0]
+
+ result
+end
+
+# reduce 42 omitted
+
+def _reduce_43(val, _values, result)
+ result = val[0].append val[1]
+
+ result
+end
+
+def _reduce_44(val, _values, result)
+ result = inline val[0]
+
+ result
+end
+
+def _reduce_45(val, _values, result)
+ result = val[0].append val[1]
+
+ result
+end
+
+def _reduce_46(val, _values, result)
+ result = val[0]
+
+ result
+end
+
+# reduce 47 omitted
+
+# reduce 48 omitted
+
+# reduce 49 omitted
+
+# reduce 50 omitted
+
+# reduce 51 omitted
+
+# reduce 52 omitted
+
+# reduce 53 omitted
+
+# reduce 54 omitted
+
+# reduce 55 omitted
+
+# reduce 56 omitted
+
+def _reduce_57(val, _values, result)
+ result = val[0]
+
+ result
+end
+
+def _reduce_58(val, _values, result)
+ result = inline val[0]
+
+ result
+end
+
+def _reduce_59(val, _values, result)
+ result = inline val[0]
+
+ result
+end
+
+def _reduce_60(val, _values, result)
+ result << val[1]
+ result
+end
+
+# reduce 61 omitted
+
+def _reduce_62(val, _values, result)
+ result << val[1]
+
+ result
+end
+
+# reduce 63 omitted
+
+def _reduce_64(val, _values, result)
+ result << val[1]
+
+ result
+end
+
+# reduce 65 omitted
+
+# reduce 66 omitted
+
+# reduce 67 omitted
+
+# reduce 68 omitted
+
+# reduce 69 omitted
+
+# reduce 70 omitted
+
+# reduce 71 omitted
+
+# reduce 72 omitted
+
+# reduce 73 omitted
+
+# reduce 74 omitted
+
+# reduce 75 omitted
+
+# reduce 76 omitted
+
+# reduce 77 omitted
+
+def _reduce_78(val, _values, result)
+ result << val[1]
+ result
+end
+
+# reduce 79 omitted
+
+# reduce 80 omitted
+
+# reduce 81 omitted
+
+# reduce 82 omitted
+
+# reduce 83 omitted
+
+# reduce 84 omitted
+
+# reduce 85 omitted
+
+# reduce 86 omitted
+
+# reduce 87 omitted
+
+# reduce 88 omitted
+
+# reduce 89 omitted
+
+# reduce 90 omitted
+
+# reduce 91 omitted
+
+# reduce 92 omitted
+
+# reduce 93 omitted
+
+# reduce 94 omitted
+
+# reduce 95 omitted
+
+# reduce 96 omitted
+
+# reduce 97 omitted
+
+# reduce 98 omitted
+
+# reduce 99 omitted
+
+# reduce 100 omitted
+
+def _reduce_101(val, _values, result)
+ index = @block_parser.add_footnote val[1].rdoc
+ result = "{*#{index}}[rdoc-label:foottext-#{index}:footmark-#{index}]"
+
+ result
+end
+
+def _reduce_102(val, _values, result)
+ result = "<tt>#{val[1]}</tt>"
+
+ result
+end
+
+# reduce 103 omitted
+
+# reduce 104 omitted
+
+# reduce 105 omitted
+
+# reduce 106 omitted
+
+# reduce 107 omitted
+
+# reduce 108 omitted
+
+def _reduce_109(val, _values, result)
+ result << val[1]
+ result
+end
+
+# reduce 110 omitted
+
+def _reduce_111(val, _values, result)
+ result = inline val[0]
+
+ result
+end
+
+# reduce 112 omitted
+
+def _reduce_113(val, _values, result)
+ result = val[1]
+ result
+end
+
+def _reduce_114(val, _values, result)
+ result = val[1]
+ result
+end
+
+def _reduce_115(val, _values, result)
+ result = val[1]
+ result
+end
+
+# reduce 116 omitted
+
+# reduce 117 omitted
+
+# reduce 118 omitted
+
+# reduce 119 omitted
+
+# reduce 120 omitted
+
+# reduce 121 omitted
+
+# reduce 122 omitted
+
+# reduce 123 omitted
+
+# reduce 124 omitted
+
+# reduce 125 omitted
+
+# reduce 126 omitted
+
+# reduce 127 omitted
+
+# reduce 128 omitted
+
+# reduce 129 omitted
+
+# reduce 130 omitted
+
+# reduce 131 omitted
+
+# reduce 132 omitted
+
+# reduce 133 omitted
+
+# reduce 134 omitted
+
+# reduce 135 omitted
+
+def _reduce_136(val, _values, result)
+ result << val[1]
+ result
+end
+
+# reduce 137 omitted
+
+def _reduce_none(val, _values, result)
+ val[0]
+end
+
+end # class InlineParser
+
+end
diff --git a/lib/rdoc/rdoc.rb b/lib/rdoc/rdoc.rb
index 95ba9ae8ab..d72e686249 100644
--- a/lib/rdoc/rdoc.rb
+++ b/lib/rdoc/rdoc.rb
@@ -1,53 +1,38 @@
require 'rdoc'
-require 'rdoc/encoding'
-require 'rdoc/parser'
-
-# Simple must come first
-require 'rdoc/parser/simple'
-require 'rdoc/parser/ruby'
-require 'rdoc/parser/c'
-
-require 'rdoc/stats'
-require 'rdoc/options'
-
require 'find'
require 'fileutils'
require 'time'
##
-# Encapsulate the production of rdoc documentation. Basically you can use this
-# as you would invoke rdoc from the command line:
-#
-# rdoc = RDoc::RDoc.new
-# rdoc.document(args)
-#
-# Where +args+ is an array of strings, each corresponding to an argument you'd
-# give rdoc on the command line. See <tt>rdoc --help<tt> for details.
+# This is the driver for generating RDoc output. It handles file parsing and
+# generation of output.
#
-# = Plugins
+# To use this class to generate RDoc output via the API, the recommended way
+# is:
#
-# When you <tt>require 'rdoc/rdoc'</tt> RDoc looks for 'rdoc/discover' files
-# in your installed gems. This can be used to load alternate generators or
-# add additional preprocessor directives.
-#
-# You will want to wrap your plugin loading in an RDoc version check.
-# Something like:
+# rdoc = RDoc::RDoc.new
+# options = rdoc.load_options # returns an RDoc::Options instance
+# # set extra options
+# rdoc.document options
#
-# begin
-# gem 'rdoc', '~> 3'
-# require 'path/to/my/awesome/rdoc/plugin'
-# rescue Gem::LoadError
-# end
+# You can also generate output like the +rdoc+ executable:
#
-# The most obvious plugin type is a new output generator. See RDoc::Generator
-# for details.
+# rdoc = RDoc::RDoc.new
+# rdoc.document argv
#
-# You can also hook into RDoc::Markup to add new directives (:nodoc: is a
-# directive). See RDoc::Markup::PreProcess::register for details.
+# Where +argv+ is an array of strings, each corresponding to an argument you'd
+# give rdoc on the command line. See <tt>rdoc --help<tt> for details.
class RDoc::RDoc
+ @current = nil
+
+ ##
+ # This is the list of supported output generators
+
+ GENERATORS = {}
+
##
# File pattern to exclude
@@ -74,9 +59,9 @@ class RDoc::RDoc
attr_reader :stats
##
- # This is the list of supported output generators
+ # The current documentation store
- GENERATORS = {}
+ attr_reader :store
##
# Add +klass+ that can generate output after parsing
@@ -96,19 +81,11 @@ class RDoc::RDoc
##
# Sets the active RDoc::RDoc instance
- def self.current=(rdoc)
+ def self.current= rdoc
@current = rdoc
end
##
- # Resets all internal state
-
- def self.reset
- RDoc::TopLevel.reset
- RDoc::Parser::C.reset
- end
-
- ##
# Creates a new RDoc::RDoc instance. Call #document to parse files and
# generate documentation.
@@ -120,6 +97,7 @@ class RDoc::RDoc
@old_siginfo = nil
@options = nil
@stats = nil
+ @store = nil
end
##
@@ -141,15 +119,21 @@ class RDoc::RDoc
file_list = file_list.uniq
file_list = remove_unparseable file_list
+
+ file_list.sort
end
##
# Turns RDoc from stdin into HTML
def handle_pipe
- @html = RDoc::Markup::ToHtml.new
+ @html = RDoc::Markup::ToHtml.new @options
+
+ parser = RDoc::Text::MARKUP_FORMAT[@options.markup]
- out = @html.convert $stdin.read
+ document = parser.parse $stdin.read
+
+ out = @html.convert document
$stdout.write out
end
@@ -166,6 +150,33 @@ class RDoc::RDoc
end
##
+ # Loads options from .rdoc_options if the file exists, otherwise creates a
+ # new RDoc::Options instance.
+
+ def load_options
+ options_file = File.expand_path '.rdoc_options'
+ return RDoc::Options.new unless File.exist? options_file
+
+ RDoc.load_yaml
+
+ parse_error = if Object.const_defined? :Psych then
+ Psych::SyntaxError
+ else
+ ArgumentError
+ end
+
+ begin
+ options = YAML.load_file '.rdoc_options'
+ rescue *parse_error
+ end
+
+ raise RDoc::Error, "#{options_file} is not a valid rdoc options file" unless
+ RDoc::Options === options
+
+ options
+ end
+
+ ##
# Create an output dir if it doesn't exist. If it does exist, but doesn't
# contain the flag file <tt>created.rid</tt> then we refuse to use it, as
# we may clobber some manually generated documentation
@@ -212,6 +223,15 @@ option)
end
##
+ # Sets the current documentation tree to +store+ and sets the store's rdoc
+ # driver to this instance.
+
+ def store= store
+ @store = store
+ @store.rdoc = self
+ end
+
+ ##
# Update the flag file in an output directory.
def update_output_dir(op_dir, time, last = {})
@@ -291,7 +311,7 @@ option)
file_list << list_files_in_directory(rel_file_name)
end
else
- raise RDoc::Error, "I can't deal with a #{type} #{rel_file_name}"
+ warn "rdoc can't parse the #{type} #{rel_file_name}"
end
end
@@ -325,7 +345,7 @@ option)
return unless content
- top_level = RDoc::TopLevel.new filename
+ top_level = @store.add_file filename
parser = RDoc::Parser.for top_level, filename, content, @options, @stats
@@ -340,6 +360,14 @@ option)
top_level
+ rescue Errno::EACCES => e
+ $stderr.puts <<-EOF
+Unable to read #{filename}, #{e.message}
+
+Please check the permissions for this file. Perhaps you do not have access to
+it or perhaps the original author's permissions are to restrictive. If the
+this is not your library please report a bug to the author.
+ EOF
rescue => e
$stderr.puts <<-EOF
Before reporting this, could you check that the file you're documenting
@@ -366,7 +394,7 @@ The internal error was:
def parse_files files
file_list = gather_files files
- @stats = RDoc::Stats.new file_list.size, @options.verbosity
+ @stats = RDoc::Stats.new @store, file_list.length, @options.verbosity
return [] if file_list.empty?
@@ -385,11 +413,16 @@ The internal error was:
end
##
- # Removes file extensions known to be unparseable from +files+
+ # Removes file extensions known to be unparseable from +files+ and TAGS
+ # files for emacs and vim.
def remove_unparseable files
files.reject do |file|
- file =~ /\.(?:class|eps|erb|scpt\.txt|ttf|yml)$/i
+ file =~ /\.(?:class|eps|erb|scpt\.txt|ttf|yml)$/i or
+ (file =~ /tags$/i and
+ open(file, 'rb') { |io|
+ io.read(100) =~ /\A(\f\n[^,]+,\d+$|!_TAG_)/
+ })
end
end
@@ -408,13 +441,13 @@ The internal error was:
# current directory, so make sure you're somewhere writable before invoking.
def document options
- RDoc::RDoc.reset
+ self.store = RDoc::Store.new
if RDoc::Options === options then
@options = options
@options.finish
else
- @options = RDoc::Options.new
+ @options = load_options
@options.parse options
end
@@ -429,13 +462,18 @@ The internal error was:
@last_modified = setup_output_dir @options.op_dir, @options.force_update
end
+ @store.encoding = @options.encoding if @options.respond_to? :encoding
+ @store.dry_run = @options.dry_run
+ @store.main = @options.main_page
+ @store.title = @options.title
+
@start_time = Time.now
file_info = parse_files @options.files
@options.default_title = "RDoc Documentation"
- RDoc::TopLevel.complete @options.visibility
+ @store.complete @options.visibility
@stats.coverage_level = @options.coverage_report
@@ -448,9 +486,9 @@ The internal error was:
else
gen_klass = @options.generator
- @generator = gen_klass.new @options
+ @generator = gen_klass.new @store, @options
- generate file_info
+ generate
end
if @stats and (@options.coverage_report or not @options.quiet) then
@@ -466,20 +504,14 @@ The internal error was:
# output dir using the generator selected
# by the RDoc options
- def generate file_info
+ def generate
Dir.chdir @options.op_dir do
- begin
- self.class.current = self
-
- unless @options.quiet then
- $stderr.puts "\nGenerating #{@generator.class.name.sub(/^.*::/, '')} format into #{Dir.pwd}..."
- end
-
- @generator.generate file_info
- update_output_dir '.', @start_time, @last_modified
- ensure
- self.class.current = nil
+ unless @options.quiet then
+ $stderr.puts "\nGenerating #{@generator.class.name.sub(/^.*::/, '')} format into #{Dir.pwd}..."
end
+
+ @generator.generate
+ update_output_dir '.', @start_time, @last_modified
end
end
diff --git a/lib/rdoc/require.rb b/lib/rdoc/require.rb
index 65d3d464da..a3d4bd18c0 100644
--- a/lib/rdoc/require.rb
+++ b/lib/rdoc/require.rb
@@ -1,5 +1,3 @@
-require 'rdoc/code_object'
-
##
# A file loaded by \#require
diff --git a/lib/rdoc/ri.rb b/lib/rdoc/ri.rb
index 17da3fbe83..8b35e0fa2f 100644
--- a/lib/rdoc/ri.rb
+++ b/lib/rdoc/ri.rb
@@ -12,7 +12,9 @@ module RDoc::RI
class Error < RDoc::Error; end
-end
+ autoload :Driver, 'rdoc/ri/driver'
+ autoload :Paths, 'rdoc/ri/paths'
+ autoload :Store, 'rdoc/ri/store'
-require 'rdoc/ri/store'
+end
diff --git a/lib/rdoc/ri/driver.rb b/lib/rdoc/ri/driver.rb
index 26304dca96..4beda55881 100644
--- a/lib/rdoc/ri/driver.rb
+++ b/lib/rdoc/ri/driver.rb
@@ -11,11 +11,7 @@ begin
rescue LoadError
end
-require 'rdoc/ri'
-require 'rdoc/ri/paths'
-require 'rdoc/markup'
-require 'rdoc/markup/formatter'
-require 'rdoc/text'
+require 'rdoc'
##
# For RubyGems backwards compatibility
@@ -61,6 +57,11 @@ class RDoc::RI::Driver
end
##
+ # Show all method documentation following a class or module
+
+ attr_accessor :show_all
+
+ ##
# An RDoc::RI::Store for each entry in the RI path
attr_accessor :stores
@@ -75,17 +76,18 @@ class RDoc::RI::Driver
def self.default_options
options = {}
- options[:use_stdout] = !$stdout.tty?
- options[:width] = 72
options[:interactive] = false
- options[:use_cache] = true
- options[:profile] = false
+ options[:profile] = false
+ options[:show_all] = false
+ options[:use_cache] = true
+ options[:use_stdout] = !$stdout.tty?
+ options[:width] = 72
# By default all standard paths are used.
- options[:use_system] = true
- options[:use_site] = true
- options[:use_home] = true
- options[:use_gems] = true
+ options[:use_system] = true
+ options[:use_site] = true
+ options[:use_home] = true
+ options[:use_gems] = true
options[:extra_doc_dirs] = []
return options
@@ -123,7 +125,11 @@ Usage: #{opt.program_name} [options] [names...]
Where name can be:
- Class | Class::method | Class#method | Class.method | method
+ Class | Module | Module::Class
+
+ Class::method | Class#method | Class.method | method
+
+ gem_name: | gem_name:README | gem_name:History
All class names may be abbreviated to their minimum unambiguous form. If a name
is ambiguous, all valid options will be listed.
@@ -131,12 +137,18 @@ is ambiguous, all valid options will be listed.
A '.' matches either class or instance methods, while #method
matches only instance and ::method matches only class methods.
+README and other files may be displayed by prefixing them with the gem name
+they're contained in. If the gem name is followed by a ':' all files in the
+gem will be shown. The file name extension may be omitted where it is
+unambiguous.
+
For example:
#{opt.program_name} Fil
#{opt.program_name} File
#{opt.program_name} File.new
#{opt.program_name} zip
+ #{opt.program_name} rdoc:README
Note that shell quoting or escaping may be required for method names containing
punctuation:
@@ -151,7 +163,10 @@ To see the default directories ri will search, run:
Specifying the --system, --site, --home, --gems or --doc-dir options will
limit ri to searching only the specified directories.
-Options may also be set in the 'RI' environment variable.
+ri options may be set in the 'RI' environment variable.
+
+The ri pager can be set with the 'RI_PAGER' environment variable or the
+'PAGER' environment variable.
EOT
opt.separator nil
@@ -159,64 +174,74 @@ Options may also be set in the 'RI' environment variable.
opt.separator nil
- formatters = RDoc::Markup.constants.grep(/^To[A-Z][a-z]+$/).sort
- formatters = formatters.sort.map do |formatter|
- formatter.to_s.sub('To', '').downcase
+ opt.on("--[no-]interactive", "-i",
+ "In interactive mode you can repeatedly",
+ "look up methods with autocomplete.") do |interactive|
+ options[:interactive] = interactive
end
- opt.on("--format=NAME", "-f",
- "Uses the selected formatter. The default",
- "formatter is bs for paged output and ansi",
- "otherwise. Valid formatters are:",
- formatters.join(' '), formatters) do |value|
- options[:formatter] = RDoc::Markup.const_get "To#{value.capitalize}"
+ opt.separator nil
+
+ opt.on("--[no-]all", "-a",
+ "Show all documentation for a class or",
+ "module.") do |show_all|
+ options[:show_all] = show_all
end
opt.separator nil
- opt.on("--no-pager", "-T",
- "Send output directly to stdout,",
- "rather than to a pager.") do
- options[:use_stdout] = true
+ opt.on("--[no-]list", "-l",
+ "List classes ri knows about.") do |list|
+ options[:list] = list
end
opt.separator nil
- opt.on("--width=WIDTH", "-w", OptionParser::DecimalInteger,
- "Set the width of the output.") do |value|
- options[:width] = value
+ opt.on("--[no-]pager", "-T",
+ "Send output directly to stdout,",
+ "rather than to a pager.") do |use_pager|
+ options[:use_stdout] = !use_pager
end
opt.separator nil
- opt.on("--interactive", "-i",
- "In interactive mode you can repeatedly",
- "look up methods with autocomplete.") do
- options[:interactive] = true
+ opt.on("--width=WIDTH", "-w", OptionParser::DecimalInteger,
+ "Set the width of the output.") do |width|
+ options[:width] = width
end
opt.separator nil
- opt.on("--list", "-l",
- "List classes ri knows about.") do
- options[:list] = true
+ opt.on("--server [PORT]", Integer,
+ "Run RDoc server on the given port.",
+ "The default port is 8214.") do |port|
+ options[:server] = port || 8214
end
opt.separator nil
- opt.on("--[no-]profile",
- "Run with the ruby profiler") do |value|
- options[:profile] = value
+ formatters = RDoc::Markup.constants.grep(/^To[A-Z][a-z]+$/).sort
+ formatters = formatters.sort.map do |formatter|
+ formatter.to_s.sub('To', '').downcase
+ end
+ formatters -= %w[html label test] # remove useless output formats
+
+ opt.on("--format=NAME", "-f",
+ "Uses the selected formatter. The default",
+ "formatter is bs for paged output and ansi",
+ "otherwise. Valid formatters are:",
+ formatters.join(' '), formatters) do |value|
+ options[:formatter] = RDoc::Markup.const_get "To#{value.capitalize}"
end
opt.separator nil
opt.separator "Data source options:"
opt.separator nil
- opt.on("--list-doc-dirs",
+ opt.on("--[no-]list-doc-dirs",
"List the directories from which ri will",
- "source documentation on stdout and exit.") do
- options[:list_doc_dirs] = true
+ "source documentation on stdout and exit.") do |list_doc_dirs|
+ options[:list_doc_dirs] = list_doc_dirs
end
opt.separator nil
@@ -284,6 +309,13 @@ Options may also be set in the 'RI' environment variable.
opt.separator "Debug options:"
opt.separator nil
+ opt.on("--[no-]profile",
+ "Run with the ruby profiler") do |value|
+ options[:profile] = value
+ end
+
+ opt.separator nil
+
opt.on("--dump=CACHE", File,
"Dumps data from an ri cache or data file") do |value|
options[:dump_path] = value
@@ -356,7 +388,12 @@ Options may also be set in the 'RI' environment variable.
@list_doc_dirs = options[:list_doc_dirs]
@interactive = options[:interactive]
+ @server = options[:server]
@use_stdout = options[:use_stdout]
+ @show_all = options[:show_all]
+
+ # pager process for jruby
+ @jruby_pager_process = nil
end
##
@@ -404,15 +441,23 @@ Options may also be set in the 'RI' environment variable.
end
##
- # Adds +includes+ to +out+
+ # Adds +extends+ to +out+
- def add_includes out, includes
- return if includes.empty?
+ def add_extends out, extends
+ add_extension_modules out, 'Extended by', extends
+ end
+
+ ##
+ # Adds a list of +extensions+ to this module of the given +type+ to +out+.
+ # add_includes and add_extends call this, so you should use those directly.
+
+ def add_extension_modules out, type, extensions
+ return if extensions.empty?
out << RDoc::Markup::Rule.new(1)
- out << RDoc::Markup::Heading.new(1, "Includes:")
+ out << RDoc::Markup::Heading.new(1, "#{type}:")
- includes.each do |modules, store|
+ extensions.each do |modules, store|
if modules.length == 1 then
include = modules.first
name = include.name
@@ -450,6 +495,37 @@ Options may also be set in the 'RI' environment variable.
end
##
+ # Adds +includes+ to +out+
+
+ def add_includes out, includes
+ add_extension_modules out, 'Includes', includes
+ end
+
+ ##
+ # Looks up the method +name+ and adds it to +out+
+
+ def add_method out, name
+ filtered = lookup_method name
+
+ method_out = method_document name, filtered
+
+ out.concat method_out.parts
+ end
+
+ ##
+ # Adds documentation for all methods in +klass+ to +out+
+
+ def add_method_documentation out, klass
+ klass.method_list.each do |method|
+ begin
+ add_method out, method.full_name
+ rescue NotFoundError
+ next
+ end
+ end
+ end
+
+ ##
# Adds a list of +methods+ to +out+ with a heading of +name+
def add_method_list out, methods, name
@@ -458,10 +534,10 @@ Options may also be set in the 'RI' environment variable.
out << RDoc::Markup::Heading.new(1, "#{name}:")
out << RDoc::Markup::BlankLine.new
- if @use_stdout and !@interactive
- out.push(*methods.map do |method|
+ if @use_stdout and !@interactive then
+ out.concat methods.map { |method|
RDoc::Markup::Verbatim.new method
- end)
+ }
else
out << RDoc::Markup::IndentedParagraph.new(2, methods.join(', '))
end
@@ -493,8 +569,8 @@ Options may also be set in the 'RI' environment variable.
klasses = klasses - seen
- ancestors.push(*klasses)
- unexamined.push(*klasses)
+ ancestors.concat klasses
+ unexamined.concat klasses
end
ancestors.reverse
@@ -509,7 +585,7 @@ Options may also be set in the 'RI' environment variable.
##
# Builds a RDoc::Markup::Document from +found+, +klasess+ and +includes+
- def class_document name, found, klasses, includes
+ def class_document name, found, klasses, includes, extends
also_in = []
out = RDoc::Markup::Document.new
@@ -517,6 +593,7 @@ Options may also be set in the 'RI' environment variable.
add_class out, name, klasses
add_includes out, includes
+ add_extends out, extends
found.each do |store, klass|
comment = klass.comment
@@ -542,7 +619,7 @@ Options may also be set in the 'RI' environment variable.
parts.flatten!
parts.pop
- out.push(*parts)
+ out.concat parts
else
out << comment
end
@@ -559,13 +636,13 @@ Options may also be set in the 'RI' environment variable.
constants = klass.constants.sort_by { |constant| constant.name }
- list.push(*constants.map do |constant|
+ list.items.concat constants.map { |constant|
parts = constant.comment.parts if constant.comment
parts << RDoc::Markup::Paragraph.new('[not documented]') if
parts.empty?
RDoc::Markup::ListItem.new(constant.name, *parts)
- end)
+ }
out << list
out << RDoc::Markup::BlankLine.new
@@ -574,6 +651,8 @@ Options may also be set in the 'RI' environment variable.
add_method_list out, class_methods, 'Class methods'
add_method_list out, instance_methods, 'Instance methods'
add_method_list out, attributes, 'Attributes'
+
+ add_method_documentation out, klass if @show_all
end
add_also_in out, also_in
@@ -601,26 +680,29 @@ Options may also be set in the 'RI' environment variable.
end
##
- # Returns the stores wherin +name+ is found along with the classes and
- # includes that match it
+ # Returns the stores wherein +name+ is found along with the classes,
+ # extends and includes that match it
- def classes_and_includes_for name
+ def classes_and_includes_and_extends_for name
klasses = []
+ extends = []
includes = []
found = @stores.map do |store|
begin
klass = store.load_class name
klasses << klass
+ extends << [klass.extends, store] if klass.extends
includes << [klass.includes, store] if klass.includes
[store, klass]
- rescue Errno::ENOENT
+ rescue RDoc::Store::MissingFileError
end
end.compact
+ extends.reject! do |modules,| modules.empty? end
includes.reject! do |modules,| modules.empty? end
- [found, klasses, includes]
+ [found, klasses, includes, extends]
end
##
@@ -659,7 +741,7 @@ Options may also be set in the 'RI' environment variable.
completions << "#{klass}#{selector}"
end
- completions.push(*methods)
+ completions.concat methods
end
completions.sort.uniq
@@ -682,11 +764,12 @@ Options may also be set in the 'RI' environment variable.
def display_class name
return if name =~ /#|\./
- found, klasses, includes = classes_and_includes_for name
+ found, klasses, includes, extends =
+ classes_and_includes_and_extends_for name
return if found.empty?
- out = class_document name, found, klasses, includes
+ out = class_document name, found, klasses, includes, extends
display out
end
@@ -695,13 +778,9 @@ Options may also be set in the 'RI' environment variable.
# Outputs formatted RI data for method +name+
def display_method name
- found = load_methods_matching name
-
- raise NotFoundError, name if found.empty?
-
- filtered = filter_methods found, name
+ out = RDoc::Markup::Document.new
- out = method_document name, filtered
+ add_method out, name
display out
end
@@ -713,6 +792,11 @@ Options may also be set in the 'RI' environment variable.
# be guessed, raises an error if +name+ couldn't be guessed.
def display_name name
+ if name =~ /\w:(\w|$)/ then
+ display_page name
+ return true
+ end
+
return true if display_class name
display_method name if name =~ /::|#|\./
@@ -727,7 +811,7 @@ Options may also be set in the 'RI' environment variable.
page do |io|
io.puts "#{name} not found, maybe you meant:"
io.puts
- io.puts matches.join("\n")
+ io.puts matches.sort.join("\n")
end
false
@@ -745,6 +829,61 @@ Options may also be set in the 'RI' environment variable.
end
##
+ # Outputs formatted RI data for page +name+.
+
+ def display_page name
+ store_name, page_name = name.split ':', 2
+
+ store = @stores.find { |s| s.source == store_name }
+
+ return display_page_list store if page_name.empty?
+
+ pages = store.cache[:pages]
+
+ unless pages.include? page_name then
+ found_names = pages.select do |n|
+ n =~ /^#{Regexp.escape page_name}\.[^.]+$/
+ end
+
+ if found_names.length > 1 then
+ return display_page_list store, found_names, page_name
+ end
+
+ page_name = found_names.first
+ end
+
+ page = store.load_page page_name
+
+ display page.comment
+ end
+
+ ##
+ # Outputs a formatted RI page list for the pages in +store+.
+
+ def display_page_list store, pages = store.cache[:pages], search = nil
+ out = RDoc::Markup::Document.new
+
+ title = if search then
+ "#{search} pages"
+ else
+ 'Pages'
+ end
+
+ out << RDoc::Markup::Heading.new(1, "#{title} in #{store.friendly_path}")
+ out << RDoc::Markup::BlankLine.new
+
+ list = RDoc::Markup::List.new(:BULLET)
+
+ pages.each do |page|
+ list << RDoc::Markup::Paragraph.new(page)
+ end
+
+ out << list
+
+ display out
+ end
+
+ ##
# Expands abbreviated klass +klass+ into a fully-qualified class. "Zl::Da"
# will be expanded to Zlib::DataError.
@@ -776,7 +915,12 @@ Options may also be set in the 'RI' environment variable.
return [selector, method].join if klass.empty?
- "#{expand_class klass}#{selector}#{method}"
+ case selector
+ when ':' then
+ [find_store(klass), selector, method]
+ else
+ [expand_class(klass), selector, method]
+ end.join
end
##
@@ -841,6 +985,55 @@ Options may also be set in the 'RI' environment variable.
end
##
+ # Finds the given +pager+ for jruby. Returns an IO if +pager+ was found.
+ #
+ # Returns false if +pager+ does not exist.
+ #
+ # Returns nil if the jruby JVM doesn't support ProcessBuilder redirection
+ # (1.6 and older).
+
+ def find_pager_jruby pager
+ require 'java'
+ require 'shellwords'
+
+ return nil unless java.lang.ProcessBuilder.constants.include? :Redirect
+
+ pager = Shellwords.split pager
+
+ pb = java.lang.ProcessBuilder.new(*pager)
+ pb = pb.redirect_output java.lang.ProcessBuilder::Redirect::INHERIT
+
+ @jruby_pager_process = pb.start
+
+ input = @jruby_pager_process.output_stream
+
+ io = input.to_io
+ io.sync = true
+ io
+ rescue java.io.IOException
+ false
+ end
+
+ ##
+ # Finds a store that matches +name+ which can be the name of a gem, "ruby",
+ # "home" or "site".
+ #
+ # See also RDoc::Store#source
+
+ def find_store name
+ @stores.each do |store|
+ source = store.source
+
+ return source if source == name
+
+ return source if
+ store.type == :gem and source =~ /^#{Regexp.escape name}-\d/
+ end
+
+ raise RDoc::RI::Driver::NotFoundError, name
+ end
+
+ ##
# Creates a new RDoc::Markup::Formatter. If a formatter is given with -f,
# use it. If we're outputting to a pager, use bs, otherwise ansi.
@@ -909,7 +1102,7 @@ Options may also be set in the 'RI' environment variable.
classes = []
stores.each do |store|
- classes << store.modules
+ classes << store.module_names
end
classes = classes.flatten.uniq.sort
@@ -951,7 +1144,7 @@ Options may also be set in the 'RI' environment variable.
"#{klass}##{match}"
end
- found.push(*matches)
+ found.concat matches
end
end
@@ -965,7 +1158,7 @@ Options may also be set in the 'RI' environment variable.
"#{klass}::#{match}"
end
- found.push(*matches)
+ found.concat matches
end
end
@@ -1012,7 +1205,18 @@ Options may also be set in the 'RI' environment variable.
end
##
- # Builds a RDoc::Markup::Document from +found+, +klasess+ and +includes+
+ # Returns a filtered list of methods matching +name+
+
+ def lookup_method name
+ found = load_methods_matching name
+
+ raise NotFoundError, name if found.empty?
+
+ filter_methods found, name
+ end
+
+ ##
+ # Builds a RDoc::Markup::Document from +found+, +klasses+ and +includes+
def method_document name, filtered
out = RDoc::Markup::Document.new
@@ -1027,6 +1231,7 @@ Options may also be set in the 'RI' environment variable.
unless name =~ /^#{Regexp.escape method.parent_name}/ then
out << RDoc::Markup::Heading.new(3, "Implementation from #{method.parent_name}")
end
+
out << RDoc::Markup::Rule.new(1)
if method.arglists then
@@ -1036,6 +1241,12 @@ Options may also be set in the 'RI' environment variable.
out << RDoc::Markup::Rule.new(1)
end
+ if method.respond_to?(:superclass_method) and method.superclass_method
+ out << RDoc::Markup::BlankLine.new
+ out << RDoc::Markup::Heading.new(4, "(Uses superclass method #{method.superclass_method})")
+ out << RDoc::Markup::Rule.new(1)
+ end
+
out << RDoc::Markup::BlankLine.new
out << method.comment
out << RDoc::Markup::BlankLine.new
@@ -1080,6 +1291,7 @@ Options may also be set in the 'RI' environment variable.
yield pager
ensure
pager.close
+ @jruby_pager_process.wait_for if @jruby_pager_process
end
else
yield $stdout
@@ -1101,10 +1313,10 @@ Options may also be set in the 'RI' environment variable.
# Foo::Bar#baz.
#
# NOTE: Given Foo::Bar, Bar is considered a class even though it may be a
- # method
+ # method
def parse_name name
- parts = name.split(/(::|#|\.)/)
+ parts = name.split(/(::?|#|\.)/)
if parts.length == 1 then
if parts.first =~ /^[a-z]|^([%&*+\/<>^`|~-]|\+@|-@|<<|<=>?|===?|=>|=~|>>|\[\]=?|~@)$/ then
@@ -1135,6 +1347,8 @@ Options may also be set in the 'RI' environment variable.
puts @doc_dirs
elsif @list then
list_known_classes @names
+ elsif @server then
+ start_server
elsif @interactive or @names.empty? then
interactive
else
@@ -1151,6 +1365,8 @@ Options may also be set in the 'RI' environment variable.
def setup_pager
return if @use_stdout
+ jruby = Object.const_defined?(:RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
+
pagers = [ENV['RI_PAGER'], ENV['PAGER'], 'pager', 'less', 'more']
pagers.compact.uniq.each do |pager|
@@ -1160,9 +1376,17 @@ Options may also be set in the 'RI' environment variable.
next unless in_path? pager_cmd
- io = IO.popen(pager, 'w') rescue next
+ if jruby then
+ case io = find_pager_jruby(pager)
+ when nil then break
+ when false then next
+ else io
+ end
+ else
+ io = IO.popen(pager, 'w') rescue next
+ end
- next if $? and $?.exited? # pager didn't work
+ next if $? and $?.pid == io.pid and $?.exited? # pager didn't work
@paging = true
@@ -1174,5 +1398,21 @@ Options may also be set in the 'RI' environment variable.
nil
end
+ ##
+ # Starts a WEBrick server for ri.
+
+ def start_server
+ require 'webrick'
+
+ server = WEBrick::HTTPServer.new :Port => @server
+
+ server.mount '/', RDoc::Servlet
+
+ trap 'INT' do server.shutdown end
+ trap 'TERM' do server.shutdown end
+
+ server.start
+ end
+
end
diff --git a/lib/rdoc/ri/paths.rb b/lib/rdoc/ri/paths.rb
index a3c65bf928..d7ea285eaa 100644
--- a/lib/rdoc/ri/paths.rb
+++ b/lib/rdoc/ri/paths.rb
@@ -1,7 +1,8 @@
require 'rdoc/ri'
##
-# The directories where ri data lives.
+# The directories where ri data lives. Paths can be enumerated via ::each, or
+# queried individually via ::system_dir, ::site_dir, ::home_dir and ::gem_dir.
module RDoc::RI::Paths
@@ -10,15 +11,12 @@ module RDoc::RI::Paths
version = RbConfig::CONFIG['ruby_version']
- base = if RbConfig::CONFIG.key? 'ridir' then
+ BASE = if RbConfig::CONFIG.key? 'ridir' then
File.join RbConfig::CONFIG['ridir'], version
else
File.join RbConfig::CONFIG['datadir'], 'ri', version
end
- SYSDIR = File.join base, "system"
- SITEDIR = File.join base, "site"
-
homedir = begin
File.expand_path('~')
rescue ArgumentError
@@ -32,8 +30,6 @@ module RDoc::RI::Paths
end
#:startdoc:
- @gemdirs = nil
-
##
# Iterates over each selected path yielding the directory and type.
#
@@ -47,16 +43,19 @@ module RDoc::RI::Paths
# :extra:: ri data directory from the command line. Yielded for each
# entry in +extra_dirs+
- def self.each system, site, home, gems, *extra_dirs # :yields: directory, type
+ def self.each system = true, site = true, home = true, gems = :latest, *extra_dirs # :yields: directory, type
+ return enum_for __method__, system, site, home, gems, *extra_dirs unless
+ block_given?
+
extra_dirs.each do |dir|
yield dir, :extra
end
- yield SYSDIR, :system if system
- yield SITEDIR, :site if site
- yield HOMEDIR, :home if home and HOMEDIR
+ yield system_dir, :system if system
+ yield site_dir, :site if site
+ yield home_dir, :home if home and HOMEDIR
- gemdirs.each do |dir|
+ gemdirs(gems).each do |dir|
yield dir, :gem
end if gems
@@ -64,36 +63,72 @@ module RDoc::RI::Paths
end
##
- # The latest installed gems' ri directories
+ # The ri directory for the gem with +gem_name+.
- def self.gemdirs
- return @gemdirs if @gemdirs
+ def self.gem_dir name, version
+ req = Gem::Requirement.new "= #{version}"
- require 'rubygems' unless defined?(Gem)
+ spec = Gem::Specification.find_by_name name, req
- # HACK dup'd from Gem.latest_partials and friends
- all_paths = []
+ File.join spec.doc_dir, 'ri'
+ end
- all_paths = Gem.path.map do |dir|
- Dir[File.join(dir, 'doc', '*', 'ri')]
- end.flatten
+ ##
+ # The latest installed gems' ri directories. +filter+ can be :all or
+ # :latest.
+ #
+ # A +filter+ :all includes all versions of gems and includes gems without
+ # ri documentation.
+
+ def self.gemdirs filter = :latest
+ require 'rubygems' unless defined?(Gem)
ri_paths = {}
- all_paths.each do |dir|
- base = File.basename File.dirname(dir)
- if base =~ /(.*)-((\d+\.)*\d+)/ then
- name, version = $1, $2
- ver = Gem::Version.new version
- if ri_paths[name].nil? or ver > ri_paths[name][0] then
- ri_paths[name] = [ver, dir]
+ all = Gem::Specification.map do |spec|
+ [File.join(spec.doc_dir, 'ri'), spec.name, spec.version]
+ end
+
+ if filter == :all then
+ gemdirs = []
+
+ all.group_by do |_, name, _|
+ name
+ end.sort_by do |group, _|
+ group
+ end.map do |group, items|
+ items.sort_by do |_, _, version|
+ version
+ end.reverse_each do |dir,|
+ gemdirs << dir
end
end
+
+ return gemdirs
+ end
+
+ all.each do |dir, name, ver|
+ next unless File.exist? dir
+
+ if ri_paths[name].nil? or ver > ri_paths[name].first then
+ ri_paths[name] = [ver, name, dir]
+ end
end
- @gemdirs = ri_paths.map { |k,v| v.last }.sort
+ ri_paths.sort_by { |_, (_, name, _)| name }.map { |k, v| v.last }
rescue LoadError
- @gemdirs = []
+ []
+ end
+
+ ##
+ # The location of the rdoc data in the user's home directory.
+ #
+ # Like ::system, ri data in the user's home directory is rare and predates
+ # libraries distributed via RubyGems. ri data is rarely generated into this
+ # directory.
+
+ def self.home_dir
+ HOMEDIR
end
##
@@ -102,7 +137,7 @@ module RDoc::RI::Paths
#
# See also ::each
- def self.path(system, site, home, gems, *extra_dirs)
+ def self.path(system = true, site = true, home = true, gems = :latest, *extra_dirs)
path = raw_path system, site, home, gems, *extra_dirs
path.select { |directory| File.directory? directory }
@@ -124,5 +159,29 @@ module RDoc::RI::Paths
path.compact
end
+ ##
+ # The location of ri data installed into the site dir.
+ #
+ # Historically this was available for documentation installed by ruby
+ # libraries predating RubyGems. It is unlikely to contain any content for
+ # modern ruby installations.
+
+ def self.site_dir
+ File.join BASE, 'site'
+ end
+
+ ##
+ # The location of the built-in ri data.
+ #
+ # This data is built automatically when `make` is run when ruby is
+ # installed. If you did not install ruby by hand you may need to install
+ # the documentation yourself. Please consult the documentation for your
+ # package manager or ruby installer for details. You can also use the
+ # rdoc-data gem to install system ri data for common versions of ruby.
+
+ def self.system_dir
+ File.join BASE, 'system'
+ end
+
end
diff --git a/lib/rdoc/ri/store.rb b/lib/rdoc/ri/store.rb
index fe4ccc244d..9fa9bbb03c 100644
--- a/lib/rdoc/ri/store.rb
+++ b/lib/rdoc/ri/store.rb
@@ -1,358 +1,6 @@
-require 'rdoc/code_objects'
-require 'fileutils'
+module RDoc::RI
-##
-# A set of ri data.
-#
-# The store manages reading and writing ri data for a project (gem, path,
-# etc.) and maintains a cache of methods, classes and ancestors in the
-# store.
-#
-# The store maintains a #cache of its contents for faster lookup. After
-# adding items to the store it must be flushed using #save_cache. The cache
-# contains the following structures:
-#
-# @cache = {
-# :class_methods => {}, # class name => class methods
-# :instance_methods => {}, # class name => instance methods
-# :attributes => {}, # class name => attributes
-# :modules => [], # classes and modules in this store
-# :ancestors => {}, # class name => ancestor names
-# }
-#--
-# TODO need to store the list of files and prune classes
-
-class RDoc::RI::Store
-
- ##
- # If true this Store will not write any files
-
- attr_accessor :dry_run
-
- ##
- # Path this store reads or writes
-
- attr_accessor :path
-
- ##
- # Type of ri datastore this was loaded from. See RDoc::RI::Driver,
- # RDoc::RI::Paths.
-
- attr_accessor :type
-
- ##
- # The contents of the Store
-
- attr_reader :cache
-
- ##
- # The encoding of the contents in the Store
-
- attr_accessor :encoding
-
- ##
- # Creates a new Store of +type+ that will load or save to +path+
-
- def initialize path, type = nil
- @dry_run = false
- @type = type
- @path = path
- @encoding = nil
-
- @cache = {
- :ancestors => {},
- :attributes => {},
- :class_methods => {},
- :encoding => @encoding,
- :instance_methods => {},
- :modules => [],
- }
- end
-
- ##
- # Ancestors cache accessor. Maps a klass name to an Array of its ancestors
- # in this store. If Foo in this store inherits from Object, Kernel won't be
- # listed (it will be included from ruby's ri store).
-
- def ancestors
- @cache[:ancestors]
- end
-
- ##
- # Attributes cache accessor. Maps a class to an Array of its attributes.
-
- def attributes
- @cache[:attributes]
- end
-
- ##
- # Path to the cache file
-
- def cache_path
- File.join @path, 'cache.ri'
- end
-
- ##
- # Path to the ri data for +klass_name+
-
- def class_file klass_name
- name = klass_name.split('::').last
- File.join class_path(klass_name), "cdesc-#{name}.ri"
- end
-
- ##
- # Class methods cache accessor. Maps a class to an Array of its class
- # methods (not full name).
-
- def class_methods
- @cache[:class_methods]
- end
-
- ##
- # Path where data for +klass_name+ will be stored (methods or class data)
-
- def class_path klass_name
- File.join @path, *klass_name.split('::')
- end
-
- ##
- # Removes empty items and ensures item in each collection are unique and
- # sorted
-
- def clean_cache_collection collection # :nodoc:
- collection.each do |name, item|
- if item.empty? then
- collection.delete name
- else
- # HACK mongrel-1.1.5 documents its files twice
- item.uniq!
- item.sort!
- end
- end
- end
-
- ##
- # Friendly rendition of #path
-
- def friendly_path
- case type
- when :gem then
- sep = Regexp.union(*['/', File::ALT_SEPARATOR].compact)
- @path =~ /#{sep}doc#{sep}(.*?)#{sep}ri$/
- "gem #{$1}"
- when :home then '~/.ri'
- when :site then 'ruby site'
- when :system then 'ruby core'
- else @path
- end
- end
-
- def inspect # :nodoc:
- "#<%s:0x%x %s %p>" % [self.class, object_id, @path, modules.sort]
- end
-
- ##
- # Instance methods cache accessor. Maps a class to an Array of its
- # instance methods (not full name).
-
- def instance_methods
- @cache[:instance_methods]
- end
-
- ##
- # Loads cache file for this store
-
- def load_cache
- #orig_enc = @encoding
-
- open cache_path, 'rb' do |io|
- @cache = Marshal.load io.read
- end
-
- load_enc = @cache[:encoding]
-
- # TODO this feature will be time-consuming to add:
- # a) Encodings may be incompatible but transcodeable
- # b) Need to warn in the appropriate spots, wherever they may be
- # c) Need to handle cross-cache differences in encodings
- # d) Need to warn when generating into a cache with diffent encodings
- #
- #if orig_enc and load_enc != orig_enc then
- # warn "Cached encoding #{load_enc} is incompatible with #{orig_enc}\n" \
- # "from #{path}/cache.ri" unless
- # Encoding.compatible? orig_enc, load_enc
- #end
-
- @encoding = load_enc unless @encoding
-
- @cache
- rescue Errno::ENOENT
- end
-
- ##
- # Loads ri data for +klass_name+
-
- def load_class klass_name
- open class_file(klass_name), 'rb' do |io|
- Marshal.load io.read
- end
- end
-
- ##
- # Loads ri data for +method_name+ in +klass_name+
-
- def load_method klass_name, method_name
- open method_file(klass_name, method_name), 'rb' do |io|
- Marshal.load io.read
- end
- end
-
- ##
- # Path to the ri data for +method_name+ in +klass_name+
-
- def method_file klass_name, method_name
- method_name = method_name.split('::').last
- method_name =~ /#(.*)/
- method_type = $1 ? 'i' : 'c'
- method_name = $1 if $1
-
- method_name = if ''.respond_to? :ord then
- method_name.gsub(/\W/) { "%%%02x" % $&[0].ord }
- else
- method_name.gsub(/\W/) { "%%%02x" % $&[0] }
- end
-
- File.join class_path(klass_name), "#{method_name}-#{method_type}.ri"
- end
-
- ##
- # Modules cache accessor. An Array of all the modules (and classes) in the
- # store.
-
- def modules
- @cache[:modules]
- end
-
- ##
- # Writes the cache file for this store
-
- def save_cache
- clean_cache_collection @cache[:ancestors]
- clean_cache_collection @cache[:attributes]
- clean_cache_collection @cache[:class_methods]
- clean_cache_collection @cache[:instance_methods]
-
- @cache[:modules].uniq!
- @cache[:modules].sort!
- @cache[:encoding] = @encoding # this gets set twice due to assert_cache
-
- return if @dry_run
-
- marshal = Marshal.dump @cache
-
- open cache_path, 'wb' do |io|
- io.write marshal
- end
- end
-
- ##
- # Writes the ri data for +klass+
-
- def save_class klass
- full_name = klass.full_name
-
- FileUtils.mkdir_p class_path(full_name) unless @dry_run
-
- @cache[:modules] << full_name
-
- path = class_file full_name
-
- begin
- disk_klass = load_class full_name
-
- klass = disk_klass.merge klass
- rescue Errno::ENOENT
- end
-
- # BasicObject has no ancestors
- ancestors = klass.ancestors.compact.map do |ancestor|
- # HACK for classes we don't know about (class X < RuntimeError)
- String === ancestor ? ancestor : ancestor.full_name
- end
-
- @cache[:ancestors][full_name] ||= []
- @cache[:ancestors][full_name].push(*ancestors)
-
- attributes = klass.attributes.map do |attribute|
- "#{attribute.definition} #{attribute.name}"
- end
-
- unless attributes.empty? then
- @cache[:attributes][full_name] ||= []
- @cache[:attributes][full_name].push(*attributes)
- end
-
- to_delete = []
-
- unless klass.method_list.empty? then
- @cache[:class_methods][full_name] ||= []
- @cache[:instance_methods][full_name] ||= []
-
- class_methods, instance_methods =
- klass.method_list.partition { |meth| meth.singleton }
-
- class_methods = class_methods. map { |method| method.name }
- instance_methods = instance_methods.map { |method| method.name }
-
- old = @cache[:class_methods][full_name] - class_methods
- to_delete.concat old.map { |method|
- method_file full_name, "#{full_name}::#{method}"
- }
-
- old = @cache[:instance_methods][full_name] - instance_methods
- to_delete.concat old.map { |method|
- method_file full_name, "#{full_name}##{method}"
- }
-
- @cache[:class_methods][full_name] = class_methods
- @cache[:instance_methods][full_name] = instance_methods
- end
-
- return if @dry_run
-
- FileUtils.rm_f to_delete
-
- marshal = Marshal.dump klass
-
- open path, 'wb' do |io|
- io.write marshal
- end
- end
-
- ##
- # Writes the ri data for +method+ on +klass+
-
- def save_method klass, method
- full_name = klass.full_name
-
- FileUtils.mkdir_p class_path(full_name) unless @dry_run
-
- cache = if method.singleton then
- @cache[:class_methods]
- else
- @cache[:instance_methods]
- end
- cache[full_name] ||= []
- cache[full_name] << method.name
-
- return if @dry_run
-
- marshal = Marshal.dump method
-
- open method_file(full_name, method.full_name), 'wb' do |io|
- io.write marshal
- end
- end
+ Store = RDoc::Store # :nodoc:
end
diff --git a/lib/rdoc/ruby_lex.rb b/lib/rdoc/ruby_lex.rb
index 4392cea9cf..845569b0bc 100644
--- a/lib/rdoc/ruby_lex.rb
+++ b/lib/rdoc/ruby_lex.rb
@@ -11,7 +11,6 @@
require "e2mmap"
require "irb/slex"
-require "rdoc/ruby_token"
require "stringio"
##
@@ -21,6 +20,12 @@ require "stringio"
class RDoc::RubyLex
+ ##
+ # Raised upon invalid input
+
+ class Error < RDoc::Error
+ end
+
# :stopdoc:
extend Exception2MessageMapper
@@ -51,6 +56,29 @@ class RDoc::RubyLex
self.debug_level = 0
+ # :startdoc:
+
+ ##
+ # Returns an Array of +ruby+ tokens. See ::new for a description of
+ # +options+.
+
+ def self.tokenize ruby, options
+ tokens = []
+
+ scanner = RDoc::RubyLex.new ruby, options
+ scanner.exception_on_syntax_error = true
+
+ while token = scanner.token do
+ tokens << token
+ end
+
+ tokens
+ end
+
+ ##
+ # Creates a new lexer for +content+. +options+ is an RDoc::Options, only
+ # +tab_width is used.
+
def initialize(content, options)
lex_init
@@ -91,8 +119,11 @@ class RDoc::RubyLex
@prompt = nil
@prev_seek = nil
+ @ltype = nil
end
+ # :stopdoc:
+
def inspect # :nodoc:
"#<%s:0x%x pos %d lex_state %p space_seen %p>" % [
self.class, object_id,
@@ -122,8 +153,8 @@ class RDoc::RubyLex
end
def get_readed
- if idx = @readed.reverse.index("\n")
- @base_char_no = idx
+ if idx = @readed.rindex("\n")
+ @base_char_no = @readed.size - (idx + 1)
else
@base_char_no += @readed.size
end
@@ -188,8 +219,8 @@ class RDoc::RubyLex
@seek -= 1
if c == "\n"
@line_no -= 1
- if idx = @readed.reverse.index("\n")
- @char_no = @readed.size - idx
+ if idx = @readed.rindex("\n")
+ @char_no = idx + 1
else
@char_no = @base_char_no + @readed.size
end
@@ -323,7 +354,7 @@ class RDoc::RubyLex
tk = @OP.match(self)
@space_seen = tk.kind_of?(TkSPACE)
rescue SyntaxError => e
- raise RDoc::Error, "syntax error: #{e.message}" if
+ raise Error, "syntax error: #{e.message}" if
@exception_on_syntax_error
tk = TkError.new(@seek, @line_no, @char_no)
@@ -381,7 +412,7 @@ class RDoc::RubyLex
def lex_init()
@OP = IRB::SLex.new
@OP.def_rules("\0", "\004", "\032") do |op, io|
- Token(TkEND_OF_SCRIPT)
+ Token(TkEND_OF_SCRIPT, '')
end
@OP.def_rules(" ", "\t", "\f", "\r", "\13") do |op, io|
@@ -413,7 +444,7 @@ class RDoc::RubyLex
gets # consume =end
@ltype = nil
- Token(TkCOMMENT, res)
+ Token(TkRD_COMMENT, res)
end
@OP.def_rule("\n") do |op, io|
@@ -460,7 +491,7 @@ class RDoc::RubyLex
|op, io|
tk = nil
if @lex_state != EXPR_END && @lex_state != EXPR_CLASS &&
- (@lex_state != EXPR_ARG || @space_seen)
+ (@lex_state != EXPR_ARG || @space_seen)
c = peek(0)
if /\S/ =~ c && (/["'`]/ =~ c || /\w/ =~ c || c == "-")
tk = identify_here_document
@@ -505,13 +536,8 @@ class RDoc::RubyLex
@lex_state = EXPR_BEG;
Token(TkQUESTION)
else
- str = ch
- if ch == '\\'
- str << read_escape
- end
@lex_state = EXPR_END
- str << (ch.respond_to?(:ord) ? ch.ord : ch[0])
- Token(TkINTEGER, str)
+ Token(TkSTRING, ch)
end
end
end
@@ -782,7 +808,8 @@ class RDoc::RubyLex
@OP.def_rule("_") do
if peek_match?(/_END__/) and @lex_state == EXPR_BEG then
- Token(TkEND_OF_SCRIPT)
+ 6.times { getc }
+ Token(TkEND_OF_SCRIPT, '__END__')
else
ungetc
identify_identifier
@@ -909,6 +936,8 @@ class RDoc::RubyLex
@indent += 1
@indent_stack.push token_c
end
+ else
+ token_c = TkIDENTIFIER
end
elsif DEINDENT_CLAUSE.include?(token)
@@ -929,7 +958,8 @@ class RDoc::RubyLex
if peek(0) == '='
token.concat getc
end
- elsif @lex_state == EXPR_BEG || @lex_state == EXPR_DOT
+ elsif @lex_state == EXPR_BEG || @lex_state == EXPR_DOT ||
+ @lex_state == EXPR_ARG
@lex_state = EXPR_ARG
else
@lex_state = EXPR_END
@@ -978,14 +1008,15 @@ class RDoc::RubyLex
end
@here_header = false
- doc = ''
+ doc = '"'
while l = gets
- l = l.sub(/(:?\r)?\n\z/, '')
- if (indent ? l.strip : l) == quoted
+ l = l.sub(/(:?\r)?\n\z/, "\n")
+ if (indent ? l.strip : l.chomp) == quoted
break
end
doc << l
end
+ doc << '"'
@here_header = true
@here_readed.concat reserve
@@ -999,13 +1030,14 @@ class RDoc::RubyLex
end
def identify_quotation
- ch = getc
- if lt = PERCENT_LTYPE[ch]
+ type = ch = getc
+ if lt = PERCENT_LTYPE[type]
ch = getc
- elsif ch =~ /\W/
+ elsif type =~ /\W/
+ type = nil
lt = "\""
else
- raise RDoc::Error, "unknown type of %string #{ch.inspect}"
+ return Token(TkMOD, '%')
end
# if ch !~ /\W/
# ungetc
@@ -1013,7 +1045,7 @@ class RDoc::RubyLex
# end
#@ltype = lt
@quoted = ch unless @quoted = PERCENT_PAREN[ch]
- identify_string(lt, @quoted)
+ identify_string(lt, @quoted, type)
end
def identify_number(op = "")
@@ -1040,7 +1072,7 @@ class RDoc::RubyLex
when /[0-7]/
match = /[0-7_]/
when /[89]/
- raise RDoc::Error, "Illegal octal digit"
+ raise Error, "Illegal octal digit"
else
return Token(TkINTEGER, num)
end
@@ -1054,7 +1086,7 @@ class RDoc::RubyLex
if match =~ ch
if ch == "_"
if non_digit
- raise RDoc::Error, "trailing `#{ch}' in number"
+ raise Error, "trailing `#{ch}' in number"
else
non_digit = ch
end
@@ -1066,10 +1098,10 @@ class RDoc::RubyLex
ungetc
num[-1, 1] = ''
if len0
- raise RDoc::Error, "numeric literal without digits"
+ raise Error, "numeric literal without digits"
end
if non_digit
- raise RDoc::Error, "trailing `#{non_digit}' in number"
+ raise Error, "trailing `#{non_digit}' in number"
end
break
end
@@ -1090,7 +1122,7 @@ class RDoc::RubyLex
non_digit = ch
when allow_point && "."
if non_digit
- raise RDoc::Error, "trailing `#{non_digit}' in number"
+ raise Error, "trailing `#{non_digit}' in number"
end
type = TkFLOAT
if peek(0) !~ /[0-9]/
@@ -1102,7 +1134,7 @@ class RDoc::RubyLex
allow_point = false
when allow_e && "e", allow_e && "E"
if non_digit
- raise RDoc::Error, "trailing `#{non_digit}' in number"
+ raise Error, "trailing `#{non_digit}' in number"
end
type = TkFLOAT
if peek(0) =~ /[+-]/
@@ -1113,7 +1145,7 @@ class RDoc::RubyLex
non_digit = ch
else
if non_digit
- raise RDoc::Error, "trailing `#{non_digit}' in number"
+ raise Error, "trailing `#{non_digit}' in number"
end
ungetc
num[-1, 1] = ''
@@ -1124,14 +1156,17 @@ class RDoc::RubyLex
Token(type, num)
end
- def identify_string(ltype, quoted = ltype)
+ def identify_string(ltype, quoted = ltype, type = nil)
+ close = PERCENT_PAREN.values.include?(quoted)
@ltype = ltype
@quoted = quoted
- str = if ltype == quoted then
+ str = if ltype == quoted and %w[" ' /].include? ltype then
ltype.dup
+ elsif RUBY_VERSION > '1.9' then
+ "%#{type or PERCENT_LTYPE.key ltype}#{PERCENT_PAREN_REV[quoted]}"
else
- "%#{PERCENT_PAREN_REV[quoted]}"
+ "%#{type or PERCENT_LTYPE.index ltype}#{PERCENT_PAREN_REV[quoted]}"
end
subtype = nil
@@ -1141,7 +1176,7 @@ class RDoc::RubyLex
while ch = getc
str << ch
- if @quoted == ch and nest == 0
+ if @quoted == ch and nest <= 0
break
elsif @ltype != "'" && @ltype != "]" && @ltype != ":" and ch == "#"
ch = getc
@@ -1152,17 +1187,21 @@ class RDoc::RubyLex
else
ungetc
end
- elsif ch == '\\' and @ltype == "'" #'
- case ch = getc
- when "\\", "\n", "'"
+ elsif ch == '\\'
+ if %w[' /].include? @ltype then
+ case ch = getc
+ when "\\", "\n", "'"
+ when @ltype
+ str << ch
+ else
+ ungetc
+ end
else
- ungetc
+ str << read_escape
end
- elsif ch == '\\' #'
- str << read_escape
end
- if PERCENT_PAREN.values.include?(@quoted)
+ if close then
if PERCENT_PAREN[ch] == @quoted
nest += 1
elsif ch == @quoted
diff --git a/lib/rdoc/ruby_token.rb b/lib/rdoc/ruby_token.rb
index 93b7a5cbc8..571ea70404 100644
--- a/lib/rdoc/ruby_token.rb
+++ b/lib/rdoc/ruby_token.rb
@@ -60,6 +60,11 @@ module RDoc::RubyToken
self
end
+ def inspect # :nodoc:
+ klass = self.class.name.split('::').last
+ "{%s %d, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @text]
+ end
+
end
class TkNode < Token
@@ -83,6 +88,12 @@ module RDoc::RubyToken
end
alias text node
+
+ def inspect # :nodoc:
+ klass = self.class.name.split('::').last
+ "{%s %d, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @node]
+ end
+
end
class TkId < Token
@@ -105,6 +116,12 @@ module RDoc::RubyToken
end
alias text name
+
+ def inspect # :nodoc:
+ klass = self.class.name.split('::').last
+ "{%s %d, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @name]
+ end
+
end
class TkKW < TkId
@@ -130,6 +147,12 @@ module RDoc::RubyToken
end
alias text value
+
+ def inspect # :nodoc:
+ klass = self.class.name.split('::').last
+ "{%s %s, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @value]
+ end
+
end
class TkOp < Token
@@ -153,6 +176,12 @@ module RDoc::RubyToken
end
alias text name
+
+ def inspect # :nodoc:
+ klass = self.class.name.split('::').last
+ "{%s %d, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @name]
+ end
+
end
class TkOPASGN < TkOp
@@ -175,6 +204,12 @@ module RDoc::RubyToken
def text
@text ||= "#{TkToken2Reading[op]}="
end
+
+ def inspect # :nodoc:
+ klass = self.class.name.split('::').last
+ "{%s %d, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @op]
+ end
+
end
class TkUnknownChar < Token
@@ -197,6 +232,12 @@ module RDoc::RubyToken
end
alias text name
+
+ def inspect # :nodoc:
+ klass = self.class.name.split('::').last
+ "{%s %d, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @name]
+ end
+
end
class TkError < Token
@@ -329,13 +370,13 @@ module RDoc::RubyToken
[:TkfLPAREN, Token, "("], # func( #
[:TkfLBRACK, Token, "["], # func[ #
[:TkfLBRACE, Token, "{"], # func{ #
- [:TkSTAR, Token, "*"], # *arg
- [:TkAMPER, Token, "&"], # &arg #
[:TkSYMBEG, Token, ":"], # :SYMBOL
+ [:TkAMPER, TkOp, "&"],
[:TkGT, TkOp, ">"],
[:TkLT, TkOp, "<"],
[:TkPLUS, TkOp, "+"],
+ [:TkSTAR, TkOp, "*"],
[:TkMINUS, TkOp, "-"],
[:TkMULT, TkOp, "*"],
[:TkDIV, TkOp, "/"],
@@ -360,7 +401,6 @@ module RDoc::RubyToken
[:TkSEMICOLON, Token, ";"],
[:TkCOMMENT, TkVal],
- [:TkRD_COMMENT],
[:TkSPACE, Token, " "],
[:TkNL, Token, "\n"],
[:TkEND_OF_SCRIPT],
@@ -401,7 +441,9 @@ module RDoc::RubyToken
def_token(*defs)
end
- NEWLINE_TOKEN = TkNL.new nil, 0, 0, "\n"
+ def_token :TkRD_COMMENT, TkCOMMENT
+
+ NEWLINE_TOKEN = TkNL.new 0, 0, 0, "\n"
class TkSYMBOL
diff --git a/lib/rdoc/rubygems_hook.rb b/lib/rdoc/rubygems_hook.rb
index 178ca1d2ae..90529848dc 100644
--- a/lib/rdoc/rubygems_hook.rb
+++ b/lib/rdoc/rubygems_hook.rb
@@ -73,7 +73,6 @@ class RDoc::RubygemsHook
def initialize spec, generate_rdoc = true, generate_ri = true
@doc_dir = spec.doc_dir
- @file_info = nil
@force = false
@rdoc = nil
@spec = spec
@@ -120,7 +119,7 @@ class RDoc::RubygemsHook
Dir.chdir options.op_dir do
begin
@rdoc.class.current = @rdoc
- @rdoc.generator.generate @file_info
+ @rdoc.generator.generate
ensure
@rdoc.class.current = nil
end
@@ -140,8 +139,8 @@ class RDoc::RubygemsHook
options = ::RDoc::Options.new
options.default_title = "#{@spec.full_name} Documentation"
options.files = []
- options.files.push(*@spec.require_paths)
- options.files.push(*@spec.extra_rdoc_files)
+ options.files.concat @spec.require_paths
+ options.files.concat @spec.extra_rdoc_files
args = @spec.rdoc_options
@@ -160,7 +159,7 @@ class RDoc::RubygemsHook
@rdoc.options = options
Dir.chdir @spec.full_gem_path do
- @file_info = @rdoc.parse_files options.files
+ @rdoc.parse_files options.files
end
document 'ri', options, @ri_dir if
diff --git a/lib/rdoc/servlet.rb b/lib/rdoc/servlet.rb
new file mode 100644
index 0000000000..a4aafeb252
--- /dev/null
+++ b/lib/rdoc/servlet.rb
@@ -0,0 +1,298 @@
+require 'rdoc'
+require 'time'
+require 'webrick'
+
+class RDoc::Servlet < WEBrick::HTTPServlet::AbstractServlet
+
+ @server_stores = Hash.new { |hash, server| hash[server] = {} }
+ @cache = Hash.new { |hash, store| hash[store] = {} }
+
+ attr_reader :asset_dirs
+
+ attr_reader :options
+
+ def self.get_instance server, *options
+ stores = @server_stores[server]
+
+ new server, stores, @cache, *options
+ end
+
+ def initialize server, stores, cache
+ super server
+
+ @stores = stores
+ @cache = cache
+ @options = RDoc::Options.new
+ @options.op_dir = '.'
+
+ darkfish_dir = nil
+
+ # HACK dup
+ $LOAD_PATH.each do |path|
+ darkfish_dir = File.join path, 'rdoc/generator/template/darkfish/'
+ next unless File.directory? darkfish_dir
+ @options.template_dir = darkfish_dir
+ break
+ end
+
+ @asset_dirs = {
+ :darkfish => darkfish_dir,
+ :json_index =>
+ File.expand_path('../generator/template/json_index/', __FILE__),
+ }
+ end
+
+ def asset generator_name, req, res
+ asset_dir = @asset_dirs[generator_name]
+
+ asset_path = File.join asset_dir, req.path
+
+ if_modified_since req, res, asset_path
+
+ res.body = File.read asset_path
+
+ res.content_type = case req.path
+ when /css$/ then 'text/css'
+ when /js$/ then 'application/javascript'
+ else 'application/octet-stream'
+ end
+ end
+
+ def do_GET req, res
+ case req.path
+ when '/' then
+ root req, res
+ when '/rdoc.css', '/js/darkfish.js', '/js/jquery.js', '/js/search.js',
+ %r%^/images/% then
+ asset :darkfish, req, res
+ when '/js/navigation.js', '/js/searcher.js' then
+ asset :json_index, req, res
+ when '/js/search_index.js' then
+ root_search req, res
+ else
+ show_documentation req, res
+ end
+ rescue WEBrick::HTTPStatus::Status
+ raise
+ rescue => e
+ error e, req, res
+ end
+
+ def documentation_page store, generator, path, req, res
+ name = path.sub(/.html$/, '').gsub '/', '::'
+
+ if klass = store.find_class_or_module(name) then
+ res.body = generator.generate_class klass
+ elsif page = store.find_text_page(name.sub(/_([^_]*)$/, '.\1')) then
+ res.body = generator.generate_page page
+ else
+ not_found generator, req, res
+ end
+ end
+
+ def documentation_search store, generator, req, res
+ json_index = @cache[store].fetch :json_index do
+ @cache[store][:json_index] =
+ JSON.dump generator.json_index.build_index
+ end
+
+ res.content_type = 'application/javascript'
+ res.body = "var search_data = #{json_index}"
+ end
+
+ def documentation_source path
+ _, source_name, path = path.split '/', 3
+
+ store = @stores[source_name]
+ return store, path if store
+
+ store = store_for source_name
+
+ store.load_all
+
+ @stores[source_name] = store
+
+ return store, path
+ end
+
+ def error e, req, res
+ backtrace = e.backtrace.join "\n"
+
+ res.content_type = 'text/html'
+ res.status = 500
+ res.body = <<-BODY
+<!DOCTYPE html>
+<html>
+<head>
+<meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
+
+<title>Error - #{ERB::Util.html_escape e.class}</title>
+
+<link type="text/css" media="screen" href="/rdoc.css" rel="stylesheet">
+</head>
+<body>
+<h1>Error</h1>
+
+<p>While processing <code>#{ERB::Util.html_escape req.request_uri}</code> the
+RDoc server has encountered a <code>#{ERB::Util.html_escape e.class}</code>
+exception:
+
+<pre>#{ERB::Util.html_escape e.message}</pre>
+
+<p>Backtrace:
+
+<pre>#{ERB::Util.html_escape backtrace}</pre>
+
+</body>
+</html>
+ BODY
+ end
+
+ def generator_for store
+ generator = RDoc::Generator::Darkfish.new store, @options
+ generator.file_output = false
+ generator.asset_rel_path = '..'
+
+ rdoc = RDoc::RDoc.new
+ rdoc.store = store
+ rdoc.generator = generator
+ rdoc.options = @options
+
+ @options.main_page = store.main
+ @options.title = store.title
+
+ generator
+ end
+
+ def if_modified_since req, res, path = nil
+ last_modified = File.stat(path).mtime if path
+
+ res['last-modified'] = last_modified.httpdate
+
+ return unless ims = req['if-modified-since']
+
+ ims = Time.parse ims
+
+ unless ims < last_modified then
+ res.body = ''
+ raise WEBrick::HTTPStatus::NotModified
+ end
+ end
+
+ def installed_docs
+ ri_paths.map do |path, type|
+ store = RDoc::Store.new path, type
+ exists = File.exist? store.cache_path
+
+ case type
+ when :gem then
+ gem_path = path[%r%/([^/]*)/ri$%, 1]
+ [gem_path, "#{gem_path}/", exists, type, path]
+ when :system then
+ ['Ruby Documentation', 'ruby/', exists, type, path]
+ when :site then
+ ['Site Documentation', 'site/', exists, type, path]
+ when :home then
+ ['Home Documentation', 'home/', exists, type, path]
+ end
+ end
+ end
+
+ def not_found generator, req, res
+ res.body = generator.generate_servlet_not_found req.path
+ res.status = 404
+ end
+
+ def ri_paths &block
+ RDoc::RI::Paths.each true, true, true, :all, &block
+ end
+
+ def root req, res
+ generator = RDoc::Generator::Darkfish.new nil, @options
+
+ res.body = generator.generate_servlet_root installed_docs
+
+ res.content_type = 'text/html'
+ end
+
+ def root_search req, res
+ search_index = []
+ info = []
+
+ installed_docs.map do |name, href, exists, type, path|
+ next unless exists
+
+ search_index << name
+
+ comment = case type
+ when :gem
+ gemspec = path.gsub(%r%/doc/([^/]*?)/ri$%,
+ '/specifications/\1.gemspec')
+
+ spec = Gem::Specification.load gemspec
+
+ spec.summary
+ when :system then
+ 'Documentation for the Ruby standard library'
+ when :site then
+ 'Documentation for non-gem libraries'
+ when :home then
+ 'Documentation from your home directory'
+ end
+
+ info << [name, '', path, '', comment]
+ end
+
+ index = {
+ :index => {
+ :searchIndex => search_index,
+ :longSearchIndex => search_index,
+ :info => info,
+ }
+ }
+
+ res.body = "var search_data = #{JSON.dump index};"
+ res.content_type = 'application/javascript'
+ end
+
+ def show_documentation req, res
+ store, path = documentation_source req.path
+
+ if_modified_since req, res, store.cache_path
+
+ generator = generator_for store
+
+ case path
+ when nil, '', 'index.html' then
+ res.body = generator.generate_index
+ when 'table_of_contents.html' then
+ res.body = generator.generate_table_of_contents
+ when 'js/search_index.js' then
+ documentation_search store, generator, req, res
+ else
+ documentation_page store, generator, path, req, res
+ end
+ ensure
+ res.content_type ||= 'text/html'
+ end
+
+ def store_for source_name
+ case source_name
+ when 'ruby' then
+ RDoc::Store.new RDoc::RI::Paths.system_dir, :system
+ else
+ ri_dir, type = ri_paths.find do |dir, dir_type|
+ next unless dir_type == :gem
+
+ source_name == dir[%r%/([^/]*)/ri$%, 1]
+ end
+
+ raise "could not find ri documentation for #{source_name}" unless
+ ri_dir
+
+ RDoc::Store.new ri_dir, type
+ end
+ end
+
+end
+
diff --git a/lib/rdoc/single_class.rb b/lib/rdoc/single_class.rb
index e48758d9c8..9e77a65c73 100644
--- a/lib/rdoc/single_class.rb
+++ b/lib/rdoc/single_class.rb
@@ -1,5 +1,3 @@
-require 'rdoc/class_module'
-
##
# A singleton class
diff --git a/lib/rdoc/stats.rb b/lib/rdoc/stats.rb
index e6101bb457..4fa519d243 100644
--- a/lib/rdoc/stats.rb
+++ b/lib/rdoc/stats.rb
@@ -1,5 +1,3 @@
-require 'rdoc'
-
##
# RDoc statistics collector which prints a summary and report of a project's
# documentation totals.
@@ -25,17 +23,18 @@ class RDoc::Stats
# Creates a new Stats that will have +num_files+. +verbosity+ defaults to 1
# which will create an RDoc::Stats::Normal outputter.
- def initialize num_files, verbosity = 1
- @files_so_far = 0
+ def initialize store, num_files, verbosity = 1
@num_files = num_files
+ @store = store
- @coverage_level = 0
- @doc_items = nil
+ @coverage_level = 0
+ @doc_items = nil
+ @files_so_far = 0
@fully_documented = false
- @num_params = 0
- @percent_doc = nil
- @start = Time.now
- @undoc_params = 0
+ @num_params = 0
+ @percent_doc = nil
+ @start = Time.now
+ @undoc_params = 0
@display = case verbosity
when 0 then Quiet.new num_files
@@ -108,7 +107,10 @@ class RDoc::Stats
def calculate
return if @doc_items
- ucm = RDoc::TopLevel.unique_classes_and_modules
+ ucm = @store.unique_classes_and_modules
+
+ classes = @store.unique_classes.reject { |cm| cm.full_name == 'Object' }
+
constants = []
ucm.each { |cm| constants.concat cm.constants }
@@ -119,10 +121,10 @@ class RDoc::Stats
ucm.each { |cm| attributes.concat cm.attributes }
@num_attributes, @undoc_attributes = doc_stats attributes
- @num_classes, @undoc_classes = doc_stats RDoc::TopLevel.unique_classes
+ @num_classes, @undoc_classes = doc_stats classes
@num_constants, @undoc_constants = doc_stats constants
@num_methods, @undoc_methods = doc_stats methods
- @num_modules, @undoc_modules = doc_stats RDoc::TopLevel.unique_modules
+ @num_modules, @undoc_modules = doc_stats @store.unique_modules
@num_items =
@num_attributes +
@@ -160,7 +162,8 @@ class RDoc::Stats
# Returns the length and number of undocumented items in +collection+.
def doc_stats collection
- [collection.length, collection.count { |item| not item.documented? }]
+ visible = collection.select { |item| item.display? }
+ [visible.length, visible.count { |item| not item.documented? }]
end
##
@@ -211,9 +214,6 @@ class RDoc::Stats
def report
if @coverage_level > 0 then
- require 'rdoc/markup/to_tt_only'
- require 'rdoc/generator/markup'
- require 'rdoc/text'
extend RDoc::Text
end
@@ -225,7 +225,7 @@ class RDoc::Stats
return great_job if @num_items == @doc_items
end
- ucm = RDoc::TopLevel.unique_classes_and_modules
+ ucm = @store.unique_classes_and_modules
ucm.sort.each do |cm|
report << report_class_module(cm) {
@@ -259,8 +259,8 @@ class RDoc::Stats
cm.each_attribute do |attr|
next if attr.documented?
- report << " #{attr.definition} :#{attr.name} " \
- "# in file #{attr.file.full_name}"
+ line = attr.line ? ":#{attr.line}" : nil
+ report << " #{attr.definition} :#{attr.name} # in file #{attr.file.full_name}#{line}"
end
report
@@ -271,14 +271,14 @@ class RDoc::Stats
def report_class_module cm
return if cm.fully_documented? and @coverage_level.zero?
+ return unless cm.display?
report = []
if cm.in_files.empty? then
report << "# #{cm.definition} is referenced but empty."
- report << '#'
- report << '# It probably came from another project. ' \
- "I'm sorry I'm holding it against you."
+ report << "#"
+ report << "# It probably came from another project. I'm sorry I'm holding it against you."
report << nil
return report
@@ -321,7 +321,9 @@ class RDoc::Stats
# TODO constant aliases are listed in the summary but not reported
# figure out what to do here
next if constant.documented? || constant.is_alias_for
- report << " # in file #{constant.file.full_name}"
+
+ line = constant.line ? ":#{constant.line}" : line
+ report << " # in file #{constant.file.full_name}#{line}"
report << " #{constant.name} = nil"
end
@@ -353,9 +355,13 @@ class RDoc::Stats
end
next if method.documented? and not param_report
- report << " # in file #{method.file.full_name}"
+
+ line = method.line ? ":#{method.line}" : nil
+ scope = method.singleton ? 'self.' : nil
+
+ report << " # in file #{method.file.full_name}#{line}"
report << param_report if param_report
- report << " def #{method.name}#{method.params}; end"
+ report << " def #{scope}#{method.name}#{method.params}; end"
report << nil
end
diff --git a/lib/rdoc/store.rb b/lib/rdoc/store.rb
new file mode 100644
index 0000000000..ee58a4d873
--- /dev/null
+++ b/lib/rdoc/store.rb
@@ -0,0 +1,881 @@
+require 'fileutils'
+
+##
+# A set of rdoc data for a single project (gem, path, etc.).
+#
+# The store manages reading and writing ri data for a project and maintains a
+# cache of methods, classes and ancestors in the store.
+#
+# The store maintains a #cache of its contents for faster lookup. After
+# adding items to the store it must be flushed using #save_cache. The cache
+# contains the following structures:
+#
+# @cache = {
+# :ancestors => {}, # class name => ancestor names
+# :attributes => {}, # class name => attributes
+# :class_methods => {}, # class name => class methods
+# :instance_methods => {}, # class name => instance methods
+# :modules => [], # classes and modules in this store
+# :pages => [], # page names
+# }
+#--
+# TODO need to prune classes
+
+class RDoc::Store
+
+ ##
+ # Errors raised from loading or saving the store
+
+ class Error < RDoc::Error
+ end
+
+ ##
+ # Raised when a stored file for a class, module, page or method is missing.
+
+ class MissingFileError < Error
+
+ ##
+ # The store the file should exist in
+
+ attr_reader :store
+
+ ##
+ # The file the #name should be saved as
+
+ attr_reader :file
+
+ ##
+ # The name of the object the #file would be loaded from
+
+ attr_reader :name
+
+ ##
+ # Creates a new MissingFileError for the missing +file+ for the given
+ # +name+ that should have been in the +store+.
+
+ def initialize store, file, name
+ @store = store
+ @file = file
+ @name = name
+ end
+
+ def message
+ "store at #{@store.path} missing file #{@file} for #{@name}"
+ end
+
+ end
+
+ ##
+ # Stores the name of the C variable a class belongs to. This helps wire up
+ # classes defined from C across files.
+
+ attr_reader :c_enclosure_classes
+
+ ##
+ # If true this Store will not write any files
+
+ attr_accessor :dry_run
+
+ ##
+ # Path this store reads or writes
+
+ attr_accessor :path
+
+ ##
+ # The RDoc::RDoc driver for this parse tree. This allows classes consulting
+ # the documentation tree to access user-set options, for example.
+
+ attr_accessor :rdoc
+
+ ##
+ # Type of ri datastore this was loaded from. See RDoc::RI::Driver,
+ # RDoc::RI::Paths.
+
+ attr_accessor :type
+
+ ##
+ # The contents of the Store
+
+ attr_reader :cache
+
+ ##
+ # The encoding of the contents in the Store
+
+ attr_accessor :encoding
+
+ ##
+ # Creates a new Store of +type+ that will load or save to +path+
+
+ def initialize path = nil, type = nil
+ @dry_run = false
+ @encoding = nil
+ @path = path
+ @rdoc = nil
+ @type = type
+
+ @cache = {
+ :ancestors => {},
+ :attributes => {},
+ :class_methods => {},
+ :encoding => @encoding,
+ :instance_methods => {},
+ :main => nil,
+ :modules => [],
+ :pages => [],
+ :title => nil,
+ }
+
+ @classes_hash = {}
+ @modules_hash = {}
+ @files_hash = {}
+
+ @c_enclosure_classes = {}
+
+ @unique_classes = nil
+ @unique_modules = nil
+ end
+
+ ##
+ # Adds the file with +name+ as an RDoc::TopLevel to the store. Returns the
+ # created RDoc::TopLevel.
+
+ def add_file name
+ unless top_level = @files_hash[name] then
+ top_level = RDoc::TopLevel.new name
+ top_level.store = self
+ @files_hash[name] = top_level
+ end
+
+ top_level
+ end
+
+ ##
+ # Returns all classes discovered by RDoc
+
+ def all_classes
+ @classes_hash.values
+ end
+
+ ##
+ # Returns all classes and modules discovered by RDoc
+
+ def all_classes_and_modules
+ @classes_hash.values + @modules_hash.values
+ end
+
+ ##
+ # All TopLevels known to RDoc
+
+ def all_files
+ @files_hash.values
+ end
+
+ ##
+ # Returns all modules discovered by RDoc
+
+ def all_modules
+ modules_hash.values
+ end
+
+ ##
+ # Ancestors cache accessor. Maps a klass name to an Array of its ancestors
+ # in this store. If Foo in this store inherits from Object, Kernel won't be
+ # listed (it will be included from ruby's ri store).
+
+ def ancestors
+ @cache[:ancestors]
+ end
+
+ ##
+ # Attributes cache accessor. Maps a class to an Array of its attributes.
+
+ def attributes
+ @cache[:attributes]
+ end
+
+ ##
+ # Path to the cache file
+
+ def cache_path
+ File.join @path, 'cache.ri'
+ end
+
+ ##
+ # Path to the ri data for +klass_name+
+
+ def class_file klass_name
+ name = klass_name.split('::').last
+ File.join class_path(klass_name), "cdesc-#{name}.ri"
+ end
+
+ ##
+ # Class methods cache accessor. Maps a class to an Array of its class
+ # methods (not full name).
+
+ def class_methods
+ @cache[:class_methods]
+ end
+
+ ##
+ # Path where data for +klass_name+ will be stored (methods or class data)
+
+ def class_path klass_name
+ File.join @path, *klass_name.split('::')
+ end
+
+ ##
+ # Hash of all classes known to RDoc
+
+ def classes_hash
+ @classes_hash
+ end
+
+ ##
+ # Removes empty items and ensures item in each collection are unique and
+ # sorted
+
+ def clean_cache_collection collection # :nodoc:
+ collection.each do |name, item|
+ if item.empty? then
+ collection.delete name
+ else
+ # HACK mongrel-1.1.5 documents its files twice
+ item.uniq!
+ item.sort!
+ end
+ end
+ end
+
+ ##
+ # Prepares the RDoc code object tree for use by a generator.
+ #
+ # It finds unique classes/modules defined, and replaces classes/modules that
+ # are aliases for another one by a copy with RDoc::ClassModule#is_alias_for
+ # set.
+ #
+ # It updates the RDoc::ClassModule#constant_aliases attribute of "real"
+ # classes or modules.
+ #
+ # It also completely removes the classes and modules that should be removed
+ # from the documentation and the methods that have a visibility below
+ # +min_visibility+, which is the <tt>--visibility</tt> option.
+ #
+ # See also RDoc::Context#remove_from_documentation?
+
+ def complete min_visibility
+ fix_basic_object_inheritance
+
+ # cache included modules before they are removed from the documentation
+ all_classes_and_modules.each { |cm| cm.ancestors }
+
+ remove_nodoc @classes_hash
+ remove_nodoc @modules_hash
+
+ @unique_classes = find_unique @classes_hash
+ @unique_modules = find_unique @modules_hash
+
+ unique_classes_and_modules.each do |cm|
+ cm.complete min_visibility
+ end
+
+ @files_hash.each_key do |file_name|
+ tl = @files_hash[file_name]
+
+ unless tl.text? then
+ tl.modules_hash.clear
+ tl.classes_hash.clear
+
+ tl.classes_or_modules.each do |cm|
+ name = cm.full_name
+ if cm.type == 'class' then
+ tl.classes_hash[name] = cm if @classes_hash[name]
+ else
+ tl.modules_hash[name] = cm if @modules_hash[name]
+ end
+ end
+ end
+ end
+ end
+
+ ##
+ # Hash of all files known to RDoc
+
+ def files_hash
+ @files_hash
+ end
+
+ ##
+ # Finds the class with +name+ in all discovered classes
+
+ def find_class_named name
+ @classes_hash[name]
+ end
+
+ ##
+ # Finds the class with +name+ starting in namespace +from+
+
+ def find_class_named_from name, from
+ from = find_class_named from unless RDoc::Context === from
+
+ until RDoc::TopLevel === from do
+ return nil unless from
+
+ klass = from.find_class_named name
+ return klass if klass
+
+ from = from.parent
+ end
+
+ find_class_named name
+ end
+
+ ##
+ # Finds the class or module with +name+
+
+ def find_class_or_module name
+ name = $' if name =~ /^::/
+ @classes_hash[name] || @modules_hash[name]
+ end
+
+ ##
+ # Finds the file with +name+ in all discovered files
+
+ def find_file_named name
+ @files_hash[name]
+ end
+
+ ##
+ # Finds the module with +name+ in all discovered modules
+
+ def find_module_named name
+ @modules_hash[name]
+ end
+
+ ##
+ # Returns the RDoc::TopLevel that is a text file and has the given
+ # +file_name+
+
+ def find_text_page file_name
+ @files_hash.each_value.find do |file|
+ file.text? and file.full_name == file_name
+ end
+ end
+
+ ##
+ # Finds unique classes/modules defined in +all_hash+,
+ # and returns them as an array. Performs the alias
+ # updates in +all_hash+: see ::complete.
+ #--
+ # TODO aliases should be registered by Context#add_module_alias
+
+ def find_unique all_hash
+ unique = []
+
+ all_hash.each_pair do |full_name, cm|
+ unique << cm if full_name == cm.full_name
+ end
+
+ unique
+ end
+
+ ##
+ # Fixes the erroneous <tt>BasicObject < Object</tt> in 1.9.
+ #
+ # Because we assumed all classes without a stated superclass
+ # inherit from Object, we have the above wrong inheritance.
+ #
+ # We fix BasicObject right away if we are running in a Ruby
+ # version >= 1.9. If not, we may be documenting 1.9 source
+ # while running under 1.8: we search the files of BasicObject
+ # for "object.c", and fix the inheritance if we find it.
+
+ def fix_basic_object_inheritance
+ basic = classes_hash['BasicObject']
+ return unless basic
+ if RUBY_VERSION >= '1.9'
+ basic.superclass = nil
+ elsif basic.in_files.any? { |f| File.basename(f.full_name) == 'object.c' }
+ basic.superclass = nil
+ end
+ end
+
+ ##
+ # Friendly rendition of #path
+
+ def friendly_path
+ case type
+ when :gem then
+ parent = File.expand_path '..', @path
+ "gem #{File.basename parent}"
+ when :home then '~/.rdoc'
+ when :site then 'ruby site'
+ when :system then 'ruby core'
+ else @path
+ end
+ end
+
+ def inspect # :nodoc:
+ "#<%s:0x%x %s %p>" % [self.class, object_id, @path, module_names.sort]
+ end
+
+ ##
+ # Instance methods cache accessor. Maps a class to an Array of its
+ # instance methods (not full name).
+
+ def instance_methods
+ @cache[:instance_methods]
+ end
+
+ ##
+ # Loads all items from this store into memory. This recreates a
+ # documentation tree for use by a generator
+
+ def load_all
+ load_cache
+
+ module_names.each do |module_name|
+ mod = find_class_or_module(module_name) || load_class(module_name)
+
+ # load method documentation since the loaded class/module does not have
+ # it
+ loaded_methods = mod.method_list.map do |method|
+ load_method module_name, method.full_name
+ end
+
+ mod.method_list.replace loaded_methods
+
+ loaded_attributes = mod.attributes.map do |attribute|
+ load_method module_name, attribute.full_name
+ end
+
+ mod.attributes.replace loaded_attributes
+ end
+
+ all_classes_and_modules.each do |mod|
+ descendent_re = /^#{mod.full_name}::[^:]+$/
+
+ module_names.each do |name|
+ next unless name =~ descendent_re
+
+ descendent = find_class_or_module name
+
+ case descendent
+ when RDoc::NormalClass then
+ mod.classes_hash[name] = descendent
+ when RDoc::NormalModule then
+ mod.modules_hash[name] = descendent
+ end
+ end
+ end
+
+ @cache[:pages].each do |page_name|
+ page = load_page page_name
+ @files_hash[page_name] = page
+ end
+ end
+
+ ##
+ # Loads cache file for this store
+
+ def load_cache
+ #orig_enc = @encoding
+
+ open cache_path, 'rb' do |io|
+ @cache = Marshal.load io.read
+ end
+
+ load_enc = @cache[:encoding]
+
+ # TODO this feature will be time-consuming to add:
+ # a) Encodings may be incompatible but transcodeable
+ # b) Need to warn in the appropriate spots, wherever they may be
+ # c) Need to handle cross-cache differences in encodings
+ # d) Need to warn when generating into a cache with different encodings
+ #
+ #if orig_enc and load_enc != orig_enc then
+ # warn "Cached encoding #{load_enc} is incompatible with #{orig_enc}\n" \
+ # "from #{path}/cache.ri" unless
+ # Encoding.compatible? orig_enc, load_enc
+ #end
+
+ @encoding = load_enc unless @encoding
+
+ @cache[:pages] ||= []
+ @cache[:main] ||= nil
+
+ @cache
+ rescue Errno::ENOENT
+ end
+
+ ##
+ # Loads ri data for +klass_name+
+
+ def load_class klass_name
+ file = class_file klass_name
+
+ obj = open file, 'rb' do |io|
+ Marshal.load io.read
+ end
+
+ obj.store = self
+
+ case obj
+ when RDoc::NormalClass then
+ @classes_hash[klass_name] = obj
+ when RDoc::NormalModule then
+ @modules_hash[klass_name] = obj
+ end
+ rescue Errno::ENOENT => e
+ error = MissingFileError.new(self, file, klass_name)
+ error.set_backtrace e.backtrace
+ raise error
+ end
+
+ ##
+ # Loads ri data for +method_name+ in +klass_name+
+
+ def load_method klass_name, method_name
+ file = method_file klass_name, method_name
+
+ open file, 'rb' do |io|
+ obj = Marshal.load io.read
+ obj.store = self
+ obj.parent =
+ find_class_or_module(klass_name) || load_class(klass_name) unless
+ obj.parent
+ obj
+ end
+ rescue Errno::ENOENT => e
+ error = MissingFileError.new(self, file, klass_name + method_name)
+ error.set_backtrace e.backtrace
+ raise error
+ end
+
+ ##
+ # Loads ri data for +page_name+
+
+ def load_page page_name
+ file = page_file page_name
+
+ open file, 'rb' do |io|
+ obj = Marshal.load io.read
+ obj.store = self
+ obj
+ end
+ rescue Errno::ENOENT => e
+ error = MissingFileError.new(self, file, page_name)
+ error.set_backtrace e.backtrace
+ raise error
+ end
+
+ ##
+ # Gets the main page for this RDoc store. This page is used as the root of
+ # the RDoc server.
+
+ def main
+ @cache[:main]
+ end
+
+ ##
+ # Sets the main page for this RDoc store.
+
+ def main= page
+ @cache[:main] = page
+ end
+
+ ##
+ # Path to the ri data for +method_name+ in +klass_name+
+
+ def method_file klass_name, method_name
+ method_name = method_name.split('::').last
+ method_name =~ /#(.*)/
+ method_type = $1 ? 'i' : 'c'
+ method_name = $1 if $1
+
+ method_name = if ''.respond_to? :ord then
+ method_name.gsub(/\W/) { "%%%02x" % $&[0].ord }
+ else
+ method_name.gsub(/\W/) { "%%%02x" % $&[0] }
+ end
+
+ File.join class_path(klass_name), "#{method_name}-#{method_type}.ri"
+ end
+
+ ##
+ # Modules cache accessor. An Array of all the module (and class) names in
+ # the store.
+
+ def module_names
+ @cache[:modules]
+ end
+
+ ##
+ # Hash of all modules known to RDoc
+
+ def modules_hash
+ @modules_hash
+ end
+
+ ##
+ # Returns the RDoc::TopLevel that is a text file and has the given +name+
+
+ def page name
+ @files_hash.each_value.find do |file|
+ file.text? and file.page_name == name
+ end
+ end
+
+ ##
+ # Path to the ri data for +page_name+
+
+ def page_file page_name
+ file_name = File.basename(page_name).gsub('.', '_')
+
+ File.join @path, File.dirname(page_name), "page-#{file_name}.ri"
+ end
+
+ ##
+ # Removes from +all_hash+ the contexts that are nodoc or have no content.
+ #
+ # See RDoc::Context#remove_from_documentation?
+
+ def remove_nodoc all_hash
+ all_hash.keys.each do |name|
+ context = all_hash[name]
+ all_hash.delete(name) if context.remove_from_documentation?
+ end
+ end
+
+ ##
+ # Saves all entries in the store
+
+ def save
+ load_cache
+
+ all_classes_and_modules.each do |klass|
+ save_class klass
+
+ klass.each_method do |method|
+ save_method klass, method
+ end
+
+ klass.each_attribute do |attribute|
+ save_method klass, attribute
+ end
+ end
+
+ all_files.each do |file|
+ save_page file
+ end
+
+ save_cache
+ end
+
+ ##
+ # Writes the cache file for this store
+
+ def save_cache
+ clean_cache_collection @cache[:ancestors]
+ clean_cache_collection @cache[:attributes]
+ clean_cache_collection @cache[:class_methods]
+ clean_cache_collection @cache[:instance_methods]
+
+ @cache[:modules].uniq!
+ @cache[:modules].sort!
+
+ @cache[:pages].uniq!
+ @cache[:pages].sort!
+
+ @cache[:encoding] = @encoding # this gets set twice due to assert_cache
+
+ return if @dry_run
+
+ marshal = Marshal.dump @cache
+
+ open cache_path, 'wb' do |io|
+ io.write marshal
+ end
+ end
+
+ ##
+ # Writes the ri data for +klass+ (or module)
+
+ def save_class klass
+ full_name = klass.full_name
+
+ FileUtils.mkdir_p class_path(full_name) unless @dry_run
+
+ @cache[:modules] << full_name
+
+ path = class_file full_name
+
+ begin
+ disk_klass = load_class full_name
+
+ klass = disk_klass.merge klass
+ rescue MissingFileError
+ end
+
+ # BasicObject has no ancestors
+ ancestors = klass.direct_ancestors.compact.map do |ancestor|
+ # HACK for classes we don't know about (class X < RuntimeError)
+ String === ancestor ? ancestor : ancestor.full_name
+ end
+
+ @cache[:ancestors][full_name] ||= []
+ @cache[:ancestors][full_name].concat ancestors
+
+ attributes = klass.attributes.map do |attribute|
+ "#{attribute.definition} #{attribute.name}"
+ end
+
+ unless attributes.empty? then
+ @cache[:attributes][full_name] ||= []
+ @cache[:attributes][full_name].concat attributes
+ end
+
+ to_delete = []
+
+ unless klass.method_list.empty? then
+ @cache[:class_methods][full_name] ||= []
+ @cache[:instance_methods][full_name] ||= []
+
+ class_methods, instance_methods =
+ klass.method_list.partition { |meth| meth.singleton }
+
+ class_methods = class_methods. map { |method| method.name }
+ instance_methods = instance_methods.map { |method| method.name }
+
+ old = @cache[:class_methods][full_name] - class_methods
+ to_delete.concat old.map { |method|
+ method_file full_name, "#{full_name}::#{method}"
+ }
+
+ old = @cache[:instance_methods][full_name] - instance_methods
+ to_delete.concat old.map { |method|
+ method_file full_name, "#{full_name}##{method}"
+ }
+
+ @cache[:class_methods][full_name] = class_methods
+ @cache[:instance_methods][full_name] = instance_methods
+ end
+
+ return if @dry_run
+
+ FileUtils.rm_f to_delete
+
+ marshal = Marshal.dump klass
+
+ open path, 'wb' do |io|
+ io.write marshal
+ end
+ end
+
+ ##
+ # Writes the ri data for +method+ on +klass+
+
+ def save_method klass, method
+ full_name = klass.full_name
+
+ FileUtils.mkdir_p class_path(full_name) unless @dry_run
+
+ cache = if method.singleton then
+ @cache[:class_methods]
+ else
+ @cache[:instance_methods]
+ end
+ cache[full_name] ||= []
+ cache[full_name] << method.name
+
+ return if @dry_run
+
+ marshal = Marshal.dump method
+
+ open method_file(full_name, method.full_name), 'wb' do |io|
+ io.write marshal
+ end
+ end
+
+ ##
+ # Writes the ri data for +page+
+
+ def save_page page
+ return unless page.text?
+
+ path = page_file page.full_name
+
+ FileUtils.mkdir_p File.dirname(path) unless @dry_run
+
+ cache[:pages] ||= []
+ cache[:pages] << page.full_name
+
+ return if @dry_run
+
+ marshal = Marshal.dump page
+
+ open path, 'wb' do |io|
+ io.write marshal
+ end
+ end
+
+ ##
+ # Source of the contents of this store.
+ #
+ # For a store from a gem the source is the gem name. For a store from the
+ # home directory the source is "home". For system ri store (the standard
+ # library documentation) the source is"ruby". For a store from the site
+ # ri directory the store is "site". For other stores the source is the
+ # #path.
+
+ def source
+ case type
+ when :gem then File.basename File.expand_path '..', @path
+ when :home then 'home'
+ when :site then 'site'
+ when :system then 'ruby'
+ else @path
+ end
+ end
+
+ ##
+ # Gets the title for this RDoc store. This is used as the title in each
+ # page on the RDoc server
+
+ def title
+ @cache[:title]
+ end
+
+ ##
+ # Sets the title page for this RDoc store.
+
+ def title= title
+ @cache[:title] = title
+ end
+
+ ##
+ # Returns the unique classes discovered by RDoc.
+ #
+ # ::complete must have been called prior to using this method.
+
+ def unique_classes
+ @unique_classes
+ end
+
+ ##
+ # Returns the unique classes and modules discovered by RDoc.
+ # ::complete must have been called prior to using this method.
+
+ def unique_classes_and_modules
+ @unique_classes + @unique_modules
+ end
+
+ ##
+ # Returns the unique modules discovered by RDoc.
+ # ::complete must have been called prior to using this method.
+
+ def unique_modules
+ @unique_modules
+ end
+
+end
+
diff --git a/lib/rdoc/task.rb b/lib/rdoc/task.rb
index b4ff3e99c6..d347e4d6ab 100644
--- a/lib/rdoc/task.rb
+++ b/lib/rdoc/task.rb
@@ -25,12 +25,12 @@ require 'rubygems'
begin
gem 'rdoc'
rescue Gem::LoadError
-end
+end unless defined?(RDoc)
begin
gem 'rake'
rescue Gem::LoadError
-end
+end unless defined?(Rake)
require 'rdoc'
require 'rake'
@@ -52,7 +52,6 @@ require 'rake/tasklib'
#
# Simple Example:
#
-# gem 'rdoc'
# require 'rdoc/task'
#
# RDoc::Task.new do |rdoc|
@@ -69,7 +68,6 @@ require 'rake/tasklib'
# generating two sets of documentation. For instance, if you want to have a
# development set of documentation including private methods:
#
-# gem 'rdoc'
# require 'rdoc/task'
#
# RDoc::Task.new :rdoc_dev do |rdoc|
@@ -87,7 +85,6 @@ require 'rake/tasklib'
#
# For example:
#
-# gem 'rdoc'
# require 'rdoc/task'
#
# RDoc::Task.new(:rdoc => "rdoc", :clobber_rdoc => "rdoc:clean",
@@ -104,6 +101,12 @@ class RDoc::Task < Rake::TaskLib
attr_accessor :name
##
+ # Comment markup format. rdoc, rd and tomdoc are supported. (default is
+ # 'rdoc')
+
+ attr_accessor :markup
+
+ ##
# Name of directory to receive the html output files. (default is "html")
attr_accessor :rdoc_dir
@@ -125,7 +128,8 @@ class RDoc::Task < Rake::TaskLib
attr_accessor :template
##
- # Name of format generator (--fmt) used by rdoc. (defaults to rdoc's default)
+ # Name of format generator (<tt>--format<tt>) used by rdoc. (defaults to
+ # rdoc's default)
attr_accessor :generator
@@ -241,7 +245,6 @@ class RDoc::Task < Rake::TaskLib
args = option_list + @rdoc_files
$stderr.puts "rdoc #{args.join ' '}" if Rake.application.options.trace
- require 'rdoc/rdoc'
RDoc::RDoc.new.document args
end
@@ -253,11 +256,12 @@ class RDoc::Task < Rake::TaskLib
def option_list
result = @options.dup
- result << "-o" << @rdoc_dir
- result << "--main" << main if main
- result << "--title" << title if title
- result << "-T" << template if template
- result << '-f' << generator if generator
+ result << "-o" << @rdoc_dir
+ result << "--main" << main if main
+ result << "--markup" << markup if markup
+ result << "--title" << title if title
+ result << "-T" << template if template
+ result << '-f' << generator if generator
result
end
@@ -316,8 +320,6 @@ end
# :stopdoc:
module Rake
- remove_const(:RDocTask) if defined?(RDocTask) # remove deprecated class
-
##
# For backwards compatibility
diff --git a/lib/rdoc/test_case.rb b/lib/rdoc/test_case.rb
new file mode 100644
index 0000000000..c2eb855d83
--- /dev/null
+++ b/lib/rdoc/test_case.rb
@@ -0,0 +1,162 @@
+require 'rubygems'
+require 'minitest/autorun'
+require 'minitest/benchmark' if ENV['BENCHMARK']
+
+require 'fileutils'
+require 'pp'
+require 'tempfile'
+require 'tmpdir'
+require 'stringio'
+
+require 'rdoc'
+
+##
+# RDoc::TestCase is an abstract TestCase to provide common setup and teardown
+# across all RDoc tests. The test case uses minitest, so all the assertions
+# of minitest may be used.
+#
+# The testcase provides the following:
+#
+# * A reset code-object tree
+# * A reset markup preprocessor (RDoc::Markup::PreProcess)
+# * The <code>@RM</code> alias of RDoc::Markup (for less typing)
+# * <code>@pwd</code> containing the current working directory
+# * FileUtils, pp, Tempfile, Dir.tmpdir and StringIO
+
+class RDoc::TestCase < MiniTest::Unit::TestCase
+
+ ##
+ # Abstract test-case setup
+
+ def setup
+ super
+
+ @top_level = nil
+
+ @RM = RDoc::Markup
+
+ RDoc::Markup::PreProcess.reset
+
+ @pwd = Dir.pwd
+
+ @store = RDoc::Store.new
+
+ @rdoc = RDoc::RDoc.new
+ @rdoc.store = @store
+
+ g = Object.new
+ def g.class_dir() end
+ def g.file_dir() end
+ @rdoc.generator = g
+ end
+
+ ##
+ # Shortcut for RDoc::Markup::BlankLine.new
+
+ def blank_line
+ @RM::BlankLine.new
+ end
+
+ ##
+ # Shortcut for RDoc::Markup::BlockQuote.new with +contents+
+
+ def block *contents
+ @RM::BlockQuote.new(*contents)
+ end
+
+ ##
+ # Creates an RDoc::Comment with +text+ which was defined on +top_level+.
+ # By default the comment has the 'rdoc' format.
+
+ def comment text, top_level = @top_level
+ RDoc::Comment.new text, top_level
+ end
+
+ ##
+ # Shortcut for RDoc::Markup::Document.new with +contents+
+
+ def doc *contents
+ @RM::Document.new(*contents)
+ end
+
+ ##
+ # Shortcut for RDoc::Markup::HardBreak.new
+
+ def hard_break
+ @RM::HardBreak.new
+ end
+
+ ##
+ # Shortcut for RDoc::Markup::Heading.new with +level+ and +text+
+
+ def head level, text
+ @RM::Heading.new level, text
+ end
+
+ ##
+ # Shortcut for RDoc::Markup::ListItem.new with +label+ and +parts+
+
+ def item label = nil, *parts
+ @RM::ListItem.new label, *parts
+ end
+
+ ##
+ # Shortcut for RDoc::Markup::List.new with +type+ and +items+
+
+ def list type = nil, *items
+ @RM::List.new type, *items
+ end
+
+ ##
+ # Shortcut for RDoc::Markup::Paragraph.new with +contents+
+
+ def para *a
+ @RM::Paragraph.new(*a)
+ end
+
+ ##
+ # Shortcut for RDoc::Markup::Rule.new with +weight+
+
+ def rule weight
+ @RM::Rule.new weight
+ end
+
+ ##
+ # Shortcut for RDoc::Markup::Raw.new with +contents+
+
+ def raw *contents
+ @RM::Raw.new(*contents)
+ end
+
+ ##
+ # Creates a temporary directory changes the current directory to it for the
+ # duration of the block.
+ #
+ # Depends upon Dir.mktmpdir
+
+ def temp_dir
+ skip "No Dir::mktmpdir, upgrade your ruby" unless Dir.respond_to? :mktmpdir
+
+ Dir.mktmpdir do |temp_dir|
+ Dir.chdir temp_dir do
+ yield temp_dir
+ end
+ end
+ end
+
+ ##
+ # Shortcut for RDoc::Markup::Verbatim.new with +parts+
+
+ def verb *parts
+ @RM::Verbatim.new(*parts)
+ end
+
+end
+
+# This hack allows autoload to work when Dir.pwd is changed for Ruby 1.8 since
+# -I paths are not expanded.
+$LOAD_PATH.each do |load_path|
+ break if load_path[0] == ?/
+ load_path.replace File.expand_path load_path
+end if RUBY_VERSION < '1.9'
+
diff --git a/lib/rdoc/text.rb b/lib/rdoc/text.rb
index 3ac55ed560..c731dde097 100644
--- a/lib/rdoc/text.rb
+++ b/lib/rdoc/text.rb
@@ -6,11 +6,34 @@
require 'strscan'
##
+# For RDoc::Text#snippet
+
+begin
+ gem 'json'
+rescue Gem::LoadError
+end
+
+require 'json'
+
+##
# Methods for manipulating comment text
module RDoc::Text
##
+ # Maps markup formats to classes that can parse them. If the format is
+ # unknown, "rdoc" format is used.
+
+ MARKUP_FORMAT = {
+ 'markdown' => RDoc::Markdown,
+ 'rdoc' => RDoc::Markup,
+ 'rd' => RDoc::RD,
+ 'tomdoc' => RDoc::TomDoc,
+ }
+
+ MARKUP_FORMAT.default = RDoc::Markup
+
+ ##
# Maps an encoding to a Hash of characters properly transcoded for that
# encoding.
#
@@ -45,7 +68,7 @@ module RDoc::Text
expanded = []
text.each_line do |line|
- line.gsub!(/^(.{8}*?)([^\t\r\n]{0,7})\t/) do
+ line.gsub!(/^((?:.{8})*?)([^\t\r\n]{0,7})\t/) do
r = "#{$1}#{$2}#{' ' * (8 - $2.size)}"
r.force_encoding text.encoding if Object.const_defined? :Encoding
r
@@ -80,9 +103,7 @@ module RDoc::Text
# Requires the including class to implement #formatter
def markup text
- document = parse text
-
- document.accept formatter
+ parse(text).accept formatter
end
##
@@ -91,9 +112,10 @@ module RDoc::Text
def normalize_comment text
return text if text.empty?
- text = strip_hashes text
- text = expand_tabs text
- text = flush_left text
+ text = strip_stars text
+ text = strip_hashes text
+ text = expand_tabs text
+ text = flush_left text
text = strip_newlines text
text
end
@@ -101,35 +123,24 @@ module RDoc::Text
##
# Normalizes +text+ then builds a RDoc::Markup::Document from it
- def parse text
+ def parse text, format = 'rdoc'
return text if RDoc::Markup::Document === text
+ return text.parse if RDoc::Comment === text
- text = normalize_comment text
+ text = normalize_comment text # TODO remove, should not be necessary
return RDoc::Markup::Document.new if text =~ /\A\n*\z/
- RDoc::Markup::Parser.parse text
- rescue RDoc::Markup::Parser::Error => e
- $stderr.puts <<-EOF
-While parsing markup, RDoc encountered a #{e.class}:
-
-#{e}
-\tfrom #{e.backtrace.join "\n\tfrom "}
-
----8<---
-#{text}
----8<---
-
-RDoc #{RDoc::VERSION}
-
-Ruby #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL} #{RUBY_RELEASE_DATE}
+ MARKUP_FORMAT[format].parse text
+ end
-Please file a bug report with the above information at:
+ ##
+ # The first +limit+ characters of +text+ as HTML
-https://github.com/rdoc/rdoc/issues
+ def snippet text, limit = 100
+ document = parse text
- EOF
- raise
+ RDoc::Markup::ToHtmlSnippet.new(limit).convert document
end
##
@@ -155,6 +166,8 @@ https://github.com/rdoc/rdoc/issues
# Strips /* */ style comments
def strip_stars text
+ return text unless text =~ %r%/\*.*\*/%m
+
encoding = text.encoding if Object.const_defined? :Encoding
text = text.gsub %r%Document-method:\s+[\w:.#=!?]+%, ''
@@ -202,10 +215,10 @@ https://github.com/rdoc/rdoc/issues
until s.eos? do
case
- when s.scan(/<tt>.*?<\/tt>/) then # skip contents of tt
+ when s.scan(/<(tt|code)>.*?<\/\1>/) then # skip contents of tt
html << s.matched.gsub('\\\\', '\\')
- when s.scan(/<tt>.*?/) then
- warn 'mismatched <tt> tag' # TODO signal file/line
+ when s.scan(/<(tt|code)>.*?/) then
+ warn "mismatched <#{s[1]}> tag" # TODO signal file/line
html << s.matched
when s.scan(/<[^>]+\/?s*>/) then # skip HTML tags
html << s.matched
diff --git a/lib/rdoc/token_stream.rb b/lib/rdoc/token_stream.rb
index fb887f2fa4..851bc05bf5 100644
--- a/lib/rdoc/token_stream.rb
+++ b/lib/rdoc/token_stream.rb
@@ -8,6 +8,51 @@
module RDoc::TokenStream
##
+ # Converts +token_stream+ to HTML wrapping various tokens with
+ # <tt><span></tt> elements. The following tokens types are wrapped in spans
+ # with the given class names:
+ #
+ # TkCONSTANT :: 'ruby-constant'
+ # TkKW :: 'ruby-keyword'
+ # TkIVAR :: 'ruby-ivar'
+ # TkOp :: 'ruby-operator'
+ # TkId :: 'ruby-identifier'
+ # TkNode :: 'ruby-node'
+ # TkCOMMENT :: 'ruby-comment'
+ # TkREGEXP :: 'ruby-regexp'
+ # TkSTRING :: 'ruby-string'
+ # TkVal :: 'ruby-value'
+ #
+ # Other token types are not wrapped in spans.
+
+ def self.to_html token_stream
+ token_stream.map do |t|
+ next unless t
+
+ style = case t
+ when RDoc::RubyToken::TkCONSTANT then 'ruby-constant'
+ when RDoc::RubyToken::TkKW then 'ruby-keyword'
+ 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'
+ when RDoc::RubyToken::TkREGEXP then 'ruby-regexp'
+ when RDoc::RubyToken::TkSTRING then 'ruby-string'
+ when RDoc::RubyToken::TkVal then 'ruby-value'
+ end
+
+ text = CGI.escapeHTML t.text
+
+ if style then
+ "<span class=\"#{style}\">#{text}</span>"
+ else
+ text
+ end
+ end.join
+ end
+
+ ##
# Adds +tokens+ to the collected tokens
def add_tokens(*tokens)
diff --git a/lib/rdoc/tom_doc.rb b/lib/rdoc/tom_doc.rb
new file mode 100644
index 0000000000..b95ef25d99
--- /dev/null
+++ b/lib/rdoc/tom_doc.rb
@@ -0,0 +1,233 @@
+# :markup: tomdoc
+
+# A parser for TomDoc based on TomDoc 1.0.0-rc1 (02adef9b5a)
+#
+# The TomDoc specification can be found at:
+#
+# http://tomdoc.org
+#
+# The latest version of the TomDoc specification can be found at:
+#
+# https://github.com/mojombo/tomdoc/blob/master/tomdoc.md
+#
+# To choose TomDoc as your only default format see RDoc::Options@Saved+Options
+# for instructions on setting up a <code>.rdoc_options</code> file to store
+# your project default.
+#
+# There are a few differences between this parser and the specification. A
+# best-effort was made to follow the specification as closely as possible but
+# some choices to deviate were made.
+#
+# A future version of RDoc will warn when a MUST or MUST NOT is violated and
+# may warn when a SHOULD or SHOULD NOT is violated. RDoc will always try
+# to emit documentation even if given invalid TomDoc.
+#
+# Here are some implementation choices this parser currently makes:
+#
+# This parser allows rdoc-style inline markup but you should not depended on
+# it.
+#
+# This parser allows a space between the comment and the method body.
+#
+# This parser does not require the default value to be described for an
+# optional argument.
+#
+# This parser does not examine the order of sections. An Examples section may
+# precede the Arguments section.
+#
+# This class is documented in TomDoc format. Since this is a subclass of the
+# RDoc markup parser there isn't much to see here, unfortunately.
+
+class RDoc::TomDoc < RDoc::Markup::Parser
+
+ # Internal: Token accessor
+
+ attr_reader :tokens
+
+ # Internal: Adds a post-processor which sets the RDoc section based on the
+ # comment's status.
+ #
+ # Returns nothing.
+
+ def self.add_post_processor # :nodoc:
+ RDoc::Markup::PreProcess.post_process do |comment, code_object|
+ next unless code_object and
+ RDoc::Comment === comment and comment.format == 'tomdoc'
+
+ comment.text.gsub!(/(\A\s*# )(Public|Internal|Deprecated):\s+/) do
+ section = code_object.add_section $2
+ code_object.temporary_section = section
+
+ $1
+ end
+ end
+ end
+
+ add_post_processor
+
+ # Public: Parses TomDoc from text
+ #
+ # text - A String containing TomDoc-format text.
+ #
+ # Examples
+ #
+ # RDoc::TomDoc.parse <<-TOMDOC
+ # This method does some things
+ #
+ # Returns nothing.
+ # TOMDOC
+ # # => #<RDoc::Markup::Document:0xXXX @parts=[...], @file=nil>
+ #
+ # Returns an RDoc::Markup::Document representing the TomDoc format.
+
+ def self.parse text
+ parser = new
+
+ parser.tokenize text
+ doc = RDoc::Markup::Document.new
+ parser.parse doc
+ doc
+ end
+
+ # Internal: Extracts the Signature section's method signature
+ #
+ # comment - An RDoc::Comment that will be parsed and have the signature
+ # extracted
+ #
+ # Returns a String containing the signature and nil if not
+
+ def self.signature comment
+ return unless comment.tomdoc?
+
+ document = comment.parse
+
+ signature = nil
+ found_heading = false
+ found_signature = false
+
+ document.parts.delete_if do |part|
+ next false if found_signature
+
+ found_heading ||=
+ RDoc::Markup::Heading === part && part.text == 'Signature'
+
+ next false unless found_heading
+
+ next true if RDoc::Markup::BlankLine === part
+
+ if RDoc::Markup::Verbatim === part then
+ signature = part
+ found_signature = true
+ end
+ end
+
+ signature and signature.text
+ end
+
+ # Public: Creates a new TomDoc parser. See also RDoc::Markup::parse
+
+ def initialize
+ super
+
+ @section = nil
+ end
+
+ # Internal: Builds a heading from the token stream
+ #
+ # level - The level of heading to create
+ #
+ # Returns an RDoc::Markup::Heading
+
+ def build_heading level
+ heading = super
+
+ @section = heading.text
+
+ heading
+ end
+
+ # Internal: Builds a verbatim from the token stream. A verbatim in the
+ # Examples section will be marked as in ruby format.
+ #
+ # margin - The indentation from the margin for lines that belong to this
+ # verbatim section.
+ #
+ # Returns an RDoc::Markup::Verbatim
+
+ def build_verbatim margin
+ verbatim = super
+
+ verbatim.format = :ruby if @section == 'Examples'
+
+ verbatim
+ end
+
+ # Internal: Builds a paragraph from the token stream
+ #
+ # margin - Unused
+ #
+ # Returns an RDoc::Markup::Paragraph.
+
+ def build_paragraph margin
+ p :paragraph_start => margin if @debug
+
+ paragraph = RDoc::Markup::Paragraph.new
+
+ until @tokens.empty? do
+ type, data, = get
+
+ if type == :TEXT then
+ paragraph << data
+ skip :NEWLINE
+ else
+ unget
+ break
+ end
+ end
+
+ p :paragraph_end => margin if @debug
+
+ paragraph
+ end
+
+ # Internal: Turns text into an Array of tokens
+ #
+ # text - A String containing TomDoc-format text.
+ #
+ # Returns self.
+
+ def tokenize text
+ text.sub!(/\A(Public|Internal|Deprecated):\s+/, '')
+
+ setup_scanner text
+
+ until @s.eos? do
+ pos = @s.pos
+
+ # leading spaces will be reflected by the column of the next token
+ # the only thing we loose are trailing spaces at the end of the file
+ next if @s.scan(/ +/)
+
+ @tokens << case
+ when @s.scan(/\r?\n/) then
+ token = [:NEWLINE, @s.matched, *token_pos(pos)]
+ @line_pos = char_pos @s.pos
+ @line += 1
+ token
+ when @s.scan(/(Examples|Signature)$/) then
+ @tokens << [:HEADER, 3, *token_pos(pos)]
+
+ [:TEXT, @s[1], *token_pos(pos)]
+ when @s.scan(/([:\w]\w*)[ ]+- /) then
+ [:NOTE, @s[1], *token_pos(pos)]
+ else
+ @s.scan(/.*/)
+ [:TEXT, @s.matched.sub(/\r$/, ''), *token_pos(pos)]
+ end
+ end
+
+ self
+ end
+
+end
+
diff --git a/lib/rdoc/top_level.rb b/lib/rdoc/top_level.rb
index 3825a091fe..9cf38539de 100644
--- a/lib/rdoc/top_level.rb
+++ b/lib/rdoc/top_level.rb
@@ -1,10 +1,10 @@
-require 'rdoc/context'
-
##
# A TopLevel context is a representation of the contents of a single file
class RDoc::TopLevel < RDoc::Context
+ MARSHAL_VERSION = 0 # :nodoc:
+
##
# This TopLevel's File::Stat struct
@@ -35,267 +35,9 @@ class RDoc::TopLevel < RDoc::Context
attr_accessor :parser
##
- # Returns all classes discovered by RDoc
-
- def self.all_classes
- @all_classes_hash.values
- end
-
- ##
- # Returns all classes and modules discovered by RDoc
-
- def self.all_classes_and_modules
- @all_classes_hash.values + @all_modules_hash.values
- end
-
- ##
- # Hash of all classes known to RDoc
-
- def self.all_classes_hash
- @all_classes_hash
- end
-
- ##
- # All TopLevels known to RDoc
-
- def self.all_files
- @all_files_hash.values
- end
-
- ##
- # Hash of all files known to RDoc
-
- def self.all_files_hash
- @all_files_hash
- end
-
- ##
- # Returns all modules discovered by RDoc
-
- def self.all_modules
- all_modules_hash.values
- end
-
- ##
- # Hash of all modules known to RDoc
-
- def self.all_modules_hash
- @all_modules_hash
- end
-
- ##
- # Prepares the RDoc code object tree for use by a generator.
- #
- # It finds unique classes/modules defined, and replaces classes/modules that
- # are aliases for another one by a copy with RDoc::ClassModule#is_alias_for
- # set.
- #
- # It updates the RDoc::ClassModule#constant_aliases attribute of "real"
- # classes or modules.
- #
- # It also completely removes the classes and modules that should be removed
- # from the documentation and the methods that have a visibility below
- # +min_visibility+, which is the <tt>--visibility</tt> option.
- #
- # See also RDoc::Context#remove_from_documentation?
-
- def self.complete min_visibility
- fix_basic_object_inheritance
-
- # cache included modules before they are removed from the documentation
- all_classes_and_modules.each { |cm| cm.ancestors }
-
- remove_nodoc @all_classes_hash
- remove_nodoc @all_modules_hash
-
- @unique_classes = find_unique @all_classes_hash
- @unique_modules = find_unique @all_modules_hash
-
- unique_classes_and_modules.each do |cm|
- cm.complete min_visibility
- end
-
- @all_files_hash.each_key do |file_name|
- tl = @all_files_hash[file_name]
-
- unless RDoc::Parser::Simple === tl.parser then
- tl.modules_hash.clear
- tl.classes_hash.clear
-
- tl.classes_or_modules.each do |cm|
- name = cm.full_name
- if cm.type == 'class' then
- tl.classes_hash[name] = cm if @all_classes_hash[name]
- else
- tl.modules_hash[name] = cm if @all_modules_hash[name]
- end
- end
- end
- end
- end
-
- ##
- # Finds the class with +name+ in all discovered classes
-
- def self.find_class_named(name)
- @all_classes_hash[name]
- end
-
- ##
- # Finds the class with +name+ starting in namespace +from+
-
- def self.find_class_named_from name, from
- from = find_class_named from unless RDoc::Context === from
-
- until RDoc::TopLevel === from do
- return nil unless from
-
- klass = from.find_class_named name
- return klass if klass
-
- from = from.parent
- end
-
- find_class_named name
- end
-
- ##
- # Finds the class or module with +name+
-
- def self.find_class_or_module(name)
- name = $' if name =~ /^::/
- RDoc::TopLevel.classes_hash[name] || RDoc::TopLevel.modules_hash[name]
- end
-
- ##
- # Finds the file with +name+ in all discovered files
-
- def self.find_file_named(name)
- @all_files_hash[name]
- end
-
- ##
- # Finds the module with +name+ in all discovered modules
-
- def self.find_module_named(name)
- modules_hash[name]
- end
-
- ##
- # Finds unique classes/modules defined in +all_hash+,
- # and returns them as an array. Performs the alias
- # updates in +all_hash+: see ::complete.
- #--
- # TODO aliases should be registered by Context#add_module_alias
-
- def self.find_unique(all_hash)
- unique = []
-
- all_hash.each_pair do |full_name, cm|
- unique << cm if full_name == cm.full_name
- end
-
- unique
- end
-
- ##
- # Fixes the erroneous <tt>BasicObject < Object</tt> in 1.9.
- #
- # Because we assumed all classes without a stated superclass
- # inherit from Object, we have the above wrong inheritance.
- #
- # We fix BasicObject right away if we are running in a Ruby
- # version >= 1.9. If not, we may be documenting 1.9 source
- # while running under 1.8: we search the files of BasicObject
- # for "object.c", and fix the inheritance if we find it.
-
- def self.fix_basic_object_inheritance
- basic = all_classes_hash['BasicObject']
- return unless basic
- if RUBY_VERSION >= '1.9'
- basic.superclass = nil
- elsif basic.in_files.any? { |f| File.basename(f.full_name) == 'object.c' }
- basic.superclass = nil
- end
- end
-
- ##
- # Creates a new RDoc::TopLevel with +file_name+ only if one with the same
- # name does not exist in all_files.
-
- def self.new file_name
- if top_level = @all_files_hash[file_name] then
- top_level
- else
- top_level = super
- @all_files_hash[file_name] = top_level
- top_level
- end
- end
-
- ##
- # Removes from +all_hash+ the contexts that are nodoc or have no content.
- #
- # See RDoc::Context#remove_from_documentation?
-
- def self.remove_nodoc(all_hash)
- all_hash.keys.each do |name|
- context = all_hash[name]
- all_hash.delete(name) if context.remove_from_documentation?
- end
- end
-
- ##
- # Empties RDoc of stored class, module and file information
-
- def self.reset
- @all_classes_hash = {}
- @all_modules_hash = {}
- @all_files_hash = {}
- end
-
- ##
- # Returns the unique classes discovered by RDoc.
- #
- # ::complete must have been called prior to using this method.
-
- def self.unique_classes
- @unique_classes
- end
-
- ##
- # Returns the unique classes and modules discovered by RDoc.
- # ::complete must have been called prior to using this method.
-
- def self.unique_classes_and_modules
- @unique_classes + @unique_modules
- end
-
- ##
- # Returns the unique modules discovered by RDoc.
- # ::complete must have been called prior to using this method.
-
- def self.unique_modules
- @unique_modules
- end
-
- class << self
- alias classes all_classes
- alias classes_hash all_classes_hash
-
- alias files all_files
- alias files_hash all_files_hash
-
- alias modules all_modules
- alias modules_hash all_modules_hash
- end
-
- reset
-
- ##
# Creates a new TopLevel for +file_name+
- def initialize(file_name)
+ def initialize file_name
super()
@name = nil
@relative_name = file_name
@@ -305,15 +47,13 @@ class RDoc::TopLevel < RDoc::Context
@parser = nil
@classes_or_modules = []
-
- RDoc::TopLevel.files_hash[file_name] = self
end
##
# An RDoc::TopLevel is equal to another with the same absolute_name
def == other
- other.class === self and @absolute_name == other.absolute_name
+ self.class === other and @absolute_name == other.absolute_name
end
alias eql? ==
@@ -330,7 +70,7 @@ class RDoc::TopLevel < RDoc::Context
##
# Adds +constant+ to +Object+ instead of +self+.
- def add_constant(constant)
+ def add_constant constant
object_class.record_location self
return constant unless @document_self
object_class.add_constant constant
@@ -372,13 +112,21 @@ class RDoc::TopLevel < RDoc::Context
alias name base_name
##
+ # Only a TopLevel that contains text file) will be displayed. See also
+ # RDoc::CodeObject#display?
+
+ def display?
+ text? and super
+ end
+
+ ##
# See RDoc::TopLevel::find_class_or_module
#--
# TODO Why do we search through all classes/modules found, not just the
# ones of this instance?
def find_class_or_module name
- RDoc::TopLevel.find_class_or_module name
+ @store.find_class_or_module name
end
##
@@ -436,23 +184,56 @@ class RDoc::TopLevel < RDoc::Context
end
##
+ # Dumps this TopLevel for use by ri. See also #marshal_load
+ def marshal_dump
+ [
+ MARSHAL_VERSION,
+ @absolute_name,
+ @parser,
+ parse(@comment),
+ ]
+ end
+
+ ##
+ # Loads this TopLevel from +array+.
+
+ def marshal_load array # :nodoc:
+ initialize array[1]
+
+ @parser = array[2]
+ @comment = array[3]
+
+ @file_stat = nil
+ end
+
+ ##
# Returns the NormalClass "Object", creating it if not found.
#
# Records +self+ as a location in "Object".
def object_class
@object_class ||= begin
- oc = self.class.find_class_named('Object') || add_class(RDoc::NormalClass, 'Object')
+ oc = @store.find_class_named('Object') || add_class(RDoc::NormalClass, 'Object')
oc.record_location self
oc
end
end
##
- # Path to this file
+ # Base name of this file without the extension
+
+ def page_name
+ basename = File.basename @absolute_name
+ basename =~ /\.[^.]*$/
+
+ $` || basename
+ end
+
+ ##
+ # Path to this file for use with HTML generator output.
def path
- http_url RDoc::RDoc.current.generator.file_dir
+ http_url @store.rdoc.generator.file_dir
end
def pretty_print q # :nodoc:
@@ -461,11 +242,35 @@ class RDoc::TopLevel < RDoc::Context
q.breakable
items = @modules.map { |n,m| m }
- items.push(*@modules.map { |n,c| c })
+ items.concat @modules.map { |n,c| c }
q.seplist items do |mod| q.pp mod end
end
end
+ ##
+ # Search record used by RDoc::Generator::JsonIndex
+
+ def search_record
+ return unless @parser < RDoc::Parser::Text
+
+ [
+ page_name,
+ '',
+ page_name,
+ '',
+ path,
+ '',
+ snippet(@comment),
+ ]
+ end
+
+ ##
+ # Is this TopLevel from a text file instead of a source code file?
+
+ def text?
+ @parser and @parser.ancestors.include? RDoc::Parser::Text
+ end
+
def to_s # :nodoc:
"file #{full_name}"
end
diff --git a/test/rdoc/MarkdownTest_1.0.3/Amps and angle encoding.text b/test/rdoc/MarkdownTest_1.0.3/Amps and angle encoding.text
new file mode 100644
index 0000000000..0e9527f931
--- /dev/null
+++ b/test/rdoc/MarkdownTest_1.0.3/Amps and angle encoding.text
@@ -0,0 +1,21 @@
+AT&T has an ampersand in their name.
+
+AT&amp;T is another way to write it.
+
+This & that.
+
+4 < 5.
+
+6 > 5.
+
+Here's a [link] [1] with an ampersand in the URL.
+
+Here's a link with an amersand in the link text: [AT&T] [2].
+
+Here's an inline [link](/script?foo=1&bar=2).
+
+Here's an inline [link](</script?foo=1&bar=2>).
+
+
+[1]: http://example.com/?foo=1&bar=2
+[2]: http://att.com/ "AT&T" \ No newline at end of file
diff --git a/test/rdoc/MarkdownTest_1.0.3/Auto links.text b/test/rdoc/MarkdownTest_1.0.3/Auto links.text
new file mode 100644
index 0000000000..abbc48869d
--- /dev/null
+++ b/test/rdoc/MarkdownTest_1.0.3/Auto links.text
@@ -0,0 +1,13 @@
+Link: <http://example.com/>.
+
+With an ampersand: <http://example.com/?foo=1&bar=2>
+
+* In a list?
+* <http://example.com/>
+* It should.
+
+> Blockquoted: <http://example.com/>
+
+Auto-links should not occur here: `<http://example.com/>`
+
+ or here: <http://example.com/> \ No newline at end of file
diff --git a/test/rdoc/MarkdownTest_1.0.3/Backslash escapes.text b/test/rdoc/MarkdownTest_1.0.3/Backslash escapes.text
new file mode 100644
index 0000000000..5b014cb33d
--- /dev/null
+++ b/test/rdoc/MarkdownTest_1.0.3/Backslash escapes.text
@@ -0,0 +1,120 @@
+These should all get escaped:
+
+Backslash: \\
+
+Backtick: \`
+
+Asterisk: \*
+
+Underscore: \_
+
+Left brace: \{
+
+Right brace: \}
+
+Left bracket: \[
+
+Right bracket: \]
+
+Left paren: \(
+
+Right paren: \)
+
+Greater-than: \>
+
+Hash: \#
+
+Period: \.
+
+Bang: \!
+
+Plus: \+
+
+Minus: \-
+
+
+
+These should not, because they occur within a code block:
+
+ Backslash: \\
+
+ Backtick: \`
+
+ Asterisk: \*
+
+ Underscore: \_
+
+ Left brace: \{
+
+ Right brace: \}
+
+ Left bracket: \[
+
+ Right bracket: \]
+
+ Left paren: \(
+
+ Right paren: \)
+
+ Greater-than: \>
+
+ Hash: \#
+
+ Period: \.
+
+ Bang: \!
+
+ Plus: \+
+
+ Minus: \-
+
+
+Nor should these, which occur in code spans:
+
+Backslash: `\\`
+
+Backtick: `` \` ``
+
+Asterisk: `\*`
+
+Underscore: `\_`
+
+Left brace: `\{`
+
+Right brace: `\}`
+
+Left bracket: `\[`
+
+Right bracket: `\]`
+
+Left paren: `\(`
+
+Right paren: `\)`
+
+Greater-than: `\>`
+
+Hash: `\#`
+
+Period: `\.`
+
+Bang: `\!`
+
+Plus: `\+`
+
+Minus: `\-`
+
+
+These should get escaped, even though they're matching pairs for
+other Markdown constructs:
+
+\*asterisks\*
+
+\_underscores\_
+
+\`backticks\`
+
+This is a code span with a literal backslash-backtick sequence: `` \` ``
+
+This is a tag with unescaped backticks <span attr='`ticks`'>bar</span>.
+
+This is a tag with backslashes <span attr='\\backslashes\\'>bar</span>.
diff --git a/test/rdoc/MarkdownTest_1.0.3/Blockquotes with code blocks.text b/test/rdoc/MarkdownTest_1.0.3/Blockquotes with code blocks.text
new file mode 100644
index 0000000000..c31d171049
--- /dev/null
+++ b/test/rdoc/MarkdownTest_1.0.3/Blockquotes with code blocks.text
@@ -0,0 +1,11 @@
+> Example:
+>
+> sub status {
+> print "working";
+> }
+>
+> Or:
+>
+> sub status {
+> return "working";
+> }
diff --git a/test/rdoc/MarkdownTest_1.0.3/Code Blocks.text b/test/rdoc/MarkdownTest_1.0.3/Code Blocks.text
new file mode 100644
index 0000000000..b54b09285a
--- /dev/null
+++ b/test/rdoc/MarkdownTest_1.0.3/Code Blocks.text
@@ -0,0 +1,14 @@
+ code block on the first line
+
+Regular text.
+
+ code block indented by spaces
+
+Regular text.
+
+ the lines in this block
+ all contain trailing spaces
+
+Regular Text.
+
+ code block on the last line \ No newline at end of file
diff --git a/test/rdoc/MarkdownTest_1.0.3/Code Spans.text b/test/rdoc/MarkdownTest_1.0.3/Code Spans.text
new file mode 100644
index 0000000000..750a1973df
--- /dev/null
+++ b/test/rdoc/MarkdownTest_1.0.3/Code Spans.text
@@ -0,0 +1,6 @@
+`<test a="` content of attribute `">`
+
+Fix for backticks within HTML tag: <span attr='`ticks`'>like this</span>
+
+Here's how you put `` `backticks` `` in a code span.
+
diff --git a/test/rdoc/MarkdownTest_1.0.3/Hard-wrapped paragraphs with list-like lines.text b/test/rdoc/MarkdownTest_1.0.3/Hard-wrapped paragraphs with list-like lines.text
new file mode 100644
index 0000000000..f8a5b27bf4
--- /dev/null
+++ b/test/rdoc/MarkdownTest_1.0.3/Hard-wrapped paragraphs with list-like lines.text
@@ -0,0 +1,8 @@
+In Markdown 1.0.0 and earlier. Version
+8. This line turns into a list item.
+Because a hard-wrapped line in the
+middle of a paragraph looked like a
+list item.
+
+Here's one with a bullet.
+* criminey.
diff --git a/test/rdoc/MarkdownTest_1.0.3/Horizontal rules.text b/test/rdoc/MarkdownTest_1.0.3/Horizontal rules.text
new file mode 100644
index 0000000000..1594bda27b
--- /dev/null
+++ b/test/rdoc/MarkdownTest_1.0.3/Horizontal rules.text
@@ -0,0 +1,67 @@
+Dashes:
+
+---
+
+ ---
+
+ ---
+
+ ---
+
+ ---
+
+- - -
+
+ - - -
+
+ - - -
+
+ - - -
+
+ - - -
+
+
+Asterisks:
+
+***
+
+ ***
+
+ ***
+
+ ***
+
+ ***
+
+* * *
+
+ * * *
+
+ * * *
+
+ * * *
+
+ * * *
+
+
+Underscores:
+
+___
+
+ ___
+
+ ___
+
+ ___
+
+ ___
+
+_ _ _
+
+ _ _ _
+
+ _ _ _
+
+ _ _ _
+
+ _ _ _
diff --git a/test/rdoc/MarkdownTest_1.0.3/Inline HTML (Advanced).text b/test/rdoc/MarkdownTest_1.0.3/Inline HTML (Advanced).text
new file mode 100644
index 0000000000..86b7206d2a
--- /dev/null
+++ b/test/rdoc/MarkdownTest_1.0.3/Inline HTML (Advanced).text
@@ -0,0 +1,15 @@
+Simple block on one line:
+
+<div>foo</div>
+
+And nested without indentation:
+
+<div>
+<div>
+<div>
+foo
+</div>
+<div style=">"/>
+</div>
+<div>bar</div>
+</div>
diff --git a/test/rdoc/MarkdownTest_1.0.3/Inline HTML (Simple).text b/test/rdoc/MarkdownTest_1.0.3/Inline HTML (Simple).text
new file mode 100644
index 0000000000..14aa2dc272
--- /dev/null
+++ b/test/rdoc/MarkdownTest_1.0.3/Inline HTML (Simple).text
@@ -0,0 +1,69 @@
+Here's a simple block:
+
+<div>
+ foo
+</div>
+
+This should be a code block, though:
+
+ <div>
+ foo
+ </div>
+
+As should this:
+
+ <div>foo</div>
+
+Now, nested:
+
+<div>
+ <div>
+ <div>
+ foo
+ </div>
+ </div>
+</div>
+
+This should just be an HTML comment:
+
+<!-- Comment -->
+
+Multiline:
+
+<!--
+Blah
+Blah
+-->
+
+Code block:
+
+ <!-- Comment -->
+
+Just plain comment, with trailing spaces on the line:
+
+<!-- foo -->
+
+Code:
+
+ <hr />
+
+Hr's:
+
+<hr>
+
+<hr/>
+
+<hr />
+
+<hr>
+
+<hr/>
+
+<hr />
+
+<hr class="foo" id="bar" />
+
+<hr class="foo" id="bar"/>
+
+<hr class="foo" id="bar" >
+
diff --git a/test/rdoc/MarkdownTest_1.0.3/Inline HTML comments.text b/test/rdoc/MarkdownTest_1.0.3/Inline HTML comments.text
new file mode 100644
index 0000000000..41d830d038
--- /dev/null
+++ b/test/rdoc/MarkdownTest_1.0.3/Inline HTML comments.text
@@ -0,0 +1,13 @@
+Paragraph one.
+
+<!-- This is a simple comment -->
+
+<!--
+ This is another comment.
+-->
+
+Paragraph two.
+
+<!-- one comment block -- -- with two comments -->
+
+The end.
diff --git a/test/rdoc/MarkdownTest_1.0.3/Links, inline style.text b/test/rdoc/MarkdownTest_1.0.3/Links, inline style.text
new file mode 100644
index 0000000000..09017a90c7
--- /dev/null
+++ b/test/rdoc/MarkdownTest_1.0.3/Links, inline style.text
@@ -0,0 +1,12 @@
+Just a [URL](/url/).
+
+[URL and title](/url/ "title").
+
+[URL and title](/url/ "title preceded by two spaces").
+
+[URL and title](/url/ "title preceded by a tab").
+
+[URL and title](/url/ "title has spaces afterward" ).
+
+
+[Empty]().
diff --git a/test/rdoc/MarkdownTest_1.0.3/Links, reference style.text b/test/rdoc/MarkdownTest_1.0.3/Links, reference style.text
new file mode 100644
index 0000000000..341ec88e3d
--- /dev/null
+++ b/test/rdoc/MarkdownTest_1.0.3/Links, reference style.text
@@ -0,0 +1,71 @@
+Foo [bar] [1].
+
+Foo [bar][1].
+
+Foo [bar]
+[1].
+
+[1]: /url/ "Title"
+
+
+With [embedded [brackets]] [b].
+
+
+Indented [once][].
+
+Indented [twice][].
+
+Indented [thrice][].
+
+Indented [four][] times.
+
+ [once]: /url
+
+ [twice]: /url
+
+ [thrice]: /url
+
+ [four]: /url
+
+
+[b]: /url/
+
+* * *
+
+[this] [this] should work
+
+So should [this][this].
+
+And [this] [].
+
+And [this][].
+
+And [this].
+
+But not [that] [].
+
+Nor [that][].
+
+Nor [that].
+
+[Something in brackets like [this][] should work]
+
+[Same with [this].]
+
+In this case, [this](/somethingelse/) points to something else.
+
+Backslashing should suppress \[this] and [this\].
+
+[this]: foo
+
+
+* * *
+
+Here's one where the [link
+breaks] across lines.
+
+Here's another where the [link
+breaks] across lines, but with a line-ending space.
+
+
+[link breaks]: /url/
diff --git a/test/rdoc/MarkdownTest_1.0.3/Links, shortcut references.text b/test/rdoc/MarkdownTest_1.0.3/Links, shortcut references.text
new file mode 100644
index 0000000000..8c44c98fee
--- /dev/null
+++ b/test/rdoc/MarkdownTest_1.0.3/Links, shortcut references.text
@@ -0,0 +1,20 @@
+This is the [simple case].
+
+[simple case]: /simple
+
+
+
+This one has a [line
+break].
+
+This one has a [line
+break] with a line-ending space.
+
+[line break]: /foo
+
+
+[this] [that] and the [other]
+
+[this]: /this
+[that]: /that
+[other]: /other
diff --git a/test/rdoc/MarkdownTest_1.0.3/Literal quotes in titles.text b/test/rdoc/MarkdownTest_1.0.3/Literal quotes in titles.text
new file mode 100644
index 0000000000..29d0e4235b
--- /dev/null
+++ b/test/rdoc/MarkdownTest_1.0.3/Literal quotes in titles.text
@@ -0,0 +1,7 @@
+Foo [bar][].
+
+Foo [bar](/url/ "Title with "quotes" inside").
+
+
+ [bar]: /url/ "Title with "quotes" inside"
+
diff --git a/test/rdoc/MarkdownTest_1.0.3/Markdown Documentation - Basics.text b/test/rdoc/MarkdownTest_1.0.3/Markdown Documentation - Basics.text
new file mode 100644
index 0000000000..486055ca7f
--- /dev/null
+++ b/test/rdoc/MarkdownTest_1.0.3/Markdown Documentation - Basics.text
@@ -0,0 +1,306 @@
+Markdown: Basics
+================
+
+<ul id="ProjectSubmenu">
+ <li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
+ <li><a class="selected" title="Markdown Basics">Basics</a></li>
+ <li><a href="/projects/markdown/syntax" title="Markdown Syntax Documentation">Syntax</a></li>
+ <li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
+ <li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
+</ul>
+
+
+Getting the Gist of Markdown's Formatting Syntax
+------------------------------------------------
+
+This page offers a brief overview of what it's like to use Markdown.
+The [syntax page] [s] provides complete, detailed documentation for
+every feature, but Markdown should be very easy to pick up simply by
+looking at a few examples of it in action. The examples on this page
+are written in a before/after style, showing example syntax and the
+HTML output produced by Markdown.
+
+It's also helpful to simply try Markdown out; the [Dingus] [d] is a
+web application that allows you type your own Markdown-formatted text
+and translate it to XHTML.
+
+**Note:** This document is itself written using Markdown; you
+can [see the source for it by adding '.text' to the URL] [src].
+
+ [s]: /projects/markdown/syntax "Markdown Syntax"
+ [d]: /projects/markdown/dingus "Markdown Dingus"
+ [src]: /projects/markdown/basics.text
+
+
+## Paragraphs, Headers, Blockquotes ##
+
+A paragraph is simply one or more consecutive lines of text, separated
+by one or more blank lines. (A blank line is any line that looks like a
+blank line -- a line containing nothing spaces or tabs is considered
+blank.) Normal paragraphs should not be intended with spaces or tabs.
+
+Markdown offers two styles of headers: *Setext* and *atx*.
+Setext-style headers for `<h1>` and `<h2>` are created by
+"underlining" with equal signs (`=`) and hyphens (`-`), respectively.
+To create an atx-style header, you put 1-6 hash marks (`#`) at the
+beginning of the line -- the number of hashes equals the resulting
+HTML header level.
+
+Blockquotes are indicated using email-style '`>`' angle brackets.
+
+Markdown:
+
+ A First Level Header
+ ====================
+
+ A Second Level Header
+ ---------------------
+
+ Now is the time for all good men to come to
+ the aid of their country. This is just a
+ regular paragraph.
+
+ The quick brown fox jumped over the lazy
+ dog's back.
+
+ ### Header 3
+
+ > This is a blockquote.
+ >
+ > This is the second paragraph in the blockquote.
+ >
+ > ## This is an H2 in a blockquote
+
+
+Output:
+
+ <h1>A First Level Header</h1>
+
+ <h2>A Second Level Header</h2>
+
+ <p>Now is the time for all good men to come to
+ the aid of their country. This is just a
+ regular paragraph.</p>
+
+ <p>The quick brown fox jumped over the lazy
+ dog's back.</p>
+
+ <h3>Header 3</h3>
+
+ <blockquote>
+ <p>This is a blockquote.</p>
+
+ <p>This is the second paragraph in the blockquote.</p>
+
+ <h2>This is an H2 in a blockquote</h2>
+ </blockquote>
+
+
+
+### Phrase Emphasis ###
+
+Markdown uses asterisks and underscores to indicate spans of emphasis.
+
+Markdown:
+
+ Some of these words *are emphasized*.
+ Some of these words _are emphasized also_.
+
+ Use two asterisks for **strong emphasis**.
+ Or, if you prefer, __use two underscores instead__.
+
+Output:
+
+ <p>Some of these words <em>are emphasized</em>.
+ Some of these words <em>are emphasized also</em>.</p>
+
+ <p>Use two asterisks for <strong>strong emphasis</strong>.
+ Or, if you prefer, <strong>use two underscores instead</strong>.</p>
+
+
+
+## Lists ##
+
+Unordered (bulleted) lists use asterisks, pluses, and hyphens (`*`,
+`+`, and `-`) as list markers. These three markers are
+interchangable; this:
+
+ * Candy.
+ * Gum.
+ * Booze.
+
+this:
+
+ + Candy.
+ + Gum.
+ + Booze.
+
+and this:
+
+ - Candy.
+ - Gum.
+ - Booze.
+
+all produce the same output:
+
+ <ul>
+ <li>Candy.</li>
+ <li>Gum.</li>
+ <li>Booze.</li>
+ </ul>
+
+Ordered (numbered) lists use regular numbers, followed by periods, as
+list markers:
+
+ 1. Red
+ 2. Green
+ 3. Blue
+
+Output:
+
+ <ol>
+ <li>Red</li>
+ <li>Green</li>
+ <li>Blue</li>
+ </ol>
+
+If you put blank lines between items, you'll get `<p>` tags for the
+list item text. You can create multi-paragraph list items by indenting
+the paragraphs by 4 spaces or 1 tab:
+
+ * A list item.
+
+ With multiple paragraphs.
+
+ * Another item in the list.
+
+Output:
+
+ <ul>
+ <li><p>A list item.</p>
+ <p>With multiple paragraphs.</p></li>
+ <li><p>Another item in the list.</p></li>
+ </ul>
+
+
+
+### Links ###
+
+Markdown supports two styles for creating links: *inline* and
+*reference*. With both styles, you use square brackets to delimit the
+text you want to turn into a link.
+
+Inline-style links use parentheses immediately after the link text.
+For example:
+
+ This is an [example link](http://example.com/).
+
+Output:
+
+ <p>This is an <a href="http://example.com/">
+ example link</a>.</p>
+
+Optionally, you may include a title attribute in the parentheses:
+
+ This is an [example link](http://example.com/ "With a Title").
+
+Output:
+
+ <p>This is an <a href="http://example.com/" title="With a Title">
+ example link</a>.</p>
+
+Reference-style links allow you to refer to your links by names, which
+you define elsewhere in your document:
+
+ I get 10 times more traffic from [Google][1] than from
+ [Yahoo][2] or [MSN][3].
+
+ [1]: http://google.com/ "Google"
+ [2]: http://search.yahoo.com/ "Yahoo Search"
+ [3]: http://search.msn.com/ "MSN Search"
+
+Output:
+
+ <p>I get 10 times more traffic from <a href="http://google.com/"
+ title="Google">Google</a> than from <a href="http://search.yahoo.com/"
+ title="Yahoo Search">Yahoo</a> or <a href="http://search.msn.com/"
+ title="MSN Search">MSN</a>.</p>
+
+The title attribute is optional. Link names may contain letters,
+numbers and spaces, but are *not* case sensitive:
+
+ I start my morning with a cup of coffee and
+ [The New York Times][NY Times].
+
+ [ny times]: http://www.nytimes.com/
+
+Output:
+
+ <p>I start my morning with a cup of coffee and
+ <a href="http://www.nytimes.com/">The New York Times</a>.</p>
+
+
+### Images ###
+
+Image syntax is very much like link syntax.
+
+Inline (titles are optional):
+
+ ![alt text](/path/to/img.jpg "Title")
+
+Reference-style:
+
+ ![alt text][id]
+
+ [id]: /path/to/img.jpg "Title"
+
+Both of the above examples produce the same output:
+
+ <img src="/path/to/img.jpg" alt="alt text" title="Title" />
+
+
+
+### Code ###
+
+In a regular paragraph, you can create code span by wrapping text in
+backtick quotes. Any ampersands (`&`) and angle brackets (`<` or
+`>`) will automatically be translated into HTML entities. This makes
+it easy to use Markdown to write about HTML example code:
+
+ I strongly recommend against using any `<blink>` tags.
+
+ I wish SmartyPants used named entities like `&mdash;`
+ instead of decimal-encoded entites like `&#8212;`.
+
+Output:
+
+ <p>I strongly recommend against using any
+ <code>&lt;blink&gt;</code> tags.</p>
+
+ <p>I wish SmartyPants used named entities like
+ <code>&amp;mdash;</code> instead of decimal-encoded
+ entites like <code>&amp;#8212;</code>.</p>
+
+
+To specify an entire block of pre-formatted code, indent every line of
+the block by 4 spaces or 1 tab. Just like with code spans, `&`, `<`,
+and `>` characters will be escaped automatically.
+
+Markdown:
+
+ If you want your page to validate under XHTML 1.0 Strict,
+ you've got to put paragraph tags in your blockquotes:
+
+ <blockquote>
+ <p>For example.</p>
+ </blockquote>
+
+Output:
+
+ <p>If you want your page to validate under XHTML 1.0 Strict,
+ you've got to put paragraph tags in your blockquotes:</p>
+
+ <pre><code>&lt;blockquote&gt;
+ &lt;p&gt;For example.&lt;/p&gt;
+ &lt;/blockquote&gt;
+ </code></pre>
diff --git a/test/rdoc/MarkdownTest_1.0.3/Markdown Documentation - Syntax.text b/test/rdoc/MarkdownTest_1.0.3/Markdown Documentation - Syntax.text
new file mode 100644
index 0000000000..57360a16c8
--- /dev/null
+++ b/test/rdoc/MarkdownTest_1.0.3/Markdown Documentation - Syntax.text
@@ -0,0 +1,888 @@
+Markdown: Syntax
+================
+
+<ul id="ProjectSubmenu">
+ <li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
+ <li><a href="/projects/markdown/basics" title="Markdown Basics">Basics</a></li>
+ <li><a class="selected" title="Markdown Syntax Documentation">Syntax</a></li>
+ <li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
+ <li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
+</ul>
+
+
+* [Overview](#overview)
+ * [Philosophy](#philosophy)
+ * [Inline HTML](#html)
+ * [Automatic Escaping for Special Characters](#autoescape)
+* [Block Elements](#block)
+ * [Paragraphs and Line Breaks](#p)
+ * [Headers](#header)
+ * [Blockquotes](#blockquote)
+ * [Lists](#list)
+ * [Code Blocks](#precode)
+ * [Horizontal Rules](#hr)
+* [Span Elements](#span)
+ * [Links](#link)
+ * [Emphasis](#em)
+ * [Code](#code)
+ * [Images](#img)
+* [Miscellaneous](#misc)
+ * [Backslash Escapes](#backslash)
+ * [Automatic Links](#autolink)
+
+
+**Note:** This document is itself written using Markdown; you
+can [see the source for it by adding '.text' to the URL][src].
+
+ [src]: /projects/markdown/syntax.text
+
+* * *
+
+<h2 id="overview">Overview</h2>
+
+<h3 id="philosophy">Philosophy</h3>
+
+Markdown is intended to be as easy-to-read and easy-to-write as is feasible.
+
+Readability, however, is emphasized above all else. A Markdown-formatted
+document should be publishable as-is, as plain text, without looking
+like it's been marked up with tags or formatting instructions. While
+Markdown's syntax has been influenced by several existing text-to-HTML
+filters -- including [Setext] [1], [atx] [2], [Textile] [3], [reStructuredText] [4],
+[Grutatext] [5], and [EtText] [6] -- the single biggest source of
+inspiration for Markdown's syntax is the format of plain text email.
+
+ [1]: http://docutils.sourceforge.net/mirror/setext.html
+ [2]: http://www.aaronsw.com/2002/atx/
+ [3]: http://textism.com/tools/textile/
+ [4]: http://docutils.sourceforge.net/rst.html
+ [5]: http://www.triptico.com/software/grutatxt.html
+ [6]: http://ettext.taint.org/doc/
+
+To this end, Markdown's syntax is comprised entirely of punctuation
+characters, which punctuation characters have been carefully chosen so
+as to look like what they mean. E.g., asterisks around a word actually
+look like \*emphasis\*. Markdown lists look like, well, lists. Even
+blockquotes look like quoted passages of text, assuming you've ever
+used email.
+
+
+
+<h3 id="html">Inline HTML</h3>
+
+Markdown's syntax is intended for one purpose: to be used as a
+format for *writing* for the web.
+
+Markdown is not a replacement for HTML, or even close to it. Its
+syntax is very small, corresponding only to a very small subset of
+HTML tags. The idea is *not* to create a syntax that makes it easier
+to insert HTML tags. In my opinion, HTML tags are already easy to
+insert. The idea for Markdown is to make it easy to read, write, and
+edit prose. HTML is a *publishing* format; Markdown is a *writing*
+format. Thus, Markdown's formatting syntax only addresses issues that
+can be conveyed in plain text.
+
+For any markup that is not covered by Markdown's syntax, you simply
+use HTML itself. There's no need to preface it or delimit it to
+indicate that you're switching from Markdown to HTML; you just use
+the tags.
+
+The only restrictions are that block-level HTML elements -- e.g. `<div>`,
+`<table>`, `<pre>`, `<p>`, etc. -- must be separated from surrounding
+content by blank lines, and the start and end tags of the block should
+not be indented with tabs or spaces. Markdown is smart enough not
+to add extra (unwanted) `<p>` tags around HTML block-level tags.
+
+For example, to add an HTML table to a Markdown article:
+
+ This is a regular paragraph.
+
+ <table>
+ <tr>
+ <td>Foo</td>
+ </tr>
+ </table>
+
+ This is another regular paragraph.
+
+Note that Markdown formatting syntax is not processed within block-level
+HTML tags. E.g., you can't use Markdown-style `*emphasis*` inside an
+HTML block.
+
+Span-level HTML tags -- e.g. `<span>`, `<cite>`, or `<del>` -- can be
+used anywhere in a Markdown paragraph, list item, or header. If you
+want, you can even use HTML tags instead of Markdown formatting; e.g. if
+you'd prefer to use HTML `<a>` or `<img>` tags instead of Markdown's
+link or image syntax, go right ahead.
+
+Unlike block-level HTML tags, Markdown syntax *is* processed within
+span-level tags.
+
+
+<h3 id="autoescape">Automatic Escaping for Special Characters</h3>
+
+In HTML, there are two characters that demand special treatment: `<`
+and `&`. Left angle brackets are used to start tags; ampersands are
+used to denote HTML entities. If you want to use them as literal
+characters, you must escape them as entities, e.g. `&lt;`, and
+`&amp;`.
+
+Ampersands in particular are bedeviling for web writers. If you want to
+write about 'AT&T', you need to write '`AT&amp;T`'. You even need to
+escape ampersands within URLs. Thus, if you want to link to:
+
+ http://images.google.com/images?num=30&q=larry+bird
+
+you need to encode the URL as:
+
+ http://images.google.com/images?num=30&amp;q=larry+bird
+
+in your anchor tag `href` attribute. Needless to say, this is easy to
+forget, and is probably the single most common source of HTML validation
+errors in otherwise well-marked-up web sites.
+
+Markdown allows you to use these characters naturally, taking care of
+all the necessary escaping for you. If you use an ampersand as part of
+an HTML entity, it remains unchanged; otherwise it will be translated
+into `&amp;`.
+
+So, if you want to include a copyright symbol in your article, you can write:
+
+ &copy;
+
+and Markdown will leave it alone. But if you write:
+
+ AT&T
+
+Markdown will translate it to:
+
+ AT&amp;T
+
+Similarly, because Markdown supports [inline HTML](#html), if you use
+angle brackets as delimiters for HTML tags, Markdown will treat them as
+such. But if you write:
+
+ 4 < 5
+
+Markdown will translate it to:
+
+ 4 &lt; 5
+
+However, inside Markdown code spans and blocks, angle brackets and
+ampersands are *always* encoded automatically. This makes it easy to use
+Markdown to write about HTML code. (As opposed to raw HTML, which is a
+terrible format for writing about HTML syntax, because every single `<`
+and `&` in your example code needs to be escaped.)
+
+
+* * *
+
+
+<h2 id="block">Block Elements</h2>
+
+
+<h3 id="p">Paragraphs and Line Breaks</h3>
+
+A paragraph is simply one or more consecutive lines of text, separated
+by one or more blank lines. (A blank line is any line that looks like a
+blank line -- a line containing nothing but spaces or tabs is considered
+blank.) Normal paragraphs should not be intended with spaces or tabs.
+
+The implication of the "one or more consecutive lines of text" rule is
+that Markdown supports "hard-wrapped" text paragraphs. This differs
+significantly from most other text-to-HTML formatters (including Movable
+Type's "Convert Line Breaks" option) which translate every line break
+character in a paragraph into a `<br />` tag.
+
+When you *do* want to insert a `<br />` break tag using Markdown, you
+end a line with two or more spaces, then type return.
+
+Yes, this takes a tad more effort to create a `<br />`, but a simplistic
+"every line break is a `<br />`" rule wouldn't work for Markdown.
+Markdown's email-style [blockquoting][bq] and multi-paragraph [list items][l]
+work best -- and look better -- when you format them with hard breaks.
+
+ [bq]: #blockquote
+ [l]: #list
+
+
+
+<h3 id="header">Headers</h3>
+
+Markdown supports two styles of headers, [Setext] [1] and [atx] [2].
+
+Setext-style headers are "underlined" using equal signs (for first-level
+headers) and dashes (for second-level headers). For example:
+
+ This is an H1
+ =============
+
+ This is an H2
+ -------------
+
+Any number of underlining `=`'s or `-`'s will work.
+
+Atx-style headers use 1-6 hash characters at the start of the line,
+corresponding to header levels 1-6. For example:
+
+ # This is an H1
+
+ ## This is an H2
+
+ ###### This is an H6
+
+Optionally, you may "close" atx-style headers. This is purely
+cosmetic -- you can use this if you think it looks better. The
+closing hashes don't even need to match the number of hashes
+used to open the header. (The number of opening hashes
+determines the header level.) :
+
+ # This is an H1 #
+
+ ## This is an H2 ##
+
+ ### This is an H3 ######
+
+
+<h3 id="blockquote">Blockquotes</h3>
+
+Markdown uses email-style `>` characters for blockquoting. If you're
+familiar with quoting passages of text in an email message, then you
+know how to create a blockquote in Markdown. It looks best if you hard
+wrap the text and put a `>` before every line:
+
+ > This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
+ > consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
+ > Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
+ >
+ > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
+ > id sem consectetuer libero luctus adipiscing.
+
+Markdown allows you to be lazy and only put the `>` before the first
+line of a hard-wrapped paragraph:
+
+ > This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
+ consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
+ Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
+
+ > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
+ id sem consectetuer libero luctus adipiscing.
+
+Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by
+adding additional levels of `>`:
+
+ > This is the first level of quoting.
+ >
+ > > This is nested blockquote.
+ >
+ > Back to the first level.
+
+Blockquotes can contain other Markdown elements, including headers, lists,
+and code blocks:
+
+ > ## This is a header.
+ >
+ > 1. This is the first list item.
+ > 2. This is the second list item.
+ >
+ > Here's some example code:
+ >
+ > return shell_exec("echo $input | $markdown_script");
+
+Any decent text editor should make email-style quoting easy. For
+example, with BBEdit, you can make a selection and choose Increase
+Quote Level from the Text menu.
+
+
+<h3 id="list">Lists</h3>
+
+Markdown supports ordered (numbered) and unordered (bulleted) lists.
+
+Unordered lists use asterisks, pluses, and hyphens -- interchangably
+-- as list markers:
+
+ * Red
+ * Green
+ * Blue
+
+is equivalent to:
+
+ + Red
+ + Green
+ + Blue
+
+and:
+
+ - Red
+ - Green
+ - Blue
+
+Ordered lists use numbers followed by periods:
+
+ 1. Bird
+ 2. McHale
+ 3. Parish
+
+It's important to note that the actual numbers you use to mark the
+list have no effect on the HTML output Markdown produces. The HTML
+Markdown produces from the above list is:
+
+ <ol>
+ <li>Bird</li>
+ <li>McHale</li>
+ <li>Parish</li>
+ </ol>
+
+If you instead wrote the list in Markdown like this:
+
+ 1. Bird
+ 1. McHale
+ 1. Parish
+
+or even:
+
+ 3. Bird
+ 1. McHale
+ 8. Parish
+
+you'd get the exact same HTML output. The point is, if you want to,
+you can use ordinal numbers in your ordered Markdown lists, so that
+the numbers in your source match the numbers in your published HTML.
+But if you want to be lazy, you don't have to.
+
+If you do use lazy list numbering, however, you should still start the
+list with the number 1. At some point in the future, Markdown may support
+starting ordered lists at an arbitrary number.
+
+List markers typically start at the left margin, but may be indented by
+up to three spaces. List markers must be followed by one or more spaces
+or a tab.
+
+To make lists look nice, you can wrap items with hanging indents:
+
+ * Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+ Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
+ viverra nec, fringilla in, laoreet vitae, risus.
+ * Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
+ Suspendisse id sem consectetuer libero luctus adipiscing.
+
+But if you want to be lazy, you don't have to:
+
+ * Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+ Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
+ viverra nec, fringilla in, laoreet vitae, risus.
+ * Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
+ Suspendisse id sem consectetuer libero luctus adipiscing.
+
+If list items are separated by blank lines, Markdown will wrap the
+items in `<p>` tags in the HTML output. For example, this input:
+
+ * Bird
+ * Magic
+
+will turn into:
+
+ <ul>
+ <li>Bird</li>
+ <li>Magic</li>
+ </ul>
+
+But this:
+
+ * Bird
+
+ * Magic
+
+will turn into:
+
+ <ul>
+ <li><p>Bird</p></li>
+ <li><p>Magic</p></li>
+ </ul>
+
+List items may consist of multiple paragraphs. Each subsequent
+paragraph in a list item must be intended by either 4 spaces
+or one tab:
+
+ 1. This is a list item with two paragraphs. Lorem ipsum dolor
+ sit amet, consectetuer adipiscing elit. Aliquam hendrerit
+ mi posuere lectus.
+
+ Vestibulum enim wisi, viverra nec, fringilla in, laoreet
+ vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
+ sit amet velit.
+
+ 2. Suspendisse id sem consectetuer libero luctus adipiscing.
+
+It looks nice if you indent every line of the subsequent
+paragraphs, but here again, Markdown will allow you to be
+lazy:
+
+ * This is a list item with two paragraphs.
+
+ This is the second paragraph in the list item. You're
+ only required to indent the first line. Lorem ipsum dolor
+ sit amet, consectetuer adipiscing elit.
+
+ * Another item in the same list.
+
+To put a blockquote within a list item, the blockquote's `>`
+delimiters need to be indented:
+
+ * A list item with a blockquote:
+
+ > This is a blockquote
+ > inside a list item.
+
+To put a code block within a list item, the code block needs
+to be indented *twice* -- 8 spaces or two tabs:
+
+ * A list item with a code block:
+
+ <code goes here>
+
+
+It's worth noting that it's possible to trigger an ordered list by
+accident, by writing something like this:
+
+ 1986. What a great season.
+
+In other words, a *number-period-space* sequence at the beginning of a
+line. To avoid this, you can backslash-escape the period:
+
+ 1986\. What a great season.
+
+
+
+<h3 id="precode">Code Blocks</h3>
+
+Pre-formatted code blocks are used for writing about programming or
+markup source code. Rather than forming normal paragraphs, the lines
+of a code block are interpreted literally. Markdown wraps a code block
+in both `<pre>` and `<code>` tags.
+
+To produce a code block in Markdown, simply indent every line of the
+block by at least 4 spaces or 1 tab. For example, given this input:
+
+ This is a normal paragraph:
+
+ This is a code block.
+
+Markdown will generate:
+
+ <p>This is a normal paragraph:</p>
+
+ <pre><code>This is a code block.
+ </code></pre>
+
+One level of indentation -- 4 spaces or 1 tab -- is removed from each
+line of the code block. For example, this:
+
+ Here is an example of AppleScript:
+
+ tell application "Foo"
+ beep
+ end tell
+
+will turn into:
+
+ <p>Here is an example of AppleScript:</p>
+
+ <pre><code>tell application "Foo"
+ beep
+ end tell
+ </code></pre>
+
+A code block continues until it reaches a line that is not indented
+(or the end of the article).
+
+Within a code block, ampersands (`&`) and angle brackets (`<` and `>`)
+are automatically converted into HTML entities. This makes it very
+easy to include example HTML source code using Markdown -- just paste
+it and indent it, and Markdown will handle the hassle of encoding the
+ampersands and angle brackets. For example, this:
+
+ <div class="footer">
+ &copy; 2004 Foo Corporation
+ </div>
+
+will turn into:
+
+ <pre><code>&lt;div class="footer"&gt;
+ &amp;copy; 2004 Foo Corporation
+ &lt;/div&gt;
+ </code></pre>
+
+Regular Markdown syntax is not processed within code blocks. E.g.,
+asterisks are just literal asterisks within a code block. This means
+it's also easy to use Markdown to write about Markdown's own syntax.
+
+
+
+<h3 id="hr">Horizontal Rules</h3>
+
+You can produce a horizontal rule tag (`<hr />`) by placing three or
+more hyphens, asterisks, or underscores on a line by themselves. If you
+wish, you may use spaces between the hyphens or asterisks. Each of the
+following lines will produce a horizontal rule:
+
+ * * *
+
+ ***
+
+ *****
+
+ - - -
+
+ ---------------------------------------
+
+ _ _ _
+
+
+* * *
+
+<h2 id="span">Span Elements</h2>
+
+<h3 id="link">Links</h3>
+
+Markdown supports two style of links: *inline* and *reference*.
+
+In both styles, the link text is delimited by [square brackets].
+
+To create an inline link, use a set of regular parentheses immediately
+after the link text's closing square bracket. Inside the parentheses,
+put the URL where you want the link to point, along with an *optional*
+title for the link, surrounded in quotes. For example:
+
+ This is [an example](http://example.com/ "Title") inline link.
+
+ [This link](http://example.net/) has no title attribute.
+
+Will produce:
+
+ <p>This is <a href="http://example.com/" title="Title">
+ an example</a> inline link.</p>
+
+ <p><a href="http://example.net/">This link</a> has no
+ title attribute.</p>
+
+If you're referring to a local resource on the same server, you can
+use relative paths:
+
+ See my [About](/about/) page for details.
+
+Reference-style links use a second set of square brackets, inside
+which you place a label of your choosing to identify the link:
+
+ This is [an example][id] reference-style link.
+
+You can optionally use a space to separate the sets of brackets:
+
+ This is [an example] [id] reference-style link.
+
+Then, anywhere in the document, you define your link label like this,
+on a line by itself:
+
+ [id]: http://example.com/ "Optional Title Here"
+
+That is:
+
+* Square brackets containing the link identifier (optionally
+ indented from the left margin using up to three spaces);
+* followed by a colon;
+* followed by one or more spaces (or tabs);
+* followed by the URL for the link;
+* optionally followed by a title attribute for the link, enclosed
+ in double or single quotes.
+
+The link URL may, optionally, be surrounded by angle brackets:
+
+ [id]: <http://example.com/> "Optional Title Here"
+
+You can put the title attribute on the next line and use extra spaces
+or tabs for padding, which tends to look better with longer URLs:
+
+ [id]: http://example.com/longish/path/to/resource/here
+ "Optional Title Here"
+
+Link definitions are only used for creating links during Markdown
+processing, and are stripped from your document in the HTML output.
+
+Link definition names may constist of letters, numbers, spaces, and punctuation -- but they are *not* case sensitive. E.g. these two links:
+
+ [link text][a]
+ [link text][A]
+
+are equivalent.
+
+The *implicit link name* shortcut allows you to omit the name of the
+link, in which case the link text itself is used as the name.
+Just use an empty set of square brackets -- e.g., to link the word
+"Google" to the google.com web site, you could simply write:
+
+ [Google][]
+
+And then define the link:
+
+ [Google]: http://google.com/
+
+Because link names may contain spaces, this shortcut even works for
+multiple words in the link text:
+
+ Visit [Daring Fireball][] for more information.
+
+And then define the link:
+
+ [Daring Fireball]: http://daringfireball.net/
+
+Link definitions can be placed anywhere in your Markdown document. I
+tend to put them immediately after each paragraph in which they're
+used, but if you want, you can put them all at the end of your
+document, sort of like footnotes.
+
+Here's an example of reference links in action:
+
+ I get 10 times more traffic from [Google] [1] than from
+ [Yahoo] [2] or [MSN] [3].
+
+ [1]: http://google.com/ "Google"
+ [2]: http://search.yahoo.com/ "Yahoo Search"
+ [3]: http://search.msn.com/ "MSN Search"
+
+Using the implicit link name shortcut, you could instead write:
+
+ I get 10 times more traffic from [Google][] than from
+ [Yahoo][] or [MSN][].
+
+ [google]: http://google.com/ "Google"
+ [yahoo]: http://search.yahoo.com/ "Yahoo Search"
+ [msn]: http://search.msn.com/ "MSN Search"
+
+Both of the above examples will produce the following HTML output:
+
+ <p>I get 10 times more traffic from <a href="http://google.com/"
+ title="Google">Google</a> than from
+ <a href="http://search.yahoo.com/" title="Yahoo Search">Yahoo</a>
+ or <a href="http://search.msn.com/" title="MSN Search">MSN</a>.</p>
+
+For comparison, here is the same paragraph written using
+Markdown's inline link style:
+
+ I get 10 times more traffic from [Google](http://google.com/ "Google")
+ than from [Yahoo](http://search.yahoo.com/ "Yahoo Search") or
+ [MSN](http://search.msn.com/ "MSN Search").
+
+The point of reference-style links is not that they're easier to
+write. The point is that with reference-style links, your document
+source is vastly more readable. Compare the above examples: using
+reference-style links, the paragraph itself is only 81 characters
+long; with inline-style links, it's 176 characters; and as raw HTML,
+it's 234 characters. In the raw HTML, there's more markup than there
+is text.
+
+With Markdown's reference-style links, a source document much more
+closely resembles the final output, as rendered in a browser. By
+allowing you to move the markup-related metadata out of the paragraph,
+you can add links without interrupting the narrative flow of your
+prose.
+
+
+<h3 id="em">Emphasis</h3>
+
+Markdown treats asterisks (`*`) and underscores (`_`) as indicators of
+emphasis. Text wrapped with one `*` or `_` will be wrapped with an
+HTML `<em>` tag; double `*`'s or `_`'s will be wrapped with an HTML
+`<strong>` tag. E.g., this input:
+
+ *single asterisks*
+
+ _single underscores_
+
+ **double asterisks**
+
+ __double underscores__
+
+will produce:
+
+ <em>single asterisks</em>
+
+ <em>single underscores</em>
+
+ <strong>double asterisks</strong>
+
+ <strong>double underscores</strong>
+
+You can use whichever style you prefer; the lone restriction is that
+the same character must be used to open and close an emphasis span.
+
+Emphasis can be used in the middle of a word:
+
+ un*fucking*believable
+
+But if you surround an `*` or `_` with spaces, it'll be treated as a
+literal asterisk or underscore.
+
+To produce a literal asterisk or underscore at a position where it
+would otherwise be used as an emphasis delimiter, you can backslash
+escape it:
+
+ \*this text is surrounded by literal asterisks\*
+
+
+
+<h3 id="code">Code</h3>
+
+To indicate a span of code, wrap it with backtick quotes (`` ` ``).
+Unlike a pre-formatted code block, a code span indicates code within a
+normal paragraph. For example:
+
+ Use the `printf()` function.
+
+will produce:
+
+ <p>Use the <code>printf()</code> function.</p>
+
+To include a literal backtick character within a code span, you can use
+multiple backticks as the opening and closing delimiters:
+
+ ``There is a literal backtick (`) here.``
+
+which will produce this:
+
+ <p><code>There is a literal backtick (`) here.</code></p>
+
+The backtick delimiters surrounding a code span may include spaces --
+one after the opening, one before the closing. This allows you to place
+literal backtick characters at the beginning or end of a code span:
+
+ A single backtick in a code span: `` ` ``
+
+ A backtick-delimited string in a code span: `` `foo` ``
+
+will produce:
+
+ <p>A single backtick in a code span: <code>`</code></p>
+
+ <p>A backtick-delimited string in a code span: <code>`foo`</code></p>
+
+With a code span, ampersands and angle brackets are encoded as HTML
+entities automatically, which makes it easy to include example HTML
+tags. Markdown will turn this:
+
+ Please don't use any `<blink>` tags.
+
+into:
+
+ <p>Please don't use any <code>&lt;blink&gt;</code> tags.</p>
+
+You can write this:
+
+ `&#8212;` is the decimal-encoded equivalent of `&mdash;`.
+
+to produce:
+
+ <p><code>&amp;#8212;</code> is the decimal-encoded
+ equivalent of <code>&amp;mdash;</code>.</p>
+
+
+
+<h3 id="img">Images</h3>
+
+Admittedly, it's fairly difficult to devise a "natural" syntax for
+placing images into a plain text document format.
+
+Markdown uses an image syntax that is intended to resemble the syntax
+for links, allowing for two styles: *inline* and *reference*.
+
+Inline image syntax looks like this:
+
+ ![Alt text](/path/to/img.jpg)
+
+ ![Alt text](/path/to/img.jpg "Optional title")
+
+That is:
+
+* An exclamation mark: `!`;
+* followed by a set of square brackets, containing the `alt`
+ attribute text for the image;
+* followed by a set of parentheses, containing the URL or path to
+ the image, and an optional `title` attribute enclosed in double
+ or single quotes.
+
+Reference-style image syntax looks like this:
+
+ ![Alt text][id]
+
+Where "id" is the name of a defined image reference. Image references
+are defined using syntax identical to link references:
+
+ [id]: url/to/image "Optional title attribute"
+
+As of this writing, Markdown has no syntax for specifying the
+dimensions of an image; if this is important to you, you can simply
+use regular HTML `<img>` tags.
+
+
+* * *
+
+
+<h2 id="misc">Miscellaneous</h2>
+
+<h3 id="autolink">Automatic Links</h3>
+
+Markdown supports a shortcut style for creating "automatic" links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this:
+
+ <http://example.com/>
+
+Markdown will turn this into:
+
+ <a href="http://example.com/">http://example.com/</a>
+
+Automatic links for email addresses work similarly, except that
+Markdown will also perform a bit of randomized decimal and hex
+entity-encoding to help obscure your address from address-harvesting
+spambots. For example, Markdown will turn this:
+
+ <address@example.com>
+
+into something like this:
+
+ <a href="&#x6D;&#x61;i&#x6C;&#x74;&#x6F;:&#x61;&#x64;&#x64;&#x72;&#x65;
+ &#115;&#115;&#64;&#101;&#120;&#x61;&#109;&#x70;&#x6C;e&#x2E;&#99;&#111;
+ &#109;">&#x61;&#x64;&#x64;&#x72;&#x65;&#115;&#115;&#64;&#101;&#120;&#x61;
+ &#109;&#x70;&#x6C;e&#x2E;&#99;&#111;&#109;</a>
+
+which will render in a browser as a clickable link to "address@example.com".
+
+(This sort of entity-encoding trick will indeed fool many, if not
+most, address-harvesting bots, but it definitely won't fool all of
+them. It's better than nothing, but an address published in this way
+will probably eventually start receiving spam.)
+
+
+
+<h3 id="backslash">Backslash Escapes</h3>
+
+Markdown allows you to use backslash escapes to generate literal
+characters which would otherwise have special meaning in Markdown's
+formatting syntax. For example, if you wanted to surround a word with
+literal asterisks (instead of an HTML `<em>` tag), you can backslashes
+before the asterisks, like this:
+
+ \*literal asterisks\*
+
+Markdown provides backslash escapes for the following characters:
+
+ \ backslash
+ ` backtick
+ * asterisk
+ _ underscore
+ {} curly braces
+ [] square brackets
+ () parentheses
+ # hash mark
+ + plus sign
+ - minus sign (hyphen)
+ . dot
+ ! exclamation mark
+
diff --git a/test/rdoc/MarkdownTest_1.0.3/Nested blockquotes.text b/test/rdoc/MarkdownTest_1.0.3/Nested blockquotes.text
new file mode 100644
index 0000000000..ed3c624ffb
--- /dev/null
+++ b/test/rdoc/MarkdownTest_1.0.3/Nested blockquotes.text
@@ -0,0 +1,5 @@
+> foo
+>
+> > bar
+>
+> foo
diff --git a/test/rdoc/MarkdownTest_1.0.3/Ordered and unordered lists.text b/test/rdoc/MarkdownTest_1.0.3/Ordered and unordered lists.text
new file mode 100644
index 0000000000..7f3b49777f
--- /dev/null
+++ b/test/rdoc/MarkdownTest_1.0.3/Ordered and unordered lists.text
@@ -0,0 +1,131 @@
+## Unordered
+
+Asterisks tight:
+
+* asterisk 1
+* asterisk 2
+* asterisk 3
+
+
+Asterisks loose:
+
+* asterisk 1
+
+* asterisk 2
+
+* asterisk 3
+
+* * *
+
+Pluses tight:
+
++ Plus 1
++ Plus 2
++ Plus 3
+
+
+Pluses loose:
+
++ Plus 1
+
++ Plus 2
+
++ Plus 3
+
+* * *
+
+
+Minuses tight:
+
+- Minus 1
+- Minus 2
+- Minus 3
+
+
+Minuses loose:
+
+- Minus 1
+
+- Minus 2
+
+- Minus 3
+
+
+## Ordered
+
+Tight:
+
+1. First
+2. Second
+3. Third
+
+and:
+
+1. One
+2. Two
+3. Three
+
+
+Loose using tabs:
+
+1. First
+
+2. Second
+
+3. Third
+
+and using spaces:
+
+1. One
+
+2. Two
+
+3. Three
+
+Multiple paragraphs:
+
+1. Item 1, graf one.
+
+ Item 2. graf two. The quick brown fox jumped over the lazy dog's
+ back.
+
+2. Item 2.
+
+3. Item 3.
+
+
+
+## Nested
+
+* Tab
+ * Tab
+ * Tab
+
+Here's another:
+
+1. First
+2. Second:
+ * Fee
+ * Fie
+ * Foe
+3. Third
+
+Same thing but with paragraphs:
+
+1. First
+
+2. Second:
+ * Fee
+ * Fie
+ * Foe
+
+3. Third
+
+
+This was an error in Markdown 1.0.1:
+
+* this
+
+ * sub
+
+ that
diff --git a/test/rdoc/MarkdownTest_1.0.3/Strong and em together.text b/test/rdoc/MarkdownTest_1.0.3/Strong and em together.text
new file mode 100644
index 0000000000..95ee690dbe
--- /dev/null
+++ b/test/rdoc/MarkdownTest_1.0.3/Strong and em together.text
@@ -0,0 +1,7 @@
+***This is strong and em.***
+
+So is ***this*** word.
+
+___This is strong and em.___
+
+So is ___this___ word.
diff --git a/test/rdoc/MarkdownTest_1.0.3/Tabs.text b/test/rdoc/MarkdownTest_1.0.3/Tabs.text
new file mode 100644
index 0000000000..589d1136e1
--- /dev/null
+++ b/test/rdoc/MarkdownTest_1.0.3/Tabs.text
@@ -0,0 +1,21 @@
++ this is a list item
+ indented with tabs
+
++ this is a list item
+ indented with spaces
+
+Code:
+
+ this code block is indented by one tab
+
+And:
+
+ this code block is indented by two tabs
+
+And:
+
+ + this is an example list item
+ indented with tabs
+
+ + this is an example list item
+ indented with spaces
diff --git a/test/rdoc/MarkdownTest_1.0.3/Tidyness.text b/test/rdoc/MarkdownTest_1.0.3/Tidyness.text
new file mode 100644
index 0000000000..5f18b8da21
--- /dev/null
+++ b/test/rdoc/MarkdownTest_1.0.3/Tidyness.text
@@ -0,0 +1,5 @@
+> A list within a blockquote:
+>
+> * asterisk 1
+> * asterisk 2
+> * asterisk 3
diff --git a/test/rdoc/test.ja.largedoc b/test/rdoc/test.ja.large.rdoc
index a9c6c4691c..a9c6c4691c 100644
--- a/test/rdoc/test.ja.largedoc
+++ b/test/rdoc/test.ja.large.rdoc
diff --git a/test/rdoc/test_attribute_manager.rb b/test/rdoc/test_attribute_manager.rb
index 25e8ca5e04..8832a5d515 100644
--- a/test/rdoc/test_attribute_manager.rb
+++ b/test/rdoc/test_attribute_manager.rb
@@ -1,27 +1,26 @@
-require 'rubygems'
-require 'minitest/autorun'
-require 'rdoc'
-require 'rdoc/markup'
-require 'rdoc/markup/formatter'
-require 'rdoc/markup/attribute_manager'
+require 'rdoc/test_case'
-class TestAttributeManager < MiniTest::Unit::TestCase # HACK fix test name
+class TestAttributeManager < RDoc::TestCase # HACK fix test name
def setup
+ super
+
+ @options = RDoc::Options.new
+
@am = RDoc::Markup::AttributeManager.new
@klass = RDoc::Markup::AttributeManager
- @formatter = RDoc::Markup::Formatter.new
+ @formatter = RDoc::Markup::Formatter.new @options
@formatter.add_tag :BOLD, '<B>', '</B>'
@formatter.add_tag :EM, '<EM>', '</EM>'
- @formatter.add_tag :TT, '<TT>', '</TT>'
+ @formatter.add_tag :TT, '<CODE>', '</CODE>'
end
def test_convert_attrs_ignores_code
- assert_equal 'foo <TT>__send__</TT> bar', output('foo <code>__send__</code> bar')
+ assert_equal 'foo <CODE>__send__</CODE> bar', output('foo <code>__send__</code> bar')
end
def test_convert_attrs_ignores_tt
- assert_equal 'foo <TT>__send__</TT> bar', output('foo <tt>__send__</tt> bar')
+ assert_equal 'foo <CODE>__send__</CODE> bar', output('foo <tt>__send__</tt> bar')
end
def test_convert_attrs_preserves_double
@@ -30,7 +29,7 @@ class TestAttributeManager < MiniTest::Unit::TestCase # HACK fix test name
end
def test_convert_attrs_does_not_ignore_after_tt
- assert_equal 'the <TT>IF:</TT><EM>key</EM> directive', output('the <tt>IF:</tt>_key_ directive')
+ assert_equal 'the <CODE>IF:</CODE><EM>key</EM> directive', output('the <tt>IF:</tt>_key_ directive')
end
def test_initial_word_pairs
@@ -73,38 +72,39 @@ class TestAttributeManager < MiniTest::Unit::TestCase # HACK fix test name
end
def test_add_special
- @am.add_special("WikiWord", :WIKIWORD)
+ @am.add_special "WikiWord", :WIKIWORD
specials = @am.special
- assert_equal(1,specials.size)
- assert(specials.has_key?("WikiWord"))
+
+ assert_equal 1, specials.size
+ assert specials.assoc "WikiWord"
end
def test_escapes
- assert_equal '<TT>text</TT>', output('<tt>text</tt>')
- assert_equal '<tt>text</tt>', output('\\<tt>text</tt>')
- assert_equal '<tt>', output('\\<tt>')
- assert_equal '<TT><tt></TT>', output('<tt>\\<tt></tt>')
- assert_equal '<TT>\\<tt></TT>', output('<tt>\\\\<tt></tt>')
- assert_equal '<B>text</B>', output('*text*')
- assert_equal '*text*', output('\\*text*')
- assert_equal '\\', output('\\')
- assert_equal '\\text', output('\\text')
- assert_equal '\\\\text', output('\\\\text')
- assert_equal 'text \\ text', output('text \\ text')
-
- assert_equal 'and <TT>\\s</TT> matches space',
+ assert_equal '<CODE>text</CODE>', output('<tt>text</tt>')
+ assert_equal '<tt>text</tt>', output('\\<tt>text</tt>')
+ assert_equal '<tt>', output('\\<tt>')
+ assert_equal '<CODE><tt></CODE>', output('<tt>\\<tt></tt>')
+ assert_equal '<CODE>\\<tt></CODE>', output('<tt>\\\\<tt></tt>')
+ assert_equal '<B>text</B>', output('*text*')
+ assert_equal '*text*', output('\\*text*')
+ assert_equal '\\', output('\\')
+ assert_equal '\\text', output('\\text')
+ assert_equal '\\\\text', output('\\\\text')
+ assert_equal 'text \\ text', output('text \\ text')
+
+ assert_equal 'and <CODE>\\s</CODE> matches space',
output('and <tt>\\s</tt> matches space')
- assert_equal 'use <TT><tt>text</TT></tt> for code',
+ assert_equal 'use <CODE><tt>text</CODE></tt> for code',
output('use <tt>\\<tt>text</tt></tt> for code')
- assert_equal 'use <TT><tt>text</tt></TT> for code',
+ assert_equal 'use <CODE><tt>text</tt></CODE> for code',
output('use <tt>\\<tt>text\\</tt></tt> for code')
assert_equal 'use <tt><tt>text</tt></tt> for code',
output('use \\<tt>\\<tt>text</tt></tt> for code')
- assert_equal 'use <tt><TT>text</TT></tt> for code',
+ assert_equal 'use <tt><CODE>text</CODE></tt> for code',
output('use \\<tt><tt>text</tt></tt> for code')
- assert_equal 'use <TT>+text+</TT> for code',
+ assert_equal 'use <CODE>+text+</CODE> for code',
output('use <tt>\\+text+</tt> for code')
- assert_equal 'use <tt><TT>text</TT></tt> for code',
+ assert_equal 'use <tt><CODE>text</CODE></tt> for code',
output('use \\<tt>+text+</tt> for code')
assert_equal 'illegal <tag>not</tag> changed',
output('illegal <tag>not</tag> changed')
diff --git a/test/rdoc/test_rdoc_any_method.rb b/test/rdoc/test_rdoc_any_method.rb
index c0feccef95..abf749c4c9 100644
--- a/test/rdoc/test_rdoc_any_method.rb
+++ b/test/rdoc/test_rdoc_any_method.rb
@@ -1,8 +1,6 @@
require File.expand_path '../xref_test_case', __FILE__
-require 'rdoc/code_objects'
-require 'rdoc/generator/markup'
-class RDocAnyMethodTest < XrefTestCase
+class TestRDocAnyMethod < XrefTestCase
def test_aref
m = RDoc::AnyMethod.new nil, 'method?'
@@ -47,34 +45,12 @@ method(a, b) { |c, d| ... }
def test_markup_code
tokens = [
RDoc::RubyToken::TkCONSTANT. new(0, 0, 0, 'CONSTANT'),
- RDoc::RubyToken::TkDEF. new(0, 0, 0, 'KW'),
- RDoc::RubyToken::TkIVAR. new(0, 0, 0, 'IVAR'),
- RDoc::RubyToken::TkOp. new(0, 0, 0, 'Op'),
- RDoc::RubyToken::TkId. new(0, 0, 0, 'Id'),
- RDoc::RubyToken::TkNode. new(0, 0, 0, 'Node'),
- RDoc::RubyToken::TkCOMMENT. new(0, 0, 0, 'COMMENT'),
- RDoc::RubyToken::TkREGEXP. new(0, 0, 0, 'REGEXP'),
- RDoc::RubyToken::TkSTRING. new(0, 0, 0, 'STRING'),
- RDoc::RubyToken::TkVal. new(0, 0, 0, 'Val'),
- RDoc::RubyToken::TkBACKSLASH.new(0, 0, 0, '\\'),
]
@c2_a.collect_tokens
@c2_a.add_tokens(*tokens)
- expected = [
- '<span class="ruby-constant">CONSTANT</span>',
- '<span class="ruby-keyword">KW</span>',
- '<span class="ruby-ivar">IVAR</span>',
- '<span class="ruby-operator">Op</span>',
- '<span class="ruby-identifier">Id</span>',
- '<span class="ruby-node">Node</span>',
- '<span class="ruby-comment">COMMENT</span>',
- '<span class="ruby-regexp">REGEXP</span>',
- '<span class="ruby-string">STRING</span>',
- '<span class="ruby-value">Val</span>',
- '\\'
- ].join
+ expected = '<span class="ruby-constant">CONSTANT</span>'
assert_equal expected, @c2_a.markup_code
end
@@ -84,7 +60,9 @@ method(a, b) { |c, d| ... }
end
def test_marshal_dump
- top_level = RDoc::TopLevel.new 'file.rb'
+ @store.path = Dir.tmpdir
+ top_level = @store.add_file 'file.rb'
+
m = RDoc::AnyMethod.new nil, 'method'
m.block_params = 'some_block'
m.call_seq = 'call_seq'
@@ -92,20 +70,23 @@ method(a, b) { |c, d| ... }
m.params = 'param'
m.record_location top_level
- cm = RDoc::ClassModule.new 'Klass'
+ cm = top_level.add_class RDoc::ClassModule, 'Klass'
cm.add_method m
+ section = cm.sections.first
+
al = RDoc::Alias.new nil, 'method', 'aliased', 'alias comment'
al_m = m.add_alias al, cm
loaded = Marshal.load Marshal.dump m
+ loaded.store = @store
comment = RDoc::Markup::Document.new(
RDoc::Markup::Paragraph.new('this is a comment'))
assert_equal m, loaded
- assert_equal [al_m], loaded.aliases
+ assert_equal [al_m.name], loaded.aliases.map { |alas| alas.name }
assert_equal 'some_block', loaded.block_params
assert_equal 'call_seq', loaded.call_seq
assert_equal comment, loaded.comment
@@ -115,6 +96,8 @@ method(a, b) { |c, d| ... }
assert_equal 'param', loaded.params
assert_equal nil, loaded.singleton # defaults to nil
assert_equal :public, loaded.visibility
+ assert_equal cm, loaded.parent
+ assert_equal section, loaded.section
end
def test_marshal_load
@@ -138,28 +121,37 @@ method(a, b) { |c, d| ... }
end
def test_marshal_load_version_0
+ @store.path = Dir.tmpdir
+ top_level = @store.add_file 'file.rb'
+
m = RDoc::AnyMethod.new nil, 'method'
- cm = RDoc::ClassModule.new 'Klass'
+
+ cm = top_level.add_class RDoc::ClassModule, 'Klass'
cm.add_method m
+
+ section = cm.sections.first
+
al = RDoc::Alias.new nil, 'method', 'aliased', 'alias comment'
al_m = m.add_alias al, cm
- loaded = Marshal.load "\x04\bU:\x14RDoc::AnyMethod[\x0Fi\x00I" \
- "\"\vmethod\x06:\x06EF\"\x11Klass#method0:\vpublic" \
- "o:\eRDoc::Markup::Document\x06:\v@parts[\x06" \
- "o:\x1CRDoc::Markup::Paragraph\x06;\t[\x06I" \
- "\"\x16this is a comment\x06;\x06FI" \
- "\"\rcall_seq\x06;\x06FI\"\x0Fsome_block\x06;\x06F" \
- "[\x06[\aI\"\faliased\x06;\x06Fo;\b\x06;\t[\x06" \
- "o;\n\x06;\t[\x06I\"\x12alias comment\x06;\x06FI" \
+ loaded = Marshal.load "\x04\bU:\x14RDoc::AnyMethod[\x0Fi\x00I" +
+ "\"\vmethod\x06:\x06EF\"\x11Klass#method0:\vpublic" +
+ "o:\eRDoc::Markup::Document\x06:\v@parts[\x06" +
+ "o:\x1CRDoc::Markup::Paragraph\x06;\t[\x06I" +
+ "\"\x16this is a comment\x06;\x06FI" +
+ "\"\rcall_seq\x06;\x06FI\"\x0Fsome_block\x06;\x06F" +
+ "[\x06[\aI\"\faliased\x06;\x06Fo;\b\x06;\t[\x06" +
+ "o;\n\x06;\t[\x06I\"\x12alias comment\x06;\x06FI" +
"\"\nparam\x06;\x06F"
+ loaded.store = @store
+
comment = RDoc::Markup::Document.new(
RDoc::Markup::Paragraph.new('this is a comment'))
assert_equal m, loaded
- assert_equal [al_m], loaded.aliases
+ assert_equal [al_m.name], loaded.aliases.map { |alas| alas.name }
assert_equal 'some_block', loaded.block_params
assert_equal 'call_seq', loaded.call_seq
assert_equal comment, loaded.comment
@@ -169,6 +161,8 @@ method(a, b) { |c, d| ... }
assert_equal nil, loaded.singleton # defaults to nil
assert_equal :public, loaded.visibility
assert_equal nil, loaded.file
+ assert_equal cm, loaded.parent
+ assert_equal section, loaded.section
end
def test_name
@@ -200,6 +194,15 @@ method(a, b) { |c, d| ... }
assert_equal %w[a b c d], m.param_list
end
+ def test_param_list_default
+ m = RDoc::AnyMethod.new nil, 'method'
+ m.parent = @c1
+
+ m.params = '(b = default)'
+
+ assert_equal %w[b], m.param_list
+ end
+
def test_param_list_params
m = RDoc::AnyMethod.new nil, 'method'
m.parent = @c1
@@ -259,5 +262,58 @@ method(a, b) { |c, d| ... }
assert_equal 'C1', @c1.method_list.last.parent_name
end
+ def test_store_equals
+ loaded = Marshal.load Marshal.dump(@c1.method_list.last)
+
+ loaded.store = @store
+
+ assert_equal @store, loaded.file.store
+ end
+
+ def test_superclass_method
+ m3 = RDoc::AnyMethod.new '', 'no_super'
+
+ m2 = RDoc::AnyMethod.new '', 'supers'
+ m2.calls_super = true
+
+ m1 = RDoc::AnyMethod.new '', 'supers'
+
+ c1 = RDoc::NormalClass.new 'Outer'
+ c1.store = @store
+ c1.add_method m1
+
+ c2 = RDoc::NormalClass.new 'Inner', c1
+ c2.store = @store
+ c2.add_method m2
+ c2.add_method m3
+
+ assert_nil m3.superclass_method,
+ 'no superclass method for no_super'
+
+ assert_equal m1, m2.superclass_method,
+ 'superclass method missing for supers'
+ end
+
+ def test_superclass_method_multilevel
+ m2 = RDoc::AnyMethod.new '', 'supers'
+ m2.calls_super = true
+
+ m1 = RDoc::AnyMethod.new '', 'supers'
+
+ c1 = RDoc::NormalClass.new 'Outer'
+ c1.store = @store
+ c1.add_method m1
+
+ c2 = RDoc::NormalClass.new 'Middle', c1
+ c2.store = @store
+
+ c3 = RDoc::NormalClass.new 'Inner', c2
+ c3.store = @store
+ c3.add_method m2
+
+ assert_equal m1, m2.superclass_method,
+ 'superclass method missing for supers'
+ end
+
end
diff --git a/test/rdoc/test_rdoc_attr.rb b/test/rdoc/test_rdoc_attr.rb
index b69d8c6499..92ff1b9856 100644
--- a/test/rdoc/test_rdoc_attr.rb
+++ b/test/rdoc/test_rdoc_attr.rb
@@ -1,10 +1,10 @@
-require 'rubygems'
-require 'minitest/autorun'
-require 'rdoc/rdoc'
+require 'rdoc/test_case'
-class TestRDocAttr < MiniTest::Unit::TestCase
+class TestRDocAttr < RDoc::TestCase
def setup
+ super
+
@a = RDoc::Attr.new nil, 'attr', 'RW', ''
end
@@ -43,15 +43,18 @@ class TestRDocAttr < MiniTest::Unit::TestCase
end
def test_marshal_dump
- tl = RDoc::TopLevel.new 'file.rb'
+ tl = @store.add_file 'file.rb'
@a.comment = 'this is a comment'
@a.record_location tl
- cm = RDoc::ClassModule.new 'Klass'
+ cm = tl.add_class RDoc::NormalClass, 'Klass'
cm.add_attribute @a
+ section = cm.sections.first
+
loaded = Marshal.load Marshal.dump @a
+ loaded.store = @store
assert_equal @a, loaded
@@ -65,31 +68,58 @@ class TestRDocAttr < MiniTest::Unit::TestCase
assert_equal 'RW', loaded.rw
assert_equal false, loaded.singleton
assert_equal :public, loaded.visibility
+ assert_equal tl, loaded.file
+ assert_equal cm, loaded.parent
+ assert_equal section, loaded.section
+ end
+
+ def test_marshal_dump_singleton
+ tl = @store.add_file 'file.rb'
+
+ @a.comment = 'this is a comment'
+ @a.record_location tl
+
+ cm = tl.add_class RDoc::NormalClass, 'Klass'
+ cm.add_attribute @a
+
+ section = cm.sections.first
@a.rw = 'R'
@a.singleton = true
@a.visibility = :protected
loaded = Marshal.load Marshal.dump @a
+ loaded.store = @store
assert_equal @a, loaded
+ comment = RDoc::Markup::Document.new(
+ RDoc::Markup::Paragraph.new('this is a comment'))
+
assert_equal comment, loaded.comment
assert_equal 'Klass::attr', loaded.full_name
assert_equal 'attr', loaded.name
assert_equal 'R', loaded.rw
assert_equal true, loaded.singleton
assert_equal :protected, loaded.visibility
+ assert_equal tl, loaded.file
+ assert_equal cm, loaded.parent
+ assert_equal section, loaded.section
end
def test_marshal_load_version_1
- data = "\x04\bU:\x0FRDoc::Attr[\fi\x06I\"\tattr\x06:\x06EF" \
- "\"\x0FKlass#attrI\"\aRW\x06;\x06F:\vpublic" \
- "o:\eRDoc::Markup::Document\x06:\v@parts[\x06" \
- "o:\x1CRDoc::Markup::Paragraph\x06;\t[\x06I" \
+ tl = @store.add_file 'file.rb'
+ cm = tl.add_class RDoc::NormalClass, 'Klass'
+ section = cm.sections.first
+
+ data = "\x04\bU:\x0FRDoc::Attr[\fi\x06I\"\tattr\x06:\x06EF" +
+ "\"\x0FKlass#attrI\"\aRW\x06;\x06F:\vpublic" +
+ "o:\eRDoc::Markup::Document\x06:\v@parts[\x06" +
+ "o:\x1CRDoc::Markup::Paragraph\x06;\t[\x06I" +
"\"\x16this is a comment\x06;\x06FF"
loaded = Marshal.load data
+ loaded.store = @store
comment = RDoc::Markup::Document.new(
RDoc::Markup::Paragraph.new('this is a comment'))
@@ -101,7 +131,40 @@ class TestRDocAttr < MiniTest::Unit::TestCase
assert_equal false, loaded.singleton
assert_equal :public, loaded.visibility
- assert_equal nil, loaded.file # version 2
+ # version 2
+ assert_nil loaded.file
+
+ # version 3
+ assert_equal cm, loaded.parent
+ assert_equal section, loaded.section
+ end
+
+ def test_marshal_load_version_2
+ tl = @store.add_file 'file.rb'
+ cm = tl.add_class RDoc::NormalClass, 'Klass'
+ section = cm.sections.first
+
+ loaded = Marshal.load "\x04\bU:\x0FRDoc::Attr[\ri\aI\"\tattr\x06" +
+ ":\x06ETI\"\x0FKlass#attr\x06;\x06TI\"\aRW\x06" +
+ ";\x06T:\vpublico:\eRDoc::Markup::Document\a" +
+ ":\v@parts[\x06o:\x1CRDoc::Markup::Paragraph\x06;" +
+ "\t[\x06I\"\x16this is a comment\x06;\x06T:\n" +
+ "@file0FI\"\ffile.rb\x06;\x06T"
+ loaded.store = @store
+
+ comment = doc(para('this is a comment'))
+
+ assert_equal comment, loaded.comment
+ assert_equal 'Klass#attr', loaded.full_name
+ assert_equal 'attr', loaded.name
+ assert_equal 'RW', loaded.rw
+ assert_equal false, loaded.singleton
+ assert_equal :public, loaded.visibility
+ assert_equal tl, loaded.file
+
+ # version 3
+ assert_equal cm, loaded.parent
+ assert_equal section, loaded.section
end
def test_params
diff --git a/test/rdoc/test_rdoc_class_module.rb b/test/rdoc/test_rdoc_class_module.rb
index 7d32a91580..a6aa1e9472 100644
--- a/test/rdoc/test_rdoc_class_module.rb
+++ b/test/rdoc/test_rdoc_class_module.rb
@@ -1,14 +1,7 @@
-require 'pp'
require File.expand_path '../xref_test_case', __FILE__
class TestRDocClassModule < XrefTestCase
- def setup
- super
-
- @RM = RDoc::Markup
- end
-
def mu_pp obj
s = ''
s = PP.pp obj, s
@@ -17,9 +10,9 @@ class TestRDocClassModule < XrefTestCase
end
def test_add_comment
- tl1 = RDoc::TopLevel.new 'one.rb'
- tl2 = RDoc::TopLevel.new 'two.rb'
- tl3 = RDoc::TopLevel.new 'three.rb'
+ tl1 = @store.add_file 'one.rb'
+ tl2 = @store.add_file 'two.rb'
+ tl3 = @store.add_file 'three.rb'
cm = RDoc::ClassModule.new 'Klass'
cm.add_comment '# comment 1', tl1
@@ -40,8 +33,16 @@ class TestRDocClassModule < XrefTestCase
assert_equal "comment 1\n---\ncomment 2\n---\n* comment 3", cm.comment
end
+ def test_add_comment_comment
+ cm = RDoc::ClassModule.new 'Klass'
+
+ cm.add_comment comment('comment'), @top_level
+
+ assert_equal 'comment', cm.comment.text
+ end
+
def test_add_comment_stopdoc
- tl = RDoc::TopLevel.new 'file.rb'
+ tl = @store.add_file 'file.rb'
cm = RDoc::ClassModule.new 'Klass'
cm.stop_doc
@@ -52,7 +53,7 @@ class TestRDocClassModule < XrefTestCase
end
def test_ancestors
- assert_equal [@parent], @child.ancestors
+ assert_equal [@parent, "Object"], @child.ancestors
end
def test_comment_equals
@@ -70,14 +71,41 @@ class TestRDocClassModule < XrefTestCase
assert_equal "comment 1\n---\ncomment 2\n---\n* comment 3", cm.comment
end
+ def test_comment_equals_comment
+ cm = RDoc::ClassModule.new 'Klass'
+
+ cm.comment = comment 'comment'
+
+ assert_equal 'comment', cm.comment.text
+ end
+
+ def test_docuent_self_or_methods
+ assert @c1.document_self_or_methods
+
+ @c1.document_self = false
+
+ assert @c1.document_self_or_methods
+
+ @c1_m.document_self = false
+
+ assert @c1.document_self_or_methods
+
+ @c1__m.document_self = false
+
+ refute @c1.document_self_or_methods
+ end
+
def test_each_ancestor
- ancestors = []
+ assert_equal [@parent], @child.each_ancestor.to_a
+ end
- @child.each_ancestor do |mod|
- ancestors << mod
- end
+ def test_each_ancestor_cycle
+ m_incl = RDoc::Include.new 'M', nil
+
+ m = @top_level.add_module RDoc::NormalModule, 'M'
+ m.add_include m_incl
- assert_equal [@parent], ancestors
+ assert_empty m.each_ancestor.to_a
end
# handle making a short module alias of yourself
@@ -89,7 +117,7 @@ class TestRDocClassModule < XrefTestCase
end
def test_from_module_comment
- tl = RDoc::TopLevel.new 'file.rb'
+ tl = @store.add_file 'file.rb'
klass = tl.add_class RDoc::NormalModule, 'Klass'
klass.add_comment 'really a class', tl
@@ -99,7 +127,8 @@ class TestRDocClassModule < XrefTestCase
end
def test_marshal_dump
- tl = RDoc::TopLevel.new 'file.rb'
+ @store.path = Dir.tmpdir
+ tl = @store.add_file 'file.rb'
ns = tl.add_module RDoc::NormalModule, 'Namespace'
@@ -120,20 +149,32 @@ class TestRDocClassModule < XrefTestCase
i1 = RDoc::Include.new 'I1', ''
i1.record_location tl
+ e1 = RDoc::Extend.new 'E1', ''
+ e1.record_location tl
+
+ section_comment = RDoc::Comment.new('section comment')
+ section_comment.location = tl
+
+ assert_equal 1, cm.sections.length, 'sanity, default section only'
+ s0 = cm.sections.first
+ s1 = cm.add_section 'section', section_comment
+
cm.add_attribute a1
cm.add_attribute a2
cm.add_method m1
cm.add_constant c1
cm.add_include i1
+ cm.add_extend e1
cm.add_comment 'this is a comment', tl
loaded = Marshal.load Marshal.dump cm
+ loaded.store = @store
assert_equal cm, loaded
inner = RDoc::Markup::Document.new(
RDoc::Markup::Paragraph.new('this is a comment'))
- inner.file = tl.absolute_name
+ inner.file = tl
comment = RDoc::Markup::Document.new inner
@@ -142,9 +183,15 @@ class TestRDocClassModule < XrefTestCase
assert_equal [c1], loaded.constants
assert_equal 'Namespace::Klass', loaded.full_name
assert_equal [i1], loaded.includes
+ assert_equal [e1], loaded.extends
assert_equal [m1], loaded.method_list
assert_equal 'Klass', loaded.name
assert_equal 'Super', loaded.superclass
+ assert_equal [tl], loaded.in_files
+ assert_equal 'Namespace', loaded.parent.name
+
+ expected = { nil => s0, 'section' => s1 }
+ assert_equal expected, loaded.sections_hash
assert_equal tl, loaded.attributes.first.file
@@ -152,11 +199,13 @@ class TestRDocClassModule < XrefTestCase
assert_equal tl, loaded.includes.first.file
+ assert_equal tl, loaded.extends.first.file
+
assert_equal tl, loaded.method_list.first.file
end
def test_marshal_load_version_0
- tl = RDoc::TopLevel.new 'file.rb'
+ tl = @store.add_file 'file.rb'
ns = tl.add_module RDoc::NormalModule, 'Namespace'
cm = ns.add_class RDoc::NormalClass, 'Klass', 'Super'
@@ -165,25 +214,29 @@ class TestRDocClassModule < XrefTestCase
c = RDoc::Constant.new('C1', nil, '')
i = RDoc::Include.new('I1', '')
+ s0 = cm.sections.first
+
cm.add_attribute a
cm.add_method m
cm.add_constant c
cm.add_include i
cm.add_comment 'this is a comment', tl
- loaded = Marshal.load "\x04\bU:\x16RDoc::NormalClass[\x0Ei\x00\"\nKlass" \
- "\"\x15Namespace::KlassI\"\nSuper\x06:\x06EF" \
- "o:\eRDoc::Markup::Document\x06:\v@parts[\x06" \
- "o:\x1CRDoc::Markup::Paragraph\x06;\b[\x06I" \
- "\"\x16this is a comment\x06;\x06F[\x06[\aI" \
- "\"\aa1\x06;\x06FI\"\aRW\x06;\x06F[\x06[\aI" \
- "\"\aC1\x06;\x06Fo;\a\x06;\b[\x00[\x06[\aI" \
- "\"\aI1\x06;\x06Fo;\a\x06;\b[\x00[\a[\aI" \
- "\"\nclass\x06;\x06F[\b[\a:\vpublic[\x00[\a" \
- ":\x0Eprotected[\x00[\a:\fprivate[\x00[\aI" \
- "\"\rinstance\x06;\x06F[\b[\a;\n[\x06I" \
+ loaded = Marshal.load "\x04\bU:\x16RDoc::NormalClass[\x0Ei\x00\"\nKlass" +
+ "\"\x15Namespace::KlassI\"\nSuper\x06:\x06EF" +
+ "o:\eRDoc::Markup::Document\x06:\v@parts[\x06" +
+ "o:\x1CRDoc::Markup::Paragraph\x06;\b[\x06I" +
+ "\"\x16this is a comment\x06;\x06F[\x06[\aI" +
+ "\"\aa1\x06;\x06FI\"\aRW\x06;\x06F[\x06[\aI" +
+ "\"\aC1\x06;\x06Fo;\a\x06;\b[\x00[\x06[\aI" +
+ "\"\aI1\x06;\x06Fo;\a\x06;\b[\x00[\a[\aI" +
+ "\"\nclass\x06;\x06F[\b[\a:\vpublic[\x00[\a" +
+ ":\x0Eprotected[\x00[\a:\fprivate[\x00[\aI" +
+ "\"\rinstance\x06;\x06F[\b[\a;\n[\x06I" +
"\"\am1\x06;\x06F[\a;\v[\x00[\a;\f[\x00"
+ loaded.store = @store
+
assert_equal cm, loaded
comment = RDoc::Markup::Document.new(
@@ -197,12 +250,300 @@ class TestRDocClassModule < XrefTestCase
assert_equal [m], loaded.method_list
assert_equal 'Klass', loaded.name
assert_equal 'Super', loaded.superclass
- assert_equal nil, loaded.file
+ assert_nil loaded.file
+ assert_empty loaded.in_files
+ assert_nil loaded.parent
+ assert loaded.current_section
+
+ expected = { nil => s0 }
+ assert_equal expected, loaded.sections_hash
+ end
+
+ def test_marshal_load_version_1
+ tl = @store.add_file 'file.rb'
+
+ ns = tl.add_module RDoc::NormalModule, 'Namespace'
+
+ cm = ns.add_class RDoc::NormalClass, 'Klass', 'Super'
+ cm.record_location tl
+
+ a1 = RDoc::Attr.new nil, 'a1', 'RW', ''
+ a1.record_location tl
+ a2 = RDoc::Attr.new nil, 'a2', 'RW', '', true
+ a2.record_location tl
+
+ m1 = RDoc::AnyMethod.new nil, 'm1'
+ m1.record_location tl
+
+ c1 = RDoc::Constant.new 'C1', nil, ''
+ c1.record_location tl
+
+ i1 = RDoc::Include.new 'I1', ''
+ i1.record_location tl
+
+ s0 = cm.sections.first
+
+ cm.add_attribute a1
+ cm.add_attribute a2
+ cm.add_method m1
+ cm.add_constant c1
+ cm.add_include i1
+ cm.add_comment 'this is a comment', tl
+
+ loaded = Marshal.load "\x04\bU:\x16RDoc::NormalClass[\x0Ei\x06I\"\nKlass" +
+ "\x06:\x06EFI\"\x15Namespace::Klass\x06;\x06FI" +
+ "\"\nSuper\x06;\x06Fo:\eRDoc::Markup::Document\a" +
+ ":\v@parts[\x06o;\a\a;\b[\x06o" +
+ ":\x1CRDoc::Markup::Paragraph\x06;\b" +
+ "[\x06I\"\x16this is a comment\x06;\x06F" +
+ ":\n@fileI\"\ffile.rb\x06;\x06F;\n0[\a[\nI" +
+ "\"\aa2\x06;\x06FI\"\aRW\x06;\x06F:\vpublicT@\x11" +
+ "[\nI\"\aa1\x06;\x06FI\"\aRW\x06;\x06F;\vF@\x11" +
+ "[\x06[\bI\"\aC1\x06;\x06Fo;\a\a;\b[\x00;\n0@\x11" +
+ "[\x06[\bI\"\aI1\x06;\x06Fo;\a\a;\b[\x00;\n0@\x11" +
+ "[\a[\aI\"\nclass\x06;\x06F[\b[\a;\v[\x00" +
+ "[\a:\x0Eprotected[\x00[\a:\fprivate[\x00[\aI" +
+ "\"\rinstance\x06;\x06F[\b[\a;\v[\x06[\aI" +
+ "\"\am1\x06;\x06F@\x11[\a;\f[\x00[\a;\r[\x00"
+
+ loaded.store = @store
+
+ assert_equal cm, loaded
+
+ inner = RDoc::Markup::Document.new(
+ RDoc::Markup::Paragraph.new('this is a comment'))
+ inner.file = tl
+
+ comment = RDoc::Markup::Document.new inner
+
+ assert_equal [a2, a1], loaded.attributes.sort
+ assert_equal comment, loaded.comment
+ assert_equal [c1], loaded.constants
+ assert_equal 'Namespace::Klass', loaded.full_name
+ assert_equal [i1], loaded.includes
+ assert_empty loaded.extends
+ assert_equal [m1], loaded.method_list
+ assert_equal 'Klass', loaded.name
+ assert_equal 'Super', loaded.superclass
+ assert_empty loaded.in_files
+ assert_nil loaded.parent
+ assert loaded.current_section
+
+ assert_equal tl, loaded.attributes.first.file
+ assert_equal tl, loaded.constants.first.file
+ assert_equal tl, loaded.includes.first.file
+ assert_equal tl, loaded.method_list.first.file
+
+ expected = { nil => s0 }
+ assert_equal expected, loaded.sections_hash
+ end
+
+ def test_marshal_load_version_2
+ tl = @store.add_file 'file.rb'
+
+ ns = tl.add_module RDoc::NormalModule, 'Namespace'
+
+ cm = ns.add_class RDoc::NormalClass, 'Klass', 'Super'
+ cm.record_location tl
+
+ a1 = RDoc::Attr.new nil, 'a1', 'RW', ''
+ a1.record_location tl
+ a2 = RDoc::Attr.new nil, 'a2', 'RW', '', true
+ a2.record_location tl
+
+ m1 = RDoc::AnyMethod.new nil, 'm1'
+ m1.record_location tl
+
+ c1 = RDoc::Constant.new 'C1', nil, ''
+ c1.record_location tl
+
+ i1 = RDoc::Include.new 'I1', ''
+ i1.record_location tl
+
+ e1 = RDoc::Extend.new 'E1', ''
+ e1.record_location tl
+
+ s0 = cm.sections.first
+
+ cm.add_attribute a1
+ cm.add_attribute a2
+ cm.add_method m1
+ cm.add_constant c1
+ cm.add_include i1
+ cm.add_extend e1
+ cm.add_comment 'this is a comment', tl
+
+ loaded = Marshal.load "\x04\bU:\x16RDoc::NormalClass[\x0Fi\aI\"\nKlass" +
+ "\x06:\x06EFI\"\x15Namespace::Klass\x06;\x06FI" +
+ "\"\nSuper\x06;\x06Fo:\eRDoc::Markup::Document\a" +
+ ":\v@parts[\x06o;\a\a;\b[\x06o" +
+ ":\x1CRDoc::Markup::Paragraph\x06;\b" +
+ "[\x06I\"\x16this is a comment\x06;\x06F" +
+ ":\n@fileI\"\ffile.rb\x06;\x06F;\n0[\a[\nI" +
+ "\"\aa2\x06;\x06FI\"\aRW\x06;\x06F:\vpublicT@\x11" +
+ "[\nI\"\aa1\x06;\x06FI\"\aRW\x06;\x06F;\vF@\x11" +
+ "[\x06[\bI\"\aC1\x06;\x06Fo;\a\a;\b[\x00;\n0@\x11" +
+ "[\x06[\bI\"\aI1\x06;\x06Fo;\a\a;\b[\x00;\n0@\x11" +
+ "[\a[\aI\"\nclass\x06;\x06F[\b[\a;\v[\x00" +
+ "[\a:\x0Eprotected[\x00[\a:\fprivate[\x00[\aI" +
+ "\"\rinstance\x06;\x06F[\b[\a;\v[\x06[\aI" +
+ "\"\am1\x06;\x06F@\x11[\a;\f[\x00[\a;\r[\x00" +
+ "[\x06[\bI\"\aE1\x06;\x06Fo;\a\a;\b[\x00;\n0@\x11"
+
+ loaded.store = @store
+
+ assert_equal cm, loaded
+
+ inner = RDoc::Markup::Document.new(
+ RDoc::Markup::Paragraph.new('this is a comment'))
+ inner.file = tl
+
+ comment = RDoc::Markup::Document.new inner
+
+ assert_equal [a2, a1], loaded.attributes.sort
+ assert_equal comment, loaded.comment
+ assert_equal [c1], loaded.constants
+ assert_equal 'Namespace::Klass', loaded.full_name
+ assert_equal [i1], loaded.includes
+ assert_equal [e1], loaded.extends
+ assert_equal [m1], loaded.method_list
+ assert_equal 'Klass', loaded.name
+ assert_equal 'Super', loaded.superclass
+ assert_empty loaded.in_files
+ assert_nil loaded.parent
+ assert loaded.current_section
+
+ assert_equal tl, loaded.attributes. first.file
+ assert_equal tl, loaded.constants. first.file
+ assert_equal tl, loaded.includes. first.file
+ assert_equal tl, loaded.extends. first.file
+ assert_equal tl, loaded.method_list.first.file
+
+ expected = { nil => s0 }
+ assert_equal expected, loaded.sections_hash
+ end
+
+ def test_marshal_load_version_3
+ tl = @store.add_file 'file.rb'
+
+ ns = tl.add_module RDoc::NormalModule, 'Namespace'
+
+ cm = ns.add_class RDoc::NormalClass, 'Klass', 'Super'
+ cm.record_location tl
+
+ a1 = RDoc::Attr.new nil, 'a1', 'RW', ''
+ a1.record_location tl
+ a2 = RDoc::Attr.new nil, 'a2', 'RW', '', true
+ a2.record_location tl
+
+ m1 = RDoc::AnyMethod.new nil, 'm1'
+ m1.record_location tl
+
+ c1 = RDoc::Constant.new 'C1', nil, ''
+ c1.record_location tl
+
+ i1 = RDoc::Include.new 'I1', ''
+ i1.record_location tl
+
+ e1 = RDoc::Extend.new 'E1', ''
+ e1.record_location tl
+
+ section_comment = RDoc::Comment.new('section comment')
+ section_comment.location = tl
+
+ assert_equal 1, cm.sections.length, 'sanity, default section only'
+ s0 = cm.sections.first
+ s1 = cm.add_section 'section', section_comment
+
+ cm.add_attribute a1
+ cm.add_attribute a2
+ cm.add_method m1
+ cm.add_constant c1
+ cm.add_include i1
+ cm.add_extend e1
+ cm.add_comment 'this is a comment', tl
+
+ loaded = Marshal.load "\x04\bU:\x16RDoc::NormalClass[\x13i\bI\"\nKlass" +
+ "\x06:\x06ETI\"\x15Namespace::Klass\x06;\x06TI" +
+ "\"\nSuper\x06;\x06To:\eRDoc::Markup::Document\a" +
+ ":\v@parts[\x06o;\a\a;\b[\x06o" +
+ ":\x1CRDoc::Markup::Paragraph\x06;\b[\x06I" +
+ "\"\x16this is a comment\x06;\x06T:\n@fileI" +
+ "\"\ffile.rb\x06;\x06T;\n0[\a[\nI\"\aa2\x06;" +
+ "\x06TI\"\aRW\x06;\x06T:\vpublicT@\x11[\nI" +
+ "\"\aa1\x06;\x06TI\"\aRW\x06;\x06T;\vF@\x11" +
+ "[\x06U:\x13RDoc::Constant[\x0Fi\x00I\"\aC1\x06" +
+ ";\x06TI\"\x19Namespace::Klass::C1\x06;\x06T00o" +
+ ";\a\a;\b[\x00;\n0@\x11@\ac\x16RDoc::NormalClass0" +
+ "[\x06[\bI\"\aI1\x06;\x06To;\a\a;\b[\x00;\n0@\x11" +
+ "[\a[\aI\"\nclass\x06;\x06T[\b[\a;\v[\x00[\a" +
+ ":\x0Eprotected[\x00[\a:\fprivate[\x00[\aI" +
+ "\"\rinstance\x06;\x06T[\b[\a;\v[\x06[\aI" +
+ "\"\am1\x06;\x06T@\x11[\a;\r[\x00[\a;\x0E[\x00" +
+ "[\x06[\bI\"\aE1\x06;\x06To;\a\a;\b[\x00;\n0@\x11" +
+ "[\aU:\eRDoc::Context::Section[\bi\x000o;\a\a;\b" +
+ "[\x00;\n0U;\x0F[\bi\x00I\"\fsection\x06;\x06To" +
+ ";\a\a;\b[\x06o;\a\a;\b[\x06o;\t\x06;\b[\x06I" +
+ "\"\x14section comment\x06;\x06T;\n@\x11;\n0" +
+ "[\x06@\x11I\"\x0ENamespace\x06" +
+ ";\x06Tc\x17RDoc::NormalModule"
+
+ loaded.store = @store
+
+ assert_equal cm, loaded
+
+ inner = RDoc::Markup::Document.new(
+ RDoc::Markup::Paragraph.new('this is a comment'))
+ inner.file = tl
+
+ comment = RDoc::Markup::Document.new inner
+
+ assert_equal [a2, a1], loaded.attributes.sort
+ assert_equal comment, loaded.comment
+ assert_equal [c1], loaded.constants
+ assert_equal 'Namespace::Klass', loaded.full_name
+ assert_equal [i1], loaded.includes
+ assert_equal [e1], loaded.extends
+ assert_equal [m1], loaded.method_list
+ assert_equal 'Klass', loaded.name
+ assert_equal 'Super', loaded.superclass
+ assert_equal 'Namespace', loaded.parent.name
+ assert loaded.current_section
+
+ expected = {
+ nil => s0,
+ 'section' => s1,
+ }
+
+ assert_equal expected, loaded.sections_hash
+ assert_equal [tl], loaded.in_files
+
+ assert_equal tl, loaded.attributes. first.file
+ assert_equal tl, loaded.constants. first.file
+ assert_equal tl, loaded.includes. first.file
+ assert_equal tl, loaded.extends. first.file
+ assert_equal tl, loaded.method_list.first.file
+ end
+
+ def test_merge
+ tl = @store.add_file 'one.rb'
+ p1 = tl.add_class RDoc::NormalClass, 'Parent'
+ c1 = p1.add_class RDoc::NormalClass, 'Klass'
+
+ c2 = RDoc::NormalClass.new 'Klass'
+
+ c2.merge c1
+
+ assert_equal 'Parent', c1.parent_name, 'original parent name'
+ assert_equal 'Parent', c2.parent_name, 'merged parent name'
+
+ assert c1.current_section, 'original current_section'
+ assert c2.current_section, 'merged current_section'
end
def test_merge_attributes
- tl1 = RDoc::TopLevel.new 'one.rb'
- tl2 = RDoc::TopLevel.new 'two.rb'
+ tl1 = @store.add_file 'one.rb'
+ tl2 = @store.add_file 'two.rb'
cm1 = RDoc::ClassModule.new 'Klass'
@@ -237,7 +578,7 @@ class TestRDocClassModule < XrefTestCase
end
def test_merge_attributes_version_0
- tl1 = RDoc::TopLevel.new 'one.rb'
+ tl1 = @store.add_file 'one.rb'
cm1 = RDoc::ClassModule.new 'Klass'
@@ -270,7 +611,7 @@ class TestRDocClassModule < XrefTestCase
end
def test_merge_collections_drop
- tl = RDoc::TopLevel.new 'file'
+ tl = @store.add_file 'file'
cm1 = RDoc::ClassModule.new 'C'
cm1.record_location tl
@@ -297,17 +638,21 @@ class TestRDocClassModule < XrefTestCase
end
def test_merge_comment
- tl1 = RDoc::TopLevel.new 'one.rb'
- tl2 = RDoc::TopLevel.new 'two.rb'
+ tl1 = @store.add_file 'one.rb'
+ tl2 = @store.add_file 'two.rb'
- cm1 = RDoc::ClassModule.new 'Klass'
+ cm1 = tl1.add_class RDoc::ClassModule, 'Klass'
cm1.add_comment 'klass 1', tl1
+ cm1.record_location tl1
- cm2 = RDoc::ClassModule.new 'Klass'
+ cm2 = tl1.add_class RDoc::NormalClass, 'Klass'
cm2.add_comment 'klass 2', tl2
cm2.add_comment 'klass 3', tl1
+ cm2.record_location tl1
+ cm2.record_location tl2
cm2 = Marshal.load Marshal.dump cm2
+ cm2.store = @store
cm1.merge cm2
@@ -322,7 +667,7 @@ class TestRDocClassModule < XrefTestCase
end
def test_merge_comment_version_0
- tl = RDoc::TopLevel.new 'file.rb'
+ tl = @store.add_file 'file.rb'
cm1 = RDoc::ClassModule.new 'Klass'
cm1.add_comment 'klass 1', tl
@@ -347,17 +692,19 @@ class TestRDocClassModule < XrefTestCase
end
def test_merge_constants
- tl1 = RDoc::TopLevel.new 'one.rb'
- tl2 = RDoc::TopLevel.new 'two.rb'
+ tl1 = @store.add_file 'one.rb'
+ tl2 = @store.add_file 'two.rb'
- cm1 = RDoc::ClassModule.new 'Klass'
+ cm1 = tl1.add_class RDoc::ClassModule, 'Klass'
const = cm1.add_constant RDoc::Constant.new('C1', nil, 'one')
const.record_location tl1
const = cm1.add_constant RDoc::Constant.new('C3', nil, 'one')
const.record_location tl1
- cm2 = RDoc::ClassModule.new 'Klass'
+ store = RDoc::Store.new
+ tl = store.add_file 'one.rb'
+ cm2 = tl.add_class RDoc::ClassModule, 'Klass'
cm2.instance_variable_set :@comment, @RM::Document.new
const = cm2.add_constant RDoc::Constant.new('C2', nil, 'two')
@@ -381,16 +728,18 @@ class TestRDocClassModule < XrefTestCase
end
def test_merge_constants_version_0
- tl1 = RDoc::TopLevel.new 'one.rb'
+ tl1 = @store.add_file 'one.rb'
- cm1 = RDoc::ClassModule.new 'Klass'
+ cm1 = tl1.add_class RDoc::ClassModule, 'Klass'
const = cm1.add_constant RDoc::Constant.new('C1', nil, 'one')
const.record_location tl1
const = cm1.add_constant RDoc::Constant.new('C3', nil, 'one')
const.record_location tl1
- cm2 = RDoc::ClassModule.new 'Klass'
+ store = RDoc::Store.new
+ tl = store.add_file 'one.rb'
+ cm2 = tl.add_class RDoc::ClassModule, 'Klass'
cm2.instance_variable_set :@comment, @RM::Document.new
const = cm2.add_constant RDoc::Constant.new('C2', nil, 'two')
@@ -411,18 +760,55 @@ class TestRDocClassModule < XrefTestCase
assert_equal expected, cm1.constants.sort
end
+ def test_merge_extends
+ tl1 = @store.add_file 'one.rb'
+ cm1 = tl1.add_class RDoc::ClassModule, 'Klass'
+
+ ext = cm1.add_extend RDoc::Extend.new('I1', 'one')
+ ext.record_location tl1
+ ext = cm1.add_extend RDoc::Extend.new('I3', 'one')
+ ext.record_location tl1
+
+ tl2 = @store.add_file 'two.rb'
+ tl2.store = RDoc::Store.new
+
+ cm2 = tl2.add_class RDoc::ClassModule, 'Klass'
+ cm2.instance_variable_set :@comment, @RM::Document.new
+
+ ext = cm2.add_extend RDoc::Extend.new('I2', 'two')
+ ext.record_location tl2
+ ext = cm2.add_extend RDoc::Extend.new('I3', 'one')
+ ext.record_location tl1
+ ext = cm2.add_extend RDoc::Extend.new('I4', 'one')
+ ext.record_location tl1
+
+ cm1.merge cm2
+
+ expected = [
+ RDoc::Extend.new('I2', 'two'),
+ RDoc::Extend.new('I3', 'one'),
+ RDoc::Extend.new('I4', 'one'),
+ ]
+
+ expected.each do |a| a.parent = cm1 end
+
+ assert_equal expected, cm1.extends.sort
+ end
+
def test_merge_includes
- tl1 = RDoc::TopLevel.new 'one.rb'
- tl2 = RDoc::TopLevel.new 'two.rb'
+ tl1 = @store.add_file 'one.rb'
- cm1 = RDoc::ClassModule.new 'Klass'
+ cm1 = tl1.add_class RDoc::ClassModule, 'Klass'
incl = cm1.add_include RDoc::Include.new('I1', 'one')
incl.record_location tl1
incl = cm1.add_include RDoc::Include.new('I3', 'one')
incl.record_location tl1
- cm2 = RDoc::ClassModule.new 'Klass'
+ tl2 = @store.add_file 'two.rb'
+ tl2.store = RDoc::Store.new
+
+ cm2 = tl2.add_class RDoc::ClassModule, 'Klass'
cm2.instance_variable_set :@comment, @RM::Document.new
incl = cm2.add_include RDoc::Include.new('I2', 'two')
@@ -446,16 +832,19 @@ class TestRDocClassModule < XrefTestCase
end
def test_merge_includes_version_0
- tl1 = RDoc::TopLevel.new 'one.rb'
+ tl1 = @store.add_file 'one.rb'
- cm1 = RDoc::ClassModule.new 'Klass'
+ cm1 = tl1.add_class RDoc::ClassModule, 'Klass'
incl = cm1.add_include RDoc::Include.new('I1', 'one')
incl.record_location tl1
incl = cm1.add_include RDoc::Include.new('I3', 'one')
incl.record_location tl1
- cm2 = RDoc::ClassModule.new 'Klass'
+ tl2 = @store.add_file 'one.rb'
+ tl2.store = RDoc::Store.new
+
+ cm2 = tl2.add_class RDoc::ClassModule, 'Klass'
cm2.instance_variable_set :@comment, @RM::Document.new
incl = cm2.add_include RDoc::Include.new('I2', 'two')
@@ -477,10 +866,10 @@ class TestRDocClassModule < XrefTestCase
end
def test_merge_methods
- tl1 = RDoc::TopLevel.new 'one.rb'
- tl2 = RDoc::TopLevel.new 'two.rb'
+ tl1 = @store.add_file 'one.rb'
+ tl2 = @store.add_file 'two.rb'
- cm1 = RDoc::ClassModule.new 'Klass'
+ cm1 = tl1.add_class RDoc::NormalClass, 'Klass'
meth = cm1.add_method RDoc::AnyMethod.new(nil, 'm1')
meth.record_location tl1
@@ -488,6 +877,7 @@ class TestRDocClassModule < XrefTestCase
meth.record_location tl1
cm2 = RDoc::ClassModule.new 'Klass'
+ cm2.store = @store
cm2.instance_variable_set :@comment, @RM::Document.new
meth = cm2.add_method RDoc::AnyMethod.new(nil, 'm2')
@@ -511,9 +901,9 @@ class TestRDocClassModule < XrefTestCase
end
def test_merge_methods_version_0
- tl1 = RDoc::TopLevel.new 'one.rb'
+ tl1 = @store.add_file 'one.rb'
- cm1 = RDoc::ClassModule.new 'Klass'
+ cm1 = tl1.add_class RDoc::NormalClass, 'Klass'
meth = cm1.add_method RDoc::AnyMethod.new(nil, 'm1')
meth.record_location tl1
@@ -521,6 +911,7 @@ class TestRDocClassModule < XrefTestCase
meth.record_location tl1
cm2 = RDoc::ClassModule.new 'Klass'
+ cm2.store = @store
cm2.instance_variable_set :@comment, @RM::Document.new
meth = cm2.add_method RDoc::AnyMethod.new(nil, 'm2')
@@ -541,49 +932,176 @@ class TestRDocClassModule < XrefTestCase
assert_equal expected, cm1.method_list.sort
end
+ def test_merge_sections
+ store1 = @store
+
+ tl1_1 = store1.add_file 'one.rb'
+
+ cm1 = tl1_1.add_class RDoc::ClassModule, 'Klass'
+ cm1.record_location tl1_1
+
+ s1_0 = cm1.sections.first
+ s1_1 = cm1.add_section 'section 1', comment('comment 1', tl1_1)
+ cm1.add_section 'section 2', comment('comment 2 a', tl1_1)
+ cm1.add_section 'section 4', comment('comment 4 a', tl1_1)
+
+ store2 = RDoc::Store.new
+ tl2_1 = store2.add_file 'one.rb'
+ tl2_2 = store2.add_file 'two.rb'
+
+ cm2 = tl2_1.add_class RDoc::ClassModule, 'Klass'
+ cm2.record_location tl2_1
+ cm2.record_location tl2_2
+
+ cm2.sections.first
+ s2_2 = cm2.add_section 'section 2', comment('comment 2 b', tl2_1)
+ s2_3 = cm2.add_section 'section 3', comment('comment 3', tl2_2)
+ cm2.add_section 'section 4', comment('comment 4 b', tl2_2)
+
+ cm1.merge cm2
+
+ expected = [
+ s1_0,
+ s1_1,
+ s2_2,
+ s2_3,
+ RDoc::Context::Section.new(cm1, 'section 4', nil)
+ ]
+
+ merged_sections = cm1.sections.sort_by do |s|
+ s.title || ''
+ end
+
+ assert_equal expected, merged_sections
+
+ assert_equal [comment('comment 2 b', tl2_1)],
+ cm1.sections_hash['section 2'].comments
+
+ expected_s4_comments = [
+ comment('comment 4 a', tl2_1),
+ comment('comment 4 b', tl2_2),
+ ]
+
+ assert_equal expected_s4_comments, cm1.sections_hash['section 4'].comments
+ end
+
+ def test_merge_sections_overlap
+ store1 = @store
+
+ tl1_1 = store1.add_file 'one.rb'
+ tl1_3 = store1.add_file 'three.rb'
+
+ cm1 = tl1_1.add_class RDoc::ClassModule, 'Klass'
+ cm1.record_location tl1_1
+
+ cm1.add_section 'section', comment('comment 1 a', tl1_1)
+ cm1.add_section 'section', comment('comment 3', tl1_3)
+
+ store2 = RDoc::Store.new
+ tl2_1 = store2.add_file 'one.rb'
+ tl2_2 = store2.add_file 'two.rb'
+ tl2_3 = store2.add_file 'three.rb'
+
+ cm2 = tl2_1.add_class RDoc::ClassModule, 'Klass'
+ cm2.record_location tl2_1
+ cm2.record_location tl2_2
+
+ s2_0 = cm2.sections.first
+ s2_1 = cm2.add_section 'section', comment('comment 1 b', tl1_1)
+ cm2.add_section 'section', comment('comment 2', tl2_2)
+
+ cm1.merge_sections cm2
+
+ expected = [
+ s2_0,
+ s2_1,
+ ]
+
+ merged_sections = cm1.sections.sort_by do |s|
+ s.title || ''
+ end
+
+ assert_equal expected, merged_sections
+
+ expected = [
+ comment('comment 1 b', tl2_1),
+ comment('comment 3', tl2_3),
+ comment('comment 2', tl2_2),
+ ]
+
+ comments = cm1.sections_hash['section'].comments
+
+ assert_equal expected, comments.sort_by { |c| c.file.name }
+ end
+
def test_parse
- tl1 = RDoc::TopLevel.new 'one.rb'
- tl2 = RDoc::TopLevel.new 'two.rb'
+ tl1 = @store.add_file 'one.rb'
+ tl2 = @store.add_file 'two.rb'
cm = RDoc::ClassModule.new 'Klass'
cm.add_comment 'comment 1', tl1
cm.add_comment 'comment 2', tl2
doc1 = @RM::Document.new @RM::Paragraph.new 'comment 1'
- doc1.file = tl1.absolute_name
+ doc1.file = tl1
doc2 = @RM::Document.new @RM::Paragraph.new 'comment 2'
- doc2.file = tl2.absolute_name
+ doc2.file = tl2
expected = @RM::Document.new doc1, doc2
assert_equal expected, cm.parse(cm.comment_location)
end
- def test_parse_comment_location
- tl1 = RDoc::TopLevel.new 'one.rb'
- tl2 = RDoc::TopLevel.new 'two.rb'
+ def test_parse_comment
+ tl1 = @store.add_file 'one.rb'
+
+ cm = RDoc::ClassModule.new 'Klass'
+ cm.comment = comment 'comment 1', tl1
+
+ doc = @RM::Document.new @RM::Paragraph.new 'comment 1'
+ doc.file = tl1
+
+ assert_equal doc, cm.parse(cm.comment)
+ end
+
+ def test_parse_comment_format
+ tl1 = @store.add_file 'one.rb'
cm = RDoc::ClassModule.new 'Klass'
+ cm.comment = comment 'comment ((*1*))', tl1
+ cm.comment.format = 'rd'
+
+ doc = @RM::Document.new @RM::Paragraph.new 'comment <em>1</em>'
+ doc.file = tl1
+
+ assert_equal doc, cm.parse(cm.comment)
+ end
+
+ def test_parse_comment_location
+ tl1 = @store.add_file 'one.rb'
+ tl2 = @store.add_file 'two.rb'
+
+ cm = tl1.add_class RDoc::NormalClass, 'Klass'
cm.add_comment 'comment 1', tl1
cm.add_comment 'comment 2', tl2
cm = Marshal.load Marshal.dump cm
doc1 = @RM::Document.new @RM::Paragraph.new 'comment 1'
- doc1.file = tl1.absolute_name
+ doc1.file = tl1
doc2 = @RM::Document.new @RM::Paragraph.new 'comment 2'
- doc2.file = tl2.absolute_name
+ doc2.file = tl2
assert_same cm.comment_location, cm.parse(cm.comment_location)
end
def test_remove_nodoc_children
- parent = RDoc::ClassModule.new 'A'
+ parent = @top_level.add_class RDoc::ClassModule, 'A'
parent.modules_hash.replace 'B' => true, 'C' => true
- RDoc::TopLevel.all_modules_hash.replace 'A::B' => true
+ @store.modules_hash.replace 'A::B' => true
parent.classes_hash.replace 'D' => true, 'E' => true
- RDoc::TopLevel.all_classes_hash.replace 'A::D' => true
+ @store.classes_hash.replace 'A::D' => true
parent.remove_nodoc_children
@@ -591,6 +1109,83 @@ class TestRDocClassModule < XrefTestCase
assert_equal %w[D], parent.classes_hash.keys
end
+ def test_search_record
+ @c2_c3.add_comment 'This is a comment.', @xref_data
+
+ expected = [
+ 'C3',
+ 'C2::C3',
+ 'C2::C3',
+ '',
+ 'C2/C3.html',
+ '',
+ "<p>This is a comment.\n"
+ ]
+
+ assert_equal expected, @c2_c3.search_record
+ end
+
+ def test_search_record_merged
+ @c2_c3.add_comment 'comment A', @store.add_file('a.rb')
+ @c2_c3.add_comment 'comment B', @store.add_file('b.rb')
+
+ expected = [
+ 'C3',
+ 'C2::C3',
+ 'C2::C3',
+ '',
+ 'C2/C3.html',
+ '',
+ "<p>comment A\n<p>comment B\n"
+ ]
+
+ assert_equal expected, @c2_c3.search_record
+ end
+
+ def test_store_equals
+ # version 2
+ loaded = Marshal.load "\x04\bU:\x16RDoc::NormalClass[\x0Fi\aI\"\nKlass" +
+ "\x06:\x06EFI\"\x15Namespace::Klass\x06;\x06FI" +
+ "\"\nSuper\x06;\x06Fo:\eRDoc::Markup::Document\a" +
+ ":\v@parts[\x06o;\a\a;\b[\x06o" +
+ ":\x1CRDoc::Markup::Paragraph\x06;\b" +
+ "[\x06I\"\x16this is a comment\x06;\x06F" +
+ ":\n@fileI\"\ffile.rb\x06;\x06F;\n0[\a[\nI" +
+ "\"\aa2\x06;\x06FI\"\aRW\x06;\x06F:\vpublicT@\x11" +
+ "[\nI\"\aa1\x06;\x06FI\"\aRW\x06;\x06F;\vF@\x11" +
+ "[\x06[\bI\"\aC1\x06;\x06Fo;\a\a;\b[\x00;\n0@\x11" +
+ "[\x06[\bI\"\aI1\x06;\x06Fo;\a\a;\b[\x00;\n0@\x11" +
+ "[\a[\aI\"\nclass\x06;\x06F[\b[\a;\v[\x00" +
+ "[\a:\x0Eprotected[\x00[\a:\fprivate[\x00[\aI" +
+ "\"\rinstance\x06;\x06F[\b[\a;\v[\x06[\aI" +
+ "\"\am1\x06;\x06F@\x11[\a;\f[\x00[\a;\r[\x00" +
+ "[\x06[\bI\"\aE1\x06;\x06Fo;\a\a;\b[\x00;\n0@\x11"
+
+ loaded.store = @store
+
+ assert_same @store, loaded.store
+
+ a = loaded.attributes.first
+ assert_same @store, a.store
+ assert_same @store, a.file.store
+
+ c = loaded.constants.first
+ assert_same @store, c.store
+ assert_same @store, c.file.store
+
+ i = loaded.includes.first
+ assert_same @store, i.store
+ assert_same @store, i.file.store
+
+ e = loaded.extends.first
+ assert_same @store, e.store
+ assert_same @store, e.file.store
+
+ m = loaded.method_list.first
+ assert_same @store, m.store
+ assert_same @store, m.file.store
+ end
+
def test_superclass
assert_equal @c3_h1, @c3_h2.superclass
end
@@ -668,6 +1263,30 @@ class TestRDocClassModule < XrefTestCase
assert_equal 'O1::A1', o1_a1_m.full_name
end
+ def test_update_aliases_reparent_root
+ store = RDoc::Store.new
+
+ top_level = store.add_file 'file.rb'
+
+ klass = top_level.add_class RDoc::NormalClass, 'Klass'
+ object = top_level.add_class RDoc::NormalClass, 'Object'
+
+ const = RDoc::Constant.new 'A', nil, ''
+ const.record_location top_level
+ const.is_alias_for = klass
+
+ top_level.add_module_alias klass, 'A', top_level
+
+ object.add_constant const
+
+ object.update_aliases
+
+ assert_equal %w[A Klass Object], store.classes_hash.keys.sort
+
+ assert_equal 'A', store.classes_hash['A'].full_name
+ assert_equal 'Klass', store.classes_hash['Klass'].full_name
+ end
+
def test_update_includes
a = RDoc::Include.new 'M1', nil
b = RDoc::Include.new 'M2', nil
@@ -681,16 +1300,30 @@ class TestRDocClassModule < XrefTestCase
@m1_m2.document_self = nil
assert @m1_m2.remove_from_documentation?
- assert RDoc::TopLevel.all_modules_hash.key? @m1_m2.full_name
- refute RDoc::TopLevel.all_modules_hash[@m1_m2.full_name].nil?
- RDoc::TopLevel.remove_nodoc RDoc::TopLevel.all_modules_hash
- refute RDoc::TopLevel.all_modules_hash.key? @m1_m2.full_name
+ assert @store.modules_hash.key? @m1_m2.full_name
+ refute @store.modules_hash[@m1_m2.full_name].nil?
+
+ @store.remove_nodoc @store.modules_hash
+ refute @store.modules_hash.key? @m1_m2.full_name
@c1.update_includes
assert_equal [a, c], @c1.includes
end
+ def test_update_includes_trim
+ a = RDoc::Include.new 'D::M', nil
+ b = RDoc::Include.new 'D::M', nil
+
+ @c1.add_include a
+ @c1.add_include b
+ @c1.ancestors # cache included modules
+
+ @c1.update_includes
+
+ assert_equal [a], @c1.includes
+ end
+
def test_update_includes_with_colons
a = RDoc::Include.new 'M1', nil
b = RDoc::Include.new 'M1::M2', nil
@@ -704,15 +1337,75 @@ class TestRDocClassModule < XrefTestCase
@m1_m2.document_self = nil
assert @m1_m2.remove_from_documentation?
- assert RDoc::TopLevel.all_modules_hash.key? @m1_m2.full_name
- refute RDoc::TopLevel.all_modules_hash[@m1_m2.full_name].nil?
- RDoc::TopLevel.remove_nodoc RDoc::TopLevel.all_modules_hash
- refute RDoc::TopLevel.all_modules_hash.key? @m1_m2.full_name
+ assert @store.modules_hash.key? @m1_m2.full_name
+ refute @store.modules_hash[@m1_m2.full_name].nil?
+ @store.remove_nodoc @store.modules_hash
+ refute @store.modules_hash.key? @m1_m2.full_name
@c1.update_includes
assert_equal [a, c], @c1.includes
end
+ def test_update_extends
+ a = RDoc::Extend.new 'M1', nil
+ b = RDoc::Extend.new 'M2', nil
+ c = RDoc::Extend.new 'C', nil
+
+ @c1.add_extend a
+ @c1.add_extend b
+ @c1.add_extend c
+ @c1.each_extend do |extend| extend.module end # cache extended modules
+
+ @m1_m2.document_self = nil
+ assert @m1_m2.remove_from_documentation?
+
+ assert @store.modules_hash.key? @m1_m2.full_name
+ refute @store.modules_hash[@m1_m2.full_name].nil?
+ @store.remove_nodoc @store.modules_hash
+ refute @store.modules_hash.key? @m1_m2.full_name
+
+ @c1.update_extends
+
+ assert_equal [a, c], @c1.extends
+ end
+
+ def test_update_extends_trim
+ a = RDoc::Extend.new 'D::M', nil
+ b = RDoc::Extend.new 'D::M', nil
+
+ @c1.add_extend a
+ @c1.add_extend b
+ @c1.each_extend do |extend| extend.module end # cache extended modules
+
+ @c1.update_extends
+
+ assert_equal [a], @c1.extends
+ end
+
+ def test_update_extends_with_colons
+ a = RDoc::Extend.new 'M1', nil
+ b = RDoc::Extend.new 'M1::M2', nil
+ c = RDoc::Extend.new 'C', nil
+
+ @c1.add_extend a
+ @c1.add_extend b
+ @c1.add_extend c
+ @c1.each_extend do |extend| extend.module end # cache extended modules
+
+ @m1_m2.document_self = nil
+ assert @m1_m2.remove_from_documentation?
+
+ assert @store.modules_hash.key? @m1_m2.full_name
+ refute @store.modules_hash[@m1_m2.full_name].nil?
+
+ @store.remove_nodoc @store.modules_hash
+ refute @store.modules_hash.key? @m1_m2.full_name
+
+ @c1.update_extends
+
+ assert_equal [a, c], @c1.extends
+ end
+
end
diff --git a/test/rdoc/test_rdoc_code_object.rb b/test/rdoc/test_rdoc_code_object.rb
index c7a37488cc..ef8a5df713 100644
--- a/test/rdoc/test_rdoc_code_object.rb
+++ b/test/rdoc/test_rdoc_code_object.rb
@@ -1,9 +1,6 @@
# coding: US-ASCII
-require 'rubygems'
-require 'minitest/autorun'
require File.expand_path '../xref_test_case', __FILE__
-require 'rdoc/code_object'
class TestRDocCodeObject < XrefTestCase
@@ -32,6 +29,16 @@ class TestRDocCodeObject < XrefTestCase
assert_equal 'I am a comment', @co.comment
end
+ def test_comment_equals_comment
+ @co.comment = comment ''
+
+ assert_equal '', @co.comment.text
+
+ @co.comment = comment 'I am a comment'
+
+ assert_equal 'I am a comment', @co.comment.text
+ end
+
def test_comment_equals_document
doc = RDoc::Markup::Document.new
@co.comment = doc
@@ -167,7 +174,7 @@ class TestRDocCodeObject < XrefTestCase
def test_file_name
assert_equal nil, @co.file_name
- @co.record_location RDoc::TopLevel.new 'lib/file.rb'
+ @co.record_location @store.add_file 'lib/file.rb'
assert_equal 'lib/file.rb', @co.file_name
end
@@ -256,6 +263,26 @@ class TestRDocCodeObject < XrefTestCase
refute @co.ignored?
end
+ def test_section
+ parent = RDoc::Context.new
+ section = parent.sections.first
+
+ @co.parent = parent
+ @co.instance_variable_set :@section, section
+
+ assert_equal section, @co.section
+
+ @co.instance_variable_set :@section, nil
+ @co.instance_variable_set :@section_title, nil
+
+ assert_equal section, @co.section
+
+ @co.instance_variable_set :@section, nil
+ @co.instance_variable_set :@section_title, 'new title'
+
+ assert_equal 'new title', @co.section.title
+ end
+
def test_start_doc
@co.document_self = false
@co.document_children = false
diff --git a/test/rdoc/test_rdoc_comment.rb b/test/rdoc/test_rdoc_comment.rb
new file mode 100644
index 0000000000..1afc94c251
--- /dev/null
+++ b/test/rdoc/test_rdoc_comment.rb
@@ -0,0 +1,504 @@
+# coding: us-ascii
+
+require 'rdoc/test_case'
+
+class TestRDocComment < RDoc::TestCase
+
+ def setup
+ super
+
+ @top_level = @store.add_file 'file.rb'
+ @comment = RDoc::Comment.new
+ @comment.location = @top_level
+ @comment.text = 'this is a comment'
+ end
+
+ def test_empty_eh
+ refute_empty @comment
+
+ @comment = ''
+
+ assert_empty @comment
+ end
+
+ def test_equals2
+ assert_equal @comment, @comment.dup
+
+ c2 = @comment.dup
+ c2.text = nil
+
+ refute_equal @comment, c2
+
+ c3 = @comment.dup
+ c3.location = nil
+
+ refute_equal @comment, c3
+ end
+
+ def test_extract_call_seq
+ m = RDoc::AnyMethod.new nil, 'm'
+
+ comment = RDoc::Comment.new <<-COMMENT, @top_level
+call-seq:
+ bla => true or false
+
+moar comment
+ COMMENT
+
+ comment.extract_call_seq m
+
+ assert_equal "bla => true or false\n", m.call_seq
+ end
+
+ def test_extract_call_seq_blank
+ m = RDoc::AnyMethod.new nil, 'm'
+
+ comment = RDoc::Comment.new <<-COMMENT, @top_level
+call-seq:
+ bla => true or false
+
+ COMMENT
+
+ comment.extract_call_seq m
+
+ assert_equal "bla => true or false\n", m.call_seq
+ end
+
+ def test_extract_call_seq_commented
+ m = RDoc::AnyMethod.new nil, 'm'
+
+ comment = RDoc::Comment.new <<-COMMENT, @top_level
+# call-seq:
+# bla => true or false
+#
+# moar comment
+ COMMENT
+
+ comment.extract_call_seq m
+
+ assert_equal nil, m.call_seq
+ end
+
+ def test_extract_call_seq_no_blank
+ m = RDoc::AnyMethod.new nil, 'm'
+
+ comment = RDoc::Comment.new <<-COMMENT, @top_level
+call-seq:
+ bla => true or false
+ COMMENT
+
+ comment.extract_call_seq m
+
+ assert_equal "bla => true or false\n", m.call_seq
+ end
+
+ def test_extract_call_seq_undent
+ m = RDoc::AnyMethod.new nil, 'm'
+
+ comment = RDoc::Comment.new <<-COMMENT, @top_level
+call-seq:
+ bla => true or false
+moar comment
+ COMMENT
+
+ comment.extract_call_seq m
+
+ assert_equal "bla => true or false\nmoar comment\n", m.call_seq
+ end
+
+ def test_extract_call_seq_c
+ comment = RDoc::Comment.new <<-COMMENT
+call-seq:
+ commercial() -> Date <br />
+ commercial(cwyear, cweek=41, cwday=5, sg=nil) -> Date [ruby 1.8] <br />
+ commercial(cwyear, cweek=1, cwday=1, sg=nil) -> Date [ruby 1.9]
+
+If no arguments are given:
+* ruby 1.8: returns a +Date+ for 1582-10-15 (the Day of Calendar Reform in
+ Italy)
+* ruby 1.9: returns a +Date+ for julian day 0
+
+Otherwise, returns a +Date+ for the commercial week year, commercial week,
+and commercial week day given. Ignores the 4th argument.
+ COMMENT
+
+ method_obj = RDoc::AnyMethod.new nil, 'blah'
+
+ comment.extract_call_seq method_obj
+
+ expected = <<-CALL_SEQ.chomp
+commercial() -> Date <br />
+commercial(cwyear, cweek=41, cwday=5, sg=nil) -> Date [ruby 1.8] <br />
+commercial(cwyear, cweek=1, cwday=1, sg=nil) -> Date [ruby 1.9]
+
+ CALL_SEQ
+
+ assert_equal expected, method_obj.call_seq
+ end
+
+ def test_extract_call_seq_c_no_blank
+ comment = RDoc::Comment.new <<-COMMENT
+call-seq:
+ commercial() -> Date <br />
+ commercial(cwyear, cweek=41, cwday=5, sg=nil) -> Date [ruby 1.8] <br />
+ commercial(cwyear, cweek=1, cwday=1, sg=nil) -> Date [ruby 1.9]
+ COMMENT
+
+ method_obj = RDoc::AnyMethod.new nil, 'blah'
+
+ comment.extract_call_seq method_obj
+
+ expected = <<-CALL_SEQ.chomp
+commercial() -> Date <br />
+commercial(cwyear, cweek=41, cwday=5, sg=nil) -> Date [ruby 1.8] <br />
+commercial(cwyear, cweek=1, cwday=1, sg=nil) -> Date [ruby 1.9]
+
+ CALL_SEQ
+
+ assert_equal expected, method_obj.call_seq
+ end
+
+ def test_extract_call_seq_c_separator
+ comment = RDoc::Comment.new <<-'COMMENT'
+call-seq:
+ ARGF.readlines(sep=$/) -> array
+ ARGF.readlines(limit) -> array
+ ARGF.readlines(sep, limit) -> array
+
+ ARGF.to_a(sep=$/) -> array
+ ARGF.to_a(limit) -> array
+ ARGF.to_a(sep, limit) -> array
+
+Reads +ARGF+'s current file in its entirety, returning an +Array+ of its
+lines, one line per element. Lines are assumed to be separated by _sep_.
+
+ lines = ARGF.readlines
+ lines[0] #=> "This is line one\n"
+
+ COMMENT
+
+ method_obj = RDoc::AnyMethod.new nil, 'blah'
+
+ comment.extract_call_seq method_obj
+
+ expected = <<-CALL_SEQ
+ARGF.readlines(sep=$/) -> array
+ARGF.readlines(limit) -> array
+ARGF.readlines(sep, limit) -> array
+ARGF.to_a(sep=$/) -> array
+ARGF.to_a(limit) -> array
+ARGF.to_a(sep, limit) -> array
+ CALL_SEQ
+
+ assert_equal expected, method_obj.call_seq
+
+ expected = <<-'COMMENT'
+
+Reads +ARGF+'s current file in its entirety, returning an +Array+ of its
+lines, one line per element. Lines are assumed to be separated by _sep_.
+
+ lines = ARGF.readlines
+ lines[0] #=> "This is line one\n"
+
+ COMMENT
+
+ assert_equal expected, comment.text
+ end
+
+ def test_force_encoding
+ skip "Encoding not implemented" unless Object.const_defined? :Encoding
+
+ @comment.force_encoding Encoding::UTF_8
+
+ assert_equal Encoding::UTF_8, @comment.text.encoding
+ end
+
+ def test_format
+ assert_equal 'rdoc', @comment.format
+ end
+
+ def test_format_equals
+ c = comment 'content'
+ document = c.parse
+
+ c.format = RDoc::RD
+
+ assert_equal RDoc::RD, c.format
+ refute_same document, c.parse
+ end
+
+ def test_initialize_copy
+ copy = @comment.dup
+
+ refute_same @comment.text, copy.text
+ assert_same @comment.location, copy.location
+ end
+
+ def test_location
+ assert_equal @top_level, @comment.location
+ end
+
+ def test_normalize
+ @comment.text = <<-TEXT
+ # comment
+ TEXT
+
+ assert_same @comment, @comment.normalize
+
+ assert_equal 'comment', @comment.text
+ end
+
+ def test_normalize_twice
+ @comment.text = <<-TEXT
+ # comment
+ TEXT
+
+ @comment.normalize
+
+ text = @comment.text
+
+ @comment.normalize
+
+ assert_same text, @comment.text, 'normalize not cached'
+ end
+
+ def test_normalize_document
+ @comment.text = nil
+ @comment.document = @RM::Document.new
+
+ assert_same @comment, @comment.normalize
+
+ assert_nil @comment.text
+ end
+
+ def test_normalize_eh
+ refute @comment.normalized?
+
+ @comment.normalize
+
+ assert @comment.normalized?
+ end
+
+ def test_text
+ assert_equal 'this is a comment', @comment.text
+ end
+
+ def test_text_equals
+ @comment.text = 'other'
+
+ assert_equal 'other', @comment.text
+ refute @comment.normalized?
+ end
+
+ def test_text_equals_no_text
+ c = RDoc::Comment.new nil, @top_level
+ c.document = @RM::Document.new
+
+ e = assert_raises RDoc::Error do
+ c.text = 'other'
+ end
+
+ assert_equal 'replacing document-only comment is not allowed', e.message
+ end
+
+ def test_text_equals_parsed
+ document = @comment.parse
+
+ @comment.text = 'other'
+
+ refute_equal document, @comment.parse
+ end
+
+ def test_tomdoc_eh
+ refute @comment.tomdoc?
+
+ @comment.format = 'tomdoc'
+
+ assert @comment.tomdoc?
+ end
+
+ def test_parse
+ parsed = @comment.parse
+
+ expected = @RM::Document.new(
+ @RM::Paragraph.new('this is a comment'))
+
+ expected.file = @top_level
+
+ assert_equal expected, parsed
+ assert_same parsed, @comment.parse
+ end
+
+ def test_parse_rd
+ c = comment 'it ((*works*))'
+ c.format = 'rd'
+
+ expected =
+ @RM::Document.new(
+ @RM::Paragraph.new('it <em>works</em>'))
+ expected.file = @top_level
+
+ assert_equal expected, c.parse
+ end
+
+ def test_remove_private_encoding
+ skip "Encoding not implemented" unless Object.const_defined? :Encoding
+
+ comment = RDoc::Comment.new <<-EOS, @top_level
+# This is text
+#--
+# this is private
+ EOS
+
+ comment.force_encoding Encoding::IBM437
+
+ comment.remove_private
+
+ assert_equal Encoding::IBM437, comment.text.encoding
+ end
+
+ def test_remove_private_hash
+ @comment.text = <<-TEXT
+#--
+# private
+#++
+# public
+ TEXT
+
+ @comment.remove_private
+
+ assert_equal "# public\n", @comment.text
+ end
+
+ def test_remove_private_hash_trail
+ comment = RDoc::Comment.new <<-EOS, @top_level
+# This is text
+#--
+# this is private
+ EOS
+
+ expected = RDoc::Comment.new <<-EOS, @top_level
+# This is text
+ EOS
+
+ comment.remove_private
+
+ assert_equal expected, comment
+ end
+
+ def test_remove_private_long
+ comment = RDoc::Comment.new <<-EOS, @top_level
+#-----
+#++
+# this is text
+#-----
+ EOS
+
+ expected = RDoc::Comment.new <<-EOS, @top_level
+# this is text
+ EOS
+
+ comment.remove_private
+
+ assert_equal expected, comment
+ end
+
+ def test_remove_private_rule
+ comment = RDoc::Comment.new <<-EOS, @top_level
+# This is text with a rule:
+# ---
+# this is also text
+ EOS
+
+ expected = comment.dup
+
+ comment.remove_private
+
+ assert_equal expected, comment
+ end
+
+ def test_remove_private_star
+ @comment.text = <<-TEXT
+/*
+ *--
+ * private
+ *++
+ * public
+ */
+ TEXT
+
+ @comment.remove_private
+
+ assert_equal "/*\n * public\n */\n", @comment.text
+ end
+
+ def test_remove_private_star2
+ @comment.text = <<-TEXT
+/*--
+ * private
+ *++
+ * public
+ */
+ TEXT
+
+ @comment.remove_private
+
+ assert_equal "/*--\n * private\n *++\n * public\n */\n", @comment.text
+ end
+
+ def test_remove_private_toggle
+ comment = RDoc::Comment.new <<-EOS, @top_level
+# This is text
+#--
+# this is private
+#++
+# This is text again.
+ EOS
+
+ expected = RDoc::Comment.new <<-EOS, @top_level
+# This is text
+# This is text again.
+ EOS
+
+ comment.remove_private
+
+ assert_equal expected, comment
+ end
+
+ def test_remove_private_toggle_encoding
+ skip "Encoding not implemented" unless Object.const_defined? :Encoding
+
+ comment = RDoc::Comment.new <<-EOS, @top_level
+# This is text
+#--
+# this is private
+#++
+# This is text again.
+ EOS
+
+ comment.force_encoding Encoding::IBM437
+
+ comment.remove_private
+
+ assert_equal Encoding::IBM437, comment.text.encoding
+ end
+
+ def test_remove_private_toggle_encoding_ruby_bug?
+ skip "Encoding not implemented" unless Object.const_defined? :Encoding
+
+ comment = RDoc::Comment.new <<-EOS, @top_level
+#--
+# this is private
+#++
+# This is text again.
+ EOS
+
+ comment.force_encoding Encoding::IBM437
+
+ comment.remove_private
+
+ assert_equal Encoding::IBM437, comment.text.encoding
+ end
+
+end
+
diff --git a/test/rdoc/test_rdoc_constant.rb b/test/rdoc/test_rdoc_constant.rb
index b915f5cc7a..1a2e43a6e4 100644
--- a/test/rdoc/test_rdoc_constant.rb
+++ b/test/rdoc/test_rdoc_constant.rb
@@ -8,6 +8,138 @@ class TestRDocConstant < XrefTestCase
@const = @c1.constants.first
end
+ def test_full_name
+ assert_equal 'C1::CONST', @const.full_name
+ end
+
+ def test_is_alias_for
+ top_level = @store.add_file 'file.rb'
+
+ c = RDoc::Constant.new 'CONST', nil, 'comment'
+ top_level.add_constant c
+
+ assert_nil c.is_alias_for
+
+ c.is_alias_for = 'C1'
+
+ assert_equal @c1, c.is_alias_for
+
+ c.is_alias_for = 'unknown'
+
+ assert_equal 'unknown', c.is_alias_for
+ end
+
+ def test_marshal_dump
+ top_level = @store.add_file 'file.rb'
+
+ c = RDoc::Constant.new 'CONST', nil, 'this is a comment'
+ c.record_location top_level
+
+ aliased = top_level.add_class RDoc::NormalClass, 'Aliased'
+ c.is_alias_for = aliased
+
+ cm = top_level.add_class RDoc::NormalClass, 'Klass'
+ cm.add_constant c
+
+ section = cm.sections.first
+
+ loaded = Marshal.load Marshal.dump c
+ loaded.store = @store
+
+ comment = doc(para('this is a comment'))
+
+ assert_equal c, loaded
+
+ assert_equal aliased, loaded.is_alias_for
+ assert_equal comment, loaded.comment
+ assert_equal top_level, loaded.file
+ assert_equal 'Klass::CONST', loaded.full_name
+ assert_equal 'CONST', loaded.name
+ assert_nil loaded.visibility
+ assert_equal cm, loaded.parent
+ assert_equal section, loaded.section
+ end
+
+ def test_marshal_load
+ top_level = @store.add_file 'file.rb'
+
+ c = RDoc::Constant.new 'CONST', nil, 'this is a comment'
+ c.record_location top_level
+
+ cm = top_level.add_class RDoc::NormalClass, 'Klass'
+ cm.add_constant c
+
+ section = cm.sections.first
+
+ loaded = Marshal.load Marshal.dump c
+ loaded.store = @store
+
+ comment = doc(para('this is a comment'))
+
+ assert_equal c, loaded
+
+ assert_nil loaded.is_alias_for
+ assert_equal comment, loaded.comment
+ assert_equal top_level, loaded.file
+ assert_equal 'Klass::CONST', loaded.full_name
+ assert_equal 'CONST', loaded.name
+ assert_nil loaded.visibility
+ assert_equal cm, loaded.parent
+ assert_equal section, loaded.section
+ end
+
+ def test_marshal_load_version_0
+ top_level = @store.add_file 'file.rb'
+
+ aliased = top_level.add_class RDoc::NormalClass, 'Aliased'
+ cm = top_level.add_class RDoc::NormalClass, 'Klass'
+ section = cm.sections.first
+
+ loaded = Marshal.load "\x04\bU:\x13RDoc::Constant[\x0Fi\x00I" +
+ "\"\nCONST\x06:\x06ETI\"\x11Klass::CONST\x06" +
+ ";\x06T0I\"\fAliased\x06;\x06To" +
+ ":\eRDoc::Markup::Document\a:\v@parts[\x06o" +
+ ":\x1CRDoc::Markup::Paragraph\x06;\b[\x06I" +
+ "\"\x16this is a comment\x06;\x06T:\n@file0I" +
+ "\"\ffile.rb\x06;\x06TI\"\nKlass\x06" +
+ ";\x06Tc\x16RDoc::NormalClass0"
+
+ loaded.store = @store
+
+ comment = doc(para('this is a comment'))
+
+ assert_equal aliased, loaded.is_alias_for
+ assert_equal comment, loaded.comment
+ assert_equal top_level, loaded.file
+ assert_equal 'Klass::CONST', loaded.full_name
+ assert_equal 'CONST', loaded.name
+ assert_nil loaded.visibility
+ assert_equal cm, loaded.parent
+ assert_equal section, loaded.section
+ end
+
+ def test_marshal_round_trip
+ top_level = @store.add_file 'file.rb'
+
+ c = RDoc::Constant.new 'CONST', nil, 'this is a comment'
+ c.record_location top_level
+ c.is_alias_for = 'Unknown'
+
+ cm = top_level.add_class RDoc::NormalClass, 'Klass'
+ cm.add_constant c
+
+ section = cm.sections.first
+
+ loaded = Marshal.load Marshal.dump c
+ loaded.store = @store
+
+ reloaded = Marshal.load Marshal.dump loaded
+ reloaded.store = @store
+
+ assert_equal section, reloaded.section
+ assert_equal 'Unknown', reloaded.is_alias_for
+ end
+
def test_path
assert_equal 'C1.html#CONST', @const.path
end
diff --git a/test/rdoc/test_rdoc_context.rb b/test/rdoc/test_rdoc_context.rb
index 2fb8ef7bb7..bd0baaa725 100644
--- a/test/rdoc/test_rdoc_context.rb
+++ b/test/rdoc/test_rdoc_context.rb
@@ -1,5 +1,3 @@
-require 'rubygems'
-require 'minitest/autorun'
require File.expand_path '../xref_test_case', __FILE__
class TestRDocContext < XrefTestCase
@@ -8,6 +6,10 @@ class TestRDocContext < XrefTestCase
super
@context = RDoc::Context.new
+ @context.store = @store
+
+ @enumerator = # 1.8 vs 1.9
+ Object.const_defined?(:Enumerator) ? Enumerator : Enumerable::Enumerator
end
def test_initialize
@@ -40,7 +42,7 @@ class TestRDocContext < XrefTestCase
end
def test_add_alias_method_attr
- top_level = RDoc::TopLevel.new 'file.rb'
+ top_level = @store.add_file 'file.rb'
attr = RDoc::Attr.new nil, 'old_name', 'R', ''
@@ -60,7 +62,7 @@ class TestRDocContext < XrefTestCase
end
def test_add_alias_method
- top_level = RDoc::TopLevel.new 'file.rb'
+ top_level = @store.add_file 'file.rb'
meth = RDoc::AnyMethod.new nil, 'old_name'
meth.singleton = false
@@ -103,7 +105,7 @@ class TestRDocContext < XrefTestCase
@c1.add_class RDoc::NormalClass, 'Klass', 'Object'
assert_includes @c1.classes.map { |k| k.full_name }, 'C1::Klass'
- assert_includes RDoc::TopLevel.classes.map { |k| k.full_name }, 'C1::Klass'
+ assert_includes @store.all_classes.map { |k| k.full_name }, 'C1::Klass'
end
def test_add_class_basic_object
@@ -142,7 +144,7 @@ class TestRDocContext < XrefTestCase
@c1.add_class RDoc::NormalClass, 'Klass', 'Object'
assert_includes @c1.classes.map { |k| k.full_name }, 'C1::Klass'
- assert_includes RDoc::TopLevel.classes.map { |k| k.full_name }, 'C1::Klass'
+ assert_includes @store.all_classes.map { |k| k.full_name }, 'C1::Klass'
end
def test_add_class_superclass
@@ -163,9 +165,9 @@ class TestRDocContext < XrefTestCase
refute_includes @c1.modules.map { |k| k.full_name }, 'C1::Klass',
'c1 modules'
- assert_includes RDoc::TopLevel.classes.map { |k| k.full_name }, 'C1::Klass',
+ assert_includes @store.all_classes.map { |k| k.full_name }, 'C1::Klass',
'TopLevel classes'
- refute_includes RDoc::TopLevel.modules.map { |k| k.full_name }, 'C1::Klass',
+ refute_includes @store.all_modules.map { |k| k.full_name }, 'C1::Klass',
'TopLevel modules'
end
@@ -176,6 +178,13 @@ class TestRDocContext < XrefTestCase
assert_equal [const], @context.constants
end
+ def test_add_extend
+ ext = RDoc::Extend.new 'Name', 'comment'
+ @context.add_extend ext
+
+ assert_equal [ext], @context.extends
+ end
+
def test_add_include
incl = RDoc::Include.new 'Name', 'comment'
@context.add_include incl
@@ -183,16 +192,6 @@ class TestRDocContext < XrefTestCase
assert_equal [incl], @context.includes
end
- def test_add_include_twice
- incl1 = RDoc::Include.new 'Name', 'comment'
- @context.add_include incl1
-
- incl2 = RDoc::Include.new 'Name', 'comment'
- @context.add_include incl2
-
- assert_equal [incl1], @context.includes
- end
-
def test_add_method
meth = RDoc::AnyMethod.new nil, 'old_name'
meth.visibility = nil
@@ -217,6 +216,34 @@ class TestRDocContext < XrefTestCase
assert_equal %w[old_name new_name], @context.method_list.map { |m| m.name }
end
+ def test_add_method_duplicate
+ @store.rdoc.options.verbosity = 2
+
+ meth1 = RDoc::AnyMethod.new nil, 'name'
+ meth1.record_location @store.add_file 'first.rb'
+ meth1.visibility = nil
+ meth1.comment = comment 'first'
+
+ @context.add_method meth1
+
+ meth2 = RDoc::AnyMethod.new nil, 'name'
+ meth2.record_location @store.add_file 'second.rb'
+ meth2.comment = comment 'second'
+
+ _, err = capture_io do
+ @context.add_method meth2
+ end
+
+ expected = 'Duplicate method (unknown)#name in file second.rb, ' \
+ 'previously in file first.rb'
+
+ assert_equal expected, err.chomp
+
+ method = @context.method_list.first
+
+ assert_equal 'first', method.comment.text
+ end
+
def test_add_module
@c1.add_module RDoc::NormalModule, 'Mod'
@@ -224,18 +251,35 @@ class TestRDocContext < XrefTestCase
end
def test_add_module_alias
- tl = RDoc::TopLevel.new 'file.rb'
+ tl = @store.add_file 'file.rb'
c3_c4 = @c2.add_module_alias @c2_c3, 'C4', tl
- c4 = @c2.find_module_named('C4')
-
alias_constant = @c2.constants.first
- assert_equal c4, c3_c4
+ assert_equal 'C2::C4', c3_c4.full_name
assert_equal tl, alias_constant.file
end
+ def test_add_module_alias_top_level
+ store = RDoc::Store.new
+
+ top_level = store.add_file 'file.rb'
+
+ klass = top_level.add_class RDoc::NormalClass, 'Klass'
+ klass.comment = 'klass comment'
+
+ object = top_level.add_class RDoc::NormalClass, 'Object'
+
+ top_level.add_module_alias klass, 'A', top_level
+
+ refute_empty object.constants
+
+ constant = object.constants.first
+
+ assert_equal 'klass comment', constant.comment
+ end
+
def test_add_module_class
k = @c1.add_class RDoc::NormalClass, 'Klass', nil
m = @c1.add_module RDoc::NormalModule, 'Klass'
@@ -255,18 +299,20 @@ class TestRDocContext < XrefTestCase
def test_add_section
default_section = @context.sections.first
- @context.add_section nil, '# comment'
+ @context.add_section nil, comment('comment', @top_level)
assert_equal 1, @context.sections.length
- assert_equal '# comment', @context.sections.first.comment
+ assert_equal [comment("comment", @top_level)],
+ @context.sections.first.comments
- @context.add_section nil, '# new comment'
+ @context.add_section nil, comment('new comment', @top_level)
assert_equal 1, @context.sections.length
- assert_equal "# comment\n# ---\n# new comment",
- @context.sections.first.comment
+ assert_equal [comment('comment', @top_level),
+ comment('new comment', @top_level)],
+ @context.sections.first.comments
- @context.add_section 'other', ''
+ @context.add_section 'other', comment('', @top_level)
assert_equal 2, @context.sections.length
@@ -275,6 +321,23 @@ class TestRDocContext < XrefTestCase
assert_equal default_section, @context.current_section
end
+ def test_add_section_no_comment
+ default_section = @context.sections.first
+
+ @context.add_section nil
+
+ assert_equal 1, @context.sections.length
+
+ @context.add_section 'other'
+
+ assert_equal 2, @context.sections.length
+
+ new_section = @context.sections.find { |section| section.title == 'other' }
+
+ assert new_section
+ assert_equal default_section, @context.current_section
+ end
+
def test_add_to
incl = RDoc::Include.new 'Name', 'comment'
arr = []
@@ -288,7 +351,8 @@ class TestRDocContext < XrefTestCase
def test_add_to_temporary_section
incl = RDoc::Include.new 'Name', 'comment'
arr = []
- section = @context.add_section 'temporary', ''
+ section =
+ @context.add_section 'temporary', RDoc::Comment.new('', @top_level)
@context.temporary_section = section
@context.add_to arr, incl
@@ -316,19 +380,30 @@ class TestRDocContext < XrefTestCase
refute_includes arr, incl
end
+ def bench_add_include
+ cm = RDoc::ClassModule.new 'Klass'
+
+ assert_performance_linear 0.9 do |count|
+ count.times do |i|
+ cm.add_include RDoc::Include.new("N::M#{i}", nil)
+ end
+ end
+ end
+
def test_child_name
assert_equal 'C1::C1', @c1.child_name('C1')
end
def test_classes
assert_equal %w[C2::C3], @c2.classes.map { |k| k.full_name }
- assert_equal %w[C3::H1 C3::H2], @c3.classes.map { |k| k.full_name }
+ assert_equal %w[C3::H1 C3::H2], @c3.classes.map { |k| k.full_name }.sort
end
def test_current_section
default_section = @context.current_section
- new_section = @context.add_section 'other', ''
+ new_section =
+ @context.add_section 'other', RDoc::Comment.new('', @top_level)
@context.temporary_section = new_section
assert_equal new_section, @context.current_section
@@ -338,7 +413,7 @@ class TestRDocContext < XrefTestCase
def test_defined_in_eh
assert @c1.defined_in?(@c1.top_level)
- refute @c1.defined_in?(RDoc::TopLevel.new('name.rb'))
+ refute @c1.defined_in?(@store.add_file('name.rb'))
end
def test_equals2
@@ -347,6 +422,10 @@ class TestRDocContext < XrefTestCase
refute_equal @c2_c3, @c3
end
+ def test_each_method_enumerator
+ assert_kind_of @enumerator, @c1.each_method
+ end
+
def test_each_section
sects = []
consts = []
@@ -375,6 +454,10 @@ class TestRDocContext < XrefTestCase
assert_equal expected_attrs, attrs
end
+ def test_each_section_enumerator
+ assert_kind_of @enumerator, @c1.each_section
+ end
+
def test_find_attribute_named
assert_equal nil, @c1.find_attribute_named('none')
assert_equal 'R', @c1.find_attribute_named('attr').rw
@@ -448,6 +531,16 @@ class TestRDocContext < XrefTestCase
assert_equal @c1__m, @c1.find_symbol('::m')
end
+ def test_find_symbol_module
+ assert_nil @m1_m2.find_symbol_module 'N'
+ assert_nil @m1_m2.find_symbol_module 'M2::M1'
+
+ @m1_m2.parent = nil # loaded from legacy ri store
+
+ assert_nil @m1_m2.find_symbol_module 'N'
+ assert_nil @m1_m2.find_symbol_module 'M2::M1'
+ end
+
def test_fully_documented_eh
context = RDoc::Context.new
@@ -650,14 +743,51 @@ class TestRDocContext < XrefTestCase
assert_equal [@pub, @prot, @priv], methods
end
+ def test_section_contents
+ default = @context.sections.first
+ @context.add_method RDoc::AnyMethod.new(nil, 'm1')
+
+ b = @context.add_section 'B'
+ m = @context.add_method RDoc::AnyMethod.new(nil, 'm2')
+ m.section = b
+
+ assert_equal [default, b], @context.section_contents
+ end
+
+ def test_section_contents_no_default
+ @context = RDoc::Context.new
+ b = @context.add_section 'B'
+ m = @context.add_method RDoc::AnyMethod.new(nil, 'm')
+ m.section = b
+
+ assert_equal [b], @context.section_contents
+ end
+
+ def test_section_contents_only_default
+ @context = RDoc::Context.new
+
+ @context.add_method RDoc::AnyMethod.new(nil, 'm')
+
+ assert_empty @context.section_contents
+ end
+
+ def test_section_contents_unused
+ @context = RDoc::Context.new
+
+ @context.add_method RDoc::AnyMethod.new(nil, 'm')
+ @context.add_section 'B'
+
+ assert_empty @context.section_contents
+ end
+
def test_set_current_section
default_section = @context.sections.first
- @context.set_current_section nil, ''
+ @context.set_current_section nil, RDoc::Comment.new('', @top_level)
assert_equal default_section, @context.current_section
- @context.set_current_section 'other', ''
+ @context.set_current_section 'other', RDoc::Comment.new('', @top_level)
new_section = @context.sections.find { |section|
section != default_section
@@ -666,6 +796,38 @@ class TestRDocContext < XrefTestCase
assert_equal new_section, @context.current_section
end
+ def test_sort_sections
+ c = RDoc::Context.new
+ c.add_section 'C'
+ c.add_section 'A'
+ c.add_section 'B'
+
+ titles = c.sort_sections.map { |section| section.title }
+
+ assert_equal [nil, 'A', 'B', 'C'], titles
+ end
+
+ def test_sort_sections_tomdoc
+ c = RDoc::Context.new
+ c.add_section 'Public'
+ c.add_section 'Internal'
+ c.add_section 'Deprecated'
+
+ titles = c.sort_sections.map { |section| section.title }
+
+ assert_equal [nil, 'Public', 'Internal', 'Deprecated'], titles
+ end
+
+ def test_sort_sections_tomdoc_missing
+ c = RDoc::Context.new
+ c.add_section 'Internal'
+ c.add_section 'Public'
+
+ titles = c.sort_sections.map { |section| section.title }
+
+ assert_equal [nil, 'Public', 'Internal'], titles
+ end
+
def util_visibilities
@pub = RDoc::AnyMethod.new nil, 'pub'
@prot = RDoc::AnyMethod.new nil, 'prot'
diff --git a/test/rdoc/test_rdoc_context_section.rb b/test/rdoc/test_rdoc_context_section.rb
index d37a4d222e..716d3ae6bb 100644
--- a/test/rdoc/test_rdoc_context_section.rb
+++ b/test/rdoc/test_rdoc_context_section.rb
@@ -1,14 +1,49 @@
-require 'rubygems'
-require 'cgi'
-require 'minitest/autorun'
-require 'rdoc'
-require 'rdoc/code_objects'
+require 'rdoc/test_case'
-class TestRDocContextSection < MiniTest::Unit::TestCase
+class TestRDocContextSection < RDoc::TestCase
def setup
+ super
+
+ @top_level = @store.add_file 'file.rb'
+
+ @klass = @top_level.add_class RDoc::NormalClass, 'Object'
+
@S = RDoc::Context::Section
- @s = @S.new nil, 'section', '# comment'
+ @s = @S.new @klass, 'section', comment('# comment', @top_level)
+ end
+
+ def mu_pp obj
+ s = ''
+ s = PP.pp obj, s
+ s.force_encoding Encoding.default_external if defined? Encoding
+ s.chomp
+ end
+
+ def test_add_comment
+ file1 = @store.add_file 'file1.rb'
+
+ klass = file1.add_class RDoc::NormalClass, 'Klass'
+
+ c1 = RDoc::Comment.new "# :section: section\n", file1
+ c2 = RDoc::Comment.new "# hello\n", file1
+ c3 = RDoc::Comment.new "# world\n", file1
+
+ s = @S.new klass, 'section', c1
+
+ assert_empty s.comments
+
+ s.add_comment nil
+
+ assert_empty s.comments
+
+ s.add_comment c2
+
+ assert_equal [c2], s.comments
+
+ s.add_comment c3
+
+ assert_equal [c2, c3], s.comments
end
def test_aref
@@ -19,27 +54,75 @@ class TestRDocContextSection < MiniTest::Unit::TestCase
assert_equal 'one+two', @S.new(nil, 'one two', nil).aref
end
- def test_comment_equals
- @s.comment = "# :section: section\n"
+ def test_extract_comment
+ assert_equal '', @s.extract_comment(comment('')).text
+ assert_equal '', @s.extract_comment(comment("# :section: b\n")).text
+ assert_equal '# c', @s.extract_comment(comment("# :section: b\n# c")).text
+ assert_equal '# c',
+ @s.extract_comment(comment("# a\n# :section: b\n# c")).text
+ end
+
+ def test_marshal_dump
+ loaded = Marshal.load Marshal.dump @s
- assert_equal "# comment", @s.comment
+ expected = RDoc::Comment.new('comment', @top_level).parse
+ expected = doc(expected)
- @s.comment = "# :section: section\n# other"
+ assert_equal 'section', loaded.title
+ assert_equal expected, loaded.comments
+ assert_nil loaded.parent, 'parent is set manually'
+ end
- assert_equal "# comment\n# ---\n# other", @s.comment
+ def test_marshal_dump_no_comment
+ s = @S.new @klass, 'section', comment('')
- s = @S.new nil, nil, nil
+ loaded = Marshal.load Marshal.dump s
+
+ assert_equal 'section', loaded.title
+ assert_empty loaded.comments
+ assert_nil loaded.parent, 'parent is set manually'
+ end
- s.comment = "# :section:\n# other"
+ def test_marshal_load_version_0
+ loaded = Marshal.load "\x04\bU:\eRDoc::Context::Section" +
+ "[\bi\x00I\"\fsection\x06:\x06EFo" +
+ ":\eRDoc::Markup::Document\a:\v@parts" +
+ "[\x06o;\a\a;\b[\x06o" +
+ ":\x1CRDoc::Markup::Paragraph\x06;\b" +
+ "[\x06I\"\fcomment\x06;\x06F:\n@fileI" +
+ "\"\ffile.rb\x06;\x06F;\n0"
- assert_equal "# other", s.comment
+ expected = doc RDoc::Comment.new('comment', @top_level).parse
+
+ assert_equal 'section', loaded.title
+ assert_equal expected, loaded.comments
+ assert_nil loaded.parent, 'parent is set manually'
end
- def test_extract_comment
- assert_equal '', @s.extract_comment('')
- assert_equal '', @s.extract_comment("# :section: b\n")
- assert_equal '# c', @s.extract_comment("# :section: b\n# c")
- assert_equal '# c', @s.extract_comment("# a\n# :section: b\n# c")
+ def test_remove_comment_array
+ other = @store.add_file 'other.rb'
+
+ other_comment = comment('bogus', other)
+
+ @s.add_comment other_comment
+
+ @s.remove_comment comment('bogus', @top_level)
+
+ assert_equal [other_comment], @s.comments
+ end
+
+ def test_remove_comment_document
+ other = @store.add_file 'other.rb'
+
+ other_comment = comment('bogus', other)
+
+ @s.add_comment other_comment
+
+ loaded = Marshal.load Marshal.dump @s
+
+ loaded.remove_comment comment('bogus', @top_level)
+
+ assert_equal doc(other_comment.parse), loaded.comments
end
def test_sequence
diff --git a/test/rdoc/test_rdoc_cross_reference.rb b/test/rdoc/test_rdoc_cross_reference.rb
index 06062ba125..45afd80d31 100644
--- a/test/rdoc/test_rdoc_cross_reference.rb
+++ b/test/rdoc/test_rdoc_cross_reference.rb
@@ -1,5 +1,3 @@
-require 'rubygems'
-require 'minitest/autorun'
require File.expand_path '../xref_test_case', __FILE__
class TestRDocCrossReference < XrefTestCase
@@ -95,7 +93,7 @@ class TestRDocCrossReference < XrefTestCase
end
def test_resolve_file
- assert_ref @xref_data, 'xref_data.rb'
+ refute_ref 'xref_data.rb'
end
def test_resolve_method
@@ -131,6 +129,30 @@ class TestRDocCrossReference < XrefTestCase
assert_ref @c2_c3_m, '::C2::C3#m(*)'
end
+ def test_resolve_page
+ page = @store.add_file 'README.txt'
+ page.parser = RDoc::Parser::Simple
+
+ assert_ref page, 'README'
+ end
+
+ def test_resolve_percent
+ i_percent = RDoc::AnyMethod.new nil, '%'
+ i_percent.singleton = false
+ @c1.add_method i_percent
+
+ c_percent = RDoc::AnyMethod.new nil, '%'
+ c_percent.singleton = true
+ @c1.add_method c_percent
+
+ assert_ref i_percent, '%'
+ assert_ref i_percent, '#%'
+ assert_ref c_percent, '::%'
+
+ assert_ref i_percent, 'C1#%'
+ assert_ref c_percent, 'C1::%'
+ end
+
def test_resolve_no_ref
assert_equal '', @xref.resolve('', '')
diff --git a/test/rdoc/test_rdoc_encoding.rb b/test/rdoc/test_rdoc_encoding.rb
index b5ffd7714c..d43bc2e244 100644
--- a/test/rdoc/test_rdoc_encoding.rb
+++ b/test/rdoc/test_rdoc_encoding.rb
@@ -1,15 +1,12 @@
# coding: US-ASCII
-require 'rubygems'
-require 'minitest/autorun'
-require 'rdoc'
-require 'rdoc/encoding'
+require 'rdoc/test_case'
-require 'tempfile'
-
-class TestRDocEncoding < MiniTest::Unit::TestCase
+class TestRDocEncoding < RDoc::TestCase
def setup
+ super
+
@tempfile = Tempfile.new 'test_rdoc_encoding'
end
@@ -100,6 +97,22 @@ class TestRDocEncoding < MiniTest::Unit::TestCase
assert_equal Encoding::UTF_8, content.encoding
end
+ def test_class_read_file_encoding_invalid
+ skip "Encoding not implemented" unless Object.const_defined? :Encoding
+
+ @tempfile.write "# coding: ascii\nM\xE4r"
+ @tempfile.flush
+
+ contents = :junk
+ _, err = capture_io do
+ contents = RDoc::Encoding.read_file @tempfile.path, Encoding::UTF_8
+ end
+
+ assert_equal "unable to convert \"\\xE4\" on US-ASCII for #{@tempfile.path}, skipping\n", err
+
+ assert_nil contents
+ end
+
def test_class_read_file_encoding_with_signature
skip "Encoding not implemented" unless defined? ::Encoding
diff --git a/test/rdoc/test_rdoc_extend.rb b/test/rdoc/test_rdoc_extend.rb
new file mode 100644
index 0000000000..149931549d
--- /dev/null
+++ b/test/rdoc/test_rdoc_extend.rb
@@ -0,0 +1,94 @@
+require File.expand_path '../xref_test_case', __FILE__
+
+class TestRDocExtend < XrefTestCase
+
+ def setup
+ super
+
+ @ext = RDoc::Extend.new 'M1', 'comment'
+ @ext.parent = @m1
+ @ext.store = @store
+ end
+
+ def test_module
+ assert_equal @m1, @ext.module
+ assert_equal 'Unknown', RDoc::Extend.new('Unknown', 'comment').module
+ end
+
+ def test_module_extended
+ m1 = @xref_data.add_module RDoc::NormalModule, 'Mod1'
+ m1.add_module RDoc::NormalModule, 'Mod3'
+ m1_m2 = m1.add_module RDoc::NormalModule, 'Mod2'
+ m1_m2_m3 = m1_m2.add_module RDoc::NormalModule, 'Mod3'
+ m1_m2_m3.add_module RDoc::NormalModule, 'Mod4'
+ m1_m2.add_module RDoc::NormalModule, 'Mod4'
+ m1_m2_k0 = m1_m2.add_class RDoc::NormalClass, 'Klass0'
+ m1_m2_k0_m4 = m1_m2_k0.add_module RDoc::NormalModule, 'Mod4'
+ m1_m2_k0_m4.add_module RDoc::NormalModule, 'Mod6'
+ m1_m2_k0.add_module RDoc::NormalModule, 'Mod5'
+
+ e0_m4 = RDoc::Extend.new 'Mod4', nil
+ e0_m5 = RDoc::Extend.new 'Mod5', nil
+ e0_m6 = RDoc::Extend.new 'Mod6', nil
+ e0_m1 = RDoc::Extend.new 'Mod1', nil
+ e0_m2 = RDoc::Extend.new 'Mod2', nil
+ e0_m3 = RDoc::Extend.new 'Mod3', nil
+
+ m1_m2_k0.add_extend e0_m4
+ m1_m2_k0.add_extend e0_m5
+ m1_m2_k0.add_extend e0_m6
+ m1_m2_k0.add_extend e0_m1
+ m1_m2_k0.add_extend e0_m2
+ m1_m2_k0.add_extend e0_m3
+
+ assert_equal [e0_m4, e0_m5, e0_m6, e0_m1, e0_m2, e0_m3], m1_m2_k0.extends
+ assert_equal ['Object'], m1_m2_k0.ancestors
+
+ m1_k1 = m1.add_class RDoc::NormalClass, 'Klass1'
+
+ e1_m1 = RDoc::Extend.new 'Mod1', nil
+ e1_m2 = RDoc::Extend.new 'Mod2', nil
+ e1_m3 = RDoc::Extend.new 'Mod3', nil
+ e1_m4 = RDoc::Extend.new 'Mod4', nil
+ e1_k0_m4 = RDoc::Extend.new 'Klass0::Mod4', nil
+
+ m1_k1.add_extend e1_m1
+ m1_k1.add_extend e1_m2
+ m1_k1.add_extend e1_m3
+ m1_k1.add_extend e1_m4
+ m1_k1.add_extend e1_k0_m4
+
+ assert_equal [e1_m1, e1_m2, e1_m3, e1_m4, e1_k0_m4], m1_k1.extends
+ assert_equal ['Object'], m1_k1.ancestors
+
+ m1_k2 = m1.add_class RDoc::NormalClass, 'Klass2'
+
+ e2_m1 = RDoc::Extend.new 'Mod1', nil
+ e2_m2 = RDoc::Extend.new 'Mod2', nil
+ e2_m3 = RDoc::Extend.new 'Mod3', nil
+ e2_k0_m4 = RDoc::Extend.new 'Klass0::Mod4', nil
+
+ m1_k2.add_extend e2_m1
+ m1_k2.add_extend e2_m3
+ m1_k2.add_extend e2_m2
+ m1_k2.add_extend e2_k0_m4
+
+ assert_equal [e2_m1, e2_m3, e2_m2, e2_k0_m4], m1_k2.extends
+ assert_equal ['Object'], m1_k2.ancestors
+
+ m1_k3 = m1.add_class RDoc::NormalClass, 'Klass3'
+
+ e3_m1 = RDoc::Extend.new 'Mod1', nil
+ e3_m2 = RDoc::Extend.new 'Mod2', nil
+ e3_m4 = RDoc::Extend.new 'Mod4', nil
+
+ m1_k3.add_extend e3_m1
+ m1_k3.add_extend e3_m2
+ m1_k3.add_extend e3_m4
+
+ assert_equal [e3_m1, e3_m2, e3_m4], m1_k3.extends
+ assert_equal ['Object'], m1_k3.ancestors
+ end
+
+end
+
diff --git a/test/rdoc/test_rdoc_generator_darkfish.rb b/test/rdoc/test_rdoc_generator_darkfish.rb
index faea1ae34a..d1c2f66665 100644
--- a/test/rdoc/test_rdoc_generator_darkfish.rb
+++ b/test/rdoc/test_rdoc_generator_darkfish.rb
@@ -1,16 +1,12 @@
-require 'minitest/autorun'
-require 'rdoc/rdoc'
-require 'rdoc/generator/darkfish'
-require 'tmpdir'
-require 'fileutils'
+require 'rdoc/test_case'
-class TestRDocGeneratorDarkfish < MiniTest::Unit::TestCase
+class TestRDocGeneratorDarkfish < RDoc::TestCase
def setup
- @pwd = Dir.pwd
+ super
+
@lib_dir = "#{@pwd}/lib"
$LOAD_PATH.unshift @lib_dir # ensure we load from this RDoc
- RDoc::TopLevel.reset
@options = RDoc::Options.new
@options.option_parser = OptionParser.new
@@ -22,22 +18,27 @@ class TestRDocGeneratorDarkfish < MiniTest::Unit::TestCase
@options.generator = RDoc::Generator::Darkfish
$LOAD_PATH.each do |path|
- darkfish_dir = File.join path, 'rdoc/generator/template/darkfish'
+ darkfish_dir = File.join path, 'rdoc/generator/template/darkfish/'
next unless File.directory? darkfish_dir
@options.template_dir = darkfish_dir
break
end
- rd = RDoc::RDoc.new
- rd.options = @options
- RDoc::RDoc.current = rd
+ @rdoc.options = @options
+
+ @g = @options.generator.new @store, @options
+ @rdoc.generator = @g
+
+ @top_level = @store.add_file 'file.rb'
+ @top_level.parser = RDoc::Parser::Ruby
+ @klass = @top_level.add_class RDoc::NormalClass, 'Klass'
- @g = @options.generator.new @options
+ @alias_constant = RDoc::Constant.new 'A', nil, ''
+ @alias_constant.record_location @top_level
- rd.generator = @g
+ @top_level.add_constant @alias_constant
- @top_level = RDoc::TopLevel.new 'file.rb'
- @klass = @top_level.add_class RDoc::NormalClass, 'Object'
+ @klass.add_module_alias @klass, 'A', @top_level
@meth = RDoc::AnyMethod.new nil, 'method'
@meth_bang = RDoc::AnyMethod.new nil, 'method!'
@@ -49,9 +50,16 @@ class TestRDocGeneratorDarkfish < MiniTest::Unit::TestCase
@ignored = @top_level.add_class RDoc::NormalClass, 'Ignored'
@ignored.ignore
+
+ @store.complete :private
+
+ @object = @store.find_class_or_module 'Object'
+ @klass_alias = @store.find_class_or_module 'Klass::A'
end
def teardown
+ super
+
$LOAD_PATH.shift
Dir.chdir @pwd
FileUtils.rm_rf @tmpdir
@@ -65,15 +73,23 @@ class TestRDocGeneratorDarkfish < MiniTest::Unit::TestCase
refute File.exist?(path), "#{path} exists"
end
+ def mu_pp obj
+ s = ''
+ s = PP.pp obj, s
+ s = s.force_encoding Encoding.default_external if defined? Encoding
+ s.chomp
+ end
+
def test_generate
- top_level = RDoc::TopLevel.new 'file.rb'
+ top_level = @store.add_file 'file.rb'
top_level.add_class @klass.class, @klass.name
- @g.generate [top_level]
+ @g.generate
assert_file 'index.html'
assert_file 'Object.html'
- assert_file 'file_rb.html'
+ assert_file 'table_of_contents.html'
+ assert_file 'js/search_index.js'
encoding = if Object.const_defined? :Encoding then
Regexp.escape Encoding.default_external.name
@@ -85,37 +101,73 @@ class TestRDocGeneratorDarkfish < MiniTest::Unit::TestCase
File.read('index.html'))
assert_match(/<meta content="text\/html; charset=#{encoding}"/,
File.read('Object.html'))
- assert_match(/<meta content="text\/html; charset=#{encoding}"/,
- File.read('file_rb.html'))
refute_match(/Ignored/, File.read('index.html'))
end
def test_generate_dry_run
- @options.dry_run = true
- top_level = RDoc::TopLevel.new 'file.rb'
+ @g.dry_run = true
+ top_level = @store.add_file 'file.rb'
top_level.add_class @klass.class, @klass.name
- @g.generate [top_level]
+ @g.generate
refute_file 'index.html'
refute_file 'Object.html'
- refute_file 'file_rb.html'
+ end
+
+ def test_generate_static
+ FileUtils.mkdir_p 'dir/images'
+ FileUtils.touch 'dir/images/image.png'
+ FileUtils.mkdir_p 'file'
+ FileUtils.touch 'file/file.txt'
+
+ @options.static_path = [
+ File.expand_path('dir'),
+ File.expand_path('file/file.txt'),
+ ]
+
+ @g.generate
+
+ assert_file 'images/image.png'
+ assert_file 'file.txt'
+ end
+
+ def test_generate_static_dry_run
+ FileUtils.mkdir 'static'
+ FileUtils.touch 'static/image.png'
+
+ @options.static_path = [File.expand_path('static')]
+ @g.dry_run = true
+
+ @g.generate
+
+ refute_file 'image.png'
+ end
+
+ def test_setup
+ @g.setup
+
+ assert_equal [@klass_alias, @ignored, @klass, @object],
+ @g.classes.sort_by { |klass| klass.full_name }
+ assert_equal [@top_level], @g.files
+ assert_equal [@meth, @meth, @meth_bang, @meth_bang], @g.methods
+ assert_equal [@klass_alias, @klass, @object], @g.modsort
end
def test_template_for
- classpage = Pathname.new @options.template_dir + '/classpage.rhtml'
+ classpage = Pathname.new @options.template_dir + 'class.rhtml'
- template = @g.send(:template_for, classpage)
+ template = @g.send(:template_for, classpage, true, RDoc::ERBIO)
assert_kind_of RDoc::ERBIO, template
assert_same template, @g.send(:template_for, classpage)
end
def test_template_for_dry_run
- classpage = Pathname.new @options.template_dir + '/classpage.rhtml'
+ classpage = Pathname.new @options.template_dir + 'class.rhtml'
- template = @g.send(:template_for, classpage)
+ template = @g.send(:template_for, classpage, true, ERB)
assert_kind_of ERB, template
assert_same template, @g.send(:template_for, classpage)
diff --git a/test/rdoc/test_rdoc_generator_json_index.rb b/test/rdoc/test_rdoc_generator_json_index.rb
new file mode 100644
index 0000000000..717159eeda
--- /dev/null
+++ b/test/rdoc/test_rdoc_generator_json_index.rb
@@ -0,0 +1,275 @@
+# coding: US-ASCII
+
+require 'rdoc/test_case'
+
+class TestRDocGeneratorJsonIndex < RDoc::TestCase
+
+ def setup
+ super
+
+ @tmpdir = File.join Dir.tmpdir, "test_rdoc_generator_darkfish_#{$$}"
+ FileUtils.mkdir_p @tmpdir
+
+ @options = RDoc::Options.new
+ @options.files = []
+ # JsonIndex is used in conjunction with another generator
+ @options.setup_generator 'darkfish'
+ @options.template_dir = ''
+ @options.op_dir = @tmpdir
+ @options.option_parser = OptionParser.new
+ @options.finish
+
+ @darkfish = RDoc::Generator::Darkfish.new @store, @options
+ @g = RDoc::Generator::JsonIndex.new @darkfish, @options
+
+ @rdoc.options = @options
+ @rdoc.generator = @g
+
+ @top_level = @store.add_file 'file.rb'
+ @top_level.parser = RDoc::Parser::Ruby
+
+ @klass = @top_level.add_class RDoc::NormalClass, 'C'
+
+ @meth = @klass.add_method RDoc::AnyMethod.new(nil, 'meth')
+ @meth.record_location @top_level
+
+ @nest_klass = @klass.add_class RDoc::NormalClass, 'D'
+ @nest_klass.record_location @top_level
+
+ @nest_meth = @nest_klass.add_method RDoc::AnyMethod.new(nil, 'meth')
+
+ @ignored = @top_level.add_class RDoc::NormalClass, 'Ignored'
+ @ignored.ignore
+
+ @page = @store.add_file 'page.rdoc'
+ @page.parser = RDoc::Parser::Simple
+
+ @top_levels = [@top_level, @page].sort
+ @klasses = [@klass, @nest_klass, @ignored]
+
+ Dir.chdir @tmpdir
+ end
+
+ def teardown
+ super
+
+ Dir.chdir @pwd
+ FileUtils.rm_rf @tmpdir
+ end
+
+ def assert_file path
+ assert File.file?(path), "#{path} is not a file"
+ end
+
+ def mu_pp obj
+ s = ''
+ s = PP.pp obj, s
+ s = s.force_encoding Encoding.default_external if defined? Encoding
+ s.chomp
+ end
+
+ def test_build_index
+ index = @g.build_index
+
+ expected = {
+ :index => {
+ :searchIndex => %w[c d meth() meth() page],
+ :longSearchIndex => %w[c c::d c#meth() c::d#meth()],
+ :info => [
+ @klass.search_record[2..-1],
+ @nest_klass.search_record[2..-1],
+ @meth.search_record[2..-1],
+ @nest_meth.search_record[2..-1],
+ @page.search_record[2..-1],
+ ],
+ },
+ }
+
+ expected[:index][:longSearchIndex] << ''
+
+ assert_equal expected, index
+ end
+
+ def test_class_dir
+ assert_equal @darkfish.class_dir, @g.class_dir
+ end
+
+ def test_file_dir
+ assert_equal @darkfish.file_dir, @g.file_dir
+ end
+
+ def test_generate
+ @g.generate
+
+ assert_file 'js/searcher.js'
+ assert_file 'js/navigation.js'
+ assert_file 'js/search_index.js'
+
+ json = File.read 'js/search_index.js'
+
+ json =~ /\Avar search_data = /
+
+ assignment = $&
+ index = $'
+
+ refute_empty assignment
+
+ index = JSON.parse index
+
+ info = [
+ @klass.search_record[2..-1],
+ @nest_klass.search_record[2..-1],
+ @meth.search_record[2..-1],
+ @nest_meth.search_record[2..-1],
+ @page.search_record[2..-1],
+ ]
+
+ expected = {
+ 'index' => {
+ 'searchIndex' => [
+ 'c',
+ 'd',
+ 'meth()',
+ 'meth()',
+ 'page',
+ ],
+ 'longSearchIndex' => [
+ 'c',
+ 'c::d',
+ 'c#meth()',
+ 'c::d#meth()',
+ '',
+ ],
+ 'info' => info,
+ },
+ }
+
+ assert_equal expected, index
+ end
+
+ def test_generate_utf_8
+ skip "Encoding not implemented" unless Object.const_defined? :Encoding
+
+ text = "5\xB0"
+ text.force_encoding Encoding::ISO_8859_1
+ @klass.add_comment comment(text), @top_level
+
+ @g.generate
+
+ json = File.read 'js/search_index.js'
+ json.force_encoding Encoding::UTF_8
+
+ json =~ /\Avar search_data = /
+
+ index = $'
+
+ index = JSON.parse index
+
+ klass_record = @klass.search_record[2..-1]
+ klass_record[-1] = "<p>5\xc2\xb0\n"
+ klass_record.last.force_encoding Encoding::UTF_8
+
+ info = [
+ klass_record,
+ @nest_klass.search_record[2..-1],
+ @meth.search_record[2..-1],
+ @nest_meth.search_record[2..-1],
+ @page.search_record[2..-1],
+ ]
+
+ expected = {
+ 'index' => {
+ 'searchIndex' => [
+ 'c',
+ 'd',
+ 'meth()',
+ 'meth()',
+ 'page',
+ ],
+ 'longSearchIndex' => [
+ 'c',
+ 'c::d',
+ 'c#meth()',
+ 'c::d#meth()',
+ '',
+ ],
+ 'info' => info,
+ },
+ }
+
+ assert_equal expected, index
+ end
+
+ def test_index_classes
+ @g.reset @top_levels, @klasses
+
+ @g.index_classes
+
+ expected = {
+ :searchIndex => %w[c d],
+ :longSearchIndex => %w[c c::d],
+ :info => [
+ @klass.search_record[2..-1],
+ @nest_klass.search_record[2..-1],
+ ],
+ }
+
+ assert_equal expected, @g.index
+ end
+
+ def test_index_classes_nodoc
+ @klass.document_self = false
+ @nest_klass.document_self = false
+ @meth.document_self = false
+ @nest_meth.document_self = false
+
+ @g.reset @top_levels, @klasses
+
+ @g.index_classes
+
+ expected = {
+ :searchIndex => [],
+ :longSearchIndex => [],
+ :info => [],
+ }
+
+ assert_equal expected, @g.index
+ end
+
+ def test_index_methods
+ @g.reset @top_levels, @klasses
+
+ @g.index_methods
+
+ expected = {
+ :searchIndex => %w[meth() meth()],
+ :longSearchIndex => %w[c#meth() c::d#meth()],
+ :info => [
+ @meth.search_record[2..-1],
+ @nest_meth.search_record[2..-1],
+ ],
+ }
+
+ assert_equal expected, @g.index
+ end
+
+ def test_index_pages
+ @g.reset @top_levels, @klasses
+
+ @g.index_pages
+
+ expected = {
+ :searchIndex => %w[page],
+ :longSearchIndex => [''],
+ :info => [@page.search_record[2..-1]],
+ }
+
+ assert_equal expected, @g.index
+ end
+
+ def test_search_string
+ assert_equal 'cd', @g.search_string('C d')
+ end
+
+end
+
diff --git a/test/rdoc/test_rdoc_generator_markup.rb b/test/rdoc/test_rdoc_generator_markup.rb
new file mode 100644
index 0000000000..1b44085283
--- /dev/null
+++ b/test/rdoc/test_rdoc_generator_markup.rb
@@ -0,0 +1,56 @@
+require 'rdoc/test_case'
+
+class TestRDocGeneratorMarkup < RDoc::TestCase
+
+ include RDoc::Text
+ include RDoc::Generator::Markup
+
+ attr_reader :store
+
+ def setup
+ super
+
+ @options = RDoc::Options.new
+ @rdoc.options = @options
+
+ @parent = self
+ @path = '/index.html'
+ @symbols = {}
+ end
+
+ def test_aref_to
+ assert_equal 'Foo/Bar.html', aref_to('Foo/Bar.html')
+ end
+
+ def test_as_href
+ assert_equal '../index.html', as_href('Foo/Bar.html')
+ end
+
+ def test_cvs_url
+ assert_equal 'http://example/this_page',
+ cvs_url('http://example/', 'this_page')
+
+ assert_equal 'http://example/?page=this_page&foo=bar',
+ cvs_url('http://example/?page=%s&foo=bar', 'this_page')
+ end
+
+ def test_description
+ @comment = '= Hello'
+
+ assert_equal "\n<h1 id=\"label-Hello\">Hello</h1>\n", description
+ end
+
+ def test_formatter
+ assert_kind_of RDoc::Markup::ToHtmlCrossref, formatter
+ refute formatter.show_hash
+ assert_same self, formatter.context
+ end
+
+ attr_reader :path
+
+ def find_symbol name
+ @symbols[name]
+ end
+
+end
+
diff --git a/test/rdoc/test_rdoc_generator_ri.rb b/test/rdoc/test_rdoc_generator_ri.rb
index 2be006843c..a2bcec534d 100644
--- a/test/rdoc/test_rdoc_generator_ri.rb
+++ b/test/rdoc/test_rdoc_generator_ri.rb
@@ -1,26 +1,22 @@
-require 'rubygems'
-require 'minitest/autorun'
-require 'rdoc/rdoc'
-require 'rdoc/generator/ri'
-require 'tmpdir'
-require 'fileutils'
+require 'rdoc/test_case'
-class TestRDocGeneratorRI < MiniTest::Unit::TestCase
+class TestRDocGeneratorRI < RDoc::TestCase
def setup
- @options = RDoc::Options.new
- @options.encoding = Encoding::UTF_8 if Object.const_defined? :Encoding
+ super
- @pwd = Dir.pwd
- RDoc::TopLevel.reset
+ @options = RDoc::Options.new
+ if Object.const_defined? :Encoding then
+ @options.encoding = Encoding::UTF_8
+ @store.encoding = Encoding::UTF_8
+ end
@tmpdir = File.join Dir.tmpdir, "test_rdoc_generator_ri_#{$$}"
FileUtils.mkdir_p @tmpdir
- Dir.chdir @tmpdir
- @g = RDoc::Generator::RI.new @options
+ @g = RDoc::Generator::RI.new @store, @options
- @top_level = RDoc::TopLevel.new 'file.rb'
+ @top_level = @store.add_file 'file.rb'
@klass = @top_level.add_class RDoc::NormalClass, 'Object'
@meth = RDoc::AnyMethod.new nil, 'method'
@@ -35,9 +31,13 @@ class TestRDocGeneratorRI < MiniTest::Unit::TestCase
@klass.add_method @meth
@klass.add_method @meth_bang
@klass.add_attribute @attr
+
+ Dir.chdir @tmpdir
end
def teardown
+ super
+
Dir.chdir @pwd
FileUtils.rm_rf @tmpdir
end
@@ -51,7 +51,7 @@ class TestRDocGeneratorRI < MiniTest::Unit::TestCase
end
def test_generate
- @g.generate nil
+ @g.generate
assert_file File.join(@tmpdir, 'cache.ri')
@@ -70,16 +70,15 @@ class TestRDocGeneratorRI < MiniTest::Unit::TestCase
end
def test_generate_dry_run
- @options.dry_run = true
- @g = RDoc::Generator::RI.new @options
+ @store.dry_run = true
+ @g = RDoc::Generator::RI.new @store, @options
- top_level = RDoc::TopLevel.new 'file.rb'
+ top_level = @store.add_file 'file.rb'
top_level.add_class @klass.class, @klass.name
- @g.generate nil
+ @g.generate
refute_file File.join(@tmpdir, 'cache.ri')
-
refute_file File.join(@tmpdir, 'Object')
end
diff --git a/test/rdoc/test_rdoc_include.rb b/test/rdoc/test_rdoc_include.rb
index 71eaf9abf8..464a698018 100644
--- a/test/rdoc/test_rdoc_include.rb
+++ b/test/rdoc/test_rdoc_include.rb
@@ -7,6 +7,8 @@ class TestRDocInclude < XrefTestCase
@inc = RDoc::Include.new 'M1', 'comment'
@inc.parent = @m1
+ @inc.record_location @top_level
+ @inc.store = @store
end
def test_module
@@ -92,5 +94,15 @@ class TestRDocInclude < XrefTestCase
assert_equal [m1_m2_m4, m1_m2, m1, 'Object'], m1_k3.ancestors
end
+ def test_store_equals
+ incl = RDoc::Include.new 'M', nil
+ incl.record_location RDoc::TopLevel.new @top_level.name
+
+ incl.store = @store
+
+ assert_same @top_level, incl.file
+ assert_same @store, incl.file.store
+ end
+
end
diff --git a/test/rdoc/test_rdoc_markdown.rb b/test/rdoc/test_rdoc_markdown.rb
new file mode 100644
index 0000000000..f3eb22227c
--- /dev/null
+++ b/test/rdoc/test_rdoc_markdown.rb
@@ -0,0 +1,977 @@
+# coding: UTF-8
+
+require 'rubygems'
+require 'minitest/autorun'
+require 'pp'
+
+require 'rdoc'
+require 'rdoc/markup/block_quote'
+require 'rdoc/markdown'
+
+class TestRDocMarkdown < RDoc::TestCase
+
+ def setup
+ @RM = RDoc::Markup
+
+ @parser = RDoc::Markdown.new
+ end
+
+ def mu_pp obj
+ s = ''
+ s = PP.pp obj, s
+ s.force_encoding Encoding.default_external if defined? Encoding
+ s.chomp
+ end
+
+ def test_class_parse
+ doc = RDoc::Markdown.parse "hello\n\nworld"
+
+ expected = doc(para("hello"), para("world"))
+
+ assert_equal expected, doc
+ end
+
+ def test_emphasis
+ assert_equal '_word_', @parser.emphasis('word')
+ assert_equal '<em>two words</em>', @parser.emphasis('two words')
+ assert_equal '<em>*bold*</em>', @parser.emphasis('*bold*')
+ end
+
+ def test_parse_auto_link_email
+ doc = parse "Autolink: <nobody-0+_./!%~$@example>"
+
+ expected = doc(para("Autolink: mailto:nobody-0+_./!%~$@example"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_auto_link_url
+ doc = parse "Autolink: <http://example>"
+
+ expected = doc(para("Autolink: http://example"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_block_quote
+ doc = parse <<-BLOCK_QUOTE
+> this is
+> a block quote
+ BLOCK_QUOTE
+
+ expected =
+ doc(
+ block(
+ para("this is\na block quote")))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_block_quote_continue
+ doc = parse <<-BLOCK_QUOTE
+> this is
+a block quote
+ BLOCK_QUOTE
+
+ expected =
+ doc(
+ block(
+ para("this is\na block quote")))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_block_quote_list
+ doc = parse <<-BLOCK_QUOTE
+> text
+>
+> * one
+> * two
+ BLOCK_QUOTE
+
+ expected =
+ doc(
+ block(
+ para("text"),
+ list(:BULLET,
+ item(nil, para("one")),
+ item(nil, para("two")))))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_block_quote_newline
+ doc = parse <<-BLOCK_QUOTE
+> this is
+a block quote
+
+ BLOCK_QUOTE
+
+ expected =
+ doc(
+ block(
+ para("this is\na block quote")))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_block_quote_separate
+ doc = parse <<-BLOCK_QUOTE
+> this is
+a block quote
+
+> that continues
+ BLOCK_QUOTE
+
+ expected =
+ doc(
+ block(
+ para("this is\na block quote"),
+ para("that continues")))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_char_entity
+ doc = parse '&pi; &nn;'
+
+ expected = doc(para('π &nn;'))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_code
+ doc = parse "Code: `text`"
+
+ expected = doc(para("Code: <code>text</code>"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_code_github
+ doc = parse <<-MD
+Example:
+
+```
+code goes here
+```
+ MD
+
+ expected =
+ doc(
+ para("Example:"),
+ verb("code goes here\n"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_code_github_format
+ doc = parse <<-MD
+Example:
+
+``` ruby
+code goes here
+```
+ MD
+
+ code = verb("code goes here\n")
+ code.format = :ruby
+
+ expected =
+ doc(
+ para("Example:"),
+ code)
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_definition_list
+ doc = parse <<-MD
+one
+: This is a definition
+
+two
+: This is another definition
+ MD
+
+ expected = doc(
+ list(:NOTE,
+ item(%w[one], para("This is a definition")),
+ item(%w[two], para("This is another definition"))))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_definition_list_indents
+ doc = parse <<-MD
+zero
+: Indented zero characters
+
+one
+ : Indented one characters
+
+two
+ : Indented two characters
+
+three
+ : Indented three characters
+
+four
+ : Indented four characters
+
+ MD
+
+ expected = doc(
+ list(:NOTE,
+ item(%w[zero], para("Indented zero characters")),
+ item(%w[one], para("Indented one characters")),
+ item(%w[two], para("Indented two characters")),
+ item(%w[three], para("Indented three characters"))),
+ para("four\n : Indented four characters"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_definition_list_multi_description
+ doc = parse <<-MD
+label
+: This is a definition
+
+: This is another definition
+ MD
+
+ expected = doc(
+ list(:NOTE,
+ item(%w[label], para("This is a definition")),
+ item(nil, para("This is another definition"))))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_definition_list_multi_label
+ doc = parse <<-MD
+one
+two
+: This is a definition
+ MD
+
+ expected = doc(
+ list(:NOTE,
+ item(%w[one two], para("This is a definition"))))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_definition_list_multi_line
+ doc = parse <<-MD
+one
+: This is a definition
+that extends to two lines
+
+two
+: This is another definition
+that also extends to two lines
+ MD
+
+ expected = doc(
+ list(:NOTE,
+ item(%w[one],
+ para("This is a definition\nthat extends to two lines")),
+ item(%w[two],
+ para("This is another definition\nthat also extends to two lines"))))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_definition_list_no
+ @parser.definition_lists = false
+
+ doc = parse <<-MD
+one
+: This is a definition
+
+two
+: This is another definition
+ MD
+
+ expected = doc(
+ para("one\n: This is a definition"),
+ para("two\n: This is another definition"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_entity_dec
+ doc = parse "Entity: &#65;"
+
+ expected = doc(para("Entity: A"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_entity_hex
+ doc = parse "Entity: &#x41;"
+
+ expected = doc(para("Entity: A"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_entity_named
+ doc = parse "Entity: &pi;"
+
+ expected = doc(para("Entity: π"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_emphasis_star
+ doc = parse "it *works*\n"
+
+ expected = @RM::Document.new(
+ @RM::Paragraph.new("it _works_"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_emphasis_underscore
+ doc = parse "it _works_\n"
+
+ expected =
+ doc(
+ para("it _works_"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_emphasis_underscore_embedded
+ doc = parse "foo_bar bar_baz\n"
+
+ expected =
+ doc(
+ para("foo_bar bar_baz"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_emphasis_underscore_in_word
+ doc = parse "it foo_bar_baz\n"
+
+ expected =
+ doc(
+ para("it foo_bar_baz"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_escape
+ assert_equal doc(para("Backtick: `")), parse("Backtick: \\`")
+
+ assert_equal doc(para("Backslash: \\")), parse("Backslash: \\\\")
+
+ assert_equal doc(para("Colon: :")), parse("Colon: \\:")
+ end
+
+ def test_parse_heading_atx
+ doc = parse "# heading\n"
+
+ expected = @RM::Document.new(
+ @RM::Heading.new(1, "heading"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_heading_setext_dash
+ doc = parse <<-MD
+heading
+---
+ MD
+
+ expected = @RM::Document.new(
+ @RM::Heading.new(2, "heading"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_heading_setext_equals
+ doc = parse <<-MD
+heading
+===
+ MD
+
+ expected = @RM::Document.new(
+ @RM::Heading.new(1, "heading"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_html
+ @parser.html = true
+
+ doc = parse "<address>Links here</address>\n"
+
+ expected = doc(
+ @RM::Raw.new("<address>Links here</address>"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_html_hr
+ @parser.html = true
+
+ doc = parse "<hr>\n"
+
+ expected = doc(raw("<hr>"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_html_no_html
+ @parser.html = false
+
+ doc = parse "<address>Links here</address>\n"
+
+ expected = doc()
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_image
+ doc = parse "image ![alt text](path/to/image.jpg)"
+
+ expected = doc(para("image {alt text}[path/to/image.jpg]"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_line_break
+ doc = parse "Some text \nwith extra lines"
+
+ expected = doc(
+ para("Some text", hard_break, "with extra lines"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_link_reference_id
+ doc = parse <<-MD
+This is [an example][id] reference-style link.
+
+[id]: http://example.com "Optional Title Here"
+ MD
+
+ expected = doc(
+ para("This is {an example}[http://example.com] reference-style link."))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_link_reference_id_adjacent
+ doc = parse <<-MD
+[this] [this] should work
+
+[this]: example
+ MD
+
+ expected = doc(
+ para("{this}[example] should work"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_link_reference_id_eof
+ doc = parse <<-MD.chomp
+This is [an example][id] reference-style link.
+
+[id]: http://example.com "Optional Title Here"
+ MD
+
+ expected = doc(
+ para("This is {an example}[http://example.com] reference-style link."))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_link_reference_id_many
+ doc = parse <<-MD
+This is [an example][id] reference-style link.
+
+And [another][id].
+
+[id]: http://example.com "Optional Title Here"
+ MD
+
+ expected = doc(
+ para("This is {an example}[http://example.com] reference-style link."),
+ para("And {another}[http://example.com]."))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_link_reference_implicit
+ doc = parse <<-MD
+This is [an example][] reference-style link.
+
+[an example]: http://example.com "Optional Title Here"
+ MD
+
+ expected = doc(
+ para("This is {an example}[http://example.com] reference-style link."))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_list_bullet
+ doc = parse <<-MD
+* one
+* two
+ MD
+
+ expected = doc(
+ list(:BULLET,
+ item(nil, para("one")),
+ item(nil, para("two"))))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_list_bullet_auto_link
+ doc = parse <<-MD
+* <http://example/>
+ MD
+
+ expected = doc(
+ list(:BULLET,
+ item(nil, para("http://example/"))))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_list_bullet_continue
+ doc = parse <<-MD
+* one
+
+* two
+ MD
+
+ expected = doc(
+ list(:BULLET,
+ item(nil, para("one")),
+ item(nil, para("two"))))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_list_bullet_multiline
+ doc = parse <<-MD
+* one
+ two
+ MD
+
+ expected = doc(
+ list(:BULLET,
+ item(nil, para("one\n two"))))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_list_bullet_nest
+ doc = parse <<-MD
+* outer
+ * inner
+ MD
+
+ expected = doc(
+ list(:BULLET,
+ item(nil,
+ para("outer"),
+ list(:BULLET,
+ item(nil,
+ para("inner"))))))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_list_bullet_nest_loose
+ doc = parse <<-MD
+* outer
+
+ * inner
+ MD
+
+ expected = doc(
+ list(:BULLET,
+ item(nil,
+ para("outer"),
+ list(:BULLET,
+ item(nil, para("inner"))))))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_list_bullet_nest_continue
+ doc = parse <<-MD
+* outer
+ * inner
+ continue inner
+* outer 2
+ MD
+
+ expected = doc(
+ list(:BULLET,
+ item(nil,
+ para("outer"),
+ list(:BULLET,
+ item(nil,
+ para("inner\n continue inner")))),
+ item(nil,
+ para("outer 2"))))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_list_number
+ doc = parse <<-MD
+1. one
+1. two
+ MD
+
+ expected = doc(
+ list(:NUMBER,
+ item(nil, para("one")),
+ item(nil, para("two"))))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_list_number_continue
+ doc = parse <<-MD
+1. one
+
+1. two
+ MD
+
+ expected = doc(
+ list(:NUMBER,
+ item(nil, para("one")),
+ item(nil, para("two"))))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_note
+ @parser.notes = true
+
+ doc = parse <<-MD
+Some text.[^1]
+
+[^1]: With a footnote
+ MD
+
+ expected = doc(
+ para("Some text.{*1}[rdoc-label:foottext-1:footmark-1]"),
+ @RM::Rule.new(1),
+ para("{^1}[rdoc-label:footmark-1:foottext-1] With a footnote"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_note_indent
+ @parser.notes = true
+
+ doc = parse <<-MD
+Some text.[^1]
+
+[^1]: With a footnote
+
+ more
+ MD
+
+ expected = doc(
+ para("Some text.{*1}[rdoc-label:foottext-1:footmark-1]"),
+ rule(1),
+ para("{^1}[rdoc-label:footmark-1:foottext-1] With a footnote\n\nmore"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_note_inline
+ @parser.notes = true
+
+ doc = parse <<-MD
+Some text. ^[With a footnote]
+ MD
+
+ expected = doc(
+ para("Some text. {*1}[rdoc-label:foottext-1:footmark-1]"),
+ @RM::Rule.new(1),
+ para("{^1}[rdoc-label:footmark-1:foottext-1] With a footnote"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_note_no_notes
+ @parser.notes = false
+
+ assert_raises RuntimeError do # TODO use a real error
+ parse "Some text.[^1]"
+ end
+ end
+
+ def test_parse_note_multiple
+ @parser.notes = true
+
+ doc = parse <<-MD
+Some text[^1]
+with inline notes^[like this]
+and an extra note.[^2]
+
+[^1]: With a footnote
+
+[^2]: Which should be numbered correctly
+ MD
+
+ expected = doc(
+ para("Some text{*1}[rdoc-label:foottext-1:footmark-1]\n" +
+ "with inline notes{*2}[rdoc-label:foottext-2:footmark-2]\n" +
+ "and an extra note.{*3}[rdoc-label:foottext-3:footmark-3]"),
+
+ rule(1),
+
+ para("{^1}[rdoc-label:footmark-1:foottext-1] With a footnote"),
+ para("{^2}[rdoc-label:footmark-2:foottext-2] like this"),
+ para("{^3}[rdoc-label:footmark-3:foottext-3] " +
+ "Which should be numbered correctly"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_paragraph
+ doc = parse "it worked\n"
+
+ expected = doc(para("it worked"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_paragraph_break_on_newline
+ @parser.break_on_newline = true
+
+ doc = parse "one\ntwo\n"
+
+ expected = doc(para("one", hard_break, "two"))
+
+ assert_equal expected, doc
+
+ doc = parse "one \ntwo\nthree\n"
+
+ expected = doc(para("one", hard_break, "two", hard_break, "three"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_paragraph_stars
+ doc = parse "it worked ****\n"
+
+ expected = @RM::Document.new(
+ @RM::Paragraph.new("it worked ****"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_paragraph_html
+ @parser.html = true
+
+ doc = parse "<address>Links here</address>"
+
+ expected = doc(raw("<address>Links here</address>"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_paragraph_html_no_html
+ @parser.html = false
+
+ doc = parse "<address>Links here</address>"
+
+ expected = doc()
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_paragraph_indent_one
+ doc = parse <<-MD
+ text
+ MD
+
+ expected = doc(para("text"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_paragraph_indent_two
+ doc = parse <<-MD
+ text
+ MD
+
+ expected = doc(para("text"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_paragraph_indent_three
+ doc = parse <<-MD
+ text
+ MD
+
+ expected = doc(para("text"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_paragraph_multiline
+ doc = parse "one\ntwo"
+
+ expected = doc(para("one\ntwo"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_paragraph_two
+ doc = parse "one\n\ntwo"
+
+ expected = @RM::Document.new(
+ @RM::Paragraph.new("one"),
+ @RM::Paragraph.new("two"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_plain
+ doc = parse "it worked"
+
+ expected = @RM::Document.new(
+ @RM::Paragraph.new("it worked"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_reference_link_embedded_bracket
+ doc = parse "With [embedded [brackets]] [b].\n\n[b]: /url/\n"
+
+ expected =
+ doc(
+ para("With {embedded [brackets]}[/url/]."))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_rule_dash
+ doc = parse "- - -\n\n"
+
+ expected = @RM::Document.new(@RM::Rule.new(1))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_rule_underscore
+ doc = parse "_ _ _\n\n"
+
+ expected = @RM::Document.new(@RM::Rule.new(1))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_rule_star
+ doc = parse "* * *\n\n"
+
+ expected = @RM::Document.new(@RM::Rule.new(1))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_strong_star
+ doc = parse "it **works**\n"
+
+ expected = @RM::Document.new(
+ @RM::Paragraph.new("it *works*"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_strong_underscore
+ doc = parse "it __works__\n"
+
+ expected = @RM::Document.new(
+ @RM::Paragraph.new("it *works*"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_strong_emphasis_star
+ doc = parse "it ***works***\n"
+
+ expected = @RM::Document.new(
+ @RM::Paragraph.new("it <b>_works_</b>"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_strong_emphasis_underscore
+ doc = parse "it ___works___\n"
+
+ expected = @RM::Document.new(
+ @RM::Paragraph.new("it <b>_works_</b>"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_style
+ @parser.css = true
+
+ doc = parse "<style>h1 { color: red }</style>\n"
+
+ expected = doc(
+ @RM::Raw.new("<style>h1 { color: red }</style>"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_style_disabled
+ doc = parse "<style>h1 { color: red }</style>\n"
+
+ expected = doc()
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_verbatim
+ doc = parse <<-MD
+ text
+ MD
+
+ expected = doc(verb("text\n"))
+
+ assert_equal expected, doc
+ end
+
+ def test_parse_verbatim_eof
+ doc = parse " text"
+
+ expected = doc(verb("text\n"))
+
+ assert_equal expected, doc
+ end
+
+ def test_strong
+ assert_equal '*word*', @parser.strong('word')
+ assert_equal '<b>two words</b>', @parser.strong('two words')
+ assert_equal '<b>_emphasis_</b>', @parser.strong('_emphasis_')
+ end
+
+ def parse text
+ @parser.parse text
+ end
+
+end
+
diff --git a/test/rdoc/test_rdoc_markdown_test.rb b/test/rdoc/test_rdoc_markdown_test.rb
new file mode 100644
index 0000000000..7dfe727ef5
--- /dev/null
+++ b/test/rdoc/test_rdoc_markdown_test.rb
@@ -0,0 +1,1891 @@
+require 'rubygems'
+require 'minitest/autorun'
+require 'pp'
+
+require 'rdoc'
+require 'rdoc/markdown'
+
+class TestRDocMarkdownTest < RDoc::TestCase
+
+ MARKDOWN_TEST_PATH = File.expand_path '../MarkdownTest_1.0.3/', __FILE__
+
+ def setup
+ super
+
+ @parser = RDoc::Markdown.new
+ end
+
+ def mu_pp obj
+ s = ''
+ s = PP.pp obj, s
+ s.force_encoding Encoding.default_external if defined? Encoding
+ s.chomp
+ end
+
+ def test_amps_and_angle_encoding
+ input = File.read "#{MARKDOWN_TEST_PATH}/Amps and angle encoding.text"
+
+ doc = @parser.parse input
+
+ expected =
+ doc(
+ para("AT&T has an ampersand in their name."),
+ para("AT&T is another way to write it."),
+ para("This & that."),
+ para("4 < 5."),
+ para("6 > 5."),
+ para("Here's a {link}[http://example.com/?foo=1&bar=2] with " +
+ "an ampersand in the URL."),
+ para("Here's a link with an amersand in the link text: " +
+ "{AT&T}[http://att.com/]."),
+ para("Here's an inline {link}[/script?foo=1&bar=2]."),
+ para("Here's an inline {link}[/script?foo=1&bar=2]."))
+
+ assert_equal expected, doc
+ end
+
+ def test_auto_links
+ input = File.read "#{MARKDOWN_TEST_PATH}/Auto links.text"
+
+ doc = @parser.parse input
+
+ # TODO verify rdoc auto-links too
+ expected =
+ doc(
+ para("Link: http://example.com/."),
+ para("With an ampersand: http://example.com/?foo=1&bar=2"),
+ list(:BULLET,
+ item(nil, para("In a list?")),
+ item(nil, para("http://example.com/")),
+ item(nil, para("It should."))),
+ block(
+ para("Blockquoted: http://example.com/")),
+ para("Auto-links should not occur here: " +
+ "<code><http://example.com/></code>"),
+ verb("or here: <http://example.com/>\n"))
+
+ assert_equal expected, doc
+ end
+
+ def test_backslash_escapes
+ input = File.read "#{MARKDOWN_TEST_PATH}/Backslash escapes.text"
+
+ doc = @parser.parse input
+
+ expected =
+ doc(
+ para("These should all get escaped:"),
+
+ para("Backslash: \\"),
+ para("Backtick: `"),
+ para("Asterisk: *"),
+ para("Underscore: _"),
+ para("Left brace: {"),
+ para("Right brace: }"),
+ para("Left bracket: ["),
+ para("Right bracket: ]"),
+ para("Left paren: ("),
+ para("Right paren: )"),
+ para("Greater-than: >"),
+ para("Hash: #"),
+ para("Period: ."),
+ para("Bang: !"),
+ para("Plus: +"),
+ para("Minus: -"),
+
+ para("These should not, because they occur within a code block:"),
+
+ verb("Backslash: \\\\\n",
+ "\n",
+ "Backtick: \\`\n",
+ "\n",
+ "Asterisk: \\*\n",
+ "\n",
+ "Underscore: \\_\n",
+ "\n",
+ "Left brace: \\{\n",
+ "\n",
+ "Right brace: \\}\n",
+ "\n",
+ "Left bracket: \\[\n",
+ "\n",
+ "Right bracket: \\]\n",
+ "\n",
+ "Left paren: \\(\n",
+ "\n",
+ "Right paren: \\)\n",
+ "\n",
+ "Greater-than: \\>\n",
+ "\n",
+ "Hash: \\#\n",
+ "\n",
+ "Period: \\.\n",
+ "\n",
+ "Bang: \\!\n",
+ "\n",
+ "Plus: \\+\n",
+ "\n",
+ "Minus: \\-\n"),
+
+ para("Nor should these, which occur in code spans:"),
+
+ para("Backslash: <code>\\\\</code>"),
+ para("Backtick: <code>\\`</code>"),
+ para("Asterisk: <code>\\*</code>"),
+ para("Underscore: <code>\\_</code>"),
+ para("Left brace: <code>\\{</code>"),
+ para("Right brace: <code>\\}</code>"),
+ para("Left bracket: <code>\\[</code>"),
+ para("Right bracket: <code>\\]</code>"),
+ para("Left paren: <code>\\(</code>"),
+ para("Right paren: <code>\\)</code>"),
+ para("Greater-than: <code>\\></code>"),
+ para("Hash: <code>\\#</code>"),
+ para("Period: <code>\\.</code>"),
+ para("Bang: <code>\\!</code>"),
+ para("Plus: <code>\\+</code>"),
+ para("Minus: <code>\\-</code>"),
+
+ para("These should get escaped, even though they're matching pairs for\n" +
+ "other Markdown constructs:"),
+
+ para("\*asterisks\*"),
+ para("\_underscores\_"),
+ para("`backticks`"),
+
+ para("This is a code span with a literal backslash-backtick " +
+ "sequence: <code>\\`</code>"),
+
+ para("This is a tag with unescaped backticks " +
+ "<span attr='`ticks`'>bar</span>."),
+
+ para("This is a tag with backslashes " +
+ "<span attr='\\\\backslashes\\\\'>bar</span>."))
+
+ assert_equal expected, doc
+ end
+
+ def test_blockquotes_with_code_blocks
+ input = File.read "#{MARKDOWN_TEST_PATH}/Blockquotes with code blocks.text"
+
+ doc = @parser.parse input
+
+ expected =
+ doc(
+ block(
+ para("Example:"),
+ verb("sub status {\n",
+ " print \"working\";\n",
+ "}\n"),
+ para("Or:"),
+ verb("sub status {\n",
+ " return \"working\";\n",
+ "}\n")))
+
+ assert_equal expected, doc
+ end
+
+ def test_code_blocks
+ input = File.read "#{MARKDOWN_TEST_PATH}/Code Blocks.text"
+
+ doc = @parser.parse input
+
+ expected =
+ doc(
+ verb("code block on the first line\n"),
+ para("Regular text."),
+
+ verb("code block indented by spaces\n"),
+ para("Regular text."),
+
+ verb("the lines in this block \n",
+ "all contain trailing spaces \n"),
+ para("Regular Text."),
+
+ verb("code block on the last line\n"))
+
+ assert_equal expected, doc
+ end
+
+ def test_code_spans
+ input = File.read "#{MARKDOWN_TEST_PATH}/Code Spans.text"
+
+ doc = @parser.parse input
+
+ expected = doc(
+ para("<code><test a=\"</code> content of attribute <code>\"></code>"),
+ para("Fix for backticks within HTML tag: " +
+ "<span attr='`ticks`'>like this</span>"),
+ para("Here's how you put <code>`backticks`</code> in a code span."))
+
+ assert_equal expected, doc
+ end
+
+ def test_hard_wrapped_paragraphs_with_list_like_lines
+ input = File.read "#{MARKDOWN_TEST_PATH}/Hard-wrapped paragraphs with list-like lines.text"
+
+ doc = @parser.parse input
+
+ expected =
+ doc(
+ para("In Markdown 1.0.0 and earlier. Version\n" +
+ "8. This line turns into a list item.\n" +
+ "Because a hard-wrapped line in the\n" +
+ "middle of a paragraph looked like a\n" +
+ "list item."),
+ para("Here's one with a bullet.\n" +
+ "* criminey."))
+
+ assert_equal expected, doc
+ end
+
+ def test_horizontal_rules
+ input = File.read "#{MARKDOWN_TEST_PATH}/Horizontal rules.text"
+
+ doc = @parser.parse input
+
+ expected =
+ doc(
+ para("Dashes:"),
+
+ rule(1),
+ rule(1),
+ rule(1),
+ rule(1),
+ verb("---\n"),
+
+ rule(1),
+ rule(1),
+ rule(1),
+ rule(1),
+ verb("- - -\n"),
+
+ para("Asterisks:"),
+
+ rule(1),
+ rule(1),
+ rule(1),
+ rule(1),
+ verb("***\n"),
+
+ rule(1),
+ rule(1),
+ rule(1),
+ rule(1),
+ verb("* * *\n"),
+
+ para("Underscores:"),
+
+ rule(1),
+ rule(1),
+ rule(1),
+ rule(1),
+ verb("___\n"),
+
+ rule(1),
+ rule(1),
+ rule(1),
+ rule(1),
+ verb("_ _ _\n"))
+
+ assert_equal expected, doc
+ end
+
+ def test_inline_html_advanced
+ input = File.read "#{MARKDOWN_TEST_PATH}/Inline HTML (Advanced).text"
+
+ @parser.html = true
+
+ doc = @parser.parse input
+
+ expected =
+ doc(
+ para("Simple block on one line:"),
+ raw("<div>foo</div>"),
+ para("And nested without indentation:"),
+ raw(<<-RAW.chomp))
+<div>
+<div>
+<div>
+foo
+</div>
+<div style=">"/>
+</div>
+<div>bar</div>
+</div>
+ RAW
+
+ assert_equal expected, doc
+ end
+
+ def test_inline_html_simple
+ input = File.read "#{MARKDOWN_TEST_PATH}/Inline HTML (Simple).text"
+
+ @parser.html = true
+
+ doc = @parser.parse input
+
+ expected =
+ doc(
+ para("Here's a simple block:"),
+ raw("<div>\n\tfoo\n</div>"),
+
+ para("This should be a code block, though:"),
+ verb("<div>\n",
+ "\tfoo\n",
+ "</div>\n"),
+
+ para("As should this:"),
+ verb("<div>foo</div>\n"),
+
+ para("Now, nested:"),
+ raw("<div>\n\t<div>\n\t\t<div>\n\t\t\tfoo\n" +
+ "\t\t</div>\n\t</div>\n</div>"),
+
+ para("This should just be an HTML comment:"),
+ raw("<!-- Comment -->"),
+
+ para("Multiline:"),
+ raw("<!--\nBlah\nBlah\n-->"),
+
+ para("Code block:"),
+ verb("<!-- Comment -->\n"),
+
+ para("Just plain comment, with trailing spaces on the line:"),
+ raw("<!-- foo -->"),
+
+ para("Code:"),
+ verb("<hr />\n"),
+
+ para("Hr's:"),
+ raw("<hr>"),
+ raw("<hr/>"),
+ raw("<hr />"),
+
+ raw("<hr>"),
+ raw("<hr/>"),
+ raw("<hr />"),
+
+ raw("<hr class=\"foo\" id=\"bar\" />"),
+ raw("<hr class=\"foo\" id=\"bar\"/>"),
+ raw("<hr class=\"foo\" id=\"bar\" >"))
+
+ assert_equal expected, doc
+ end
+
+ def test_inline_html_comments
+ input = File.read "#{MARKDOWN_TEST_PATH}/Inline HTML comments.text"
+
+ doc = @parser.parse input
+
+ expected =
+ doc(
+ para("Paragraph one."),
+
+ raw("<!-- This is a simple comment -->"),
+
+ raw("<!--\n\tThis is another comment.\n-->"),
+
+ para("Paragraph two."),
+
+ raw("<!-- one comment block -- -- with two comments -->"),
+
+ para("The end."))
+
+ assert_equal expected, doc
+ end
+
+ def test_links_inline_style
+ input = File.read "#{MARKDOWN_TEST_PATH}/Links, inline style.text"
+
+ doc = @parser.parse input
+
+ expected =
+ doc(
+ para("Just a {URL}[/url/]."),
+ para("{URL and title}[/url/]."),
+ para("{URL and title}[/url/]."),
+ para("{URL and title}[/url/]."),
+ para("{URL and title}[/url/]."),
+ para("{Empty}[]."))
+
+ assert_equal expected, doc
+ end
+
+ def test_links_reference_style
+ input = File.read "#{MARKDOWN_TEST_PATH}/Links, reference style.text"
+
+ doc = @parser.parse input
+
+ expected =
+ doc(
+ para("Foo {bar}[/url/]."),
+ para("Foo {bar}[/url/]."),
+ para("Foo {bar}[/url/]."),
+
+ para("With {embedded [brackets]}[/url/]."),
+
+ para("Indented {once}[/url]."),
+ para("Indented {twice}[/url]."),
+ para("Indented {thrice}[/url]."),
+ para("Indented [four][] times."),
+
+ verb("[four]: /url\n"),
+
+ rule(1),
+
+ para("{this}[foo] should work"),
+ para("So should {this}[foo]."),
+ para("And {this}[foo]."),
+ para("And {this}[foo]."),
+ para("And {this}[foo]."),
+
+ para("But not [that] []."),
+ para("Nor [that][]."),
+ para("Nor [that]."),
+
+ para("[Something in brackets like {this}[foo] should work]"),
+ para("[Same with {this}[foo].]"),
+
+ para("In this case, {this}[/somethingelse/] points to something else."),
+ para("Backslashing should suppress [this] and [this]."),
+
+ rule(1),
+
+ para("Here's one where the {link breaks}[/url/] across lines."),
+ para("Here's another where the {link breaks}[/url/] across lines, " +
+ "but with a line-ending space."))
+
+ assert_equal expected, doc
+ end
+
+ def test_links_shortcut_references
+ input = File.read "#{MARKDOWN_TEST_PATH}/Links, shortcut references.text"
+
+ doc = @parser.parse input
+
+ expected =
+ doc(
+ para("This is the {simple case}[/simple]."),
+ para("This one has a {line break}[/foo]."),
+ para("This one has a {line break}[/foo] with a line-ending space."),
+ para("{this}[/that] and the {other}[/other]"))
+
+ assert_equal expected, doc
+ end
+
+ def test_literal_quotes_in_titles
+ input = File.read "#{MARKDOWN_TEST_PATH}/Literal quotes in titles.text"
+
+ doc = @parser.parse input
+
+ # TODO support title attribute
+ expected =
+ doc(
+ para("Foo {bar}[/url/]."),
+ para("Foo {bar}[/url/]."))
+
+ assert_equal expected, doc
+ end
+
+ def test_markdown_documentation_basics
+ input = File.read "#{MARKDOWN_TEST_PATH}/Markdown Documentation - Basics.text"
+
+ doc = @parser.parse input
+
+ expected =
+ doc(
+ head(1, "Markdown: Basics"),
+
+ raw(<<-RAW.chomp),
+<ul id="ProjectSubmenu">
+ <li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
+ <li><a class="selected" title="Markdown Basics">Basics</a></li>
+ <li><a href="/projects/markdown/syntax" title="Markdown Syntax Documentation">Syntax</a></li>
+ <li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
+ <li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
+</ul>
+ RAW
+
+ head(2, "Getting the Gist of Markdown's Formatting Syntax"),
+
+ para("This page offers a brief overview of what it's like to use Markdown.\n" +
+ "The {syntax page}[/projects/markdown/syntax] provides complete, detailed documentation for\n" +
+ "every feature, but Markdown should be very easy to pick up simply by\n" +
+ "looking at a few examples of it in action. The examples on this page\n" +
+ "are written in a before/after style, showing example syntax and the\n" +
+ "HTML output produced by Markdown."),
+
+ para("It's also helpful to simply try Markdown out; the {Dingus}[/projects/markdown/dingus] is a\n" +
+ "web application that allows you type your own Markdown-formatted text\n" +
+ "and translate it to XHTML."),
+
+ para("<b>Note:</b> This document is itself written using Markdown; you\n" +
+ "can {see the source for it by adding '.text' to the URL}[/projects/markdown/basics.text]."),
+
+ head(2, "Paragraphs, Headers, Blockquotes"),
+
+ para("A paragraph is simply one or more consecutive lines of text, separated\n" +
+ "by one or more blank lines. (A blank line is any line that looks like a\n" +
+ "blank line -- a line containing nothing spaces or tabs is considered\n" +
+ "blank.) Normal paragraphs should not be intended with spaces or tabs."),
+
+ para("Markdown offers two styles of headers: _Setext_ and _atx_.\n" +
+ "Setext-style headers for <code><h1></code> and <code><h2></code> are created by\n" +
+ "\"underlining\" with equal signs (<code>=</code>) and hyphens (<code>-</code>), respectively.\n" +
+ "To create an atx-style header, you put 1-6 hash marks (<code>#</code>) at the\n" +
+ "beginning of the line -- the number of hashes equals the resulting\n" +
+ "HTML header level."),
+
+ para("Blockquotes are indicated using email-style '<code>></code>' angle brackets."),
+
+ para("Markdown:"),
+
+ verb("A First Level Header\n",
+ "====================\n",
+ "\n",
+ "A Second Level Header\n",
+ "---------------------\n",
+ "\n",
+ "Now is the time for all good men to come to\n",
+ "the aid of their country. This is just a\n",
+ "regular paragraph.\n",
+ "\n",
+ "The quick brown fox jumped over the lazy\n",
+ "dog's back.\n",
+ "\n",
+ "### Header 3\n",
+ "\n",
+ "> This is a blockquote.\n",
+ "> \n",
+ "> This is the second paragraph in the blockquote.\n",
+ ">\n",
+ "> ## This is an H2 in a blockquote\n"),
+
+ para("Output:"),
+
+ verb("<h1>A First Level Header</h1>\n",
+ "\n",
+ "<h2>A Second Level Header</h2>\n",
+ "\n",
+ "<p>Now is the time for all good men to come to\n",
+ "the aid of their country. This is just a\n",
+ "regular paragraph.</p>\n",
+ "\n",
+ "<p>The quick brown fox jumped over the lazy\n",
+ "dog's back.</p>\n",
+ "\n",
+ "<h3>Header 3</h3>\n",
+ "\n",
+ "<blockquote>\n",
+ " <p>This is a blockquote.</p>\n",
+ "\n",
+ " <p>This is the second paragraph in the blockquote.</p>\n",
+ "\n",
+ " <h2>This is an H2 in a blockquote</h2>\n",
+ "</blockquote>\n"),
+
+ head(3, "Phrase Emphasis"),
+ para("Markdown uses asterisks and underscores to indicate spans of emphasis."),
+
+ para("Markdown:"),
+
+ verb("Some of these words *are emphasized*.\n",
+ "Some of these words _are emphasized also_.\n",
+ "\n",
+ "Use two asterisks for **strong emphasis**.\n",
+ "Or, if you prefer, __use two underscores instead__.\n"),
+
+ para("Output:"),
+
+ verb("<p>Some of these words <em>are emphasized</em>.\n",
+ "Some of these words <em>are emphasized also</em>.</p>\n",
+ "\n",
+ "<p>Use two asterisks for <strong>strong emphasis</strong>.\n",
+ "Or, if you prefer, <strong>use two underscores instead</strong>.</p>\n"),
+
+ head(2, "Lists"),
+
+ para("Unordered (bulleted) lists use asterisks, pluses, and hyphens (<code>*</code>,\n" +
+ "<code>+</code>, and <code>-</code>) as list markers. These three markers are\n" +
+ "interchangable; this:"),
+
+ verb("* Candy.\n",
+ "* Gum.\n",
+ "* Booze.\n"),
+
+ para("this:"),
+
+ verb("+ Candy.\n",
+ "+ Gum.\n",
+ "+ Booze.\n"),
+
+ para("and this:"),
+
+ verb("- Candy.\n",
+ "- Gum.\n",
+ "- Booze.\n"),
+
+ para("all produce the same output:"),
+
+ verb("<ul>\n",
+ "<li>Candy.</li>\n",
+ "<li>Gum.</li>\n",
+ "<li>Booze.</li>\n",
+ "</ul>\n"),
+
+ para("Ordered (numbered) lists use regular numbers, followed by periods, as\n" +
+ "list markers:"),
+
+ verb("1. Red\n",
+ "2. Green\n",
+ "3. Blue\n"),
+
+ para("Output:"),
+
+ verb("<ol>\n",
+ "<li>Red</li>\n",
+ "<li>Green</li>\n",
+ "<li>Blue</li>\n",
+ "</ol>\n"),
+
+ para("If you put blank lines between items, you'll get <code><p></code> tags for the\n" +
+ "list item text. You can create multi-paragraph list items by indenting\n" +
+ "the paragraphs by 4 spaces or 1 tab:"),
+
+ verb("* A list item.\n",
+ "\n",
+ " With multiple paragraphs.\n",
+ "\n",
+ "* Another item in the list.\n"),
+
+ para("Output:"),
+
+ verb("<ul>\n",
+ "<li><p>A list item.</p>\n",
+ "<p>With multiple paragraphs.</p></li>\n",
+ "<li><p>Another item in the list.</p></li>\n",
+ "</ul>\n"),
+
+ head(3, "Links"),
+
+ para("Markdown supports two styles for creating links: _inline_ and\n" +
+ "_reference_. With both styles, you use square brackets to delimit the\n" +
+ "text you want to turn into a link."),
+
+ para("Inline-style links use parentheses immediately after the link text.\n" +
+ "For example:"),
+
+ verb("This is an [example link](http://example.com/).\n"),
+
+ para("Output:"),
+
+ verb("<p>This is an <a href=\"http://example.com/\">\n",
+ "example link</a>.</p>\n"),
+
+ para("Optionally, you may include a title attribute in the parentheses:"),
+
+ verb("This is an [example link](http://example.com/ \"With a Title\").\n"),
+
+ para("Output:"),
+
+ verb("<p>This is an <a href=\"http://example.com/\" title=\"With a Title\">\n",
+ "example link</a>.</p>\n"),
+
+ para("Reference-style links allow you to refer to your links by names, which\n" +
+ "you define elsewhere in your document:"),
+
+ verb("I get 10 times more traffic from [Google][1] than from\n",
+ "[Yahoo][2] or [MSN][3].\n",
+ "\n",
+ "[1]: http://google.com/ \"Google\"\n",
+ "[2]: http://search.yahoo.com/ \"Yahoo Search\"\n",
+ "[3]: http://search.msn.com/ \"MSN Search\"\n"),
+
+ para("Output:"),
+
+ verb("<p>I get 10 times more traffic from <a href=\"http://google.com/\"\n",
+ "title=\"Google\">Google</a> than from <a href=\"http://search.yahoo.com/\"\n",
+ "title=\"Yahoo Search\">Yahoo</a> or <a href=\"http://search.msn.com/\"\n",
+ "title=\"MSN Search\">MSN</a>.</p>\n"),
+
+ para("The title attribute is optional. Link names may contain letters,\n" +
+ "numbers and spaces, but are _not_ case sensitive:"),
+
+ verb("I start my morning with a cup of coffee and\n",
+ "[The New York Times][NY Times].\n",
+ "\n",
+ "[ny times]: http://www.nytimes.com/\n"),
+
+ para("Output:"),
+
+ verb("<p>I start my morning with a cup of coffee and\n",
+ "<a href=\"http://www.nytimes.com/\">The New York Times</a>.</p>\n"),
+
+ head(3, "Images"),
+
+ para("Image syntax is very much like link syntax."),
+
+ para("Inline (titles are optional):"),
+
+ verb("![alt text](/path/to/img.jpg \"Title\")\n"),
+
+ para("Reference-style:"),
+
+ verb("![alt text][id]\n",
+ "\n",
+ "[id]: /path/to/img.jpg \"Title\"\n"),
+
+ para("Both of the above examples produce the same output:"),
+
+ verb("<img src=\"/path/to/img.jpg\" alt=\"alt text\" title=\"Title\" />\n"),
+
+ head(3, "Code"),
+
+ para("In a regular paragraph, you can create code span by wrapping text in\n" +
+ "backtick quotes. Any ampersands (<code>&</code>) and angle brackets (<code><</code> or\n" +
+ "<code>></code>) will automatically be translated into HTML entities. This makes\n" +
+ "it easy to use Markdown to write about HTML example code:"),
+
+ verb(
+ "I strongly recommend against using any `<blink>` tags.\n",
+ "\n",
+ "I wish SmartyPants used named entities like `&mdash;`\n",
+ "instead of decimal-encoded entites like `&#8212;`.\n"),
+
+ para("Output:"),
+
+ verb("<p>I strongly recommend against using any\n",
+ "<code>&lt;blink&gt;</code> tags.</p>\n",
+ "\n",
+ "<p>I wish SmartyPants used named entities like\n",
+ "<code>&amp;mdash;</code> instead of decimal-encoded\n",
+ "entites like <code>&amp;#8212;</code>.</p>\n"),
+
+ para("To specify an entire block of pre-formatted code, indent every line of\n" +
+ "the block by 4 spaces or 1 tab. Just like with code spans, <code>&</code>, <code><</code>,\n" +
+ "and <code>></code> characters will be escaped automatically."),
+
+ para("Markdown:"),
+
+ verb("If you want your page to validate under XHTML 1.0 Strict,\n",
+ "you've got to put paragraph tags in your blockquotes:\n",
+ "\n",
+ " <blockquote>\n",
+ " <p>For example.</p>\n",
+ " </blockquote>\n"),
+
+ para("Output:"),
+
+ verb("<p>If you want your page to validate under XHTML 1.0 Strict,\n",
+ "you've got to put paragraph tags in your blockquotes:</p>\n",
+ "\n",
+ "<pre><code>&lt;blockquote&gt;\n",
+ " &lt;p&gt;For example.&lt;/p&gt;\n",
+ "&lt;/blockquote&gt;\n",
+ "</code></pre>\n"))
+
+ assert_equal expected, doc
+ end
+
+ def test_markdown_documentation_syntax
+ input = File.read "#{MARKDOWN_TEST_PATH}/Markdown Documentation - Syntax.text"
+
+ doc = @parser.parse input
+
+ expected =
+ doc(
+ head(1, "Markdown: Syntax"),
+
+ raw(<<-RAW.chomp),
+<ul id="ProjectSubmenu">
+ <li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
+ <li><a href="/projects/markdown/basics" title="Markdown Basics">Basics</a></li>
+ <li><a class="selected" title="Markdown Syntax Documentation">Syntax</a></li>
+ <li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
+ <li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
+</ul>
+ RAW
+
+ list(:BULLET,
+ item(nil,
+ para("{Overview}[#overview]"),
+ list(:BULLET,
+ item(nil,
+ para("{Philosophy}[#philosophy]")),
+ item(nil,
+ para("{Inline HTML}[#html]")),
+ item(nil,
+ para("{Automatic Escaping for Special Characters}[#autoescape]")))),
+ item(nil,
+ para("{Block Elements}[#block]"),
+ list(:BULLET,
+ item(nil,
+ para("{Paragraphs and Line Breaks}[#p]")),
+ item(nil,
+ para("{Headers}[#header]")),
+ item(nil,
+ para("{Blockquotes}[#blockquote]")),
+ item(nil,
+ para("{Lists}[#list]")),
+ item(nil,
+ para("{Code Blocks}[#precode]")),
+ item(nil,
+ para("{Horizontal Rules}[#hr]")))),
+ item(nil,
+ para("{Span Elements}[#span]"),
+ list(:BULLET,
+ item(nil,
+ para("{Links}[#link]")),
+ item(nil,
+ para("{Emphasis}[#em]")),
+ item(nil,
+ para("{Code}[#code]")),
+ item(nil,
+ para("{Images}[#img]")))),
+ item(nil,
+ para("{Miscellaneous}[#misc]"),
+ list(:BULLET,
+ item(nil,
+ para("{Backslash Escapes}[#backslash]")),
+ item(nil,
+ para("{Automatic Links}[#autolink]"))))),
+
+ para("<b>Note:</b> This document is itself written using Markdown; you\n" +
+ "can {see the source for it by adding '.text' to the URL}[/projects/markdown/syntax.text]."),
+
+ rule(1),
+
+ raw("<h2 id=\"overview\">Overview</h2>"),
+
+ raw("<h3 id=\"philosophy\">Philosophy</h3>"),
+
+ para("Markdown is intended to be as easy-to-read and easy-to-write as is feasible."),
+
+ para("Readability, however, is emphasized above all else. A Markdown-formatted\n" +
+ "document should be publishable as-is, as plain text, without looking\n" +
+ "like it's been marked up with tags or formatting instructions. While\n" +
+ "Markdown's syntax has been influenced by several existing text-to-HTML\n" +
+ "filters -- including {Setext}[http://docutils.sourceforge.net/mirror/setext.html], {atx}[http://www.aaronsw.com/2002/atx/], {Textile}[http://textism.com/tools/textile/], {reStructuredText}[http://docutils.sourceforge.net/rst.html],\n" +
+ "{Grutatext}[http://www.triptico.com/software/grutatxt.html], and {EtText}[http://ettext.taint.org/doc/] -- the single biggest source of\n" +
+ "inspiration for Markdown's syntax is the format of plain text email."),
+
+ para("To this end, Markdown's syntax is comprised entirely of punctuation\n" +
+ "characters, which punctuation characters have been carefully chosen so\n" +
+ "as to look like what they mean. E.g., asterisks around a word actually\n" +
+ "look like \*emphasis\*. Markdown lists look like, well, lists. Even\n" +
+ "blockquotes look like quoted passages of text, assuming you've ever\n" +
+ "used email."),
+
+ raw("<h3 id=\"html\">Inline HTML</h3>"),
+
+ para("Markdown's syntax is intended for one purpose: to be used as a\n" +
+ "format for _writing_ for the web."),
+
+ para("Markdown is not a replacement for HTML, or even close to it. Its\n" +
+ "syntax is very small, corresponding only to a very small subset of\n" +
+ "HTML tags. The idea is _not_ to create a syntax that makes it easier\n" +
+ "to insert HTML tags. In my opinion, HTML tags are already easy to\n" +
+ "insert. The idea for Markdown is to make it easy to read, write, and\n" +
+ "edit prose. HTML is a _publishing_ format; Markdown is a _writing_\n" +
+ "format. Thus, Markdown's formatting syntax only addresses issues that\n" +
+ "can be conveyed in plain text."),
+
+ para("For any markup that is not covered by Markdown's syntax, you simply\n" +
+ "use HTML itself. There's no need to preface it or delimit it to\n" +
+ "indicate that you're switching from Markdown to HTML; you just use\n" +
+ "the tags."),
+
+ para("The only restrictions are that block-level HTML elements -- e.g. <code><div></code>,\n" +
+ "<code><table></code>, <code><pre></code>, <code><p></code>, etc. -- must be separated from surrounding\n" +
+ "content by blank lines, and the start and end tags of the block should\n" +
+ "not be indented with tabs or spaces. Markdown is smart enough not\n" +
+ "to add extra (unwanted) <code><p></code> tags around HTML block-level tags."),
+
+ para("For example, to add an HTML table to a Markdown article:"),
+
+ verb("This is a regular paragraph.\n",
+ "\n",
+ "<table>\n",
+ " <tr>\n",
+ " <td>Foo</td>\n",
+ " </tr>\n",
+ "</table>\n",
+ "\n",
+ "This is another regular paragraph.\n"),
+
+ para("Note that Markdown formatting syntax is not processed within block-level\n" +
+ "HTML tags. E.g., you can't use Markdown-style <code>*emphasis*</code> inside an\n" +
+ "HTML block."),
+
+ para("Span-level HTML tags -- e.g. <code><span></code>, <code><cite></code>, or <code><del></code> -- can be\n" +
+ "used anywhere in a Markdown paragraph, list item, or header. If you\n" +
+ "want, you can even use HTML tags instead of Markdown formatting; e.g. if\n" +
+ "you'd prefer to use HTML <code><a></code> or <code><img></code> tags instead of Markdown's\n" +
+ "link or image syntax, go right ahead."),
+
+ para("Unlike block-level HTML tags, Markdown syntax _is_ processed within\n" +
+ "span-level tags."),
+
+ raw("<h3 id=\"autoescape\">Automatic Escaping for Special Characters</h3>"),
+
+ para("In HTML, there are two characters that demand special treatment: <code><</code>\n" +
+ "and <code>&</code>. Left angle brackets are used to start tags; ampersands are\n" +
+ "used to denote HTML entities. If you want to use them as literal\n" +
+ "characters, you must escape them as entities, e.g. <code>&lt;</code>, and\n" +
+ "<code>&amp;</code>."),
+
+ para("Ampersands in particular are bedeviling for web writers. If you want to\n" +
+ "write about 'AT&T', you need to write '<code>AT&amp;T</code>'. You even need to\n" +
+ "escape ampersands within URLs. Thus, if you want to link to:"),
+
+ verb("http://images.google.com/images?num=30&q=larry+bird\n"),
+
+ para("you need to encode the URL as:"),
+
+ verb("http://images.google.com/images?num=30&amp;q=larry+bird\n"),
+
+ para("in your anchor tag <code>href</code> attribute. Needless to say, this is easy to\n" +
+ "forget, and is probably the single most common source of HTML validation\n" +
+ "errors in otherwise well-marked-up web sites."),
+
+ para("Markdown allows you to use these characters naturally, taking care of\n" +
+ "all the necessary escaping for you. If you use an ampersand as part of\n" +
+ "an HTML entity, it remains unchanged; otherwise it will be translated\n" +
+ "into <code>&amp;</code>."),
+
+ para("So, if you want to include a copyright symbol in your article, you can write:"),
+
+ verb("&copy;\n"),
+
+ para("and Markdown will leave it alone. But if you write:"),
+
+ verb("AT&T\n"),
+
+ para("Markdown will translate it to:"),
+
+ verb("AT&amp;T\n"),
+
+ para("Similarly, because Markdown supports {inline HTML}[#html], if you use\n" +
+ "angle brackets as delimiters for HTML tags, Markdown will treat them as\n" +
+ "such. But if you write:"),
+
+ verb("4 < 5\n"),
+
+ para("Markdown will translate it to:"),
+
+ verb("4 &lt; 5\n"),
+
+ para("However, inside Markdown code spans and blocks, angle brackets and\n" +
+ "ampersands are _always_ encoded automatically. This makes it easy to use\n" +
+ "Markdown to write about HTML code. (As opposed to raw HTML, which is a\n" +
+ "terrible format for writing about HTML syntax, because every single <code><</code>\n" +
+ "and <code>&</code> in your example code needs to be escaped.)"),
+
+ rule(1),
+
+ raw("<h2 id=\"block\">Block Elements</h2>"),
+
+ raw("<h3 id=\"p\">Paragraphs and Line Breaks</h3>"),
+
+ para("A paragraph is simply one or more consecutive lines of text, separated\n" +
+ "by one or more blank lines. (A blank line is any line that looks like a\n" +
+ "blank line -- a line containing nothing but spaces or tabs is considered\n" +
+ "blank.) Normal paragraphs should not be intended with spaces or tabs."),
+
+ para("The implication of the \"one or more consecutive lines of text\" rule is\n" +
+ "that Markdown supports \"hard-wrapped\" text paragraphs. This differs\n" +
+ "significantly from most other text-to-HTML formatters (including Movable\n" +
+ "Type's \"Convert Line Breaks\" option) which translate every line break\n" +
+ "character in a paragraph into a <code><br /></code> tag."),
+
+ para("When you _do_ want to insert a <code><br /></code> break tag using Markdown, you\n" +
+ "end a line with two or more spaces, then type return."),
+
+ para("Yes, this takes a tad more effort to create a <code><br /></code>, but a simplistic\n" +
+ "\"every line break is a <code><br /></code>\" rule wouldn't work for Markdown.\n" +
+ "Markdown's email-style {blockquoting}[#blockquote] and multi-paragraph {list items}[#list]\n" +
+ "work best -- and look better -- when you format them with hard breaks."),
+
+ raw("<h3 id=\"header\">Headers</h3>"),
+
+ para("Markdown supports two styles of headers, {Setext}[http://docutils.sourceforge.net/mirror/setext.html] and {atx}[http://www.aaronsw.com/2002/atx/]."),
+
+ para("Setext-style headers are \"underlined\" using equal signs (for first-level\n" +
+ "headers) and dashes (for second-level headers). For example:"),
+
+ verb("This is an H1\n",
+ "=============\n",
+ "\n",
+ "This is an H2\n",
+ "-------------\n"),
+
+ para("Any number of underlining <code>=</code>'s or <code>-</code>'s will work."),
+
+ para("Atx-style headers use 1-6 hash characters at the start of the line,\n" +
+ "corresponding to header levels 1-6. For example:"),
+
+ verb("# This is an H1\n",
+ "\n",
+ "## This is an H2\n",
+ "\n",
+ "###### This is an H6\n"),
+
+ para("Optionally, you may \"close\" atx-style headers. This is purely\n" +
+ "cosmetic -- you can use this if you think it looks better. The\n" +
+ "closing hashes don't even need to match the number of hashes\n" +
+ "used to open the header. (The number of opening hashes\n" +
+ "determines the header level.) :"),
+
+ verb("# This is an H1 #\n",
+ "\n",
+ "## This is an H2 ##\n",
+ "\n",
+ "### This is an H3 ######\n"),
+
+ raw("<h3 id=\"blockquote\">Blockquotes</h3>"),
+
+ para(
+ "Markdown uses email-style <code>></code> characters for blockquoting. If you're\n" +
+ "familiar with quoting passages of text in an email message, then you\n" +
+ "know how to create a blockquote in Markdown. It looks best if you hard\n" +
+ "wrap the text and put a <code>></code> before every line:"),
+
+ verb("> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,\n",
+ "> consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.\n",
+ "> Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.\n",
+ "> \n",
+ "> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse\n",
+ "> id sem consectetuer libero luctus adipiscing.\n"),
+
+ para("Markdown allows you to be lazy and only put the <code>></code> before the first\n" +
+ "line of a hard-wrapped paragraph:"),
+
+ verb("> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,\n",
+ "consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.\n",
+ "Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.\n",
+ "\n",
+ "> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse\n",
+ "id sem consectetuer libero luctus adipiscing.\n"),
+
+ para("Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by\n" +
+ "adding additional levels of <code>></code>:"),
+
+ verb("> This is the first level of quoting.\n",
+ ">\n",
+ "> > This is nested blockquote.\n",
+ ">\n",
+ "> Back to the first level.\n"),
+
+ para("Blockquotes can contain other Markdown elements, including headers, lists,\n" +
+ "and code blocks:"),
+
+ verb("> ## This is a header.\n",
+ "> \n",
+ "> 1. This is the first list item.\n",
+ "> 2. This is the second list item.\n",
+ "> \n",
+ "> Here's some example code:\n",
+ "> \n",
+ "> return shell_exec(\"echo $input | $markdown_script\");\n"),
+
+ para("Any decent text editor should make email-style quoting easy. For\n" +
+ "example, with BBEdit, you can make a selection and choose Increase\n" +
+ "Quote Level from the Text menu."),
+
+ raw("<h3 id=\"list\">Lists</h3>"),
+
+ para("Markdown supports ordered (numbered) and unordered (bulleted) lists."),
+
+ para("Unordered lists use asterisks, pluses, and hyphens -- interchangably\n" +
+ "-- as list markers:"),
+
+ verb("* Red\n",
+ "* Green\n",
+ "* Blue\n"),
+
+ para("is equivalent to:"),
+
+ verb("+ Red\n",
+ "+ Green\n",
+ "+ Blue\n"),
+
+ para("and:"),
+
+ verb("- Red\n",
+ "- Green\n",
+ "- Blue\n"),
+
+ para("Ordered lists use numbers followed by periods:"),
+
+ verb("1. Bird\n",
+ "2. McHale\n",
+ "3. Parish\n"),
+
+ para("It's important to note that the actual numbers you use to mark the\n" +
+ "list have no effect on the HTML output Markdown produces. The HTML\n" +
+ "Markdown produces from the above list is:"),
+
+ verb("<ol>\n",
+ "<li>Bird</li>\n",
+ "<li>McHale</li>\n",
+ "<li>Parish</li>\n",
+ "</ol>\n"),
+
+ para("If you instead wrote the list in Markdown like this:"),
+
+ verb("1. Bird\n",
+ "1. McHale\n",
+ "1. Parish\n"),
+
+ para("or even:"),
+
+ verb("3. Bird\n",
+ "1. McHale\n",
+ "8. Parish\n"),
+
+ para("you'd get the exact same HTML output. The point is, if you want to,\n" +
+ "you can use ordinal numbers in your ordered Markdown lists, so that\n" +
+ "the numbers in your source match the numbers in your published HTML.\n" +
+ "But if you want to be lazy, you don't have to."),
+
+ para("If you do use lazy list numbering, however, you should still start the\n" +
+ "list with the number 1. At some point in the future, Markdown may support\n" +
+ "starting ordered lists at an arbitrary number."),
+
+ para("List markers typically start at the left margin, but may be indented by\n" +
+ "up to three spaces. List markers must be followed by one or more spaces\n" +
+ "or a tab."),
+
+ para("To make lists look nice, you can wrap items with hanging indents:"),
+
+ verb("* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.\n",
+ " Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,\n",
+ " viverra nec, fringilla in, laoreet vitae, risus.\n",
+ "* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.\n",
+ " Suspendisse id sem consectetuer libero luctus adipiscing.\n"),
+
+ para("But if you want to be lazy, you don't have to:"),
+
+ verb("* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.\n",
+ "Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,\n",
+ "viverra nec, fringilla in, laoreet vitae, risus.\n",
+ "* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.\n",
+ "Suspendisse id sem consectetuer libero luctus adipiscing.\n"),
+
+ para("If list items are separated by blank lines, Markdown will wrap the\n" +
+ "items in <code><p></code> tags in the HTML output. For example, this input:"),
+
+ verb("* Bird\n",
+ "* Magic\n"),
+
+ para("will turn into:"),
+
+ verb("<ul>\n",
+ "<li>Bird</li>\n",
+ "<li>Magic</li>\n",
+ "</ul>\n"),
+
+ para("But this:"),
+
+ verb("* Bird\n",
+ "\n",
+ "* Magic\n"),
+
+ para("will turn into:"),
+
+ verb("<ul>\n",
+ "<li><p>Bird</p></li>\n",
+ "<li><p>Magic</p></li>\n",
+ "</ul>\n"),
+
+ para("List items may consist of multiple paragraphs. Each subsequent\n" +
+ "paragraph in a list item must be intended by either 4 spaces\n" +
+ "or one tab:"),
+
+ verb("1. This is a list item with two paragraphs. Lorem ipsum dolor\n",
+ " sit amet, consectetuer adipiscing elit. Aliquam hendrerit\n",
+ " mi posuere lectus.\n",
+ "\n",
+ " Vestibulum enim wisi, viverra nec, fringilla in, laoreet\n",
+ " vitae, risus. Donec sit amet nisl. Aliquam semper ipsum\n",
+ " sit amet velit.\n",
+ "\n",
+ "2. Suspendisse id sem consectetuer libero luctus adipiscing.\n"),
+
+ para("It looks nice if you indent every line of the subsequent\n" +
+ "paragraphs, but here again, Markdown will allow you to be\n" +
+ "lazy:"),
+
+ verb("* This is a list item with two paragraphs.\n",
+ "\n",
+ " This is the second paragraph in the list item. You're\n",
+ "only required to indent the first line. Lorem ipsum dolor\n",
+ "sit amet, consectetuer adipiscing elit.\n",
+ "\n",
+ "* Another item in the same list.\n"),
+
+ para("To put a blockquote within a list item, the blockquote's <code>></code>\n" +
+ "delimiters need to be indented:"),
+
+ verb("* A list item with a blockquote:\n",
+ "\n",
+ " > This is a blockquote\n",
+ " > inside a list item.\n"),
+
+ para(
+ "To put a code block within a list item, the code block needs\n" +
+ "to be indented _twice_ -- 8 spaces or two tabs:"),
+
+ verb("* A list item with a code block:\n",
+ "\n",
+ " <code goes here>\n"),
+
+ para("It's worth noting that it's possible to trigger an ordered list by\n" +
+ "accident, by writing something like this:"),
+
+ verb("1986. What a great season.\n"),
+
+ para("In other words, a <em>number-period-space</em> sequence at the beginning of a\n" +
+ "line. To avoid this, you can backslash-escape the period:"),
+
+ verb("1986\\. What a great season.\n"),
+
+ raw("<h3 id=\"precode\">Code Blocks</h3>"),
+
+ para("Pre-formatted code blocks are used for writing about programming or\n" +
+ "markup source code. Rather than forming normal paragraphs, the lines\n" +
+ "of a code block are interpreted literally. Markdown wraps a code block\n" +
+ "in both <code><pre></code> and <code><code></code> tags."),
+
+ para("To produce a code block in Markdown, simply indent every line of the\n" +
+ "block by at least 4 spaces or 1 tab. For example, given this input:"),
+
+ verb("This is a normal paragraph:\n",
+ "\n",
+ " This is a code block.\n"),
+
+ para("Markdown will generate:"),
+
+ verb("<p>This is a normal paragraph:</p>\n",
+ "\n",
+ "<pre><code>This is a code block.\n",
+ "</code></pre>\n"),
+
+ para("One level of indentation -- 4 spaces or 1 tab -- is removed from each\n" +
+ "line of the code block. For example, this:"),
+
+ verb("Here is an example of AppleScript:\n",
+ "\n",
+ " tell application \"Foo\"\n",
+ " beep\n",
+ " end tell\n"),
+
+ para("will turn into:"),
+
+ verb("<p>Here is an example of AppleScript:</p>\n",
+ "\n",
+ "<pre><code>tell application \"Foo\"\n",
+ " beep\n",
+ "end tell\n",
+ "</code></pre>\n"),
+
+ para("A code block continues until it reaches a line that is not indented\n" +
+ "(or the end of the article)."),
+
+ para("Within a code block, ampersands (<code>&</code>) and angle brackets (<code><</code> and <code>></code>)\n" +
+ "are automatically converted into HTML entities. This makes it very\n" +
+ "easy to include example HTML source code using Markdown -- just paste\n" +
+ "it and indent it, and Markdown will handle the hassle of encoding the\n" +
+ "ampersands and angle brackets. For example, this:"),
+
+ verb(" <div class=\"footer\">\n",
+ " &copy; 2004 Foo Corporation\n",
+ " </div>\n"),
+
+ para("will turn into:"),
+
+ verb("<pre><code>&lt;div class=\"footer\"&gt;\n",
+ " &amp;copy; 2004 Foo Corporation\n",
+ "&lt;/div&gt;\n",
+ "</code></pre>\n"),
+
+ para("Regular Markdown syntax is not processed within code blocks. E.g.,\n" +
+ "asterisks are just literal asterisks within a code block. This means\n" +
+ "it's also easy to use Markdown to write about Markdown's own syntax."),
+
+ raw("<h3 id=\"hr\">Horizontal Rules</h3>"),
+
+ para("You can produce a horizontal rule tag (<code><hr /></code>) by placing three or\n" +
+ "more hyphens, asterisks, or underscores on a line by themselves. If you\n" +
+ "wish, you may use spaces between the hyphens or asterisks. Each of the\n" +
+ "following lines will produce a horizontal rule:"),
+
+ verb("* * *\n",
+ "\n",
+ "***\n",
+ "\n",
+ "*****\n",
+ "\n",
+ "- - -\n",
+ "\n",
+ "---------------------------------------\n",
+ "\n",
+ "_ _ _\n"),
+
+ rule(1),
+
+ raw("<h2 id=\"span\">Span Elements</h2>"),
+
+ raw("<h3 id=\"link\">Links</h3>"),
+
+ para("Markdown supports two style of links: _inline_ and _reference_."),
+
+ para("In both styles, the link text is delimited by [square brackets]."),
+
+ para("To create an inline link, use a set of regular parentheses immediately\n" +
+ "after the link text's closing square bracket. Inside the parentheses,\n" +
+ "put the URL where you want the link to point, along with an _optional_\n" +
+ "title for the link, surrounded in quotes. For example:"),
+
+ verb("This is [an example](http://example.com/ \"Title\") inline link.\n",
+ "\n",
+ "[This link](http://example.net/) has no title attribute.\n"),
+
+ para("Will produce:"),
+
+ verb("<p>This is <a href=\"http://example.com/\" title=\"Title\">\n",
+ "an example</a> inline link.</p>\n",
+ "\n",
+ "<p><a href=\"http://example.net/\">This link</a> has no\n",
+ "title attribute.</p>\n"),
+
+ para("If you're referring to a local resource on the same server, you can\n" +
+ "use relative paths:"),
+
+ verb("See my [About](/about/) page for details.\n"),
+
+ para("Reference-style links use a second set of square brackets, inside\n" +
+ "which you place a label of your choosing to identify the link:"),
+
+ verb("This is [an example][id] reference-style link.\n"),
+
+ para("You can optionally use a space to separate the sets of brackets:"),
+
+ verb("This is [an example] [id] reference-style link.\n"),
+
+ para("Then, anywhere in the document, you define your link label like this,\n" +
+ "on a line by itself:"),
+
+ verb("[id]: http://example.com/ \"Optional Title Here\"\n"),
+
+ para("That is:"),
+
+ list(:BULLET,
+ item(nil,
+ para("Square brackets containing the link identifier (optionally\n" +
+ "indented from the left margin using up to three spaces);")),
+ item(nil,
+ para("followed by a colon;")),
+ item(nil,
+ para("followed by one or more spaces (or tabs);")),
+ item(nil,
+ para("followed by the URL for the link;")),
+ item(nil,
+ para("optionally followed by a title attribute for the link, enclosed\n" +
+ "in double or single quotes."))),
+
+ para("The link URL may, optionally, be surrounded by angle brackets:"),
+
+ verb("[id]: <http://example.com/> \"Optional Title Here\"\n"),
+
+ para("You can put the title attribute on the next line and use extra spaces\n" +
+ "or tabs for padding, which tends to look better with longer URLs:"),
+
+ verb("[id]: http://example.com/longish/path/to/resource/here\n",
+ " \"Optional Title Here\"\n"),
+
+ para("Link definitions are only used for creating links during Markdown\n" +
+ "processing, and are stripped from your document in the HTML output."),
+
+ para("Link definition names may constist of letters, numbers, spaces, and punctuation -- but they are _not_ case sensitive. E.g. these two links:"),
+
+ verb("[link text][a]\n",
+ "[link text][A]\n"),
+
+ para("are equivalent."),
+
+ para("The <em>implicit link name</em> shortcut allows you to omit the name of the\n" +
+ "link, in which case the link text itself is used as the name.\n" +
+ "Just use an empty set of square brackets -- e.g., to link the word\n" +
+ "\"Google\" to the google.com web site, you could simply write:"),
+
+ verb("[Google][]\n"),
+
+ para("And then define the link:"),
+
+ verb("[Google]: http://google.com/\n"),
+
+ para("Because link names may contain spaces, this shortcut even works for\n" +
+ "multiple words in the link text:"),
+
+
+ verb("Visit [Daring Fireball][] for more information.\n"),
+
+ para("And then define the link:"),
+
+ verb("[Daring Fireball]: http://daringfireball.net/\n"),
+
+ para("Link definitions can be placed anywhere in your Markdown document. I\n" +
+ "tend to put them immediately after each paragraph in which they're\n" +
+ "used, but if you want, you can put them all at the end of your\n" +
+ "document, sort of like footnotes."),
+
+ para("Here's an example of reference links in action:"),
+
+ verb("I get 10 times more traffic from [Google] [1] than from\n",
+ "[Yahoo] [2] or [MSN] [3].\n",
+ "\n",
+ " [1]: http://google.com/ \"Google\"\n",
+ " [2]: http://search.yahoo.com/ \"Yahoo Search\"\n",
+ " [3]: http://search.msn.com/ \"MSN Search\"\n"),
+
+ para("Using the implicit link name shortcut, you could instead write:"),
+
+ verb("I get 10 times more traffic from [Google][] than from\n",
+ "[Yahoo][] or [MSN][].\n",
+ "\n",
+ " [google]: http://google.com/ \"Google\"\n",
+ " [yahoo]: http://search.yahoo.com/ \"Yahoo Search\"\n",
+ " [msn]: http://search.msn.com/ \"MSN Search\"\n"),
+
+ para("Both of the above examples will produce the following HTML output:"),
+
+ verb("<p>I get 10 times more traffic from <a href=\"http://google.com/\"\n",
+ "title=\"Google\">Google</a> than from\n",
+ "<a href=\"http://search.yahoo.com/\" title=\"Yahoo Search\">Yahoo</a>\n",
+ "or <a href=\"http://search.msn.com/\" title=\"MSN Search\">MSN</a>.</p>\n"),
+
+ para("For comparison, here is the same paragraph written using\n" +
+ "Markdown's inline link style:"),
+
+ verb("I get 10 times more traffic from [Google](http://google.com/ \"Google\")\n",
+ "than from [Yahoo](http://search.yahoo.com/ \"Yahoo Search\") or\n",
+ "[MSN](http://search.msn.com/ \"MSN Search\").\n"),
+
+ para("The point of reference-style links is not that they're easier to\n" +
+ "write. The point is that with reference-style links, your document\n" +
+ "source is vastly more readable. Compare the above examples: using\n" +
+ "reference-style links, the paragraph itself is only 81 characters\n" +
+ "long; with inline-style links, it's 176 characters; and as raw HTML,\n" +
+ "it's 234 characters. In the raw HTML, there's more markup than there\n" +
+ "is text."),
+
+ para("With Markdown's reference-style links, a source document much more\n" +
+ "closely resembles the final output, as rendered in a browser. By\n" +
+ "allowing you to move the markup-related metadata out of the paragraph,\n" +
+ "you can add links without interrupting the narrative flow of your\n" +
+ "prose."),
+
+ raw("<h3 id=\"em\">Emphasis</h3>"),
+
+ para("Markdown treats asterisks (<code>*</code>) and underscores (<code>_</code>) as indicators of\n" +
+ "emphasis. Text wrapped with one <code>*</code> or <code>_</code> will be wrapped with an\n" +
+ "HTML <code><em></code> tag; double <code>*</code>'s or <code>_</code>'s will be wrapped with an HTML\n" +
+ "<code><strong></code> tag. E.g., this input:"),
+
+ verb("*single asterisks*\n",
+ "\n",
+ "_single underscores_\n",
+ "\n",
+ "**double asterisks**\n",
+ "\n",
+ "__double underscores__\n"),
+
+ para("will produce:"),
+
+ verb("<em>single asterisks</em>\n",
+ "\n",
+ "<em>single underscores</em>\n",
+ "\n",
+ "<strong>double asterisks</strong>\n",
+ "\n",
+ "<strong>double underscores</strong>\n"),
+
+ para("You can use whichever style you prefer; the lone restriction is that\n" +
+ "the same character must be used to open and close an emphasis span."),
+
+ para("Emphasis can be used in the middle of a word:"),
+
+ verb("un*fucking*believable\n"),
+
+ para("But if you surround an <code>*</code> or <code>_</code> with spaces, it'll be treated as a\n" +
+ "literal asterisk or underscore."),
+
+ para("To produce a literal asterisk or underscore at a position where it\n" +
+ "would otherwise be used as an emphasis delimiter, you can backslash\n" +
+ "escape it:"),
+
+ verb("\\*this text is surrounded by literal asterisks\\*\n"),
+
+ raw("<h3 id=\"code\">Code</h3>"),
+
+ para("To indicate a span of code, wrap it with backtick quotes (<code>`</code>).\n" +
+ "Unlike a pre-formatted code block, a code span indicates code within a\n" +
+ "normal paragraph. For example:"),
+
+ verb("Use the `printf()` function.\n"),
+
+ para("will produce:"),
+
+ verb("<p>Use the <code>printf()</code> function.</p>\n"),
+
+ para("To include a literal backtick character within a code span, you can use\n" +
+ "multiple backticks as the opening and closing delimiters:"),
+
+ verb("``There is a literal backtick (`) here.``\n"),
+
+ para("which will produce this:"),
+
+ verb("<p><code>There is a literal backtick (`) here.</code></p>\n"),
+
+ para("The backtick delimiters surrounding a code span may include spaces --\n" +
+ "one after the opening, one before the closing. This allows you to place\n" +
+ "literal backtick characters at the beginning or end of a code span:"),
+
+ verb("A single backtick in a code span: `` ` ``\n",
+ "\n",
+ "A backtick-delimited string in a code span: `` `foo` ``\n"),
+
+ para("will produce:"),
+
+ verb("<p>A single backtick in a code span: <code>`</code></p>\n",
+ "\n",
+ "<p>A backtick-delimited string in a code span: <code>`foo`</code></p>\n"),
+
+ para("With a code span, ampersands and angle brackets are encoded as HTML\n" +
+ "entities automatically, which makes it easy to include example HTML\n" +
+ "tags. Markdown will turn this:"),
+
+ verb("Please don't use any `<blink>` tags.\n"),
+
+ para("into:"),
+
+ verb("<p>Please don't use any <code>&lt;blink&gt;</code> tags.</p>\n"),
+
+ para("You can write this:"),
+
+ verb("`&#8212;` is the decimal-encoded equivalent of `&mdash;`.\n"),
+
+ para("to produce:"),
+
+ verb( "<p><code>&amp;#8212;</code> is the decimal-encoded\n",
+ "equivalent of <code>&amp;mdash;</code>.</p>\n"),
+
+ raw("<h3 id=\"img\">Images</h3>"),
+
+ para("Admittedly, it's fairly difficult to devise a \"natural\" syntax for\n" +
+ "placing images into a plain text document format."),
+
+ para("Markdown uses an image syntax that is intended to resemble the syntax\n" +
+ "for links, allowing for two styles: _inline_ and _reference_."),
+
+ para("Inline image syntax looks like this:"),
+
+ verb("![Alt text](/path/to/img.jpg)\n",
+ "\n",
+ "![Alt text](/path/to/img.jpg \"Optional title\")\n"),
+
+ para("That is:"),
+
+ list(:BULLET,
+ item(nil,
+ para("An exclamation mark: <code>!</code>;")),
+ item(nil,
+ para("followed by a set of square brackets, containing the <code>alt</code>\n" +
+ "attribute text for the image;")),
+ item(nil,
+ para("followed by a set of parentheses, containing the URL or path to\n" +
+ "the image, and an optional <code>title</code> attribute enclosed in double\n" +
+ "or single quotes."))),
+
+ para("Reference-style image syntax looks like this:"),
+
+ verb("![Alt text][id]\n"),
+
+ para("Where \"id\" is the name of a defined image reference. Image references\n" +
+ "are defined using syntax identical to link references:"),
+
+ verb("[id]: url/to/image \"Optional title attribute\"\n"),
+
+ para("As of this writing, Markdown has no syntax for specifying the\n" +
+ "dimensions of an image; if this is important to you, you can simply\n" +
+ "use regular HTML <code><img></code> tags."),
+
+ rule(1),
+
+ raw("<h2 id=\"misc\">Miscellaneous</h2>"),
+
+ raw("<h3 id=\"autolink\">Automatic Links</h3>"),
+
+ para("Markdown supports a shortcut style for creating \"automatic\" links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this:"),
+
+ verb("<http://example.com/>\n"),
+
+ para("Markdown will turn this into:"),
+
+ verb("<a href=\"http://example.com/\">http://example.com/</a>\n"),
+
+ para("Automatic links for email addresses work similarly, except that\n" +
+ "Markdown will also perform a bit of randomized decimal and hex\n" +
+ "entity-encoding to help obscure your address from address-harvesting\n" +
+ "spambots. For example, Markdown will turn this:"),
+
+ verb("<address@example.com>\n"),
+
+ para("into something like this:"),
+
+ verb("<a href=\"&#x6D;&#x61;i&#x6C;&#x74;&#x6F;:&#x61;&#x64;&#x64;&#x72;&#x65;\n",
+ "&#115;&#115;&#64;&#101;&#120;&#x61;&#109;&#x70;&#x6C;e&#x2E;&#99;&#111;\n",
+ "&#109;\">&#x61;&#x64;&#x64;&#x72;&#x65;&#115;&#115;&#64;&#101;&#120;&#x61;\n",
+ "&#109;&#x70;&#x6C;e&#x2E;&#99;&#111;&#109;</a>\n"),
+
+ para("which will render in a browser as a clickable link to \"address@example.com\"."),
+
+ para("(This sort of entity-encoding trick will indeed fool many, if not\n" +
+ "most, address-harvesting bots, but it definitely won't fool all of\n" +
+ "them. It's better than nothing, but an address published in this way\n" +
+ "will probably eventually start receiving spam.)"),
+
+ raw("<h3 id=\"backslash\">Backslash Escapes</h3>"),
+
+ para("Markdown allows you to use backslash escapes to generate literal\n" +
+ "characters which would otherwise have special meaning in Markdown's\n" +
+ "formatting syntax. For example, if you wanted to surround a word with\n" +
+ "literal asterisks (instead of an HTML <code><em></code> tag), you can backslashes\n" +
+ "before the asterisks, like this:"),
+
+ verb("\\*literal asterisks\\*\n"),
+
+ para("Markdown provides backslash escapes for the following characters:"),
+
+ verb("\\ backslash\n",
+ "` backtick\n",
+ "* asterisk\n",
+ "_ underscore\n",
+ "{} curly braces\n",
+ "[] square brackets\n",
+ "() parentheses\n",
+ "# hash mark\n",
+ "+ plus sign\n",
+ "- minus sign (hyphen)\n",
+ ". dot\n",
+ "! exclamation mark\n"))
+
+ assert_equal expected, doc
+ end
+
+ def test_nested_blockquotes
+ input = File.read "#{MARKDOWN_TEST_PATH}/Nested blockquotes.text"
+
+ doc = @parser.parse input
+
+ expected =
+ doc(
+ block(
+ para("foo"),
+ block(
+ para("bar")),
+ para("foo")))
+
+ assert_equal expected, doc
+ end
+
+ def test_ordered_and_unordered_lists
+ input = File.read "#{MARKDOWN_TEST_PATH}/Ordered and unordered lists.text"
+
+ doc = @parser.parse input
+
+ expected =
+ doc(
+ head(2, 'Unordered'),
+
+ para('Asterisks tight:'),
+ list(:BULLET,
+ item(nil, para("asterisk 1")),
+ item(nil, para("asterisk 2")),
+ item(nil, para("asterisk 3"))),
+ para('Asterisks loose:'),
+ list(:BULLET,
+ item(nil, para("asterisk 1")),
+ item(nil, para("asterisk 2")),
+ item(nil, para("asterisk 3"))),
+
+ rule(1),
+
+ para("Pluses tight:"),
+ list(:BULLET,
+ item(nil, para("Plus 1")),
+ item(nil, para("Plus 2")),
+ item(nil, para("Plus 3"))),
+ para("Pluses loose:"),
+ list(:BULLET,
+ item(nil, para("Plus 1")),
+ item(nil, para("Plus 2")),
+ item(nil, para("Plus 3"))),
+
+ rule(1),
+
+ para("Minuses tight:"),
+ list(:BULLET,
+ item(nil, para("Minus 1")),
+ item(nil, para("Minus 2")),
+ item(nil, para("Minus 3"))),
+ para("Minuses loose:"),
+ list(:BULLET,
+ item(nil, para("Minus 1")),
+ item(nil, para("Minus 2")),
+ item(nil, para("Minus 3"))),
+
+ head(2, "Ordered"),
+
+ para("Tight:"),
+ list(:NUMBER,
+ item(nil, para("First")),
+ item(nil, para("Second")),
+ item(nil, para("Third"))),
+ para("and:"),
+ list(:NUMBER,
+ item(nil, para("One")),
+ item(nil, para("Two")),
+ item(nil, para("Three"))),
+
+ para("Loose using tabs:"),
+ list(:NUMBER,
+ item(nil, para("First")),
+ item(nil, para("Second")),
+ item(nil, para("Third"))),
+ para("and using spaces:"),
+ list(:NUMBER,
+ item(nil, para("One")),
+ item(nil, para("Two")),
+ item(nil, para("Three"))),
+
+ para("Multiple paragraphs:"),
+ list(:NUMBER,
+ item(nil,
+ para("Item 1, graf one."),
+ para("Item 2. graf two. The quick brown fox " +
+ "jumped over the lazy dog's\nback.")),
+ item(nil, para("Item 2.")),
+ item(nil, para("Item 3."))),
+
+ head(2, "Nested"),
+ list(:BULLET,
+ item(nil,
+ para("Tab"),
+ list(:BULLET,
+ item(nil,
+ para("Tab"),
+ list(:BULLET,
+ item(nil,
+ para("Tab"))))))),
+
+ para("Here's another:"),
+ list(:NUMBER,
+ item(nil, para("First")),
+ item(nil, para("Second:"),
+ list(:BULLET,
+ item(nil, para("Fee")),
+ item(nil, para("Fie")),
+ item(nil, para("Foe")))),
+ item(nil, para("Third"))),
+
+ para("Same thing but with paragraphs:"),
+ list(:NUMBER,
+ item(nil, para("First")),
+ item(nil, para("Second:"),
+ list(:BULLET,
+ item(nil, para("Fee")),
+ item(nil, para("Fie")),
+ item(nil, para("Foe")))),
+ item(nil, para("Third"))),
+
+ para("This was an error in Markdown 1.0.1:"),
+ list(:BULLET,
+ item(nil,
+ para("this"),
+ list(:BULLET,
+ item(nil, para("sub"))),
+ para("that"))))
+
+ assert_equal expected, doc
+ end
+
+ def test_strong_and_em_together
+ input = File.read "#{MARKDOWN_TEST_PATH}/Strong and em together.text"
+
+ doc = @parser.parse input
+
+ expected =
+ doc(
+ para("<b><em>This is strong and em.</em></b>"),
+ para("So is <b>_this_</b> word."),
+ para("<b><em>This is strong and em.</em></b>"),
+ para("So is <b>_this_</b> word."))
+
+ assert_equal expected, doc
+ end
+
+ def test_tabs
+ input = File.read "#{MARKDOWN_TEST_PATH}/Tabs.text"
+
+ doc = @parser.parse input
+
+ expected =
+ doc(
+ list(:BULLET,
+ item(nil,
+ para("this is a list item\nindented with tabs")),
+ item(nil,
+ para("this is a list item\nindented with spaces"))),
+
+ para("Code:"),
+
+ verb("this code block is indented by one tab\n"),
+
+ para("And:"),
+
+ verb("\tthis code block is indented by two tabs\n"),
+
+ para("And:"),
+
+ verb(
+ "+\tthis is an example list item\n",
+ "\tindented with tabs\n",
+ "\n",
+ "+ this is an example list item\n",
+ " indented with spaces\n"))
+
+ assert_equal expected, doc
+ end
+
+ def test_tidyness
+ input = File.read "#{MARKDOWN_TEST_PATH}/Tidyness.text"
+
+ doc = @parser.parse input
+
+ expected =
+ doc(
+ block(
+ para("A list within a blockquote:"),
+ list(:BULLET,
+ item(nil, para("asterisk 1")),
+ item(nil, para("asterisk 2")),
+ item(nil, para("asterisk 3")))))
+
+ assert_equal expected, doc
+ end
+
+end
+
diff --git a/test/rdoc/test_rdoc_markup.rb b/test/rdoc/test_rdoc_markup.rb
index ae6c11e7da..5c28a2c6e6 100644
--- a/test/rdoc/test_rdoc_markup.rb
+++ b/test/rdoc/test_rdoc_markup.rb
@@ -1,9 +1,13 @@
-require 'rubygems'
-require 'minitest/autorun'
-require 'rdoc/markup'
-require 'rdoc/markup/to_test'
+require 'rdoc/test_case'
-class TestRDocMarkup < MiniTest::Unit::TestCase
+class TestRDocMarkup < RDoc::TestCase
+
+ def test_class_parse
+ expected = @RM::Document.new(
+ @RM::Paragraph.new('hello'))
+
+ assert_equal expected, RDoc::Markup.parse('hello')
+ end
def test_convert
str = <<-STR
@@ -44,7 +48,7 @@ the time
m = RDoc::Markup.new
m.add_word_pair '{', '}', :STRIKE
- tt = RDoc::Markup::ToTest.new m
+ tt = RDoc::Markup::ToTest.new nil, m
tt.add_tag :STRIKE, 'STRIKE ', ' STRIKE'
out = m.convert str, tt
diff --git a/test/rdoc/test_rdoc_markup_attribute_manager.rb b/test/rdoc/test_rdoc_markup_attribute_manager.rb
index b65457fc7e..36edea3f73 100644
--- a/test/rdoc/test_rdoc_markup_attribute_manager.rb
+++ b/test/rdoc/test_rdoc_markup_attribute_manager.rb
@@ -1,13 +1,10 @@
-require 'rubygems'
-require 'minitest/autorun'
-require 'rdoc'
-require 'rdoc/markup'
-require 'rdoc/markup/inline'
-require 'rdoc/markup/to_html_crossref'
+require 'rdoc/test_case'
-class TestRDocMarkupAttributeManager < MiniTest::Unit::TestCase
+class TestRDocMarkupAttributeManager < RDoc::TestCase
def setup
+ super
+
@am = RDoc::Markup::AttributeManager.new
@bold_on = @am.changed_attribute_by_name([], [:BOLD])
@@ -32,8 +29,8 @@ class TestRDocMarkupAttributeManager < MiniTest::Unit::TestCase
end
def crossref(text)
- crossref_bitmap = RDoc::Markup::Attribute.bitmap_for(:_SPECIAL_) |
- RDoc::Markup::Attribute.bitmap_for(:CROSSREF)
+ crossref_bitmap = @am.attributes.bitmap_for(:_SPECIAL_) |
+ @am.attributes.bitmap_for(:CROSSREF)
[ @am.changed_attribute_by_name([], [:CROSSREF, :_SPECIAL_]),
RDoc::Markup::Special.new(crossref_bitmap, text),
@@ -212,7 +209,7 @@ class TestRDocMarkupAttributeManager < MiniTest::Unit::TestCase
end
def test_special
- @am.add_special(RDoc::Markup::ToHtmlCrossref::CROSSREF_REGEXP, :CROSSREF)
+ @am.add_special(RDoc::CrossReference::CROSSREF_REGEXP, :CROSSREF)
#
# The apostrophes in "cats'" and "dogs'" suppress the flagging of these
diff --git a/test/rdoc/test_rdoc_markup_attributes.rb b/test/rdoc/test_rdoc_markup_attributes.rb
new file mode 100644
index 0000000000..636e0cca68
--- /dev/null
+++ b/test/rdoc/test_rdoc_markup_attributes.rb
@@ -0,0 +1,39 @@
+require 'rdoc/test_case'
+
+class TestRDocMarkupAttributes < RDoc::TestCase
+
+ def setup
+ super
+
+ @as = RDoc::Markup::Attributes.new
+ end
+
+ def test_bitmap_for
+ assert_equal 2, @as.bitmap_for('two')
+ assert_equal 2, @as.bitmap_for('two')
+ assert_equal 4, @as.bitmap_for('three')
+ end
+
+ def test_as_string
+ @as.bitmap_for 'two'
+ @as.bitmap_for 'three'
+
+ assert_equal 'none', @as.as_string(0)
+ assert_equal '_SPECIAL_', @as.as_string(1)
+ assert_equal 'two', @as.as_string(2)
+ assert_equal '_SPECIAL_,two', @as.as_string(3)
+ end
+
+ def test_each_name_of
+ @as.bitmap_for 'two'
+ @as.bitmap_for 'three'
+
+ assert_equal %w[], @as.each_name_of(0).to_a
+ assert_equal %w[], @as.each_name_of(1).to_a
+ assert_equal %w[two], @as.each_name_of(2).to_a
+ assert_equal %w[three], @as.each_name_of(4).to_a
+ assert_equal %w[two three], @as.each_name_of(6).to_a
+ end
+
+end
+
diff --git a/test/rdoc/test_rdoc_markup_document.rb b/test/rdoc/test_rdoc_markup_document.rb
index 9eea019ae4..564434dfe6 100644
--- a/test/rdoc/test_rdoc_markup_document.rb
+++ b/test/rdoc/test_rdoc_markup_document.rb
@@ -1,12 +1,10 @@
-require 'pp'
-require 'rubygems'
-require 'minitest/autorun'
-require 'rdoc/markup'
+require 'rdoc/test_case'
-class TestRDocMarkupDocument < MiniTest::Unit::TestCase
+class TestRDocMarkupDocument < RDoc::TestCase
def setup
- @RM = RDoc::Markup
+ super
+
@d = @RM::Document.new
end
@@ -47,6 +45,21 @@ class TestRDocMarkupDocument < MiniTest::Unit::TestCase
end
end
+ def test_concat
+ @d.concat [@RM::BlankLine.new, @RM::BlankLine.new]
+
+ refute_empty @d
+ end
+
+ def test_each
+ a = @RM::Document.new
+ b = @RM::Document.new(@RM::Paragraph.new('hi'))
+
+ @d.push a, b
+
+ assert_equal [a, b], @d.map { |sub_doc| sub_doc }
+ end
+
def test_empty_eh
assert_empty @d
@@ -82,6 +95,18 @@ class TestRDocMarkupDocument < MiniTest::Unit::TestCase
assert_equal @d, d2
end
+ def test_file_equals
+ @d.file = 'file.rb'
+
+ assert_equal 'file.rb', @d.file
+ end
+
+ def test_file_equals_top_level
+ @d.file = @store.add_file 'file.rb'
+
+ assert_equal 'file.rb', @d.file
+ end
+
def test_lt2
@d << @RM::BlankLine.new
@@ -148,5 +173,23 @@ class TestRDocMarkupDocument < MiniTest::Unit::TestCase
refute_empty @d
end
+ def test_table_of_contents
+ doc = @RM::Document.new(
+ @RM::Heading.new(1, 'A'),
+ @RM::Paragraph.new('B'),
+ @RM::Heading.new(2, 'C'),
+ @RM::Paragraph.new('D'),
+ @RM::Heading.new(1, 'E'),
+ @RM::Paragraph.new('F'))
+
+ expected = [
+ @RM::Heading.new(1, 'A'),
+ @RM::Heading.new(2, 'C'),
+ @RM::Heading.new(1, 'E'),
+ ]
+
+ assert_equal expected, doc.table_of_contents
+ end
+
end
diff --git a/test/rdoc/test_rdoc_markup_formatter.rb b/test/rdoc/test_rdoc_markup_formatter.rb
index 73e75e2aa1..9512babce3 100644
--- a/test/rdoc/test_rdoc_markup_formatter.rb
+++ b/test/rdoc/test_rdoc_markup_formatter.rb
@@ -1,17 +1,13 @@
-require 'rubygems'
-require 'minitest/autorun'
-require 'rdoc'
-require 'rdoc/markup'
-require 'rdoc/markup/formatter'
+require 'rdoc/test_case'
-class TestRDocMarkupFormatter < MiniTest::Unit::TestCase
+class TestRDocMarkupFormatter < RDoc::TestCase
class ToTest < RDoc::Markup::Formatter
def initialize markup
- super
+ super nil, markup
- add_tag :TT, '<tt>', '</tt>'
+ add_tag :TT, '<code>', '</code>'
end
def accept_paragraph paragraph
@@ -37,20 +33,25 @@ class TestRDocMarkupFormatter < MiniTest::Unit::TestCase
end
def setup
- @markup = RDoc::Markup.new
+ super
+
+ @markup = @RM.new
@markup.add_special(/[A-Z]+/, :CAPS)
+ @attribute_manager = @markup.attribute_manager
+ @attributes = @attribute_manager.attributes
+
@to = ToTest.new @markup
- @caps = RDoc::Markup::Attribute.bitmap_for :CAPS
- @special = RDoc::Markup::Attribute.bitmap_for :_SPECIAL_
- @tt = RDoc::Markup::Attribute.bitmap_for :TT
+ @caps = @attributes.bitmap_for :CAPS
+ @special = @attributes.bitmap_for :_SPECIAL_
+ @tt = @attributes.bitmap_for :TT
end
def test_convert_tt_special
- converted = @to.convert '<tt>AAA</tt>'
+ converted = @to.convert '<code>AAA</code>'
- assert_equal '<tt>AAA</tt>', converted
+ assert_equal '<code>AAA</code>', converted
end
end
diff --git a/test/rdoc/test_rdoc_markup_hard_break.rb b/test/rdoc/test_rdoc_markup_hard_break.rb
new file mode 100644
index 0000000000..b9f7873160
--- /dev/null
+++ b/test/rdoc/test_rdoc_markup_hard_break.rb
@@ -0,0 +1,31 @@
+require 'rdoc/test_case'
+
+class TestRDocMarkupHardBreak < RDoc::TestCase
+
+ def setup
+ super
+
+ @hb = RDoc::Markup::HardBreak.new
+ end
+
+ def test_accept
+ visitor = Object.new
+
+ def visitor.accept_hard_break(obj) @obj = obj end
+ def visitor.obj() @obj end
+
+ @hb.accept visitor
+
+ assert_same @hb, visitor.obj
+ end
+
+ def test_equals2
+ other = RDoc::Markup::HardBreak.new
+
+ assert_equal @hb, other
+
+ refute_equal @hb, Object.new
+ end
+
+end
+
diff --git a/test/rdoc/test_rdoc_markup_heading.rb b/test/rdoc/test_rdoc_markup_heading.rb
new file mode 100644
index 0000000000..eef051a64e
--- /dev/null
+++ b/test/rdoc/test_rdoc_markup_heading.rb
@@ -0,0 +1,20 @@
+require 'rdoc/test_case'
+
+class TestRDocMarkupHeading < RDoc::TestCase
+
+ def setup
+ super
+
+ @h = RDoc::Markup::Heading.new 1, 'Hello *Friend*!'
+ end
+
+ def test_aref
+ assert_equal 'label-Hello+Friend%21', @h.aref
+ end
+
+ def test_plain_html
+ assert_equal 'Hello <strong>Friend</strong>!', @h.plain_html
+ end
+
+end
+
diff --git a/test/rdoc/test_rdoc_markup_include.rb b/test/rdoc/test_rdoc_markup_include.rb
new file mode 100644
index 0000000000..37a5b320e9
--- /dev/null
+++ b/test/rdoc/test_rdoc_markup_include.rb
@@ -0,0 +1,19 @@
+require 'rdoc/test_case'
+
+class TestRDocMarkupInclude < RDoc::TestCase
+
+ def setup
+ super
+
+ @include = @RM::Include.new 'file', [Dir.tmpdir]
+ end
+
+ def test_equals2
+ assert_equal @include, @RM::Include.new('file', [Dir.tmpdir])
+ refute_equal @include, @RM::Include.new('file', %w[.])
+ refute_equal @include, @RM::Include.new('other', [Dir.tmpdir])
+ refute_equal @include, Object.new
+ end
+
+end
+
diff --git a/test/rdoc/test_rdoc_markup_indented_paragraph.rb b/test/rdoc/test_rdoc_markup_indented_paragraph.rb
index e3e2b630e1..d8dd795e5b 100644
--- a/test/rdoc/test_rdoc_markup_indented_paragraph.rb
+++ b/test/rdoc/test_rdoc_markup_indented_paragraph.rb
@@ -1,11 +1,10 @@
-require 'pp'
-require 'rubygems'
-require 'minitest/autorun'
-require 'rdoc/markup'
+require 'rdoc/test_case'
-class TestRDocMarkupIndentedParagraph < MiniTest::Unit::TestCase
+class TestRDocMarkupIndentedParagraph < RDoc::TestCase
def setup
+ super
+
@IP = RDoc::Markup::IndentedParagraph
end
@@ -36,5 +35,19 @@ class TestRDocMarkupIndentedParagraph < MiniTest::Unit::TestCase
refute_equal one, two
end
+ def test_text
+ paragraph = @IP.new(2, 'hello', ' world')
+
+ assert_equal 'hello world', paragraph.text
+ end
+
+ def test_text_break
+ paragraph = @IP.new(2, 'hello', hard_break, 'world')
+
+ assert_equal 'helloworld', paragraph.text
+
+ assert_equal "hello\n world", paragraph.text("\n")
+ end
+
end
diff --git a/test/rdoc/test_rdoc_markup_paragraph.rb b/test/rdoc/test_rdoc_markup_paragraph.rb
index 6ae1ad9a84..8de1c3cff5 100644
--- a/test/rdoc/test_rdoc_markup_paragraph.rb
+++ b/test/rdoc/test_rdoc_markup_paragraph.rb
@@ -1,9 +1,6 @@
-require 'pp'
-require 'rubygems'
-require 'minitest/autorun'
-require 'rdoc/markup'
+require 'rdoc/test_case'
-class TestRDocMarkupParagraph < MiniTest::Unit::TestCase
+class TestRDocMarkupParagraph < RDoc::TestCase
def test_accept
visitor = Object.new
@@ -14,7 +11,21 @@ class TestRDocMarkupParagraph < MiniTest::Unit::TestCase
paragraph.accept visitor
- assert_equal paragraph, visitor.obj
+ assert_same paragraph, visitor.obj
+ end
+
+ def test_text
+ paragraph = para('hello', ' world')
+
+ assert_equal 'hello world', paragraph.text
+ end
+
+ def test_text_break
+ paragraph = para('hello', hard_break, 'world')
+
+ assert_equal 'helloworld', paragraph.text
+
+ assert_equal "hello\nworld", paragraph.text("\n")
end
end
diff --git a/test/rdoc/test_rdoc_markup_parser.rb b/test/rdoc/test_rdoc_markup_parser.rb
index e214c4defc..45f911acd1 100644
--- a/test/rdoc/test_rdoc_markup_parser.rb
+++ b/test/rdoc/test_rdoc_markup_parser.rb
@@ -1,14 +1,12 @@
# coding: utf-8
-require 'pp'
-require 'rubygems'
-require 'minitest/autorun'
-require 'rdoc/markup'
+require 'rdoc/test_case'
-class TestRDocMarkupParser < MiniTest::Unit::TestCase
+class TestRDocMarkupParser < RDoc::TestCase
def setup
- @RM = RDoc::Markup
+ super
+
@RMP = @RM::Parser
end
@@ -30,6 +28,19 @@ class TestRDocMarkupParser < MiniTest::Unit::TestCase
assert_equal @RM::Heading.new(3, 'heading three'), parser.build_heading(3)
end
+ def test_char_pos
+ parser = @RMP.new
+ s = parser.setup_scanner 'cät'
+
+ s.scan(/\S+/)
+
+ if Object.const_defined? :Encoding then
+ assert_equal 3, parser.char_pos(s.pos)
+ else
+ assert_equal 4, parser.char_pos(s.pos)
+ end
+ end
+
def test_get
parser = util_parser
@@ -148,13 +159,11 @@ the time
STR
expected = [
- @RM::List.new(:BULLET, *[
- @RM::ListItem.new(nil,
- @RM::Paragraph.new('l1', 'l1+')),
- @RM::ListItem.new(nil,
- @RM::Paragraph.new('l2')),
- ]),
- ]
+ list(:BULLET,
+ item(nil,
+ para('l1 ', 'l1+')),
+ item(nil,
+ para('l2')))]
assert_equal expected, @RMP.parse(str).parts
end
@@ -191,16 +200,16 @@ the time
STR
expected = [
- @RM::List.new(:BULLET, *[
- @RM::ListItem.new(nil,
- @RM::Paragraph.new('l1'),
- @RM::List.new(:BULLET, *[
- @RM::ListItem.new(nil,
- @RM::Paragraph.new('l1.1', 'text'),
- @RM::Verbatim.new("code\n", " code\n"),
- @RM::Paragraph.new('text'))])),
- @RM::ListItem.new(nil,
- @RM::Paragraph.new('l2'))])]
+ list(:BULLET,
+ item(nil,
+ para('l1'),
+ list(:BULLET,
+ item(nil,
+ para('l1.1 ', 'text'),
+ verb("code\n", " code\n"),
+ para('text')))),
+ item(nil,
+ para('l2')))]
assert_equal expected, @RMP.parse(str).parts
end
@@ -326,11 +335,11 @@ the time
STR
expected = [
- @RM::List.new(:LABEL, *[
- @RM::ListItem.new('one',
- @RM::Paragraph.new('item one')),
- @RM::ListItem.new('two',
- @RM::Paragraph.new('item two'))])]
+ list(:LABEL,
+ item(%w[one],
+ para('item one')),
+ item(%w[two],
+ para('item two')))]
assert_equal expected, @RMP.parse(str).parts
end
@@ -343,19 +352,33 @@ the time
STR
expected = [
- @RM::List.new(:LABEL, *[
- @RM::ListItem.new('cat',
- @RM::Paragraph.new('l1'),
- @RM::List.new(:BULLET, *[
- @RM::ListItem.new(nil,
- @RM::Paragraph.new('l1.1'))])),
- @RM::ListItem.new('dog',
- @RM::Paragraph.new('l2'))])]
+ list(:LABEL,
+ item(%w[cat],
+ para('l1'),
+ list(:BULLET,
+ item(nil,
+ para('l1.1')))),
+ item(%w[dog],
+ para('l2')))]
+
+ assert_equal expected, @RMP.parse(str).parts
+ end
+
+ def test_parse_label_multi_label
+ str = <<-STR
+[one]
+[two] some description
+ STR
+
+ expected = [
+ list(:LABEL,
+ item(%w[one two],
+ para('some description')))]
assert_equal expected, @RMP.parse(str).parts
end
- def test_parse_label_multiline
+ def test_parse_label_multi_line
str = <<-STR
[cat] l1
continuation
@@ -363,11 +386,11 @@ the time
STR
expected = [
- @RM::List.new(:LABEL, *[
- @RM::ListItem.new('cat',
- @RM::Paragraph.new('l1', 'continuation')),
- @RM::ListItem.new('dog',
- @RM::Paragraph.new('l2'))])]
+ list(:LABEL,
+ item(%w[cat],
+ para('l1 ', 'continuation')),
+ item(%w[dog],
+ para('l2')))]
assert_equal expected, @RMP.parse(str).parts
end
@@ -381,12 +404,11 @@ the time
STR
expected = [
- @RM::List.new(:LABEL, *[
- @RM::ListItem.new('one',
- @RM::Paragraph.new('item one')),
- @RM::ListItem.new('two',
- @RM::Paragraph.new('item two')),
- ])]
+ list(:LABEL,
+ item(%w[one],
+ para('item one')),
+ item(%w[two],
+ para('item two')))]
assert_equal expected, @RMP.parse(str).parts
end
@@ -443,6 +465,17 @@ a. 新しい機能
assert_equal expected, @RMP.parse(str).parts
end
+ def test_parse_line_break
+ str = "now is\nthe time \nfor all"
+
+ expected = [
+ para('now is ', 'the time'),
+ blank_line,
+ para('for all')]
+
+ assert_equal expected, @RMP.parse(str).parts
+ end
+
def test_parse_list_list_1
str = <<-STR
10. para 1
@@ -456,16 +489,16 @@ a. 新しい機能
STR
expected = [
- @RM::List.new(:NUMBER, *[
- @RM::ListItem.new(nil, *[
- @RM::Paragraph.new('para 1'),
- @RM::BlankLine.new,
- @RM::List.new(:LABEL, *[
- @RM::ListItem.new('label 1', *[
- @RM::Paragraph.new('para 1.1'),
- @RM::BlankLine.new,
- @RM::Verbatim.new("code\n"),
- @RM::Paragraph.new('para 1.2')])])])])]
+ list(:NUMBER,
+ item(nil,
+ para('para 1'),
+ blank_line,
+ list(:LABEL,
+ item(%w[label\ 1],
+ para('para 1.1'),
+ blank_line,
+ verb("code\n"),
+ para('para 1.2')))))]
assert_equal expected, @RMP.parse(str).parts
end
@@ -479,15 +512,15 @@ a. 新しい機能
STR
expected = [
- @RM::List.new(:NUMBER, *[
- @RM::ListItem.new(nil, *[
- @RM::Paragraph.new('para'),
- @RM::BlankLine.new,
- @RM::List.new(:NOTE, *[
- @RM::ListItem.new('label 1',
- @RM::Paragraph.new('text 1')),
- @RM::ListItem.new('label 2',
- @RM::Paragraph.new('text 2'))])])])]
+ list(:NUMBER,
+ item(nil,
+ para('para'),
+ blank_line,
+ list(:NOTE,
+ item(%w[label\ 1],
+ para('text 1')),
+ item(%w[label\ 2],
+ para('text 2')))))]
assert_equal expected, @RMP.parse(str).parts
end
@@ -546,11 +579,11 @@ two:: item two
STR
expected = [
- @RM::List.new(:NOTE, *[
- @RM::ListItem.new('one',
- @RM::Paragraph.new('item one')),
- @RM::ListItem.new('two',
- @RM::Paragraph.new('item two'))])]
+ list(:NOTE,
+ item(%w[one],
+ para('item one')),
+ item(%w[two],
+ para('item two')))]
assert_equal expected, @RMP.parse(str).parts
end
@@ -562,11 +595,9 @@ two::
STR
expected = [
- @RM::List.new(:NOTE, *[
- @RM::ListItem.new('one',
- @RM::BlankLine.new),
- @RM::ListItem.new('two',
- @RM::BlankLine.new)])]
+ list(:NOTE,
+ item(%w[one two],
+ blank_line))]
assert_equal expected, @RMP.parse(str).parts
end
@@ -577,11 +608,11 @@ one:: two::
STR
expected = [
- @RM::List.new(:NOTE, *[
- @RM::ListItem.new('one',
- @RM::List.new(:NOTE, *[
- @RM::ListItem.new('two',
- @RM::BlankLine.new)]))])]
+ list(:NOTE,
+ item(%w[one],
+ list(:NOTE,
+ item(%w[two],
+ blank_line))))]
assert_equal expected, @RMP.parse(str).parts
end
@@ -594,14 +625,14 @@ one:: two::
STR
expected = [
- @RM::List.new(:NUMBER, *[
- @RM::ListItem.new(nil,
- @RM::Paragraph.new('l1'),
- @RM::List.new(:BULLET, *[
- @RM::ListItem.new(nil,
- @RM::Paragraph.new('l1.1'))])),
- @RM::ListItem.new(nil,
- @RM::Paragraph.new('l2'))])]
+ list(:NUMBER,
+ item(nil,
+ para('l1'),
+ list(:BULLET,
+ item(nil,
+ para('l1.1')))),
+ item(nil,
+ para('l2')))]
assert_equal expected, @RMP.parse(str).parts
end
@@ -623,7 +654,7 @@ for all good men
def test_parse_paragraph_multiline
str = "now is the time\nfor all good men"
- expected = @RM::Paragraph.new 'now is the time for all good men'
+ expected = @RM::Paragraph.new 'now is the time ', 'for all good men'
assert_equal [expected], @RMP.parse(str).parts
end
@@ -1185,6 +1216,38 @@ the time
assert_equal expected, @RMP.tokenize(str)
end
+ def test_tokenize_label_newline
+ str = <<-STR
+[cat]
+ l1
+ STR
+
+ expected = [
+ [:LABEL, 'cat', 0, 0],
+ [:NEWLINE, "\n", 5, 0],
+ [:TEXT, 'l1', 2, 1],
+ [:NEWLINE, "\n", 4, 1],
+ ]
+
+ assert_equal expected, @RMP.tokenize(str)
+ end
+
+ def test_tokenize_label_newline_windows
+ str = <<-STR
+[cat]\r
+ l1\r
+ STR
+
+ expected = [
+ [:LABEL, 'cat', 0, 0],
+ [:NEWLINE, "\n", 6, 0],
+ [:TEXT, 'l1', 2, 1],
+ [:NEWLINE, "\n", 5, 1],
+ ]
+
+ assert_equal expected, @RMP.tokenize(str)
+ end
+
def test_tokenize_lalpha
str = <<-STR
a. l1
@@ -1203,6 +1266,53 @@ b. l1.1
assert_equal expected, @RMP.tokenize(str)
end
+ def test_tokenize_line_break
+ str = "now is\nthe time \nfor all\n"
+
+ expected = [
+ [:TEXT, 'now is', 0, 0],
+ [:NEWLINE, "\n", 6, 0],
+ [:TEXT, 'the time', 0, 1],
+ [:BREAK, " ", 8, 1],
+ [:NEWLINE, "\n", 10, 1],
+ [:TEXT, 'for all', 0, 2],
+ [:NEWLINE, "\n", 7, 2],
+ ]
+
+ assert_equal expected, @RMP.tokenize(str)
+ end
+
+ def test_tokenize_line_break_long
+ str = "now is\nthe time \nfor all\n"
+
+ expected = [
+ [:TEXT, 'now is', 0, 0],
+ [:NEWLINE, "\n", 6, 0],
+ [:TEXT, 'the time ', 0, 1],
+ [:BREAK, ' ', 9, 1],
+ [:NEWLINE, "\n", 11, 1],
+ [:TEXT, 'for all', 0, 2],
+ [:NEWLINE, "\n", 7, 2],
+ ]
+
+ assert_equal expected, @RMP.tokenize(str)
+ end
+
+ def test_tokenize_line_break_no_short
+ str = "now is\nthe time \nfor all\n"
+
+ expected = [
+ [:TEXT, 'now is', 0, 0],
+ [:NEWLINE, "\n", 6, 0],
+ [:TEXT, 'the time ', 0, 1],
+ [:NEWLINE, "\n", 9, 1],
+ [:TEXT, 'for all', 0, 2],
+ [:NEWLINE, "\n", 7, 2],
+ ]
+
+ assert_equal expected, @RMP.tokenize(str)
+ end
+
def test_tokenize_note
str = <<-STR
cat:: l1
@@ -1237,6 +1347,64 @@ dog::
assert_equal expected, @RMP.tokenize(str)
end
+ def test_tokenize_note_newline
+ str = <<-STR
+cat::
+ l1
+ STR
+
+ expected = [
+ [:NOTE, 'cat', 0, 0],
+ [:NEWLINE, "\n", 5, 0],
+ [:TEXT, 'l1', 2, 1],
+ [:NEWLINE, "\n", 4, 1],
+ ]
+
+ assert_equal expected, @RMP.tokenize(str)
+ end
+
+ def test_tokenize_note_utf_8
+ skip 'Encoding not implemented' unless Object.const_defined? :Encoding
+
+ str = <<-STR
+cät:: l1a
+ l1b
+døg:: l2a
+ l2b
+ STR
+
+ expected = [
+ [:NOTE, 'cät', 0, 0],
+ [:TEXT, 'l1a', 6, 0],
+ [:NEWLINE, "\n", 9, 0],
+ [:TEXT, 'l1b', 6, 1],
+ [:NEWLINE, "\n", 9, 1],
+ [:NOTE, 'døg', 0, 2],
+ [:TEXT, 'l2a', 6, 2],
+ [:NEWLINE, "\n", 9, 2],
+ [:TEXT, 'l2b', 6, 3],
+ [:NEWLINE, "\n", 9, 3],
+ ]
+
+ assert_equal expected, @RMP.tokenize(str)
+ end
+
+ def test_tokenize_note_newline_windows
+ str = <<-STR
+cat::\r
+ l1\r
+ STR
+
+ expected = [
+ [:NOTE, 'cat', 0, 0],
+ [:NEWLINE, "\n", 6, 0],
+ [:TEXT, 'l1', 2, 1],
+ [:NEWLINE, "\n", 5, 1],
+ ]
+
+ assert_equal expected, @RMP.tokenize(str)
+ end
+
def test_tokenize_note_not
str = <<-STR
Cat::Dog
@@ -1363,6 +1531,24 @@ for all
assert_equal expected, @RMP.tokenize(str)
end
+ def test_tokenize_rule_windows
+ str = <<-STR
+---\r
+
+--- blah ---\r
+ STR
+
+ expected = [
+ [:RULE, 1, 0, 0],
+ [:NEWLINE, "\n", 4, 0],
+ [:NEWLINE, "\n", 0, 1],
+ [:TEXT, "--- blah ---", 0, 2],
+ [:NEWLINE, "\n", 13, 2],
+ ]
+
+ assert_equal expected, @RMP.tokenize(str)
+ end
+
def test_tokenize_ualpha
str = <<-STR
A. l1
@@ -1438,6 +1624,19 @@ Example heading:
assert_equal expected, @RMP.tokenize(str)
end
+ def test_token_pos
+ parser = @RMP.new
+ s = parser.setup_scanner 'cät'
+
+ s.scan(/\S+/)
+
+ if Object.const_defined? :Encoding then
+ assert_equal [3, 0], parser.token_pos(s.pos)
+ else
+ assert_equal [4, 0], parser.token_pos(s.pos)
+ end
+ end
+
# HACK move to Verbatim test case
def test_verbatim_normalize
v = @RM::Verbatim.new "foo\n", "\n", "\n", "bar\n"
diff --git a/test/rdoc/test_rdoc_markup_pre_process.rb b/test/rdoc/test_rdoc_markup_pre_process.rb
index 34867c8c6b..3a991a6397 100644
--- a/test/rdoc/test_rdoc_markup_pre_process.rb
+++ b/test/rdoc/test_rdoc_markup_pre_process.rb
@@ -1,16 +1,11 @@
# coding: utf-8
-require 'tempfile'
-require 'rubygems'
-require 'minitest/autorun'
-require 'rdoc/markup/pre_process'
-require 'rdoc/code_objects'
-require 'rdoc/options'
+require 'rdoc/test_case'
-class TestRDocMarkupPreProcess < MiniTest::Unit::TestCase
+class TestRDocMarkupPreProcess < RDoc::TestCase
def setup
- RDoc::Markup::PreProcess.registered.clear
+ super
@tempfile = Tempfile.new 'test_rdoc_markup_pre_process'
@file_name = File.basename @tempfile.path
@@ -20,11 +15,23 @@ class TestRDocMarkupPreProcess < MiniTest::Unit::TestCase
end
def teardown
- RDoc::Markup::PreProcess.registered.clear
+ super
@tempfile.close
end
+ def test_class_register
+ RDoc::Markup::PreProcess.register 'for_test' do raise 'fail' end
+
+ assert_equal %w[for_test], RDoc::Markup::PreProcess.registered.keys
+ end
+
+ def test_class_post_process
+ RDoc::Markup::PreProcess.post_process do end
+
+ assert_equal 1, RDoc::Markup::PreProcess.post_processors.length
+ end
+
def test_include_file
@tempfile.write <<-INCLUDE
# -*- mode: rdoc; coding: utf-8; fill-column: 74; -*-
@@ -73,6 +80,50 @@ contents of a string.
assert_equal "#\n", text
end
+ def test_handle_comment
+ text = "# :main: M\n"
+ c = comment text
+
+ out = @pp.handle c
+
+ assert_same out, text
+ assert_equal "#\n", text
+ end
+
+ def test_handle_markup
+ c = comment ':markup: rd'
+
+ @pp.handle c
+
+ assert_equal 'rd', c.format
+ end
+
+ def test_handle_markup_empty
+ c = comment ':markup:'
+
+ @pp.handle c
+
+ assert_equal 'rdoc', c.format
+ end
+
+ def test_handle_post_process
+ cd = RDoc::CodeObject.new
+
+ RDoc::Markup::PreProcess.post_process do |text, code_object|
+ code_object.metadata[:stuff] = text
+
+ :junk
+ end
+
+ text = "# a b c\n"
+
+ out = @pp.handle text, cd
+
+ assert_same out, text
+ assert_equal "# a b c\n", text
+ assert_equal "# a b c\n", cd.metadata[:stuff]
+ end
+
def test_handle_unregistered
text = "# :x: y\n"
out = @pp.handle text
diff --git a/test/rdoc/test_rdoc_markup_raw.rb b/test/rdoc/test_rdoc_markup_raw.rb
index 4e57b7df39..16cc60e3a8 100644
--- a/test/rdoc/test_rdoc_markup_raw.rb
+++ b/test/rdoc/test_rdoc_markup_raw.rb
@@ -1,12 +1,10 @@
-require 'pp'
-require 'rubygems'
-require 'minitest/autorun'
-require 'rdoc/markup'
+require 'rdoc/test_case'
-class TestRDocMarkupRaw < MiniTest::Unit::TestCase
+class TestRDocMarkupRaw < RDoc::TestCase
def setup
- @RM = RDoc::Markup
+ super
+
@p = @RM::Raw.new
end
@@ -23,5 +21,9 @@ class TestRDocMarkupRaw < MiniTest::Unit::TestCase
assert_equal @RM::Raw.new('hi', 'there'), @p
end
+ def test_pretty_print
+ assert_equal '[raw: ]', mu_pp(@p)
+ end
+
end
diff --git a/test/rdoc/test_rdoc_markup_to_ansi.rb b/test/rdoc/test_rdoc_markup_to_ansi.rb
index f60d1999c2..5afaf94350 100644
--- a/test/rdoc/test_rdoc_markup_to_ansi.rb
+++ b/test/rdoc/test_rdoc_markup_to_ansi.rb
@@ -1,7 +1,4 @@
-require 'rubygems'
-require 'rdoc/markup/text_formatter_test_case'
-require 'rdoc/markup/to_ansi'
-require 'minitest/autorun'
+require 'rdoc/test_case'
class TestRDocMarkupToAnsi < RDoc::Markup::TextFormatterTestCase
@@ -18,6 +15,10 @@ class TestRDocMarkupToAnsi < RDoc::Markup::TextFormatterTestCase
assert_equal "\e[0m\n", @to.res.join
end
+ def accept_block_quote
+ assert_equal "\e[0m> quote\n", @to.res.join
+ end
+
def accept_document
assert_equal "\e[0mhello\n", @to.res.join
end
@@ -67,7 +68,7 @@ class TestRDocMarkupToAnsi < RDoc::Markup::TextFormatterTestCase
end
def accept_list_item_end_label
- assert_equal "\e[0m", @to.res.join
+ assert_equal "\e[0mcat:\n", @to.res.join
assert_equal 0, @to.indent, 'indent'
end
@@ -77,7 +78,7 @@ class TestRDocMarkupToAnsi < RDoc::Markup::TextFormatterTestCase
end
def accept_list_item_end_note
- assert_equal "\e[0m", @to.res.join
+ assert_equal "\e[0mcat:\n", @to.res.join
assert_equal 0, @to.indent, 'indent'
end
@@ -245,10 +246,28 @@ class TestRDocMarkupToAnsi < RDoc::Markup::TextFormatterTestCase
@to.res.join
end
+ def accept_list_item_start_note_multi_description
+ assert_equal "\e[0mlabel:\n description one\n\n description two\n\n",
+ @to.res.join
+ end
+
+ def accept_list_item_start_note_multi_label
+ assert_equal "\e[0mone\ntwo:\n two headers\n\n",
+ @to.res.join
+ end
+
def accept_paragraph_b
assert_equal "\e[0mreg \e[1mbold words\e[m reg\n", @to.end_accepting
end
+ def accept_paragraph_br
+ assert_equal "\e[0mone\ntwo\n", @to.end_accepting
+ end
+
+ def accept_paragraph_break
+ assert_equal "\e[0mhello\nworld\n", @to.end_accepting
+ end
+
def accept_paragraph_i
assert_equal "\e[0mreg \e[4mitalic words\e[m reg\n", @to.end_accepting
end
@@ -328,5 +347,23 @@ words words words words
assert_equal expected, @to.end_accepting
end
+ # functional test
+ def test_convert_list_note
+ note_list = <<-NOTE_LIST
+foo ::
+bar ::
+ hi
+ NOTE_LIST
+
+ expected = <<-EXPECTED
+\e[0mfoo
+bar:
+ hi
+
+ EXPECTED
+
+ assert_equal expected, @to.convert(note_list)
+ end
+
end
diff --git a/test/rdoc/test_rdoc_markup_to_bs.rb b/test/rdoc/test_rdoc_markup_to_bs.rb
index 35a9266b5d..f2e6352b69 100644
--- a/test/rdoc/test_rdoc_markup_to_bs.rb
+++ b/test/rdoc/test_rdoc_markup_to_bs.rb
@@ -1,7 +1,4 @@
-require 'rubygems'
-require 'rdoc/markup/text_formatter_test_case'
-require 'rdoc/markup/to_bs'
-require 'minitest/autorun'
+require 'rdoc/test_case'
class TestRDocMarkupToBs < RDoc::Markup::TextFormatterTestCase
@@ -18,6 +15,10 @@ class TestRDocMarkupToBs < RDoc::Markup::TextFormatterTestCase
assert_equal "\n", @to.res.join
end
+ def accept_block_quote
+ assert_equal "> quote\n", @to.res.join
+ end
+
def accept_document
assert_equal "hello\n", @to.res.join
end
@@ -68,7 +69,7 @@ class TestRDocMarkupToBs < RDoc::Markup::TextFormatterTestCase
end
def accept_list_item_end_label
- assert_equal "\n", @to.res.join
+ assert_equal "cat:\n", @to.res.join
assert_equal 0, @to.indent, 'indent'
end
@@ -78,7 +79,7 @@ class TestRDocMarkupToBs < RDoc::Markup::TextFormatterTestCase
end
def accept_list_item_end_note
- assert_equal "\n", @to.res.join
+ assert_equal "cat:\n", @to.res.join
assert_equal 0, @to.indent, 'indent'
end
@@ -252,12 +253,32 @@ class TestRDocMarkupToBs < RDoc::Markup::TextFormatterTestCase
assert_equal "teletype:\n teletype description\n\n", @to.res.join
end
+ def accept_list_item_start_note_multi_description
+ assert_equal "label:\n description one\n\n description two\n\n",
+ @to.res.join
+ end
+
+ def accept_list_item_start_note_multi_label
+ assert_equal "one\ntwo:\n two headers\n\n", @to.res.join
+ end
+
def accept_paragraph_b
skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars
assert_equal "reg b\bbo\bol\bld\bd \b w\bwo\bor\brd\bds\bs reg\n",
@to.end_accepting
end
+ def accept_paragraph_br
+ skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars
+ assert_equal "one\ntwo\n", @to.end_accepting
+ end
+
+ def accept_paragraph_break
+ skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars
+ assert_equal "hello\nworld\n",
+ @to.end_accepting
+ end
+
def accept_paragraph_i
skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars
assert_equal "reg _\bi_\bt_\ba_\bl_\bi_\bc_\b _\bw_\bo_\br_\bd_\bs reg\n",
diff --git a/test/rdoc/test_rdoc_markup_to_html.rb b/test/rdoc/test_rdoc_markup_to_html.rb
index 2cb16e88ae..cb444a531f 100644
--- a/test/rdoc/test_rdoc_markup_to_html.rb
+++ b/test/rdoc/test_rdoc_markup_to_html.rb
@@ -1,7 +1,4 @@
-require 'rubygems'
-require 'rdoc/markup/formatter_test_case'
-require 'rdoc/markup/to_html'
-require 'minitest/autorun'
+require 'rdoc/test_case'
class TestRDocMarkupToHtml < RDoc::Markup::FormatterTestCase
@@ -10,7 +7,7 @@ class TestRDocMarkupToHtml < RDoc::Markup::FormatterTestCase
def setup
super
- @to = RDoc::Markup::ToHtml.new
+ @to = RDoc::Markup::ToHtml.new @options
end
def test_class_gen_relative_url
@@ -30,36 +27,41 @@ class TestRDocMarkupToHtml < RDoc::Markup::FormatterTestCase
assert_empty @to.res.join
end
+ def accept_block_quote
+ assert_equal "\n<blockquote>\n<p>quote</p>\n</blockquote>\n", @to.res.join
+ end
+
def accept_document
assert_equal "\n<p>hello</p>\n", @to.res.join
end
def accept_heading
- assert_equal "\n<h5>Hello</h5>\n", @to.res.join
+ assert_equal "\n<h5 id=\"label-Hello\">Hello</h5>\n", @to.res.join
end
def accept_heading_1
- assert_equal "\n<h1>Hello</h1>\n", @to.res.join
+ assert_equal "\n<h1 id=\"label-Hello\">Hello</h1>\n", @to.res.join
end
def accept_heading_2
- assert_equal "\n<h2>Hello</h2>\n", @to.res.join
+ assert_equal "\n<h2 id=\"label-Hello\">Hello</h2>\n", @to.res.join
end
def accept_heading_3
- assert_equal "\n<h3>Hello</h3>\n", @to.res.join
+ assert_equal "\n<h3 id=\"label-Hello\">Hello</h3>\n", @to.res.join
end
def accept_heading_4
- assert_equal "\n<h4>Hello</h4>\n", @to.res.join
+ assert_equal "\n<h4 id=\"label-Hello\">Hello</h4>\n", @to.res.join
end
def accept_heading_b
- assert_equal "\n<h1><b>Hello</b></h1>\n", @to.res.join
+ assert_equal "\n<h1 id=\"label-Hello\"><strong>Hello</strong></h1>\n",
+ @to.res.join
end
def accept_heading_suppressed_crossref
- assert_equal "\n<h1>Hello</h1>\n", @to.res.join
+ assert_equal "\n<h1 id=\"label-Hello\">Hello</h1>\n", @to.res.join
end
def accept_list_end_bullet
@@ -73,14 +75,14 @@ class TestRDocMarkupToHtml < RDoc::Markup::FormatterTestCase
assert_equal [], @to.list
assert_equal [], @to.in_list_entry
- assert_equal "<dl class=\"rdoc-list\"></dl>\n", @to.res.join
+ assert_equal "<dl class=\"rdoc-list label-list\"></dl>\n", @to.res.join
end
def accept_list_end_lalpha
assert_equal [], @to.list
assert_equal [], @to.in_list_entry
- assert_equal "<ol style=\"display: lower-alpha\"></ol>\n", @to.res.join
+ assert_equal "<ol style=\"list-style-type: lower-alpha\"></ol>\n", @to.res.join
end
def accept_list_end_number
@@ -94,14 +96,14 @@ class TestRDocMarkupToHtml < RDoc::Markup::FormatterTestCase
assert_equal [], @to.list
assert_equal [], @to.in_list_entry
- assert_equal "<table class=\"rdoc-list\"></table>\n", @to.res.join
+ assert_equal "<dl class=\"rdoc-list note-list\"></dl>\n", @to.res.join
end
def accept_list_end_ualpha
assert_equal [], @to.list
assert_equal [], @to.in_list_entry
- assert_equal "<ol style=\"display: upper-alpha\"></ol>\n", @to.res.join
+ assert_equal "<ol style=\"list-style-type: upper-alpha\"></ol>\n", @to.res.join
end
def accept_list_item_end_bullet
@@ -117,7 +119,7 @@ class TestRDocMarkupToHtml < RDoc::Markup::FormatterTestCase
end
def accept_list_item_end_note
- assert_equal %w[</td></tr>], @to.in_list_entry
+ assert_equal %w[</dd>], @to.in_list_entry
end
def accept_list_item_end_number
@@ -133,24 +135,49 @@ class TestRDocMarkupToHtml < RDoc::Markup::FormatterTestCase
end
def accept_list_item_start_label
- assert_equal "<dl class=\"rdoc-list\"><dt>cat</dt>\n<dd>", @to.res.join
+ assert_equal "<dl class=\"rdoc-list label-list\"><dt>cat\n<dd>", @to.res.join
end
def accept_list_item_start_lalpha
- assert_equal "<ol style=\"display: lower-alpha\"><li>", @to.res.join
+ assert_equal "<ol style=\"list-style-type: lower-alpha\"><li>", @to.res.join
end
def accept_list_item_start_note
- assert_equal "<table class=\"rdoc-list\"><tr><td class=\"rdoc-term\"><p>cat</p></td>\n<td>",
+ assert_equal "<dl class=\"rdoc-list note-list\"><dt>cat\n<dd>",
@to.res.join
end
def accept_list_item_start_note_2
expected = <<-EXPECTED
-<table class="rdoc-list"><tr><td class="rdoc-term"><p><tt>teletype</tt></p></td>
-<td>
+<dl class="rdoc-list note-list"><dt><code>teletype</code>
+<dd>
<p>teletype description</p>
-</td></tr></table>
+</dd></dl>
+ EXPECTED
+
+ assert_equal expected, @to.res.join
+ end
+
+ def accept_list_item_start_note_multi_description
+ expected = <<-EXPECTED
+<dl class="rdoc-list note-list"><dt>label
+<dd>
+<p>description one</p>
+</dd><dd>
+<p>description two</p>
+</dd></dl>
+ EXPECTED
+
+ assert_equal expected, @to.res.join
+ end
+
+ def accept_list_item_start_note_multi_label
+ expected = <<-EXPECTED
+<dl class="rdoc-list note-list"><dt>one
+<dt>two
+<dd>
+<p>two headers</p>
+</dd></dl>
EXPECTED
assert_equal expected, @to.res.join
@@ -161,7 +188,7 @@ class TestRDocMarkupToHtml < RDoc::Markup::FormatterTestCase
end
def accept_list_item_start_ualpha
- assert_equal "<ol style=\"display: upper-alpha\"><li>", @to.res.join
+ assert_equal "<ol style=\"list-style-type: upper-alpha\"><li>", @to.res.join
end
def accept_list_start_bullet
@@ -175,21 +202,21 @@ class TestRDocMarkupToHtml < RDoc::Markup::FormatterTestCase
assert_equal [:LABEL], @to.list
assert_equal [false], @to.in_list_entry
- assert_equal '<dl class="rdoc-list">', @to.res.join
+ assert_equal '<dl class="rdoc-list label-list">', @to.res.join
end
def accept_list_start_lalpha
assert_equal [:LALPHA], @to.list
assert_equal [false], @to.in_list_entry
- assert_equal "<ol style=\"display: lower-alpha\">", @to.res.join
+ assert_equal "<ol style=\"list-style-type: lower-alpha\">", @to.res.join
end
def accept_list_start_note
assert_equal [:NOTE], @to.list
assert_equal [false], @to.in_list_entry
- assert_equal "<table class=\"rdoc-list\">", @to.res.join
+ assert_equal "<dl class=\"rdoc-list note-list\">", @to.res.join
end
def accept_list_start_number
@@ -203,7 +230,7 @@ class TestRDocMarkupToHtml < RDoc::Markup::FormatterTestCase
assert_equal [:UALPHA], @to.list
assert_equal [false], @to.in_list_entry
- assert_equal "<ol style=\"display: upper-alpha\">", @to.res.join
+ assert_equal "<ol style=\"list-style-type: upper-alpha\">", @to.res.join
end
def accept_paragraph
@@ -211,7 +238,15 @@ class TestRDocMarkupToHtml < RDoc::Markup::FormatterTestCase
end
def accept_paragraph_b
- assert_equal "\n<p>reg <b>bold words</b> reg</p>\n", @to.res.join
+ assert_equal "\n<p>reg <strong>bold words</strong> reg</p>\n", @to.res.join
+ end
+
+ def accept_paragraph_br
+ assert_equal "\n<p>one<br>two</p>\n", @to.res.join
+ end
+
+ def accept_paragraph_break
+ assert_equal "\n<p>hello<br>\nworld</p>\n", @to.res.join
end
def accept_paragraph_i
@@ -219,11 +254,11 @@ class TestRDocMarkupToHtml < RDoc::Markup::FormatterTestCase
end
def accept_paragraph_plus
- assert_equal "\n<p>reg <tt>teletype</tt> reg</p>\n", @to.res.join
+ assert_equal "\n<p>reg <code>teletype</code> reg</p>\n", @to.res.join
end
def accept_paragraph_star
- assert_equal "\n<p>reg <b>bold</b> reg</p>\n", @to.res.join
+ assert_equal "\n<p>reg <strong>bold</strong> reg</p>\n", @to.res.join
end
def accept_paragraph_underscore
@@ -297,20 +332,155 @@ class TestRDocMarkupToHtml < RDoc::Markup::FormatterTestCase
assert_equal expected, @to.end_accepting
end
+ def test_accept_heading_7
+ @to.start_accepting
+
+ @to.accept_heading @RM::Heading.new(7, 'Hello')
+
+ assert_equal "\n<h6 id=\"label-Hello\">Hello</h6>\n", @to.res.join
+ end
+
+ def test_accept_heading_aref_class
+ @to.code_object = RDoc::NormalClass.new 'Foo'
+ @to.start_accepting
+
+ @to.accept_heading @RM::Heading.new(1, 'Hello')
+
+ assert_equal "\n<h1 id=\"label-Hello\">Hello</h1>\n",
+ @to.res.join
+ end
+
+ def test_accept_heading_aref_method
+ @to.code_object = RDoc::AnyMethod.new nil, 'foo'
+ @to.start_accepting
+
+ @to.accept_heading @RM::Heading.new(1, 'Hello')
+
+ assert_equal "\n<h1 id=\"method-i-foo-label-Hello\">Hello</h1>\n",
+ @to.res.join
+ end
+
+ def test_accept_verbatim_parseable
+ verb = @RM::Verbatim.new("class C\n", "end\n")
+
+ @to.start_accepting
+ @to.accept_verbatim verb
+
+ expected = <<-EXPECTED
+
+<pre class="ruby"><span class="ruby-keyword">class</span> <span class="ruby-constant">C</span>
+<span class="ruby-keyword">end</span>
+</pre>
+ EXPECTED
+
+ assert_equal expected, @to.res.join
+ end
+
+ def test_accept_verbatim_parseable_error
+ verb = @RM::Verbatim.new("a % 09 # => blah\n")
+
+ @to.start_accepting
+ @to.accept_verbatim verb
+
+ inner = CGI.escapeHTML "a % 09 # => blah"
+
+ expected = <<-EXPECTED
+
+<pre>#{inner}
+</pre>
+ EXPECTED
+
+ assert_equal expected, @to.res.join
+ end
+
+ def test_accept_verbatim_ruby
+ verb = @RM::Verbatim.new("1 + 1\n")
+ verb.format = :ruby
+
+ @to.start_accepting
+ @to.accept_verbatim verb
+
+ expected = <<-EXPECTED
+
+<pre class="ruby"><span class="ruby-value">1</span> <span class="ruby-operator">+</span> <span class="ruby-value">1</span>
+</pre>
+ EXPECTED
+
+ assert_equal expected, @to.res.join
+ end
+
def test_convert_string
assert_equal '&lt;&gt;', @to.convert_string('<>')
end
+ def test_convert_HYPERLINK_irc
+ result = @to.convert 'irc://irc.freenode.net/#ruby-lang'
+
+ assert_equal "\n<p><a href=\"irc://irc.freenode.net/#ruby-lang\">irc.freenode.net/#ruby-lang</a></p>\n", result
+ end
+
+ def test_convert_RDOCLINK_label_label
+ result = @to.convert 'rdoc-label:label-One'
+
+ assert_equal "\n<p><a href=\"#label-One\">One</a></p>\n", result
+ end
+
+ def test_convert_RDOCLINK_label_foottext
+ result = @to.convert 'rdoc-label:foottext-1'
+
+ assert_equal "\n<p><a href=\"#foottext-1\">*1</a></p>\n", result
+ end
+
+ def test_convert_RDOCLINK_label_footmark
+ result = @to.convert 'rdoc-label:footmark-1'
+
+ assert_equal "\n<p><a href=\"#footmark-1\">^1</a></p>\n", result
+ end
+
+ def test_convert_RDOCLINK_ref
+ result = @to.convert 'rdoc-ref:C'
+
+ assert_equal "\n<p>C</p>\n", result
+ end
+
+ def test_convert_TIDYLINK_footnote
+ result = @to.convert 'text{*1}[rdoc-label:foottext-1:footmark-1]'
+
+ assert_equal "\n<p>text<a id=\"footmark-1\" href=\"#foottext-1\">*1</a></p>\n", result
+ end
+
+ def test_convert_TIDYLINK_rdoc_label
+ result = @to.convert '{foo}[rdoc-label:foottext-1]'
+
+ assert_equal "\n<p><a href=\"#foottext-1\">foo</a></p>\n", result
+ end
+
+ def test_convert_TIDYLINK_irc
+ result = @to.convert '{ruby-lang}[irc://irc.freenode.net/#ruby-lang]'
+
+ assert_equal "\n<p><a href=\"irc://irc.freenode.net/#ruby-lang\">ruby-lang</a></p>\n", result
+ end
+
def test_gen_url
assert_equal '<a href="example">example</a>',
@to.gen_url('link:example', 'example')
end
- def test_gem_url_image_url
+ def test_gen_url_rdoc_label
+ assert_equal '<a href="#foottext-1">example</a>',
+ @to.gen_url('rdoc-label:foottext-1', 'example')
+ end
+
+ def test_gen_url_rdoc_label_id
+ assert_equal '<a id="footmark-1" href="#foottext-1">example</a>',
+ @to.gen_url('rdoc-label:foottext-1:footmark-1', 'example')
+ end
+
+ def test_gen_url_image_url
assert_equal '<img src="http://example.com/image.png" />', @to.gen_url('http://example.com/image.png', 'ignored')
end
- def test_gem_url_ssl_image_url
+ def test_gen_url_ssl_image_url
assert_equal '<img src="https://example.com/image.png" />', @to.gen_url('https://example.com/image.png', 'ignored')
end
@@ -322,6 +492,14 @@ class TestRDocMarkupToHtml < RDoc::Markup::FormatterTestCase
assert_equal '<a href="README.txt">README.txt</a>', link
end
+ def test_handle_special_HYPERLINK_irc
+ special = RDoc::Markup::Special.new 0, 'irc://irc.freenode.net/#ruby-lang'
+
+ link = @to.handle_special_HYPERLINK special
+
+ assert_equal '<a href="irc://irc.freenode.net/#ruby-lang">irc.freenode.net/#ruby-lang</a>', link
+ end
+
def test_list_verbatim_2
str = "* one\n verb1\n verb2\n* two\n"
@@ -339,8 +517,21 @@ verb2</pre>
assert_equal expected, @m.convert(str, @to)
end
+ def test_parseable_eh
+ assert @to.parseable?('def x() end'), 'def'
+ assert @to.parseable?('class C end'), 'class'
+ assert @to.parseable?('module M end'), 'module'
+ assert @to.parseable?('a # => blah'), '=>'
+ assert @to.parseable?('x { |y| ... }'), '{ |x|'
+ assert @to.parseable?('x do |y| ... end'), 'do |x|'
+ refute @to.parseable?('* 1'), '* 1'
+ refute @to.parseable?('# only a comment'), '# only a comment'
+ refute @to.parseable?('<% require "foo" %>'), 'ERB'
+ refute @to.parseable?('class="foo"'), 'HTML class'
+ end
+
def test_to_html
- assert_equal "\n<p><tt>--</tt></p>\n", util_format("<tt>--</tt>")
+ assert_equal "\n<p><code>--</code></p>\n", util_format("<tt>--</tt>")
end
def util_format text
diff --git a/test/rdoc/test_rdoc_markup_to_html_crossref.rb b/test/rdoc/test_rdoc_markup_to_html_crossref.rb
index 4f122512ac..27a60120f4 100644
--- a/test/rdoc/test_rdoc_markup_to_html_crossref.rb
+++ b/test/rdoc/test_rdoc_markup_to_html_crossref.rb
@@ -1,8 +1,3 @@
-require 'rubygems'
-require 'minitest/autorun'
-require 'rdoc/rdoc'
-require 'rdoc/code_objects'
-require 'rdoc/markup/to_html_crossref'
require File.expand_path '../xref_test_case', __FILE__
class TestRDocMarkupToHtmlCrossref < XrefTestCase
@@ -10,25 +5,93 @@ class TestRDocMarkupToHtmlCrossref < XrefTestCase
def setup
super
- @to = RDoc::Markup::ToHtmlCrossref.new 'index.html', @c1, true
+ @options.hyperlink_all = true
+
+ @to = RDoc::Markup::ToHtmlCrossref.new @options, 'index.html', @c1
end
def test_convert_CROSSREF
result = @to.convert 'C1'
- assert_equal "\n<p><a href=\"C1.html\">C1</a></p>\n", result
+ assert_equal para("<a href=\"C1.html\">C1</a>"), result
+ end
+
+ def test_convert_CROSSREF_label
+ result = @to.convert 'C1@foo'
+ assert_equal para("<a href=\"C1.html#label-foo\">foo at C1</a>"), result
+
+ result = @to.convert 'C1#m@foo'
+ assert_equal para("<a href=\"C1.html#method-i-m-label-foo\">foo at C1#m</a>"),
+ result
end
- def test_convert_HYPERLINK_rdoc_ref
+ def test_convert_CROSSREF_label_period
+ result = @to.convert 'C1@foo.'
+ assert_equal para("<a href=\"C1.html#label-foo\">foo at C1</a>."), result
+ end
+
+ def test_convert_CROSSREF_label_space
+ result = @to.convert 'C1@foo+bar'
+ assert_equal para("<a href=\"C1.html#label-foo+bar\">foo bar at C1</a>"),
+ result
+ end
+
+ def test_convert_RDOCLINK_rdoc_ref
result = @to.convert 'rdoc-ref:C1'
- assert_equal "\n<p><a href=\"C1.html\">C1</a></p>\n", result
+ assert_equal para("<a href=\"C1.html\">C1</a>"), result
+ end
+
+ def test_convert_RDOCLINK_rdoc_ref_method
+ result = @to.convert 'rdoc-ref:C1#m'
+
+ assert_equal para("<a href=\"C1.html#method-i-m\">#m</a>"), result
end
- def test_convert_TIDYLINK_rdoc_ref
- result = @to.convert '{foo}[rdoc-ref:C1]'
+ def test_convert_RDOCLINK_rdoc_ref_method_label
+ result = @to.convert 'rdoc-ref:C1#m@foo'
+
+ assert_equal para("<a href=\"C1.html#method-i-m-label-foo\">foo at C1#m</a>"),
+ result, 'rdoc-ref:C1#m@foo'
+ end
+
+ def test_convert_RDOCLINK_rdoc_ref_method_percent
+ m = @c1.add_method RDoc::AnyMethod.new nil, '%'
+ m.singleton = false
+
+ result = @to.convert 'rdoc-ref:C1#%'
+
+ assert_equal para("<a href=\"C1.html#method-i-25\">#%</a>"), result
+
+ m.singleton = true
+
+ result = @to.convert 'rdoc-ref:C1::%'
+
+ assert_equal para("<a href=\"C1.html#method-c-25\">::%</a>"), result
+ end
+
+ def test_convert_RDOCLINK_rdoc_ref_method_percent_label
+ m = @c1.add_method RDoc::AnyMethod.new nil, '%'
+ m.singleton = false
+
+ result = @to.convert 'rdoc-ref:C1#%@f'
+
+ assert_equal para("<a href=\"C1.html#method-i-25-label-f\">f at C1#%</a>"),
+ result
+
+ m.singleton = true
+
+ result = @to.convert 'rdoc-ref:C1::%@f'
- assert_equal "\n<p><a href=\"C1.html\">foo</a></p>\n", result
+ assert_equal para("<a href=\"C1.html#method-c-25-label-f\">f at C1::%</a>"),
+ result
+ end
+
+ def test_convert_RDOCLINK_rdoc_ref_label
+ result = @to.convert 'rdoc-ref:C1@foo'
+
+ assert_equal para("<a href=\"C1.html#label-foo\">foo at C1</a>"), result,
+ 'rdoc-ref:C1@foo'
end
def test_gen_url
@@ -43,6 +106,11 @@ class TestRDocMarkupToHtmlCrossref < XrefTestCase
assert_equal "<a href=\"C2/C3.html\">C2::C3</a>", SPECIAL('C2::C3')
end
+ def test_handle_special_CROSSREF_label
+ assert_equal "<a href=\"C1.html#method-i-m-label-foo\">foo at C1#m</a>",
+ SPECIAL('C1#m@foo')
+ end
+
def test_handle_special_CROSSREF_show_hash_false
@to.show_hash = false
@@ -51,8 +119,10 @@ class TestRDocMarkupToHtmlCrossref < XrefTestCase
end
def test_handle_special_HYPERLINK_rdoc
- RDoc::TopLevel.new 'README.txt'
- @to = RDoc::Markup::ToHtmlCrossref.new 'C2.html', @c2, true
+ readme = @store.add_file 'README.txt'
+ readme.parser = RDoc::Parser::Simple
+
+ @to = RDoc::Markup::ToHtmlCrossref.new @options, 'C2.html', @c2
link = @to.handle_special_HYPERLINK hyper 'C2::C3'
@@ -68,8 +138,10 @@ class TestRDocMarkupToHtmlCrossref < XrefTestCase
end
def test_handle_special_TIDYLINK_rdoc
- RDoc::TopLevel.new 'README.txt'
- @to = RDoc::Markup::ToHtmlCrossref.new 'C2.html', @c2, true
+ readme = @store.add_file 'README.txt'
+ readme.parser = RDoc::Parser::Simple
+
+ @to = RDoc::Markup::ToHtmlCrossref.new @options, 'C2.html', @c2
link = @to.handle_special_TIDYLINK tidy 'C2::C3'
@@ -79,15 +151,51 @@ class TestRDocMarkupToHtmlCrossref < XrefTestCase
assert_equal '<a href="C4.html">tidy</a>', link
+ link = @to.handle_special_TIDYLINK tidy 'C1#m'
+
+ assert_equal '<a href="C1.html#method-i-m">tidy</a>', link
+
link = @to.handle_special_TIDYLINK tidy 'README.txt'
assert_equal '<a href="README_txt.html">tidy</a>', link
end
+ def test_handle_special_TIDYLINK_label
+ link = @to.handle_special_TIDYLINK tidy 'C1#m@foo'
+
+ assert_equal "<a href=\"C1.html#method-i-m-label-foo\">tidy</a>",
+ link, 'C1#m@foo'
+ end
+
+ def test_to_html_CROSSREF_email
+ @options.hyperlink_all = false
+
+ @to = RDoc::Markup::ToHtmlCrossref.new @options, 'index.html', @c1
+
+ result = @to.to_html 'first.last@example.com'
+
+ assert_equal 'first.last@example.com', result
+ end
+
+ def test_to_html_CROSSREF_email_hyperlink_all
+ result = @to.to_html 'first.last@example.com'
+
+ assert_equal 'first.last@example.com', result
+ end
+
def test_link
assert_equal 'n', @to.link('n', 'n')
- assert_equal '<a href="C1.html#method-c-m">m</a>', @to.link('m', 'm')
+ assert_equal '<a href="C1.html#method-c-m">::m</a>', @to.link('m', 'm')
+ end
+
+ def test_link_class_method_full
+ assert_equal '<a href="Parent.html#method-c-m">Parent.m</a>',
+ @to.link('Parent::m', 'Parent::m')
+ end
+
+ def para text
+ "\n<p>#{text}</p>\n"
end
def SPECIAL text
diff --git a/test/rdoc/test_rdoc_markup_to_html_snippet.rb b/test/rdoc/test_rdoc_markup_to_html_snippet.rb
new file mode 100644
index 0000000000..065b2edbc8
--- /dev/null
+++ b/test/rdoc/test_rdoc_markup_to_html_snippet.rb
@@ -0,0 +1,710 @@
+require 'rdoc/test_case'
+
+class TestRDocMarkupToHtmlSnippet < RDoc::Markup::FormatterTestCase
+
+ add_visitor_tests
+
+ def setup
+ super
+
+ @to = RDoc::Markup::ToHtmlSnippet.new @options, 100, 100
+ @ellipsis = @to.to_html '...'
+ end
+
+ def accept_blank_line
+ assert_empty @to.res.join
+ end
+
+ def accept_block_quote
+ assert_equal "\n<blockquote><p>quote\n</blockquote>\n", @to.res.join
+
+ assert_equal 5, @to.characters
+ end
+
+ def accept_document
+ assert_equal "<p>hello\n", @to.res.join
+ assert_equal 5, @to.characters
+ end
+
+ def accept_heading
+ assert_equal "<p>Hello\n", @to.res.join
+ assert_equal 5, @to.characters
+ end
+
+ def accept_heading_1
+ assert_equal "<p>Hello\n", @to.res.join
+ assert_equal 5, @to.characters
+ end
+
+ def accept_heading_2
+ assert_equal "<p>Hello\n", @to.res.join
+ assert_equal 5, @to.characters
+ end
+
+ def accept_heading_3
+ assert_equal "<p>Hello\n", @to.res.join
+ assert_equal 5, @to.characters
+ end
+
+ def accept_heading_4
+ assert_equal "<p>Hello\n", @to.res.join
+ assert_equal 5, @to.characters
+ end
+
+ def accept_heading_b
+ assert_equal "<p><strong>Hello</strong>\n",
+ @to.res.join
+ assert_equal 5, @to.characters
+ end
+
+ def accept_heading_suppressed_crossref
+ assert_equal "<p>Hello\n", @to.res.join
+ assert_equal 5, @to.characters
+ end
+
+ def accept_list_end_bullet
+ assert_equal [], @to.list
+ assert_equal [], @to.in_list_entry
+
+ assert_equal "\n", @to.res.join
+ assert_equal 0, @to.characters
+ end
+
+ def accept_list_end_label
+ assert_equal [], @to.list
+ assert_equal [], @to.in_list_entry
+
+ assert_equal "\n", @to.res.join
+ assert_equal 0, @to.characters
+ end
+
+ def accept_list_end_lalpha
+ assert_equal [], @to.list
+ assert_equal [], @to.in_list_entry
+
+ assert_equal "\n", @to.res.join
+ assert_equal 0, @to.characters
+ end
+
+ def accept_list_end_number
+ assert_equal [], @to.list
+ assert_equal [], @to.in_list_entry
+
+ assert_equal "\n", @to.res.join
+ assert_equal 0, @to.characters
+ end
+
+ def accept_list_end_note
+ assert_equal [], @to.list
+ assert_equal [], @to.in_list_entry
+
+ assert_equal "\n", @to.res.join
+ assert_equal 0, @to.characters
+ end
+
+ def accept_list_end_ualpha
+ assert_equal [], @to.list
+ assert_equal [], @to.in_list_entry
+
+ assert_equal "\n", @to.res.join
+ assert_equal 0, @to.characters
+ end
+
+ def accept_list_item_end_bullet
+ assert_equal [''], @to.in_list_entry
+ assert_equal 0, @to.characters
+ end
+
+ def accept_list_item_end_label
+ assert_equal [''], @to.in_list_entry
+ assert_equal 4, @to.characters
+ end
+
+ def accept_list_item_end_lalpha
+ assert_equal [''], @to.in_list_entry
+ assert_equal 0, @to.characters
+ end
+
+ def accept_list_item_end_note
+ assert_equal [''], @to.in_list_entry
+ assert_equal 4, @to.characters
+ end
+
+ def accept_list_item_end_number
+ assert_equal [''], @to.in_list_entry
+ assert_equal 0, @to.characters
+ end
+
+ def accept_list_item_end_ualpha
+ assert_equal [''], @to.in_list_entry
+ assert_equal 0, @to.characters
+ end
+
+ def accept_list_item_start_bullet
+ assert_equal "<p>", @to.res.join
+ assert_equal 0, @to.characters
+ end
+
+ def accept_list_item_start_label
+ assert_equal "<p>cat &mdash; ", @to.res.join
+ assert_equal 4, @to.characters
+ end
+
+ def accept_list_item_start_lalpha
+ assert_equal "<p>", @to.res.join
+ assert_equal 0, @to.characters
+ end
+
+ def accept_list_item_start_note
+ assert_equal "<p>cat &mdash; ",
+ @to.res.join
+ assert_equal 4, @to.characters
+ end
+
+ def accept_list_item_start_note_2
+ expected = <<-EXPECTED
+<p><code>teletype</code> &mdash; teletype description
+
+ EXPECTED
+
+ assert_equal expected, @to.res.join
+ assert_equal 29, @to.characters
+ end
+
+ def accept_list_item_start_note_multi_description
+ expected = <<-EXPECTED
+<p>label &mdash; description one
+<p>description two
+
+ EXPECTED
+
+ assert_equal expected, @to.res.join
+ assert_equal 37, @to.characters
+ end
+
+ def accept_list_item_start_note_multi_label
+ expected = <<-EXPECTED
+<p>one, two &mdash; two headers
+
+ EXPECTED
+
+ assert_equal expected, @to.res.join
+ assert_equal 18, @to.characters
+ end
+
+ def accept_list_item_start_number
+ assert_equal "<p>", @to.res.join
+ assert_equal 0, @to.characters
+ end
+
+ def accept_list_item_start_ualpha
+ assert_equal "<p>", @to.res.join
+ assert_equal 0, @to.characters
+ end
+
+ def accept_list_start_bullet
+ assert_equal [:BULLET], @to.list
+ assert_equal [''], @to.in_list_entry
+
+ assert_equal '', @to.res.join
+ assert_equal 0, @to.characters
+ end
+
+ def accept_list_start_label
+ assert_equal [:LABEL], @to.list
+ assert_equal [''], @to.in_list_entry
+
+ assert_equal '', @to.res.join
+ assert_equal 0, @to.characters
+ end
+
+ def accept_list_start_lalpha
+ assert_equal [:LALPHA], @to.list
+ assert_equal [''], @to.in_list_entry
+
+ assert_equal '', @to.res.join
+ assert_equal 0, @to.characters
+ end
+
+ def accept_list_start_note
+ assert_equal [:NOTE], @to.list
+ assert_equal [''], @to.in_list_entry
+
+ assert_equal '', @to.res.join
+ assert_equal 0, @to.characters
+ end
+
+ def accept_list_start_number
+ assert_equal [:NUMBER], @to.list
+ assert_equal [''], @to.in_list_entry
+
+ assert_equal '', @to.res.join
+ assert_equal 0, @to.characters
+ end
+
+ def accept_list_start_ualpha
+ assert_equal [:UALPHA], @to.list
+ assert_equal [''], @to.in_list_entry
+
+ assert_equal '', @to.res.join
+ assert_equal 0, @to.characters
+ end
+
+ def accept_paragraph
+ assert_equal "<p>hi\n", @to.res.join
+
+ assert_equal 2, @to.characters
+ end
+
+ def accept_paragraph_b
+ assert_equal "<p>reg <strong>bold words</strong> reg\n", @to.res.join
+
+ assert_equal 18, @to.characters
+ end
+
+ def accept_paragraph_br
+ assert_equal "<p>one<br>two\n", @to.res.join
+
+ assert_equal 6, @to.characters
+ end
+
+ def accept_paragraph_break
+ assert_equal "<p>hello<br>\nworld\n", @to.res.join
+
+ assert_equal 11, @to.characters
+ end
+
+ def accept_paragraph_i
+ assert_equal "<p>reg <em>italic words</em> reg\n", @to.res.join
+
+ assert_equal 20, @to.characters
+ end
+
+ def accept_paragraph_plus
+ assert_equal "<p>reg <code>teletype</code> reg\n", @to.res.join
+
+ assert_equal 16, @to.characters
+ end
+
+ def accept_paragraph_star
+ assert_equal "<p>reg <strong>bold</strong> reg\n", @to.res.join
+
+ assert_equal 12, @to.characters
+ end
+
+ def accept_paragraph_underscore
+ assert_equal "<p>reg <em>italic</em> reg\n", @to.res.join
+
+ assert_equal 14, @to.characters
+ end
+
+ def accept_raw
+ assert_equal '', @to.res.join
+ assert_equal 0, @to.characters
+ end
+
+ def accept_rule
+ assert_empty @to.res
+ assert_equal 0, @to.characters
+ end
+
+ def accept_verbatim
+ assert_equal "\n<pre>hi\n world</pre>\n", @to.res.join
+ assert_equal 10, @to.characters
+ end
+
+ def end_accepting
+ assert_equal 'hi', @to.res.join
+ end
+
+ def start_accepting
+ assert_equal [], @to.res
+ assert_equal [], @to.in_list_entry
+ assert_equal [], @to.list
+ assert_equal 0, @to.characters
+ end
+
+ def list_nested
+ expected = <<-EXPECTED
+<p>l1
+<p>l1.1
+
+<p>l2
+
+ EXPECTED
+
+ assert_equal expected, @to.res.join
+ assert_equal 8, @to.characters
+ end
+
+ def list_verbatim
+ expected = <<-EXPECTED
+<p>list stuff
+
+<pre>* list
+ with
+
+ second
+
+ 1. indented
+ 2. numbered
+
+ third
+
+* second</pre>
+
+ EXPECTED
+
+ assert_equal expected, @to.end_accepting
+ assert_equal 81, @to.characters
+ end
+
+ def test_accept_heading_7
+ @to.start_accepting
+
+ @to.accept_heading @RM::Heading.new(7, 'Hello')
+
+ assert_equal "<p>Hello\n", @to.res.join
+ assert_equal 5, @to.characters
+ end
+
+ def test_accept_heading_aref_class
+ @to.code_object = RDoc::NormalClass.new 'Foo'
+ @to.start_accepting
+
+ @to.accept_heading @RM::Heading.new(1, 'Hello')
+
+ assert_equal "<p>Hello\n",
+ @to.res.join
+ assert_equal 5, @to.characters
+ end
+
+ def test_accept_heading_aref_method
+ @to.code_object = RDoc::AnyMethod.new nil, 'foo'
+ @to.start_accepting
+
+ @to.accept_heading @RM::Heading.new(1, 'Hello')
+
+ assert_equal "<p>Hello\n",
+ @to.res.join
+ assert_equal 5, @to.characters
+ end
+
+ def test_accept_verbatim_ruby
+ options = RDoc::Options.new
+ rdoc = RDoc::RDoc.new
+ rdoc.options = options
+ RDoc::RDoc.current = rdoc
+
+ verb = @RM::Verbatim.new("class C\n", "end\n")
+
+ @to.start_accepting
+ @to.accept_verbatim verb
+
+ expected = <<-EXPECTED
+
+<pre class="ruby"><span class="ruby-keyword">class</span> <span class="ruby-constant">C</span>
+<span class="ruby-keyword">end</span>
+</pre>
+ EXPECTED
+
+ assert_equal expected, @to.res.join
+ assert_equal 11, @to.characters
+ end
+
+ def test_accept_verbatim_ruby_error
+ options = RDoc::Options.new
+ rdoc = RDoc::RDoc.new
+ rdoc.options = options
+ RDoc::RDoc.current = rdoc
+
+ verb = @RM::Verbatim.new("a % 09 # => blah\n")
+
+ @to.start_accepting
+ @to.accept_verbatim verb
+
+ inner = CGI.escapeHTML "a % 09 # => blah"
+
+ expected = <<-EXPECTED
+
+<pre>#{inner}
+</pre>
+ EXPECTED
+
+ assert_equal expected, @to.res.join
+ assert_equal 16, @to.characters
+ end
+
+ def test_add_paragraph
+ @to = RDoc::Markup::ToHtmlSnippet.new @options, 0, 3
+ assert_throws :done do
+ @to.add_paragraph
+ @to.add_paragraph
+ @to.add_paragraph
+ end
+
+ assert_equal 3, @to.paragraphs
+ end
+
+ def test_convert_limit
+ rdoc = <<-RDOC
+= Hello
+
+This is some text, it *will* be cut off after 100 characters and an ellipsis
+must follow
+
+So there you have it
+ RDOC
+
+ expected = <<-EXPECTED
+<p>Hello
+<p>This is some text, it <strong>will</strong> be cut off after 100 characters
+and an ellipsis must follow
+<p>So there you #{@ellipsis}
+ EXPECTED
+
+ actual = @to.convert rdoc
+
+ assert_equal expected, actual
+ assert_equal 111, @to.characters, 'snippet character length'
+ end
+
+ def test_convert_limit_2
+ rdoc = <<-RDOC
+Outputs formatted RI data for the class or method +name+.
+
+Returns true if +name+ was found, false if it was not an alternative could
+be guessed, raises an error if +name+ couldn't be guessed.
+ RDOC
+
+ expected = <<-EXPECTED
+<p>Outputs formatted RI data for the class or method <code>name</code>.
+<p>Returns true if <code>name</code> was found, false if it was #{@ellipsis}
+ EXPECTED
+
+ actual = @to.convert rdoc
+
+ assert_equal expected, actual
+ assert_equal 159, @to.characters, 'snippet character length'
+ end
+
+ def test_convert_limit_paragraphs
+ @to = RDoc::Markup::ToHtmlSnippet.new @options, 100, 3
+
+ rdoc = <<-RDOC
+= \RDoc - Ruby Documentation System
+
+* {RDoc Project Page}[https://github.com/rdoc/rdoc/]
+* {RDoc Documentation}[http://docs.seattlerb.org/rdoc]
+* {RDoc Bug Tracker}[https://github.com/rdoc/rdoc/issues]
+
+== DESCRIPTION:
+
+RDoc produces HTML and command-line documentation for Ruby projects. RDoc
+includes the +rdoc+ and +ri+ tools for generating and displaying online
+documentation.
+
+See RDoc for a description of RDoc's markup and basic use.
+ RDOC
+
+ expected = <<-EXPECTED
+<p>RDoc - Ruby Documentation System
+<p>RDoc Project Page
+<p>RDoc Documentation
+ EXPECTED
+
+ actual = @to.convert rdoc
+
+ assert_equal expected, actual
+ assert_equal 67, @to.characters
+ end
+
+ def test_convert_limit_in_tag
+ @to = RDoc::Markup::ToHtmlSnippet.new @options, 4
+ rdoc = "* ab *c* d\n"
+
+ expected = "<p>ab <strong>c</strong> #{@ellipsis}\n\n"
+
+ actual = @to.convert rdoc
+
+ assert_equal 4, @to.characters
+ assert_equal expected, actual
+ end
+
+ def test_convert_limit_verbatim
+ rdoc = <<-RDOC
+= Hello There
+
+This is some text, it *will* be cut off after 100 characters
+
+ This one is cut off in this verbatim section
+ RDOC
+
+ expected = <<-EXPECTED
+<p>Hello There
+<p>This is some text, it <strong>will</strong> be cut off after 100 characters
+
+<pre>This one is cut off in this verbatim ...</pre>
+ EXPECTED
+
+ actual = @to.convert rdoc
+
+ assert_equal expected, actual
+ assert_equal 113, @to.characters
+ end
+
+ def test_convert_limit_verbatim_2
+ rdoc = <<-RDOC
+Extracts the class, selector and method name parts from +name+ like
+Foo::Bar#baz.
+
+NOTE: Given Foo::Bar, Bar is considered a class even though it may be a
+ method
+ RDOC
+
+ expected = <<-EXPECTED
+<p>Extracts the class, selector and method name parts from <code>name</code>
+like Foo::Bar#baz.
+<p>NOTE: Given Foo::Bar, #{@ellipsis}
+ EXPECTED
+
+ actual = @to.convert rdoc
+
+ assert_equal expected, actual
+ assert_equal 101, @to.characters
+ end
+
+ def test_convert_limit_verbatim_multiline
+ rdoc = <<-RDOC
+Look for directives in a normal comment block:
+
+ # :stopdoc:
+ # Don't display comment from this point forward
+
+This routine modifies its +comment+ parameter.
+ RDOC
+
+ inner = CGI.escapeHTML "# Don't display comment from this point forward"
+ expected = <<-EXPECTED
+<p>Look for directives in a normal comment block:
+
+<pre># :stopdoc:
+#{inner}</pre>
+ EXPECTED
+
+ actual = @to.convert rdoc
+
+ assert_equal expected, actual
+ assert_equal 105, @to.characters
+ end
+
+ def test_convert_limit_over
+ @to = RDoc::Markup::ToHtmlSnippet.new @options, 4
+ rdoc = "* text\n" * 2
+
+ expected = "<p>text\n"
+ expected.chomp!
+ expected << " #{@ellipsis}\n"
+
+ actual = @to.convert rdoc
+
+ assert_equal 4, @to.characters
+ assert_equal expected, actual
+ end
+
+ def test_convert_string
+ assert_equal '&lt;&gt;', @to.convert_string('<>')
+ end
+
+ def test_convert_RDOCLINK_label_label
+ result = @to.convert 'rdoc-label:label-One'
+
+ assert_equal "<p>One\n", result
+ assert_equal 3, @to.characters
+ end
+
+ def test_convert_RDOCLINK_label_foottext
+ result = @to.convert 'rdoc-label:foottext-1'
+
+ assert_equal "<p>*1\n", result
+ assert_equal 2, @to.characters
+ end
+
+ def test_convert_RDOCLINK_label_footmark
+ result = @to.convert 'rdoc-label:footmark-1'
+
+ assert_equal "<p>^1\n", result
+ assert_equal 2, @to.characters
+ end
+
+ def test_convert_RDOCLINK_ref
+ result = @to.convert 'rdoc-ref:C'
+
+ assert_equal "<p>C\n", result
+ assert_equal 1, @to.characters
+ end
+
+ def test_convert_TIDYLINK_rdoc_label
+ result = @to.convert '{foo}[rdoc-label:foottext-1]'
+
+ assert_equal "<p>foo\n", result
+ assert_equal 3, @to.characters
+ end
+
+ def test_handle_special_HYPERLINK_link
+ special = RDoc::Markup::Special.new 0, 'link:README.txt'
+
+ link = @to.handle_special_HYPERLINK special
+
+ assert_equal 'README.txt', link
+ end
+
+ def test_list_verbatim_2
+ str = "* one\n verb1\n verb2\n* two\n"
+
+ expected = <<-EXPECTED
+<p>one
+
+<pre>verb1
+verb2</pre>
+<p>two
+
+ EXPECTED
+
+ assert_equal expected, @m.convert(str, @to)
+ assert_equal 17, @to.characters
+ end
+
+ def test_on_tags
+ on = RDoc::Markup::AttrChanger.new 2, 0
+
+ @to.on_tags [], on
+
+ assert_equal 2, @to.mask
+ end
+
+ def test_off_tags
+ on = RDoc::Markup::AttrChanger.new 2, 0
+ off = RDoc::Markup::AttrChanger.new 0, 2
+
+ @to.on_tags [], on
+ @to.off_tags [], off
+
+ assert_equal 0, @to.mask
+ end
+
+ def test_to_html
+ assert_equal "<p><code>--</code>\n", util_format("<tt>--</tt>")
+ assert_equal 2, @to.characters
+ end
+
+ def util_format text
+ paragraph = RDoc::Markup::Paragraph.new text
+
+ @to.start_accepting
+ @to.accept_paragraph paragraph
+ @to.end_accepting
+ end
+
+end
+
diff --git a/test/rdoc/test_rdoc_markup_to_joined_paragraph.rb b/test/rdoc/test_rdoc_markup_to_joined_paragraph.rb
new file mode 100644
index 0000000000..148edb1772
--- /dev/null
+++ b/test/rdoc/test_rdoc_markup_to_joined_paragraph.rb
@@ -0,0 +1,32 @@
+require 'rdoc/test_case'
+
+class TestRDocMarkupToJoinedParagraph < RDoc::TestCase
+
+ def setup
+ super
+
+ @to = RDoc::Markup::ToJoinedParagraph.new
+ end
+
+ def test_accept_paragraph
+ parsed = para('hello', ' ', 'world')
+
+ @to.accept_paragraph parsed
+
+ expected = para('hello world')
+
+ assert_equal expected, parsed
+ end
+
+ def test_accept_paragraph_break
+ parsed = para('hello', ' ', 'world', hard_break, 'everyone')
+
+ @to.accept_paragraph parsed
+
+ expected = para('hello world', hard_break, 'everyone')
+
+ assert_equal expected, parsed
+ end
+
+end
+
diff --git a/test/rdoc/test_rdoc_markup_to_label.rb b/test/rdoc/test_rdoc_markup_to_label.rb
new file mode 100644
index 0000000000..5fb358bee3
--- /dev/null
+++ b/test/rdoc/test_rdoc_markup_to_label.rb
@@ -0,0 +1,112 @@
+require 'rdoc/test_case'
+
+class TestRDocMarkupToLabel < RDoc::Markup::FormatterTestCase
+
+ add_visitor_tests
+
+ def setup
+ super
+
+ @to = RDoc::Markup::ToLabel.new
+ end
+
+ def empty
+ assert_empty @to.res
+ end
+
+ def end_accepting
+ assert_equal %w[hi], @to.res
+ end
+
+ alias accept_blank_line empty
+ alias accept_block_quote empty
+ alias accept_document empty
+ alias accept_heading empty
+ alias accept_heading_1 empty
+ alias accept_heading_2 empty
+ alias accept_heading_3 empty
+ alias accept_heading_4 empty
+ alias accept_heading_b empty
+ alias accept_heading_suppressed_crossref empty
+ alias accept_list_end_bullet empty
+ alias accept_list_end_label empty
+ alias accept_list_end_lalpha empty
+ alias accept_list_end_note empty
+ alias accept_list_end_number empty
+ alias accept_list_end_ualpha empty
+ alias accept_list_item_end_bullet empty
+ alias accept_list_item_end_label empty
+ alias accept_list_item_end_lalpha empty
+ alias accept_list_item_end_note empty
+ alias accept_list_item_end_number empty
+ alias accept_list_item_end_ualpha empty
+ alias accept_list_item_start_bullet empty
+ alias accept_list_item_start_label empty
+ alias accept_list_item_start_lalpha empty
+ alias accept_list_item_start_note empty
+ alias accept_list_item_start_note_2 empty
+ alias accept_list_item_start_note_multi_description empty
+ alias accept_list_item_start_note_multi_label empty
+ alias accept_list_item_start_number empty
+ alias accept_list_item_start_ualpha empty
+ alias accept_list_start_bullet empty
+ alias accept_list_start_label empty
+ alias accept_list_start_lalpha empty
+ alias accept_list_start_note empty
+ alias accept_list_start_number empty
+ alias accept_list_start_ualpha empty
+ alias accept_paragraph empty
+ alias accept_paragraph_b empty
+ alias accept_paragraph_br empty
+ alias accept_paragraph_break empty
+ alias accept_paragraph_i empty
+ alias accept_paragraph_plus empty
+ alias accept_paragraph_star empty
+ alias accept_paragraph_underscore empty
+ alias accept_raw empty
+ alias accept_rule empty
+ alias accept_verbatim empty
+ alias list_nested empty
+ alias list_verbatim empty
+ alias start_accepting empty
+
+ def test_convert_bold
+ assert_equal 'bold', @to.convert('<b>bold</b>')
+ assert_equal 'bold', @to.convert('*bold*')
+ end
+
+ def test_convert_crossref
+ assert_equal 'SomeClass', @to.convert('SomeClass')
+ assert_equal 'SomeClass', @to.convert('\\SomeClass')
+
+ assert_equal 'some_method', @to.convert('some_method')
+ assert_equal 'some_method', @to.convert('\\some_method')
+
+ assert_equal '%23some_method', @to.convert('#some_method')
+ assert_equal '%23some_method', @to.convert('\\#some_method')
+ end
+
+ def test_convert_em
+ assert_equal 'em', @to.convert('<em>em</em>')
+ assert_equal 'em', @to.convert('*em*')
+ end
+
+ def test_convert_em_dash # for HTML conversion
+ assert_equal '--', @to.convert('--')
+ end
+
+ def test_convert_escape
+ assert_equal 'a+%3E+b', @to.convert('a > b')
+ end
+
+ def test_convert_tidylink
+ assert_equal 'text', @to.convert('{text}[stuff]')
+ assert_equal 'text', @to.convert('text[stuff]')
+ end
+
+ def test_convert_tt
+ assert_equal 'tt', @to.convert('<tt>tt</tt>')
+ end
+
+end
+
diff --git a/test/rdoc/test_rdoc_markup_to_markdown.rb b/test/rdoc/test_rdoc_markup_to_markdown.rb
new file mode 100644
index 0000000000..56f84b41db
--- /dev/null
+++ b/test/rdoc/test_rdoc_markup_to_markdown.rb
@@ -0,0 +1,352 @@
+require 'rdoc/test_case'
+
+class TestRDocMarkupToMarkdown < RDoc::Markup::TextFormatterTestCase
+
+ add_visitor_tests
+ add_text_tests
+
+ def setup
+ super
+
+ @to = RDoc::Markup::ToMarkdown.new
+ end
+
+ def accept_blank_line
+ assert_equal "\n", @to.res.join
+ end
+
+ def accept_block_quote
+ assert_equal "> quote\n", @to.res.join
+ end
+
+ def accept_document
+ assert_equal "hello\n", @to.res.join
+ end
+
+ def accept_heading
+ assert_equal "##### Hello\n", @to.res.join
+ end
+
+ def accept_list_end_bullet
+ assert_empty @to.list_index
+ assert_empty @to.list_type
+ assert_empty @to.list_width
+ end
+
+ def accept_list_end_label
+ assert_empty @to.list_index
+ assert_empty @to.list_type
+ assert_empty @to.list_width
+ end
+
+ def accept_list_end_lalpha
+ assert_empty @to.list_index
+ assert_empty @to.list_type
+ assert_empty @to.list_width
+ end
+
+ def accept_list_end_note
+ assert_empty @to.list_index
+ assert_empty @to.list_type
+ assert_empty @to.list_width
+ end
+
+ def accept_list_end_number
+ assert_empty @to.list_index
+ assert_empty @to.list_type
+ assert_empty @to.list_width
+ end
+
+ def accept_list_end_ualpha
+ assert_empty @to.list_index
+ assert_empty @to.list_type
+ assert_empty @to.list_width
+ end
+
+ def accept_list_item_end_bullet
+ assert_equal 0, @to.indent, 'indent'
+ end
+
+ def accept_list_item_end_label
+ assert_equal "cat\n: ", @to.res.join
+ assert_equal 0, @to.indent, 'indent'
+ end
+
+ def accept_list_item_end_lalpha
+ assert_equal 0, @to.indent, 'indent'
+ assert_equal 2, @to.list_index.last
+ end
+
+ def accept_list_item_end_note
+ assert_equal "cat\n: ", @to.res.join
+ assert_equal 0, @to.indent, 'indent'
+ end
+
+ def accept_list_item_end_number
+ assert_equal 0, @to.indent, 'indent'
+ assert_equal 2, @to.list_index.last
+ end
+
+ def accept_list_item_end_ualpha
+ assert_equal 0, @to.indent, 'indent'
+ assert_equal 2, @to.list_index.last
+ end
+
+ def accept_list_item_start_bullet
+ assert_equal [""], @to.res
+ assert_equal '* ', @to.prefix
+ end
+
+ def accept_list_item_start_label
+ assert_equal [""], @to.res
+ assert_equal "cat\n: ", @to.prefix
+
+ assert_equal 4, @to.indent
+ end
+
+ def accept_list_item_start_lalpha
+ assert_equal [""], @to.res
+ assert_equal '1. ', @to.prefix
+
+ assert_equal 1, @to.list_index.last
+ assert_equal 4, @to.indent
+ end
+
+ def accept_list_item_start_note
+ assert_equal [""], @to.res
+ assert_equal "cat\n: ", @to.prefix
+
+ assert_equal 4, @to.indent
+ end
+
+ def accept_list_item_start_number
+ assert_equal [""], @to.res
+ assert_equal '1. ', @to.prefix
+
+ assert_equal 1, @to.list_index.last
+ assert_equal 4, @to.indent
+ end
+
+ def accept_list_item_start_ualpha
+ assert_equal [""], @to.res
+ assert_equal '1. ', @to.prefix
+
+ assert_equal 1, @to.list_index.last
+ assert_equal 4, @to.indent
+ end
+
+ def accept_list_start_bullet
+ assert_equal "", @to.res.join
+ assert_equal [nil], @to.list_index
+ assert_equal [:BULLET], @to.list_type
+ assert_equal [4], @to.list_width
+ end
+
+ def accept_list_start_label
+ assert_equal "", @to.res.join
+ assert_equal [nil], @to.list_index
+ assert_equal [:LABEL], @to.list_type
+ assert_equal [4], @to.list_width
+ end
+
+ def accept_list_start_lalpha
+ assert_equal "", @to.res.join
+ assert_equal [1], @to.list_index
+ assert_equal [:LALPHA], @to.list_type
+ assert_equal [4], @to.list_width
+ end
+
+ def accept_list_start_note
+ assert_equal "", @to.res.join
+ assert_equal [nil], @to.list_index
+ assert_equal [:NOTE], @to.list_type
+ assert_equal [4], @to.list_width
+ end
+
+ def accept_list_start_number
+ assert_equal "", @to.res.join
+ assert_equal [1], @to.list_index
+ assert_equal [:NUMBER], @to.list_type
+ assert_equal [4], @to.list_width
+ end
+
+ def accept_list_start_ualpha
+ assert_equal "", @to.res.join
+ assert_equal [1], @to.list_index
+ assert_equal [:UALPHA], @to.list_type
+ assert_equal [4], @to.list_width
+ end
+
+ def accept_paragraph
+ assert_equal "hi\n", @to.res.join
+ end
+
+ def accept_raw
+ raw = <<-RAW.rstrip
+<table>
+<tr><th>Name<th>Count
+<tr><td>a<td>1
+<tr><td>b<td>2
+</table>
+ RAW
+
+ assert_equal raw, @to.res.join
+ end
+
+ def accept_rule
+ assert_equal "---\n", @to.res.join
+ end
+
+ def accept_verbatim
+ assert_equal " hi\n world\n\n", @to.res.join
+ end
+
+ def end_accepting
+ assert_equal "hi", @to.end_accepting
+ end
+
+ def start_accepting
+ assert_equal 0, @to.indent
+ assert_equal [""], @to.res
+ assert_empty @to.list_index
+ assert_empty @to.list_type
+ assert_empty @to.list_width
+ end
+
+ def accept_heading_1
+ assert_equal "# Hello\n", @to.end_accepting
+ end
+
+ def accept_heading_2
+ assert_equal "## Hello\n", @to.end_accepting
+ end
+
+ def accept_heading_3
+ assert_equal "### Hello\n", @to.end_accepting
+ end
+
+ def accept_heading_4
+ assert_equal "#### Hello\n", @to.end_accepting
+ end
+
+ def accept_heading_indent
+ assert_equal " # Hello\n", @to.end_accepting
+ end
+
+ def accept_heading_b
+ assert_equal "# **Hello**\n", @to.end_accepting
+ end
+
+ def accept_heading_suppressed_crossref
+ assert_equal "# Hello\n", @to.end_accepting
+ end
+
+ def accept_list_item_start_note_2
+ assert_equal "`teletype`\n: teletype description\n\n", @to.res.join
+ end
+
+ def accept_list_item_start_note_multi_description
+ assert_equal "label\n: description one\n\n: description two\n\n",
+ @to.res.join
+ end
+
+ def accept_list_item_start_note_multi_label
+ assert_equal "one\ntwo\n: two headers\n\n", @to.res.join
+ end
+
+ def accept_paragraph_b
+ assert_equal "reg **bold words** reg\n", @to.end_accepting
+ end
+
+ def accept_paragraph_br
+ assert_equal "one \ntwo\n", @to.end_accepting
+ end
+
+ def accept_paragraph_break
+ assert_equal "hello \nworld\n", @to.end_accepting
+ end
+
+ def accept_paragraph_i
+ assert_equal "reg *italic words* reg\n", @to.end_accepting
+ end
+
+ def accept_paragraph_indent
+ expected = <<-EXPECTED
+ words words words words words words words words words words words words
+ words words words words words words words words words words words words
+ words words words words words words
+ EXPECTED
+
+ assert_equal expected, @to.end_accepting
+ end
+
+ def accept_paragraph_plus
+ assert_equal "reg `teletype` reg\n", @to.end_accepting
+ end
+
+ def accept_paragraph_star
+ assert_equal "reg **bold** reg\n", @to.end_accepting
+ end
+
+ def accept_paragraph_underscore
+ assert_equal "reg *italic* reg\n", @to.end_accepting
+ end
+
+ def accept_paragraph_wrap
+ expected = <<-EXPECTED
+words words words words words words words words words words words words words
+words words words words words words words words words words words words words
+words words words words
+ EXPECTED
+
+ assert_equal expected, @to.end_accepting
+ end
+
+ def accept_rule_indent
+ assert_equal " ---\n", @to.end_accepting
+ end
+
+ def accept_verbatim_indent
+ assert_equal " hi\n world\n\n", @to.end_accepting
+ end
+
+ def accept_verbatim_big_indent
+ assert_equal " hi\n world\n\n", @to.end_accepting
+ end
+
+ def list_nested
+ expected = <<-EXPECTED
+* l1
+ * l1.1
+
+* l2
+
+ EXPECTED
+
+ assert_equal expected, @to.end_accepting
+ end
+
+ def list_verbatim
+ expected = <<-EXPECTED # HACK overblown
+* list stuff
+
+ * list
+ with
+
+ second
+
+ 1. indented
+ 2. numbered
+
+ third
+
+ * second
+
+
+ EXPECTED
+
+ assert_equal expected, @to.end_accepting
+ end
+
+end
+
diff --git a/test/rdoc/test_rdoc_markup_to_rdoc.rb b/test/rdoc/test_rdoc_markup_to_rdoc.rb
index 06cae078c6..4b60d0133e 100644
--- a/test/rdoc/test_rdoc_markup_to_rdoc.rb
+++ b/test/rdoc/test_rdoc_markup_to_rdoc.rb
@@ -1,7 +1,4 @@
-require 'rubygems'
-require 'rdoc/markup/text_formatter_test_case'
-require 'rdoc/markup/to_rdoc'
-require 'minitest/autorun'
+require 'rdoc/test_case'
class TestRDocMarkupToRDoc < RDoc::Markup::TextFormatterTestCase
@@ -18,6 +15,10 @@ class TestRDocMarkupToRDoc < RDoc::Markup::TextFormatterTestCase
assert_equal "\n", @to.res.join
end
+ def accept_block_quote
+ assert_equal "> quote\n", @to.res.join
+ end
+
def accept_document
assert_equal "hello\n", @to.res.join
end
@@ -67,7 +68,7 @@ class TestRDocMarkupToRDoc < RDoc::Markup::TextFormatterTestCase
end
def accept_list_item_end_label
- assert_equal "\n", @to.res.join
+ assert_equal "cat:\n", @to.res.join
assert_equal 0, @to.indent, 'indent'
end
@@ -77,7 +78,7 @@ class TestRDocMarkupToRDoc < RDoc::Markup::TextFormatterTestCase
end
def accept_list_item_end_note
- assert_equal "\n", @to.res.join
+ assert_equal "cat:\n", @to.res.join
assert_equal 0, @to.indent, 'indent'
end
@@ -244,10 +245,27 @@ class TestRDocMarkupToRDoc < RDoc::Markup::TextFormatterTestCase
assert_equal "<tt>teletype</tt>:\n teletype description\n\n", @to.res.join
end
+ def accept_list_item_start_note_multi_description
+ assert_equal "label:\n description one\n\n description two\n\n",
+ @to.res.join
+ end
+
+ def accept_list_item_start_note_multi_label
+ assert_equal "one\ntwo:\n two headers\n\n", @to.res.join
+ end
+
def accept_paragraph_b
assert_equal "reg <b>bold words</b> reg\n", @to.end_accepting
end
+ def accept_paragraph_br
+ assert_equal "one\ntwo\n", @to.end_accepting
+ end
+
+ def accept_paragraph_break
+ assert_equal "hello\nworld\n", @to.end_accepting
+ end
+
def accept_paragraph_i
assert_equal "reg <em>italic words</em> reg\n", @to.end_accepting
end
@@ -327,6 +345,24 @@ words words words words
assert_equal expected, @to.end_accepting
end
+ # functional test
+ def test_convert_list_note
+ note_list = <<-NOTE_LIST
+foo ::
+bar ::
+ hi
+ NOTE_LIST
+
+ expected = <<-EXPECTED
+foo
+bar:
+ hi
+
+ EXPECTED
+
+ assert_equal expected, @to.convert(note_list)
+ end
+
def test_accept_indented_paragraph
ip = RDoc::Markup::IndentedParagraph.new 2, 'cats are cool'
diff --git a/test/rdoc/test_rdoc_markup_to_table_of_contents.rb b/test/rdoc/test_rdoc_markup_to_table_of_contents.rb
new file mode 100644
index 0000000000..fd0be746d8
--- /dev/null
+++ b/test/rdoc/test_rdoc_markup_to_table_of_contents.rb
@@ -0,0 +1,95 @@
+require 'rdoc/test_case'
+
+class TestRDocMarkupToTableOfContents < RDoc::Markup::FormatterTestCase
+
+ add_visitor_tests
+
+ def setup
+ super
+
+ @to = RDoc::Markup::ToTableOfContents.new
+ end
+
+ def end_accepting
+ assert_equal %w[hi], @to.res
+ end
+
+ def empty
+ assert_empty @to.res
+ end
+
+ def accept_heading
+ assert_equal [@RM::Heading.new(5, 'Hello')], @to.res
+ end
+
+ def accept_heading_1
+ assert_equal [@RM::Heading.new(1, 'Hello')], @to.res
+ end
+
+ def accept_heading_2
+ assert_equal [@RM::Heading.new(2, 'Hello')], @to.res
+ end
+
+ def accept_heading_3
+ assert_equal [@RM::Heading.new(3, 'Hello')], @to.res
+ end
+
+ def accept_heading_4
+ assert_equal [@RM::Heading.new(4, 'Hello')], @to.res
+ end
+
+ def accept_heading_b
+ assert_equal [@RM::Heading.new(1, '*Hello*')], @to.res
+ end
+
+ def accept_heading_suppressed_crossref
+ assert_equal [@RM::Heading.new(1, '\\Hello')], @to.res
+ end
+
+ alias accept_blank_line empty
+ alias accept_block_quote empty
+ alias accept_document empty
+ alias accept_list_end_bullet empty
+ alias accept_list_end_label empty
+ alias accept_list_end_lalpha empty
+ alias accept_list_end_note empty
+ alias accept_list_end_number empty
+ alias accept_list_end_ualpha empty
+ alias accept_list_item_end_bullet empty
+ alias accept_list_item_end_label empty
+ alias accept_list_item_end_lalpha empty
+ alias accept_list_item_end_note empty
+ alias accept_list_item_end_number empty
+ alias accept_list_item_end_ualpha empty
+ alias accept_list_item_start_bullet empty
+ alias accept_list_item_start_label empty
+ alias accept_list_item_start_lalpha empty
+ alias accept_list_item_start_note empty
+ alias accept_list_item_start_note_2 empty
+ alias accept_list_item_start_note_multi_description empty
+ alias accept_list_item_start_note_multi_label empty
+ alias accept_list_item_start_number empty
+ alias accept_list_item_start_ualpha empty
+ alias accept_list_start_bullet empty
+ alias accept_list_start_label empty
+ alias accept_list_start_lalpha empty
+ alias accept_list_start_note empty
+ alias accept_list_start_number empty
+ alias accept_list_start_ualpha empty
+ alias accept_paragraph empty
+ alias accept_paragraph_b empty
+ alias accept_paragraph_br empty
+ alias accept_paragraph_break empty
+ alias accept_paragraph_i empty
+ alias accept_paragraph_plus empty
+ alias accept_paragraph_star empty
+ alias accept_paragraph_underscore empty
+ alias accept_raw empty
+ alias accept_rule empty
+ alias accept_verbatim empty
+ alias list_nested empty
+ alias list_verbatim empty
+ alias start_accepting empty
+
+end
+
diff --git a/test/rdoc/test_rdoc_markup_to_tt_only.rb b/test/rdoc/test_rdoc_markup_to_tt_only.rb
index f5bb662897..2e950dd1b0 100644
--- a/test/rdoc/test_rdoc_markup_to_tt_only.rb
+++ b/test/rdoc/test_rdoc_markup_to_tt_only.rb
@@ -1,7 +1,4 @@
-require 'rubygems'
-require 'rdoc/markup/formatter_test_case'
-require 'rdoc/markup/to_tt_only'
-require 'minitest/autorun'
+require 'rdoc/test_case'
class TestRDocMarkupToTtOnly < RDoc::Markup::FormatterTestCase
@@ -17,6 +14,10 @@ class TestRDocMarkupToTtOnly < RDoc::Markup::FormatterTestCase
assert_empty @to.end_accepting
end
+ def accept_block_quote
+ assert_empty @to.end_accepting
+ end
+
def accept_document
assert_equal [], @to.res
end
@@ -125,6 +126,10 @@ class TestRDocMarkupToTtOnly < RDoc::Markup::FormatterTestCase
assert_empty @to.end_accepting
end
+ def accept_paragraph_break
+ assert_empty @to.end_accepting
+ end
+
def accept_raw
assert_empty @to.end_accepting
end
@@ -177,10 +182,22 @@ class TestRDocMarkupToTtOnly < RDoc::Markup::FormatterTestCase
assert_equal [nil, 'teletype', nil], @to.res
end
+ def accept_list_item_start_note_multi_description
+ assert_empty @to.res
+ end
+
+ def accept_list_item_start_note_multi_label
+ assert_empty @to.res
+ end
+
def accept_paragraph_b
assert_empty @to.end_accepting
end
+ def accept_paragraph_br
+ assert_empty @to.end_accepting
+ end
+
def accept_paragraph_i
assert_empty @to.end_accepting
end
diff --git a/test/rdoc/test_rdoc_markup_verbatim.rb b/test/rdoc/test_rdoc_markup_verbatim.rb
new file mode 100644
index 0000000000..781d52849a
--- /dev/null
+++ b/test/rdoc/test_rdoc_markup_verbatim.rb
@@ -0,0 +1,29 @@
+require 'rdoc/test_case'
+
+class TestRDocMarkupVerbatim < RDoc::TestCase
+
+ def test_equals2
+ v1 = verb('1 + 1')
+ v2 = verb('1 + 1')
+ v3 = verb('1 + 2')
+ v4 = verb('1 + 1')
+ v4.format = :ruby
+
+ assert_equal v1, v2
+
+ refute_equal v1, v3
+ refute_equal v1, v4
+ end
+
+ def test_ruby_eh
+ verbatim = RDoc::Markup::Verbatim.new
+
+ refute verbatim.ruby?
+
+ verbatim.format = :ruby
+
+ assert verbatim.ruby?
+ end
+
+end
+
diff --git a/test/rdoc/test_rdoc_method_attr.rb b/test/rdoc/test_rdoc_method_attr.rb
index 007a3f6b35..8fff038289 100644
--- a/test/rdoc/test_rdoc_method_attr.rb
+++ b/test/rdoc/test_rdoc_method_attr.rb
@@ -111,12 +111,45 @@ class TestRDocMethodAttr < XrefTestCase
assert_nil @m1_m.find_method_or_attribute 'm'
end
+ def test_full_name
+ assert_equal 'C1#m', @c1_m.full_name
+ assert_equal 'C1::m', @c1__m.full_name
+ end
+
+ def test_output_name
+ assert_equal '#m', @c1_m.output_name(@c1)
+ assert_equal '::m', @c1__m.output_name(@c1)
+
+ assert_equal 'C1#m', @c1_m.output_name(@c2)
+ assert_equal 'C1.m', @c1__m.output_name(@c2)
+ end
+
+ def test_search_record
+ @c1_m.comment = 'This is a comment.'
+
+ expected = [
+ 'm',
+ 'C1#m',
+ 'm',
+ 'C1',
+ 'C1.html#method-i-m',
+ '(foo)',
+ "<p>This is a comment.\n",
+ ]
+
+ assert_equal expected, @c1_m.search_record
+ end
+
+ def test_equals2
+ assert_equal @c1_m, @c1_m
+ refute_equal @c1_m, @parent_m
+ end
+
def test_to_s
assert_equal 'RDoc::AnyMethod: C1#m', @c1_m.to_s
assert_equal 'RDoc::AnyMethod: C2#b', @c2_b.to_s
assert_equal 'RDoc::AnyMethod: C1::m', @c1__m.to_s
end
-
end
diff --git a/test/rdoc/test_rdoc_normal_class.rb b/test/rdoc/test_rdoc_normal_class.rb
index bd0d67e19c..f3c7890d59 100644
--- a/test/rdoc/test_rdoc_normal_class.rb
+++ b/test/rdoc/test_rdoc_normal_class.rb
@@ -2,15 +2,34 @@ require File.expand_path '../xref_test_case', __FILE__
class TestRDocNormalClass < XrefTestCase
- def test_ancestors_class
- top_level = RDoc::TopLevel.new 'file.rb'
- klass = top_level.add_class RDoc::NormalClass, 'Klass'
+ def test_ancestors
+ klass = @top_level.add_class RDoc::NormalClass, 'Klass'
incl = RDoc::Include.new 'Incl', ''
- sub_klass = klass.add_class RDoc::NormalClass, 'SubClass', 'Klass'
+ sub_klass = @top_level.add_class RDoc::NormalClass, 'SubClass'
+ sub_klass.superclass = klass
sub_klass.add_include incl
- assert_equal [incl.name, klass], sub_klass.ancestors
+ assert_equal [incl.name, klass, 'Object'], sub_klass.ancestors
+ end
+
+ def test_ancestors_multilevel
+ c1 = @top_level.add_class RDoc::NormalClass, 'Outer'
+ c2 = @top_level.add_class RDoc::NormalClass, 'Middle', c1
+ c3 = @top_level.add_class RDoc::NormalClass, 'Inner', c2
+
+ assert_equal [c2, c1, 'Object'], c3.ancestors
+ end
+
+ def test_direct_ancestors
+ incl = RDoc::Include.new 'Incl', ''
+
+ c1 = @top_level.add_class RDoc::NormalClass, 'Outer'
+ c2 = @top_level.add_class RDoc::NormalClass, 'Middle', c1
+ c3 = @top_level.add_class RDoc::NormalClass, 'Inner', c2
+ c3.add_include incl
+
+ assert_equal [incl.name, c2], c3.direct_ancestors
end
def test_definition
diff --git a/test/rdoc/test_rdoc_normal_module.rb b/test/rdoc/test_rdoc_normal_module.rb
index 975bf911fe..120f56a284 100644
--- a/test/rdoc/test_rdoc_normal_module.rb
+++ b/test/rdoc/test_rdoc_normal_module.rb
@@ -9,7 +9,7 @@ class TestRDocNormalModule < XrefTestCase
end
def test_ancestors_module
- top_level = RDoc::TopLevel.new 'file.rb'
+ top_level = @store.add_file 'file.rb'
mod = top_level.add_module RDoc::NormalModule, 'Mod'
incl = RDoc::Include.new 'Incl', ''
diff --git a/test/rdoc/test_rdoc_options.rb b/test/rdoc/test_rdoc_options.rb
index 2f74f45b45..ddd9cb83ae 100644
--- a/test/rdoc/test_rdoc_options.rb
+++ b/test/rdoc/test_rdoc_options.rb
@@ -1,56 +1,130 @@
-require 'rubygems'
-require 'minitest/autorun'
-require 'rdoc/options'
+require 'rdoc/test_case'
-require 'fileutils'
-require 'tmpdir'
-
-class TestRDocOptions < MiniTest::Unit::TestCase
+class TestRDocOptions < RDoc::TestCase
def setup
+ super
+
@options = RDoc::Options.new
@generators = RDoc::RDoc::GENERATORS.dup
end
def teardown
+ super
+
RDoc::RDoc::GENERATORS.replace @generators
end
+ def mu_pp obj
+ s = ''
+ s = PP.pp obj, s
+ s = s.force_encoding Encoding.default_external if defined? Encoding
+ s.chomp
+ end
+
def test_check_files
skip "assumes UNIX permission model" if /mswin|mingw/ =~ RUBY_PLATFORM
+
out, err = capture_io do
- Dir.mktmpdir do |dir|
- Dir.chdir dir do
- FileUtils.touch 'unreadable'
- FileUtils.chmod 0, 'unreadable'
+ temp_dir do
+ FileUtils.touch 'unreadable'
+ FileUtils.chmod 0, 'unreadable'
- @options.files = %w[nonexistent unreadable]
+ @options.files = %w[nonexistent unreadable]
- @options.check_files
- end
+ @options.check_files
end
end
assert_empty @options.files
- assert_equal '', out
+ assert_empty out
+ assert_empty err
+ end
- expected = <<-EXPECTED
-file 'nonexistent' not found
-file 'unreadable' not readable
- EXPECTED
+ def test_check_files_warn
+ @options.verbosity = 2
- assert_equal expected, err
+ out, err = capture_io do
+ @options.files = %w[nonexistent]
+
+ @options.check_files
+ end
+
+ assert_empty out
+ assert_equal "file 'nonexistent' not found\n", err
+ assert_empty @options.files
end
def test_dry_run_default
refute @options.dry_run
end
+ def test_encode_with
+ coder = {}
+ class << coder; alias add []=; end
+
+ @options.encode_with coder
+
+ encoding = Object.const_defined?(:Encoding) ? 'UTF-8' : nil
+
+ expected = {
+ 'charset' => 'UTF-8',
+ 'encoding' => encoding,
+ 'exclude' => [],
+ 'hyperlink_all' => false,
+ 'line_numbers' => false,
+ 'main_page' => nil,
+ 'markup' => 'rdoc',
+ 'rdoc_include' => [],
+ 'show_hash' => false,
+ 'static_path' => [],
+ 'tab_width' => 8,
+ 'title' => nil,
+ 'visibility' => :protected,
+ 'webcvs' => nil,
+ }
+
+ assert_equal expected, coder
+ end
+
+ def test_encode_with_trim_paths
+ subdir = nil
+ coder = {}
+ class << coder; alias add []=; end
+
+ temp_dir do |dir|
+ FileUtils.mkdir 'project'
+ FileUtils.mkdir 'dir'
+ FileUtils.touch 'file'
+
+ Dir.chdir 'project' do
+ subdir = File.expand_path 'subdir'
+ FileUtils.mkdir 'subdir'
+ @options.parse %w[
+ --copy subdir
+ --copy ../file
+ --copy ../
+ --copy /
+ --include subdir
+ --include ../dir
+ --include ../
+ --include /
+ ]
+
+ @options.encode_with coder
+ end
+ end
+
+ assert_equal [subdir], coder['rdoc_include']
+
+ assert_equal [subdir], coder['static_path']
+ end
+
def test_encoding_default
skip "Encoding not implemented" unless Object.const_defined? :Encoding
- assert_equal Encoding.default_external, @options.encoding
+ assert_equal Encoding::UTF_8, @options.encoding
end
def test_generator_descriptions
@@ -67,6 +141,63 @@ file 'unreadable' not readable
assert_equal expected, @options.generator_descriptions
end
+ def test_init_with_encoding
+ skip "Encoding not implemented" unless Object.const_defined? :Encoding
+ RDoc.load_yaml
+
+ @options.encoding = Encoding::IBM437
+
+ options = YAML.load YAML.dump @options
+
+ assert_equal Encoding::IBM437, options.encoding
+ end
+
+ def test_init_with_trim_paths
+ RDoc.load_yaml
+
+ yaml = <<-YAML
+--- !ruby/object:RDoc::Options
+static_path:
+- /etc
+rdoc_include:
+- /etc
+ YAML
+
+ options = YAML.load yaml
+
+ assert_empty options.rdoc_include
+ assert_empty options.static_path
+ end
+
+ def test_parse_copy_files_file_relative
+ file = File.basename __FILE__
+ expected = File.expand_path __FILE__
+
+ Dir.chdir File.expand_path('..', __FILE__) do
+ @options.parse %W[--copy-files #{file}]
+
+ assert_equal [expected], @options.static_path
+ end
+ end
+
+ def test_parse_copy_files_file_absolute
+ @options.parse %W[--copy-files #{File.expand_path __FILE__}]
+
+ assert_equal [File.expand_path(__FILE__)], @options.static_path
+ end
+
+ def test_parse_copy_files_directory_relative
+ @options.parse %w[--copy-files .]
+
+ assert_equal [@pwd], @options.static_path
+ end
+
+ def test_parse_copy_files_directory_absolute
+ @options.parse %w[--copy-files /]
+
+ assert_equal ['/'], @options.static_path
+ end
+
def test_parse_coverage
@options.parse %w[--dcov]
@@ -286,6 +417,17 @@ file 'unreadable' not readable
assert_equal 'MAIN', @options.main_page
end
+ def test_parse_markup
+ out, err = capture_io do
+ @options.parse %w[--markup tomdoc]
+ end
+
+ assert_empty out
+ assert_empty err
+
+ assert_equal 'tomdoc', @options.markup
+ end
+
def test_parse_template
out, err = capture_io do
@options.parse %w[--template darkfish]
@@ -337,13 +479,21 @@ file 'unreadable' not readable
$LOAD_PATH.replace orig_LOAD_PATH
end
- def test_parse_extension_alias
- out, err = capture_io do
- @options.parse %w[--extension foobar=rdoc]
- end
+ def test_parse_write_options
+ tmpdir = File.join Dir.tmpdir, "test_rdoc_options_#{$$}"
+ FileUtils.mkdir_p tmpdir
- assert_empty out
- assert_empty err
+ Dir.chdir tmpdir do
+ e = assert_raises SystemExit do
+ @options.parse %w[--write-options]
+ end
+
+ assert_equal 0, e.status
+
+ assert File.exist? '.rdoc_options'
+ end
+ ensure
+ FileUtils.rm_rf tmpdir
end
def test_setup_generator
@@ -397,5 +547,33 @@ file 'unreadable' not readable
refute @options.update_output_dir
end
+ def test_warn
+ out, err = capture_io do
+ @options.warn "warnings off"
+ end
+
+ assert_empty out
+ assert_empty err
+
+ @options.verbosity = 2
+
+ out, err = capture_io do
+ @options.warn "warnings on"
+ end
+
+ assert_empty out
+ assert_equal "warnings on\n", err
+ end
+
+ def test_write_options
+ temp_dir do |dir|
+ @options.write_options
+
+ assert File.exist? '.rdoc_options'
+
+ assert_equal @options, YAML.load(File.read('.rdoc_options'))
+ end
+ end
+
end
diff --git a/test/rdoc/test_rdoc_parser.rb b/test/rdoc/test_rdoc_parser.rb
index c323efeac3..35a797063a 100644
--- a/test/rdoc/test_rdoc_parser.rb
+++ b/test/rdoc/test_rdoc_parser.rb
@@ -1,14 +1,16 @@
-require 'rubygems'
-require 'minitest/autorun'
-require 'rdoc/parser'
-require 'rdoc/parser/ruby'
-require 'tmpdir'
+require 'rdoc/test_case'
-class TestRDocParser < MiniTest::Unit::TestCase
+class TestRDocParser < RDoc::TestCase
def setup
+ super
+
@RP = RDoc::Parser
@binary_dat = File.expand_path '../binary.dat', __FILE__
+
+ @fn = 'file.rb'
+ @top_level = RDoc::TopLevel.new @fn
+ @options = RDoc::Options.new
end
def test_class_binary_eh_marshal
@@ -29,11 +31,8 @@ class TestRDocParser < MiniTest::Unit::TestCase
end
def test_class_binary_large_japanese_rdoc
- extenc, Encoding.default_external = Encoding.default_external, Encoding::US_ASCII
- file_name = File.expand_path '../test.ja.largedoc', __FILE__
+ file_name = File.expand_path '../test.ja.large.rdoc', __FILE__
assert !@RP.binary?(file_name)
- ensure
- Encoding.default_external = extenc
end
def test_class_binary_japanese_rdoc
@@ -60,13 +59,18 @@ class TestRDocParser < MiniTest::Unit::TestCase
readme_file_name = File.expand_path '../README', __FILE__
assert_equal @RP::Simple, @RP.can_parse(readme_file_name)
+ end
- jtest_largerdoc_file_name = File.expand_path '../test.ja.largedoc', __FILE__
- assert_nil @RP.can_parse(jtest_largerdoc_file_name)
-
- @RP.alias_extension("rdoc", "largedoc")
- assert_equal @RP::Simple, @RP.can_parse(jtest_largerdoc_file_name)
+ def test_class_can_parse_forbidden
+ Tempfile.open 'forbidden' do |io|
+ begin
+ File.chmod 0000, io.path
+ assert_nil @RP.can_parse io.path
+ ensure
+ File.chmod 0400, io.path
+ end
+ end
end
##
@@ -89,5 +93,92 @@ class TestRDocParser < MiniTest::Unit::TestCase
assert_nil @RP.for(nil, @binary_dat, nil, nil, nil)
end
+ def test_class_for_markup
+ content = <<-CONTENT
+# coding: utf-8 markup: rd
+ CONTENT
+
+ parser = @RP.for @top_level, __FILE__, content, @options, nil
+
+ assert_kind_of @RP::RD, parser
+ end
+
+ def test_class_use_markup
+ content = <<-CONTENT
+# coding: utf-8 markup: rd
+ CONTENT
+
+ parser = @RP.use_markup content
+
+ assert_equal @RP::RD, parser
+ end
+
+ def test_class_use_markup_markdown
+ content = <<-CONTENT
+# coding: utf-8 markup: markdown
+ CONTENT
+
+ parser = @RP.use_markup content
+
+ assert_equal @RP::Ruby, parser
+ end
+
+ def test_class_use_markup_modeline
+ content = <<-CONTENT
+# -*- coding: utf-8 -*-
+# markup: rd
+ CONTENT
+
+ parser = @RP.use_markup content
+
+ assert_equal @RP::RD, parser
+ end
+
+ def test_class_use_markup_modeline_shebang
+ content = <<-CONTENT
+#!/bin/sh
+/* -*- coding: utf-8 -*-
+ * markup: rd
+ */
+ CONTENT
+
+ parser = @RP.use_markup content
+
+ assert_equal @RP::RD, parser
+ end
+
+ def test_class_use_markup_shebang
+ content = <<-CONTENT
+#!/usr/bin/env ruby
+# coding: utf-8 markup: rd
+ CONTENT
+
+ parser = @RP.use_markup content
+
+ assert_equal @RP::RD, parser
+ end
+
+ def test_class_use_markup_tomdoc
+ content = <<-CONTENT
+# coding: utf-8 markup: tomdoc
+ CONTENT
+
+ parser = @RP.use_markup content
+
+ assert_equal @RP::Ruby, parser
+ end
+
+ def test_class_use_markup_none
+ parser = @RP.use_markup ''
+
+ assert_nil parser
+ end
+
+ def test_initialize
+ @RP.new @top_level, @fn, '', @options, nil
+
+ assert_equal @RP, @top_level.parser
+ end
+
end
diff --git a/test/rdoc/test_rdoc_parser_c.rb b/test/rdoc/test_rdoc_parser_c.rb
index 438eeee2ab..4e5e6ab1a2 100644
--- a/test/rdoc/test_rdoc_parser_c.rb
+++ b/test/rdoc/test_rdoc_parser_c.rb
@@ -1,9 +1,4 @@
-require 'stringio'
-require 'tempfile'
-require 'rubygems'
-require 'minitest/autorun'
-require 'rdoc/options'
-require 'rdoc/parser/c'
+require 'rdoc/test_case'
=begin
TODO: test call-seq parsing
@@ -51,22 +46,24 @@ class RDoc::Parser::C
public :do_classes, :do_constants
end
-class TestRDocParserC < MiniTest::Unit::TestCase
+class TestRDocParserC < RDoc::TestCase
def setup
+ super
+
@tempfile = Tempfile.new self.class.name
filename = @tempfile.path
- @top_level = RDoc::TopLevel.new filename
+ @top_level = @store.add_file filename
@fn = filename
@options = RDoc::Options.new
- @stats = RDoc::Stats.new 0
-
- RDoc::Parser::C.reset
- RDoc::TopLevel.reset
+ @options.verbosity = 2
+ @stats = RDoc::Stats.new @store, 0
end
def teardown
+ super
+
@tempfile.close
end
@@ -116,18 +113,18 @@ void Init_Blah(void) {
accessor = attrs.shift
assert_equal 'accessor', accessor.name
assert_equal 'RW', accessor.rw
- assert_equal 'This is an accessor', accessor.comment
+ assert_equal 'This is an accessor', accessor.comment.text
assert_equal @top_level, accessor.file
reader = attrs.shift
assert_equal 'reader', reader.name
assert_equal 'R', reader.rw
- assert_equal 'This is a reader', reader.comment
+ assert_equal 'This is a reader', reader.comment.text
writer = attrs.shift
assert_equal 'writer', writer.name
assert_equal 'W', writer.rw
- assert_equal 'This is a writer', writer.comment
+ assert_equal 'This is a writer', writer.comment.text
end
def test_do_attr_rb_define_attr
@@ -150,7 +147,7 @@ void Init_Blah(void) {
accessor = attrs.shift
assert_equal 'accessor', accessor.name
assert_equal 'RW', accessor.rw
- assert_equal 'This is an accessor', accessor.comment
+ assert_equal 'This is an accessor', accessor.comment.text
assert_equal @top_level, accessor.file
end
@@ -211,7 +208,7 @@ void Init_Blah(void) {
assert_equal 'bleh', methods.last.name
assert methods.last.singleton
assert_equal 'blah', methods.last.is_alias_for.name
- assert_equal 'This should show up as an alias', methods.last.comment
+ assert_equal 'This should show up as an alias', methods.last.comment.text
end
def test_do_classes_boot_class
@@ -223,7 +220,7 @@ VALUE cFoo = boot_defclass("Foo", rb_cObject);
EOF
klass = util_get_class content, 'cFoo'
- assert_equal "this is the Foo boot class", klass.comment
+ assert_equal "this is the Foo boot class", klass.comment.text
assert_equal 'Object', klass.superclass
end
@@ -236,7 +233,7 @@ VALUE cFoo = boot_defclass("Foo", 0);
EOF
klass = util_get_class content, 'cFoo'
- assert_equal "this is the Foo boot class", klass.comment
+ assert_equal "this is the Foo boot class", klass.comment.text
assert_equal nil, klass.superclass
end
@@ -251,7 +248,7 @@ void Init_Blah(void) {
refute util_get_class(content, 'cDate')
end
- assert_equal "Enclosing class/module \"cDate\" for alias b a not known\n",
+ assert_equal "Enclosing class or module \"cDate\" for alias b a is not known\n",
err
end
@@ -264,7 +261,21 @@ VALUE cFoo = rb_define_class("Foo", rb_cObject);
EOF
klass = util_get_class content, 'cFoo'
- assert_equal "this is the Foo class", klass.comment
+ assert_equal "this is the Foo class", klass.comment.text
+ end
+
+ def test_do_classes_struct
+ content = <<-EOF
+/* Document-class: Foo
+ * this is the Foo class
+ */
+VALUE cFoo = rb_struct_define_without_accessor(
+ "Foo", rb_cObject, foo_alloc,
+ "some", "various", "fields", NULL);
+ EOF
+
+ klass = util_get_class content, 'cFoo'
+ assert_equal "this is the Foo class", klass.comment.text
end
def test_do_classes_class_under
@@ -277,7 +288,7 @@ VALUE cFoo = rb_define_class_under(rb_mKernel, "Foo", rb_cObject);
klass = util_get_class content, 'cFoo'
assert_equal 'Kernel::Foo', klass.full_name
- assert_equal "this is the Foo class under Kernel", klass.comment
+ assert_equal "this is the Foo class under Kernel", klass.comment.text
end
def test_do_classes_class_under_rb_path2class
@@ -292,7 +303,7 @@ VALUE cFoo = rb_define_class_under(rb_mKernel, "Foo", rb_path2class("A::B"));
assert_equal 'Kernel::Foo', klass.full_name
assert_equal 'A::B', klass.superclass
- assert_equal 'this is Kernel::Foo < A::B', klass.comment
+ assert_equal 'this is Kernel::Foo < A::B', klass.comment.text
end
def test_do_classes_singleton
@@ -315,7 +326,7 @@ VALUE mFoo = rb_define_module("Foo");
EOF
klass = util_get_class content, 'mFoo'
- assert_equal "this is the Foo module", klass.comment
+ assert_equal "this is the Foo module", klass.comment.text
end
def test_do_classes_module_under
@@ -327,7 +338,7 @@ VALUE mFoo = rb_define_module_under(rb_mKernel, "Foo");
EOF
klass = util_get_class content, 'mFoo'
- assert_equal "this is the Foo module under Kernel", klass.comment
+ assert_equal "this is the Foo module under Kernel", klass.comment.text
end
def test_do_constants
@@ -377,6 +388,12 @@ void Init_foo(){
*/
rb_define_const(cFoo, "MULTILINE_NOT_EMPTY", INT2FIX(1));
+ /*
+ * Multiline comment goes here because this comment spans multiple lines.
+ * 1: However, the value extraction should only happen for the first line
+ */
+ rb_define_const(cFoo, "MULTILINE_COLON_ON_SECOND_LINE", INT2FIX(1));
+
}
EOF
@@ -393,7 +410,7 @@ void Init_foo(){
assert_equal @top_level, constants.first.file
- constants = constants.map { |c| [c.name, c.value, c.comment] }
+ constants = constants.map { |c| [c.name, c.value, c.comment.text] }
assert_equal ['PERFECT', '300', 'The highest possible score in bowling '],
constants.shift
@@ -426,6 +443,13 @@ Multiline comment goes here because this comment spans multiple lines.
assert_equal ['MULTILINE_VALUE', '1', comment], constants.shift
assert_equal ['MULTILINE_NOT_EMPTY', 'INT2FIX(1)', comment], constants.shift
+ comment = <<-EOF.chomp
+Multiline comment goes here because this comment spans multiple lines.
+1: However, the value extraction should only happen for the first line
+ EOF
+ assert_equal ['MULTILINE_COLON_ON_SECOND_LINE', 'INT2FIX(1)', comment],
+ constants.shift
+
assert constants.empty?, constants.inspect
end
@@ -445,6 +469,7 @@ void Init_curses(){
@parser = util_parser content
+ @parser.do_modules
@parser.do_classes
@parser.do_constants
@@ -455,7 +480,40 @@ void Init_curses(){
assert_equal 'COLOR_BLACK', constants.first.name
assert_equal 'UINT2NUM(COLOR_BLACK)', constants.first.value
- assert_equal 'Value of the color black', constants.first.comment
+ assert_equal 'Value of the color black', constants.first.comment.text
+ end
+
+ def test_do_constants_file
+ content = <<-EOF
+void Init_File(void) {
+ rb_cFile = rb_define_class("File", rb_cIO);
+ rb_mFConst = rb_define_module_under(rb_cFile, "Constants");
+ rb_include_module(rb_cIO, rb_mFConst);
+
+ /* Document-const: LOCK_SH
+ *
+ * Shared lock
+ */
+ rb_file_const("LOCK_SH", INT2FIX(LOCK_SH));
+}
+ EOF
+
+ @parser = util_parser content
+
+ @parser.do_modules
+ @parser.do_classes
+ @parser.do_constants
+
+ klass = @parser.classes['rb_mFConst']
+
+ constants = klass.constants
+ refute_empty klass.constants
+
+ constant = constants.first
+
+ assert_equal 'LOCK_SH', constant.name
+ assert_equal 'INT2FIX(LOCK_SH)', constant.value
+ assert_equal 'Shared lock', constant.comment.text
end
def test_do_includes
@@ -472,7 +530,7 @@ Init_foo() {
incl = klass.includes.first
assert_equal 'Inc', incl.name
- assert_equal '', incl.comment
+ assert_equal '', incl.comment.text
assert_equal @top_level, incl.file
end
@@ -563,12 +621,63 @@ void Init_Blah(void) {
assert methods.first.singleton
end
+ def test_do_missing
+ parser = util_parser
+
+ klass_a = @top_level.add_class RDoc::ClassModule, 'A'
+ parser.classes['a'] = klass_a
+
+ parser.enclosure_dependencies['c'] << 'b'
+ parser.enclosure_dependencies['b'] << 'a'
+ parser.enclosure_dependencies['d'] << 'a'
+
+ parser.missing_dependencies['d'] = ['d', :class, 'D', 'Object', 'a']
+ parser.missing_dependencies['c'] = ['c', :class, 'C', 'Object', 'b']
+ parser.missing_dependencies['b'] = ['b', :class, 'B', 'Object', 'a']
+
+ parser.do_missing
+
+ assert_equal %w[A A::B A::B::C A::D],
+ @store.all_classes_and_modules.map { |m| m.full_name }.sort
+ end
+
+ def test_do_missing_cycle
+ parser = util_parser
+
+ klass_a = @top_level.add_class RDoc::ClassModule, 'A'
+ parser.classes['a'] = klass_a
+
+ parser.enclosure_dependencies['c'] << 'b'
+ parser.enclosure_dependencies['b'] << 'a'
+
+ parser.missing_dependencies['c'] = ['c', :class, 'C', 'Object', 'b']
+ parser.missing_dependencies['b'] = ['b', :class, 'B', 'Object', 'a']
+
+ parser.enclosure_dependencies['y'] << 'z'
+ parser.enclosure_dependencies['z'] << 'y'
+
+ parser.missing_dependencies['y'] = ['y', :class, 'Y', 'Object', 'z']
+ parser.missing_dependencies['z'] = ['z', :class, 'Z', 'Object', 'y']
+
+ _, err = capture_io do
+ parser.do_missing
+ end
+
+ expected = 'Unable to create class Y (y), class Z (z) ' +
+ 'due to a cyclic class or module creation'
+
+ assert_equal expected, err.chomp
+
+ assert_equal %w[A A::B A::B::C],
+ @store.all_classes_and_modules.map { |m| m.full_name }.sort
+ end
+
def test_find_alias_comment
- parser = util_parser ''
+ parser = util_parser
comment = parser.find_alias_comment 'C', '[]', 'index'
- assert_equal '', comment
+ assert_equal '', comment.text
parser = util_parser <<-C
/*
@@ -580,27 +689,28 @@ rb_define_alias(C, "[]", "index");
comment = parser.find_alias_comment 'C', '[]', 'index'
- assert_equal "/*\n * comment\n */\n\n", comment
+ assert_equal "/*\n * comment\n */\n\n", comment.text
end
- def test_find_class_comment_include
+ def test_find_class_comment
@options.rdoc_include << File.dirname(__FILE__)
content = <<-EOF
/*
- * a comment for class Foo
- *
- * :include: test.txt
+ * Comment 1
*/
-void
-Init_Foo(void) {
- VALUE foo = rb_define_class("Foo", rb_cObject);
-}
+foo = rb_define_class("MyClassName1", rb_cObject);
+
+/*
+ * Comment 2
+ */
+bar = rb_define_class("MyClassName2", rb_cObject);
EOF
- klass = util_get_class content, 'foo'
+ util_get_class content
- assert_equal "a comment for class Foo\n\ntest file", klass.comment
+ assert_equal "Comment 1", @parser.classes['foo'].comment.text
+ assert_equal "Comment 2", @parser.classes['bar'].comment.text
end
def test_find_class_comment_init
@@ -616,7 +726,7 @@ Init_Foo(void) {
klass = util_get_class content, 'foo'
- assert_equal "a comment for class Foo", klass.comment
+ assert_equal "a comment for class Foo", klass.comment.text
end
def test_find_class_comment_define_class
@@ -629,7 +739,7 @@ VALUE foo = rb_define_class("Foo", rb_cObject);
klass = util_get_class content, 'foo'
- assert_equal "a comment for class Foo", klass.comment
+ assert_equal "a comment for class Foo", klass.comment.text
end
def test_find_class_comment_define_class_Init_Foo
@@ -648,7 +758,7 @@ Init_Foo(void) {
klass = util_get_class content, 'foo'
- assert_equal "a comment for class Foo on Init", klass.comment
+ assert_equal "a comment for class Foo on Init", klass.comment.text
end
def test_find_class_comment_define_class_Init_Foo_no_void
@@ -667,7 +777,7 @@ Init_Foo() {
klass = util_get_class content, 'foo'
- assert_equal "a comment for class Foo on Init", klass.comment
+ assert_equal "a comment for class Foo on Init", klass.comment.text
end
def test_find_class_comment_define_class_bogus_comment
@@ -687,7 +797,42 @@ Init_Foo(void) {
klass = util_get_class content, 'foo'
- assert_equal '', klass.comment
+ assert_equal '', klass.comment.text
+ end
+
+ def test_find_class_comment_define_class_under
+ content = <<-EOF
+/*
+ * a comment for class Foo
+ */
+VALUE foo = rb_define_class_under(rb_cObject, "Foo", rb_cObject);
+ EOF
+
+ klass = util_get_class content, 'foo'
+
+ assert_equal "a comment for class Foo", klass.comment.text
+ end
+
+ def test_find_class_comment_define_class_under_Init
+ content = <<-EOF
+/*
+ * a comment for class Foo on Init
+ */
+void
+Init_Foo(void) {
+ /*
+ * a comment for class Foo on rb_define_class
+ */
+ VALUE foo = rb_define_class_under(rb_cObject, "Foo", rb_cObject);
+}
+ EOF
+
+ klass = util_get_class content, 'foo'
+
+ # the inner comment is used since Object::Foo is not necessarily the same
+ # thing as "Foo" for Init_
+ assert_equal "a comment for class Foo on rb_define_class",
+ klass.comment.text
end
def test_find_const_comment_rb_define
@@ -702,7 +847,7 @@ rb_define_const(cFoo, "CONST", value);
comment = parser.find_const_comment 'const', 'CONST'
- assert_equal "/*\n * A comment\n */\n", comment
+ assert_equal "/*\n * A comment\n */\n", comment.text
end
def test_find_const_comment_document_const
@@ -718,7 +863,7 @@ rb_define_const(cFoo, "CONST", value);
comment = parser.find_const_comment nil, 'CONST'
- assert_equal " *\n * A comment\n */", comment
+ assert_equal "/*\n *\n * A comment\n */", comment.text
end
def test_find_const_comment_document_const_full_name
@@ -734,7 +879,7 @@ rb_define_const(cFoo, "CONST", value);
comment = parser.find_const_comment nil, 'CONST', 'Foo'
- assert_equal " *\n * A comment\n */", comment
+ assert_equal "/*\n *\n * A comment\n */", comment.text
end
def test_find_body
@@ -759,7 +904,7 @@ Init_Foo(void) {
assert_equal 'my_method', other_function.name
assert_equal "a comment for other_function",
- other_function.comment
+ other_function.comment.text
assert_equal '()', other_function.params
code = other_function.token_stream.first.text
@@ -832,7 +977,7 @@ Init_Foo(void) {
other_function = klass.method_list.first
assert_equal 'my_method', other_function.name
- assert_equal 'a comment for rb_other_function', other_function.comment
+ assert_equal 'a comment for rb_other_function', other_function.comment.text
assert_equal '()', other_function.params
assert_equal 118, other_function.offset
assert_equal 8, other_function.line
@@ -866,7 +1011,7 @@ Init_Foo(void) {
other_function = klass.method_list.first
assert_equal 'my_method', other_function.name
- assert_equal 'a comment for other_function', other_function.comment
+ assert_equal 'a comment for other_function', other_function.comment.text
assert_equal '()', other_function.params
assert_equal 39, other_function.offset
assert_equal 4, other_function.line
@@ -904,11 +1049,11 @@ Init_Foo(void) {
bar = methods.first
assert_equal 'Foo#bar', bar.full_name
- assert_equal "a comment for bar", bar.comment
+ assert_equal "a comment for bar", bar.comment.text
baz = methods.last
assert_equal 'Foo#baz', baz.full_name
- assert_equal "a comment for bar", baz.comment
+ assert_equal "a comment for bar", baz.comment.text
end
def test_find_body_document_method_equals
@@ -938,7 +1083,7 @@ Init_zlib() {
bar = methods.first
assert_equal 'Zlib::GzipWriter#mtime=', bar.full_name
- assert_equal 'A comment', bar.comment
+ assert_equal 'A comment', bar.comment.text
end
def test_find_body_document_method_same
@@ -979,73 +1124,37 @@ Init_Foo(void) {
s_bar = methods.first
assert_equal 'Foo::bar', s_bar.full_name
- assert_equal "a comment for Foo::bar", s_bar.comment
+ assert_equal "a comment for Foo::bar", s_bar.comment.text
bar = methods.last
assert_equal 'Foo#bar', bar.full_name
- assert_equal "a comment for Foo#bar", bar.comment
+ assert_equal "a comment for Foo#bar", bar.comment.text
end
def test_find_modifiers_call_seq
- comment = <<-COMMENT
-/* call-seq:
- * commercial() -> Date <br />
- * commercial(cwyear, cweek=41, cwday=5, sg=nil) -> Date [ruby 1.8] <br />
- * commercial(cwyear, cweek=1, cwday=1, sg=nil) -> Date [ruby 1.9]
- *
- * If no arguments are given:
- * * ruby 1.8: returns a +Date+ for 1582-10-15 (the Day of Calendar Reform in
- * Italy)
- * * ruby 1.9: returns a +Date+ for julian day 0
- *
- * Otherwise, returns a +Date+ for the commercial week year, commercial week,
- * and commercial week day given. Ignores the 4th argument.
- */
-
- COMMENT
-
- parser = util_parser ''
- method_obj = RDoc::AnyMethod.new nil, 'blah'
-
- parser.find_modifiers comment, method_obj
+ comment = RDoc::Comment.new <<-COMMENT
+call-seq:
+ commercial() -> Date <br />
- expected = <<-CALL_SEQ.chomp
-commercial() -> Date <br />
-commercial(cwyear, cweek=41, cwday=5, sg=nil) -> Date [ruby 1.8] <br />
-commercial(cwyear, cweek=1, cwday=1, sg=nil) -> Date [ruby 1.9]
-
- CALL_SEQ
-
- assert_equal expected, method_obj.call_seq
- end
-
- def test_find_modifiers_call_seq_no_blank
- comment = <<-COMMENT
-/* call-seq:
- * commercial() -> Date <br />
- * commercial(cwyear, cweek=41, cwday=5, sg=nil) -> Date [ruby 1.8] <br />
- * commercial(cwyear, cweek=1, cwday=1, sg=nil) -> Date [ruby 1.9]
- */
+If no arguments are given:
COMMENT
- parser = util_parser ''
+ parser = util_parser
method_obj = RDoc::AnyMethod.new nil, 'blah'
parser.find_modifiers comment, method_obj
expected = <<-CALL_SEQ.chomp
commercial() -> Date <br />
-commercial(cwyear, cweek=41, cwday=5, sg=nil) -> Date [ruby 1.8] <br />
-commercial(cwyear, cweek=1, cwday=1, sg=nil) -> Date [ruby 1.9]
-
+
CALL_SEQ
assert_equal expected, method_obj.call_seq
end
def test_find_modifiers_nodoc
- comment = <<-COMMENT
+ comment = RDoc::Comment.new <<-COMMENT
/* :nodoc:
*
* Blah
@@ -1053,7 +1162,7 @@ commercial(cwyear, cweek=1, cwday=1, sg=nil) -> Date [ruby 1.9]
COMMENT
- parser = util_parser ''
+ parser = util_parser
method_obj = RDoc::AnyMethod.new nil, 'blah'
parser.find_modifiers comment, method_obj
@@ -1062,7 +1171,7 @@ commercial(cwyear, cweek=1, cwday=1, sg=nil) -> Date [ruby 1.9]
end
def test_find_modifiers_yields
- comment = <<-COMMENT
+ comment = RDoc::Comment.new <<-COMMENT
/* :yields: a, b
*
* Blah
@@ -1070,22 +1179,14 @@ commercial(cwyear, cweek=1, cwday=1, sg=nil) -> Date [ruby 1.9]
COMMENT
- parser = util_parser ''
+ parser = util_parser
method_obj = RDoc::AnyMethod.new nil, 'blah'
parser.find_modifiers comment, method_obj
assert_equal 'a, b', method_obj.block_params
- expected = <<-EXPECTED
-/*
- *
- * Blah
- */
-
- EXPECTED
-
- assert_equal expected, comment
+ assert_equal "\n\nBlah", comment.text
end
def test_handle_method_args_minus_1
@@ -1206,14 +1307,14 @@ void Init_Blah(void) {
end
def test_look_for_directives_in
- parser = util_parser ''
+ parser = util_parser
- comment = "# :markup: not_rdoc\n"
+ comment = RDoc::Comment.new "# :other: not_handled\n"
parser.look_for_directives_in @top_level, comment
- assert_equal "# :markup: not_rdoc\n", comment
- assert_equal 'not_rdoc', @top_level.metadata['markup']
+ assert_equal "# :other: not_handled\n", comment.text
+ assert_equal 'not_handled', @top_level.metadata['other']
end
def test_define_method
@@ -1240,7 +1341,7 @@ Init_IO(void) {
klass = util_get_class content, 'rb_cIO'
read_method = klass.method_list.first
assert_equal "read", read_method.name
- assert_equal "Method Comment! ", read_method.comment
+ assert_equal "Method Comment! ", read_method.comment.text
assert_equal "rb_io_s_read", read_method.c_function
assert read_method.singleton
end
@@ -1271,7 +1372,7 @@ Init_IO(void) {
klass = util_get_class content, 'rb_cIO'
read_method = klass.method_list.first
assert_equal "read", read_method.name
- assert_equal "Method Comment! ", read_method.comment
+ assert_equal "Method Comment! ", read_method.comment.text
assert_equal "rb_io_s_read", read_method.c_function
assert read_method.singleton
end
@@ -1301,7 +1402,7 @@ Init_IO(void) {
read_method = klass.method_list.first
assert_equal 'IO#read', read_method.full_name
assert_equal :private, read_method.visibility
- assert_equal "Method Comment! ", read_method.comment
+ assert_equal "Method Comment! ", read_method.comment.text
end
def test_define_method_private_singleton
@@ -1329,7 +1430,7 @@ Init_IO(void) {
klass = util_get_class content, 'rb_cIO'
read_method = klass.method_list.first
assert_equal "read", read_method.name
- assert_equal "Method Comment! ", read_method.comment
+ assert_equal "Method Comment! ", read_method.comment.text
assert_equal :private, read_method.visibility
assert read_method.singleton
end
@@ -1359,12 +1460,12 @@ Init_IO(void) {
klass = util_get_class content, 'rb_cIO'
read_method = klass.method_list.first
assert_equal "read", read_method.name
- assert_equal "Method Comment! ", read_method.comment
+ assert_equal "Method Comment! ", read_method.comment.text
assert read_method.singleton
end
def test_rb_scan_args
- parser = util_parser ''
+ parser = util_parser
assert_equal '(p1)',
parser.rb_scan_args('rb_scan_args(a, b, "1",)')
@@ -1422,13 +1523,39 @@ Init_IO(void) {
parser.rb_scan_args('rb_scan_args(a, b, "*:&",)')
end
- def util_get_class(content, name)
+ def test_scan_order_dependent
+ parser = util_parser <<-C
+void a(void) {
+ mA = rb_define_module("A");
+}
+
+void b(void) {
+ cB = rb_define_class_under(mA, "B", rb_cObject);
+}
+
+void c(void) {
+ mC = rb_define_module_under(cB, "C");
+}
+
+void d(void) {
+ mD = rb_define_class_under(mC, "D");
+}
+ C
+
+ parser.scan
+
+ assert_equal %w[A A::B A::B::C],
+ @store.all_classes_and_modules.map { |m| m.full_name }.sort
+ end
+
+ def util_get_class content, name = nil
@parser = util_parser content
@parser.scan
- @parser.classes[name]
+
+ @parser.classes[name] if name
end
- def util_parser(content)
+ def util_parser content = ''
RDoc::Parser::C.new @top_level, @fn, content, @options, @stats
end
diff --git a/test/rdoc/test_rdoc_parser_markdown.rb b/test/rdoc/test_rdoc_parser_markdown.rb
new file mode 100644
index 0000000000..df0e04d5c1
--- /dev/null
+++ b/test/rdoc/test_rdoc_parser_markdown.rb
@@ -0,0 +1,55 @@
+require 'rdoc/test_case'
+
+class TestRDocParserMarkdown < RDoc::TestCase
+
+ def setup
+ super
+
+ @RP = RDoc::Parser
+
+ @tempfile = Tempfile.new self.class.name
+ filename = @tempfile.path
+
+ @top_level = @store.add_file filename
+ @fn = filename
+ @options = RDoc::Options.new
+ @stats = RDoc::Stats.new @store, 0
+ end
+
+ def teardown
+ super
+
+ @tempfile.close
+ end
+
+ def test_file
+ assert_kind_of RDoc::Parser::Text, util_parser('')
+ end
+
+ def test_class_can_parse
+ assert_equal @RP::Markdown, @RP.can_parse('foo.md')
+ assert_equal @RP::Markdown, @RP.can_parse('foo.md.ja')
+
+ assert_equal @RP::Markdown, @RP.can_parse('foo.markdown')
+ assert_equal @RP::Markdown, @RP.can_parse('foo.markdown.ja')
+ end
+
+ def test_scan
+ parser = util_parser 'it *really* works'
+
+ expected =
+ @RM::Document.new(
+ @RM::Paragraph.new('it _really_ works'))
+ expected.file = @top_level
+
+ parser.scan
+
+ assert_equal expected, @top_level.comment.parse
+ end
+
+ def util_parser content
+ RDoc::Parser::Markdown.new @top_level, @fn, content, @options, @stats
+ end
+
+end
+
diff --git a/test/rdoc/test_rdoc_parser_rd.rb b/test/rdoc/test_rdoc_parser_rd.rb
new file mode 100644
index 0000000000..b94280f497
--- /dev/null
+++ b/test/rdoc/test_rdoc_parser_rd.rb
@@ -0,0 +1,52 @@
+require 'rdoc/test_case'
+
+class TestRDocParserRd < RDoc::TestCase
+
+ def setup
+ super
+
+ @RP = RDoc::Parser
+
+ @tempfile = Tempfile.new self.class.name
+ filename = @tempfile.path
+
+ @top_level = @store.add_file filename
+ @fn = filename
+ @options = RDoc::Options.new
+ @stats = RDoc::Stats.new @store, 0
+ end
+
+ def teardown
+ super
+
+ @tempfile.close
+ end
+
+ def test_file
+ assert_kind_of RDoc::Parser::Text, util_parser('')
+ end
+
+ def test_class_can_parse
+ assert_equal @RP::RD, @RP.can_parse('foo.rd')
+ assert_equal @RP::RD, @RP.can_parse('foo.rd.ja')
+ end
+
+ def test_scan
+ parser = util_parser 'it ((*really*)) works'
+
+ expected =
+ @RM::Document.new(
+ @RM::Paragraph.new('it <em>really</em> works'))
+ expected.file = @top_level
+
+ parser.scan
+
+ assert_equal expected, @top_level.comment.parse
+ end
+
+ def util_parser content
+ RDoc::Parser::RD.new @top_level, @fn, content, @options, @stats
+ end
+
+end
+
diff --git a/test/rdoc/test_rdoc_parser_ruby.rb b/test/rdoc/test_rdoc_parser_ruby.rb
index 6086b3ec13..b25a36301e 100644
--- a/test/rdoc/test_rdoc_parser_ruby.rb
+++ b/test/rdoc/test_rdoc_parser_ruby.rb
@@ -1,17 +1,12 @@
# coding: utf-8
-require 'stringio'
-require 'tempfile'
-require 'rubygems'
-require 'minitest/autorun'
+require 'rdoc/test_case'
-require 'rdoc/options'
-require 'rdoc/parser/ruby'
-require 'rdoc/stats'
-
-class TestRDocParserRuby < MiniTest::Unit::TestCase
+class TestRDocParserRuby < RDoc::TestCase
def setup
+ super
+
@tempfile = Tempfile.new self.class.name
@filename = @tempfile.path
@@ -19,19 +14,32 @@ class TestRDocParserRuby < MiniTest::Unit::TestCase
@tempfile2 = Tempfile.new self.class.name
@filename2 = @tempfile2.path
- util_top_level
+ @top_level = @store.add_file @filename
+ @top_level2 = @store.add_file @filename2
+
@options = RDoc::Options.new
@options.quiet = true
@options.option_parser = OptionParser.new
- @stats = RDoc::Stats.new 0
+ @comment = RDoc::Comment.new '', @top_level
+
+ @stats = RDoc::Stats.new @store, 0
end
def teardown
+ super
+
@tempfile.close
@tempfile2.close
end
+ def mu_pp obj
+ s = ''
+ s = PP.pp obj, s
+ s = s.force_encoding(Encoding.default_external) if defined? Encoding
+ s.chomp
+ end
+
def test_collect_first_comment
p = util_parser <<-CONTENT
# first
@@ -42,7 +50,7 @@ class C; end
comment = p.collect_first_comment
- assert_equal "# first\n", comment
+ assert_equal RDoc::Comment.new("# first\n", @top_level), comment
end
def test_collect_first_comment_encoding
@@ -59,67 +67,46 @@ class C; end
comment = p.collect_first_comment
- assert_equal Encoding::CP852, comment.encoding
+ assert_equal Encoding::CP852, comment.text.encoding
end
- def test_extract_call_seq
- m = RDoc::AnyMethod.new nil, 'm'
- p = util_parser ''
+ def test_get_class_or_module
+ ctxt = RDoc::Context.new
+ ctxt.store = @store
- comment = <<-COMMENT
- # call-seq:
- # bla => true or false
- #
- # moar comment
- COMMENT
+ cont, name_t, given_name = util_parser('A') .get_class_or_module ctxt
- p.extract_call_seq comment, m
+ assert_equal ctxt, cont
+ assert_equal 'A', name_t.text
+ assert_equal 'A', given_name
- assert_equal "bla => true or false\n", m.call_seq
- end
+ cont, name_t, given_name = util_parser('A::B') .get_class_or_module ctxt
- def test_extract_call_seq_blank
- m = RDoc::AnyMethod.new nil, 'm'
- p = util_parser ''
+ assert_equal @store.find_module_named('A'), cont
+ assert_equal 'B', name_t.text
+ assert_equal 'A::B', given_name
- comment = <<-COMMENT
- # call-seq:
- # bla => true or false
- #
- COMMENT
+ cont, name_t, given_name = util_parser('A:: B').get_class_or_module ctxt
- p.extract_call_seq comment, m
+ assert_equal @store.find_module_named('A'), cont
+ assert_equal 'B', name_t.text
+ assert_equal 'A::B', given_name
- assert_equal "bla => true or false\n", m.call_seq
- end
-
- def test_extract_call_seq_no_blank
- m = RDoc::AnyMethod.new nil, 'm'
- p = util_parser ''
-
- comment = <<-COMMENT
- # call-seq:
- # bla => true or false
- COMMENT
-
- p.extract_call_seq comment, m
-
- assert_equal "bla => true or false\n", m.call_seq
+ assert_raises NoMethodError do
+ util_parser("A::\nB").get_class_or_module ctxt
+ end
end
- def test_extract_call_seq_undent
- m = RDoc::AnyMethod.new nil, 'm'
- p = util_parser ''
+ def test_get_class_specification
+ assert_equal 'A', util_parser('A') .get_class_specification
+ assert_equal 'A::B', util_parser('A::B').get_class_specification
+ assert_equal '::A', util_parser('::A').get_class_specification
- comment = <<-COMMENT
- # call-seq:
- # bla => true or false
- # moar comment
- COMMENT
+ assert_equal 'self', util_parser('self').get_class_specification
- p.extract_call_seq comment, m
+ assert_equal '', util_parser('').get_class_specification
- assert_equal "bla => true or false\nmoar comment\n", m.call_seq
+ assert_equal '', util_parser('$g').get_class_specification
end
def test_get_symbol_or_name
@@ -149,159 +136,32 @@ class C; end
def test_look_for_directives_in_attr
util_parser ""
- comment = "# :attr: my_attr\n"
+ comment = RDoc::Comment.new "# :attr: my_attr\n", @top_level
@parser.look_for_directives_in @top_level, comment
- assert_equal "# :attr: my_attr\n", comment
+ assert_equal "# :attr: my_attr\n", comment.text
- comment = "# :attr_reader: my_method\n"
+ comment = RDoc::Comment.new "# :attr_reader: my_method\n", @top_level
@parser.look_for_directives_in @top_level, comment
- assert_equal "# :attr_reader: my_method\n", comment
+ assert_equal "# :attr_reader: my_method\n", comment.text
- comment = "# :attr_writer: my_method\n"
+ comment = RDoc::Comment.new "# :attr_writer: my_method\n", @top_level
@parser.look_for_directives_in @top_level, comment
- assert_equal "# :attr_writer: my_method\n", comment
- end
-
- def test_remove_private_comments
- util_parser ''
-
- comment = <<-EOS
-# This is text
-#--
-# this is private
- EOS
-
- expected = <<-EOS
-# This is text
- EOS
-
- @parser.remove_private_comments(comment)
-
- assert_equal expected, comment
- end
-
- def test_remove_private_comments_encoding
- skip "Encoding not implemented" unless Object.const_defined? :Encoding
-
- util_parser ''
-
- comment = <<-EOS
-# This is text
-#--
-# this is private
- EOS
- comment.force_encoding Encoding::IBM437
-
- @parser.remove_private_comments comment
-
- assert_equal Encoding::IBM437, comment.encoding
- end
-
- def test_remove_private_comments_long
- util_parser ''
-
- comment = <<-EOS
-#-----
-#++
-# this is text
-#-----
- EOS
-
- expected = <<-EOS
-# this is text
- EOS
-
- @parser.remove_private_comments(comment)
-
- assert_equal expected, comment
- end
-
- def test_remove_private_comments_rule
- util_parser ''
-
- comment = <<-EOS
-# This is text with a rule:
-# ---
-# this is also text
- EOS
-
- expected = comment.dup
-
- @parser.remove_private_comments(comment)
-
- assert_equal expected, comment
- end
-
- def test_remove_private_comments_toggle
- util_parser ''
-
- comment = <<-EOS
-# This is text
-#--
-# this is private
-#++
-# This is text again.
- EOS
-
- expected = <<-EOS
-# This is text
-# This is text again.
- EOS
-
- @parser.remove_private_comments(comment)
-
- assert_equal expected, comment
- end
-
- def test_remove_private_comments_toggle_encoding
- skip "Encoding not implemented" unless Object.const_defined? :Encoding
-
- util_parser ''
-
- comment = <<-EOS
-# This is text
-#--
-# this is private
-#++
-# This is text again.
- EOS
-
- comment.force_encoding Encoding::IBM437
-
- @parser.remove_private_comments comment
-
- assert_equal Encoding::IBM437, comment.encoding
- end
-
- def test_remove_private_comments_toggle_encoding_ruby_bug?
- skip "Encoding not implemented" unless Object.const_defined? :Encoding
-
- util_parser ''
-
- comment = <<-EOS
-#--
-# this is private
-#++
-# This is text again.
- EOS
-
- comment.force_encoding Encoding::IBM437
-
- @parser.remove_private_comments comment
-
- assert_equal Encoding::IBM437, comment.encoding
+ assert_equal "# :attr_writer: my_method\n", comment.text
end
def test_look_for_directives_in_commented
util_parser ""
- comment = "# how to make a section:\n# # :section: new section\n"
+ comment = RDoc::Comment.new <<-COMMENT, @top_level
+# how to make a section:
+# # :section: new section
+ COMMENT
@parser.look_for_directives_in @top_level, comment
@@ -310,43 +170,48 @@ class C; end
assert_equal nil, section.comment
assert_equal "# how to make a section:\n# # :section: new section\n",
- comment
+ comment.text
end
def test_look_for_directives_in_method
util_parser ""
- comment = "# :method: my_method\n"
+ comment = RDoc::Comment.new "# :method: my_method\n", @top_level
@parser.look_for_directives_in @top_level, comment
- assert_equal "# :method: my_method\n", comment
+ assert_equal "# :method: my_method\n", comment.text
- comment = "# :singleton-method: my_method\n"
+ comment = RDoc::Comment.new "# :singleton-method: my_method\n", @top_level
@parser.look_for_directives_in @top_level, comment
- assert_equal "# :singleton-method: my_method\n", comment
+ assert_equal "# :singleton-method: my_method\n", comment.text
end
def test_look_for_directives_in_section
util_parser ""
- comment = "# :section: new section\n# woo stuff\n"
+ comment = RDoc::Comment.new <<-COMMENT, @top_level
+# :section: new section
+# woo stuff
+ COMMENT
@parser.look_for_directives_in @top_level, comment
section = @top_level.current_section
assert_equal 'new section', section.title
- assert_equal "# woo stuff\n", section.comment
+ assert_equal [comment("# woo stuff\n", @top_level)], section.comments
- assert_equal '', comment
+ assert_empty comment
end
def test_look_for_directives_in_unhandled
util_parser ""
- @parser.look_for_directives_in @top_level, "# :unhandled: blah\n"
+ comment = RDoc::Comment.new "# :unhandled: blah\n", @top_level
+
+ @parser.look_for_directives_in @top_level, comment
assert_equal 'blah', @top_level.metadata['unhandled']
end
@@ -420,7 +285,7 @@ class C; end
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
- comment = "##\n# my attr\n"
+ comment = RDoc::Comment.new "##\n# my attr\n", @top_level
util_parser "attr :foo, :bar"
@@ -432,7 +297,7 @@ class C; end
foo = klass.attributes.first
assert_equal 'foo', foo.name
- assert_equal 'my attr', foo.comment
+ assert_equal 'my attr', foo.comment.text
assert_equal @top_level, foo.file
assert_equal 0, foo.offset
assert_equal 1, foo.line
@@ -443,7 +308,7 @@ class C; end
klass.parent = @top_level
klass.stop_doc
- comment = "##\n# my attr\n"
+ comment = RDoc::Comment.new "##\n# my attr\n", @top_level
util_parser "attr :foo, :bar"
@@ -458,7 +323,7 @@ class C; end
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
- comment = "##\n# my attr\n"
+ comment = RDoc::Comment.new "##\n# my attr\n", @top_level
util_parser "attr_accessor :foo, :bar"
@@ -471,7 +336,7 @@ class C; end
foo = klass.attributes.first
assert_equal 'foo', foo.name
assert_equal 'RW', foo.rw
- assert_equal 'my attr', foo.comment
+ assert_equal 'my attr', foo.comment.text
assert_equal @top_level, foo.file
assert_equal 0, foo.offset
assert_equal 1, foo.line
@@ -479,14 +344,14 @@ class C; end
bar = klass.attributes.last
assert_equal 'bar', bar.name
assert_equal 'RW', bar.rw
- assert_equal 'my attr', bar.comment
+ assert_equal 'my attr', bar.comment.text
end
def test_parse_attr_accessor_nodoc
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
- comment = "##\n# my attr\n"
+ comment = RDoc::Comment.new "##\n# my attr\n", @top_level
util_parser "attr_accessor :foo, :bar # :nodoc:"
@@ -502,7 +367,7 @@ class C; end
klass.parent = @top_level
klass.stop_doc
- comment = "##\n# my attr\n"
+ comment = RDoc::Comment.new "##\n# my attr\n", @top_level
util_parser "attr_accessor :foo, :bar"
@@ -517,7 +382,7 @@ class C; end
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
- comment = "##\n# my attr\n"
+ comment = RDoc::Comment.new "##\n# my attr\n", @top_level
util_parser "attr_writer :foo, :bar"
@@ -530,20 +395,20 @@ class C; end
foo = klass.attributes.first
assert_equal 'foo', foo.name
assert_equal 'W', foo.rw
- assert_equal "my attr", foo.comment
+ assert_equal "my attr", foo.comment.text
assert_equal @top_level, foo.file
bar = klass.attributes.last
assert_equal 'bar', bar.name
assert_equal 'W', bar.rw
- assert_equal "my attr", bar.comment
+ assert_equal "my attr", bar.comment.text
end
def test_parse_meta_attr
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
- comment = "##\n# :attr: \n# my method\n"
+ comment = RDoc::Comment.new "##\n# :attr: \n# my method\n", @top_level
util_parser "add_my_method :foo, :bar"
@@ -555,7 +420,7 @@ class C; end
foo = klass.attributes.first
assert_equal 'foo', foo.name
assert_equal 'RW', foo.rw
- assert_equal "my method", foo.comment
+ assert_equal "my method", foo.comment.text
assert_equal @top_level, foo.file
end
@@ -563,7 +428,8 @@ class C; end
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
- comment = "##\n# :attr_accessor: \n# my method\n"
+ comment =
+ RDoc::Comment.new "##\n# :attr_accessor: \n# my method\n", @top_level
util_parser "add_my_method :foo, :bar"
@@ -575,7 +441,7 @@ class C; end
foo = klass.attributes.first
assert_equal 'foo', foo.name
assert_equal 'RW', foo.rw
- assert_equal 'my method', foo.comment
+ assert_equal 'my method', foo.comment.text
assert_equal @top_level, foo.file
end
@@ -583,7 +449,7 @@ class C; end
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
- comment = "##\n# :attr: foo\n# my method\n"
+ comment = RDoc::Comment.new "##\n# :attr: foo\n# my method\n", @top_level
util_parser "add_my_method :foo, :bar"
@@ -595,7 +461,7 @@ class C; end
foo = klass.attributes.first
assert_equal 'foo', foo.name
assert_equal 'RW', foo.rw
- assert_equal 'my method', foo.comment
+ assert_equal 'my method', foo.comment.text
assert_equal @top_level, foo.file
end
@@ -603,7 +469,8 @@ class C; end
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
- comment = "##\n# :attr_reader: \n# my method\n"
+ comment =
+ RDoc::Comment.new "##\n# :attr_reader: \n# my method\n", @top_level
util_parser "add_my_method :foo, :bar"
@@ -614,7 +481,7 @@ class C; end
foo = klass.attributes.first
assert_equal 'foo', foo.name
assert_equal 'R', foo.rw
- assert_equal 'my method', foo.comment
+ assert_equal 'my method', foo.comment.text
assert_equal @top_level, foo.file
end
@@ -623,7 +490,7 @@ class C; end
klass.parent = @top_level
klass.stop_doc
- comment = "##\n# :attr: \n# my method\n"
+ comment = RDoc::Comment.new "##\n# :attr: \n# my method\n", @top_level
util_parser "add_my_method :foo, :bar"
@@ -638,7 +505,8 @@ class C; end
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
- comment = "##\n# :attr_writer: \n# my method\n"
+ comment =
+ RDoc::Comment.new "##\n# :attr_writer: \n# my method\n", @top_level
util_parser "add_my_method :foo, :bar"
@@ -649,12 +517,12 @@ class C; end
foo = klass.attributes.first
assert_equal 'foo', foo.name
assert_equal 'W', foo.rw
- assert_equal "my method", foo.comment
+ assert_equal "my method", foo.comment.text
assert_equal @top_level, foo.file
end
def test_parse_class
- comment = "##\n# my class\n"
+ comment = RDoc::Comment.new "##\n# my class\n", @top_level
util_parser "class Foo\nend"
@@ -664,7 +532,7 @@ class C; end
foo = @top_level.classes.first
assert_equal 'Foo', foo.full_name
- assert_equal 'my class', foo.comment
+ assert_equal 'my class', foo.comment.text
assert_equal [@top_level], foo.in_files
assert_equal 0, foo.offset
assert_equal 1, foo.line
@@ -681,7 +549,7 @@ end
tk = @parser.get_tk
- @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, ''
+ @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment
foo = @top_level.classes.first
assert_equal 'Foo', foo.full_name
@@ -712,7 +580,7 @@ end
tk = @parser.get_tk
- @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, ''
+ @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment
foo = @top_level.classes.first
assert_equal 'Foo', foo.full_name
@@ -721,7 +589,7 @@ end
end
def test_parse_class_nodoc
- comment = "##\n# my class\n"
+ comment = RDoc::Comment.new "##\n# my class\n", @top_level
util_parser "class Foo # :nodoc:\nend"
@@ -737,10 +605,23 @@ end
assert_equal 1, foo.line
end
+ def test_parse_class_single_root
+ comment = RDoc::Comment.new "##\n# my class\n", @top_level
+
+ util_parser "class << ::Foo\nend"
+
+ tk = @parser.get_tk
+
+ @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, comment
+
+ foo = @store.all_modules.first
+ assert_equal 'Foo', foo.full_name
+ end
+
def test_parse_class_stopdoc
@top_level.stop_doc
- comment = "##\n# my class\n"
+ comment = RDoc::Comment.new "##\n# my class\n", @top_level
util_parser "class Foo\nend"
@@ -772,7 +653,7 @@ end
tk = @parser.get_tk
- @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, ''
+ @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment
foo = @top_level.classes.first
assert_equal 'Foo', foo.full_name
@@ -794,7 +675,7 @@ end
tk = @parser.get_tk
- @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, ''
+ @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment
const_fail_meta = @top_level.classes.first
assert_equal 'ConstFailMeta', const_fail_meta.full_name
@@ -803,21 +684,20 @@ end
end
def test_parse_class_nested_superclass
- util_top_level
foo = @top_level.add_module RDoc::NormalModule, 'Foo'
util_parser "class Bar < Super\nend"
tk = @parser.get_tk
- @parser.parse_class foo, RDoc::Parser::Ruby::NORMAL, tk, ''
+ @parser.parse_class foo, RDoc::Parser::Ruby::NORMAL, tk, @comment
bar = foo.classes.first
assert_equal 'Super', bar.superclass
end
def test_parse_module
- comment = "##\n# my module\n"
+ comment = RDoc::Comment.new "##\n# my module\n", @top_level
util_parser "module Foo\nend"
@@ -827,13 +707,13 @@ end
foo = @top_level.modules.first
assert_equal 'Foo', foo.full_name
- assert_equal 'my module', foo.comment
+ assert_equal 'my module', foo.comment.text
end
def test_parse_module_nodoc
@top_level.stop_doc
- comment = "##\n# my module\n"
+ comment = RDoc::Comment.new "##\n# my module\n", @top_level
util_parser "module Foo # :nodoc:\nend"
@@ -849,7 +729,7 @@ end
def test_parse_module_stopdoc
@top_level.stop_doc
- comment = "##\n# my module\n"
+ comment = RDoc::Comment.new "##\n# my module\n", @top_level
util_parser "module Foo\nend"
@@ -859,7 +739,7 @@ end
foo = @top_level.modules.first
assert_equal 'Foo', foo.full_name
- assert_equal 'my module', foo.comment
+ assert_empty foo.comment
end
def test_parse_class_colon3
@@ -872,9 +752,24 @@ end
util_parser code
- @parser.parse_class @top_level, false, @parser.get_tk, ''
+ @parser.parse_class @top_level, false, @parser.get_tk, @comment
+
+ assert_equal %w[A B], @store.all_classes.map { |c| c.full_name }.sort
+ end
+
+ def test_parse_class_colon3_self_reference
+ code = <<-CODE
+class A::B
+ class ::A
+ end
+end
+ CODE
+
+ util_parser code
+
+ @parser.parse_class @top_level, false, @parser.get_tk, @comment
- assert_equal %w[A B], RDoc::TopLevel.classes.map { |c| c.full_name }
+ assert_equal %w[A A::B], @store.all_classes.map { |c| c.full_name }.sort
end
def test_parse_class_single
@@ -891,23 +786,44 @@ end
util_parser code
- @parser.parse_class @top_level, false, @parser.get_tk, ''
+ @parser.parse_class @top_level, false, @parser.get_tk, @comment
+
+ assert_equal %w[A], @store.all_classes.map { |c| c.full_name }
- assert_equal %w[A], RDoc::TopLevel.classes.map { |c| c.full_name }
- assert_equal %w[A::B A::d], RDoc::TopLevel.modules.map { |c| c.full_name }
+ modules = @store.all_modules.sort_by { |c| c.full_name }
+ assert_equal %w[A::B A::d], modules.map { |c| c.full_name }
- b = RDoc::TopLevel.modules.first
+ b = modules.first
assert_equal 10, b.offset
assert_equal 2, b.line
# make sure method/alias was not added to enclosing class/module
- a = RDoc::TopLevel.all_classes_hash['A']
+ a = @store.classes_hash['A']
assert_empty a.method_list
# make sure non-constant-named module will be removed from documentation
- d = RDoc::TopLevel.all_modules_hash['A::d']
+ d = @store.modules_hash['A::d']
assert d.remove_from_documentation?
+ end
+ def test_parse_class_single_gvar
+ code = <<-CODE
+class << $g
+ def m
+ end
+end
+ CODE
+
+ util_parser code
+
+ @parser.parse_class @top_level, false, @parser.get_tk, ''
+
+ assert_empty @store.all_classes
+ mod = @store.all_modules.first
+
+ refute mod.document_self
+
+ assert_empty mod.method_list
end
# TODO this is really a Context#add_class test
@@ -925,13 +841,16 @@ end
util_parser code
- @parser.parse_module @top_level, false, @parser.get_tk, ''
+ @parser.parse_module @top_level, false, @parser.get_tk, @comment
+
+ assert_equal %w[A],
+ @store.all_modules.map { |c| c.full_name }
+ assert_equal %w[A::B A::C A::Object],
+ @store.all_classes.map { |c| c.full_name }.sort
- assert_equal %w[A], RDoc::TopLevel.modules.map { |c| c.full_name }
- assert_equal %w[A::B A::C A::Object], RDoc::TopLevel.classes.map { |c| c.full_name }.sort
- assert_equal 'Object', RDoc::TopLevel.classes_hash['A::B'].superclass
- assert_equal 'Object', RDoc::TopLevel.classes_hash['A::Object'].superclass
- assert_equal 'A::Object', RDoc::TopLevel.classes_hash['A::C'].superclass.full_name
+ assert_equal 'Object', @store.classes_hash['A::B'].superclass
+ assert_equal 'Object', @store.classes_hash['A::Object'].superclass
+ assert_equal 'A::Object', @store.classes_hash['A::C'].superclass.full_name
end
def test_parse_class_mistaken_for_module
@@ -954,7 +873,7 @@ end
@parser.scan
- assert_equal %w[Foo::Baz], RDoc::TopLevel.modules_hash.keys
+ assert_equal %w[Foo::Baz], @store.modules_hash.keys
assert_empty @top_level.modules
foo = @top_level.classes.first
@@ -968,9 +887,9 @@ end
end
def test_parse_class_definition_encountered_after_class_reference
- # The code below is not strictly legal Ruby (Foo must have been defined
- # before Foo.bar is encountered), but RDoc might encounter Foo.bar before
- # Foo if they live in different files.
+ # The code below is not legal Ruby (Foo must have been defined before
+ # Foo.bar is encountered), but RDoc might encounter Foo.bar before Foo if
+ # they live in different files.
code = <<-EOF
def Foo.bar
@@ -984,9 +903,8 @@ end
@parser.scan
- assert_empty RDoc::TopLevel.modules_hash
- # HACK why does it fail?
- #assert_empty @top_level.modules
+ assert_empty @store.modules_hash
+ assert_empty @store.all_modules
foo = @top_level.classes.first
assert_equal 'Foo', foo.full_name
@@ -997,13 +915,14 @@ end
end
def test_parse_module_relative_to_top_level_namespace
- comment = <<-EOF
+ comment = RDoc::Comment.new <<-EOF, @top_level
#
# Weirdly named module
#
EOF
- code = comment + <<-EOF
+ code = <<-EOF
+#{comment.text}
module ::Foo
class Helper
end
@@ -1015,7 +934,7 @@ EOF
foo = @top_level.modules.first
assert_equal 'Foo', foo.full_name
- assert_equal 'Weirdly named module', foo.comment
+ assert_equal 'Weirdly named module', foo.comment.text
helper = foo.classes.first
assert_equal 'Foo::Helper', helper.full_name
@@ -1025,7 +944,7 @@ EOF
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
- comment = "##\n# :attr: foo\n# my attr\n"
+ comment = RDoc::Comment.new "##\n# :attr: foo\n# my attr\n", @top_level
util_parser "\n"
@@ -1036,7 +955,7 @@ EOF
foo = klass.attributes.first
assert_equal 'foo', foo.name
assert_equal 'RW', foo.rw
- assert_equal 'my attr', foo.comment
+ assert_equal 'my attr', foo.comment.text
assert_equal @top_level, foo.file
assert_equal 0, foo.offset
assert_equal 1, foo.line
@@ -1058,7 +977,7 @@ EOF
klass.parent = @top_level
klass.stop_doc
- comment = "##\n# :attr: foo\n# my attr\n"
+ comment = RDoc::Comment.new "##\n# :attr: foo\n# my attr\n", @top_level
util_parser "\n"
@@ -1073,7 +992,7 @@ EOF
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
- comment = "##\n# :method: foo\n# my method\n"
+ comment = RDoc::Comment.new "##\n# :method: foo\n# my method\n", @top_level
util_parser "\n"
@@ -1083,7 +1002,7 @@ EOF
foo = klass.method_list.first
assert_equal 'foo', foo.name
- assert_equal 'my method', foo.comment
+ assert_equal 'my method', foo.comment.text
assert_equal @top_level, foo.file
assert_equal 0, foo.offset
assert_equal 1, foo.line
@@ -1106,9 +1025,10 @@ EOF
assert_equal klass.current_section, foo.section
stream = [
- tk(:COMMENT, 1, 1, nil, "# File #{@top_level.absolute_name}, line 1"),
+ tk(:COMMENT, 0, 1, 1, nil,
+ "# File #{@top_level.absolute_name}, line 1"),
RDoc::Parser::Ruby::NEWLINE_TOKEN,
- tk(:SPACE, 1, 1, nil, ''),
+ tk(:SPACE, 0, 1, 1, nil, ''),
]
assert_equal stream, foo.token_stream
@@ -1119,7 +1039,7 @@ EOF
klass.parent = @top_level
klass.stop_doc
- comment = "##\n# :method: foo\n# my method\n"
+ comment = RDoc::Comment.new "##\n# :method: foo\n# my method\n", @top_level
util_parser "\n"
@@ -1131,15 +1051,13 @@ EOF
end
def test_parse_constant
- util_top_level
-
klass = @top_level.add_class RDoc::NormalClass, 'Foo'
util_parser "A = v"
tk = @parser.get_tk
- @parser.parse_constant klass, tk, ''
+ @parser.parse_constant klass, tk, @comment
foo = klass.constants.first
@@ -1150,52 +1068,47 @@ EOF
end
def test_parse_constant_attrasgn
- util_top_level
-
klass = @top_level.add_class RDoc::NormalClass, 'Foo'
util_parser "A[k] = v"
tk = @parser.get_tk
- @parser.parse_constant klass, tk, ''
+ @parser.parse_constant klass, tk, @comment
assert klass.constants.empty?
end
def test_parse_constant_alias
- util_top_level
klass = @top_level.add_class RDoc::NormalClass, 'Foo'
- cB = klass.add_class RDoc::NormalClass, 'B'
+ klass.add_class RDoc::NormalClass, 'B'
util_parser "A = B"
tk = @parser.get_tk
- @parser.parse_constant klass, tk, ''
+ @parser.parse_constant klass, tk, @comment
- assert_equal cB, klass.find_module_named('A')
+ assert_equal 'Foo::A', klass.find_module_named('A').full_name
end
def test_parse_constant_alias_same_name
foo = @top_level.add_class RDoc::NormalClass, 'Foo'
- top_bar = @top_level.add_class RDoc::NormalClass, 'Bar'
+ @top_level.add_class RDoc::NormalClass, 'Bar'
bar = foo.add_class RDoc::NormalClass, 'Bar'
- assert RDoc::TopLevel.find_class_or_module('::Bar')
+ assert @store.find_class_or_module('::Bar')
util_parser "A = ::Bar"
tk = @parser.get_tk
- @parser.parse_constant foo, tk, ''
+ @parser.parse_constant foo, tk, @comment
- assert_equal top_bar, bar.find_module_named('A')
+ assert_equal 'A', bar.find_module_named('A').full_name
end
def test_parse_constant_stopdoc
- util_top_level
-
klass = @top_level.add_class RDoc::NormalClass, 'Foo'
klass.stop_doc
@@ -1203,7 +1116,7 @@ EOF
tk = @parser.get_tk
- @parser.parse_constant klass, tk, ''
+ @parser.parse_constant klass, tk, @comment
assert_empty klass.constants
end
@@ -1212,7 +1125,7 @@ EOF
klass = RDoc::NormalClass.new 'C'
klass.parent = @top_level
- comment = "# my include\n"
+ comment = RDoc::Comment.new "# my include\n", @top_level
util_parser "include I"
@@ -1224,15 +1137,35 @@ EOF
incl = klass.includes.first
assert_equal 'I', incl.name
- assert_equal 'my include', incl.comment
+ assert_equal 'my include', incl.comment.text
assert_equal @top_level, incl.file
end
+ def test_parse_extend
+ klass = RDoc::NormalClass.new 'C'
+ klass.parent = @top_level
+
+ comment = RDoc::Comment.new "# my extend\n", @top_level
+
+ util_parser "extend I"
+
+ @parser.get_tk # extend
+
+ @parser.parse_extend klass, comment
+
+ assert_equal 1, klass.extends.length
+
+ ext = klass.extends.first
+ assert_equal 'I', ext.name
+ assert_equal 'my extend', ext.comment.text
+ assert_equal @top_level, ext.file
+ end
+
def test_parse_meta_method
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
- comment = "##\n# my method\n"
+ comment = RDoc::Comment.new "##\n# my method\n", @top_level
util_parser "add_my_method :foo, :bar\nadd_my_method :baz"
@@ -1242,7 +1175,7 @@ EOF
foo = klass.method_list.first
assert_equal 'foo', foo.name
- assert_equal 'my method', foo.comment
+ assert_equal 'my method', foo.comment.text
assert_equal @top_level, foo.file
assert_equal 0, foo.offset
assert_equal 1, foo.line
@@ -1265,16 +1198,17 @@ EOF
assert_equal klass.current_section, foo.section
stream = [
- tk(:COMMENT, 1, 1, nil, "# File #{@top_level.absolute_name}, line 1"),
+ tk(:COMMENT, 0, 1, 1, nil,
+ "# File #{@top_level.absolute_name}, line 1"),
RDoc::Parser::Ruby::NEWLINE_TOKEN,
- tk(:SPACE, 1, 1, nil, ''),
- tk(:IDENTIFIER, 1, 0, 'add_my_method', 'add_my_method'),
- tk(:SPACE, 1, 13, nil, ' '),
- tk(:SYMBOL, 1, 14, nil, ':foo'),
- tk(:COMMA, 1, 18, nil, ','),
- tk(:SPACE, 1, 19, nil, ' '),
- tk(:SYMBOL, 1, 20, nil, ':bar'),
- tk(:NL, 1, 24, nil, "\n"),
+ tk(:SPACE, 0, 1, 1, nil, ''),
+ tk(:IDENTIFIER, 0, 1, 0, 'add_my_method', 'add_my_method'),
+ tk(:SPACE, 0, 1, 13, nil, ' '),
+ tk(:SYMBOL, 0, 1, 14, nil, ':foo'),
+ tk(:COMMA, 0, 1, 18, nil, ','),
+ tk(:SPACE, 0, 1, 19, nil, ' '),
+ tk(:SYMBOL, 0, 1, 20, nil, ':bar'),
+ tk(:NL, 0, 1, 24, nil, "\n"),
]
assert_equal stream, foo.token_stream
@@ -1284,7 +1218,7 @@ EOF
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
- comment = "##\n# my method\n"
+ comment = RDoc::Comment.new "##\n# my method\n", @top_level
content = <<-CONTENT
inline(:my_method) do |*args|
@@ -1298,14 +1232,31 @@ end
@parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
- assert_nil @parser.get_tk
+ assert_equal tk(:NL, 0, 3, 3, 3, "\n"), @parser.get_tk
+ end
+
+ def test_parse_meta_method_define_method
+ klass = RDoc::NormalClass.new 'Foo'
+ comment = RDoc::Comment.new "##\n# my method\n", @top_level
+
+ util_parser "define_method :foo do end"
+
+ tk = @parser.get_tk
+
+ @parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
+
+ foo = klass.method_list.first
+ assert_equal 'foo', foo.name
+ assert_equal 'my method', foo.comment.text
+ assert_equal @top_level, foo.file
end
def test_parse_meta_method_name
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
- comment = "##\n# :method: woo_hoo!\n# my method\n"
+ comment =
+ RDoc::Comment.new "##\n# :method: woo_hoo!\n# my method\n", @top_level
util_parser "add_my_method :foo, :bar\nadd_my_method :baz"
@@ -1315,7 +1266,7 @@ end
foo = klass.method_list.first
assert_equal 'woo_hoo!', foo.name
- assert_equal 'my method', foo.comment
+ assert_equal 'my method', foo.comment.text
assert_equal @top_level, foo.file
end
@@ -1323,7 +1274,8 @@ end
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
- comment = "##\n# :singleton-method:\n# my method\n"
+ comment =
+ RDoc::Comment.new "##\n# :singleton-method:\n# my method\n", @top_level
util_parser "add_my_method :foo, :bar\nadd_my_method :baz"
@@ -1334,7 +1286,7 @@ end
foo = klass.method_list.first
assert_equal 'foo', foo.name
assert_equal true, foo.singleton, 'singleton method'
- assert_equal 'my method', foo.comment
+ assert_equal 'my method', foo.comment.text
assert_equal @top_level, foo.file
end
@@ -1342,7 +1294,9 @@ end
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
- comment = "##\n# :singleton-method: woo_hoo!\n# my method\n"
+ comment =
+ RDoc::Comment.new "##\n# :singleton-method: woo_hoo!\n# my method\n",
+ @top_level
util_parser "add_my_method :foo, :bar\nadd_my_method :baz"
@@ -1353,13 +1307,13 @@ end
foo = klass.method_list.first
assert_equal 'woo_hoo!', foo.name
assert_equal true, foo.singleton, 'singleton method'
- assert_equal 'my method', foo.comment
+ assert_equal 'my method', foo.comment.text
assert_equal @top_level, foo.file
end
def test_parse_meta_method_string_name
klass = RDoc::NormalClass.new 'Foo'
- comment = "##\n# my method\n"
+ comment = RDoc::Comment.new "##\n# my method\n", @top_level
util_parser "add_my_method 'foo'"
@@ -1369,7 +1323,7 @@ end
foo = klass.method_list.first
assert_equal 'foo', foo.name
- assert_equal 'my method', foo.comment
+ assert_equal 'my method', foo.comment.text
assert_equal @top_level, foo.file
end
@@ -1378,7 +1332,7 @@ end
klass.parent = @top_level
klass.stop_doc
- comment = "##\n# my method\n"
+ comment = RDoc::Comment.new "##\n# my method\n", @top_level
util_parser "add_my_method :foo, :bar\nadd_my_method :baz"
@@ -1391,7 +1345,7 @@ end
def test_parse_meta_method_unknown
klass = RDoc::NormalClass.new 'Foo'
- comment = "##\n# my method\n"
+ comment = RDoc::Comment.new "##\n# my method\n", @top_level
util_parser "add_my_method ('foo')"
@@ -1401,7 +1355,7 @@ end
foo = klass.method_list.first
assert_equal 'unknown', foo.name
- assert_equal 'my method', foo.comment
+ assert_equal 'my method', foo.comment.text
assert_equal @top_level, foo.file
end
@@ -1409,7 +1363,7 @@ end
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
- comment = "##\n# my method\n"
+ comment = RDoc::Comment.new "##\n# my method\n", @top_level
util_parser "def foo() :bar end"
@@ -1419,7 +1373,7 @@ end
foo = klass.method_list.first
assert_equal 'foo', foo.name
- assert_equal 'my method', foo.comment
+ assert_equal 'my method', foo.comment.text
assert_equal @top_level, foo.file
assert_equal 0, foo.offset
assert_equal 1, foo.line
@@ -1442,19 +1396,20 @@ end
assert_equal klass.current_section, foo.section
stream = [
- tk(:COMMENT, 1, 1, nil, "# File #{@top_level.absolute_name}, line 1"),
+ tk(:COMMENT, 0, 1, 1, nil,
+ "# File #{@top_level.absolute_name}, line 1"),
RDoc::Parser::Ruby::NEWLINE_TOKEN,
- tk(:SPACE, 1, 1, nil, ''),
- tk(:DEF, 1, 0, 'def', 'def'),
- tk(:SPACE, 1, 3, nil, ' '),
- tk(:IDENTIFIER, 1, 4, 'foo', 'foo'),
- tk(:LPAREN, 1, 7, nil, '('),
- tk(:RPAREN, 1, 8, nil, ')'),
- tk(:SPACE, 1, 9, nil, ' '),
- tk(:COLON, 1, 10, nil, ':'),
- tk(:IDENTIFIER, 1, 11, 'bar', 'bar'),
- tk(:SPACE, 1, 14, nil, ' '),
- tk(:END, 1, 15, 'end', 'end'),
+ tk(:SPACE, 0, 1, 1, nil, ''),
+ tk(:DEF, 0, 1, 0, 'def', 'def'),
+ tk(:SPACE, 3, 1, 3, nil, ' '),
+ tk(:IDENTIFIER, 4, 1, 4, 'foo', 'foo'),
+ tk(:LPAREN, 7, 1, 7, nil, '('),
+ tk(:RPAREN, 8, 1, 8, nil, ')'),
+ tk(:SPACE, 9, 1, 9, nil, ' '),
+ tk(:COLON, 10, 1, 10, nil, ':'),
+ tk(:IDENTIFIER, 11, 1, 11, 'bar', 'bar'),
+ tk(:SPACE, 14, 1, 14, nil, ' '),
+ tk(:END, 15, 1, 15, 'end', 'end'),
]
assert_equal stream, foo.token_stream
@@ -1468,19 +1423,34 @@ end
tk = @parser.get_tk
- @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, ''
+ @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
assert klass.aliases.empty?
end
+ def test_parse_method_ampersand
+ klass = RDoc::NormalClass.new 'Foo'
+ klass.parent = @top_level
+
+ util_parser "def self.&\nend"
+
+ tk = @parser.get_tk
+
+ @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
+
+ ampersand = klass.method_list.first
+ assert_equal '&', ampersand.name
+ assert ampersand.singleton
+ end
+
def test_parse_method_false
util_parser "def false.foo() :bar end"
tk = @parser.get_tk
- @parser.parse_method @top_level, RDoc::Parser::Ruby::NORMAL, tk, ''
+ @parser.parse_method @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment
- klass = RDoc::TopLevel.find_class_named 'FalseClass'
+ klass = @store.find_class_named 'FalseClass'
foo = klass.method_list.first
assert_equal 'foo', foo.name
@@ -1494,9 +1464,9 @@ end
tk = @parser.get_tk
- @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, ''
+ @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
- assert klass.method_list.empty?
+ assert_empty klass.method_list
end
def test_parse_method_gvar
@@ -1504,11 +1474,27 @@ end
tk = @parser.get_tk
- @parser.parse_method @top_level, RDoc::Parser::Ruby::NORMAL, tk, ''
+ @parser.parse_method @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment
assert @top_level.method_list.empty?
end
+ def test_parse_method_gvar_insane
+ util_parser "def $stdout.foo() class << $other; end; end"
+
+ tk = @parser.get_tk
+
+ @parser.parse_method @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment
+
+ assert @top_level.method_list.empty?
+
+ assert_empty @store.all_classes
+
+ assert_equal 1, @store.all_modules.length
+
+ refute @store.all_modules.first.document_self
+ end
+
def test_parse_method_internal_gvar
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
@@ -1517,7 +1503,7 @@ end
tk = @parser.get_tk
- @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, ''
+ @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
assert_equal 1, klass.method_list.length
end
@@ -1530,7 +1516,7 @@ end
tk = @parser.get_tk
- @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, ''
+ @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
assert_equal 1, klass.method_list.length
end
@@ -1543,7 +1529,7 @@ end
tk = @parser.get_tk
- @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, ''
+ @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
assert_equal 1, klass.method_list.length
end
@@ -1553,9 +1539,9 @@ end
tk = @parser.get_tk
- @parser.parse_method @top_level, RDoc::Parser::Ruby::NORMAL, tk, ''
+ @parser.parse_method @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment
- klass = RDoc::TopLevel.find_class_named 'NilClass'
+ klass = @store.find_class_named 'NilClass'
foo = klass.method_list.first
assert_equal 'foo', foo.name
@@ -1569,7 +1555,7 @@ end
tk = @parser.get_tk
- @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, ''
+ @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
foo = klass.method_list.first
assert_equal '(arg1, arg2 = {})', foo.params
@@ -1584,7 +1570,7 @@ end
tk = @parser.get_tk
- @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, ''
+ @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
foo = klass.method_list.first
assert_equal '(arg1, arg2)', foo.params
@@ -1598,18 +1584,33 @@ end
tk = @parser.get_tk
- @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, ''
+ @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
foo = klass.method_list.first
assert_equal '(arg1, arg2, arg3)', foo.params
end
+ def test_parse_method_star
+ klass = RDoc::NormalClass.new 'Foo'
+ klass.parent = @top_level
+
+ util_parser "def self.*\nend"
+
+ tk = @parser.get_tk
+
+ @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
+
+ ampersand = klass.method_list.first
+ assert_equal '*', ampersand.name
+ assert ampersand.singleton
+ end
+
def test_parse_method_stopdoc
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
klass.stop_doc
- comment = "##\n# my method\n"
+ comment = RDoc::Comment.new "##\n# my method\n", @top_level
util_parser "def foo() :bar end"
@@ -1627,9 +1628,9 @@ end
tk = @parser.get_tk
- @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, ''
+ @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
- object = RDoc::TopLevel.find_class_named 'Object'
+ object = @store.find_class_named 'Object'
foo = object.method_list.first
assert_equal 'Object#foo', foo.full_name
@@ -1643,9 +1644,9 @@ end
tk = @parser.get_tk
- @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, ''
+ @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
- object = RDoc::TopLevel.find_class_named 'Object'
+ object = @store.find_class_named 'Object'
foo = object.method_list.first
assert_equal 'Object::foo', foo.full_name
@@ -1656,9 +1657,9 @@ end
tk = @parser.get_tk
- @parser.parse_method @top_level, RDoc::Parser::Ruby::NORMAL, tk, ''
+ @parser.parse_method @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment
- klass = RDoc::TopLevel.find_class_named 'TrueClass'
+ klass = @store.find_class_named 'TrueClass'
foo = klass.method_list.first
assert_equal 'foo', foo.name
@@ -1677,7 +1678,7 @@ end
tk = @parser.get_tk
- @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, ''
+ @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
omega = klass.method_list.first
assert_equal "def \317\211", omega.text
@@ -1695,7 +1696,7 @@ module Foo
end
CODE
- @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, ''
+ @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil
foo = @top_level.modules.first
assert_equal 'Foo', foo.full_name, 'module Foo'
@@ -1706,18 +1707,44 @@ end
end
def test_parse_statements_class_nested
- comment = "##\n# my method\n"
+ comment = RDoc::Comment.new "##\n# my method\n", @top_level
- util_parser "module Foo\n#{comment}class Bar\nend\nend"
+ util_parser "module Foo\n#{comment.text}class Bar\nend\nend"
- @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, ''
+ @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL
foo = @top_level.modules.first
assert_equal 'Foo', foo.full_name, 'module Foo'
bar = foo.classes.first
assert_equal 'Foo::Bar', bar.full_name, 'class Foo::Bar'
- assert_equal 'my method', bar.comment
+ assert_equal 'my method', bar.comment.text
+ end
+
+ def test_parse_statements_def_percent_string_pound
+ util_parser "class C\ndef a\n%r{#}\nend\ndef b() end\nend"
+
+ @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL
+
+ x = @top_level.classes.first
+
+ assert_equal 2, x.method_list.length
+ a = x.method_list.first
+
+ expected = [
+ tk(:COMMENT, 0, 2, 1, nil, "# File #{@filename}, line 2"),
+ tk(:NL, 0, 0, 0, nil, "\n"),
+ tk(:SPACE, 0, 1, 1, nil, ''),
+ tk(:DEF, 8, 2, 0, 'def', 'def'),
+ tk(:SPACE, 11, 2, 3, nil, ' '),
+ tk(:IDENTIFIER, 12, 2, 4, 'a', 'a'),
+ tk(:NL, 13, 2, 5, nil, "\n"),
+ tk(:DREGEXP, 14, 3, 0, nil, '%r{#}'),
+ tk(:NL, 19, 3, 5, nil, "\n"),
+ tk(:END, 20, 4, 0, 'end', 'end'),
+ ]
+
+ assert_equal expected, a.token_stream
end
def test_parse_statements_encoding
@@ -1738,8 +1765,8 @@ end
foo = @top_level.classes.first.method_list.first
assert_equal 'foo', foo.name
- assert_equal 'this is my method', foo.comment
- assert_equal Encoding::CP852, foo.comment.encoding
+ assert_equal 'this is my method', foo.comment.text
+ assert_equal Encoding::CP852, foo.comment.text.encoding
end
def test_parse_statements_identifier_meta_method
@@ -1822,8 +1849,25 @@ EOF
assert_equal 'unknown', @top_level.classes.first.external_aliases[0].old_name
end
- def test_parse_statements_identifier_constant
+ def test_parse_statements_identifier_args
+ comment = "##\n# :args: x\n# :method: b\n# my method\n"
+
+ util_parser "module M\n#{comment}def_delegator :a, :b, :b\nend"
+ @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL
+
+ m = @top_level.modules.first
+ assert_equal 'M', m.full_name
+
+ b = m.method_list.first
+ assert_equal 'M#b', b.full_name
+ assert_equal 'x', b.params
+ assert_equal 'my method', b.comment.text
+
+ assert_nil m.params, 'Module parameter not removed'
+ end
+
+ def test_parse_statements_identifier_constant
sixth_constant = <<-EOF
Class.new do
rule :file do
@@ -1934,6 +1978,24 @@ EOF
assert_equal 'RW', foo.rw
end
+ def test_parse_statements_identifier_define_method
+ util_parser <<-RUBY
+class C
+ ##
+ # :method: a
+ define_method :a do end
+ ##
+ # :method: b
+ define_method :b do end
+end
+ RUBY
+
+ @parser.parse_statements @top_level
+ c = @top_level.classes.first
+
+ assert_equal %w[a b], c.method_list.map { |m| m.name }
+ end
+
def test_parse_statements_identifier_include
content = "class Foo\ninclude Bar\nend"
@@ -1991,10 +2053,10 @@ end
@parser.parse_statements @top_level
- date, date_time = @top_level.classes
+ date, date_time = @top_level.classes.sort_by { |c| c.full_name }
date_now = date.method_list.first
- date_time_now = date_time.method_list.first
+ date_time_now = date_time.method_list.sort_by { |m| m.full_name }.first
assert_equal :private, date_now.visibility
assert_equal :public, date_time_now.visibility
@@ -2016,10 +2078,11 @@ end
@parser.parse_statements @top_level
- date, date_time = @top_level.classes
+ # TODO sort classes by default
+ date, date_time = @top_level.classes.sort_by { |c| c.full_name }
date_now = date.method_list.first
- date_time_now = date_time.method_list.first
+ date_time_now = date_time.method_list.sort_by { |m| m.full_name }.first
assert_equal :public, date_now.visibility, date_now.full_name
assert_equal :private, date_time_now.visibility, date_time_now.full_name
@@ -2035,9 +2098,25 @@ end
assert_equal 1, @top_level.requires.length
end
- def test_parse_statements_stopdoc_TkALIAS
- util_top_level
+ def test_parse_statements_identifier_yields
+ comment = "##\n# :yields: x\n# :method: b\n# my method\n"
+
+ util_parser "module M\n#{comment}def_delegator :a, :b, :b\nend"
+
+ @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL
+
+ m = @top_level.modules.first
+ assert_equal 'M', m.full_name
+
+ b = m.method_list.first
+ assert_equal 'M#b', b.full_name
+ assert_equal 'x', b.block_params
+ assert_equal 'my method', b.comment.text
+
+ assert_nil m.params, 'Module parameter not removed'
+ end
+ def test_parse_statements_stopdoc_TkALIAS
klass = @top_level.add_class RDoc::NormalClass, 'Foo'
util_parser "\n# :stopdoc:\nalias old new"
@@ -2049,8 +2128,6 @@ end
end
def test_parse_statements_stopdoc_TkIDENTIFIER_alias_method
- util_top_level
-
klass = @top_level.add_class RDoc::NormalClass, 'Foo'
util_parser "\n# :stopdoc:\nalias_method :old :new"
@@ -2062,8 +2139,6 @@ end
end
def test_parse_statements_stopdoc_TkIDENTIFIER_metaprogrammed
- util_top_level
-
klass = @top_level.add_class RDoc::NormalClass, 'Foo'
util_parser "\n# :stopdoc:\n# attr :meta"
@@ -2075,8 +2150,6 @@ end
end
def test_parse_statements_stopdoc_TkCONSTANT
- util_top_level
-
klass = @top_level.add_class RDoc::NormalClass, 'Foo'
util_parser "\n# :stopdoc:\nA = v"
@@ -2087,8 +2160,6 @@ end
end
def test_parse_statements_stopdoc_TkDEF
- util_top_level
-
klass = @top_level.add_class RDoc::NormalClass, 'Foo'
util_parser "\n# :stopdoc:\ndef m\n end"
@@ -2098,6 +2169,25 @@ end
assert_empty klass.method_list
end
+ def test_parse_statements_super
+ m = RDoc::AnyMethod.new '', 'm'
+ util_parser 'super'
+
+ @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, m
+
+ assert m.calls_super
+ end
+
+ def test_parse_statements_super_no_method
+ content = "super"
+
+ util_parser content
+
+ @parser.parse_statements @top_level
+
+ assert_nil @parser.get_tk
+ end
+
def test_parse_statements_while_begin
util_parser <<-RUBY
class A
@@ -2220,12 +2310,104 @@ end
tk = @parser.get_tk
- @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, ''
+ @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
foo = klass.method_list.first
assert_equal 'nth(i)', foo.block_params
end
+ def test_read_directive
+ parser = util_parser '# :category: test'
+
+ directive, value = parser.read_directive %w[category]
+
+ assert_equal 'category', directive
+ assert_equal 'test', value
+
+ assert_kind_of RDoc::RubyToken::TkNL, parser.get_tk
+ end
+
+ def test_read_directive_allow
+ parser = util_parser '# :category: test'
+
+ directive = parser.read_directive []
+
+ assert_nil directive
+
+ assert_kind_of RDoc::RubyToken::TkNL, parser.get_tk
+ end
+
+ def test_read_directive_empty
+ parser = util_parser '# test'
+
+ directive = parser.read_directive %w[category]
+
+ assert_nil directive
+
+ assert_kind_of RDoc::RubyToken::TkNL, parser.get_tk
+ end
+
+ def test_read_directive_no_comment
+ parser = util_parser ''
+
+ directive = parser.read_directive %w[category]
+
+ assert_nil directive
+
+ assert_kind_of RDoc::RubyToken::TkNL, parser.get_tk
+ end
+
+ def test_read_directive_one_liner
+ parser = util_parser '; end # :category: test'
+
+ directive, value = parser.read_directive %w[category]
+
+ assert_equal 'category', directive
+ assert_equal 'test', value
+
+ assert_kind_of RDoc::RubyToken::TkSEMICOLON, parser.get_tk
+ end
+
+ def test_read_documentation_modifiers
+ c = RDoc::Context.new
+
+ parser = util_parser '# :category: test'
+
+ parser.read_documentation_modifiers c, %w[category]
+
+ assert_equal 'test', c.current_section.title
+ end
+
+ def test_read_documentation_modifiers_notnew
+ m = RDoc::AnyMethod.new nil, 'initialize'
+
+ parser = util_parser '# :notnew: test'
+
+ parser.read_documentation_modifiers m, %w[notnew]
+
+ assert m.dont_rename_initialize
+ end
+
+ def test_read_documentation_modifiers_not_dash_new
+ m = RDoc::AnyMethod.new nil, 'initialize'
+
+ parser = util_parser '# :not-new: test'
+
+ parser.read_documentation_modifiers m, %w[not-new]
+
+ assert m.dont_rename_initialize
+ end
+
+ def test_read_documentation_modifiers_not_new
+ m = RDoc::AnyMethod.new nil, 'initialize'
+
+ parser = util_parser '# :not_new: test'
+
+ parser.read_documentation_modifiers m, %w[not_new]
+
+ assert m.dont_rename_initialize
+ end
+
def test_sanity_integer
util_parser '1'
assert_equal '1', @parser.get_tk.text
@@ -2255,7 +2437,7 @@ end
def test_sanity_interpolation_curly
util_parser '%{ #{} }'
- assert_equal '%{ #{} }', @parser.get_tk.text
+ assert_equal '%Q{ #{} }', @parser.get_tk.text
assert_equal RDoc::RubyToken::TkNL, @parser.get_tk.class
end
@@ -2312,11 +2494,11 @@ end
foo = @top_level.classes.first
- assert_equal 'Foo comment', foo.comment
+ assert_equal 'Foo comment', foo.comment.text
m = foo.method_list.first
- assert_equal 'm comment', m.comment
+ assert_equal 'm comment', m.comment.text
end
def test_scan_block_comment_nested # Issue #41
@@ -2338,12 +2520,12 @@ end
foo = @top_level.modules.first
assert_equal 'Foo', foo.full_name
- assert_equal 'findmeindoc', foo.comment
+ assert_equal 'findmeindoc', foo.comment.text
bar = foo.classes.first
assert_equal 'Foo::Bar', bar.full_name
- assert_equal '', bar.comment
+ assert_equal '', bar.comment.text
end
def test_scan_block_comment_notflush
@@ -2386,11 +2568,46 @@ end
foo = @top_level.classes.first
assert_equal "= DESCRIPTION\n\nThis is a simple test class\n\n= RUMPUS\n\nIs a silly word",
- foo.comment
+ foo.comment.text
m = foo.method_list.first
- assert_equal 'A nice girl', m.comment
+ assert_equal 'A nice girl', m.comment.text
+ end
+
+ def test_scan_constant_nodoc
+ content = <<-CONTENT # newline is after M is important
+module M
+
+ C = v # :nodoc:
+end
+ CONTENT
+
+ util_parser content
+
+ @parser.scan
+
+ c = @top_level.modules.first.constants.first
+
+ assert c.documented?
+ end
+
+ def test_scan_constant_nodoc_block
+ content = <<-CONTENT # newline is after M is important
+module M
+
+ C = v do # :nodoc:
+ end
+end
+ CONTENT
+
+ util_parser content
+
+ @parser.scan
+
+ c = @top_level.modules.first.constants.first
+
+ assert c.documented?
end
def test_scan_meta_method_block
@@ -2415,6 +2632,157 @@ class C
assert_equal 2, @top_level.classes.first.method_list.length
end
+ def test_scan_markup_override
+ content = <<-CONTENT
+# *awesome*
+class C
+ # :markup: rd
+ # ((*radical*))
+ def m
+ end
+end
+ CONTENT
+
+ util_parser content
+
+ @parser.scan
+
+ c = @top_level.classes.first
+
+ assert_equal 'rdoc', c.comment.format
+
+ assert_equal 'rd', c.method_list.first.comment.format
+ end
+
+ def test_scan_markup_first_comment
+ content = <<-CONTENT
+# :markup: rd
+
+# ((*awesome*))
+class C
+ # ((*radical*))
+ def m
+ end
+end
+ CONTENT
+
+ util_parser content
+
+ @parser.scan
+
+ c = @top_level.classes.first
+
+ assert_equal 'rd', c.comment.format
+
+ assert_equal 'rd', c.method_list.first.comment.format
+ end
+
+ def test_scan_tomdoc_meta
+ util_parser <<-RUBY
+# :markup: tomdoc
+
+class C
+
+ # Signature
+ #
+ # find_by_<field>[_and_<field>...](args)
+ #
+ # field - A field name.
+
+end
+
+ RUBY
+
+ @parser.scan
+
+ c = @top_level.classes.first
+
+ m = c.method_list.first
+
+ assert_equal "find_by_<field>[_and_<field>...]", m.name
+ assert_equal "find_by_<field>[_and_<field>...](args)\n", m.call_seq
+
+ expected =
+ doc(
+ head(3, 'Signature'),
+ list(:NOTE,
+ item(%w[field],
+ para('A field name.'))))
+ expected.file = @top_level
+
+ assert_equal expected, m.comment.parse
+ end
+
+ def test_scan_stopdoc
+ util_parser <<-RUBY
+class C
+ # :stopdoc:
+ class Hidden
+ end
+end
+ RUBY
+
+ @parser.scan
+
+ c = @top_level.classes.first
+
+ hidden = c.classes.first
+
+ refute hidden.document_self
+ assert hidden.ignored?
+ end
+
+ def test_scan_stopdoc_class_alias
+ util_parser <<-RUBY
+# :stopdoc:
+module A
+ B = C
+end
+ RUBY
+
+ @parser.scan
+
+ assert_empty @store.all_classes
+
+ assert_equal 1, @store.all_modules.length
+ m = @store.all_modules.first
+
+ assert m.ignored?
+ end
+
+ def test_scan_stopdoc_nested
+ util_parser <<-RUBY
+# :stopdoc:
+class A::B
+end
+ RUBY
+
+ @parser.scan
+
+ a = @store.modules_hash['A']
+ a_b = @store.classes_hash['A::B']
+
+ refute a.document_self, 'A is inside stopdoc'
+ assert a.ignored?, 'A is inside stopdoc'
+
+ refute a_b.document_self, 'A::B is inside stopdoc'
+ assert a_b.ignored?, 'A::B is inside stopdoc'
+ end
+
+ def test_scan_struct_self_brackets
+ util_parser <<-RUBY
+class C < M.m
+ def self.[]
+ end
+end
+ RUBY
+
+ @parser.scan
+
+ c = @store.find_class_named 'C'
+ assert_equal %w[C::[]], c.method_list.map { |m| m.full_name }
+ end
+
def test_stopdoc_after_comment
util_parser <<-EOS
module Bar
@@ -2433,21 +2801,21 @@ class C
foo = @top_level.modules.first.modules.first
assert_equal 'Foo', foo.name
- assert_equal 'hello', foo.comment
+ assert_equal 'hello', foo.comment.text
baz = @top_level.modules.first.classes.first
assert_equal 'Baz', baz.name
- assert_equal 'there', baz.comment
+ assert_equal 'there', baz.comment.text
end
- def tk(klass, line, char, name, text)
+ def tk klass, scan, line, char, name, text
klass = RDoc::RubyToken.const_get "Tk#{klass.to_s.upcase}"
token = if klass.instance_method(:initialize).arity == 3 then
- raise ArgumentError, "name not used for #{klass}" unless name.nil?
- klass.new nil, line, char
+ raise ArgumentError, "name not used for #{klass}" if name
+ klass.new scan, line, char
else
- klass.new nil, line, char, name
+ klass.new scan, line, char, name
end
token.set_text text
@@ -2467,11 +2835,5 @@ class C
second_file_content, @options, @stats
end
- def util_top_level
- RDoc::TopLevel.reset
- @top_level = RDoc::TopLevel.new @filename
- @top_level2 = RDoc::TopLevel.new @filename2
- end
-
end
diff --git a/test/rdoc/test_rdoc_parser_simple.rb b/test/rdoc/test_rdoc_parser_simple.rb
index 8cedfaa2fc..356ea07504 100644
--- a/test/rdoc/test_rdoc_parser_simple.rb
+++ b/test/rdoc/test_rdoc_parser_simple.rb
@@ -1,24 +1,22 @@
-require 'tempfile'
-require 'rubygems'
-require 'minitest/autorun'
-require 'rdoc/options'
-require 'rdoc/parser'
+require 'rdoc/test_case'
-class TestRDocParserSimple < MiniTest::Unit::TestCase
+class TestRDocParserSimple < RDoc::TestCase
def setup
+ super
+
@tempfile = Tempfile.new self.class.name
filename = @tempfile.path
- @top_level = RDoc::TopLevel.new filename
+ @top_level = @store.add_file filename
@fn = filename
@options = RDoc::Options.new
- @stats = RDoc::Stats.new 0
-
- RDoc::TopLevel.reset
+ @stats = RDoc::Stats.new @store, 0
end
def teardown
+ super
+
@tempfile.close
end
@@ -45,7 +43,7 @@ Regular expressions (<i>regexp</i>s) are patterns which describe the
contents of a string.
TEXT
- assert_equal expected, @top_level.comment
+ assert_equal expected, @top_level.comment.text
end
# RDoc stops processing comments if it finds a comment line CONTAINING
@@ -74,21 +72,39 @@ contents of a string.
# # ---
def test_remove_private_comments
- parser = util_parser ''
- text = "foo\n\n--\nbar\n++\n\nbaz\n"
+ parser = util_parser "foo\n\n--\nbar\n++\n\nbaz\n"
+
+ parser.scan
- expected = "foo\n\n\n\nbaz\n"
+ expected = "foo\n\n\nbaz"
- assert_equal expected, parser.remove_private_comments(text)
+ assert_equal expected, @top_level.comment.text
+ end
+
+ def test_remove_private_comments_rule
+ parser = util_parser "foo\n---\nbar"
+
+ parser.scan
+
+ expected = "foo\n---\nbar"
+
+ assert_equal expected, @top_level.comment.text
end
def test_remove_private_comments_star
- parser = util_parser ''
+ parser = util_parser "* foo\n* bar\n"
+
+ parser.scan
- text = "* foo\n* bar\n"
- expected = text.dup
+ assert_equal "* foo\n* bar", @top_level.comment.text
+ end
+
+ def test_scan
+ parser = util_parser 'it *really* works'
+
+ parser.scan
- assert_equal expected, parser.remove_private_comments(text)
+ assert_equal 'it *really* works', @top_level.comment.text
end
def util_parser(content)
diff --git a/test/rdoc/test_rdoc_rd.rb b/test/rdoc/test_rdoc_rd.rb
new file mode 100644
index 0000000000..d917a63661
--- /dev/null
+++ b/test/rdoc/test_rdoc_rd.rb
@@ -0,0 +1,30 @@
+require 'rdoc/test_case'
+
+class TestRDocRd < RDoc::TestCase
+
+ def test_class_parse
+ expected =
+ @RM::Document.new(
+ @RM::Paragraph.new('hello'))
+
+ assert_equal expected, RDoc::RD.parse("hello")
+ end
+
+ def test_class_parse_begin_end
+ expected =
+ @RM::Document.new(
+ @RM::Paragraph.new('hello'))
+
+ assert_equal expected, RDoc::RD.parse("=begin\nhello\n=end\n")
+ end
+
+ def test_class_parse_newline
+ expected =
+ @RM::Document.new(
+ @RM::Paragraph.new('hello'))
+
+ assert_equal expected, RDoc::RD.parse("hello\n")
+ end
+
+end
+
diff --git a/test/rdoc/test_rdoc_rd_block_parser.rb b/test/rdoc/test_rdoc_rd_block_parser.rb
new file mode 100644
index 0000000000..541c26fd89
--- /dev/null
+++ b/test/rdoc/test_rdoc_rd_block_parser.rb
@@ -0,0 +1,523 @@
+require 'rdoc/test_case'
+
+class TestRDocRdBlockParser < RDoc::TestCase
+
+ def setup
+ super
+
+ @block_parser = RDoc::RD::BlockParser.new
+ end
+
+ def mu_pp(obj)
+ s = ""
+ s = PP.pp obj, s
+ s = s.force_encoding(Encoding.default_external) if defined? Encoding
+ s.chomp
+ end
+
+ def test_parse_desclist
+ list = <<-LIST
+:one
+ desc one
+:two
+ desc two
+ LIST
+
+ expected =
+ doc(
+ @RM::List.new(:NOTE,
+ @RM::ListItem.new("one", @RM::Paragraph.new("desc one")),
+ @RM::ListItem.new("two", @RM::Paragraph.new("desc two"))))
+
+ assert_equal expected, parse(list)
+ end
+
+ def test_parse_enumlist
+ list = <<-LIST
+(1) one
+(1) two
+ LIST
+
+ expected =
+ doc(
+ @RM::List.new(:NUMBER,
+ @RM::ListItem.new(nil, @RM::Paragraph.new("one")),
+ @RM::ListItem.new(nil, @RM::Paragraph.new("two"))))
+
+ assert_equal expected, parse(list)
+ end
+
+ def test_parse_enumlist_paragraphs
+ list = <<-LIST
+(1) one
+
+ two
+ LIST
+
+ expected =
+ doc(
+ @RM::List.new(:NUMBER,
+ @RM::ListItem.new(nil,
+ @RM::Paragraph.new("one"),
+ @RM::Paragraph.new("two"))))
+
+ assert_equal expected, parse(list)
+ end
+
+ def test_parse_enumlist_multiline
+ list = <<-LIST
+(1) one
+ two
+ LIST
+
+ contents = "one\n two" # 1.8 vs 1.9
+
+ expected =
+ doc(
+ @RM::List.new(:NUMBER,
+ @RM::ListItem.new(nil, @RM::Paragraph.new(*contents))))
+
+ assert_equal expected, parse(list)
+ end
+
+ def test_parse_enumlist_verbatim
+ list = <<-LIST
+(1) item
+ verbatim
+ LIST
+
+ expected =
+ doc(
+ @RM::List.new(:NUMBER,
+ @RM::ListItem.new(nil,
+ @RM::Paragraph.new("item"),
+ @RM::Verbatim.new("verbatim\n"))))
+
+ assert_equal expected, parse(list)
+ end
+
+ def test_parse_enumlist_verbatim_continue
+ list = <<-LIST
+(1) one
+ verbatim
+ two
+ LIST
+
+ expected =
+ doc(
+ @RM::List.new(:NUMBER,
+ @RM::ListItem.new(nil,
+ @RM::Paragraph.new("one"),
+ @RM::Verbatim.new("verbatim\n"),
+ @RM::Paragraph.new("two"))))
+
+ assert_equal expected, parse(list)
+ end
+
+ def test_parse_footnote
+ expected =
+ doc(
+ @RM::Paragraph.new("{*1}[rdoc-label:foottext-1:footmark-1]"),
+ @RM::Rule.new(1),
+ @RM::Paragraph.new("{^1}[rdoc-label:footmark-1:foottext-1]", "text"))
+
+ assert_equal expected, parse("((-text-))")
+ end
+
+ def test_parse_include
+ @block_parser.include_path = [Dir.tmpdir]
+
+ expected = doc(@RM::Include.new("parse_include", [Dir.tmpdir]))
+
+ assert_equal expected, parse("<<< parse_include")
+ end
+
+ def test_parse_include_subtree
+ @block_parser.include_path = [Dir.tmpdir]
+
+ expected =
+ doc(
+ @RM::BlankLine.new,
+ @RM::Paragraph.new("include <em>worked</em>"),
+ @RM::BlankLine.new,
+ @RM::BlankLine.new)
+
+ Tempfile.open %w[parse_include .rd] do |io|
+ io.puts "=begin\ninclude ((*worked*))\n=end"
+ io.flush
+
+ str = <<-STR
+<<< #{File.basename io.path}
+ STR
+
+ assert_equal expected, parse(str)
+ end
+ end
+
+ def test_parse_heading
+ assert_equal doc(@RM::Heading.new(1, "H")), parse("= H")
+ assert_equal doc(@RM::Heading.new(2, "H")), parse("== H")
+ assert_equal doc(@RM::Heading.new(3, "H")), parse("=== H")
+ assert_equal doc(@RM::Heading.new(4, "H")), parse("==== H")
+ assert_equal doc(@RM::Heading.new(5, "H")), parse("+ H")
+ assert_equal doc(@RM::Heading.new(6, "H")), parse("++ H")
+ end
+
+ def test_parse_itemlist
+ list = <<-LIST
+* one
+* two
+ LIST
+
+ expected =
+ doc(
+ @RM::List.new(:BULLET,
+ @RM::ListItem.new(nil, @RM::Paragraph.new("one")),
+ @RM::ListItem.new(nil, @RM::Paragraph.new("two"))))
+
+ assert_equal expected, parse(list)
+ end
+
+ def test_parse_itemlist_multiline
+ list = <<-LIST
+* one
+ two
+ LIST
+
+ contents = "one\n two" # 1.8 vs 1.9
+
+ expected =
+ doc(
+ @RM::List.new(:BULLET,
+ @RM::ListItem.new(nil, @RM::Paragraph.new(*contents))))
+
+ assert_equal expected, parse(list)
+ end
+
+ def test_parse_itemlist_nest
+ list = <<-LIST
+* one
+ * inner
+* two
+ LIST
+
+ expected =
+ doc(
+ @RM::List.new(:BULLET,
+ @RM::ListItem.new(nil,
+ @RM::Paragraph.new("one"),
+ @RM::List.new(:BULLET,
+ @RM::ListItem.new(nil, @RM::Paragraph.new("inner")))),
+ @RM::ListItem.new(nil,
+ @RM::Paragraph.new("two"))))
+
+ assert_equal expected, parse(list)
+ end
+
+ def test_parse_itemlist_paragraphs
+ list = <<-LIST
+* one
+
+ two
+ LIST
+
+ expected =
+ doc(
+ @RM::List.new(:BULLET,
+ @RM::ListItem.new(nil,
+ @RM::Paragraph.new("one"),
+ @RM::Paragraph.new("two"))))
+
+ assert_equal expected, parse(list)
+ end
+
+ def test_parse_itemlist_verbatim
+ list = <<-LIST
+* item
+ verbatim
+ LIST
+
+ expected =
+ doc(
+ @RM::List.new(:BULLET,
+ @RM::ListItem.new(nil,
+ @RM::Paragraph.new("item"),
+ @RM::Verbatim.new("verbatim\n"))))
+
+ assert_equal expected, parse(list)
+ end
+
+ def test_parse_itemlist_verbatim_continue
+ list = <<-LIST
+* one
+ verbatim
+ two
+ LIST
+
+ expected =
+ doc(
+ @RM::List.new(:BULLET,
+ @RM::ListItem.new(nil,
+ @RM::Paragraph.new("one"),
+ @RM::Verbatim.new("verbatim\n"),
+ @RM::Paragraph.new("two"))))
+
+ assert_equal expected, parse(list)
+ end
+
+ def test_parse_lists
+ list = <<-LIST
+(1) one
+(1) two
+* three
+* four
+(1) five
+(1) six
+ LIST
+
+ expected =
+ doc(
+ @RM::List.new(:NUMBER,
+ @RM::ListItem.new(nil, @RM::Paragraph.new("one")),
+ @RM::ListItem.new(nil, @RM::Paragraph.new("two"))),
+ @RM::List.new(:BULLET,
+ @RM::ListItem.new(nil, @RM::Paragraph.new("three")),
+ @RM::ListItem.new(nil, @RM::Paragraph.new("four"))),
+ @RM::List.new(:NUMBER,
+ @RM::ListItem.new(nil, @RM::Paragraph.new("five")),
+ @RM::ListItem.new(nil, @RM::Paragraph.new("six"))))
+
+ assert_equal expected, parse(list)
+ end
+
+ def test_parse_lists_nest
+ list = <<-LIST
+(1) one
+(1) two
+ * three
+ * four
+(1) five
+(1) six
+ LIST
+
+ expected =
+ doc(
+ @RM::List.new(:NUMBER,
+ @RM::ListItem.new(nil, @RM::Paragraph.new("one")),
+ @RM::ListItem.new(nil,
+ @RM::Paragraph.new("two"),
+ @RM::List.new(:BULLET,
+ @RM::ListItem.new(nil, @RM::Paragraph.new("three")),
+ @RM::ListItem.new(nil, @RM::Paragraph.new("four")))),
+ @RM::ListItem.new(nil, @RM::Paragraph.new("five")),
+ @RM::ListItem.new(nil, @RM::Paragraph.new("six"))))
+
+ assert_equal expected, parse(list)
+ end
+
+ def test_parse_lists_nest_verbatim
+ list = <<-LIST
+(1) one
+(1) two
+ * three
+ * four
+ verbatim
+(1) five
+(1) six
+ LIST
+
+ expected =
+ doc(
+ @RM::List.new(:NUMBER,
+ @RM::ListItem.new(nil, @RM::Paragraph.new("one")),
+ @RM::ListItem.new(nil,
+ @RM::Paragraph.new("two"),
+ @RM::List.new(:BULLET,
+ @RM::ListItem.new(nil, @RM::Paragraph.new("three")),
+ @RM::ListItem.new(nil, @RM::Paragraph.new("four"))),
+ @RM::Verbatim.new("verbatim\n")),
+ @RM::ListItem.new(nil, @RM::Paragraph.new("five")),
+ @RM::ListItem.new(nil, @RM::Paragraph.new("six"))))
+
+ assert_equal expected, parse(list)
+ end
+
+ def test_parse_lists_nest_verbatim2
+ list = <<-LIST
+(1) one
+(1) two
+ * three
+ * four
+ verbatim
+(1) five
+(1) six
+ LIST
+
+ expected =
+ doc(
+ @RM::List.new(:NUMBER,
+ @RM::ListItem.new(nil, @RM::Paragraph.new("one")),
+ @RM::ListItem.new(nil,
+ @RM::Paragraph.new("two"),
+ @RM::List.new(:BULLET,
+ @RM::ListItem.new(nil, @RM::Paragraph.new("three")),
+ @RM::ListItem.new(nil, @RM::Paragraph.new("four"))),
+ @RM::Verbatim.new("verbatim\n")),
+ @RM::ListItem.new(nil, @RM::Paragraph.new("five")),
+ @RM::ListItem.new(nil, @RM::Paragraph.new("six"))))
+
+ assert_equal expected, parse(list)
+ end
+
+ def test_parse_methodlist
+ list = <<-LIST
+--- Array#each {|i| ... }
+ yield block for each item.
+--- Array#index(val)
+ return index of first item which equals with val. if it hasn't
+ same item, return nil.
+ LIST
+
+ expected =
+ doc(
+ @RM::List.new(:LABEL,
+ @RM::ListItem.new(
+ "<tt>Array#each {|i| ... }</tt>",
+ @RM::Paragraph.new("yield block for each item.")),
+ @RM::ListItem.new(
+ "<tt>Array#index(val)</tt>",
+ @RM::Paragraph.new("return index of first item which equals with val. if it hasn't same item, return nil."))))
+
+ assert_equal expected, parse(list)
+ end
+
+ def test_parse_methodlist_empty
+ list = <<-LIST
+--- A#b
+
+ LIST
+
+ expected =
+ doc(
+ @RM::List.new(:LABEL,
+ @RM::ListItem.new("<tt>A#b</tt>")))
+
+ assert_equal expected, parse(list)
+ end
+
+ def test_parse_methodlist_paragraph
+ list = <<-LIST
+--- A#b
+
+ one
+ LIST
+
+ expected =
+ doc(
+ @RM::List.new(:LABEL,
+ @RM::ListItem.new(
+ "<tt>A#b</tt>",
+ @RM::Paragraph.new("one"))))
+
+ assert_equal expected, parse(list)
+ end
+
+ def test_parse_methodlist_paragraph2
+ list = <<-LIST.chomp
+--- A#b
+
+ one
+two
+ LIST
+
+ expected =
+ doc(
+ @RM::List.new(:LABEL,
+ @RM::ListItem.new(
+ "<tt>A#b</tt>",
+ @RM::Paragraph.new("one"))),
+ @RM::Paragraph.new("two"))
+
+ assert_equal expected, parse(list)
+ end
+
+ def test_parse_methodlist_paragraph_verbatim
+ list = <<-LIST.chomp
+--- A#b
+
+ text
+ verbatim
+ LIST
+
+ expected =
+ doc(
+ @RM::List.new(:LABEL,
+ @RM::ListItem.new(
+ "<tt>A#b</tt>",
+ @RM::Paragraph.new("text"),
+ @RM::Verbatim.new("verbatim\n"))))
+
+ assert_equal expected, parse(list)
+ end
+
+ def test_parse_verbatim
+ assert_equal doc(@RM::Verbatim.new("verbatim\n")), parse(" verbatim")
+ end
+
+ def test_parse_verbatim_blankline
+ expected = doc(@RM::Verbatim.new("one\n", "\n", "two\n"))
+
+ verbatim = <<-VERBATIM
+ one
+
+ two
+ VERBATIM
+
+ assert_equal expected, parse(verbatim)
+ end
+
+ def test_parse_verbatim_indent
+ expected = doc(@RM::Verbatim.new("one\n", " two\n"))
+
+ verbatim = <<-VERBATIM
+ one
+ two
+ VERBATIM
+
+ assert_equal expected, parse(verbatim)
+ end
+
+ def test_parse_verbatim_multi
+ expected = doc(@RM::Verbatim.new("one\n", "two\n"))
+
+ verbatim = <<-VERBATIM
+ one
+ two
+ VERBATIM
+
+ assert_equal expected, parse(verbatim)
+ end
+
+ def test_parse_textblock
+ assert_equal doc(@RM::Paragraph.new("text")), parse("text")
+ end
+
+ def test_parse_textblock_multi
+ expected = doc(@RM::Paragraph.new("one two"))
+
+ assert_equal expected, parse("one\ntwo")
+ end
+
+ def parse text
+ text = ["=begin", text, "=end"].join "\n"
+
+ doc = @block_parser.parse text.lines.to_a
+
+ assert_equal @RM::BlankLine.new, doc.parts.shift, "=begin blankline"
+ assert_equal @RM::BlankLine.new, doc.parts.pop, "=end blankline"
+
+ doc
+ end
+
+end
+
diff --git a/test/rdoc/test_rdoc_rd_inline.rb b/test/rdoc/test_rdoc_rd_inline.rb
new file mode 100644
index 0000000000..d601ecca1a
--- /dev/null
+++ b/test/rdoc/test_rdoc_rd_inline.rb
@@ -0,0 +1,63 @@
+require 'rdoc/test_case'
+
+class TestRDocRdInline < RDoc::TestCase
+
+ def setup
+ super
+
+ @inline = RDoc::RD::Inline.new '+text+', 'text'
+ end
+
+ def test_class_new
+ inline = RDoc::RD::Inline.new @inline
+
+ refute_equal inline.rdoc, inline.reference
+ end
+
+ def test_initialize
+ inline = RDoc::RD::Inline.new 'text'
+
+ assert_equal inline.rdoc, inline.reference
+ refute_same inline.rdoc, inline.reference
+ end
+
+ def test_initialize_inline
+ inline = RDoc::RD::Inline.new @inline
+
+ assert_equal '+text+', inline.rdoc
+ assert_equal 'text', inline.reference
+ end
+
+ def test_append_inline
+ out = @inline.append @inline
+
+ assert_same @inline, out
+
+ assert_equal '+text++text+', @inline.rdoc
+ assert_equal 'texttext', @inline.reference
+ end
+
+ def test_append_string
+ @inline.append ' more'
+
+ assert_equal '+text+ more', @inline.rdoc
+ assert_equal 'text more', @inline.reference
+ end
+
+ def test_equals2
+ assert_equal @inline, RDoc::RD::Inline.new('+text+', 'text')
+ refute_equal @inline, RDoc::RD::Inline.new('+text+', 'other')
+ refute_equal @inline, RDoc::RD::Inline.new('+other+', 'text')
+ refute_equal @inline, Object.new
+ end
+
+ def test_inspect
+ assert_equal '(inline: +text+)', @inline.inspect
+ end
+
+ def test_to_s
+ assert_equal '+text+', @inline.to_s
+ end
+
+end
+
diff --git a/test/rdoc/test_rdoc_rd_inline_parser.rb b/test/rdoc/test_rdoc_rd_inline_parser.rb
new file mode 100644
index 0000000000..6b6c00f886
--- /dev/null
+++ b/test/rdoc/test_rdoc_rd_inline_parser.rb
@@ -0,0 +1,173 @@
+require 'rdoc/test_case'
+
+class TestRDocRdInlineParser < RDoc::TestCase
+
+ def setup
+ super
+
+ @block_parser = RDoc::RD::BlockParser.new
+ @block_parser.instance_variable_set :@i, 0
+ @inline_parser = RDoc::RD::InlineParser.new @block_parser
+ end
+
+ def test_parse
+ assert_equal 'regular <em>emphasis</em>', parse('regular ((*emphasis*))')
+ end
+
+ def test_parse_code
+ assert_equal '<code>text</code>', parse('(({text}))')
+ end
+
+ def test_parse_em
+ assert_equal '<em>text</em>', parse('((*text*))')
+ end
+
+ def test_parse_footnote
+ assert_equal '{*1}[rdoc-label:foottext-1:footmark-1]', parse('((-text-))')
+
+ expected = [
+ @RM::Paragraph.new('{^1}[rdoc-label:footmark-1:foottext-1]', 'text')
+ ]
+
+ assert_equal expected, @block_parser.footnotes
+ end
+
+ def test_parse_index
+ assert_equal '<span id="label-text">text</span>', parse('((:text:))')
+
+ assert_includes @block_parser.labels, 'text'
+ end
+
+ def test_parse_kbd
+ assert_equal '<tt>text</tt>', parse('((%text%))')
+ end
+
+ def test_parse_multiple
+ assert_equal '<em>one</em> <em>two</em>', parse('((*one*)) ((*two*))')
+ end
+
+ def test_parse_newline
+ assert_equal "one\ntwo", parse("one\ntwo")
+ end
+
+ def test_parse_quote
+ assert_equal 'one " two', parse('one " two')
+ end
+
+ def test_parse_ref
+ assert_equal '{text}[rdoc-label:text]', parse('((<text>))')
+ end
+
+ def test_parse_ref_em
+ assert_equal '{<em>text</em>}[rdoc-label:text]', parse('((<((*text*))>))')
+ end
+
+ def test_parse_ref_filename_quote
+ assert_equal '{RD/foo}[rdoc-label:RD/foo]', parse('((<RD/"foo">))')
+ end
+
+ def test_parse_ref_filename
+ assert_equal '{RD}[rdoc-label:RD/]', parse('((<RD/>))')
+ end
+
+ def test_parse_ref_quote
+ assert_equal '{text \\"}[rdoc-label:text \\"]', parse('((<text \">))')
+ end
+
+ def test_parse_ref_quote_content
+ assert_equal '{<em>text</em>}[rdoc-label:text]',
+ parse('((<"((*text*))">))')
+ end
+
+ def test_parse_ref_quote_content_multi
+ assert_equal '{<em>one</em> <em>two</em>}[rdoc-label:one two]',
+ parse('((<"((*one*)) ((*two*))">))')
+ end
+
+ def test_parse_ref_substitute
+ assert_equal '{text}[rdoc-label:thing]', parse('((<text|thing>))')
+ end
+
+ def test_parse_ref_substitute_element_quote
+ assert_equal '{text}[rdoc-label:"RD"]',
+ parse('((<text|"RD">))')
+ end
+
+ def test_parse_ref_substitute_filename
+ assert_equal '{text}[rdoc-label:RD/]', parse('((<text|RD/>))')
+ end
+
+ def test_parse_ref_substitute_filename_label
+ assert_equal '{text}[rdoc-label:RD/label]',
+ parse('((<text|RD/label>))')
+ end
+
+ def test_parse_ref_substitute_filename_quote
+ assert_equal '{text}[rdoc-label:"RD"/]', parse('((<text|"RD"/>))')
+ end
+
+ def test_parse_ref_substitute_multi_content
+ assert_equal '{<em>one</em> two}[rdoc-label:thing]',
+ parse('((<((*one*)) two|thing>))')
+ end
+
+ def test_parse_ref_substitute_multi_content2
+ assert_equal '{<em>one</em> \\" two}[rdoc-label:thing]',
+ parse('((<((*one*)) \" two|thing>))')
+ end
+
+ def test_parse_ref_substitute_multi_content3
+ assert_equal '{<em>one</em> \\" <em>two</em>}[rdoc-label:thing]',
+ parse('((<((*one*)) \" ((*two*))|thing>))')
+ end
+
+ def test_parse_ref_substitute_quote
+ assert_equal '{one | two}[rdoc-label:thing]',
+ parse('((<"one | two"|thing>))')
+ end
+
+ def test_parse_ref_substitute_quote_content
+ assert_equal '{<em>text</em>}[rdoc-label:thing]',
+ parse('((<"((*text*))"|thing>))')
+ end
+
+ def test_parse_ref_substitute_url
+ assert_equal '{text}[http://example]',
+ parse('((<text|URL:http://example>))')
+ end
+
+ def test_parse_ref_url
+ assert_equal '{http://example}[http://example]',
+ parse('((<URL:http://example>))')
+ end
+
+ def test_parse_var
+ assert_equal '+text+', parse('((|text|))')
+ end
+
+ def test_parse_verb
+ assert_equal '<tt>text</tt>', parse("(('text'))")
+ end
+
+ def test_parse_verb_backslash
+ assert_equal "<tt>(('text'))</tt>", parse("(('(('text\\'))'))")
+ end
+
+ def test_parse_verb_backslash_backslash
+ assert_equal '<tt>text \\</tt>', parse("(('text \\\\'))")
+ end
+
+ def test_parse_verb_backslash_quote
+ assert_equal '<tt>text "</tt>', parse("(('text \\\"'))")
+ end
+
+ def test_parse_verb_multiple
+ assert_equal '<tt>((*text*))</tt>', parse("(('((*text*))'))")
+ end
+
+ def parse text
+ @inline_parser.parse text
+ end
+
+end
+
diff --git a/test/rdoc/test_rdoc_rdoc.rb b/test/rdoc/test_rdoc_rdoc.rb
index aedccc9dbf..fd6b3f81e4 100644
--- a/test/rdoc/test_rdoc_rdoc.rb
+++ b/test/rdoc/test_rdoc_rdoc.rb
@@ -1,47 +1,107 @@
-require 'rubygems'
-require 'minitest/autorun'
-require 'rdoc/rdoc'
+require 'rdoc/test_case'
-require 'fileutils'
-require 'tempfile'
-require 'tmpdir'
-
-class TestRDocRDoc < MiniTest::Unit::TestCase
+class TestRDocRDoc < RDoc::TestCase
def setup
- RDoc::TopLevel.reset
+ super
@rdoc = RDoc::RDoc.new
@rdoc.options = RDoc::Options.new
- @stats = RDoc::Stats.new 0, 0
+ @stats = RDoc::Stats.new @store, 0, 0
@rdoc.instance_variable_set :@stats, @stats
end
- def test_class_reset
- tl = RDoc::TopLevel.new 'file.rb'
- tl.add_class RDoc::NormalClass, 'C'
- tl.add_class RDoc::NormalModule, 'M'
+ def test_document # functional test
+ options = RDoc::Options.new
+ options.files = [File.expand_path('../xref_data.rb')]
+ options.setup_generator 'ri'
+ options.main_page = 'MAIN_PAGE.rdoc'
+ options.title = 'title'
- c = RDoc::Parser::C
- enclosure_classes = c.send :class_variable_get, :@@enclosure_classes
- enclosure_classes['A'] = 'B'
- known_bodies = c.send :class_variable_get, :@@known_bodies
- known_bodies['A'] = 'B'
+ rdoc = RDoc::RDoc.new
- RDoc::RDoc.reset
+ temp_dir do
+ capture_io do
+ rdoc.document options
+ end
- assert_empty RDoc::TopLevel.all_classes_hash
- assert_empty RDoc::TopLevel.all_files_hash
- assert_empty RDoc::TopLevel.all_modules_hash
+ assert File.directory? 'doc'
+ assert_equal rdoc, rdoc.store.rdoc
+ end
- assert_empty c.send :class_variable_get, :@@enclosure_classes
- assert_empty c.send :class_variable_get, :@@known_bodies
+ store = rdoc.store
+
+ assert_equal 'MAIN_PAGE.rdoc', store.main
+ assert_equal 'title', store.title
end
def test_gather_files
- file = File.expand_path __FILE__
- assert_equal [file], @rdoc.gather_files([file, file])
+ a = File.expand_path __FILE__
+ b = File.expand_path '../test_rdoc_text.rb', __FILE__
+
+ assert_equal [a, b], @rdoc.gather_files([b, a, b])
+ end
+
+ def test_handle_pipe
+ $stdin = StringIO.new "hello"
+
+ out, = capture_io do
+ @rdoc.handle_pipe
+ end
+
+ assert_equal "\n<p>hello</p>\n", out
+ ensure
+ $stdin = STDIN
+ end
+
+ def test_handle_pipe_rd
+ $stdin = StringIO.new "=begin\nhello\n=end"
+
+ @rdoc.options.markup = 'rd'
+
+ out, = capture_io do
+ @rdoc.handle_pipe
+ end
+
+ assert_equal "\n<p>hello</p>\n", out
+ ensure
+ $stdin = STDIN
+ end
+
+ def test_load_options
+ temp_dir do
+ options = RDoc::Options.new
+ options.markup = 'tomdoc'
+ options.write_options
+
+ options = @rdoc.load_options
+
+ assert_equal 'tomdoc', options.markup
+ end
+ end
+
+ def test_load_options_invalid
+ temp_dir do
+ open '.rdoc_options', 'w' do |io|
+ io.write "a: !ruby.yaml.org,2002:str |\nfoo"
+ end
+
+ e = assert_raises RDoc::Error do
+ @rdoc.load_options
+ end
+
+ options_file = File.expand_path '.rdoc_options'
+ assert_equal "#{options_file} is not a valid rdoc options file", e.message
+ end
+ end
+
+ def load_options_no_file
+ temp_dir do
+ options = @rdoc.load_options
+
+ assert_kind_of RDoc::Options, options
+ end
end
def test_normalized_file_list
@@ -62,9 +122,29 @@ class TestRDocRDoc < MiniTest::Unit::TestCase
assert_empty files
end
+ def test_normalized_file_list_non_file_directory
+ skip '/dev/stdin is not a character special' unless
+ File.chardev? '/dev/stdin'
+
+ files = nil
+
+ out, err = capture_io do
+ files = @rdoc.normalized_file_list %w[/dev/stdin]
+ end
+
+ files = files.map { |file| File.expand_path file }
+
+ assert_empty files
+
+ assert_empty out
+ assert_match %r%^rdoc can't parse%, err
+ assert_match %r%/dev/stdin$%, err
+ end
+
def test_parse_file_encoding
skip "Encoding not implemented" unless Object.const_defined? :Encoding
@rdoc.options.encoding = Encoding::ISO_8859_1
+ @rdoc.store = RDoc::Store.new
Tempfile.open 'test.txt' do |io|
io.write 'hi'
@@ -76,6 +156,31 @@ class TestRDocRDoc < MiniTest::Unit::TestCase
end
end
+ def test_parse_file_forbidden
+ @rdoc.store = RDoc::Store.new
+
+ Tempfile.open 'test.txt' do |io|
+ io.write 'hi'
+ io.rewind
+
+ File.chmod 0000, io.path
+
+ begin
+ top_level = :bug
+
+ _, err = capture_io do
+ top_level = @rdoc.parse_file io.path
+ end
+
+ assert_match "Unable to read #{io.path},", err
+
+ assert_nil top_level
+ ensure
+ File.chmod 0400, io.path
+ end
+ end
+ end
+
def test_remove_unparseable
file_list = %w[
blah.class
@@ -89,9 +194,35 @@ class TestRDocRDoc < MiniTest::Unit::TestCase
assert_empty @rdoc.remove_unparseable file_list
end
- def test_setup_output_dir
- skip "No Dir::mktmpdir, upgrade your ruby" unless Dir.respond_to? :mktmpdir
+ def test_remove_unparseable_tags_emacs
+ temp_dir do
+ open 'TAGS', 'w' do |io| # emacs
+ io.write "\f\nlib/foo.rb,43\n"
+ end
+
+ file_list = %w[
+ TAGS
+ ]
+
+ assert_empty @rdoc.remove_unparseable file_list
+ end
+ end
+ def test_remove_unparseable_tags_vim
+ temp_dir do
+ open 'TAGS', 'w' do |io| # emacs
+ io.write "!_TAG_"
+ end
+
+ file_list = %w[
+ TAGS
+ ]
+
+ assert_empty @rdoc.remove_unparseable file_list
+ end
+ end
+
+ def test_setup_output_dir
Dir.mktmpdir {|d|
path = File.join d, 'testdir'
@@ -105,8 +236,6 @@ class TestRDocRDoc < MiniTest::Unit::TestCase
end
def test_setup_output_dir_dry_run
- skip "No Dir::mktmpdir, upgrade your ruby" unless Dir.respond_to? :mktmpdir
-
@rdoc.options.dry_run = true
Dir.mktmpdir do |d|
@@ -119,8 +248,6 @@ class TestRDocRDoc < MiniTest::Unit::TestCase
end
def test_setup_output_dir_exists
- skip "No Dir::mktmpdir, upgrade your ruby" unless Dir.respond_to? :mktmpdir
-
Dir.mktmpdir {|path|
open @rdoc.output_flag_file(path), 'w' do |io|
io.puts Time.at 0
@@ -135,8 +262,6 @@ class TestRDocRDoc < MiniTest::Unit::TestCase
end
def test_setup_output_dir_exists_empty_created_rid
- skip "No Dir::mktmpdir, upgrade your ruby" unless Dir.respond_to? :mktmpdir
-
Dir.mktmpdir {|path|
open @rdoc.output_flag_file(path), 'w' do end
@@ -162,8 +287,6 @@ class TestRDocRDoc < MiniTest::Unit::TestCase
end
def test_setup_output_dir_exists_not_rdoc
- skip "No Dir::mktmpdir, upgrade your ruby" unless Dir.respond_to? :mktmpdir
-
Dir.mktmpdir do |dir|
e = assert_raises RDoc::Error do
@rdoc.setup_output_dir dir, false
@@ -174,8 +297,6 @@ class TestRDocRDoc < MiniTest::Unit::TestCase
end
def test_update_output_dir
- skip "No Dir::mktmpdir, upgrade your ruby" unless Dir.respond_to? :mktmpdir
-
Dir.mktmpdir do |d|
@rdoc.update_output_dir d, Time.now, {}
@@ -184,8 +305,6 @@ class TestRDocRDoc < MiniTest::Unit::TestCase
end
def test_update_output_dir_dont
- skip "No Dir::mktmpdir, upgrade your ruby" unless Dir.respond_to? :mktmpdir
-
Dir.mktmpdir do |d|
@rdoc.options.update_output_dir = false
@rdoc.update_output_dir d, Time.now, {}
@@ -195,8 +314,6 @@ class TestRDocRDoc < MiniTest::Unit::TestCase
end
def test_update_output_dir_dry_run
- skip "No Dir::mktmpdir, upgrade your ruby" unless Dir.respond_to? :mktmpdir
-
Dir.mktmpdir do |d|
@rdoc.options.dry_run = true
@rdoc.update_output_dir d, Time.now, {}
diff --git a/test/rdoc/test_rdoc_ri_driver.rb b/test/rdoc/test_rdoc_ri_driver.rb
index e219993e57..8fb91c5e1c 100644
--- a/test/rdoc/test_rdoc_ri_driver.rb
+++ b/test/rdoc/test_rdoc_ri_driver.rb
@@ -1,16 +1,9 @@
-require 'pp'
-require 'rubygems'
-require 'minitest/autorun'
-require 'tmpdir'
-require 'fileutils'
-require 'stringio'
-require 'rdoc/ri/driver'
-require 'rdoc/rdoc'
+require 'rdoc/test_case'
-class TestRDocRIDriver < MiniTest::Unit::TestCase
+class TestRDocRIDriver < RDoc::TestCase
def setup
- @RM = RDoc::Markup
+ super
@tmpdir = File.join Dir.tmpdir, "test_rdoc_ri_driver_#{$$}"
@home_ri = File.join @tmpdir, 'dot_ri'
@@ -23,14 +16,22 @@ class TestRDocRIDriver < MiniTest::Unit::TestCase
ENV['HOME'] = @tmpdir
ENV.delete 'RI'
- @options = RDoc::RI::Driver.process_args []
- @options[:home] = @tmpdir
+ @options = RDoc::RI::Driver.default_options
+ @options[:use_system] = false
+ @options[:use_site] = false
+ @options[:use_home] = false
+ @options[:use_gems] = false
+
+ @options[:home] = @tmpdir
@options[:use_stdout] = true
- @options[:formatter] = @RM::ToRdoc
+ @options[:formatter] = @RM::ToRdoc
+
@driver = RDoc::RI::Driver.new @options
end
def teardown
+ super
+
ENV['HOME'] = @orig_home
ENV['RI'] = @orig_ri
FileUtils.rm_rf @tmpdir
@@ -56,7 +57,7 @@ class TestRDocRIDriver < MiniTest::Unit::TestCase
util_store
out, = capture_io do
- RDoc::RI::Driver.dump @store.cache_path
+ RDoc::RI::Driver.dump @store1.cache_path
end
assert_match %r%:class_methods%, out
@@ -85,8 +86,8 @@ class TestRDocRIDriver < MiniTest::Unit::TestCase
expected = @RM::Document.new(
@RM::Rule.new(1),
@RM::Paragraph.new('Also found in:'),
- @RM::Verbatim.new("ruby core\n",
- "~/.ri\n"))
+ @RM::Verbatim.new("ruby core", "\n",
+ "~/.rdoc", "\n"))
assert_equal expected, out
end
@@ -107,26 +108,44 @@ class TestRDocRIDriver < MiniTest::Unit::TestCase
def test_add_from
util_store
- @store.type = :system
+ @store1.type = :system
out = @RM::Document.new
- @driver.add_from out, @store
+ @driver.add_from out, @store1
expected = @RM::Document.new @RM::Paragraph.new("(from ruby core)")
assert_equal expected, out
end
- def test_add_includes_empty
+ def test_add_extends
+ util_store
+
out = @RM::Document.new
- @driver.add_includes out, []
+ @driver.add_extends out, [[[@cFooExt], @store1]]
+
+ expected = @RM::Document.new(
+ @RM::Rule.new(1),
+ @RM::Heading.new(1, "Extended by:"),
+ @RM::Paragraph.new("Ext (from #{@store1.friendly_path})"),
+ @RM::BlankLine.new,
+ @RM::Paragraph.new("Extend thingy"),
+ @RM::BlankLine.new)
+
+ assert_equal expected, out
+ end
+
+ def test_add_extension_modules_empty
+ out = @RM::Document.new
+
+ @driver.add_extension_modules out, 'Includes', []
assert_empty out
end
- def test_add_includes_many
+ def test_add_extension_modules_many
util_store
out = @RM::Document.new
@@ -134,23 +153,23 @@ class TestRDocRIDriver < MiniTest::Unit::TestCase
enum = RDoc::Include.new 'Enumerable', nil
@cFoo.add_include enum
- @driver.add_includes out, [[[@cFooInc, enum], @store]]
+ @driver.add_extension_modules out, 'Includes', [[[@cFooInc, enum], @store1]]
expected = @RM::Document.new(
@RM::Rule.new(1),
@RM::Heading.new(1, "Includes:"),
- @RM::Paragraph.new("(from #{@store.friendly_path})"),
+ @RM::Paragraph.new("(from #{@store1.friendly_path})"),
@RM::BlankLine.new,
@RM::Paragraph.new("Inc"),
@RM::BlankLine.new,
@RM::Paragraph.new("Include thingy"),
@RM::BlankLine.new,
- @RM::Verbatim.new("Enumerable\n"))
+ @RM::Verbatim.new("Enumerable", "\n"))
assert_equal expected, out
end
- def test_add_includes_many_no_doc
+ def test_add_extension_modules_many_no_doc
util_store
out = @RM::Document.new
@@ -159,29 +178,29 @@ class TestRDocRIDriver < MiniTest::Unit::TestCase
@cFoo.add_include enum
@cFooInc.instance_variable_set :@comment, ''
- @driver.add_includes out, [[[@cFooInc, enum], @store]]
+ @driver.add_extension_modules out, 'Includes', [[[@cFooInc, enum], @store1]]
expected = @RM::Document.new(
@RM::Rule.new(1),
@RM::Heading.new(1, "Includes:"),
- @RM::Paragraph.new("(from #{@store.friendly_path})"),
- @RM::Verbatim.new("Inc\n",
- "Enumerable\n"))
+ @RM::Paragraph.new("(from #{@store1.friendly_path})"),
+ @RM::Verbatim.new("Inc", "\n",
+ "Enumerable", "\n"))
assert_equal expected, out
end
- def test_add_includes_one
+ def test_add_extension_modules_one
util_store
out = @RM::Document.new
- @driver.add_includes out, [[[@cFooInc], @store]]
+ @driver.add_extension_modules out, 'Includes', [[[@cFooInc], @store1]]
expected = @RM::Document.new(
@RM::Rule.new(1),
@RM::Heading.new(1, "Includes:"),
- @RM::Paragraph.new("Inc (from #{@store.friendly_path})"),
+ @RM::Paragraph.new("Inc (from #{@store1.friendly_path})"),
@RM::BlankLine.new,
@RM::Paragraph.new("Include thingy"),
@RM::BlankLine.new)
@@ -189,6 +208,137 @@ class TestRDocRIDriver < MiniTest::Unit::TestCase
assert_equal expected, out
end
+ def test_add_includes
+ util_store
+
+ out = @RM::Document.new
+
+ @driver.add_includes out, [[[@cFooInc], @store1]]
+
+ expected = @RM::Document.new(
+ @RM::Rule.new(1),
+ @RM::Heading.new(1, "Includes:"),
+ @RM::Paragraph.new("Inc (from #{@store1.friendly_path})"),
+ @RM::BlankLine.new,
+ @RM::Paragraph.new("Include thingy"),
+ @RM::BlankLine.new)
+
+ assert_equal expected, out
+ end
+
+ def test_add_method
+ util_store
+
+ out = doc
+
+ @driver.add_method out, 'Foo::Bar#blah'
+
+ expected =
+ doc(
+ head(1, 'Foo::Bar#blah'),
+ blank_line,
+ para('(from ~/.rdoc)'),
+ head(3, 'Implementation from Bar'),
+ rule(1),
+ verb("blah(5) => 5\n",
+ "blah(6) => 6\n"),
+ rule(1),
+ blank_line,
+ blank_line)
+
+ assert_equal expected, out
+ end
+
+ def test_add_method_attribute
+ util_store
+
+ out = doc
+
+ @driver.add_method out, 'Foo::Bar#attr'
+
+ expected =
+ doc(
+ head(1, 'Foo::Bar#attr'),
+ blank_line,
+ para('(from ~/.rdoc)'),
+ rule(1),
+ blank_line,
+ blank_line)
+
+ assert_equal expected, out
+ end
+
+ def test_add_method_inherited
+ util_multi_store
+
+ out = doc
+
+ @driver.add_method out, 'Bar#inherit'
+
+ expected =
+ doc(
+ head(1, 'Bar#inherit'),
+ blank_line,
+ para('(from ~/.rdoc)'),
+ head(3, 'Implementation from Foo'),
+ rule(1),
+ blank_line,
+ blank_line)
+
+ assert_equal expected, out
+ end
+
+ def test_add_method_overriden
+ util_multi_store
+
+ out = doc
+
+ @driver.add_method out, 'Bar#override'
+
+ expected =
+ doc(
+ head(1, 'Bar#override'),
+ blank_line,
+ para("(from #{@store2.path})"),
+ rule(1),
+ blank_line,
+ para('must be displayed'),
+ blank_line,
+ blank_line)
+
+ assert_equal expected, out
+ end
+
+ def test_add_method_documentation
+ util_store
+
+ out = doc()
+
+ missing = RDoc::AnyMethod.new nil, 'missing'
+ @cFoo.add_method missing
+
+ @driver.add_method_documentation out, @cFoo
+
+ expected =
+ doc(
+ head(1, 'Foo#inherit'),
+ blank_line,
+ para('(from ~/.rdoc)'),
+ rule(1),
+ blank_line,
+ blank_line,
+ head(1, 'Foo#override'),
+ blank_line,
+ para('(from ~/.rdoc)'),
+ rule(1),
+ blank_line,
+ para('must not be displayed in Bar#override'),
+ blank_line,
+ blank_line)
+
+ assert_equal expected, out
+ end
+
def test_add_method_list
out = @RM::Document.new
@@ -241,35 +391,48 @@ class TestRDocRIDriver < MiniTest::Unit::TestCase
expected = {
'Ambiguous' => [@store1, @store2],
'Bar' => [@store2],
- 'Foo' => [@store1],
+ 'Ext' => [@store1],
+ 'Foo' => [@store1, @store2],
'Foo::Bar' => [@store1],
'Foo::Baz' => [@store1, @store2],
'Inc' => [@store1],
}
- assert_equal expected, @driver.classes
+ classes = @driver.classes
+
+ assert_equal expected.keys.sort, classes.keys.sort
+
+ expected.each do |klass, stores|
+ assert_equal stores, classes[klass].sort_by { |store| store.path },
+ "mismatch for #{klass}"
+ end
end
def test_class_document
util_store
- tl1 = RDoc::TopLevel.new 'one.rb'
- tl2 = RDoc::TopLevel.new 'two.rb'
+ tl1 = @store1.add_file 'one.rb'
+ tl2 = @store1.add_file 'two.rb'
@cFoo.add_comment 'one', tl1
@cFoo.add_comment 'two', tl2
- @store.save_class @cFoo
+
+ @store1.save_class @cFoo
found = [
- [@store, @store.load_class(@cFoo.full_name)]
+ [@store1, @store1.load_class(@cFoo.full_name)]
]
- out = @driver.class_document @cFoo.full_name, found, [], []
+ extends = [[[@cFooExt], @store1]]
+ includes = [[[@cFooInc], @store1]]
+
+ out = @driver.class_document @cFoo.full_name, found, [], includes, extends
expected = @RM::Document.new
@driver.add_class expected, 'Foo', []
- @driver.add_includes expected, []
- @driver.add_from expected, @store
+ @driver.add_includes expected, includes
+ @driver.add_extends expected, extends
+ @driver.add_from expected, @store1
expected << @RM::Rule.new(1)
doc = @RM::Document.new(@RM::Paragraph.new('one'))
@@ -375,6 +538,32 @@ class TestRDocRIDriver < MiniTest::Unit::TestCase
assert_match %r%^ attr_accessor attr%, out
assert_equal 1, out.scan(/-\n/).length
+
+ refute_match %r%Foo::Bar#blah%, out
+ end
+
+ def test_display_class_all
+ util_store
+
+ @driver.show_all = true
+
+ out, = capture_io do
+ @driver.display_class 'Foo::Bar'
+ end
+
+ assert_match %r%^= Foo::Bar%, out
+ assert_match %r%^\(from%, out
+
+ assert_match %r%^= Class methods:%, out
+ assert_match %r%^ new%, out
+ assert_match %r%^= Instance methods:%, out
+ assert_match %r%^ blah%, out
+ assert_match %r%^= Attributes:%, out
+ assert_match %r%^ attr_accessor attr%, out
+
+ assert_equal 6, out.scan(/-\n/).length
+
+ assert_match %r%Foo::Bar#blah%, out
end
def test_display_class_ambiguous
@@ -421,6 +610,14 @@ class TestRDocRIDriver < MiniTest::Unit::TestCase
assert_match %r%^= Inc$%, out
end
+ def test_display_class_page
+ out, = capture_io do
+ @driver.display_class 'ruby:README'
+ end
+
+ assert_empty out
+ end
+
def test_display_method
util_store
@@ -509,6 +706,68 @@ Foo::Bar#bother
assert_match %r%things.*stuff%, out
end
+ def test_display_page
+ util_store
+
+ out, = capture_io do
+ @driver.display_page 'home:README.rdoc'
+ end
+
+ assert_match %r%= README%, out
+ end
+
+ def test_display_page_add_extension
+ util_store
+
+ out, = capture_io do
+ @driver.display_page 'home:README'
+ end
+
+ assert_match %r%= README%, out
+ end
+
+ def test_display_page_ambiguous
+ util_store
+
+ other = @store1.add_file 'README.md'
+ other.parser = RDoc::Parser::Simple
+ other.comment =
+ doc(
+ head(1, 'README.md'),
+ para('This is the other README'))
+
+ @store1.save_page other
+
+ out, = capture_io do
+ @driver.display_page 'home:README'
+ end
+
+ assert_match %r%= README pages in ~/\.rdoc%, out
+ assert_match %r%README\.rdoc%, out
+ assert_match %r%README\.md%, out
+ end
+
+ def test_display_page_list
+ util_store
+
+ other = @store1.add_file 'OTHER.rdoc'
+ other.parser = RDoc::Parser::Simple
+ other.comment =
+ doc(
+ head(1, 'OTHER'),
+ para('This is OTHER'))
+
+ @store1.save_page other
+
+ out, = capture_io do
+ @driver.display_page_list @store1
+ end
+
+ assert_match %r%= Pages in ~/\.rdoc%, out
+ assert_match %r%README\.rdoc%, out
+ assert_match %r%OTHER\.rdoc%, out
+ end
+
def test_expand_class
util_store
@@ -532,6 +791,17 @@ Foo::Bar#bother
end
assert_equal 'Z', e.name
+
+ @driver.stores << RDoc::Store.new(nil, :system)
+
+ assert_equal 'ruby:README', @driver.expand_name('ruby:README')
+ assert_equal 'ruby:', @driver.expand_name('ruby:')
+
+ e = assert_raises RDoc::RI::Driver::NotFoundError do
+ @driver.expand_name 'nonexistent_gem:'
+ end
+
+ assert_equal 'nonexistent_gem', e.name
end
def test_find_methods
@@ -544,7 +814,7 @@ Foo::Bar#bother
end
expected = [
- [@store, 'Foo::Bar', 'Foo::Bar', :both, nil],
+ [@store1, 'Foo::Bar', 'Foo::Bar', :both, nil],
]
assert_equal expected, items
@@ -560,11 +830,12 @@ Foo::Bar#bother
end
expected = [
- [@store, 'Ambiguous', 'Ambiguous', :both, 'blah'],
- [@store, 'Foo', 'Foo', :both, 'blah'],
- [@store, 'Foo::Bar', 'Foo::Bar', :both, 'blah'],
- [@store, 'Foo::Baz', 'Foo::Baz', :both, 'blah'],
- [@store, 'Inc', 'Inc', :both, 'blah'],
+ [@store1, 'Ambiguous', 'Ambiguous', :both, 'blah'],
+ [@store1, 'Ext', 'Ext', :both, 'blah'],
+ [@store1, 'Foo', 'Foo', :both, 'blah'],
+ [@store1, 'Foo::Bar', 'Foo::Bar', :both, 'blah'],
+ [@store1, 'Foo::Baz', 'Foo::Baz', :both, 'blah'],
+ [@store1, 'Inc', 'Inc', :both, 'blah'],
]
assert_equal expected, items
@@ -596,6 +867,21 @@ Foo::Bar#bother
assert_equal found, sorted
end
+ def test_find_store
+ @driver.stores << RDoc::Store.new(nil, :system)
+ @driver.stores << RDoc::Store.new('doc/gem-1.0/ri', :gem)
+
+ assert_equal 'ruby', @driver.find_store('ruby')
+ assert_equal 'gem-1.0', @driver.find_store('gem-1.0')
+ assert_equal 'gem-1.0', @driver.find_store('gem')
+
+ e = assert_raises RDoc::RI::Driver::NotFoundError do
+ @driver.find_store 'nonexistent'
+ end
+
+ assert_equal 'nonexistent', e.name
+ end
+
def test_formatter
tty = Object.new
def tty.tty?() true; end
@@ -609,20 +895,21 @@ Foo::Bar#bother
driver.instance_variable_set :@paging, true
assert_instance_of @RM::ToBs, driver.formatter(StringIO.new)
-
- driver.instance_variable_set :@formatter_klass, @RM::ToHtml
-
- assert_instance_of @RM::ToHtml, driver.formatter(tty)
end
def test_in_path_eh
path = ENV['PATH']
- refute @driver.in_path?('/nonexistent')
+ test_path = File.expand_path '..', __FILE__
+
+ temp_dir do |dir|
+ nonexistent = File.join dir, 'nonexistent'
+ refute @driver.in_path?(nonexistent)
- ENV['PATH'] = File.expand_path '..', __FILE__
+ ENV['PATH'] = test_path
- assert @driver.in_path?(File.basename(__FILE__))
+ assert @driver.in_path?(File.basename(__FILE__))
+ end
ensure
ENV['PATH'] = path
end
@@ -658,7 +945,7 @@ Foo::Bar#bother
@driver.list_known_classes
end
- assert_equal "Ambiguous\nFoo\nFoo::Bar\nFoo::Baz\nInc\n", out
+ assert_equal "Ambiguous\nExt\nFoo\nFoo::Bar\nFoo::Baz\nInc\n", out
end
def test_list_known_classes_name
@@ -700,15 +987,15 @@ Foo::Bar#bother
index = RDoc::AnyMethod.new nil, '[]'
index.record_location @top_level
@cFoo.add_method index
- @store.save_method @cFoo, index
+ @store1.save_method @cFoo, index
c_index = RDoc::AnyMethod.new nil, '[]'
c_index.singleton = true
c_index.record_location @top_level
@cFoo.add_method c_index
- @store.save_method @cFoo, c_index
+ @store1.save_method @cFoo, c_index
- @store.save_cache
+ @store1.save_cache
assert_equal %w[Foo#[]], @driver.list_methods_matching('Foo#[]')
assert_equal %w[Foo::[]], @driver.list_methods_matching('Foo::[]')
@@ -717,7 +1004,7 @@ Foo::Bar#bother
def test_load_method
util_store
- method = @driver.load_method(@store, :instance_methods, 'Foo', '#',
+ method = @driver.load_method(@store1, :instance_methods, 'Foo', '#',
'inherit')
assert_equal @inherit, method
@@ -735,11 +1022,11 @@ Foo::Bar#bother
def test_load_methods_matching
util_store
- expected = [[@store, [@inherit]]]
+ expected = [[@store1, [@inherit]]]
assert_equal expected, @driver.load_methods_matching('Foo#inherit')
- expected = [[@store, [@blah]]]
+ expected = [[@store1, [@blah]]]
assert_equal expected, @driver.load_methods_matching('.blah')
@@ -768,6 +1055,18 @@ Foo::Bar#bother
refute @driver.paging?
end
+ def test_page_in_presence_of_child_status
+ skip 'this test hangs on travis-ci.org' if ENV['CI']
+ @driver.use_stdout = false
+
+ with_dummy_pager do
+ @driver.page do |io|
+ refute_equal $stdout, io
+ assert @driver.paging?
+ end
+ end
+ end
+
def test_page_stdout
@driver.use_stdout = true
@@ -798,6 +1097,20 @@ Foo::Bar#bother
assert_equal 'foo', meth, '::foo method'
end
+ def test_parse_name_page
+ klass, type, meth = @driver.parse_name 'ruby:README'
+
+ assert_equal 'ruby', klass, 'ruby project'
+ assert_equal ':', type, 'ruby type'
+ assert_equal 'README', meth, 'ruby page'
+
+ klass, type, meth = @driver.parse_name 'ruby:'
+
+ assert_equal 'ruby', klass, 'ruby project'
+ assert_equal ':', type, 'ruby type'
+ assert_equal nil, meth, 'ruby page'
+ end
+
def test_parse_name_single_class
klass, type, meth = @driver.parse_name 'Foo'
@@ -958,13 +1271,11 @@ Foo::Bar#bother
def util_multi_store
util_store
- @store1 = @store
-
- @top_level = RDoc::TopLevel.new 'file.rb'
-
@home_ri2 = "#{@home_ri}2"
@store2 = RDoc::RI::Store.new @home_ri2
+ @top_level = @store2.add_file 'file.rb'
+
# as if seen in a namespace like class Ambiguous::Other
@mAmbiguous = @top_level.add_module RDoc::NormalModule, 'Ambiguous'
@@ -980,29 +1291,31 @@ Foo::Bar#bother
@override.comment = 'must be displayed'
@override.record_location @top_level
- @store2.save_class @mAmbiguous
- @store2.save_class @cBar
- @store2.save_class @cFoo_Baz
-
- @store2.save_method @cBar, @override
- @store2.save_method @cBar, @baz
-
- @store2.save_cache
+ @store2.save
@driver.stores = [@store1, @store2]
-
- RDoc::RDoc.reset
end
def util_store
- @store = RDoc::RI::Store.new @home_ri
+ @store1 = RDoc::RI::Store.new @home_ri, :home
- @top_level = RDoc::TopLevel.new 'file.rb'
+ @top_level = @store1.add_file 'file.rb'
+
+ @readme = @store1.add_file 'README.rdoc'
+ @readme.parser = RDoc::Parser::Simple
+ @readme.comment =
+ doc(
+ head(1, 'README'),
+ para('This is a README'))
@cFoo = @top_level.add_class RDoc::NormalClass, 'Foo'
+ @mExt = @top_level.add_module RDoc::NormalModule, 'Ext'
@mInc = @top_level.add_module RDoc::NormalModule, 'Inc'
@cAmbiguous = @top_level.add_class RDoc::NormalClass, 'Ambiguous'
+ doc = @RM::Document.new @RM::Paragraph.new('Extend thingy')
+ @cFooExt = @cFoo.add_extend RDoc::Extend.new('Ext', doc)
+ @cFooExt.record_location @top_level
doc = @RM::Document.new @RM::Paragraph.new('Include thingy')
@cFooInc = @cFoo.add_include RDoc::Include.new('Inc', doc)
@cFooInc.record_location @top_level
@@ -1033,28 +1346,12 @@ Foo::Bar#bother
# overriden by Bar in multi_store
@overriden = @cFoo.add_method RDoc::AnyMethod.new(nil, 'override')
- @overriden.comment = 'must not be displayed'
+ @overriden.comment = 'must not be displayed in Bar#override'
@overriden.record_location @top_level
- @store.save_class @cFoo
- @store.save_class @cFoo_Bar
- @store.save_class @cFoo_Baz
- @store.save_class @mInc
- @store.save_class @cAmbiguous
-
- @store.save_method @cFoo_Bar, @blah
- @store.save_method @cFoo_Bar, @bother
- @store.save_method @cFoo_Bar, @new
- @store.save_method @cFoo_Bar, @attr
-
- @store.save_method @cFoo, @inherit
- @store.save_method @cFoo, @overriden
-
- @store.save_cache
-
- @driver.stores = [@store]
+ @store1.save
- RDoc::RDoc.reset
+ @driver.stores = [@store1]
end
end
diff --git a/test/rdoc/test_rdoc_ri_paths.rb b/test/rdoc/test_rdoc_ri_paths.rb
index e6f33d7d5e..0ef80345bb 100644
--- a/test/rdoc/test_rdoc_ri_paths.rb
+++ b/test/rdoc/test_rdoc_ri_paths.rb
@@ -1,42 +1,154 @@
-require 'rubygems'
-require 'minitest/autorun'
-require 'tmpdir'
-require 'fileutils'
-require 'rdoc/ri/paths'
+require 'rdoc/test_case'
-class TestRDocRIPaths < MiniTest::Unit::TestCase
+class TestRDocRIPaths < RDoc::TestCase
def setup
- RDoc::RI::Paths.instance_variable_set :@gemdirs, %w[/nonexistent/gemdir]
+ super
+
+ @orig_gem_path = Gem.path
+
+ @tempdir = File.join Dir.tmpdir, "test_rdoc_ri_paths_#{$$}"
+ Gem.use_paths @tempdir
+ Gem.ensure_gem_subdirectories @tempdir
+
+ specs = [
+ @rake_10 = Gem::Specification.new('rake', '10.0.1'),
+ @rdoc_4_0 = Gem::Specification.new('rdoc', '4.0'),
+ @rdoc_3_12 = Gem::Specification.new('rdoc', '3.12'),
+ @nodoc = Gem::Specification.new('nodoc', '1.0'),
+ ]
+
+ specs.each do |spec|
+ spec.loaded_from = File.join @tempdir, spec.spec_file
+
+ open spec.spec_file, 'w' do |file|
+ file.write spec.to_ruby_for_cache
+ end
+
+ FileUtils.mkdir_p File.join(spec.doc_dir, 'ri') unless
+ spec.name == 'nodoc'
+ end
+
+ Gem::Specification.reset
+ Gem::Specification.all = specs
end
def teardown
- RDoc::RI::Paths.instance_variable_set :@gemdirs, nil
+ super
+
+ Gem.use_paths(*@orig_gem_path)
+ Gem::Specification.reset
+ FileUtils.rm_rf @tempdir
+ end
+
+ def test_class_each
+ enum = RDoc::RI::Paths.each true, true, true, :all
+
+ path = enum.map { |dir,| dir }
+
+ assert_equal RDoc::RI::Paths.system_dir, path.shift
+ assert_equal RDoc::RI::Paths.site_dir, path.shift
+ assert_equal RDoc::RI::Paths.home_dir, path.shift
+ assert_equal File.join(@nodoc.doc_dir, 'ri'), path.shift
+ assert_equal File.join(@rake_10.doc_dir, 'ri'), path.shift
+ assert_equal File.join(@rdoc_4_0.doc_dir, 'ri'), path.shift
+ assert_equal File.join(@rdoc_3_12.doc_dir, 'ri'), path.shift
+ assert_empty path
+ end
+
+ def test_class_gemdirs_latest
+ Dir.chdir @tempdir do
+ gemdirs = RDoc::RI::Paths.gemdirs :latest
+
+ expected = [
+ File.join(@rake_10.doc_dir, 'ri'),
+ File.join(@rdoc_4_0.doc_dir, 'ri'),
+ ]
+
+ assert_equal expected, gemdirs
+ end
+ end
+
+ def test_class_gemdirs_legacy
+ Dir.chdir @tempdir do
+ gemdirs = RDoc::RI::Paths.gemdirs true
+
+ expected = [
+ File.join(@rake_10.doc_dir, 'ri'),
+ File.join(@rdoc_4_0.doc_dir, 'ri'),
+ ]
+
+ assert_equal expected, gemdirs
+ end
+ end
+
+ def test_class_gemdirs_all
+ Dir.chdir @tempdir do
+ gemdirs = RDoc::RI::Paths.gemdirs :all
+
+ expected = [
+ File.join(@nodoc.doc_dir, 'ri'),
+ File.join(@rake_10.doc_dir, 'ri'),
+ File.join(@rdoc_4_0.doc_dir, 'ri'),
+ File.join(@rdoc_3_12.doc_dir, 'ri'),
+ ]
+
+ assert_equal expected, gemdirs
+ end
+ end
+
+ def test_class_gem_dir
+ dir = RDoc::RI::Paths.gem_dir 'rake', '10.0.1'
+
+ expected = File.join @rake_10.doc_dir, 'ri'
+
+ assert_equal expected, dir
+ end
+
+ def test_class_home_dir
+ dir = RDoc::RI::Paths.home_dir
+
+ assert_equal RDoc::RI::Paths::HOMEDIR, dir
end
def test_class_path_nonexistent
- path = RDoc::RI::Paths.path true, true, true, true, '/nonexistent'
+ temp_dir do |dir|
+ nonexistent = File.join dir, 'nonexistent'
+ dir = RDoc::RI::Paths.path true, true, true, true, nonexistent
- refute_includes path, '/nonexistent'
+ refute_includes dir, nonexistent
+ end
end
def test_class_raw_path
path = RDoc::RI::Paths.raw_path true, true, true, true
- assert_equal RDoc::RI::Paths::SYSDIR, path.shift
- assert_equal RDoc::RI::Paths::SITEDIR, path.shift
- assert_equal RDoc::RI::Paths::HOMEDIR, path.shift
- assert_equal '/nonexistent/gemdir', path.shift
+ assert_equal RDoc::RI::Paths.system_dir, path.shift
+ assert_equal RDoc::RI::Paths.site_dir, path.shift
+ assert_equal RDoc::RI::Paths.home_dir, path.shift
+ assert_equal File.join(@rake_10.doc_dir, 'ri'), path.shift
end
def test_class_raw_path_extra_dirs
path = RDoc::RI::Paths.raw_path true, true, true, true, '/nonexistent'
- assert_equal '/nonexistent', path.shift
- assert_equal RDoc::RI::Paths::SYSDIR, path.shift
- assert_equal RDoc::RI::Paths::SITEDIR, path.shift
- assert_equal RDoc::RI::Paths::HOMEDIR, path.shift
- assert_equal '/nonexistent/gemdir', path.shift
+ assert_equal '/nonexistent', path.shift
+ assert_equal RDoc::RI::Paths.system_dir, path.shift
+ assert_equal RDoc::RI::Paths.site_dir, path.shift
+ assert_equal RDoc::RI::Paths.home_dir, path.shift
+ assert_equal File.join(@rake_10.doc_dir, 'ri'), path.shift
+ end
+
+ def test_class_site_dir
+ dir = RDoc::RI::Paths.site_dir
+
+ assert_equal File.join(RDoc::RI::Paths::BASE, 'site'), dir
+ end
+
+ def test_class_system_dir
+ dir = RDoc::RI::Paths.system_dir
+
+ assert_equal File.join(RDoc::RI::Paths::BASE, 'system'), dir
end
end
diff --git a/test/rdoc/test_rdoc_ruby_lex.rb b/test/rdoc/test_rdoc_ruby_lex.rb
index 4398f4119f..1dc11e95a3 100644
--- a/test/rdoc/test_rdoc_ruby_lex.rb
+++ b/test/rdoc/test_rdoc_ruby_lex.rb
@@ -1,9 +1,219 @@
-require 'rubygems'
-require 'minitest/autorun'
-require 'rdoc/rdoc'
-require 'rdoc/ruby_lex'
+require 'rdoc/test_case'
+
+class TestRDocRubyLex < RDoc::TestCase
+
+ def setup
+ @TK = RDoc::RubyToken
+ end
+
+ def mu_pp obj
+ s = ''
+ s = PP.pp obj, s
+ s = s.force_encoding(Encoding.default_external) if defined? Encoding
+ s.chomp
+ end
+
+ def test_class_tokenize
+ tokens = RDoc::RubyLex.tokenize "def x() end", nil
+
+ expected = [
+ @TK::TkDEF .new( 0, 1, 0, "def"),
+ @TK::TkSPACE .new( 3, 1, 3, " "),
+ @TK::TkIDENTIFIER.new( 4, 1, 4, "x"),
+ @TK::TkLPAREN .new( 5, 1, 5, "("),
+ @TK::TkRPAREN .new( 6, 1, 6, ")"),
+ @TK::TkSPACE .new( 7, 1, 7, " "),
+ @TK::TkEND .new( 8, 1, 8, "end"),
+ @TK::TkNL .new(11, 1, 11, "\n"),
+ ]
+
+ assert_equal expected, tokens
+ end
+
+ def test_class_tokenize___END__
+ tokens = RDoc::RubyLex.tokenize '__END__', nil
+
+ expected = [
+ @TK::TkEND_OF_SCRIPT.new(0, 1, 0, '__END__'),
+ @TK::TkNL .new(7, 1, 7, "\n"),
+ ]
+
+ assert_equal expected, tokens
+ end
+
+ def test_class_tokenize_character_literal
+ tokens = RDoc::RubyLex.tokenize "?\\", nil
+
+ expected = [
+ @TK::TkSTRING.new( 0, 1, 0, "\\"),
+ @TK::TkNL .new( 2, 1, 2, "\n"),
+ ]
+
+ assert_equal expected, tokens
+ end
+
+ def test_class_tokenize_def_heredoc
+ tokens = RDoc::RubyLex.tokenize <<-'RUBY', nil
+def x
+ <<E
+Line 1
+Line 2
+E
+end
+ RUBY
+
+ expected = [
+ @TK::TkDEF .new( 0, 1, 0, 'def'),
+ @TK::TkSPACE .new( 3, 1, 3, ' '),
+ @TK::TkIDENTIFIER.new( 4, 1, 4, 'x'),
+ @TK::TkNL .new( 5, 1, 5, "\n"),
+ @TK::TkSPACE .new( 6, 2, 0, ' '),
+ @TK::TkSTRING .new( 8, 2, 2, %Q{"Line 1\nLine 2\n"}),
+ @TK::TkNL .new(27, 5, 28, "\n"),
+ @TK::TkEND .new(28, 6, 0, 'end'),
+ @TK::TkNL .new(31, 6, 28, "\n"),
+ ]
+
+ assert_equal expected, tokens
+ end
+
+ def test_class_tokenize_hash_symbol
+ tokens = RDoc::RubyLex.tokenize '{ class:"foo" }', nil
+
+ expected = [
+ @TK::TkLBRACE .new( 0, 1, 0, '{'),
+ @TK::TkSPACE .new( 1, 1, 1, ' '),
+ @TK::TkIDENTIFIER.new( 2, 1, 2, 'class'),
+ @TK::TkSYMBEG .new( 7, 1, 7, ':'),
+ @TK::TkSTRING .new( 8, 1, 8, '"foo"'),
+ @TK::TkSPACE .new(13, 1, 13, ' '),
+ @TK::TkRBRACE .new(14, 1, 14, '}'),
+ @TK::TkNL .new(15, 1, 15, "\n"),
+ ]
+
+ assert_equal expected, tokens
+ end
+
+ def test_class_tokenize_heredoc_indent
+ tokens = RDoc::RubyLex.tokenize <<-'RUBY', nil
+string = <<-STRING
+Line 1
+Line 2
+STRING
+ RUBY
+
+ expected = [
+ @TK::TkIDENTIFIER.new( 0, 1, 0, 'string'),
+ @TK::TkSPACE .new( 6, 1, 6, ' '),
+ @TK::TkASSIGN .new( 7, 1, 7, '='),
+ @TK::TkSPACE .new( 8, 1, 8, ' '),
+ @TK::TkSTRING .new( 9, 1, 9, %Q{"Line 1\nLine 2\n"}),
+ @TK::TkNL .new(39, 4, 40, "\n"),
+ ]
+
+ assert_equal expected, tokens
+ end
+
+ def test_class_tokenize_heredoc_percent_N
+ tokens = RDoc::RubyLex.tokenize <<-'RUBY', nil
+a b <<-U
+%N
+U
+ RUBY
+
+ expected = [
+ @TK::TkIDENTIFIER.new( 0, 1, 0, 'a'),
+ @TK::TkSPACE .new( 1, 1, 1, ' '),
+ @TK::TkIDENTIFIER.new( 2, 1, 2, 'b'),
+ @TK::TkSPACE .new( 3, 1, 3, ' '),
+ @TK::TkSTRING .new( 4, 1, 4, %Q{"%N\n"}),
+ @TK::TkNL .new(13, 3, 14, "\n"),
+ ]
+
+ assert_equal expected, tokens
+ end
+
+ def test_class_tokenize_percent_1
+ tokens = RDoc::RubyLex.tokenize 'v%10==10', nil
+
+ expected = [
+ @TK::TkIDENTIFIER.new(0, 1, 0, 'v'),
+ @TK::TkMOD.new( 1, 1, 1, '%'),
+ @TK::TkINTEGER.new( 2, 1, 2, '10'),
+ @TK::TkEQ.new( 4, 1, 4, '=='),
+ @TK::TkINTEGER.new( 6, 1, 6, '10'),
+ @TK::TkNL.new( 8, 1, 8, "\n"),
+ ]
+
+ assert_equal expected, tokens
+ end
+
+ def test_class_tokenize_percent_r
+ tokens = RDoc::RubyLex.tokenize '%r[hi]', nil
+
+ expected = [
+ @TK::TkREGEXP.new( 0, 1, 0, '%r[hi]'),
+ @TK::TkNL .new( 6, 1, 6, "\n"),
+ ]
+
+ assert_equal expected, tokens
+ end
+
+ def test_class_tokenize_percent_w
+ tokens = RDoc::RubyLex.tokenize '%w[hi]', nil
+
+ expected = [
+ @TK::TkDSTRING.new( 0, 1, 0, '%w[hi]'),
+ @TK::TkNL .new( 6, 1, 6, "\n"),
+ ]
+
+ assert_equal expected, tokens
+ end
+
+ def test_class_tokenize_regexp
+ tokens = RDoc::RubyLex.tokenize "/hay/", nil
+
+ expected = [
+ @TK::TkREGEXP.new( 0, 1, 0, "/hay/"),
+ @TK::TkNL .new( 5, 1, 5, "\n"),
+ ]
+
+ assert_equal expected, tokens
+ end
+
+ def test_class_tokenize_regexp_backref
+ tokens = RDoc::RubyLex.tokenize "/[csh](..) [csh]\\1 in/", nil
+
+ expected = [
+ @TK::TkREGEXP.new( 0, 1, 0, "/[csh](..) [csh]\\1 in/"),
+ @TK::TkNL .new(22, 1, 22, "\n"),
+ ]
+
+ assert_equal expected, tokens
+ end
+
+ def test_class_tokenize_regexp_escape
+ tokens = RDoc::RubyLex.tokenize "/\\//", nil
+
+ expected = [
+ @TK::TkREGEXP.new( 0, 1, 0, "/\\//"),
+ @TK::TkNL .new( 4, 1, 4, "\n"),
+ ]
+
+ assert_equal expected, tokens
+ end
+
+ def test_class_tokenize_string
+ tokens = RDoc::RubyLex.tokenize "'hi'", nil
+
+ expected = [
+ @TK::TkSTRING.new( 0, 1, 0, "'hi'"),
+ @TK::TkNL .new( 4, 1, 4, "\n"),
+ ]
+
+ assert_equal expected, tokens
+ end
-class TestRubyLex < MiniTest::Unit::TestCase
def test_unary_minus
ruby_lex = RDoc::RubyLex.new("-1", nil)
assert_equal("-1", ruby_lex.token.value)
@@ -20,4 +230,6 @@ class TestRubyLex < MiniTest::Unit::TestCase
2.times { ruby_lex.token } # skip "0" and "+"
assert_equal("-0.1", ruby_lex.token.value)
end
+
end
+
diff --git a/test/rdoc/test_rdoc_ruby_token.rb b/test/rdoc/test_rdoc_ruby_token.rb
new file mode 100644
index 0000000000..ed8c8275ba
--- /dev/null
+++ b/test/rdoc/test_rdoc_ruby_token.rb
@@ -0,0 +1,19 @@
+require 'rdoc/test_case'
+
+class TestRDocRubyToken < RDoc::TestCase
+
+ def test_Token_text
+ token = RDoc::RubyToken::Token.new 0, 0, 0, 'text'
+
+ assert_equal 'text', token.text
+ end
+
+ def test_TkOp_name
+ token = RDoc::RubyToken::TkOp.new 0, 0, 0, '&'
+
+ assert_equal '&', token.text
+ assert_equal '&', token.name
+ end
+
+end
+
diff --git a/test/rdoc/test_rdoc_rubygems_hook.rb b/test/rdoc/test_rdoc_rubygems_hook.rb
index af6ffddf4a..fc2231965f 100644
--- a/test/rdoc/test_rdoc_rubygems_hook.rb
+++ b/test/rdoc/test_rdoc_rubygems_hook.rb
@@ -1,5 +1,5 @@
-require 'rubygems/test_case'
require 'rubygems'
+require 'rubygems/test_case'
require 'rdoc/rubygems_hook'
class TestRDocRubygemsHook < Gem::TestCase
@@ -7,6 +7,9 @@ class TestRDocRubygemsHook < Gem::TestCase
def setup
super
+ skip 'requires RubyGems 1.9+' unless
+ Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.9')
+
@a = quick_spec 'a'
@rdoc = RDoc::RubygemsHook.new @a
@@ -195,5 +198,5 @@ class TestRDocRubygemsHook < Gem::TestCase
FileUtils.chmod 0755, @a.doc_dir
end
-end if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.9')
+end
diff --git a/test/rdoc/test_rdoc_servlet.rb b/test/rdoc/test_rdoc_servlet.rb
new file mode 100644
index 0000000000..0234d33077
--- /dev/null
+++ b/test/rdoc/test_rdoc_servlet.rb
@@ -0,0 +1,408 @@
+require 'rdoc/test_case'
+class TestRDocServlet < RDoc::TestCase
+
+ def setup
+ super
+
+ @orig_gem_path = Gem.path
+
+ @tempdir = File.join Dir.tmpdir, "test_rdoc_servlet_#{$$}"
+ Gem.use_paths @tempdir
+ Gem.ensure_gem_subdirectories @tempdir
+
+ @spec = Gem::Specification.new 'spec', '1.0'
+ @spec.loaded_from = File.join @tempdir, @spec.spec_file
+
+ Gem::Specification.reset
+ Gem::Specification.all = [@spec]
+
+ server = {}
+ def server.mount(*) end
+
+ @stores = {}
+ @cache = Hash.new { |hash, store| hash[store] = {} }
+
+ @s = RDoc::Servlet.new server, @stores, @cache
+
+ @req = WEBrick::HTTPRequest.new :Logger => nil
+ @res = WEBrick::HTTPResponse.new :HTTPVersion => '1.0'
+
+ def @req.path= path
+ instance_variable_set :@path, path
+ end
+
+ @req.instance_variable_set :@header, Hash.new { |h, k| h[k] = [] }
+
+ @base = File.join @tempdir, 'base'
+ @system_dir = File.join @tempdir, 'base', 'system'
+
+ @orig_base = RDoc::RI::Paths::BASE
+ RDoc::RI::Paths::BASE.replace @base
+ @orig_ri_path_homedir = RDoc::RI::Paths::HOMEDIR
+ RDoc::RI::Paths::HOMEDIR.replace File.join @tempdir, 'home'
+
+ RDoc::RI::Paths.instance_variable_set \
+ :@gemdirs, %w[/nonexistent/gems/example-1.0/ri]
+ end
+
+ def teardown
+ super
+
+ Gem.use_paths(*@orig_gem_path)
+ Gem::Specification.reset
+
+ FileUtils.rm_rf @tempdir
+
+ RDoc::RI::Paths::BASE.replace @orig_base
+ RDoc::RI::Paths::HOMEDIR.replace @orig_ri_path_homedir
+ RDoc::RI::Paths.instance_variable_set :@gemdirs, nil
+ end
+
+ def test_asset
+ temp_dir do
+ now = Time.now
+
+ open 'rdoc.css', 'w' do |io| io.write 'h1 { color: red }' end
+ File.utime now, now, 'rdoc.css'
+
+ @s.asset_dirs[:darkfish] = '.'
+
+ @req.path = 'rdoc.css'
+
+ @s.asset :darkfish, @req, @res
+
+ assert_equal 'h1 { color: red }', @res.body
+ assert_equal 'text/css', @res.content_type
+ assert_equal now.httpdate, @res['last-modified']
+ end
+ end
+
+ def test_do_GET
+ touch_system_cache_path
+
+ @req.path = '/ruby/Missing.html'
+
+ @s.do_GET @req, @res
+
+ assert_equal 404, @res.status
+ end
+
+ def test_do_GET_asset_darkfish
+ temp_dir do
+ FileUtils.touch 'rdoc.css'
+
+ @s.asset_dirs[:darkfish] = '.'
+
+ @req.path = '/rdoc.css'
+
+ @s.do_GET @req, @res
+
+ assert_equal 'text/css', @res.content_type
+ end
+ end
+
+ def test_do_GET_asset_json_index
+ temp_dir do
+ FileUtils.mkdir 'js'
+ FileUtils.touch 'js/navigation.js'
+
+ @s.asset_dirs[:json_index] = '.'
+
+ @req.path = '/js/navigation.js'
+
+ @s.do_GET @req, @res
+
+ assert_equal 'application/javascript', @res.content_type
+ end
+ end
+
+ def test_do_GET_error
+ touch_system_cache_path
+
+ def @req.path() raise 'no' end
+
+ @s.do_GET @req, @res
+
+ assert_equal 500, @res.status
+ end
+
+ def test_do_GET_not_modified
+ touch_system_cache_path
+ @req.header['if-modified-since'] = [(Time.now + 10).httpdate]
+ @req.path = '/ruby/Missing.html'
+
+ assert_raises WEBrick::HTTPStatus::NotModified do
+ @s.do_GET @req, @res
+ end
+ end
+
+ def test_do_GET_root
+ touch_system_cache_path
+
+ @req.path = '/'
+
+ @s.do_GET @req, @res
+
+ assert_equal 'text/html', @res.content_type
+ assert_match %r%<title>Local RDoc Documentation</title>%, @res.body
+ end
+
+ def test_do_GET_root_search
+ touch_system_cache_path
+
+ @req.path = '/js/search_index.js'
+
+ @s.do_GET @req, @res
+
+ assert_equal 'application/javascript', @res.content_type
+ end
+
+ def test_documentation_page_class
+ store = RDoc::Store.new
+
+ generator = @s.generator_for store
+
+ file = store.add_file 'file.rb'
+ klass = file.add_class RDoc::NormalClass, 'Klass'
+ klass.add_class RDoc::NormalClass, 'Sub'
+
+ @s.documentation_page store, generator, 'Klass::Sub.html', @req, @res
+
+ assert_match %r%<title>class Klass::Sub - </title>%, @res.body
+ assert_match %r%<body id="top" class="class">%, @res.body
+ end
+
+ def test_documentation_page_not_found
+ store = RDoc::Store.new
+
+ generator = @s.generator_for store
+
+ @req.path = '/ruby/Missing.html'
+
+ @s.documentation_page store, generator, 'Missing.html', @req, @res
+
+ assert_equal 404, @res.status
+ end
+
+ def test_documentation_page_page
+ store = RDoc::Store.new
+
+ generator = @s.generator_for store
+
+ readme = store.add_file 'README.rdoc'
+ readme.parser = RDoc::Parser::Simple
+
+ @s.documentation_page store, generator, 'README_rdoc.html', @req, @res
+
+ assert_match %r%<title>README - </title>%, @res.body
+ assert_match %r%<body class="file">%, @res.body
+ end
+
+ def test_documentation_source
+ store, path = @s.documentation_source '/ruby/Object.html'
+
+ assert_equal @system_dir, store.path
+
+ assert_equal 'Object.html', path
+ end
+
+ def test_documentation_source_cached
+ cached_store = RDoc::Store.new
+
+ @stores['ruby'] = cached_store
+
+ store, path = @s.documentation_source '/ruby/Object.html'
+
+ assert_same cached_store, store
+
+ assert_equal 'Object.html', path
+ end
+
+ def test_error
+ e = RuntimeError.new 'foo'
+ e.set_backtrace caller
+
+ @s.error e, @req, @res
+
+ assert_equal 'text/html', @res.content_type
+ assert_equal 500, @res.status
+ assert_match %r%<title>Error%, @res.body
+ end
+
+ def test_generator_for
+ store = RDoc::Store.new
+ store.main = 'MAIN_PAGE.rdoc'
+ store.title = 'Title'
+
+ generator = @s.generator_for store
+
+ refute generator.file_output
+
+ assert_equal '..', generator.asset_rel_path
+
+ assert_equal 'MAIN_PAGE.rdoc', @s.options.main_page
+ assert_equal 'Title', @s.options.title
+
+ assert_kind_of RDoc::RDoc, store.rdoc
+ assert_same generator, store.rdoc.generator
+ end
+
+ def test_if_modified_since
+ temp_dir do
+ now = Time.now
+ File.utime now, now, '.'
+
+ @s.if_modified_since @req, @res, '.'
+
+ assert_equal now.to_i, Time.parse(@res['last-modified']).to_i
+ end
+ end
+
+ def test_if_modified_since_not_modified
+ temp_dir do
+ now = Time.now
+ File.utime now, now, '.'
+
+ @req.header['if-modified-since'] = [(now + 10).httpdate]
+
+ assert_raises WEBrick::HTTPStatus::NotModified do
+ @s.if_modified_since @req, @res, '.'
+ end
+
+ assert_equal now.to_i, Time.parse(@res['last-modified']).to_i
+ end
+ end
+
+ def test_installed_docs
+ touch_system_cache_path
+
+ expected = [
+ ['Ruby Documentation', 'ruby/', true, :system,
+ @system_dir],
+ ['Site Documentation', 'site/', false, :site,
+ File.join(@base, 'site')],
+ ['Home Documentation', 'home/', false, :home,
+ RDoc::RI::Paths::HOMEDIR],
+ ['spec-1.0', 'spec-1.0/', false, :gem,
+ File.join(@spec.doc_dir, 'ri')],
+ ]
+
+ assert_equal expected, @s.installed_docs
+ end
+
+ def test_not_found
+ generator = @s.generator_for RDoc::Store.new
+
+ @req.path = '/ruby/Missing.html'
+
+ @s.not_found generator, @req, @res
+
+ assert_equal 404, @res.status
+ assert_match %r%<title>Not Found</title>%, @res.body
+ assert_match %r%<kbd>/ruby/Missing\.html</kbd>%, @res.body
+ end
+
+ def test_ri_paths
+ paths = @s.ri_paths
+
+ expected = [
+ [@system_dir, :system],
+ [File.join(@base, 'site'), :site],
+ [RDoc::RI::Paths::HOMEDIR, :home],
+ [File.join(@spec.doc_dir, 'ri'), :gem],
+ ]
+
+ assert_equal expected, paths.to_a
+ end
+
+ def test_root
+ @s.root @req, @res
+
+ assert_equal 'text/html', @res.content_type
+ assert_match %r%<title>Local RDoc Documentation</title>%, @res.body
+ end
+
+ def test_root_search
+ touch_system_cache_path
+
+ @s.root_search @req, @res
+
+ assert_equal 'application/javascript', @res.content_type
+
+ @res.body =~ /\{.*\}/
+
+ index = JSON.parse $&
+
+ expected = {
+ 'index' => {
+ 'searchIndex' => %w[
+ Ruby\ Documentation
+ ],
+ 'longSearchIndex' => %w[
+ Ruby\ Documentation
+ ],
+ 'info' => [
+ ['Ruby Documentation', '', @system_dir, '',
+ 'Documentation for the Ruby standard library'],
+ ],
+ }
+ }
+
+ assert_equal expected, index
+ end
+
+ def test_show_documentation_index
+ touch_system_cache_path
+
+ @req.path = '/ruby'
+
+ @s.show_documentation @req, @res
+
+ assert_equal 'text/html', @res.content_type
+ assert_match %r%<title>Standard Library Documentation%, @res.body
+ end
+
+ def test_show_documentation_table_of_contents
+ touch_system_cache_path
+
+ @req.path = '/ruby/table_of_contents.html'
+
+ @s.show_documentation @req, @res
+
+ assert_equal 'text/html', @res.content_type
+ assert_match %r%<title>Table of Contents - Standard Library Documentation%,
+ @res.body
+ end
+
+ def test_show_documentation_page
+ touch_system_cache_path
+
+ @req.path = '/ruby/Missing.html'
+
+ @s.show_documentation @req, @res
+
+ assert_equal 404, @res.status
+ end
+
+ def test_show_documentation_search_index
+ touch_system_cache_path
+
+ @req.path = '/ruby/js/search_index.js'
+
+ @s.show_documentation @req, @res
+
+ assert_equal 'application/javascript', @res.content_type
+ assert_match %r%\Avar search_data =%, @res.body
+ end
+
+ def touch_system_cache_path
+ store = RDoc::Store.new @system_dir
+ store.title = 'Standard Library Documentation'
+
+ FileUtils.mkdir_p File.dirname store.cache_path
+
+ store.save
+ end
+
+end
+
diff --git a/test/rdoc/test_rdoc_stats.rb b/test/rdoc/test_rdoc_stats.rb
index 0bf08334da..5073e53b7e 100644
--- a/test/rdoc/test_rdoc_stats.rb
+++ b/test/rdoc/test_rdoc_stats.rb
@@ -1,29 +1,46 @@
-require 'rubygems'
-require 'minitest/autorun'
-require 'rdoc/stats'
-require 'rdoc/code_objects'
-require 'rdoc/markup'
-require 'rdoc/parser'
+require 'rdoc/test_case'
-class TestRDocStats < MiniTest::Unit::TestCase
+class TestRDocStats < RDoc::TestCase
def setup
- RDoc::TopLevel.reset
+ super
- @s = RDoc::Stats.new 0
+ @s = RDoc::Stats.new @store, 0
+
+ @tl = @store.add_file 'file.rb'
+ @tl.parser = RDoc::Parser::Ruby
+ end
+
+ def test_doc_stats
+ c = RDoc::CodeObject.new
+
+ assert_equal [1, 1], @s.doc_stats([c])
+ end
+
+ def test_doc_stats_documented
+ c = RDoc::CodeObject.new
+ c.comment = comment 'x'
+
+ assert_equal [1, 0], @s.doc_stats([c])
+ end
+
+ def test_doc_stats_display_eh
+ c = RDoc::CodeObject.new
+ c.ignore
+
+ assert_equal [0, 0], @s.doc_stats([c])
end
def test_report_attr
- tl = RDoc::TopLevel.new 'file.rb'
- c = tl.add_class RDoc::NormalClass, 'C'
- c.record_location tl
- c.add_comment 'C', tl
+ c = @tl.add_class RDoc::NormalClass, 'C'
+ c.record_location @tl
+ c.add_comment 'C', @tl
a = RDoc::Attr.new nil, 'a', 'RW', nil
- a.record_location tl
+ a.record_location @tl
c.add_attribute a
- RDoc::TopLevel.complete :public
+ @store.complete :public
report = @s.report
@@ -40,33 +57,46 @@ end
end
def test_report_attr_documented
- tl = RDoc::TopLevel.new 'file.rb'
- c = tl.add_class RDoc::NormalClass, 'C'
- c.record_location tl
- c.add_comment 'C', tl
+ c = @tl.add_class RDoc::NormalClass, 'C'
+ c.record_location @tl
+ c.add_comment 'C', @tl
a = RDoc::Attr.new nil, 'a', 'RW', 'a'
- a.record_location tl
+ a.record_location @tl
c.add_attribute a
- RDoc::TopLevel.complete :public
+ @store.complete :public
report = @s.report
assert_equal @s.great_job, report
end
+ def test_report_attr_line
+ c = @tl.add_class RDoc::NormalClass, 'C'
+ c.record_location @tl
+ c.add_comment 'C', @tl
+
+ a = RDoc::Attr.new nil, 'a', 'RW', nil
+ a.record_location @tl
+ a.line = 3
+ c.add_attribute a
+
+ @store.complete :public
+
+ assert_match '# in file file.rb:3', @s.report
+ end
+
def test_report_constant
- tl = RDoc::TopLevel.new 'file.rb'
- m = tl.add_module RDoc::NormalModule, 'M'
- m.record_location tl
- m.add_comment 'M', tl
+ m = @tl.add_module RDoc::NormalModule, 'M'
+ m.record_location @tl
+ m.add_comment 'M', @tl
c = RDoc::Constant.new 'C', nil, nil
- c.record_location tl
+ c.record_location @tl
m.add_constant c
- RDoc::TopLevel.complete :public
+ @store.complete :public
report = @s.report
@@ -84,18 +114,17 @@ end
end
def test_report_constant_alias
- tl = RDoc::TopLevel.new 'file.rb'
- mod = tl.add_module RDoc::NormalModule, 'M'
+ mod = @tl.add_module RDoc::NormalModule, 'M'
- c = tl.add_class RDoc::NormalClass, 'C'
+ c = @tl.add_class RDoc::NormalClass, 'C'
mod.add_constant c
ca = RDoc::Constant.new 'CA', nil, nil
ca.is_alias_for = c
- tl.add_constant ca
+ @tl.add_constant ca
- RDoc::TopLevel.complete :public
+ @store.complete :public
report = @s.report
@@ -105,33 +134,46 @@ end
end
def test_report_constant_documented
- tl = RDoc::TopLevel.new 'file.rb'
- m = tl.add_module RDoc::NormalModule, 'M'
- m.record_location tl
+ m = @tl.add_module RDoc::NormalModule, 'M'
+ m.record_location @tl
m.comment = 'M'
c = RDoc::Constant.new 'C', nil, 'C'
- c.record_location tl
+ c.record_location @tl
m.add_constant c
- RDoc::TopLevel.complete :public
+ @store.complete :public
report = @s.report
assert_equal @s.great_job, report
end
+ def test_report_constant_line
+ m = @tl.add_module RDoc::NormalModule, 'M'
+ m.record_location @tl
+ m.add_comment 'M', @tl
+
+ c = RDoc::Constant.new 'C', nil, nil
+ c.record_location @tl
+ c.line = 5
+ m.add_constant c
+
+ @store.complete :public
+
+ assert_match '# in file file.rb:5', @s.report
+ end
+
def test_report_class
- tl = RDoc::TopLevel.new 'file.rb'
- c = tl.add_class RDoc::NormalClass, 'C'
- c.record_location tl
+ c = @tl.add_class RDoc::NormalClass, 'C'
+ c.record_location @tl
m = RDoc::AnyMethod.new nil, 'm'
- m.record_location tl
+ m.record_location @tl
c.add_method m
m.comment = 'm'
- RDoc::TopLevel.complete :public
+ @store.complete :public
report = @s.report
@@ -148,18 +190,31 @@ end
assert_equal expected, report
end
+ def test_report_skip_object
+ c = @tl.add_class RDoc::NormalClass, 'Object'
+ c.record_location @tl
+
+ m = RDoc::AnyMethod.new nil, 'm'
+ m.record_location @tl
+ c.add_method m
+ m.comment = 'm'
+
+ @store.complete :public
+
+ refute_match %r%^class Object$%, @s.report
+ end
+
def test_report_class_documented
- tl = RDoc::TopLevel.new 'file.rb'
- c = tl.add_class RDoc::NormalClass, 'C'
- c.record_location tl
- c.add_comment 'C', tl
+ c = @tl.add_class RDoc::NormalClass, 'C'
+ c.record_location @tl
+ c.add_comment 'C', @tl
m = RDoc::AnyMethod.new nil, 'm'
- m.record_location tl
+ m.record_location @tl
c.add_method m
m.comment = 'm'
- RDoc::TopLevel.complete :public
+ @store.complete :public
report = @s.report
@@ -167,25 +222,24 @@ end
end
def test_report_class_documented_level_1
- tl = RDoc::TopLevel.new 'file.rb'
- c1 = tl.add_class RDoc::NormalClass, 'C1'
- c1.record_location tl
- c1.add_comment 'C1', tl
+ c1 = @tl.add_class RDoc::NormalClass, 'C1'
+ c1.record_location @tl
+ c1.add_comment 'C1', @tl
m1 = RDoc::AnyMethod.new nil, 'm1'
- m1.record_location tl
+ m1.record_location @tl
c1.add_method m1
m1.comment = 'm1'
- c2 = tl.add_class RDoc::NormalClass, 'C2'
- c2.record_location tl
+ c2 = @tl.add_class RDoc::NormalClass, 'C2'
+ c2.record_location @tl
m2 = RDoc::AnyMethod.new nil, 'm2'
- m2.record_location tl
+ m2.record_location @tl
c2.add_method m2
m2.comment = 'm2'
- RDoc::TopLevel.complete :public
+ @store.complete :public
@s.coverage_level = 1
@@ -206,10 +260,9 @@ end
end
def test_report_class_empty
- tl = RDoc::TopLevel.new 'file.rb'
- tl.add_class RDoc::NormalClass, 'C'
+ @tl.add_class RDoc::NormalClass, 'C'
- RDoc::TopLevel.complete :public
+ @store.complete :public
report = @s.report
@@ -225,15 +278,14 @@ The following items are not documented:
end
def test_report_class_empty_2
- tl = RDoc::TopLevel.new 'file.rb'
- c1 = tl.add_class RDoc::NormalClass, 'C1'
- c1.record_location tl
+ c1 = @tl.add_class RDoc::NormalClass, 'C1'
+ c1.record_location @tl
- c2 = tl.add_class RDoc::NormalClass, 'C2'
- c2.record_location tl
- c2.add_comment 'C2', tl
+ c2 = @tl.add_class RDoc::NormalClass, 'C2'
+ c2.record_location @tl
+ c2.add_comment 'C2', @tl
- RDoc::TopLevel.complete :public
+ @store.complete :public
@s.coverage_level = 1
report = @s.report
@@ -253,16 +305,15 @@ end
end
def test_report_class_method_documented
- tl = RDoc::TopLevel.new 'file.rb'
- c = tl.add_class RDoc::NormalClass, 'C'
- c.record_location tl
+ c = @tl.add_class RDoc::NormalClass, 'C'
+ c.record_location @tl
m = RDoc::AnyMethod.new nil, 'm'
- m.record_location tl
+ m.record_location @tl
c.add_method m
m.comment = 'm'
- RDoc::TopLevel.complete :public
+ @store.complete :public
report = @s.report
@@ -279,8 +330,19 @@ end
assert_equal expected, report
end
+ def test_report_class_module_ignore
+ c = @tl.add_class RDoc::NormalClass, 'C'
+ c.ignore
+
+ @store.complete :public
+
+ report = @s.report_class_module c
+
+ assert_nil report
+ end
+
def test_report_empty
- RDoc::TopLevel.complete :public
+ @store.complete :public
report = @s.report
@@ -288,21 +350,20 @@ end
end
def test_report_method
- tl = RDoc::TopLevel.new 'file.rb'
- c = tl.add_class RDoc::NormalClass, 'C'
- c.record_location tl
- c.add_comment 'C', tl
+ c = @tl.add_class RDoc::NormalClass, 'C'
+ c.record_location @tl
+ c.add_comment 'C', @tl
m1 = RDoc::AnyMethod.new nil, 'm1'
- m1.record_location tl
+ m1.record_location @tl
c.add_method m1
m2 = RDoc::AnyMethod.new nil, 'm2'
- m2.record_location tl
+ m2.record_location @tl
c.add_method m2
m2.comment = 'm2'
- RDoc::TopLevel.complete :public
+ @store.complete :public
report = @s.report
@@ -320,42 +381,89 @@ end
assert_equal expected, report
end
+ def test_report_method_class
+ c = @tl.add_class RDoc::NormalClass, 'C'
+ c.record_location @tl
+ c.add_comment 'C', @tl
+
+ m1 = RDoc::AnyMethod.new nil, 'm1'
+ m1.record_location @tl
+ m1.singleton = true
+ c.add_method m1
+
+ m2 = RDoc::AnyMethod.new nil, 'm2'
+ m2.record_location @tl
+ m2.singleton = true
+ c.add_method m2
+ m2.comment = 'm2'
+
+ @store.complete :public
+
+ report = @s.report
+
+ expected = <<-EXPECTED
+The following items are not documented:
+
+class C # is documented
+
+ # in file file.rb
+ def self.m1; end
+
+end
+ EXPECTED
+
+ assert_equal expected, report
+ end
+
def test_report_method_documented
- tl = RDoc::TopLevel.new 'file.rb'
- c = tl.add_class RDoc::NormalClass, 'C'
- c.record_location tl
- c.add_comment 'C', tl
+ c = @tl.add_class RDoc::NormalClass, 'C'
+ c.record_location @tl
+ c.add_comment 'C', @tl
m = RDoc::AnyMethod.new nil, 'm'
- m.record_location tl
+ m.record_location @tl
c.add_method m
m.comment = 'm'
- RDoc::TopLevel.complete :public
+ @store.complete :public
report = @s.report
assert_equal @s.great_job, report
end
+ def test_report_method_line
+ c = @tl.add_class RDoc::NormalClass, 'C'
+ c.record_location @tl
+ c.add_comment 'C', @tl
+
+ m1 = RDoc::AnyMethod.new nil, 'm1'
+ m1.record_location @tl
+ m1.line = 4
+ c.add_method m1
+
+ @store.complete :public
+
+ assert_match '# in file file.rb:4', @s.report
+ end
+
def test_report_method_parameters
- tl = RDoc::TopLevel.new 'file.rb'
- c = tl.add_class RDoc::NormalClass, 'C'
- c.record_location tl
- c.add_comment 'C', tl
+ c = @tl.add_class RDoc::NormalClass, 'C'
+ c.record_location @tl
+ c.add_comment 'C', @tl
m1 = RDoc::AnyMethod.new nil, 'm1'
- m1.record_location tl
+ m1.record_location @tl
m1.params = '(p1, p2)'
m1.comment = 'Stuff with +p1+'
c.add_method m1
m2 = RDoc::AnyMethod.new nil, 'm2'
- m2.record_location tl
+ m2.record_location @tl
c.add_method m2
m2.comment = 'm2'
- RDoc::TopLevel.complete :public
+ @store.complete :public
@s.coverage_level = 1
report = @s.report
@@ -376,18 +484,18 @@ end
end
def test_report_method_parameters_documented
- tl = RDoc::TopLevel.new 'file.rb'
- c = tl.add_class RDoc::NormalClass, 'C'
- c.record_location tl
- c.add_comment 'C', tl
+ @tl.parser = RDoc::Parser::Ruby
+ c = @tl.add_class RDoc::NormalClass, 'C'
+ c.record_location @tl
+ c.add_comment 'C', @tl
m = RDoc::AnyMethod.new nil, 'm'
- m.record_location tl
+ m.record_location @tl
m.params = '(p1)'
m.comment = 'Stuff with +p1+'
c.add_method m
- RDoc::TopLevel.complete :public
+ @store.complete :public
@s.coverage_level = 1
report = @s.report
@@ -396,13 +504,12 @@ end
end
def test_report_method_parameters_yield
- tl = RDoc::TopLevel.new 'file.rb'
- c = tl.add_class RDoc::NormalClass, 'C'
- c.record_location tl
- c.add_comment 'C', tl
+ c = @tl.add_class RDoc::NormalClass, 'C'
+ c.record_location @tl
+ c.add_comment 'C', @tl
m = RDoc::AnyMethod.new nil, 'm'
- m.record_location tl
+ m.record_location @tl
m.call_seq = <<-SEQ
m(a) { |c| ... }
m(a, b) { |c, d| ... }
@@ -410,7 +517,7 @@ m(a, b) { |c, d| ... }
m.comment = 'Stuff with +a+, yields +c+ for you to do stuff with'
c.add_method m
- RDoc::TopLevel.complete :public
+ @store.complete :public
@s.coverage_level = 1
report = @s.report
@@ -431,26 +538,25 @@ end
end
def test_summary
- tl = RDoc::TopLevel.new 'file.rb'
- c = tl.add_class RDoc::NormalClass, 'C'
- c.record_location tl
+ c = @tl.add_class RDoc::NormalClass, 'C'
+ c.record_location @tl
- m = tl.add_module RDoc::NormalModule, 'M'
- m.record_location tl
+ m = @tl.add_module RDoc::NormalModule, 'M'
+ m.record_location @tl
a = RDoc::Attr.new nil, 'a', 'RW', nil
- a.record_location tl
+ a.record_location @tl
c.add_attribute a
c_c = RDoc::Constant.new 'C', nil, nil
- c_c.record_location tl
+ c_c.record_location @tl
c.add_constant c_c
m = RDoc::AnyMethod.new nil, 'm'
- m.record_location tl
+ m.record_location @tl
c.add_method m
- RDoc::TopLevel.complete :public
+ @store.complete :public
summary = @s.summary
summary.sub!(/Elapsed:.*/, '')
@@ -473,11 +579,10 @@ Total: 5 (5 undocumented)
end
def test_summary_level_false
- tl = RDoc::TopLevel.new 'file.rb'
- c = tl.add_class RDoc::NormalClass, 'C'
- c.record_location tl
+ c = @tl.add_class RDoc::NormalClass, 'C'
+ c.record_location @tl
- RDoc::TopLevel.complete :public
+ @store.complete :public
@s.coverage_level = false
@@ -502,18 +607,17 @@ Total: 1 (1 undocumented)
end
def test_summary_level_1
- tl = RDoc::TopLevel.new 'file.rb'
- c = tl.add_class RDoc::NormalClass, 'C'
- c.record_location tl
- c.add_comment 'C', tl
+ c = @tl.add_class RDoc::NormalClass, 'C'
+ c.record_location @tl
+ c.add_comment 'C', @tl
m = RDoc::AnyMethod.new nil, 'm'
- m.record_location tl
+ m.record_location @tl
m.params = '(p1, p2)'
m.comment = 'Stuff with +p1+'
c.add_method m
- RDoc::TopLevel.complete :public
+ @store.complete :public
@s.coverage_level = 1
@s.report
diff --git a/test/rdoc/test_rdoc_ri_store.rb b/test/rdoc/test_rdoc_store.rb
index 23e441b633..1b87ca6036 100644
--- a/test/rdoc/test_rdoc_ri_store.rb
+++ b/test/rdoc/test_rdoc_store.rb
@@ -1,23 +1,20 @@
-require 'rubygems'
-require 'minitest/autorun'
-require 'rdoc/rdoc'
-require 'rdoc/ri'
-require 'rdoc/markup'
-require 'tmpdir'
-require 'fileutils'
-require 'pp'
+require File.expand_path '../xref_test_case', __FILE__
-class TestRDocRIStore < MiniTest::Unit::TestCase
+class TestRDocStore < XrefTestCase
OBJECT_ANCESTORS = defined?(::BasicObject) ? %w[BasicObject] : []
def setup
- RDoc::TopLevel.reset
+ super
@tmpdir = File.join Dir.tmpdir, "test_rdoc_ri_store_#{$$}"
@s = RDoc::RI::Store.new @tmpdir
- @top_level = RDoc::TopLevel.new 'file.rb'
+ @top_level = @s.add_file 'file.rb'
+
+ @page = @s.add_file 'README.txt'
+ @page.parser = RDoc::Parser::Simple
+ @page.comment = RDoc::Comment.new 'This is a page', @page
@klass = @top_level.add_class RDoc::NormalClass, 'Object'
@klass.add_comment 'original', @top_level
@@ -26,14 +23,27 @@ class TestRDocRIStore < MiniTest::Unit::TestCase
@cmeth.singleton = true
@cmeth.record_location @top_level
+ @meth_comment = RDoc::Comment.new 'method comment'
+ @meth_comment.location = @top_level
+
@meth = RDoc::AnyMethod.new nil, 'method'
@meth.record_location @top_level
+ @meth.comment = @meth_comment
@meth_bang = RDoc::AnyMethod.new nil, 'method!'
@meth_bang.record_location @top_level
+ @meth_bang_alias = RDoc::Alias.new nil, 'method!', 'method_bang', ''
+ @meth_bang_alias.record_location @top_level
+
+ @meth_bang.add_alias @meth_bang_alias, @klass
+
+ @attr_comment = RDoc::Comment.new 'attribute comment'
+ @attr_comment.location = @top_level
+
@attr = RDoc::Attr.new nil, 'attr', 'RW', ''
@attr.record_location @top_level
+ @attr.comment = @attr_comment
@klass.add_method @cmeth
@klass.add_method @meth
@@ -50,10 +60,13 @@ class TestRDocRIStore < MiniTest::Unit::TestCase
@nest_klass.add_method @nest_meth
@nest_klass.add_include @nest_incl
- @RM = RDoc::Markup
+ @mod = @top_level.add_module RDoc::NormalModule, 'Mod'
+ @mod.record_location @top_level
end
def teardown
+ super
+
FileUtils.rm_rf @tmpdir
end
@@ -64,8 +77,9 @@ class TestRDocRIStore < MiniTest::Unit::TestCase
s.chomp
end
- def assert_cache imethods, cmethods, attrs, modules, ancestors = {}
- imethods ||= { 'Object' => %w[method method!] }
+ def assert_cache imethods, cmethods, attrs, modules,
+ ancestors = {}, pages = [], main = nil, title = nil
+ imethods ||= { 'Object' => %w[method method! method_bang] }
cmethods ||= { 'Object' => %w[cmethod] }
attrs ||= { 'Object' => ['attr_accessor attr'] }
@@ -79,6 +93,9 @@ class TestRDocRIStore < MiniTest::Unit::TestCase
:encoding => nil,
:instance_methods => imethods,
:modules => modules,
+ :pages => pages,
+ :main => main,
+ :title => title,
}
@s.save_cache
@@ -98,6 +115,40 @@ class TestRDocRIStore < MiniTest::Unit::TestCase
refute File.exist?(path), "#{path} exists"
end
+ def test_add_file
+ top_level = @store.add_file 'file.rb'
+
+ assert_kind_of RDoc::TopLevel, top_level
+ assert_equal @store, top_level.store
+ assert_equal 'file.rb', top_level.name
+ assert_includes @store.all_files, top_level
+
+ assert_same top_level, @store.add_file('file.rb')
+ refute_same top_level, @store.add_file('other.rb')
+ end
+
+ def test_all_classes_and_modules
+ expected = %w[
+ C1 C2 C2::C3 C2::C3::H1 C3 C3::H1 C3::H2 C4 C4::C4 C5 C5::C1
+ Child
+ M1 M1::M2
+ Parent
+ ]
+
+ assert_equal expected,
+ @store.all_classes_and_modules.map { |m| m.full_name }.sort
+ end
+
+ def test_all_files
+ assert_equal %w[xref_data.rb],
+ @store.all_files.map { |m| m.full_name }.sort
+ end
+
+ def test_all_modules
+ assert_equal %w[M1 M1::M2],
+ @store.all_modules.map { |m| m.full_name }.sort
+ end
+
def test_attributes
@s.cache[:attributes]['Object'] = %w[attr]
@@ -127,12 +178,63 @@ class TestRDocRIStore < MiniTest::Unit::TestCase
@s.class_path('Object::SubClass')
end
- def test_dry_run
- refute @s.dry_run
+ def test_classes
+ expected = %w[
+ C1 C2 C2::C3 C2::C3::H1 C3 C3::H1 C3::H2 C4 C4::C4 C5 C5::C1
+ Child
+ Parent
+ ]
- @s.dry_run = true
+ assert_equal expected, @store.all_classes.map { |m| m.full_name }.sort
+ end
- assert @s.dry_run
+ def test_complete
+ @c2.add_module_alias @c2_c3, 'A1', @top_level
+
+ @store.complete :public
+
+ a1 = @xref_data.find_class_or_module 'C2::A1'
+
+ assert_equal 'C2::A1', a1.full_name
+ refute_empty a1.aliases
+ end
+
+ def test_find_class_named
+ assert_equal @c1, @store.find_class_named('C1')
+
+ assert_equal @c2_c3, @store.find_class_named('C2::C3')
+ end
+
+ def test_find_class_named_from
+ assert_equal @c5_c1, @store.find_class_named_from('C1', 'C5')
+
+ assert_equal @c1, @store.find_class_named_from('C1', 'C4')
+ end
+
+ def test_find_class_or_module
+ assert_equal @m1, @store.find_class_or_module('M1')
+ assert_equal @c1, @store.find_class_or_module('C1')
+
+ assert_equal @m1, @store.find_class_or_module('::M1')
+ assert_equal @c1, @store.find_class_or_module('::C1')
+ end
+
+ def test_find_file_named
+ assert_equal @xref_data, @store.find_file_named(@file_name)
+ end
+
+ def test_find_module_named
+ assert_equal @m1, @store.find_module_named('M1')
+ assert_equal @m1_m2, @store.find_module_named('M1::M2')
+ end
+
+ def test_find_text_page
+ page = @store.add_file 'PAGE.txt'
+ page.parser = RDoc::Parser::Simple
+
+ assert_nil @store.find_text_page 'no such page'
+
+ assert_equal page, @store.find_text_page('PAGE.txt')
end
def test_friendly_path
@@ -150,13 +252,21 @@ class TestRDocRIStore < MiniTest::Unit::TestCase
assert_equal "ruby site", @s.friendly_path
@s.type = :home
- assert_equal "~/.ri", @s.friendly_path
+ assert_equal "~/.rdoc", @s.friendly_path
@s.type = :gem
@s.path = "#{@tmpdir}/gem_repository/doc/gem_name-1.0/ri"
assert_equal "gem gem_name-1.0", @s.friendly_path
end
+ def test_dry_run
+ refute @s.dry_run
+
+ @s.dry_run = true
+
+ assert @s.dry_run
+ end
+
def test_instance_methods
@s.cache[:instance_methods]['Object'] = %w[method]
@@ -165,11 +275,50 @@ class TestRDocRIStore < MiniTest::Unit::TestCase
assert_equal expected, @s.instance_methods
end
+ def test_load_all
+ FileUtils.mkdir_p @tmpdir
+
+ @s.save
+
+ s = RDoc::Store.new @tmpdir
+
+ s.load_all
+
+ assert_equal [@klass, @nest_klass], s.all_classes.sort
+ assert_equal [@mod], s.all_modules.sort
+ assert_equal [@page, @top_level], s.all_files.sort
+
+ methods = s.all_classes_and_modules.map do |mod|
+ mod.method_list
+ end.flatten.sort
+
+ _meth_bang_alias = RDoc::AnyMethod.new nil, 'method_bang'
+ _meth_bang_alias.parent = @klass
+
+ assert_equal [@meth, @meth_bang, _meth_bang_alias, @nest_meth, @cmeth],
+ methods.sort_by { |m| m.full_name }
+
+ method = methods.find { |m| m == @meth }
+ assert_equal @meth_comment.parse, method.comment
+
+ assert_equal @klass, methods.last.parent
+
+ attributes = s.all_classes_and_modules.map do |mod|
+ mod.attributes
+ end.flatten.sort
+
+ assert_equal [@attr], attributes
+
+ assert_equal @attr_comment.parse, attributes.first.comment
+ end
+
def test_load_cache
cache = {
:encoding => :encoding_value,
- :methods => %w[Object#method],
+ :methods => { "Object" => %w[Object#method] },
+ :main => @page.full_name,
:modules => %w[Object],
+ :pages => [],
}
Dir.mkdir @tmpdir
@@ -183,6 +332,7 @@ class TestRDocRIStore < MiniTest::Unit::TestCase
assert_equal cache, @s.cache
assert_equal :encoding_value, @s.encoding
+ assert_equal 'README.txt', @s.main
end
def test_load_cache_encoding_differs
@@ -190,8 +340,10 @@ class TestRDocRIStore < MiniTest::Unit::TestCase
cache = {
:encoding => Encoding::ISO_8859_1,
- :methods => %w[Object#method],
+ :main => nil,
+ :methods => { "Object" => %w[Object#method] },
:modules => %w[Object],
+ :pages => [],
}
Dir.mkdir @tmpdir
@@ -216,7 +368,10 @@ class TestRDocRIStore < MiniTest::Unit::TestCase
:class_methods => {},
:encoding => nil,
:instance_methods => {},
+ :main => nil,
:modules => [],
+ :pages => [],
+ :title => nil,
}
@s.load_cache
@@ -224,17 +379,96 @@ class TestRDocRIStore < MiniTest::Unit::TestCase
assert_equal cache, @s.cache
end
+ def test_load_cache_legacy
+ cache = {
+ :ancestors => {},
+ :attributes => {},
+ :class_methods => {},
+ :encoding => :encoding_value,
+ :instance_methods => { "Object" => %w[Object#method] },
+ :modules => %w[Object],
+ # no :pages
+ # no :main
+ }
+
+ Dir.mkdir @tmpdir
+
+ open File.join(@tmpdir, 'cache.ri'), 'wb' do |io|
+ Marshal.dump cache, io
+ end
+
+ @s.load_cache
+
+ expected = {
+ :ancestors => {},
+ :attributes => {},
+ :class_methods => {},
+ :encoding => :encoding_value,
+ :instance_methods => { "Object" => %w[Object#method] },
+ :main => nil,
+ :modules => %w[Object],
+ :pages => [],
+ }
+
+ assert_equal expected, @s.cache
+
+ assert_equal :encoding_value, @s.encoding
+ assert_nil @s.main
+ end
+
def test_load_class
@s.save_class @klass
+ @s.classes_hash.clear
assert_equal @klass, @s.load_class('Object')
+
+ assert_includes @s.classes_hash, 'Object'
end
- def test_load_method_bang
+ def test_load_method
@s.save_method @klass, @meth_bang
meth = @s.load_method('Object', '#method!')
assert_equal @meth_bang, meth
+ assert_equal @klass, meth.parent
+ assert_equal @s, meth.store
+ end
+
+ def test_load_method_legacy
+ @s.save_method @klass, @meth
+
+ file = @s.method_file @klass.full_name, @meth.full_name
+
+ open file, 'wb' do |io|
+ io.write "\x04\bU:\x14RDoc::AnyMethod[\x0Fi\x00I" +
+ "\"\vmethod\x06:\x06EF\"\x11Klass#method0:\vpublic" +
+ "o:\eRDoc::Markup::Document\x06:\v@parts[\x06" +
+ "o:\x1CRDoc::Markup::Paragraph\x06;\t[\x06I" +
+ "\"\x16this is a comment\x06;\x06FI" +
+ "\"\rcall_seq\x06;\x06FI\"\x0Fsome_block\x06;\x06F" +
+ "[\x06[\aI\"\faliased\x06;\x06Fo;\b\x06;\t[\x06" +
+ "o;\n\x06;\t[\x06I\"\x12alias comment\x06;\x06FI" +
+ "\"\nparam\x06;\x06F"
+ end
+
+ meth = @s.load_method('Object', '#method')
+ assert_equal 'Klass#method', meth.full_name
+ assert_equal @klass, meth.parent
+ assert_equal @s, meth.store
+ end
+
+ def test_load_page
+ @s.save_page @page
+
+ assert_equal @page, @s.load_page('README.txt')
+ end
+
+ def test_main
+ assert_equal nil, @s.main
+
+ @s.main = 'README.txt'
+
+ assert_equal 'README.txt', @s.main
end
def test_method_file
@@ -251,29 +485,89 @@ class TestRDocRIStore < MiniTest::Unit::TestCase
@s.method_file('Object', 'Object::method')
end
+ def test_module_names
+ @s.save_class @klass
+
+ assert_equal %w[Object], @s.module_names
+ end
+
+ def test_page
+ page = @store.add_file 'PAGE.txt'
+ page.parser = RDoc::Parser::Simple
+
+ assert_nil @store.page 'no such page'
+
+ assert_equal page, @store.page('PAGE')
+ end
+
+ def test_save
+ FileUtils.mkdir_p @tmpdir
+
+ @s.save
+
+ assert_directory File.join(@tmpdir, 'Object')
+
+ assert_file File.join(@tmpdir, 'Object', 'cdesc-Object.ri')
+ assert_file File.join(@tmpdir, 'Object', 'method-i.ri')
+ assert_file File.join(@tmpdir, 'page-README_txt.ri')
+
+ assert_file File.join(@tmpdir, 'cache.ri')
+
+ expected = {
+ :ancestors => {
+ 'Object::SubClass' => %w[Incl Object],
+ },
+ :attributes => { 'Object' => ['attr_accessor attr'] },
+ :class_methods => { 'Object' => %w[cmethod] },
+ :instance_methods => {
+ 'Object' => %w[attr method method! method_bang],
+ 'Object::SubClass' => %w[method],
+ },
+ :main => nil,
+ :modules => %w[Mod Object Object::SubClass],
+ :encoding => nil,
+ :pages => %w[README.txt],
+ :title => nil,
+ }
+
+ expected[:ancestors]['Object'] = %w[BasicObject] if defined?(::BasicObject)
+
+ open File.join(@tmpdir, 'cache.ri'), 'rb' do |io|
+ cache = Marshal.load io.read
+
+ assert_equal expected, cache
+ end
+ end
+
def test_save_cache
@s.save_class @klass
@s.save_method @klass, @meth
@s.save_method @klass, @cmeth
@s.save_class @nest_klass
+ @s.save_page @page
@s.encoding = :encoding_value
+ @s.main = @page.full_name
+ @s.title = 'title'
@s.save_cache
assert_file File.join(@tmpdir, 'cache.ri')
expected = {
+ :ancestors => {
+ 'Object::SubClass' => %w[Incl Object],
+ },
:attributes => { 'Object' => ['attr_accessor attr'] },
:class_methods => { 'Object' => %w[cmethod] },
:instance_methods => {
- 'Object' => %w[method method!],
+ 'Object' => %w[method method! method_bang],
'Object::SubClass' => %w[method],
},
+ :main => @page.full_name,
:modules => %w[Object Object::SubClass],
- :ancestors => {
- 'Object::SubClass' => %w[Incl Object],
- },
:encoding => :encoding_value,
+ :pages => %w[README.txt],
+ :title => 'title',
}
expected[:ancestors]['Object'] = %w[BasicObject] if defined?(::BasicObject)
@@ -307,6 +601,15 @@ class TestRDocRIStore < MiniTest::Unit::TestCase
assert_cache({ 'Object' => %w[method] }, {}, {}, [])
end
+ def test_save_cache_duplicate_pages
+ @s.save_page @page
+ @s.save_page @page
+
+ @s.save_cache
+
+ assert_cache({}, {}, {}, [], {}, %w[README.txt])
+ end
+
def test_save_class
@s.save_class @klass
@@ -386,7 +689,7 @@ class TestRDocRIStore < MiniTest::Unit::TestCase
s = RDoc::RI::Store.new @tmpdir
inner = @RM::Document.new @RM::Paragraph.new 'new comment'
- inner.file = @top_level.absolute_name
+ inner.file = @top_level
document = @RM::Document.new inner
@@ -395,8 +698,10 @@ class TestRDocRIStore < MiniTest::Unit::TestCase
# This is a functional test
def test_save_class_merge_constant
- tl = RDoc::TopLevel.new 'file.rb'
- klass = RDoc::NormalClass.new 'C'
+ store = RDoc::Store.new
+ tl = store.add_file 'file.rb'
+
+ klass = tl.add_class RDoc::NormalClass, 'C'
klass.add_comment 'comment', tl
const = klass.add_constant RDoc::Constant.new('CONST', nil, nil)
@@ -404,14 +709,16 @@ class TestRDocRIStore < MiniTest::Unit::TestCase
@s.save_class klass
- RDoc::RDoc.reset
-
- klass2 = RDoc::NormalClass.new 'C'
+ # separate parse run, independent store
+ store = RDoc::Store.new
+ tl = store.add_file 'file.rb'
+ klass2 = tl.add_class RDoc::NormalClass, 'C'
klass2.record_location tl
s = RDoc::RI::Store.new @tmpdir
s.save_class klass2
+ # separate `ri` run, independent store
s = RDoc::RI::Store.new @tmpdir
result = s.load_class 'C'
@@ -469,5 +776,49 @@ class TestRDocRIStore < MiniTest::Unit::TestCase
assert_cache({ 'Object::SubClass' => %w[method] }, {}, {}, [])
end
+ def test_save_page
+ @s.save_page @page
+
+ assert_file File.join(@tmpdir, 'page-README_txt.ri')
+
+ assert_cache({}, {}, {}, [], {}, %w[README.txt])
+ end
+
+ def test_save_page_file
+ @s.save_page @top_level
+
+ refute_file File.join(@tmpdir, 'page-file_rb.ri')
+ end
+
+ def test_source
+ @s.path = @tmpdir
+ @s.type = nil
+ assert_equal @s.path, @s.source
+
+ @s.type = :extra
+ assert_equal @s.path, @s.source
+
+ @s.type = :system
+ assert_equal "ruby", @s.source
+
+ @s.type = :site
+ assert_equal "site", @s.source
+
+ @s.type = :home
+ assert_equal "home", @s.source
+
+ @s.type = :gem
+ @s.path = "#{@tmpdir}/gem_repository/doc/gem_name-1.0/ri"
+ assert_equal "gem_name-1.0", @s.source
+ end
+
+ def test_title
+ assert_equal nil, @s.title
+
+ @s.title = 'rdoc'
+
+ assert_equal 'rdoc', @s.title
+ end
+
end
diff --git a/test/rdoc/test_rdoc_task.rb b/test/rdoc/test_rdoc_task.rb
index c17a5c8b38..dce02bc9b7 100644
--- a/test/rdoc/test_rdoc_task.rb
+++ b/test/rdoc/test_rdoc_task.rb
@@ -1,10 +1,11 @@
-require 'rubygems'
-require 'minitest/autorun'
-require 'rdoc/task'
+require 'rdoc/test_case'
+require 'rake'
-class TestRDocTask < MiniTest::Unit::TestCase
+class TestRDocTask < RDoc::TestCase
def setup
+ super
+
Rake::Task.clear
@t = RDoc::Task.new
@@ -32,6 +33,14 @@ class TestRDocTask < MiniTest::Unit::TestCase
end
end
+ def test_markup_option
+ rdoc_task = RDoc::Task.new do |rd|
+ rd.markup = "tomdoc"
+ end
+
+ assert_equal %w[-o html --markup tomdoc], rdoc_task.option_list
+ end
+
def test_tasks_creation
RDoc::Task.new
assert Rake::Task[:rdoc]
diff --git a/test/rdoc/test_rdoc_text.rb b/test/rdoc/test_rdoc_text.rb
index e11c995e59..47eb4de906 100644
--- a/test/rdoc/test_rdoc_text.rb
+++ b/test/rdoc/test_rdoc_text.rb
@@ -1,16 +1,26 @@
# coding: utf-8
-require 'rubygems'
-require 'minitest/autorun'
-require 'rdoc'
-require 'rdoc/text'
-require 'rdoc/markup'
-require 'rdoc/markup/formatter'
+require 'rdoc/test_case'
-class TestRDocText < MiniTest::Unit::TestCase
+class TestRDocText < RDoc::TestCase
include RDoc::Text
+ def setup
+ super
+
+ @options = RDoc::Options.new
+
+ @top_level = @store.add_file 'file.rb'
+ end
+
+ def mu_pp obj
+ s = ''
+ s = PP.pp obj, s
+ s = s.force_encoding Encoding.default_external if defined? Encoding
+ s.chomp
+ end
+
def test_self_encode_fallback
skip "Encoding not implemented" unless Object.const_defined? :Encoding
@@ -110,13 +120,19 @@ The comments associated with
assert_equal Encoding::US_ASCII, result.encoding
end
- def test_markup
- def formatter() RDoc::Markup::ToHtml.new end
+ def test_markup_string
+ out = markup('hi').gsub("\n", '')
- assert_equal "<p>hi</p>", markup('hi').gsub("\n", '')
+ assert_equal '<p>hi</p>', out
end
- def test_normalize_comment
+ def test_markup_comment
+ out = markup(comment('hi')).gsub("\n", '')
+
+ assert_equal '<p>hi</p>', out
+ end
+
+ def test_normalize_comment_hash
text = <<-TEXT
##
# we don't worry too much.
@@ -133,10 +149,57 @@ The comments associated with
assert_equal expected, normalize_comment(text)
end
+ def test_normalize_comment_stars_single_space
+ text = <<-TEXT
+/*
+ * we don't worry too much.
+ *
+ * The comments associated with
+ */
+ TEXT
+
+ expected = <<-EXPECTED.rstrip
+we don't worry too much.
+
+The comments associated with
+ EXPECTED
+
+ assert_equal expected, normalize_comment(text)
+ end
+
+ def test_normalize_comment_stars_single_double_space
+ text = <<-TEXT
+/*
+ * we don't worry too much.
+ *
+ * The comments associated with
+ */
+ TEXT
+
+ expected = <<-EXPECTED.rstrip
+we don't worry too much.
+
+The comments associated with
+ EXPECTED
+
+ assert_equal expected, normalize_comment(text)
+ end
+
def test_parse
assert_kind_of RDoc::Markup::Document, parse('hi')
end
+ def test_parse_comment
+ expected = RDoc::Markup::Document.new
+ expected.file = @top_level
+
+ c = comment ''
+ parsed = parse c
+
+ assert_equal expected, parsed
+ assert_same parsed, parse(c)
+ end
+
def test_parse_document
assert_equal RDoc::Markup::Document.new, parse(RDoc::Markup::Document.new)
end
@@ -149,10 +212,92 @@ The comments associated with
assert_equal RDoc::Markup::Document.new, parse("#\n")
end
+ def test_parse_format_markdown
+ expected =
+ @RM::Document.new(
+ @RM::Paragraph.new('it _works_'))
+
+ parsed = parse 'it *works*', 'markdown'
+
+ assert_equal expected, parsed
+ end
+
+ def test_parse_format_rd
+ expected =
+ @RM::Document.new(
+ @RM::Paragraph.new('it <em>works</em>'))
+
+ parsed = parse 'it ((*works*))', 'rd'
+
+ assert_equal expected, parsed
+ end
+
+ def test_parse_format_tomdoc
+ code = verb('1 + 1')
+ code.format = :ruby
+
+ expected =
+ doc(
+ para('It does a thing'),
+ blank_line,
+ head(3, 'Examples'),
+ blank_line,
+ code)
+
+ text = <<-TOMDOC
+It does a thing
+
+Examples
+
+ 1 + 1
+ TOMDOC
+
+ parsed = parse text, 'tomdoc'
+
+ assert_equal expected, parsed
+ end
+
def test_parse_newline
assert_equal RDoc::Markup::Document.new, parse("\n")
end
+# def test_snippet
+# text = <<-TEXT
+#This is one-hundred characters or more of text in a single paragraph. This
+#paragraph will be cut off some point after the one-hundredth character.
+# TEXT
+#
+# expected = text.gsub(/\r?\n/, ' ').sub(/ some point.*/, '')
+#
+# assert_equal expected, snippet(text)
+# end
+#
+# def test_snippet_comment
+# c = comment 'This is a comment'
+#
+# assert_equal 'This is a comment', snippet(c)
+# end
+#
+# def test_snippet_no_space
+# text = <<-TEXT.strip
+#This is one-hundred characters or more of text in a single paragraph. This
+#paragraph will not be cut
+# TEXT
+#
+# expected = <<-EXPECTED.strip.gsub(/\r?\n/, ' ')
+#This is one-hundred characters or more of text in a single paragraph. This
+#paragraph will not be cut
+# EXPECTED
+#
+# assert_equal expected, snippet(text)
+# end
+#
+# def test_snippet_short
+# text = 'This is a comment'
+#
+# assert_equal text.dup, snippet(text)
+# end
+
def test_strip_hashes
text = <<-TEXT
##
@@ -309,6 +454,24 @@ The comments associated with
assert_equal Encoding::BINARY, result.encoding
end
+ def test_strip_stars_no_stars
+ text = <<-TEXT
+* we don't worry too much.
+
+The comments associated with
+
+ TEXT
+
+ expected = <<-EXPECTED
+* we don't worry too much.
+
+The comments associated with
+
+ EXPECTED
+
+ assert_equal expected, strip_stars(text)
+ end
+
def test_to_html_apostrophe
assert_equal '‘a', to_html("'a")
assert_equal 'a’', to_html("a'")
@@ -320,6 +483,10 @@ The comments associated with
assert_equal 'S', to_html('\\S')
end
+ def test_to_html_br
+ assert_equal '<br>', to_html('<br>')
+ end
+
def test_to_html_copyright
assert_equal '©', to_html('(c)')
end
@@ -393,5 +560,9 @@ The comments associated with
assert_equal "mismatched <tt> tag\n", err
end
+ def formatter()
+ RDoc::Markup::ToHtml.new @options
+ end
+
end
diff --git a/test/rdoc/test_rdoc_token_stream.rb b/test/rdoc/test_rdoc_token_stream.rb
new file mode 100644
index 0000000000..3c1a225c25
--- /dev/null
+++ b/test/rdoc/test_rdoc_token_stream.rb
@@ -0,0 +1,42 @@
+require 'rdoc/test_case'
+
+class TestRDocTokenStream < RDoc::TestCase
+
+ def test_class_to_html
+ tokens = [
+ RDoc::RubyToken::TkCONSTANT. new(0, 0, 0, 'CONSTANT'),
+ RDoc::RubyToken::TkDEF. new(0, 0, 0, 'KW'),
+ RDoc::RubyToken::TkIVAR. new(0, 0, 0, 'IVAR'),
+ RDoc::RubyToken::TkOp. new(0, 0, 0, 'Op'),
+ RDoc::RubyToken::TkId. new(0, 0, 0, 'Id'),
+ RDoc::RubyToken::TkNode. new(0, 0, 0, 'Node'),
+ RDoc::RubyToken::TkCOMMENT. new(0, 0, 0, 'COMMENT'),
+ RDoc::RubyToken::TkREGEXP. new(0, 0, 0, 'REGEXP'),
+ RDoc::RubyToken::TkSTRING. new(0, 0, 0, 'STRING'),
+ RDoc::RubyToken::TkVal. new(0, 0, 0, 'Val'),
+ RDoc::RubyToken::TkBACKSLASH.new(0, 0, 0, '\\'),
+ ]
+
+ expected = [
+ '<span class="ruby-constant">CONSTANT</span>',
+ '<span class="ruby-keyword">KW</span>',
+ '<span class="ruby-ivar">IVAR</span>',
+ '<span class="ruby-operator">Op</span>',
+ '<span class="ruby-identifier">Id</span>',
+ '<span class="ruby-node">Node</span>',
+ '<span class="ruby-comment">COMMENT</span>',
+ '<span class="ruby-regexp">REGEXP</span>',
+ '<span class="ruby-string">STRING</span>',
+ '<span class="ruby-value">Val</span>',
+ '\\'
+ ].join
+
+ assert_equal expected, RDoc::TokenStream.to_html(tokens)
+ end
+
+ def test_class_to_html_empty
+ assert_equal '', RDoc::TokenStream.to_html([])
+ end
+
+end
+
diff --git a/test/rdoc/test_rdoc_tom_doc.rb b/test/rdoc/test_rdoc_tom_doc.rb
new file mode 100644
index 0000000000..08f30d1e53
--- /dev/null
+++ b/test/rdoc/test_rdoc_tom_doc.rb
@@ -0,0 +1,455 @@
+require 'rdoc/test_case'
+
+class TestRDocTomDoc < RDoc::TestCase
+
+ def setup
+ super
+
+ @top_level = @store.add_file 'file.rb'
+
+ @TD = RDoc::TomDoc
+ @td = @TD.new
+ end
+
+ def mu_pp obj
+ s = ''
+ s = PP.pp obj, s
+ s = s.force_encoding Encoding.default_external if defined? Encoding
+ s.chomp
+ end
+
+ def test_class_add_post_processor
+ RDoc::TomDoc.add_post_processor
+
+ pp = RDoc::Markup::PreProcess.new __FILE__, []
+
+ text = "# Public: Do some stuff\n"
+
+ comment = RDoc::Comment.new text, nil
+ comment.format = 'tomdoc'
+
+ parent = RDoc::Context.new
+
+ pp.handle comment, parent
+
+ method = parent.add_method RDoc::AnyMethod.new(nil, 'm')
+
+ assert_equal 'Public', method.section.title
+ assert_equal "# Do some stuff\n", comment.text
+ end
+
+ def test_class_signature
+ c = comment <<-COMMENT
+Signature
+
+ method_<here>(args)
+
+here - something
+ COMMENT
+ c.format = 'tomdoc'
+
+ signature = @TD.signature c
+
+ assert_equal "method_<here>(args)\n", signature
+ end
+
+ def test_class_signature_no_space
+ c = comment <<-COMMENT
+Signature
+ method_<here>(args)
+
+here - something
+ COMMENT
+ c.format = 'tomdoc'
+
+ signature = @TD.signature c
+
+ assert_equal "method_<here>(args)\n", signature
+
+ expected =
+ doc(
+ head(3, 'Signature'),
+ list(:NOTE,
+ item(%w[here],
+ para('something'))))
+ expected.file = @top_level
+
+ assert_equal expected, c.parse
+ end
+
+ def test_class_signature_none
+ c = comment ''
+ c.format = 'tomdoc'
+
+ assert_nil @TD.signature c
+ end
+
+ def test_class_rdoc
+ c = comment <<-COMMENT
+=== Signature
+
+ method_<here>(args)
+
+here - something
+ COMMENT
+ c.format = 'rdoc'
+
+ signature = @TD.signature c
+
+ assert_nil signature
+ end
+
+ def test_class_signature_two_space
+ c = comment <<-COMMENT
+Signature
+
+
+ method_<here>(args)
+
+here - something
+ COMMENT
+ c.format = 'tomdoc'
+
+ signature = @TD.signature c
+
+ assert_equal "method_<here>(args)\n", signature
+
+ expected =
+ doc(
+ head(3, 'Signature'),
+ list(:NOTE,
+ item(%w[here],
+ para('something'))))
+ expected.file = @top_level
+
+ assert_equal expected, c.parse
+ end
+
+ def test_parse_paragraph
+ text = "Public: Do some stuff\n"
+
+ expected =
+ @RM::Document.new(
+ @RM::Paragraph.new('Do some stuff'))
+
+ assert_equal expected, @TD.parse(text)
+ end
+
+ def test_parse_arguments
+ text = <<-TEXT
+Create new Arg object.
+
+name - name of argument
+description - arguments description
+ TEXT
+
+ expected =
+ doc(
+ para('Create new Arg object.'),
+ blank_line,
+ list(:NOTE,
+ item(%w[name],
+ para('name of argument')),
+ item(%w[description],
+ para('arguments description'))))
+
+ assert_equal expected, @TD.parse(text)
+ end
+
+ def test_parse_arguments_multiline
+ text = <<-TEXT
+Do some stuff
+
+foo - A comment goes here
+ and is more than one line
+ TEXT
+
+ expected =
+ doc(
+ para('Do some stuff'),
+ blank_line,
+ list(:NOTE,
+ item(%w[foo],
+ para('A comment goes here', 'and is more than one line'))))
+
+ assert_equal expected, @TD.parse(text)
+ end
+
+ def test_parse_arguments_nested
+ text = <<-TEXT
+Do some stuff
+
+foo - A comment goes here
+ :bar - bar documentation
+ TEXT
+
+ expected =
+ doc(
+ para('Do some stuff'),
+ blank_line,
+ list(:NOTE,
+ item(%w[foo],
+ para('A comment goes here'),
+ list(:NOTE,
+ item(%w[:bar],
+ para('bar documentation'))))))
+
+ assert_equal expected, @TD.parse(text)
+ end
+
+ def test_parse_examples
+ text = <<-TEXT
+Do some stuff
+
+Examples
+
+ 1 + 1
+ TEXT
+
+ code = verb("1 + 1\n")
+ code.format = :ruby
+
+ expected =
+ doc(
+ para('Do some stuff'),
+ blank_line,
+ head(3, 'Examples'),
+ blank_line,
+ code)
+
+ document = @TD.parse(text)
+ assert_equal expected, document
+ assert document.parts.last.ruby?
+ end
+
+ def test_parse_examples_signature
+ text = <<-TEXT
+Do some stuff
+
+Examples
+
+ 1 + 1
+
+Signature
+
+ foo(args)
+ TEXT
+
+ code1 = verb("1 + 1\n")
+ code1.format = :ruby
+
+ code2 = verb("foo(args)\n")
+
+ expected =
+ doc(
+ para('Do some stuff'),
+ blank_line,
+ head(3, 'Examples'),
+ blank_line,
+ code1,
+ head(3, 'Signature'),
+ blank_line,
+ code2)
+
+ document = @TD.parse text
+
+ assert_equal expected, document
+ end
+
+ def test_parse_returns
+ text = <<-TEXT
+Do some stuff
+
+Returns a thing
+ TEXT
+
+ expected =
+ @RM::Document.new(
+ @RM::Paragraph.new('Do some stuff'),
+ @RM::BlankLine.new,
+ @RM::Paragraph.new('Returns a thing'))
+
+ assert_equal expected, @TD.parse(text)
+ end
+
+ def test_parse_returns_multiline
+ text = <<-TEXT
+Do some stuff
+
+Returns a thing
+ that is multiline
+ TEXT
+
+ expected =
+ @RM::Document.new(
+ @RM::Paragraph.new('Do some stuff'),
+ @RM::BlankLine.new,
+ @RM::Paragraph.new('Returns a thing', 'that is multiline'))
+
+ assert_equal expected, @TD.parse(text)
+ end
+
+ def test_parse_signature
+ text = <<-TEXT
+Do some stuff
+
+Signature
+
+ some_method(args)
+ TEXT
+
+ expected =
+ @RM::Document.new(
+ @RM::Paragraph.new('Do some stuff'),
+ @RM::BlankLine.new,
+ @RM::Heading.new(3, 'Signature'),
+ @RM::BlankLine.new,
+ @RM::Verbatim.new("some_method(args)\n"))
+
+ assert_equal expected, @TD.parse(text)
+ end
+
+ def test_tokenize_paragraph
+ @td.tokenize "Public: Do some stuff\n"
+
+ expected = [
+ [:TEXT, "Do some stuff", 0, 0],
+ [:NEWLINE, "\n", 13, 0],
+ ]
+
+ assert_equal expected, @td.tokens
+ end
+
+ def test_tokenize_arguments
+ @td.tokenize <<-TEXT
+Create new Arg object.
+
+name - name of argument
+description - arguments description
+ TEXT
+
+ expected = [
+ [:TEXT, "Create new Arg object.", 0, 0],
+ [:NEWLINE, "\n", 22, 0],
+ [:NEWLINE, "\n", 0, 1],
+ [:NOTE, "name", 0, 2],
+ [:TEXT, "name of argument", 14, 2],
+ [:NEWLINE, "\n", 30, 2],
+ [:NOTE, "description", 0, 3],
+ [:TEXT, "arguments description", 14, 3],
+ [:NEWLINE, "\n", 35, 3],
+ ]
+
+ assert_equal expected, @td.tokens
+ end
+
+ def test_tokenize_arguments_multiline
+ @td.tokenize <<-TEXT
+Do some stuff
+
+foo - A comment goes here
+ and is more than one line
+ TEXT
+
+ expected = [
+ [:TEXT, "Do some stuff", 0, 0],
+ [:NEWLINE, "\n", 13, 0],
+ [:NEWLINE, "\n", 0, 1],
+ [:NOTE, "foo", 0, 2],
+ [:TEXT, "A comment goes here", 6, 2],
+ [:NEWLINE, "\n", 25, 2],
+ [:TEXT, "and is more than one line", 2, 3],
+ [:NEWLINE, "\n", 27, 3],
+ ]
+
+ assert_equal expected, @td.tokens
+ end
+
+ def test_tokenize_arguments_nested
+ @td.tokenize <<-TEXT
+Do some stuff
+
+foo - A comment goes here
+ :bar - bar documentation
+ TEXT
+
+ expected = [
+ [:TEXT, "Do some stuff", 0, 0],
+ [:NEWLINE, "\n", 13, 0],
+ [:NEWLINE, "\n", 0, 1],
+ [:NOTE, "foo", 0, 2],
+ [:TEXT, "A comment goes here", 6, 2],
+ [:NEWLINE, "\n", 25, 2],
+ [:NOTE, ":bar", 6, 3],
+ [:TEXT, "bar documentation", 13, 3],
+ [:NEWLINE, "\n", 30, 3],
+ ]
+
+ assert_equal expected, @td.tokens
+ end
+
+ def test_tokenize_examples
+ @td.tokenize <<-TEXT
+Do some stuff
+
+Examples
+
+ 1 + 1
+ TEXT
+
+ expected = [
+ [:TEXT, "Do some stuff", 0, 0],
+ [:NEWLINE, "\n", 13, 0],
+ [:NEWLINE, "\n", 0, 1],
+ [:HEADER, 3, 0, 2],
+ [:TEXT, "Examples", 0, 2],
+ [:NEWLINE, "\n", 8, 2],
+ [:NEWLINE, "\n", 0, 3],
+ [:TEXT, "1 + 1", 2, 4],
+ [:NEWLINE, "\n", 7, 4],
+ ]
+
+ assert_equal expected, @td.tokens
+ end
+
+ def test_tokenize_returns
+ @td.tokenize <<-TEXT
+Do some stuff
+
+Returns a thing
+ TEXT
+
+ expected = [
+ [:TEXT, "Do some stuff", 0, 0],
+ [:NEWLINE, "\n", 13, 0],
+ [:NEWLINE, "\n", 0, 1],
+ [:TEXT, "Returns a thing", 0, 2],
+ [:NEWLINE, "\n", 15, 2],
+ ]
+
+ assert_equal expected, @td.tokens
+ end
+
+ def test_tokenize_returns_multiline
+ @td.tokenize <<-TEXT
+Do some stuff
+
+Returns a thing
+ that is multiline
+ TEXT
+
+ expected = [
+ [:TEXT, "Do some stuff", 0, 0],
+ [:NEWLINE, "\n", 13, 0],
+ [:NEWLINE, "\n", 0, 1],
+ [:TEXT, "Returns a thing", 0, 2],
+ [:NEWLINE, "\n", 15, 2],
+ [:TEXT, "that is multiline", 2, 3],
+ [:NEWLINE, "\n", 19, 3],
+ ]
+
+ assert_equal expected, @td.tokens
+ end
+
+end
+
diff --git a/test/rdoc/test_rdoc_top_level.rb b/test/rdoc/test_rdoc_top_level.rb
index 9e68bc4bdd..61f4362d09 100644
--- a/test/rdoc/test_rdoc_top_level.rb
+++ b/test/rdoc/test_rdoc_top_level.rb
@@ -1,5 +1,3 @@
-require 'rubygems'
-require 'minitest/autorun'
require File.expand_path '../xref_test_case', __FILE__
class TestRDocTopLevel < XrefTestCase
@@ -7,102 +5,15 @@ class TestRDocTopLevel < XrefTestCase
def setup
super
- @top_level = RDoc::TopLevel.new 'path/top_level.rb'
- end
-
- def test_class_all_classes_and_modules
- expected = %w[
- C1 C2 C2::C3 C2::C3::H1 C3 C3::H1 C3::H2 C4 C4::C4 C5 C5::C1
- Child
- M1 M1::M2
- Parent
- ]
-
- assert_equal expected,
- RDoc::TopLevel.all_classes_and_modules.map { |m| m.full_name }.sort
- end
-
- def test_class_classes
- expected = %w[
- C1 C2 C2::C3 C2::C3::H1 C3 C3::H1 C3::H2 C4 C4::C4 C5 C5::C1
- Child Parent
- ]
-
- assert_equal expected, RDoc::TopLevel.classes.map { |m| m.full_name }.sort
- end
-
- def test_class_complete
- @c2.add_module_alias @c2_c3, 'A1', @top_level
-
- RDoc::TopLevel.complete :public
-
- a1 = @xref_data.find_class_or_module 'C2::A1'
-
- assert_equal 'C2::A1', a1.full_name
- refute_empty a1.aliases
- end
-
- def test_class_files
- assert_equal %w[path/top_level.rb xref_data.rb],
- RDoc::TopLevel.files.map { |m| m.full_name }.sort
- end
-
- def test_class_find_class_named
- assert_equal @c1, RDoc::TopLevel.find_class_named('C1')
-
- assert_equal @c2_c3, RDoc::TopLevel.find_class_named('C2::C3')
- end
-
- def test_class_find_class_named_from
- assert_equal @c5_c1, RDoc::TopLevel.find_class_named_from('C1', 'C5')
-
- assert_equal @c1, RDoc::TopLevel.find_class_named_from('C1', 'C4')
- end
-
- def test_class_find_class_or_module
- assert_equal @m1, RDoc::TopLevel.find_class_or_module('M1')
- assert_equal @c1, RDoc::TopLevel.find_class_or_module('C1')
-
- assert_equal @m1, RDoc::TopLevel.find_class_or_module('::M1')
- assert_equal @c1, RDoc::TopLevel.find_class_or_module('::C1')
- end
-
- def test_class_find_file_named
- assert_equal @xref_data, RDoc::TopLevel.find_file_named(@file_name)
- end
-
- def test_class_find_module_named
- assert_equal @m1, RDoc::TopLevel.find_module_named('M1')
- assert_equal @m1_m2, RDoc::TopLevel.find_module_named('M1::M2')
- end
-
- def test_class_modules
- assert_equal %w[M1 M1::M2],
- RDoc::TopLevel.modules.map { |m| m.full_name }.sort
- end
-
- def test_class_new
- tl1 = RDoc::TopLevel.new 'file.rb'
- tl2 = RDoc::TopLevel.new 'file.rb'
- tl3 = RDoc::TopLevel.new 'other.rb'
-
- assert_same tl1, tl2
- refute_same tl1, tl3
- end
-
- def test_class_reset
- RDoc::TopLevel.reset
-
- assert_empty RDoc::TopLevel.classes
- assert_empty RDoc::TopLevel.modules
- assert_empty RDoc::TopLevel.files
+ @top_level = @store.add_file 'path/top_level.rb'
+ @top_level.parser = RDoc::Parser::Ruby
end
def test_add_alias
a = RDoc::Alias.new nil, 'old', 'new', nil
@top_level.add_alias a
- object = RDoc::TopLevel.find_class_named 'Object'
+ object = @store.find_class_named 'Object'
expected = { '#old' => [a] }
assert_equal expected, object.unmatched_alias_lists
assert_includes object.in_files, @top_level
@@ -114,7 +25,7 @@ class TestRDocTopLevel < XrefTestCase
a = RDoc::Alias.new nil, 'old', 'new', nil
@top_level.add_alias a
- object = RDoc::TopLevel.find_class_named('Object')
+ object = @store.find_class_named('Object')
assert_empty object.unmatched_alias_lists
assert_includes object.in_files, @top_level
end
@@ -123,7 +34,7 @@ class TestRDocTopLevel < XrefTestCase
const = RDoc::Constant.new 'C', nil, nil
@top_level.add_constant const
- object = RDoc::TopLevel.find_class_named 'Object'
+ object = @store.find_class_named 'Object'
assert_equal [const], object.constants
assert_includes object.in_files, @top_level
end
@@ -134,7 +45,7 @@ class TestRDocTopLevel < XrefTestCase
const = RDoc::Constant.new 'C', nil, nil
@top_level.add_constant const
- object = RDoc::TopLevel.find_class_named 'Object'
+ object = @store.find_class_named 'Object'
assert_empty object.constants
assert_includes object.in_files, @top_level
end
@@ -143,7 +54,7 @@ class TestRDocTopLevel < XrefTestCase
include = RDoc::Include.new 'C', nil
@top_level.add_include include
- object = RDoc::TopLevel.find_class_named 'Object'
+ object = @store.find_class_named 'Object'
assert_equal [include], object.includes
assert_includes object.in_files, @top_level
end
@@ -154,7 +65,7 @@ class TestRDocTopLevel < XrefTestCase
include = RDoc::Include.new 'C', nil
@top_level.add_include include
- object = RDoc::TopLevel.find_class_named('Object')
+ object = @store.find_class_named('Object')
assert_empty object.includes
assert_includes object.in_files, @top_level
end
@@ -163,7 +74,7 @@ class TestRDocTopLevel < XrefTestCase
method = RDoc::AnyMethod.new nil, 'm'
@top_level.add_method method
- object = RDoc::TopLevel.find_class_named 'Object'
+ object = @store.find_class_named 'Object'
assert_equal [method], object.method_list
assert_includes object.in_files, @top_level
end
@@ -174,7 +85,7 @@ class TestRDocTopLevel < XrefTestCase
method = RDoc::AnyMethod.new nil, 'm'
@top_level.add_method method
- object = RDoc::TopLevel.find_class_named('Object')
+ object = @store.find_class_named('Object')
assert_empty object.method_list
assert_includes object.in_files, @top_level
end
@@ -183,9 +94,18 @@ class TestRDocTopLevel < XrefTestCase
assert_equal 'top_level.rb', @top_level.base_name
end
+ def test_display_eh
+ refute @top_level.display?
+
+ page = @store.add_file 'README.txt'
+ page.parser = RDoc::Parser::Simple
+
+ assert page.display?
+ end
+
def test_eql_eh
- top_level2 = RDoc::TopLevel.new 'path/top_level.rb'
- other_level = RDoc::TopLevel.new 'path/other_level.rb'
+ top_level2 = @store.add_file 'path/top_level.rb'
+ other_level = @store.add_file 'path/other_level.rb'
assert_operator @top_level, :eql?, top_level2
@@ -193,8 +113,8 @@ class TestRDocTopLevel < XrefTestCase
end
def test_equals2
- top_level2 = RDoc::TopLevel.new 'path/top_level.rb'
- other_level = RDoc::TopLevel.new 'path/other_level.rb'
+ top_level2 = @store.add_file 'path/top_level.rb'
+ other_level = @store.add_file 'path/other_level.rb'
assert_equal @top_level, top_level2
@@ -213,8 +133,8 @@ class TestRDocTopLevel < XrefTestCase
end
def test_hash
- tl2 = RDoc::TopLevel.new 'path/top_level.rb'
- tl3 = RDoc::TopLevel.new 'other/top_level.rb'
+ tl2 = @store.add_file 'path/top_level.rb'
+ tl3 = @store.add_file 'other/top_level.rb'
assert_equal @top_level.hash, tl2.hash
refute_equal @top_level.hash, tl3.hash
@@ -232,9 +152,106 @@ class TestRDocTopLevel < XrefTestCase
assert_equal 0, @top_level.last_modified
end
+ def test_marshal_dump
+ page = @store.add_file 'README.txt'
+ page.parser = RDoc::Parser::Simple
+ page.comment = RDoc::Comment.new 'This is a page', page
+
+ loaded = Marshal.load Marshal.dump page
+
+ comment = RDoc::Markup::Document.new(
+ RDoc::Markup::Paragraph.new('This is a page'))
+ comment.file = loaded
+
+ assert_equal page, loaded
+
+ assert_equal 'README.txt', loaded.absolute_name
+ assert_equal 'README.txt', loaded.relative_name
+
+ assert_equal RDoc::Parser::Simple, loaded.parser
+
+ assert_equal comment, loaded.comment
+ end
+
+ def test_marshal_load_version_0
+ loaded = Marshal.load "\x04\bU:\x13RDoc::TopLevel" +
+ "[\ti\x00I\"\x0FREADME.txt\x06:\x06EF" +
+ "c\x19RDoc::Parser::Simple" +
+ "o:\eRDoc::Markup::Document\a:\v@parts" +
+ "[\x06o:\x1CRDoc::Markup::Paragraph\x06;\b" +
+ "[\x06I\"\x13This is a page\x06;\x06F:\n@file@\a"
+
+ comment = RDoc::Markup::Document.new(
+ RDoc::Markup::Paragraph.new('This is a page'))
+ comment.file = loaded
+
+ assert_equal 'README.txt', loaded.absolute_name
+ assert_equal 'README.txt', loaded.relative_name
+
+ assert_equal RDoc::Parser::Simple, loaded.parser
+
+ assert_equal comment, loaded.comment
+ end
+
def test_name
assert_equal 'top_level.rb', @top_level.name
end
+ def test_page_name
+ assert_equal 'top_level', @top_level.page_name
+
+ tl = @store.add_file 'README.ja.rdoc'
+
+ assert_equal 'README.ja', tl.page_name
+
+ tl = @store.add_file 'Rakefile'
+
+ assert_equal 'Rakefile', tl.page_name
+ end
+
+ def test_search_record
+ assert_nil @xref_data.search_record
+ end
+
+ def test_search_record_page
+ page = @store.add_file 'README.txt'
+ page.parser = RDoc::Parser::Simple
+ page.comment = 'This is a comment.'
+
+ expected = [
+ 'README',
+ '',
+ 'README',
+ '',
+ 'README_txt.html',
+ '',
+ "<p>This is a comment.\n",
+ ]
+
+ assert_equal expected, page.search_record
+ end
+
+ def test_text_eh
+ refute @xref_data.text?
+
+ rd = @store.add_file 'rd_format.rd'
+ rd.parser = RDoc::Parser::RD
+
+ assert rd.text?
+
+ simple = @store.add_file 'simple.txt'
+ simple.parser = RDoc::Parser::Simple
+
+ assert simple.text?
+ end
+
+ def test_text_eh_no_parser
+ refute @xref_data.text?
+
+ rd = @store.add_file 'rd_format.rd'
+
+ refute rd.text?
+ end
+
end
diff --git a/test/rdoc/xref_test_case.rb b/test/rdoc/xref_test_case.rb
index a001700d3b..29021a301c 100644
--- a/test/rdoc/xref_test_case.rb
+++ b/test/rdoc/xref_test_case.rb
@@ -1,26 +1,21 @@
ENV['RDOC_TEST'] = 'yes'
-require 'rubygems'
-require 'minitest/autorun'
require 'rdoc'
-require 'rdoc/stats'
-require 'rdoc/options'
-require 'rdoc/code_objects'
-require 'rdoc/parser/ruby'
require File.expand_path '../xref_data', __FILE__
-class XrefTestCase < MiniTest::Unit::TestCase
+class XrefTestCase < RDoc::TestCase
def setup
- RDoc::TopLevel.reset
-
- @file_name = 'xref_data.rb'
- @xref_data = RDoc::TopLevel.new @file_name
+ super
@options = RDoc::Options.new
@options.quiet = true
- stats = RDoc::Stats.new 0
+ @file_name = 'xref_data.rb'
+ @xref_data = @store.add_file @file_name
+ @top_level = @xref_data
+
+ stats = RDoc::Stats.new @store, 0
parser = RDoc::Parser::Ruby.new @xref_data, @file_name, XREF_DATA, @options,
stats
@@ -30,9 +25,8 @@ class XrefTestCase < MiniTest::Unit::TestCase
generator = Object.new
def generator.class_dir() nil end
def generator.file_dir() nil end
- rdoc = RDoc::RDoc.new
- RDoc::RDoc.current = rdoc
- rdoc.generator = generator
+ @rdoc.options = @options
+ @rdoc.generator = generator
@c1 = @xref_data.find_module_named 'C1'
@c1_m = @c1.method_list.last # C1#m