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:
drbrain 2008-01-14 03:34:05 +00:00
Родитель cbd4604c53
Коммит fcb0b1f503
31 изменённых файлов: 2573 добавлений и 2863 удалений

Просмотреть файл

@ -1,3 +1,8 @@
Mon Jan 14 12:33:07 2008 Eric Hodel <drbrain@segment7.net>
* lib/rdoc/markup*: Renamespace from SM::SimpleMarkup to
RDoc::Markup.
Mon Jan 14 10:45:45 2008 Martin Duerst <duerst@it.aoyama.ac.jp>
* enc/ascii.c: Exchanged order of arguments for one ENC_ALIAS

Просмотреть файл

@ -8,59 +8,14 @@
#
# $Revision$
## Transitional Hack ####
#
# RDoc was initially distributed independently, and installed
# itself into <prefix>/lib/ruby/site_ruby/<ver>/rdoc...
#
# Now that RDoc is part of the distribution, it's installed into
# <prefix>/lib/ruby/<ver>, which unfortunately appears later in the
# search path. This means that if you have previously installed RDoc,
# and then install from ruby-lang, you'll pick up the old one by
# default. This hack checks for the condition, and readjusts the
# search path if necessary.
def adjust_for_existing_rdoc(path)
$stderr.puts %{
It seems as if you have a previously-installed RDoc in
the directory #{path}.
Because this is now out-of-date, you might want to consider
removing the directories:
#{File.join(path, "rdoc")}
and
#{File.join(path, "markup")}
}
# Move all the site_ruby directories to the end
p $:
$:.replace($:.partition {|path| /site_ruby/ !~ path}.flatten)
p $:
end
$:.each do |path|
if /site_ruby/ =~ path
rdoc_path = File.join(path, 'rdoc', 'rdoc.rb')
if File.exist?(rdoc_path)
adjust_for_existing_rdoc(path)
break
end
end
end
## End of Transitional Hack ##
require 'rdoc/rdoc'
begin
r = RDoc::RDoc.new
r.document ARGV
rescue Interrupt
$stderr.puts
$stderr.puts "Interrupted"
rescue RDoc::Error => e
$stderr.puts e.message
exit 1

Просмотреть файл

@ -64,6 +64,7 @@ profiler.rb
pstore.rb
racc
rational.rb
rdoc.rb
rdoc
readbytes.rb
resolv-replace.rb

Просмотреть файл

@ -3,6 +3,13 @@
module RDoc
##
# Exception thrown by any rdoc error.
class Error < RuntimeError; end
RDocError = Error # :nodoc:
##
# RDoc version you are using
@ -14,5 +21,16 @@ module RDoc
DOT_DOC_FILENAME = ".document"
GENERAL_MODIFIERS = %w[nodoc].freeze
CLASS_MODIFIERS = GENERAL_MODIFIERS
ATTR_MODIFIERS = GENERAL_MODIFIERS
CONSTANT_MODIFIERS = GENERAL_MODIFIERS
METHOD_MODIFIERS = GENERAL_MODIFIERS +
%w[arg args yield yields notnew not-new not_new doc]
end

Просмотреть файл

@ -1,38 +1,34 @@
= RDOC - Ruby Documentation System
This package contains Rdoc and SimpleMarkup. Rdoc is an application
that produces documentation for one or more Ruby source files. We work
similarly to JavaDoc, parsing the source, and extracting the
definition for classes, modules, and methods (along with includes and
requires). We associate with these optional documentation contained
in the immediately preceding comment block, and then render the result
using a pluggable output formatter. (Currently, HTML is the only
supported format. Markup is a library that converts plain text into
various output formats. The Markup library is used to interpret the
comment blocks that Rdoc uses to document methods, classes, and so on.
This library contains two packages, rdoc itself and a text markup
library, 'markup'.
This package contains RDoc and RDoc::Markup. RDoc is an application that
produces documentation for one or more Ruby source files. We work similarly to
JavaDoc, parsing the source, and extracting the definition for classes,
modules, and methods (along with includes and requires). We associate with
these optional documentation contained in the immediately preceding comment
block, and then render the result using a pluggable output formatter.
RDoc::Markup is a library that converts plain text into various output formats.
The markup library is used to interpret the comment blocks that RDoc uses to
document methods, classes, and so on.
== Roadmap
* If you want to use Rdoc to create documentation for your Ruby source
files, read on.
* If you want to include extensions written in C, see rdoc/parsers/parse_c.rb.
* For information on the various markups available in comment
blocks, see markup/simple_markup.rb.
* If you want to drive Rdoc programatically, see RDoc::RDoc.
* If you want to use the library to format text blocks into HTML,
have a look at SM::SimpleMarkup.
* If you want to use RDoc to create documentation for your Ruby source files,
read on.
* If you want to include extensions written in C, see RDoc::C_Parser
* For information on the various markups available in comment blocks, see
RDoc::Markup.
* If you want to drive RDoc programatically, see RDoc::RDoc.
* If you want to use the library to format text blocks into HTML, have a look
at RDoc::Markup.
* If you want to try writing your own HTML output template, see
RDoc::Page.
RDoc::Generator::HTML
== Summary
Once installed, you can create documentation using the 'rdoc' command
(the command is 'rdoc.bat' under Windows)
% rdoc [options] [names...]
% rdoc [options] [names...]
Type "rdoc --help" for an up-to-date option summary.
@ -42,24 +38,170 @@ source (such as rdoc itself).
% rdoc
This command generates documentation for all the Ruby and C source
files in and below the current directory. These will be stored in a
files in and below the current directory. These will be stored in a
documentation tree starting in the subdirectory 'doc'.
You can make this slightly more useful for your readers by having the
index page contain the documentation for the primary file. In our
index page contain the documentation for the primary file. In our
case, we could type
% rdoc --main rdoc/rdoc.rb
% rdoc --main rdoc.rb
You'll find information on the various formatting tricks you can use
in comment blocks in the documentation this generates.
RDoc uses file extensions to determine how to process each file. File
names ending <tt>.rb</tt> and <tt>.rbw</tt> are assumed to be Ruby
source. Files ending <tt>.c</tt> are parsed as C files. All other
files are assumed to contain just SimpleMarkup-style markup (with or
without leading '#' comment markers). If directory names are passed to
RDoc, they are scanned recursively for C and Ruby source files only.
RDoc uses file extensions to determine how to process each file. File names
ending +.rb+ and <tt>.rbw</tt> are assumed to be Ruby source. Files
ending +.c+ are parsed as C files. All other files are assumed to
contain just Markup-style markup (with or without leading '#' comment markers).
If directory names are passed to RDoc, they are scanned recursively for C and
Ruby source files only.
= 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
@ -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
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
This software is provided "as is" and without any express or
implied warranties, including, without limitation, the implied
warranties of merchantibility and fitness for a particular
purpose.
This software is provided "as is" and without any express or implied
warranties, including, without limitation, the implied warranties of
merchantibility and fitness for a particular purpose.

Просмотреть файл

@ -458,7 +458,7 @@ module RDoc
end
##
# A TopLevel context is a source file
class TopLevel < Context
@ -470,7 +470,7 @@ module RDoc
@@all_classes = {}
@@all_modules = {}
def TopLevel::reset
def self.reset
@@all_classes = {}
@@all_modules = {}
end
@ -488,14 +488,15 @@ module RDoc
nil
end
# Adding a class or module to a TopLevel is special, as we only
# want one copy of a particular top-level class. For example,
# if both file A and file B implement class C, we only want one
# ClassModule object for C. This code arranges to share
# classes and modules between files.
##
# Adding a class or module to a TopLevel is special, as we only want one
# copy of a particular top-level class. For example, if both file A and
# file B implement class C, we only want one ClassModule object for C.
# This code arranges to share classes and modules between files.
def add_class_or_module(collection, class_type, name, superclass)
cls = collection[name]
if cls
puts "Reusing class/module #{name}" if $DEBUG_RDOC
else
@ -504,23 +505,29 @@ module RDoc
else
all = @@all_classes
end
cls = all[name]
if !cls
cls = class_type.new(name, superclass)
all[name] = cls unless @done_documenting
all[name] = cls unless @done_documenting
end
puts "Adding class/module #{name} to #@name" if $DEBUG_RDOC
puts "Adding class/module #{name} to #{@name}" if $DEBUG_RDOC
collection[name] = cls unless @done_documenting
cls.parent = self
end
cls
end
def TopLevel.all_classes_and_modules
def self.all_classes_and_modules
@@all_classes.values + @@all_modules.values
end
def TopLevel.find_class_named(name)
def self.find_class_named(name)
@@all_classes.each_value do |c|
res = c.find_class_named(name)
return res if res
@ -538,12 +545,13 @@ module RDoc
nil
end
##
# Find a named module
def find_module_named(name)
find_class_or_module_named(name) || find_enclosing_module_named(name)
end
end
# ClassModule is the base class for objects representing either a

Просмотреть файл

@ -1,7 +1,7 @@
require 'cgi'
require 'rdoc'
require 'rdoc/options'
require 'rdoc/markup/simple_markup'
require 'rdoc/markup'
require 'rdoc/template'
module RDoc::Generator

Просмотреть файл

@ -1,7 +1,7 @@
require 'fileutils'
require 'rdoc/generator'
require 'rdoc/markup/simple_markup/to_html'
require 'rdoc/markup/to_html'
module RDoc::Generator
@ -34,12 +34,11 @@ module RDoc::Generator
end
##
# Subclass of the SM::ToHtml class that supports looking
# up words in the AllReferences list. Those that are
# found (like AllReferences in this comment) will
# be hyperlinked
# Subclass of the RDoc::Markup::ToHtml class that supports looking up words
# in the AllReferences list. Those that are found (like AllReferences in
# this comment) will be hyperlinked
class HyperlinkHtml < SM::ToHtml
class HyperlinkHtml < RDoc::Markup::ToHtml
##
# We need to record the html path of our caller so we can generate
@ -161,13 +160,13 @@ module RDoc::Generator
##
# Convert a string in markup format into HTML. We keep a cached
# SimpleMarkup object lying around after the first time we're
# RDoc::Markup object lying around after the first time we're
# called per object.
def markup(str, remove_para=false)
return '' unless str
unless defined? @markup
@markup = SM::SimpleMarkup.new
@markup = RDoc::Markup.new
# class names, variable names, or instance variables
@markup.add_special(/(

Просмотреть файл

@ -1,5 +1,5 @@
require 'rdoc/generator'
require 'rdoc/markup/simple_markup/to_flow'
require 'rdoc/markup/to_flow'
require 'rdoc/ri/cache'
require 'rdoc/ri/reader'
@ -26,8 +26,8 @@ class RDoc::Generator::RI
def initialize(options) #:not-new:
@options = options
@ri_writer = RDoc::RI::Writer.new "."
@markup = SM::SimpleMarkup.new
@to_flow = SM::ToFlow.new
@markup = RDoc::Markup.new
@to_flow = RDoc::Markup::ToFlow.new
@generated = {}
end
@ -38,7 +38,7 @@ class RDoc::Generator::RI
def generate(toplevels)
RDoc::TopLevel.all_classes_and_modules.each do |cls|
process_class(cls)
process_class cls
end
end
@ -58,6 +58,7 @@ class RDoc::Generator::RI
cls_desc = RDoc::RI::ClassDescription.new
cls_desc.superclass = cls.superclass
end
cls_desc.name = cls.name
cls_desc.full_name = cls.full_name
cls_desc.comment = markup(cls.comment)

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
@ -119,7 +120,7 @@ module SM
##
# Collect groups of lines together. Each group will end up containing a flow
# of text
# of text.
class LineCollection

Просмотреть файл

@ -1,8 +1,10 @@
module SM
require 'rdoc/markup'
class RDoc::Markup
##
# We manage a set of attributes. Each attribute has a symbol name and a bit
# value
# value.
class Attribute
SPECIAL = 1
@ -39,7 +41,7 @@ module SM
##
# An AttrChanger records a change in attributes. It contains a bitmap of the
# attributes to turn on, and a bitmap of those to turn off
# attributes to turn on, and a bitmap of those to turn off.
AttrChanger = Struct.new(:turn_on, :turn_off)
@ -50,7 +52,7 @@ module SM
end
##
# An array of attributes which parallels the characters in a string
# An array of attributes which parallels the characters in a string.
class AttrSpan
def initialize(length)
@ -84,12 +86,12 @@ module SM
end
def to_s
"Special: type=#{type}, name=#{SM::Attribute.as_string type}, text=#{text.dump}"
"Special: type=#{type}, name=#{RDoc::Markup::Attribute.as_string type}, text=#{text.dump}"
end
def inspect
"#<SM::Special:0x%x @type=%p, name=%p @text=%p>" % [
object_id, @type, SM::Attribute.as_string(type), text.dump]
"#<RDoc::Markup::Special:0x%x @type=%p, name=%p @text=%p>" % [
object_id, @type, RDoc::Markup::Attribute.as_string(type), text.dump]
end
end

Просмотреть файл

@ -1,4 +1,4 @@
module SM
class RDoc::Markup
##
# We store the lines we're working on as objects of class Line. These
@ -14,7 +14,7 @@ module SM
RULE = :RULE
PARAGRAPH = :PARAGRAPH
VERBATIM = :VERBATIM
# line type
attr_accessor :type
@ -36,7 +36,6 @@ module SM
# true if this line has been deleted from the list of lines
attr_accessor :deleted
def initialize(text)
@text = text.dup
@ -69,7 +68,6 @@ module SM
##
# Strip off the leading margin
#
def strip_leading(size)
if @text.size > size
@ -85,7 +83,7 @@ module SM
end
##
# A container for all the lines
# A container for all the lines.
class Lines

Просмотреть файл

@ -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(/---?/, '&#8212;'). #gsub(/--/, '&#8211;').
# convert ... to elipsis (and make sure .... becomes .<elipsis>)
gsub(/\.\.\.\./, '.&#8230;').gsub(/\.\.\./, '&#8230;').
# convert single closing quote
gsub(%r{([^ \t\r\n\[\{\(])\'}) { "#$1&#8217;" }.
gsub(%r{\'(?=\W|s\b)}) { "&#8217;" }.
# convert single opening quote
gsub(/'/, '&#8216;').
# convert double closing quote
gsub(%r{([^ \t\r\n\[\{\(])\'(?=\W)}) { "#$1&#8221;" }.
# convert double opening quote
gsub(/'/, '&#8220;').
# convert copyright
gsub(/\(c\)/, '&#169;').
# convert and registered trademark
gsub(/\(r\)/, '&#174;')
end
def convert_special(special)
handled = false
Attribute.each_name_of(special.type) do |name|
method_name = "handle_special_#{name}"
if self.respond_to? method_name
special.text = send(method_name, special)
handled = true
end
end
raise "Unhandled special: #{special}" unless handled
special.text
end
def convert_heading(level, flow)
res =
annotate("<h#{level}>") +
convert_flow(flow) +
annotate("</h#{level}>\n")
end
def html_list_name(list_type, is_open_tag)
tags = LIST_TYPE_TO_HTML[list_type] || raise("Invalid list type: #{list_type.inspect}")
annotate(tags[ is_open_tag ? 0 : 1])
end
def list_item_start(am, fragment)
case fragment.type
when ListBase::BULLET, ListBase::NUMBER
annotate("<li>")
when ListBase::UPPERALPHA
annotate("<li type=\"A\">")
when ListBase::LOWERALPHA
annotate("<li type=\"a\">")
when ListBase::LABELED
annotate("<dt>") +
convert_flow(am.flow(fragment.param)) +
annotate("</dt>") +
annotate("<dd>")
when ListBase::NOTE
annotate("<tr>") +
annotate("<td valign=\"top\">") +
convert_flow(am.flow(fragment.param)) +
annotate("</td>") +
annotate("<td>")
else
raise "Invalid list type"
end
end
def list_end_for(fragment_type)
case fragment_type
when ListBase::BULLET, ListBase::NUMBER, ListBase::UPPERALPHA,
ListBase::LOWERALPHA
"</li>"
when ListBase::LABELED
"</dd>"
when ListBase::NOTE
"</td></tr>"
else
raise "Invalid list type"
end
end
end
end

Просмотреть файл

@ -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/simple_markup/inline'
require 'rdoc/markup/fragments'
require 'rdoc/markup/inline'
require 'cgi'
module SM
class RDoc::Markup
module Flow
P = Struct.new(:body)
@ -24,12 +24,12 @@ module SM
class ToFlow
LIST_TYPE_TO_HTML = {
SM::ListBase::BULLET => [ "<ul>", "</ul>" ],
SM::ListBase::NUMBER => [ "<ol>", "</ol>" ],
SM::ListBase::UPPERALPHA => [ "<ol>", "</ol>" ],
SM::ListBase::LOWERALPHA => [ "<ol>", "</ol>" ],
SM::ListBase::LABELED => [ "<dl>", "</dl>" ],
SM::ListBase::NOTE => [ "<table>", "</table>" ],
RDoc::Markup::ListBase::BULLET => [ "<ul>", "</ul>" ],
RDoc::Markup::ListBase::NUMBER => [ "<ol>", "</ol>" ],
RDoc::Markup::ListBase::UPPERALPHA => [ "<ol>", "</ol>" ],
RDoc::Markup::ListBase::LOWERALPHA => [ "<ol>", "</ol>" ],
RDoc::Markup::ListBase::LABELED => [ "<dl>", "</dl>" ],
RDoc::Markup::ListBase::NOTE => [ "<table>", "</table>" ],
}
InlineTag = Struct.new(:bit, :on, :off)
@ -43,9 +43,9 @@ module SM
def init_tags
@attr_tags = [
InlineTag.new(SM::Attribute.bitmap_for(:BOLD), "<b>", "</b>"),
InlineTag.new(SM::Attribute.bitmap_for(:TT), "<tt>", "</tt>"),
InlineTag.new(SM::Attribute.bitmap_for(:EM), "<em>", "</em>"),
InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:BOLD), "<b>", "</b>"),
InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:TT), "<tt>", "</tt>"),
InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:EM), "<em>", "</em>"),
]
end
@ -54,7 +54,7 @@ module SM
# end tags for flexibility
def add_tag(name, start, stop)
@attr_tags << InlineTag.new(SM::Attribute.bitmap_for(name), start, stop)
@attr_tags << InlineTag.new(RDoc::Markup::Attribute.bitmap_for(name), start, stop)
end
##

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(/---?/, '&#8212;'). #gsub(/--/, '&#8211;').
# convert ... to elipsis (and make sure .... becomes .<elipsis>)
gsub(/\.\.\.\./, '.&#8230;').gsub(/\.\.\./, '&#8230;').
# convert single closing quote
gsub(%r{([^ \t\r\n\[\{\(])\'}) { "#$1&#8217;" }.
gsub(%r{\'(?=\W|s\b)}) { "&#8217;" }.
# convert single opening quote
gsub(/'/, '&#8216;').
# convert double closing quote
gsub(%r{([^ \t\r\n\[\{\(])\'(?=\W)}) { "#$1&#8221;" }.
# convert double opening quote
gsub(/'/, '&#8220;').
# convert copyright
gsub(/\(c\)/, '&#169;').
# convert and registered trademark
gsub(/\(r\)/, '&#174;')
end
def convert_special(special)
handled = false
RDoc::Markup::Attribute.each_name_of(special.type) do |name|
method_name = "handle_special_#{name}"
if self.respond_to? method_name
special.text = send(method_name, special)
handled = true
end
end
raise "Unhandled special: #{special}" unless handled
special.text
end
def convert_heading(level, flow)
res =
annotate("<h#{level}>") +
convert_flow(flow) +
annotate("</h#{level}>\n")
end
def html_list_name(list_type, is_open_tag)
tags = LIST_TYPE_TO_HTML[list_type] || raise("Invalid list type: #{list_type.inspect}")
annotate(tags[ is_open_tag ? 0 : 1])
end
def list_item_start(am, fragment)
case fragment.type
when RDoc::Markup::ListBase::BULLET, RDoc::Markup::ListBase::NUMBER then
annotate("<li>")
when RDoc::Markup::ListBase::UPPERALPHA then
annotate("<li type=\"A\">")
when RDoc::Markup::ListBase::LOWERALPHA then
annotate("<li type=\"a\">")
when RDoc::Markup::ListBase::LABELED then
annotate("<dt>") +
convert_flow(am.flow(fragment.param)) +
annotate("</dt>") +
annotate("<dd>")
when RDoc::Markup::ListBase::NOTE then
annotate("<tr>") +
annotate("<td valign=\"top\">") +
convert_flow(am.flow(fragment.param)) +
annotate("</td>") +
annotate("<td>")
else
raise "Invalid list type"
end
end
def list_end_for(fragment_type)
case fragment_type
when RDoc::Markup::ListBase::BULLET, RDoc::Markup::ListBase::NUMBER,
RDoc::Markup::ListBase::UPPERALPHA,
RDoc::Markup::ListBase::LOWERALPHA then
"</li>"
when RDoc::Markup::ListBase::LABELED then
"</dd>"
when RDoc::Markup::ListBase::NOTE then
"</td></tr>"
else
raise "Invalid list type"
end
end
end

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

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,41 +1,40 @@
# Parse a non-source file. We basically take the whole thing
# as one big comment. If the first character in the file
# is '#', we strip leading pound signs.
require 'rdoc'
require 'rdoc/code_objects'
require 'rdoc/markup/preprocess'
##
# Parse a non-source file. We basically take the whole thing as one big
# comment. If the first character in the file is '#', we strip leading pound
# signs.
require "rdoc/code_objects"
require "rdoc/markup/simple_markup/preprocess"
class RDoc::SimpleParser
module RDoc
# See rdoc/parsers/parse_c.rb
##
# Prepare to parse a plain file
class SimpleParser
# prepare to parse a plain file
def initialize(top_level, file_name, body, options, stats)
preprocess = SM::PreProcess.new(file_name, options.rdoc_include)
preprocess.handle(body) do |directive, param|
$stderr.puts "Unrecognized directive '#{directive}' in #{file_name}"
end
@body = body
@options = options
@top_level = top_level
end
# Extract the file contents and attach them to the toplevel as a
# comment
def scan
# @body.gsub(/^(\s\n)+/, '')
@top_level.comment = remove_private_comments(@body)
@top_level
def initialize(top_level, file_name, body, options, stats)
preprocess = RDoc::Markup::PreProcess.new(file_name, options.rdoc_include)
preprocess.handle(body) do |directive, param|
warn "Unrecognized directive '#{directive}' in #{file_name}"
end
def remove_private_comments(comment)
comment.gsub(/^--.*?^\+\+/m, '').sub(/^--.*/m, '')
end
@body = body
@options = options
@top_level = top_level
end
##
# Extract the file contents and attach them to the toplevel as a comment
def scan
@top_level.comment = remove_private_comments(@body)
@top_level
end
def remove_private_comments(comment)
comment.gsub(/^--[^-].*?^\+\+/m, '').sub(/^--.*/m, '')
end
end

Просмотреть файл

@ -5,6 +5,7 @@ require 'rdoc/parsers/parse_c.rb'
require 'rdoc/parsers/parse_f95.rb'
require 'rdoc/parsers/parse_simple.rb'
require 'rdoc/stats'
require 'rdoc/options'
require 'rdoc/diagram'
@ -15,31 +16,6 @@ require 'time'
module RDoc
##
# Simple stats collector
class Stats
attr_accessor :num_files, :num_classes, :num_modules, :num_methods
def initialize
@num_files = @num_classes = @num_modules = @num_methods = 0
@start = Time.now
end
def print
puts "Files: #@num_files"
puts "Classes: #@num_classes"
puts "Modules: #@num_modules"
puts "Methods: #@num_methods"
puts "Elapsed: " + sprintf("%0.3fs", Time.now - @start)
end
end
##
# Exception thrown by any rdoc error.
class Error < RuntimeError; end
RDocError = Error # :nodoc:
##
# Encapsulate the production of rdoc documentation. Basically
# you can use this as you would invoke rdoc from the command
@ -192,22 +168,27 @@ module RDoc
# for .document files.
def list_files_in_directory(dir, options)
normalized_file_list(options, Dir.glob(File.join(dir, "*")), false, options.exclude)
files = Dir.glob File.join(dir, "*")
normalized_file_list options, files, false, options.exclude
end
##
# Parse each file on the command line, recursively entering directories.
def parse_files(options)
file_info = []
files = options.files
files = ["."] if files.empty?
file_list = normalized_file_list(options, files, true)
return [] if file_list.empty?
file_info = []
width = file_list.map { |name| name.length }.max + 1
file_list.each do |fn|
$stderr.printf("\n%35s: ", File.basename(fn)) unless options.quiet
$stderr.printf("\n%*s: ", width, fn) unless options.quiet
content = File.open(fn, "r:ascii-8bit") {|f| f.read}
if /coding:\s*(\S+)/ =~ content[/\A(?:.*\n){0,2}/]
@ -252,6 +233,7 @@ module RDoc
unless options.all_one_file
@last_created = setup_output_dir(options.op_dir, options.force_update)
end
start_time = Time.now
file_info = parse_files(options)

Просмотреть файл

@ -1,5 +1,5 @@
require 'yaml'
require 'rdoc/markup/simple_markup/fragments'
require 'rdoc/markup/fragments'
require 'rdoc/ri'
#--
@ -91,7 +91,7 @@ class RDoc::RI::ModuleDescription < RDoc::RI::Description
@comment = old.comment
else
unless old.comment.nil? or old.comment.empty? then
@comment << SM::Flow::RULE.new
@comment << RDoc::Markup::Flow::RULE.new
@comment.concat old.comment
end
end

Просмотреть файл

@ -26,7 +26,7 @@ end
##
# A paging display module. Uses the RDoc::RI::Formatter class to do the actual
# presentation
# presentation.
class RDoc::RI::DefaultDisplay

Просмотреть файл

@ -6,8 +6,8 @@ require 'rdoc/ri/paths'
require 'rdoc/ri/formatter'
require 'rdoc/ri/display'
require 'fileutils'
require 'rdoc/markup/simple_markup'
require 'rdoc/markup/simple_markup/to_flow'
require 'rdoc/markup'
require 'rdoc/markup/to_flow'
class RDoc::RI::Driver
@ -222,7 +222,7 @@ Options may also be set in the 'RI' environment variable.
return @class_cache if @class_cache
newest = map_dirs('created.rid', :all) do |f|
File.mtime f if test ?f, f
File.mtime f if test ?f, f
end.max
up_to_date = (File.exist?(class_cache_file_path) and
@ -341,7 +341,7 @@ Options may also be set in the 'RI' environment variable.
end
def read_yaml(path)
YAML.load File.read(path).gsub(/ \!ruby\/(object|struct):(RDoc|RI).*/, '')
YAML.load File.read(path).gsub(/ \!ruby\/(object|struct):(RDoc::RI|RI).*/, '')
end
def run

Просмотреть файл

@ -99,17 +99,17 @@ class RDoc::RI::Formatter
def display_list(list)
case list.type
when SM::ListBase::BULLET
when RDoc::Markup::ListBase::BULLET
prefixer = proc { |ignored| @indent + "* " }
when SM::ListBase::NUMBER,
SM::ListBase::UPPERALPHA,
SM::ListBase::LOWERALPHA
when RDoc::Markup::ListBase::NUMBER,
RDoc::Markup::ListBase::UPPERALPHA,
RDoc::Markup::ListBase::LOWERALPHA
start = case list.type
when SM::ListBase::NUMBER then 1
when SM::ListBase::UPPERALPHA then 'A'
when SM::ListBase::LOWERALPHA then 'a'
when RDoc::Markup::ListBase::NUMBER then 1
when RDoc::Markup::ListBase::UPPERALPHA then 'A'
when RDoc::Markup::ListBase::LOWERALPHA then 'a'
end
prefixer = proc do |ignored|
res = @indent + "#{start}.".ljust(4)
@ -117,15 +117,15 @@ class RDoc::RI::Formatter
res
end
when SM::ListBase::LABELED
when RDoc::Markup::ListBase::LABELED
prefixer = proc do |li|
li.label
end
when SM::ListBase::NOTE
when RDoc::Markup::ListBase::NOTE
longest = 0
list.contents.each do |item|
if item.kind_of?(SM::Flow::LI) && item.label.length > longest
if item.kind_of?(RDoc::Markup::Flow::LI) && item.label.length > longest
longest = item.label.length
end
end
@ -140,7 +140,7 @@ class RDoc::RI::Formatter
end
list.contents.each do |item|
if item.kind_of? SM::Flow::LI
if item.kind_of? RDoc::Markup::Flow::LI
prefix = prefixer.call(item)
display_flow_item(item, prefix)
else
@ -153,20 +153,20 @@ class RDoc::RI::Formatter
def display_flow_item(item, prefix=@indent)
case item
when SM::Flow::P, SM::Flow::LI
when RDoc::Markup::Flow::P, RDoc::Markup::Flow::LI
wrap(conv_html(item.body), prefix)
blankline
when SM::Flow::LIST
when RDoc::Markup::Flow::LIST
display_list(item)
when SM::Flow::VERB
when RDoc::Markup::Flow::VERB
display_verbatim_flow_item(item, @indent)
when SM::Flow::H
when RDoc::Markup::Flow::H
display_heading(conv_html(item.text), item.level, @indent)
when SM::Flow::RULE
when RDoc::Markup::Flow::RULE
draw_line
else
@ -508,23 +508,23 @@ class RDoc::RI::HtmlFormatter < RDoc::RI::AttributeFormatter
def display_list(list)
case list.type
when SM::ListBase::BULLET
when RDoc::Markup::ListBase::BULLET
list_type = "ul"
prefixer = proc { |ignored| "<li>" }
when SM::ListBase::NUMBER,
SM::ListBase::UPPERALPHA,
SM::ListBase::LOWERALPHA
when RDoc::Markup::ListBase::NUMBER,
RDoc::Markup::ListBase::UPPERALPHA,
RDoc::Markup::ListBase::LOWERALPHA
list_type = "ol"
prefixer = proc { |ignored| "<li>" }
when SM::ListBase::LABELED
when RDoc::Markup::ListBase::LABELED
list_type = "dl"
prefixer = proc do |li|
"<dt><b>" + escape(li.label) + "</b><dd>"
end
when SM::ListBase::NOTE
when RDoc::Markup::ListBase::NOTE
list_type = "table"
prefixer = proc do |li|
%{<tr valign="top"><td>#{li.label.gsub(/ /, '&nbsp;')}</td><td>}
@ -535,7 +535,7 @@ class RDoc::RI::HtmlFormatter < RDoc::RI::AttributeFormatter
print "<#{list_type}>"
list.contents.each do |item|
if item.kind_of? SM::Flow::LI
if item.kind_of? RDoc::Markup::Flow::LI
prefix = prefixer.call(item)
print prefix
display_flow_item(item, prefix)

Просмотреть файл

@ -1,7 +1,7 @@
require 'rdoc/ri'
require 'rdoc/ri/descriptions'
require 'rdoc/ri/writer'
require 'rdoc/markup/simple_markup/to_flow'
require 'rdoc/markup/to_flow'
class RDoc::RI::Reader

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