summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--bin/rdoc51
-rw-r--r--lib/.document1
-rw-r--r--lib/rdoc.rb18
-rw-r--r--lib/rdoc/README605
-rw-r--r--lib/rdoc/code_objects.rb32
-rw-r--r--lib/rdoc/generator.rb2
-rw-r--r--lib/rdoc/generator/html.rb15
-rw-r--r--lib/rdoc/generator/ri.rb9
-rw-r--r--lib/rdoc/markup.rb466
-rw-r--r--lib/rdoc/markup/.document2
-rw-r--r--lib/rdoc/markup/fragments.rb (renamed from lib/rdoc/markup/simple_markup/fragments.rb)7
-rw-r--r--lib/rdoc/markup/inline.rb (renamed from lib/rdoc/markup/simple_markup/inline.rb)16
-rw-r--r--lib/rdoc/markup/lines.rb (renamed from lib/rdoc/markup/simple_markup/lines.rb)8
-rw-r--r--lib/rdoc/markup/preprocess.rb71
-rw-r--r--lib/rdoc/markup/simple_markup.rb463
-rw-r--r--lib/rdoc/markup/simple_markup/preprocess.rb73
-rw-r--r--lib/rdoc/markup/simple_markup/to_html.rb287
-rw-r--r--lib/rdoc/markup/simple_markup/to_latex.rb332
-rw-r--r--lib/rdoc/markup/to_flow.rb (renamed from lib/rdoc/markup/simple_markup/to_flow.rb)26
-rw-r--r--lib/rdoc/markup/to_html.rb286
-rw-r--r--lib/rdoc/markup/to_latex.rb331
-rw-r--r--lib/rdoc/parsers/parse_rb.rb2002
-rw-r--r--lib/rdoc/parsers/parse_simple.rb73
-rw-r--r--lib/rdoc/rdoc.rb40
-rw-r--r--lib/rdoc/ri/descriptions.rb4
-rw-r--r--lib/rdoc/ri/display.rb2
-rw-r--r--lib/rdoc/ri/driver.rb8
-rw-r--r--lib/rdoc/ri/formatter.rb46
-rw-r--r--lib/rdoc/ri/reader.rb2
-rw-r--r--lib/rdoc/stats.rb25
31 files changed, 2509 insertions, 2799 deletions
diff --git a/ChangeLog b/ChangeLog
index b2774bef1c..218237a1b6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Mon Jan 14 12:33:07 2008 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rdoc/markup*: Renamespace from SM::SimpleMarkup to
+ RDoc::Markup.
+
Mon Jan 14 10:45:45 2008 Martin Duerst <duerst@it.aoyama.ac.jp>
* enc/ascii.c: Exchanged order of arguments for one ENC_ALIAS
diff --git a/bin/rdoc b/bin/rdoc
index 0642ec671b..e50285478d 100644
--- a/bin/rdoc
+++ b/bin/rdoc
@@ -8,59 +8,14 @@
#
# $Revision$
-## Transitional Hack ####
-#
-# RDoc was initially distributed independently, and installed
-# itself into <prefix>/lib/ruby/site_ruby/<ver>/rdoc...
-#
-# Now that RDoc is part of the distribution, it's installed into
-# <prefix>/lib/ruby/<ver>, which unfortunately appears later in the
-# search path. This means that if you have previously installed RDoc,
-# and then install from ruby-lang, you'll pick up the old one by
-# default. This hack checks for the condition, and readjusts the
-# search path if necessary.
-
-def adjust_for_existing_rdoc(path)
-
- $stderr.puts %{
- It seems as if you have a previously-installed RDoc in
- the directory #{path}.
-
- Because this is now out-of-date, you might want to consider
- removing the directories:
-
- #{File.join(path, "rdoc")}
-
- and
-
- #{File.join(path, "markup")}
-
- }
-
- # Move all the site_ruby directories to the end
- p $:
- $:.replace($:.partition {|path| /site_ruby/ !~ path}.flatten)
- p $:
-end
-
-$:.each do |path|
- if /site_ruby/ =~ path
- rdoc_path = File.join(path, 'rdoc', 'rdoc.rb')
- if File.exist?(rdoc_path)
- adjust_for_existing_rdoc(path)
- break
- end
- end
-end
-
-## End of Transitional Hack ##
-
-
require 'rdoc/rdoc'
begin
r = RDoc::RDoc.new
r.document ARGV
+rescue Interrupt
+ $stderr.puts
+ $stderr.puts "Interrupted"
rescue RDoc::Error => e
$stderr.puts e.message
exit 1
diff --git a/lib/.document b/lib/.document
index a7582bf102..f6b301327f 100644
--- a/lib/.document
+++ b/lib/.document
@@ -64,6 +64,7 @@ profiler.rb
pstore.rb
racc
rational.rb
+rdoc.rb
rdoc
readbytes.rb
resolv-replace.rb
diff --git a/lib/rdoc.rb b/lib/rdoc.rb
index 0d2dc26764..25989189ad 100644
--- a/lib/rdoc.rb
+++ b/lib/rdoc.rb
@@ -4,6 +4,13 @@
module RDoc
##
+ # Exception thrown by any rdoc error.
+
+ class Error < RuntimeError; end
+
+ RDocError = Error # :nodoc:
+
+ ##
# RDoc version you are using
VERSION = "2.0.0"
@@ -14,5 +21,16 @@ module RDoc
DOT_DOC_FILENAME = ".document"
+ GENERAL_MODIFIERS = %w[nodoc].freeze
+
+ CLASS_MODIFIERS = GENERAL_MODIFIERS
+
+ ATTR_MODIFIERS = GENERAL_MODIFIERS
+
+ CONSTANT_MODIFIERS = GENERAL_MODIFIERS
+
+ METHOD_MODIFIERS = GENERAL_MODIFIERS +
+ %w[arg args yield yields notnew not-new not_new doc]
+
end
diff --git a/lib/rdoc/README b/lib/rdoc/README
index 8ad023f35d..cb00a5e355 100644
--- a/lib/rdoc/README
+++ b/lib/rdoc/README
@@ -1,38 +1,34 @@
= RDOC - Ruby Documentation System
-This package contains Rdoc and SimpleMarkup. Rdoc is an application
-that produces documentation for one or more Ruby source files. We work
-similarly to JavaDoc, parsing the source, and extracting the
-definition for classes, modules, and methods (along with includes and
-requires). We associate with these optional documentation contained
-in the immediately preceding comment block, and then render the result
-using a pluggable output formatter. (Currently, HTML is the only
-supported format. Markup is a library that converts plain text into
-various output formats. The Markup library is used to interpret the
-comment blocks that Rdoc uses to document methods, classes, and so on.
-
-This library contains two packages, rdoc itself and a text markup
-library, 'markup'.
+This package contains RDoc and RDoc::Markup. RDoc is an application that
+produces documentation for one or more Ruby source files. We work similarly to
+JavaDoc, parsing the source, and extracting the definition for classes,
+modules, and methods (along with includes and requires). We associate with
+these optional documentation contained in the immediately preceding comment
+block, and then render the result using a pluggable output formatter.
+RDoc::Markup is a library that converts plain text into various output formats.
+The markup library is used to interpret the comment blocks that RDoc uses to
+document methods, classes, and so on.
== Roadmap
-* If you want to use Rdoc to create documentation for your Ruby source
- files, read on.
-* If you want to include extensions written in C, see rdoc/parsers/parse_c.rb.
-* For information on the various markups available in comment
- blocks, see markup/simple_markup.rb.
-* If you want to drive Rdoc programatically, see RDoc::RDoc.
-* If you want to use the library to format text blocks into HTML,
- have a look at SM::SimpleMarkup.
+* If you want to use RDoc to create documentation for your Ruby source files,
+ read on.
+* If you want to include extensions written in C, see RDoc::C_Parser
+* For information on the various markups available in comment blocks, see
+ RDoc::Markup.
+* If you want to drive RDoc programatically, see RDoc::RDoc.
+* If you want to use the library to format text blocks into HTML, have a look
+ at RDoc::Markup.
* If you want to try writing your own HTML output template, see
- RDoc::Page.
+ RDoc::Generator::HTML
== Summary
Once installed, you can create documentation using the 'rdoc' command
(the command is 'rdoc.bat' under Windows)
- % rdoc [options] [names...]
+ % rdoc [options] [names...]
Type "rdoc --help" for an up-to-date option summary.
@@ -42,448 +38,195 @@ source (such as rdoc itself).
% rdoc
This command generates documentation for all the Ruby and C source
-files in and below the current directory. These will be stored in a
+files in and below the current directory. These will be stored in a
documentation tree starting in the subdirectory 'doc'.
You can make this slightly more useful for your readers by having the
-index page contain the documentation for the primary file. In our
+index page contain the documentation for the primary file. In our
case, we could type
- % rdoc --main rdoc/rdoc.rb
+ % rdoc --main rdoc.rb
You'll find information on the various formatting tricks you can use
in comment blocks in the documentation this generates.
-RDoc uses file extensions to determine how to process each file. File
-names ending <tt>.rb</tt> and <tt>.rbw</tt> are assumed to be Ruby
-source. Files ending <tt>.c</tt> are parsed as C files. All other
-files are assumed to contain just SimpleMarkup-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.
+RDoc uses file extensions to determine how to process each file. File names
+ending +.rb+ and <tt>.rbw</tt> are assumed to be Ruby source. Files
+ending +.c+ are parsed as C files. All other files are assumed to
+contain just Markup-style markup (with or without leading '#' comment markers).
+If directory names are passed to RDoc, they are scanned recursively for C and
+Ruby source files only.
-== Credits
+= Markup
-* 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.
+For information on how to make lists, hyperlinks, & etc. with RDoc, see
+RDoc::Markup.
-* Code to diagram classes and modules was written by Sergey A Yanovitsky
- (Jah) of Enticla.
+Comment blocks can be written fairly naturally, either using '#' on successive
+lines of the comment, or by including the comment in an =begin/=end block. If
+you use the latter form, the =begin line must be flagged with an RDoc tag:
-* Charset patch from MoonWolf.
+ =begin rdoc
+ Documentation to be processed by RDoc.
+
+ ...
+ =end
-* Rich Kilmer wrote the kilmer.rb output template.
+RDoc stops processing comments if it finds a comment line containing '+#--+'.
+This can be used to separate external from internal comments, or to stop a
+comment being associated with a method, class, or module. Commenting can be
+turned back on with a line that starts '+#+++'.
+
+ ##
+ # Extract the age and calculate the date-of-birth.
+ #--
+ # FIXME: fails if the birthday falls on February 29th
+ #++
+ # The DOB is returned as a Time object.
+
+ def get_dob(person)
+ # ...
+ end
-* Dan Brickley led the design of the RDF format.
+Names of classes, source files, and any method names containing an underscore
+or preceded by a hash character are automatically hyperlinked from comment text
+to their description.
-== License
+Method parameter lists are extracted and displayed with the method description.
+If a method calls +yield+, then the parameters passed to yield will also be
+displayed:
-RDoc is Copyright (c) 2001-2003 Dave Thomas, The Pragmatic Programmers. It
-is free software, and may be redistributed under the terms specified
-in the README file of the Ruby distribution.
+ def fred
+ ...
+ yield line, address
+
+This will get documented as:
-= Usage
+ fred() { |line, address| ... }
-RDoc is invoked from the command line using:
+You can override this using a comment containing ':yields: ...' immediately
+after the method definition
- % rdoc <options> [name...]
+ def fred # :yields: index, position
+ # ...
+
+ yield line, address
-Files are parsed, and the information they contain collected, before
-any output is produced. This allows cross references between all files
-to be resolved. If a name is a directory, it is traversed. If no
-names are specified, all Ruby files in the current directory (and
-subdirectories) are processed.
+which will get documented as
-Options are:
+ fred() { |index, position| ... }
-[<tt>--accessor</tt> <i>name[,name...]</i>]
- specifies the name(s) of additional methods that should be treated
- as if they were <tt>attr_</tt><i>xxx</i> methods. Specifying
- "--accessor db_opt" means lines such as
++:yields:+ is an example of a documentation directive. These appear immediately
+after the start of the document element they are modifying.
- db_opt :name, :age
+== Directives
+
+[+:nodoc:+ / +:nodoc:+ all]
+ Don't include this element in the documentation. For classes
+ and modules, the methods, aliases, constants, and attributes
+ directly within the affected class or module will also be
+ omitted. By default, though, modules and classes within that
+ class of module _will_ be documented. This is turned off by
+ adding the +all+ modifier.
+
+ module MyModule # :nodoc:
+ class Input
+ end
+ end
+
+ module OtherModule # :nodoc: all
+ class Output
+ end
+ end
- will get parsed and displayed in the documentation. Each name may have an
- optional "=flagtext" appended, in which case the given flagtext will appear
- where (for example) the 'rw' appears for attr_accessor.
-
-[<tt>--all</tt>]
- include protected and private methods in the output (by default
- only public methods are included)
-
-[<tt>--charset</tt> _charset_]
- Set the character set for the generated HTML.
-
-[<tt>--diagram</tt>]
- include diagrams showing modules and classes. This is currently
- an experimental feature, and may not be supported by all output
- templates. You need dot V1.8.6 or later to use the --diagram
- option correctly (http://www.research.att.com/sw/tools/graphviz/).
-
-[<tt>--exclude</tt> <i>pattern</i>]
- exclude files and directories matching this pattern from processing
-
-[<tt>--extension</tt> <i>new=old</i>]
- treat files ending <i>.new</i> as if they ended
- <i>.old</i>. Saying '--extension cgi=rb' causes RDoc to treat .cgi
- files as Ruby source.
-
-[<tt>fileboxes</tt>]
- Classes are put in boxes which represents files, where these
- classes reside. Classes shared between more than one file are
- shown with list of files that sharing them. Silently discarded if
- --diagram is not given Experimental.
-
-[<tt>--fmt</tt> _fmt_]
- generate output in a particular format.
-
-[<tt>--help</tt>]
- generate a usage summary.
-
-[<tt>--help-output</tt>]
- explain the various output options.
-
-[<tt>--image-format</tt> <i>gif/png/jpg/jpeg</i>]
- sets output image format for diagrams. Can be png, gif, jpeg,
- jpg. If this option is omitted, png is used. Requires --diagram.
-
-[<tt>--include</tt> <i>dir,...</i>]
- specify one or more directories to be searched when satisfying
- :+include+: directives. Multiple <tt>--include</tt> options may be
- given. The directory containing the file currently being processed
- is always searched.
-
-[<tt>--inline-source</tt>]
- By default, the source code of methods is shown in a popup. With
- this option, it's displayed inline.
-
-[<tt>line-numbers</tt>]
- include line numbers in the source code
-
-[<tt>--main</tt> _name_]
- the class of module _name_ will appear on the index page. If you
- want to set a particular file as a main page (a README, for
- example) simply specifiy its name as the first on the command
- line.
-
-[<tt>--merge</tt>]
- when generating _ri_ output, if classes being processed already
- exist in the destination directory, merge in the current details
- rather than overwrite them.
-
-[<tt>--one-file</tt>]
- place all the output into a single file
-
-[<tt>--op</tt> _dir_]
- set the output directory to _dir_ (the default is the directory
- "doc")
-
-[<tt>--op-name</tt> _name_]
- set the name of the output. Has no effect for HTML.
- "doc")
-
-[<tt>--opname</tt> _name_]
- set the output name (has no effect for HTML).
-
-[<tt>--promiscuous</tt>]
- If a module or class is defined in more than one source file, and
- you click on a particular file's name in the top navigation pane,
- RDoc will normally only show you the inner classes and modules of
- that class that are defined in the particular file. Using this
- option makes it show all classes and modules defined in the class,
- regardless of the file they were defined in.
-
-[<tt>--quiet</tt>]
- do not display progress messages
-
-[<tt>--ri</tt>, <tt>--ri-site</tt>, _and_ <tt>--ri-system</tt>]
- generate output than can be read by the _ri_ command-line tool.
- By default --ri places its output in ~/.rdoc, --ri-site in
- $datadir/ri/<ver>/site, and --ri-system in
- $datadir/ri/<ver>/system. All can be overridden with a subsequent
- --op option. All default directories are in ri's default search
- path.
-
-[<tt>--show-hash</tt>]
- A name of the form #name in a comment is a possible hyperlink to
- an instance method name. When displayed, the '#' is removed unless
- this option is specified
-
-[<tt>--style</tt> <i>stylesheet url</i>]
- specifies the URL of an external stylesheet to use (rather than
- generating one of our own)
-
-[<tt>tab-width</tt> _n_]
- set the width of tab characters (default 8)
-
-[<tt>--template</tt> <i>name</i>]
- specify an alternate template to use when generating output (the
- default is 'standard'). This template should be in a directory
- accessible via $: as rdoc/generator/xxxx_template, where 'xxxx'
- depends on the output formatter.
-
-[<tt>--version</tt>]
- display RDoc's version
-
-[<tt>--webcvs</tt> _url_]
- Specify a URL for linking to a web frontend to CVS. If the URL
- contains a '\%s', the name of the current file will be
- substituted; if the URL doesn't contain a '\%s', the filename will
- be appended to it.
-
-= Example
+ In the above code, only class +MyModule::Input+ will be documented.
+
+[+:doc:+]
+ Force a method or attribute to be documented even if it wouldn't otherwise
+ be. Useful if, for example, you want to include documentation of a
+ particular private method.
+
+[+:notnew:+]
+ Only applicable to the +initialize+ instance method. Normally RDoc assumes
+ that the documentation and parameters for #initialize are actually for the
+ ::new method, and so fakes out a ::new for the class. The :notnew: modifier
+ stops this. Remember that #initialize is protected, so you won't see the
+ documentation unless you use the -a command line option.
+
+Comment blocks can contain other directives:
+
+[+:section: title+]
+ Starts a new section in the output. The title following +:section:+ is used
+ as the section heading, and the remainder of the comment containing the
+ section is used as introductory text. Subsequent methods, aliases,
+ attributes, and classes will be documented in this section. A :section:
+ comment block may have one or more lines before the :section: directive.
+ These will be removed, and any identical lines at the end of the block are
+ also removed. This allows you to add visual cues such as:
+
+ # ----------------------------------------
+ # :section: My Section
+ # This is the section that I wrote.
+ # See it glisten in the noon-day sun.
+ # ----------------------------------------
+
+[+:call-seq:+]
+ Lines up to the next blank line in the comment are treated as the method's
+ calling sequence, overriding the default parsing of method parameters and
+ yield arguments.
+
+[+:include:+ _filename_]
+ Include the contents of the named file at this point. The file will be
+ searched for in the directories listed by the +--include+ option, or in the
+ current directory by default. The contents of the file will be shifted to
+ have the same indentation as the ':' at the start of the :include: directive.
+
+[+:title:+ _text_]
+ Sets the title for the document. Equivalent to the --title command line
+ parameter. (The command line parameter overrides any :title: directive in
+ the source).
+
+[+:enddoc:+]
+ Document nothing further at the current level.
+
+[+:main:+ _name_]
+ Equivalent to the --main command line parameter.
+
+[+:stopdoc:+ / +:startdoc:+]
+ Stop and start adding new documentation elements to the current container.
+ For example, if a class has a number of constants that you don't want to
+ document, put a +:stopdoc:+ before the first, and a +:startdoc:+ after the
+ last. If you don't specifiy a +:startdoc:+ by the end of the container,
+ disables documentation for the entire class or module.
-A typical small Ruby program commented using RDoc might be as follows. You
-can see the formatted result in EXAMPLE.rb and Anagram.
+= Other stuff
- :include: EXAMPLE.rb
+Author:: Dave Thomas <dave@pragmaticprogrammer.com>
-= Markup
+== Credits
-Comment blocks can be written fairly naturally, either using '#' on
-successive lines of the comment, or by including the comment in
-an =begin/=end block. If you use the latter form, the =begin line
-must be flagged with an RDoc tag:
+* 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.
- =begin rdoc
- Documentation to
- be processed by RDoc.
- =end
+* Code to diagram classes and modules was written by Sergey A Yanovitsky
+ (Jah) of Enticla.
-Paragraphs are lines that share the left margin. Text indented past
-this margin are formatted verbatim.
-
-1. Lists are typed as indented paragraphs with:
- * a '*' or '-' (for bullet lists)
- * a digit followed by a period for
- numbered lists
- * an upper or lower case letter followed
- by a period for alpha lists.
+* Charset patch from MoonWolf.
- For example, the input that produced the above paragraph looked like
- 1. Lists are typed as indented
- paragraphs with:
- * a '*' or '-' (for bullet lists)
- * a digit followed by a period for
- numbered lists
- * an upper or lower case letter followed
- by a period for alpha lists.
-
-2. Labeled lists (sometimes called description
- lists) are typed using square brackets for the label.
- [cat] small domestic animal
- [+cat+] command to copy standard input
-
-3. Labeled lists may also be produced by putting a double colon
- after the label. This sets the result in tabular form, so the
- descriptions all line up. This was used to create the 'author'
- block at the bottom of this description.
- cat:: small domestic animal
- +cat+:: command to copy standard input
-
- For both kinds of labeled lists, if the body text starts on the same
- line as the label, then the start of that text determines the block
- indent for the rest of the body. The text may also start on the line
- following the label, indented from the start of the label. This is
- often preferable if the label is long. Both the following are
- valid labeled list entries:
-
- <tt>--output</tt> <i>name [, name]</i>::
- specify the name of one or more output files. If multiple
- files are present, the first is used as the index.
-
- <tt>--quiet:</tt>:: do not output the names, sizes, byte counts,
- index areas, or bit ratios of units as
- they are processed.
-
-4. Headings are entered using equals signs
-
- = Level One Heading
- == Level Two Heading
- and so on
-
-5. Rules (horizontal lines) are entered using three or
- more hyphens.
-
-6. Non-verbatim text can be marked up:
-
- _italic_:: \_word_ or \<em>text</em>
- *bold*:: \*word* or \<b>text</b>
- +typewriter+:: \+word+ or \<tt>text</tt>
-
- The first form only works around 'words', where a word is a
- sequence of upper and lower case letters and underscores. Putting a
- backslash before inline markup stops it being interpreted, which is
- how I created the table above:
-
- _italic_:: \_word_ or \<em>text</em>
- *bold*:: \*word* or \<b>text</b>
- +typewriter+:: \+word+ or \<tt>text</tt>
-
-7. Names of classes, source files, and any method names
- containing an underscore or preceded by a hash
- character are automatically hyperlinked from
- comment text to their description.
-
-8. Hyperlinks to the web starting http:, mailto:, ftp:, or www. are
- recognized. An HTTP url that references an external image file is
- converted into an inline <IMG..>. Hyperlinks starting 'link:' are
- assumed to refer to local files whose path is relative to the --op
- directory.
-
- Hyperlinks can also be of the form <tt>label</tt>[url], in which
- case the label is used in the displayed text, and <tt>url</tt> is
- used as the target. If <tt>label</tt> contains multiple words,
- put it in braces: <em>{multi word label}[</em>url<em>]</em>.
-
-9. Method parameter lists are extracted and displayed with
- the method description. If a method calls +yield+, then
- the parameters passed to yield will also be displayed:
-
- def fred
- ...
- yield line, address
-
- This will get documented as
-
- fred() { |line, address| ... }
-
- You can override this using a comment containing
- ':yields: ...' immediately after the method definition
-
- def fred # :yields: index, position
- ...
- yield line, address
-
- which will get documented as
-
- fred() { |index, position| ... }
-
-
-10. ':yields:' is an example of a documentation modifier. These appear
- immediately after the start of the document element they are modifying.
- Other modifiers include
-
- [<tt>:nodoc:</tt><i>[all]</i>]
- don't include this element in the documentation. For classes
- and modules, the methods, aliases, constants, and attributes
- directly within the affected class or module will also be
- omitted. By default, though, modules and classes within that
- class of module _will_ be documented. This is turned off by
- adding the +all+ modifier.
-
- module SM #:nodoc:
- class Input
- end
- end
- module Markup #:nodoc: all
- class Output
- end
- end
-
- In the above code, only class <tt>SM::Input</tt> will be
- documented.
-
- [<tt>:doc:</tt>]
- force a method or attribute to be documented even if it
- wouldn't otherwise be. Useful if, for example, you want to
- include documentation of a particular private method.
-
- [<tt>:notnew:</tt>]
- only applicable to the +initialize+ instance method. Normally
- RDoc assumes that the documentation and parameters for
- #initialize are actually for the ::new method, and so fakes
- out a ::new for the class. THe :notnew: modifier stops
- this. Remember that #initialize is protected, so you won't
- see the documentation unless you use the -a command line
- option.
-
-
-11. RDoc stops processing comments if it finds a comment
- line containing '<tt>#--</tt>'. This can be used to
- separate external from internal comments, or
- to stop a comment being associated with a method,
- class, or module. Commenting can be turned back on with
- a line that starts '<tt>#++</tt>'.
-
- # Extract the age and calculate the
- # date-of-birth.
- #--
- # FIXME: fails if the birthday falls on
- # February 29th
- #++
- # The DOB is returned as a Time object.
-
- def get_dob(person)
- ...
-
-12. Comment blocks can contain other directives:
-
- [<tt>:section: title</tt>]
- Starts a new section in the output. The title following
- <tt>:section:</tt> is used as the section heading, and the
- remainder of the comment containing the section is used as
- introductory text. Subsequent methods, aliases, attributes,
- and classes will be documented in this section. A :section:
- comment block may have one or more lines before the :section:
- directive. These will be removed, and any identical lines at
- the end of the block are also removed. This allows you to add
- visual cues such as
-
- # ----------------------------------------
- # :section: My Section
- # This is the section that I wrote.
- # See it glisten in the noon-day sun.
- # ----------------------------------------
-
- [<tt>call-seq:</tt>]
- 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.
-
- [<tt>:include:</tt><i>filename</i>]
- include the contents of the named file at this point. The
- file will be searched for in the directories listed by
- the <tt>--include</tt> 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.
-
- [<tt>:title:</tt><i>text</i>]
- Sets the title for the document. Equivalent to the --title command
- line parameter. (The command line parameter overrides any :title:
- directive in the source).
-
- [<tt>:enddoc:</tt>]
- Document nothing further at the current level.
-
- [<tt>:main:</tt><i>name</i>]
- Equivalent to the --main command line parameter.
-
- [<tt>:stopdoc: / :startdoc:</tt>]
- Stop and start adding new documentation elements to the
- current container. For example, if a class has a number of
- constants that you don't want to document, put a
- <tt>:stopdoc:</tt> before the first, and a
- <tt>:startdoc:</tt> after the last. If you don't specifiy a
- <tt>:startdoc:</tt> by the end of the container, disables
- documentation for the entire class or module.
-
-
----
-
-See also markup/simple_markup.rb.
+* Rich Kilmer wrote the kilmer.rb output template.
-= Other stuff
+* Dan Brickley led the design of the RDF format.
-Author:: Dave Thomas <dave@pragmaticprogrammer.com>
-Requires:: Ruby 1.8.1 or later
-License:: Copyright (c) 2001-2003 Dave Thomas.
- Released under the same license as Ruby.
+== License
+
+RDoc is Copyright (c) 2001-2003 Dave Thomas, The Pragmatic Programmers. It
+is free software, and may be redistributed under the terms specified
+in the README file of the Ruby distribution.
== Warranty
-This software is provided "as is" and without any express or
-implied warranties, including, without limitation, the implied
-warranties of merchantibility and fitness for a particular
-purpose.
+This software is provided "as is" and without any express or implied
+warranties, including, without limitation, the implied warranties of
+merchantibility and fitness for a particular purpose.
+
diff --git a/lib/rdoc/code_objects.rb b/lib/rdoc/code_objects.rb
index d75670de72..dfc0fff9cc 100644
--- a/lib/rdoc/code_objects.rb
+++ b/lib/rdoc/code_objects.rb
@@ -458,7 +458,7 @@ module RDoc
end
-
+ ##
# A TopLevel context is a source file
class TopLevel < Context
@@ -470,7 +470,7 @@ module RDoc
@@all_classes = {}
@@all_modules = {}
- def TopLevel::reset
+ def self.reset
@@all_classes = {}
@@all_modules = {}
end
@@ -488,14 +488,15 @@ module RDoc
nil
end
- # Adding a class or module to a TopLevel is special, as we only
- # want one copy of a particular top-level class. For example,
- # if both file A and file B implement class C, we only want one
- # ClassModule object for C. This code arranges to share
- # classes and modules between files.
+ ##
+ # Adding a class or module to a TopLevel is special, as we only want one
+ # copy of a particular top-level class. For example, if both file A and
+ # file B implement class C, we only want one ClassModule object for C.
+ # This code arranges to share classes and modules between files.
def add_class_or_module(collection, class_type, name, superclass)
cls = collection[name]
+
if cls
puts "Reusing class/module #{name}" if $DEBUG_RDOC
else
@@ -504,23 +505,29 @@ module RDoc
else
all = @@all_classes
end
+
cls = all[name]
+
if !cls
cls = class_type.new(name, superclass)
- all[name] = cls unless @done_documenting
+ all[name] = cls unless @done_documenting
end
- puts "Adding class/module #{name} to #@name" if $DEBUG_RDOC
+
+ puts "Adding class/module #{name} to #{@name}" if $DEBUG_RDOC
+
collection[name] = cls unless @done_documenting
+
cls.parent = self
end
+
cls
end
- def TopLevel.all_classes_and_modules
+ def self.all_classes_and_modules
@@all_classes.values + @@all_modules.values
end
- def TopLevel.find_class_named(name)
+ def self.find_class_named(name)
@@all_classes.each_value do |c|
res = c.find_class_named(name)
return res if res
@@ -538,12 +545,13 @@ module RDoc
nil
end
+ ##
# Find a named module
+
def find_module_named(name)
find_class_or_module_named(name) || find_enclosing_module_named(name)
end
-
end
# ClassModule is the base class for objects representing either a
diff --git a/lib/rdoc/generator.rb b/lib/rdoc/generator.rb
index cf4bb3a6f1..7db23058e3 100644
--- a/lib/rdoc/generator.rb
+++ b/lib/rdoc/generator.rb
@@ -1,7 +1,7 @@
require 'cgi'
require 'rdoc'
require 'rdoc/options'
-require 'rdoc/markup/simple_markup'
+require 'rdoc/markup'
require 'rdoc/template'
module RDoc::Generator
diff --git a/lib/rdoc/generator/html.rb b/lib/rdoc/generator/html.rb
index 32f8235537..e6a6cd9ac9 100644
--- a/lib/rdoc/generator/html.rb
+++ b/lib/rdoc/generator/html.rb
@@ -1,7 +1,7 @@
require 'fileutils'
require 'rdoc/generator'
-require 'rdoc/markup/simple_markup/to_html'
+require 'rdoc/markup/to_html'
module RDoc::Generator
@@ -34,12 +34,11 @@ module RDoc::Generator
end
##
- # Subclass of the SM::ToHtml class that supports looking
- # up words in the AllReferences list. Those that are
- # found (like AllReferences in this comment) will
- # be hyperlinked
+ # Subclass of the RDoc::Markup::ToHtml class that supports looking up words
+ # in the AllReferences list. Those that are found (like AllReferences in
+ # this comment) will be hyperlinked
- class HyperlinkHtml < SM::ToHtml
+ class HyperlinkHtml < RDoc::Markup::ToHtml
##
# We need to record the html path of our caller so we can generate
@@ -161,13 +160,13 @@ module RDoc::Generator
##
# Convert a string in markup format into HTML. We keep a cached
- # SimpleMarkup object lying around after the first time we're
+ # RDoc::Markup object lying around after the first time we're
# called per object.
def markup(str, remove_para=false)
return '' unless str
unless defined? @markup
- @markup = SM::SimpleMarkup.new
+ @markup = RDoc::Markup.new
# class names, variable names, or instance variables
@markup.add_special(/(
diff --git a/lib/rdoc/generator/ri.rb b/lib/rdoc/generator/ri.rb
index bb0c4f4021..2452d79132 100644
--- a/lib/rdoc/generator/ri.rb
+++ b/lib/rdoc/generator/ri.rb
@@ -1,5 +1,5 @@
require 'rdoc/generator'
-require 'rdoc/markup/simple_markup/to_flow'
+require 'rdoc/markup/to_flow'
require 'rdoc/ri/cache'
require 'rdoc/ri/reader'
@@ -26,8 +26,8 @@ class RDoc::Generator::RI
def initialize(options) #:not-new:
@options = options
@ri_writer = RDoc::RI::Writer.new "."
- @markup = SM::SimpleMarkup.new
- @to_flow = SM::ToFlow.new
+ @markup = RDoc::Markup.new
+ @to_flow = RDoc::Markup::ToFlow.new
@generated = {}
end
@@ -38,7 +38,7 @@ class RDoc::Generator::RI
def generate(toplevels)
RDoc::TopLevel.all_classes_and_modules.each do |cls|
- process_class(cls)
+ process_class cls
end
end
@@ -58,6 +58,7 @@ class RDoc::Generator::RI
cls_desc = RDoc::RI::ClassDescription.new
cls_desc.superclass = cls.superclass
end
+
cls_desc.name = cls.name
cls_desc.full_name = cls.full_name
cls_desc.comment = markup(cls.comment)
diff --git a/lib/rdoc/markup.rb b/lib/rdoc/markup.rb
new file mode 100644
index 0000000000..46654ebb58
--- /dev/null
+++ b/lib/rdoc/markup.rb
@@ -0,0 +1,466 @@
+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,
+# chunks of verbatim text, list entries and the like. Other parts happen at
+# the character level: a piece of bold text, a word in code font. This markup
+# 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 is extendable at runtime: you can add new markup elements to be
+# recognised in the documents that RDoc::Markup parses.
+#
+# RDoc::Markup is intended to be the basis for a family of tools which share
+# the common requirement that simple, plain-text should be rendered in a
+# variety of different output formats and media. It is envisaged that
+# RDoc::Markup could be the basis for formating RDoc style comment blocks,
+# Wiki entries, and online FAQs.
+#
+# = Basic Formatting
+#
+# * RDoc::Markup looks for a document's natural left margin. This is
+# used as the initial margin for the document.
+#
+# * Consecutive lines starting at this margin are considered to be a
+# paragraph.
+#
+# * If a paragraph starts with a "*", "-", or with "<digit>.", then it is
+# taken to be the start of a list. The margin in increased to be the
+# first non-space following the list start flag. Subsequent lines
+# should be indented to this new margin until the list ends. For
+# example:
+#
+# * this is a list with three paragraphs in
+# the first item. This is the first paragraph.
+#
+# And this is the second paragraph.
+#
+# 1. This is an indented, numbered list.
+# 2. This is the second item in that list
+#
+# This is the third conventional paragraph in the
+# first list item.
+#
+# * This is the second item in the original list
+#
+# * You can also construct labeled lists, sometimes called description
+# or definition lists. Do this by putting the label in square brackets
+# and indenting the list body:
+#
+# [cat] a small furry mammal
+# that seems to sleep a lot
+#
+# [ant] a little insect that is known
+# to enjoy picnics
+#
+# A minor variation on labeled lists uses two colons to separate the
+# label from the list body:
+#
+# cat:: a small furry mammal
+# that seems to sleep a lot
+#
+# ant:: a little insect that is known
+# to enjoy picnics
+#
+# This latter style guarantees that the list bodies' left margins are
+# aligned: think of them as a two column table.
+#
+# * Any line that starts to the right of the current margin is treated
+# as verbatim text. This is useful for code listings. The example of a
+# list above is also verbatim text.
+#
+# * A line starting with an equals sign (=) is treated as a
+# heading. Level one headings have one equals sign, level two headings
+# have two,and so on.
+#
+# * A line starting with three or more hyphens (at the current indent)
+# generates a horizontal rule. The more hyphens, the thicker the rule
+# (within reason, and if supported by the output device)
+#
+# * You can use markup within text (except verbatim) to change the
+# appearance of parts of that text. Out of the box, RDoc::Markup
+# supports word-based and general markup.
+#
+# Word-based markup uses flag characters around individual words:
+#
+# [\*word*] displays word in a *bold* font
+# [\_word_] displays word in an _emphasized_ font
+# [\+word+] displays word in a +code+ font
+#
+# General markup affects text between a start delimiter and and end
+# delimiter. Not surprisingly, these delimiters look like HTML markup.
+#
+# [\<b>text...</b>] displays word in a *bold* font
+# [\<em>text...</em>] displays word in an _emphasized_ font
+# [\<i>text...</i>] displays word in an _emphasized_ font
+# [\<tt>text...</tt>] displays word in a +code+ font
+#
+# Unlike conventional Wiki markup, general markup can cross line
+# boundaries. You can turn off the interpretation of markup by
+# preceding the first character with a backslash, so \\\<b>bold
+# text</b> and \\\*bold* produce \<b>bold text</b> and \*bold
+# respectively.
+#
+# * Hyperlinks to the web starting http:, mailto:, ftp:, or www. are
+# recognized. An HTTP url that references an external image file is
+# converted into an inline <IMG..>. Hyperlinks starting 'link:' are
+# assumed to refer to local files whose path is relative to the --op
+# directory.
+#
+# Hyperlinks can also be of the form <tt>label</tt>[url], in which
+# case the label is used in the displayed text, and <tt>url</tt> is
+# used as the target. If <tt>label</tt> contains multiple words,
+# put it in braces: <em>{multi word label}[</em>url<em>]</em>.
+#
+# == Synopsis
+#
+# This code converts <tt>input_string</tt> to HTML. The conversion
+# takes place in the +convert+ method, so you can use the same
+# RDoc::Markup object to convert multiple input strings.
+#
+# require 'rdoc/markup'
+# require 'rdoc/markup/to_html'
+#
+# p = RDoc::Markup.new
+# h = RDoc::Markup::ToHtml.new
+#
+# puts p.convert(input_string, h)
+#
+# You can extend the RDoc::Markup parser to recognise new markup
+# sequences, and to add special processing for text that matches a
+# regular epxression. Here we make WikiWords significant to the parser,
+# and also make the sequences {word} and \<no>text...</no> signify
+# strike-through text. When then subclass the HTML output class to deal
+# with these:
+#
+# require 'rdoc/markup'
+# require 'rdoc/markup/to_html'
+#
+# class WikiHtml < RDoc::Markup::ToHtml
+# def handle_special_WIKIWORD(special)
+# "<font color=red>" + special.text + "</font>"
+# end
+# end
+#
+# p = RDoc::Markup.new
+# p.add_word_pair("{", "}", :STRIKE)
+# p.add_html("no", :STRIKE)
+#
+# p.add_special(/\b([A-Z][a-z]+[A-Z]\w+)/, :WIKIWORD)
+#
+# h = WikiHtml.new
+# h.add_tag(:STRIKE, "<strike>", "</strike>")
+#
+# puts "<body>" + p.convert(ARGF.read, h) + "</body>"
+#
+#--
+# Author:: Dave Thomas, dave@pragmaticprogrammer.com
+# Version:: 0.0
+# License:: Ruby license
+
+class RDoc::Markup
+
+ SPACE = ?\s
+
+ # List entries look like:
+ # * text
+ # 1. text
+ # [label] text
+ # label:: text
+ #
+ # Flag it as a list entry, and work out the indent for subsequent lines
+
+ SIMPLE_LIST_RE = /^(
+ ( \* (?# bullet)
+ |- (?# bullet)
+ |\d+\. (?# numbered )
+ |[A-Za-z]\. (?# alphabetically numbered )
+ )
+ \s+
+ )\S/x
+
+ LABEL_LIST_RE = /^(
+ ( \[.*?\] (?# labeled )
+ |\S.*:: (?# note )
+ )(?:\s+|$)
+ )/x
+
+ ##
+ # Take a block of text and use various heuristics to determine it's
+ # structure (paragraphs, lists, and so on). Invoke an event handler as we
+ # identify significant chunks.
+
+ def initialize
+ @am = AttributeManager.new
+ @output = nil
+ end
+
+ ##
+ # Add to the sequences used to add formatting to an individual word (such
+ # as *bold*). Matching entries will generate attibutes that the output
+ # formatters can recognize by their +name+.
+
+ def add_word_pair(start, stop, name)
+ @am.add_word_pair(start, stop, name)
+ end
+
+ ##
+ # Add to the sequences recognized as general markup.
+
+ def add_html(tag, name)
+ @am.add_html(tag, name)
+ end
+
+ ##
+ # Add to other inline sequences. For example, we could add WikiWords using
+ # something like:
+ #
+ # parser.add_special(/\b([A-Z][a-z]+[A-Z]\w+)/, :WIKIWORD)
+ #
+ # Each wiki word will be presented to the output formatter via the
+ # accept_special method.
+
+ def add_special(pattern, name)
+ @am.add_special(pattern, name)
+ end
+
+ ##
+ # We take a string, split it into lines, work out the type of each line,
+ # and from there deduce groups of lines (for example all lines in a
+ # paragraph). We then invoke the output formatter using a Visitor to
+ # display the result.
+
+ def convert(str, op)
+ @lines = Lines.new(str.split(/\r?\n/).collect { |aLine|
+ Line.new(aLine) })
+ return "" if @lines.empty?
+ @lines.normalize
+ assign_types_to_lines
+ group = group_lines
+ # call the output formatter to handle the result
+ # group.to_a.each {|i| p i}
+ group.accept(@am, op)
+ end
+
+ private
+
+ ##
+ # Look through the text at line indentation. We flag each line as being
+ # Blank, a paragraph, a list element, or verbatim text.
+
+ def assign_types_to_lines(margin = 0, level = 0)
+
+ while line = @lines.next
+ if line.isBlank?
+ line.stamp(Line::BLANK, level)
+ next
+ end
+
+ # if a line contains non-blanks before the margin, then it must belong
+ # to an outer level
+
+ text = line.text
+
+ for i in 0...margin
+ if text[i] != SPACE
+ @lines.unget
+ return
+ end
+ end
+
+ active_line = text[margin..-1]
+
+ # Rules (horizontal lines) look like
+ #
+ # --- (three or more hyphens)
+ #
+ # The more hyphens, the thicker the rule
+ #
+
+ if /^(---+)\s*$/ =~ active_line
+ line.stamp(Line::RULE, level, $1.length-2)
+ next
+ end
+
+ # Then look for list entries. First the ones that have to have
+ # text following them (* xxx, - xxx, and dd. xxx)
+
+ if SIMPLE_LIST_RE =~ active_line
+
+ offset = margin + $1.length
+ prefix = $2
+ prefix_length = prefix.length
+
+ flag = case prefix
+ when "*","-" then ListBase::BULLET
+ when /^\d/ then ListBase::NUMBER
+ when /^[A-Z]/ then ListBase::UPPERALPHA
+ when /^[a-z]/ then ListBase::LOWERALPHA
+ else raise "Invalid List Type: #{self.inspect}"
+ end
+
+ line.stamp(Line::LIST, level+1, prefix, flag)
+ text[margin, prefix_length] = " " * prefix_length
+ assign_types_to_lines(offset, level + 1)
+ next
+ end
+
+
+ if LABEL_LIST_RE =~ active_line
+ offset = margin + $1.length
+ prefix = $2
+ prefix_length = prefix.length
+
+ next if handled_labeled_list(line, level, margin, offset, prefix)
+ end
+
+ # Headings look like
+ # = Main heading
+ # == Second level
+ # === Third
+ #
+ # Headings reset the level to 0
+
+ if active_line[0] == ?= and active_line =~ /^(=+)\s*(.*)/
+ prefix_length = $1.length
+ prefix_length = 6 if prefix_length > 6
+ line.stamp(Line::HEADING, 0, prefix_length)
+ line.strip_leading(margin + prefix_length)
+ next
+ end
+
+ # If the character's a space, then we have verbatim text,
+ # otherwise
+
+ if active_line[0] == SPACE
+ line.strip_leading(margin) if margin > 0
+ line.stamp(Line::VERBATIM, level)
+ else
+ line.stamp(Line::PARAGRAPH, level)
+ end
+ end
+ end
+
+ ##
+ # Handle labeled list entries, We have a special case to deal with.
+ # Because the labels can be long, they force the remaining block of text
+ # over the to right:
+ #
+ # this is a long label that I wrote:: and here is the
+ # block of text with
+ # a silly margin
+ #
+ # So we allow the special case. If the label is followed by nothing, and
+ # if the following line is indented, then we take the indent of that line
+ # as the new margin.
+ #
+ # this is a long label that I wrote::
+ # here is a more reasonably indented block which
+ # will be attached to the label.
+ #
+
+ def handled_labeled_list(line, level, margin, offset, prefix)
+ prefix_length = prefix.length
+ text = line.text
+ flag = nil
+ case prefix
+ when /^\[/
+ flag = ListBase::LABELED
+ prefix = prefix[1, prefix.length-2]
+ when /:$/
+ flag = ListBase::NOTE
+ prefix.chop!
+ else raise "Invalid List Type: #{self.inspect}"
+ end
+
+ # body is on the next line
+
+ if text.length <= offset
+ original_line = line
+ line = @lines.next
+ return(false) unless line
+ text = line.text
+
+ for i in 0..margin
+ if text[i] != SPACE
+ @lines.unget
+ return false
+ end
+ end
+ i = margin
+ i += 1 while text[i] == SPACE
+ if i >= text.length
+ @lines.unget
+ return false
+ else
+ offset = i
+ prefix_length = 0
+ @lines.delete(original_line)
+ end
+ end
+
+ line.stamp(Line::LIST, level+1, prefix, flag)
+ text[margin, prefix_length] = " " * prefix_length
+ assign_types_to_lines(offset, level + 1)
+ return true
+ end
+
+ ##
+ # Return a block consisting of fragments which are paragraphs, list
+ # entries or verbatim text. We merge consecutive lines of the same type
+ # and level together. We are also slightly tricky with lists: the lines
+ # following a list introduction look like paragraph lines at the next
+ # level, and we remap them into list entries instead.
+
+ def group_lines
+ @lines.rewind
+
+ inList = false
+ wantedType = wantedLevel = nil
+
+ block = LineCollection.new
+ group = nil
+
+ while line = @lines.next
+ if line.level == wantedLevel and line.type == wantedType
+ group.add_text(line.text)
+ else
+ group = block.fragment_for(line)
+ block.add(group)
+ if line.type == Line::LIST
+ wantedType = Line::PARAGRAPH
+ else
+ wantedType = line.type
+ end
+ wantedLevel = line.type == Line::HEADING ? line.param : line.level
+ end
+ end
+
+ block.normalize
+ block
+ end
+
+ ##
+ # For debugging, we allow access to our line contents as text.
+
+ def content
+ @lines.as_text
+ end
+ public :content
+
+ ##
+ # For debugging, return the list of line types.
+
+ def get_line_types
+ @lines.line_types
+ end
+ public :get_line_types
+
+end
+
+require 'rdoc/markup/fragments'
+require 'rdoc/markup/lines'
diff --git a/lib/rdoc/markup/.document b/lib/rdoc/markup/.document
deleted file mode 100644
index 3cf4f21bd7..0000000000
--- a/lib/rdoc/markup/.document
+++ /dev/null
@@ -1,2 +0,0 @@
-simple_markup
-simple_markup.rb
diff --git a/lib/rdoc/markup/simple_markup/fragments.rb b/lib/rdoc/markup/fragments.rb
index bd60ca0fec..2dd3614fc1 100644
--- a/lib/rdoc/markup/simple_markup/fragments.rb
+++ b/lib/rdoc/markup/fragments.rb
@@ -1,6 +1,7 @@
-require 'rdoc/markup/simple_markup/lines.rb'
+require 'rdoc/markup'
+require 'rdoc/markup/lines'
-module SM
+class RDoc::Markup
##
# A Fragment is a chunk of text, subclassed as a paragraph, a list
@@ -119,7 +120,7 @@ module SM
##
# Collect groups of lines together. Each group will end up containing a flow
- # of text
+ # of text.
class LineCollection
diff --git a/lib/rdoc/markup/simple_markup/inline.rb b/lib/rdoc/markup/inline.rb
index eafda011e8..cbf5032a68 100644
--- a/lib/rdoc/markup/simple_markup/inline.rb
+++ b/lib/rdoc/markup/inline.rb
@@ -1,8 +1,10 @@
-module SM
+require 'rdoc/markup'
+
+class RDoc::Markup
##
# We manage a set of attributes. Each attribute has a symbol name and a bit
- # value
+ # value.
class Attribute
SPECIAL = 1
@@ -39,7 +41,7 @@ module SM
##
# 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
+ # attributes to turn on, and a bitmap of those to turn off.
AttrChanger = Struct.new(:turn_on, :turn_off)
@@ -50,7 +52,7 @@ module SM
end
##
- # An array of attributes which parallels the characters in a string
+ # An array of attributes which parallels the characters in a string.
class AttrSpan
def initialize(length)
@@ -84,12 +86,12 @@ module SM
end
def to_s
- "Special: type=#{type}, name=#{SM::Attribute.as_string type}, text=#{text.dump}"
+ "Special: type=#{type}, name=#{RDoc::Markup::Attribute.as_string type}, text=#{text.dump}"
end
def inspect
- "#<SM::Special:0x%x @type=%p, name=%p @text=%p>" % [
- object_id, @type, SM::Attribute.as_string(type), text.dump]
+ "#<RDoc::Markup::Special:0x%x @type=%p, name=%p @text=%p>" % [
+ object_id, @type, RDoc::Markup::Attribute.as_string(type), text.dump]
end
end
diff --git a/lib/rdoc/markup/simple_markup/lines.rb b/lib/rdoc/markup/lines.rb
index 8ef66079b2..5fb5bde993 100644
--- a/lib/rdoc/markup/simple_markup/lines.rb
+++ b/lib/rdoc/markup/lines.rb
@@ -1,4 +1,4 @@
-module SM
+class RDoc::Markup
##
# We store the lines we're working on as objects of class Line. These
@@ -14,7 +14,7 @@ module SM
RULE = :RULE
PARAGRAPH = :PARAGRAPH
VERBATIM = :VERBATIM
-
+
# line type
attr_accessor :type
@@ -36,7 +36,6 @@ module SM
# true if this line has been deleted from the list of lines
attr_accessor :deleted
-
def initialize(text)
@text = text.dup
@@ -69,7 +68,6 @@ module SM
##
# Strip off the leading margin
- #
def strip_leading(size)
if @text.size > size
@@ -85,7 +83,7 @@ module SM
end
##
- # A container for all the lines
+ # A container for all the lines.
class Lines
diff --git a/lib/rdoc/markup/preprocess.rb b/lib/rdoc/markup/preprocess.rb
new file mode 100644
index 0000000000..760351d386
--- /dev/null
+++ b/lib/rdoc/markup/preprocess.rb
@@ -0,0 +1,71 @@
+require 'rdoc/markup'
+
+##
+# Handle common directives that can occur in a block of text:
+#
+# : include : filename
+
+class RDoc::Markup::PreProcess
+
+ def initialize(input_file_name, include_path)
+ @input_file_name = input_file_name
+ @include_path = include_path
+ end
+
+ ##
+ # Look for common options in a chunk of text. Options that we don't handle
+ # are passed back to our caller as |directive, param|
+
+ def handle(text)
+ text.gsub!(/^([ \t#]*):(\w+):\s*(.+)?\n/) do
+ prefix = $1
+ directive = $2.downcase
+ param = $3
+
+ case directive
+ when "include"
+ filename = param.split[0]
+ include_file(filename, prefix)
+
+ else
+ yield(directive, param)
+ end
+ end
+ end
+
+ private
+
+ ##
+ # Include a file, indenting it correctly.
+
+ def include_file(name, indent)
+ if full_name = find_include_file(name) then
+ content = File.open(full_name) {|f| f.read}
+ # strip leading '#'s, but only if all lines start with them
+ if content =~ /^[^#]/
+ content.gsub(/^/, indent)
+ else
+ content.gsub(/^#?/, indent)
+ end
+ else
+ $stderr.puts "Couldn't find file to include: '#{name}'"
+ ''
+ end
+ end
+
+ ##
+ # Look for the given file in the directory containing the current file,
+ # and then in each of the directories specified in the RDOC_INCLUDE path
+
+ def find_include_file(name)
+ to_search = [ File.dirname(@input_file_name) ].concat @include_path
+ to_search.each do |dir|
+ full_name = File.join(dir, name)
+ stat = File.stat(full_name) rescue next
+ return full_name if stat.readable?
+ end
+ nil
+ end
+
+end
+
diff --git a/lib/rdoc/markup/simple_markup.rb b/lib/rdoc/markup/simple_markup.rb
deleted file mode 100644
index ed3b4d3270..0000000000
--- a/lib/rdoc/markup/simple_markup.rb
+++ /dev/null
@@ -1,463 +0,0 @@
-require 'rdoc/markup/simple_markup/fragments'
-require 'rdoc/markup/simple_markup/lines.rb'
-
-##
-# SimpleMarkup parses plain text documents and attempts to decompose
-# them into their constituent parts. Some of these parts are high-level:
-# paragraphs, chunks of verbatim text, list entries and the like. Other
-# parts happen at the character level: a piece of bold text, a word in
-# code font. This markup is similar in spirit to that used on WikiWiki
-# webs, where folks create web pages using a simple set of formatting
-# rules.
-#
-# SimpleMarkup itself does no output formatting: this is left to a
-# different set of classes.
-#
-# SimpleMarkup is extendable at runtime: you can add new markup
-# elements to be recognised in the documents that SimpleMarkup parses.
-#
-# SimpleMarkup 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 variety of different output formats and media. It is
-# envisaged that SimpleMarkup could be the basis for formating RDoc
-# style comment blocks, Wiki entries, and online FAQs.
-#
-# = Basic Formatting
-#
-# * SimpleMarkup looks for a document's natural left margin. This is
-# used as the initial margin for the document.
-#
-# * Consecutive lines starting at this margin are considered to be a
-# paragraph.
-#
-# * If a paragraph starts with a "*", "-", or with "<digit>.", then it is
-# taken to be the start of a list. The margin in increased to be the
-# first non-space following the list start flag. Subsequent lines
-# should be indented to this new margin until the list ends. For
-# example:
-#
-# * this is a list with three paragraphs in
-# the first item. This is the first paragraph.
-#
-# And this is the second paragraph.
-#
-# 1. This is an indented, numbered list.
-# 2. This is the second item in that list
-#
-# This is the third conventional paragraph in the
-# first list item.
-#
-# * This is the second item in the original list
-#
-# * You can also construct labeled lists, sometimes called description
-# or definition lists. Do this by putting the label in square brackets
-# and indenting the list body:
-#
-# [cat] a small furry mammal
-# that seems to sleep a lot
-#
-# [ant] a little insect that is known
-# to enjoy picnics
-#
-# A minor variation on labeled lists uses two colons to separate the
-# label from the list body:
-#
-# cat:: a small furry mammal
-# that seems to sleep a lot
-#
-# ant:: a little insect that is known
-# to enjoy picnics
-#
-# This latter style guarantees that the list bodies' left margins are
-# aligned: think of them as a two column table.
-#
-# * Any line that starts to the right of the current margin is treated
-# as verbatim text. This is useful for code listings. The example of a
-# list above is also verbatim text.
-#
-# * A line starting with an equals sign (=) is treated as a
-# heading. Level one headings have one equals sign, level two headings
-# have two,and so on.
-#
-# * A line starting with three or more hyphens (at the current indent)
-# generates a horizontal rule. THe more hyphens, the thicker the rule
-# (within reason, and if supported by the output device)
-#
-# * You can use markup within text (except verbatim) to change the
-# appearance of parts of that text. Out of the box, SimpleMarkup
-# supports word-based and general markup.
-#
-# Word-based markup uses flag characters around individual words:
-#
-# [\*word*] displays word in a *bold* font
-# [\_word_] displays word in an _emphasized_ font
-# [\+word+] displays word in a +code+ font
-#
-# General markup affects text between a start delimiter and and end
-# delimiter. Not surprisingly, these delimiters look like HTML markup.
-#
-# [\<b>text...</b>] displays word in a *bold* font
-# [\<em>text...</em>] displays word in an _emphasized_ font
-# [\<i>text...</i>] displays word in an _emphasized_ font
-# [\<tt>text...</tt>] displays word in a +code+ font
-#
-# Unlike conventional Wiki markup, general markup can cross line
-# boundaries. You can turn off the interpretation of markup by
-# preceding the first character with a backslash, so \\\<b>bold
-# text</b> and \\\*bold* produce \<b>bold text</b> and \*bold
-# respectively.
-#
-# = Using SimpleMarkup
-#
-# For information on using SimpleMarkup programatically, see SM::SimpleMarkup.
-#--
-# Author:: Dave Thomas, dave@pragmaticprogrammer.com
-# Version:: 0.0
-# License:: Ruby license
-
-module SM
-
- # == Synopsis
- #
- # This code converts <tt>input_string</tt>, which is in the format
- # described in markup/simple_markup.rb, to HTML. The conversion
- # takes place in the +convert+ method, so you can use the same
- # SimpleMarkup object to convert multiple input strings.
- #
- # require 'rdoc/markup/simple_markup'
- # require 'rdoc/markup/simple_markup/to_html'
- #
- # p = SM::SimpleMarkup.new
- # h = SM::ToHtml.new
- #
- # puts p.convert(input_string, h)
- #
- # You can extend the SimpleMarkup parser to recognise new markup
- # sequences, and to add special processing for text that matches a
- # regular epxression. Here we make WikiWords significant to the parser,
- # and also make the sequences {word} and \<no>text...</no> signify
- # strike-through text. When then subclass the HTML output class to deal
- # with these:
- #
- # require 'rdoc/markup/simple_markup'
- # require 'rdoc/markup/simple_markup/to_html'
- #
- # class WikiHtml < SM::ToHtml
- # def handle_special_WIKIWORD(special)
- # "<font color=red>" + special.text + "</font>"
- # end
- # end
- #
- # p = SM::SimpleMarkup.new
- # p.add_word_pair("{", "}", :STRIKE)
- # p.add_html("no", :STRIKE)
- #
- # p.add_special(/\b([A-Z][a-z]+[A-Z]\w+)/, :WIKIWORD)
- #
- # h = WikiHtml.new
- # h.add_tag(:STRIKE, "<strike>", "</strike>")
- #
- # puts "<body>" + p.convert(ARGF.read, h) + "</body>"
-
- class SimpleMarkup
-
- SPACE = ?\s
-
- # List entries look like:
- # * text
- # 1. text
- # [label] text
- # label:: text
- #
- # Flag it as a list entry, and work out the indent for subsequent lines
-
- SIMPLE_LIST_RE = /^(
- ( \* (?# bullet)
- |- (?# bullet)
- |\d+\. (?# numbered )
- |[A-Za-z]\. (?# alphabetically numbered )
- )
- \s+
- )\S/x
-
- LABEL_LIST_RE = /^(
- ( \[.*?\] (?# labeled )
- |\S.*:: (?# note )
- )(?:\s+|$)
- )/x
-
- ##
- # Take a block of text and use various heuristics to determine it's
- # structure (paragraphs, lists, and so on). Invoke an event handler as we
- # identify significant chunks.
-
- def initialize
- @am = AttributeManager.new
- @output = nil
- end
-
- ##
- # Add to the sequences used to add formatting to an individual word (such
- # as *bold*). Matching entries will generate attibutes that the output
- # formatters can recognize by their +name+.
-
- def add_word_pair(start, stop, name)
- @am.add_word_pair(start, stop, name)
- end
-
- ##
- # Add to the sequences recognized as general markup.
-
- def add_html(tag, name)
- @am.add_html(tag, name)
- end
-
- ##
- # Add to other inline sequences. For example, we could add WikiWords using
- # something like:
- #
- # parser.add_special(/\b([A-Z][a-z]+[A-Z]\w+)/, :WIKIWORD)
- #
- # Each wiki word will be presented to the output formatter via the
- # accept_special method.
-
- def add_special(pattern, name)
- @am.add_special(pattern, name)
- end
-
- ##
- # We take a string, split it into lines, work out the type of each line,
- # and from there deduce groups of lines (for example all lines in a
- # paragraph). We then invoke the output formatter using a Visitor to
- # display the result.
-
- def convert(str, op)
- @lines = Lines.new(str.split(/\r?\n/).collect { |aLine|
- Line.new(aLine) })
- return "" if @lines.empty?
- @lines.normalize
- assign_types_to_lines
- group = group_lines
- # call the output formatter to handle the result
- # group.to_a.each {|i| p i}
- group.accept(@am, op)
- end
-
- private
-
- ##
- # Look through the text at line indentation. We flag each line as being
- # Blank, a paragraph, a list element, or verbatim text.
-
- def assign_types_to_lines(margin = 0, level = 0)
-
- while line = @lines.next
- if line.isBlank?
- line.stamp(Line::BLANK, level)
- next
- end
-
- # if a line contains non-blanks before the margin, then it must belong
- # to an outer level
-
- text = line.text
-
- for i in 0...margin
- if text[i] != SPACE
- @lines.unget
- return
- end
- end
-
- active_line = text[margin..-1]
-
- # Rules (horizontal lines) look like
- #
- # --- (three or more hyphens)
- #
- # The more hyphens, the thicker the rule
- #
-
- if /^(---+)\s*$/ =~ active_line
- line.stamp(Line::RULE, level, $1.length-2)
- next
- end
-
- # Then look for list entries. First the ones that have to have
- # text following them (* xxx, - xxx, and dd. xxx)
-
- if SIMPLE_LIST_RE =~ active_line
-
- offset = margin + $1.length
- prefix = $2
- prefix_length = prefix.length
-
- flag = case prefix
- when "*","-" then ListBase::BULLET
- when /^\d/ then ListBase::NUMBER
- when /^[A-Z]/ then ListBase::UPPERALPHA
- when /^[a-z]/ then ListBase::LOWERALPHA
- else raise "Invalid List Type: #{self.inspect}"
- end
-
- line.stamp(Line::LIST, level+1, prefix, flag)
- text[margin, prefix_length] = " " * prefix_length
- assign_types_to_lines(offset, level + 1)
- next
- end
-
-
- if LABEL_LIST_RE =~ active_line
- offset = margin + $1.length
- prefix = $2
- prefix_length = prefix.length
-
- next if handled_labeled_list(line, level, margin, offset, prefix)
- end
-
- # Headings look like
- # = Main heading
- # == Second level
- # === Third
- #
- # Headings reset the level to 0
-
- if active_line[0] == ?= and active_line =~ /^(=+)\s*(.*)/
- prefix_length = $1.length
- prefix_length = 6 if prefix_length > 6
- line.stamp(Line::HEADING, 0, prefix_length)
- line.strip_leading(margin + prefix_length)
- next
- end
-
- # If the character's a space, then we have verbatim text,
- # otherwise
-
- if active_line[0] == SPACE
- line.strip_leading(margin) if margin > 0
- line.stamp(Line::VERBATIM, level)
- else
- line.stamp(Line::PARAGRAPH, level)
- end
- end
- end
-
- ##
- # Handle labeled list entries, We have a special case to deal with.
- # Because the labels can be long, they force the remaining block of text
- # over the to right:
- #
- # this is a long label that I wrote:: and here is the
- # block of text with
- # a silly margin
- #
- # So we allow the special case. If the label is followed by nothing, and
- # if the following line is indented, then we take the indent of that line
- # as the new margin.
- #
- # this is a long label that I wrote::
- # here is a more reasonably indented block which
- # will be attached to the label.
- #
-
- def handled_labeled_list(line, level, margin, offset, prefix)
- prefix_length = prefix.length
- text = line.text
- flag = nil
- case prefix
- when /^\[/
- flag = ListBase::LABELED
- prefix = prefix[1, prefix.length-2]
- when /:$/
- flag = ListBase::NOTE
- prefix.chop!
- else raise "Invalid List Type: #{self.inspect}"
- end
-
- # body is on the next line
-
- if text.length <= offset
- original_line = line
- line = @lines.next
- return(false) unless line
- text = line.text
-
- for i in 0..margin
- if text[i] != SPACE
- @lines.unget
- return false
- end
- end
- i = margin
- i += 1 while text[i] == SPACE
- if i >= text.length
- @lines.unget
- return false
- else
- offset = i
- prefix_length = 0
- @lines.delete(original_line)
- end
- end
-
- line.stamp(Line::LIST, level+1, prefix, flag)
- text[margin, prefix_length] = " " * prefix_length
- assign_types_to_lines(offset, level + 1)
- return true
- end
-
- ##
- # Return a block consisting of fragments which are paragraphs, list
- # entries or verbatim text. We merge consecutive lines of the same type
- # and level together. We are also slightly tricky with lists: the lines
- # following a list introduction look like paragraph lines at the next
- # level, and we remap them into list entries instead.
-
- def group_lines
- @lines.rewind
-
- inList = false
- wantedType = wantedLevel = nil
-
- block = LineCollection.new
- group = nil
-
- while line = @lines.next
- if line.level == wantedLevel and line.type == wantedType
- group.add_text(line.text)
- else
- group = block.fragment_for(line)
- block.add(group)
- if line.type == Line::LIST
- wantedType = Line::PARAGRAPH
- else
- wantedType = line.type
- end
- wantedLevel = line.type == Line::HEADING ? line.param : line.level
- end
- end
-
- block.normalize
- block
- end
-
- ##
- # For debugging, we allow access to our line contents as text.
-
- def content
- @lines.as_text
- end
- public :content
-
- ##
- # For debugging, return the list of line types.
-
- def get_line_types
- @lines.line_types
- end
- public :get_line_types
-
- end
-
-end
-
diff --git a/lib/rdoc/markup/simple_markup/preprocess.rb b/lib/rdoc/markup/simple_markup/preprocess.rb
deleted file mode 100644
index c7d29ad48f..0000000000
--- a/lib/rdoc/markup/simple_markup/preprocess.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-module SM
-
- ##
- # Handle common directives that can occur in a block of text:
- #
- # : include : filename
-
- class PreProcess
-
- def initialize(input_file_name, include_path)
- @input_file_name = input_file_name
- @include_path = include_path
- end
-
- ##
- # Look for common options in a chunk of text. Options that we don't handle
- # are passed back to our caller as |directive, param|
-
- def handle(text)
- text.gsub!(/^([ \t#]*):(\w+):\s*(.+)?\n/) do
- prefix = $1
- directive = $2.downcase
- param = $3
-
- case directive
- when "include"
- filename = param.split[0]
- include_file(filename, prefix)
-
- else
- yield(directive, param)
- end
- end
- end
-
- private
-
- ##
- # Include a file, indenting it correctly.
-
- def include_file(name, indent)
- if (full_name = find_include_file(name))
- content = File.open(full_name) {|f| f.read}
- # strip leading '#'s, but only if all lines start with them
- if content =~ /^[^#]/
- content.gsub(/^/, indent)
- else
- content.gsub(/^#?/, indent)
- end
- else
- $stderr.puts "Couldn't find file to include: '#{name}'"
- ''
- end
- end
-
- ##
- # Look for the given file in the directory containing the current file,
- # and then in each of the directories specified in the RDOC_INCLUDE path
-
- def find_include_file(name)
- to_search = [ File.dirname(@input_file_name) ].concat @include_path
- to_search.each do |dir|
- full_name = File.join(dir, name)
- stat = File.stat(full_name) rescue next
- return full_name if stat.readable?
- end
- nil
- end
-
- end
-
-end
-
diff --git a/lib/rdoc/markup/simple_markup/to_html.rb b/lib/rdoc/markup/simple_markup/to_html.rb
deleted file mode 100644
index d78468684f..0000000000
--- a/lib/rdoc/markup/simple_markup/to_html.rb
+++ /dev/null
@@ -1,287 +0,0 @@
-require 'rdoc/markup/simple_markup/fragments'
-require 'rdoc/markup/simple_markup/inline'
-
-require 'cgi'
-
-module SM
-
- class ToHtml
-
- LIST_TYPE_TO_HTML = {
- ListBase::BULLET => [ "<ul>", "</ul>" ],
- ListBase::NUMBER => [ "<ol>", "</ol>" ],
- ListBase::UPPERALPHA => [ "<ol>", "</ol>" ],
- ListBase::LOWERALPHA => [ "<ol>", "</ol>" ],
- ListBase::LABELED => [ "<dl>", "</dl>" ],
- ListBase::NOTE => [ "<table>", "</table>" ],
- }
-
- InlineTag = Struct.new(:bit, :on, :off)
-
- def initialize
- init_tags
- end
-
- ##
- # Set up the standard mapping of attributes to HTML tags
-
- def init_tags
- @attr_tags = [
- InlineTag.new(SM::Attribute.bitmap_for(:BOLD), "<b>", "</b>"),
- InlineTag.new(SM::Attribute.bitmap_for(:TT), "<tt>", "</tt>"),
- InlineTag.new(SM::Attribute.bitmap_for(:EM), "<em>", "</em>"),
- ]
- end
-
- ##
- # Add a new set of HTML tags for an attribute. We allow separate start and
- # end tags for flexibility.
-
- def add_tag(name, start, stop)
- @attr_tags << InlineTag.new(SM::Attribute.bitmap_for(name), start, stop)
- end
-
- ##
- # Given an HTML tag, decorate it with class information and the like if
- # required. This is a no-op in the base class, but is overridden in HTML
- # output classes that implement style sheets.
-
- def annotate(tag)
- tag
- end
-
- ##
- # Here's the client side of the visitor pattern
-
- def start_accepting
- @res = ""
- @in_list_entry = []
- end
-
- def end_accepting
- @res
- end
-
- def accept_paragraph(am, fragment)
- @res << annotate("<p>") + "\n"
- @res << wrap(convert_flow(am.flow(fragment.txt)))
- @res << annotate("</p>") + "\n"
- end
-
- def accept_verbatim(am, fragment)
- @res << annotate("<pre>") + "\n"
- @res << CGI.escapeHTML(fragment.txt)
- @res << annotate("</pre>") << "\n"
- end
-
- def accept_rule(am, fragment)
- size = fragment.param
- size = 10 if size > 10
- @res << "<hr size=\"#{size}\"></hr>"
- end
-
- def accept_list_start(am, fragment)
- @res << html_list_name(fragment.type, true) << "\n"
- @in_list_entry.push false
- end
-
- def accept_list_end(am, fragment)
- if tag = @in_list_entry.pop
- @res << annotate(tag) << "\n"
- end
- @res << html_list_name(fragment.type, false) << "\n"
- end
-
- def accept_list_item(am, fragment)
- if tag = @in_list_entry.last
- @res << annotate(tag) << "\n"
- end
- @res << list_item_start(am, fragment)
- @res << wrap(convert_flow(am.flow(fragment.txt))) << "\n"
- @in_list_entry[-1] = list_end_for(fragment.type)
- end
-
- def accept_blank_line(am, fragment)
- # @res << annotate("<p />") << "\n"
- end
-
- def accept_heading(am, fragment)
- @res << convert_heading(fragment.head_level, am.flow(fragment.txt))
- end
-
- ##
- # This is a higher speed (if messier) version of wrap
-
- def wrap(txt, line_len = 76)
- res = ""
- sp = 0
- ep = txt.length
- while sp < ep
- # scan back for a space
- p = sp + line_len - 1
- if p >= ep
- p = ep
- else
- while p > sp and txt[p] != ?\s
- p -= 1
- end
- if p <= sp
- p = sp + line_len
- while p < ep and txt[p] != ?\s
- p += 1
- end
- end
- end
- res << txt[sp...p] << "\n"
- sp = p
- sp += 1 while sp < ep and txt[sp] == ?\s
- end
- res
- end
-
- private
-
- def on_tags(res, item)
- attr_mask = item.turn_on
- return if attr_mask.zero?
-
- @attr_tags.each do |tag|
- if attr_mask & tag.bit != 0
- res << annotate(tag.on)
- end
- end
- end
-
- def off_tags(res, item)
- attr_mask = item.turn_off
- return if attr_mask.zero?
-
- @attr_tags.reverse_each do |tag|
- if attr_mask & tag.bit != 0
- res << annotate(tag.off)
- end
- end
- end
-
- def convert_flow(flow)
- res = ""
- flow.each do |item|
- case item
- when String
- res << convert_string(item)
- when AttrChanger
- off_tags(res, item)
- on_tags(res, item)
- when Special
- res << convert_special(item)
- else
- raise "Unknown flow element: #{item.inspect}"
- end
- end
- res
- end
-
- ##
- # some of these patterns are taken from SmartyPants...
-
- def convert_string(item)
- CGI.escapeHTML(item).
-
- # convert -- to em-dash, (-- to en-dash)
- gsub(/---?/, '&#8212;'). #gsub(/--/, '&#8211;').
-
- # convert ... to elipsis (and make sure .... becomes .<elipsis>)
- gsub(/\.\.\.\./, '.&#8230;').gsub(/\.\.\./, '&#8230;').
-
- # convert single closing quote
- gsub(%r{([^ \t\r\n\[\{\(])\'}) { "#$1&#8217;" }.
- gsub(%r{\'(?=\W|s\b)}) { "&#8217;" }.
-
- # convert single opening quote
- gsub(/'/, '&#8216;').
-
- # convert double closing quote
- gsub(%r{([^ \t\r\n\[\{\(])\'(?=\W)}) { "#$1&#8221;" }.
-
- # convert double opening quote
- gsub(/'/, '&#8220;').
-
- # convert copyright
- gsub(/\(c\)/, '&#169;').
-
- # convert and registered trademark
- gsub(/\(r\)/, '&#174;')
-
- end
-
- def convert_special(special)
- handled = false
- Attribute.each_name_of(special.type) do |name|
- method_name = "handle_special_#{name}"
- if self.respond_to? method_name
- special.text = send(method_name, special)
- handled = true
- end
- end
- raise "Unhandled special: #{special}" unless handled
- special.text
- end
-
- def convert_heading(level, flow)
- res =
- annotate("<h#{level}>") +
- convert_flow(flow) +
- annotate("</h#{level}>\n")
- end
-
- def html_list_name(list_type, is_open_tag)
- tags = LIST_TYPE_TO_HTML[list_type] || raise("Invalid list type: #{list_type.inspect}")
- annotate(tags[ is_open_tag ? 0 : 1])
- end
-
- def list_item_start(am, fragment)
- case fragment.type
- when ListBase::BULLET, ListBase::NUMBER
- annotate("<li>")
-
- when ListBase::UPPERALPHA
- annotate("<li type=\"A\">")
-
- when ListBase::LOWERALPHA
- annotate("<li type=\"a\">")
-
- when ListBase::LABELED
- annotate("<dt>") +
- convert_flow(am.flow(fragment.param)) +
- annotate("</dt>") +
- annotate("<dd>")
-
- when ListBase::NOTE
- annotate("<tr>") +
- annotate("<td valign=\"top\">") +
- convert_flow(am.flow(fragment.param)) +
- annotate("</td>") +
- annotate("<td>")
- else
- raise "Invalid list type"
- end
- end
-
- def list_end_for(fragment_type)
- case fragment_type
- when ListBase::BULLET, ListBase::NUMBER, ListBase::UPPERALPHA,
- ListBase::LOWERALPHA
- "</li>"
- when ListBase::LABELED
- "</dd>"
- when ListBase::NOTE
- "</td></tr>"
- else
- raise "Invalid list type"
- end
- end
-
- end
-
-end
-
diff --git a/lib/rdoc/markup/simple_markup/to_latex.rb b/lib/rdoc/markup/simple_markup/to_latex.rb
deleted file mode 100644
index b014b6990b..0000000000
--- a/lib/rdoc/markup/simple_markup/to_latex.rb
+++ /dev/null
@@ -1,332 +0,0 @@
-require 'rdoc/markup/simple_markup/fragments'
-require 'rdoc/markup/simple_markup/inline'
-
-require 'cgi'
-
-module SM
-
- # Convert SimpleMarkup to basic LaTeX report format
-
- class ToLaTeX
-
- BS = "\020" # \
- OB = "\021" # {
- CB = "\022" # }
- DL = "\023" # Dollar
-
- BACKSLASH = "#{BS}symbol#{OB}92#{CB}"
- HAT = "#{BS}symbol#{OB}94#{CB}"
- BACKQUOTE = "#{BS}symbol#{OB}0#{CB}"
- TILDE = "#{DL}#{BS}sim#{DL}"
- LESSTHAN = "#{DL}<#{DL}"
- GREATERTHAN = "#{DL}>#{DL}"
-
- def self.l(str)
- str.tr('\\', BS).tr('{', OB).tr('}', CB).tr('$', DL)
- end
-
- def l(arg)
- SM::ToLaTeX.l(arg)
- end
-
- LIST_TYPE_TO_LATEX = {
- ListBase::BULLET => [ l("\\begin{itemize}"), l("\\end{itemize}") ],
- ListBase::NUMBER => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\arabic" ],
- ListBase::UPPERALPHA => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\Alph" ],
- ListBase::LOWERALPHA => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\alph" ],
- ListBase::LABELED => [ l("\\begin{description}"), l("\\end{description}") ],
- ListBase::NOTE => [
- l("\\begin{tabularx}{\\linewidth}{@{} l X @{}}"),
- l("\\end{tabularx}") ],
- }
-
- InlineTag = Struct.new(:bit, :on, :off)
-
- def initialize
- init_tags
- @list_depth = 0
- @prev_list_types = []
- end
-
- ##
- # Set up the standard mapping of attributes to LaTeX
-
- def init_tags
- @attr_tags = [
- InlineTag.new(SM::Attribute.bitmap_for(:BOLD), l("\\textbf{"), l("}")),
- InlineTag.new(SM::Attribute.bitmap_for(:TT), l("\\texttt{"), l("}")),
- InlineTag.new(SM::Attribute.bitmap_for(:EM), l("\\emph{"), l("}")),
- ]
- end
-
- ##
- # Escape a LaTeX string
-
- def escape(str)
-# $stderr.print "FE: ", str
- s = str.
-# sub(/\s+$/, '').
- gsub(/([_\${}&%#])/, "#{BS}\\1").
- gsub(/\\/, BACKSLASH).
- gsub(/\^/, HAT).
- gsub(/~/, TILDE).
- gsub(/</, LESSTHAN).
- gsub(/>/, GREATERTHAN).
- gsub(/,,/, ",{},").
- gsub(/\`/, BACKQUOTE)
-# $stderr.print "-> ", s, "\n"
- s
- end
-
- ##
- # Add a new set of LaTeX tags for an attribute. We allow
- # separate start and end tags for flexibility
-
- def add_tag(name, start, stop)
- @attr_tags << InlineTag.new(SM::Attribute.bitmap_for(name), start, stop)
- end
-
- ##
- # Here's the client side of the visitor pattern
-
- def start_accepting
- @res = ""
- @in_list_entry = []
- end
-
- def end_accepting
- @res.tr(BS, '\\').tr(OB, '{').tr(CB, '}').tr(DL, '$')
- end
-
- def accept_paragraph(am, fragment)
- @res << wrap(convert_flow(am.flow(fragment.txt)))
- @res << "\n"
- end
-
- def accept_verbatim(am, fragment)
- @res << "\n\\begin{code}\n"
- @res << fragment.txt.sub(/[\n\s]+\Z/, '')
- @res << "\n\\end{code}\n\n"
- end
-
- def accept_rule(am, fragment)
- size = fragment.param
- size = 10 if size > 10
- @res << "\n\n\\rule{\\linewidth}{#{size}pt}\n\n"
- end
-
- def accept_list_start(am, fragment)
- @res << list_name(fragment.type, true) << "\n"
- @in_list_entry.push false
- end
-
- def accept_list_end(am, fragment)
- if tag = @in_list_entry.pop
- @res << tag << "\n"
- end
- @res << list_name(fragment.type, false) << "\n"
- end
-
- def accept_list_item(am, fragment)
- if tag = @in_list_entry.last
- @res << tag << "\n"
- end
- @res << list_item_start(am, fragment)
- @res << wrap(convert_flow(am.flow(fragment.txt))) << "\n"
- @in_list_entry[-1] = list_end_for(fragment.type)
- end
-
- def accept_blank_line(am, fragment)
- # @res << "\n"
- end
-
- def accept_heading(am, fragment)
- @res << convert_heading(fragment.head_level, am.flow(fragment.txt))
- end
-
- ##
- # This is a higher speed (if messier) version of wrap
-
- def wrap(txt, line_len = 76)
- res = ""
- sp = 0
- ep = txt.length
- while sp < ep
- # scan back for a space
- p = sp + line_len - 1
- if p >= ep
- p = ep
- else
- while p > sp and txt[p] != ?\s
- p -= 1
- end
- if p <= sp
- p = sp + line_len
- while p < ep and txt[p] != ?\s
- p += 1
- end
- end
- end
- res << txt[sp...p] << "\n"
- sp = p
- sp += 1 while sp < ep and txt[sp] == ?\s
- end
- res
- end
-
- private
-
- def on_tags(res, item)
- attr_mask = item.turn_on
- return if attr_mask.zero?
-
- @attr_tags.each do |tag|
- if attr_mask & tag.bit != 0
- res << tag.on
- end
- end
- end
-
- def off_tags(res, item)
- attr_mask = item.turn_off
- return if attr_mask.zero?
-
- @attr_tags.reverse_each do |tag|
- if attr_mask & tag.bit != 0
- res << tag.off
- end
- end
- end
-
- def convert_flow(flow)
- res = ""
- flow.each do |item|
- case item
- when String
-# $stderr.puts "Converting '#{item}'"
- res << convert_string(item)
- when AttrChanger
- off_tags(res, item)
- on_tags(res, item)
- when Special
- res << convert_special(item)
- else
- raise "Unknown flow element: #{item.inspect}"
- end
- end
- res
- end
-
- ##
- # some of these patterns are taken from SmartyPants...
-
- def convert_string(item)
- escape(item).
-
- # convert ... to elipsis (and make sure .... becomes .<elipsis>)
- gsub(/\.\.\.\./, '.\ldots{}').gsub(/\.\.\./, '\ldots{}').
-
- # convert single closing quote
- gsub(%r{([^ \t\r\n\[\{\(])\'}) { "#$1'" }.
- gsub(%r{\'(?=\W|s\b)}) { "'" }.
-
- # convert single opening quote
- gsub(/'/, '`').
-
- # convert double closing quote
- gsub(%r{([^ \t\r\n\[\{\(])\"(?=\W)}) { "#$1''" }.
-
- # convert double opening quote
- gsub(/"/, "``").
-
- # convert copyright
- gsub(/\(c\)/, '\copyright{}')
-
- end
-
- def convert_special(special)
- handled = false
- Attribute.each_name_of(special.type) do |name|
- method_name = "handle_special_#{name}"
- if self.respond_to? method_name
- special.text = send(method_name, special)
- handled = true
- end
- end
- raise "Unhandled special: #{special}" unless handled
- special.text
- end
-
- def convert_heading(level, flow)
- res =
- case level
- when 1 then "\\chapter{"
- when 2 then "\\section{"
- when 3 then "\\subsection{"
- when 4 then "\\subsubsection{"
- else "\\paragraph{"
- end +
- convert_flow(flow) +
- "}\n"
- end
-
- def list_name(list_type, is_open_tag)
- tags = LIST_TYPE_TO_LATEX[list_type] || raise("Invalid list type: #{list_type.inspect}")
- if tags[2] # enumerate
- if is_open_tag
- @list_depth += 1
- if @prev_list_types[@list_depth] != tags[2]
- case @list_depth
- when 1
- roman = "i"
- when 2
- roman = "ii"
- when 3
- roman = "iii"
- when 4
- roman = "iv"
- else
- raise("Too deep list: level #{@list_depth}")
- end
- @prev_list_types[@list_depth] = tags[2]
- return l("\\renewcommand{\\labelenum#{roman}}{#{tags[2]}{enum#{roman}}}") + "\n" + tags[0]
- end
- else
- @list_depth -= 1
- end
- end
- tags[ is_open_tag ? 0 : 1]
- end
-
- def list_item_start(am, fragment)
- case fragment.type
- when ListBase::BULLET, ListBase::NUMBER, ListBase::UPPERALPHA,
- ListBase::LOWERALPHA
- "\\item "
-
- when ListBase::LABELED
- "\\item[" + convert_flow(am.flow(fragment.param)) + "] "
-
- when ListBase::NOTE
- convert_flow(am.flow(fragment.param)) + " & "
- else
- raise "Invalid list type"
- end
- end
-
- def list_end_for(fragment_type)
- case fragment_type
- when ListBase::BULLET, ListBase::NUMBER, ListBase::UPPERALPHA,
- ListBase::LOWERALPHA, ListBase::LABELED
- ""
- when ListBase::NOTE
- "\\\\\n"
- else
- raise "Invalid list type"
- end
- end
-
- end
-
-end
-
diff --git a/lib/rdoc/markup/simple_markup/to_flow.rb b/lib/rdoc/markup/to_flow.rb
index fc8c5f5ce6..58ae52be24 100644
--- a/lib/rdoc/markup/simple_markup/to_flow.rb
+++ b/lib/rdoc/markup/to_flow.rb
@@ -1,8 +1,8 @@
-require 'rdoc/markup/simple_markup/fragments'
-require 'rdoc/markup/simple_markup/inline'
+require 'rdoc/markup/fragments'
+require 'rdoc/markup/inline'
require 'cgi'
-module SM
+class RDoc::Markup
module Flow
P = Struct.new(:body)
@@ -24,12 +24,12 @@ module SM
class ToFlow
LIST_TYPE_TO_HTML = {
- SM::ListBase::BULLET => [ "<ul>", "</ul>" ],
- SM::ListBase::NUMBER => [ "<ol>", "</ol>" ],
- SM::ListBase::UPPERALPHA => [ "<ol>", "</ol>" ],
- SM::ListBase::LOWERALPHA => [ "<ol>", "</ol>" ],
- SM::ListBase::LABELED => [ "<dl>", "</dl>" ],
- SM::ListBase::NOTE => [ "<table>", "</table>" ],
+ RDoc::Markup::ListBase::BULLET => [ "<ul>", "</ul>" ],
+ RDoc::Markup::ListBase::NUMBER => [ "<ol>", "</ol>" ],
+ RDoc::Markup::ListBase::UPPERALPHA => [ "<ol>", "</ol>" ],
+ RDoc::Markup::ListBase::LOWERALPHA => [ "<ol>", "</ol>" ],
+ RDoc::Markup::ListBase::LABELED => [ "<dl>", "</dl>" ],
+ RDoc::Markup::ListBase::NOTE => [ "<table>", "</table>" ],
}
InlineTag = Struct.new(:bit, :on, :off)
@@ -43,9 +43,9 @@ module SM
def init_tags
@attr_tags = [
- InlineTag.new(SM::Attribute.bitmap_for(:BOLD), "<b>", "</b>"),
- InlineTag.new(SM::Attribute.bitmap_for(:TT), "<tt>", "</tt>"),
- InlineTag.new(SM::Attribute.bitmap_for(:EM), "<em>", "</em>"),
+ InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:BOLD), "<b>", "</b>"),
+ InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:TT), "<tt>", "</tt>"),
+ InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:EM), "<em>", "</em>"),
]
end
@@ -54,7 +54,7 @@ module SM
# end tags for flexibility
def add_tag(name, start, stop)
- @attr_tags << InlineTag.new(SM::Attribute.bitmap_for(name), start, stop)
+ @attr_tags << InlineTag.new(RDoc::Markup::Attribute.bitmap_for(name), start, stop)
end
##
diff --git a/lib/rdoc/markup/to_html.rb b/lib/rdoc/markup/to_html.rb
new file mode 100644
index 0000000000..98259cfd16
--- /dev/null
+++ b/lib/rdoc/markup/to_html.rb
@@ -0,0 +1,286 @@
+require 'rdoc/markup/fragments'
+require 'rdoc/markup/inline'
+
+require 'cgi'
+
+class RDoc::Markup::ToHtml
+
+ LIST_TYPE_TO_HTML = {
+ RDoc::Markup::ListBase::BULLET => [ "<ul>", "</ul>" ],
+ RDoc::Markup::ListBase::NUMBER => [ "<ol>", "</ol>" ],
+ RDoc::Markup::ListBase::UPPERALPHA => [ "<ol>", "</ol>" ],
+ RDoc::Markup::ListBase::LOWERALPHA => [ "<ol>", "</ol>" ],
+ RDoc::Markup::ListBase::LABELED => [ "<dl>", "</dl>" ],
+ RDoc::Markup::ListBase::NOTE => [ "<table>", "</table>" ],
+ }
+
+ InlineTag = Struct.new(:bit, :on, :off)
+
+ def initialize
+ init_tags
+ end
+
+ ##
+ # Set up the standard mapping of attributes to HTML tags
+
+ def init_tags
+ @attr_tags = [
+ InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:BOLD), "<b>", "</b>"),
+ InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:TT), "<tt>", "</tt>"),
+ InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:EM), "<em>", "</em>"),
+ ]
+ end
+
+ ##
+ # Add a new set of HTML tags for an attribute. We allow separate start and
+ # end tags for flexibility.
+
+ def add_tag(name, start, stop)
+ @attr_tags << InlineTag.new(RDoc::Markup::Attribute.bitmap_for(name), start, stop)
+ end
+
+ ##
+ # Given an HTML tag, decorate it with class information and the like if
+ # required. This is a no-op in the base class, but is overridden in HTML
+ # output classes that implement style sheets.
+
+ def annotate(tag)
+ tag
+ end
+
+ ##
+ # Here's the client side of the visitor pattern
+
+ def start_accepting
+ @res = ""
+ @in_list_entry = []
+ end
+
+ def end_accepting
+ @res
+ end
+
+ def accept_paragraph(am, fragment)
+ @res << annotate("<p>") + "\n"
+ @res << wrap(convert_flow(am.flow(fragment.txt)))
+ @res << annotate("</p>") + "\n"
+ end
+
+ def accept_verbatim(am, fragment)
+ @res << annotate("<pre>") + "\n"
+ @res << CGI.escapeHTML(fragment.txt)
+ @res << annotate("</pre>") << "\n"
+ end
+
+ def accept_rule(am, fragment)
+ size = fragment.param
+ size = 10 if size > 10
+ @res << "<hr size=\"#{size}\"></hr>"
+ end
+
+ def accept_list_start(am, fragment)
+ @res << html_list_name(fragment.type, true) << "\n"
+ @in_list_entry.push false
+ end
+
+ def accept_list_end(am, fragment)
+ if tag = @in_list_entry.pop
+ @res << annotate(tag) << "\n"
+ end
+ @res << html_list_name(fragment.type, false) << "\n"
+ end
+
+ def accept_list_item(am, fragment)
+ if tag = @in_list_entry.last
+ @res << annotate(tag) << "\n"
+ end
+ @res << list_item_start(am, fragment)
+ @res << wrap(convert_flow(am.flow(fragment.txt))) << "\n"
+ @in_list_entry[-1] = list_end_for(fragment.type)
+ end
+
+ def accept_blank_line(am, fragment)
+ # @res << annotate("<p />") << "\n"
+ end
+
+ def accept_heading(am, fragment)
+ @res << convert_heading(fragment.head_level, am.flow(fragment.txt))
+ end
+
+ ##
+ # This is a higher speed (if messier) version of wrap
+
+ def wrap(txt, line_len = 76)
+ res = ""
+ sp = 0
+ ep = txt.length
+ while sp < ep
+ # scan back for a space
+ p = sp + line_len - 1
+ if p >= ep
+ p = ep
+ else
+ while p > sp and txt[p] != ?\s
+ p -= 1
+ end
+ if p <= sp
+ p = sp + line_len
+ while p < ep and txt[p] != ?\s
+ p += 1
+ end
+ end
+ end
+ res << txt[sp...p] << "\n"
+ sp = p
+ sp += 1 while sp < ep and txt[sp] == ?\s
+ end
+ res
+ end
+
+ private
+
+ def on_tags(res, item)
+ attr_mask = item.turn_on
+ return if attr_mask.zero?
+
+ @attr_tags.each do |tag|
+ if attr_mask & tag.bit != 0
+ res << annotate(tag.on)
+ end
+ end
+ end
+
+ def off_tags(res, item)
+ attr_mask = item.turn_off
+ return if attr_mask.zero?
+
+ @attr_tags.reverse_each do |tag|
+ if attr_mask & tag.bit != 0
+ res << annotate(tag.off)
+ end
+ end
+ end
+
+ def convert_flow(flow)
+ res = ""
+
+ flow.each do |item|
+ case item
+ when String
+ res << convert_string(item)
+ when RDoc::Markup::AttrChanger
+ off_tags(res, item)
+ on_tags(res, item)
+ when RDoc::Markup::Special
+ res << convert_special(item)
+ else
+ raise "Unknown flow element: #{item.inspect}"
+ end
+ end
+
+ res
+ end
+
+ ##
+ # some of these patterns are taken from SmartyPants...
+
+ def convert_string(item)
+ CGI.escapeHTML(item).
+
+ # convert -- to em-dash, (-- to en-dash)
+ gsub(/---?/, '&#8212;'). #gsub(/--/, '&#8211;').
+
+ # convert ... to elipsis (and make sure .... becomes .<elipsis>)
+ gsub(/\.\.\.\./, '.&#8230;').gsub(/\.\.\./, '&#8230;').
+
+ # convert single closing quote
+ gsub(%r{([^ \t\r\n\[\{\(])\'}) { "#$1&#8217;" }.
+ gsub(%r{\'(?=\W|s\b)}) { "&#8217;" }.
+
+ # convert single opening quote
+ gsub(/'/, '&#8216;').
+
+ # convert double closing quote
+ gsub(%r{([^ \t\r\n\[\{\(])\'(?=\W)}) { "#$1&#8221;" }.
+
+ # convert double opening quote
+ gsub(/'/, '&#8220;').
+
+ # convert copyright
+ gsub(/\(c\)/, '&#169;').
+
+ # convert and registered trademark
+ gsub(/\(r\)/, '&#174;')
+
+ end
+
+ def convert_special(special)
+ handled = false
+ RDoc::Markup::Attribute.each_name_of(special.type) do |name|
+ method_name = "handle_special_#{name}"
+ if self.respond_to? method_name
+ special.text = send(method_name, special)
+ handled = true
+ end
+ end
+ raise "Unhandled special: #{special}" unless handled
+ special.text
+ end
+
+ def convert_heading(level, flow)
+ res =
+ annotate("<h#{level}>") +
+ convert_flow(flow) +
+ annotate("</h#{level}>\n")
+ end
+
+ def html_list_name(list_type, is_open_tag)
+ tags = LIST_TYPE_TO_HTML[list_type] || raise("Invalid list type: #{list_type.inspect}")
+ annotate(tags[ is_open_tag ? 0 : 1])
+ end
+
+ def list_item_start(am, fragment)
+ case fragment.type
+ when RDoc::Markup::ListBase::BULLET, RDoc::Markup::ListBase::NUMBER then
+ annotate("<li>")
+
+ when RDoc::Markup::ListBase::UPPERALPHA then
+ annotate("<li type=\"A\">")
+
+ when RDoc::Markup::ListBase::LOWERALPHA then
+ annotate("<li type=\"a\">")
+
+ when RDoc::Markup::ListBase::LABELED then
+ annotate("<dt>") +
+ convert_flow(am.flow(fragment.param)) +
+ annotate("</dt>") +
+ annotate("<dd>")
+
+ when RDoc::Markup::ListBase::NOTE then
+ annotate("<tr>") +
+ annotate("<td valign=\"top\">") +
+ convert_flow(am.flow(fragment.param)) +
+ annotate("</td>") +
+ annotate("<td>")
+ else
+ raise "Invalid list type"
+ end
+ end
+
+ def list_end_for(fragment_type)
+ case fragment_type
+ when RDoc::Markup::ListBase::BULLET, RDoc::Markup::ListBase::NUMBER,
+ RDoc::Markup::ListBase::UPPERALPHA,
+ RDoc::Markup::ListBase::LOWERALPHA then
+ "</li>"
+ when RDoc::Markup::ListBase::LABELED then
+ "</dd>"
+ when RDoc::Markup::ListBase::NOTE then
+ "</td></tr>"
+ else
+ raise "Invalid list type"
+ end
+ end
+
+end
+
diff --git a/lib/rdoc/markup/to_latex.rb b/lib/rdoc/markup/to_latex.rb
new file mode 100644
index 0000000000..2964e315bd
--- /dev/null
+++ b/lib/rdoc/markup/to_latex.rb
@@ -0,0 +1,331 @@
+require 'rdoc/markup/fragments'
+require 'rdoc/markup/inline'
+
+require 'cgi'
+
+##
+# Convert SimpleMarkup to basic LaTeX report format.
+
+class RDoc::Markup::ToLaTeX
+
+ BS = "\020" # \
+ OB = "\021" # {
+ CB = "\022" # }
+ DL = "\023" # Dollar
+
+ BACKSLASH = "#{BS}symbol#{OB}92#{CB}"
+ HAT = "#{BS}symbol#{OB}94#{CB}"
+ BACKQUOTE = "#{BS}symbol#{OB}0#{CB}"
+ TILDE = "#{DL}#{BS}sim#{DL}"
+ LESSTHAN = "#{DL}<#{DL}"
+ GREATERTHAN = "#{DL}>#{DL}"
+
+ def self.l(str)
+ str.tr('\\', BS).tr('{', OB).tr('}', CB).tr('$', DL)
+ end
+
+ def l(arg)
+ RDoc::Markup::ToLaTeX.l(arg)
+ end
+
+ LIST_TYPE_TO_LATEX = {
+ ListBase::BULLET => [ l("\\begin{itemize}"), l("\\end{itemize}") ],
+ ListBase::NUMBER => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\arabic" ],
+ ListBase::UPPERALPHA => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\Alph" ],
+ ListBase::LOWERALPHA => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\alph" ],
+ ListBase::LABELED => [ l("\\begin{description}"), l("\\end{description}") ],
+ ListBase::NOTE => [
+ l("\\begin{tabularx}{\\linewidth}{@{} l X @{}}"),
+ l("\\end{tabularx}") ],
+ }
+
+ InlineTag = Struct.new(:bit, :on, :off)
+
+ def initialize
+ init_tags
+ @list_depth = 0
+ @prev_list_types = []
+ end
+
+ ##
+ # Set up the standard mapping of attributes to LaTeX
+
+ def init_tags
+ @attr_tags = [
+ InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:BOLD), l("\\textbf{"), l("}")),
+ InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:TT), l("\\texttt{"), l("}")),
+ InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:EM), l("\\emph{"), l("}")),
+ ]
+ end
+
+ ##
+ # Escape a LaTeX string
+
+ def escape(str)
+$stderr.print "FE: ", str
+ s = str.
+ sub(/\s+$/, '').
+ gsub(/([_\${}&%#])/, "#{BS}\\1").
+ gsub(/\\/, BACKSLASH).
+ gsub(/\^/, HAT).
+ gsub(/~/, TILDE).
+ gsub(/</, LESSTHAN).
+ gsub(/>/, GREATERTHAN).
+ gsub(/,,/, ",{},").
+ gsub(/\`/, BACKQUOTE)
+$stderr.print "-> ", s, "\n"
+ s
+ end
+
+ ##
+ # Add a new set of LaTeX tags for an attribute. We allow
+ # separate start and end tags for flexibility
+
+ def add_tag(name, start, stop)
+ @attr_tags << InlineTag.new(RDoc::Markup::Attribute.bitmap_for(name), start, stop)
+ end
+
+ ##
+ # Here's the client side of the visitor pattern
+
+ def start_accepting
+ @res = ""
+ @in_list_entry = []
+ end
+
+ def end_accepting
+ @res.tr(BS, '\\').tr(OB, '{').tr(CB, '}').tr(DL, '$')
+ end
+
+ def accept_paragraph(am, fragment)
+ @res << wrap(convert_flow(am.flow(fragment.txt)))
+ @res << "\n"
+ end
+
+ def accept_verbatim(am, fragment)
+ @res << "\n\\begin{code}\n"
+ @res << fragment.txt.sub(/[\n\s]+\Z/, '')
+ @res << "\n\\end{code}\n\n"
+ end
+
+ def accept_rule(am, fragment)
+ size = fragment.param
+ size = 10 if size > 10
+ @res << "\n\n\\rule{\\linewidth}{#{size}pt}\n\n"
+ end
+
+ def accept_list_start(am, fragment)
+ @res << list_name(fragment.type, true) << "\n"
+ @in_list_entry.push false
+ end
+
+ def accept_list_end(am, fragment)
+ if tag = @in_list_entry.pop
+ @res << tag << "\n"
+ end
+ @res << list_name(fragment.type, false) << "\n"
+ end
+
+ def accept_list_item(am, fragment)
+ if tag = @in_list_entry.last
+ @res << tag << "\n"
+ end
+ @res << list_item_start(am, fragment)
+ @res << wrap(convert_flow(am.flow(fragment.txt))) << "\n"
+ @in_list_entry[-1] = list_end_for(fragment.type)
+ end
+
+ def accept_blank_line(am, fragment)
+ # @res << "\n"
+ end
+
+ def accept_heading(am, fragment)
+ @res << convert_heading(fragment.head_level, am.flow(fragment.txt))
+ end
+
+ ##
+ # This is a higher speed (if messier) version of wrap
+
+ def wrap(txt, line_len = 76)
+ res = ""
+ sp = 0
+ ep = txt.length
+ while sp < ep
+ # scan back for a space
+ p = sp + line_len - 1
+ if p >= ep
+ p = ep
+ else
+ while p > sp and txt[p] != ?\s
+ p -= 1
+ end
+ if p <= sp
+ p = sp + line_len
+ while p < ep and txt[p] != ?\s
+ p += 1
+ end
+ end
+ end
+ res << txt[sp...p] << "\n"
+ sp = p
+ sp += 1 while sp < ep and txt[sp] == ?\s
+ end
+ res
+ end
+
+ private
+
+ def on_tags(res, item)
+ attr_mask = item.turn_on
+ return if attr_mask.zero?
+
+ @attr_tags.each do |tag|
+ if attr_mask & tag.bit != 0
+ res << tag.on
+ end
+ end
+ end
+
+ def off_tags(res, item)
+ attr_mask = item.turn_off
+ return if attr_mask.zero?
+
+ @attr_tags.reverse_each do |tag|
+ if attr_mask & tag.bit != 0
+ res << tag.off
+ end
+ end
+ end
+
+ def convert_flow(flow)
+ res = ""
+ flow.each do |item|
+ case item
+ when String
+ $stderr.puts "Converting '#{item}'"
+ res << convert_string(item)
+ when AttrChanger
+ off_tags(res, item)
+ on_tags(res, item)
+ when Special
+ res << convert_special(item)
+ else
+ raise "Unknown flow element: #{item.inspect}"
+ end
+ end
+ res
+ end
+
+ ##
+ # some of these patterns are taken from SmartyPants...
+
+ def convert_string(item)
+ escape(item).
+
+ # convert ... to elipsis (and make sure .... becomes .<elipsis>)
+ gsub(/\.\.\.\./, '.\ldots{}').gsub(/\.\.\./, '\ldots{}').
+
+ # convert single closing quote
+ gsub(%r{([^ \t\r\n\[\{\(])\'}) { "#$1'" }.
+ gsub(%r{\'(?=\W|s\b)}) { "'" }.
+
+ # convert single opening quote
+ gsub(/'/, '`').
+
+ # convert double closing quote
+ gsub(%r{([^ \t\r\n\[\{\(])\"(?=\W)}) { "#$1''" }.
+
+ # convert double opening quote
+ gsub(/"/, "``").
+
+ # convert copyright
+ gsub(/\(c\)/, '\copyright{}')
+
+ end
+
+ def convert_special(special)
+ handled = false
+ Attribute.each_name_of(special.type) do |name|
+ method_name = "handle_special_#{name}"
+ if self.respond_to? method_name
+ special.text = send(method_name, special)
+ handled = true
+ end
+ end
+ raise "Unhandled special: #{special}" unless handled
+ special.text
+ end
+
+ def convert_heading(level, flow)
+ res =
+ case level
+ when 1 then "\\chapter{"
+ when 2 then "\\section{"
+ when 3 then "\\subsection{"
+ when 4 then "\\subsubsection{"
+ else "\\paragraph{"
+ end +
+ convert_flow(flow) +
+ "}\n"
+ end
+
+ def list_name(list_type, is_open_tag)
+ tags = LIST_TYPE_TO_LATEX[list_type] || raise("Invalid list type: #{list_type.inspect}")
+ if tags[2] # enumerate
+ if is_open_tag
+ @list_depth += 1
+ if @prev_list_types[@list_depth] != tags[2]
+ case @list_depth
+ when 1
+ roman = "i"
+ when 2
+ roman = "ii"
+ when 3
+ roman = "iii"
+ when 4
+ roman = "iv"
+ else
+ raise("Too deep list: level #{@list_depth}")
+ end
+ @prev_list_types[@list_depth] = tags[2]
+ return l("\\renewcommand{\\labelenum#{roman}}{#{tags[2]}{enum#{roman}}}") + "\n" + tags[0]
+ end
+ else
+ @list_depth -= 1
+ end
+ end
+ tags[ is_open_tag ? 0 : 1]
+ end
+
+ def list_item_start(am, fragment)
+ case fragment.type
+ when ListBase::BULLET, ListBase::NUMBER, ListBase::UPPERALPHA,
+ ListBase::LOWERALPHA
+ "\\item "
+
+ when ListBase::LABELED
+ "\\item[" + convert_flow(am.flow(fragment.param)) + "] "
+
+ when ListBase::NOTE
+ convert_flow(am.flow(fragment.param)) + " & "
+ else
+ raise "Invalid list type"
+ end
+ end
+
+ def list_end_for(fragment_type)
+ case fragment_type
+ when ListBase::BULLET, ListBase::NUMBER, ListBase::UPPERALPHA,
+ ListBase::LOWERALPHA, ListBase::LABELED
+ ""
+ when ListBase::NOTE
+ "\\\\\n"
+ else
+ raise "Invalid list type"
+ end
+ end
+
+end
+
+d
+
diff --git a/lib/rdoc/parsers/parse_rb.rb b/lib/rdoc/parsers/parse_rb.rb
index 42256b2523..baf90577cb 100644
--- a/lib/rdoc/parsers/parse_rb.rb
+++ b/lib/rdoc/parsers/parse_rb.rb
@@ -7,9 +7,9 @@
# This file contains stuff stolen outright from:
#
-# rtags.rb -
+# rtags.rb -
# ruby-lex.rb - ruby lexcal analizer
-# ruby-token.rb - ruby tokens
+# ruby-token.rb - ruby tokens
# by Keiju ISHITSUKA (Nippon Rational Inc.)
#
@@ -19,11 +19,11 @@ require "irb/slex"
require "rdoc/code_objects"
require "rdoc/tokenstream"
-require "rdoc/markup/simple_markup/preprocess"
+require "rdoc/markup/preprocess"
require "rdoc/parsers/parserfactory"
-$TOKEN_DEBUG = $DEBUG_RDOC
+#$TOKEN_DEBUG = $DEBUG_RDOC
# Definitions of all tokens involved in the lexical analysis
@@ -35,7 +35,7 @@ module RubyToken
EXPR_FNAME = :EXPR_FNAME
EXPR_DOT = :EXPR_DOT
EXPR_CLASS = :EXPR_CLASS
-
+
class Token
NO_TEXT = "??".freeze
attr_accessor :text
@@ -117,8 +117,8 @@ module RubyToken
if (tk = source[token]).nil?
fail TkReading2TokenNoKey, token
end
- tk = Token(tk[0], value)
- else
+ tk = Token(tk[0], value)
+ else
tk = if (token.ancestors & [TkId, TkVal, TkOPASGN, TkUnknownChar]).empty?
token.new(@prev_line_no, @prev_char_no)
else
@@ -218,14 +218,14 @@ module RubyToken
[:TkASSOC, TkOp, "=>"],
[:TkQUESTION, TkOp, "?"], #?
[:TkCOLON, TkOp, ":"], #:
-
+
[:TkfLPAREN], # func( #
[:TkfLBRACK], # func[ #
[:TkfLBRACE], # func{ #
[:TkSTAR], # *arg
[:TkAMPER], # &arg #
[:TkSYMBOL, TkId], # :SYMBOL
- [:TkSYMBEG, TkId],
+ [:TkSYMBEG, TkId],
[:TkGT, TkOp, ">"],
[:TkLT, TkOp, "<"],
[:TkPLUS, TkOp, "+"],
@@ -276,7 +276,7 @@ module RubyToken
token_c = Class.new super_token
RubyToken.const_set token_n, token_c
# token_c.inspect
-
+
if reading
if TkReading2Token[reading]
fail TkReading2TokenDuplicateError, token_n, reading
@@ -338,14 +338,14 @@ class RubyLex
# here document. Once complete, it needs to read the rest of the
# original line, but then skip the here document body.
#
-
+
class BufferedReader
-
+
attr_reader :line_num
-
+
def initialize(content, options)
@options = options
-
+
if /\t/ =~ content
tab_width = @options.tab_width
content = content.split(/\n/).map do |line|
@@ -363,34 +363,34 @@ class RubyLex
@last_newline = 0
@newline_pending = false
end
-
+
def column
@offset - @last_newline
end
-
+
def getc
return nil if @offset >= @size
ch = @content[@offset, 1]
-
+
@offset += 1
@hwm = @offset if @hwm < @offset
-
+
if @newline_pending
@line_num += 1
@last_newline = @offset - 1
@newline_pending = false
end
-
+
if ch == "\n"
@newline_pending = true
end
ch
end
-
+
def getc_already_read
getc
end
-
+
def ungetc(ch)
raise "unget past beginning of file" if @offset <= 0
@offset -= 1
@@ -398,13 +398,13 @@ class RubyLex
@newline_pending = false
end
end
-
+
def get_read
res = @content[@read_back_offset...@offset]
@read_back_offset = @offset
res
end
-
+
def peek(at)
pos = @offset + at
if pos >= @size
@@ -413,11 +413,11 @@ class RubyLex
@content[pos, 1]
end
end
-
+
def peek_equal(str)
@content[@offset, str.length] == str
end
-
+
def divert_read_from(reserve)
@content[@offset, 0] = reserve
@size = @content.size
@@ -430,10 +430,10 @@ class RubyLex
def_exception(:AlreadyDefinedToken, "Already defined token(%s)")
def_exception(:TkReading2TokenNoKey, "key nothing(key='%s')")
def_exception(:TkSymbol2TokenNoKey, "key nothing(key='%s')")
- def_exception(:TkReading2TokenDuplicateError,
+ def_exception(:TkReading2TokenDuplicateError,
"key duplicate(token_n='%s', key='%s')")
def_exception(:SyntaxError, "%s")
-
+
include RubyToken
include IRB
@@ -459,7 +459,7 @@ class RubyLex
@quoted = nil
@lex_state = EXPR_BEG
@space_seen = false
-
+
@continue = false
@line = ""
@@ -546,10 +546,9 @@ class RubyLex
get_read
end
# throw :eof unless tk
- p tk if $DEBUG_RDOC
tk
end
-
+
ENINDENT_CLAUSE = [
"case", "class", "def", "do", "for", "if",
"module", "unless", "until", "while", "begin" #, "when"
@@ -564,7 +563,7 @@ class RubyLex
"r" => "/",
"w" => "]"
}
-
+
PERCENT_PAREN = {
"{" => "}",
"[" => "]",
@@ -647,10 +646,10 @@ class RubyLex
Token(TkNL).set_text("\n")
end
- @OP.def_rules("*", "**",
+ @OP.def_rules("*", "**",
"!", "!=", "!~",
- "=", "==", "===",
- "=~", "<=>",
+ "=", "==", "===",
+ "=~", "<=>",
"<", "<=",
">", ">=", ">>") do
|op, io|
@@ -717,8 +716,8 @@ class RubyLex
@lex_state = EXPR_BEG
Token(op).set_text(op)
end
-
- @OP.def_rules("+=", "-=", "*=", "**=",
+
+ @OP.def_rules("+=", "-=", "*=", "**=",
"&=", "|=", "^=", "<<=", ">>=", "||=", "&&=") do
|op, io|
@lex_state = EXPR_BEG
@@ -772,7 +771,7 @@ class RubyLex
lex_int2
end
-
+
def lex_int2
@OP.def_rules("]", "}", ")") do
|op, io|
@@ -814,7 +813,7 @@ class RubyLex
Token(TkOPASGN, :/).set_text("/=") #")
elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/
identify_string(op)
- else
+ else
@lex_state = EXPR_BEG
Token("/").set_text(op)
end
@@ -829,7 +828,7 @@ class RubyLex
# @lex_state = EXPR_BEG
# Token(TkOPASGN, :^)
# end
-
+
@OP.def_rules(",", ";") do
|op, io|
@lex_state = EXPR_BEG
@@ -845,7 +844,7 @@ class RubyLex
@lex_state = EXPR_BEG
Token("~").set_text("~@")
end
-
+
@OP.def_rule("(") do
@indent += 1
if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
@@ -895,15 +894,15 @@ class RubyLex
end
@OP.def_rule('\\') do #'
- if getc == "\n"
+ if getc == "\n"
@space_seen = true
@continue = true
Token(TkSPACE).set_text("\\\n")
- else
+ else
ungetc
Token("\\").set_text("\\") #"
- end
- end
+ end
+ end
@OP.def_rule('%') do
|op, io|
@@ -933,7 +932,7 @@ class RubyLex
end
end
- # @OP.def_rule("def", proc{|op, io| /\s/ =~ io.peek(0)}) do
+ # @OP.def_rule("def", proc{|op, io| /\s/ =~ io.peek(0)}) do
# |op, io|
# @indent += 1
# @lex_state = EXPR_FNAME
@@ -958,10 +957,10 @@ class RubyLex
printf "MATCH: end %s: %s\n", op, io.inspect if RubyLex.debug?
t
end
-
+
p @OP if RubyLex.debug?
end
-
+
def identify_gvar
@lex_state = EXPR_END
str = "$"
@@ -970,15 +969,15 @@ class RubyLex
when /[~_*$?!@\/\\;,=:<>".]/ #"
str << ch
Token(TkGVAR, str)
-
+
when "-"
str << "-" << getc
Token(TkGVAR, str)
-
+
when "&", "`", "'", "+"
str << ch
Token(TkBACK_REF, str)
-
+
when /[1-9]/
str << ch
while (ch = getc) =~ /[0-9]/
@@ -990,13 +989,13 @@ class RubyLex
ungetc
ungetc
return identify_identifier
- else
+ else
ungetc
- Token("$")
+ Token("$")
end
tk.set_text(str)
end
-
+
def identify_identifier
token = ""
token.concat getc if peek(0) =~ /[$@]/
@@ -1007,7 +1006,7 @@ class RubyLex
token.concat ch
end
ungetc
-
+
if ch == "!" or ch == "?"
token.concat getc
end
@@ -1022,7 +1021,7 @@ class RubyLex
@lex_state = EXPR_END
return Token(TkIVAR, token).set_text(token)
end
-
+
if @lex_state != EXPR_DOT
print token, "\n" if RubyLex.debug?
@@ -1120,7 +1119,7 @@ class RubyLex
@lex_state = EXPR_END
Token(Ltype2Token[lt], str).set_text(str.dump)
end
-
+
def identify_quotation(initial_char)
ch = getc
if lt = PERCENT_LTYPE[ch]
@@ -1201,7 +1200,7 @@ class RubyLex
end
Token(type).set_text(str)
end
-
+
def identify_string(ltype, quoted = ltype, opener=nil, initial_char = nil)
@ltype = ltype
@quoted = quoted
@@ -1213,9 +1212,9 @@ class RubyLex
nest = 0
begin
- while ch = getc
+ while ch = getc
str << ch
- if @quoted == ch
+ if @quoted == ch
if nest == 0
break
else
@@ -1276,7 +1275,7 @@ class RubyLex
if ch == "\n"
ch = " "
else
- comment << "\\"
+ comment << "\\"
end
else
if ch == "\n"
@@ -1289,7 +1288,7 @@ class RubyLex
end
return Token(TkCOMMENT).set_text(comment)
end
-
+
def read_escape
res = ""
case ch = getc
@@ -1306,7 +1305,7 @@ class RubyLex
end
res << ch
end
-
+
when "x"
res << ch
2.times do
@@ -1361,493 +1360,476 @@ end
#
# This file is based on rtags
-module RDoc
-
- GENERAL_MODIFIERS = [ 'nodoc' ].freeze
-
- CLASS_MODIFIERS = GENERAL_MODIFIERS
-
- ATTR_MODIFIERS = GENERAL_MODIFIERS
+class RDoc::RubyParser
- CONSTANT_MODIFIERS = GENERAL_MODIFIERS
-
- METHOD_MODIFIERS = GENERAL_MODIFIERS +
- [ 'arg', 'args', 'yield', 'yields', 'notnew', 'not-new', 'not_new', 'doc' ]
-
-
- class RubyParser
- include RubyToken
- include TokenStream
+ include RubyToken
+ include RDoc::TokenStream
- extend ParserFactory
+ extend RDoc::ParserFactory
- parse_files_matching(/\.rbw?$/)
+ parse_files_matching(/\.rbw?$/)
+ def initialize(top_level, file_name, content, options, stats)
+ @options = options
+ @stats = stats
+ @size = 0
+ @token_listeners = nil
+ @input_file_name = file_name
+ @scanner = RubyLex.new content, @options
+ @scanner.exception_on_syntax_error = false
+ @top_level = top_level
+ @progress = $stderr unless options.quiet
+ end
- def initialize(top_level, file_name, content, options, stats)
- @options = options
- @stats = stats
- @size = 0
- @token_listeners = nil
- @input_file_name = file_name
- @scanner = RubyLex.new content, @options
- @scanner.exception_on_syntax_error = false
- @top_level = top_level
- @progress = $stderr unless options.quiet
- end
-
- def scan
- @tokens = []
- @unget_read = []
- @read = []
- catch(:eof) do
- catch(:enddoc) do
- begin
- parse_toplevel_statements(@top_level)
- rescue Exception => e
- $stderr.puts "\n\n"
- $stderr.puts "RDoc failure in #@input_file_name at or around " +
- "line #{@scanner.line_no} column #{@scanner.char_no}"
- $stderr.puts
- $stderr.puts "Before reporting this, could you check that the file"
- $stderr.puts "you're documenting compiles cleanly--RDoc is not a"
- $stderr.puts "full Ruby parser, and gets confused easily if fed"
- $stderr.puts "invalid programs."
- $stderr.puts
- $stderr.puts "The internal error was:\n\n"
-
- e.set_backtrace(e.backtrace[0,4])
- raise
- end
+ def scan
+ @tokens = []
+ @unget_read = []
+ @read = []
+ catch(:eof) do
+ catch(:enddoc) do
+ begin
+ parse_toplevel_statements(@top_level)
+ rescue Exception => e
+ $stderr.puts "\n\n"
+ $stderr.puts "RDoc failure in #@input_file_name at or around " +
+ "line #{@scanner.line_no} column #{@scanner.char_no}"
+ $stderr.puts
+ $stderr.puts "Before reporting this, could you check that the file"
+ $stderr.puts "you're documenting compiles cleanly--RDoc is not a"
+ $stderr.puts "full Ruby parser, and gets confused easily if fed"
+ $stderr.puts "invalid programs."
+ $stderr.puts
+ $stderr.puts "The internal error was:\n\n"
+
+ e.set_backtrace(e.backtrace[0,4])
+ raise
end
end
- @top_level
end
+ @top_level
+ end
- private
+ private
- def make_message(msg)
- prefix = "\n" + @input_file_name + ":"
- if @scanner
- prefix << "#{@scanner.line_no}:#{@scanner.char_no}: "
- end
- return prefix + msg
+ def make_message(msg)
+ prefix = "\n" + @input_file_name + ":"
+ if @scanner
+ prefix << "#{@scanner.line_no}:#{@scanner.char_no}: "
end
+ return prefix + msg
+ end
- def warn(msg)
- return if @options.quiet
- msg = make_message msg
- $stderr.puts msg
- end
+ def warn(msg)
+ return if @options.quiet
+ msg = make_message msg
+ $stderr.puts msg
+ end
- def error(msg)
- msg = make_message msg
- $stderr.puts msg
- exit(1)
- end
+ def error(msg)
+ msg = make_message msg
+ $stderr.puts msg
+ exit(1)
+ end
- def progress(char)
- unless @options.quiet
- @progress.print(char)
- @progress.flush
- end
+ def progress(char)
+ unless @options.quiet
+ @progress.print(char)
+ @progress.flush
end
+ end
- def add_token_listener(obj)
- @token_listeners ||= []
- @token_listeners << obj
- end
+ def add_token_listener(obj)
+ @token_listeners ||= []
+ @token_listeners << obj
+ end
- def remove_token_listener(obj)
- @token_listeners.delete(obj)
- end
+ def remove_token_listener(obj)
+ @token_listeners.delete(obj)
+ end
- def get_tk
- tk = nil
- if @tokens.empty?
- tk = @scanner.token
- @read.push @scanner.get_read
- puts "get_tk1 => #{tk.inspect}" if $TOKEN_DEBUG
- else
- @read.push @unget_read.shift
- tk = @tokens.shift
- puts "get_tk2 => #{tk.inspect}" if $TOKEN_DEBUG
- end
+ def get_tk
+ tk = nil
+ if @tokens.empty?
+ tk = @scanner.token
+ @read.push @scanner.get_read
+ puts "get_tk1 => #{tk.inspect}" if $TOKEN_DEBUG
+ else
+ @read.push @unget_read.shift
+ tk = @tokens.shift
+ puts "get_tk2 => #{tk.inspect}" if $TOKEN_DEBUG
+ end
- if tk.kind_of?(TkSYMBEG)
- set_token_position(tk.line_no, tk.char_no)
- tk1 = get_tk
- if tk1.kind_of?(TkId) || tk1.kind_of?(TkOp) || tk1.kind_of?(TkSTRING)
- if tk1.respond_to?(:name)
- tk = Token(TkSYMBOL).set_text(":" + tk1.name)
- else
- tk = Token(TkSYMBOL).set_text(":" + tk1.text)
- end
- # remove the identifier we just read (we're about to
- # replace it with a symbol)
- @token_listeners.each do |obj|
- obj.pop_token
- end if @token_listeners
+ if tk.kind_of?(TkSYMBEG)
+ set_token_position(tk.line_no, tk.char_no)
+ tk1 = get_tk
+ if tk1.kind_of?(TkId) || tk1.kind_of?(TkOp) || tk1.kind_of?(TkSTRING)
+ if tk1.respond_to?(:name)
+ tk = Token(TkSYMBOL).set_text(":" + tk1.name)
else
- warn("':' not followed by identifier or operator")
- tk = tk1
+ tk = Token(TkSYMBOL).set_text(":" + tk1.text)
end
+ # remove the identifier we just read (we're about to
+ # replace it with a symbol)
+ @token_listeners.each do |obj|
+ obj.pop_token
+ end if @token_listeners
+ else
+ warn("':' not followed by identifier or operator")
+ tk = tk1
end
+ end
- # inform any listeners of our shiny new token
- @token_listeners.each do |obj|
- obj.add_token(tk)
- end if @token_listeners
+ # inform any listeners of our shiny new token
+ @token_listeners.each do |obj|
+ obj.add_token(tk)
+ end if @token_listeners
- tk
- end
+ tk
+ end
- def peek_tk
- unget_tk(tk = get_tk)
- tk
- end
+ def peek_tk
+ unget_tk(tk = get_tk)
+ tk
+ end
- def unget_tk(tk)
- @tokens.unshift tk
- @unget_read.unshift @read.pop
+ def unget_tk(tk)
+ @tokens.unshift tk
+ @unget_read.unshift @read.pop
- # Remove this token from any listeners
- @token_listeners.each do |obj|
- obj.pop_token
- end if @token_listeners
- end
+ # Remove this token from any listeners
+ @token_listeners.each do |obj|
+ obj.pop_token
+ end if @token_listeners
+ end
- def skip_tkspace(skip_nl = true)
- tokens = []
- while ((tk = get_tk).kind_of?(TkSPACE) ||
- (skip_nl && tk.kind_of?(TkNL)))
- tokens.push tk
- end
- unget_tk(tk)
- tokens
+ def skip_tkspace(skip_nl = true)
+ tokens = []
+ while ((tk = get_tk).kind_of?(TkSPACE) ||
+ (skip_nl && tk.kind_of?(TkNL)))
+ tokens.push tk
end
+ unget_tk(tk)
+ tokens
+ end
- def get_tkread
- read = @read.join("")
- @read = []
- read
- end
+ def get_tkread
+ read = @read.join("")
+ @read = []
+ read
+ end
- def peek_read
- @read.join('')
- end
+ def peek_read
+ @read.join('')
+ end
- NORMAL = "::"
- SINGLE = "<<"
+ NORMAL = "::"
+ SINGLE = "<<"
- # Look for the first comment in a file that isn't
- # a shebang line.
+ ##
+ # Look for the first comment in a file that isn't a shebang line.
- def collect_first_comment
- skip_tkspace
- res = ''
- first_line = true
+ def collect_first_comment
+ skip_tkspace
+ res = ''
+ first_line = true
- tk = get_tk
- while tk.kind_of?(TkCOMMENT)
- if first_line && tk.text[0,2] == "#!"
- skip_tkspace
- tk = get_tk
- else
- res << tk.text << "\n"
+ tk = get_tk
+ while tk.kind_of?(TkCOMMENT)
+ if first_line && tk.text[0,2] == "#!"
+ skip_tkspace
+ tk = get_tk
+ else
+ res << tk.text << "\n"
+ tk = get_tk
+ if tk.kind_of? TkNL
+ skip_tkspace(false)
tk = get_tk
- if tk.kind_of? TkNL
- skip_tkspace(false)
- tk = get_tk
- end
end
- first_line = false
end
- unget_tk(tk)
- res
+ first_line = false
end
+ unget_tk(tk)
+ res
+ end
+
+ def parse_toplevel_statements(container)
+ comment = collect_first_comment
+ look_for_directives_in(container, comment)
+ container.comment = comment unless comment.empty?
+ parse_statements(container, NORMAL, nil, comment)
+ end
+
+ def parse_statements(container, single=NORMAL, current_method=nil, comment='')
+ nest = 1
+ save_visibility = container.visibility
- def parse_toplevel_statements(container)
- comment = collect_first_comment
- look_for_directives_in(container, comment)
- container.comment = comment unless comment.empty?
- parse_statements(container, NORMAL, nil, comment)
- end
-
- def parse_statements(container, single=NORMAL, current_method=nil, comment='')
- nest = 1
- save_visibility = container.visibility
-
# if container.kind_of?(TopLevel)
# else
# comment = ''
# end
- non_comment_seen = true
-
- while tk = get_tk
-
- keep_comment = false
-
- non_comment_seen = true unless tk.kind_of?(TkCOMMENT)
-
- case tk
+ non_comment_seen = true
- when TkNL
- skip_tkspace(true) # Skip blanks and newlines
- tk = get_tk
- if tk.kind_of?(TkCOMMENT)
- if non_comment_seen
- comment = ''
- non_comment_seen = false
- end
- while tk.kind_of?(TkCOMMENT)
- comment << tk.text << "\n"
- tk = get_tk # this is the newline
- skip_tkspace(false) # leading spaces
- tk = get_tk
- end
- unless comment.empty?
- look_for_directives_in(container, comment)
- if container.done_documenting
- container.ongoing_visibility = save_visibility
-# return
- end
+ while tk = get_tk
+ keep_comment = false
+
+ non_comment_seen = true unless tk.kind_of?(TkCOMMENT)
+
+ case tk
+ when TkNL
+ skip_tkspace(true) # Skip blanks and newlines
+ tk = get_tk
+ if tk.kind_of?(TkCOMMENT)
+ if non_comment_seen
+ comment = ''
+ non_comment_seen = false
+ end
+ while tk.kind_of?(TkCOMMENT)
+ comment << tk.text << "\n"
+ tk = get_tk # this is the newline
+ skip_tkspace(false) # leading spaces
+ tk = get_tk
+ end
+ unless comment.empty?
+ look_for_directives_in(container, comment)
+ if container.done_documenting
+ container.ongoing_visibility = save_visibility
+ # return
end
- keep_comment = true
- else
- non_comment_seen = true
end
- unget_tk(tk)
keep_comment = true
+ else
+ non_comment_seen = true
+ end
+ unget_tk(tk)
+ keep_comment = true
+ when TkCLASS
+ if container.document_children
+ parse_class(container, single, tk, comment)
+ else
+ nest += 1
+ end
- when TkCLASS
- if container.document_children
- parse_class(container, single, tk, comment)
- else
- nest += 1
- end
-
- when TkMODULE
- if container.document_children
- parse_module(container, single, tk, comment)
- else
- nest += 1
- end
+ when TkMODULE
+ if container.document_children
+ parse_module(container, single, tk, comment)
+ else
+ nest += 1
+ end
- when TkDEF
- if container.document_self
- parse_method(container, single, tk, comment)
- else
- nest += 1
- end
+ when TkDEF
+ if container.document_self
+ parse_method(container, single, tk, comment)
+ else
+ nest += 1
+ end
- when TkCONSTANT
- if container.document_self
- parse_constant(container, single, tk, comment)
- end
+ when TkCONSTANT
+ if container.document_self
+ parse_constant(container, single, tk, comment)
+ end
- when TkALIAS
- if container.document_self
- parse_alias(container, single, tk, comment)
- end
+ when TkALIAS
+ if container.document_self
+ parse_alias(container, single, tk, comment)
+ end
- when TkYIELD
- if current_method.nil?
- warn("Warning: yield outside of method") if container.document_self
- else
- parse_yield(container, single, tk, current_method)
- end
+ when TkYIELD
+ if current_method.nil?
+ warn("Warning: yield outside of method") if container.document_self
+ else
+ parse_yield(container, single, tk, current_method)
+ end
- # Until and While can have a 'do', which shouldn't increas
- # the nesting. We can't solve the general case, but we can
- # handle most occurrences by ignoring a do at the end of a line
+ # Until and While can have a 'do', which shouldn't increas
+ # the nesting. We can't solve the general case, but we can
+ # handle most occurrences by ignoring a do at the end of a line
- when TkUNTIL, TkWHILE
- nest += 1
- puts "FOUND #{tk.class} in #{container.name}, nest = #{nest}, " +
- "line #{tk.line_no}" if $DEBUG_RDOC
- skip_optional_do_after_expression
+ when TkUNTIL, TkWHILE
+ nest += 1
+ puts "Found #{tk.class} in #{container.name}, nest = #{nest}, " +
+ "line #{tk.line_no}" if $DEBUG_RDOC
+ skip_optional_do_after_expression
# 'for' is trickier
- when TkFOR
- nest += 1
- puts "FOUND #{tk.class} in #{container.name}, nest = #{nest}, " +
- "line #{tk.line_no}" if $DEBUG_RDOC
- skip_for_variable
- skip_optional_do_after_expression
-
- when TkCASE, TkDO, TkIF, TkUNLESS, TkBEGIN
- nest += 1
- puts "Found #{tk.class} in #{container.name}, nest = #{nest}, " +
- "line #{tk.line_no}" if $DEBUG_RDOC
-
- when TkIDENTIFIER
- if nest == 1 and current_method.nil?
- case tk.name
- when "private", "protected", "public",
- "private_class_method", "public_class_method"
- parse_visibility(container, single, tk)
- keep_comment = true
- when "attr"
- parse_attr(container, single, tk, comment)
- when /^attr_(reader|writer|accessor)$/, @options.extra_accessors
- parse_attr_accessor(container, single, tk, comment)
- when "alias_method"
- if container.document_self
- parse_alias(container, single, tk, comment)
- end
- end
- end
-
- case tk.name
- when "require"
- parse_require(container, comment)
- when "include"
- parse_include(container, comment)
- end
-
+ when TkFOR
+ nest += 1
+ puts "Found #{tk.class} in #{container.name}, nest = #{nest}, " +
+ "line #{tk.line_no}" if $DEBUG_RDOC
+ skip_for_variable
+ skip_optional_do_after_expression
- when TkEND
- nest -= 1
- puts "Found 'end' in #{container.name}, nest = #{nest}, line #{tk.line_no}" if $DEBUG_RDOC
- puts "Method = #{current_method.name}" if $DEBUG_RDOC and current_method
- if nest == 0
- read_documentation_modifiers(container, CLASS_MODIFIERS)
- container.ongoing_visibility = save_visibility
- return
+ when TkCASE, TkDO, TkIF, TkUNLESS, TkBEGIN
+ nest += 1
+ puts "Found #{tk.class} in #{container.name}, nest = #{nest}, " +
+ "line #{tk.line_no}" if $DEBUG_RDOC
+
+ when TkIDENTIFIER
+ if nest == 1 and current_method.nil?
+ case tk.name
+ when "private", "protected", "public",
+ "private_class_method", "public_class_method"
+ parse_visibility(container, single, tk)
+ keep_comment = true
+ when "attr"
+ parse_attr(container, single, tk, comment)
+ when /^attr_(reader|writer|accessor)$/, @options.extra_accessors
+ parse_attr_accessor(container, single, tk, comment)
+ when "alias_method"
+ if container.document_self
+ parse_alias(container, single, tk, comment)
+ end
end
+ end
- end
+ case tk.name
+ when "require"
+ parse_require(container, comment)
+ when "include"
+ parse_include(container, comment)
+ end
- comment = '' unless keep_comment
- begin
- get_tkread
- skip_tkspace(false)
- end while peek_tk == TkNL
+
+ when TkEND
+ nest -= 1
+ puts "Found 'end' in #{container.name}, nest = #{nest}, line #{tk.line_no}" if $DEBUG_RDOC
+ puts "Method = #{current_method.name}" if $DEBUG_RDOC and current_method
+ if nest == 0
+ read_documentation_modifiers container, RDoc::CLASS_MODIFIERS
+ container.ongoing_visibility = save_visibility
+ return
+ end
end
+
+ comment = '' unless keep_comment
+
+ begin
+ get_tkread
+ skip_tkspace(false)
+ end while peek_tk == TkNL
end
-
- def parse_class(container, single, tk, comment, &block)
- progress("c")
+ end
- @stats.num_classes += 1
+ def parse_class(container, single, tk, comment, &block)
+ progress("c")
- container, name_t = get_class_or_module(container)
+ @stats.num_classes += 1
- case name_t
- when TkCONSTANT
- name = name_t.name
- superclass = "Object"
-
- if peek_tk.kind_of?(TkLT)
- get_tk
- skip_tkspace(true)
- superclass = get_class_specification
- superclass = "<unknown>" if superclass.empty?
- end
+ container, name_t = get_class_or_module(container)
- if single == SINGLE
- cls_type = SingleClass
- else
- cls_type = NormalClass
- end
+ case name_t
+ when TkCONSTANT
+ name = name_t.name
+ superclass = "Object"
- cls = container.add_class(cls_type, name, superclass)
- read_documentation_modifiers(cls, CLASS_MODIFIERS)
- cls.record_location(@top_level)
- parse_statements(cls)
- cls.comment = comment
+ if peek_tk.kind_of?(TkLT)
+ get_tk
+ skip_tkspace(true)
+ superclass = get_class_specification
+ superclass = "<unknown>" if superclass.empty?
+ end
- when TkLSHFT
- case name = get_class_specification
- when "self", container.name
- parse_statements(container, SINGLE, &block)
- else
- other = TopLevel.find_class_named(name)
- unless other
-# other = @top_level.add_class(NormalClass, name, nil)
-# other.record_location(@top_level)
-# other.comment = comment
- other = NormalClass.new("Dummy", nil)
- end
- read_documentation_modifiers(other, CLASS_MODIFIERS)
- parse_statements(other, SINGLE, &block)
- end
+ if single == SINGLE
+ cls_type = RDoc::SingleClass
+ else
+ cls_type = RDoc::NormalClass
+ end
+
+ cls = container.add_class cls_type, name, superclass
+ read_documentation_modifiers cls, RDoc::CLASS_MODIFIERS
+ cls.record_location(@top_level)
+ parse_statements(cls)
+ cls.comment = comment
+ when TkLSHFT
+ case name = get_class_specification
+ when "self", container.name
+ parse_statements(container, SINGLE, &block)
else
- warn("Expected class name or '<<'. Got #{name_t.class}: #{name_t.text.inspect}")
+ other = RDoc::TopLevel.find_class_named(name)
+ unless other
+ # other = @top_level.add_class(NormalClass, name, nil)
+ # other.record_location(@top_level)
+ # other.comment = comment
+ other = RDoc::NormalClass.new "Dummy", nil
+ end
+ read_documentation_modifiers other, RDoc::CLASS_MODIFIERS
+ parse_statements(other, SINGLE, &block)
end
+
+ else
+ warn("Expected class name or '<<'. Got #{name_t.class}: #{name_t.text.inspect}")
end
+ end
- def parse_module(container, single, tk, comment)
- progress("m")
- @stats.num_modules += 1
- container, name_t = get_class_or_module(container)
+ def parse_module(container, single, tk, comment)
+ progress("m")
+ @stats.num_modules += 1
+ container, name_t = get_class_or_module(container)
# skip_tkspace
- name = name_t.name
- mod = container.add_module(NormalModule, name)
- mod.record_location(@top_level)
- read_documentation_modifiers(mod, CLASS_MODIFIERS)
- parse_statements(mod)
- mod.comment = comment
- end
+ name = name_t.name
+ mod = container.add_module RDoc::NormalModule, name
+ mod.record_location @top_level
+ read_documentation_modifiers mod, RDoc::CLASS_MODIFIERS
+ parse_statements(mod)
+ mod.comment = comment
+ end
- # Look for the name of a class of module (optionally with a leading :: or
- # with :: separated named) and return the ultimate name and container
+ # Look for the name of a class of module (optionally with a leading :: or
+ # with :: separated named) and return the ultimate name and container
- def get_class_or_module(container)
- skip_tkspace
- name_t = get_tk
+ def get_class_or_module(container)
+ skip_tkspace
+ name_t = get_tk
- # class ::A -> A is in the top level
- if name_t.kind_of?(TkCOLON2)
- name_t = get_tk
- container = @top_level
- end
+ # class ::A -> A is in the top level
+ if name_t.kind_of?(TkCOLON2)
+ name_t = get_tk
+ container = @top_level
+ end
- skip_tkspace(false)
+ skip_tkspace(false)
- while peek_tk.kind_of?(TkCOLON2)
- prev_container = container
- container = container.find_module_named(name_t.name)
- if !container
+ while peek_tk.kind_of?(TkCOLON2)
+ prev_container = container
+ container = container.find_module_named(name_t.name)
+ if !container
# warn("Couldn't find module #{name_t.name}")
- container = prev_container.add_module(NormalModule, name_t.name)
- end
- get_tk
- name_t = get_tk
+ container = prev_container.add_module RDoc::NormalModule, name_t.name
end
- skip_tkspace(false)
- return [container, name_t]
+ get_tk
+ name_t = get_tk
end
+ skip_tkspace(false)
+ return [container, name_t]
+ end
- def parse_constant(container, single, tk, comment)
- name = tk.name
- skip_tkspace(false)
- eq_tk = get_tk
+ def parse_constant(container, single, tk, comment)
+ name = tk.name
+ skip_tkspace(false)
+ eq_tk = get_tk
- unless eq_tk.kind_of?(TkASSIGN)
- unget_tk(eq_tk)
- return
- end
+ unless eq_tk.kind_of?(TkASSIGN)
+ unget_tk(eq_tk)
+ return
+ end
- nest = 0
- get_tkread
+ nest = 0
+ get_tkread
- tk = get_tk
- if tk.kind_of? TkGT
- unget_tk(tk)
- unget_tk(eq_tk)
- return
- end
+ tk = get_tk
+ if tk.kind_of? TkGT
+ unget_tk(tk)
+ unget_tk(eq_tk)
+ return
+ end
- loop do
- puts("Param: #{tk}, #{@scanner.continue} " +
- "#{@scanner.lex_state} #{nest}") if $DEBUG_RDOC
+ loop do
+ puts "Param: %p, %s %s %s" %
+ [tk.text, @scanner.continue, @scanner.lex_state, nest] if $DEBUG_RDOC
case tk
when TkSEMICOLON
@@ -1868,182 +1850,184 @@ module RDoc
end
end
tk = get_tk
- end
+ end
- res = get_tkread.tr("\n", " ").strip
- res = "" if res == ";"
- con = Constant.new(name, res, comment)
- read_documentation_modifiers(con, CONSTANT_MODIFIERS)
- if con.document_self
- container.add_constant(con)
- end
+ res = get_tkread.tr("\n", " ").strip
+ res = "" if res == ";"
+
+ con = RDoc::Constant.new name, res, comment
+ read_documentation_modifiers con, RDoc::CONSTANT_MODIFIERS
+
+ if con.document_self
+ container.add_constant(con)
end
+ end
- def parse_method(container, single, tk, comment)
- progress(".")
- @stats.num_methods += 1
- line_no = tk.line_no
- column = tk.char_no
-
- start_collecting_tokens
- add_token(tk)
- add_token_listener(self)
-
+ def parse_method(container, single, tk, comment)
+ progress(".")
+ @stats.num_methods += 1
+ line_no = tk.line_no
+ column = tk.char_no
+
+ start_collecting_tokens
+ add_token(tk)
+ add_token_listener(self)
+
+ @scanner.instance_eval{@lex_state = EXPR_FNAME}
+ skip_tkspace(false)
+ name_t = get_tk
+ back_tk = skip_tkspace
+ meth = nil
+ added_container = false
+
+ dot = get_tk
+ if dot.kind_of?(TkDOT) or dot.kind_of?(TkCOLON2)
@scanner.instance_eval{@lex_state = EXPR_FNAME}
- skip_tkspace(false)
- name_t = get_tk
- back_tk = skip_tkspace
- meth = nil
- added_container = false
-
- dot = get_tk
- if dot.kind_of?(TkDOT) or dot.kind_of?(TkCOLON2)
- @scanner.instance_eval{@lex_state = EXPR_FNAME}
- skip_tkspace
- name_t2 = get_tk
- case name_t
- when TkSELF
- name = name_t2.name
- when TkCONSTANT
- name = name_t2.name
- prev_container = container
- container = container.find_module_named(name_t.name)
- if !container
- added_container = true
- obj = name_t.name.split("::").inject(Object) do |state, item|
- state.const_get(item)
- end rescue nil
-
- type = obj.class == Class ? NormalClass : NormalModule
- if not [Class, Module].include?(obj.class)
- warn("Couldn't find #{name_t.name}. Assuming it's a module")
- end
+ skip_tkspace
+ name_t2 = get_tk
+ case name_t
+ when TkSELF
+ name = name_t2.name
+ when TkCONSTANT
+ name = name_t2.name
+ prev_container = container
+ container = container.find_module_named(name_t.name)
+ if !container
+ added_container = true
+ obj = name_t.name.split("::").inject(Object) do |state, item|
+ state.const_get(item)
+ end rescue nil
+
+ type = obj.class == Class ? RDoc::NormalClass : RDoc::NormalModule
+ if not [Class, Module].include?(obj.class)
+ warn("Couldn't find #{name_t.name}. Assuming it's a module")
+ end
- if type == NormalClass then
- container = prev_container.add_class(type, name_t.name, obj.superclass.name)
- else
- container = prev_container.add_module(type, name_t.name)
- end
+ if type == RDoc::NormalClass then
+ container = prev_container.add_class(type, name_t.name, obj.superclass.name)
+ else
+ container = prev_container.add_module(type, name_t.name)
end
- else
- # warn("Unexpected token '#{name_t2.inspect}'")
- # break
- skip_method(container)
- return
- end
- meth = AnyMethod.new(get_tkread, name)
- meth.singleton = true
+ end
else
- unget_tk dot
- back_tk.reverse_each do |token|
- unget_tk token
- end
- name = name_t.name
-
- meth = AnyMethod.new(get_tkread, name)
- meth.singleton = (single == SINGLE)
+ # warn("Unexpected token '#{name_t2.inspect}'")
+ # break
+ skip_method(container)
+ return
end
+ meth = RDoc::AnyMethod.new(get_tkread, name)
+ meth.singleton = true
+ else
+ unget_tk dot
+ back_tk.reverse_each do |token|
+ unget_tk token
+ end
+ name = name_t.name
- remove_token_listener(self)
+ meth = RDoc::AnyMethod.new get_tkread, name
+ meth.singleton = (single == SINGLE)
+ end
- meth.start_collecting_tokens
- indent = TkSPACE.new(1,1)
- indent.set_text(" " * column)
+ remove_token_listener(self)
- meth.add_tokens([TkCOMMENT.new(line_no,
- 1,
- "# File #{@top_level.file_absolute_name}, line #{line_no}"),
- NEWLINE_TOKEN,
- indent])
+ meth.start_collecting_tokens
+ indent = TkSPACE.new(1,1)
+ indent.set_text(" " * column)
- meth.add_tokens(@token_stream)
+ meth.add_tokens([TkCOMMENT.new(line_no,
+ 1,
+ "# File #{@top_level.file_absolute_name}, line #{line_no}"),
+ NEWLINE_TOKEN,
+ indent])
- add_token_listener(meth)
+ meth.add_tokens(@token_stream)
- @scanner.instance_eval{@continue = false}
- parse_method_parameters(meth)
+ add_token_listener(meth)
- if meth.document_self
- container.add_method(meth)
- elsif added_container
- container.document_self = false
- end
+ @scanner.instance_eval{@continue = false}
+ parse_method_parameters(meth)
- # Having now read the method parameters and documentation modifiers, we
- # now know whether we have to rename #initialize to ::new
+ if meth.document_self
+ container.add_method(meth)
+ elsif added_container
+ container.document_self = false
+ end
- if name == "initialize" && !meth.singleton
- if meth.dont_rename_initialize
- meth.visibility = :protected
- else
- meth.singleton = true
- meth.name = "new"
- meth.visibility = :public
- end
- end
-
- parse_statements(container, single, meth)
-
- remove_token_listener(meth)
-
- # Look for a 'call-seq' in the comment, and override the
- # normal parameter stuff
-
- if comment.sub!(/:?call-seq:(.*?)^\s*\#?\s*$/m, '')
- seq = $1
- seq.gsub!(/^\s*\#\s*/, '')
- meth.call_seq = seq
- end
-
- meth.comment = comment
-
- end
-
- def skip_method(container)
- meth = AnyMethod.new("", "anon")
- parse_method_parameters(meth)
- parse_statements(container, false, meth)
- end
-
- # Capture the method's parameters. Along the way,
- # look for a comment containing
- #
- # # yields: ....
- #
- # and add this as the block_params for the method
-
- def parse_method_parameters(method)
- res = parse_method_or_yield_parameters(method)
- res = "(" + res + ")" unless res[0] == ?(
- method.params = res unless method.params
- if method.block_params.nil?
- skip_tkspace(false)
- read_documentation_modifiers(method, METHOD_MODIFIERS)
+ # Having now read the method parameters and documentation modifiers, we
+ # now know whether we have to rename #initialize to ::new
+
+ if name == "initialize" && !meth.singleton
+ if meth.dont_rename_initialize
+ meth.visibility = :protected
+ else
+ meth.singleton = true
+ meth.name = "new"
+ meth.visibility = :public
end
end
- def parse_method_or_yield_parameters(method=nil, modifiers=METHOD_MODIFIERS)
+ parse_statements(container, single, meth)
+
+ remove_token_listener(meth)
+
+ # Look for a 'call-seq' in the comment, and override the
+ # normal parameter stuff
+
+ if comment.sub!(/:?call-seq:(.*?)^\s*\#?\s*$/m, '')
+ seq = $1
+ seq.gsub!(/^\s*\#\s*/, '')
+ meth.call_seq = seq
+ end
+
+ meth.comment = comment
+ end
+
+ def skip_method(container)
+ meth = RDoc::AnyMethod.new "", "anon"
+ parse_method_parameters(meth)
+ parse_statements(container, false, meth)
+ end
+
+ # Capture the method's parameters. Along the way, look for a comment
+ # containing.
+ #
+ # # yields: ....
+ #
+ # and add this as the block_params for the method
+
+ def parse_method_parameters(method)
+ res = parse_method_or_yield_parameters(method)
+ res = "(" + res + ")" unless res[0] == ?(
+ method.params = res unless method.params
+ if method.block_params.nil?
skip_tkspace(false)
- tk = get_tk
+ read_documentation_modifiers method, RDoc::METHOD_MODIFIERS
+ end
+ end
- # Little hack going on here. In the statement
- # f = 2*(1+yield)
- # We see the RPAREN as the next token, so we need
- # to exit early. This still won't catch all cases
- # (such as "a = yield + 1"
- end_token = case tk
- when TkLPAREN, TkfLPAREN
- TkRPAREN
- when TkRPAREN
- return ""
- else
- TkNL
- end
- nest = 0
+ def parse_method_or_yield_parameters(method = nil,
+ modifiers = RDoc::METHOD_MODIFIERS)
+ skip_tkspace(false)
+ tk = get_tk
- loop do
- puts("Param: #{tk.inspect}, #{@scanner.continue} " +
- "#{@scanner.lex_state} #{nest}") if $DEBUG_RDOC
+ # Little hack going on here. In the statement
+ # f = 2*(1+yield)
+ # We see the RPAREN as the next token, so we need
+ # to exit early. This still won't catch all cases
+ # (such as "a = yield + 1"
+ end_token = case tk
+ when TkLPAREN, TkfLPAREN
+ TkRPAREN
+ when TkRPAREN
+ return ""
+ else
+ TkNL
+ end
+ nest = 0
+
+ loop do
+ puts "Param: %p, %s %s %s" %
+ [tk.text, @scanner.continue, @scanner.lex_state, nest] if $DEBUG_RDOC
case tk
when TkSEMICOLON
break
@@ -2064,113 +2048,113 @@ module RDoc
break unless @scanner.continue
end
when method && method.block_params.nil? && TkCOMMENT
- unget_tk(tk)
- read_documentation_modifiers(method, modifiers)
+ unget_tk(tk)
+ read_documentation_modifiers(method, modifiers)
end
- tk = get_tk
- end
- res = get_tkread.tr("\n", " ").strip
- res = "" if res == ";"
- res
+ tk = get_tk
end
+ res = get_tkread.tr("\n", " ").strip
+ res = "" if res == ";"
+ res
+ end
- # skip the var [in] part of a 'for' statement
- def skip_for_variable
- skip_tkspace(false)
- tk = get_tk
- skip_tkspace(false)
- tk = get_tk
- unget_tk(tk) unless tk.kind_of?(TkIN)
+ # skip the var [in] part of a 'for' statement
+ def skip_for_variable
+ skip_tkspace(false)
+ tk = get_tk
+ skip_tkspace(false)
+ tk = get_tk
+ unget_tk(tk) unless tk.kind_of?(TkIN)
+ end
+
+ # while, until, and for have an optional
+ def skip_optional_do_after_expression
+ skip_tkspace(false)
+ tk = get_tk
+ case tk
+ when TkLPAREN, TkfLPAREN
+ end_token = TkRPAREN
+ else
+ end_token = TkNL
end
- # while, until, and for have an optional
- def skip_optional_do_after_expression
- skip_tkspace(false)
- tk = get_tk
+ nest = 0
+ @scanner.instance_eval{@continue = false}
+
+ loop do
+ puts("\nWhile: #{tk.text.inspect}, #{@scanner.continue} " \
+ "#{@scanner.lex_state} #{nest}") if $DEBUG_RDOC
case tk
+ when TkSEMICOLON
+ break
when TkLPAREN, TkfLPAREN
- end_token = TkRPAREN
- else
- end_token = TkNL
- end
-
- nest = 0
- @scanner.instance_eval{@continue = false}
-
- loop do
- puts("\nWhile: #{tk}, #{@scanner.continue} " +
- "#{@scanner.lex_state} #{nest}") if $DEBUG_RDOC
- case tk
- when TkSEMICOLON
- break
- when TkLPAREN, TkfLPAREN
- nest += 1
- when TkDO
- break if nest.zero?
- when end_token
- if end_token == TkRPAREN
- nest -= 1
- break if @scanner.lex_state == EXPR_END and nest.zero?
- else
- break unless @scanner.continue
- end
+ nest += 1
+ when TkDO
+ break if nest.zero?
+ when end_token
+ if end_token == TkRPAREN
+ nest -= 1
+ break if @scanner.lex_state == EXPR_END and nest.zero?
+ else
+ break unless @scanner.continue
end
- tk = get_tk
- end
- skip_tkspace(false)
- if peek_tk.kind_of? TkDO
- get_tk
end
+ tk = get_tk
end
-
- # Return a superclass, which can be either a constant
- # of an expression
+ skip_tkspace(false)
+ if peek_tk.kind_of? TkDO
+ get_tk
+ end
+ end
- def get_class_specification
- tk = get_tk
- return "self" if tk.kind_of?(TkSELF)
-
- res = ""
- while tk.kind_of?(TkCOLON2) ||
- tk.kind_of?(TkCOLON3) ||
- tk.kind_of?(TkCONSTANT)
-
- res += tk.text
- tk = get_tk
- end
+ # Return a superclass, which can be either a constant
+ # of an expression
- unget_tk(tk)
- skip_tkspace(false)
+ def get_class_specification
+ tk = get_tk
+ return "self" if tk.kind_of?(TkSELF)
- get_tkread # empty out read buffer
+ res = ""
+ while tk.kind_of?(TkCOLON2) ||
+ tk.kind_of?(TkCOLON3) ||
+ tk.kind_of?(TkCONSTANT)
+ res += tk.text
tk = get_tk
+ end
- case tk
- when TkNL, TkCOMMENT, TkSEMICOLON
- unget_tk(tk)
- return res
- end
+ unget_tk(tk)
+ skip_tkspace(false)
- res += parse_call_parameters(tk)
- res
+ get_tkread # empty out read buffer
+
+ tk = get_tk
+
+ case tk
+ when TkNL, TkCOMMENT, TkSEMICOLON
+ unget_tk(tk)
+ return res
end
- def parse_call_parameters(tk)
+ res += parse_call_parameters(tk)
+ res
+ end
+
+ def parse_call_parameters(tk)
- end_token = case tk
- when TkLPAREN, TkfLPAREN
- TkRPAREN
- when TkRPAREN
- return ""
- else
- TkNL
- end
- nest = 0
+ end_token = case tk
+ when TkLPAREN, TkfLPAREN
+ TkRPAREN
+ when TkRPAREN
+ return ""
+ else
+ TkNL
+ end
+ nest = 0
- loop do
- puts("Call param: #{tk}, #{@scanner.continue} " +
- "#{@scanner.lex_state} #{nest}") if $DEBUG_RDOC
+ loop do
+ puts("Call param: #{tk}, #{@scanner.continue} " +
+ "#{@scanner.lex_state} #{nest}") if $DEBUG_RDOC
case tk
when TkSEMICOLON
break
@@ -2184,214 +2168,209 @@ module RDoc
break unless @scanner.continue
end
when TkCOMMENT
- unget_tk(tk)
- break
+ unget_tk(tk)
+ break
end
tk = get_tk
- end
- res = get_tkread.tr("\n", " ").strip
- res = "" if res == ";"
- res
end
+ res = get_tkread.tr("\n", " ").strip
+ res = "" if res == ";"
+ res
+ end
+ # Parse a constant, which might be qualified by
+ # one or more class or module names
- # Parse a constant, which might be qualified by
- # one or more class or module names
+ def get_constant
+ res = ""
+ skip_tkspace(false)
+ tk = get_tk
- def get_constant
- res = ""
- skip_tkspace(false)
- tk = get_tk
+ while tk.kind_of?(TkCOLON2) ||
+ tk.kind_of?(TkCOLON3) ||
+ tk.kind_of?(TkCONSTANT)
- while tk.kind_of?(TkCOLON2) ||
- tk.kind_of?(TkCOLON3) ||
- tk.kind_of?(TkCONSTANT)
-
- res += tk.text
- tk = get_tk
- end
+ res += tk.text
+ tk = get_tk
+ end
# if res.empty?
# warn("Unexpected token #{tk} in constant")
-# end
- unget_tk(tk)
- res
- end
+# end
+ unget_tk(tk)
+ res
+ end
- # Get a constant that may be surrounded by parens
-
- def get_constant_with_optional_parens
- skip_tkspace(false)
- nest = 0
- while (tk = peek_tk).kind_of?(TkLPAREN) || tk.kind_of?(TkfLPAREN)
- get_tk
- skip_tkspace(true)
- nest += 1
- end
+ # Get a constant that may be surrounded by parens
+
+ def get_constant_with_optional_parens
+ skip_tkspace(false)
+ nest = 0
+ while (tk = peek_tk).kind_of?(TkLPAREN) || tk.kind_of?(TkfLPAREN)
+ get_tk
+ skip_tkspace(true)
+ nest += 1
+ end
- name = get_constant
+ name = get_constant
- while nest > 0
- skip_tkspace(true)
- tk = get_tk
- nest -= 1 if tk.kind_of?(TkRPAREN)
- end
- name
- end
-
- # Directives are modifier comments that can appear after class, module,
- # or method names. For example
- #
- # def fred # :yields: a, b
- #
- # or
- #
- # class SM # :nodoc:
- #
- # we return the directive name and any parameters as a two element array
-
- def read_directive(allowed)
+ while nest > 0
+ skip_tkspace(true)
tk = get_tk
- puts "directive: #{tk.inspect}" if $DEBUG_RDOC
- result = nil
- if tk.kind_of?(TkCOMMENT)
- if tk.text =~ /\s*:?(\w+):\s*(.*)/
- directive = $1.downcase
- if allowed.include?(directive)
- result = [directive, $2]
- end
+ nest -= 1 if tk.kind_of?(TkRPAREN)
+ end
+ name
+ end
+
+ # Directives are modifier comments that can appear after class, module,
+ # or method names. For example:
+ #
+ # def fred # :yields: a, b
+ #
+ # or:
+ #
+ # class MyClass # :nodoc:
+ #
+ # We return the directive name and any parameters as a two element array
+
+ def read_directive(allowed)
+ tk = get_tk
+ puts "directive: #{tk.text.inspect}" if $DEBUG_RDOC
+ result = nil
+ if tk.kind_of?(TkCOMMENT)
+ if tk.text =~ /\s*:?(\w+):\s*(.*)/
+ directive = $1.downcase
+ if allowed.include?(directive)
+ result = [directive, $2]
end
- else
- unget_tk(tk)
end
- result
+ else
+ unget_tk(tk)
end
+ result
+ end
-
- def read_documentation_modifiers(context, allow)
- dir = read_directive(allow)
+ def read_documentation_modifiers(context, allow)
+ dir = read_directive(allow)
- case dir[0]
+ case dir[0]
- when "notnew", "not_new", "not-new"
- context.dont_rename_initialize = true
+ when "notnew", "not_new", "not-new"
+ context.dont_rename_initialize = true
- when "nodoc"
- context.document_self = false
- if dir[1].downcase == "all"
- context.document_children = false
- end
+ when "nodoc"
+ context.document_self = false
+ if dir[1].downcase == "all"
+ context.document_children = false
+ end
- when "doc"
- context.document_self = true
- context.force_documentation = true
+ when "doc"
+ context.document_self = true
+ context.force_documentation = true
- when "yield", "yields"
- unless context.params.nil?
- context.params.sub!(/(,|)\s*&\w+/,'') # remove parameter &proc
- end
- context.block_params = dir[1]
-
- when "arg", "args"
- context.params = dir[1]
- end if dir
- end
-
-
- # Look for directives in a normal comment block:
- #
- # #-- - don't display comment from this point forward
- #
- #
- # This routine modifies it's parameter
-
- def look_for_directives_in(context, comment)
-
- preprocess = SM::PreProcess.new(@input_file_name,
- @options.rdoc_include)
-
- preprocess.handle(comment) do |directive, param|
- case directive
- when "stopdoc"
- context.stop_doc
- ""
- when "startdoc"
- context.start_doc
- context.force_documentation = true
- ""
-
- when "enddoc"
- #context.done_documenting = true
- #""
- throw :enddoc
-
- when "main"
- @options.main_page = param
- ""
-
- when "title"
- @options.title = param
- ""
-
- when "section"
- context.set_current_section(param, comment)
- comment.clear
- break
- else
- warn "Unrecognized directive '#{directive}'"
- break
- end
+ when "yield", "yields"
+ unless context.params.nil?
+ context.params.sub!(/(,|)\s*&\w+/,'') # remove parameter &proc
end
+ context.block_params = dir[1]
- remove_private_comments(comment)
- end
+ when "arg", "args"
+ context.params = dir[1]
+ end if dir
+ end
- def remove_private_comments(comment)
- comment.gsub!(/^#--.*?^#\+\+/m, '')
- comment.sub!(/^#--.*/m, '')
- end
+ ##
+ # Look for directives in a normal comment block:
+ #
+ # #-- - don't display comment from this point forward
+ #
+ # This routine modifies it's parameter
+
+ def look_for_directives_in(context, comment)
+ preprocess = RDoc::Markup::PreProcess.new(@input_file_name,
+ @options.rdoc_include)
+
+ preprocess.handle(comment) do |directive, param|
+ case directive
+ when "stopdoc"
+ context.stop_doc
+ ""
+ when "startdoc"
+ context.start_doc
+ context.force_documentation = true
+ ""
+ when "enddoc"
+ #context.done_documenting = true
+ #""
+ throw :enddoc
+ when "main"
+ @options.main_page = param
+ ""
+
+ when "title"
+ @options.title = param
+ ""
+
+ when "section"
+ context.set_current_section(param, comment)
+ comment.clear
+ break
- def get_symbol_or_name
- tk = get_tk
- case tk
- when TkSYMBOL
- tk.text.sub(/^:/, '')
- when TkId, TkOp
- tk.name
- when TkSTRING
- tk.text
else
- raise "Name or symbol expected (got #{tk})"
+ warn "Unrecognized directive '#{directive}'"
+ break
end
end
-
- def parse_alias(context, single, tk, comment)
+
+ remove_private_comments(comment)
+ end
+
+ def remove_private_comments(comment)
+ comment.gsub!(/^#--.*?^#\+\+/m, '')
+ comment.sub!(/^#--.*/m, '')
+ end
+
+ def get_symbol_or_name
+ tk = get_tk
+ case tk
+ when TkSYMBOL
+ tk.text.sub(/^:/, '')
+ when TkId, TkOp
+ tk.name
+ when TkSTRING
+ tk.text
+ else
+ raise "Name or symbol expected (got #{tk})"
+ end
+ end
+
+ def parse_alias(context, single, tk, comment)
+ skip_tkspace
+ if (peek_tk.kind_of? TkLPAREN)
+ get_tk
skip_tkspace
- if (peek_tk.kind_of? TkLPAREN)
- get_tk
- skip_tkspace
- end
- new_name = get_symbol_or_name
- @scanner.instance_eval{@lex_state = EXPR_FNAME}
+ end
+ new_name = get_symbol_or_name
+ @scanner.instance_eval{@lex_state = EXPR_FNAME}
+ skip_tkspace
+ if (peek_tk.kind_of? TkCOMMA)
+ get_tk
skip_tkspace
- if (peek_tk.kind_of? TkCOMMA)
- get_tk
- skip_tkspace
- end
- old_name = get_symbol_or_name
-
- al = Alias.new(get_tkread, old_name, new_name, comment)
- read_documentation_modifiers(al, ATTR_MODIFIERS)
- if al.document_self
- context.add_alias(al)
- end
end
+ old_name = get_symbol_or_name
- def parse_yield_parameters
- parse_method_or_yield_parameters
+ al = RDoc::Alias.new get_tkread, old_name, new_name, comment
+ read_documentation_modifiers al, RDoc::ATTR_MODIFIERS
+ if al.document_self
+ context.add_alias(al)
end
+ end
+
+ def parse_yield_parameters
+ parse_method_or_yield_parameters
+ end
def parse_yield(context, single, tk, method)
if method.block_params.nil?
@@ -2413,15 +2392,15 @@ module RDoc
case tk
when TkSTRING
name = tk.text
-# when TkCONSTANT, TkIDENTIFIER, TkIVAR, TkGVAR
-# name = tk.name
+ # when TkCONSTANT, TkIDENTIFIER, TkIVAR, TkGVAR
+ # name = tk.name
when TkDSTRING
warn "Skipping require of dynamic string: #{tk.text}"
- # else
- # warn "'require' used as variable"
+ # else
+ # warn "'require' used as variable"
end
if name
- context.add_require(Require.new(name, comment))
+ context.add_require(RDoc::Require.new(name, comment))
else
unget_tk(tk)
end
@@ -2432,174 +2411,171 @@ module RDoc
skip_tkspace_comment
name = get_constant_with_optional_parens
unless name.empty?
- context.add_include(Include.new(name, comment))
+ context.add_include RDoc::Include.new(name, comment)
end
return unless peek_tk.kind_of?(TkCOMMA)
get_tk
end
end
- def get_bool
- skip_tkspace
+ def get_bool
+ skip_tkspace
+ tk = get_tk
+ case tk
+ when TkTRUE
+ true
+ when TkFALSE, TkNIL
+ false
+ else
+ unget_tk tk
+ true
+ end
+ end
+
+ def parse_attr(context, single, tk, comment)
+ args = parse_symbol_arg(1)
+ if args.size > 0
+ name = args[0]
+ rw = "R"
+ skip_tkspace(false)
tk = get_tk
- case tk
- when TkTRUE
- true
- when TkFALSE, TkNIL
- false
+ if tk.kind_of? TkCOMMA
+ rw = "RW" if get_bool
else
unget_tk tk
- true
end
- end
-
- def parse_attr(context, single, tk, comment)
- args = parse_symbol_arg(1)
- if args.size > 0
- name = args[0]
- rw = "R"
- skip_tkspace(false)
- tk = get_tk
- if tk.kind_of? TkCOMMA
- rw = "RW" if get_bool
- else
- unget_tk tk
- end
- att = Attr.new(get_tkread, name, rw, comment)
- read_documentation_modifiers(att, ATTR_MODIFIERS)
- if att.document_self
- context.add_attribute(att)
- end
- else
- warn("'attr' ignored - looks like a variable")
- end
-
- end
-
- def parse_visibility(container, single, tk)
- singleton = (single == SINGLE)
- vis = case tk.name
- when "private" then :private
- when "protected" then :protected
- when "public" then :public
- when "private_class_method"
- singleton = true
- :private
- when "public_class_method"
- singleton = true
- :public
- else raise "Invalid visibility: #{tk.name}"
- end
-
- skip_tkspace_comment(false)
- case peek_tk
- # Ryan Davis suggested the extension to ignore modifiers, because he
- # often writes
- #
- # protected unless $TESTING
- #
- when TkNL, TkUNLESS_MOD, TkIF_MOD
-# error("Missing argument") if singleton
- container.ongoing_visibility = vis
- else
- args = parse_symbol_arg
- container.set_visibility_for(args, vis, singleton)
+ att = RDoc::Attr.new get_tkread, name, rw, comment
+ read_documentation_modifiers att, RDoc::ATTR_MODIFIERS
+ if att.document_self
+ context.add_attribute(att)
end
+ else
+ warn("'attr' ignored - looks like a variable")
end
+ end
+
+ def parse_visibility(container, single, tk)
+ singleton = (single == SINGLE)
+ vis = case tk.name
+ when "private" then :private
+ when "protected" then :protected
+ when "public" then :public
+ when "private_class_method"
+ singleton = true
+ :private
+ when "public_class_method"
+ singleton = true
+ :public
+ else raise "Invalid visibility: #{tk.name}"
+ end
- def parse_attr_accessor(context, single, tk, comment)
+ skip_tkspace_comment(false)
+ case peek_tk
+ # Ryan Davis suggested the extension to ignore modifiers, because he
+ # often writes
+ #
+ # protected unless $TESTING
+ #
+ when TkNL, TkUNLESS_MOD, TkIF_MOD
+ # error("Missing argument") if singleton
+ container.ongoing_visibility = vis
+ else
args = parse_symbol_arg
- read = get_tkread
- rw = "?"
+ container.set_visibility_for(args, vis, singleton)
+ end
+ end
- # If nodoc is given, don't document any of them
+ def parse_attr_accessor(context, single, tk, comment)
+ args = parse_symbol_arg
+ read = get_tkread
+ rw = "?"
- tmp = CodeObject.new
- read_documentation_modifiers(tmp, ATTR_MODIFIERS)
- return unless tmp.document_self
+ # If nodoc is given, don't document any of them
- case tk.name
- when "attr_reader" then rw = "R"
- when "attr_writer" then rw = "W"
- when "attr_accessor" then rw = "RW"
- else
- rw = @options.extra_accessor_flags[tk.name]
- end
-
- for name in args
- att = Attr.new(get_tkread, name, rw, comment)
- context.add_attribute(att)
- end
+ tmp = RDoc::CodeObject.new
+ read_documentation_modifiers tmp, RDoc::ATTR_MODIFIERS
+ return unless tmp.document_self
+
+ case tk.name
+ when "attr_reader" then rw = "R"
+ when "attr_writer" then rw = "W"
+ when "attr_accessor" then rw = "RW"
+ else
+ rw = @options.extra_accessor_flags[tk.name]
end
- def skip_tkspace_comment(skip_nl = true)
- loop do
- skip_tkspace(skip_nl)
- return unless peek_tk.kind_of? TkCOMMENT
- get_tk
- end
+ for name in args
+ att = RDoc::Attr.new get_tkread, name, rw, comment
+ context.add_attribute att
end
+ end
- def parse_symbol_arg(no = nil)
+ def skip_tkspace_comment(skip_nl = true)
+ loop do
+ skip_tkspace(skip_nl)
+ return unless peek_tk.kind_of? TkCOMMENT
+ get_tk
+ end
+ end
- args = []
- skip_tkspace_comment
- case tk = get_tk
- when TkLPAREN
- loop do
- skip_tkspace_comment
- if tk1 = parse_symbol_in_arg
- args.push tk1
- break if no and args.size >= no
- end
-
- skip_tkspace_comment
- case tk2 = get_tk
- when TkRPAREN
- break
- when TkCOMMA
- else
- warn("unexpected token: '#{tk2.inspect}'") if $DEBUG_RDOC
- break
- end
- end
- else
- unget_tk tk
- if tk = parse_symbol_in_arg
- args.push tk
- return args if no and args.size >= no
- end
+ def parse_symbol_arg(no = nil)
+ args = []
+ skip_tkspace_comment
+ case tk = get_tk
+ when TkLPAREN
+ loop do
+ skip_tkspace_comment
+ if tk1 = parse_symbol_in_arg
+ args.push tk1
+ break if no and args.size >= no
+ end
- loop do
-# skip_tkspace_comment(false)
- skip_tkspace(false)
+ skip_tkspace_comment
+ case tk2 = get_tk
+ when TkRPAREN
+ break
+ when TkCOMMA
+ else
+ warn("unexpected token: '#{tk2.inspect}'") if $DEBUG_RDOC
+ break
+ end
+ end
+ else
+ unget_tk tk
+ if tk = parse_symbol_in_arg
+ args.push tk
+ return args if no and args.size >= no
+ end
- tk1 = get_tk
- unless tk1.kind_of?(TkCOMMA)
- unget_tk tk1
- break
- end
-
- skip_tkspace_comment
- if tk = parse_symbol_in_arg
- args.push tk
- break if no and args.size >= no
- end
- end
+ loop do
+ # skip_tkspace_comment(false)
+ skip_tkspace(false)
+
+ tk1 = get_tk
+ unless tk1.kind_of?(TkCOMMA)
+ unget_tk tk1
+ break
+ end
+
+ skip_tkspace_comment
+ if tk = parse_symbol_in_arg
+ args.push tk
+ break if no and args.size >= no
+ end
end
- args
end
+ args
+ end
- def parse_symbol_in_arg
- case tk = get_tk
- when TkSYMBOL
- tk.text.sub(/^:/, '')
- when TkSTRING
- eval @read[-1]
- else
- warn("Expected symbol or string, got #{tk.inspect}") if $DEBUG_RDOC
- nil
- end
+ def parse_symbol_in_arg
+ case tk = get_tk
+ when TkSYMBOL
+ tk.text.sub(/^:/, '')
+ when TkSTRING
+ eval @read[-1]
+ else
+ warn("Expected symbol or string, got #{tk.inspect}") if $DEBUG_RDOC
+ nil
end
end
diff --git a/lib/rdoc/parsers/parse_simple.rb b/lib/rdoc/parsers/parse_simple.rb
index 3f1a546964..f4b501fe93 100644
--- a/lib/rdoc/parsers/parse_simple.rb
+++ b/lib/rdoc/parsers/parse_simple.rb
@@ -1,41 +1,40 @@
-# Parse a non-source file. We basically take the whole thing
-# as one big comment. If the first character in the file
-# is '#', we strip leading pound signs.
-
-
-require "rdoc/code_objects"
-require "rdoc/markup/simple_markup/preprocess"
-
-module RDoc
- # See rdoc/parsers/parse_c.rb
-
- class SimpleParser
-
- # prepare to parse a plain file
- def initialize(top_level, file_name, body, options, stats)
-
- preprocess = SM::PreProcess.new(file_name, options.rdoc_include)
-
- preprocess.handle(body) do |directive, param|
- $stderr.puts "Unrecognized directive '#{directive}' in #{file_name}"
- end
-
- @body = body
- @options = options
- @top_level = top_level
- end
-
- # Extract the file contents and attach them to the toplevel as a
- # comment
-
- def scan
- # @body.gsub(/^(\s\n)+/, '')
- @top_level.comment = remove_private_comments(@body)
- @top_level
- end
+require 'rdoc'
+require 'rdoc/code_objects'
+require 'rdoc/markup/preprocess'
+
+##
+# Parse a non-source file. We basically take the whole thing as one big
+# comment. If the first character in the file is '#', we strip leading pound
+# signs.
+
+class RDoc::SimpleParser
- def remove_private_comments(comment)
- comment.gsub(/^--.*?^\+\+/m, '').sub(/^--.*/m, '')
+ ##
+ # Prepare to parse a plain file
+
+ def initialize(top_level, file_name, body, options, stats)
+ preprocess = RDoc::Markup::PreProcess.new(file_name, options.rdoc_include)
+
+ preprocess.handle(body) do |directive, param|
+ warn "Unrecognized directive '#{directive}' in #{file_name}"
end
+
+ @body = body
+ @options = options
+ @top_level = top_level
end
+
+ ##
+ # Extract the file contents and attach them to the toplevel as a comment
+
+ def scan
+ @top_level.comment = remove_private_comments(@body)
+ @top_level
+ end
+
+ def remove_private_comments(comment)
+ comment.gsub(/^--[^-].*?^\+\+/m, '').sub(/^--.*/m, '')
+ end
+
end
+
diff --git a/lib/rdoc/rdoc.rb b/lib/rdoc/rdoc.rb
index 559af5e37a..ffaf56e427 100644
--- a/lib/rdoc/rdoc.rb
+++ b/lib/rdoc/rdoc.rb
@@ -5,6 +5,7 @@ require 'rdoc/parsers/parse_c.rb'
require 'rdoc/parsers/parse_f95.rb'
require 'rdoc/parsers/parse_simple.rb'
+require 'rdoc/stats'
require 'rdoc/options'
require 'rdoc/diagram'
@@ -16,31 +17,6 @@ require 'time'
module RDoc
##
- # Simple stats collector
-
- class Stats
- attr_accessor :num_files, :num_classes, :num_modules, :num_methods
- def initialize
- @num_files = @num_classes = @num_modules = @num_methods = 0
- @start = Time.now
- end
- def print
- puts "Files: #@num_files"
- puts "Classes: #@num_classes"
- puts "Modules: #@num_modules"
- puts "Methods: #@num_methods"
- puts "Elapsed: " + sprintf("%0.3fs", Time.now - @start)
- end
- end
-
- ##
- # Exception thrown by any rdoc error.
-
- class Error < RuntimeError; end
-
- RDocError = Error # :nodoc:
-
- ##
# Encapsulate the production of rdoc documentation. Basically
# you can use this as you would invoke rdoc from the command
# line:
@@ -192,22 +168,27 @@ module RDoc
# for .document files.
def list_files_in_directory(dir, options)
- normalized_file_list(options, Dir.glob(File.join(dir, "*")), false, options.exclude)
+ files = Dir.glob File.join(dir, "*")
+
+ normalized_file_list options, files, false, options.exclude
end
##
# Parse each file on the command line, recursively entering directories.
def parse_files(options)
- file_info = []
-
files = options.files
files = ["."] if files.empty?
file_list = normalized_file_list(options, files, true)
+ return [] if file_list.empty?
+
+ file_info = []
+ width = file_list.map { |name| name.length }.max + 1
+
file_list.each do |fn|
- $stderr.printf("\n%35s: ", File.basename(fn)) unless options.quiet
+ $stderr.printf("\n%*s: ", width, fn) unless options.quiet
content = File.open(fn, "r:ascii-8bit") {|f| f.read}
if /coding:\s*(\S+)/ =~ content[/\A(?:.*\n){0,2}/]
@@ -252,6 +233,7 @@ module RDoc
unless options.all_one_file
@last_created = setup_output_dir(options.op_dir, options.force_update)
end
+
start_time = Time.now
file_info = parse_files(options)
diff --git a/lib/rdoc/ri/descriptions.rb b/lib/rdoc/ri/descriptions.rb
index c9b7c9ba77..643d01fea8 100644
--- a/lib/rdoc/ri/descriptions.rb
+++ b/lib/rdoc/ri/descriptions.rb
@@ -1,5 +1,5 @@
require 'yaml'
-require 'rdoc/markup/simple_markup/fragments'
+require 'rdoc/markup/fragments'
require 'rdoc/ri'
#--
@@ -91,7 +91,7 @@ class RDoc::RI::ModuleDescription < RDoc::RI::Description
@comment = old.comment
else
unless old.comment.nil? or old.comment.empty? then
- @comment << SM::Flow::RULE.new
+ @comment << RDoc::Markup::Flow::RULE.new
@comment.concat old.comment
end
end
diff --git a/lib/rdoc/ri/display.rb b/lib/rdoc/ri/display.rb
index 21fd488bb3..1aa66b7ac5 100644
--- a/lib/rdoc/ri/display.rb
+++ b/lib/rdoc/ri/display.rb
@@ -26,7 +26,7 @@ end
##
# A paging display module. Uses the RDoc::RI::Formatter class to do the actual
-# presentation
+# presentation.
class RDoc::RI::DefaultDisplay
diff --git a/lib/rdoc/ri/driver.rb b/lib/rdoc/ri/driver.rb
index a1aa64e598..3b3c5fa9d8 100644
--- a/lib/rdoc/ri/driver.rb
+++ b/lib/rdoc/ri/driver.rb
@@ -6,8 +6,8 @@ require 'rdoc/ri/paths'
require 'rdoc/ri/formatter'
require 'rdoc/ri/display'
require 'fileutils'
-require 'rdoc/markup/simple_markup'
-require 'rdoc/markup/simple_markup/to_flow'
+require 'rdoc/markup'
+require 'rdoc/markup/to_flow'
class RDoc::RI::Driver
@@ -222,7 +222,7 @@ Options may also be set in the 'RI' environment variable.
return @class_cache if @class_cache
newest = map_dirs('created.rid', :all) do |f|
- File.mtime f if test ?f, f
+ File.mtime f if test ?f, f
end.max
up_to_date = (File.exist?(class_cache_file_path) and
@@ -341,7 +341,7 @@ Options may also be set in the 'RI' environment variable.
end
def read_yaml(path)
- YAML.load File.read(path).gsub(/ \!ruby\/(object|struct):(RDoc|RI).*/, '')
+ YAML.load File.read(path).gsub(/ \!ruby\/(object|struct):(RDoc::RI|RI).*/, '')
end
def run
diff --git a/lib/rdoc/ri/formatter.rb b/lib/rdoc/ri/formatter.rb
index 0a98508dde..960f2e3c91 100644
--- a/lib/rdoc/ri/formatter.rb
+++ b/lib/rdoc/ri/formatter.rb
@@ -99,17 +99,17 @@ class RDoc::RI::Formatter
def display_list(list)
case list.type
- when SM::ListBase::BULLET
+ when RDoc::Markup::ListBase::BULLET
prefixer = proc { |ignored| @indent + "* " }
- when SM::ListBase::NUMBER,
- SM::ListBase::UPPERALPHA,
- SM::ListBase::LOWERALPHA
+ when RDoc::Markup::ListBase::NUMBER,
+ RDoc::Markup::ListBase::UPPERALPHA,
+ RDoc::Markup::ListBase::LOWERALPHA
start = case list.type
- when SM::ListBase::NUMBER then 1
- when SM::ListBase::UPPERALPHA then 'A'
- when SM::ListBase::LOWERALPHA then 'a'
+ when RDoc::Markup::ListBase::NUMBER then 1
+ when RDoc::Markup::ListBase::UPPERALPHA then 'A'
+ when RDoc::Markup::ListBase::LOWERALPHA then 'a'
end
prefixer = proc do |ignored|
res = @indent + "#{start}.".ljust(4)
@@ -117,15 +117,15 @@ class RDoc::RI::Formatter
res
end
- when SM::ListBase::LABELED
+ when RDoc::Markup::ListBase::LABELED
prefixer = proc do |li|
li.label
end
- when SM::ListBase::NOTE
+ when RDoc::Markup::ListBase::NOTE
longest = 0
list.contents.each do |item|
- if item.kind_of?(SM::Flow::LI) && item.label.length > longest
+ if item.kind_of?(RDoc::Markup::Flow::LI) && item.label.length > longest
longest = item.label.length
end
end
@@ -140,7 +140,7 @@ class RDoc::RI::Formatter
end
list.contents.each do |item|
- if item.kind_of? SM::Flow::LI
+ if item.kind_of? RDoc::Markup::Flow::LI
prefix = prefixer.call(item)
display_flow_item(item, prefix)
else
@@ -153,20 +153,20 @@ class RDoc::RI::Formatter
def display_flow_item(item, prefix=@indent)
case item
- when SM::Flow::P, SM::Flow::LI
+ when RDoc::Markup::Flow::P, RDoc::Markup::Flow::LI
wrap(conv_html(item.body), prefix)
blankline
- when SM::Flow::LIST
+ when RDoc::Markup::Flow::LIST
display_list(item)
- when SM::Flow::VERB
+ when RDoc::Markup::Flow::VERB
display_verbatim_flow_item(item, @indent)
- when SM::Flow::H
+ when RDoc::Markup::Flow::H
display_heading(conv_html(item.text), item.level, @indent)
- when SM::Flow::RULE
+ when RDoc::Markup::Flow::RULE
draw_line
else
@@ -508,23 +508,23 @@ class RDoc::RI::HtmlFormatter < RDoc::RI::AttributeFormatter
def display_list(list)
case list.type
- when SM::ListBase::BULLET
+ when RDoc::Markup::ListBase::BULLET
list_type = "ul"
prefixer = proc { |ignored| "<li>" }
- when SM::ListBase::NUMBER,
- SM::ListBase::UPPERALPHA,
- SM::ListBase::LOWERALPHA
+ when RDoc::Markup::ListBase::NUMBER,
+ RDoc::Markup::ListBase::UPPERALPHA,
+ RDoc::Markup::ListBase::LOWERALPHA
list_type = "ol"
prefixer = proc { |ignored| "<li>" }
- when SM::ListBase::LABELED
+ when RDoc::Markup::ListBase::LABELED
list_type = "dl"
prefixer = proc do |li|
"<dt><b>" + escape(li.label) + "</b><dd>"
end
- when SM::ListBase::NOTE
+ when RDoc::Markup::ListBase::NOTE
list_type = "table"
prefixer = proc do |li|
%{<tr valign="top"><td>#{li.label.gsub(/ /, '&nbsp;')}</td><td>}
@@ -535,7 +535,7 @@ class RDoc::RI::HtmlFormatter < RDoc::RI::AttributeFormatter
print "<#{list_type}>"
list.contents.each do |item|
- if item.kind_of? SM::Flow::LI
+ if item.kind_of? RDoc::Markup::Flow::LI
prefix = prefixer.call(item)
print prefix
display_flow_item(item, prefix)
diff --git a/lib/rdoc/ri/reader.rb b/lib/rdoc/ri/reader.rb
index e56c9fb76e..986bb75954 100644
--- a/lib/rdoc/ri/reader.rb
+++ b/lib/rdoc/ri/reader.rb
@@ -1,7 +1,7 @@
require 'rdoc/ri'
require 'rdoc/ri/descriptions'
require 'rdoc/ri/writer'
-require 'rdoc/markup/simple_markup/to_flow'
+require 'rdoc/markup/to_flow'
class RDoc::RI::Reader
diff --git a/lib/rdoc/stats.rb b/lib/rdoc/stats.rb
new file mode 100644
index 0000000000..0fa2dadf61
--- /dev/null
+++ b/lib/rdoc/stats.rb
@@ -0,0 +1,25 @@
+require 'rdoc'
+
+##
+# Simple stats collector
+
+class RDoc::Stats
+
+ attr_accessor :num_files, :num_classes, :num_modules, :num_methods
+
+ def initialize
+ @num_files = @num_classes = @num_modules = @num_methods = 0
+ @start = Time.now
+ end
+
+ def print
+ puts "Files: #@num_files"
+ puts "Classes: #@num_classes"
+ puts "Modules: #@num_modules"
+ puts "Methods: #@num_methods"
+ puts "Elapsed: " + sprintf("%0.3fs", Time.now - @start)
+ end
+
+end
+
+