git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@30249 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
drbrain 2010-12-20 03:22:49 +00:00
Родитель d7effd506f
Коммит 2ef9c50c6e
106 изменённых файлов: 8878 добавлений и 4179 удалений

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

@ -1,3 +1,7 @@
Mon Dec 20 12:15:32 2010 Eric Hodel <drbrain@segment7.net>
* lib/rdoc: Import RDoc 3.0.
Mon Dec 20 01:55:03 2010 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
* io.c (Init_IO): Added O_DIRECT. This feature was propsed by Run Paint Run Run.

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

@ -18,14 +18,16 @@ $DEBUG_RDOC = nil
# == Roadmap
#
# * If you want to use RDoc to create documentation for your Ruby source files,
# read on.
# read the summary below, and refer to <tt>rdoc --help</tt> for command line
# usage, and RDoc::Markup for a detailed description of RDoc's markup.
# * If you want to generate documentation for extensions written in C, see
# RDoc::Parser::C
# * If you want to drive RDoc programmatically, see RDoc::RDoc.
# * If you want to use the library to format text blocks into HTML, have a look
# at RDoc::Markup.
# * If you want to try writing your own HTML output template, see
# RDoc::Generator::HTML
# * If you want to use the library to format text blocks into HTML, look at
# RDoc::Markup.
# * If you want to make an RDoc plugin such as a generator or directive
# handler see RDoc::RDoc.
# * If you want to try writing your own output generator see RDoc::Generator.
#
# == Summary
#
@ -50,7 +52,7 @@ $DEBUG_RDOC = nil
# index page contain the documentation for the primary file. In our
# case, we could type
#
# % rdoc --main rdoc.rb
# % rdoc --main README.txt
#
# You'll find information on the various formatting tricks you can use
# in comment blocks in the documentation this generates.
@ -62,281 +64,9 @@ $DEBUG_RDOC = nil
# markers). If directory names are passed to RDoc, they are scanned
# recursively for C and Ruby source files only.
#
# == \Options
#
# rdoc can be passed a variety of command-line options. In addition,
# options can be specified via the +RDOCOPT+ environment variable, which
# functions similarly to the +RUBYOPT+ environment variable.
#
# % export RDOCOPT="-S"
#
# will make rdoc default to inline method source code. Command-line options
# always will override those in +RDOCOPT+.
#
# Run:
#
# rdoc --help
#
# for full details on rdoc's options.
#
# == Documenting Source Code
#
# Comment blocks can be written fairly naturally, either using <tt>#</tt> on
# successive lines of the comment, or by including the comment in
# a =begin/=end block. If you use the latter form, the =begin line must be
# flagged with an RDoc tag:
#
# =begin rdoc
# Documentation to be processed by RDoc.
#
# ...
# =end
#
# RDoc stops processing comments if it finds a comment line containing
# a <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 with a
# <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)
# # ...
# end
#
# Names of classes, 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.
#
# RDoc automatically cross-references words with underscores or camel-case.
# To suppress cross-references, prefix the word with a \\ character. To
# include special characters like "\\n", you'll need to use two \\
# characters like "\\\\\\n".
#
# == \Markup
#
# * The markup engine looks for a document's natural left margin. This is
# 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:
#
# [<tt>\*word*</tt>] displays word in a *bold* font
# [<tt>\_word_</tt>] displays word in an _emphasized_ font
# [<tt>\+word+</tt>] displays word in a +code+ font
#
# General markup affects text between a start delimiter and and end
# delimiter. Not surprisingly, these delimiters look like HTML markup.
#
# [<tt>\<b>text...</b></tt>] displays word in a *bold* font
# [<tt>\<em>text...</em></tt>] displays word in an _emphasized_ font
# [<tt>\<i>text...</i></tt>] displays word in an <i>italicized</i> font
# [<tt>\<tt>text...\</tt></tt>] displays word in a +code+ font
#
# Unlike conventional Wiki markup, general markup can cross line
# boundaries. You can turn off the interpretation of markup by
# preceding the first character with a backslash. This only works for
# simple markup, not HTML-style markup.
#
# * 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 +url+ is
# used as the target. If +label+ contains multiple words,
# put it in braces: <em>{multi word label}[</em>url<em>]</em>.
#
# Example hyperlinks:
#
# link:RDoc.html
# http://rdoc.rubyforge.org
# mailto:user@example.com
# {RDoc Documentation}[http://rdoc.rubyforge.org]
# {RDoc Markup}[link:RDoc/Markup.html]
#
# == Directives
#
# [+:nodoc:+ / +:nodoc:+ all]
# This directive prevents documentation for the element from
# being generated. For classes and modules, the methods, aliases,
# constants, and attributes directly within the affected class or
# module also will be omitted. By default, though, modules and
# classes within that class of module _will_ be documented. This is
# turned off by adding the +all+ modifier.
#
# module MyModule # :nodoc:
# class Input
# end
# end
#
# module OtherModule # :nodoc: all
# class Output
# end
# end
#
# In the above code, only class <tt>MyModule::Input</tt> will be documented.
# The +:nodoc:+ directive is global across all files for the class or module
# to which it applies, so use +:stopdoc:+/+:startdoc:+ to suppress
# documentation only for a particular set of methods, etc.
#
# [+:doc:+]
# Forces a method or attribute to be documented even if it wouldn't be
# otherwise. 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 private,
# so you won't see the documentation unless you use the +-a+ command line
# option.
#
# Comment blocks can contain other directives:
#
# [<tt>:section: title</tt>]
# 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 <tt>--title</tt>
# 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 <tt>--main</tt> command line parameter.
#
# [+:stopdoc:+ / +:startdoc:+]
# Stop and start adding new documentation elements to the current container.
# For example, if a class has a number of constants that you don't want to
# document, put a +:stopdoc:+ before the first, and a +:startdoc:+ after the
# last. If you don't specify a +:startdoc:+ by the end of the container,
# disables documentation for the entire class or module.
#
# Further directives can be found in RDoc::Parser::Ruby and RDoc::Parser::C
#
# == Other stuff
#
# RDoc is currently being maintained by Eric Hodel <drbrain@segment7.net>
# RDoc is currently being maintained by Eric Hodel <drbrain@segment7.net>.
#
# Dave Thomas <dave@pragmaticprogrammer.com> is the original author of RDoc.
#
@ -345,24 +75,6 @@ $DEBUG_RDOC = nil
# * The Ruby parser in rdoc/parse.rb is based heavily on the outstanding
# work of Keiju ISHITSUKA of Nippon Rational Inc, who produced the Ruby
# parser for irb and the rtags package.
#
# * Charset patch from MoonWolf.
#
# * Rich Kilmer wrote the kilmer.rb output template.
#
# * Dan Brickley led the design of the RDF format.
#
# == License
#
# RDoc is Copyright (c) 2001-2003 Dave Thomas, The Pragmatic Programmers. It
# is free software, and may be redistributed under the terms specified
# in the README file of the Ruby distribution.
#
# == Warranty
#
# This software is provided "as is" and without any express or implied
# warranties, including, without limitation, the implied warranties of
# merchantibility and fitness for a particular purpose.
module RDoc
@ -383,7 +95,12 @@ module RDoc
##
# RDoc version you are using
VERSION = '2.5.8'
VERSION = '3.0'
##
# Method visibilities
VISIBILITIES = [:public, :protected, :private]
##
# Name of the dotfile that contains the description of files to be processed

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

@ -3,41 +3,77 @@ require 'rdoc/code_object'
##
# Represent an alias, which is an old_name/new_name pair associated with a
# particular context
#--
# TODO implement Alias as a proxy to a method/attribute, inheriting from
# MethodAttr
class RDoc::Alias < RDoc::CodeObject
##
# Allow comments to be overridden
# Aliased method's name
attr_writer :comment
attr_reader :new_name
alias name new_name
##
# Aliased name
# Aliasee method's name
attr_accessor :new_name
attr_reader :old_name
##
# Aliasee's name
# Is this an alias declared in a singleton context?
attr_accessor :old_name
attr_accessor :singleton
##
# Source file token stream
attr_accessor :text
attr_reader :text
##
# Creates a new Alias with a token stream of +text+ that aliases +old_name+
# to +new_name+ and has +comment+
# to +new_name+, has +comment+ and is a +singleton+ context.
def initialize(text, old_name, new_name, comment)
def initialize(text, old_name, new_name, comment, singleton = false)
super()
@text = text
@singleton = singleton
@old_name = old_name
@new_name = new_name
self.comment = comment
end
##
# Order by #singleton then #new_name
def <=>(other)
[@singleton ? 0 : 1, new_name] <=> [other.singleton ? 0 : 1, other.new_name]
end
##
# HTML fragment reference for this alias
def aref
type = singleton ? 'c' : 'i'
"#alias-#{type}-#{html_name}"
end
##
# Full old name including namespace
def full_old_name
@full_name || "#{parent.name}#{pretty_old_name}"
end
##
# HTML id-friendly version of +#new_name+.
def html_name
CGI.escape(@new_name.gsub('-', '-2D')).gsub('%','-').sub(/^-/, '')
end
def inspect # :nodoc:
parent_name = parent ? parent.name : '(unknown)'
"#<%s:0x%x %s.alias_method %s, %s>" % [
@ -46,8 +82,31 @@ class RDoc::Alias < RDoc::CodeObject
]
end
##
# '::' for the alias of a singleton method/attribute, '#' for instance-level.
def name_prefix
singleton ? '::' : '#'
end
##
# Old name with prefix '::' or '#'.
def pretty_old_name
"#{singleton ? '::' : '#'}#{@old_name}"
end
##
# New name with prefix '::' or '#'.
def pretty_new_name
"#{singleton ? '::' : '#'}#{@new_name}"
end
alias pretty_name pretty_new_name
def to_s # :nodoc:
"alias: #{self.old_name} -> #{self.new_name}\n#{self.comment}"
"alias: #{self.new_name} -> #{self.pretty_old_name} in: #{parent}"
end
end

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

@ -1,29 +1,12 @@
require 'rdoc/code_object'
require 'rdoc/tokenstream'
require 'rdoc/method_attr'
require 'rdoc/token_stream'
##
# AnyMethod is the base class for objects representing methods
class RDoc::AnyMethod < RDoc::CodeObject
class RDoc::AnyMethod < RDoc::MethodAttr
MARSHAL_VERSION = 1 # :nodoc:
include Comparable
##
# Method name
attr_writer :name
##
# public, protected, private
attr_accessor :visibility
##
# Parameters yielded by the called block
attr_accessor :block_params
MARSHAL_VERSION = 0 # :nodoc:
##
# Don't rename \#initialize to \::new
@ -31,76 +14,49 @@ class RDoc::AnyMethod < RDoc::CodeObject
attr_accessor :dont_rename_initialize
##
# Is this a singleton method?
# Different ways to call this method
attr_accessor :singleton
##
# Source file token stream
attr_reader :text
##
# Array of other names for this method
attr_reader :aliases
##
# The method we're aliasing
attr_accessor :is_alias_for
attr_accessor :call_seq
##
# Parameters for this method
attr_accessor :params
##
# Different ways to call this method
attr_accessor :call_seq
include RDoc::TokenStream
def initialize(text, name)
super()
##
# Creates a new AnyMethod with a token stream +text+ and +name+
@text = text
@name = name
def initialize text, name
super
@aliases = []
@block_params = nil
@call_seq = nil
@dont_rename_initialize = false
@is_alias_for = nil
@params = nil
@parent_name = nil
@singleton = nil
@token_stream = nil
@visibility = :public
end
##
# Order by #singleton then #name
# Adds +an_alias+ as an alias for this method in +context+.
def <=>(other)
[@singleton ? 0 : 1, @name] <=> [other.singleton ? 0 : 1, other.name]
end
def add_alias(an_alias, context)
method = self.class.new an_alias.text, an_alias.new_name
##
# Adds +method+ as an alias for this method
def add_alias(method)
method.record_location an_alias.file
method.singleton = self.singleton
method.params = self.params
method.visibility = self.visibility
method.comment = an_alias.comment
method.is_alias_for = self
@aliases << method
context.add_method method
method
end
##
# HTML fragment reference for this method
# Prefix for +aref+ is 'method'.
def aref
type = singleton ? 'c' : 'i'
"method-#{type}-#{CGI.escape name}"
def aref_prefix
'method'
end
##
@ -116,30 +72,6 @@ class RDoc::AnyMethod < RDoc::CodeObject
end
end
##
# HTML id-friendly method name
def html_name
@name.gsub(/[^a-z]+/, '-')
end
def inspect # :nodoc:
alias_for = @is_alias_for ? " (alias for #{@is_alias_for.name})" : nil
"#<%s:0x%x %s (%s)%s>" % [
self.class, object_id,
full_name,
visibility,
alias_for,
]
end
##
# Full method name including namespace
def full_name
@full_name ||= "#{@parent ? @parent.full_name : '(unknown)'}#{pretty_name}"
end
##
# Dumps this AnyMethod for use by ri. See also #marshal_load
@ -192,12 +124,14 @@ class RDoc::AnyMethod < RDoc::CodeObject
end
array[8].each do |new_name, comment|
add_alias RDoc::Alias.new(nil, @name, new_name, comment)
add_alias RDoc::Alias.new(nil, @name, new_name, comment, @singleton)
end
end
##
# Method name
#
# If the method has no assigned name, it extracts it from #call_seq.
def name
return @name if @name
@ -229,62 +163,5 @@ class RDoc::AnyMethod < RDoc::CodeObject
params
end
##
# Name of our parent with special handling for un-marshaled methods
def parent_name
@parent_name || super
end
##
# Path to this method
def path
"#{@parent.path}##{aref}"
end
##
# Method name with class/instance indicator
def pretty_name
"#{singleton ? '::' : '#'}#{@name}"
end
def pretty_print q # :nodoc:
alias_for = @is_alias_for ? "alias for #{@is_alias_for.name}" : nil
q.group 2, "[#{self.class.name} #{full_name} #{visibility}", "]" do
if alias_for then
q.breakable
q.text alias_for
end
if text then
q.breakable
q.text "text:"
q.breakable
q.pp @text
end
unless comment.empty? then
q.breakable
q.text "comment:"
q.breakable
q.pp @comment
end
end
end
def to_s # :nodoc:
"#{self.class.name}: #{full_name} (#{@text})\n#{@comment}"
end
##
# Type of method (class or instance)
def type
singleton ? 'class' : 'instance'
end
end

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

@ -1,104 +1,71 @@
require 'rdoc/code_object'
require 'rdoc/method_attr'
##
# An attribute created by \#attr, \#attr_reader, \#attr_writer or
# \#attr_accessor
class RDoc::Attr < RDoc::CodeObject
class RDoc::Attr < RDoc::MethodAttr
MARSHAL_VERSION = 0 # :nodoc:
MARSHAL_VERSION = 1 # :nodoc:
##
# Name of the attribute
attr_accessor :name
##
# Is the attribute readable, writable or both?
# Is the attribute readable ('R'), writable ('W') or both ('RW')?
attr_accessor :rw
##
# Source file token stream
# Creates a new Attr with body +text+, +name+, read/write status +rw+ and
# +comment+. +singleton+ marks this as a class attribute.
attr_accessor :text
def initialize(text, name, rw, comment, singleton = false)
super text, name
##
# public, protected, private
attr_accessor :visibility
def initialize(text, name, rw, comment)
super()
@text = text
@name = name
@rw = rw
@visibility = :public
@singleton = singleton
self.comment = comment
end
##
# Attributes are ordered by name
def <=>(other)
self.name <=> other.name
end
##
# Attributes are equal when their names and rw is identical
# Attributes are equal when their names, singleton and rw are identical
def == other
self.class == other.class and
self.name == other.name and
self.rw == other.rw
self.rw == other.rw and
self.singleton == other.singleton
end
##
# Returns nil, for duck typing with RDoc::AnyMethod
# Add +an_alias+ as an attribute in +context+.
def arglists
def add_alias(an_alias, context)
new_attr = self.class.new(self.text, an_alias.new_name, self.rw,
self.comment, self.singleton)
new_attr.record_location an_alias.file
new_attr.visibility = self.visibility
new_attr.is_alias_for = self
@aliases << new_attr
context.add_attribute new_attr
new_attr
end
##
# Returns nil, for duck typing with RDoc::AnyMethod
# The #aref prefix for attributes
def block_params
def aref_prefix
'attribute'
end
##
# Returns nil, for duck typing with RDoc::AnyMethod
# Returns attr_reader, attr_writer or attr_accessor as appropriate.
def call_seq
end
##
# Partially bogus as Attr has no parent. For duck typing with
# RDoc::AnyMethod.
def full_name
@full_name ||= "#{@parent ? @parent.full_name : '(unknown)'}##{name}"
end
##
# An HTML id-friendly representation of #name
def html_name
@name.gsub(/[^a-z]+/, '-')
end
def inspect # :nodoc:
attr = case rw
when 'RW' then :attr_accessor
when 'R' then :attr_reader
when 'W' then :attr_writer
else
" (#{rw})"
end
"#<%s:0x%x %s.%s :%s>" % [
self.class, object_id,
parent_name, attr, @name,
]
def definition
case @rw
when 'RW' then 'attr_accessor'
when 'R' then 'attr_reader'
when 'W' then 'attr_writer'
end
end
##
@ -111,11 +78,12 @@ class RDoc::Attr < RDoc::CodeObject
@rw,
@visibility,
parse(@comment),
singleton,
]
end
##
# Loads this AnyMethod from +array+. For a loaded AnyMethod the following
# Loads this Attr from +array+. For a loaded Attr the following
# methods will return cached values:
#
# * #full_name
@ -127,51 +95,13 @@ class RDoc::Attr < RDoc::CodeObject
@rw = array[3]
@visibility = array[4]
@comment = array[5]
@singleton = array[6] || false # MARSHAL_VERSION == 0
@parent_name = @full_name
end
##
# Name of our parent with special handling for un-marshaled methods
def parent_name
@parent_name || super
end
##
# For duck typing with RDoc::AnyMethod, returns nil
def params
nil
end
##
# URL path for this attribute
def path
"#{@parent.path}##{@name}"
end
##
# For duck typing with RDoc::AnyMethod
def singleton
false
end
def to_s # :nodoc:
"#{type} #{name}\n#{comment}"
end
##
# Returns attr_reader, attr_writer or attr_accessor as appropriate
def type
case @rw
when 'RW' then 'attr_accessor'
when 'R' then 'attr_reader'
when 'W' then 'attr_writer'
end
"#{definition} #{name} in: #{parent}"
end
end

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

@ -8,31 +8,114 @@ class RDoc::ClassModule < RDoc::Context
MARSHAL_VERSION = 0 # :nodoc:
attr_accessor :diagram
##
# Constants that are aliases for this class or module
attr_accessor :constant_aliases
attr_accessor :diagram # :nodoc:
##
# Class or module this constant is an alias for
attr_accessor :is_alias_for
##
# Return a RDoc::ClassModule of class +class_type+ that is a copy
# of module +module+. Used to promote modules to classes.
def self.from_module(class_type, mod)
klass = class_type.new(mod.name)
klass.comment = mod.comment
klass.parent = mod.parent
klass.section = mod.section
klass.viewer = mod.viewer
klass.attributes.concat mod.attributes
klass.method_list.concat mod.method_list
klass.aliases.concat mod.aliases
klass.external_aliases.concat mod.external_aliases
klass.constants.concat mod.constants
klass.includes.concat mod.includes
klass.methods_hash.update mod.methods_hash
klass.constants_hash.update mod.constants_hash
klass.current_section = mod.current_section
klass.in_files.concat mod.in_files
klass.sections.concat mod.sections
klass.unmatched_alias_lists = mod.unmatched_alias_lists
klass.current_section = mod.current_section
klass.visibility = mod.visibility
klass.classes_hash.update mod.classes_hash
klass.modules_hash.update mod.modules_hash
klass.metadata.update mod.metadata
klass.document_self = mod.received_nodoc ? nil : mod.document_self
klass.document_children = mod.document_children
klass.force_documentation = mod.force_documentation
klass.done_documenting = mod.done_documenting
# update the parent of all children
(klass.attributes +
klass.method_list +
klass.aliases +
klass.external_aliases +
klass.constants +
klass.includes +
klass.classes +
klass.modules).each do |obj|
obj.parent = klass
obj.full_name = nil
end
klass
end
##
# Creates a new ClassModule with +name+ with optional +superclass+
#
# This is a constructor for subclasses, and must never be called directly.
def initialize(name, superclass = 'Object')
@diagram = nil
@full_name = nil
@name = name
@superclass = superclass
def initialize(name, superclass = nil)
@constant_aliases = []
@diagram = nil
@is_alias_for = nil
@name = name
@superclass = superclass
super()
end
##
# Ancestors list for this ClassModule (abstract)
# Ancestors list for this ClassModule: the list of included modules
# (classes will add their superclass if any).
#
# Returns the included classes or modules, not the includes
# themselves. The returned values are either String or
# RDoc::NormalModule instances (see RDoc::Include#module).
#
# The values are returned in reverse order of their inclusion,
# which is the order suitable for searching methods/attributes
# in the ancestors. The superclass, if any, comes last.
def ancestors
raise NotImplementedError
includes.map { |i| i.module }.reverse
end
##
# Clears the comment. Used by the ruby parser.
def clear_comment
@comment = ''
end
##
# Appends +comment+ to the current comment, but separated by a rule. Works
# more like <tt>+=</tt>.
def comment=(comment)
def comment= comment
return if comment.empty?
comment = "#{@comment}\n---\n#{normalize_comment comment}" unless
@ -41,10 +124,35 @@ class RDoc::ClassModule < RDoc::Context
super
end
##
# Prepares this ClassModule for use by a generator.
#
# See RDoc::TopLevel::complete
def complete min_visibility
update_aliases
remove_nodoc_children
update_includes
remove_invisible min_visibility
end
##
# Looks for a symbol in the #ancestors. See Context#find_local_symbol.
def find_ancestor_local_symbol symbol
ancestors.each do |m|
next if m.is_a?(String)
res = m.find_local_symbol(symbol)
return res if res
end
nil
end
##
# Finds a class or module with +name+ in this namespace or its descendents
def find_class_named(name)
def find_class_named name
return self if full_name == name
return self if @name == name
@ -65,14 +173,8 @@ class RDoc::ClassModule < RDoc::Context
end
end
##
# 'module' or 'class'
def type
module? ? 'module' : 'class'
end
def marshal_dump # :nodoc:
# TODO must store the singleton attribute
attrs = attributes.sort.map do |attr|
[attr.name, attr.rw]
end
@ -106,10 +208,13 @@ class RDoc::ClassModule < RDoc::Context
end
def marshal_load array # :nodoc:
# TODO must restore the singleton attribute
initialize_methods_etc
@document_self = true
@done_documenting = false
@current_section = nil
@parent = nil
@visibility = nil
@name = array[1]
@full_name = array[2]
@ -183,6 +288,15 @@ class RDoc::ClassModule < RDoc::Context
false
end
##
# Allows overriding the initial name.
#
# Used for modules and classes that are constant aliases.
def name= new_name
@name = new_name
end
##
# Path to this class or module
@ -190,12 +304,52 @@ class RDoc::ClassModule < RDoc::Context
http_url RDoc::RDoc.current.generator.class_dir
end
##
# Name to use to generate the url:
# modules and classes that are aliases for another
# module or classe return the name of the latter.
def name_for_path
is_alias_for ? is_alias_for.full_name : full_name
end
##
# Returns the classes and modules that are not constants
# aliasing another class or module. For use by formatters
# only (caches its result).
def non_aliases
@non_aliases ||= classes_and_modules.reject { |cm| cm.is_alias_for }
end
##
# Updates the child modules or classes of class/module +parent+ by
# deleting the ones that have been removed from the documentation.
#
# +parent_hash+ is either <tt>parent.modules_hash</tt> or
# <tt>parent.classes_hash</tt> and +all_hash+ is ::all_modules_hash or
# ::all_classes_hash.
def remove_nodoc_children
prefix = self.full_name + '::'
modules_hash.each_key do |name|
full_name = prefix + name
modules_hash.delete name unless RDoc::TopLevel.all_modules_hash[full_name]
end
classes_hash.each_key do |name|
full_name = prefix + name
classes_hash.delete name unless RDoc::TopLevel.all_classes_hash[full_name]
end
end
##
# Get the superclass of this class. Attempts to retrieve the superclass
# object, returns the name if it is not known.
def superclass
RDoc::TopLevel.find_class_named_from(@superclass, parent) || @superclass
RDoc::TopLevel.find_class_named(@superclass) || @superclass
end
##
@ -203,12 +357,72 @@ class RDoc::ClassModule < RDoc::Context
def superclass=(superclass)
raise NoMethodError, "#{full_name} is a module" if module?
@superclass = superclass if @superclass.nil? or @superclass == 'Object'
@superclass = superclass
end
def to_s # :nodoc:
"#{self.class}: #{full_name} #{@comment} #{super}"
if is_alias_for then
"#{self.class.name} #{self.full_name} -> #{is_alias_for}"
else
super
end
end
##
# 'module' or 'class'
def type
module? ? 'module' : 'class'
end
##
# Updates the child modules & classes by replacing the ones that are
# aliases through a constant.
#
# The aliased module/class is replaced in the children and in
# RDoc::TopLevel::all_modules_hash or RDoc::TopLevel::all_classes_hash
# by a copy that has <tt>RDoc::ClassModule#is_alias_for</tt> set to
# the aliased module/class, and this copy is added to <tt>#aliases</tt>
# of the aliased module/class.
#
# Formatters can use the #non_aliases method to retrieve children that
# are not aliases, for instance to list the namespace content, since
# the aliased modules are included in the constants of the class/module,
# that are listed separately.
def update_aliases
constants.each do |const|
next unless cm = const.is_alias_for
cm_alias = cm.dup
cm_alias.name = const.name
cm_alias.parent = self
cm_alias.full_name = nil # force update for new parent
cm_alias.aliases.clear
cm_alias.is_alias_for = cm
if cm.module? then
RDoc::TopLevel.all_modules_hash[cm_alias.full_name] = cm_alias
modules_hash[const.name] = cm_alias
else
RDoc::TopLevel.all_classes_hash[cm_alias.full_name] = cm_alias
classes_hash[const.name] = cm_alias
end
cm.aliases << cm_alias
end
end
##
# Deletes from #includes those whose module has been removed from the
# documentation.
#--
# FIXME: includes are not reliably removed, see _possible_bug test case
def update_includes
includes.reject! do |include|
mod = include.module
!(String === mod) && RDoc::TopLevel.all_modules_hash[mod.full_name].nil?
end
end
end

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

@ -12,15 +12,16 @@ require 'rdoc/text'
# * RDoc::Context
# * RDoc::TopLevel
# * RDoc::ClassModule
# * RDoc::AnonClass
# * RDoc::AnonClass (never used so far)
# * RDoc::NormalClass
# * RDoc::NormalModule
# * RDoc::SingleClass
# * RDoc::AnyMethod
# * RDoc::GhostMethod
# * RDoc::MetaMethod
# * RDoc::MethodAttr
# * RDoc::Attr
# * RDoc::AnyMethod
# * RDoc::GhostMethod
# * RDoc::MetaMethod
# * RDoc::Alias
# * RDoc::Attr
# * RDoc::Constant
# * RDoc::Require
# * RDoc::Include
@ -47,12 +48,17 @@ class RDoc::CodeObject
##
# Are we done documenting (ie, did we come across a :enddoc:)?
attr_accessor :done_documenting
attr_reader :done_documenting
##
# Which file this code object was defined in
attr_reader :file
##
# Force documentation of this CodeObject
attr_accessor :force_documentation
attr_reader :force_documentation
##
# Hash of arbitrary metadata for this CodeObject
@ -64,6 +70,11 @@ class RDoc::CodeObject
attr_accessor :parent
##
# Did we ever receive a +:nodoc:+ directive?
attr_reader :received_nodoc
##
# Which section are we in
@ -80,15 +91,17 @@ class RDoc::CodeObject
# Creates a new CodeObject that will document itself and its children
def initialize
@metadata = {}
@comment = ''
@metadata = {}
@comment = ''
@parent = nil
@file = nil
@full_name = nil
@document_children = true
@document_self = true
@done_documenting = false
@force_documentation = false
@parent = nil
@received_nodoc = false
end
##
@ -108,28 +121,64 @@ class RDoc::CodeObject
end
##
# Enables or disables documentation of this CodeObject's children. Calls
# remove_classes_and_modules when disabling.
# Enables or disables documentation of this CodeObject's children unless it
# has been turned off by :enddoc:
def document_children=(document_children)
@document_children = document_children
remove_classes_and_modules unless document_children
@document_children = document_children unless @done_documenting
end
##
# Enables or disables documentation of this CodeObject. Calls
# remove_methods_etc when disabling.
# Enables or disables documentation of this CodeObject unless it has been
# turned off by :enddoc:. If the argument is +nil+ it means the
# documentation is turned off by +:nodoc:+.
def document_self=(document_self)
return if @done_documenting
@document_self = document_self
remove_methods_etc unless document_self
@received_nodoc = true if document_self.nil?
end
##
# Does this class have a comment with content or is document_self false.
# Does this object have a comment with content or is #received_nodoc true?
def documented?
!(@document_self and @comment.empty?)
@received_nodoc or !@comment.empty?
end
##
# Turns documentation on/off, and turns on/off #document_self
# and #document_children.
#
# Once documentation has been turned off (by +:enddoc:+),
# the object will refuse to turn #document_self or
# #document_children on, so +:doc:+ and +:start_doc:+ directives
# will have no effect in the current file.
def done_documenting=(value)
@done_documenting = value
@document_self = !value
@document_children = @document_self
end
##
# Force the documentation of this object unless documentation
# has been turned off by :endoc:
#--
# HACK untested, was assigning to an ivar
def force_documentation=(value)
@force_documentation = value unless @done_documenting
end
##
# Sets the full_name overriding any computed full name.
#
# Set to +nil+ to clear RDoc's cached value
def full_name= full_name
@full_name = full_name
end
##
@ -147,23 +196,19 @@ class RDoc::CodeObject
end
##
# Callback called upon disabling documentation of children. See
# #document_children=
# Records the RDoc::TopLevel (file) where this code object was defined
def remove_classes_and_modules
def record_location top_level
@file = top_level
end
##
# Callback called upon disabling documentation of ourself. See
# #document_self=
def remove_methods_etc
end
##
# Enable capture of documentation
# Enable capture of documentation unless documentation has been
# turned off by :endoc:
def start_doc
return if @done_documenting
@document_self = true
@document_children = true
end

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

@ -5,6 +5,13 @@ require 'rdoc/code_object'
class RDoc::Constant < RDoc::CodeObject
##
# If this constant is an alias for a module or class,
# this is the RDoc::ClassModule it is an alias for.
# +nil+ otherwise.
attr_accessor :is_alias_for
##
# The constant's name
@ -22,6 +29,7 @@ class RDoc::Constant < RDoc::CodeObject
super()
@name = name
@value = value
@is_alias_for = nil
self.comment = comment
end
@ -34,17 +42,28 @@ class RDoc::Constant < RDoc::CodeObject
[parent_name, name] <=> [other.parent_name, other.name]
end
##
# Constants are equal when their #parent and #name is the same
def == other
self.class == other.class and
@parent == other.parent and
@name == other.name
end
##
# A constant is documented if it has a comment, or is an alias
# for a documented class or module.
def documented?
super or is_alias_for && is_alias_for.documented?
end
def inspect # :nodoc:
"#<%s:0x%x %s::%s>" % [
self.class, object_id,
parent_name, @name,
]
"#<%s:0x%x %s::%s>" % [
self.class, object_id,
parent_name, @name,
]
end
##
@ -54,5 +73,14 @@ class RDoc::Constant < RDoc::CodeObject
"#{@parent.path}##{@name}"
end
def to_s # :nodoc:
parent_name = parent ? parent.full_name : '(unknown)'
if is_alias_for
"constant #{parent_name}::#@name -> #{is_alias_for}"
else
"constant #{parent_name}::#@name"
end
end
end

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

79
lib/rdoc/encoding.rb Normal file
Просмотреть файл

@ -0,0 +1,79 @@
require 'rdoc'
##
# This class is a wrapper around File IO and Encoding that helps RDoc load
# files and convert them to the correct encoding.
module RDoc::Encoding
##
# Reads the contents of +filename+ and handles any encoding directives in
# the file.
#
# The content will be converted to the +encoding+. If the file cannot be
# converted a warning will be printed and nil will be returned.
def self.read_file filename, encoding
content = open filename, "rb" do |f| f.read end
utf8 = content.sub!(/\A\xef\xbb\xbf/, '')
RDoc::Encoding.set_encoding content
if Object.const_defined? :Encoding then
encoding ||= Encoding.default_external
orig_encoding = content.encoding
if utf8 then
content.force_encoding Encoding::UTF_8
content.encode! encoding
else
# assume the content is in our output encoding
content.force_encoding encoding
end
unless content.valid_encoding? then
# revert and try to transcode
content.force_encoding orig_encoding
content.encode! encoding
end
unless content.valid_encoding? then
warn "unable to convert #{filename} to #{encoding}, skipping"
content = nil
end
end
content
rescue ArgumentError => e
raise unless e.message =~ /unknown encoding name - (.*)/
warn "unknown encoding name \"#{$1}\" for #{filename}, skipping"
nil
rescue Encoding::UndefinedConversionError => e
warn "unable to convert #{e.message} for #{filename}, skipping"
nil
rescue Errno::EISDIR, Errno::ENOENT
nil
end
##
# Sets the encoding of +string+ based on the magic comment
def self.set_encoding string
return unless Object.const_defined? :Encoding
first_line = string[/\A(?:#!.*\n)?.*\n/]
name = case first_line
when /^<\?xml[^?]*encoding=(["'])(.*?)\1/ then $2
when /\b(?:en)?coding[=:]\s*([^\s;]+)/i then $1
else return
end
enc = Encoding.find name
string.force_encoding enc if enc
end
end

37
lib/rdoc/erbio.rb Normal file
Просмотреть файл

@ -0,0 +1,37 @@
require 'erb'
##
# A subclass of ERB that writes directly to an IO. Credit to Aaron Patterson
# and Masatoshi SEKI.
#
# To use:
#
# erbio = RDoc::ERBIO.new '<%= "hello world" %>', nil, nil
#
# open 'hello.txt', 'w' do |io|
# erbio.result binding
# end
#
# Note that binding must enclose the io you wish to output on.
class RDoc::ERBIO < ERB
##
# Defaults +eoutvar+ to 'io', otherwise is identical to ERB's initialize
def initialize str, safe_level = nil, trim_mode = nil, eoutvar = 'io'
super
end
##
# Instructs +compiler+ how to write to +io_variable+
def set_eoutvar compiler, io_variable
compiler.put_cmd = "#{io_variable}.write"
compiler.insert_cmd = "#{io_variable}.write"
compiler.pre_cmd = []
compiler.post_cmd = []
end
end

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

@ -1,7 +1,39 @@
require 'rdoc'
##
# Namespace for generators
# RDoc uses generators to turn parsed source code in the form of an
# RDoc::CodeObject tree into some form of output. RDoc comes with the HTML
# generator RDoc::Generator::Darkfish and an ri data generator
# RDoc::Generator::RI.
#
# = Registering a Generator
#
# Generators are registered by calling RDoc::RDoc.add_generator with the class
# of the generator:
#
# class My::Awesome::Generator
# RDoc::RDoc.add_generator self
# end
#
# = Adding Options to +rdoc+
#
# Before option processing in +rdoc+, RDoc::Options will call ::setup_options
# on the generator class with an RDoc::Options instance. The generator can
# use RDoc::Options#option_parser to add command-line options to the +rdoc+
# tool. See OptionParser for details on how to add options.
#
# You can extend the RDoc::Options instance with additional accesors for your
# generator.
#
# = Generator Instantiation
#
# After parsing, RDoc::RDoc will instantiate a generator by calling
# #initialize with an RDoc::Options instance.
#
# RDoc will then call #generate on the generator instance and pass in an Array
# of RDoc::TopLevel instances, each representing a parsed file. You can use
# the various class methods on RDoc::TopLevel and in the RDoc::CodeObject tree
# to create your desired output format.
module RDoc::Generator
end

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

@ -1,15 +1,12 @@
# -*- mode: ruby; ruby-indent-level: 2; tab-width: 2 -*-
# vim: noet ts=2 sts=8 sw=2
require 'pathname'
require 'fileutils'
require 'erb'
require 'rdoc/erbio'
require 'rdoc/generator/markup'
$DARKFISH_DRYRUN = false # TODO make me non-global
#
##
# Darkfish RDoc HTML Generator
#
# $Id: darkfish.rb 52 2009-01-07 02:08:11Z deveiant $
@ -52,401 +49,314 @@ $DARKFISH_DRYRUN = false # TODO make me non-global
#
class RDoc::Generator::Darkfish
RDoc::RDoc.add_generator( self )
RDoc::RDoc.add_generator self
include ERB::Util
include ERB::Util
# Subversion rev
SVNRev = %$Rev: 52 $
# Path to this file's parent directory. Used to find templates and other
# resources.
# Subversion ID
SVNId = %$Id: darkfish.rb 52 2009-01-07 02:08:11Z deveiant $
GENERATOR_DIR = File.join 'rdoc', 'generator'
# Path to this file's parent directory. Used to find templates and other
# resources.
GENERATOR_DIR = File.join 'rdoc', 'generator'
##
# Release Version
# Release Version
VERSION = '1.1.6'
VERSION = '2'
# Directory where generated classes live relative to the root
CLASS_DIR = nil
##
# Initialize a few instance variables before we start
# Directory where generated files live relative to the root
FILE_DIR = nil
def initialize options
@options = options
@template_dir = Pathname.new options.template_dir
@template_cache = {}
#################################################################
### C L A S S M E T H O D S
#################################################################
@files = nil
@classes = nil
### Standard generator factory method
def self::for( options )
new( options )
end
@basedir = Pathname.pwd.expand_path
end
##
# The output directory
#################################################################
### I N S T A N C E M E T H O D S
#################################################################
attr_reader :outputdir
### Initialize a few instance variables before we start
def initialize( options )
@options = options
##
# Output progress information if debugging is enabled
template = @options.template || 'darkfish'
def debug_msg *msg
return unless $DEBUG_RDOC
$stderr.puts(*msg)
end
template_dir = $LOAD_PATH.map do |path|
File.join File.expand_path(path), GENERATOR_DIR, 'template', template
end.find do |dir|
File.directory? dir
end
##
# Directory where generated class HTML files live relative to the output
# dir.
raise RDoc::Error, "could not find template #{template.inspect}" unless
template_dir
def class_dir
nil
end
@template_dir = Pathname.new File.expand_path(template_dir)
##
# Directory where generated class HTML files live relative to the output
# dir.
@files = nil
@classes = nil
def file_dir
nil
end
@basedir = Pathname.pwd.expand_path
end
##
# Create the directories the generated docs will live in if they don't
# already exist.
######
public
######
def gen_sub_directories
@outputdir.mkpath
end
# The output directory
attr_reader :outputdir
##
# Copy over the stylesheet into the appropriate place in the output
# directory.
def write_style_sheet
debug_msg "Copying static files"
options = { :verbose => $DEBUG_RDOC, :noop => @options.dry_run }
### Output progress information if debugging is enabled
def debug_msg( *msg )
return unless $DEBUG_RDOC
$stderr.puts( *msg )
end
FileUtils.cp @template_dir + 'rdoc.css', '.', options
def class_dir
CLASS_DIR
end
Dir[(@template_dir + "{js,images}/**/*").to_s].each do |path|
next if File.directory? path
next if File.basename(path) =~ /^\./
def file_dir
FILE_DIR
end
dst = Pathname.new(path).relative_path_from @template_dir
# I suck at glob
dst_dir = dst.dirname
FileUtils.mkdir_p dst_dir, options unless File.exist? dst_dir
FileUtils.cp @template_dir + path, dst, options
end
end
##
# Build the initial indices and output objects based on an array of TopLevel
# objects containing the extracted information.
def generate top_levels
@outputdir = Pathname.new(@options.op_dir).expand_path(@basedir)
@files = top_levels.sort
@classes = RDoc::TopLevel.all_classes_and_modules.sort
@methods = @classes.map { |m| m.method_list }.flatten.sort
@modsort = get_sorted_module_list(@classes)
# Now actually write the output
write_style_sheet
generate_index
generate_class_files
generate_file_files
rescue StandardError => err
debug_msg "%s: %s\n %s" % [
err.class.name, err.message, err.backtrace.join("\n ")
]
raise
end
protected
##
# Return a list of the documented modules sorted by salience first, then
# by name.
def get_sorted_module_list(classes)
nscounts = classes.inject({}) do |counthash, klass|
top_level = klass.full_name.gsub(/::.*/, '')
counthash[top_level] ||= 0
counthash[top_level] += 1
counthash
end
# Sort based on how often the top level namespace occurs, and then on the
# name of the module -- this works for projects that put their stuff into
# a namespace, of course, but doesn't hurt if they don't.
classes.sort_by do |klass|
top_level = klass.full_name.gsub( /::.*/, '' )
[nscounts[top_level] * -1, klass.full_name]
end.select do |klass|
klass.document_self
end
end
##
# Generate an index page which lists all the classes which are documented.
def generate_index
template_file = @template_dir + 'index.rhtml'
return unless template_file.exist?
debug_msg "Rendering the index page..."
out_file = @basedir + @options.op_dir + 'index.html'
render_template template_file, out_file do |io| binding end
end
##
# Generate a documentation file for each class
def generate_class_files
template_file = @template_dir + 'classpage.rhtml'
return unless template_file.exist?
debug_msg "Generating class documentation in #@outputdir"
@classes.each do |klass|
debug_msg " working on %s (%s)" % [klass.full_name, klass.path]
out_file = @outputdir + klass.path
# suppress 1.9.3 warning
rel_prefix = rel_prefix = @outputdir.relative_path_from(out_file.dirname)
svninfo = svninfo = self.get_svninfo(klass)
debug_msg " rendering #{out_file}"
render_template template_file, out_file do |io| binding end
end
end
##
# Generate a documentation file for each file
def generate_file_files
template_file = @template_dir + 'filepage.rhtml'
return unless template_file.exist?
debug_msg "Generating file documentation in #@outputdir"
@files.each do |file|
out_file = @outputdir + file.path
debug_msg " working on %s (%s)" % [ file.full_name, out_file ]
# suppress 1.9.3 warning
rel_prefix = rel_prefix = @outputdir.relative_path_from(out_file.dirname)
debug_msg " rendering #{out_file}"
render_template template_file, out_file do |io| binding end
end
end
##
# Return a string describing the amount of time in the given number of
# seconds in terms a human can understand easily.
def time_delta_string seconds
return 'less than a minute' if seconds < 60
return "#{seconds / 60} minute#{seconds / 60 == 1 ? '' : 's'}" if
seconds < 3000 # 50 minutes
return 'about one hour' if seconds < 5400 # 90 minutes
return "#{seconds / 3600} hours" if seconds < 64800 # 18 hours
return 'one day' if seconds < 86400 # 1 day
return 'about one day' if seconds < 172800 # 2 days
return "#{seconds / 86400} days" if seconds < 604800 # 1 week
return 'about one week' if seconds < 1209600 # 2 week
return "#{seconds / 604800} weeks" if seconds < 7257600 # 3 months
return "#{seconds / 2419200} months" if seconds < 31536000 # 1 year
return "#{seconds / 31536000} years"
end
# %q$Id: darkfish.rb 52 2009-01-07 02:08:11Z deveiant $"
SVNID_PATTERN = /
\$Id:\s
(\S+)\s # filename
(\d+)\s # rev
(\d{4}-\d{2}-\d{2})\s # Date (YYYY-MM-DD)
(\d{2}:\d{2}:\d{2}Z)\s # Time (HH:MM:SSZ)
(\w+)\s # committer
\$$
/x
##
# Try to extract Subversion information out of the first constant whose
# value looks like a subversion Id tag. If no matching constant is found,
# and empty hash is returned.
def get_svninfo klass
constants = klass.constants or return {}
constants.find { |c| c.value =~ SVNID_PATTERN } or return {}
filename, rev, date, time, committer = $~.captures
commitdate = Time.parse "#{date} #{time}"
return {
:filename => filename,
:rev => Integer(rev),
:commitdate => commitdate,
:commitdelta => time_delta_string(Time.now - commitdate),
:committer => committer,
}
end
##
# Load and render the erb template in the given +template_file+ and write
# it out to +out_file+.
#
# Both +template_file+ and +out_file+ should be Pathname-like objects.
#
# An io will be yielded which must be captured by binding in the caller.
def render_template template_file, out_file # :yield: io
template = template_for template_file
unless @options.dry_run then
debug_msg "Outputting to %s" % [out_file.expand_path]
out_file.dirname.mkpath
out_file.open 'w', 0644 do |io|
io.set_encoding @options.encoding if Object.const_defined? :Encoding
context = yield io
template_result template, context, template_file
end
else
context = yield nil
output = template_result template, context, template_file
debug_msg " would have written %d characters to %s" % [
output.length, out_file.expand_path
]
end
end
##
# Creates the result for +template+ with +context+. If an error is raised a
# Pathname +template_file+ will indicate the file where the error occurred.
def template_result template, context, template_file
template.filename = template_file.to_s
template.result context
rescue NoMethodError => e
raise RDoc::Error, "Error while evaluating %s: %s" % [
template_file.expand_path,
e.message,
], e.backtrace
end
##
# Retrieves a cache template for +file+, if present, or fills the cache.
def template_for file
template = @template_cache[file]
return template if template
klass = @options.dry_run ? ERB : RDoc::ERBIO
template = klass.new file.read, nil, '<>'
@template_cache[file] = template
template
end
### Create the directories the generated docs will live in if
### they don't already exist.
def gen_sub_directories
@outputdir.mkpath
end
### Copy over the stylesheet into the appropriate place in the output
### directory.
def write_style_sheet
debug_msg "Copying static files"
options = { :verbose => $DEBUG_RDOC, :noop => $DARKFISH_DRYRUN }
FileUtils.cp @template_dir + 'rdoc.css', '.', options
Dir[(@template_dir + "{js,images}/**/*").to_s].each do |path|
next if File.directory? path
next if path =~ /#{File::SEPARATOR}\./
dst = Pathname.new(path).relative_path_from @template_dir
# I suck at glob
dst_dir = dst.dirname
FileUtils.mkdir_p dst_dir, options unless File.exist? dst_dir
FileUtils.cp @template_dir + path, dst, options
end
end
### Build the initial indices and output objects
### based on an array of TopLevel objects containing
### the extracted information.
def generate( top_levels )
@outputdir = Pathname.new( @options.op_dir ).expand_path( @basedir )
@files = top_levels.sort
@classes = RDoc::TopLevel.all_classes_and_modules.sort
@methods = @classes.map { |m| m.method_list }.flatten.sort
@modsort = get_sorted_module_list( @classes )
# Now actually write the output
write_style_sheet
generate_index
generate_class_files
generate_file_files
rescue StandardError => err
debug_msg "%s: %s\n %s" % [ err.class.name, err.message, err.backtrace.join("\n ") ]
raise
end
#########
protected
#########
### Return a list of the documented modules sorted by salience first, then
### by name.
def get_sorted_module_list( classes )
nscounts = classes.inject({}) do |counthash, klass|
top_level = klass.full_name.gsub( /::.*/, '' )
counthash[top_level] ||= 0
counthash[top_level] += 1
counthash
end
# Sort based on how often the top level namespace occurs, and then on the
# name of the module -- this works for projects that put their stuff into
# a namespace, of course, but doesn't hurt if they don't.
classes.sort_by do |klass|
top_level = klass.full_name.gsub( /::.*/, '' )
[
nscounts[ top_level ] * -1,
klass.full_name
]
end.select do |klass|
klass.document_self
end
end
### Generate an index page which lists all the classes which
### are documented.
def generate_index
template_file = @template_dir + 'index.rhtml'
return unless template_file.exist?
debug_msg "Rendering the index page..."
template_src = template_file.read
template = ERB.new( template_src, nil, '<>' )
template.filename = template_file.to_s
context = binding()
output = nil
begin
output = template.result( context )
rescue NoMethodError => err
raise RDoc::Error, "Error while evaluating %s: %s (at %p)" % [
template_file,
err.message,
eval( "_erbout[-50,50]", context )
], err.backtrace
end
outfile = @basedir + @options.op_dir + 'index.html'
unless $DARKFISH_DRYRUN
debug_msg "Outputting to %s" % [outfile.expand_path]
outfile.open( 'w', 0644 ) do |fh|
fh.print( output )
end
else
debug_msg "Would have output to %s" % [outfile.expand_path]
end
end
### Generate a documentation file for each class
def generate_class_files
template_file = @template_dir + 'classpage.rhtml'
return unless template_file.exist?
debug_msg "Generating class documentation in #@outputdir"
@classes.each do |klass|
debug_msg " working on %s (%s)" % [ klass.full_name, klass.path ]
outfile = @outputdir + klass.path
rel_prefix = @outputdir.relative_path_from( outfile.dirname )
svninfo = self.get_svninfo( klass )
debug_msg " rendering #{outfile}"
self.render_template( template_file, binding(), outfile )
end
end
### Generate a documentation file for each file
def generate_file_files
template_file = @template_dir + 'filepage.rhtml'
return unless template_file.exist?
debug_msg "Generating file documentation in #@outputdir"
@files.each do |file|
outfile = @outputdir + file.path
debug_msg " working on %s (%s)" % [ file.full_name, outfile ]
rel_prefix = @outputdir.relative_path_from( outfile.dirname )
debug_msg " rendering #{outfile}"
self.render_template( template_file, binding(), outfile )
end
end
### Return a string describing the amount of time in the given number of
### seconds in terms a human can understand easily.
def time_delta_string( seconds )
return 'less than a minute' if seconds < 1.minute
return (seconds / 1.minute).to_s + ' minute' + (seconds/60 == 1 ? '' : 's') if seconds < 50.minutes
return 'about one hour' if seconds < 90.minutes
return (seconds / 1.hour).to_s + ' hours' if seconds < 18.hours
return 'one day' if seconds < 1.day
return 'about one day' if seconds < 2.days
return (seconds / 1.day).to_s + ' days' if seconds < 1.week
return 'about one week' if seconds < 2.week
return (seconds / 1.week).to_s + ' weeks' if seconds < 3.months
return (seconds / 1.month).to_s + ' months' if seconds < 1.year
return (seconds / 1.year).to_s + ' years'
end
# %q$Id: darkfish.rb 52 2009-01-07 02:08:11Z deveiant $"
SVNID_PATTERN = /
\$Id:\s
(\S+)\s # filename
(\d+)\s # rev
(\d{4}-\d{2}-\d{2})\s # Date (YYYY-MM-DD)
(\d{2}:\d{2}:\d{2}Z)\s # Time (HH:MM:SSZ)
(\w+)\s # committer
\$$
/x
### Try to extract Subversion information out of the first constant whose value looks like
### a subversion Id tag. If no matching constant is found, and empty hash is returned.
def get_svninfo( klass )
constants = klass.constants or return {}
constants.find {|c| c.value =~ SVNID_PATTERN } or return {}
filename, rev, date, time, committer = $~.captures
commitdate = Time.parse( date + ' ' + time )
return {
:filename => filename,
:rev => Integer( rev ),
:commitdate => commitdate,
:commitdelta => time_delta_string( Time.now.to_i - commitdate.to_i ),
:committer => committer,
}
end
### Load and render the erb template in the given +template_file+ within the
### specified +context+ (a Binding object) and write it out to +outfile+.
### Both +template_file+ and +outfile+ should be Pathname-like objects.
def render_template( template_file, context, outfile )
template_src = template_file.read
template = ERB.new( template_src, nil, '<>' )
template.filename = template_file.to_s
output = begin
template.result( context )
rescue NoMethodError => err
raise RDoc::Error, "Error while evaluating %s: %s (at %p)" % [
template_file.to_s,
err.message,
eval( "_erbout[-50,50]", context )
], err.backtrace
end
unless $DARKFISH_DRYRUN
outfile.dirname.mkpath
outfile.open( 'w', 0644 ) do |ofh|
ofh.print( output )
end
else
debug_msg " would have written %d bytes to %s" %
[ output.length, outfile ]
end
end
end # Roc::Generator::Darkfish
# :stopdoc:
### Time constants
module TimeConstantMethods # :nodoc:
### Number of seconds (returns receiver unmodified)
def seconds
return self
end
alias_method :second, :seconds
### Returns number of seconds in <receiver> minutes
def minutes
return self * 60
end
alias_method :minute, :minutes
### Returns the number of seconds in <receiver> hours
def hours
return self * 60.minutes
end
alias_method :hour, :hours
### Returns the number of seconds in <receiver> days
def days
return self * 24.hours
end
alias_method :day, :days
### Return the number of seconds in <receiver> weeks
def weeks
return self * 7.days
end
alias_method :week, :weeks
### Returns the number of seconds in <receiver> fortnights
def fortnights
return self * 2.weeks
end
alias_method :fortnight, :fortnights
### Returns the number of seconds in <receiver> months (approximate)
def months
return self * 30.days
end
alias_method :month, :months
### Returns the number of seconds in <receiver> years (approximate)
def years
return (self * 365.25.days).to_i
end
alias_method :year, :years
### Returns the Time <receiver> number of seconds before the
### specified +time+. E.g., 2.hours.before( header.expiration )
def before( time )
return time - self
end
### Returns the Time <receiver> number of seconds ago. (e.g.,
### expiration > 2.hours.ago )
def ago
return self.before( ::Time.now )
end
### Returns the Time <receiver> number of seconds after the given +time+.
### E.g., 10.minutes.after( header.expiration )
def after( time )
return time + self
end
# Reads best without arguments: 10.minutes.from_now
def from_now
return self.after( ::Time.now )
end
end # module TimeConstantMethods
# Extend Numeric with time constants
class Numeric # :nodoc:
include TimeConstantMethods
end

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

@ -36,8 +36,9 @@ module RDoc::Generator::Markup
return @formatter if defined? @formatter
show_hash = RDoc::RDoc.current.options.show_hash
hyperlink_all = RDoc::RDoc.current.options.hyperlink_all
this = RDoc::Context === self ? self : @parent
@formatter = RDoc::Markup::ToHtmlCrossref.new this.path, this, show_hash
@formatter = RDoc::Markup::ToHtmlCrossref.new this.path, this, show_hash, hyperlink_all
end
##
@ -57,36 +58,65 @@ end
class RDoc::AnyMethod
##
# Maps RDoc::RubyToken classes to CSS class names
STYLE_MAP = {
RDoc::RubyToken::TkCONSTANT => 'ruby-constant',
RDoc::RubyToken::TkKW => 'ruby-keyword',
RDoc::RubyToken::TkIVAR => 'ruby-ivar',
RDoc::RubyToken::TkOp => 'ruby-operator',
RDoc::RubyToken::TkId => 'ruby-identifier',
RDoc::RubyToken::TkNode => 'ruby-node',
RDoc::RubyToken::TkCOMMENT => 'ruby-comment',
RDoc::RubyToken::TkREGEXP => 'ruby-regexp',
RDoc::RubyToken::TkSTRING => 'ruby-string',
RDoc::RubyToken::TkVal => 'ruby-value',
}
include RDoc::Generator::Markup
@add_line_numbers = false
class << self
##
# Allows controlling whether <tt>#markup_code</tt> adds line numbers to
# the source code.
attr_accessor :add_line_numbers
end
##
# Prepend +src+ with line numbers. Relies on the first line of a source
# code listing having:
#
# # File xxxxx, line dddd
# # File xxxxx, line dddd
#
# If it has, line numbers are added an ', line dddd' is removed.
def add_line_numbers(src)
if src =~ /\A.*, line (\d+)/ then
first = $1.to_i - 1
last = first + src.count("\n")
size = last.to_s.length
return unless src.sub!(/\A(.*)(, line (\d+))/, '\1')
first = $3.to_i - 1
last = first + src.count("\n")
size = last.to_s.length
line = first
src.gsub!(/^/) do
res = if line == first then
" " * (size + 2)
else
"%2$*1$d: " % [size, line]
end
line = first
src.gsub!(/^/) do
res = if line == first then
" " * (size + 1)
else
"<span class=\"line-num\">%2$*1$d</span> " % [size, line]
end
line += 1
res
end
line += 1
res
end
end
##
# Turns the method's token stream into HTML
# Turns the method's token stream into HTML.
#
# Prepends line numbers if +add_line_numbers+ is true.
def markup_code
return '' unless @token_stream
@ -95,32 +125,32 @@ class RDoc::AnyMethod
@token_stream.each do |t|
next unless t
# style = STYLE_MAP[t.class]
style = case t
when RDoc::RubyToken::TkCONSTANT then "ruby-constant"
when RDoc::RubyToken::TkKW then "ruby-keyword kw"
when RDoc::RubyToken::TkIVAR then "ruby-ivar"
when RDoc::RubyToken::TkOp then "ruby-operator"
when RDoc::RubyToken::TkId then "ruby-identifier"
when RDoc::RubyToken::TkNode then "ruby-node"
when RDoc::RubyToken::TkCOMMENT then "ruby-comment cmt"
when RDoc::RubyToken::TkREGEXP then "ruby-regexp re"
when RDoc::RubyToken::TkSTRING then "ruby-value str"
when RDoc::RubyToken::TkVal then "ruby-value"
else
nil
end
style = STYLE_MAP[t.class]
text = CGI.escapeHTML t.text
if style
if style then
src << "<span class=\"#{style}\">#{text}</span>"
else
src << text
end
end
add_line_numbers src
# dedent the source
indent = src.length
lines = src.lines.to_a
lines.shift if src =~ /\A.*#\ *File/i # remove '# File' comment
lines.each do |line|
if line =~ /^ *(?=\S)/
n = $&.length
indent = n if n < indent
break if n == 0
end
end
src.gsub!(/^#{' ' * indent}/, '') if indent > 0
add_line_numbers(src) if self.class.add_line_numbers
src
end
@ -133,6 +163,12 @@ class RDoc::Attr
end
class RDoc::Alias
include RDoc::Generator::Markup
end
class RDoc::Constant
include RDoc::Generator::Markup

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

@ -8,10 +8,6 @@ class RDoc::Generator::RI
RDoc::RDoc.add_generator self
def self.for options
new options
end
##
# Set up a new ri generator
@ -20,6 +16,8 @@ class RDoc::Generator::RI
@store = RDoc::RI::Store.new '.'
@old_siginfo = nil
@current = nil
@store.dry_run = @options.dry_run
end
##

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

@ -1,296 +1,289 @@
<?xml version="1.0" encoding="<%= @options.charset %>"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta content="text/html; charset=<%= @options.charset %>" http-equiv="Content-Type" />
<meta content="text/html; charset=<%= @options.charset %>" http-equiv="Content-Type" />
<title><%= klass.type.capitalize %>: <%= klass.full_name %></title>
<title><%= klass.type.capitalize %>: <%= klass.full_name %></title>
<link rel="stylesheet" href="<%= rel_prefix %>/rdoc.css" type="text/css" media="screen" />
<link rel="stylesheet" href="<%= rel_prefix %>/rdoc.css" type="text/css" media="screen" />
<script src="<%= rel_prefix %>/js/jquery.js" type="text/javascript"
charset="utf-8"></script>
<script src="<%= rel_prefix %>/js/thickbox-compressed.js" type="text/javascript"
charset="utf-8"></script>
<script src="<%= rel_prefix %>/js/quicksearch.js" type="text/javascript"
charset="utf-8"></script>
<script src="<%= rel_prefix %>/js/darkfish.js" type="text/javascript"
charset="utf-8"></script>
<script src="<%= rel_prefix %>/js/jquery.js" type="text/javascript"
charset="utf-8"></script>
<script src="<%= rel_prefix %>/js/thickbox-compressed.js" type="text/javascript"
charset="utf-8"></script>
<script src="<%= rel_prefix %>/js/quicksearch.js" type="text/javascript"
charset="utf-8"></script>
<script src="<%= rel_prefix %>/js/darkfish.js" type="text/javascript"
charset="utf-8"></script>
</head>
<body class="<%= klass.type %>">
<div id="metadata">
<div id="home-metadata">
<div id="home-section" class="section">
<div id="metadata">
<div id="home-metadata">
<div id="home-section" class="section">
<h3 class="section-header">
<a href="<%= rel_prefix %>/index.html">Home</a>
<a href="<%= rel_prefix %>/index.html#classes">Classes</a>
<a href="<%= rel_prefix %>/index.html#methods">Methods</a>
</h3>
</div>
</div>
</div>
</div>
<div id="file-metadata">
<div id="file-list-section" class="section">
<h3 class="section-header">In Files</h3>
<div class="section-body">
<ul>
<% klass.in_files.each do |tl| %>
<li><a href="<%= rel_prefix %>/<%= h tl.path %>?TB_iframe=true&amp;height=550&amp;width=785"
class="thickbox" title="<%= h tl.absolute_name %>"><%= h tl.absolute_name %></a></li>
<% end %>
</ul>
</div>
</div>
<div id="file-metadata">
<div id="file-list-section" class="section">
<h3 class="section-header">In Files</h3>
<div class="section-body">
<ul>
<% klass.in_files.each do |tl| %>
<li><a href="<%= rel_prefix %>/<%= h tl.path %>?TB_iframe=true&amp;height=550&amp;width=785"
class="thickbox" title="<%= h tl.absolute_name %>"><%= h tl.absolute_name %></a></li>
<% end %>
</ul>
</div>
</div>
<% if !svninfo.empty? %>
<div id="file-svninfo-section" class="section">
<h3 class="section-header">Subversion Info</h3>
<div class="section-body">
<dl class="svninfo">
<dt>Rev</dt>
<dd><%= svninfo[:rev] %></dd>
<% if !svninfo.empty? %>
<div id="file-svninfo-section" class="section">
<h3 class="section-header">Subversion Info</h3>
<div class="section-body">
<dl class="svninfo">
<dt>Rev</dt>
<dd><%= svninfo[:rev] %></dd>
<dt>Last Checked In</dt>
<dd><%= svninfo[:commitdate].strftime('%Y-%m-%d %H:%M:%S') %>
(<%= svninfo[:commitdelta] %> ago)</dd>
<dt>Last Checked In</dt>
<dd><%= svninfo[:commitdate].strftime('%Y-%m-%d %H:%M:%S') %>
(<%= svninfo[:commitdelta] %> ago)</dd>
<dt>Checked in by</dt>
<dd><%= svninfo[:committer] %></dd>
</dl>
</div>
</div>
<% end %>
</div>
<dt>Checked in by</dt>
<dd><%= svninfo[:committer] %></dd>
</dl>
</div>
</div>
<% end %>
</div>
<div id="class-metadata">
<div id="class-metadata">
<!-- Parent Class -->
<% if klass.type == 'class' %>
<div id="parent-class-section" class="section">
<h3 class="section-header">Parent</h3>
<% unless String === klass.superclass %>
<p class="link"><a href="<%= klass.aref_to klass.superclass.path %>"><%= klass.superclass.full_name %></a></p>
<% else %>
<p class="link"><%= klass.superclass %></p>
<% end %>
</div>
<% end %>
<!-- Parent Class -->
<% if klass.type == 'class' %>
<div id="parent-class-section" class="section">
<h3 class="section-header">Parent</h3>
<% if klass.superclass and not String === klass.superclass then %>
<p class="link"><a href="<%= klass.aref_to klass.superclass.path %>"><%= klass.superclass.full_name %></a></p>
<% else %>
<p class="link"><%= klass.superclass %></p>
<% end %>
</div>
<% end %>
<!-- Namespace Contents -->
<% unless klass.classes_and_modules.empty? %>
<div id="namespace-list-section" class="section">
<h3 class="section-header">Namespace</h3>
<ul class="link-list">
<% (klass.modules.sort + klass.classes.sort).each do |mod| %>
<li><span class="type"><%= mod.type.upcase %></span> <a href="<%= klass.aref_to mod.path %>"><%= mod.full_name %></a></li>
<% end %>
</ul>
</div>
<% end %>
<!-- Namespace Contents -->
<% unless klass.classes_and_modules.empty? %>
<div id="namespace-list-section" class="section">
<h3 class="section-header">Namespace</h3>
<ul class="link-list">
<% (klass.modules.sort + klass.classes.sort).each do |mod| %>
<li><span class="type"><%= mod.type.upcase %></span> <a href="<%= klass.aref_to mod.path %>"><%= mod.full_name %></a></li>
<% end %>
</ul>
</div>
<% end %>
<!-- Method Quickref -->
<% unless klass.method_list.empty? %>
<div id="method-list-section" class="section">
<h3 class="section-header">Methods</h3>
<ul class="link-list">
<% klass.each_method do |meth| %>
<li><a href="#<%= meth.aref %>"><%= meth.singleton ? '::' : '#' %><%= meth.name %></a></li>
<% end %>
</ul>
</div>
<% end %>
<!-- Method Quickref -->
<% unless klass.method_list.empty? %>
<div id="method-list-section" class="section">
<h3 class="section-header">Methods</h3>
<ul class="link-list">
<% klass.each_method do |meth| %>
<li><a href="#<%= meth.aref %>"><%= meth.singleton ? '::' : '#' %><%= meth.name %></a></li>
<% end %>
</ul>
</div>
<% end %>
<!-- Included Modules -->
<% unless klass.includes.empty? %>
<div id="includes-section" class="section">
<h3 class="section-header">Included Modules</h3>
<ul class="link-list">
<% klass.each_include do |inc| %>
<% unless String === inc.module %>
<li><a class="include" href="<%= klass.aref_to inc.module.path %>"><%= inc.module.full_name %></a></li>
<% else %>
<li><span class="include"><%= inc.name %></span></li>
<% end %>
<% end %>
</ul>
</div>
<% end %>
</div>
<!-- Included Modules -->
<% unless klass.includes.empty? %>
<div id="includes-section" class="section">
<h3 class="section-header">Included Modules</h3>
<ul class="link-list">
<% klass.each_include do |inc| %>
<% unless String === inc.module %>
<li><a class="include" href="<%= klass.aref_to inc.module.path %>"><%= inc.module.full_name %></a></li>
<% else %>
<li><span class="include"><%= inc.name %></span></li>
<% end %>
<% end %>
</ul>
</div>
<% end %>
</div>
<div id="project-metadata">
<% simple_files = @files.select {|tl| tl.parser == RDoc::Parser::Simple } %>
<% unless simple_files.empty? then %>
<div id="fileindex-section" class="section project-section">
<h3 class="section-header">Files</h3>
<ul>
<% simple_files.each do |file| %>
<li class="file"><a href="<%= rel_prefix %>/<%= file.path %>"><%= h file.base_name %></a></li>
<% end %>
</ul>
</div>
<% end %>
<div id="project-metadata">
<% simple_files = @files.select {|tl| tl.parser == RDoc::Parser::Simple } %>
<% unless simple_files.empty? then %>
<div id="fileindex-section" class="section project-section">
<h3 class="section-header">Files</h3>
<ul>
<% simple_files.each do |file| %>
<li class="file"><a href="<%= rel_prefix %>/<%= file.path %>"><%= h file.base_name %></a></li>
<% end %>
</ul>
</div>
<% end %>
<div id="classindex-section" class="section project-section">
<h3 class="section-header">Class Index
<span class="search-toggle"><img src="<%= rel_prefix %>/images/find.png"
height="16" width="16" alt="[+]"
title="show/hide quicksearch" /></span></h3>
<form action="#" method="get" accept-charset="utf-8" class="initially-hidden">
<fieldset>
<legend>Quicksearch</legend>
<input type="text" name="quicksearch" value=""
class="quicksearch-field" />
</fieldset>
</form>
<div id="classindex-section" class="section project-section">
<h3 class="section-header">Class Index
<span class="search-toggle"><img src="<%= rel_prefix %>/images/find.png"
height="16" width="16" alt="[+]"
title="show/hide quicksearch" /></span></h3>
<form action="#" method="get" accept-charset="utf-8" class="initially-hidden">
<fieldset>
<legend>Quicksearch</legend>
<input type="text" name="quicksearch" value=""
class="quicksearch-field" />
</fieldset>
</form>
<ul class="link-list">
<% @modsort.each do |index_klass| %>
<li><a href="<%= rel_prefix %>/<%= index_klass.path %>"><%= index_klass.full_name %></a></li>
<% end %>
</ul>
<div id="no-class-search-results" style="display: none;">No matching classes.</div>
</div>
<ul class="link-list">
<% @modsort.each do |index_klass| %>
<li><a href="<%= rel_prefix %>/<%= index_klass.path %>"><%= index_klass.full_name %></a></li>
<% end %>
</ul>
<div id="no-class-search-results" style="display: none;">No matching classes.</div>
</div>
<% if $DEBUG_RDOC %>
<div id="debugging-toggle"><img src="<%= rel_prefix %>/images/bug.png"
alt="toggle debugging" height="16" width="16" /></div>
<% end %>
</div>
</div>
<% if $DEBUG_RDOC %>
<div id="debugging-toggle"><img src="<%= rel_prefix %>/images/bug.png"
alt="toggle debugging" height="16" width="16" /></div>
<% end %>
</div>
</div>
<div id="documentation">
<h1 class="<%= klass.type %>"><%= klass.full_name %></h1>
<div id="documentation">
<h1 class="<%= klass.type %>"><%= klass.full_name %></h1>
<div id="description">
<%= klass.description %>
</div>
<div id="description">
<%= klass.description %>
</div>
<!-- Constants -->
<% unless klass.constants.empty? %>
<div id="constants-list" class="section">
<h3 class="section-header">Constants</h3>
<dl>
<% klass.each_constant do |const| %>
<dt><a name="<%= const.name %>"><%= const.name %></a></dt>
<% if const.comment %>
<dd class="description"><%= const.description.strip %></dd>
<% else %>
<dd class="description missing-docs">(Not documented)</dd>
<% end %>
<% end %>
</dl>
</div>
<% end %>
<!-- Constants -->
<% unless klass.constants.empty? %>
<div id="constants-list" class="section">
<h3 class="section-header">Constants</h3>
<dl>
<% klass.each_constant do |const| %>
<dt><a name="<%= const.name %>"><%= const.name %></a></dt>
<% if const.comment %>
<dd class="description"><%= const.description.strip %></dd>
<% else %>
<dd class="description missing-docs">(Not documented)</dd>
<% end %>
<% end %>
</dl>
</div>
<% end %>
<!-- Attributes -->
<% unless klass.attributes.empty? %>
<div id="attribute-method-details" class="method-section section">
<h3 class="section-header">Attributes</h3>
<!-- Attributes -->
<% unless klass.attributes.empty? %>
<div id="attribute-method-details" class="method-section section">
<h3 class="section-header">Attributes</h3>
<% klass.each_attribute do |attrib| %>
<div id="<%= attrib.html_name %>-attribute-method" class="method-detail">
<a name="<%= h attrib.name %>"></a>
<% if attrib.rw =~ /w/i %>
<a name="<%= h attrib.name %>="></a>
<% end %>
<div class="method-heading attribute-method-heading">
<span class="method-name"><%= h attrib.name %></span><span
class="attribute-access-type">[<%= attrib.rw %>]</span>
</div>
<% klass.each_attribute do |attrib| %>
<div id="<%= attrib.html_name %>-attribute-method" class="method-detail">
<a name="<%= h attrib.name %>"></a>
<% if attrib.rw =~ /w/i %>
<a name="<%= h attrib.name %>="></a>
<% end %>
<div class="method-heading attribute-method-heading">
<span class="method-name"><%= h attrib.name %></span><span
class="attribute-access-type">[<%= attrib.rw %>]</span>
</div>
<div class="method-description">
<% if attrib.comment %>
<%= attrib.description.strip %>
<% else %>
<p class="missing-docs">(Not documented)</p>
<% end %>
</div>
</div>
<% end %>
</div>
<% end %>
<div class="method-description">
<% if attrib.comment %>
<%= attrib.description.strip %>
<% else %>
<p class="missing-docs">(Not documented)</p>
<% end %>
</div>
</div>
<% end %>
</div>
<% end %>
<!-- Methods -->
<% klass.methods_by_type.each do |type, visibilities|
next if visibilities.empty?
visibilities.each do |visibility, methods|
next if methods.empty? %>
<div id="<%= visibility %>-<%= type %>-method-details" class="method-section section">
<h3 class="section-header"><%= visibility.to_s.capitalize %> <%= type.capitalize %> Methods</h3>
<!-- Methods -->
<% klass.methods_by_type.each do |type, visibilities|
next if visibilities.empty?
visibilities.each do |visibility, methods|
next if methods.empty? %>
<div id="<%= visibility %>-<%= type %>-method-details" class="method-section section">
<h3 class="section-header"><%= visibility.to_s.capitalize %> <%= type.capitalize %> Methods</h3>
<% methods.each do |method| %>
<div id="<%= method.html_name %>-method" class="method-detail <%= method.is_alias_for ? "method-alias" : '' %>">
<a name="<%= h method.aref %>"></a>
<% methods.each do |method| %>
<div id="<%= method.html_name %>-method" class="method-detail <%= method.is_alias_for ? "method-alias" : '' %>">
<a name="<%= h method.aref %>"></a>
<div class="method-heading">
<% if method.call_seq %>
<span class="method-callseq"><%= method.call_seq.strip.gsub(/->/, '&rarr;').gsub( /^\w.+\./m, '') %></span>
<span class="method-click-advice">click to toggle source</span>
<% else %>
<span class="method-name"><%= h method.name %></span><span
class="method-args"><%= method.params %></span>
<span class="method-click-advice">click to toggle source</span>
<% end %>
</div>
<div class="method-heading">
<% if method.call_seq %>
<span class="method-callseq"><%= method.call_seq.strip.gsub(/->/, '&rarr;').gsub( /^\w.+\./m, '') %></span>
<span class="method-click-advice">click to toggle source</span>
<% else %>
<span class="method-name"><%= h method.name %></span><span
class="method-args"><%= method.params %></span>
<span class="method-click-advice">click to toggle source</span>
<% end %>
</div>
<div class="method-description">
<% if method.comment %>
<%= method.description.strip %>
<% else %>
<p class="missing-docs">(Not documented)</p>
<% end %>
<div class="method-description">
<% if method.comment %>
<%= method.description.strip %>
<% else %>
<p class="missing-docs">(Not documented)</p>
<% end %>
<% if method.token_stream %>
<div class="method-source-code"
id="<%= method.html_name %>-source">
<% if method.token_stream %>
<div class="method-source-code"
id="<%= method.html_name %>-source">
<pre>
<%= method.markup_code %>
</pre>
</div>
<% end %>
</div>
</div>
<% end %>
</div>
<% unless method.aliases.empty? %>
<div class="aliases">
Also aliased as: <%= method.aliases.map do |aka|
%{<a href="#{ klass.aref_to aka.path}">#{h aka.name}</a>}
end.join(", ") %>
</div>
<% end %>
<% unless method.aliases.empty? %>
<div class="aliases">
Also aliased as: <%= method.aliases.map do |aka|
if aka.parent then # HACK lib/rexml/encodings
%{<a href="#{klass.aref_to aka.path}">#{h aka.name}</a>}
else
h aka.name
end
end.join ", " %>
</div>
<% end %>
<% if method.is_alias_for then %>
<div class="aliases">
<% if method.is_alias_for then %>
<div class="aliases">
Alias for: <a href="<%= klass.aref_to method.is_alias_for.path %>"><%= h method.is_alias_for.name %></a>
</div>
<% end %>
</div>
</div>
<% end %>
</div>
<% end %>
</div>
<% end
end %>
<% end %>
</div>
<% end
end %>
</div>
</div>
<div id="rdoc-debugging-section-dump" class="debugging-section">
<% if $DEBUG_RDOC
require 'pp' %>
<pre><%= h PP.pp(klass, _erbout) %></pre>
</div>
<% else %>
<p>Disabled; run with --debug to generate this.</p>
<% end %>
</div>
<div id="validator-badges">
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
<p><small>Generated with the <a href="http://deveiate.org/projects/Darkfish-Rdoc/">Darkfish
Rdoc Generator</a> <%= RDoc::Generator::Darkfish::VERSION %></small>.</p>
</div>
<div id="validator-badges">
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
<p><small>Generated with the <a href="http://deveiate.org/projects/Darkfish-Rdoc/">Darkfish
Rdoc Generator</a> <%= RDoc::Generator::Darkfish::VERSION %></small>.</p>
</div>
</body>
</html>

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

@ -1,123 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta content="text/html; charset=<%= @options.charset %>" http-equiv="Content-Type" />
<meta content="text/html; charset=<%= @options.charset %>" http-equiv="Content-Type" />
<title>File: <%= file.base_name %> [<%= @options.title %>]</title>
<title>File: <%= file.base_name %> [<%= @options.title %>]</title>
<link type="text/css" media="screen" href="<%= rel_prefix %>/rdoc.css" rel="stylesheet" />
<link type="text/css" media="screen" href="<%= rel_prefix %>/rdoc.css" rel="stylesheet" />
<script src="<%= rel_prefix %>/js/jquery.js" type="text/javascript"
charset="utf-8"></script>
<script src="<%= rel_prefix %>/js/thickbox-compressed.js" type="text/javascript"
charset="utf-8"></script>
<script src="<%= rel_prefix %>/js/quicksearch.js" type="text/javascript"
charset="utf-8"></script>
<script src="<%= rel_prefix %>/js/darkfish.js" type="text/javascript"
charset="utf-8"></script>
<script src="<%= rel_prefix %>/js/jquery.js" type="text/javascript"
charset="utf-8"></script>
<script src="<%= rel_prefix %>/js/thickbox-compressed.js" type="text/javascript"
charset="utf-8"></script>
<script src="<%= rel_prefix %>/js/quicksearch.js" type="text/javascript"
charset="utf-8"></script>
<script src="<%= rel_prefix %>/js/darkfish.js" type="text/javascript"
charset="utf-8"></script>
</head>
<% if file.parser == RDoc::Parser::Simple %>
<body class="file">
<div id="metadata">
<div id="home-metadata">
<div id="home-section" class="section">
<div id="metadata">
<div id="home-metadata">
<div id="home-section" class="section">
<h3 class="section-header">
<a href="<%= rel_prefix %>/index.html">Home</a>
<a href="<%= rel_prefix %>/index.html#classes">Classes</a>
<a href="<%= rel_prefix %>/index.html#methods">Methods</a>
</h3>
</div>
</div>
</div>
</div>
<div id="project-metadata">
<% simple_files = @files.select { |f| f.parser == RDoc::Parser::Simple } %>
<% unless simple_files.empty? then %>
<div id="fileindex-section" class="section project-section">
<h3 class="section-header">Files</h3>
<ul>
<% simple_files.each do |f| %>
<li class="file"><a href="<%= rel_prefix %>/<%= f.path %>"><%= h f.base_name %></a></li>
<% end %>
</ul>
</div>
<% end %>
<div id="project-metadata">
<% simple_files = @files.select { |f| f.parser == RDoc::Parser::Simple } %>
<% unless simple_files.empty? then %>
<div id="fileindex-section" class="section project-section">
<h3 class="section-header">Files</h3>
<ul>
<% simple_files.each do |f| %>
<li class="file"><a href="<%= rel_prefix %>/<%= f.path %>"><%= h f.base_name %></a></li>
<% end %>
</ul>
</div>
<% end %>
<div id="classindex-section" class="section project-section">
<h3 class="section-header">Class Index
<span class="search-toggle"><img src="<%= rel_prefix %>/images/find.png"
height="16" width="16" alt="[+]"
title="show/hide quicksearch" /></span></h3>
<form action="#" method="get" accept-charset="utf-8" class="initially-hidden">
<fieldset>
<legend>Quicksearch</legend>
<input type="text" name="quicksearch" value=""
class="quicksearch-field" />
</fieldset>
</form>
<div id="classindex-section" class="section project-section">
<h3 class="section-header">Class Index
<span class="search-toggle"><img src="<%= rel_prefix %>/images/find.png"
height="16" width="16" alt="[+]"
title="show/hide quicksearch" /></span></h3>
<form action="#" method="get" accept-charset="utf-8" class="initially-hidden">
<fieldset>
<legend>Quicksearch</legend>
<input type="text" name="quicksearch" value=""
class="quicksearch-field" />
</fieldset>
</form>
<ul class="link-list">
<% @modsort.each do |index_klass| %>
<li><a href="<%= rel_prefix %>/<%= index_klass.path %>"><%= index_klass.full_name %></a></li>
<% end %>
</ul>
<div id="no-class-search-results" style="display: none;">No matching classes.</div>
</div>
<ul class="link-list">
<% @modsort.each do |index_klass| %>
<li><a href="<%= rel_prefix %>/<%= index_klass.path %>"><%= index_klass.full_name %></a></li>
<% end %>
</ul>
<div id="no-class-search-results" style="display: none;">No matching classes.</div>
</div>
<% if $DEBUG_RDOC %>
<div id="debugging-toggle"><img src="<%= rel_prefix %>/images/bug.png"
alt="toggle debugging" height="16" width="16" /></div>
<% end %>
</div>
</div>
<% if $DEBUG_RDOC %>
<div id="debugging-toggle"><img src="<%= rel_prefix %>/images/bug.png"
alt="toggle debugging" height="16" width="16" /></div>
<% end %>
</div>
</div>
<div id="documentation">
<%= file.description %>
</div>
<div id="documentation">
<%= file.description %>
</div>
<div id="validator-badges">
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
<p><small>Generated with the <a href="http://deveiate.org/projects/Darkfish-Rdoc/">Darkfish
Rdoc Generator</a> <%= RDoc::Generator::Darkfish::VERSION %></small>.</p>
</div>
<div id="validator-badges">
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
<p><small>Generated with the <a href="http://deveiate.org/projects/Darkfish-Rdoc/">Darkfish
Rdoc Generator</a> <%= RDoc::Generator::Darkfish::VERSION %></small>.</p>
</div>
</body>
<% else %>
<body class="file file-popup">
<div id="metadata">
<dl>
<dt class="modified-date">Last Modified</dt>
<dd class="modified-date"><%= file.last_modified %></dd>
<div id="metadata">
<dl>
<dt class="modified-date">Last Modified</dt>
<dd class="modified-date"><%= file.last_modified %></dd>
<% if file.requires %>
<dt class="requires">Requires</dt>
<dd class="requires">
<ul>
<% file.requires.each do |require| %>
<li><%= require.name %></li>
<% end %>
</ul>
</dd>
<% end %>
<% if file.requires %>
<dt class="requires">Requires</dt>
<dd class="requires">
<ul>
<% file.requires.each do |require| %>
<li><%= require.name %></li>
<% end %>
</ul>
</dd>
<% end %>
<% if @options.webcvs %>
<dt class="scs-url">Trac URL</dt>
<dd class="scs-url"><a target="_top"
href="<%= file.cvs_url %>"><%= file.cvs_url %></a></dd>
<% end %>
</dl>
</div>
<% if @options.webcvs %>
<dt class="scs-url">Trac URL</dt>
<dd class="scs-url"><a target="_top"
href="<%= file.cvs_url %>"><%= file.cvs_url %></a></dd>
<% end %>
</dl>
</div>
<div id="documentation">
<% if file.comment %>
<div class="description">
<h2>Description</h2>
<%= file.description %>
</div>
<% end %>
</div>
<div id="documentation">
<% if file.comment %>
<div class="description">
<h2>Description</h2>
<%= file.description %>
</div>
<% end %>
</div>
</body>
<% end %>
</html>

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

@ -1,64 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta content="text/html; charset=<%= @options.charset %>" http-equiv="Content-Type" />
<meta content="text/html; charset=<%= @options.charset %>" http-equiv="Content-Type" />
<title><%= h @options.title %></title>
<title><%= h @options.title %></title>
<link type="text/css" media="screen" href="rdoc.css" rel="stylesheet" />
<link type="text/css" media="screen" href="rdoc.css" rel="stylesheet" />
<script src="js/jquery.js" type="text/javascript" charset="utf-8"></script>
<script src="js/thickbox-compressed.js" type="text/javascript" charset="utf-8"></script>
<script src="js/quicksearch.js" type="text/javascript" charset="utf-8"></script>
<script src="js/darkfish.js" type="text/javascript" charset="utf-8"></script>
<script src="js/jquery.js" type="text/javascript" charset="utf-8"></script>
<script src="js/thickbox-compressed.js" type="text/javascript" charset="utf-8"></script>
<script src="js/quicksearch.js" type="text/javascript" charset="utf-8"></script>
<script src="js/darkfish.js" type="text/javascript" charset="utf-8"></script>
</head>
<body class="indexpage">
<% $stderr.sync = true %>
<h1><%= h @options.title %></h1>
<% $stderr.sync = true %>
<h1><%= h @options.title %></h1>
<% if @options.main_page && main_page = @files.find { |f| f.full_name == @options.main_page } %>
<div id="main">
<%= main_page.description.sub(%r{^\s*<h1.*?/h1>}i, '') %>
</div>
<% else %>
<p>This is the API documentation for '<%= @options.title %>'.</p>
<% end %>
<% if @options.main_page && main_page = @files.find { |f| f.full_name == @options.main_page } then %>
<div id="main">
<%= main_page.description.sub(%r{^\s*<h1.*?/h1>}i, '') %>
</div>
<% else %>
<p>This is the API documentation for '<%= @options.title %>'.</p>
<% end %>
<% simple_files = @files.select {|tl| tl.parser == RDoc::Parser::Simple } %>
<% unless simple_files.empty? then %>
<h2>Files</h2>
<ul>
<% simple_files.sort.each do |file| %>
<li class="file"><a href="<%= file.path %>"><%= h file.base_name %></a></li>
<% end %>
</ul>
<% end %>
<% simple_files = @files.select {|tl| tl.parser == RDoc::Parser::Simple } %>
<% unless simple_files.empty? then %>
<h2>Files</h2>
<ul>
<% simple_files.sort.each do |file| %>
<li class="file"><a href="<%= file.path %>"><%= h file.base_name %></a></li>
<% end %>
</ul>
<% end %>
<h2 id="classes">Classes/Modules</h2>
<ul>
<% @modsort.each do |klass| %>
<li class="<%= klass.type %>"><a href="<%= klass.path %>"><%= klass.full_name %></a></li>
<% end %>
</ul>
<h2 id="classes">Classes/Modules</h2>
<ul>
<% @modsort.each do |klass| %>
<li class="<%= klass.type %>"><a href="<%= klass.path %>"><%= klass.full_name %></a></li>
<% end %>
</ul>
<h2 id="methods">Methods</h2>
<ul>
<% RDoc::TopLevel.all_classes_and_modules.map do |mod|
mod.method_list
end.flatten.sort.each do |method| %>
<li><a href="<%= method.path %>"><%= method.pretty_name %> &mdash; <%= method.parent.full_name %></a></li>
<% end %>
</ul>
<h2 id="methods">Methods</h2>
<ul>
<% RDoc::TopLevel.all_classes_and_modules.map do |mod|
mod.method_list
end.flatten.sort.each do |method| %>
<li><a href="<%= method.path %>"><%= method.pretty_name %> &mdash; <%= method.parent.full_name %></a></li>
<% end %>
</ul>
<div id="validator-badges">
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
<p><small>Generated with the <a href="http://deveiate.org/projects/Darkfish-Rdoc/">Darkfish
Rdoc Generator</a> <%= RDoc::Generator::Darkfish::VERSION %></small>.</p>
</div>
<div id="validator-badges">
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
<p><small>Generated with the <a href="http://deveiate.org/projects/Darkfish-Rdoc/">Darkfish
Rdoc Generator</a> <%= RDoc::Generator::Darkfish::VERSION %></small>.</p>
</div>
</body>
</html>

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

@ -12,76 +12,76 @@
body {
background: #efefef;
font: 14px "Helvetica Neue", Helvetica, Tahoma, sans-serif;
font: 14px "Helvetica Neue", Helvetica, Tahoma, sans-serif;
}
body.class, body.module, body.file {
margin-left: 40px;
margin-left: 40px;
}
body.file-popup {
font-size: 90%;
margin-left: 0;
font-size: 90%;
margin-left: 0;
}
h1 {
font-size: 300%;
text-shadow: rgba(135,145,135,0.65) 2px 2px 3px;
color: #6C8C22;
font-size: 300%;
text-shadow: rgba(135,145,135,0.65) 2px 2px 3px;
color: #6C8C22;
}
h2,h3,h4 { margin-top: 1.5em; }
:link,
:visited {
color: #6C8C22;
text-decoration: none;
color: #6C8C22;
text-decoration: none;
}
:link:hover,
:visited:hover {
border-bottom: 1px dotted #6C8C22;
border-bottom: 1px dotted #6C8C22;
}
pre {
background: #ddd;
padding: 0.5em 0;
background: #ddd;
padding: 0.5em 0;
}
/* @group Generic Classes */
.initially-hidden {
display: none;
display: none;
}
.quicksearch-field {
width: 98%;
background: #ddd;
border: 1px solid #aaa;
height: 1.5em;
-webkit-border-radius: 4px;
width: 98%;
background: #ddd;
border: 1px solid #aaa;
height: 1.5em;
-webkit-border-radius: 4px;
}
.quicksearch-field:focus {
background: #f1edba;
background: #f1edba;
}
.missing-docs {
font-size: 120%;
background: white url(images/wrench_orange.png) no-repeat 4px center;
color: #ccc;
line-height: 2em;
border: 1px solid #d00;
opacity: 1;
padding-left: 20px;
text-indent: 24px;
letter-spacing: 3px;
font-weight: bold;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
font-size: 120%;
background: white url(images/wrench_orange.png) no-repeat 4px center;
color: #ccc;
line-height: 2em;
border: 1px solid #d00;
opacity: 1;
padding-left: 20px;
text-indent: 24px;
letter-spacing: 3px;
font-weight: bold;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
}
.target-section {
border: 2px solid #dcce90;
border-left-width: 8px;
padding: 0 1em;
background: #fff3c2;
border: 2px solid #dcce90;
border-left-width: 8px;
padding: 0 1em;
background: #fff3c2;
}
/* @end */
@ -89,37 +89,37 @@ pre {
/* @group Index Page, Standalone file pages */
body.indexpage {
margin: 1em 3em;
margin: 1em 3em;
}
body.indexpage p,
body.indexpage div,
body.file p {
margin: 1em 0;
margin: 1em 0;
}
.indexpage ul,
.file #documentation ul {
line-height: 160%;
list-style: none;
line-height: 160%;
list-style: none;
}
.indexpage ul :link,
.indexpage ul :visited {
font-size: 16px;
font-size: 16px;
}
.indexpage li,
.file #documentation li {
padding-left: 20px;
background: url(images/bullet_black.png) no-repeat left 4px;
padding-left: 20px;
background: url(images/bullet_black.png) no-repeat left 4px;
}
.indexpage li.module {
background: url(images/package.png) no-repeat left 4px;
background: url(images/package.png) no-repeat left 4px;
}
.indexpage li.class {
background: url(images/ruby.png) no-repeat left 4px;
background: url(images/ruby.png) no-repeat left 4px;
}
.indexpage li.file {
background: url(images/page_white_text.png) no-repeat left 4px;
background: url(images/page_white_text.png) no-repeat left 4px;
}
.file li p,
.indexpage li p {
@ -133,48 +133,48 @@ body.file p {
.class #metadata,
.file #metadata,
.module #metadata {
float: left;
width: 260px;
float: left;
width: 260px;
}
.class #documentation,
.file #documentation,
.module #documentation {
margin: 2em 1em 5em 300px;
min-width: 340px;
margin: 2em 1em 5em 300px;
min-width: 340px;
}
.file #metadata {
margin: 0.8em;
margin: 0.8em;
}
#validator-badges {
clear: both;
margin: 1em 1em 2em;
clear: both;
margin: 1em 1em 2em;
}
/* @end */
/* @group Metadata Section */
#metadata .section {
background-color: #dedede;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border: 1px solid #aaa;
margin: 0 8px 16px;
font-size: 90%;
overflow: hidden;
background-color: #dedede;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border: 1px solid #aaa;
margin: 0 8px 16px;
font-size: 90%;
overflow: hidden;
}
#metadata h3.section-header {
margin: 0;
padding: 2px 8px;
background: #ccc;
color: #666;
-moz-border-radius-topleft: 4px;
-moz-border-radius-topright: 4px;
-webkit-border-top-left-radius: 4px;
-webkit-border-top-right-radius: 4px;
border-bottom: 1px solid #aaa;
margin: 0;
padding: 2px 8px;
background: #ccc;
color: #666;
-moz-border-radius-topleft: 4px;
-moz-border-radius-topright: 4px;
-webkit-border-top-left-radius: 4px;
-webkit-border-top-right-radius: 4px;
border-bottom: 1px solid #aaa;
}
#metadata #home-section h3.section-header {
border-bottom: 0;
@ -183,33 +183,33 @@ body.file p {
#metadata ul,
#metadata dl,
#metadata p {
padding: 8px;
list-style: none;
padding: 8px;
list-style: none;
}
#file-metadata ul {
padding-left: 28px;
list-style-image: url(images/page_green.png);
padding-left: 28px;
list-style-image: url(images/page_green.png);
}
dl.svninfo {
color: #666;
margin: 0;
color: #666;
margin: 0;
}
dl.svninfo dt {
font-weight: bold;
font-weight: bold;
}
ul.link-list li {
white-space: nowrap;
white-space: nowrap;
}
ul.link-list .type {
font-size: 8px;
text-transform: uppercase;
color: white;
background: #969696;
padding: 2px 4px;
-webkit-border-radius: 5px;
font-size: 8px;
text-transform: uppercase;
color: white;
background: #969696;
padding: 2px 4px;
-webkit-border-radius: 5px;
}
/* @end */
@ -217,7 +217,7 @@ ul.link-list .type {
/* @group Project Metadata Section */
#project-metadata {
margin-top: 3em;
margin-top: 3em;
}
.file #project-metadata {
@ -225,34 +225,34 @@ ul.link-list .type {
}
#project-metadata .section {
border: 1px solid #aaa;
border: 1px solid #aaa;
}
#project-metadata h3.section-header {
border-bottom: 1px solid #aaa;
position: relative;
border-bottom: 1px solid #aaa;
position: relative;
}
#project-metadata h3.section-header .search-toggle {
position: absolute;
right: 5px;
position: absolute;
right: 5px;
}
#project-metadata form {
color: #777;
background: #ccc;
padding: 8px 8px 16px;
border-bottom: 1px solid #bbb;
color: #777;
background: #ccc;
padding: 8px 8px 16px;
border-bottom: 1px solid #bbb;
}
#project-metadata fieldset {
border: 0;
border: 0;
}
#no-class-search-results {
margin: 0 auto 1em;
text-align: center;
font-size: 14px;
font-weight: bold;
color: #aaa;
margin: 0 auto 1em;
text-align: center;
font-size: 14px;
font-weight: bold;
color: #aaa;
}
/* @end */
@ -260,12 +260,12 @@ ul.link-list .type {
/* @group Documentation Section */
#description {
font-size: 100%;
color: #333;
font-size: 100%;
color: #333;
}
#description p {
margin: 1em 0.4em;
margin: 1em 0.4em;
}
#description li p {
@ -273,152 +273,152 @@ ul.link-list .type {
}
#description ul {
margin-left: 1.5em;
margin-left: 1.5em;
}
#description ul li {
line-height: 1.4em;
line-height: 1.4em;
}
#description dl,
#documentation dl {
margin: 8px 1.5em;
border: 1px solid #ccc;
margin: 8px 1.5em;
border: 1px solid #ccc;
}
#description dl {
font-size: 14px;
font-size: 14px;
}
#description dt,
#documentation dt {
padding: 2px 4px;
font-weight: bold;
background: #ddd;
padding: 2px 4px;
font-weight: bold;
background: #ddd;
}
#description dd,
#documentation dd {
padding: 2px 12px;
padding: 2px 12px;
}
#description dd + dt,
#documentation dd + dt {
margin-top: 0.7em;
margin-top: 0.7em;
}
#documentation .section {
font-size: 90%;
font-size: 90%;
}
#documentation h3.section-header {
margin-top: 2em;
padding: 0.75em 0.5em;
background-color: #dedede;
color: #333;
font-size: 150%;
border: 1px solid #bbb;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
margin-top: 2em;
padding: 0.75em 0.5em;
background-color: #dedede;
color: #333;
font-size: 150%;
border: 1px solid #bbb;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
}
#constants-list > dl,
#attributes-list > dl {
margin: 1em 0 2em;
border: 0;
margin: 1em 0 2em;
border: 0;
}
#constants-list > dl dt,
#attributes-list > dl dt {
padding-left: 0;
font-weight: bold;
font-family: Monaco, "Andale Mono";
background: inherit;
padding-left: 0;
font-weight: bold;
font-family: Monaco, "Andale Mono";
background: inherit;
}
#constants-list > dl dt a,
#attributes-list > dl dt a {
color: inherit;
color: inherit;
}
#constants-list > dl dd,
#attributes-list > dl dd {
margin: 0 0 1em 0;
padding: 0;
color: #666;
margin: 0 0 1em 0;
padding: 0;
color: #666;
}
/* @group Method Details */
#documentation .method-source-code {
display: none;
display: none;
}
#documentation .method-detail {
margin: 0.5em 0;
padding: 0.5em 0;
cursor: pointer;
margin: 0.5em 0;
padding: 0.5em 0;
cursor: pointer;
}
#documentation .method-detail:hover {
background-color: #f1edba;
background-color: #f1edba;
}
#documentation .method-heading {
position: relative;
padding: 2px 4px 0 20px;
font-size: 125%;
font-weight: bold;
color: #333;
background: url(images/brick.png) no-repeat left bottom;
position: relative;
padding: 2px 4px 0 20px;
font-size: 125%;
font-weight: bold;
color: #333;
background: url(images/brick.png) no-repeat left bottom;
}
#documentation .method-heading :link,
#documentation .method-heading :visited {
color: inherit;
color: inherit;
}
#documentation .method-click-advice {
position: absolute;
top: 2px;
right: 5px;
font-size: 10px;
color: #9b9877;
visibility: hidden;
padding-right: 20px;
line-height: 20px;
background: url(images/zoom.png) no-repeat right top;
position: absolute;
top: 2px;
right: 5px;
font-size: 10px;
color: #9b9877;
visibility: hidden;
padding-right: 20px;
line-height: 20px;
background: url(images/zoom.png) no-repeat right top;
}
#documentation .method-detail:hover .method-click-advice {
visibility: visible;
visibility: visible;
}
#documentation .method-alias .method-heading {
color: #666;
background: url(images/brick_link.png) no-repeat left bottom;
color: #666;
background: url(images/brick_link.png) no-repeat left bottom;
}
#documentation .method-description,
#documentation .aliases {
margin: 0 20px;
line-height: 1.2em;
color: #666;
margin: 0 20px;
line-height: 1.2em;
color: #666;
}
#documentation .aliases {
padding-top: 4px;
font-style: italic;
cursor: default;
padding-top: 4px;
font-style: italic;
cursor: default;
}
#documentation .method-description p {
padding: 0;
padding: 0;
}
#documentation .method-description p + p {
margin-bottom: 0.5em;
margin-bottom: 0.5em;
}
#documentation .method-description ul {
margin-left: 1.5em;
}
#documentation .attribute-method-heading {
background: url(images/tag_green.png) no-repeat left bottom;
background: url(images/tag_green.png) no-repeat left bottom;
}
#documentation #attribute-method-details .method-detail:hover {
background-color: transparent;
cursor: default;
background-color: transparent;
cursor: default;
}
#documentation .attribute-access-type {
font-size: 60%;
text-transform: uppercase;
vertical-align: super;
padding: 0 2px;
font-size: 60%;
text-transform: uppercase;
vertical-align: super;
padding: 0 2px;
}
/* @end */
@ -429,19 +429,19 @@ ul.link-list .type {
/* @group Source Code */
div.method-source-code {
background: #262626;
color: #efefef;
margin: 1em;
padding: 0.5em;
border: 1px dashed #999;
overflow: hidden;
background: #262626;
color: #efefef;
margin: 1em;
padding: 0.5em;
border: 1px dashed #999;
overflow: hidden;
}
div.method-source-code pre {
background: inherit;
padding: 0;
color: white;
overflow: auto;
background: inherit;
padding: 0;
color: white;
overflow: auto;
}
/* @group Ruby keyword styles */
@ -467,51 +467,51 @@ div.method-source-code pre {
}
.file-popup dl {
font-size: 80%;
padding: 0.75em;
background-color: #dedede;
color: #333;
border: 1px solid #bbb;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
font-size: 80%;
padding: 0.75em;
background-color: #dedede;
color: #333;
border: 1px solid #bbb;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
}
.file dt {
font-weight: bold;
padding-left: 22px;
line-height: 20px;
background: url(images/page_white_width.png) no-repeat left top;
font-weight: bold;
padding-left: 22px;
line-height: 20px;
background: url(images/page_white_width.png) no-repeat left top;
}
.file dt.modified-date {
background: url(images/date.png) no-repeat left top;
background: url(images/date.png) no-repeat left top;
}
.file dt.requires {
background: url(images/plugin.png) no-repeat left top;
background: url(images/plugin.png) no-repeat left top;
}
.file dt.scs-url {
background: url(images/wrench.png) no-repeat left top;
background: url(images/wrench.png) no-repeat left top;
}
.file dl dd {
margin: 0 0 1em 0;
margin: 0 0 1em 0;
}
.file #metadata dl dd ul {
list-style: circle;
margin-left: 20px;
padding-top: 0;
list-style: circle;
margin-left: 20px;
padding-top: 0;
}
.file #metadata dl dd ul li {
}
.file h2 {
margin-top: 2em;
padding: 0.75em 0.5em;
background-color: #dedede;
color: #333;
font-size: 120%;
border: 1px solid #bbb;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
margin-top: 2em;
padding: 0.75em 0.5em;
background-color: #dedede;
color: #333;
font-size: 120%;
border: 1px solid #bbb;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
}
/* @end */
@ -521,13 +521,13 @@ div.method-source-code pre {
/* @group ThickBox Styles */
#TB_window {
font: 12px Arial, Helvetica, sans-serif;
color: #333333;
font: 12px Arial, Helvetica, sans-serif;
color: #333333;
}
#TB_secondLine {
font: 10px Arial, Helvetica, sans-serif;
color:#666666;
font: 10px Arial, Helvetica, sans-serif;
color:#666666;
}
#TB_window :link,
@ -540,147 +540,147 @@ div.method-source-code pre {
#TB_window :visited:focus { color: #666666; }
#TB_overlay {
position: fixed;
z-index:100;
top: 0px;
left: 0px;
height:100%;
width:100%;
position: fixed;
z-index:100;
top: 0px;
left: 0px;
height:100%;
width:100%;
}
.TB_overlayMacFFBGHack {background: url(images/macFFBgHack.png) repeat;}
.TB_overlayBG {
background-color:#000;
filter:alpha(opacity=75);
-moz-opacity: 0.75;
opacity: 0.75;
background-color:#000;
filter:alpha(opacity=75);
-moz-opacity: 0.75;
opacity: 0.75;
}
* html #TB_overlay { /* ie6 hack */
position: absolute;
height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
position: absolute;
height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
}
#TB_window {
position: fixed;
background: #ffffff;
z-index: 102;
color:#000000;
display:none;
border: 4px solid #525252;
text-align:left;
top:50%;
left:50%;
position: fixed;
background: #ffffff;
z-index: 102;
color:#000000;
display:none;
border: 4px solid #525252;
text-align:left;
top:50%;
left:50%;
}
* html #TB_window { /* ie6 hack */
position: absolute;
margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px');
position: absolute;
margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px');
}
#TB_window img#TB_Image {
display:block;
margin: 15px 0 0 15px;
border-right: 1px solid #ccc;
border-bottom: 1px solid #ccc;
border-top: 1px solid #666;
border-left: 1px solid #666;
display:block;
margin: 15px 0 0 15px;
border-right: 1px solid #ccc;
border-bottom: 1px solid #ccc;
border-top: 1px solid #666;
border-left: 1px solid #666;
}
#TB_caption{
height:25px;
padding:7px 30px 10px 25px;
float:left;
height:25px;
padding:7px 30px 10px 25px;
float:left;
}
#TB_closeWindow{
height:25px;
padding:11px 25px 10px 0;
float:right;
height:25px;
padding:11px 25px 10px 0;
float:right;
}
#TB_closeAjaxWindow{
padding:7px 10px 5px 0;
margin-bottom:1px;
text-align:right;
float:right;
padding:7px 10px 5px 0;
margin-bottom:1px;
text-align:right;
float:right;
}
#TB_ajaxWindowTitle{
float:left;
padding:7px 0 5px 10px;
margin-bottom:1px;
font-size: 22px;
float:left;
padding:7px 0 5px 10px;
margin-bottom:1px;
font-size: 22px;
}
#TB_title{
background-color: #6C8C22;
color: #dedede;
height:40px;
background-color: #6C8C22;
color: #dedede;
height:40px;
}
#TB_title :link,
#TB_title :visited {
color: white !important;
border-bottom: 1px dotted #dedede;
color: white !important;
border-bottom: 1px dotted #dedede;
}
#TB_ajaxContent{
clear:both;
padding:2px 15px 15px 15px;
overflow:auto;
text-align:left;
line-height:1.4em;
clear:both;
padding:2px 15px 15px 15px;
overflow:auto;
text-align:left;
line-height:1.4em;
}
#TB_ajaxContent.TB_modal{
padding:15px;
padding:15px;
}
#TB_ajaxContent p{
padding:5px 0px 5px 0px;
padding:5px 0px 5px 0px;
}
#TB_load{
position: fixed;
display:none;
height:13px;
width:208px;
z-index:103;
top: 50%;
left: 50%;
margin: -6px 0 0 -104px; /* -height/2 0 0 -width/2 */
position: fixed;
display:none;
height:13px;
width:208px;
z-index:103;
top: 50%;
left: 50%;
margin: -6px 0 0 -104px; /* -height/2 0 0 -width/2 */
}
* html #TB_load { /* ie6 hack */
position: absolute;
margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px');
position: absolute;
margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px');
}
#TB_HideSelect{
z-index:99;
position:fixed;
top: 0;
left: 0;
background-color:#fff;
border:none;
filter:alpha(opacity=0);
-moz-opacity: 0;
opacity: 0;
height:100%;
width:100%;
z-index:99;
position:fixed;
top: 0;
left: 0;
background-color:#fff;
border:none;
filter:alpha(opacity=0);
-moz-opacity: 0;
opacity: 0;
height:100%;
width:100%;
}
* html #TB_HideSelect { /* ie6 hack */
position: absolute;
height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
position: absolute;
height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
}
#TB_iframeContent{
clear:both;
border:none;
margin-bottom:-1px;
margin-top:1px;
_margin-bottom:1px;
clear:both;
border:none;
margin-bottom:-1px;
margin-top:1px;
_margin-bottom:1px;
}
/* @end */
@ -688,17 +688,17 @@ margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = d
/* @group Debugging Section */
#debugging-toggle {
text-align: center;
text-align: center;
}
#debugging-toggle img {
cursor: pointer;
cursor: pointer;
}
#rdoc-debugging-section-dump {
display: none;
margin: 0 2em 2em;
background: #ccc;
border: 1px solid #999;
display: none;
margin: 0 2em 2em;
background: #ccc;
border: 1px solid #999;
}

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

@ -17,6 +17,7 @@ class RDoc::Include < RDoc::CodeObject
super()
@name = name
self.comment = comment
@module = nil # cache for module if found
end
##
@ -52,9 +53,47 @@ class RDoc::Include < RDoc::CodeObject
##
# Attempts to locate the included module object. Returns the name if not
# known.
#
# The scoping rules of Ruby to resolve the name of an included module are:
# - first look into the children of the current context;
# - if not found, look into the children of included modules,
# in reverse inclusion order;
# - if still not found, go up the hierarchy of names.
def module
RDoc::TopLevel.find_module_named(@name) || @name
return @module if @module
# search the current context
return @name unless parent
full_name = parent.child_name(@name)
@module = RDoc::TopLevel.modules_hash[full_name]
return @module if @module
return @name if @name =~ /^::/
# search the includes before this one, in reverse order
searched = parent.includes.take_while { |i| i != self }.reverse
searched.each do |i|
inc = i.module
next if String === inc
full_name = inc.child_name(@name)
@module = RDoc::TopLevel.modules_hash[full_name]
return @module if @module
end
# go up the hierarchy of names
p = parent.parent
while p
full_name = p.child_name(@name)
@module = RDoc::TopLevel.modules_hash[full_name]
return @module if @module
p = p.parent
end
@name
end
def to_s # :nodoc:
"include #@name in: #{parent}"
end
end

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

@ -59,12 +59,477 @@ require 'rdoc'
#
# puts "<body>#{wh.convert ARGF.read}</body>"
#
# == Encoding
#
# Where Encoding support is available RDoc will automatically convert all
# documents to the same output encoding. The output encoding can be set via
# RDoc::Options#encoding and defaults to Encoding.default_external.
#
# = \RDoc Markup Reference
#
# == Block Markup
#
# === Paragraphs and Verbatim
#
# The markup engine 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. Empty lines separate paragraphs.
#
# Any line that starts to the right of the current margin is treated
# as verbatim text. This is useful for code listings:
#
# 3.times { puts "Ruby" }
#
# In verbatim text, two or more blank lines are collapsed into one,
# and trailing blank lines are removed:
#
# This is the first line
#
#
# This is the second non-blank line,
# after 2 blank lines in the source markup.
#
#
# There were two trailing blank lines right above this paragraph, that
# have been removed. In addition, the verbatim text has been shifted
# left, so the amount of indentation of verbatim text is unimportant.
#
# === Headers and Rules
#
# A line starting with an equal sign (=) is treated as a
# heading. Level one headings have one equals sign, level two headings
# have two, and so on until level six, which is the maximum
# (seven hyphens or more result in a level six heading).
#
# For example, the above header was obtained with:
# == Headers and Rules
#
# 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).
#
# In the case of HTML output, three dashes generate a 1-pixel high rule,
# four dashes result in 2 pixels, and so on. The actual height is limited
# to 10 pixels:
#
# ---
# -----
# -----------------------------------------------------
#
# produces:
#
# ---
# -----
# -----------------------------------------------------
#
# === Simple Lists
#
# If a paragraph starts with a "*", "-", "<digit>." or "<letter>.",
# 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
#
# produces:
#
# * 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
#
# === Labeled Lists
#
# 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
#
# produces:
#
# [cat] a small furry mammal
# that seems to sleep a lot
#
# [ant] a little insect that is known
# to enjoy picnics
#
# If you want the list bodies to line up to the left of the labels,
# use two colons:
#
# cat:: a small furry mammal
# that seems to sleep a lot
#
# ant:: a little insect that is known
# to enjoy picnics
#
# produces:
#
# cat:: a small furry mammal
# that seems to sleep a lot
#
# ant:: a little insect that is known
# to enjoy picnics
#
# Notice that blank lines right after the label are ignored in labeled lists:
#
# [one]
#
# definition 1
#
# [two]
#
# definition 2
#
# produces the same output as
#
# [one] definition 1
# [two] definition 2
#
#
# === Lists and Verbatim
#
# If you want to introduce a verbatim section right after a list, it has to be
# less indented than the list item bodies, but more indented than the list
# label, letter, digit or bullet. For instance:
#
# * point 1
#
# * point 2, first paragraph
#
# point 2, second paragraph
# verbatim text inside point 2
# point 2, third paragraph
# verbatim text outside of the list (the list is therefore closed)
# regular paragraph after the list
#
# produces:
#
# * point 1
#
# * point 2, first paragraph
#
# point 2, second paragraph
# verbatim text inside point 2
# point 2, third paragraph
# verbatim text outside of the list (the list is therefore closed)
# regular paragraph after the list
#
#
# == Text Markup
#
# === Bold, Italic, Typewriter Text
#
# 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:
#
# <tt>\*_word_\*</tt>:: displays _word_ in a *bold* font
# <tt>\__word_\_</tt>:: displays _word_ in an _emphasized_ font
# <tt>\+_word_\+</tt>:: displays _word_ in a +code+ font
#
# General markup affects text between a start delimiter and an end
# delimiter. Not surprisingly, these delimiters look like HTML markup.
#
# <tt>\<b>_text_</b></tt>:: displays _text_ in a *bold* font
# <tt>\<em>_text_</em></tt>:: displays _text_ in an _emphasized_ font
# (alternate tag: <tt>\<i></tt>)
# <tt>\<tt>_text_\</tt></tt>:: displays _text_ in a +code+ font
# (alternate tag: <tt>\<code></tt>)
#
# 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 (see <i>Escaping
# Text Markup</i>, below).
#
# === Hyperlinks
#
# Hyperlinks to the web starting with +http:+, +mailto:+, +ftp:+ or +www.+
# are recognized. An HTTP url that references an external image file is
# converted into an inline <img...>. Hyperlinks starting with +link:+ are
# assumed to refer to local files whose path is relative to the <tt>--op</tt>
# directory.
#
# Hyperlinks can also be of the form _label_[_url_], in which
# case _label_ is used in the displayed text, and _url_ is
# used as the target. If _label_ contains multiple words,
# put it in braces: {<em>multi word label</em>}[url].
#
# Example hyperlinks:
#
# link:RDoc.html
# http://rdoc.rubyforge.org
# mailto:user@example.com
# {RDoc Documentation}[http://rdoc.rubyforge.org]
# {RDoc Markup}[link:RDoc/Markup.html]
#
# === Escaping Text Markup
#
# Text markup can be escaped with a backslash, as in \<tt>, which was obtained
# with "<tt>\\<tt></tt>". Except in verbatim sections and between \<tt> tags,
# to produce a backslash, you have to double it unless it is followed by a
# space, tab or newline. Otherwise, the HTML formatter will discard it, as it
# is used to escape potential hyperlinks:
#
# * The \ must be doubled if not followed by white space: \\.
# * But not in \<tt> tags: in a Regexp, <tt>\S</tt> matches non-space.
# * This is a link to {ruby-lang}[www.ruby-lang.org].
# * This is not a link, however: \{ruby-lang.org}[www.ruby-lang.org].
# * This will not be hyperlinked to \RDoc::RDoc#document
#
# generates:
#
# * The \ must be doubled if not followed by white space: \\.
# * But not in \<tt> tags: in a Regexp, <tt>\S</tt> matches non-space.
# * This is a link to {ruby-lang}[www.ruby-lang.org]
# * This is not a link, however: \{ruby-lang.org}[www.ruby-lang.org]
# * This will not be hyperlinked to \RDoc::RDoc#document
#
# Inside \<tt> tags, more precisely, leading backslashes are removed
# only if followed by a markup character (<tt><*_+</tt>), a backslash,
# or a known hyperlink reference (a known class or method). So in the
# example above, the backslash of <tt>\S</tt> would be removed
# if there was a class or module named +S+ in the current context.
#
# This behavior is inherited from RDoc version 1, and has been kept
# for compatibility with existing RDoc documentation.
#
# === Conversion of characters
#
# HTML will convert two/three dashes to an em-dash. Other common characters are
# converted as well:
#
# em-dash:: -- or ---
# ellipsis:: ...
#
# single quotes:: 'text' or `text'
# double quotes:: "text" or ``text''
#
# copyright:: (c)
# registered trademark:: (r)
#
# produces:
#
# em-dash:: -- or ---
# ellipsis:: ...
#
# single quotes:: 'text' or `text'
# double quotes:: "text" or ``text''
#
# copyright:: (c)
# registered trademark:: (r)
#
#
# == Documenting Source Code
#
# Comment blocks can be written fairly naturally, either using <tt>#</tt> on
# successive lines of the comment, or by including the comment in
# a <tt>=begin</tt>/<tt>=end</tt> block. If you use the latter form,
# the <tt>=begin</tt> 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 starting
# with <tt>--</tt> right after the <tt>#</tt> character (otherwise,
# it will be treated as a rule if it has three dashes or more).
# 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 with <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)
# # ...
# end
#
# Names of classes, files, and any method names containing an
# underscore or preceded by a hash character are automatically hyperlinked
# from comment text to their description. This hyperlinking works inside
# the current class or module, and with ancestor methods (in included modules
# or in the superclass).
#
# 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.
#
# RDoc automatically cross-references words with underscores or camel-case.
# To suppress cross-references, prefix the word with a \ character. To
# include special characters like "<tt>\n</tt>", you'll need to use
# two \ characters in normal text, but only one in \<tt> text:
#
# "\\n" or "<tt>\n</tt>"
#
# produces:
#
# "\\n" or "<tt>\n</tt>"
#
# == Directives
#
# Directives are keywords surrounded by ":" characters.
#
# === Controlling what is documented
#
# [+:nodoc:+ / <tt>:nodoc: all</tt>]
# This directive prevents documentation for the element from
# being generated. For classes and modules, the methods, aliases,
# constants, and attributes directly within the affected class or
# module also will be omitted. By default, though, modules and
# classes within that class of module _will_ be documented. This is
# turned off by adding the +all+ modifier.
#
# module MyModule # :nodoc:
# class Input
# end
# end
#
# module OtherModule # :nodoc: all
# class Output
# end
# end
#
# In the above code, only class <tt>MyModule::Input</tt> will be documented.
#
# The +:nodoc:+ directive, like +:enddoc:+, +:stopdoc:+ and +:startdoc:+
# presented below, is local to the current file: if you do not want to
# document a module that appears in several files, specify +:nodoc:+ on each
# appearance, at least once per file.
#
# [+:stopdoc:+ / +:startdoc:+]
# Stop and start adding new documentation elements to the current container.
# For example, if a class has a number of constants that you don't want to
# document, put a +:stopdoc:+ before the first, and a +:startdoc:+ after the
# last. If you don't specify a +:startdoc:+ by the end of the container,
# disables documentation for the rest of the current file.
#
# [+:doc:+]
# Forces a method or attribute to be documented even if it wouldn't be
# otherwise. Useful if, for example, you want to include documentation of a
# particular private method.
#
# [+:enddoc:+]
# Document nothing further at the current level: directives +:startdoc:+ and
# +:doc:+ that appear after this will not be honored for the current container
# (file, class or module), in the current file.
#
# [+:notnew:+ / +:not_new:+ / +:not-new:+ ]
# 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:+ directive stops this. Remember that +initialize+ is private,
# so you won't see the documentation unless you use the +-a+ command line
# option.
#
# === Other directives
#
# [+:include:+ _filename_]
# Include the contents of the named file at this point. This directive
# must appear alone on one line, possibly preceded by spaces. In this
# position, it can be escapd with a \ in front of the first colon.
#
# The file will be searched for in the directories listed by the +--include+
# option, or in the current directory by default. The contents of the file
# will be shifted to have the same indentation as the ':' at the start of
# the +:include:+ directive.
#
# [+:title:+ _text_]
# Sets the title for the document. Equivalent to the <tt>--title</tt>
# command line parameter. (The command line parameter overrides any :title:
# directive in the source).
#
# [+:main:+ _name_]
# Equivalent to the <tt>--main</tt> command line parameter.
#
# [<tt>:section: title</tt>]
# 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.
# # ----------------------------------------
#
# <i>Note: Current formatters to not take sections into account.</i>
#
# [+: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.
#
# Further directives can be found in RDoc::Parser::Ruby and RDoc::Parser::C.
#--
# Author:: Dave Thomas, dave@pragmaticprogrammer.com
# License:: Ruby license
# Original Author:: Dave Thomas, dave@pragmaticprogrammer.com
# License:: Ruby license
class RDoc::Markup
##
# An AttributeManager which handles inline markup.
attr_reader :attribute_manager
##

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

@ -15,9 +15,12 @@ class RDoc::Markup::AttributeManager
# optimistic
#++
A_PROTECT = 004 # :nodoc:
A_PROTECT = 004 # :nodoc:
PROTECT_ATTR = A_PROTECT.chr # :nodoc:
##
# Special mask character to prevent inline markup handling
PROTECT_ATTR = A_PROTECT.chr # :nodoc:
##
# This maps delimiters that occur around words (such as *bold* or +tt+)
@ -56,7 +59,7 @@ class RDoc::Markup::AttributeManager
def initialize
@html_tags = {}
@matching_word_pairs = {}
@protectable = %w[<\\]
@protectable = %w[<]
@special = {}
@word_pair_map = {}
@ -79,12 +82,19 @@ class RDoc::Markup::AttributeManager
RDoc::Markup::AttrChanger.new turn_on, turn_off
end
def change_attribute(current, new)
##
# Changes the current attribute from +current+ to +new+
def change_attribute current, new
diff = current ^ new
attribute(new & diff, current & diff)
end
def changed_attribute_by_name(current_set, new_set)
##
# Used by the tests to change attributes by name from +current_set+ to
# +new_set+
def changed_attribute_by_name current_set, new_set
current = new = 0
current_set.each do |name|
current |= RDoc::Markup::Attribute.bitmap_for(name)
@ -97,6 +107,9 @@ class RDoc::Markup::AttributeManager
change_attribute(current, new)
end
##
# Copies +start_pos+ to +end_pos+ from the current string
def copy_string(start_pos, end_pos)
res = @str[start_pos...end_pos]
res.gsub!(/\000/, '')
@ -112,7 +125,7 @@ class RDoc::Markup::AttributeManager
# first do matching ones
tags = @matching_word_pairs.keys.join("")
re = /(^|[^\w#{NULL}])([#{tags}])([#:\\]?[\w.\/-]+?\S?)\2(\W|$)/
re = /(^|\W)([#{tags}])([#:\\]?[\w.\/-]+?\S?)\2(\W|$)/
1 while str.gsub!(re) do
attr = @matching_word_pairs[$2]
@ -164,6 +177,9 @@ class RDoc::Markup::AttributeManager
# Escapes special sequences of text to prevent conversion to RDoc
def mask_protected_sequences
# protect __send__, __FILE__, etc.
@str.gsub!(/__([a-z]+)__/i,
"_#{PROTECT_ATTR}_#{PROTECT_ATTR}\\1_#{PROTECT_ATTR}_#{PROTECT_ATTR}")
@str.gsub!(/\\([#{Regexp.escape @protectable.join('')}])/,
"\\1#{PROTECT_ATTR}")
end
@ -228,8 +244,8 @@ class RDoc::Markup::AttributeManager
@attrs = RDoc::Markup::AttrSpan.new @str.length
convert_html @str, @attrs
convert_attrs @str, @attrs
convert_html @str, @attrs
convert_specials @str, @attrs
unmask_protected_sequences
@ -262,6 +278,9 @@ class RDoc::Markup::AttributeManager
end
end
##
# Splits the string into chunks by attribute change
def split_into_flow
res = []
current_attr = 0

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

@ -1,12 +1,20 @@
##
# An empty line
# An empty line. This class is a singleton.
class RDoc::Markup::BlankLine
def == other # :nodoc:
self.class == other.class
@instance = new
##
# RDoc::Markup::BlankLine is a singleton
def self.new
@instance
end
##
# Calls #accept_blank_line on +visitor+
def accept visitor
visitor.accept_blank_line self
end

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

@ -39,6 +39,9 @@ class RDoc::Markup::Document
self.class == other.class and @parts == other.parts
end
##
# Runs this document and all its #items through +visitor+
def accept visitor
visitor.start_accepting
@ -49,6 +52,9 @@ class RDoc::Markup::Document
visitor.end_accepting
end
##
# Does this document have no parts?
def empty?
@parts.empty?
end

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

@ -7,6 +7,10 @@ require 'rdoc/markup'
class RDoc::Markup::Formatter
##
# Tag for inline markup containing a +bit+ for the bitmask and the +on+ and
# +off+ triggers.
InlineTag = Struct.new(:bit, :on, :off)
##
@ -101,6 +105,9 @@ class RDoc::Markup::Formatter
@in_tt > 0
end
##
# Turns on tags for +item+ on +res+
def on_tags res, item
attr_mask = item.turn_on
return if attr_mask.zero?
@ -113,6 +120,9 @@ class RDoc::Markup::Formatter
end
end
##
# Turns off tags for +item+ on +res+
def off_tags res, item
attr_mask = item.turn_off
return if attr_mask.zero?

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

@ -4,14 +4,57 @@ require 'rdoc/markup/formatter'
##
# Test case for creating new RDoc::Markup formatters. See
# test/test_rdoc_markup_to_*.rb for examples.
#
# This test case adds a variety of tests to your subclass when
# #add_visitor_tests is called. Most tests set up a scenario then call a
# method you will provide to perform the assertion on the output.
#
# Your subclass must instantiate a visitor and assign it to <tt>@to</tt>.
#
# For example, test_accept_blank_line sets up a RDoc::Markup::BlockLine then
# calls accept_blank_line on your visitor. You are responsible for asserting
# that the output is correct.
#
# Example:
#
# class TestRDocMarkupToNewFormat < RDoc::Markup::FormatterTestCase
#
# add_visitor_tests
#
# def setup
# super
#
# @to = RDoc::Markup::ToNewFormat.new
# end
#
# def accept_blank_line
# assert_equal :junk, @to.res.join
# end
#
# # ...
#
# end
class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
##
# Call #setup when inheriting from this test case.
#
# Provides the following instance variables:
#
# +@m+:: RDoc::Markup.new
# +@RM+:: RDoc::Markup # to reduce typing
# +@bullet_list+:: @RM::List.new :BULLET, # ...
# +@label_list+:: @RM::List.new :LABEL, # ...
# +@lalpha_list+:: @RM::List.new :LALPHA, # ...
# +@note_list+:: @RM::List.new :NOTE, # ...
# +@number_list+:: @RM::List.new :NUMBER, # ...
# +@ualpha_list+:: @RM::List.new :UALPHA, # ...
def setup
super
@m = RDoc::Markup.new
@am = RDoc::Markup::AttributeManager.new
@RM = RDoc::Markup
@bullet_list = @RM::List.new(:BULLET,
@ -39,14 +82,25 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
@RM::ListItem.new(nil, @RM::Paragraph.new('l2')))
end
##
# Call to add the visitor tests to your test case
def self.add_visitor_tests
self.class_eval do
##
# Calls start_accepting which needs to verify startup state
def test_start_accepting
@to.start_accepting
start_accepting
end
##
# Calls end_accepting on your test case which needs to call
# <tt>@to.end_accepting</tt> and verify document generation
def test_end_accepting
@to.start_accepting
@to.res << 'hi'
@ -54,6 +108,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
end_accepting
end
##
# Calls accept_blank_line
def test_accept_blank_line
@to.start_accepting
@ -62,6 +119,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_blank_line
end
##
# Calls accept_heading with a level 5 RDoc::Markup::Heading
def test_accept_heading
@to.start_accepting
@ -70,6 +130,79 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_heading
end
##
# Calls accept_heading_1 with a level 1 RDoc::Markup::Heading
def test_accept_heading_1
@to.start_accepting
@to.accept_heading @RM::Heading.new(1, 'Hello')
accept_heading_1
end
##
# Calls accept_heading_2 with a level 2 RDoc::Markup::Heading
def test_accept_heading_2
@to.start_accepting
@to.accept_heading @RM::Heading.new(2, 'Hello')
accept_heading_2
end
##
# Calls accept_heading_3 with a level 3 RDoc::Markup::Heading
def test_accept_heading_3
# HACK this doesn't belong here
skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars
@to.start_accepting
@to.accept_heading @RM::Heading.new(3, 'Hello')
accept_heading_3
end
##
# Calls accept_heading_4 with a level 4 RDoc::Markup::Heading
def test_accept_heading_4
@to.start_accepting
@to.accept_heading @RM::Heading.new(4, 'Hello')
accept_heading_4
end
##
# Calls accept_heading_b with a bold level 1 RDoc::Markup::Heading
def test_accept_heading_b
@to.start_accepting
@to.accept_heading @RM::Heading.new(1, '*Hello*')
accept_heading_b
end
##
# Calls accept_heading_suppressed_crossref with a level 1
# RDoc::Markup::Heading containing a suppressed crossref
def test_accept_heading_suppressed_crossref # HACK to_html_crossref test
@to.start_accepting
@to.accept_heading @RM::Heading.new(1, '\\Hello')
accept_heading_suppressed_crossref
end
##
# Calls accept_paragraph
def test_accept_paragraph
@to.start_accepting
@ -78,15 +211,80 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_paragraph
end
##
# Calls accept_paragraph_b with a RDoc::Markup::Paragraph containing
# bold words
def test_accept_paragraph_b
@to.start_accepting
@to.accept_paragraph @RM::Paragraph.new('reg <b>bold words</b> reg')
accept_paragraph_b
end
##
# Calls accept_paragraph_i with a RDoc::Markup::Paragraph containing
# emphasized words
def test_accept_paragraph_i
@to.start_accepting
@to.accept_paragraph @RM::Paragraph.new('reg <em>italic words</em> reg')
accept_paragraph_i
end
##
# Calls accept_paragraph_plus with a RDoc::Markup::Paragraph containing
# teletype words
def test_accept_paragraph_plus
@to.start_accepting
@to.accept_paragraph @RM::Paragraph.new('reg +teletype+ reg')
accept_paragraph_plus
end
##
# Calls accept_paragraph_star with a RDoc::Markup::Paragraph containing
# bold words
def test_accept_paragraph_star
@to.start_accepting
@to.accept_paragraph @RM::Paragraph.new('reg *bold* reg')
accept_paragraph_star
end
##
# Calls accept_paragraph_underscore with a RDoc::Markup::Paragraph
# containing emphasized words
def test_accept_paragraph_underscore
@to.start_accepting
@to.accept_paragraph @RM::Paragraph.new('reg _italic_ reg')
accept_paragraph_underscore
end
##
# Calls accept_verbatim with a RDoc::Markup::Verbatim
def test_accept_verbatim
@to.start_accepting
@to.accept_verbatim @RM::Verbatim.new(' ', 'hi', "\n",
' ', 'world', "\n")
@to.accept_verbatim @RM::Verbatim.new("hi\n", " world\n")
accept_verbatim
end
##
# Calls accept_raw with a RDoc::Markup::Raw
def test_accept_raw
@to.start_accepting
@ -99,6 +297,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_raw
end
##
# Calls accept_rule with a RDoc::Markup::Rule
def test_accept_rule
@to.start_accepting
@ -107,6 +308,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_rule
end
##
# Calls accept_list_item_start_bullet
def test_accept_list_item_start_bullet
@to.start_accepting
@ -117,6 +321,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_list_item_start_bullet
end
##
# Calls accept_list_item_start_label
def test_accept_list_item_start_label
@to.start_accepting
@ -127,6 +334,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_list_item_start_label
end
##
# Calls accept_list_item_start_lalpha
def test_accept_list_item_start_lalpha
@to.start_accepting
@ -137,6 +347,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_list_item_start_lalpha
end
##
# Calls accept_list_item_start_note
def test_accept_list_item_start_note
@to.start_accepting
@ -147,6 +360,26 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_list_item_start_note
end
##
# Calls accept_list_item_start_note_2
def test_accept_list_item_start_note_2
list = @RM::List.new(:NOTE,
@RM::ListItem.new('<tt>teletype</tt>',
@RM::Paragraph.new('teletype description')))
@to.start_accepting
list.accept @to
@to.end_accepting
accept_list_item_start_note_2
end
##
# Calls accept_list_item_start_number
def test_accept_list_item_start_number
@to.start_accepting
@ -157,6 +390,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_list_item_start_number
end
##
# Calls accept_list_item_start_ualpha
def test_accept_list_item_start_ualpha
@to.start_accepting
@ -167,6 +403,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_list_item_start_ualpha
end
##
# Calls accept_list_item_end_bullet
def test_accept_list_item_end_bullet
@to.start_accepting
@ -179,6 +418,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_list_item_end_bullet
end
##
# Calls accept_list_item_end_label
def test_accept_list_item_end_label
@to.start_accepting
@ -191,6 +433,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_list_item_end_label
end
##
# Calls accept_list_item_end_lalpha
def test_accept_list_item_end_lalpha
@to.start_accepting
@ -203,6 +448,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_list_item_end_lalpha
end
##
# Calls accept_list_item_end_note
def test_accept_list_item_end_note
@to.start_accepting
@ -215,6 +463,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_list_item_end_note
end
##
# Calls accept_list_item_end_number
def test_accept_list_item_end_number
@to.start_accepting
@ -227,6 +478,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_list_item_end_number
end
##
# Calls accept_list_item_end_ualpha
def test_accept_list_item_end_ualpha
@to.start_accepting
@ -239,6 +493,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_list_item_end_ualpha
end
##
# Calls accept_list_start_bullet
def test_accept_list_start_bullet
@to.start_accepting
@ -247,6 +504,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_list_start_bullet
end
##
# Calls accept_list_start_label
def test_accept_list_start_label
@to.start_accepting
@ -255,6 +515,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_list_start_label
end
##
# Calls accept_list_start_lalpha
def test_accept_list_start_lalpha
@to.start_accepting
@ -263,6 +526,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_list_start_lalpha
end
##
# Calls accept_list_start_note
def test_accept_list_start_note
@to.start_accepting
@ -271,6 +537,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_list_start_note
end
##
# Calls accept_list_start_number
def test_accept_list_start_number
@to.start_accepting
@ -279,6 +548,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_list_start_number
end
##
# Calls accept_list_start_ualpha
def test_accept_list_start_ualpha
@to.start_accepting
@ -287,6 +559,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_list_start_ualpha
end
##
# Calls accept_list_end_bullet
def test_accept_list_end_bullet
@to.start_accepting
@ -297,6 +572,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_list_end_bullet
end
##
# Calls accept_list_end_label
def test_accept_list_end_label
@to.start_accepting
@ -307,6 +585,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_list_end_label
end
##
# Calls accept_list_end_lalpha
def test_accept_list_end_lalpha
@to.start_accepting
@ -317,6 +598,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_list_end_lalpha
end
##
# Calls accept_list_end_number
def test_accept_list_end_number
@to.start_accepting
@ -327,6 +611,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_list_end_number
end
##
# Calls accept_list_end_note
def test_accept_list_end_note
@to.start_accepting
@ -337,6 +624,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_list_end_note
end
##
# Calls accept_list_end_ulpha
def test_accept_list_end_ualpha
@to.start_accepting
@ -346,6 +636,52 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
accept_list_end_ualpha
end
##
# Calls list_nested with a two-level list
def test_list_nested
doc = @RM::Document.new(
@RM::List.new(:BULLET,
@RM::ListItem.new(nil,
@RM::Paragraph.new('l1'),
@RM::List.new(:BULLET,
@RM::ListItem.new(nil,
@RM::Paragraph.new('l1.1')))),
@RM::ListItem.new(nil,
@RM::Paragraph.new('l2'))))
doc.accept @to
list_nested
end
##
# Calls list_verbatim with a list containing a verbatim block
def test_list_verbatim # HACK overblown
doc = @RM::Document.new(
@RM::List.new(:BULLET,
@RM::ListItem.new(nil,
@RM::Paragraph.new('list', 'stuff'),
@RM::BlankLine.new,
@RM::Verbatim.new("* list\n",
" with\n",
"\n",
" second\n",
"\n",
" 1. indented\n",
" 2. numbered\n",
"\n",
" third\n",
"\n",
"* second\n"))))
doc.accept @to
list_verbatim
end
end
end

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

@ -3,6 +3,9 @@
class RDoc::Markup::Heading < Struct.new :level, :text
##
# Calls #accept_heading on +wisitor+
def accept visitor
visitor.accept_heading self
end

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

@ -1,3 +1,4 @@
require 'rdoc'
class RDoc::Markup
##
@ -14,6 +15,9 @@ class RDoc::Markup
@@name_to_bitmap = { :_SPECIAL_ => SPECIAL }
@@next_bitmap = 2
##
# Returns a unique bit for +name+
def self.bitmap_for(name)
bitmap = @@name_to_bitmap[name]
unless bitmap then
@ -24,6 +28,9 @@ class RDoc::Markup
bitmap
end
##
# Returns a string reperesentation of +bitmap+
def self.as_string(bitmap)
return "none" if bitmap.zero?
res = []
@ -33,6 +40,9 @@ class RDoc::Markup
res.join(",")
end
##
# yields each attribute name in +bitmap+
def self.each_name_of(bitmap)
@@name_to_bitmap.each do |name, bit|
next if bit == SPECIAL
@ -75,7 +85,7 @@ class RDoc::Markup
end
##
# Acccesses flags for character +n+
# Accesses flags for character +n+
def [](n)
@attrs[n]

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

@ -35,6 +35,9 @@ class RDoc::Markup::List
@items == other.items
end
##
# Runs this list and all its #items through +visitor+
def accept visitor
visitor.accept_list_start self

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

@ -35,6 +35,9 @@ class RDoc::Markup::ListItem
@parts == other.parts
end
##
# Runs this list item and all its #parts through +visitor+
def accept visitor
visitor.accept_list_item_start self

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

@ -3,6 +3,9 @@
class RDoc::Markup::Paragraph < RDoc::Markup::Raw
##
# Calls #accept_paragraph on +visitor+
def accept visitor
visitor.accept_paragraph self
end

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

@ -52,13 +52,13 @@ class RDoc::Markup::Parser
attr_reader :tokens
##
# Parsers +str+ into a Document
# Parses +str+ into a Document
def self.parse str
parser = new
#parser.debug = true
parser.tokenize str
RDoc::Markup::Document.new(*parser.parse)
doc = RDoc::Markup::Document.new
parser.parse doc
end
##
@ -86,6 +86,7 @@ class RDoc::Markup::Parser
# Builds a Heading of +level+
def build_heading level
_, text, = get # TEXT
heading = RDoc::Markup::Heading.new level, text
skip :NEWLINE
@ -105,38 +106,69 @@ class RDoc::Markup::Parser
case type
when :BULLET, :LABEL, :LALPHA, :NOTE, :NUMBER, :UALPHA then
list_type = type
if column < margin then
if column < margin || (list.type && list.type != type) then
unget
break
end
if list.type and list.type != list_type then
unget
break
end
list.type = list_type
list.type = type
peek_type, _, column, = peek_token
case type
when :NOTE, :LABEL then
_, indent, = get # SPACE
if :NEWLINE == peek_token.first then
get
peek_type, new_indent, peek_column, = peek_token
indent = new_indent if
peek_type == :INDENT and peek_column >= column
unget
if peek_type == :NEWLINE then
# description not on the same line as LABEL/NOTE
# skip the trailing newline & any blank lines below
while peek_type == :NEWLINE
get
peek_type, _, column, = peek_token
end
# we may be:
# - at end of stream
# - at a column < margin:
# [text]
# blah blah blah
# - at the same column, but with a different type of list item
# [text]
# * blah blah
# - at the same column, with the same type of list item
# [one]
# [two]
# In all cases, we have an empty description.
# In the last case only, we continue.
if peek_type.nil? || column < margin then
empty = 1
elsif column == margin then
case peek_type
when type
empty = 2 # continue
when *LIST_TOKENS
empty = 1
else
empty = 0
end
else
empty = 0
end
if empty > 0 then
item = RDoc::Markup::ListItem.new(data)
item << RDoc::Markup::BlankLine.new
list << item
break if empty == 1
next
end
end
else
data = nil
_, indent, = get
end
list_item = build_list_item(margin + indent, data)
list_item = RDoc::Markup::ListItem.new data
parse list_item, column
list << list_item
list << list_item if list_item
else
unget
break
@ -150,54 +182,6 @@ class RDoc::Markup::Parser
list
end
##
# Builds a ListItem that is flush to +indent+ with type +item_type+
def build_list_item indent, item_type = nil
p :list_item_start => [indent, item_type] if @debug
list_item = RDoc::Markup::ListItem.new item_type
until @tokens.empty? do
type, data, column = get
if column < indent and
not type == :NEWLINE and
(type != :INDENT or data < indent) then
unget
break
end
case type
when :INDENT then
unget
list_item.push(*parse(indent))
when :TEXT then
unget
list_item << build_paragraph(indent)
when :HEADER then
list_item << build_heading(data)
when :NEWLINE then
list_item << RDoc::Markup::BlankLine.new
when *LIST_TOKENS then
unget
list_item << build_list(column)
else
raise ParseError, "Unhandled token #{@current_token.inspect}"
end
end
p :list_item_end => [indent, item_type] if @debug
return nil if list_item.empty?
list_item.parts.shift if
RDoc::Markup::BlankLine === list_item.parts.first and
list_item.length > 1
list_item
end
##
# Builds a Paragraph that is flush to +margin+
@ -209,18 +193,7 @@ class RDoc::Markup::Parser
until @tokens.empty? do
type, data, column, = get
case type
when :INDENT then
next if data == margin and peek_token[0] == :TEXT
unget
break
when :TEXT then
if column != margin then
unget
break
end
if type == :TEXT && column == margin then
paragraph << data
skip :NEWLINE
else
@ -235,67 +208,81 @@ class RDoc::Markup::Parser
end
##
# Builds a Verbatim that is flush to +margin+
# Builds a Verbatim that is indented from +margin+.
#
# The verbatim block is shifted left (the least indented lines start in
# column 0). Each part of the verbatim is one line of text, always
# terminated by a newline. Blank lines always consist of a single newline
# character, and there is never a single newline at the end of the verbatim.
def build_verbatim margin
p :verbatim_begin => margin if @debug
verbatim = RDoc::Markup::Verbatim.new
min_indent = nil
generate_leading_spaces = true
line = ''
until @tokens.empty? do
type, data, column, = get
case type
when :INDENT then
if margin >= data then
unget
break
end
if type == :NEWLINE then
line << data
verbatim << line
line = ''
generate_leading_spaces = true
next
end
indent = data - margin
verbatim << ' ' * indent
when :HEADER then
verbatim << '=' * data
_, _, peek_column, = peek_token
peek_column ||= column + data
verbatim << ' ' * (peek_column - column - data)
when :RULE then
width = 2 + data
verbatim << '-' * width
_, _, peek_column, = peek_token
peek_column ||= column + data + 2
verbatim << ' ' * (peek_column - column - width)
when :TEXT then
verbatim << data
when *LIST_TOKENS then
if column <= margin then
unget
break
end
list_marker = case type
when :BULLET then '*'
when :LABEL then "[#{data}]"
when :LALPHA, :NUMBER, :UALPHA then "#{data}."
when :NOTE then "#{data}::"
end
verbatim << list_marker
_, data, = get
verbatim << ' ' * (data - list_marker.length)
when :NEWLINE then
verbatim << data
break unless [:INDENT, :NEWLINE].include? peek_token[0]
else
if column <= margin
unget
break
end
if generate_leading_spaces then
indent = column - margin
line << ' ' * indent
min_indent = indent if min_indent.nil? || indent < min_indent
generate_leading_spaces = false
end
case type
when :HEADER then
line << '=' * data
_, _, peek_column, = peek_token
peek_column ||= column + data
indent = peek_column - column - data
line << ' ' * indent
when :RULE then
width = 2 + data
line << '-' * width
_, _, peek_column, = peek_token
peek_column ||= column + width
indent = peek_column - column - width
line << ' ' * indent
when :TEXT then
line << data
else # *LIST_TOKENS
list_marker = case type
when :BULLET then data
when :LABEL then "[#{data}]"
when :NOTE then "#{data}::"
else # :LALPHA, :NUMBER, :UALPHA
"#{data}."
end
line << list_marker
peek_type, _, peek_column = peek_token
unless peek_type == :NEWLINE then
peek_column ||= column + list_marker.length
indent = peek_column - column - list_marker.length
line << ' ' * indent
end
end
end
verbatim << line << "\n" unless line.empty?
verbatim.parts.each { |p| p.slice!(0, min_indent) unless p == "\n" } if min_indent > 0
verbatim.normalize
p :verbatim_end => margin if @debug
@ -313,65 +300,60 @@ class RDoc::Markup::Parser
end
##
# Parses the tokens into a Document
# Parses the tokens into an array of RDoc::Markup::XXX objects,
# and appends them to the passed +parent+ RDoc::Markup::YYY object.
#
# Exits at the end of the token stream, or when it encounters a token
# in a column less than +indent+ (unless it is a NEWLINE).
#
# Returns +parent+.
def parse indent = 0
def parse parent, indent = 0
p :parse_start => indent if @debug
document = []
until @tokens.empty? do
type, data, column, = get
if type != :INDENT and column < indent then
unget
break
if type == :NEWLINE then
# trailing newlines are skipped below, so this is a blank line
parent << RDoc::Markup::BlankLine.new
skip :NEWLINE, false
next
end
# indentation change: break or verbattim
if column < indent then
unget
break
elsif column > indent then
unget
parent << build_verbatim(indent)
next
end
# indentation is the same
case type
when :HEADER then
document << build_heading(data)
when :INDENT then
if indent > data then
unget
break
elsif indent == data then
next
end
unget
document << build_verbatim(indent)
when :NEWLINE then
document << RDoc::Markup::BlankLine.new
skip :NEWLINE, false
parent << build_heading(data)
when :RULE then
document << RDoc::Markup::Rule.new(data)
parent << RDoc::Markup::Rule.new(data)
skip :NEWLINE
when :TEXT then
unget
document << build_paragraph(indent)
# we're done with this paragraph (indent mismatch)
break if peek_token[0] == :TEXT
parent << build_paragraph(indent)
when *LIST_TOKENS then
unget
list = build_list(indent)
document << list if list
# we're done with this list (indent mismatch)
break if LIST_TOKENS.include? peek_token.first and indent > 0
parent << build_list(indent)
else
type, data, column, line = @current_token
raise ParseError,
"Unhandled token #{type} (#{data.inspect}) at #{line}:#{column}"
raise ParseError, "Unhandled token #{type} (#{data.inspect}) at #{line}:#{column}"
end
end
p :parse_end => indent if @debug
document
parent
end
##
@ -384,63 +366,16 @@ class RDoc::Markup::Parser
end
##
# Skips a token of +token_type+, optionally raising an error.
# Skips the next token if its type is +token_type+.
#
# Optionally raises an error if the next token is not of the expected type.
def skip token_type, error = true
type, = get
return unless type # end of stream
return @current_token if token_type == type
unget
raise ParseError, "expected #{token_type} got #{@current_token.inspect}" if
error
end
##
# Consumes tokens until NEWLINE and turns them back into text
def text
text = ''
loop do
type, data, = get
text << case type
when :BULLET then
_, space, = get # SPACE
"*#{' ' * (space - 1)}"
when :LABEL then
_, space, = get # SPACE
"[#{data}]#{' ' * (space - data.length - 2)}"
when :LALPHA, :NUMBER, :UALPHA then
_, space, = get # SPACE
"#{data}.#{' ' * (space - 2)}"
when :NOTE then
_, space = get # SPACE
"#{data}::#{' ' * (space - data.length - 2)}"
when :TEXT then
data
when :NEWLINE then
unget
break
when nil then
break
else
raise ParseError, "unhandled token #{@current_token.inspect}"
end
end
text
end
##
# Calculates the column and line of the current token based on +offset+.
def token_pos offset
[offset - @line_pos, @line]
raise ParseError, "expected #{token_type} got #{@current_token.inspect}" if error
end
##
@ -455,51 +390,62 @@ class RDoc::Markup::Parser
until s.eos? do
pos = s.pos
# leading spaces will be reflected by the column of the next token
# the only thing we loose are trailing spaces at the end of the file
next if s.scan(/ +/)
# note: after BULLET, LABEL, etc.,
# indent will be the column of the next non-newline token
@tokens << case
# [CR]LF => :NEWLINE
when s.scan(/\r?\n/) then
token = [:NEWLINE, s.matched, *token_pos(pos)]
@line_pos = s.pos
@line += 1
token
when s.scan(/ +/) then
[:INDENT, s.matched_size, *token_pos(pos)]
# === text => :HEADER then :TEXT
when s.scan(/(=+)\s*/) then
level = s[1].length
level = 6 if level > 6
@tokens << [:HEADER, level, *token_pos(pos)]
pos = s.pos
s.scan(/.*/)
[:TEXT, s.matched, *token_pos(pos)]
when s.scan(/^(-{3,}) *$/) then
[:TEXT, s.matched.sub(/\r$/, ''), *token_pos(pos)]
# --- (at least 3) and nothing else on the line => :RULE
when s.scan(/(-{3,}) *$/) then
[:RULE, s[1].length - 2, *token_pos(pos)]
when s.scan(/([*-])\s+/) then
@tokens << [:BULLET, :BULLET, *token_pos(pos)]
[:SPACE, s.matched_size, *token_pos(pos)]
when s.scan(/([a-z]|\d+)\.[ \t]+\S/i) then
# * or - followed by white space and text => :BULLET
when s.scan(/([*-]) +(\S)/) then
s.pos -= s[2].bytesize # unget \S
[:BULLET, s[1], *token_pos(pos)]
# A. text, a. text, 12. text => :UALPHA, :LALPHA, :NUMBER
when s.scan(/([a-z]|\d+)\. +(\S)/i) then
# FIXME if tab(s), the column will be wrong
# either support tabs everywhere by first expanding them to
# spaces, or assume that they will have been replaced
# before (and provide a check for that at least in debug
# mode)
list_label = s[1]
width = s.matched_size - 1
s.pos -= 1 # unget \S
list_type = case list_label
when /[a-z]/ then :LALPHA
when /[A-Z]/ then :UALPHA
when /\d/ then :NUMBER
else
raise ParseError, "BUG token #{list_label}"
end
@tokens << [list_type, list_label, *token_pos(pos)]
[:SPACE, width, *token_pos(pos)]
s.pos -= s[2].bytesize # unget \S
list_type =
case list_label
when /[a-z]/ then :LALPHA
when /[A-Z]/ then :UALPHA
when /\d/ then :NUMBER
else
raise ParseError, "BUG token #{list_label}"
end
[list_type, list_label, *token_pos(pos)]
# [text] followed by spaces or end of line => :LABEL
when s.scan(/\[(.*?)\]( +|$)/) then
@tokens << [:LABEL, s[1], *token_pos(pos)]
[:SPACE, s.matched_size, *token_pos(pos)]
[:LABEL, s[1], *token_pos(pos)]
# text:: followed by spaces or end of line => :NOTE
when s.scan(/(.*?)::( +|$)/) then
@tokens << [:NOTE, s[1], *token_pos(pos)]
[:SPACE, s.matched_size, *token_pos(pos)]
[:NOTE, s[1], *token_pos(pos)]
# anything else: :TEXT
else s.scan(/.*/)
[:TEXT, s.matched, *token_pos(pos)]
[:TEXT, s.matched.sub(/\r$/, ''), *token_pos(pos)]
end
end
@ -507,9 +453,17 @@ class RDoc::Markup::Parser
end
##
# Returns the current token or +token+ to the token stream
# Calculates the column and line of the current token based on +offset+.
def unget token = @current_token
def token_pos offset
[offset - @line_pos, @line]
end
##
# Returns the current token to the token stream
def unget
token = @current_token
p :unget => token if @debug
raise Error, 'too many #ungets' if token == @tokens.first
@tokens.unshift token if token

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

@ -1,12 +1,15 @@
require 'rdoc/markup'
require 'rdoc/encoding'
##
# Handle common directives that can occur in a block of text:
#
# : include : filename
# \:include: filename
#
# RDoc plugin authors can register additional directives to be handled through
# RDoc::Markup::PreProcess::register
# Directives can be escaped by preceding them with a backslash.
#
# RDoc plugin authors can register additional directives to be handled by
# using RDoc::Markup::PreProcess::register
class RDoc::Markup::PreProcess
@ -52,18 +55,25 @@ class RDoc::Markup::PreProcess
# +code_object+. See RDoc::CodeObject#metadata
def handle text, code_object = nil
text.gsub!(/^([ \t]*#?[ \t]*):(\w+):([ \t]*)(.+)?\n/) do
next $& if $3.empty? and $4 and $4[0, 1] == ':'
# regexp helper (square brackets for optional)
# $1 $2 $3 $4 $5
# [prefix][\]:directive:[spaces][param]newline
text.gsub!(/^([ \t]*#?[ \t]*)(\\?):(\w+):([ \t]*)(.+)?\n/) do
# skip something like ':toto::'
next $& if $4.empty? and $5 and $5[0, 1] == ':'
# skip if escaped
next "#$1:#$3:#$4#$5\n" unless $2.empty?
prefix = $1
directive = $2.downcase
param = $4
directive = $3.downcase
param = $5
case directive
when 'include' then
filename = param.split[0]
include_file filename, prefix
encoding = if defined?(Encoding) then text.encoding else nil end
include_file filename, prefix, encoding
else
result = yield directive, param if block_given?
@ -88,27 +98,38 @@ class RDoc::Markup::PreProcess
end
##
# Include a file, indenting it correctly.
# Handles the <tt>:include: _filename_</tt> directive.
#
# If the first line of the included file starts with '#', and contains
# an encoding information in the form 'coding:' or 'coding=', it is
# removed.
#
# If all lines in the included file start with a '#', this leading '#'
# is removed before inclusion. The included content is indented like
# the <tt>:include:</tt> directive.
#--
# so all content will be verbatim because of the likely space after '#'?
# TODO shift left the whole file content in that case
# TODO comment stop/start #-- and #++ in included file must be processed here
def include_file(name, indent)
if full_name = find_include_file(name) then
content = if defined?(Encoding) then
File.binread full_name
else
File.read full_name
end
# HACK determine content type and force encoding
content = content.sub(/\A# .*coding[=:].*$/, '').lstrip
def include_file name, indent, encoding
full_name = find_include_file name
# strip leading '#'s, but only if all lines start with them
if content =~ /^[^#]/ then
content.gsub(/^/, indent)
else
content.gsub(/^#?/, indent)
end
else
unless full_name then
warn "Couldn't find file to include '#{name}' from #{@input_file_name}"
''
return ''
end
content = RDoc::Encoding.read_file full_name, encoding
# strip magic comment
content = content.sub(/\A# .*coding[=:].*$/, '').lstrip
# strip leading '#'s, but only if all lines start with them
if content =~ /^[^#]/ then
content.gsub(/^/, indent)
else
content.gsub(/^#?/, indent)
end
end

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

@ -27,6 +27,9 @@ class RDoc::Markup::Raw
self.class == other.class and text == other.text
end
##
# Calls #accept_raw+ on +visitor+
def accept visitor
visitor.accept_raw self
end
@ -63,3 +66,4 @@ class RDoc::Markup::Raw
end
end

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

@ -3,6 +3,9 @@
class RDoc::Markup::Rule < Struct.new :weight
##
# Calls #accept_rule on +visitor+
def accept visitor
visitor.accept_rule self
end

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

@ -0,0 +1,116 @@
require 'rdoc/markup/formatter_test_case'
##
# Test case for creating new plain-text RDoc::Markup formatters. See also
# RDoc::Markup::FormatterTestCase
#
# See test_rdoc_markup_to_rdoc.rb for a complete example.
#
# Example:
#
# class TestRDocMarkupToNewTextFormat < RDoc::Markup::TextFormatterTestCase
#
# add_visitor_tests
# add_text_tests
#
# def setup
# super
#
# @to = RDoc::Markup::ToNewTextFormat.new
# end
#
# def accept_blank_line
# assert_equal :junk, @to.res.join
# end
#
# # ...
#
# end
class RDoc::Markup::TextFormatterTestCase < RDoc::Markup::FormatterTestCase
##
# Adds test cases to the calling TestCase.
def self.add_text_tests
self.class_eval do
##
# Test case that calls <tt>@to.accept_heading</tt>
def test_accept_heading_indent
@to.start_accepting
@to.indent = 3
@to.accept_heading @RM::Heading.new(1, 'Hello')
accept_heading_indent
end
##
# Test case that calls <tt>@to.accept_rule</tt>
def test_accept_rule_indent
@to.start_accepting
@to.indent = 3
@to.accept_rule @RM::Rule.new(1)
accept_rule_indent
end
##
# Test case that calls <tt>@to.accept_verbatim</tt>
def test_accept_verbatim_indent
@to.start_accepting
@to.indent = 2
@to.accept_verbatim @RM::Verbatim.new("hi\n", " world\n")
accept_verbatim_indent
end
##
# Test case that calls <tt>@to.accept_verbatim</tt> with a big indent
def test_accept_verbatim_big_indent
@to.start_accepting
@to.indent = 2
@to.accept_verbatim @RM::Verbatim.new("hi\n", "world\n")
accept_verbatim_big_indent
end
##
# Test case that calls <tt>@to.accept_paragraph</tt> with an indent
def test_accept_paragraph_indent
@to.start_accepting
@to.indent = 3
@to.accept_paragraph @RM::Paragraph.new(('words ' * 30).strip)
accept_paragraph_indent
end
##
# Test case that calls <tt>@to.accept_paragraph</tt> with a long line
def test_accept_paragraph_wrap
@to.start_accepting
@to.accept_paragraph @RM::Paragraph.new(('words ' * 30).strip)
accept_paragraph_wrap
end
##
# Test case that calls <tt>@to.attributes</tt> with an escaped
# cross-reference. If this test doesn't pass something may be very
# wrong.
def test_attributes
assert_equal 'Dog', @to.attributes("\\Dog")
end
end
end
end

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

@ -1,10 +1,13 @@
require 'rdoc/markup/inline'
require 'rdoc/markup/to_rdoc'
##
# Outputs RDoc markup with vibrant ANSI color!
class RDoc::Markup::ToAnsi < RDoc::Markup::ToRdoc
##
# Creates a new ToAnsi visitor that is ready to output vibrant ANSI color!
def initialize
super
@ -23,12 +26,15 @@ class RDoc::Markup::ToAnsi < RDoc::Markup::ToRdoc
add_tag :EM, "\e[4m", "\e[m"
end
##
# Overrides indent width to ensure output lines up correctly.
def accept_list_item_end list_item
width = case @list_type.last
when :BULLET then
2
when :NOTE, :LABEL then
@res << "\n"
@res << "\n" unless res.length == 1
2
else
bullet = @list_index.last.to_s
@ -39,6 +45,9 @@ class RDoc::Markup::ToAnsi < RDoc::Markup::ToRdoc
@indent -= width
end
##
# Adds coloring to note and label list items
def accept_list_item_start list_item
bullet = case @list_type.last
when :BULLET then
@ -62,6 +71,9 @@ class RDoc::Markup::ToAnsi < RDoc::Markup::ToRdoc
end
end
##
# Starts accepting with a reset screen
def start_accepting
super

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

@ -1,4 +1,4 @@
require 'rdoc/markup/inline'
require 'rdoc/markup/to_rdoc'
##
# Outputs RDoc markup with hot backspace action! You will probably need a
@ -8,6 +8,9 @@ require 'rdoc/markup/inline'
class RDoc::Markup::ToBs < RDoc::Markup::ToRdoc
##
# Returns a new ToBs that is ready for hot backspace action!
def initialize
super
@ -22,8 +25,12 @@ class RDoc::Markup::ToBs < RDoc::Markup::ToRdoc
def init_tags
add_tag :BOLD, '+b', '-b'
add_tag :EM, '+_', '-_'
add_tag :TT, '' , '' # we need in_tt information maintained
end
##
# Makes heading text bold.
def accept_heading heading
use_prefix or @res << ' ' * @indent
@res << @headings[heading.level][0]
@ -44,7 +51,6 @@ class RDoc::Markup::ToBs < RDoc::Markup::ToRdoc
when '+_' then @in_em = true
when '-_' then @in_em = false
end
''
end

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

@ -8,6 +8,8 @@ require 'cgi'
class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
include RDoc::Text
##
# Maps RDoc::Markup::Parser::LIST_TOKENS types to HTML tags
@ -15,7 +17,7 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
:BULLET => ['<ul>', '</ul>'],
:LABEL => ['<dl>', '</dl>'],
:LALPHA => ['<ol style="display: lower-alpha">', '</ol>'],
:NOTE => ['<table>', '</table>'],
:NOTE => ['<table class="rdoc-list">', '</table>'],
:NUMBER => ['<ol>', '</ol>'],
:UALPHA => ['<ol style="display: upper-alpha">', '</ol>'],
}
@ -48,6 +50,9 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
File.join(*from)
end
##
# Creates a new formatter that will output HTML
def initialize
super
@ -103,13 +108,15 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
end
end
# :section: Special handling
##
# And we're invoked with a potential external hyperlink mailto:
# just gets inserted. http: links are checked to see if they
# And we're invoked with a potential external hyperlink. <tt>mailto:</tt>
# just gets inserted. <tt>http:</tt> links are checked to see if they
# reference an image. If so, that image gets inserted using an
# <img> tag. Otherwise a conventional <a href> is used. We also
# support a special type of hyperlink, link:, which is a reference
# to a local file whose path is relative to the --op directory.
# <tt><img></tt> tag. Otherwise a conventional <tt><a href></tt> is used.
# We also support a special type of hyperlink, <tt>link:</tt>, which is a
# reference to a local file whose path is relative to the --op directory.
def handle_special_HYPERLINK(special)
url = special.text
@ -118,7 +125,7 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
##
# Here's a hypedlink where the label is different to the URL
# <label>[url] or {long label}[url]
# <label>[url] or {long label}[url]
def handle_special_TIDYLINK(special)
text = special.text
@ -130,8 +137,10 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
gen_url url, label
end
# :section: Utilities
##
# This is a higher speed (if messier) version of wrap
# Wraps +txt+ to +line_len+
def wrap(txt, line_len = 76)
res = []
@ -159,173 +168,150 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
sp += 1 while sp < ep and txt[sp] == ?\s
end
res.join
res.join.strip
end
##
# :section: Visitor
##
# Prepares the visitor for HTML generation
def start_accepting
@res = []
@in_list_entry = []
@list = []
end
##
# Returns the generated output
def end_accepting
@res.join
end
##
# Adds +paragraph+ to the output
def accept_paragraph(paragraph)
@res << annotate("<p>") + "\n"
@res << wrap(convert_flow(@am.flow(paragraph.text)))
@res << annotate("</p>") + "\n"
@res << "\n<p>"
@res << wrap(to_html(paragraph.text))
@res << "</p>\n"
end
##
# Adds +verbatim+ to the output
def accept_verbatim(verbatim)
@res << annotate("<pre>") << "\n"
@res << CGI.escapeHTML(verbatim.text)
@res << annotate("</pre>") << "\n"
@res << "\n<pre>"
@res << CGI.escapeHTML(verbatim.text.rstrip)
@res << "</pre>\n"
end
##
# Adds +rule+ to the output
def accept_rule(rule)
size = rule.weight
size = 10 if size > 10
@res << "<hr style=\"height: #{size}px\"></hr>"
@res << "<hr style=\"height: #{size}px\">\n"
end
##
# Prepares the visitor for consuming +list+
def accept_list_start(list)
@list << list.type
@res << html_list_name(list.type, true) << "\n"
@res << html_list_name(list.type, true)
@in_list_entry.push false
end
##
# Finishes consumption of +list+
def accept_list_end(list)
@list.pop
if tag = @in_list_entry.pop
@res << annotate(tag) << "\n"
@res << tag
end
@res << html_list_name(list.type, false) << "\n"
end
##
# Prepares the visitor for consuming +list_item+
def accept_list_item_start(list_item)
if tag = @in_list_entry.last
@res << annotate(tag) << "\n"
@res << tag
end
@res << list_item_start(list_item, @list.last)
end
##
# Finishes consumption of +list_item+
def accept_list_item_end(list_item)
@in_list_entry[-1] = list_end_for(@list.last)
end
##
# Adds +blank_line+ to the output
def accept_blank_line(blank_line)
# @res << annotate("<p />") << "\n"
end
##
# Adds +heading+ to the output
def accept_heading(heading)
@res << convert_heading(heading.level, @am.flow(heading.text))
@res << "\n<h#{heading.level}>"
@res << to_html(heading.text)
@res << "</h#{heading.level}>\n"
end
##
# Adds +raw+ to the output
def accept_raw raw
@res << raw.parts.join("\n")
end
private
##
# Converts string +item+
# CGI escapes +text+
def convert_string(item)
in_tt? ? convert_string_simple(item) : convert_string_fancy(item)
def convert_string(text)
CGI.escapeHTML text
end
##
# Escapes HTML in +item+
def convert_string_simple(item)
CGI.escapeHTML item
end
##
# Converts ampersand, dashes, elipsis, quotes, copyright and registered
# trademark symbols to HTML escaped Unicode.
def convert_string_fancy(item)
# convert ampersand before doing anything else
item.gsub(/&/, '&amp;').
# 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 registered trademark
gsub(/\(r\)/, '&#174;')
end
##
# Converts headings to hN elements
def convert_heading(level, flow)
[annotate("<h#{level}>"),
convert_flow(flow),
annotate("</h#{level}>\n")].join
end
##
# Determins the HTML list element for +list_type+ and +open_tag+
# Determines the HTML list element for +list_type+ and +open_tag+
def html_list_name(list_type, open_tag)
tags = LIST_TYPE_TO_HTML[list_type]
raise RDoc::Error, "Invalid list type: #{list_type.inspect}" unless tags
annotate tags[open_tag ? 0 : 1]
tags[open_tag ? 0 : 1]
end
##
# Starts a list item
# Returns the HTML tag for +list_type+, possible using a label from
# +list_item+
def list_item_start(list_item, list_type)
case list_type
when :BULLET, :LALPHA, :NUMBER, :UALPHA then
annotate("<li>")
"<li>"
when :LABEL then
annotate("<dt>") +
convert_flow(@am.flow(list_item.label)) +
annotate("</dt>") +
annotate("<dd>")
"<dt>#{to_html list_item.label}</dt>\n<dd>"
when :NOTE then
annotate("<tr>") +
annotate("<td valign=\"top\">") +
convert_flow(@am.flow(list_item.label)) +
annotate("</td>") +
annotate("<td>")
"<tr><td class=\"rdoc-term\"><p>#{to_html list_item.label}</p></td>\n<td>"
else
raise RDoc::Error, "Invalid list type: #{list_type.inspect}"
end
end
##
# Ends a list item
# Returns the HTML end-tag for +list_type+
def list_end_for(list_type)
case list_type
@ -340,5 +326,12 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
end
end
##
# Converts +item+ to HTML using RDoc::Text#to_html
def to_html item
super convert_flow @am.flow item
end
end

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

@ -9,10 +9,10 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
##
# Regular expression to match class references
#
# 1) There can be a '\' in front of text to suppress any cross-references
# 2) There can be a '::' in front of class names to reference from the
# 1. There can be a '\\' in front of text to suppress the cross-reference
# 2. There can be a '::' in front of class names to reference from the
# top-level namespace.
# 3) The method can be followed by parenthesis
# 3. The method can be followed by parenthesis (not recommended)
CLASS_REGEXP_STR = '\\\\?((?:\:{2})?[A-Z]\w*(?:\:\:\w+)*)'
@ -34,10 +34,10 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
# A::B::C.meth
#{CLASS_REGEXP_STR}(?:[.#]|::)#{METHOD_REGEXP_STR}
# Stand-alone method (proceeded by a #)
# Stand-alone method (preceeded by a #)
| \\?\##{METHOD_REGEXP_STR}
# Stand-alone method (proceeded by ::)
# Stand-alone method (preceeded by ::)
| ::#{METHOD_REGEXP_STR}
# A::B::C
@ -51,9 +51,10 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
# In order that words like "can't" not
# be flagged as potential cross-references, only
# flag potential class cross-references if the character
# after the cross-referece is a space or sentence
# punctuation.
| #{CLASS_REGEXP_STR}(?=[\s\)\.\?\!\,\;]|\z)
# after the cross-referece is a space, sentence
# punctuation, tag start character, or attribute
# marker.
| #{CLASS_REGEXP_STR}(?=[\s\)\.\?\!\,\;<\000]|\z)
# Things that look like filenames
# The key thing is that there must be at least
@ -62,7 +63,29 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
| (?:\.\.\/)*[-\/\w]+[_\/\.][-\w\/\.]+
# Things that have markup suppressed
| \\[^\s]
# Don't process things like '\<' in \<tt>, though.
# TODO: including < is a hack, not very satisfying.
| \\[^\s<]
)/x
##
# Version of CROSSREF_REGEXP used when <tt>--hyperlink-all</tt> is specified.
ALL_CROSSREF_REGEXP = /(
# A::B::C.meth
#{CLASS_REGEXP_STR}(?:[.#]|::)#{METHOD_REGEXP_STR}
# Stand-alone method
| \\?#{METHOD_REGEXP_STR}
# A::B::C
| #{CLASS_REGEXP_STR}(?=[\s\)\.\?\!\,\;<\000]|\z)
# Things that look like filenames
| (?:\.\.\/)*[-\/\w]+[_\/\.][-\w\/\.]+
# Things that have markup suppressed
| \\[^\s<]
)/x
##
@ -70,20 +93,29 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
attr_accessor :context
##
# Should we show '#' characters on method references?
attr_accessor :show_hash
##
# Creates a new crossref resolver that generates links relative to +context+
# which lives at +from_path+ in the generated files. '#' characters on
# references are removed unless +show_hash+ is true.
# references are removed unless +show_hash+ is true. Only method names
# preceded by '#' or '::' are hyperlinked, unless +hyperlink_all+ is true.
def initialize(from_path, context, show_hash)
def initialize(from_path, context, show_hash, hyperlink_all = false)
raise ArgumentError, 'from_path cannot be nil' if from_path.nil?
super()
@markup.add_special(CROSSREF_REGEXP, :CROSSREF)
crossref_re = hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP
@markup.add_special crossref_re, :CROSSREF
@from_path = from_path
@context = context
@show_hash = show_hash
@hyperlink_all = hyperlink_all
@seen = {}
end
@ -92,22 +124,24 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
# We're invoked when any text matches the CROSSREF pattern. If we find the
# corresponding reference, generate a hyperlink. If the name we're looking
# for contains no punctuation, we look for it up the module/class chain.
# For example, HyperlinkHtml is found, even without the Generator:: prefix,
# because we look for it in module Generator first.
# For example, ToHtml is found, even without the <tt>RDoc::Markup::</tt>
# prefix, because we look for it in module Markup first.
def handle_special_CROSSREF(special)
name = special.text
# This ensures that words entirely consisting of lowercase letters will
# not have cross-references generated (to suppress lots of erroneous
# cross-references to "new" in text, for instance)
return name if name =~ /\A[a-z]*\z/
unless @hyperlink_all then
# This ensures that words entirely consisting of lowercase letters will
# not have cross-references generated (to suppress lots of erroneous
# cross-references to "new" in text, for instance)
return name if name =~ /\A[a-z]*\z/
end
return @seen[name] if @seen.include? name
lookup = name
name = name[0, 1] unless @show_hash if name[0, 1] == '#'
name = name[1..-1] unless @show_hash if name[0, 1] == '#'
# Find class, module, or method in class or module.
#
@ -120,26 +154,47 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
# whether the string as a whole is a known symbol).
if /#{CLASS_REGEXP_STR}([.#]|::)#{METHOD_REGEXP_STR}/ =~ lookup then
container = $1
type = $2
type = '#' if type == '.'
type = '' if type == '.' # will find either #method or ::method
method = "#{type}#{$3}"
ref = @context.find_symbol container, method
container = @context.find_symbol_module($1)
elsif /^([.#]|::)#{METHOD_REGEXP_STR}/ =~ lookup then
type = $1
type = '' if type == '.'
method = "#{type}#{$2}"
container = @context
else
container = nil
end
if container then
ref = container.find_local_symbol method
unless ref || RDoc::TopLevel === container then
ref = container.find_ancestor_local_symbol method
end
end
ref = @context.find_symbol lookup unless ref
ref = nil if RDoc::Alias === ref # external alias: can't link to it
out = if lookup == '\\' then
lookup
elsif lookup =~ /^\\/ then
$'
elsif ref and ref.document_self then
"<a href=\"#{ref.as_href @from_path}\">#{name}</a>"
# we remove the \ only in front of what we know:
# other backslashes are treated later, only outside of <tt>
ref ? $' : lookup
elsif ref then
if ref.document_self then
"<a href=\"#{ref.as_href @from_path}\">#{name}</a>"
else
name
end
else
name
lookup
end
@seen[name] = out
@seen[lookup] = out
out
end

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

@ -1,3 +1,4 @@
require 'rdoc/markup/formatter'
require 'rdoc/markup/inline'
##
@ -5,21 +6,49 @@ require 'rdoc/markup/inline'
class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
##
# Current indent amount for output in characters
attr_accessor :indent
##
# Output width in characters
attr_accessor :width
##
# Stack of current list indexes for alphabetic and numeric lists
attr_reader :list_index
##
# Stack of list types
attr_reader :list_type
##
# Stack of list widths for indentation
attr_reader :list_width
##
# Prefix for the next list item. See #use_prefix
attr_reader :prefix
##
# Output accumulator
attr_reader :res
##
# Creates a new formatter that will output (mostly) \RDoc markup
def initialize
super
@markup.add_special(/\\[^\s]/, :SUPPRESSED_CROSSREF)
@markup.add_special(/\\\S/, :SUPPRESSED_CROSSREF)
@width = 78
@prefix = ''
init_tags
@headings = {}
@ -34,7 +63,7 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
end
##
# Maps attributes to ANSI sequences
# Maps attributes to HTML sequences
def init_tags
add_tag :BOLD, "<b>", "</b>"
@ -42,10 +71,16 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
add_tag :EM, "<em>", "</em>"
end
##
# Adds +blank_line+ to the output
def accept_blank_line blank_line
@res << "\n"
end
##
# Adds +heading+ to the output
def accept_heading heading
use_prefix or @res << ' ' * @indent
@res << @headings[heading.level][0]
@ -54,12 +89,18 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
@res << "\n"
end
##
# Finishes consumption of +list+
def accept_list_end list
@list_index.pop
@list_type.pop
@list_width.pop
end
##
# Finishes consumption of +list_item+
def accept_list_item_end list_item
width = case @list_type.last
when :BULLET then
@ -76,29 +117,29 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
@indent -= width
end
##
# Prepares the visitor for consuming +list_item+
def accept_list_item_start list_item
bullet = case @list_type.last
when :BULLET then
'*'
when :NOTE, :LABEL then
attributes(list_item.label) + ":\n"
else
@list_index.last.to_s + '.'
end
type = @list_type.last
case @list_type.last
case type
when :NOTE, :LABEL then
bullet = attributes(list_item.label) + ":\n"
@prefix = ' ' * @indent
@indent += 2
@prefix = bullet + (' ' * @indent)
@prefix << bullet + (' ' * @indent)
else
bullet = type == :BULLET ? '*' : @list_index.last.to_s + '.'
@prefix = (' ' * @indent) + bullet.ljust(bullet.length + 1)
width = bullet.length + 1
@indent += width
end
end
##
# Prepares the visitor for consuming +list+
def accept_list_start list
case list.type
when :BULLET then
@ -123,14 +164,23 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
@list_type << list.type
end
##
# Adds +paragraph+ to the output
def accept_paragraph paragraph
wrap attributes(paragraph.text)
end
##
# Adds +raw+ to the output
def accept_raw raw
@res << raw.parts.join("\n")
end
##
# Adds +rule+ to the output
def accept_rule rule
use_prefix or @res << ' ' * @indent
@res << '-' * (@width - @indent)
@ -138,58 +188,46 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
end
##
# Outputs +verbatim+ flush left and indented 2 columns
# Outputs +verbatim+ indented 2 columns
def accept_verbatim verbatim
indent = ' ' * (@indent + 2)
lines = []
current_line = []
# split into lines
verbatim.parts.each do |part|
current_line << part
if part == "\n" then
lines << current_line
current_line = []
end
@res << indent unless part == "\n"
@res << part
end
lines << current_line unless current_line.empty?
# calculate margin
indented = lines.select { |line| line != ["\n"] }
margin = indented.map { |line| line.first.length }.min
# flush left
indented.each { |line| line[0][0...margin] = '' }
# output
use_prefix or @res << indent # verbatim is unlikely to have prefix
@res << lines.shift.join
lines.each do |line|
@res << indent unless line == ["\n"]
@res << line.join
end
@res << "\n"
@res << "\n" unless @res =~ /\n\z/
end
##
# Applies attribute-specific markup to +text+ using RDoc::AttributeManager
def attributes text
flow = @am.flow text.dup
convert_flow flow
end
##
# Returns the generated output
def end_accepting
@res.join
end
##
# Removes preceeding \\ from the suppressed crossref +special+
def handle_special_SUPPRESSED_CROSSREF special
special.text.sub(/\\/, '')
text = special.text
text = text.sub('\\', '') unless in_tt?
text
end
##
# Prepares the visitor for text generation
def start_accepting
@res = [""]
@indent = 0
@ -200,6 +238,10 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
@list_width = []
end
##
# Adds the stored #prefix to the output and clears it. Lists generate a
# prefix for later consumption.
def use_prefix
prefix = @prefix
@prefix = nil
@ -208,6 +250,9 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
prefix
end
##
# Wraps +text+ to #width
def wrap text
return unless text && !text.empty?

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

@ -6,6 +6,8 @@ require 'rdoc/markup/formatter'
class RDoc::Markup::ToTest < RDoc::Markup::Formatter
# :stopdoc:
##
# :section: Visitor
@ -22,8 +24,12 @@ class RDoc::Markup::ToTest < RDoc::Markup::Formatter
@res << paragraph.text
end
def accept_raw raw
@res << raw.parts.join
end
def accept_verbatim(verbatim)
@res << verbatim.text
@res << verbatim.text.gsub(/^(\S)/, ' \1')
end
def accept_list_start(list)
@ -60,5 +66,7 @@ class RDoc::Markup::ToTest < RDoc::Markup::Formatter
@res << '-' * rule.weight
end
# :startdoc:
end

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

@ -3,6 +3,9 @@
class RDoc::Markup::Verbatim < RDoc::Markup::Raw
##
# Calls #accept_verbatim on +visitor+
def accept visitor
visitor.accept_verbatim self
end
@ -17,16 +20,16 @@ class RDoc::Markup::Verbatim < RDoc::Markup::Raw
@parts.each do |part|
case part
when /\n/ then
when /^\s*\n/ then
newlines += 1
parts << part if newlines <= 2
parts << part if newlines == 1
else
newlines = 0
parts << part
end
end
parts.slice!(-1) if parts[-2..-1] == ["\n", "\n"]
parts.pop if parts.last =~ /\A\r?\n\z/
@parts = parts
end

353
lib/rdoc/method_attr.rb Normal file
Просмотреть файл

@ -0,0 +1,353 @@
require 'rdoc/code_object'
##
# Abstract class representing either a method or an attribute.
class RDoc::MethodAttr < RDoc::CodeObject
include Comparable
##
# Name of this method/attribute.
attr_accessor :name
##
# public, protected, private
attr_accessor :visibility
##
# Is this a singleton method/attribute?
attr_accessor :singleton
##
# Source file token stream
attr_reader :text
##
# Array of other names for this method/attribute
attr_reader :aliases
##
# The method/attribute we're aliasing
attr_accessor :is_alias_for
#--
# The attributes below are for AnyMethod only.
# They are left here for the time being to
# allow ri to operate.
# TODO modify ri to avoid calling these on attributes.
#++
##
# Parameters yielded by the called block
attr_reader :block_params
##
# Parameters for this method
attr_accessor :params
##
# Different ways to call this method
attr_accessor :call_seq
##
# The call_seq or the param_seq with method name, if there is no call_seq.
attr_reader :arglists
##
# Pretty parameter list for this method
attr_reader :param_seq
##
# Creates a new MethodAttr from token stream +text+ and method or attribute
# name +name+.
#
# Usually this is called by super from a subclass.
def initialize text, name
super()
@text = text
@name = name
@aliases = []
@is_alias_for = nil
@parent_name = nil
@singleton = nil
@visibility = :public
@see = false
@arglists = nil
@block_params = nil
@call_seq = nil
@param_seq = nil
@params = nil
end
##
# Order by #singleton then #name
def <=>(other)
[@singleton ? 0 : 1, name] <=> [other.singleton ? 0 : 1, other.name]
end
##
# A method/attribute is documented if any of the following is true:
# - it was marked with :nodoc:;
# - it has a comment;
# - it is an alias for a documented method;
# - it has a +#see+ method that is documented.
def documented?
super or
(is_alias_for and is_alias_for.documented?) or
(see and see.documented?)
end
##
# A method/attribute to look at,
# in particular if this method/attribute has no documentation.
#
# It can be a method/attribute of the superclass or of an included module,
# including the Kernel module, which is always appended to the included
# modules.
#
# Returns +nil+ if there is no such method/attribute.
# The +#is_alias_for+ method/attribute, if any, is not included.
#
# Templates may generate a "see also ..." if this method/attribute
# has documentation, and "see ..." if it does not.
def see
@see = find_see if @see == false
@see
end
def find_see # :nodoc:
return nil if singleton || is_alias_for
# look for the method
other = find_method_or_attribute name
return other if other
# if it is a setter, look for a getter
return nil unless name =~ /[a-z_]=$/i # avoid == or ===
return find_method_or_attribute name[0..-2]
end
def find_method_or_attribute name # :nodoc:
return nil unless parent.respond_to? :ancestors
searched = parent.ancestors
kernel = RDoc::TopLevel.all_modules_hash['Kernel']
searched << kernel if kernel &&
parent != kernel && !searched.include?(kernel)
searched.each do |ancestor|
next if parent == ancestor
next if String === ancestor
other = ancestor.find_method_named('#' << name) ||
ancestor.find_attribute_named(name)
return other if other
end
nil
end
##
# Abstract method. Contexts in their building phase call this
# to register a new alias for this known method/attribute.
#
# - creates a new AnyMethod/Attribute +newa+ named an_alias.new_name;
# - adds +self+ as +newa.is_alias_for+;
# - adds +newa+ to #aliases
# - adds +newa+ to the methods/attributes of +context+.
def add_alias(an_alias, context)
raise NotImplementedError
end
##
# HTML fragment reference for this method
def aref
type = singleton ? 'c' : 'i'
# % characters are not allowed in html names => dash instead
"#{aref_prefix}-#{type}-#{html_name}"
end
##
# Prefix for +aref+, defined by subclasses.
def aref_prefix
raise NotImplementedError
end
##
# Attempts to sanitize the content passed by the ruby parser:
# remove outer parentheses, etc.
def block_params=(value)
# 'yield.to_s' or 'assert yield, msg'
return @block_params = '' if value =~ /^[\.,]/
# remove trailing 'if/unless ...'
return @block_params = '' if value =~ /^(if|unless)\s/
value = $1.strip if value =~ /^(.+)\s(if|unless)\s/
# outer parentheses
value = $1 if value =~ /^\s*\((.*)\)\s*$/
value = value.strip
# proc/lambda
return @block_params = $1 if value =~ /^(proc|lambda)(\s*\{|\sdo)/
# surrounding +...+ or [...]
value = $1.strip if value =~ /^\+(.*)\+$/
value = $1.strip if value =~ /^\[(.*)\]$/
return @block_params = '' if value.empty?
# global variable
return @block_params = 'str' if value =~ /^\$[&0-9]$/
# wipe out array/hash indices
value.gsub!(/(\w)\[[^\[]+\]/, '\1')
# remove @ from class/instance variables
value.gsub!(/@@?([a-z0-9_]+)/, '\1')
# method calls => method name
value.gsub!(/([A-Z:a-z0-9_]+)\.([a-z0-9_]+)(\s*\(\s*[a-z0-9_.,\s]*\s*\)\s*)?/) do
case $2
when 'to_s' then $1
when 'const_get' then 'const'
when 'new' then
$1.split('::').last. # ClassName => class_name
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
gsub(/([a-z\d])([A-Z])/,'\1_\2').
downcase
else
$2
end
end
# class prefixes
value.gsub!(/[A-Za-z0-9_:]+::/, '')
# simple expressions
value = $1 if value =~ /^([a-z0-9_]+)\s*[-*+\/]/
@block_params = value.strip
end
##
# HTML id-friendly method/attribute name
def html_name
CGI.escape(@name.gsub('-', '-2D')).gsub('%','-').sub(/^-/, '')
end
##
# Full method/attribute name including namespace
def full_name
@full_name || "#{parent_name}#{pretty_name}"
end
##
# '::' for a class method/attribute, '#' for an instance method.
def name_prefix
singleton ? '::' : '#'
end
##
# Method/attribute name with class/instance indicator
def pretty_name
"#{name_prefix}#{@name}"
end
##
# Type of method/attribute (class or instance)
def type
singleton ? 'class' : 'instance'
end
##
# Path to this method
def path
"#{@parent.path}##{aref}"
end
##
# Name of our parent with special handling for un-marshaled methods
def parent_name
@parent_name || super
end
def pretty_print q # :nodoc:
alias_for = @is_alias_for ? "alias for #{@is_alias_for.name}" : nil
q.group 2, "[#{self.class.name} #{full_name} #{visibility}", "]" do
if alias_for then
q.breakable
q.text alias_for
end
if text then
q.breakable
q.text "text:"
q.breakable
q.pp @text
end
unless comment.empty? then
q.breakable
q.text "comment:"
q.breakable
q.pp @comment
end
end
end
def inspect # :nodoc:
alias_for = @is_alias_for ? " (alias for #{@is_alias_for.name})" : nil
"#<%s:0x%x %s (%s)%s>" % [
self.class, object_id,
full_name,
visibility,
alias_for,
]
end
def to_s # :nodoc:
if @is_alias_for
"#{self.class.name}: #{full_name} -> #{is_alias_for}"
else
"#{self.class.name}: #{full_name}"
end
end
end

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

@ -6,10 +6,10 @@ require 'rdoc/class_module'
class RDoc::NormalClass < RDoc::ClassModule
##
# Ancestor ClassModules
# Appends the superclass, if any, to the included modules.
def ancestors
includes + [superclass]
superclass ? super + [superclass] : super
end
def inspect # :nodoc:
@ -20,6 +20,15 @@ class RDoc::NormalClass < RDoc::ClassModule
]
end
def to_s # :nodoc:
display = "#{self.class.name} #{self.full_name}"
if superclass
display << ' < ' << (superclass.is_a?(String) ? superclass : superclass.full_name)
end
display << ' -> ' << is_alias_for.to_s if is_alias_for
display
end
def pretty_print q # :nodoc:
superclass = @superclass ? " < #{@superclass}" : nil

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

@ -5,11 +5,6 @@ require 'rdoc/class_module'
class RDoc::NormalModule < RDoc::ClassModule
##
# Included NormalModules
alias ancestors includes
def inspect # :nodoc:
"#<%s:0x%x module %s includes: %p attributes: %p methods: %p aliases: %p>" % [
self.class, object_id,

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

@ -8,9 +8,41 @@ require 'rdoc/ri/paths'
class RDoc::Options
##
# Character-set
# The deprecated options.
attr_reader :charset
DEPRECATED = {
'--accessor' => 'support discontinued',
'--diagram' => 'support discontinued',
'--help-output' => 'support discontinued',
'--image-format' => 'was an option for --diagram',
'--inline-source' => 'source code is now always inlined',
'--merge' => 'ri now always merges class information',
'--one-file' => 'support discontinued',
'--op-name' => 'support discontinued',
'--opname' => 'support discontinued',
'--promiscuous' => 'files always only document their content',
'--ri-system' => 'Ruby installers use other techniques',
}
##
# Template option validator for OptionParser
Template = nil
##
# Character-set for HTML output. #encoding is preferred over #charset
attr_accessor :charset
##
# If true, RDoc will not write any files.
attr_accessor :dry_run
##
# Encoding of output where. This is set via --encoding.
attr_accessor :encoding if Object.const_defined? :Encoding
##
# Files matching this pattern will be excluded
@ -22,10 +54,21 @@ class RDoc::Options
attr_accessor :files
##
# Create the output even if the output directory does not look
# like an rdoc output directory
attr_accessor :force_output
##
# Scan newer sources than the flag file if true.
attr_reader :force_update
attr_accessor :force_update
##
# Formatter to mark up text with
attr_accessor :formatter
##
# Description of the output generator (set with the <tt>-fmt</tt> option)
@ -33,9 +76,21 @@ class RDoc::Options
attr_accessor :generator
##
# Formatter to mark up text with
# Loaded generator options. Used to prevent --help from loading the same
# options multiple times.
attr_accessor :formatter
attr_accessor :generator_options
##
# Old rdoc behavior: hyperlink all words that match a method name,
# even if not preceded by '#' or '::'
attr_accessor :hyperlink_all
##
# Include line numbers in the source code
attr_accessor :line_numbers
##
# Name of the file, class or module to display in the initial index page (if
@ -43,11 +98,21 @@ class RDoc::Options
attr_accessor :main_page
##
# If true, only report on undocumented files
attr_accessor :coverage_report
##
# The name of the output directory
attr_accessor :op_dir
##
# The OptionParser for this instance
attr_accessor :option_parser
##
# Is RDoc in pipe mode?
@ -56,32 +121,32 @@ class RDoc::Options
##
# Array of directories to search for files to satisfy an :include:
attr_reader :rdoc_include
##
# Include private and protected methods in the output?
attr_accessor :show_all
attr_accessor :rdoc_include
##
# Include the '#' at the front of hyperlinked instance method names
attr_reader :show_hash
attr_accessor :show_hash
##
# The number of columns in a tab
attr_reader :tab_width
attr_accessor :tab_width
##
# Template to be used when generating output
attr_reader :template
attr_accessor :template
##
# Directory the template lives in
attr_accessor :template_dir
##
# Documentation title
attr_reader :title
attr_accessor :title
##
# Verbosity, zero means quiet
@ -91,29 +156,88 @@ class RDoc::Options
##
# URL of web cvs frontend
attr_reader :webcvs
attr_accessor :webcvs
##
# Minimum visibility of a documented method. One of +:public+,
# +:protected+, +:private+. May be overridden on a per-method
# basis with the :doc: directive.
attr_accessor :visibility
def initialize # :nodoc:
require 'rdoc/rdoc'
@op_dir = nil
@show_all = false
@main_page = nil
@dry_run = false
@exclude = []
@generators = RDoc::RDoc::GENERATORS
@generator = RDoc::Generator::Darkfish
@generator_name = nil
@rdoc_include = []
@title = nil
@template = nil
@show_hash = false
@tab_width = 8
@force_output = false
@force_update = true
@verbosity = 1
@generator = nil
@generator_name = nil
@generator_options = []
@generators = RDoc::RDoc::GENERATORS
@hyperlink_all = false
@line_numbers = false
@main_page = nil
@coverage_report = false
@op_dir = nil
@pipe = false
@rdoc_include = []
@show_hash = false
@stylesheet_url = nil
@tab_width = 8
@template = nil
@template_dir = nil
@title = nil
@verbosity = 1
@visibility = :protected
@webcvs = nil
@charset = 'utf-8'
if Object.const_defined? :Encoding then
@encoding = Encoding.default_external
@charset = @encoding.to_s
else
@charset = 'UTF-8'
end
end
##
# Check that the files on the command line exist
def check_files
@files.delete_if do |file|
if File.exist? file then
if File.readable? file then
false
else
warn "file '#{file}' not readable"
true
end
else
warn "file '#{file}' not found"
true
end
end
end
##
# Ensure only one generator is loaded
def check_generator
if @generator then
raise OptionParser::InvalidOption,
"generator already set to #{@generator_name}"
end
end
##
# Set the title, but only if not already set. Used to set the title
# from a source file, so that a title set from the command line
# will have the priority.
def default_title=(string)
@title ||= string
end
##
@ -122,7 +246,10 @@ class RDoc::Options
def parse(argv)
ignore_invalid = true
argv.insert(0, *ENV['RDOCOPT'].split) if ENV['RDOCOPT']
opts = OptionParser.new do |opt|
@option_parser = opt
opt.program_name = File.basename $0
opt.version = RDoc::VERSION
opt.release = nil
@ -139,6 +266,14 @@ Usage: #{opt.program_name} [options] [names...]
How RDoc generates output depends on the output formatter being used, and on
the options you give.
Options can be specified via the RDOCOPT environment variable, which
functions similar to the RUBYOPT environment variable for ruby.
$ export RDOCOPT="--show-hash"
will make rdoc show hashes in method links by default. Command-line options
always will override those in RDOCOPT.
- Darkfish creates frameless HTML output by Michael Granger.
- ri creates ri data files
@ -156,14 +291,44 @@ Usage: #{opt.program_name} [options] [names...]
opt.banner << " - #{parser}: #{regexp.join ', '}\n"
end
opt.banner << "\n The following options are deprecated:\n\n"
name_length = DEPRECATED.keys.sort_by { |k| k.length }.last.length
DEPRECATED.sort_by { |k,| k }.each do |name, reason|
opt.banner << " %*1$2$s %3$s\n" % [-name_length, name, reason]
end
opt.accept Template do |template|
template_dir = template_dir_for template
unless template_dir then
warn "could not find template #{template}"
nil
else
[template, template_dir]
end
end
opt.separator nil
opt.separator "Parsing Options:"
opt.separator "Parsing options:"
opt.separator nil
if Object.const_defined? :Encoding then
opt.on("--encoding=ENCODING", "-e", Encoding.list.map { |e| e.name },
"Specifies the output encoding. All files",
"read will be converted to this encoding.",
"Preferred over --charset") do |value|
@encoding = Encoding.find value
@charset = @encoding.to_s # may not be valid value
end
opt.separator nil
end
opt.on("--all", "-a",
"Include all methods (not just public) in",
"the output.") do |value|
@show_all = value
"Synonym for --visibility=private.") do |value|
@visibility = :private
end
opt.separator nil
@ -207,20 +372,41 @@ Usage: #{opt.program_name} [options] [names...]
end
opt.separator nil
opt.separator "Generator Options:"
opt.on("--tab-width=WIDTH", "-w", OptionParser::DecimalInteger,
"Set the width of tab characters.") do |value|
@tab_width = value
end
opt.separator nil
opt.on("--charset=CHARSET", "-c",
"Specifies the output HTML character-set.") do |value|
@charset = value
opt.on("--visibility=VISIBILITY", "-V", RDoc::VISIBILITIES,
"Minimum visibility to document a method.",
"One of 'public', 'protected' (the default)",
"or 'private'. Can be abbreviated.") do |value|
@visibility = value
end
opt.separator nil
opt.separator "Common generator options:"
opt.separator nil
opt.on("--force-output", "-O",
"Forces rdoc to write the output files,",
"even if the output directory exists",
"and does not seem to have been created",
"by rdoc.") do |value|
@force_output = value
end
opt.separator nil
generator_text = @generators.keys.map { |name| " #{name}" }.sort
opt.on("--fmt=FORMAT", "--format=FORMAT", "-f", @generators.keys,
opt.on("-f", "--fmt=FORMAT", "--format=FORMAT", @generators.keys,
"Set the output formatter. One of:", *generator_text) do |value|
check_generator
@generator_name = value.downcase
setup_generator
end
@ -236,9 +422,11 @@ Usage: #{opt.program_name} [options] [names...]
opt.separator nil
opt.on("--main=NAME", "-m",
"NAME will be the initial page displayed.") do |value|
@main_page = value
opt.on("--[no-]coverage-report", "--[no-]dcov", "-C",
"Prints a report on undocumented items.",
"Does not generate files.") do |value|
@coverage_report = value
@force_update = true if value
end
opt.separator nil
@ -250,6 +438,51 @@ Usage: #{opt.program_name} [options] [names...]
opt.separator nil
opt.on("-d",
"Deprecated --diagram option.",
"Prevents firing debug mode",
"with legacy invocation.") do |value|
end
opt.separator nil
opt.separator 'HTML generator options:'
opt.separator nil
opt.on("--charset=CHARSET", "-c",
"Specifies the output HTML character-set.",
"Use --encoding instead of --charset if",
"available.") do |value|
@charset = value
end
opt.separator nil
opt.on("--hyperlink-all", "-A",
"Generate hyperlinks for all words that",
"correspond to known methods, even if they",
"do not start with '#' or '::' (legacy",
"behavior).") do |value|
@hyperlink_all = value
end
opt.separator nil
opt.on("--main=NAME", "-m",
"NAME will be the initial page displayed.") do |value|
@main_page = value
end
opt.separator nil
opt.on("--[no-]line-numbers", "-N",
"Include line numbers in the source code.",
"By default, only the number of the first",
"line is displayed, in a leading comment.") do |value|
@line_numbers = value
end
opt.separator nil
opt.on("--show-hash", "-H",
"A name of the form #name in a comment is a",
"possible hyperlink to an instance method",
@ -260,17 +493,12 @@ Usage: #{opt.program_name} [options] [names...]
opt.separator nil
opt.on("--tab-width=WIDTH", "-w", OptionParser::DecimalInteger,
"Set the width of tab characters.") do |value|
@tab_width = value
end
opt.separator nil
opt.on("--template=NAME", "-T",
opt.on("--template=NAME", "-T", Template,
"Set the template used when generating",
"output.") do |value|
@template = value
"output. The default depends on the",
"formatter used.") do |(template, template_dir)|
@template = template
@template_dir = template_dir
end
opt.separator nil
@ -292,11 +520,7 @@ Usage: #{opt.program_name} [options] [names...]
end
opt.separator nil
opt.on("-d", "--diagram", "Prevents -d from tripping --debug")
opt.separator nil
opt.separator "ri Generator Options:"
opt.separator "ri generator options:"
opt.separator nil
opt.on("--ri", "-r",
@ -305,6 +529,8 @@ Usage: #{opt.program_name} [options] [names...]
"your home directory unless overridden by a",
"subsequent --op parameter, so no special",
"privileges are needed.") do |value|
check_generator
@generator_name = "ri"
@op_dir ||= RDoc::RI::Paths::HOMEDIR
setup_generator
@ -317,22 +543,30 @@ Usage: #{opt.program_name} [options] [names...]
"are stored in a site-wide directory,",
"making them accessible to others, so",
"special privileges are needed.") do |value|
check_generator
@generator_name = "ri"
@op_dir = RDoc::RI::Paths::SITEDIR
setup_generator
end
opt.separator nil
opt.separator "Generic Options:"
opt.separator "Generic options:"
opt.separator nil
opt.on("--[no-]dry-run",
"Don't write any files") do |value|
@dry_run = value
end
opt.on("-D", "--[no-]debug",
"Displays lots on internal stuff.") do |value|
$DEBUG_RDOC = value
end
opt.on("--[no-]ignore-invalid",
"Ignore invalid options and continue.") do |value|
"Ignore invalid options and continue",
"(default true).") do |value|
ignore_invalid = value
end
@ -342,38 +576,70 @@ Usage: #{opt.program_name} [options] [names...]
end
opt.on("--verbose", "-v",
"Display extra progress as we parse.") do |value|
"Display extra progress as RDoc parses") do |value|
@verbosity = 2
end
opt.on("--help",
"Display this help") do
RDoc::RDoc::GENERATORS.each_key do |generator|
setup_generator generator
end
puts opt.help
exit
end
opt.separator nil
end
argv.insert(0, *ENV['RDOCOPT'].split) if ENV['RDOCOPT']
ignored = []
setup_generator 'darkfish' if
argv.grep(/\A(-f|--fmt|--format|-r|-R|--ri|--ri-site)\b/).empty?
deprecated = []
invalid = []
begin
opts.parse! argv
rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e
if ignore_invalid then
ignored << e.args.join(' ')
retry
if DEPRECATED[e.args.first] then
deprecated << e.args.first
elsif %w[--format --ri -r --ri-site -R].include? e.args.first then
raise
else
$stderr.puts opts
$stderr.puts
$stderr.puts e
exit 1
invalid << e.args.join(' ')
end
retry
end
unless @generator then
@generator = RDoc::Generator::Darkfish
@generator_name = 'darkfish'
end
if @pipe and not argv.empty? then
@pipe = false
ignored << '-p (with files)'
invalid << '-p (with files)'
end
unless ignored.empty? or quiet then
$stderr.puts "invalid options: #{ignored.join ', '}"
$stderr.puts '(invalid options are ignored)'
unless quiet then
deprecated.each do |opt|
$stderr.puts 'option ' << opt << ' is deprecated: ' << DEPRECATED[opt]
end
unless invalid.empty? then
invalid = "invalid options: #{invalid.join ', '}"
if ignore_invalid then
$stderr.puts invalid
$stderr.puts '(invalid options are ignored)'
else
$stderr.puts opts
$stderr.puts invalid
exit 1
end
end
end
@op_dir ||= 'doc'
@ -392,15 +658,10 @@ Usage: #{opt.program_name} [options] [names...]
# If no template was specified, use the default template for the output
# formatter
@template ||= @generator_name
end
##
# Set the title, but only if not already set. This means that a title set
# from the command line trumps one set in a source file
def title=(string)
@title ||= string
unless @template then
@template = @generator_name
@template_dir = template_dir_for @template
end
end
##
@ -410,30 +671,46 @@ Usage: #{opt.program_name} [options] [names...]
@verbosity.zero?
end
def quiet=(bool)
##
# Set quietness to +bool+
def quiet= bool
@verbosity = bool ? 0 : 1
end
private
##
# Set up an output generator for the format in @generator_name
# Set up an output generator for the named +generator_name+.
#
# If the found generator responds to :setup_options it will be called with
# the options instance. This allows generators to add custom options or set
# default options.
def setup_generator
@generator = @generators[@generator_name]
def setup_generator generator_name = @generator_name
@generator = @generators[generator_name]
unless @generator then
raise OptionParser::InvalidArgument, "Invalid output formatter"
raise OptionParser::InvalidArgument,
"Invalid output formatter #{generator_name}"
end
return if @generator_options.include? @generator
@generator_name = generator_name
@generator_options << @generator
@generator.setup_options self if @generator.respond_to? :setup_options
end
##
# Check that the files on the command line exist
# Finds the template dir for +template+
def check_files
@files.each do |f|
stat = File.stat f rescue next
raise RDoc::Error, "file '#{f}' not readable" unless stat.readable?
def template_dir_for template
template_path = File.join 'rdoc', 'generator', 'template', template
$LOAD_PATH.map do |path|
File.join File.expand_path(path), template_path
end.find do |dir|
File.directory? dir
end
end

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

@ -1,6 +1,6 @@
require 'rdoc'
require 'rdoc/code_objects'
require 'rdoc/markup/preprocess'
require 'rdoc/markup/pre_process'
require 'rdoc/stats'
##
@ -43,7 +43,15 @@ class RDoc::Parser
@parsers = []
class << self
##
# A Hash that maps file exetensions regular expressions to parsers that
# will consume them.
#
# Use parse_files_matching to register a parser's file extensions.
attr_reader :parsers
end
##
@ -67,18 +75,51 @@ class RDoc::Parser
# content that an RDoc parser shouldn't try to consume.
def self.binary?(file)
return false if file =~ /\.(rdoc|txt)$/
s = File.read(file, 1024) or return false
if s[0, 2] == Marshal.dump('')[0, 2] then
true
elsif file =~ /erb\.rb$/ then
false
elsif s.scan(/<%|%>/).length >= 4 || s.index("\x00") then
true
elsif 0.respond_to? :fdiv then
s.count("\x00-\x7F", "^ -~\t\r\n").fdiv(s.size) > 0.3
else # HACK 1.8.6
(s.count("\x00-\x7F", "^ -~\t\r\n").to_f / s.size) > 0.3
have_encoding = s.respond_to? :encoding
if have_encoding then
return false if s.encoding != Encoding::ASCII_8BIT and s.valid_encoding?
end
return true if s[0, 2] == Marshal.dump('')[0, 2] or s.index("\x00")
if have_encoding then
s.force_encoding Encoding.default_external
not s.valid_encoding?
else
if 0.respond_to? :fdiv then
s.count("\x00-\x7F", "^ -~\t\r\n").fdiv(s.size) > 0.3
else # HACK 1.8.6
(s.count("\x00-\x7F", "^ -~\t\r\n").to_f / s.size) > 0.3
end
end
end
##
# Processes common directives for CodeObjects for the C and Ruby parsers.
#
# Applies +directive+'s +value+ to +code_object+, if appropriate
def self.process_directive code_object, directive, value
case directive
when 'nodoc' then
code_object.document_self = nil # notify nodoc
code_object.document_children = value.downcase != 'all'
when 'doc' then
code_object.document_self = true
code_object.force_documentation = true
when 'yield', 'yields' then
# remove parameter &block
code_object.params.sub!(/,?\s*&\w+/, '') if code_object.params
code_object.block_params = value
when 'arg', 'args' then
code_object.params = value
end
end
@ -143,6 +184,12 @@ class RDoc::Parser
RDoc::Parser.parsers.unshift [regexp, self]
end
##
# Creates a new Parser storing +top_level+, +file_name+, +content+,
# +options+ and +stats+ in instance variables.
#
# Usually invoked by +super+
def initialize(top_level, file_name, content, options, stats)
@top_level = top_level
@file_name = file_name

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

@ -3,9 +3,9 @@ require 'rdoc/parser/ruby'
require 'rdoc/known_classes'
##
# We attempt to parse C extension files. Basically we look for
# RDoc::Parser::C attempts to parse C extension files. It looks for
# the standard patterns that you find in extensions: <tt>rb_define_class,
# rb_define_method</tt> and so on. We also try to find the corresponding
# rb_define_method</tt> and so on. It tries to find the corresponding
# C source for the methods and extract comments, but if we fail
# we don't worry too much.
#
@ -49,13 +49,26 @@ require 'rdoc/known_classes'
#
# The comment blocks may include special directives:
#
# [Document-class: <i>name</i>]
# This comment block is documentation for the given class. Use this
# when the <tt>Init_xxx</tt> method is not named after the class.
# [Document-class: +name+]
# Documentation for the named class.
#
# [Document-method: <i>name</i>]
# This comment documents the named method. Use when RDoc cannot
# automatically find the method from it's declaration
# [Document-module: +name+]
# Documentation for the named module.
#
# [Document-const: +name+]
# Documentation for the named +rb_define_const+.
#
# [Document-global: +name+]
# Documentation for the named +rb_define_global_const+
#
# [Document-variable: +name+]
# Documentation for the named +rb_define_variable+
#
# [Document-method: +name+]
# Documentation for the named method.
#
# [Document-attr: +name+]
# Documentation for the named attribute.
#
# [call-seq: <i>text up to an empty line</i>]
# Because C source doesn't give descripive names to Ruby-level parameters,
@ -120,21 +133,61 @@ class RDoc::Parser::C < RDoc::Parser
@known_classes = RDoc::KNOWN_CLASSES.dup
@content = handle_tab_width handle_ifdefs_in(@content)
@classes = Hash.new
@singleton_classes = Hash.new
@file_dir = File.dirname(@file_name)
end
##
# Scans #content for rb_define_alias
def do_aliases
@content.scan(%r{rb_define_alias\s*\(\s*(\w+),\s*"([^"]+)",\s*"([^"]+)"\s*\)}m) do
|var_name, new_name, old_name|
@content.scan(/rb_define_alias\s*\(
\s*(\w+),
\s*"(.+?)",
\s*"(.+?)"
\s*\)/xm) do |var_name, new_name, old_name|
class_name = @known_classes[var_name] || var_name
class_obj = find_class(var_name, class_name)
class_obj = find_class var_name, class_name
as = class_obj.add_alias RDoc::Alias.new("", old_name, new_name, "")
al = RDoc::Alias.new '', old_name, new_name, ''
al.singleton = @singleton_classes.key?(var_name)
@stats.add_alias as
comment = find_alias_comment var_name, new_name, old_name
comment = strip_stars comment
al.comment = comment
class_obj.add_alias al
@stats.add_alias al
end
end
##
# Scans #content for rb_attr and rb_define_attr
def do_attrs
@content.scan(/rb_attr\s*\(
\s*(\w+),
\s*([\w"()]+),
\s*([01]),
\s*([01]),
\s*\w+\);/xm) do |var_name, attr_name, read, write|
handle_attr var_name, attr_name, read, write
end
@content.scan(%r%rb_define_attr\(
\s*([\w\.]+),
\s*"([^"]+)",
\s*(\d+),
\s*(\d+)\s*\);
%xm) do |var_name, attr_name, read, write|
handle_attr var_name, attr_name, read, write
end
end
##
# Scans #content for rb_define_module, rb_define_class, boot_defclass,
# rb_define_module_under, rb_define_class_under and rb_singleton_class
def do_classes
@content.scan(/(\w+)\s* = \s*rb_define_module\s*\(\s*"(\w+)"\s*\)/mx) do
|var_name, class_name|
@ -165,35 +218,44 @@ class RDoc::Parser::C < RDoc::Parser
end
@content.scan(/([\w\.]+)\s* = \s*rb_define_class_under\s*
\(
\s*(\w+),
\s*"(\w+)",
\s*([\w\*\s\(\)\.\->]+)\s* # for SWIG
\s*\)/mx) do |var_name, in_module, class_name, parent|
\(
\s*(\w+),
\s*"(\w+)",
\s*([\w\*\s\(\)\.\->]+)\s* # for SWIG
\s*\)/mx) do |var_name, in_module, class_name, parent|
handle_class_module(var_name, "class", class_name, parent, in_module)
end
@content.scan(/([\w\.]+)\s* = \s*rb_singleton_class\s*
\(
\s*(\w+)
\s*\)/mx) do |sclass_var, class_var|
handle_singleton sclass_var, class_var
end
end
##
# Scans #content for rb_define_variable, rb_define_readonly_variable,
# rb_define_const and rb_define_global_const
def do_constants
@content.scan(%r{\Wrb_define_
@content.scan(%r%\Wrb_define_
( variable |
readonly_variable |
const |
global_const | )
global_const )
\s*\(
(?:\s*(\w+),)?
\s*"(\w+)",
\s*(.*?)\s*\)\s*;
}xm) do |type, var_name, const_name, definition|
%xm) do |type, var_name, const_name, definition|
var_name = "rb_cObject" if !var_name or var_name == "rb_mKernel"
handle_constants type, var_name, const_name, definition
end
end
##
# Look for includes of the form:
#
# rb_include_module(rb_cArray, rb_mEnumerable);
# Scans #content for rb_include_module
def do_includes
@content.scan(/rb_include_module\s*\(\s*(\w+?),\s*(\w+?)\s*\)/) do |c,m|
@ -204,8 +266,13 @@ class RDoc::Parser::C < RDoc::Parser
end
end
##
# Scans #content for rb_define_method, rb_define_singleton_method,
# rb_define_module_function, rb_define_private_method,
# rb_define_global_function and define_filetest_function
def do_methods
@content.scan(%r{rb_define_
@content.scan(%r%rb_define_
(
singleton_method |
method |
@ -217,8 +284,7 @@ class RDoc::Parser::C < RDoc::Parser
\s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
\s*(-?\w+)\s*\)
(?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))?
}xm) do
|type, var_name, meth_name, meth_body, param_count, source_file|
%xm) do |type, var_name, meth_name, meth_body, param_count, source_file|
# Ignore top-object and weird struct.c dynamic stuff
next if var_name == "ruby_top_self"
@ -231,44 +297,69 @@ class RDoc::Parser::C < RDoc::Parser
source_file)
end
@content.scan(%r{rb_define_attr\(
\s*([\w\.]+),
\s*"([^"]+)",
\s*(\d+),
\s*(\d+)\s*\);
}xm) do |var_name, attr_name, attr_reader, attr_writer|
#var_name = "rb_cObject" if var_name == "rb_mKernel"
handle_attr(var_name, attr_name,
attr_reader.to_i != 0,
attr_writer.to_i != 0)
end
@content.scan(%r{rb_define_global_function\s*\(
@content.scan(%r%rb_define_global_function\s*\(
\s*"([^"]+)",
\s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
\s*(-?\w+)\s*\)
(?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))?
}xm) do |meth_name, meth_body, param_count, source_file|
%xm) do |meth_name, meth_body, param_count, source_file|
handle_method("method", "rb_mKernel", meth_name,
meth_body, param_count, source_file)
end
@content.scan(/define_filetest_function\s*\(
\s*"([^"]+)",
\s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
\s*(-?\w+)\s*\)/xm) do
|meth_name, meth_body, param_count|
\s*"([^"]+)",
\s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
\s*(-?\w+)\s*\)/xm) do |meth_name, meth_body, param_count|
handle_method("method", "rb_mFileTest", meth_name, meth_body, param_count)
handle_method("singleton_method", "rb_cFile", meth_name, meth_body, param_count)
end
end
def find_attr_comment(attr_name)
if @content =~ %r{((?>/\*.*?\*/\s+))
rb_define_attr\((?:\s*(\w+),)?\s*"#{attr_name}"\s*,.*?\)\s*;}xmi
##
# Finds the comment for an alias on +class_name+ from +new_name+ to
# +old_name+
def find_alias_comment class_name, new_name, old_name
content =~ %r%((?>/\*.*?\*/\s+))
rb_define_alias\(\s*#{Regexp.escape class_name}\s*,
\s*"#{Regexp.escape new_name}"\s*,
\s*"#{Regexp.escape old_name}"\s*\);%xm
$1 || ''
end
##
# Finds a comment for rb_define_attr, rb_attr or Document-attr.
#
# +var_name+ is the C class variable the attribute is defined on.
# +attr_name+ is the attribute's name.
#
# +read+ and +write+ are the read/write flags ('1' or '0'). Either both or
# neither must be provided.
def find_attr_comment var_name, attr_name, read = nil, write = nil
attr_name = Regexp.escape attr_name
rw = if read and write then
/\s*#{read}\s*,\s*#{write}\s*/xm
else
/.*?/m
end
if @content =~ %r%((?>/\*.*?\*/\s+))
rb_define_attr\((?:\s*#{var_name},)?\s*
"#{attr_name}"\s*,
#{rw}\)\s*;%xm then
$1
elsif @content =~ %r{Document-attr:\s#{attr_name}\s*?\n((?>.*?\*/))}m
elsif @content =~ %r%((?>/\*.*?\*/\s+))
rb_attr\(\s*#{var_name}\s*,
\s*#{attr_name}\s*,
#{rw},.*?\)\s*;%xm then
$1
elsif @content =~ %r%Document-attr:\s#{attr_name}\s*?\n
((?>.*?\*/))%xm then
$1
else
''
@ -280,8 +371,10 @@ class RDoc::Parser::C < RDoc::Parser
def find_body(class_name, meth_name, meth_obj, body, quiet = false)
case body
when %r"((?>/\*.*?\*/\s*))((?:(?:static|SWIGINTERN)\s+)?(?:intern\s+)?VALUE\s+#{meth_name}
\s*(\([^)]*\))([^;]|$))"xm
when %r%((?>/\*.*?\*/\s*))
((?:(?:static|SWIGINTERN)\s+)?
(?:intern\s+)?VALUE\s+#{meth_name}
\s*(\([^)]*\))([^;]|$))%xm then
comment = $1
body_text = $2
@ -303,12 +396,13 @@ class RDoc::Parser::C < RDoc::Parser
find_modifiers comment, meth_obj if comment
#meth_obj.params = params
meth_obj.start_collecting_tokens
tk = RDoc::RubyToken::Token.new nil, 1, 1
tk.set_text body_text
meth_obj.add_token tk
meth_obj.comment = strip_stars comment
when %r{((?>/\*.*?\*/\s*))^\s*(\#\s*define\s+#{meth_name}\s+(\w+))}m
when %r%((?>/\*.*?\*/\s*))^\s*(\#\s*define\s+#{meth_name}\s+(\w+))%m
comment = $1
body_text = $2
find_body class_name, $3, meth_obj, body, true
@ -319,26 +413,29 @@ class RDoc::Parser::C < RDoc::Parser
tk.set_text body_text
meth_obj.add_token tk
meth_obj.comment = strip_stars(comment) + meth_obj.comment.to_s
when %r{^\s*\#\s*define\s+#{meth_name}\s+(\w+)}m
when %r%^\s*\#\s*define\s+#{meth_name}\s+(\w+)%m
unless find_body(class_name, $1, meth_obj, body, true)
warn "No definition for #{meth_name}" unless @options.quiet
warn "No definition for #{meth_name}" if @options.verbosity > 1
return false
end
else
# No body, but might still have an override comment
comment = find_override_comment(class_name, meth_obj.name)
else # No body, but might still have an override comment
comment = find_override_comment class_name, meth_obj.name
if comment
find_modifiers(comment, meth_obj)
find_modifiers comment, meth_obj
meth_obj.comment = strip_stars comment
else
warn "No definition for #{meth_name}" unless @options.quiet
warn "No definition for #{meth_name}" if @options.verbosity > 1
return false
end
end
true
end
##
# Finds a RDoc::NormalClass or RDoc::NormalModule for +raw_name+
def find_class(raw_name, name)
unless @classes[raw_name]
if raw_name =~ /^rb_m/
@ -382,16 +479,17 @@ class RDoc::Parser::C < RDoc::Parser
def find_class_comment(class_name, class_mod)
comment = nil
if @content =~ %r{
if @content =~ %r%
((?>/\*.*?\*/\s+))
(static\s+)?
void\s+
Init_#{class_name}\s*(?:_\(\s*)?\(\s*(?:void\s*)?\)}xmi then # )
Init_#{class_name}\s*(?:_\(\s*)?\(\s*(?:void\s*)?\)%xmi then
comment = $1.sub(%r%Document-(?:class|module):\s+#{class_name}%, '')
elsif @content =~ %r%Document-(?:class|module):\s+#{class_name}\s*?
(?:<\s+[:,\w]+)?\n((?>.*?\*/))%xm then
comment = $1
elsif @content =~ %r{Document-(?:class|module):\s+#{class_name}\s*?(?:<\s+[:,\w]+)?\n((?>.*?\*/))}m then
comment = $1
elsif @content =~ %r{((?>/\*.*?\*/\s+))
([\w\.\s]+\s* = \s+)?rb_define_(class|module).*?"(#{class_name})"}xm then # "
elsif @content =~ %r%((?>/\*.*?\*/\s+))
([\w\.\s]+\s* = \s+)?rb_define_(class|module).*?"(#{class_name})"%xm then
comment = $1
end
@ -409,10 +507,13 @@ class RDoc::Parser::C < RDoc::Parser
# comment or in the matching Document- section.
def find_const_comment(type, const_name)
if @content =~ %r{((?>^\s*/\*.*?\*/\s+))
rb_define_#{type}\((?:\s*(\w+),)?\s*"#{const_name}"\s*,.*?\)\s*;}xmi
if @content =~ %r%((?>^\s*/\*.*?\*/\s+))
rb_define_#{type}\((?:\s*(\w+),)?\s*
"#{const_name}"\s*,
.*?\)\s*;%xmi then
$1
elsif @content =~ %r{Document-(?:const|global|variable):\s#{const_name}\s*?\n((?>.*?\*/))}m
elsif @content =~ %r%Document-(?:const|global|variable):\s#{const_name}
\s*?\n((?>.*?\*/))%xm
$1
else
''
@ -420,56 +521,111 @@ class RDoc::Parser::C < RDoc::Parser
end
##
# If the comment block contains a section that looks like:
# Handles modifiers in +comment+ and updates +meth_obj+ as appropriate.
#
# call-seq:
# Array.new
# Array.new(10)
# If <tt>:nodoc:</tt> is found, documentation on +meth_obj+ is suppressed.
#
# use it for the parameters.
# If <tt>:yields:</tt> is followed by an argument list it is used for the
# #block_params of +meth_obj+.
#
# If the comment block contains a <tt>call-seq:</tt> section like:
#
# call-seq:
# ARGF.readlines(sep=$/) -> array
# ARGF.readlines(limit) -> array
# ARGF.readlines(sep, limit) -> array
#
# ARGF.to_a(sep=$/) -> array
# ARGF.to_a(limit) -> array
# ARGF.to_a(sep, limit) -> array
#
# it is used for the parameters of +meth_obj+.
def find_modifiers(comment, meth_obj)
if comment.sub!(/:nodoc:\s*^\s*\*?\s*$/m, '') or
comment.sub!(/\A\/\*\s*:nodoc:\s*\*\/\Z/, '')
meth_obj.document_self = false
end
if comment.sub!(/call-seq:(.*?)^\s*\*?\s*$/m, '') or
comment.sub!(/\A\/\*\s*call-seq:(.*?)\*\/\Z/, '')
seq = $1
seq.gsub!(/^\s*\*\s*/, '')
def find_modifiers comment, meth_obj
# we must handle situations like the above followed by an unindented first
# comment. The difficulty is to make sure not to match lines starting
# with ARGF at the same indent, but that are after the first description
# paragraph.
if comment =~ /call-seq:(.*?[^\s\*].*?)^\s*\*?\s*$/m then
all_start, all_stop = $~.offset(0)
seq_start, seq_stop = $~.offset(1)
# we get the following lines that start with the leading word at the
# same indent, even if they have blank lines before
if $1 =~ /(^\s*\*?\s*\n)+^(\s*\*?\s*\w+)/m then
leading = $2 # ' * ARGF' in the example above
re = %r%
\A(
(^\s*\*?\s*\n)+
(^#{Regexp.escape leading}.*?\n)+
)+
^\s*\*?\s*$
%xm
if comment[seq_stop..-1] =~ re then
all_stop = seq_stop + $~.offset(0).last
seq_stop = seq_stop + $~.offset(1).last
end
end
seq = comment[seq_start..seq_stop]
seq.gsub!(/^(\s*\*?\s*?)(\S|\n)/m, '\2')
comment.slice! all_start...all_stop
meth_obj.call_seq = seq
elsif comment.sub!(/\A\/\*\s*call-seq:(.*?)\*\/\Z/, '') then
meth_obj.call_seq = $1.strip
end
if comment.sub!(/\s*:(nodoc|doc|yields?|args?):\s*(.*)/, '') then
RDoc::Parser.process_directive meth_obj, $1, $2
end
end
##
# Finds a <tt>Document-method</tt> override for +meth_name+ in +class_name+
def find_override_comment(class_name, meth_name)
name = Regexp.escape(meth_name)
if @content =~ %r{Document-method:\s+#{class_name}(?:\.|::|#)#{name}\s*?\n((?>.*?\*/))}m then
if @content =~ %r%Document-method:\s+#{class_name}(?:\.|::|#)#{name}\s*?\n((?>.*?\*/))%m then
$1
elsif @content =~ %r{Document-method:\s#{name}\s*?\n((?>.*?\*/))}m then
elsif @content =~ %r%Document-method:\s#{name}\s*?\n((?>.*?\*/))%m then
$1
end
end
def handle_attr(var_name, attr_name, reader, writer)
##
# Creates a new RDoc::Attr +attr_name+ on class +var_name+ that is either
# +read+, +write+ or both
def handle_attr(var_name, attr_name, read, write)
rw = ''
rw << 'R' if reader
rw << 'W' if writer
rw << 'R' if '1' == read
rw << 'W' if '1' == write
class_name = @known_classes[var_name]
return unless class_name
class_obj = find_class(var_name, class_name)
class_obj = find_class var_name, class_name
if class_obj
comment = find_attr_comment(attr_name)
comment = strip_stars comment
att = RDoc::Attr.new '', attr_name, rw, comment
@stats.add_method att
class_obj.add_attribute(att)
end
return unless class_obj
comment = find_attr_comment var_name, attr_name
comment = strip_stars comment
name = attr_name.gsub(/rb_intern\("([^"]+)"\)/, '\1')
attr = RDoc::Attr.new '', name, rw, comment
class_obj.add_attribute attr
@stats.add_attribute attr
end
##
# Creates a new RDoc::NormalClass or RDoc::NormalModule based on +type+
# named +class_name+ in +parent+ which was assigned to the C +var_name+.
def handle_class_module(var_name, type, class_name, parent, in_module)
parent_name = @known_classes[parent] || parent
@ -497,7 +653,7 @@ class RDoc::Parser::C < RDoc::Parser
class_name
end
if @content =~ %r{Document-class:\s+#{full_name}\s*<\s+([:,\w]+)} then
if @content =~ %r%Document-class:\s+#{full_name}\s*<\s+([:,\w]+)% then
parent_name = $1
end
@ -519,15 +675,14 @@ class RDoc::Parser::C < RDoc::Parser
end
##
# Adds constant comments. By providing some_value: at the start ofthe
# comment you can override the C value of the comment to give a friendly
# definition.
# Adds constants. By providing some_value: at the start of the comment you
# can override the C value of the comment to give a friendly definition.
#
# /* 300: The perfect score in bowling */
# rb_define_const(cFoo, "PERFECT", INT2FIX(300);
#
# Will override +INT2FIX(300)+ with the value +300+ in the output RDoc.
# Values may include quotes and escaped colons (\:).
# Will override <tt>INT2FIX(300)</tt> with the value +300+ in the output
# RDoc. Values may include quotes and escaped colons (\:).
def handle_constants(type, var_name, const_name, definition)
class_name = @known_classes[var_name]
@ -588,22 +743,35 @@ class RDoc::Parser::C < RDoc::Parser
body.gsub(/^#ifdef HAVE_PROTOTYPES.*?#else.*?\n(.*?)#endif.*?\n/m, '\1')
end
##
# Adds an RDoc::AnyMethod +meth_name+ defined on a class or module assigned
# to +var_name+. +type+ is the type of method definition function used.
# +singleton_method+ and +module_function+ create a singleton method.
def handle_method(type, var_name, meth_name, meth_body, param_count,
source_file = nil)
singleton = false
class_name = @known_classes[var_name]
unless class_name then
class_name = @singleton_classes[var_name]
singleton = true if class_name
end
return unless class_name
class_obj = find_class var_name, class_name
if class_obj then
if meth_name == "initialize" then
meth_name = "new"
type = "singleton_method"
if meth_name == 'initialize' then
meth_name = 'new'
singleton = true
type = 'method' # force public
end
meth_obj = RDoc::AnyMethod.new '', meth_name
meth_obj.singleton = %w[singleton_method module_function].include? type
meth_obj.singleton =
singleton || %w[singleton_method module_function].include?(type)
p_count = Integer(param_count) rescue -1
@ -627,7 +795,8 @@ class RDoc::Parser::C < RDoc::Parser
body = @content
end
if find_body(class_name, meth_body, meth_obj, body) and meth_obj.document_self then
if find_body(class_name, meth_body, meth_obj, body) and
meth_obj.document_self then
class_obj.add_method meth_obj
@stats.add_method meth_obj
meth_obj.visibility = :private if 'private_method' == type
@ -635,13 +804,27 @@ class RDoc::Parser::C < RDoc::Parser
end
end
##
# Registers a singleton class +sclass_var+ as a singleton of +class_var+
def handle_singleton sclass_var, class_var
class_name = @known_classes[class_var]
@singleton_classes[sclass_var] = class_name
end
##
# Normalizes tabs in +body+
def handle_tab_width(body)
if /\t/ =~ body
tab_width = @options.tab_width
body.split(/\n/).map do |line|
1 while line.gsub!(/\t+/) { ' ' * (tab_width*$&.length - $`.length % tab_width)} && $~ #`
1 while line.gsub!(/\t+/) do
' ' * (tab_width * $&.length - $`.length % tab_width)
end && $~
line
end .join("\n")
end.join "\n"
else
body
end
@ -654,7 +837,7 @@ class RDoc::Parser::C < RDoc::Parser
# * :title: My Awesome Project
# */
#
# This routine modifies it's parameter
# This routine modifies its parameter
def look_for_directives_in(context, comment)
preprocess = RDoc::Markup::PreProcess.new @file_name, @options.rdoc_include
@ -665,29 +848,33 @@ class RDoc::Parser::C < RDoc::Parser
@options.main_page = param
''
when 'title' then
@options.title = param
@options.default_title = param if @options.respond_to? :default_title=
''
end
end
comment
end
##
# Removes lines that are commented out that might otherwise get picked up
# when scanning for classes and methods
def remove_commented_out_lines
@content.gsub!(%r{//.*rb_define_}, '//')
@content.gsub!(%r%//.*rb_define_%, '//')
end
##
# Removes private comments from +comment+
def remove_private_comments(comment)
comment.gsub!(/\/?\*--\n(.*?)\/?\*\+\+/m, '')
comment.sub!(/\/?\*--\n.*/m, '')
end
##
# Extract the classes/modules and methods from a C file and return the
# corresponding top-level object
# Extracts the classes, modules, methods, attributes, constants and aliases
# from a C file and returns an RDoc::TopLevel for this file
def scan
remove_commented_out_lines
@ -696,6 +883,7 @@ class RDoc::Parser::C < RDoc::Parser
do_methods
do_includes
do_aliases
do_attrs
@top_level
end

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

@ -1,165 +0,0 @@
require 'rdoc/parser'
##
#
# This is an attamept to write a basic parser for Perl's
# POD (Plain old Documentation) format. Ruby code must
# co-exist with Perl, and some tasks are easier in Perl
# than Ruby because of existing libraries.
#
# One difficult is that Perl POD has no means of identifying
# the classes (packages) and methods (subs) with which it
# is associated, it is more like literate programming in so
# far as it just happens to be in the same place as the code,
# but need not be.
#
# We would like to support all the markup the POD provides
# so that it will convert happily to HTML. At the moment
# I don't think I can do that: time constraints.
#
class RDoc::Parser::PerlPOD < RDoc::Parser
parse_files_matching(/.p[lm]$/)
##
# Prepare to parse a perl file
def initialize(top_level, file_name, content, options, stats)
super
preprocess = RDoc::Markup::PreProcess.new @file_name, @options.rdoc_include
preprocess.handle @content do |directive, param|
warn "Unrecognized directive '#{directive}' in #{@file_name}"
end
end
##
# Extract the Pod(-like) comments from the code.
# At its most basic there will ne no need to distinguish
# between the different types of header, etc.
#
# This uses a simple finite state machine, in a very
# procedural pattern. I could "replace case with polymorphism"
# but I think it would obscure the intent, scatter the
# code all over tha place. This machine is necessary
# because POD requires that directives be preceded by
# blank lines, so reading line by line is necessary,
# and preserving state about what is seen is necesary.
def scan
@top_level.comment ||= ""
state=:code_blank
line_number = 0
line = nil
# This started out as a really long nested case statement,
# which also led to repetitive code. I'd like to avoid that
# so I'm using a "table" instead.
# Firstly we need some procs to do the transition and processing
# work. Because these are procs they are closures, and they can
# use variables in the local scope.
#
# First, the "nothing to see here" stuff.
code_noop = lambda do
if line =~ /^\s+$/
state = :code_blank
end
end
pod_noop = lambda do
if line =~ /^\s+$/
state = :pod_blank
end
@top_level.comment += filter(line)
end
begin_noop = lambda do
if line =~ /^\s+$/
state = :begin_blank
end
@top_level.comment += filter(line)
end
# Now for the blocks that process code and comments...
transit_to_pod = lambda do
case line
when /^=(?:pod|head\d+)/
state = :pod_no_blank
@top_level.comment += filter(line)
when /^=over/
state = :over_no_blank
@top_level.comment += filter(line)
when /^=(?:begin|for)/
state = :begin_no_blank
end
end
process_pod = lambda do
case line
when /^\s*$/
state = :pod_blank
@top_level.comment += filter(line)
when /^=cut/
state = :code_no_blank
when /^=end/
$stderr.puts "'=end' unexpected at #{line_number} in #{@file_name}"
else
@top_level.comment += filter(line)
end
end
process_begin = lambda do
case line
when /^\s*$/
state = :begin_blank
@top_level.comment += filter(line)
when /^=end/
state = :code_no_blank
when /^=cut/
$stderr.puts "'=cut' unexpected at #{line_number} in #{@file_name}"
else
@top_level.comment += filter(line)
end
end
transitions = { :code_no_blank => code_noop,
:code_blank => transit_to_pod,
:pod_no_blank => pod_noop,
:pod_blank => process_pod,
:begin_no_blank => begin_noop,
:begin_blank => process_begin}
@content.each_line do |l|
line = l
line_number += 1
transitions[state].call
end # each line
@top_level
end
# Filter the perl markup that does the same as the rdoc
# filtering. Only basic for now. Will probably need a
# proper parser to cope with C<<...>> etc
def filter(comment)
return '' if comment =~ /^=pod\s*$/
comment.gsub!(/^=pod/, '==')
comment.gsub!(/^=head(\d+)/) do
"=" * $1.to_i
end
comment.gsub!(/=item/, '');
comment.gsub!(/C<(.*?)>/, '<tt>\1</tt>');
comment.gsub!(/I<(.*?)>/, '<i>\1</i>');
comment.gsub!(/B<(.*?)>/, '<b>\1</b>');
comment
end
end

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

@ -11,8 +11,8 @@ require 'rdoc/ruby_token'
require 'rdoc/ruby_lex'
require 'rdoc/code_objects'
require 'rdoc/tokenstream'
require 'rdoc/markup/preprocess'
require 'rdoc/token_stream'
require 'rdoc/markup/pre_process'
require 'rdoc/parser'
require 'rdoc/parser/ruby_tools'
@ -162,6 +162,9 @@ class RDoc::Parser::Ruby < RDoc::Parser
SINGLE = "<<"
##
# Creates a new Ruby parser.
def initialize(top_level, file_name, content, options, stats)
super
@ -209,10 +212,13 @@ class RDoc::Parser::Ruby < RDoc::Parser
comment
end
##
# Aborts with +msg+
def error(msg)
msg = make_message msg
$stderr.puts msg
exit false
abort msg
end
##
@ -229,6 +235,10 @@ class RDoc::Parser::Ruby < RDoc::Parser
meth
end
##
# Looks for a true or false token. Returns false if TkFALSE or TkNIL are
# found.
def get_bool
skip_tkspace
tk = get_tk
@ -245,20 +255,24 @@ class RDoc::Parser::Ruby < RDoc::Parser
##
# Look for the name of a class of module (optionally with a leading :: or
# with :: separated named) and return the ultimate name and container
# with :: separated named) and return the ultimate name, the associated
# container, and the given name (with the ::).
def get_class_or_module(container)
skip_tkspace
name_t = get_tk
given_name = ''
# class ::A -> A is in the top level
case name_t
when TkCOLON2, TkCOLON3 then # bug
name_t = get_tk
container = @top_level
given_name << '::'
end
skip_tkspace false
given_name << name_t.name
while TkCOLON2 === peek_tk do
prev_container = container
@ -268,9 +282,10 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
get_tk
name_t = get_tk
given_name << '::' << name_t.name
end
skip_tkspace false
return [container, name_t]
return [container, name_t, given_name]
end
##
@ -347,6 +362,9 @@ class RDoc::Parser::Ruby < RDoc::Parser
name
end
##
# Extracts a name or symbol from the token stream.
def get_symbol_or_name
tk = get_tk
case tk
@ -361,7 +379,10 @@ class RDoc::Parser::Ruby < RDoc::Parser
text
when TkId, TkOp then
tk.name
when TkSTRING, TkDSTRING then
when TkAMPER,
TkDSTRING,
TkSTAR,
TkSTRING then
tk.text
else
raise RDoc::Error, "Name or symbol expected (got #{tk})"
@ -374,7 +395,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
# # :stopdoc:
# # Don't display comment from this point forward
#
# This routine modifies it's parameter
# This routine modifies its +comment+ parameter.
def look_for_directives_in(context, comment)
preprocess = RDoc::Markup::PreProcess.new @file_name, @options.rdoc_include
@ -382,9 +403,10 @@ class RDoc::Parser::Ruby < RDoc::Parser
preprocess.handle comment, context do |directive, param|
case directive
when 'enddoc' then
throw :enddoc
context.done_documenting = true
''
when 'main' then
@options.main_page = param
@options.main_page = param if @options.respond_to? :main_page
''
when 'method', 'singleton-method',
'attr', 'attr_accessor', 'attr_reader', 'attr_writer' then
@ -401,7 +423,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
context.stop_doc
''
when 'title' then
@options.title = param
@options.default_title = param if @options.respond_to? :default_title=
''
end
end
@ -426,23 +448,28 @@ class RDoc::Parser::Ruby < RDoc::Parser
def parse_attr(context, single, tk, comment)
args = parse_symbol_arg 1
if args.size > 0
if args.size > 0 then
name = args[0]
rw = "R"
skip_tkspace false
tk = get_tk
if TkCOMMA === tk then
rw = "RW" if get_bool
else
unget_tk tk
end
att = RDoc::Attr.new get_tkread, name, rw, comment
att = RDoc::Attr.new get_tkread, name, rw, comment, single == SINGLE
att.record_location @top_level
read_documentation_modifiers att, RDoc::ATTR_MODIFIERS
if att.document_self
context.add_attribute(att)
end
context.add_attribute att if att.document_self
@stats.add_attribute att
else
warn("'attr' ignored - looks like a variable")
warn "'attr' ignored - looks like a variable"
end
end
@ -452,12 +479,8 @@ class RDoc::Parser::Ruby < RDoc::Parser
def parse_attr_accessor(context, single, tk, comment)
args = parse_symbol_arg
get_tkread
rw = "?"
# TODO If nodoc is given, don't document any of them
tmp = RDoc::CodeObject.new
read_documentation_modifiers tmp, RDoc::ATTR_MODIFIERS
return unless tmp.document_self
@ -471,17 +494,25 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
for name in args
att = RDoc::Attr.new get_tkread, name, rw, comment
att = RDoc::Attr.new get_tkread, name, rw, comment, single == SINGLE
att.record_location @top_level
context.add_attribute att
@stats.add_attribute att
end
end
##
# Parses an +alias+ in +context+ with +comment+
def parse_alias(context, single, tk, comment)
skip_tkspace
if TkLPAREN === peek_tk then
get_tk
skip_tkspace
end
new_name = get_symbol_or_name
@scanner.instance_eval { @lex_state = EXPR_FNAME }
@ -498,11 +529,20 @@ class RDoc::Parser::Ruby < RDoc::Parser
return
end
al = RDoc::Alias.new get_tkread, old_name, new_name, comment
al = RDoc::Alias.new(get_tkread, old_name, new_name, comment,
single == SINGLE)
al.record_location @top_level
read_documentation_modifiers al, RDoc::ATTR_MODIFIERS
context.add_alias al if al.document_self
@stats.add_alias al
al
end
##
# Extracts call parameters from the token stream.
def parse_call_parameters(tk)
end_token = case tk
when TkLPAREN, TkfLPAREN
@ -540,28 +580,33 @@ class RDoc::Parser::Ruby < RDoc::Parser
res
end
##
# Parses a class in +context+ with +comment+
def parse_class(container, single, tk, comment)
container, name_t = get_class_or_module container
declaration_context = container
container, name_t, given_name = get_class_or_module container
case name_t
when TkCONSTANT
name = name_t.name
superclass = "Object"
superclass = '::Object'
if TkLT === peek_tk then
get_tk
skip_tkspace
superclass = get_class_specification
superclass = "<unknown>" if superclass.empty?
superclass = '(unknown)' if superclass.empty?
end
cls_type = single == SINGLE ? RDoc::SingleClass : RDoc::NormalClass
cls = container.add_class cls_type, name, superclass
cls = declaration_context.add_class cls_type, given_name, superclass
read_documentation_modifiers cls, RDoc::CLASS_MODIFIERS
cls.record_location @top_level
cls.comment = comment
cls.comment = comment if cls.document_self
@top_level.add_to_classes_or_modules cls
@stats.add_class cls
parse_statements cls
@ -569,7 +614,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
case name = get_class_specification
when "self", container.name
parse_statements container, SINGLE
when /\A[A-Z]/
else
other = RDoc::TopLevel.find_class_named name
unless other then
@ -578,6 +623,15 @@ class RDoc::Parser::Ruby < RDoc::Parser
other.comment = comment
end
# notify :nodoc: all if not a constant-named class/module
# (and remove any comment)
unless name =~ /\A(::)?[A-Z]/
other.document_self = nil
other.document_children = false
other.clear_comment
end
@top_level.add_to_classes_or_modules other
@stats.add_class other
read_documentation_modifiers other, RDoc::CLASS_MODIFIERS
@ -589,9 +643,15 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
end
##
# Parses a constant in +context+ with +comment+
def parse_constant(container, tk, comment)
name = tk.name
skip_tkspace false
return unless name =~ /^\w+$/
eq_tk = get_tk
unless TkASSIGN === eq_tk then
@ -615,9 +675,9 @@ class RDoc::Parser::Ruby < RDoc::Parser
loop do
case tk
when TkSEMICOLON then
break
when TkLPAREN, TkfLPAREN, TkLBRACE, TkLBRACK, TkDO, TkIF, TkUNLESS,
TkCASE then
break if nest <= 0
when TkLPAREN, TkfLPAREN, TkLBRACE, TkfLBRACE, TkLBRACK, TkfLBRACK,
TkDO, TkIF, TkUNLESS, TkCASE, TkDEF, TkBEGIN then
nest += 1
when TkRPAREN, TkRBRACE, TkRBRACK, TkEND then
nest -= 1
@ -654,10 +714,11 @@ class RDoc::Parser::Ruby < RDoc::Parser
tk = get_tk
end
res = get_tkread.tr("\n", " ").strip
res = get_tkread.gsub(/^[ \t]+/, '').strip
res = "" if res == ";"
con = RDoc::Constant.new name, res, comment
con.record_location @top_level
read_documentation_modifiers con, RDoc::CONSTANT_MODIFIERS
@stats.add_constant con
@ -679,6 +740,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
name = $1 unless $1.empty?
meth = RDoc::GhostMethod.new get_tkread, name
meth.record_location @top_level
meth.singleton = singleton
meth.start_collecting_tokens
@ -709,13 +771,19 @@ class RDoc::Parser::Ruby < RDoc::Parser
name = $3 unless $3.empty?
# TODO authorize 'singleton-attr...'?
att = RDoc::Attr.new get_tkread, name, rw, comment
att.record_location @top_level
container.add_attribute att
@stats.add_method att
@stats.add_attribute att
end
end
##
# Parses an +include+ in +context+ with +comment+
def parse_include(context, comment)
loop do
skip_tkspace_comment
@ -759,8 +827,6 @@ class RDoc::Parser::Ruby < RDoc::Parser
def parse_meta_attr(context, single, tk, comment)
args = parse_symbol_arg
get_tkread
rw = "?"
# If nodoc is given, don't document any of them
@ -779,12 +845,19 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
if name then
att = RDoc::Attr.new get_tkread, name, rw, comment
att = RDoc::Attr.new get_tkread, name, rw, comment, single == SINGLE
att.record_location @top_level
context.add_attribute att
@stats.add_attribute att
else
args.each do |attr_name|
att = RDoc::Attr.new get_tkread, attr_name, rw, comment
att = RDoc::Attr.new(get_tkread, attr_name, rw, comment,
single == SINGLE)
att.record_location @top_level
context.add_attribute att
@stats.add_attribute att
end
end
end
@ -825,6 +898,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
meth = RDoc::MetaMethod.new get_tkread, name
meth.record_location @top_level
meth.singleton = singleton
remove_token_listener self
@ -882,7 +956,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
token_listener self do
@scanner.instance_eval do @lex_state = EXPR_FNAME end
skip_tkspace false
skip_tkspace
name_t = get_tk
back_tk = skip_tkspace
meth = nil
@ -922,11 +996,17 @@ class RDoc::Parser::Ruby < RDoc::Parser
container.record_location @top_level
end
when TkIDENTIFIER, TkIVAR then
when TkIDENTIFIER, TkIVAR, TkGVAR then
dummy = RDoc::Context.new
dummy.parent = container
skip_method dummy
return
when TkTRUE, TkFALSE, TkNIL then
klass_name = "#{name_t.name.capitalize}Class"
container = RDoc::TopLevel.find_class_named klass_name
container ||= @top_level.add_class RDoc::NormalClass, klass_name
name = name_t2.name
else
warn "unexpected method name token #{name_t.inspect}"
# break
@ -959,6 +1039,8 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
end
meth.record_location @top_level
meth.start_collecting_tokens
indent = TkSPACE.new nil, 1, 1
indent.set_text " " * column
@ -1001,6 +1083,9 @@ class RDoc::Parser::Ruby < RDoc::Parser
@stats.add_method meth
end
##
# Extracts +yield+ parameters from +method+
def parse_method_or_yield_parameters(method = nil,
modifiers = RDoc::METHOD_MODIFIERS)
skip_tkspace false
@ -1024,14 +1109,16 @@ class RDoc::Parser::Ruby < RDoc::Parser
loop do
case tk
when TkSEMICOLON then
break
when TkLBRACE then
break if nest == 0
when TkLBRACE, TkfLBRACE then
nest += 1
when TkRBRACE then
# we might have a.each {|i| yield i }
unget_tk(tk) if nest.zero?
nest -= 1
break if nest <= 0
if nest <= 0
# we might have a.each { |i| yield i }
unget_tk(tk) if nest < 0
break
end
when TkLPAREN, TkfLPAREN then
nest += 1
when end_token then
@ -1041,6 +1128,8 @@ class RDoc::Parser::Ruby < RDoc::Parser
else
break unless @scanner.continue
end
when TkRPAREN then
nest -= 1
when method && method.block_params.nil? && TkCOMMENT then
unget_tk tk
read_documentation_modifiers method, modifiers
@ -1078,8 +1167,11 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
end
##
# Parses an RDoc::NormalModule in +container+ with +comment+
def parse_module(container, single, tk, comment)
container, name_t = get_class_or_module container
container, name_t, = get_class_or_module container
name = name_t.name
@ -1087,12 +1179,16 @@ class RDoc::Parser::Ruby < RDoc::Parser
mod.record_location @top_level
read_documentation_modifiers mod, RDoc::CLASS_MODIFIERS
mod.comment = comment if mod.document_self
parse_statements(mod)
mod.comment = comment
@top_level.add_to_classes_or_modules mod
@stats.add_module mod
end
##
# Parses an RDoc::Require in +context+ containing +comment+
def parse_require(context, comment)
skip_tkspace_comment
tk = get_tk
@ -1105,7 +1201,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
name = tk.text if TkSTRING === tk
if name then
context.add_require RDoc::Require.new(name, comment)
@top_level.add_require RDoc::Require.new(name, comment)
else
unget_tk tk
end
@ -1206,7 +1302,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
# We can't solve the general case, but we can handle most occurrences by
# ignoring a do at the end of a line.
when TkUNTIL, TkWHILE then
when TkUNTIL, TkWHILE then
nest += 1
skip_optional_do_after_expression
@ -1275,9 +1371,14 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
end
##
# Parse up to +no+ symbol arguments
def parse_symbol_arg(no = nil)
args = []
skip_tkspace_comment
case tk = get_tk
when TkLPAREN
loop do
@ -1320,28 +1421,40 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
end
end
args
end
##
# Returns symbol text from the next token
def parse_symbol_in_arg
case tk = get_tk
when TkSYMBOL
tk.text.sub(/^:/, '')
when TkSTRING
eval @read[-1]
when TkDSTRING, TkIDENTIFIER then
nil # ignore
else
warn("Expected symbol or string, got #{tk.inspect}") if $DEBUG_RDOC
nil
end
end
##
# Parses statements at the toplevel in +container+
def parse_top_level_statements(container)
comment = collect_first_comment
look_for_directives_in(container, comment)
container.comment = comment unless comment.empty?
container.comment = comment if container.document_self unless comment.empty?
parse_statements container, NORMAL, nil, comment
end
##
# Determines the visibility in +container+ from +tk+
def parse_visibility(container, single, tk)
singleton = (single == SINGLE)
@ -1383,7 +1496,8 @@ class RDoc::Parser::Ruby < RDoc::Parser
container.methods_matching args do |m|
s_m = m.dup
s_m.singleton = true if RDoc::AnyMethod === s_m
s_m.record_location @top_level
s_m.singleton = true
s_m.visibility = :public
module_functions << s_m
end
@ -1403,6 +1517,9 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
end
##
# Determines the block parameter for +context+
def parse_yield(context, single, tk, method)
return if method.block_params
@ -1423,93 +1540,81 @@ class RDoc::Parser::Ruby < RDoc::Parser
#
# We return the directive name and any parameters as a two element array
def read_directive(allowed)
def read_directive allowed
tk = get_tk
result = nil
if TkCOMMENT === tk then
if tk.text =~ /\s*:?(\w+):\s*(.*)/ then
directive = $1.downcase
if allowed.include? directive then
result = [directive, $2]
end
end
return unless tk.text =~ /\s*:?(\w+):\s*(.*)/
directive = $1.downcase
return [directive, $2] if allowed.include? directive
else
unget_tk tk
end
result
end
##
# Handles the directive for +context+ if the directive is listed in +allow+.
# This method is called for directives following a definition.
def read_documentation_modifiers(context, allow)
dir = read_directive(allow)
directive, value = read_directive allow
case dir[0]
when "notnew", "not_new", "not-new" then
return unless directive
case directive
when 'notnew', 'not_new', 'not-new' then
context.dont_rename_initialize = true
when "nodoc" then
context.document_self = false
if dir[1].downcase == "all"
context.document_children = false
end
when "doc" then
context.document_self = true
context.force_documentation = true
when "yield", "yields" then
unless context.params.nil?
context.params.sub!(/(,|)\s*&\w+/,'') # remove parameter &proc
end
context.block_params = dir[1]
when "arg", "args" then
context.params = dir[1]
end if dir
else
RDoc::Parser.process_directive context, directive, value
end
end
##
# Removes private comments from +comment+
def remove_private_comments(comment)
comment.gsub!(/^#--\n.*?^#\+\+/m, '')
comment.sub!(/^#--\n.*/m, '')
comment.gsub!(/^#--\n.*?^#\+\+\n?/m, '')
comment.sub!(/^#--\n.*\n?/m, '')
end
##
# Scans this ruby file for ruby constructs
def scan
reset
catch :eof do
catch :enddoc do
begin
parse_top_level_statements @top_level
rescue StandardError => e
bytes = ''
begin
parse_top_level_statements @top_level
rescue StandardError => e
bytes = ''
20.times do @scanner.ungetc end
count = 0
60.times do |i|
count = i
byte = @scanner.getc
break unless byte
bytes << byte
end
count -= 20
count.times do @scanner.ungetc end
20.times do @scanner.ungetc end
count = 0
60.times do |i|
count = i
byte = @scanner.getc
break unless byte
bytes << byte
end
count -= 20
count.times do @scanner.ungetc end
$stderr.puts <<-EOF
$stderr.puts <<-EOF
#{self.class} failure around line #{@scanner.line_no} of
#{@file_name}
EOF
EOF
unless bytes.empty? then
$stderr.puts
$stderr.puts bytes.inspect
end
raise e
unless bytes.empty? then
$stderr.puts
$stderr.puts bytes.inspect
end
raise e
end
end
@ -1574,6 +1679,9 @@ class RDoc::Parser::Ruby < RDoc::Parser
unget_tk(tk) unless TkIN === tk
end
##
# Skips the next method in +container+
def skip_method container
meth = RDoc::AnyMethod.new "", "anon"
parse_method_parameters meth
@ -1591,6 +1699,9 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
end
##
# Prints +msg+ to +$stderr+ unless we're being quiet
def warn(msg)
return if @options.quiet
msg = make_message msg

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

@ -49,7 +49,6 @@ module RDoc::Parser::RubyTools
obj.pop_token
end if @token_listeners
else
warn("':' not followed by identifier or operator")
tk = tk1
end
end
@ -62,6 +61,10 @@ module RDoc::Parser::RubyTools
tk
end
##
# Reads and returns all tokens up to one of +tokens+. Leaves the matched
# token in the token list.
def get_tk_until(*tokens)
read = []

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

@ -1,7 +1,6 @@
##
# 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.
# comment.
class RDoc::Parser::Simple < RDoc::Parser
@ -32,10 +31,16 @@ class RDoc::Parser::Simple < RDoc::Parser
@top_level
end
def remove_private_comments(comment)
comment.gsub(/^--\n.*?^\+\+/m, '').sub(/^--\n.*/m, '')
##
# Removes comments wrapped in <tt>--/++</tt>
def remove_private_comments text
text.gsub(/^--\n.*?^\+\+/m, '').sub(/^--\n.*/m, '')
end
##
# Removes the encoding magic comment from +text+
def remove_coding_comment text
text.sub(/\A# .*coding[=:].*$/, '')
end

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

@ -1,5 +1,6 @@
require 'rdoc'
require 'rdoc/encoding'
require 'rdoc/parser'
# Simple must come first
@ -23,7 +24,28 @@ require 'time'
# rdoc.document(args)
#
# Where +args+ is an array of strings, each corresponding to an argument you'd
# give rdoc on the command line. See rdoc/rdoc.rb for details.
# give rdoc on the command line. See <tt>rdoc --help<tt> for details.
#
# = Plugins
#
# When you <tt>require 'rdoc/rdoc'</tt> RDoc looks for 'rdoc/discover' files
# in your installed gems. This can be used to load alternate generators or
# add additional preprocessor directives.
#
# You will want to wrap your plugin loading in an RDoc version check.
# Something like:
#
# begin
# gem 'rdoc', '~> 3'
# require 'path/to/my/awesome/rdoc/plugin'
# rescue Gem::LoadError
# end
#
# The most obvious plugin type is a new output generator. See RDoc::Generator
# for details.
#
# You can also hook into RDoc::Markup to add new directives (:nodoc: is a
# directive). See RDoc::Markup::PreProcess::register for details.
class RDoc::RDoc
@ -79,6 +101,10 @@ class RDoc::RDoc
@current = rdoc
end
##
# Creates a new RDoc::RDoc instance. Call #document to parse files and
# generate documentation.
def initialize
@current = nil
@exclude = nil
@ -142,7 +168,9 @@ class RDoc::RDoc
last = {}
if File.exist? dir then
if @options.dry_run then
# do nothing
elsif File.exist? dir then
error "#{dir} exists and is not a directory" unless File.directory? dir
begin
@ -167,7 +195,7 @@ you'll need to specify a different output directory name (using the --op <dir>
option)
ERROR
end
end unless @options.force_output
else
FileUtils.mkdir_p dir
end
@ -179,6 +207,8 @@ option)
# Update the flag file in an output directory.
def update_output_dir(op_dir, time, last = {})
return if @options.dry_run
open output_flag_file(op_dir), "w" do |f|
f.puts time.rfc2822
last.each do |n, t|
@ -277,7 +307,9 @@ option)
def parse_file filename
@stats.add_file filename
content = read_file_contents filename
encoding = @options.encoding if defined?(Encoding)
content = RDoc::Encoding.read_file filename, encoding
return unless content
@ -288,11 +320,22 @@ option)
return unless parser
parser.scan
# restart documentation for the classes & modules found
top_level.classes_or_modules.each do |cm|
cm.done_documenting = false
end
top_level
rescue => e
$stderr.puts <<-EOF
Before reporting this, could you check that the file you're documenting
compiles cleanly--RDoc is not a full Ruby parser, and gets confused easily if
fed invalid programs.
has proper syntax:
#{Gem.ruby} -c #{filename}
RDoc is not a full Ruby parser and will fail when fed invalid ruby programs.
The internal error was:
@ -300,7 +343,7 @@ The internal error was:
EOF
$stderr.puts e.backtrace.join("\n\t") if $RDOC_DEBUG
$stderr.puts e.backtrace.join("\n\t") if $DEBUG_RDOC
raise e
nil
@ -344,11 +387,9 @@ The internal error was:
# For simplicity, +argv+ is an array of strings, equivalent to the strings
# that would be passed on the command line. (This isn't a coincidence, as
# we _do_ pass in ARGV when running interactively). For a list of options,
# see rdoc/rdoc.rb. By default, output will be stored in a directory
# see <tt>rdoc --help</tt>. By default, output will be stored in a directory
# called +doc+ below the current directory, so make sure you're somewhere
# writable before invoking.
#
# Throws: RDoc::Error on error
def document(argv)
RDoc::TopLevel.reset
@ -364,29 +405,36 @@ The internal error was:
@exclude = @options.exclude
@last_modified = setup_output_dir @options.op_dir, @options.force_update
unless @options.coverage_report then
@last_modified = setup_output_dir @options.op_dir, @options.force_update
end
start_time = Time.now
file_info = parse_files @options.files
@options.title = "RDoc Documentation"
@options.default_title = "RDoc Documentation"
if file_info.empty?
RDoc::TopLevel.complete @options.visibility
if @options.coverage_report then
puts
puts @stats.report
elsif file_info.empty?
$stderr.puts "\nNo newer files." unless @options.quiet
else
gen_klass = @options.generator
unless @options.quiet then
$stderr.puts "\nGenerating #{gen_klass.name.sub(/^.*::/, '')}..."
end
@generator = gen_klass.for @options
@generator = gen_klass.new @options
Dir.chdir @options.op_dir do
begin
self.class.current = self
unless @options.quiet then
$stderr.puts "\nGenerating #{gen_klass.name.sub(/^.*::/, '')} format into #{Dir.pwd}..."
end
@generator.generate file_info
update_output_dir ".", start_time, @last_modified
ensure
@ -397,26 +445,10 @@ The internal error was:
unless @options.quiet or not @stats then
puts
@stats.print
end
end
def read_file_contents(filename)
content = open filename, "rb" do |f| f.read end
utf8 = content.sub!(/\A\xef\xbb\xbf/, '')
if defined? Encoding then
if /coding[=:]\s*([^\s;]+)/i =~ content[%r"\A(?:#!.*\n)?.*\n"]
enc = ::Encoding.find($1)
end
if enc ||= (Encoding::UTF_8 if utf8)
content.force_encoding(enc)
end
puts @stats.summary
end
content
rescue Errno::EISDIR, Errno::ENOENT
nil
exit @stats.fully_documented? if @options.coverage_report
end
##

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

@ -16,6 +16,7 @@ class RDoc::Require < RDoc::CodeObject
def initialize(name, comment)
super()
@name = name.gsub(/'|"/, "") #'
@top_level = nil
self.comment = comment
end
@ -28,5 +29,25 @@ class RDoc::Require < RDoc::CodeObject
]
end
def to_s # :nodoc:
"require #{name} in: #{parent}"
end
##
# The RDoc::TopLevel corresponding to this require, or +nil+ if not found.
def top_level
@top_level ||= begin
tl = RDoc::TopLevel.all_files_hash[name + '.rb']
if tl.nil? and RDoc::TopLevel.all_files.first.full_name =~ %r(^lib/) then
# second chance
tl = RDoc::TopLevel.all_files_hash['lib/' + name + '.rb']
end
tl
end
end
end

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

@ -6,6 +6,11 @@ begin
rescue LoadError
end
begin
require 'win32console'
rescue LoadError
end
require 'rdoc/ri'
require 'rdoc/ri/paths'
require 'rdoc/markup'
@ -55,6 +60,9 @@ class RDoc::RI::Driver
end
end
##
# An RDoc::RI::Store for each entry in the RI path
attr_accessor :stores
##
@ -97,23 +105,10 @@ class RDoc::RI::Driver
##
# Parses +argv+ and returns a Hash of options
def self.process_args argv = []
def self.process_args argv
options = default_options
opts = OptionParser.new
setup_options(opts, options)
argv = ENV['RI'].to_s.split.concat argv
opts.parse!(argv)
fixup_options(options, argv)
rescue OptionParser::ParseError => e
puts opts, nil, e
abort
end
def self.setup_options(opt, options)
begin
opts = OptionParser.new do |opt|
opt.accept File do |file,|
File.readable?(file) and not File.directory?(file) and file
end
@ -133,7 +128,7 @@ Where name can be:
All class names may be abbreviated to their minimum unambiguous form. If a name
is ambiguous, all valid options will be listed.
The form '.' method matches either class or instance methods, while #method
A '.' matches either class or instance methods, while #method
matches only instance and ::method matches only class methods.
For example:
@ -143,7 +138,7 @@ For example:
#{opt.program_name} File.new
#{opt.program_name} zip
Note that shell quoting may be required for method names containing
Note that shell quoting or escaping may be required for method names containing
punctuation:
#{opt.program_name} 'Array.[]'
@ -287,9 +282,11 @@ Options may also be set in the 'RI' environment variable.
options[:dump_path] = value
end
end
end
def self.fixup_options(options, argv)
argv = ENV['RI'].to_s.split.concat argv
opts.parse! argv
options[:names] = argv
options[:use_stdout] ||= !$stdout.tty?
@ -297,6 +294,12 @@ Options may also be set in the 'RI' environment variable.
options[:width] ||= 72
options
rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e
puts opts
puts
puts e
exit 1
end
##
@ -359,7 +362,7 @@ Options may also be set in the 'RI' environment variable.
paths = RDoc::Markup::Verbatim.new
also_in.each do |store|
paths.parts.push ' ', store.friendly_path, "\n"
paths.parts.push store.friendly_path, "\n"
end
out << paths
end
@ -427,7 +430,7 @@ Options may also be set in the 'RI' environment variable.
verb = RDoc::Markup::Verbatim.new
wout.each do |incl|
verb.push ' ', incl.name, "\n"
verb.push incl.name, "\n"
end
out << verb
@ -446,7 +449,7 @@ Options may also be set in the 'RI' environment variable.
out << RDoc::Markup::BlankLine.new
out.push(*methods.map do |method|
RDoc::Markup::Verbatim.new ' ', method
RDoc::Markup::Verbatim.new method
end)
out << RDoc::Markup::BlankLine.new
@ -664,8 +667,8 @@ Options may also be set in the 'RI' environment variable.
if method.arglists then
arglists = method.arglists.chomp.split "\n"
arglists = arglists.map { |line| [' ', line, "\n"] }
out << RDoc::Markup::Verbatim.new(*arglists.flatten)
arglists = arglists.map { |line| line + "\n" }
out << RDoc::Markup::Verbatim.new(*arglists)
out << RDoc::Markup::Rule.new(1)
end
@ -846,6 +849,17 @@ Options may also be set in the 'RI' environment variable.
exit
end
##
# Is +file+ in ENV['PATH']?
def in_path? file
return true if file =~ %r%\A/% and File.exist? file
ENV['PATH'].split(File::PATH_SEPARATOR).any? do |path|
File.exist? File.join(path, file)
end
end
##
# Lists classes known to ri
@ -1041,7 +1055,11 @@ Options may also be set in the 'RI' environment variable.
pagers.compact.uniq.each do |pager|
next unless pager
io = IO.popen pager, "w" rescue next
pager_cmd = pager.split.first
next unless in_path? pager_cmd
io = IO.popen(pager, 'w') rescue next
next if $? and $?.exited? # pager didn't work

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

@ -10,10 +10,21 @@ module RDoc::RI::Paths
version = RbConfig::CONFIG['ruby_version']
base = File.join RbConfig::CONFIG['ridir'], version
base = if RbConfig::CONFIG.key? 'ridir' then
File.join RbConfig::CONFIG['ridir'], version
else
File.join RbConfig::CONFIG['datadir'], 'ri', version
end
SYSDIR = File.join base, "system"
SITEDIR = File.join base, "site"
HOMEDIR = (File.expand_path('~/.rdoc') rescue nil)
homedir = File.expand_path('~') ||
ENV['HOME'] || ENV['USERPROFILE'] || ENV['HOMEPATH']
HOMEDIR = if homedir then
File.join homedir, ".rdoc"
end
#:startdoc:
@gemdirs = nil

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

@ -10,6 +10,11 @@ require 'fileutils'
class RDoc::RI::Store
##
# If true this Store will not write any files
attr_accessor :dry_run
##
# Path this store reads or writes
@ -21,14 +26,18 @@ class RDoc::RI::Store
attr_accessor :type
##
# The contents of the Store
attr_reader :cache
##
# Creates a new Store of +type+ that will load or save to +path+
def initialize path, type = nil
@type = type
@path = path
@dry_run = false
@type = type
@path = path
@cache = {
:class_methods => {},
@ -178,6 +187,8 @@ class RDoc::RI::Store
@cache[:instance_methods].each do |_, m| m.uniq!; m.sort! end
@cache[:modules].uniq!; @cache[:modules].sort!
return if @dry_run
open cache_path, 'wb' do |io|
Marshal.dump @cache, io
end
@ -187,7 +198,7 @@ class RDoc::RI::Store
# Writes the ri data for +klass+
def save_class klass
FileUtils.mkdir_p class_path(klass.full_name)
FileUtils.mkdir_p class_path(klass.full_name) unless @dry_run
@cache[:modules] << klass.full_name
@ -214,7 +225,7 @@ class RDoc::RI::Store
@cache[:ancestors][klass.full_name].push(*ancestors)
attributes = klass.attributes.map do |attribute|
"#{attribute.type} #{attribute.name}"
"#{attribute.definition} #{attribute.name}"
end
unless attributes.empty? then
@ -222,6 +233,8 @@ class RDoc::RI::Store
@cache[:attributes][klass.full_name].push(*attributes)
end
return if @dry_run
open path, 'wb' do |io|
Marshal.dump klass, io
end
@ -231,7 +244,7 @@ class RDoc::RI::Store
# Writes the ri data for +method+ on +klass+
def save_method klass, method
FileUtils.mkdir_p class_path(klass.full_name)
FileUtils.mkdir_p class_path(klass.full_name) unless @dry_run
cache = if method.singleton then
@cache[:class_methods]
@ -241,6 +254,8 @@ class RDoc::RI::Store
cache[klass.full_name] ||= []
cache[klass.full_name] << method.name
return if @dry_run
open method_file(klass.full_name, method.full_name), 'wb' do |io|
Marshal.dump method, io
end

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

@ -92,9 +92,9 @@ class RDoc::RubyLex
end
def inspect # :nodoc:
"#<%s:0x%x lex_state %p space_seen %p>" % [
"#<%s:0x%x pos %d lex_state %p space_seen %p>" % [
self.class, object_id,
@lex_state, @space_seen,
@io.pos, @lex_state, @space_seen,
]
end
@ -149,6 +149,7 @@ class RDoc::RubyLex
else
@char_no += 1
end
c
end
@ -674,7 +675,7 @@ class RDoc::RubyLex
tk_c = TkLPAREN
end
@indent_stack.push tk_c
Token(tk_c)
Token tk_c
end
@OP.def_rule("[]", proc{|op, io| @lex_state == EXPR_FNAME}) do
@ -822,6 +823,12 @@ class RDoc::RubyLex
end
end
IDENT_RE = if defined? Encoding then
/[\w\u0080-\uFFFF]/u
else
/[\w\x80-\xFF]/
end
def identify_identifier
token = ""
if peek(0) =~ /[$@]/
@ -831,15 +838,7 @@ class RDoc::RubyLex
end
end
# HACK to avoid a warning the regexp is hidden behind an eval
# HACK need a better way to detect oniguruma
@identifier_re ||= if defined? Encoding then
eval '/[\p{Alnum}_]/u'
else
eval '/[\w\x80-\xff]/'
end
while (ch = getc) =~ @identifier_re
while (ch = getc) =~ IDENT_RE do
print " :#{ch}: " if RDoc::RubyLex.debug?
token.concat ch
end

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

@ -178,7 +178,7 @@ module RDoc::RubyToken
end
class TkUnknownChar < Token
def initialize(seek, line_no, char_no, id)
def initialize(seek, line_no, char_no, name)
super(seek, line_no, char_no)
@name = name
end
@ -253,7 +253,7 @@ module RDoc::RubyToken
[:TkWHILE, TkKW, "while", EXPR_BEG, :TkWHILE_MOD],
[:TkUNTIL, TkKW, "until", EXPR_BEG, :TkUNTIL_MOD],
[:TkFOR, TkKW, "for", EXPR_BEG],
[:TkBREAK, TkKW, "break", EXPR_END],
[:TkBREAK, TkKW, "break", EXPR_MID],
[:TkNEXT, TkKW, "next", EXPR_END],
[:TkREDO, TkKW, "redo", EXPR_END],
[:TkRETRY, TkKW, "retry", EXPR_END],

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

@ -5,8 +5,9 @@ require 'rdoc/class_module'
class RDoc::SingleClass < RDoc::ClassModule
# Adds the superclass to the included modules.
def ancestors
includes + [superclass]
superclass ? super + [superclass] : super
end
end

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

@ -1,247 +1,287 @@
require 'rdoc'
##
# RDoc stats collector
# RDoc statistics collector which prints a summary and report of a project's
# documentation totals.
class RDoc::Stats
attr_reader :nodoc_constants
attr_reader :nodoc_methods
##
# Count of files parsed during parsing
attr_reader :files_so_far
##
# Total number of files found
attr_reader :num_constants
attr_reader :num_files
attr_reader :num_methods
attr_reader :total_files
##
# Creates a new Stats that will have +num_files+. +verbosity+ defaults to 1
# which will create an RDoc::Stats::Normal outputter.
def initialize(total_files, verbosity = 1)
@nodoc_constants = 0
@nodoc_methods = 0
@num_constants = 0
@num_files = 0
@num_methods = 0
@total_files = total_files
def initialize num_files, verbosity = 1
@files_so_far = 0
@num_files = num_files
@fully_documented = nil
@start = Time.now
@display = case verbosity
when 0 then Quiet.new total_files
when 1 then Normal.new total_files
else Verbose.new total_files
when 0 then Quiet.new num_files
when 1 then Normal.new num_files
else Verbose.new num_files
end
end
def begin_adding
@display.begin_adding
end
##
# Records the parsing of an alias +as+.
def add_alias(as)
def add_alias as
@display.print_alias as
@num_methods += 1
@nodoc_methods += 1 if as.document_self and as.comment.empty?
end
def add_class(klass)
##
# Records the parsing of an attribute +attribute+
def add_attribute attribute
@display.print_attribute attribute
end
##
# Records the parsing of a class +klass+
def add_class klass
@display.print_class klass
end
def add_constant(constant)
##
# Records the parsing of +constant+
def add_constant constant
@display.print_constant constant
@num_constants += 1
@nodoc_constants += 1 if constant.document_self and constant.comment.empty?
end
##
# Records the parsing of +file+
def add_file(file)
@display.print_file @num_files, file
@num_files += 1
@files_so_far += 1
@display.print_file @files_so_far, file
end
##
# Records the parsing of +method+
def add_method(method)
@display.print_method method
@num_methods += 1
@nodoc_methods += 1 if method.document_self and method.comment.empty?
end
##
# Records the parsing of a module +mod+
def add_module(mod)
@display.print_module mod
end
##
# Call this to mark the beginning of parsing for display purposes
def begin_adding
@display.begin_adding
end
##
# Calculates documentation totals and percentages
def calculate
return if @percent_doc
ucm = RDoc::TopLevel.unique_classes_and_modules
constants = []
ucm.each { |cm| constants.concat cm.constants }
methods = []
ucm.each { |cm| methods.concat cm.method_list }
attributes = []
ucm.each { |cm| attributes.concat cm.attributes }
@num_attributes, @undoc_attributes = doc_stats attributes
@num_classes, @undoc_classes = doc_stats RDoc::TopLevel.unique_classes
@num_constants, @undoc_constants = doc_stats constants
@num_methods, @undoc_methods = doc_stats methods
@num_modules, @undoc_modules = doc_stats RDoc::TopLevel.unique_modules
@num_items =
@num_attributes +
@num_classes +
@num_constants +
@num_methods +
@num_modules
@undoc_items =
@undoc_attributes +
@undoc_classes +
@undoc_constants +
@undoc_methods +
@undoc_modules
@doc_items = @num_items - @undoc_items
@fully_documented = (@num_items - @doc_items) == 0
@percent_doc = @doc_items.to_f / @num_items * 100 if @num_items.nonzero?
end
##
# Returns the length and number of undocumented items in +collection+.
def doc_stats collection
[collection.length, collection.count { |item| not item.documented? }]
end
##
# Call this to mark the end of parsing for display purposes
def done_adding
@display.done_adding
end
def print
classes = RDoc::TopLevel.classes
num_classes = classes.length
nodoc_classes = classes.select do |klass|
klass.document_self and klass.comment.empty?
end.length
##
# The documentation status of this project. +true+ when 100%, +false+ when
# less than 100% and +nil+ when unknown.
#
# Set by calling #calculate
modules = RDoc::TopLevel.modules
num_modules = modules.length
nodoc_modules = modules.select do |mod|
mod.document_self and mod.comment.empty?
end.length
items = num_classes + @num_constants + num_modules + @num_methods
doc_items = items -
nodoc_classes - @nodoc_constants - nodoc_modules - @nodoc_methods
percent_doc = doc_items.to_f / items * 100 if items.nonzero?
puts "Files: %5d" % @num_files
puts "Classes: %5d (%5d undocumented)" % [num_classes, nodoc_classes]
puts "Constants: %5d (%5d undocumented)" %
[@num_constants, @nodoc_constants]
puts "Modules: %5d (%5d undocumented)" % [num_modules, nodoc_modules]
puts "Methods: %5d (%5d undocumented)" % [@num_methods, @nodoc_methods]
puts "%6.2f%% documented" % percent_doc if percent_doc
puts
puts "Elapsed: %0.1fs" % (Time.now - @start)
def fully_documented?
@fully_documented
end
##
# Stats printer that prints nothing
# Returns a report on which items are not documented
class Quiet
def report
report = []
def initialize total_files
@total_files = total_files
calculate
if @num_items == @doc_items then
report << '100% documentation!'
report << nil
report << 'Great Job!'
return report.join "\n"
end
##
# Prints a message at the beginning of parsing
report << 'The following items are not documented:'
report << nil
def begin_adding(*) end
ucm = RDoc::TopLevel.unique_classes_and_modules
##
# Prints when an alias is added
ucm.sort.each do |cm|
type = case cm # TODO #definition
when RDoc::NormalClass then 'class'
when RDoc::SingleClass then 'class <<'
when RDoc::NormalModule then 'module'
end
def print_alias(*) end
if cm.fully_documented? then
next
elsif cm.in_files.empty? or
(cm.constants.empty? and cm.method_list.empty?) then
report << "# #{type} #{cm.full_name} is referenced but empty."
report << '#'
report << '# It probably came from another project. ' \
'I\'m sorry I\'m holding it against you.'
report << nil
##
# Prints when a class is added
next
elsif cm.documented? then
report << "#{type} #{cm.full_name} # is documented"
else
report << '# in files:'
def print_class(*) end
##
# Prints when a constant is added
def print_constant(*) end
##
# Prints when a file is added
def print_file(*) end
##
# Prints when a method is added
def print_method(*) end
##
# Prints when a module is added
def print_module(*) end
##
# Prints when RDoc is done
def done_adding(*) end
end
##
# Stats printer that prints just the files being documented with a progress
# bar
class Normal < Quiet
def begin_adding # :nodoc:
puts "Parsing sources..."
end
##
# Prints a file with a progress bar
def print_file(files_so_far, filename)
progress_bar = sprintf("%3d%% [%2d/%2d] ",
100 * (files_so_far + 1) / @total_files,
files_so_far + 1,
@total_files)
if $stdout.tty?
# Print a progress bar, but make sure it fits on a single line. Filename
# will be truncated if necessary.
terminal_width = (ENV['COLUMNS'] || 80).to_i
max_filename_size = terminal_width - progress_bar.size
if filename.size > max_filename_size
# Turn "some_long_filename.rb" to "...ong_filename.rb"
filename = filename[(filename.size - max_filename_size) .. -1]
filename[0..2] = "..."
cm.in_files.each do |file|
report << "# #{file.full_name}"
end
# Pad the line with whitespaces so that leftover output from the
# previous line doesn't show up.
line = "#{progress_bar}#{filename}"
padding = terminal_width - line.size
line << (" " * padding) if padding > 0
report << nil
$stdout.print("#{line}\r")
else
$stdout.puts "#{progress_bar} #{filename}"
report << "#{type} #{cm.full_name}"
end
$stdout.flush
end
def done_adding # :nodoc:
puts
unless cm.constants.empty? then
report << nil
cm.each_constant do |constant|
next if constant.documented?
report << " # in file #{constant.file.full_name}"
report << " #{constant.name} = nil"
end
end
unless cm.attributes.empty? then
report << nil
cm.each_attribute do |attr|
next if attr.documented?
report << " #{attr.definition} #{attr.name} " \
"# in file #{attr.file.full_name}"
end
end
unless cm.method_list.empty? then
report << nil
cm.each_method do |method|
next if method.documented?
report << " # in file #{method.file.full_name}"
report << " def #{method.name}#{method.params}; end"
report << nil
end
end
report << 'end'
report << nil
end
report.join "\n"
end
##
# Stats printer that prints everything documented, including the documented
# status
# Returns a summary of the collected statistics.
class Verbose < Normal
def summary
calculate
##
# Returns a marker for RDoc::CodeObject +co+ being undocumented
report = []
report << 'Files: %5d' % @num_files
report << nil
report << 'Classes: %5d (%5d undocumented)' % [@num_classes,
@undoc_classes]
report << 'Modules: %5d (%5d undocumented)' % [@num_modules,
@undoc_modules]
report << 'Constants: %5d (%5d undocumented)' % [@num_constants,
@undoc_constants]
report << 'Attributes: %5d (%5d undocumented)' % [@num_attributes,
@undoc_attributes]
report << 'Methods: %5d (%5d undocumented)' % [@num_methods,
@undoc_methods]
report << nil
report << 'Total: %5d (%5d undocumented)' % [@num_items,
@undoc_items]
def nodoc co
" (undocumented)" unless co.documented?
end
def print_alias as # :nodoc:
puts "\t\talias #{as.new_name} #{as.old_name}#{nodoc as}"
end
def print_class(klass) # :nodoc:
puts "\tclass #{klass.full_name}#{nodoc klass}"
end
def print_constant(constant) # :nodoc:
puts "\t\t#{constant.name}#{nodoc constant}"
end
def print_file(files_so_far, file) # :nodoc:
super
puts
end
def print_method(method) # :nodoc:
puts "\t\t#{method.singleton ? '::' : '#'}#{method.name}#{nodoc method}"
end
def print_module(mod) # :nodoc:
puts "\tmodule #{mod.full_name}#{nodoc mod}"
end
report << '%6.2f%% documented' % @percent_doc if @percent_doc
report << nil
report << 'Elapsed: %0.1fs' % (Time.now - @start)
report.join "\n"
end
autoload :Quiet, 'rdoc/stats/quiet'
autoload :Normal, 'rdoc/stats/normal'
autoload :Verbose, 'rdoc/stats/verbose'
end

51
lib/rdoc/stats/normal.rb Normal file
Просмотреть файл

@ -0,0 +1,51 @@
##
# Stats printer that prints just the files being documented with a progress
# bar
class RDoc::Stats::Normal < RDoc::Stats::Quiet
def begin_adding # :nodoc:
puts "Parsing sources..."
end
##
# Prints a file with a progress bar
def print_file files_so_far, filename
progress_bar = sprintf("%3d%% [%2d/%2d] ",
100 * files_so_far / @num_files,
files_so_far,
@num_files)
if $stdout.tty? then
# Print a progress bar, but make sure it fits on a single line. Filename
# will be truncated if necessary.
terminal_width = (ENV['COLUMNS'] || 80).to_i
max_filename_size = terminal_width - progress_bar.size
if filename.size > max_filename_size then
# Turn "some_long_filename.rb" to "...ong_filename.rb"
filename = filename[(filename.size - max_filename_size) .. -1]
filename[0..2] = "..."
end
# Pad the line with whitespaces so that leftover output from the
# previous line doesn't show up.
line = "#{progress_bar}#{filename}"
padding = terminal_width - line.size
line << (" " * padding) if padding > 0
$stdout.print("#{line}\r")
else
$stdout.puts "#{progress_bar} #{filename}"
end
$stdout.flush
end
def done_adding # :nodoc:
puts
end
end

59
lib/rdoc/stats/quiet.rb Normal file
Просмотреть файл

@ -0,0 +1,59 @@
##
# Stats printer that prints nothing
class RDoc::Stats::Quiet
##
# Creates a new Quiet that will print nothing
def initialize num_files
@num_files = num_files
end
##
# Prints a message at the beginning of parsing
def begin_adding(*) end
##
# Prints when an alias is added
def print_alias(*) end
##
# Prints when an attribute is added
def print_attribute(*) end
##
# Prints when a class is added
def print_class(*) end
##
# Prints when a constant is added
def print_constant(*) end
##
# Prints when a file is added
def print_file(*) end
##
# Prints when a method is added
def print_method(*) end
##
# Prints when a module is added
def print_module(*) end
##
# Prints when RDoc is done
def done_adding(*) end
end

45
lib/rdoc/stats/verbose.rb Normal file
Просмотреть файл

@ -0,0 +1,45 @@
##
# Stats printer that prints everything documented, including the documented
# status
class RDoc::Stats::Verbose < RDoc::Stats::Normal
##
# Returns a marker for RDoc::CodeObject +co+ being undocumented
def nodoc co
" (undocumented)" unless co.documented?
end
def print_alias as # :nodoc:
puts " alias #{as.new_name} #{as.old_name}#{nodoc as}"
end
def print_attribute attribute # :nodoc:
puts " #{attribute.definition} #{attribute.name}#{nodoc attribute}"
end
def print_class(klass) # :nodoc:
puts " class #{klass.full_name}#{nodoc klass}"
end
def print_constant(constant) # :nodoc:
puts " #{constant.name}#{nodoc constant}"
end
def print_file(files_so_far, file) # :nodoc:
super
puts
end
def print_method(method) # :nodoc:
puts " #{method.singleton ? '::' : '#'}#{method.name}#{nodoc method}"
end
def print_module(mod) # :nodoc:
puts " module #{mod.full_name}#{nodoc mod}"
end
end

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

@ -21,13 +21,238 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
require 'rubygems'
begin
gem 'rdoc'
rescue Gem::LoadError
end
begin
gem 'rake'
rescue Gem::LoadError
end
require 'rdoc'
require 'rake'
require 'rake/rdoctask'
require 'rake/tasklib'
##
# Create a documentation task that will generate the RDoc files for a project.
#
# The RDoc::Task will create the following targets:
#
# [rdoc]
# Main task for this RDoc task.
#
# [clobber_rdoc]
# Delete all the rdoc files. This target is automatically added to the main
# clobber target.
#
# [rerdoc]
# Rebuild the rdoc files from scratch, even if they are not out of date.
#
# Simple Example:
#
# RDoc::Task.new do |rd|
# rd.main = "README.rdoc"
# rd.rdoc_files.include("README.rdoc", "lib/**/*.rb")
# end
#
# The +rd+ object passed to the block is an RDoc::Task object. See the
# attributes list for the RDoc::Task class for available customization options.
#
# == Specifying different task names
#
# You may wish to give the task a different name, such as if you are
# generating two sets of documentation. For instance, if you want to have a
# development set of documentation including private methods:
#
# RDoc::Task.new :rdoc_dev do |rd|
# rd.main = "README.doc"
# rd.rdoc_files.include("README.rdoc", "lib/**/*.rb")
# rd.options << "--all"
# end
#
# The tasks would then be named :<em>rdoc_dev</em>,
# :clobber_<em>rdoc_dev</em>, and :re<em>rdoc_dev</em>.
#
# If you wish to have completely different task names, then pass a Hash as
# first argument. With the <tt>:rdoc</tt>, <tt>:clobber_rdoc</tt> and
# <tt>:rerdoc</tt> options, you can customize the task names to your liking.
#
# For example:
#
# RDoc::Task.new(:rdoc => "rdoc", :clobber_rdoc => "rdoc:clean",
# :rerdoc => "rdoc:force")
#
# This will create the tasks <tt>:rdoc</tt>, <tt>:rdoc:clean</tt> and
# <tt>:rdoc:force</tt>.
class RDoc::Task < Rake::TaskLib
##
# Name of the main, top level task. (default is :rdoc)
attr_accessor :name
##
# Name of directory to receive the html output files. (default is "html")
attr_accessor :rdoc_dir
##
# Title of RDoc documentation. (defaults to rdoc's default)
attr_accessor :title
##
# Name of file to be used as the main, top level file of the RDoc. (default
# is none)
attr_accessor :main
##
# Name of template to be used by rdoc. (defaults to rdoc's default)
attr_accessor :template
##
# List of files to be included in the rdoc generation. (default is [])
attr_accessor :rdoc_files
##
# Additional list of options to be passed rdoc. (default is [])
attr_accessor :options
##
# Whether to run the rdoc process as an external shell (default is false)
attr_accessor :external
##
# Create an RDoc task with the given name. See the RDoc::Task class overview
# for documentation.
def initialize(name = :rdoc) # :yield: self
if name.is_a? Hash then
invalid_options = name.keys.map { |k| k.to_sym } -
[:rdoc, :clobber_rdoc, :rerdoc]
unless invalid_options.empty? then
raise ArgumentError, "invalid options: #{invalid_options.join(", ")}"
end
end
@name = name
@rdoc_files = Rake::FileList.new
@rdoc_dir = 'html'
@main = nil
@title = nil
@template = nil
@options = []
yield self if block_given?
define
end
##
# Create the tasks defined by this task lib.
def define
desc "Build RDoc HTML files"
task rdoc_task_name
desc "Rebuild RDoc HTML files"
task rerdoc_task_name => [clobber_task_name, rdoc_task_name]
desc "Remove RDoc HTML files"
task clobber_task_name do
rm_r @rdoc_dir rescue nil
end
task :clobber => [clobber_task_name]
directory @rdoc_dir
rdoc_target_deps = [
@rdoc_files,
Rake.application.rakefile
].flatten.compact
task rdoc_task_name => [rdoc_target]
file rdoc_target => rdoc_target_deps do
@before_running_rdoc.call if @before_running_rdoc
args = option_list + @rdoc_files
if Rake.application.options.trace then
$stderr.puts "rdoc #{args.join ' '}"
end
require 'rdoc/rdoc'
RDoc::RDoc.new.document(args)
end
self
end
##
# List of options that will be supplied to RDoc
def option_list
result = @options.dup
result << "-o" << @rdoc_dir
result << "--main" << main if main
result << "--title" << title if title
result << "-T" << template if template
result
end
##
# The block passed to this method will be called just before running the
# RDoc generator. It is allowed to modify RDoc::Task attributes inside the
# block.
def before_running_rdoc(&block)
@before_running_rdoc = block
end
private
def rdoc_target
"#{rdoc_dir}/index.html"
end
def rdoc_task_name
case name
when Hash then (name[:rdoc] || "rdoc").to_s
else name.to_s
end
end
def clobber_task_name
case name
when Hash then (name[:clobber_rdoc] || "clobber_rdoc").to_s
else "clobber_#{name}"
end
end
def rerdoc_task_name
case name
when Hash then (name[:rerdoc] || "rerdoc").to_s
else "re#{name}"
end
end
end
# :stopdoc:
module RDoc
Task = Rake::RDocTask
module Rake
##
# For backwards compatibility
RDocTask = RDoc::Task
end
# :startdoc:

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

@ -1,8 +1,43 @@
# coding: utf-8
##
# For RDoc::Text#to_html
require 'strscan'
##
# Methods for manipulating comment text
module RDoc::Text
##
# Maps an encoding to a Hash of characters properly transcoded for that
# encoding.
#
# See also encode_fallback.
TO_HTML_CHARACTERS = Hash.new do |h, encoding|
h[encoding] = {
:close_dquote => encode_fallback('”', encoding, '"'),
:close_squote => encode_fallback('', encoding, '\''),
:copyright => encode_fallback('©', encoding, '(c)'),
:ellipsis => encode_fallback('…', encoding, '...'),
:em_dash => encode_fallback('—', encoding, '---'),
:en_dash => encode_fallback('–', encoding, '--'),
:open_dquote => encode_fallback('“', encoding, '"'),
:open_squote => encode_fallback('', encoding, '\''),
:trademark => encode_fallback('®', encoding, '(r)'),
}
end if Object.const_defined? :Encoding
##
# Transcodes +character+ to +encoding+ with a +fallback+ character.
def self.encode_fallback character, encoding, fallback
character.encode(encoding, :fallback => { character => fallback },
:undef => :replace, :replace => fallback)
end
##
# Expands tab characters in +text+ to eight spaces
@ -43,8 +78,7 @@ module RDoc::Text
end
##
# Convert a string in markup format into HTML. Removes the first paragraph
# tags if +remove_para+ is true.
# Convert a string in markup format into HTML.
#
# Requires the including class to implement #formatter
@ -105,7 +139,7 @@ http://rubyforge.org/tracker/?atid=2472&group_id=627&func=browse
def strip_hashes text
return text if text =~ /^(?>\s*)[^\#]/
text.gsub(/^\s*(#+)/) { $1.tr '#',' ' }
text.gsub(/^\s*(#+)/) { $1.tr '#',' ' }.gsub(/^\s+$/, '')
end
##
@ -123,7 +157,102 @@ http://rubyforge.org/tracker/?atid=2472&group_id=627&func=browse
text.sub! %r%/\*+% do " " * $&.length end
text.sub! %r%\*+/% do " " * $&.length end
text.gsub! %r%^[ \t]*\*%m do " " * $&.length end
text
text.gsub(/^\s+$/, '')
end
##
# Converts ampersand, dashes, ellipsis, quotes, copyright and registered
# trademark symbols in +text+ to properly encoded characters.
def to_html text
if Object.const_defined? :Encoding then
html = ''.encode text.encoding
encoded = RDoc::Text::TO_HTML_CHARACTERS[text.encoding]
else
html = ''
encoded = {
:close_dquote => '”',
:close_squote => '',
:copyright => '©',
:ellipsis => '…',
:em_dash => '—',
:en_dash => '–',
:open_dquote => '“',
:open_squote => '',
:trademark => '®',
}
end
s = StringScanner.new text
insquotes = false
indquotes = false
after_word = nil
until s.eos? do
case
when s.scan(/<tt>.*?<\/tt>/) then # skip contents of tt
html << s.matched.gsub('\\\\', '\\')
when s.scan(/<tt>.*?/) then
warn 'mismatched <tt> tag' # TODO signal file/line
html << s.matched
when s.scan(/<[^>]+\/?s*>/) then # skip HTML tags
html << s.matched
when s.scan(/\\(\S)/) then # unhandled suppressed crossref
html << s[1]
after_word = nil
when s.scan(/\.\.\.(\.?)/) then
html << s[1] << encoded[:ellipsis]
after_word = nil
when s.scan(/\(c\)/) then
html << encoded[:copyright]
after_word = nil
when s.scan(/\(r\)/) then
html << encoded[:trademark]
after_word = nil
when s.scan(/---/) then
html << encoded[:em_dash]
after_word = nil
when s.scan(/--/) then
html << encoded[:en_dash]
after_word = nil
when s.scan(/&quot;|"/) then
html << encoded[indquotes ? :close_dquote : :open_dquote]
indquotes = !indquotes
after_word = nil
when s.scan(/``/) then # backtick double quote
html << encoded[:open_dquote]
after_word = nil
when s.scan(/''/) then # tick double quote
html << encoded[:close_dquote]
after_word = nil
when s.scan(/'/) then # single quote
if insquotes
html << encoded[:close_squote]
insquotes = false
elsif after_word
# Mary's dog, my parents' house: do not start paired quotes
html << encoded[:close_squote]
else
html << encoded[:open_squote]
insquotes = true
end
after_word = nil
else # advance to the next potentially significant character
match = s.scan(/.+?(?=[<\\.("'`&-])/) #"
if match then
html << match
after_word = match =~ /\w$/
else
html << s.rest
break
end
end
end
html
end
end

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

@ -1,5 +1,3 @@
module RDoc; end
##
# A TokenStream is a list of tokens, gathered during the parse of some entity
# (say a method). Entities populate these streams by being registered with the

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

@ -20,7 +20,14 @@ class RDoc::TopLevel < RDoc::Context
attr_accessor :absolute_name
attr_accessor :diagram
##
# All the classes or modules that were declared in
# this file. These are assigned to either +#classes_hash+
# or +#modules_hash+ once we know what they really are.
attr_reader :classes_or_modules
attr_accessor :diagram # :nodoc:
##
# The parser that processed this file
@ -28,45 +35,110 @@ class RDoc::TopLevel < RDoc::Context
attr_accessor :parser
##
# Returns all classes and modules discovered by RDoc
# Returns all classes discovered by RDoc
def self.all_classes_and_modules
classes_hash.values + modules_hash.values
def self.all_classes
@all_classes_hash.values
end
##
# Returns all classes discovered by RDoc
# Returns all classes and modules discovered by RDoc
def self.classes
classes_hash.values
def self.all_classes_and_modules
@all_classes_hash.values + @all_modules_hash.values
end
##
# Hash of all classes known to RDoc
def self.classes_hash
@all_classes
def self.all_classes_hash
@all_classes_hash
end
##
# All TopLevels known to RDoc
def self.files
@all_files.values
def self.all_files
@all_files_hash.values
end
##
# Hash of all files known to RDoc
def self.files_hash
@all_files
def self.all_files_hash
@all_files_hash
end
##
# Returns all modules discovered by RDoc
def self.all_modules
all_modules_hash.values
end
##
# Hash of all modules known to RDoc
def self.all_modules_hash
@all_modules_hash
end
##
# Prepares the RDoc code object tree for use by a generator.
#
# It finds unique classes/modules defined, and replaces classes/modules that
# are aliases for another one by a copy with RDoc::ClassModule#is_alias_for
# set.
#
# It updates the RDoc::ClassModule#constant_aliases attribute of "real"
# classes or modules.
#
# It also completely removes the classes and modules that should be removed
# from the documentation and the methods that have a visibility below
# +min_visibility+, which is the <tt>--visibility</tt> option.
#
# See also RDoc::Context#remove_from_documentation?
def self.complete min_visibility
fix_basic_object_inheritance
# cache included modules before they are removed from the documentation
all_classes_and_modules.each { |cm| cm.ancestors }
remove_nodoc @all_classes_hash
remove_nodoc @all_modules_hash
@unique_classes = find_unique @all_classes_hash
@unique_modules = find_unique @all_modules_hash
unique_classes_and_modules.each do |cm|
cm.complete min_visibility
end
@all_files_hash.each_key do |file_name|
tl = @all_files_hash[file_name]
unless RDoc::Parser::Simple === tl.parser then
tl.modules_hash.clear
tl.classes_hash.clear
tl.classes_or_modules.each do |cm|
name = cm.full_name
if cm.type == 'class' then
tl.classes_hash[name] = cm if @all_classes_hash[name]
else
tl.modules_hash[name] = cm if @all_modules_hash[name]
end
end
end
end
end
##
# Finds the class with +name+ in all discovered classes
def self.find_class_named(name)
classes_hash[name]
@all_classes_hash[name]
end
##
@ -91,9 +163,7 @@ class RDoc::TopLevel < RDoc::Context
# Finds the class or module with +name+
def self.find_class_or_module(name)
name =~ /^::/
name = $' || name
name = $' if name =~ /^::/
RDoc::TopLevel.classes_hash[name] || RDoc::TopLevel.modules_hash[name]
end
@ -101,7 +171,7 @@ class RDoc::TopLevel < RDoc::Context
# Finds the file with +name+ in all discovered files
def self.find_file_named(name)
@all_files[name]
@all_files_hash[name]
end
##
@ -112,26 +182,98 @@ class RDoc::TopLevel < RDoc::Context
end
##
# Returns all modules discovered by RDoc
# Finds unique classes/modules defined in +all_hash+,
# and returns them as an array. Performs the alias
# updates in +all_hash+: see ::complete.
#--
# TODO aliases should be registered by Context#add_module_alias
def self.modules
modules_hash.values
def self.find_unique(all_hash)
unique = []
all_hash.each_pair do |full_name, cm|
unique << cm if full_name == cm.full_name
end
unique
end
##
# Hash of all modules known to RDoc
# Fixes the erroneous <tt>BasicObject < Object</tt> in 1.9.
#
# Because we assumed all classes without a stated superclass
# inherit from Object, we have the above wrong inheritance.
#
# We fix BasicObject right away if we are running in a Ruby
# version >= 1.9. If not, we may be documenting 1.9 source
# while running under 1.8: we search the files of BasicObject
# for "object.c", and fix the inheritance if we find it.
def self.modules_hash
@all_modules
def self.fix_basic_object_inheritance
basic = all_classes_hash['BasicObject']
return unless basic
if RUBY_VERSION >= '1.9'
basic.superclass = nil
elsif basic.in_files.any? { |f| File.basename(f.full_name) == 'object.c' }
basic.superclass = nil
end
end
##
# Removes from +all_hash+ the contexts that are nodoc or have no content.
#
# See RDoc::Context#remove_from_documentation?
def self.remove_nodoc(all_hash)
all_hash.keys.each do |name|
context = all_hash[name]
all_hash.delete(name) if context.remove_from_documentation?
end
end
##
# Empties RDoc of stored class, module and file information
def self.reset
@all_classes = {}
@all_modules = {}
@all_files = {}
@all_classes_hash = {}
@all_modules_hash = {}
@all_files_hash = {}
end
##
# Returns the unique classes discovered by RDoc.
#
# ::complete must have been called prior to using this method.
def self.unique_classes
@unique_classes
end
##
# Returns the unique classes and modules discovered by RDoc.
# ::complete must have been called prior to using this method.
def self.unique_classes_and_modules
@unique_classes + @unique_modules
end
##
# Returns the unique modules discovered by RDoc.
# ::complete must have been called prior to using this method.
def self.unique_modules
@unique_modules
end
class << self
alias classes all_classes
alias classes_hash all_classes_hash
alias files all_files
alias files_hash all_files_hash
alias modules all_modules
alias modules_hash all_modules_hash
end
reset
@ -148,17 +290,49 @@ class RDoc::TopLevel < RDoc::Context
@diagram = nil
@parser = nil
@classes_or_modules = []
RDoc::TopLevel.files_hash[file_name] = self
end
##
# Adds +method+ to Object instead of RDoc::TopLevel
# Adds +an_alias+ to +Object+ instead of +self+.
def add_alias(an_alias)
return an_alias unless @document_self
object_class.add_alias an_alias
end
##
# Adds +constant+ to +Object+ instead of +self+.
def add_constant(constant)
return constant unless @document_self
object_class.add_constant constant
end
##
# Adds +include+ to +Object+ instead of +self+.
def add_include(include)
return include unless @document_self
object_class.add_include include
end
##
# Adds +method+ to +Object+ instead of +self+.
def add_method(method)
object = self.class.find_class_named 'Object'
object = add_class RDoc::NormalClass, 'Object' unless object
return method unless @document_self
object_class.add_method method
end
object.add_method method
##
# Adds class or module +mod+. Used in the building phase
# by the ruby parser.
def add_to_classes_or_modules mod
@classes_or_modules << mod
end
##
@ -168,8 +342,13 @@ class RDoc::TopLevel < RDoc::Context
File.basename @absolute_name
end
alias name base_name
##
# See RDoc::TopLevel.find_class_or_module
# See RDoc::TopLevel::find_class_or_module
#--
# TODO Why do we search through all classes/modules found, not just the
# ones of this instance?
def find_class_or_module name
RDoc::TopLevel.find_class_or_module name
@ -186,11 +365,11 @@ class RDoc::TopLevel < RDoc::Context
# Finds a module or class with +name+
def find_module_named(name)
find_class_or_module(name) || find_enclosing_module_named(name)
find_class_or_module(name)
end
##
# The name of this file
# Returns the relative name of this file
def full_name
@relative_name
@ -215,16 +394,24 @@ class RDoc::TopLevel < RDoc::Context
end
##
# Date this file was last modified, if known
# Time this file was last modified, if known
def last_modified
@file_stat ? file_stat.mtime.to_s : 'Unknown'
@file_stat ? file_stat.mtime : nil
end
##
# Base name of this file
# Returns the NormalClass "Object", creating it if not found.
#
# Records +self+ as a location in "Object".
alias name base_name
def object_class
@object_class ||= begin
oc = self.class.find_class_named('Object') || add_class(RDoc::NormalClass, 'Object')
oc.record_location self
oc
end
end
##
# Path to this file
@ -244,5 +431,9 @@ class RDoc::TopLevel < RDoc::Context
end
end
def to_s # :nodoc:
"file #{full_name}"
end
end

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

@ -1,3 +1,5 @@
# -*- coding: utf-8 -*-
こんにちは!
初めまして。アーロンと申します。

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

@ -2,29 +2,35 @@ require 'rubygems'
require 'minitest/autorun'
require 'rdoc'
require 'rdoc/markup'
require 'rdoc/markup/formatter'
require 'rdoc/markup/attribute_manager'
class TestAttributeManager < MiniTest::Unit::TestCase
class TestAttributeManager < MiniTest::Unit::TestCase # HACK fix test name
def setup
@am = RDoc::Markup::AttributeManager.new
@klass = RDoc::Markup::AttributeManager
@formatter = RDoc::Markup::Formatter.new
@formatter.add_tag :BOLD, '<B>', '</B>'
@formatter.add_tag :EM, '<EM>', '</EM>'
@formatter.add_tag :TT, '<TT>', '</TT>'
end
def test_convert_attrs_ignores_code
collector = RDoc::Markup::AttrSpan.new 10
str = 'foo <code>__send__</code> bar'
@am.convert_html str, collector
@am.convert_attrs str, collector
assert_match(/__send__/, str)
assert_equal 'foo <TT>__send__</TT> bar', output('foo <code>__send__</code> bar')
end
def test_convert_attrs_ignores_tt
collector = RDoc::Markup::AttrSpan.new 10
str = 'foo <tt>__send__</tt> bar'
@am.convert_html str, collector
@am.convert_attrs str, collector
assert_match(/__send__/, str)
assert_equal 'foo <TT>__send__</TT> bar', output('foo <tt>__send__</tt> bar')
end
def test_convert_attrs_preserves_double
assert_equal 'foo.__send__ :bar', output('foo.__send__ :bar')
assert_equal 'use __FILE__ to', output('use __FILE__ to')
end
def test_convert_attrs_does_not_ignore_after_tt
assert_equal 'the <TT>IF:</TT><EM>key</EM> directive', output('the <tt>IF:</tt>_key_ directive')
end
def test_initial_word_pairs
@ -73,12 +79,41 @@ class TestAttributeManager < MiniTest::Unit::TestCase
assert(specials.has_key?("WikiWord"))
end
def silently(&block)
warn_level = $VERBOSE
$VERBOSE = nil
result = block.call
$VERBOSE = warn_level
result
def test_escapes
assert_equal '<TT>text</TT>', output('<tt>text</tt>')
assert_equal '<tt>text</tt>', output('\\<tt>text</tt>')
assert_equal '<tt>', output('\\<tt>')
assert_equal '<TT><tt></TT>', output('<tt>\\<tt></tt>')
assert_equal '<TT>\\<tt></TT>', output('<tt>\\\\<tt></tt>')
assert_equal '<B>text</B>', output('*text*')
assert_equal '*text*', output('\\*text*')
assert_equal '\\', output('\\')
assert_equal '\\text', output('\\text')
assert_equal '\\\\text', output('\\\\text')
assert_equal 'text \\ text', output('text \\ text')
assert_equal 'and <TT>\\s</TT> matches space',
output('and <tt>\\s</tt> matches space')
assert_equal 'use <TT><tt>text</TT></tt> for code',
output('use <tt>\\<tt>text</tt></tt> for code')
assert_equal 'use <TT><tt>text</tt></TT> for code',
output('use <tt>\\<tt>text\\</tt></tt> for code')
assert_equal 'use <tt><tt>text</tt></tt> for code',
output('use \\<tt>\\<tt>text</tt></tt> for code')
assert_equal 'use <tt><TT>text</TT></tt> for code',
output('use \\<tt><tt>text</tt></tt> for code')
assert_equal 'use <TT>+text+</TT> for code',
output('use <tt>\\+text+</tt> for code')
assert_equal 'use <tt><TT>text</TT></tt> for code',
output('use \\<tt>+text+</tt> for code')
assert_equal 'illegal <tag>not</tag> changed',
output('illegal <tag>not</tag> changed')
assert_equal 'unhandled <p>tag</p> unchanged',
output('unhandled <p>tag</p> unchanged')
end
def output str
@formatter.convert_flow @am.flow str
end
end

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

@ -0,0 +1,13 @@
require File.expand_path '../xref_test_case', __FILE__
class TestRDocAlias < XrefTestCase
def test_to_s
a = RDoc::Alias.new nil, 'a', 'b', ''
a.parent = @c2
assert_equal 'alias: b -> #a in: RDoc::NormalClass C2 < Object', a.to_s
end
end

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

@ -1,15 +1,17 @@
require File.expand_path '../xref_test_case', __FILE__
require 'rdoc/code_objects'
require 'rdoc/generator/markup'
class RDocAnyMethodTest < XrefTestCase
def test_aref
m = RDoc::AnyMethod.new nil, 'method?'
assert_equal 'method-i-method%3F', m.aref
assert_equal 'method-i-method-3F', m.aref
m.singleton = true
assert_equal 'method-c-method%3F', m.aref
assert_equal 'method-c-method-3F', m.aref
end
def test_arglists
@ -36,6 +38,45 @@ method(a, b) { |c, d| ... }
assert_equal 'C1::m', @c1.method_list.first.full_name
end
def test_markup_code
tokens = [
RDoc::RubyToken::TkCONSTANT. new(0, 0, 0, 'CONSTANT'),
RDoc::RubyToken::TkKW. new(0, 0, 0, 'KW'),
RDoc::RubyToken::TkIVAR. new(0, 0, 0, 'IVAR'),
RDoc::RubyToken::TkOp. new(0, 0, 0, 'Op'),
RDoc::RubyToken::TkId. new(0, 0, 0, 'Id'),
RDoc::RubyToken::TkNode. new(0, 0, 0, 'Node'),
RDoc::RubyToken::TkCOMMENT. new(0, 0, 0, 'COMMENT'),
RDoc::RubyToken::TkREGEXP. new(0, 0, 0, 'REGEXP'),
RDoc::RubyToken::TkSTRING. new(0, 0, 0, 'STRING'),
RDoc::RubyToken::TkVal. new(0, 0, 0, 'Val'),
RDoc::RubyToken::TkBACKSLASH.new(0, 0, 0, '\\'),
]
@c2_a.collect_tokens
@c2_a.add_tokens(*tokens)
expected = [
'<span class="ruby-constant">CONSTANT</span>',
'<span class="ruby-keyword">KW</span>',
'<span class="ruby-ivar">IVAR</span>',
'<span class="ruby-operator">Op</span>',
'<span class="ruby-identifier">Id</span>',
'<span class="ruby-node">Node</span>',
'<span class="ruby-comment">COMMENT</span>',
'<span class="ruby-regexp">REGEXP</span>',
'<span class="ruby-string">STRING</span>',
'<span class="ruby-value">Val</span>',
'\\'
].join
assert_equal expected, @c2_a.markup_code
end
def test_markup_code_empty
assert_equal '', @c2_a.markup_code
end
def test_marshal_load
instance_method = Marshal.load Marshal.dump(@c1.method_list.last)

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

@ -8,6 +8,12 @@ class TestRDocAttr < MiniTest::Unit::TestCase
@a = RDoc::Attr.new nil, 'attr', 'RW', ''
end
def test_aref
m = RDoc::Attr.new nil, 'attr', 'RW', nil
assert_equal 'attribute-i-attr', m.aref
end
def test_arglists
assert_nil @a.arglists
end
@ -20,6 +26,18 @@ class TestRDocAttr < MiniTest::Unit::TestCase
assert_nil @a.call_seq
end
def test_definition
assert_equal 'attr_accessor', @a.definition
@a.rw = 'R'
assert_equal 'attr_reader', @a.definition
@a.rw = 'W'
assert_equal 'attr_writer', @a.definition
end
def test_full_name
assert_equal '(unknown)#attr', @a.full_name
end
@ -33,15 +51,10 @@ class TestRDocAttr < MiniTest::Unit::TestCase
end
def test_type
assert_equal 'attr_accessor', @a.type
assert_equal 'instance', @a.type
@a.rw = 'R'
assert_equal 'attr_reader', @a.type
@a.rw = 'W'
assert_equal 'attr_writer', @a.type
@a.singleton = true
assert_equal 'class', @a.type
end
end

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

@ -92,9 +92,142 @@ class TestRDocClassModule < XrefTestCase
assert_equal expected, cm1.method_list.sort
end
def test_remove_nodoc_children
parent = RDoc::ClassModule.new 'A'
parent.modules_hash.replace 'B' => true, 'C' => true
RDoc::TopLevel.all_modules_hash.replace 'A::B' => true
parent.classes_hash.replace 'D' => true, 'E' => true
RDoc::TopLevel.all_classes_hash.replace 'A::D' => true
parent.remove_nodoc_children
assert_equal %w[B], parent.modules_hash.keys
assert_equal %w[D], parent.classes_hash.keys
end
def test_superclass
assert_equal @c3_h1, @c3_h2.superclass
end
def test_update_aliases_class
n1 = @xref_data.add_module RDoc::NormalClass, 'N1'
n1_k2 = n1.add_module RDoc::NormalClass, 'N2'
n1.add_module_alias n1_k2, 'A1'
n1_a1_c = n1.constants.find { |c| c.name == 'A1' }
refute_nil n1_a1_c
assert_equal n1_k2, n1_a1_c.is_alias_for, 'sanity check'
n1.update_aliases
n1_a1_k = @xref_data.find_class_or_module 'N1::A1'
refute_nil n1_a1_k
assert_equal n1_k2, n1_a1_k.is_alias_for
refute_equal n1_k2, n1_a1_k
assert_equal 1, n1_k2.aliases.length
assert_equal n1_a1_k, n1_k2.aliases.first
assert_equal 'N1::N2', n1_k2.full_name
assert_equal 'N1::A1', n1_a1_k.full_name
end
def test_update_aliases_module
n1 = @xref_data.add_module RDoc::NormalModule, 'N1'
n1_n2 = n1.add_module RDoc::NormalModule, 'N2'
n1.add_module_alias n1_n2, 'A1'
n1_a1_c = n1.constants.find { |c| c.name == 'A1' }
refute_nil n1_a1_c
assert_equal n1_n2, n1_a1_c.is_alias_for, 'sanity check'
n1.update_aliases
n1_a1_m = @xref_data.find_class_or_module 'N1::A1'
refute_nil n1_a1_m
assert_equal n1_n2, n1_a1_m.is_alias_for
refute_equal n1_n2, n1_a1_m
assert_equal 1, n1_n2.aliases.length
assert_equal n1_a1_m, n1_n2.aliases.first
assert_equal 'N1::N2', n1_n2.full_name
assert_equal 'N1::A1', n1_a1_m.full_name
end
def test_update_aliases_reparent
l1 = @xref_data.add_module RDoc::NormalModule, 'L1'
l1_l2 = l1.add_module RDoc::NormalModule, 'L2'
o1 = @xref_data.add_module RDoc::NormalModule, 'O1'
o1.add_module_alias l1_l2, 'A1'
o1_a1_c = o1.constants.find { |c| c.name == 'A1' }
refute_nil o1_a1_c
assert_equal l1_l2, o1_a1_c.is_alias_for
refute_equal l1_l2, o1_a1_c
o1.update_aliases
o1_a1_m = @xref_data.find_class_or_module 'O1::A1'
refute_nil o1_a1_m
assert_equal l1_l2, o1_a1_m.is_alias_for
assert_equal 1, l1_l2.aliases.length
assert_equal o1_a1_m, l1_l2.aliases[0]
assert_equal 'L1::L2', l1_l2.full_name
assert_equal 'O1::A1', o1_a1_m.full_name
end
def test_update_includes
a = RDoc::Include.new 'M1', nil
b = RDoc::Include.new 'M2', nil
c = RDoc::Include.new 'C', nil
@c1.add_include a
@c1.add_include b
@c1.add_include c
@c1.ancestors # cache included modules
@m1_m2.document_self = nil
assert @m1_m2.remove_from_documentation?
assert RDoc::TopLevel.all_modules_hash.key? @m1_m2.full_name
refute RDoc::TopLevel.all_modules_hash[@m1_m2.full_name].nil?
RDoc::TopLevel.remove_nodoc RDoc::TopLevel.all_modules_hash
refute RDoc::TopLevel.all_modules_hash.key? @m1_m2.full_name
@c1.update_includes
assert_equal [a, c], @c1.includes
end
def test_update_includes_with_colons
a = RDoc::Include.new 'M1', nil
b = RDoc::Include.new 'M1::M2', nil
c = RDoc::Include.new 'C', nil
@c1.add_include a
@c1.add_include b
@c1.add_include c
@c1.ancestors # cache included modules
@m1_m2.document_self = nil
assert @m1_m2.remove_from_documentation?
assert RDoc::TopLevel.all_modules_hash.key? @m1_m2.full_name
refute RDoc::TopLevel.all_modules_hash[@m1_m2.full_name].nil?
RDoc::TopLevel.remove_nodoc RDoc::TopLevel.all_modules_hash
refute RDoc::TopLevel.all_modules_hash.key? @m1_m2.full_name
@c1.update_includes
assert_equal [a, c], @c1.includes
end
end

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

@ -16,6 +16,7 @@ class TestRDocCodeObject < XrefTestCase
assert @co.document_children, 'document_children'
refute @co.force_documentation, 'force_documentation'
refute @co.done_documenting, 'done_documenting'
refute @co.received_nodoc, 'received_nodoc'
assert_equal '', @co.comment, 'comment is empty'
end
@ -33,16 +34,20 @@ class TestRDocCodeObject < XrefTestCase
@co.document_children = false
refute @co.document_children
@c2.document_children = false
assert_empty @c2.classes
# TODO this is not true anymore:
# test all the nodoc stuff etc...
#@c2.document_children = false
#assert_empty @c2.classes
end
def test_document_self_equals
@co.document_self = false
refute @co.document_self
@c1.document_self = false
assert_empty @c1.method_list
# TODO this is not true anymore:
# test all the nodoc stuff etc...
#@c1.document_self = false
#assert_empty @c1.method_list
end
def test_documented_eh
@ -56,11 +61,46 @@ class TestRDocCodeObject < XrefTestCase
refute @co.documented?
@co.document_self = false
@co.document_self = nil # notify :nodoc:
assert @co.documented?
end
def test_done_documenting
# once done_documenting is set, other properties refuse to go to "true"
@co.done_documenting = true
@co.document_self = true
refute @co.document_self
@co.document_children = true
refute @co.document_children
@co.force_documentation = true
refute @co.force_documentation
@co.start_doc
refute @co.document_self
refute @co.document_children
# turning done_documenting on
# resets others to true
@co.done_documenting = false
assert @co.document_self
assert @co.document_children
end
def test_full_name_equals
@co.full_name = 'hi'
assert_equal 'hi', @co.instance_variable_get(:@full_name)
@co.full_name = nil
assert_nil @co.instance_variable_get(:@full_name)
end
def test_metadata
assert_empty @co.metadata
@ -84,6 +124,23 @@ class TestRDocCodeObject < XrefTestCase
assert_equal 'C2', @c2_c3.parent_name
end
def test_received_ndoc
@co.document_self = false
refute @co.received_nodoc
@co.document_self = nil
assert @co.received_nodoc
@co.document_self = true
end
def test_record_location
c = RDoc::CodeObject.new
c.record_location @xref_data
assert_equal 'xref_data.rb', c.file.relative_name
end
def test_start_doc
@co.document_self = false
@co.document_children = false

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

@ -34,13 +34,38 @@ class TestRDocContext < XrefTestCase
@context.add_alias as
assert_equal [as], @context.aliases
assert_equal [as], @context.unmatched_alias_lists['old_name']
assert_equal [as], @context.external_aliases
assert_equal [as], @context.unmatched_alias_lists['#old_name']
end
def test_add_alias_method_attr
top_level = RDoc::TopLevel.new 'file.rb'
attr = RDoc::Attr.new nil, 'old_name', 'R', ''
as = RDoc::Alias.new nil, 'old_name', 'new_name', 'comment'
as.record_location top_level
as.parent = @context
@context.add_attribute attr
@context.add_alias as
assert_empty @context.aliases
assert_empty @context.unmatched_alias_lists
assert_equal %w[old_name new_name], @context.attributes.map { |m| m.name }
new = @context.attributes.last
assert_equal top_level, new.file
end
def test_add_alias_method
top_level = RDoc::TopLevel.new 'file.rb'
meth = RDoc::AnyMethod.new nil, 'old_name'
meth.singleton = false
as = RDoc::Alias.new nil, 'old_name', 'new_name', 'comment'
as.record_location top_level
as.parent = @context
@context.add_method meth
@ -49,28 +74,28 @@ class TestRDocContext < XrefTestCase
assert_empty @context.aliases
assert_empty @context.unmatched_alias_lists
assert_equal %w[old_name new_name], @context.method_list.map { |m| m.name }
new = @context.method_list.last
assert_equal top_level, new.file
end
def test_add_alias_impl
def test_add_alias_method_singleton
meth = RDoc::AnyMethod.new nil, 'old_name'
meth.comment = 'old comment'
meth.singleton = false
meth.visibility = :private
meth.singleton = true
alas = RDoc::Alias.new nil, 'old_name', 'new_name', 'new comment'
as = RDoc::Alias.new nil, 'old_name', 'new_name', 'comment'
as.singleton = true
@context.add_alias_impl alas, meth
as.parent = @context
assert_equal 1, @context.method_list.length
@context.add_method meth
@context.add_alias as
alas_meth = @context.method_list.first
assert_equal 'new_name', alas_meth.name
assert_equal 'new comment', alas_meth.comment
assert_equal false, alas_meth.singleton
assert_equal meth, alas_meth.is_alias_for
assert_equal :private, alas_meth.visibility
assert_empty @context.aliases
assert_empty @context.unmatched_alias_lists
assert_equal %w[old_name new_name], @context.method_list.map { |m| m.name }
assert_equal [alas_meth], meth.aliases
assert @context.method_list.last.singleton
end
def test_add_class
@ -133,11 +158,11 @@ class TestRDocContext < XrefTestCase
meth = RDoc::AnyMethod.new nil, 'old_name'
@context.add_alias as
refute_empty @context.aliases
refute_empty @context.external_aliases
@context.add_method meth
assert_empty @context.aliases
assert_empty @context.external_aliases
assert_empty @context.unmatched_alias_lists
assert_equal %w[old_name new_name], @context.method_list.map { |m| m.name }
end
@ -292,6 +317,46 @@ class TestRDocContext < XrefTestCase
assert_equal @c1__m, @c1.find_symbol('::m')
end
def test_fully_documented_eh
context = RDoc::Context.new
refute context.fully_documented?
context.comment = 'hi'
assert context.fully_documented?
m = @c1_m
context.add_method m
refute context.fully_documented?
m.comment = 'hi'
assert context.fully_documented?
c = RDoc::Constant.new 'C', '0', nil
context.add_constant c
refute context.fully_documented?
c.comment = 'hi'
assert context.fully_documented?
a = RDoc::Attr.new '', 'a', 'RW', nil
context.add_attribute a
refute context.fully_documented?
a.comment = 'hi'
assert context.fully_documented?
end
def test_spaceship
assert_equal(-1, @c2.<=>(@c3))
assert_equal 0, @c2.<=>(@c2)

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

@ -0,0 +1,145 @@
require 'rubygems'
require 'minitest/autorun'
require 'rdoc'
require 'rdoc/encoding'
require 'tempfile'
class TestRDocEncoding < MiniTest::Unit::TestCase
def setup
@tempfile = Tempfile.new 'test_rdoc_encoding'
end
def test_class_read_file
@tempfile.write "hi everybody"
@tempfile.flush
assert_equal "hi everybody", RDoc::Encoding.read_file(@tempfile.path, nil)
end
def test_class_read_file_encoding
skip "Encoding not implemented" unless Object.const_defined? :Encoding
expected = "# coding: utf-8\nhi everybody"
@tempfile.write expected
@tempfile.flush
# FIXME 1.9 fix on windoze
expected.gsub!("\n", "\r\n") if RUBY_VERSION =~ /^1.9/ && RUBY_PLATFORM =~ /mswin|mingw/
contents = RDoc::Encoding.read_file @tempfile.path, Encoding::UTF_8
assert_equal expected, contents
assert_equal Encoding::UTF_8, contents.encoding
end
def test_class_read_file_encoding_convert
skip "Encoding not implemented" unless Object.const_defined? :Encoding
content = ""
content.encode! 'ISO-8859-1'
content << "# coding: ISO-8859-1\nhi \xE9verybody"
@tempfile.write content
@tempfile.flush
contents = RDoc::Encoding.read_file @tempfile.path, Encoding::UTF_8
assert_equal Encoding::UTF_8, contents.encoding
assert_equal "# coding: ISO-8859-1\nhi \u00e9verybody", contents.sub("\r", '')
end
def test_class_read_file_encoding_fancy
skip "Encoding not implemented" unless Object.const_defined? :Encoding
expected = "# -*- coding: utf-8; fill-column: 74 -*-\nhi everybody"
expected.encode! Encoding::UTF_8
@tempfile.write expected
@tempfile.flush
# FIXME 1.9 fix on windoze
expected.gsub!("\n", "\r\n") if RUBY_VERSION =~ /^1.9/ && RUBY_PLATFORM =~ /win32|mingw32/
contents = RDoc::Encoding.read_file @tempfile.path, Encoding::UTF_8
assert_equal expected, contents
assert_equal Encoding::UTF_8, contents.encoding
end
def test_class_read_file_encoding_guess
skip "Encoding not implemented" unless Object.const_defined? :Encoding
path = File.expand_path '../test.ja.txt', __FILE__
content = RDoc::Encoding.read_file path, Encoding::UTF_8
assert_equal Encoding::UTF_8, content.encoding
end
def test_class_read_file_encoding_with_signature
skip "Encoding not implemented" unless defined? ::Encoding
@tempfile.write "\xEF\xBB\xBFhi everybody"
@tempfile.flush
bug3360 = '[ruby-dev:41452]'
content = RDoc::Encoding.read_file @tempfile.path, Encoding::UTF_8
assert_equal Encoding::UTF_8, content.encoding, bug3360
assert_equal "hi everybody", content, bug3360
end
def test_class_set_encoding
s = "# coding: UTF-8\n"
RDoc::Encoding.set_encoding s
# sanity check for 1.8
skip "Encoding not implemented" unless Object.const_defined? :Encoding
assert_equal Encoding::UTF_8, s.encoding
s = "#!/bin/ruby\n# coding: UTF-8\n"
RDoc::Encoding.set_encoding s
assert_equal Encoding::UTF_8, s.encoding
s = "<?xml version='1.0' encoding='UTF-8'?>\n"
expected = s.encoding
RDoc::Encoding.set_encoding s
assert_equal Encoding::UTF_8, s.encoding
s = "<?xml version='1.0' encoding=\"UTF-8\"?>\n"
expected = s.encoding
RDoc::Encoding.set_encoding s
assert_equal Encoding::UTF_8, s.encoding
end
def test_class_set_encoding_bad
skip "Encoding not implemented" unless Object.const_defined? :Encoding
s = ""
expected = s.encoding
RDoc::Encoding.set_encoding s
assert_equal expected, s.encoding
s = "# vim:set fileencoding=utf-8:\n"
expected = s.encoding
RDoc::Encoding.set_encoding s
assert_equal expected, s.encoding
s = "# vim:set fileencoding=utf-8:\n"
expected = s.encoding
RDoc::Encoding.set_encoding s
assert_equal expected, s.encoding
assert_raises ArgumentError do
RDoc::Encoding.set_encoding "# -*- encoding: undecided -*-\n"
end
end
end

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

@ -0,0 +1,119 @@
require 'minitest/autorun'
require 'rdoc/rdoc'
require 'rdoc/generator/darkfish'
require 'tmpdir'
require 'fileutils'
class TestRDocGeneratorDarkfish < MiniTest::Unit::TestCase
def setup
@pwd = Dir.pwd
@lib_dir = "#{@pwd}/lib"
$LOAD_PATH.unshift @lib_dir # ensure we load from this RDoc
RDoc::TopLevel.reset
@options = RDoc::Options.new
@options.option_parser = OptionParser.new
@tmpdir = File.join Dir.tmpdir, "test_rdoc_generator_darkfish_#{$$}"
FileUtils.mkdir_p @tmpdir
Dir.chdir @tmpdir
@options.op_dir = @tmpdir
@options.generator = RDoc::Generator::Darkfish
$LOAD_PATH.each do |path|
darkfish_dir = File.join path, 'rdoc/generator/template/darkfish'
next unless File.directory? darkfish_dir
@options.template_dir = darkfish_dir
break
end
rd = RDoc::RDoc.new
rd.options = @options
RDoc::RDoc.current = rd
@g = @options.generator.new @options
rd.generator = @g
@top_level = RDoc::TopLevel.new 'file.rb'
@klass = @top_level.add_class RDoc::NormalClass, 'Object'
@meth = RDoc::AnyMethod.new nil, 'method'
@meth_bang = RDoc::AnyMethod.new nil, 'method!'
@attr = RDoc::Attr.new nil, 'attr', 'RW', ''
@klass.add_method @meth
@klass.add_method @meth_bang
@klass.add_attribute @attr
end
def teardown
$LOAD_PATH.shift
Dir.chdir @pwd
FileUtils.rm_rf @tmpdir
end
def assert_file path
assert File.file?(path), "#{path} is not a file"
end
def refute_file path
refute File.exist?(path), "#{path} exists"
end
def test_generate
top_level = RDoc::TopLevel.new 'file.rb'
top_level.add_class @klass.class, @klass.name
@g.generate [top_level]
assert_file 'index.html'
assert_file 'Object.html'
assert_file 'file_rb.html'
encoding = if Object.const_defined? :Encoding then
Regexp.escape Encoding.default_external.name
else
Regexp.escape 'UTF-8'
end
assert_match(/<meta content="text\/html; charset=#{encoding}"/,
File.read('index.html'))
assert_match(/<meta content="text\/html; charset=#{encoding}"/,
File.read('Object.html'))
assert_match(/<meta content="text\/html; charset=#{encoding}"/,
File.read('file_rb.html'))
end
def test_generate_dry_run
@options.dry_run = true
top_level = RDoc::TopLevel.new 'file.rb'
top_level.add_class @klass.class, @klass.name
@g.generate [top_level]
refute_file 'index.html'
refute_file 'Object.html'
refute_file 'file_rb.html'
end
def test_template_for
classpage = Pathname.new @options.template_dir + '/classpage.rhtml'
template = @g.send(:template_for, classpage)
assert_kind_of RDoc::ERBIO, template
assert_same template, @g.send(:template_for, classpage)
end
def test_template_for_dry_run
classpage = Pathname.new @options.template_dir + '/classpage.rhtml'
template = @g.send(:template_for, classpage)
assert_kind_of ERB, template
assert_same template, @g.send(:template_for, classpage)
end
end

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

@ -1,21 +1,23 @@
require 'rubygems'
require 'minitest/autorun'
require 'rdoc/rdoc'
require 'rdoc/generator/ri'
require 'tmpdir'
require 'fileutils'
class TestRDocGeneratorRI < MiniTest::Unit::TestCase
def setup
@options = RDoc::Options.new
@pwd = Dir.pwd
RDoc::TopLevel.reset
@tmpdir = File.join Dir.tmpdir, "test_rdoc_generator_ri_#{$$}"
FileUtils.mkdir_p @tmpdir
Dir.chdir @tmpdir
options = RDoc::Options.new
@g = RDoc::Generator::RI.new options
@g = RDoc::Generator::RI.new @options
@top_level = RDoc::TopLevel.new 'file.rb'
@klass = @top_level.add_class RDoc::NormalClass, 'Object'
@ -37,6 +39,10 @@ class TestRDocGeneratorRI < MiniTest::Unit::TestCase
assert File.file?(path), "#{path} is not a file"
end
def refute_file path
refute File.exist?(path), "#{path} exists"
end
def test_generate
top_level = RDoc::TopLevel.new 'file.rb'
top_level.add_class @klass.class, @klass.name
@ -52,5 +58,19 @@ class TestRDocGeneratorRI < MiniTest::Unit::TestCase
assert_file File.join(@tmpdir, 'Object', 'method%21-i.ri')
end
def test_generate_dry_run
@options.dry_run = true
@g = RDoc::Generator::RI.new @options
top_level = RDoc::TopLevel.new 'file.rb'
top_level.add_class @klass.class, @klass.name
@g.generate nil
refute_file File.join(@tmpdir, 'cache.ri')
refute_file File.join(@tmpdir, 'Object')
end
end

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

@ -6,6 +6,7 @@ class TestRDocInclude < XrefTestCase
super
@inc = RDoc::Include.new 'M1', 'comment'
@inc.parent = @m1
end
def test_module
@ -13,5 +14,83 @@ class TestRDocInclude < XrefTestCase
assert_equal 'Unknown', RDoc::Include.new('Unknown', 'comment').module
end
def test_module_extended
m1 = @xref_data.add_module RDoc::NormalModule, 'Mod1'
m1_m3 = m1.add_module RDoc::NormalModule, 'Mod3'
m1_m2 = m1.add_module RDoc::NormalModule, 'Mod2'
m1_m2_m3 = m1_m2.add_module RDoc::NormalModule, 'Mod3'
m1_m2_m3_m4 = m1_m2_m3.add_module RDoc::NormalModule, 'Mod4'
m1_m2_m4 = m1_m2.add_module RDoc::NormalModule, 'Mod4'
m1_m2_k0 = m1_m2.add_class RDoc::NormalClass, 'Klass0'
m1_m2_k0_m4 = m1_m2_k0.add_module RDoc::NormalModule, 'Mod4'
#m1_m2_k0_m4_m5 = m1_m2_k0_m4.add_module RDoc::NormalModule, 'Mod5'
m1_m2_k0_m4_m6 = m1_m2_k0_m4.add_module RDoc::NormalModule, 'Mod6'
m1_m2_k0_m5 = m1_m2_k0.add_module RDoc::NormalModule, 'Mod5'
i0_m4 = RDoc::Include.new 'Mod4', nil
i0_m5 = RDoc::Include.new 'Mod5', nil
i0_m6 = RDoc::Include.new 'Mod6', nil
i0_m1 = RDoc::Include.new 'Mod1', nil
i0_m2 = RDoc::Include.new 'Mod2', nil
i0_m3 = RDoc::Include.new 'Mod3', nil
m1_m2_k0.add_include i0_m4
m1_m2_k0.add_include i0_m5
m1_m2_k0.add_include i0_m6
m1_m2_k0.add_include i0_m1
m1_m2_k0.add_include i0_m2
m1_m2_k0.add_include i0_m3
assert_equal [i0_m4, i0_m5, i0_m6, i0_m1, i0_m2, i0_m3], m1_m2_k0.includes
assert_equal [m1_m2_m3, m1_m2, m1, m1_m2_k0_m4_m6, m1_m2_k0_m5,
m1_m2_k0_m4, 'Object'], m1_m2_k0.ancestors
m1_k1 = m1.add_class RDoc::NormalClass, 'Klass1'
i1_m1 = RDoc::Include.new 'Mod1', nil
i1_m2 = RDoc::Include.new 'Mod2', nil
i1_m3 = RDoc::Include.new 'Mod3', nil
i1_m4 = RDoc::Include.new 'Mod4', nil
i1_k0_m4 = RDoc::Include.new 'Klass0::Mod4', nil
m1_k1.add_include i1_m1
m1_k1.add_include i1_m2
m1_k1.add_include i1_m3
m1_k1.add_include i1_m4
m1_k1.add_include i1_k0_m4
assert_equal [i1_m1, i1_m2, i1_m3, i1_m4, i1_k0_m4], m1_k1.includes
assert_equal [m1_m2_k0_m4, m1_m2_m3_m4, m1_m2_m3, m1_m2, m1, 'Object'],
m1_k1.ancestors
m1_k2 = m1.add_class RDoc::NormalClass, 'Klass2'
i2_m1 = RDoc::Include.new 'Mod1', nil
i2_m2 = RDoc::Include.new 'Mod2', nil
i2_m3 = RDoc::Include.new 'Mod3', nil
i2_k0_m4 = RDoc::Include.new 'Klass0::Mod4', nil
m1_k2.add_include i2_m1
m1_k2.add_include i2_m3
m1_k2.add_include i2_m2
m1_k2.add_include i2_k0_m4
assert_equal [i2_m1, i2_m3, i2_m2, i2_k0_m4], m1_k2.includes
assert_equal [m1_m2_k0_m4, m1_m2, m1_m3, m1, 'Object'], m1_k2.ancestors
m1_k3 = m1.add_class RDoc::NormalClass, 'Klass3'
i3_m1 = RDoc::Include.new 'Mod1', nil
i3_m2 = RDoc::Include.new 'Mod2', nil
i3_m4 = RDoc::Include.new 'Mod4', nil
m1_k3.add_include i3_m1
m1_k3.add_include i3_m2
m1_k3.add_include i3_m4
assert_equal [i3_m1, i3_m2, i3_m4], m1_k3.includes
assert_equal [m1_m2_m4, m1_m2, m1, 'Object'], m1_k3.ancestors
end
end

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

@ -1,9 +1,9 @@
require "rubygems"
require "minitest/autorun"
require 'rubygems'
require 'minitest/autorun'
require 'rdoc'
require 'rdoc/markup'
require "rdoc/markup/inline"
require "rdoc/markup/to_html_crossref"
require 'rdoc/markup/inline'
require 'rdoc/markup/to_html_crossref'
class TestRDocMarkupAttributeManager < MiniTest::Unit::TestCase

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

@ -1,8 +1,9 @@
# coding: utf-8
require 'pp'
require 'rubygems'
require 'minitest/autorun'
require 'rdoc/markup'
require 'rdoc/markup/to_test'
class TestRDocMarkupParser < MiniTest::Unit::TestCase
@ -53,6 +54,19 @@ class TestRDocMarkupParser < MiniTest::Unit::TestCase
assert_equal expected, @RMP.parse(str).parts
end
def test_parse_bullet_utf_8
str = <<-STR
*
STR
expected = [
@RM::List.new(:BULLET, *[
@RM::ListItem.new(nil,
@RM::Paragraph.new('新しい機能'))])]
assert_equal expected, @RMP.parse(str).parts
end
def test_parse_bullet_verbatim_heading
str = <<-STR
* l1
@ -65,7 +79,7 @@ class TestRDocMarkupParser < MiniTest::Unit::TestCase
@RM::List.new(:BULLET, *[
@RM::ListItem.new(nil,
@RM::Paragraph.new('l1'),
@RM::Verbatim.new(' ', 'v', "\n"))]),
@RM::Verbatim.new("v\n"))]),
@RM::Heading.new(1, 'H')]
assert_equal expected, @RMP.parse(str).parts
@ -183,8 +197,7 @@ the time
@RM::List.new(:BULLET, *[
@RM::ListItem.new(nil,
@RM::Paragraph.new('l1.1', 'text'),
@RM::Verbatim.new(' ', 'code', "\n",
' ', 'code', "\n"),
@RM::Verbatim.new("code\n", " code\n"),
@RM::Paragraph.new('text'))])),
@RM::ListItem.new(nil,
@RM::Paragraph.new('l2'))])]
@ -400,6 +413,68 @@ A. l4
assert_equal expected, @RMP.parse(str).parts
end
def test_parse_lalpha_utf_8
str = <<-STR
a.
STR
expected = [
@RM::List.new(:LALPHA, *[
@RM::ListItem.new(nil,
@RM::Paragraph.new('新しい機能'))])]
assert_equal expected, @RMP.parse(str).parts
end
def test_parse_list_list_1
str = <<-STR
10. para 1
[label 1]
para 1.1
code
para 1.2
STR
expected = [
@RM::List.new(:NUMBER, *[
@RM::ListItem.new(nil, *[
@RM::Paragraph.new('para 1'),
@RM::BlankLine.new,
@RM::List.new(:LABEL, *[
@RM::ListItem.new('label 1', *[
@RM::Paragraph.new('para 1.1'),
@RM::BlankLine.new,
@RM::Verbatim.new("code\n"),
@RM::Paragraph.new('para 1.2')])])])])]
assert_equal expected, @RMP.parse(str).parts
end
def test_parse_list_list_2
str = <<-STR
6. para
label 1:: text 1
label 2:: text 2
STR
expected = [
@RM::List.new(:NUMBER, *[
@RM::ListItem.new(nil, *[
@RM::Paragraph.new('para'),
@RM::BlankLine.new,
@RM::List.new(:NOTE, *[
@RM::ListItem.new('label 1',
@RM::Paragraph.new('text 1')),
@RM::ListItem.new('label 2',
@RM::Paragraph.new('text 2'))])])])]
assert_equal expected, @RMP.parse(str).parts
end
def test_parse_list_verbatim
str = <<-STR
* one
@ -412,8 +487,7 @@ A. l4
@RM::List.new(:BULLET, *[
@RM::ListItem.new(nil,
@RM::Paragraph.new('one'),
@RM::Verbatim.new(' ', 'verb1', "\n",
' ', 'verb2', "\n")),
@RM::Verbatim.new("verb1\n", "verb2\n")),
@RM::ListItem.new(nil,
@RM::Paragraph.new('two'))])]
@ -545,7 +619,7 @@ for all good men
expected = [
@RM::Paragraph.new('now is the time'),
@RM::Verbatim.new(' ', 'code _line_ here', "\n"),
@RM::Verbatim.new("code _line_ here\n"),
@RM::Paragraph.new('for all good men'),
]
assert_equal expected, @RMP.parse(str).parts
@ -567,6 +641,12 @@ B. l2
assert_equal expected, @RMP.parse(str).parts
end
def test_parse_trailing_cr
expected = [ @RM::Paragraph.new('Text') ]
# FIXME hangs the parser:
assert_equal expected, @RMP.parse("Text\r").parts
end
def test_parse_verbatim
str = <<-STR
now is
@ -576,7 +656,7 @@ the time
expected = [
@RM::Paragraph.new('now is'),
@RM::Verbatim.new(' ', 'code', "\n"),
@RM::Verbatim.new("code\n"),
@RM::Paragraph.new('the time'),
]
@ -589,7 +669,18 @@ the time
STR
expected = [
@RM::Verbatim.new(' ', '*', ' ', 'blah', "\n")]
@RM::Verbatim.new("* blah\n")]
assert_equal expected, @RMP.parse(str).parts
end
def test_parse_verbatim_dash
str = <<-STR
- blah
STR
expected = [
@RM::Verbatim.new("- blah\n")]
assert_equal expected, @RMP.parse(str).parts
end
@ -607,9 +698,7 @@ the time
expected = [
@RM::Paragraph.new('now is'),
@RM::Verbatim.new(' ', 'code', "\n",
"\n",
' ', 'code1', "\n"),
@RM::Verbatim.new("code\n", "\n", "code1\n"),
@RM::Paragraph.new('the time'),
]
@ -624,7 +713,7 @@ text
expected = [
@RM::Paragraph.new('text'),
@RM::Verbatim.new(' ', '===', ' ', 'heading three', "\n")]
@RM::Verbatim.new("=== heading three\n")]
assert_equal expected, @RMP.parse(str).parts
end
@ -634,7 +723,7 @@ text
expected = [
@RM::Paragraph.new('text'),
@RM::Verbatim.new(' ', 'code', "\n"),
@RM::Verbatim.new("code\n"),
@RM::Heading.new(3, 'heading three')]
assert_equal expected, @RMP.parse(str).parts
@ -646,7 +735,7 @@ text
STR
expected = [
@RM::Verbatim.new(' ', '[blah]', ' ', 'blah', "\n")]
@RM::Verbatim.new("[blah] blah\n")]
assert_equal expected, @RMP.parse(str).parts
end
@ -657,7 +746,7 @@ text
STR
expected = [
@RM::Verbatim.new(' ', 'b.', ' ', 'blah', "\n")]
@RM::Verbatim.new("b. blah\n")]
assert_equal expected, @RMP.parse(str).parts
end
@ -671,8 +760,7 @@ text
expected = [
@RM::Paragraph.new('text'),
@RM::Verbatim.new(' ', 'code', "\n",
' ', '===', ' ', 'heading three', "\n")]
@RM::Verbatim.new("code\n", "=== heading three\n")]
assert_equal expected, @RMP.parse(str).parts
end
@ -688,9 +776,7 @@ the time
expected = [
@RM::Paragraph.new('now is'),
@RM::Verbatim.new(' ', 'code', "\n",
"\n",
' ', 'code1', "\n"),
@RM::Verbatim.new("code\n", "\n", "code1\n"),
@RM::Paragraph.new('the time'),
]
@ -710,11 +796,7 @@ the time
expected = [
@RM::Paragraph.new('now is'),
@RM::Verbatim.new(' ', 'code', "\n",
"\n",
' ', 'code1', "\n",
"\n",
' ', 'code2', "\n"),
@RM::Verbatim.new("code\n", "\n", "code1\n", "\n", "code2\n"),
@RM::Paragraph.new('the time'),
]
@ -731,8 +813,7 @@ the time
expected = [
@RM::Paragraph.new('now is'),
@RM::Verbatim.new(' ', 'code', "\n",
' ', 'code1', "\n"),
@RM::Verbatim.new("code\n", "code1\n"),
@RM::Paragraph.new('the time'),
]
@ -749,8 +830,8 @@ for all good men
expected = [
@RM::Paragraph.new('now is the time'),
@RM::Verbatim.new(' ', 'code', "\n",
' ', 'more code', "\n"),
@RM::Verbatim.new(" code\n",
"more code\n"),
@RM::Paragraph.new('for all good men'),
]
@ -763,7 +844,7 @@ for all good men
STR
expected = [
@RM::Verbatim.new(' ', 'blah::', ' ', 'blah', "\n")]
@RM::Verbatim.new("blah:: blah\n")]
assert_equal expected, @RMP.parse(str).parts
end
@ -774,7 +855,7 @@ for all good men
STR
expected = [
@RM::Verbatim.new(' ', '2.', ' ', 'blah', "\n")]
@RM::Verbatim.new("2. blah\n")]
assert_equal expected, @RMP.parse(str).parts
end
@ -790,8 +871,8 @@ text
expected = [
@RM::Paragraph.new('text'),
@RM::BlankLine.new,
@RM::Verbatim.new(' ', '---', ' ', 'lib/blah.rb.orig', "\n",
' ', '+++', ' ', 'lib/blah.rb', "\n")]
@RM::Verbatim.new("--- lib/blah.rb.orig\n",
"+++ lib/blah.rb\n")]
assert_equal expected, @RMP.parse(str).parts
end
@ -806,7 +887,7 @@ text
expected = [
@RM::Paragraph.new('text'),
@RM::BlankLine.new,
@RM::Verbatim.new(' ', '---', '')]
@RM::Verbatim.new("---")]
assert_equal expected, @RMP.parse(str).parts
end
@ -823,9 +904,9 @@ the time
expected = [
@RM::Paragraph.new('now is'),
@RM::Verbatim.new(' ', 'code', "\n",
@RM::Verbatim.new("code\n",
"\n",
' ', 'code1', "\n"),
"code1\n"),
@RM::Paragraph.new('the time'),
]
@ -838,7 +919,7 @@ the time
STR
expected = [
@RM::Verbatim.new(' ', 'B.', ' ', 'blah', "\n")]
@RM::Verbatim.new("B. blah\n")]
assert_equal expected, @RMP.parse(str).parts
end
@ -851,58 +932,57 @@ the time
assert_equal expected, @RMP.parse('hello').parts
expected = [
@RM::Verbatim.new(' ', 'hello '),
@RM::Verbatim.new('hello '),
]
assert_equal expected, @RMP.parse(' hello ').parts
assert_equal expected, @RMP.parse(' hello ').parts
expected = [
@RM::Verbatim.new(' ', 'hello '),
@RM::Verbatim.new('hello '),
]
assert_equal expected, @RMP.parse(" hello ").parts
assert_equal expected, @RMP.parse(' hello ').parts
expected = [
@RM::Paragraph.new('1'),
@RM::Verbatim.new(' ', '2', "\n",
' ', '3'),
@RM::Verbatim.new("2\n", ' 3'),
]
assert_equal expected, @RMP.parse("1\n 2\n 3").parts
expected = [
@RM::Verbatim.new(' ', '1', "\n",
' ', '2', "\n",
' ', '3'),
@RM::Verbatim.new("1\n",
" 2\n",
" 3"),
]
assert_equal expected, @RMP.parse(" 1\n 2\n 3").parts
expected = [
@RM::Paragraph.new('1'),
@RM::Verbatim.new(' ', '2', "\n",
' ', '3', "\n"),
@RM::Verbatim.new("2\n",
" 3\n"),
@RM::Paragraph.new('1'),
@RM::Verbatim.new(' ', '2'),
@RM::Verbatim.new('2'),
]
assert_equal expected, @RMP.parse("1\n 2\n 3\n1\n 2").parts
expected = [
@RM::Verbatim.new(' ', '1', "\n",
' ', '2', "\n",
' ', '3', "\n",
' ', '1', "\n",
' ', '2'),
@RM::Verbatim.new("1\n",
" 2\n",
" 3\n",
"1\n",
' 2'),
]
assert_equal expected, @RMP.parse(" 1\n 2\n 3\n 1\n 2").parts
expected = [
@RM::Verbatim.new(' ', '1', "\n",
' ', '2', "\n",
@RM::Verbatim.new("1\n",
" 2\n",
"\n",
' ', '3'),
' 3'),
]
assert_equal expected, @RMP.parse(" 1\n 2\n\n 3").parts
@ -942,8 +1022,7 @@ the time
STR
expected = [
[:BULLET, :BULLET, 0, 0],
[:SPACE, 2, 0, 0],
[:BULLET, '*', 0, 0],
[:TEXT, 'l1', 2, 0],
[:NEWLINE, "\n", 4, 0],
]
@ -958,13 +1037,10 @@ the time
STR
expected = [
[:BULLET, :BULLET, 0, 0],
[:SPACE, 2, 0, 0],
[:BULLET, '*', 0, 0],
[:TEXT, 'l1', 2, 0],
[:NEWLINE, "\n", 4, 0],
[:INDENT, 2, 0, 1],
[:BULLET, :BULLET, 2, 1],
[:SPACE, 2, 2, 1],
[:BULLET, '*', 2, 1],
[:TEXT, 'l1.1', 4, 1],
[:NEWLINE, "\n", 8, 1],
]
@ -1030,11 +1106,9 @@ the time
expected = [
[:LABEL, 'cat', 0, 0],
[:SPACE, 6, 0, 0],
[:TEXT, 'l1', 6, 0],
[:NEWLINE, "\n", 8, 0],
[:LABEL, 'dog', 0, 1],
[:SPACE, 6, 0, 1],
[:TEXT, 'l1.1', 6, 1],
[:NEWLINE, "\n", 10, 1],
]
@ -1050,11 +1124,8 @@ the time
expected = [
[:LABEL, 'label', 0, 0],
[:SPACE, 7, 0, 0],
[:NEWLINE, "\n", 7, 0],
[:INDENT, 2, 0, 1],
[:NOTE, 'note', 2, 1],
[:SPACE, 6, 2, 1],
[:NEWLINE, "\n", 8, 1],
]
@ -1069,11 +1140,9 @@ b. l1.1
expected = [
[:LALPHA, 'a', 0, 0],
[:SPACE, 3, 0, 0],
[:TEXT, 'l1', 3, 0],
[:NEWLINE, "\n", 5, 0],
[:LALPHA, 'b', 0, 1],
[:SPACE, 3, 0, 1],
[:TEXT, 'l1.1', 3, 1],
[:NEWLINE, "\n", 7, 1],
]
@ -1089,11 +1158,9 @@ dog:: l1.1
expected = [
[:NOTE, 'cat', 0, 0],
[:SPACE, 6, 0, 0],
[:TEXT, 'l1', 6, 0],
[:NEWLINE, "\n", 8, 0],
[:NOTE, 'dog', 0, 1],
[:SPACE, 6, 0, 1],
[:TEXT, 'l1.1', 6, 1],
[:NEWLINE, "\n", 10, 1],
]
@ -1109,10 +1176,8 @@ dog::
expected = [
[:NOTE, 'cat', 0, 0],
[:SPACE, 5, 0, 0],
[:NEWLINE, "\n", 5, 0],
[:NOTE, 'dog', 0, 1],
[:SPACE, 5, 0, 1],
[:NEWLINE, "\n", 5, 1],
]
@ -1140,11 +1205,9 @@ Cat::Dog
expected = [
[:NUMBER, '1', 0, 0],
[:SPACE, 3, 0, 0],
[:TEXT, 'l1', 3, 0],
[:NEWLINE, "\n", 5, 0],
[:NUMBER, '2', 0, 1],
[:SPACE, 3, 0, 1],
[:TEXT, 'l1.1', 3, 1],
[:NEWLINE, "\n", 7, 1],
]
@ -1162,20 +1225,16 @@ Cat::Dog
expected = [
[:NUMBER, "1", 0, 0],
[:SPACE, 3, 0, 0],
[:TEXT, "blah blah blah", 3, 0],
[:NEWLINE, "\n", 17, 0],
[:INDENT, 3, 0, 1],
[:TEXT, "l.", 3, 1],
[:NEWLINE, "\n", 5, 1],
[:NUMBER, "2", 0, 2],
[:SPACE, 3, 0, 2],
[:TEXT, "blah blah blah blah", 3, 2],
[:NEWLINE, "\n", 22, 2],
[:INDENT, 3, 0, 3],
[:TEXT, "d.", 3, 3],
[:NEWLINE, "\n", 5, 3]
]
@ -1193,24 +1252,18 @@ Cat::Dog
expected = [
[:NUMBER, "1", 0, 0],
[:SPACE, 3, 0, 0],
[:TEXT, "blah blah blah", 3, 0],
[:NEWLINE, "\n", 17, 0],
[:INDENT, 3, 0, 1],
[:LALPHA, "l", 3, 1],
[:SPACE, 4, 3, 1],
[:TEXT, "more stuff", 7, 1],
[:NEWLINE, "\n", 17, 1],
[:NUMBER, "2", 0, 2],
[:SPACE, 3, 0, 2],
[:TEXT, "blah blah blah blah", 3, 2],
[:NEWLINE, "\n", 22, 2],
[:INDENT, 3, 0, 3],
[:LALPHA, "d", 3, 3],
[:SPACE, 3, 3, 3],
[:TEXT, "other stuff", 6, 3],
[:NEWLINE, "\n", 17, 3]
]
@ -1241,14 +1294,14 @@ for all
def test_tokenize_rule
str = <<-STR
---
---
--- blah ---
STR
expected = [
[:RULE, 1, 0, 0],
[:NEWLINE, "\n", 4, 0],
[:NEWLINE, "\n", 3, 0],
[:NEWLINE, "\n", 0, 1],
[:TEXT, "--- blah ---", 0, 2],
[:NEWLINE, "\n", 12, 2],
@ -1265,11 +1318,9 @@ B. l1.1
expected = [
[:UALPHA, 'A', 0, 0],
[:SPACE, 3, 0, 0],
[:TEXT, 'l1', 3, 0],
[:NEWLINE, "\n", 5, 0],
[:UALPHA, 'B', 0, 1],
[:SPACE, 3, 0, 1],
[:TEXT, 'l1.1', 3, 1],
[:NEWLINE, "\n", 7, 1],
]
@ -1288,7 +1339,6 @@ Example heading:
[:TEXT, 'Example heading:', 0, 0],
[:NEWLINE, "\n", 16, 0],
[:NEWLINE, "\n", 0, 1],
[:INDENT, 3, 0, 2],
[:HEADER, 3, 3, 2],
[:TEXT, 'heading three', 7, 2],
[:NEWLINE, "\n", 20, 2],
@ -1299,17 +1349,17 @@ Example heading:
# HACK move to Verbatim test case
def test_verbatim_normalize
v = @RM::Verbatim.new ' ', 'foo', "\n", "\n", "\n", ' ', 'bar', "\n"
v = @RM::Verbatim.new "foo\n", "\n", "\n", "bar\n"
v.normalize
assert_equal [' ', 'foo', "\n", "\n", ' ', 'bar', "\n"], v.parts
assert_equal ["foo\n", "\n", "bar\n"], v.parts
v = @RM::Verbatim.new ' ', 'foo', "\n", "\n"
v = @RM::Verbatim.new "foo\n", "\n"
v.normalize
assert_equal [' ', 'foo', "\n"], v.parts
assert_equal ["foo\n"], v.parts
end
def test_unget

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

@ -1,7 +1,7 @@
require 'tempfile'
require 'rubygems'
require 'minitest/autorun'
require 'rdoc/markup/preprocess'
require 'rdoc/markup/pre_process'
require 'rdoc/code_objects'
class TestRDocMarkupPreProcess < MiniTest::Unit::TestCase
@ -10,8 +10,7 @@ class TestRDocMarkupPreProcess < MiniTest::Unit::TestCase
RDoc::Markup::PreProcess.registered.clear
@tempfile = Tempfile.new 'test_rdoc_markup_pre_process'
@tempfile.binmode
@name = File.basename @tempfile.path
@file_name = File.basename @tempfile.path
@dir = File.dirname @tempfile.path
@pp = RDoc::Markup::PreProcess.new __FILE__, [@dir]
@ -32,13 +31,18 @@ contents of a string.
@tempfile.flush
@tempfile.rewind
content = @pp.include_file @name, ''
content = @pp.include_file @file_name, '', nil
expected = <<-EXPECTED
Regular expressions (<i>regexp</i>s) are patterns which describe the
contents of a string.
EXPECTED
# FIXME 1.9 fix on windoze
# preprocessor uses binread, so line endings are \r\n
expected.gsub!("\n", "\r\n") if
RUBY_VERSION =~ /^1.9/ && RUBY_PLATFORM =~ /mswin|mingw/
assert_equal expected, content
end

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

@ -1,11 +1,12 @@
require 'rubygems'
require 'rdoc/markup/formatter_test_case'
require 'rdoc/markup/text_formatter_test_case'
require 'rdoc/markup/to_ansi'
require 'minitest/autorun'
class TestRDocMarkupToAnsi < RDoc::Markup::FormatterTestCase
class TestRDocMarkupToAnsi < RDoc::Markup::TextFormatterTestCase
add_visitor_tests
add_text_tests
def setup
super
@ -62,7 +63,7 @@ class TestRDocMarkupToAnsi < RDoc::Markup::FormatterTestCase
end
def accept_list_item_end_label
assert_equal "\e[0m\n", @to.res.join
assert_equal "\e[0m", @to.res.join
assert_equal 0, @to.indent, 'indent'
end
@ -72,7 +73,7 @@ class TestRDocMarkupToAnsi < RDoc::Markup::FormatterTestCase
end
def accept_list_item_end_note
assert_equal "\e[0m\n", @to.res.join
assert_equal "\e[0m", @to.res.join
assert_equal 0, @to.indent, 'indent'
end
@ -191,8 +192,8 @@ class TestRDocMarkupToAnsi < RDoc::Markup::FormatterTestCase
assert_equal "\e[0m#{'-' * 78}\n", @to.res.join
end
def accept_verbatim # FormatterTestCase doesn't set indent for ToAnsi
assert_equal "\e[0m hi\n world\n\n", @to.res.join
def accept_verbatim
assert_equal "\e[0m hi\n world\n\n", @to.res.join
end
def end_accepting
@ -207,214 +208,103 @@ class TestRDocMarkupToAnsi < RDoc::Markup::FormatterTestCase
assert_empty @to.list_width
end
def test_accept_heading_1
@to.start_accepting
@to.accept_heading @RM::Heading.new(1, 'Hello')
def accept_heading_1
assert_equal "\e[0m\e[1;32mHello\e[m\n", @to.end_accepting
end
def test_accept_heading_2
@to.start_accepting
@to.accept_heading @RM::Heading.new(2, 'Hello')
def accept_heading_2
assert_equal "\e[0m\e[4;32mHello\e[m\n", @to.end_accepting
end
def test_accept_heading_3
@to.start_accepting
@to.accept_heading @RM::Heading.new(3, 'Hello')
def accept_heading_3
assert_equal "\e[0m\e[32mHello\e[m\n", @to.end_accepting
end
def test_accept_heading_4
@to.start_accepting
@to.accept_heading @RM::Heading.new(4, 'Hello')
def accept_heading_4
assert_equal "\e[0mHello\n", @to.end_accepting
end
def test_accept_heading_indent
@to.start_accepting
@to.indent = 3
@to.accept_heading @RM::Heading.new(1, 'Hello')
def accept_heading_indent
assert_equal "\e[0m \e[1;32mHello\e[m\n", @to.end_accepting
end
def test_accept_heading_b
@to.start_accepting
@to.indent = 3
@to.accept_heading @RM::Heading.new(1, '*Hello*')
assert_equal "\e[0m \e[1;32m\e[1mHello\e[m\e[m\n", @to.end_accepting
def accept_heading_b
assert_equal "\e[0m\e[1;32m\e[1mHello\e[m\e[m\n", @to.end_accepting
end
def test_accept_list_item_start_note_2
list = @RM::List.new(:NOTE,
@RM::ListItem.new('<tt>teletype</tt>',
@RM::Paragraph.new('teletype description')))
@to.start_accepting
list.accept @to
expected = "\e[0m\e[7mteletype\e[m:\n teletype description\n\n"
assert_equal expected, @to.end_accepting
def accept_heading_suppressed_crossref
assert_equal "\e[0m\e[1;32mHello\e[m\n", @to.end_accepting
end
def test_accept_paragraph_b
@to.start_accepting
@to.accept_paragraph @RM::Paragraph.new('reg <b>bold words</b> reg')
expected = "\e[0mreg \e[1mbold words\e[m reg\n"
assert_equal expected, @to.end_accepting
def accept_list_item_start_note_2
assert_equal "\e[0m\e[7mteletype\e[m:\n teletype description\n\n",
@to.res.join
end
def test_accept_paragraph_i
@to.start_accepting
@to.accept_paragraph @RM::Paragraph.new('reg <em>italic words</em> reg')
expected = "\e[0mreg \e[4mitalic words\e[m reg\n"
assert_equal expected, @to.end_accepting
def accept_paragraph_b
assert_equal "\e[0mreg \e[1mbold words\e[m reg\n", @to.end_accepting
end
def test_accept_paragraph_indent
@to.start_accepting
@to.indent = 3
@to.accept_paragraph @RM::Paragraph.new('words ' * 30)
def accept_paragraph_i
assert_equal "\e[0mreg \e[4mitalic words\e[m reg\n", @to.end_accepting
end
def accept_paragraph_indent
expected = <<-EXPECTED
\e[0m words words words words words words words words words words words words
words words words words words words words words words words words words
words words words words words words
words words words words words words
EXPECTED
assert_equal expected, @to.end_accepting
end
def test_accept_paragraph_plus
@to.start_accepting
@to.accept_paragraph @RM::Paragraph.new('regular +teletype+ regular')
expected = "\e[0mregular \e[7mteletype\e[m regular\n"
assert_equal expected, @to.end_accepting
def accept_paragraph_plus
assert_equal "\e[0mreg \e[7mteletype\e[m reg\n", @to.end_accepting
end
def test_accept_paragraph_star
@to.start_accepting
@to.accept_paragraph @RM::Paragraph.new('regular *bold* regular')
expected = "\e[0mregular \e[1mbold\e[m regular\n"
assert_equal expected, @to.end_accepting
def accept_paragraph_star
assert_equal "\e[0mreg \e[1mbold\e[m reg\n", @to.end_accepting
end
def test_accept_paragraph_underscore
@to.start_accepting
@to.accept_paragraph @RM::Paragraph.new('regular _italic_ regular')
expected = "\e[0mregular \e[4mitalic\e[m regular\n"
assert_equal expected, @to.end_accepting
def accept_paragraph_underscore
assert_equal "\e[0mreg \e[4mitalic\e[m reg\n", @to.end_accepting
end
def test_accept_paragraph_wrap
@to.start_accepting
@to.accept_paragraph @RM::Paragraph.new('words ' * 30)
def accept_paragraph_wrap
expected = <<-EXPECTED
\e[0mwords words words words words words words words words words words words words
words words words words words words words words words words words words words
words words words words
words words words words
EXPECTED
assert_equal expected, @to.end_accepting
end
def test_accept_rule_indent
@to.start_accepting
@to.indent = 3
@to.accept_rule @RM::Rule.new(1)
def accept_rule_indent
assert_equal "\e[0m #{'-' * 75}\n", @to.end_accepting
end
def test_accept_verbatim_indent
@to.start_accepting
@to.indent = 2
@to.accept_verbatim @RM::Verbatim.new(' ', 'hi', "\n",
' ', 'world', "\n")
def accept_verbatim_indent
assert_equal "\e[0m hi\n world\n\n", @to.end_accepting
end
def test_accept_verbatim_big_indent
@to.start_accepting
@to.indent = 2
@to.accept_verbatim @RM::Verbatim.new(' ', 'hi', "\n",
' ', 'world', "\n")
def accept_verbatim_big_indent
assert_equal "\e[0m hi\n world\n\n", @to.end_accepting
end
def test_attributes
assert_equal 'Dog', @to.attributes("\\Dog")
end
def test_list_nested
doc = @RM::Document.new(
@RM::List.new(:BULLET,
@RM::ListItem.new(nil,
@RM::Paragraph.new('l1'),
@RM::List.new(:BULLET,
@RM::ListItem.new(nil,
@RM::Paragraph.new('l1.1')))),
@RM::ListItem.new(nil,
@RM::Paragraph.new('l2'))))
output = doc.accept @to
def list_nested
expected = <<-EXPECTED
\e[0m* l1
* l1.1
* l2
EXPECTED
assert_equal expected, output
assert_equal expected, @to.end_accepting
end
def test_list_verbatim # HACK overblown
doc = @RM::Document.new(
@RM::List.new(:BULLET,
@RM::ListItem.new(nil,
@RM::Paragraph.new('list', 'stuff'),
@RM::BlankLine.new(),
@RM::Verbatim.new(' ', '*', ' ', 'list', "\n",
' ', 'with', "\n",
"\n",
' ', 'second', "\n",
"\n",
' ', '1.', ' ', 'indented', "\n",
' ', '2.', ' ', 'numbered', "\n",
"\n",
' ', 'third', "\n",
"\n",
' ', '*', ' ', 'second', "\n"))))
output = doc.accept @to
expected = <<-EXPECTED
def list_verbatim
expected = <<-EXPECTED # HACK overblown
\e[0m* list stuff
* list
@ -431,7 +321,7 @@ words words words words
EXPECTED
assert_equal expected, output
assert_equal expected, @to.end_accepting
end
end

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

@ -1,11 +1,12 @@
require 'rubygems'
require 'rdoc/markup/formatter_test_case'
require 'rdoc/markup/text_formatter_test_case'
require 'rdoc/markup/to_bs'
require 'minitest/autorun'
class TestRDocMarkupToBs < RDoc::Markup::FormatterTestCase
class TestRDocMarkupToBs < RDoc::Markup::TextFormatterTestCase
add_visitor_tests
add_text_tests
def setup
super
@ -63,6 +64,7 @@ class TestRDocMarkupToBs < RDoc::Markup::FormatterTestCase
end
def accept_list_item_end_label
assert_equal "\n", @to.res.join
assert_equal 0, @to.indent, 'indent'
end
@ -72,6 +74,7 @@ class TestRDocMarkupToBs < RDoc::Markup::FormatterTestCase
end
def accept_list_item_end_note
assert_equal "\n", @to.res.join
assert_equal 0, @to.indent, 'indent'
end
@ -190,8 +193,8 @@ class TestRDocMarkupToBs < RDoc::Markup::FormatterTestCase
assert_equal "#{'-' * 78}\n", @to.res.join
end
def accept_verbatim # FormatterTestCase doesn't set indent for ToAnsi
assert_equal " hi\n world\n\n", @to.res.join
def accept_verbatim
assert_equal " hi\n world\n\n", @to.res.join
end
def end_accepting
@ -206,232 +209,115 @@ class TestRDocMarkupToBs < RDoc::Markup::FormatterTestCase
assert_empty @to.list_width
end
def test_accept_heading_1
def accept_heading_1
skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars
@to.start_accepting
@to.accept_heading @RM::Heading.new(1, 'Hello')
assert_equal "= H\bHe\bel\bll\blo\bo\n", @to.end_accepting
end
def test_accept_heading_2
def accept_heading_2
skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars
@to.start_accepting
@to.accept_heading @RM::Heading.new(2, 'Hello')
assert_equal "== H\bHe\bel\bll\blo\bo\n", @to.end_accepting
end
def test_accept_heading_3
def accept_heading_3
skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars
@to.start_accepting
@to.accept_heading @RM::Heading.new(3, 'Hello')
assert_equal "=== H\bHe\bel\bll\blo\bo\n", @to.end_accepting
end
def test_accept_heading_4
def accept_heading_4
skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars
@to.start_accepting
@to.accept_heading @RM::Heading.new(4, 'Hello')
assert_equal "==== H\bHe\bel\bll\blo\bo\n", @to.end_accepting
end
def test_accept_heading_indent
def accept_heading_indent
skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars
@to.start_accepting
@to.indent = 3
@to.accept_heading @RM::Heading.new(1, 'Hello')
assert_equal " = H\bHe\bel\bll\blo\bo\n", @to.end_accepting
end
def test_accept_heading_b
def accept_heading_b
skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars
@to.start_accepting
@to.indent = 3
@to.accept_heading @RM::Heading.new(1, '*Hello*')
assert_equal " = H\bHe\bel\bll\blo\bo\n", @to.end_accepting
end
def test_accept_heading_suppressed_crossref
skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars
@to.start_accepting
@to.accept_heading @RM::Heading.new(1, '\\Hello')
assert_equal "= H\bHe\bel\bll\blo\bo\n", @to.end_accepting
end
def test_accept_list_item_start_note_2
list = @RM::List.new(:NOTE,
@RM::ListItem.new('<tt>teletype</tt>',
@RM::Paragraph.new('teletype description')))
@to.start_accepting
list.accept @to
expected = "teletype:\n teletype description\n\n"
assert_equal expected, @to.end_accepting
end
def test_accept_paragraph_b
def accept_heading_suppressed_crossref
skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars
@to.start_accepting
@to.accept_paragraph @RM::Paragraph.new('reg <b>bold words</b> reg')
expected = "reg b\bbo\bol\bld\bd \b w\bwo\bor\brd\bds\bs reg\n"
assert_equal expected, @to.end_accepting
assert_equal "= H\bHe\bel\bll\blo\bo\n", @to.end_accepting
end
def test_accept_paragraph_i
def accept_list_item_start_note_2
assert_equal "teletype:\n teletype description\n\n", @to.res.join
end
def accept_paragraph_b
skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars
@to.start_accepting
@to.accept_paragraph @RM::Paragraph.new('reg <em>italic words</em> reg')
expected = "reg _\bi_\bt_\ba_\bl_\bi_\bc_\b _\bw_\bo_\br_\bd_\bs reg\n"
assert_equal expected, @to.end_accepting
assert_equal "reg b\bbo\bol\bld\bd \b w\bwo\bor\brd\bds\bs reg\n",
@to.end_accepting
end
def test_accept_paragraph_indent
@to.start_accepting
@to.indent = 3
@to.accept_paragraph @RM::Paragraph.new('words ' * 30)
def accept_paragraph_i
skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars
assert_equal "reg _\bi_\bt_\ba_\bl_\bi_\bc_\b _\bw_\bo_\br_\bd_\bs reg\n",
@to.end_accepting
end
def accept_paragraph_indent
expected = <<-EXPECTED
words words words words words words words words words words words words
words words words words words words words words words words words words
words words words words words words
words words words words words words
EXPECTED
assert_equal expected, @to.end_accepting
end
def test_accept_paragraph_plus
@to.start_accepting
@to.accept_paragraph @RM::Paragraph.new('regular +teletype+ regular')
expected = "regular teletype regular\n"
assert_equal expected, @to.end_accepting
def accept_paragraph_plus
assert_equal "reg teletype reg\n", @to.end_accepting
end
def test_accept_paragraph_star
def accept_paragraph_star
skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars
@to.start_accepting
@to.accept_paragraph @RM::Paragraph.new('regular *bold* regular')
expected = "regular b\bbo\bol\bld\bd regular\n"
assert_equal expected, @to.end_accepting
assert_equal "reg b\bbo\bol\bld\bd reg\n", @to.end_accepting
end
def test_accept_paragraph_underscore
def accept_paragraph_underscore
skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars
@to.start_accepting
@to.accept_paragraph @RM::Paragraph.new('regular _italic_ regular')
expected = "regular _\bi_\bt_\ba_\bl_\bi_\bc regular\n"
assert_equal expected, @to.end_accepting
assert_equal "reg _\bi_\bt_\ba_\bl_\bi_\bc reg\n", @to.end_accepting
end
def test_accept_paragraph_wrap
@to.start_accepting
@to.accept_paragraph @RM::Paragraph.new('words ' * 30)
def accept_paragraph_wrap
expected = <<-EXPECTED
words words words words words words words words words words words words words
words words words words words words words words words words words words words
words words words words
words words words words
EXPECTED
assert_equal expected, @to.end_accepting
end
def test_accept_rule_indent
@to.start_accepting
@to.indent = 3
@to.accept_rule @RM::Rule.new(1)
def accept_rule_indent
assert_equal " #{'-' * 75}\n", @to.end_accepting
end
def test_accept_verbatim_indent
@to.start_accepting
@to.indent = 2
@to.accept_verbatim @RM::Verbatim.new(' ', 'hi', "\n",
' ', 'world', "\n")
def accept_verbatim_indent
assert_equal " hi\n world\n\n", @to.end_accepting
end
def test_accept_verbatim_big_indent
@to.start_accepting
@to.indent = 2
@to.accept_verbatim @RM::Verbatim.new(' ', 'hi', "\n",
' ', 'world', "\n")
def accept_verbatim_big_indent
assert_equal " hi\n world\n\n", @to.end_accepting
end
def test_attributes
assert_equal 'Dog', @to.attributes("\\Dog")
end
def test_list_nested
doc = @RM::Document.new(
@RM::List.new(:BULLET,
@RM::ListItem.new(nil,
@RM::Paragraph.new('l1'),
@RM::List.new(:BULLET,
@RM::ListItem.new(nil,
@RM::Paragraph.new('l1.1')))),
@RM::ListItem.new(nil,
@RM::Paragraph.new('l2'))))
output = doc.accept @to
def list_nested
expected = <<-EXPECTED
* l1
* l1.1
* l2
EXPECTED
assert_equal expected, output
assert_equal expected, @to.end_accepting
end
def test_list_verbatim # HACK overblown
doc = @RM::Document.new(
@RM::List.new(:BULLET,
@RM::ListItem.new(nil,
@RM::Paragraph.new('list', 'stuff'),
@RM::BlankLine.new(),
@RM::Verbatim.new(' ', '*', ' ', 'list', "\n",
' ', 'with', "\n",
"\n",
' ', 'second', "\n",
"\n",
' ', '1.', ' ', 'indented', "\n",
' ', '2.', ' ', 'numbered', "\n",
"\n",
' ', 'third', "\n",
"\n",
' ', '*', ' ', 'second', "\n"))))
output = doc.accept @to
expected = <<-EXPECTED
def list_verbatim
expected = <<-EXPECTED # HACK overblown
* list stuff
* list
@ -448,7 +334,7 @@ words words words words
EXPECTED
assert_equal expected, output
assert_equal expected, @to.end_accepting
end
end

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

@ -31,49 +31,73 @@ class TestRDocMarkupToHtml < RDoc::Markup::FormatterTestCase
end
def accept_heading
assert_equal "<h5>Hello</h5>\n", @to.res.join
assert_equal "\n<h5>Hello</h5>\n", @to.res.join
end
def accept_heading_1
assert_equal "\n<h1>Hello</h1>\n", @to.res.join
end
def accept_heading_2
assert_equal "\n<h2>Hello</h2>\n", @to.res.join
end
def accept_heading_3
assert_equal "\n<h3>Hello</h3>\n", @to.res.join
end
def accept_heading_4
assert_equal "\n<h4>Hello</h4>\n", @to.res.join
end
def accept_heading_b
assert_equal "\n<h1><b>Hello</b></h1>\n", @to.res.join
end
def accept_heading_suppressed_crossref
assert_equal "\n<h1>Hello</h1>\n", @to.res.join
end
def accept_list_end_bullet
assert_equal [], @to.list
assert_equal [], @to.in_list_entry
assert_equal "<ul>\n</ul>\n", @to.res.join
assert_equal "<ul></ul>\n", @to.res.join
end
def accept_list_end_label
assert_equal [], @to.list
assert_equal [], @to.in_list_entry
assert_equal "<dl>\n</dl>\n", @to.res.join
assert_equal "<dl></dl>\n", @to.res.join
end
def accept_list_end_lalpha
assert_equal [], @to.list
assert_equal [], @to.in_list_entry
assert_equal "<ol style=\"display: lower-alpha\">\n</ol>\n", @to.res.join
assert_equal "<ol style=\"display: lower-alpha\"></ol>\n", @to.res.join
end
def accept_list_end_number
assert_equal [], @to.list
assert_equal [], @to.in_list_entry
assert_equal "<ol>\n</ol>\n", @to.res.join
assert_equal "<ol></ol>\n", @to.res.join
end
def accept_list_end_note
assert_equal [], @to.list
assert_equal [], @to.in_list_entry
assert_equal "<table>\n</table>\n", @to.res.join
assert_equal "<table class=\"rdoc-list\"></table>\n", @to.res.join
end
def accept_list_end_ualpha
assert_equal [], @to.list
assert_equal [], @to.in_list_entry
assert_equal "<ol style=\"display: upper-alpha\">\n</ol>\n", @to.res.join
assert_equal "<ol style=\"display: upper-alpha\"></ol>\n", @to.res.join
end
def accept_list_item_end_bullet
@ -101,73 +125,105 @@ class TestRDocMarkupToHtml < RDoc::Markup::FormatterTestCase
end
def accept_list_item_start_bullet
assert_equal "<ul>\n<li>", @to.res.join
assert_equal "<ul><li>", @to.res.join
end
def accept_list_item_start_label
assert_equal "<dl>\n<dt>cat</dt><dd>", @to.res.join
assert_equal "<dl><dt>cat</dt>\n<dd>", @to.res.join
end
def accept_list_item_start_lalpha
assert_equal "<ol style=\"display: lower-alpha\">\n<li>", @to.res.join
assert_equal "<ol style=\"display: lower-alpha\"><li>", @to.res.join
end
def accept_list_item_start_note
assert_equal "<table>\n<tr><td valign=\"top\">cat</td><td>", @to.res.join
assert_equal "<table class=\"rdoc-list\"><tr><td class=\"rdoc-term\"><p>cat</p></td>\n<td>",
@to.res.join
end
def accept_list_item_start_note_2
expected = <<-EXPECTED
<table class="rdoc-list"><tr><td class="rdoc-term"><p><tt>teletype</tt></p></td>
<td>
<p>teletype description</p>
</td></tr></table>
EXPECTED
assert_equal expected, @to.res.join
end
def accept_list_item_start_number
assert_equal "<ol>\n<li>", @to.res.join
assert_equal "<ol><li>", @to.res.join
end
def accept_list_item_start_ualpha
assert_equal "<ol style=\"display: upper-alpha\">\n<li>", @to.res.join
assert_equal "<ol style=\"display: upper-alpha\"><li>", @to.res.join
end
def accept_list_start_bullet
assert_equal [:BULLET], @to.list
assert_equal [false], @to.in_list_entry
assert_equal "<ul>\n", @to.res.join
assert_equal "<ul>", @to.res.join
end
def accept_list_start_label
assert_equal [:LABEL], @to.list
assert_equal [false], @to.in_list_entry
assert_equal "<dl>\n", @to.res.join
assert_equal "<dl>", @to.res.join
end
def accept_list_start_lalpha
assert_equal [:LALPHA], @to.list
assert_equal [false], @to.in_list_entry
assert_equal "<ol style=\"display: lower-alpha\">\n", @to.res.join
assert_equal "<ol style=\"display: lower-alpha\">", @to.res.join
end
def accept_list_start_note
assert_equal [:NOTE], @to.list
assert_equal [false], @to.in_list_entry
assert_equal "<table>\n", @to.res.join
assert_equal "<table class=\"rdoc-list\">", @to.res.join
end
def accept_list_start_number
assert_equal [:NUMBER], @to.list
assert_equal [false], @to.in_list_entry
assert_equal "<ol>\n", @to.res.join
assert_equal "<ol>", @to.res.join
end
def accept_list_start_ualpha
assert_equal [:UALPHA], @to.list
assert_equal [false], @to.in_list_entry
assert_equal "<ol style=\"display: upper-alpha\">\n", @to.res.join
assert_equal "<ol style=\"display: upper-alpha\">", @to.res.join
end
def accept_paragraph
assert_equal "<p>\nhi\n</p>\n", @to.res.join
assert_equal "\n<p>hi</p>\n", @to.res.join
end
def accept_paragraph_b
assert_equal "\n<p>reg <b>bold words</b> reg</p>\n", @to.res.join
end
def accept_paragraph_i
assert_equal "\n<p>reg <em>italic words</em> reg</p>\n", @to.res.join
end
def accept_paragraph_plus
assert_equal "\n<p>reg <tt>teletype</tt> reg</p>\n", @to.res.join
end
def accept_paragraph_star
assert_equal "\n<p>reg <b>bold</b> reg</p>\n", @to.res.join
end
def accept_paragraph_underscore
assert_equal "\n<p>reg <em>italic</em> reg</p>\n", @to.res.join
end
def accept_raw
@ -183,11 +239,11 @@ class TestRDocMarkupToHtml < RDoc::Markup::FormatterTestCase
end
def accept_rule
assert_equal '<hr style="height: 4px"></hr>', @to.res.join
assert_equal "<hr style=\"height: 4px\">\n", @to.res.join
end
def accept_verbatim
assert_equal "<pre>\n hi\n world\n</pre>\n", @to.res.join
assert_equal "\n<pre>hi\n world</pre>\n", @to.res.join
end
def end_accepting
@ -200,54 +256,70 @@ class TestRDocMarkupToHtml < RDoc::Markup::FormatterTestCase
assert_equal [], @to.list
end
def test_list_verbatim
def list_nested
expected = <<-EXPECTED
<ul><li>
<p>l1</p>
<ul><li>
<p>l1.1</p>
</li></ul>
</li><li>
<p>l2</p>
</li></ul>
EXPECTED
assert_equal expected, @to.res.join
end
def list_verbatim
expected = <<-EXPECTED
<ul><li>
<p>list stuff</p>
<pre>* list
with
second
1. indented
2. numbered
third
* second</pre>
</li></ul>
EXPECTED
assert_equal expected, @to.end_accepting
end
def test_convert_string
assert_equal '&lt;&gt;', @to.convert_string('<>')
end
def test_list_verbatim_2
str = "* one\n verb1\n verb2\n* two\n"
expected = <<-EXPECTED
<ul>
<li><p>
one
</p>
<pre>
verb1
verb2
</pre>
</li>
<li><p>
two
</p>
</li>
</ul>
<ul><li>
<p>one</p>
<pre>verb1
verb2</pre>
</li><li>
<p>two</p>
</li></ul>
EXPECTED
assert_equal expected, @m.convert(str, @to)
end
def test_tt_formatting
assert_equal "<p>\n<tt>--</tt> &#8212; <tt>cats'</tt> cats&#8217;\n</p>\n",
util_format("<tt>--</tt> -- <tt>cats'</tt> cats'")
assert_equal "<p>\n<b>&#8212;</b>\n</p>\n", util_format("<b>--</b>")
def test_to_html
assert_equal "\n<p><tt>--</tt></p>\n", util_format("<tt>--</tt>")
end
def test_convert_string_fancy
#
# The HTML typesetting is broken in a number of ways, but I have fixed
# the most glaring issues for single and double quotes. Note that
# "strange" symbols (periods or dashes) need to be at the end of the
# test case strings in order to suppress cross-references.
#
assert_equal "<p>\n&#8220;cats&#8221;.\n</p>\n", util_format("\"cats\".")
assert_equal "<p>\n&#8216;cats&#8217;.\n</p>\n", util_format("\'cats\'.")
assert_equal "<p>\ncat&#8217;s-\n</p>\n", util_format("cat\'s-")
end
def util_paragraph(text)
RDoc::Markup::Paragraph.new text
end
def util_format(text)
paragraph = util_paragraph text
def util_format text
paragraph = RDoc::Markup::Paragraph.new text
@to.start_accepting
@to.accept_paragraph paragraph

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

@ -14,12 +14,11 @@ class TestRDocMarkupToHtmlCrossref < XrefTestCase
end
def assert_ref(path, ref)
assert_equal "<p>\n<a href=\"#{path}\">#{ref}</a>\n</p>\n",
@xref.convert(ref)
assert_equal "\n<p><a href=\"#{path}\">#{ref}</a></p>\n", @xref.convert(ref)
end
def refute_ref(body, ref)
assert_equal "<p>\n#{body}\n</p>\n", @xref.convert(ref)
assert_equal "\n<p>#{body}</p>\n", @xref.convert(ref)
end
def test_handle_special_CROSSREF_C2
@ -108,16 +107,16 @@ class TestRDocMarkupToHtmlCrossref < XrefTestCase
assert_ref 'C1.html#method-c-m', '::m'
assert_ref 'C1.html#method-i-m', 'C1#m'
assert_ref 'C1.html#method-i-m', 'C1.m'
assert_ref 'C1.html#method-c-m', 'C1.m'
assert_ref 'C1.html#method-c-m', 'C1::m'
assert_ref 'C1.html#method-i-m', 'C1#m'
assert_ref 'C1.html#method-i-m', 'C1#m()'
assert_ref 'C1.html#method-i-m', 'C1#m(*)'
assert_ref 'C1.html#method-i-m', 'C1.m'
assert_ref 'C1.html#method-i-m', 'C1.m()'
assert_ref 'C1.html#method-i-m', 'C1.m(*)'
assert_ref 'C1.html#method-c-m', 'C1.m'
assert_ref 'C1.html#method-c-m', 'C1.m()'
assert_ref 'C1.html#method-c-m', 'C1.m(*)'
assert_ref 'C1.html#method-c-m', 'C1::m'
assert_ref 'C1.html#method-c-m', 'C1::m()'
@ -127,7 +126,8 @@ class TestRDocMarkupToHtmlCrossref < XrefTestCase
assert_ref 'C2/C3.html#method-i-m', 'C2::C3.m'
assert_ref 'C2/C3/H1.html#method-i-m%3F', 'C2::C3::H1#m?'
# TODO stop escaping - HTML5 allows anything but space
assert_ref 'C2/C3/H1.html#method-i-m-3F', 'C2::C3::H1#m?'
assert_ref 'C2/C3.html#method-i-m', '::C2::C3#m'
assert_ref 'C2/C3.html#method-i-m', '::C2::C3#m()'
@ -153,8 +153,15 @@ class TestRDocMarkupToHtmlCrossref < XrefTestCase
refute_ref '::C3::H1#n', '\::C3::H1#n'
end
def test_handle_special_CROSSREF_show_hash_false
@xref.show_hash = false
assert_equal "\n<p><a href=\"C1.html#method-i-m\">m</a></p>\n",
@xref.convert('#m')
end
def test_handle_special_CROSSREF_special
assert_equal "<p>\n<a href=\"C2/C3.html\">C2::C3</a>;method(*)\n</p>\n",
assert_equal "\n<p><a href=\"C2/C3.html\">C2::C3</a>;method(*)</p>\n",
@xref.convert('C2::C3;method(*)')
end

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

@ -1,11 +1,12 @@
require 'rubygems'
require 'rdoc/markup/formatter_test_case'
require 'rdoc/markup/text_formatter_test_case'
require 'rdoc/markup/to_rdoc'
require 'minitest/autorun'
class TestRDocMarkupToRdoc < RDoc::Markup::FormatterTestCase
class TestRDocMarkupToRDoc < RDoc::Markup::TextFormatterTestCase
add_visitor_tests
add_text_tests
def setup
super
@ -191,8 +192,8 @@ class TestRDocMarkupToRdoc < RDoc::Markup::FormatterTestCase
assert_equal "#{'-' * 78}\n", @to.res.join
end
def accept_verbatim # FormatterTestCase doesn't set indent for ToAnsi
assert_equal " hi\n world\n\n", @to.res.join
def accept_verbatim
assert_equal " hi\n world\n\n", @to.res.join
end
def end_accepting
@ -207,214 +208,102 @@ class TestRDocMarkupToRdoc < RDoc::Markup::FormatterTestCase
assert_empty @to.list_width
end
def test_accept_heading_1
@to.start_accepting
@to.accept_heading @RM::Heading.new(1, 'Hello')
def accept_heading_1
assert_equal "= Hello\n", @to.end_accepting
end
def test_accept_heading_2
@to.start_accepting
@to.accept_heading @RM::Heading.new(2, 'Hello')
def accept_heading_2
assert_equal "== Hello\n", @to.end_accepting
end
def test_accept_heading_3
@to.start_accepting
@to.accept_heading @RM::Heading.new(3, 'Hello')
def accept_heading_3
assert_equal "=== Hello\n", @to.end_accepting
end
def test_accept_heading_4
@to.start_accepting
@to.accept_heading @RM::Heading.new(4, 'Hello')
def accept_heading_4
assert_equal "==== Hello\n", @to.end_accepting
end
def test_accept_heading_indent
@to.start_accepting
@to.indent = 3
@to.accept_heading @RM::Heading.new(1, 'Hello')
def accept_heading_indent
assert_equal " = Hello\n", @to.end_accepting
end
def test_accept_heading_b
@to.start_accepting
@to.indent = 3
@to.accept_heading @RM::Heading.new(1, '*Hello*')
assert_equal " = <b>Hello</b>\n", @to.end_accepting
def accept_heading_b
assert_equal "= <b>Hello</b>\n", @to.end_accepting
end
def test_accept_list_item_start_note_2
list = @RM::List.new(:NOTE,
@RM::ListItem.new('<tt>teletype</tt>',
@RM::Paragraph.new('teletype description')))
@to.start_accepting
list.accept @to
expected = "<tt>teletype</tt>:\n teletype description\n\n"
assert_equal expected, @to.end_accepting
def accept_heading_suppressed_crossref
assert_equal "= Hello\n", @to.end_accepting
end
def test_accept_paragraph_b
@to.start_accepting
@to.accept_paragraph @RM::Paragraph.new('reg <b>bold words</b> reg')
expected = "reg <b>bold words</b> reg\n"
assert_equal expected, @to.end_accepting
def accept_list_item_start_note_2
assert_equal "<tt>teletype</tt>:\n teletype description\n\n", @to.res.join
end
def test_accept_paragraph_i
@to.start_accepting
@to.accept_paragraph @RM::Paragraph.new('reg <em>italic words</em> reg')
expected = "reg <em>italic words</em> reg\n"
assert_equal expected, @to.end_accepting
def accept_paragraph_b
assert_equal "reg <b>bold words</b> reg\n", @to.end_accepting
end
def test_accept_paragraph_indent
@to.start_accepting
@to.indent = 3
@to.accept_paragraph @RM::Paragraph.new('words ' * 30)
def accept_paragraph_i
assert_equal "reg <em>italic words</em> reg\n", @to.end_accepting
end
def accept_paragraph_indent
expected = <<-EXPECTED
words words words words words words words words words words words words
words words words words words words words words words words words words
words words words words words words
words words words words words words
EXPECTED
assert_equal expected, @to.end_accepting
end
def test_accept_paragraph_plus
@to.start_accepting
@to.accept_paragraph @RM::Paragraph.new('regular +teletype+ regular')
expected = "regular <tt>teletype</tt> regular\n"
assert_equal expected, @to.end_accepting
def accept_paragraph_plus
assert_equal "reg <tt>teletype</tt> reg\n", @to.end_accepting
end
def test_accept_paragraph_star
@to.start_accepting
@to.accept_paragraph @RM::Paragraph.new('regular *bold* regular')
expected = "regular <b>bold</b> regular\n"
assert_equal expected, @to.end_accepting
def accept_paragraph_star
assert_equal "reg <b>bold</b> reg\n", @to.end_accepting
end
def test_accept_paragraph_underscore
@to.start_accepting
@to.accept_paragraph @RM::Paragraph.new('regular _italic_ regular')
expected = "regular <em>italic</em> regular\n"
assert_equal expected, @to.end_accepting
def accept_paragraph_underscore
assert_equal "reg <em>italic</em> reg\n", @to.end_accepting
end
def test_accept_paragraph_wrap
@to.start_accepting
@to.accept_paragraph @RM::Paragraph.new('words ' * 30)
def accept_paragraph_wrap
expected = <<-EXPECTED
words words words words words words words words words words words words words
words words words words words words words words words words words words words
words words words words
words words words words
EXPECTED
assert_equal expected, @to.end_accepting
end
def test_accept_rule_indent
@to.start_accepting
@to.indent = 3
@to.accept_rule @RM::Rule.new(1)
def accept_rule_indent
assert_equal " #{'-' * 75}\n", @to.end_accepting
end
def test_accept_verbatim_indent
@to.start_accepting
@to.indent = 2
@to.accept_verbatim @RM::Verbatim.new(' ', 'hi', "\n",
' ', 'world', "\n")
def accept_verbatim_indent
assert_equal " hi\n world\n\n", @to.end_accepting
end
def test_accept_verbatim_big_indent
@to.start_accepting
@to.indent = 2
@to.accept_verbatim @RM::Verbatim.new(' ', 'hi', "\n",
' ', 'world', "\n")
def accept_verbatim_big_indent
assert_equal " hi\n world\n\n", @to.end_accepting
end
def test_attributes
assert_equal 'Dog', @to.attributes("\\Dog")
end
def test_list_nested
doc = @RM::Document.new(
@RM::List.new(:BULLET,
@RM::ListItem.new(nil,
@RM::Paragraph.new('l1'),
@RM::List.new(:BULLET,
@RM::ListItem.new(nil,
@RM::Paragraph.new('l1.1')))),
@RM::ListItem.new(nil,
@RM::Paragraph.new('l2'))))
output = doc.accept @to
def list_nested
expected = <<-EXPECTED
* l1
* l1.1
* l2
EXPECTED
assert_equal expected, output
assert_equal expected, @to.end_accepting
end
def test_list_verbatim # HACK overblown
doc = @RM::Document.new(
@RM::List.new(:BULLET,
@RM::ListItem.new(nil,
@RM::Paragraph.new('list', 'stuff'),
@RM::BlankLine.new(),
@RM::Verbatim.new(' ', '*', ' ', 'list', "\n",
' ', 'with', "\n",
"\n",
' ', 'second', "\n",
"\n",
' ', '1.', ' ', 'indented', "\n",
' ', '2.', ' ', 'numbered', "\n",
"\n",
' ', 'third', "\n",
"\n",
' ', '*', ' ', 'second', "\n"))))
output = doc.accept @to
expected = <<-EXPECTED
def list_verbatim
expected = <<-EXPECTED # HACK overblown
* list stuff
* list
@ -431,7 +320,7 @@ words words words words
EXPECTED
assert_equal expected, output
assert_equal expected, @to.end_accepting
end
end

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

@ -0,0 +1,122 @@
require File.expand_path '../xref_test_case', __FILE__
class TestRDocMethodAttr < XrefTestCase
def test_block_params_equal
m = RDoc::MethodAttr.new(nil, 'foo')
m.block_params = ''
assert_equal '', m.block_params
m.block_params = 'a_var'
assert_equal 'a_var', m.block_params
m.block_params = '()'
assert_equal '', m.block_params
m.block_params = '(a_var, b_var)'
assert_equal 'a_var, b_var', m.block_params
m.block_params = '.to_s + "</#{element.upcase}>"'
assert_equal '', m.block_params
m.block_params = 'i.name'
assert_equal 'name', m.block_params
m.block_params = 'attr.expanded_name, attr.value'
assert_equal 'expanded_name, value', m.block_params
m.block_params = 'expanded_name, attr.value'
assert_equal 'expanded_name, value', m.block_params
m.block_params = 'attr.expanded_name, value'
assert_equal 'expanded_name, value', m.block_params
m.block_params = '(@base_notifier)'
assert_equal 'base_notifier', m.block_params
m.block_params = 'if @signal_status == :IN_LOAD'
assert_equal '', m.block_params
m.block_params = 'e if e.kind_of? Element'
assert_equal 'e', m.block_params
m.block_params = '(e, f) if e.kind_of? Element'
assert_equal 'e, f', m.block_params
m.block_params = 'back_path, back_name'
assert_equal 'back_path, back_name', m.block_params
m.block_params = '(*a[1..-1])'
assert_equal '*a', m.block_params
m.block_params = '@@context[:node] if defined? @@context[:node].namespace'
assert_equal 'context', m.block_params
m.block_params = '(result, klass.const_get(constant_name))'
assert_equal 'result, const', m.block_params
m.block_params = 'name.to_s if (bitmap & bit) != 0'
assert_equal 'name', m.block_params
m.block_params = 'line unless line.deleted'
assert_equal 'line', m.block_params
m.block_params = 'str + rs'
assert_equal 'str', m.block_params
m.block_params = 'f+rs'
assert_equal 'f', m.block_params
m.block_params = '[user, realm, hash[user]]'
assert_equal 'user, realm, hash', m.block_params
m.block_params = 'proc{|rc| rc == "rc" ? irbrc : irbrc+rc| ... }'
assert_equal 'proc', m.block_params
m.block_params = 'lambda { |x| x.to_i }'
assert_equal 'lambda', m.block_params
m.block_params = '$&'
assert_equal 'str', m.block_params
m.block_params = 'Inflections.instance'
assert_equal 'instance', m.block_params
m.block_params = 'self.class::STARTED'
assert_equal 'STARTED', m.block_params
m.block_params = 'Test::Unit::TestCase::STARTED'
assert_equal 'STARTED', m.block_params
m.block_params = 'ActiveSupport::OptionMerger.new(self, options)'
assert_equal 'option_merger', m.block_params
m.block_params = ', msg'
assert_equal '', m.block_params
m.block_params = '[size.to_s(16), term, chunk, term].join'
assert_equal '[size, term, chunk, term].join', m.block_params
m.block_params = 'YPath.new( path )'
assert_equal 'y_path', m.block_params
end
def test_find_method_or_attribute_recursive
inc = RDoc::Include.new 'M1', nil
@m1.add_include inc # M1 now includes itself
assert_nil @m1_m.find_method_or_attribute 'm'
end
def test_to_s
assert_equal 'RDoc::AnyMethod: C1#m', @c1_m.to_s
assert_equal 'RDoc::AnyMethod: C2#b', @c2_b.to_s
assert_equal 'RDoc::AnyMethod: C1::m', @c1__m.to_s
end
end

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

@ -10,7 +10,7 @@ class TestRDocNormalClass < XrefTestCase
sub_klass = klass.add_class RDoc::NormalClass, 'SubClass', 'Klass'
sub_klass.add_include incl
assert_equal [incl, klass], sub_klass.ancestors
assert_equal [incl.name, klass], sub_klass.ancestors
end
end

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

@ -15,7 +15,12 @@ class TestRDocNormalModule < XrefTestCase
mod.add_include incl
assert_equal [incl], mod.ancestors
assert_equal [incl.name], mod.ancestors
mod2 = top_level.add_module RDoc::NormalModule, 'Inc2'
inc2 = RDoc::Include.new 'Inc2', ''
mod.add_include inc2
assert_equal [mod2, incl.name], mod.ancestors
end
def test_module_eh

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

@ -2,12 +2,182 @@ require 'rubygems'
require 'minitest/autorun'
require 'rdoc/options'
require 'fileutils'
require 'tmpdir'
class TestRDocOptions < MiniTest::Unit::TestCase
def setup
@options = RDoc::Options.new
end
def test_check_files
out, err = capture_io do
Dir.mktmpdir do |dir|
Dir.chdir dir do
FileUtils.touch 'unreadable'
FileUtils.chmod 0, 'unreadable'
@options.files = %w[nonexistent unreadable]
@options.check_files
end
end
end
assert_empty @options.files
assert_equal '', out
expected = <<-EXPECTED
file 'nonexistent' not found
file 'unreadable' not readable
EXPECTED
assert_equal expected, err
end
def test_dry_run_default
refute @options.dry_run
end
def test_encoding_default
skip "Encoding not implemented" unless Object.const_defined? :Encoding
assert_equal Encoding.default_external, @options.encoding
end
def test_parse_dash_p
out, err = capture_io do
@options.parse %w[-p]
end
assert @options.pipe
refute_match %r%^Usage: %, err
refute_match %r%^invalid options%, err
assert_empty out
end
def test_parse_dash_p_files
out, err = capture_io do
@options.parse ['-p', File.expand_path(__FILE__)]
end
refute @options.pipe
refute_match %r%^Usage: %, err
assert_match %r%^invalid options: -p .with files.%, err
assert_empty out
end
def test_parse_default
@options.parse []
assert_equal RDoc::Generator::Darkfish, @options.generator
assert_equal 'darkfish', @options.template
assert_match %r%rdoc/generator/template/darkfish$%, @options.template_dir
end
def test_parse_deprecated
dep_hash = RDoc::Options::DEPRECATED
options = dep_hash.keys.sort
out, err = capture_io do
@options.parse options
end
dep_hash.each_pair do |opt, message|
assert_match %r%.*#{opt}.+#{message}%, err
end
assert_empty out
end
def test_parse_dry_run
@options.parse %w[--dry-run]
assert @options.dry_run
end
def test_parse_encoding
skip "Encoding not implemented" unless Object.const_defined? :Encoding
@options.parse %w[--encoding Big5]
assert_equal Encoding::Big5, @options.encoding
assert_equal 'Big5', @options.charset
end
def test_parse_encoding_invalid
skip "Encoding not implemented" unless Object.const_defined? :Encoding
out, err = capture_io do
@options.parse %w[--encoding invalid]
end
assert_match %r%^invalid options: --encoding invalid%, err
assert_empty out
end
def test_parse_formatter
e = assert_raises OptionParser::InvalidOption do
@options.parse %w[--format darkfish --format ri]
end
assert_equal 'invalid option: --format generator already set to darkfish',
e.message
end
def test_parse_formatter_ri
e = assert_raises OptionParser::InvalidOption do
@options.parse %w[--format darkfish --ri]
end
assert_equal 'invalid option: --ri generator already set to darkfish',
e.message
@options = RDoc::Options.new
e = assert_raises OptionParser::InvalidOption do
@options.parse %w[--format darkfish -r]
end
assert_equal 'invalid option: -r generator already set to darkfish',
e.message
end
def test_parse_formatter_ri_site
e = assert_raises OptionParser::InvalidOption do
@options.parse %w[--format darkfish --ri-site]
end
assert_equal 'invalid option: --ri-site generator already set to darkfish',
e.message
@options = RDoc::Options.new
e = assert_raises OptionParser::InvalidOption do
@options.parse %w[--format darkfish -R]
end
assert_equal 'invalid option: -R generator already set to darkfish',
e.message
end
def test_parse_help
out, = capture_io do
begin
@options.parse %w[--help]
rescue SystemExit
end
end
assert_equal 1, out.scan(/HTML generator options:/).length
assert_equal 1, out.scan(/ri generator options:/). length
end
def test_parse_ignore_invalid
out, err = capture_io do
@options.parse %w[--ignore-invalid --bogus]
@ -15,6 +185,8 @@ class TestRDocOptions < MiniTest::Unit::TestCase
refute_match %r%^Usage: %, err
assert_match %r%^invalid options: --bogus%, err
assert_empty out
end
def test_parse_ignore_invalid_default
@ -26,17 +198,21 @@ class TestRDocOptions < MiniTest::Unit::TestCase
assert_match %r%^invalid options: --bogus%, err
assert_equal 'BLAH', @options.main_page
assert_empty out
end
def test_parse_ignore_invalid_no
out, err = capture_io do
assert_raises SystemExit do
@options.parse %w[--no-ignore-invalid --bogus]
@options.parse %w[--no-ignore-invalid --bogus=arg --bobogus --visibility=extended]
end
end
assert_match %r%^Usage: %, err
assert_match %r%^invalid option: --bogus%, err
assert_match %r%^invalid options: --bogus=arg, --bobogus, --visibility=extended%, err
assert_empty out
end
def test_parse_main
@ -50,24 +226,73 @@ class TestRDocOptions < MiniTest::Unit::TestCase
assert_equal 'MAIN', @options.main_page
end
def test_parse_dash_p
def test_parse_template
out, err = capture_io do
@options.parse %w[-p]
@options.parse %w[--template darkfish]
end
assert @options.pipe
refute_match %r%^Usage: %, err
refute_match %r%^invalid options%, err
assert_empty out
assert_empty err
assert_equal 'darkfish', @options.template
assert_match %r%rdoc/generator/template/darkfish$%, @options.template_dir
end
def test_parse_dash_p_files
def test_parse_template_nonexistent
out, err = capture_io do
@options.parse %w[-p README]
@options.parse %w[--template NONEXISTENT]
end
refute @options.pipe
refute_match %r%^Usage: %, err
assert_match %r%^invalid options: -p .with files.%, err
assert_empty out
assert_equal "could not find template NONEXISTENT\n", err
assert_equal 'darkfish', @options.template
assert_match %r%rdoc/generator/template/darkfish$%, @options.template_dir
end
def test_parse_template_load_path
orig_LOAD_PATH = $LOAD_PATH.dup
template_dir = nil
Dir.mktmpdir do |dir|
$LOAD_PATH << dir
template_dir = File.join dir, 'rdoc', 'generator', 'template', 'load_path'
FileUtils.mkdir_p template_dir
out, err = capture_io do
@options.parse %w[--template load_path]
end
assert_empty out
assert_empty err
end
assert_equal 'load_path', @options.template
assert_equal template_dir, @options.template_dir
ensure
$LOAD_PATH.replace orig_LOAD_PATH
end
def test_setup_generator
test_generator = Object.new
def test_generator.setup_options(op)
@op = op
end
def test_generator.op() @op end
RDoc::RDoc::GENERATORS['TestGenerator'] = test_generator
@options.setup_generator 'TestGenerator'
assert_equal test_generator, @options.generator
assert_equal [test_generator], @options.generator_options
assert_equal @options, test_generator.op
end
end

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

@ -11,25 +11,6 @@ class TestRDocParser < MiniTest::Unit::TestCase
@binary_dat = File.expand_path '../binary.dat', __FILE__
end
def test_class_binary_eh_erb
erb = File.join Dir.tmpdir, "test_rdoc_parser_#{$$}.erb"
open erb, 'wb' do |io|
io.write 'blah blah <%= stuff %> <% more stuff %>'
end
assert @RP.binary?(erb)
erb_rb = File.join Dir.tmpdir, "test_rdoc_parser_#{$$}.erb.rb"
open erb_rb, 'wb' do |io|
io.write 'blah blah <%= stuff %>'
end
refute @RP.binary?(erb_rb)
ensure
File.unlink erb
File.unlink erb_rb if erb_rb
end
def test_class_binary_eh_marshal
marshal = File.join Dir.tmpdir, "test_rdoc_parser_#{$$}.marshal"
open marshal, 'wb' do |io|
@ -42,6 +23,18 @@ class TestRDocParser < MiniTest::Unit::TestCase
File.unlink marshal
end
def test_class_binary_japanese_text
file_name = File.expand_path '../test.ja.txt', __FILE__
refute @RP.binary?(file_name)
end
def test_class_binary_japanese_rdoc
skip "Encoding not implemented" unless Object.const_defined? :Encoding
file_name = File.expand_path '../test.ja.rdoc', __FILE__
refute @RP.binary?(file_name)
end
def test_class_can_parse
assert_equal @RP.can_parse(__FILE__), @RP::Ruby
@ -72,6 +65,10 @@ class TestRDocParser < MiniTest::Unit::TestCase
def test_class_for_binary
rp = @RP.dup
class << rp
alias old_can_parse can_parse
end
def rp.can_parse(*args) nil end
assert_nil @RP.for(nil, @binary_dat, nil, nil, nil)

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

@ -1,12 +1,52 @@
require 'stringio'
require 'tempfile'
require 'rubygems'
require 'minitest/unit'
require 'minitest/autorun'
require 'rdoc/options'
require 'rdoc/parser/c'
=begin
TODO: test call-seq parsing
/*
* call-seq:
* ARGF.readlines(sep=$/) -> array
* ARGF.readlines(limit) -> array
* ARGF.readlines(sep, limit) -> array
*
* ARGF.to_a(sep=$/) -> array
* ARGF.to_a(limit) -> array
* ARGF.to_a(sep, limit) -> array
*
* Reads +ARGF+'s current file in its entirety, returning an +Array+ of its
* lines, one line per element. Lines are assumed to be separated by _sep_.
*
* lines = ARGF.readlines
* lines[0] #=> "This is line one\n"
*/
assert call-seq did not stop at first empty line
/*
* call-seq:
*
* flt ** other -> float
*
* Raises <code>float</code> the <code>other</code> power.
*
* 2.0**3 #=> 8.0
*/
assert call-seq correct (bug: was empty)
/* call-seq: flt ** other -> float */
assert call-seq correct
=end
class RDoc::Parser::C
attr_accessor :classes
attr_accessor :classes, :singleton_classes
public :do_classes, :do_constants
end
@ -30,6 +70,129 @@ class TestRDocParserC < MiniTest::Unit::TestCase
@tempfile.close
end
def test_do_attr_rb_attr
content = <<-EOF
void Init_Blah(void) {
cBlah = rb_define_class("Blah", rb_cObject);
/*
* This is an accessor
*/
rb_attr(cBlah, rb_intern("accessor"), 1, 1, Qfalse);
/*
* This is a reader
*/
rb_attr(cBlah, rb_intern("reader"), 1, 0, Qfalse);
/*
* This is a writer
*/
rb_attr(cBlah, rb_intern("writer"), 0, 1, Qfalse);
}
EOF
klass = util_get_class content, 'cBlah'
attrs = klass.attributes
assert_equal 3, attrs.length, attrs.inspect
accessor = attrs.shift
assert_equal 'accessor', accessor.name
assert_equal 'RW', accessor.rw
assert_equal 'This is an accessor', accessor.comment
reader = attrs.shift
assert_equal 'reader', reader.name
assert_equal 'R', reader.rw
assert_equal 'This is a reader', reader.comment
writer = attrs.shift
assert_equal 'writer', writer.name
assert_equal 'W', writer.rw
assert_equal 'This is a writer', writer.comment
end
def test_do_attr_rb_define_attr
content = <<-EOF
void Init_Blah(void) {
cBlah = rb_define_class("Blah", rb_cObject);
/*
* This is an accessor
*/
rb_define_attr(cBlah, "accessor", 1, 1);
}
EOF
klass = util_get_class content, 'cBlah'
attrs = klass.attributes
assert_equal 1, attrs.length, attrs.inspect
accessor = attrs.shift
assert_equal 'accessor', accessor.name
assert_equal 'RW', accessor.rw
assert_equal 'This is an accessor', accessor.comment
end
def test_do_aliases
content = <<-EOF
/*
* This should show up as an alias with documentation
*/
VALUE blah(VALUE klass, VALUE year) {
}
void Init_Blah(void) {
cDate = rb_define_class("Date", rb_cObject);
rb_define_method(cDate, "blah", blah, 1);
rb_define_alias(cDate, "bleh", "blah");
}
EOF
klass = util_get_class content, 'cDate'
methods = klass.method_list
assert_equal 2, methods.length
assert_equal 'bleh', methods.last.name
assert_equal 'blah', methods.last.is_alias_for.name
end
def test_do_aliases_singleton
content = <<-EOF
/*
* This should show up as a method with documentation
*/
VALUE blah(VALUE klass, VALUE year) {
}
void Init_Blah(void) {
cDate = rb_define_class("Date", rb_cObject);
sDate = rb_singleton_class(cDate);
rb_define_method(sDate, "blah", blah, 1);
/*
* This should show up as an alias
*/
rb_define_alias(sDate, "bleh", "blah");
}
EOF
klass = util_get_class content, 'cDate'
methods = klass.method_list
assert_equal 2, methods.length
assert_equal 'bleh', methods.last.name
assert methods.last.singleton
assert_equal 'blah', methods.last.is_alias_for.name
assert_equal 'This should show up as an alias', methods.last.comment
end
def test_do_classes_boot_class
content = <<-EOF
/* Document-class: Foo
@ -68,6 +231,17 @@ VALUE cFoo = rb_define_class("Foo", rb_cObject);
assert_equal "this is the Foo class", klass.comment
end
def test_do_classes_singleton
content = <<-EOF
VALUE cFoo = rb_define_class("Foo", rb_cObject);
VALUE cFooS = rb_singleton_class(cFoo);
EOF
util_get_class content, 'cFooS'
assert_equal 'Foo', @parser.singleton_classes['cFooS']
end
def test_do_classes_class_under
content = <<-EOF
/* Document-class: Kernel::Foo
@ -201,6 +375,26 @@ Multiline comment goes here because this comment spans multiple lines.
assert constants.empty?, constants.inspect
end
def test_find_alias_comment
parser = util_parser ''
comment = parser.find_alias_comment 'C', '[]', 'index'
assert_equal '', comment
parser = util_parser <<-C
/*
* comment
*/
rb_define_alias(C, "[]", "index");
C
comment = parser.find_alias_comment 'C', '[]', 'index'
assert_equal "/*\n * comment\n */\n\n", comment
end
def test_find_class_comment_include
@options.rdoc_include << File.dirname(__FILE__)
@ -406,6 +600,113 @@ Init_Foo(void) {
assert_equal "a comment for bar", bar.comment
end
def test_find_modifiers_call_seq
comment = <<-COMMENT
/* call-seq:
* commercial() -> Date <br />
* commercial(cwyear, cweek=41, cwday=5, sg=nil) -> Date [ruby 1.8] <br />
* commercial(cwyear, cweek=1, cwday=1, sg=nil) -> Date [ruby 1.9]
*
* If no arguments are given:
* * ruby 1.8: returns a +Date+ for 1582-10-15 (the Day of Calendar Reform in
* Italy)
* * ruby 1.9: returns a +Date+ for julian day 0
*
* Otherwise, returns a +Date+ for the commercial week year, commercial week,
* and commercial week day given. Ignores the 4th argument.
*/
COMMENT
parser = util_parser ''
method_obj = RDoc::AnyMethod.new nil, 'blah'
parser.find_modifiers comment, method_obj
expected = <<-CALL_SEQ.chomp
commercial() -> Date <br />
commercial(cwyear, cweek=41, cwday=5, sg=nil) -> Date [ruby 1.8] <br />
commercial(cwyear, cweek=1, cwday=1, sg=nil) -> Date [ruby 1.9]
CALL_SEQ
assert_equal expected, method_obj.call_seq
end
def test_find_modifiers_nodoc
comment = <<-COMMENT
/* :nodoc:
*
* Blah
*/
COMMENT
parser = util_parser ''
method_obj = RDoc::AnyMethod.new nil, 'blah'
parser.find_modifiers comment, method_obj
assert_equal nil, method_obj.document_self
end
def test_find_modifiers_yields
comment = <<-COMMENT
/* :yields: a, b
*
* Blah
*/
COMMENT
parser = util_parser ''
method_obj = RDoc::AnyMethod.new nil, 'blah'
parser.find_modifiers comment, method_obj
assert_equal 'a, b', method_obj.block_params
expected = <<-EXPECTED
/*
*
* Blah
*/
EXPECTED
assert_equal expected, comment
end
def test_handle_method
parser = util_parser "Document-method: BasicObject#==\n blah */"
parser.handle_method 'method', 'rb_cBasicObject', '==', 'rb_obj_equal', 1
bo = @top_level.find_module_named 'BasicObject'
assert_equal 1, bo.method_list.length
equals2 = bo.method_list.first
assert_equal '==', equals2.name
end
def test_handle_method_initialize
parser = util_parser "Document-method: BasicObject::new\n blah */"
parser.handle_method('private_method', 'rb_cBasicObject',
'initialize', 'rb_obj_dummy', -1)
bo = @top_level.find_module_named 'BasicObject'
assert_equal 1, bo.method_list.length
new = bo.method_list.first
assert_equal 'new', new.name
assert_equal :public, new.visibility
end
def test_look_for_directives_in
parser = util_parser ''
@ -442,6 +743,7 @@ Init_IO(void) {
read_method = klass.method_list.first
assert_equal "read", read_method.name
assert_equal "Method Comment! ", read_method.comment
assert read_method.singleton
end
def test_define_method_private
@ -472,6 +774,65 @@ Init_IO(void) {
assert_equal "Method Comment! ", read_method.comment
end
def test_define_method_private_singleton
content = <<-EOF
/*Method Comment! */
static VALUE
rb_io_s_read(argc, argv, io)
int argc;
VALUE *argv;
VALUE io;
{
}
void
Init_IO(void) {
/*
* a comment for class Foo on rb_define_class
*/
VALUE rb_cIO = rb_define_class("IO", rb_cObject);
VALUE rb_cIO_s = rb_singleton_class(rb_cIO);
rb_define_private_method(rb_cIO_s, "read", rb_io_s_read, -1);
}
EOF
klass = util_get_class content, 'rb_cIO'
read_method = klass.method_list.first
assert_equal "read", read_method.name
assert_equal "Method Comment! ", read_method.comment
assert_equal :private, read_method.visibility
assert read_method.singleton
end
def test_define_method_singleton
content = <<-EOF
/*Method Comment! */
static VALUE
rb_io_s_read(argc, argv, io)
int argc;
VALUE *argv;
VALUE io;
{
}
void
Init_IO(void) {
/*
* a comment for class Foo on rb_define_class
*/
VALUE rb_cIO = rb_define_class("IO", rb_cObject);
VALUE rb_cIO_s = rb_singleton_class(rb_cIO);
rb_define_method(rb_cIO_s, "read", rb_io_s_read, -1);
}
EOF
klass = util_get_class content, 'rb_cIO'
read_method = klass.method_list.first
assert_equal "read", read_method.name
assert_equal "Method Comment! ", read_method.comment
assert read_method.singleton
end
def util_get_class(content, name)
@parser = util_parser content
@parser.scan
@ -484,4 +845,3 @@ Init_IO(void) {
end
MiniTest::Unit.autorun

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

@ -1,73 +0,0 @@
require 'stringio'
require 'tempfile'
require 'rubygems'
require 'minitest/autorun'
require 'rdoc/options'
require 'rdoc/parser/perl'
class TestRdocParserPerlPOD < MiniTest::Unit::TestCase
def setup
@tempfile = Tempfile.new self.class.name
filename = @tempfile.path
@top_level = RDoc::TopLevel.new filename
@fn = filename
@options = RDoc::Options.new
@stats = RDoc::Stats.new 0
end
def teardown
@tempfile.close
end
def test_uncommented_perl
content = <<-EOF
while (<>) {
tr/a-z/A-Z;
print
}
EOF
comment = util_get_comment content
assert_equal "", comment
end
def test_perl_without_pod
content = <<-EOF
#!/usr/local/bin/perl
#
#This is a pointless perl program because it does -p.
#
while(<>) {print;}:
EOF
comment = util_get_comment content
assert_equal "", comment
end
def test_simple_pod_no_structure
content = <<-EOF
=begin pod
This just contains plain old documentation
=end
EOF
comment = util_get_comment content
assert_equal 'This just contains plain old documentation', comment
end
# Get the comment of the @top_level when it has processed the input.
def util_get_comment(content)
parser = util_parser content
parser.scan.comment
end
# create a new parser with the supplied content.
def util_parser(content)
RDoc::Parser::PerlPOD.new @top_level, @fn, content, @options, @stats
end
end

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

@ -22,6 +22,8 @@ class TestRDocParserRuby < MiniTest::Unit::TestCase
util_top_level
@options = RDoc::Options.new
@options.quiet = true
@options.option_parser = OptionParser.new
@stats = RDoc::Stats.new 0
end
@ -30,6 +32,30 @@ class TestRDocParserRuby < MiniTest::Unit::TestCase
@tempfile2.close
end
def test_get_symbol_or_name
util_parser "* & | + 5 / 4"
assert_equal '*', @parser.get_symbol_or_name
@parser.skip_tkspace
assert_equal '&', @parser.get_symbol_or_name
@parser.skip_tkspace
assert_equal '|', @parser.get_symbol_or_name
@parser.skip_tkspace
assert_equal '+', @parser.get_symbol_or_name
@parser.skip_tkspace
@parser.get_tk
@parser.skip_tkspace
assert_equal '/', @parser.get_symbol_or_name
end
def test_look_for_directives_in_attr
util_parser ""
@ -52,6 +78,61 @@ class TestRDocParserRuby < MiniTest::Unit::TestCase
assert_equal "# :attr_writer: my_method\n", comment
end
def test_remove_private_comments
util_parser ''
comment = <<-EOS
# This is text
#--
# this is private
EOS
expected = <<-EOS
# This is text
EOS
@parser.remove_private_comments(comment)
assert_equal expected, comment
end
def test_remove_private_comments_rule
util_parser ''
comment = <<-EOS
# This is text with a rule:
# ---
# this is also text
EOS
expected = comment.dup
@parser.remove_private_comments(comment)
assert_equal expected, comment
end
def test_remove_private_comments_toggle
util_parser ''
comment = <<-EOS
# This is text
#--
# this is private
#++
# This is text again.
EOS
expected = <<-EOS
# This is text
# This is text again.
EOS
@parser.remove_private_comments(comment)
assert_equal expected, comment
end
def test_look_for_directives_in_commented
util_parser ""
@ -70,9 +151,9 @@ class TestRDocParserRuby < MiniTest::Unit::TestCase
def test_look_for_directives_in_enddoc
util_parser ""
assert_throws :enddoc do
@parser.look_for_directives_in @top_level, "# :enddoc:\n"
end
@parser.look_for_directives_in @top_level, "# :enddoc:\n"
assert @top_level.done_documenting
end
def test_look_for_directives_in_main
@ -105,13 +186,11 @@ class TestRDocParserRuby < MiniTest::Unit::TestCase
@top_level.stop_doc
assert !@top_level.document_self
assert !@top_level.document_children
assert !@top_level.force_documentation
@parser.look_for_directives_in @top_level, "# :startdoc:\n"
assert @top_level.document_self
assert @top_level.document_children
assert @top_level.force_documentation
end
def test_look_for_directives_in_stopdoc
@ -166,10 +245,29 @@ class TestRDocParserRuby < MiniTest::Unit::TestCase
alas = @parser.parse_alias klass, RDoc::Parser::Ruby::NORMAL, tk, 'comment'
assert_equal 'bar', alas.old_name
assert_equal 'next=', alas.new_name
assert_equal klass, alas.parent
assert_equal 'comment', alas.comment
assert_equal 'bar', alas.old_name
assert_equal 'next=', alas.new_name
assert_equal klass, alas.parent
assert_equal 'comment', alas.comment
assert_equal @top_level, alas.file
end
def test_parse_alias_singleton
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
util_parser "alias :next= :bar"
tk = @parser.get_tk
alas = @parser.parse_alias klass, RDoc::Parser::Ruby::SINGLE, tk, 'comment'
assert_equal 'bar', alas.old_name
assert_equal 'next=', alas.new_name
assert_equal klass, alas.parent
assert_equal 'comment', alas.comment
assert_equal @top_level, alas.file
assert alas.singleton
end
def test_parse_alias_meta
@ -202,6 +300,7 @@ class TestRDocParserRuby < MiniTest::Unit::TestCase
foo = klass.attributes.first
assert_equal 'foo', foo.name
assert_equal 'my attr', foo.comment
assert_equal @top_level, foo.file
end
def test_parse_attr_accessor
@ -222,6 +321,7 @@ class TestRDocParserRuby < MiniTest::Unit::TestCase
assert_equal 'foo', foo.name
assert_equal 'RW', foo.rw
assert_equal 'my attr', foo.comment
assert_equal @top_level, foo.file
bar = klass.attributes.last
assert_equal 'bar', bar.name
@ -229,6 +329,21 @@ class TestRDocParserRuby < MiniTest::Unit::TestCase
assert_equal 'my attr', bar.comment
end
def test_parse_attr_accessor_nodoc
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
comment = "##\n# my attr\n"
util_parser "attr_accessor :foo, :bar # :nodoc:"
tk = @parser.get_tk
@parser.parse_attr_accessor klass, RDoc::Parser::Ruby::NORMAL, tk, comment
assert_equal 0, klass.attributes.length
end
def test_parse_attr_accessor_writer
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
@ -247,6 +362,7 @@ class TestRDocParserRuby < MiniTest::Unit::TestCase
assert_equal 'foo', foo.name
assert_equal 'W', foo.rw
assert_equal "my attr", foo.comment
assert_equal @top_level, foo.file
bar = klass.attributes.last
assert_equal 'bar', bar.name
@ -271,6 +387,7 @@ class TestRDocParserRuby < MiniTest::Unit::TestCase
assert_equal 'foo', foo.name
assert_equal 'RW', foo.rw
assert_equal "my method", foo.comment
assert_equal @top_level, foo.file
end
def test_parse_meta_attr_accessor
@ -290,6 +407,7 @@ class TestRDocParserRuby < MiniTest::Unit::TestCase
assert_equal 'foo', foo.name
assert_equal 'RW', foo.rw
assert_equal 'my method', foo.comment
assert_equal @top_level, foo.file
end
def test_parse_meta_attr_named
@ -309,6 +427,7 @@ class TestRDocParserRuby < MiniTest::Unit::TestCase
assert_equal 'foo', foo.name
assert_equal 'RW', foo.rw
assert_equal 'my method', foo.comment
assert_equal @top_level, foo.file
end
def test_parse_meta_attr_reader
@ -327,6 +446,7 @@ class TestRDocParserRuby < MiniTest::Unit::TestCase
assert_equal 'foo', foo.name
assert_equal 'R', foo.rw
assert_equal 'my method', foo.comment
assert_equal @top_level, foo.file
end
def test_parse_meta_attr_writer
@ -345,12 +465,13 @@ class TestRDocParserRuby < MiniTest::Unit::TestCase
assert_equal 'foo', foo.name
assert_equal 'W', foo.rw
assert_equal "my method", foo.comment
assert_equal @top_level, foo.file
end
def test_parse_class
comment = "##\n# my method\n"
util_parser 'class Foo; end'
util_parser "class Foo\nend"
tk = @parser.get_tk
@ -379,11 +500,12 @@ end
blah = foo.method_list.first
assert_equal 'Foo#blah', blah.full_name
assert_equal @top_level, blah.file
end
def test_parse_class_nested_superclass
foo = RDoc::NormalModule.new 'Foo'
foo.parent = @top_level
util_top_level
foo = @top_level.add_module RDoc::NormalModule, 'Foo'
util_parser "class Bar < Super\nend"
@ -398,7 +520,7 @@ end
def test_parse_module
comment = "##\n# my module\n"
util_parser 'module Foo; end'
util_parser "module Foo\nend"
tk = @parser.get_tk
@ -430,6 +552,8 @@ class A
class << B
end
class << d = Object.new
def foo; end
alias bar foo
end
end
CODE
@ -439,7 +563,40 @@ end
@parser.parse_class @top_level, false, @parser.get_tk, ''
assert_equal %w[A], RDoc::TopLevel.classes.map { |c| c.full_name }
assert_equal %w[A::B], RDoc::TopLevel.modules.map { |c| c.full_name }
assert_equal %w[A::B A::d], RDoc::TopLevel.modules.map { |c| c.full_name }
# make sure method/alias was not added to enclosing class/module
a = RDoc::TopLevel.all_classes_hash['A']
assert_empty a.method_list
# make sure non-constant-named module will be removed from documentation
d = RDoc::TopLevel.all_modules_hash['A::d']
assert d.remove_from_documentation?
end
# TODO this is really a Context#add_class test
def test_parse_class_object
code = <<-CODE
module A
class B
end
class Object
end
class C < Object
end
end
CODE
util_parser code
@parser.parse_module @top_level, false, @parser.get_tk, ''
assert_equal %w[A], RDoc::TopLevel.modules.map { |c| c.full_name }
assert_equal %w[A::B A::C A::Object], RDoc::TopLevel.classes.map { |c| c.full_name }.sort
assert_equal 'Object', RDoc::TopLevel.classes_hash['A::B'].superclass
assert_equal 'Object', RDoc::TopLevel.classes_hash['A::Object'].superclass
assert_equal 'A::Object', RDoc::TopLevel.classes_hash['A::C'].superclass.full_name
end
def test_parse_class_mistaken_for_module
@ -447,7 +604,7 @@ end
# before Foo::Bar is encountered), but RDoc might encounter Foo::Bar
# before Foo if they live in different files.
code = <<-EOF
code = <<-RUBY
class Foo::Bar
end
@ -456,7 +613,7 @@ end
class Foo
end
EOF
RUBY
util_parser code
@ -542,18 +699,20 @@ EOF
@parser.parse_comment klass, tk, comment
foo = klass.attributes.first
assert_equal 'foo', foo.name
assert_equal 'RW', foo.rw
assert_equal 'my attr', foo.comment
assert_equal 'foo', foo.name
assert_equal 'RW', foo.rw
assert_equal 'my attr', foo.comment
assert_equal @top_level, foo.file
assert_equal nil, foo.viewer
assert_equal true, foo.document_children
assert_equal true, foo.document_self
assert_equal false, foo.done_documenting
assert_equal false, foo.force_documentation
assert_equal klass, foo.parent
assert_equal :public, foo.visibility
assert_equal "\n", foo.text
assert_equal nil, foo.viewer
assert_equal true, foo.document_children
assert_equal true, foo.document_self
assert_equal false, foo.done_documenting
assert_equal false, foo.force_documentation
assert_equal klass, foo.parent
assert_equal :public, foo.visibility
assert_equal "\n", foo.text
assert_equal klass.current_section, foo.section
end
@ -570,8 +729,9 @@ EOF
@parser.parse_comment klass, tk, comment
foo = klass.method_list.first
assert_equal 'foo', foo.name
assert_equal 'my method', foo.comment
assert_equal 'foo', foo.name
assert_equal 'my method', foo.comment
assert_equal @top_level, foo.file
assert_equal [], foo.aliases
assert_equal nil, foo.block_params
@ -599,9 +759,23 @@ EOF
assert_equal stream, foo.token_stream
end
def test_parse_constant_attrasgn
util_top_level
klass = @top_level.add_class RDoc::NormalClass, 'Foo'
util_parser "A[k] = v"
tk = @parser.get_tk
@parser.parse_constant klass, tk, ''
assert klass.constants.empty?
end
def test_parse_constant_alias
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
util_top_level
klass = @top_level.add_class RDoc::NormalClass, 'Foo'
cB = klass.add_class RDoc::NormalClass, 'B'
util_parser "A = B"
@ -642,8 +816,9 @@ EOF
@parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
foo = klass.method_list.first
assert_equal 'foo', foo.name
assert_equal 'foo', foo.name
assert_equal 'my method', foo.comment
assert_equal @top_level, foo.file
assert_equal [], foo.aliases
assert_equal nil, foo.block_params
@ -691,8 +866,9 @@ EOF
@parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
foo = klass.method_list.first
assert_equal 'woo_hoo!', foo.name
assert_equal 'woo_hoo!', foo.name
assert_equal 'my method', foo.comment
assert_equal @top_level, foo.file
end
def test_parse_meta_method_singleton
@ -711,6 +887,7 @@ EOF
assert_equal 'foo', foo.name
assert_equal true, foo.singleton, 'singleton method'
assert_equal 'my method', foo.comment
assert_equal @top_level, foo.file
end
def test_parse_meta_method_singleton_name
@ -729,6 +906,7 @@ EOF
assert_equal 'woo_hoo!', foo.name
assert_equal true, foo.singleton, 'singleton method'
assert_equal 'my method', foo.comment
assert_equal @top_level, foo.file
end
def test_parse_meta_method_string_name
@ -744,6 +922,7 @@ EOF
foo = klass.method_list.first
assert_equal 'foo', foo.name
assert_equal 'my method', foo.comment
assert_equal @top_level, foo.file
end
def test_parse_meta_method_unknown
@ -759,6 +938,7 @@ EOF
foo = klass.method_list.first
assert_equal 'unknown', foo.name
assert_equal 'my method', foo.comment
assert_equal @top_level, foo.file
end
def test_parse_method
@ -774,8 +954,9 @@ EOF
@parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
foo = klass.method_list.first
assert_equal 'foo', foo.name
assert_equal 'my method', foo.comment
assert_equal 'foo', foo.name
assert_equal 'my method', foo.comment
assert_equal @top_level, foo.file
assert_equal [], foo.aliases
assert_equal nil, foo.block_params
@ -826,41 +1007,55 @@ EOF
assert klass.aliases.empty?
end
def test_parse_method_utf8
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
comment = "##\n# my method\n"
method = "def ω() end"
assert_equal Encoding::UTF_8, method.encoding if defined? ::Encoding
util_parser method
def test_parse_method_false
util_parser "def false.foo() :bar end"
tk = @parser.get_tk
@parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
@parser.parse_method @top_level, RDoc::Parser::Ruby::NORMAL, tk, ''
omega = klass.method_list.first
assert_equal "def \317\211", omega.text
klass = RDoc::TopLevel.find_class_named 'FalseClass'
foo = klass.method_list.first
assert_equal 'foo', foo.name
end
def test_parse_method_funky
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
comment = "##\n# my method\n"
util_parser "def (blah).foo() :bar end"
tk = @parser.get_tk
@parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
@parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, ''
assert klass.method_list.empty?
end
def test_parse_method_gvar
util_parser "def $stdout.foo() :bar end"
tk = @parser.get_tk
@parser.parse_method @top_level, RDoc::Parser::Ruby::NORMAL, tk, ''
assert @top_level.method_list.empty?
end
def test_parse_method_internal_gvar
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
util_parser "def foo() def $blah.bar() end end"
tk = @parser.get_tk
@parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, ''
assert_equal 1, klass.method_list.length
end
def test_parse_method_internal_ivar
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
@ -887,33 +1082,43 @@ EOF
assert_equal 1, klass.method_list.length
end
def test_parse_method_nil
util_parser "def nil.foo() :bar end"
tk = @parser.get_tk
@parser.parse_method @top_level, RDoc::Parser::Ruby::NORMAL, tk, ''
klass = RDoc::TopLevel.find_class_named 'NilClass'
foo = klass.method_list.first
assert_equal 'foo', foo.name
end
def test_parse_method_no_parens
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
comment = "##\n# my method\n"
util_parser "def foo arg1, arg2\nend"
util_parser "def foo arg1, arg2 = {}\nend"
tk = @parser.get_tk
@parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
@parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, ''
foo = klass.method_list.first
assert_equal '(arg1, arg2)', foo.params
assert_equal '(arg1, arg2 = {})', foo.params
assert_equal @top_level, foo.file
end
def test_parse_method_parameters_comment
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
comment = "##\n# my method\n"
util_parser "def foo arg1, arg2 # some useful comment\nend"
tk = @parser.get_tk
@parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
@parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, ''
foo = klass.method_list.first
assert_equal '(arg1, arg2)', foo.params
@ -923,13 +1128,11 @@ EOF
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
comment = "##\n# my method\n"
util_parser "def foo arg1, arg2, # some useful comment\narg3\nend"
tk = @parser.get_tk
@parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
@parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, ''
foo = klass.method_list.first
assert_equal '(arg1, arg2, arg3)', foo.params
@ -938,18 +1141,17 @@ EOF
def test_parse_method_toplevel
klass = @top_level
comment = "##\n# my method\n"
util_parser "def foo arg1, arg2\nend"
tk = @parser.get_tk
@parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
@parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, ''
object = RDoc::TopLevel.find_class_named 'Object'
foo = object.method_list.first
assert_equal 'Object#foo', foo.full_name
assert_equal @top_level, foo.file
end
def test_parse_method_toplevel_class
@ -967,9 +1169,39 @@ EOF
assert_equal 'Object::foo', foo.full_name
end
def test_parse_statements_class_if
comment = "##\n# my method\n"
def test_parse_method_true
util_parser "def true.foo() :bar end"
tk = @parser.get_tk
@parser.parse_method @top_level, RDoc::Parser::Ruby::NORMAL, tk, ''
klass = RDoc::TopLevel.find_class_named 'TrueClass'
foo = klass.method_list.first
assert_equal 'foo', foo.name
end
def test_parse_method_utf8
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
method = "def ω() end"
assert_equal Encoding::UTF_8, method.encoding if
Object.const_defined? :Encoding
util_parser method
tk = @parser.get_tk
@parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, ''
omega = klass.method_list.first
assert_equal "def \317\211", omega.text
end
def test_parse_statements_class_if
util_parser <<-CODE
module Foo
X = if TRUE then
@ -1024,7 +1256,12 @@ end
end
def test_parse_statements_identifier_alias_method
content = "class Foo def foo() end; alias_method :foo2, :foo end"
content = <<-RUBY
class Foo
def foo() end
alias_method :foo2, :foo
end
RUBY
util_parser content
@ -1078,10 +1315,25 @@ EOF
assert_equal 'foo4', foo4.name
assert_equal 'foo', foo4.is_alias_for.name
assert_equal 'unknown', @top_level.classes.first.aliases[0].old_name
assert_equal 'unknown', @top_level.classes.first.external_aliases[0].old_name
end
def test_parse_statements_identifier_constant
sixth_constant = <<-EOF
Class.new do
rule :file do
all(x, y, z) {
def value
find(:require).each {|r| require r.value }
find(:grammar).map {|g| g.value }
end
def min; end
}
end
end
EOF
content = <<-EOF
class Foo
FIRST_CONSTANT = 5
@ -1103,6 +1355,10 @@ class Foo
end
FIFTH_CONSTANT = SECOND_CONSTANT.map { |element| element + 1 }
SIXTH_CONSTANT = #{sixth_constant}
SEVENTH_CONSTANT = proc { |i| begin i end }
end
EOF
@ -1115,26 +1371,43 @@ EOF
constant = constants[0]
assert_equal 'FIRST_CONSTANT', constant.name
assert_equal '5', constant.value
assert_equal @top_level, constant.file
constant = constants[1]
assert_equal 'SECOND_CONSTANT', constant.name
assert_equal '[ 1, 2, 3 ]', constant.value
assert_equal "[\n1,\n2,\n3\n]", constant.value
assert_equal @top_level, constant.file
constant = constants[2]
assert_equal 'THIRD_CONSTANT', constant.name
assert_equal "{ :foo => 'bar', :x => 'y' }", constant.value
assert_equal "{\n:foo => 'bar',\n:x => 'y'\n}", constant.value
assert_equal @top_level, constant.file
constant = constants[3]
assert_equal 'FOURTH_CONSTANT', constant.name
assert_equal 'SECOND_CONSTANT.map do |element| element + 1 element + 2 end', constant.value
assert_equal "SECOND_CONSTANT.map do |element|\nelement + 1\nelement + 2\nend", constant.value
assert_equal @top_level, constant.file
constant = constants.last
constant = constants[4]
assert_equal 'FIFTH_CONSTANT', constant.name
assert_equal 'SECOND_CONSTANT.map { |element| element + 1 }', constant.value
assert_equal @top_level, constant.file
# TODO: parse as class
constant = constants[5]
assert_equal 'SIXTH_CONSTANT', constant.name
assert_equal sixth_constant.lines.map(&:strip).join("\n"), constant.value
assert_equal @top_level, constant.file
# TODO: parse as method
constant = constants[6]
assert_equal 'SEVENTH_CONSTANT', constant.name
assert_equal "proc { |i| begin i end }", constant.value
assert_equal @top_level, constant.file
end
def test_parse_statements_identifier_attr
content = "class Foo; attr :foo; end"
content = "class Foo\nattr :foo\nend"
util_parser content
@ -1146,7 +1419,7 @@ EOF
end
def test_parse_statements_identifier_attr_accessor
content = "class Foo; attr_accessor :foo; end"
content = "class Foo\nattr_accessor :foo\nend"
util_parser content
@ -1158,7 +1431,7 @@ EOF
end
def test_parse_statements_identifier_include
content = "class Foo; include Bar; end"
content = "class Foo\ninclude Bar\nend"
util_parser content
@ -1170,24 +1443,24 @@ EOF
end
def test_parse_statements_identifier_module_function
content = "module Foo def foo() end; module_function :foo; end"
content = "module Foo\ndef foo() end\nmodule_function :foo\nend"
util_parser content
@parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, ''
foo, s_foo = @top_level.modules.first.method_list
assert_equal 'foo', foo.name, 'instance method name'
assert_equal 'foo', foo.name, 'instance method name'
assert_equal :private, foo.visibility, 'instance method visibility'
assert_equal false, foo.singleton, 'instance method singleton'
assert_equal false, foo.singleton, 'instance method singleton'
assert_equal 'foo', s_foo.name, 'module function name'
assert_equal 'foo', s_foo.name, 'module function name'
assert_equal :public, s_foo.visibility, 'module function visibility'
assert_equal true, s_foo.singleton, 'module function singleton'
assert_equal true, s_foo.singleton, 'module function singleton'
end
def test_parse_statements_identifier_private
content = "class Foo private; def foo() end end"
content = "class Foo\nprivate\ndef foo() end\nend"
util_parser content
@ -1235,6 +1508,24 @@ end
assert_equal 'A#b', m_b.full_name
end
def test_parse_symbol_in_arg
util_parser ':blah "blah" "#{blah}" blah'
assert_equal 'blah', @parser.parse_symbol_in_arg
@parser.skip_tkspace
assert_equal 'blah', @parser.parse_symbol_in_arg
@parser.skip_tkspace
assert_equal nil, @parser.parse_symbol_in_arg
@parser.skip_tkspace
assert_equal nil, @parser.parse_symbol_in_arg
end
def test_parse_top_level_statements_alias_method
content = <<-CONTENT
class A
@ -1252,6 +1543,20 @@ end
@parser.parse_statements @top_level
end
def test_parse_yield_in_braces_with_parens
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
util_parser "def foo\nn.times { |i| yield nth(i) }\nend"
tk = @parser.get_tk
@parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, ''
foo = klass.method_list.first
assert_equal 'nth(i)', foo.block_params
end
def test_sanity_integer
util_parser '1'
assert_equal '1', @parser.get_tk.text
@ -1272,7 +1577,6 @@ end
# If you're writing code like this you're doing it wrong
def test_sanity_interpolation_crazy
last_tk = nil
util_parser '"#{"#{"a")}" if b}"'
assert_equal '"#{"#{"a")}" if b}"', @parser.get_tk.text
@ -1280,7 +1584,6 @@ end
end
def test_sanity_interpolation_curly
last_tk = nil
util_parser '%{ #{} }'
assert_equal '%{ #{} }', @parser.get_tk.text
@ -1290,13 +1593,39 @@ end
def test_sanity_interpolation_format
util_parser '"#{stftime("%m-%d")}"'
while tk = @parser.get_tk do end
while @parser.get_tk do end
end
def test_sanity_symbol_interpolation
util_parser ':"#{bar}="'
while tk = @parser.get_tk do end
while @parser.get_tk do end
end
def test_stopdoc_after_comment
util_parser <<-EOS
module Bar
# hello
module Foo
# :stopdoc:
end
# there
class Baz
# :stopdoc:
end
end
EOS
@parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, ''
foo = @top_level.modules.first.modules.first
assert_equal 'Foo', foo.name
assert_equal 'hello', foo.comment
baz = @top_level.modules.first.classes.first
assert_equal 'Baz', baz.name
assert_equal 'there', baz.comment
end
def tk(klass, line, char, name, text)

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

@ -41,7 +41,6 @@ contents of a string.
parser.scan
expected = <<-TEXT.strip
Regular expressions (<i>regexp</i>s) are patterns which describe the
contents of a string.
TEXT
@ -49,6 +48,31 @@ contents of a string.
assert_equal expected, @top_level.comment
end
# 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>'.
#
# I've seen guys that comment their code like this:
# # This method....
# #-----------------
# def method
#
# => either we do it only in ruby code, or we require the leading #
# (to avoid conflict with rules).
#
# TODO: require the leading #, to provide the feature in simple text files.
# Note: in ruby & C code, we require '#--' & '#++' or '*--' & '*++',
# to allow rules:
#
# # this is a comment
# #---
# # private text
# #+++
# # this is a rule:
# # ---
def test_remove_private_comments
parser = util_parser ''
text = "foo\n\n--\nbar\n++\n\nbaz\n"

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

@ -1,15 +1,21 @@
require 'tempfile'
require 'tmpdir'
require 'rubygems'
require 'minitest/autorun'
require 'rdoc/rdoc'
require 'fileutils'
require 'tempfile'
require 'tmpdir'
class TestRDocRDoc < MiniTest::Unit::TestCase
def setup
@rdoc = RDoc::RDoc.new
@rdoc.options = RDoc::Options.new
@stats = RDoc::Stats.new 0, 0
@rdoc.instance_variable_set :@stats, @stats
@tempfile = Tempfile.new 'test_rdoc_rdoc'
@tempfile.binmode
end
def teardown
@ -39,48 +45,6 @@ class TestRDocRDoc < MiniTest::Unit::TestCase
assert_empty files
end
def test_read_file_contents
@tempfile.write "hi everybody"
@tempfile.flush
assert_equal "hi everybody", @rdoc.read_file_contents(@tempfile.path)
end
def test_read_file_contents_encoding
skip "Encoding not implemented" unless defined? ::Encoding
@tempfile.write "# coding: utf-8\nhi everybody"
@tempfile.flush
contents = @rdoc.read_file_contents @tempfile.path
assert_equal "# coding: utf-8\nhi everybody", contents
assert_equal Encoding::UTF_8, contents.encoding
end
def test_read_file_contents_encoding_fancy
skip "Encoding not implemented" unless defined? ::Encoding
@tempfile.write "# -*- coding: utf-8; fill-column: 74 -*-\nhi everybody"
@tempfile.flush
contents = @rdoc.read_file_contents @tempfile.path
assert_equal("# -*- coding: utf-8; fill-column: 74 -*-\nhi everybody",
contents)
assert_equal Encoding::UTF_8, contents.encoding
end
def test_read_file_contents_encoding_with_signature
skip "Encoding not implemented" unless defined? ::Encoding
@tempfile.write "\xEF\xBB\xBF""hi everybody"
@tempfile.flush
bug3360 = '[ruby-dev:41452]'
contents = @rdoc.read_file_contents @tempfile.path
assert_equal "hi everybody", contents, bug3360
assert_equal Encoding::UTF_8, contents.encoding, bug3360
end
def test_remove_unparsable
file_list = %w[
blah.class
@ -108,6 +72,20 @@ class TestRDocRDoc < MiniTest::Unit::TestCase
}
end
def test_setup_output_dir_dry_run
skip "No Dir::mktmpdir, upgrade your ruby" unless Dir.respond_to? :mktmpdir
@rdoc.options.dry_run = true
Dir.mktmpdir do |d|
path = File.join d, 'testdir'
@rdoc.setup_output_dir path, false
refute File.exist? path
end
end
def test_setup_output_dir_exists
skip "No Dir::mktmpdir, upgrade your ruby" unless Dir.respond_to? :mktmpdir
@ -161,5 +139,26 @@ class TestRDocRDoc < MiniTest::Unit::TestCase
end
end
def test_update_output_dir
skip "No Dir::mktmpdir, upgrade your ruby" unless Dir.respond_to? :mktmpdir
Dir.mktmpdir do |d|
@rdoc.update_output_dir d, Time.now, {}
assert File.exist? "#{d}/created.rid"
end
end
def test_update_output_dir_dry_run
skip "No Dir::mktmpdir, upgrade your ruby" unless Dir.respond_to? :mktmpdir
Dir.mktmpdir do |d|
@rdoc.options.dry_run = true
@rdoc.update_output_dir d, Time.now, {}
refute File.exist? "#{d}/created.rid"
end
end
end

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

@ -53,7 +53,7 @@ class TestRDocRIDriver < MiniTest::Unit::TestCase
def test_self_dump
util_store
out, err = capture_io do
out, = capture_io do
RDoc::RI::Driver.dump @store.cache_path
end
@ -83,8 +83,8 @@ class TestRDocRIDriver < MiniTest::Unit::TestCase
expected = @RM::Document.new(
@RM::Rule.new(1),
@RM::Paragraph.new('Also found in:'),
@RM::Verbatim.new(' ', 'ruby core', "\n",
' ', '~/.ri', "\n"))
@RM::Verbatim.new("ruby core\n",
"~/.ri\n"))
assert_equal expected, out
end
@ -143,7 +143,7 @@ class TestRDocRIDriver < MiniTest::Unit::TestCase
@RM::BlankLine.new,
@RM::Paragraph.new("Include thingy"),
@RM::BlankLine.new,
@RM::Verbatim.new(' ', 'Enumerable', "\n"))
@RM::Verbatim.new("Enumerable\n"))
assert_equal expected, out
end
@ -163,8 +163,8 @@ class TestRDocRIDriver < MiniTest::Unit::TestCase
@RM::Rule.new(1),
@RM::Heading.new(1, "Includes:"),
@RM::Paragraph.new("(from #{@store.friendly_path})"),
@RM::Verbatim.new(' ', 'Inc', "\n",
' ', 'Enumerable', "\n"))
@RM::Verbatim.new("Inc\n",
"Enumerable\n"))
assert_equal expected, out
end
@ -195,7 +195,7 @@ class TestRDocRIDriver < MiniTest::Unit::TestCase
expected = @RM::Document.new(
@RM::Heading.new(1, 'Class methods:'),
@RM::BlankLine.new,
@RM::Verbatim.new(' ', 'new'),
@RM::Verbatim.new('new'),
@RM::BlankLine.new)
assert_equal expected, out
@ -285,7 +285,7 @@ class TestRDocRIDriver < MiniTest::Unit::TestCase
doc = @RM::Document.new(
@RM::Paragraph.new('hi'))
out, err = capture_io do
out, = capture_io do
@driver.display doc
end
@ -295,12 +295,12 @@ class TestRDocRIDriver < MiniTest::Unit::TestCase
def test_display_class
util_store
out, err = capture_io do
out, = capture_io do
@driver.display_class 'Foo::Bar'
end
assert_match %r%^= Foo::Bar%, out
assert_match %r%^\(from%, out # )
assert_match %r%^\(from%, out
assert_match %r%^= Class methods:%, out
assert_match %r%^ new%, out
@ -315,7 +315,7 @@ class TestRDocRIDriver < MiniTest::Unit::TestCase
def test_display_class_ambiguous
util_multi_store
out, err = capture_io do
out, = capture_io do
@driver.display_class 'Ambiguous'
end
@ -325,7 +325,7 @@ class TestRDocRIDriver < MiniTest::Unit::TestCase
def test_display_class_multi_no_doc
util_multi_store
out, err = capture_io do
out, = capture_io do
@driver.display_class 'Foo::Baz'
end
@ -339,7 +339,7 @@ class TestRDocRIDriver < MiniTest::Unit::TestCase
def test_display_class_superclass
util_multi_store
out, err = capture_io do
out, = capture_io do
@driver.display_class 'Bar'
end
@ -349,7 +349,7 @@ class TestRDocRIDriver < MiniTest::Unit::TestCase
def test_display_class_module
util_store
out, err = capture_io do
out, = capture_io do
@driver.display_class 'Inc'
end
@ -359,7 +359,7 @@ class TestRDocRIDriver < MiniTest::Unit::TestCase
def test_display_method
util_store
out, err = capture_io do
out, = capture_io do
@driver.display_method 'Foo::Bar#blah'
end
@ -371,7 +371,7 @@ class TestRDocRIDriver < MiniTest::Unit::TestCase
def test_display_method_attribute
util_store
out, err = capture_io do
out, = capture_io do
@driver.display_method 'Foo::Bar#attr'
end
@ -382,7 +382,7 @@ class TestRDocRIDriver < MiniTest::Unit::TestCase
def test_display_method_inherited
util_multi_store
out, err = capture_io do
out, = capture_io do
@driver.display_method 'Bar#inherit'
end
@ -393,7 +393,7 @@ class TestRDocRIDriver < MiniTest::Unit::TestCase
def test_display_name_not_found_class
util_store
out, err = capture_io do
out, = capture_io do
assert_equal false, @driver.display_name('Foo::B')
end
@ -410,7 +410,7 @@ Foo::Baz
def test_display_name_not_found_method
util_store
out, err = capture_io do
out, = capture_io do
assert_equal false, @driver.display_name('Foo::Bar#b')
end
@ -427,7 +427,7 @@ Foo::Bar#bother
def test_display_method_params
util_store
out, err = capture_io do
out, = capture_io do
@driver.display_method 'Foo::Bar#bother'
end
@ -496,24 +496,34 @@ Foo::Bar#bother
end
def test_formatter
tty = Object.new
def tty.tty?() true; end
driver = RDoc::RI::Driver.new
io = Object.new
def io.tty?; false; end
assert_instance_of @RM::ToAnsi, driver.formatter(tty)
assert_instance_of @RM::ToBs, driver.formatter(io)
def io.tty?; true; end
assert_instance_of @RM::ToAnsi, driver.formatter(io)
assert_instance_of @RM::ToBs, driver.formatter(StringIO.new)
driver.instance_variable_set :@paging, true
assert_instance_of @RM::ToBs, driver.formatter(io)
assert_instance_of @RM::ToBs, driver.formatter(StringIO.new)
driver.instance_variable_set :@formatter_klass, @RM::ToHtml
assert_instance_of @RM::ToHtml, driver.formatter(io)
assert_instance_of @RM::ToHtml, driver.formatter(tty)
end
def test_in_path_eh
path = ENV['PATH']
refute @driver.in_path?('/nonexistent')
ENV['PATH'] = File.expand_path '..', __FILE__
assert @driver.in_path?(File.basename(__FILE__))
ensure
ENV['PATH'] = path
end
def test_method_type
@ -526,8 +536,8 @@ Foo::Bar#bother
def test_list_known_classes
util_store
out, err = capture_io do
@driver.list_known_classes
out, = capture_io do
@driver.list_known_classes
end
assert_equal "Ambiguous\nFoo\nFoo::Bar\nFoo::Baz\nInc\n", out

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше