mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Renamespace lib/rdoc/markup from SM::SimpleMarkup to RDoc::Markup.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@15033 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
cbd4604c53
commit
fcb0b1f503
31 changed files with 2573 additions and 2863 deletions
|
@ -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>
|
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
|
* enc/ascii.c: Exchanged order of arguments for one ENC_ALIAS
|
||||||
|
|
51
bin/rdoc
51
bin/rdoc
|
@ -8,59 +8,14 @@
|
||||||
#
|
#
|
||||||
# $Revision$
|
# $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'
|
require 'rdoc/rdoc'
|
||||||
|
|
||||||
begin
|
begin
|
||||||
r = RDoc::RDoc.new
|
r = RDoc::RDoc.new
|
||||||
r.document ARGV
|
r.document ARGV
|
||||||
|
rescue Interrupt
|
||||||
|
$stderr.puts
|
||||||
|
$stderr.puts "Interrupted"
|
||||||
rescue RDoc::Error => e
|
rescue RDoc::Error => e
|
||||||
$stderr.puts e.message
|
$stderr.puts e.message
|
||||||
exit 1
|
exit 1
|
||||||
|
|
|
@ -64,6 +64,7 @@ profiler.rb
|
||||||
pstore.rb
|
pstore.rb
|
||||||
racc
|
racc
|
||||||
rational.rb
|
rational.rb
|
||||||
|
rdoc.rb
|
||||||
rdoc
|
rdoc
|
||||||
readbytes.rb
|
readbytes.rb
|
||||||
resolv-replace.rb
|
resolv-replace.rb
|
||||||
|
|
18
lib/rdoc.rb
18
lib/rdoc.rb
|
@ -3,6 +3,13 @@
|
||||||
|
|
||||||
module RDoc
|
module RDoc
|
||||||
|
|
||||||
|
##
|
||||||
|
# Exception thrown by any rdoc error.
|
||||||
|
|
||||||
|
class Error < RuntimeError; end
|
||||||
|
|
||||||
|
RDocError = Error # :nodoc:
|
||||||
|
|
||||||
##
|
##
|
||||||
# RDoc version you are using
|
# RDoc version you are using
|
||||||
|
|
||||||
|
@ -14,5 +21,16 @@ module RDoc
|
||||||
|
|
||||||
DOT_DOC_FILENAME = ".document"
|
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
|
end
|
||||||
|
|
||||||
|
|
613
lib/rdoc/README
613
lib/rdoc/README
|
@ -1,38 +1,34 @@
|
||||||
= RDOC - Ruby Documentation System
|
= RDOC - Ruby Documentation System
|
||||||
|
|
||||||
This package contains Rdoc and SimpleMarkup. Rdoc is an application
|
This package contains RDoc and RDoc::Markup. RDoc is an application that
|
||||||
that produces documentation for one or more Ruby source files. We work
|
produces documentation for one or more Ruby source files. We work similarly to
|
||||||
similarly to JavaDoc, parsing the source, and extracting the
|
JavaDoc, parsing the source, and extracting the definition for classes,
|
||||||
definition for classes, modules, and methods (along with includes and
|
modules, and methods (along with includes and requires). We associate with
|
||||||
requires). We associate with these optional documentation contained
|
these optional documentation contained in the immediately preceding comment
|
||||||
in the immediately preceding comment block, and then render the result
|
block, and then render the result using a pluggable output formatter.
|
||||||
using a pluggable output formatter. (Currently, HTML is the only
|
RDoc::Markup is a library that converts plain text into various output formats.
|
||||||
supported format. Markup is a library that converts plain text into
|
The markup library is used to interpret the comment blocks that RDoc uses to
|
||||||
various output formats. The Markup library is used to interpret the
|
document methods, classes, and so on.
|
||||||
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'.
|
|
||||||
|
|
||||||
== Roadmap
|
== Roadmap
|
||||||
|
|
||||||
* If you want to use Rdoc to create documentation for your Ruby source
|
* If you want to use RDoc to create documentation for your Ruby source files,
|
||||||
files, read on.
|
read on.
|
||||||
* If you want to include extensions written in C, see rdoc/parsers/parse_c.rb.
|
* If you want to include extensions written in C, see RDoc::C_Parser
|
||||||
* For information on the various markups available in comment
|
* For information on the various markups available in comment blocks, see
|
||||||
blocks, see markup/simple_markup.rb.
|
RDoc::Markup.
|
||||||
* If you want to drive Rdoc programatically, see RDoc::RDoc.
|
* If you want to drive RDoc programatically, see RDoc::RDoc.
|
||||||
* If you want to use the library to format text blocks into HTML,
|
* If you want to use the library to format text blocks into HTML, have a look
|
||||||
have a look at SM::SimpleMarkup.
|
at RDoc::Markup.
|
||||||
* If you want to try writing your own HTML output template, see
|
* If you want to try writing your own HTML output template, see
|
||||||
RDoc::Page.
|
RDoc::Generator::HTML
|
||||||
|
|
||||||
== Summary
|
== Summary
|
||||||
|
|
||||||
Once installed, you can create documentation using the 'rdoc' command
|
Once installed, you can create documentation using the 'rdoc' command
|
||||||
(the command is 'rdoc.bat' under Windows)
|
(the command is 'rdoc.bat' under Windows)
|
||||||
|
|
||||||
% rdoc [options] [names...]
|
% rdoc [options] [names...]
|
||||||
|
|
||||||
Type "rdoc --help" for an up-to-date option summary.
|
Type "rdoc --help" for an up-to-date option summary.
|
||||||
|
|
||||||
|
@ -42,24 +38,170 @@ source (such as rdoc itself).
|
||||||
% rdoc
|
% rdoc
|
||||||
|
|
||||||
This command generates documentation for all the Ruby and C source
|
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'.
|
documentation tree starting in the subdirectory 'doc'.
|
||||||
|
|
||||||
You can make this slightly more useful for your readers by having the
|
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
|
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
|
You'll find information on the various formatting tricks you can use
|
||||||
in comment blocks in the documentation this generates.
|
in comment blocks in the documentation this generates.
|
||||||
|
|
||||||
RDoc uses file extensions to determine how to process each file. File
|
RDoc uses file extensions to determine how to process each file. File names
|
||||||
names ending <tt>.rb</tt> and <tt>.rbw</tt> are assumed to be Ruby
|
ending +.rb+ and <tt>.rbw</tt> are assumed to be Ruby source. Files
|
||||||
source. Files ending <tt>.c</tt> are parsed as C files. All other
|
ending +.c+ are parsed as C files. All other files are assumed to
|
||||||
files are assumed to contain just SimpleMarkup-style markup (with or
|
contain just Markup-style markup (with or without leading '#' comment markers).
|
||||||
without leading '#' comment markers). If directory names are passed to
|
If directory names are passed to RDoc, they are scanned recursively for C and
|
||||||
RDoc, they are scanned recursively for C and Ruby source files only.
|
Ruby source files only.
|
||||||
|
|
||||||
|
= Markup
|
||||||
|
|
||||||
|
For information on how to make lists, hyperlinks, & etc. with RDoc, see
|
||||||
|
RDoc::Markup.
|
||||||
|
|
||||||
|
Comment blocks can be written fairly naturally, either using '#' on successive
|
||||||
|
lines of the comment, or by including the comment in an =begin/=end block. If
|
||||||
|
you use the latter form, the =begin line must be flagged with an RDoc tag:
|
||||||
|
|
||||||
|
=begin rdoc
|
||||||
|
Documentation to be processed by RDoc.
|
||||||
|
|
||||||
|
...
|
||||||
|
=end
|
||||||
|
|
||||||
|
RDoc stops processing comments if it finds a comment line containing '+#--+'.
|
||||||
|
This can be used to separate external from internal comments, or to stop a
|
||||||
|
comment being associated with a method, class, or module. Commenting can be
|
||||||
|
turned back on with a line that starts '+#+++'.
|
||||||
|
|
||||||
|
##
|
||||||
|
# Extract the age and calculate the date-of-birth.
|
||||||
|
#--
|
||||||
|
# FIXME: fails if the birthday falls on February 29th
|
||||||
|
#++
|
||||||
|
# The DOB is returned as a Time object.
|
||||||
|
|
||||||
|
def get_dob(person)
|
||||||
|
# ...
|
||||||
|
end
|
||||||
|
|
||||||
|
Names of classes, source files, and any method names containing an underscore
|
||||||
|
or preceded by a hash character are automatically hyperlinked from comment text
|
||||||
|
to their description.
|
||||||
|
|
||||||
|
Method parameter lists are extracted and displayed with the method description.
|
||||||
|
If a method calls +yield+, then the parameters passed to yield will also be
|
||||||
|
displayed:
|
||||||
|
|
||||||
|
def fred
|
||||||
|
...
|
||||||
|
yield line, address
|
||||||
|
|
||||||
|
This will get documented as:
|
||||||
|
|
||||||
|
fred() { |line, address| ... }
|
||||||
|
|
||||||
|
You can override this using a comment containing ':yields: ...' immediately
|
||||||
|
after the method definition
|
||||||
|
|
||||||
|
def fred # :yields: index, position
|
||||||
|
# ...
|
||||||
|
|
||||||
|
yield line, address
|
||||||
|
|
||||||
|
which will get documented as
|
||||||
|
|
||||||
|
fred() { |index, position| ... }
|
||||||
|
|
||||||
|
+:yields:+ is an example of a documentation directive. These appear immediately
|
||||||
|
after the start of the document element they are modifying.
|
||||||
|
|
||||||
|
== Directives
|
||||||
|
|
||||||
|
[+:nodoc:+ / +:nodoc:+ all]
|
||||||
|
Don't include this element in the documentation. For classes
|
||||||
|
and modules, the methods, aliases, constants, and attributes
|
||||||
|
directly within the affected class or module will also be
|
||||||
|
omitted. By default, though, modules and classes within that
|
||||||
|
class of module _will_ be documented. This is turned off by
|
||||||
|
adding the +all+ modifier.
|
||||||
|
|
||||||
|
module MyModule # :nodoc:
|
||||||
|
class Input
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module OtherModule # :nodoc: all
|
||||||
|
class Output
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
In the above code, only class +MyModule::Input+ will be documented.
|
||||||
|
|
||||||
|
[+:doc:+]
|
||||||
|
Force a method or attribute to be documented even if it wouldn't otherwise
|
||||||
|
be. Useful if, for example, you want to include documentation of a
|
||||||
|
particular private method.
|
||||||
|
|
||||||
|
[+:notnew:+]
|
||||||
|
Only applicable to the +initialize+ instance method. Normally RDoc assumes
|
||||||
|
that the documentation and parameters for #initialize are actually for the
|
||||||
|
::new method, and so fakes out a ::new for the class. The :notnew: modifier
|
||||||
|
stops this. Remember that #initialize is protected, so you won't see the
|
||||||
|
documentation unless you use the -a command line option.
|
||||||
|
|
||||||
|
Comment blocks can contain other directives:
|
||||||
|
|
||||||
|
[+:section: title+]
|
||||||
|
Starts a new section in the output. The title following +:section:+ is used
|
||||||
|
as the section heading, and the remainder of the comment containing the
|
||||||
|
section is used as introductory text. Subsequent methods, aliases,
|
||||||
|
attributes, and classes will be documented in this section. A :section:
|
||||||
|
comment block may have one or more lines before the :section: directive.
|
||||||
|
These will be removed, and any identical lines at the end of the block are
|
||||||
|
also removed. This allows you to add visual cues such as:
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# :section: My Section
|
||||||
|
# This is the section that I wrote.
|
||||||
|
# See it glisten in the noon-day sun.
|
||||||
|
# ----------------------------------------
|
||||||
|
|
||||||
|
[+:call-seq:+]
|
||||||
|
Lines up to the next blank line in the comment are treated as the method's
|
||||||
|
calling sequence, overriding the default parsing of method parameters and
|
||||||
|
yield arguments.
|
||||||
|
|
||||||
|
[+:include:+ _filename_]
|
||||||
|
Include the contents of the named file at this point. The file will be
|
||||||
|
searched for in the directories listed by the +--include+ option, or in the
|
||||||
|
current directory by default. The contents of the file will be shifted to
|
||||||
|
have the same indentation as the ':' at the start of the :include: directive.
|
||||||
|
|
||||||
|
[+:title:+ _text_]
|
||||||
|
Sets the title for the document. Equivalent to the --title command line
|
||||||
|
parameter. (The command line parameter overrides any :title: directive in
|
||||||
|
the source).
|
||||||
|
|
||||||
|
[+:enddoc:+]
|
||||||
|
Document nothing further at the current level.
|
||||||
|
|
||||||
|
[+:main:+ _name_]
|
||||||
|
Equivalent to the --main command line parameter.
|
||||||
|
|
||||||
|
[+:stopdoc:+ / +:startdoc:+]
|
||||||
|
Stop and start adding new documentation elements to the current container.
|
||||||
|
For example, if a class has a number of constants that you don't want to
|
||||||
|
document, put a +:stopdoc:+ before the first, and a +:startdoc:+ after the
|
||||||
|
last. If you don't specifiy a +:startdoc:+ by the end of the container,
|
||||||
|
disables documentation for the entire class or module.
|
||||||
|
|
||||||
|
= Other stuff
|
||||||
|
|
||||||
|
Author:: Dave Thomas <dave@pragmaticprogrammer.com>
|
||||||
|
|
||||||
== Credits
|
== Credits
|
||||||
|
|
||||||
|
@ -82,408 +224,9 @@ RDoc is Copyright (c) 2001-2003 Dave Thomas, The Pragmatic Programmers. It
|
||||||
is free software, and may be redistributed under the terms specified
|
is free software, and may be redistributed under the terms specified
|
||||||
in the README file of the Ruby distribution.
|
in the README file of the Ruby distribution.
|
||||||
|
|
||||||
= Usage
|
|
||||||
|
|
||||||
RDoc is invoked from the command line using:
|
|
||||||
|
|
||||||
% rdoc <options> [name...]
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Options are:
|
|
||||||
|
|
||||||
[<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
|
|
||||||
|
|
||||||
db_opt :name, :age
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
A typical small Ruby program commented using RDoc might be as follows. You
|
|
||||||
can see the formatted result in EXAMPLE.rb and Anagram.
|
|
||||||
|
|
||||||
:include: EXAMPLE.rb
|
|
||||||
|
|
||||||
= Markup
|
|
||||||
|
|
||||||
Comment blocks can be written fairly naturally, either using '#' on
|
|
||||||
successive lines of the comment, or by including the comment in
|
|
||||||
an =begin/=end block. If you use the latter form, the =begin line
|
|
||||||
must be flagged with an RDoc tag:
|
|
||||||
|
|
||||||
=begin rdoc
|
|
||||||
Documentation to
|
|
||||||
be processed by RDoc.
|
|
||||||
=end
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
= Other stuff
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
== Warranty
|
== Warranty
|
||||||
|
|
||||||
This software is provided "as is" and without any express or
|
This software is provided "as is" and without any express or implied
|
||||||
implied warranties, including, without limitation, the implied
|
warranties, including, without limitation, the implied warranties of
|
||||||
warranties of merchantibility and fitness for a particular
|
merchantibility and fitness for a particular purpose.
|
||||||
purpose.
|
|
||||||
|
|
|
@ -458,7 +458,7 @@ module RDoc
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
# A TopLevel context is a source file
|
# A TopLevel context is a source file
|
||||||
|
|
||||||
class TopLevel < Context
|
class TopLevel < Context
|
||||||
|
@ -470,7 +470,7 @@ module RDoc
|
||||||
@@all_classes = {}
|
@@all_classes = {}
|
||||||
@@all_modules = {}
|
@@all_modules = {}
|
||||||
|
|
||||||
def TopLevel::reset
|
def self.reset
|
||||||
@@all_classes = {}
|
@@all_classes = {}
|
||||||
@@all_modules = {}
|
@@all_modules = {}
|
||||||
end
|
end
|
||||||
|
@ -488,14 +488,15 @@ module RDoc
|
||||||
nil
|
nil
|
||||||
end
|
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,
|
# Adding a class or module to a TopLevel is special, as we only want one
|
||||||
# if both file A and file B implement class C, we only want one
|
# copy of a particular top-level class. For example, if both file A and
|
||||||
# ClassModule object for C. This code arranges to share
|
# file B implement class C, we only want one ClassModule object for C.
|
||||||
# classes and modules between files.
|
# This code arranges to share classes and modules between files.
|
||||||
|
|
||||||
def add_class_or_module(collection, class_type, name, superclass)
|
def add_class_or_module(collection, class_type, name, superclass)
|
||||||
cls = collection[name]
|
cls = collection[name]
|
||||||
|
|
||||||
if cls
|
if cls
|
||||||
puts "Reusing class/module #{name}" if $DEBUG_RDOC
|
puts "Reusing class/module #{name}" if $DEBUG_RDOC
|
||||||
else
|
else
|
||||||
|
@ -504,23 +505,29 @@ module RDoc
|
||||||
else
|
else
|
||||||
all = @@all_classes
|
all = @@all_classes
|
||||||
end
|
end
|
||||||
|
|
||||||
cls = all[name]
|
cls = all[name]
|
||||||
|
|
||||||
if !cls
|
if !cls
|
||||||
cls = class_type.new(name, superclass)
|
cls = class_type.new(name, superclass)
|
||||||
all[name] = cls unless @done_documenting
|
all[name] = cls unless @done_documenting
|
||||||
end
|
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
|
collection[name] = cls unless @done_documenting
|
||||||
|
|
||||||
cls.parent = self
|
cls.parent = self
|
||||||
end
|
end
|
||||||
|
|
||||||
cls
|
cls
|
||||||
end
|
end
|
||||||
|
|
||||||
def TopLevel.all_classes_and_modules
|
def self.all_classes_and_modules
|
||||||
@@all_classes.values + @@all_modules.values
|
@@all_classes.values + @@all_modules.values
|
||||||
end
|
end
|
||||||
|
|
||||||
def TopLevel.find_class_named(name)
|
def self.find_class_named(name)
|
||||||
@@all_classes.each_value do |c|
|
@@all_classes.each_value do |c|
|
||||||
res = c.find_class_named(name)
|
res = c.find_class_named(name)
|
||||||
return res if res
|
return res if res
|
||||||
|
@ -538,12 +545,13 @@ module RDoc
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
# Find a named module
|
# Find a named module
|
||||||
|
|
||||||
def find_module_named(name)
|
def find_module_named(name)
|
||||||
find_class_or_module_named(name) || find_enclosing_module_named(name)
|
find_class_or_module_named(name) || find_enclosing_module_named(name)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# ClassModule is the base class for objects representing either a
|
# ClassModule is the base class for objects representing either a
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
require 'cgi'
|
require 'cgi'
|
||||||
require 'rdoc'
|
require 'rdoc'
|
||||||
require 'rdoc/options'
|
require 'rdoc/options'
|
||||||
require 'rdoc/markup/simple_markup'
|
require 'rdoc/markup'
|
||||||
require 'rdoc/template'
|
require 'rdoc/template'
|
||||||
|
|
||||||
module RDoc::Generator
|
module RDoc::Generator
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
require 'fileutils'
|
require 'fileutils'
|
||||||
|
|
||||||
require 'rdoc/generator'
|
require 'rdoc/generator'
|
||||||
require 'rdoc/markup/simple_markup/to_html'
|
require 'rdoc/markup/to_html'
|
||||||
|
|
||||||
module RDoc::Generator
|
module RDoc::Generator
|
||||||
|
|
||||||
|
@ -34,12 +34,11 @@ module RDoc::Generator
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
# Subclass of the SM::ToHtml class that supports looking
|
# Subclass of the RDoc::Markup::ToHtml class that supports looking up words
|
||||||
# up words in the AllReferences list. Those that are
|
# in the AllReferences list. Those that are found (like AllReferences in
|
||||||
# found (like AllReferences in this comment) will
|
# this comment) will be hyperlinked
|
||||||
# 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
|
# 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
|
# 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.
|
# called per object.
|
||||||
|
|
||||||
def markup(str, remove_para=false)
|
def markup(str, remove_para=false)
|
||||||
return '' unless str
|
return '' unless str
|
||||||
unless defined? @markup
|
unless defined? @markup
|
||||||
@markup = SM::SimpleMarkup.new
|
@markup = RDoc::Markup.new
|
||||||
|
|
||||||
# class names, variable names, or instance variables
|
# class names, variable names, or instance variables
|
||||||
@markup.add_special(/(
|
@markup.add_special(/(
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
require 'rdoc/generator'
|
require 'rdoc/generator'
|
||||||
require 'rdoc/markup/simple_markup/to_flow'
|
require 'rdoc/markup/to_flow'
|
||||||
|
|
||||||
require 'rdoc/ri/cache'
|
require 'rdoc/ri/cache'
|
||||||
require 'rdoc/ri/reader'
|
require 'rdoc/ri/reader'
|
||||||
|
@ -26,8 +26,8 @@ class RDoc::Generator::RI
|
||||||
def initialize(options) #:not-new:
|
def initialize(options) #:not-new:
|
||||||
@options = options
|
@options = options
|
||||||
@ri_writer = RDoc::RI::Writer.new "."
|
@ri_writer = RDoc::RI::Writer.new "."
|
||||||
@markup = SM::SimpleMarkup.new
|
@markup = RDoc::Markup.new
|
||||||
@to_flow = SM::ToFlow.new
|
@to_flow = RDoc::Markup::ToFlow.new
|
||||||
|
|
||||||
@generated = {}
|
@generated = {}
|
||||||
end
|
end
|
||||||
|
@ -38,7 +38,7 @@ class RDoc::Generator::RI
|
||||||
|
|
||||||
def generate(toplevels)
|
def generate(toplevels)
|
||||||
RDoc::TopLevel.all_classes_and_modules.each do |cls|
|
RDoc::TopLevel.all_classes_and_modules.each do |cls|
|
||||||
process_class(cls)
|
process_class cls
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -58,6 +58,7 @@ class RDoc::Generator::RI
|
||||||
cls_desc = RDoc::RI::ClassDescription.new
|
cls_desc = RDoc::RI::ClassDescription.new
|
||||||
cls_desc.superclass = cls.superclass
|
cls_desc.superclass = cls.superclass
|
||||||
end
|
end
|
||||||
|
|
||||||
cls_desc.name = cls.name
|
cls_desc.name = cls.name
|
||||||
cls_desc.full_name = cls.full_name
|
cls_desc.full_name = cls.full_name
|
||||||
cls_desc.comment = markup(cls.comment)
|
cls_desc.comment = markup(cls.comment)
|
||||||
|
|
466
lib/rdoc/markup.rb
Normal file
466
lib/rdoc/markup.rb
Normal file
|
@ -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'
|
|
@ -1,2 +0,0 @@
|
||||||
simple_markup
|
|
||||||
simple_markup.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
|
# 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
|
# Collect groups of lines together. Each group will end up containing a flow
|
||||||
# of text
|
# of text.
|
||||||
|
|
||||||
class LineCollection
|
class LineCollection
|
||||||
|
|
|
@ -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
|
# We manage a set of attributes. Each attribute has a symbol name and a bit
|
||||||
# value
|
# value.
|
||||||
|
|
||||||
class Attribute
|
class Attribute
|
||||||
SPECIAL = 1
|
SPECIAL = 1
|
||||||
|
@ -39,7 +41,7 @@ module SM
|
||||||
|
|
||||||
##
|
##
|
||||||
# An AttrChanger records a change in attributes. It contains a bitmap of the
|
# 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)
|
AttrChanger = Struct.new(:turn_on, :turn_off)
|
||||||
|
|
||||||
|
@ -50,7 +52,7 @@ module SM
|
||||||
end
|
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
|
class AttrSpan
|
||||||
def initialize(length)
|
def initialize(length)
|
||||||
|
@ -84,12 +86,12 @@ module SM
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_s
|
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
|
end
|
||||||
|
|
||||||
def inspect
|
def inspect
|
||||||
"#<SM::Special:0x%x @type=%p, name=%p @text=%p>" % [
|
"#<RDoc::Markup::Special:0x%x @type=%p, name=%p @text=%p>" % [
|
||||||
object_id, @type, SM::Attribute.as_string(type), text.dump]
|
object_id, @type, RDoc::Markup::Attribute.as_string(type), text.dump]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
module SM
|
class RDoc::Markup
|
||||||
|
|
||||||
##
|
##
|
||||||
# We store the lines we're working on as objects of class Line. These
|
# We store the lines we're working on as objects of class Line. These
|
||||||
|
@ -14,7 +14,7 @@ module SM
|
||||||
RULE = :RULE
|
RULE = :RULE
|
||||||
PARAGRAPH = :PARAGRAPH
|
PARAGRAPH = :PARAGRAPH
|
||||||
VERBATIM = :VERBATIM
|
VERBATIM = :VERBATIM
|
||||||
|
|
||||||
# line type
|
# line type
|
||||||
attr_accessor :type
|
attr_accessor :type
|
||||||
|
|
||||||
|
@ -36,7 +36,6 @@ module SM
|
||||||
|
|
||||||
# true if this line has been deleted from the list of lines
|
# true if this line has been deleted from the list of lines
|
||||||
attr_accessor :deleted
|
attr_accessor :deleted
|
||||||
|
|
||||||
|
|
||||||
def initialize(text)
|
def initialize(text)
|
||||||
@text = text.dup
|
@text = text.dup
|
||||||
|
@ -69,7 +68,6 @@ module SM
|
||||||
|
|
||||||
##
|
##
|
||||||
# Strip off the leading margin
|
# Strip off the leading margin
|
||||||
#
|
|
||||||
|
|
||||||
def strip_leading(size)
|
def strip_leading(size)
|
||||||
if @text.size > size
|
if @text.size > size
|
||||||
|
@ -85,7 +83,7 @@ module SM
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
# A container for all the lines
|
# A container for all the lines.
|
||||||
|
|
||||||
class Lines
|
class Lines
|
||||||
|
|
71
lib/rdoc/markup/preprocess.rb
Normal file
71
lib/rdoc/markup/preprocess.rb
Normal file
|
@ -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
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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(/---?/, '—'). #gsub(/--/, '–').
|
|
||||||
|
|
||||||
# convert ... to elipsis (and make sure .... becomes .<elipsis>)
|
|
||||||
gsub(/\.\.\.\./, '.…').gsub(/\.\.\./, '…').
|
|
||||||
|
|
||||||
# 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\)/, '©').
|
|
||||||
|
|
||||||
# convert and registered trademark
|
|
||||||
gsub(/\(r\)/, '®')
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
require 'rdoc/markup/simple_markup/fragments'
|
require 'rdoc/markup/fragments'
|
||||||
require 'rdoc/markup/simple_markup/inline'
|
require 'rdoc/markup/inline'
|
||||||
require 'cgi'
|
require 'cgi'
|
||||||
|
|
||||||
module SM
|
class RDoc::Markup
|
||||||
|
|
||||||
module Flow
|
module Flow
|
||||||
P = Struct.new(:body)
|
P = Struct.new(:body)
|
||||||
|
@ -24,12 +24,12 @@ module SM
|
||||||
|
|
||||||
class ToFlow
|
class ToFlow
|
||||||
LIST_TYPE_TO_HTML = {
|
LIST_TYPE_TO_HTML = {
|
||||||
SM::ListBase::BULLET => [ "<ul>", "</ul>" ],
|
RDoc::Markup::ListBase::BULLET => [ "<ul>", "</ul>" ],
|
||||||
SM::ListBase::NUMBER => [ "<ol>", "</ol>" ],
|
RDoc::Markup::ListBase::NUMBER => [ "<ol>", "</ol>" ],
|
||||||
SM::ListBase::UPPERALPHA => [ "<ol>", "</ol>" ],
|
RDoc::Markup::ListBase::UPPERALPHA => [ "<ol>", "</ol>" ],
|
||||||
SM::ListBase::LOWERALPHA => [ "<ol>", "</ol>" ],
|
RDoc::Markup::ListBase::LOWERALPHA => [ "<ol>", "</ol>" ],
|
||||||
SM::ListBase::LABELED => [ "<dl>", "</dl>" ],
|
RDoc::Markup::ListBase::LABELED => [ "<dl>", "</dl>" ],
|
||||||
SM::ListBase::NOTE => [ "<table>", "</table>" ],
|
RDoc::Markup::ListBase::NOTE => [ "<table>", "</table>" ],
|
||||||
}
|
}
|
||||||
|
|
||||||
InlineTag = Struct.new(:bit, :on, :off)
|
InlineTag = Struct.new(:bit, :on, :off)
|
||||||
|
@ -43,9 +43,9 @@ module SM
|
||||||
|
|
||||||
def init_tags
|
def init_tags
|
||||||
@attr_tags = [
|
@attr_tags = [
|
||||||
InlineTag.new(SM::Attribute.bitmap_for(:BOLD), "<b>", "</b>"),
|
InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:BOLD), "<b>", "</b>"),
|
||||||
InlineTag.new(SM::Attribute.bitmap_for(:TT), "<tt>", "</tt>"),
|
InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:TT), "<tt>", "</tt>"),
|
||||||
InlineTag.new(SM::Attribute.bitmap_for(:EM), "<em>", "</em>"),
|
InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:EM), "<em>", "</em>"),
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ module SM
|
||||||
# end tags for flexibility
|
# end tags for flexibility
|
||||||
|
|
||||||
def add_tag(name, start, stop)
|
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
|
end
|
||||||
|
|
||||||
##
|
##
|
286
lib/rdoc/markup/to_html.rb
Normal file
286
lib/rdoc/markup/to_html.rb
Normal file
|
@ -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(/---?/, '—'). #gsub(/--/, '–').
|
||||||
|
|
||||||
|
# convert ... to elipsis (and make sure .... becomes .<elipsis>)
|
||||||
|
gsub(/\.\.\.\./, '.…').gsub(/\.\.\./, '…').
|
||||||
|
|
||||||
|
# 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\)/, '©').
|
||||||
|
|
||||||
|
# convert and registered trademark
|
||||||
|
gsub(/\(r\)/, '®')
|
||||||
|
|
||||||
|
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
|
||||||
|
|
331
lib/rdoc/markup/to_latex.rb
Normal file
331
lib/rdoc/markup/to_latex.rb
Normal file
|
@ -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
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,41 +1,40 @@
|
||||||
# Parse a non-source file. We basically take the whole thing
|
require 'rdoc'
|
||||||
# as one big comment. If the first character in the file
|
require 'rdoc/code_objects'
|
||||||
# is '#', we strip leading pound signs.
|
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.
|
||||||
|
|
||||||
require "rdoc/code_objects"
|
class RDoc::SimpleParser
|
||||||
require "rdoc/markup/simple_markup/preprocess"
|
|
||||||
|
|
||||||
module RDoc
|
##
|
||||||
# See rdoc/parsers/parse_c.rb
|
# Prepare to parse a plain file
|
||||||
|
|
||||||
class SimpleParser
|
def initialize(top_level, file_name, body, options, stats)
|
||||||
|
preprocess = RDoc::Markup::PreProcess.new(file_name, options.rdoc_include)
|
||||||
# prepare to parse a plain file
|
|
||||||
def initialize(top_level, file_name, body, options, stats)
|
preprocess.handle(body) do |directive, param|
|
||||||
|
warn "Unrecognized directive '#{directive}' in #{file_name}"
|
||||||
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
|
end
|
||||||
|
|
||||||
def remove_private_comments(comment)
|
@body = body
|
||||||
comment.gsub(/^--.*?^\+\+/m, '').sub(/^--.*/m, '')
|
@options = options
|
||||||
end
|
@top_level = top_level
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ require 'rdoc/parsers/parse_c.rb'
|
||||||
require 'rdoc/parsers/parse_f95.rb'
|
require 'rdoc/parsers/parse_f95.rb'
|
||||||
require 'rdoc/parsers/parse_simple.rb'
|
require 'rdoc/parsers/parse_simple.rb'
|
||||||
|
|
||||||
|
require 'rdoc/stats'
|
||||||
require 'rdoc/options'
|
require 'rdoc/options'
|
||||||
|
|
||||||
require 'rdoc/diagram'
|
require 'rdoc/diagram'
|
||||||
|
@ -15,31 +16,6 @@ require 'time'
|
||||||
|
|
||||||
module RDoc
|
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
|
# Encapsulate the production of rdoc documentation. Basically
|
||||||
# you can use this as you would invoke rdoc from the command
|
# you can use this as you would invoke rdoc from the command
|
||||||
|
@ -192,22 +168,27 @@ module RDoc
|
||||||
# for .document files.
|
# for .document files.
|
||||||
|
|
||||||
def list_files_in_directory(dir, options)
|
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
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
# Parse each file on the command line, recursively entering directories.
|
# Parse each file on the command line, recursively entering directories.
|
||||||
|
|
||||||
def parse_files(options)
|
def parse_files(options)
|
||||||
file_info = []
|
|
||||||
|
|
||||||
files = options.files
|
files = options.files
|
||||||
files = ["."] if files.empty?
|
files = ["."] if files.empty?
|
||||||
|
|
||||||
file_list = normalized_file_list(options, files, true)
|
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|
|
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}
|
content = File.open(fn, "r:ascii-8bit") {|f| f.read}
|
||||||
if /coding:\s*(\S+)/ =~ content[/\A(?:.*\n){0,2}/]
|
if /coding:\s*(\S+)/ =~ content[/\A(?:.*\n){0,2}/]
|
||||||
|
@ -252,6 +233,7 @@ module RDoc
|
||||||
unless options.all_one_file
|
unless options.all_one_file
|
||||||
@last_created = setup_output_dir(options.op_dir, options.force_update)
|
@last_created = setup_output_dir(options.op_dir, options.force_update)
|
||||||
end
|
end
|
||||||
|
|
||||||
start_time = Time.now
|
start_time = Time.now
|
||||||
|
|
||||||
file_info = parse_files(options)
|
file_info = parse_files(options)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
require 'yaml'
|
require 'yaml'
|
||||||
require 'rdoc/markup/simple_markup/fragments'
|
require 'rdoc/markup/fragments'
|
||||||
require 'rdoc/ri'
|
require 'rdoc/ri'
|
||||||
|
|
||||||
#--
|
#--
|
||||||
|
@ -91,7 +91,7 @@ class RDoc::RI::ModuleDescription < RDoc::RI::Description
|
||||||
@comment = old.comment
|
@comment = old.comment
|
||||||
else
|
else
|
||||||
unless old.comment.nil? or old.comment.empty? then
|
unless old.comment.nil? or old.comment.empty? then
|
||||||
@comment << SM::Flow::RULE.new
|
@comment << RDoc::Markup::Flow::RULE.new
|
||||||
@comment.concat old.comment
|
@comment.concat old.comment
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -26,7 +26,7 @@ end
|
||||||
|
|
||||||
##
|
##
|
||||||
# A paging display module. Uses the RDoc::RI::Formatter class to do the actual
|
# A paging display module. Uses the RDoc::RI::Formatter class to do the actual
|
||||||
# presentation
|
# presentation.
|
||||||
|
|
||||||
class RDoc::RI::DefaultDisplay
|
class RDoc::RI::DefaultDisplay
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,8 @@ require 'rdoc/ri/paths'
|
||||||
require 'rdoc/ri/formatter'
|
require 'rdoc/ri/formatter'
|
||||||
require 'rdoc/ri/display'
|
require 'rdoc/ri/display'
|
||||||
require 'fileutils'
|
require 'fileutils'
|
||||||
require 'rdoc/markup/simple_markup'
|
require 'rdoc/markup'
|
||||||
require 'rdoc/markup/simple_markup/to_flow'
|
require 'rdoc/markup/to_flow'
|
||||||
|
|
||||||
class RDoc::RI::Driver
|
class RDoc::RI::Driver
|
||||||
|
|
||||||
|
@ -222,7 +222,7 @@ Options may also be set in the 'RI' environment variable.
|
||||||
return @class_cache if @class_cache
|
return @class_cache if @class_cache
|
||||||
|
|
||||||
newest = map_dirs('created.rid', :all) do |f|
|
newest = map_dirs('created.rid', :all) do |f|
|
||||||
File.mtime f if test ?f, f
|
File.mtime f if test ?f, f
|
||||||
end.max
|
end.max
|
||||||
|
|
||||||
up_to_date = (File.exist?(class_cache_file_path) and
|
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
|
end
|
||||||
|
|
||||||
def read_yaml(path)
|
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
|
end
|
||||||
|
|
||||||
def run
|
def run
|
||||||
|
|
|
@ -99,17 +99,17 @@ class RDoc::RI::Formatter
|
||||||
def display_list(list)
|
def display_list(list)
|
||||||
case list.type
|
case list.type
|
||||||
|
|
||||||
when SM::ListBase::BULLET
|
when RDoc::Markup::ListBase::BULLET
|
||||||
prefixer = proc { |ignored| @indent + "* " }
|
prefixer = proc { |ignored| @indent + "* " }
|
||||||
|
|
||||||
when SM::ListBase::NUMBER,
|
when RDoc::Markup::ListBase::NUMBER,
|
||||||
SM::ListBase::UPPERALPHA,
|
RDoc::Markup::ListBase::UPPERALPHA,
|
||||||
SM::ListBase::LOWERALPHA
|
RDoc::Markup::ListBase::LOWERALPHA
|
||||||
|
|
||||||
start = case list.type
|
start = case list.type
|
||||||
when SM::ListBase::NUMBER then 1
|
when RDoc::Markup::ListBase::NUMBER then 1
|
||||||
when SM::ListBase::UPPERALPHA then 'A'
|
when RDoc::Markup::ListBase::UPPERALPHA then 'A'
|
||||||
when SM::ListBase::LOWERALPHA then 'a'
|
when RDoc::Markup::ListBase::LOWERALPHA then 'a'
|
||||||
end
|
end
|
||||||
prefixer = proc do |ignored|
|
prefixer = proc do |ignored|
|
||||||
res = @indent + "#{start}.".ljust(4)
|
res = @indent + "#{start}.".ljust(4)
|
||||||
|
@ -117,15 +117,15 @@ class RDoc::RI::Formatter
|
||||||
res
|
res
|
||||||
end
|
end
|
||||||
|
|
||||||
when SM::ListBase::LABELED
|
when RDoc::Markup::ListBase::LABELED
|
||||||
prefixer = proc do |li|
|
prefixer = proc do |li|
|
||||||
li.label
|
li.label
|
||||||
end
|
end
|
||||||
|
|
||||||
when SM::ListBase::NOTE
|
when RDoc::Markup::ListBase::NOTE
|
||||||
longest = 0
|
longest = 0
|
||||||
list.contents.each do |item|
|
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
|
longest = item.label.length
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -140,7 +140,7 @@ class RDoc::RI::Formatter
|
||||||
end
|
end
|
||||||
|
|
||||||
list.contents.each do |item|
|
list.contents.each do |item|
|
||||||
if item.kind_of? SM::Flow::LI
|
if item.kind_of? RDoc::Markup::Flow::LI
|
||||||
prefix = prefixer.call(item)
|
prefix = prefixer.call(item)
|
||||||
display_flow_item(item, prefix)
|
display_flow_item(item, prefix)
|
||||||
else
|
else
|
||||||
|
@ -153,20 +153,20 @@ class RDoc::RI::Formatter
|
||||||
|
|
||||||
def display_flow_item(item, prefix=@indent)
|
def display_flow_item(item, prefix=@indent)
|
||||||
case item
|
case item
|
||||||
when SM::Flow::P, SM::Flow::LI
|
when RDoc::Markup::Flow::P, RDoc::Markup::Flow::LI
|
||||||
wrap(conv_html(item.body), prefix)
|
wrap(conv_html(item.body), prefix)
|
||||||
blankline
|
blankline
|
||||||
|
|
||||||
when SM::Flow::LIST
|
when RDoc::Markup::Flow::LIST
|
||||||
display_list(item)
|
display_list(item)
|
||||||
|
|
||||||
when SM::Flow::VERB
|
when RDoc::Markup::Flow::VERB
|
||||||
display_verbatim_flow_item(item, @indent)
|
display_verbatim_flow_item(item, @indent)
|
||||||
|
|
||||||
when SM::Flow::H
|
when RDoc::Markup::Flow::H
|
||||||
display_heading(conv_html(item.text), item.level, @indent)
|
display_heading(conv_html(item.text), item.level, @indent)
|
||||||
|
|
||||||
when SM::Flow::RULE
|
when RDoc::Markup::Flow::RULE
|
||||||
draw_line
|
draw_line
|
||||||
|
|
||||||
else
|
else
|
||||||
|
@ -508,23 +508,23 @@ class RDoc::RI::HtmlFormatter < RDoc::RI::AttributeFormatter
|
||||||
|
|
||||||
def display_list(list)
|
def display_list(list)
|
||||||
case list.type
|
case list.type
|
||||||
when SM::ListBase::BULLET
|
when RDoc::Markup::ListBase::BULLET
|
||||||
list_type = "ul"
|
list_type = "ul"
|
||||||
prefixer = proc { |ignored| "<li>" }
|
prefixer = proc { |ignored| "<li>" }
|
||||||
|
|
||||||
when SM::ListBase::NUMBER,
|
when RDoc::Markup::ListBase::NUMBER,
|
||||||
SM::ListBase::UPPERALPHA,
|
RDoc::Markup::ListBase::UPPERALPHA,
|
||||||
SM::ListBase::LOWERALPHA
|
RDoc::Markup::ListBase::LOWERALPHA
|
||||||
list_type = "ol"
|
list_type = "ol"
|
||||||
prefixer = proc { |ignored| "<li>" }
|
prefixer = proc { |ignored| "<li>" }
|
||||||
|
|
||||||
when SM::ListBase::LABELED
|
when RDoc::Markup::ListBase::LABELED
|
||||||
list_type = "dl"
|
list_type = "dl"
|
||||||
prefixer = proc do |li|
|
prefixer = proc do |li|
|
||||||
"<dt><b>" + escape(li.label) + "</b><dd>"
|
"<dt><b>" + escape(li.label) + "</b><dd>"
|
||||||
end
|
end
|
||||||
|
|
||||||
when SM::ListBase::NOTE
|
when RDoc::Markup::ListBase::NOTE
|
||||||
list_type = "table"
|
list_type = "table"
|
||||||
prefixer = proc do |li|
|
prefixer = proc do |li|
|
||||||
%{<tr valign="top"><td>#{li.label.gsub(/ /, ' ')}</td><td>}
|
%{<tr valign="top"><td>#{li.label.gsub(/ /, ' ')}</td><td>}
|
||||||
|
@ -535,7 +535,7 @@ class RDoc::RI::HtmlFormatter < RDoc::RI::AttributeFormatter
|
||||||
|
|
||||||
print "<#{list_type}>"
|
print "<#{list_type}>"
|
||||||
list.contents.each do |item|
|
list.contents.each do |item|
|
||||||
if item.kind_of? SM::Flow::LI
|
if item.kind_of? RDoc::Markup::Flow::LI
|
||||||
prefix = prefixer.call(item)
|
prefix = prefixer.call(item)
|
||||||
print prefix
|
print prefix
|
||||||
display_flow_item(item, prefix)
|
display_flow_item(item, prefix)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
require 'rdoc/ri'
|
require 'rdoc/ri'
|
||||||
require 'rdoc/ri/descriptions'
|
require 'rdoc/ri/descriptions'
|
||||||
require 'rdoc/ri/writer'
|
require 'rdoc/ri/writer'
|
||||||
require 'rdoc/markup/simple_markup/to_flow'
|
require 'rdoc/markup/to_flow'
|
||||||
|
|
||||||
class RDoc::RI::Reader
|
class RDoc::RI::Reader
|
||||||
|
|
||||||
|
|
25
lib/rdoc/stats.rb
Normal file
25
lib/rdoc/stats.rb
Normal file
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue