git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@18121 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
drbrain 2008-07-18 00:46:16 +00:00
Родитель 0af4a490b4
Коммит fd25f74d64
45 изменённых файлов: 6952 добавлений и 4397 удалений

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

@ -1,3 +1,7 @@
Fri Jul 18 09:44:30 2008
* lib/rdoc/*: Import RDoc r101.
Thu Jul 17 23:45:55 2008 Yusuke Endoh <mame@tsg.ne.jp>
* test/rdoc/test_rdoc_c_parser.rb (teardown): close tempfile.

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

@ -1,8 +1,8 @@
$DEBUG_RDOC = nil
##
# = RDOC - Ruby Documentation System
#
# RDoc - Ruby Documentation System
#
# This package contains RDoc and RDoc::Markup. RDoc is an application that
# produces documentation for one or more Ruby source files. We work similarly
# to JavaDoc, parsing the source, and extracting the definition for classes,
@ -12,12 +12,12 @@ $DEBUG_RDOC = nil
# RDoc::Markup is a library that converts plain text into various output
# formats. The markup library is used to interpret the comment blocks that
# RDoc uses to document methods, classes, and so on.
#
#
# == Roadmap
#
#
# * If you want to use RDoc to create documentation for your Ruby source files,
# read on.
# * If you want to include extensions written in C, see RDoc::C_Parser
# * If you want to include extensions written in C, see RDoc::Parser::C
# * For information on the various markups available in comment blocks, see
# RDoc::Markup.
# * If you want to drive RDoc programmatically, see RDoc::RDoc.
@ -25,63 +25,63 @@ $DEBUG_RDOC = nil
# at RDoc::Markup.
# * If you want to try writing your own HTML output template, see
# RDoc::Generator::HTML
#
#
# == Summary
#
#
# Once installed, you can create documentation using the 'rdoc' command
# (the command is 'rdoc.bat' under Windows)
#
#
# % rdoc [options] [names...]
#
#
# Type "rdoc --help" for an up-to-date option summary.
#
#
# A typical use might be to generate documentation for a package of Ruby
# source (such as rdoc itself).
#
# source (such as rdoc itself).
#
# % rdoc
#
#
# This command generates documentation for all the Ruby and C source
# files in and below the current directory. These will be stored in a
# documentation tree starting in the subdirectory 'doc'.
#
#
# You can make this slightly more useful for your readers by having the
# index page contain the documentation for the primary file. In our
# case, we could type
#
#
# % rdoc --main rdoc.rb
#
#
# You'll find information on the various formatting tricks you can use
# in comment blocks in the documentation this generates.
#
#
# RDoc uses file extensions to determine how to process each file. File names
# ending +.rb+ and <tt>.rbw</tt> are assumed to be Ruby source. Files
# ending +.c+ are parsed as C files. All other files are assumed to
# contain just Markup-style markup (with or without leading '#' comment
# markers). If directory names are passed to RDoc, they are scanned
# recursively for C and Ruby source files only.
#
#
# = Markup
#
#
# For information on how to make lists, hyperlinks, etc. with RDoc, see
# RDoc::Markup.
#
#
# Comment blocks can be written fairly naturally, either using '#' on
# successive lines of the comment, or by including the comment in
# an =begin/=end block. If you use the latter form, the =begin line must be
# flagged with an RDoc tag:
#
#
# =begin rdoc
# Documentation to be processed by RDoc.
#
# ...
# =end
#
#
# RDoc stops processing comments if it finds a comment line containing
# 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.
# #--
@ -92,40 +92,40 @@ $DEBUG_RDOC = nil
# def get_dob(person)
# # ...
# end
#
#
# Names of classes, source files, and any method names containing an
# underscore or preceded by a hash character are automatically hyperlinked
# from comment text to their description.
#
# from comment text to their description.
#
# Method parameter lists are extracted and displayed with the method
# description. If a method calls +yield+, then the parameters passed to yield
# will also be displayed:
#
#
# def fred
# ...
# yield line, address
#
#
# This will get documented as:
#
#
# fred() { |line, address| ... }
#
#
# You can override this using a comment containing ':yields: ...' immediately
# after the method definition
#
#
# def fred # :yields: index, position
# # ...
#
# yield line, address
#
#
# which will get documented as
#
#
# fred() { |index, position| ... }
#
#
# +:yields:+ is an example of a documentation directive. These appear
# immediately after the start of the document element they are modifying.
#
#
# == Directives
#
#
# [+:nodoc:+ / +:nodoc:+ all]
# Don't include this element in the documentation. For classes
# and modules, the methods, aliases, constants, and attributes
@ -143,27 +143,27 @@ $DEBUG_RDOC = nil
# class Output
# end
# end
#
# In the above code, only class +MyModule::Input+ will be documented.
# :nodoc: is global across all files the class or module appears in, so use
# :stopdoc:/:startdoc: to only omit documentation for a particular set of
# methods, etc.
#
#
# In the above code, only class +MyModule::Input+ will be documented.The
# The :nodoc: directive is global across all files the class or module
# appears in, so use :stopdoc:/:startdoc: to only omit documentation for a
# particular set of methods, etc.
#
# [+:doc:+]
# Force a method or attribute to be documented even if it wouldn't otherwise
# be. Useful if, for example, you want to include documentation of a
# particular private method.
#
#
# [+:notnew:+]
# Only applicable to the +initialize+ instance method. Normally RDoc
# assumes that the documentation and parameters for #initialize are
# assumes that the documentation and parameters for #initialize are
# actually for the ::new method, and so fakes out a ::new for the class.
# The :notnew: modifier stops this. Remember that #initialize is protected,
# so you won't see the documentation unless you use the -a command line
# option.
#
#
# Comment blocks can contain other directives:
#
#
# [<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
@ -178,66 +178,66 @@ $DEBUG_RDOC = nil
# # 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.
#
# 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.
#
#
# = Other stuff
#
#
# RDoc is currently being maintained by Eric Hodel <drbrain@segment7.net>
#
# Dave Thomas <dave@pragmaticprogrammer.com> is the original author of RDoc.
#
#
# == Credits
#
#
# * The Ruby parser in rdoc/parse.rb is based heavily on the outstanding
# work of Keiju ISHITSUKA of Nippon Rational Inc, who produced the Ruby
# parser for irb and the rtags package.
#
#
# * Code to diagram classes and modules was written by Sergey A Yanovitsky
# (Jah) of Enticla.
#
#
# * 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.
@ -254,7 +254,7 @@ module RDoc
##
# RDoc version you are using
VERSION = "2.0.0"
VERSION = "2.1.0"
##
# Name of the dotfile that contains the description of files to be processed

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

@ -6,8 +6,8 @@ require 'rdoc/tokenstream'
module RDoc
##
# We contain the common stuff for contexts (which are containers)
# and other elements (methods, attributes and so on)
# We contain the common stuff for contexts (which are containers) and other
# elements (methods, attributes and so on)
class CodeObject
@ -31,6 +31,13 @@ module RDoc
attr_reader :document_self
def initialize
@document_self = true
@document_children = true
@force_documentation = false
@done_documenting = false
end
def document_self=(val)
@document_self = val
if !val
@ -72,13 +79,6 @@ module RDoc
def remove_methods_etc
end
def initialize
@document_self = true
@document_children = true
@force_documentation = false
@done_documenting = false
end
# Access the code object's comment
attr_reader :comment
@ -106,15 +106,24 @@ module RDoc
end
# A Context is something that can hold modules, classes, methods,
# attributes, aliases, requires, and includes. Classes, modules, and
# files are all Contexts.
##
# A Context is something that can hold modules, classes, methods,
# attributes, aliases, requires, and includes. Classes, modules, and files
# are all Contexts.
class Context < CodeObject
attr_reader :name, :method_list, :attributes, :aliases, :constants
attr_reader :requires, :includes, :in_files, :visibility
attr_reader :sections
attr_reader :aliases
attr_reader :attributes
attr_reader :constants
attr_reader :current_section
attr_reader :in_files
attr_reader :includes
attr_reader :method_list
attr_reader :name
attr_reader :requires
attr_reader :sections
attr_reader :visibility
class Section
attr_reader :title, :comment, :sequence
@ -129,12 +138,22 @@ module RDoc
set_comment(comment)
end
private
def ==(other)
self.class === other and @sequence == other.sequence
end
# Set the comment for this section from the original comment block
# If the first line contains :section:, strip it and use the rest. Otherwise
# remove lines up to the line containing :section:, and look for
# those lines again at the end and remove them. This lets us write
def inspect
"#<%s:0x%x %s %p>" % [
self.class, object_id,
@sequence, title
]
end
##
# Set the comment for this section from the original comment block If
# the first line contains :section:, strip it and use the rest.
# Otherwise remove lines up to the line containing :section:, and look
# for those lines again at the end and remove them. This lets us write
#
# # ---------------------
# # :SECTION: The title
@ -144,9 +163,10 @@ module RDoc
def set_comment(comment)
return unless comment
if comment =~ /^.*?:section:.*$/
if comment =~ /^#[ \t]*:section:.*\n/
start = $`
rest = $'
if start.empty?
@comment = rest
else
@ -157,13 +177,13 @@ module RDoc
end
@comment = nil if @comment.empty?
end
end
def initialize
super()
super
@in_files = []
@in_files = []
@name ||= "unknown"
@comment ||= ""
@ -177,29 +197,37 @@ module RDoc
initialize_classes_and_modules
end
##
# map the class hash to an array externally
def classes
@classes.values
end
##
# map the module hash to an array externally
def modules
@modules.values
end
##
# Change the default visibility for new methods
def ongoing_visibility=(vis)
@visibility = vis
end
# Given an array +methods+ of method names, set the
# visibility of the corresponding AnyMethod object
##
# Yields Method and Attr entries matching the list of names in +methods+.
# Attributes are only returned when +singleton+ is false.
def set_visibility_for(methods, vis, singleton=false)
def methods_matching(methods, singleton = false)
count = 0
@method_list.each do |m|
if methods.include?(m.name) && m.singleton == singleton
m.visibility = vis
if methods.include? m.name and m.singleton == singleton then
yield m
count += 1
end
end
@ -209,14 +237,23 @@ module RDoc
# perhaps we need to look at attributes
@attributes.each do |a|
if methods.include?(a.name)
a.visibility = vis
count += 1
end
yield a if methods.include? a.name
end
end
##
# Given an array +methods+ of method names, set the visibility of the
# corresponding AnyMethod object
def set_visibility_for(methods, vis, singleton = false)
methods_matching methods, singleton do |m|
m.visibility = vis
end
end
##
# Record the file that we happen to find it in
def record_location(toplevel)
@in_files << toplevel unless @in_files.include?(toplevel)
end
@ -269,10 +306,10 @@ module RDoc
# Requires always get added to the top-level (file) context
def add_require(a_require)
if self.kind_of? TopLevel
add_to(@requires, a_require)
if TopLevel === self then
add_to @requires, a_require
else
parent.add_require(a_require)
parent.add_require a_require
end
end
@ -292,7 +329,7 @@ module RDoc
end
def add_to(array, thing)
array << thing if @document_self && !@done_documenting
array << thing if @document_self and not @done_documenting
thing.parent = self
thing.section = @current_section
end
@ -371,26 +408,30 @@ module RDoc
name <=> other.name
end
# Look up the given symbol. If method is non-nil, then
# we assume the symbol references a module that
# contains that method
def find_symbol(symbol, method=nil)
##
# Look up +symbol+. If +method+ is non-nil, then we assume the symbol
# references a module that contains that method.
def find_symbol(symbol, method = nil)
result = nil
case symbol
when /^::(.*)/
when /^::(.*)/ then
result = toplevel.find_symbol($1)
when /::/
when /::/ then
modules = symbol.split(/::/)
unless modules.empty?
unless modules.empty? then
module_name = modules.shift
result = find_module_named(module_name)
if result
if result then
modules.each do |name|
result = result.find_module_named(name)
break unless result
end
end
end
else
# if a method is specified, then we're definitely looking for
# a module, otherwise it could be any symbol
@ -408,22 +449,21 @@ module RDoc
end
end
end
if result && method
if !result.respond_to?(:find_local_symbol)
#p result.name
#p method
fail
end
if result and method then
fail unless result.respond_to? :find_local_symbol
result = result.find_local_symbol(method)
end
result
end
def find_local_symbol(symbol)
res = find_method_named(symbol) ||
find_constant_named(symbol) ||
find_attribute_named(symbol) ||
find_module_named(symbol)
find_module_named(symbol) ||
find_file_named(symbol)
end
# Handle sections
@ -454,7 +494,14 @@ module RDoc
def find_attribute_named(name)
@attributes.find {|m| m.name == name}
end
##
# Find a named file, or return nil
def find_file_named(name)
toplevel.class.find_file_named(name)
end
end
##
@ -465,22 +512,29 @@ module RDoc
attr_accessor :file_relative_name
attr_accessor :file_absolute_name
attr_accessor :diagram
@@all_classes = {}
@@all_modules = {}
@@all_files = {}
def self.reset
@@all_classes = {}
@@all_modules = {}
@@all_files = {}
end
def initialize(file_name)
super()
@name = "TopLevel"
@file_relative_name = file_name
@file_absolute_name = file_name
@file_stat = File.stat(file_name)
@diagram = nil
@file_relative_name = file_name
@file_absolute_name = file_name
@file_stat = File.stat(file_name)
@diagram = nil
@@all_files[file_name] = self
end
def file_base_name
File.basename @file_absolute_name
end
def full_name
@ -497,7 +551,7 @@ module RDoc
cls = collection[name]
if cls
puts "Reusing class/module #{name}" if $DEBUG_RDOC
puts "Reusing class/module #{name}" #if $DEBUG_RDOC
else
if class_type == NormalModule
all = @@all_modules
@ -534,6 +588,10 @@ module RDoc
nil
end
def self.find_file_named(name)
@@all_files[name]
end
def find_local_symbol(symbol)
find_class_or_module_named(symbol) || super
end
@ -553,8 +611,9 @@ module RDoc
end
# ClassModule is the base class for objects representing either a
# class or a module.
##
# ClassModule is the base class for objects representing either a class or a
# module.
class ClassModule < Context
@ -603,29 +662,63 @@ module RDoc
end
end
##
# Anonymous classes
class AnonClass < ClassModule
end
##
# Normal classes
class NormalClass < ClassModule
def inspect
superclass = @superclass ? " < #{@superclass}" : nil
"<%s:0x%x class %s%s includes: %p attributes: %p methods: %p aliases: %p>" % [
self.class, object_id,
@name, superclass, @includes, @attributes, @method_list, @aliases
]
end
end
##
# Singleton classes
class SingleClass < ClassModule
end
##
# Module
class NormalModule < ClassModule
def comment=(comment)
return if comment.empty?
comment = @comment << "# ---\n" << comment unless @comment.empty?
super
end
def inspect
"#<%s:0x%x module %s includes: %p attributes: %p methods: %p aliases: %p>" % [
self.class, object_id,
@name, @includes, @attributes, @method_list, @aliases
]
end
def is_module?
true
end
end
##
# AnyMethod is the base class for objects representing methods
class AnyMethod < CodeObject
attr_accessor :name
attr_accessor :visibility
attr_accessor :block_params
@ -663,10 +756,20 @@ module RDoc
@name <=> other.name
end
def to_s
res = self.class.name + ": " + @name + " (" + @text + ")\n"
res << @comment.to_s
res
def add_alias(method)
@aliases << method
end
def inspect
alias_for = @is_alias_for ? " (alias for #{@is_alias_for.name})" : nil
"#<%s:0x%x %s%s%s (%s)%s>" % [
self.class, object_id,
@parent.name,
singleton ? '::' : '#',
name,
visibility,
alias_for,
]
end
def param_seq
@ -691,16 +794,34 @@ $stderr.puts p
p
end
def add_alias(method)
@aliases << method
def to_s
res = self.class.name + ": " + @name + " (" + @text + ")\n"
res << @comment.to_s
res
end
end
# Represent an alias, which is an old_name/ new_name pair associated
# with a particular context
##
# GhostMethod represents a method referenced only by a comment
class GhostMethod < AnyMethod
end
##
# MetaMethod represents a meta-programmed method
class MetaMethod < AnyMethod
end
##
# Represent an alias, which is an old_name/ new_name pair associated with a
# particular context
class Alias < CodeObject
attr_accessor :text, :old_name, :new_name, :comment
def initialize(text, old_name, new_name, comment)
super()
@text = text
@ -709,12 +830,22 @@ $stderr.puts p
self.comment = comment
end
def inspect
"#<%s:0x%x %s.alias_method %s, %s>" % [
self.class, object_id,
parent.name, @old_name, @new_name,
]
end
def to_s
"alias: #{self.old_name} -> #{self.new_name}\n#{self.comment}"
end
end
##
# Represent a constant
class Constant < CodeObject
attr_accessor :name, :value
@ -726,7 +857,9 @@ $stderr.puts p
end
end
##
# Represent attributes
class Attr < CodeObject
attr_accessor :text, :name, :rw, :visibility
@ -739,16 +872,33 @@ $stderr.puts p
self.comment = comment
end
def <=>(other)
self.name <=> other.name
end
def inspect
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,
]
end
def to_s
"attr: #{self.name} #{self.rw}\n#{self.comment}"
end
def <=>(other)
self.name <=> other.name
end
end
# a required file
##
# A required file
class Require < CodeObject
attr_accessor :name
@ -759,16 +909,38 @@ $stderr.puts p
self.comment = comment
end
def inspect
"#<%s:0x%x require '%s' in %s>" % [
self.class,
object_id,
@name,
@parent.file_base_name,
]
end
end
# an included module
##
# An included module
class Include < CodeObject
attr_accessor :name
def initialize(name, comment)
super()
@name = name
self.comment = comment
end
def inspect
"#<%s:0x%x %s.include %s>" % [
self.class,
object_id,
@parent.name,
@name,
]
end
end

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

@ -21,27 +21,6 @@ module RDoc::Generator
CSS_NAME = "rdoc-style.css"
##
# Converts a target url to one that is relative to a given path
def self.gen_url(path, target)
from = ::File.dirname path
to, to_file = ::File.split target
from = from.split "/"
to = to.split "/"
while from.size > 0 and to.size > 0 and from[0] == to[0] do
from.shift
to.shift
end
from.fill ".."
from.concat to
from << to_file
::File.join(*from)
end
##
# Build a hash of all items that can be cross-referenced. This is used when
# we output required and included names: if the names appear in this hash,
@ -80,11 +59,6 @@ module RDoc::Generator
def markup(str, remove_para = false)
return '' unless str
unless defined? @formatter then
@formatter = RDoc::Markup::ToHtmlCrossref.new(path, self,
@options.show_hash)
end
# Convert leading comment markers to spaces, but only if all non-blank
# lines have them
if str =~ /^(?>\s*)[^\#]/ then
@ -93,7 +67,7 @@ module RDoc::Generator
content = str.gsub(/^\s*(#+)/) { $1.tr '#', ' ' }
end
res = @formatter.convert content
res = formatter.convert content
if remove_para then
res.sub!(/^<p>/, '')
@ -114,7 +88,7 @@ module RDoc::Generator
if %r{^(https?:/)?/} =~ css_name
css_name
else
RDoc::Generator.gen_url path, css_name
RDoc::Markup::ToHtml.gen_relative_url path, css_name
end
end
@ -186,6 +160,11 @@ module RDoc::Generator
@template = options.template_class
end
def formatter
@formatter ||= @options.formatter ||
RDoc::Markup::ToHtmlCrossref.new(path, self, @options.show_hash)
end
##
# convenience method to build a hyperlink
@ -201,7 +180,7 @@ module RDoc::Generator
if @options.all_one_file
"#" + path
else
RDoc::Generator.gen_url from_path, path
RDoc::Markup::ToHtml.gen_relative_url from_path, path
end
end
@ -215,7 +194,7 @@ module RDoc::Generator
list = @context.method_list
unless @options.show_all then
list = list.find_all do |m|
list = list.select do |m|
m.visibility == :public or
m.visibility == :protected or
m.force_documentation
@ -230,17 +209,15 @@ module RDoc::Generator
##
# Build a summary list of all the methods in this context
def build_method_summary_list(path_prefix="")
def build_method_summary_list(path_prefix = "")
collect_methods unless @methods
meths = @methods.sort
res = []
meths.each do |meth|
res << {
@methods.sort.map do |meth|
{
"name" => CGI.escapeHTML(meth.name),
"aref" => "#{path_prefix}\##{meth.aref}"
}
end
res
end
##
@ -248,36 +225,40 @@ module RDoc::Generator
# corresponding method
def build_alias_summary_list(section)
values = []
@context.aliases.each do |al|
@context.aliases.map do |al|
next unless al.section == section
res = {
'old_name' => al.old_name,
'new_name' => al.new_name,
}
if al.comment && !al.comment.empty?
res['desc'] = markup(al.comment, true)
if al.comment and not al.comment.empty? then
res['desc'] = markup al.comment, true
end
values << res
end
values
res
end.compact
end
##
# Build a list of constants
def build_constants_summary_list(section)
values = []
@context.constants.each do |co|
@context.constants.map do |co|
next unless co.section == section
res = {
'name' => co.name,
'value' => CGI.escapeHTML(co.value)
}
res['desc'] = markup(co.comment, true) if co.comment && !co.comment.empty?
values << res
end
values
if co.comment and not co.comment.empty? then
res['desc'] = markup co.comment, true
end
res
end.compact
end
def build_requires_list(context)
@ -339,54 +320,58 @@ module RDoc::Generator
def build_method_detail_list(section)
outer = []
methods = @methods.sort
methods = @methods.sort.select do |m|
m.document_self and m.section == section
end
for singleton in [true, false]
for vis in [ :public, :protected, :private ]
res = []
methods.each do |m|
if m.section == section and
m.document_self and
m.visibility == vis and
m.singleton == singleton
row = {}
if m.call_seq
row["callseq"] = m.call_seq.gsub(/->/, '&rarr;')
else
row["name"] = CGI.escapeHTML(m.name)
row["params"] = m.params
end
desc = m.description.strip
row["m_desc"] = desc unless desc.empty?
row["aref"] = m.aref
row["visibility"] = m.visibility.to_s
next unless m.visibility == vis and m.singleton == singleton
alias_names = []
m.aliases.each do |other|
if other.viewer # won't be if the alias is private
alias_names << {
'name' => other.name,
'aref' => other.viewer.as_href(path)
}
end
end
unless alias_names.empty?
row["aka"] = alias_names
end
row = {}
if @options.inline_source
code = m.source_code
row["sourcecode"] = code if code
else
code = m.src_url
if code
row["codeurl"] = code
row["imgurl"] = m.img_url
end
end
res << row
if m.call_seq then
row["callseq"] = m.call_seq.gsub(/->/, '&rarr;')
else
row["name"] = CGI.escapeHTML(m.name)
row["params"] = m.params
end
desc = m.description.strip
row["m_desc"] = desc unless desc.empty?
row["aref"] = m.aref
row["visibility"] = m.visibility.to_s
alias_names = []
m.aliases.each do |other|
if other.viewer then # won't be if the alias is private
alias_names << {
'name' => other.name,
'aref' => other.viewer.as_href(path)
}
end
end
row["aka"] = alias_names unless alias_names.empty?
if @options.inline_source then
code = m.source_code
row["sourcecode"] = code if code
else
code = m.src_url
if code then
row["codeurl"] = code
row["imgurl"] = m.img_url
end
end
res << row
end
if res.size > 0
if res.size > 0 then
outer << {
"type" => vis.to_s.capitalize,
"category" => singleton ? "Class" : "Instance",
@ -395,6 +380,7 @@ module RDoc::Generator
end
end
end
outer
end
@ -403,8 +389,8 @@ module RDoc::Generator
# in this context.
def build_class_list(level, from, section, infile=nil)
res = ""
prefix = "&nbsp;&nbsp;::" * level;
prefix = '&nbsp;&nbsp;::' * level;
res = ''
from.modules.sort.each do |mod|
next unless mod.section == section
@ -412,8 +398,8 @@ module RDoc::Generator
if mod.document_self
res <<
prefix <<
"Module " <<
href(url(mod.viewer.path), "link", mod.full_name) <<
'Module ' <<
href(url(mod.viewer.path), 'link', mod.full_name) <<
"<br />\n" <<
build_class_list(level + 1, mod, section, infile)
end
@ -421,12 +407,13 @@ module RDoc::Generator
from.classes.sort.each do |cls|
next unless cls.section == section
next if infile && !cls.defined_in?(infile)
next if infile and not cls.defined_in?(infile)
if cls.document_self
res <<
res <<
prefix <<
"Class " <<
href(url(cls.viewer.path), "link", cls.full_name) <<
'Class ' <<
href(url(cls.viewer.path), 'link', cls.full_name) <<
"<br />\n" <<
build_class_list(level + 1, cls, section, infile)
end
@ -436,7 +423,7 @@ module RDoc::Generator
end
def url(target)
RDoc::Generator.gen_url path, target
RDoc::Markup::ToHtml.gen_relative_url path, target
end
def aref_to(target)
@ -475,7 +462,7 @@ module RDoc::Generator
def add_table_of_sections
toc = []
@context.sections.each do |section|
if section.title
if section.title then
toc << {
'secname' => section.title,
'href' => section.sequence
@ -495,11 +482,13 @@ module RDoc::Generator
attr_reader :methods
attr_reader :path
attr_reader :values
def initialize(context, html_file, prefix, options)
super(context, options)
super context, options
@html_file = html_file
@html_class = self
@is_module = context.is_module?
@values = {}
@ -540,11 +529,19 @@ module RDoc::Generator
name
end
def write_on(f)
def write_on(f, file_list, class_list, method_list, overrides = {})
value_hash
@values['file_list'] = file_list
@values['class_list'] = class_list
@values['method_list'] = method_list
@values.update overrides
template = RDoc::TemplatePage.new(@template::BODY,
@template::CLASS_PAGE,
@template::METHOD_LIST)
template.write_html_on(f, @values)
end
@ -561,30 +558,29 @@ module RDoc::Generator
ml = build_method_summary_list @path
@values["methods"] = ml unless ml.empty?
il = build_include_list(@context)
il = build_include_list @context
@values["includes"] = il unless il.empty?
@values["sections"] = @context.sections.map do |section|
secdata = {
"sectitle" => section.title,
"secsequence" => section.sequence,
"seccomment" => markup(section.comment)
"seccomment" => markup(section.comment),
}
al = build_alias_summary_list(section)
al = build_alias_summary_list section
secdata["aliases"] = al unless al.empty?
co = build_constants_summary_list(section)
co = build_constants_summary_list section
secdata["constants"] = co unless co.empty?
al = build_attribute_list(section)
al = build_attribute_list section
secdata["attributes"] = al unless al.empty?
cl = build_class_list(0, @context, section)
cl = build_class_list 0, @context, section
secdata["classlist"] = cl unless cl.empty?
mdl = build_method_detail_list(section)
mdl = build_method_detail_list section
secdata["method_list"] = mdl unless mdl.empty?
secdata
@ -594,23 +590,25 @@ module RDoc::Generator
end
def build_attribute_list(section)
atts = @context.attributes.sort
res = []
atts.each do |att|
@context.attributes.sort.map do |att|
next unless att.section == section
if att.visibility == :public || att.visibility == :protected || @options.show_all
if att.visibility == :public or att.visibility == :protected or
@options.show_all then
entry = {
"name" => CGI.escapeHTML(att.name),
"rw" => att.rw,
"a_desc" => markup(att.comment, true)
}
unless att.visibility == :public || att.visibility == :protected
unless att.visibility == :public or att.visibility == :protected then
entry["rw"] << "-"
end
res << entry
entry
end
end
res
end.compact
end
def class_attribute_values
@ -680,9 +678,10 @@ module RDoc::Generator
attr_reader :path
attr_reader :name
attr_reader :values
def initialize(context, options, file_dir)
super(context, options)
super context, options
@values = {}
@ -755,7 +754,7 @@ module RDoc::Generator
}
cl = build_class_list(0, @context, section, file_context)
@values["classlist"] = cl unless cl.empty?
secdata["classlist"] = cl unless cl.empty?
mdl = build_method_detail_list(section)
secdata["method_list"] = mdl unless mdl.empty?
@ -764,7 +763,7 @@ module RDoc::Generator
secdata["aliases"] = al unless al.empty?
co = build_constants_summary_list(section)
@values["constants"] = co unless co.empty?
secdata["constants"] = co unless co.empty?
secdata
end
@ -772,9 +771,15 @@ module RDoc::Generator
@values
end
def write_on(f)
def write_on(f, file_list, class_list, method_list, overrides = {})
value_hash
@values['file_list'] = file_list
@values['class_list'] = class_list
@values['method_list'] = method_list
@values.update overrides
template = RDoc::TemplatePage.new(@template::BODY,
@template::FILE_PAGE,
@template::METHOD_LIST)
@ -829,15 +834,17 @@ module RDoc::Generator
end
def initialize(context, html_class, options)
# TODO: rethink the class hierarchy here...
@context = context
@html_class = html_class
@options = options
@@seq = @@seq.succ
@seq = @@seq
# HACK ugly
@template = options.template_class
@@seq = @@seq.succ
@seq = @@seq
@@all_methods << self
context.viewer = self
@ -846,7 +853,7 @@ module RDoc::Generator
@source_code = markup_code(ts)
unless @options.inline_source
@src_url = create_source_code_file(@source_code)
@img_url = RDoc::Generator.gen_url path, 'source.png'
@img_url = RDoc::Markup::ToHtml.gen_relative_url path, 'source.png'
end
end
@ -861,10 +868,32 @@ module RDoc::Generator
if @options.all_one_file
"#" + path
else
RDoc::Generator.gen_url from_path, path
RDoc::Markup::ToHtml.gen_relative_url from_path, path
end
end
def formatter
@formatter ||= @options.formatter ||
RDoc::Markup::ToHtmlCrossref.new(path, self, @options.show_hash)
end
def inspect
alias_for = if @context.is_alias_for then
" (alias_for #{@context.is_alias_for})"
else
nil
end
"#<%s:0x%x %s%s%s (%s)%s>" % [
self.class, object_id,
@context.parent.name,
@context.singleton ? '::' : '#',
name,
@context.visibility,
alias_for
]
end
def name
@context.name
end
@ -961,7 +990,7 @@ module RDoc::Generator
template.write_html_on(f, values)
end
RDoc::Generator.gen_url path, file_path
RDoc::Markup::ToHtml.gen_relative_url path, file_path
end
def <=>(other)
@ -976,19 +1005,18 @@ module RDoc::Generator
src = ""
tokens.each do |t|
next unless t
# p t.class
# style = STYLE_MAP[t.class]
style = case t
when RubyToken::TkCONSTANT then "ruby-constant"
when RubyToken::TkKW then "ruby-keyword kw"
when RubyToken::TkIVAR then "ruby-ivar"
when RubyToken::TkOp then "ruby-operator"
when RubyToken::TkId then "ruby-identifier"
when RubyToken::TkNode then "ruby-node"
when RubyToken::TkCOMMENT then "ruby-comment cmt"
when RubyToken::TkREGEXP then "ruby-regexp re"
when RubyToken::TkSTRING then "ruby-value str"
when RubyToken::TkVal then "ruby-value"
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

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

@ -82,7 +82,7 @@ class RDoc::Generator::HTML
@classes = []
write_style_sheet
gen_sub_directories()
gen_sub_directories
build_indices
generate_html
end
@ -157,6 +157,7 @@ class RDoc::Generator::HTML
# the individual descriptions for files and classes
gen_into(@files)
gen_into(@classes)
# and the index files
gen_file_index
gen_class_index
@ -168,14 +169,21 @@ class RDoc::Generator::HTML
end
def gen_into(list)
@file_list ||= index_to_links @files
@class_list ||= index_to_links @classes
@method_list ||= index_to_links RDoc::Generator::Method.all_methods
list.each do |item|
if item.document_self
op_file = item.path
FileUtils.mkdir_p(File.dirname(op_file))
open(op_file, "w") { |file| item.write_on(file) }
next unless item.document_self
op_file = item.path
FileUtils.mkdir_p File.dirname(op_file)
open op_file, 'w' do |io|
item.write_on io, @file_list, @class_list, @method_list
end
end
end
def gen_file_index
@ -221,9 +229,23 @@ class RDoc::Generator::HTML
# line.
def gen_main_index
template = RDoc::TemplatePage.new @template::INDEX
if @template.const_defined? :FRAMELESS then
main = @files.find do |file|
@main_page == file.name
end
if main.nil? then
main = @classes.find do |klass|
main_page == klass.context.full_name
end
end
else
main = RDoc::TemplatePage.new @template::INDEX
end
open 'index.html', 'w' do |f|
style_url = style_url '', @options.css
classes = @classes.sort.map { |klass| klass.value_hash }
values = {
@ -237,18 +259,31 @@ class RDoc::Generator::HTML
values['inline_source'] = @options.inline_source
template.write_html_on f, values
if main.respond_to? :write_on then
main.write_on f, @file_list, @class_list, @method_list, values
else
main.write_html_on f, values
end
end
end
def index_to_links(collection)
collection.sort.map do |f|
next unless f.document_self
{ "href" => f.path, "name" => f.index_name }
end.compact
end
##
# Returns the url of the main page
def main_url
@main_page = @options.main_page
@main_page_ref = nil
if @main_page
if @main_page then
@main_page_ref = RDoc::Generator::AllReferences[@main_page]
if @main_page_ref then
@main_page_path = @main_page_ref.path
else
@ -351,15 +386,8 @@ class RDoc::Generator::HTMLInOne < RDoc::Generator::HTML
end
def gen_an_index(collection, title)
res = []
collection.sort.each do |f|
if f.document_self
res << { "href" => f.path, "name" => f.index_name }
end
end
return {
"entries" => res,
"entries" => index_to_links(collection),
'list_title' => title,
'index_url' => main_url,
}
@ -367,4 +395,3 @@ class RDoc::Generator::HTMLInOne < RDoc::Generator::HTML
end

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

@ -0,0 +1,795 @@
require 'rdoc/generator/html'
require 'rdoc/generator/html/one_page_html'
##
# = CSS2 RDoc HTML template
#
# This is a template for RDoc that uses XHTML 1.0 Transitional and dictates a
# bit more of the appearance of the output to cascading stylesheets than the
# default. It was designed for clean inline code display, and uses DHTMl to
# toggle the visbility of each method's source with each click on the '[source]'
# link.
#
# == Authors
#
# * Michael Granger <ged@FaerieMUD.org>
#
# Copyright (c) 2002, 2003 The FaerieMUD Consortium. Some rights reserved.
#
# This work is licensed under the Creative Commons Attribution License. To view
# a copy of this license, visit http://creativecommons.org/licenses/by/1.0/ or
# send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California
# 94305, USA.
module RDoc::Generator::HTML::FRAMELESS
FRAMELESS = true
FONTS = "Verdana,Arial,Helvetica,sans-serif"
STYLE = <<-EOF
body {
font-family: #{FONTS};
font-size: 90%;
margin: 0;
margin-left: 40px;
padding: 0;
background: white;
}
h1, h2, h3, h4 {
margin: 0;
color: #efefef;
background: transparent;
}
h1 {
font-size: 150%;
}
h2,h3,h4 {
margin-top: 1em;
}
:link, :visited {
background: #eef;
color: #039;
text-decoration: none;
}
:link:hover, :visited:hover {
background: #039;
color: #eef;
}
/* Override the base stylesheet's Anchor inside a table cell */
td > :link, td > :visited {
background: transparent;
color: #039;
text-decoration: none;
}
/* and inside a section title */
.section-title > :link, .section-title > :visited {
background: transparent;
color: #eee;
text-decoration: none;
}
/* === Structural elements =================================== */
.index {
margin: 0;
margin-left: -40px;
padding: 0;
font-size: 90%;
}
.index :link, .index :visited {
margin-left: 0.7em;
}
.index .section-bar {
margin-left: 0px;
padding-left: 0.7em;
background: #ccc;
font-size: small;
}
#classHeader, #fileHeader {
width: auto;
color: white;
padding: 0.5em 1.5em 0.5em 1.5em;
margin: 0;
margin-left: -40px;
border-bottom: 3px solid #006;
}
#classHeader :link, #fileHeader :link,
#classHeader :visited, #fileHeader :visited {
background: inherit;
color: white;
}
#classHeader td, #fileHeader td {
background: inherit;
color: white;
}
#fileHeader {
background: #057;
}
#classHeader {
background: #048;
}
.class-name-in-header {
font-size: 180%;
font-weight: bold;
}
#bodyContent {
padding: 0 1.5em 0 1.5em;
}
#description {
padding: 0.5em 1.5em;
background: #efefef;
border: 1px dotted #999;
}
#description h1, #description h2, #description h3,
#description h4, #description h5, #description h6 {
color: #125;
background: transparent;
}
#copyright {
color: #333;
background: #efefef;
font: 0.75em sans-serif;
margin-top: 5em;
margin-bottom: 0;
padding: 0.5em 2em;
}
/* === Classes =================================== */
table.header-table {
color: white;
font-size: small;
}
.type-note {
font-size: small;
color: #dedede;
}
.xxsection-bar {
background: #eee;
color: #333;
padding: 3px;
}
.section-bar {
color: #333;
border-bottom: 1px solid #999;
margin-left: -20px;
}
.section-title {
background: #79a;
color: #eee;
padding: 3px;
margin-top: 2em;
margin-left: -30px;
border: 1px solid #999;
}
.top-aligned-row {
vertical-align: top
}
.bottom-aligned-row {
vertical-align: bottom
}
/* --- Context section classes ----------------------- */
.context-row { }
.context-item-name {
font-family: monospace;
font-weight: bold;
color: black;
}
.context-item-value {
font-size: small;
color: #448;
}
.context-item-desc {
color: #333;
padding-left: 2em;
}
/* --- Method classes -------------------------- */
.method-detail {
background: #efefef;
padding: 0;
margin-top: 0.5em;
margin-bottom: 1em;
border: 1px dotted #ccc;
}
.method-heading {
color: black;
background: #ccc;
border-bottom: 1px solid #666;
padding: 0.2em 0.5em 0 0.5em;
}
.method-signature {
color: black;
background: inherit;
}
.method-name {
font-weight: bold;
}
.method-args {
font-style: italic;
}
.method-description {
padding: 0 0.5em 0 0.5em;
}
/* --- Source code sections -------------------- */
:link.source-toggle, :visited.source-toggle {
font-size: 90%;
}
div.method-source-code {
background: #262626;
color: #ffdead;
margin: 1em;
padding: 0.5em;
border: 1px dashed #999;
overflow: hidden;
}
div.method-source-code pre {
color: #ffdead;
overflow: hidden;
}
/* --- Ruby keyword styles --------------------- */
.standalone-code {
background: #221111;
color: #ffdead;
overflow: hidden;
}
.ruby-constant {
color: #7fffd4;
background: transparent;
}
.ruby-keyword {
color: #00ffff;
background: transparent;
}
.ruby-ivar {
color: #eedd82;
background: transparent;
}
.ruby-operator {
color: #00ffee;
background: transparent;
}
.ruby-identifier {
color: #ffdead;
background: transparent;
}
.ruby-node {
color: #ffa07a;
background: transparent;
}
.ruby-comment {
color: #b22222;
font-weight: bold;
background: transparent;
}
.ruby-regexp {
color: #ffa07a;
background: transparent;
}
.ruby-value {
color: #7fffd4;
background: transparent;
}
EOF
##
# Header template
XHTML_PREAMBLE = <<-EOF
<?xml version="1.0" encoding="<%= values["charset"] %>"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
EOF
HEADER = XHTML_PREAMBLE + <<-EOF
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title><%= values["title"] %></title>
<meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<link rel="stylesheet" href="<%= values["style_url"] %>" type="text/css" media="screen" />
<script type="text/javascript">
// <![CDATA[
function popupCode( url ) {
window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
}
function toggleCode( id ) {
if ( document.getElementById )
elem = document.getElementById( id );
else if ( document.all )
elem = eval( "document.all." + id );
else
return false;
elemStyle = elem.style;
if ( elemStyle.display != "block" ) {
elemStyle.display = "block"
} else {
elemStyle.display = "none"
}
return true;
}
// Make codeblocks hidden by default
document.writeln( "<style type=\\"text/css\\">div.method-source-code { display: none }</style>" )
// ]]>
</script>
</head>
<body>
EOF
##
# Context content template
CONTEXT_CONTENT = %{
}
##
# Footer template
FOOTER = <<-EOF
<div id="popupmenu" class="index">
<ul>
<li class="index-entries section-bar">Classes
<ul>
<% values["class_list"].each do |klass| %>
<li><a href="<%= klass["href"] %>"><%= klass["name"] %></a>
<% end %>
</ul>
</li>
<li class="index-entries section-bar">Methods
<ul>
<% values["method_list"].each do |file| %>
<li><a href="<%= file["href"] %>"><%= file["name"] %></a>
<% end %>
</ul>
</li>
<li class="index-entries section-bar">Files
<ul>
<% values["file_list"].each do |file| %>
<li><a href="<%= file["href"] %>"><%= file["name"] %></a>
<% end %>
</ul>
</li>
</ul>
</li>
</body>
</html>
EOF
##
# File page header template
FILE_PAGE = <<-EOF
<div id="fileHeader">
<h1><%= values["short_name"] %></h1>
<table class="header-table">
<tr class="top-aligned-row">
<td><strong>Path:</strong></td>
<td><%= values["full_path"] %>
<% if values["cvsurl"] then %>
&nbsp;(<a href="<%= values["cvsurl"] %>"><acronym title="Concurrent Versioning System">CVS</acronym></a>)
<% end %>
</td>
</tr>
<tr class="top-aligned-row">
<td><strong>Last Update:</strong></td>
<td><%= values["dtm_modified"] %></td>
</tr>
</table>
</div>
EOF
##
# Class page header template
CLASS_PAGE = <<-EOF
<div id="classHeader">
<table class="header-table">
<tr class="top-aligned-row">
<td><strong><%= values["classmod"] %></strong></td>
<td class="class-name-in-header"><%= values["full_name"] %></td>
</tr>
<tr class="top-aligned-row">
<td><strong>In:</strong></td>
<td>
<% values["infiles"].each do |infiles| %>
<% if infiles["full_path_url"] then %>
<a href="<%= infiles["full_path_url"] %>">
<% end %>
<%= infiles["full_path"] %>
<% if infiles["full_path_url"] then %>
</a>
<% end %>
<% if infiles["cvsurl"] then %>
&nbsp;(<a href="<%= infiles["cvsurl"] %>"><acronym title="Concurrent Versioning System">CVS</acronym></a>)
<% end %>
<br />
<% end %><%# values["infiles"] %>
</td>
</tr>
<% if values["parent"] then %>
<tr class="top-aligned-row">
<td><strong>Parent:</strong></td>
<td>
<% if values["par_url"] then %>
<a href="<%= values["par_url"] %>">
<% end %>
<%= values["parent"] %>
<% if values["par_url"] then %>
</a>
<% end %>
</td>
</tr>
<% end %>
</table>
</div>
EOF
##
# Method list template
METHOD_LIST = <<-EOF
<div id="contextContent">
<% if values["diagram"] then %>
<div id="diagram">
<%= values["diagram"] %>
</div>
<% end %>
<% if values["description"] then %>
<div id="description">
<%= values["description"] %>
</div>
<% end %>
<% if values["requires"] then %>
<div id="requires-list">
<h3 class="section-bar">Required files</h3>
<div class="name-list">
<% values["requires"].each do |requires| %>
<%= href requires["aref"], requires["name"] %>&nbsp;&nbsp;
<% end %><%# values["requires"] %>
</div>
</div>
<% end %>
<% if values["toc"] then %>
<div id="contents-list">
<h3 class="section-bar">Contents</h3>
<ul>
<% values["toc"].each do |toc| %>
<li><a href="#<%= values["href"] %>"><%= values["secname"] %></a></li>
<% end %><%# values["toc"] %>
</ul>
<% end %>
</div>
<% if values["methods"] then %>
<div id="method-list">
<h3 class="section-bar">Methods</h3>
<div class="name-list">
<% values["methods"].each do |methods| %>
<%= href methods["aref"], methods["name"] %>&nbsp;&nbsp;
<% end %><%# values["methods"] %>
</div>
</div>
<% end %>
</div>
<!-- if includes -->
<% if values["includes"] then %>
<div id="includes">
<h3 class="section-bar">Included Modules</h3>
<div id="includes-list">
<% values["includes"].each do |includes| %>
<span class="include-name"><%= href includes["aref"], includes["name"] %></span>
<% end %><%# values["includes"] %>
</div>
</div>
<% end %>
<% values["sections"].each do |sections| %>
<div id="section">
<% if sections["sectitle"] then %>
<h2 class="section-title"><a name="<%= sections["secsequence"] %>"><%= sections["sectitle"] %></a></h2>
<% if sections["seccomment"] then %>
<div class="section-comment">
<%= sections["seccomment"] %>
</div>
<% end %>
<% end %>
<% if values["classlist"] then %>
<div id="class-list">
<h3 class="section-bar">Classes and Modules</h3>
<%= values["classlist"] %>
</div>
<% end %>
<% if values["constants"] then %>
<div id="constants-list">
<h3 class="section-bar">Constants</h3>
<div class="name-list">
<table summary="Constants">
<% values["constants"].each do |constants| %>
<tr class="top-aligned-row context-row">
<td class="context-item-name"><%= constants["name"] %></td>
<td>=</td>
<td class="context-item-value"><%= constants["value"] %></td>
<% if values["desc"] then %>
<td width="3em">&nbsp;</td>
<td class="context-item-desc"><%= constants["desc"] %></td>
<% end %>
</tr>
<% end %><%# values["constants"] %>
</table>
</div>
</div>
<% end %>
<% if values["aliases"] then %>
<div id="aliases-list">
<h3 class="section-bar">External Aliases</h3>
<div class="name-list">
<table summary="aliases">
<% values["aliases"].each do |aliases| $stderr.puts({ :aliases => aliases }.inspect) %>
<tr class="top-aligned-row context-row">
<td class="context-item-name"><%= values["old_name"] %></td>
<td>-&gt;</td>
<td class="context-item-value"><%= values["new_name"] %></td>
</tr>
<% if values["desc"] then %>
<tr class="top-aligned-row context-row">
<td>&nbsp;</td>
<td colspan="2" class="context-item-desc"><%= values["desc"] %></td>
</tr>
<% end %>
<% end %><%# values["aliases"] %>
</table>
</div>
</div>
<% end %>
<% if values["attributes"] then %>
<div id="attribute-list">
<h3 class="section-bar">Attributes</h3>
<div class="name-list">
<table>
<% values["attributes"].each do |attributes| $stderr.puts({ :attributes => attributes }.inspect) %>
<tr class="top-aligned-row context-row">
<td class="context-item-name"><%= values["name"] %></td>
<% if values["rw"] then %>
<td class="context-item-value">&nbsp;[<%= values["rw"] %>]&nbsp;</td>
<% end %>
<% unless values["rw"] then %>
<td class="context-item-value">&nbsp;&nbsp;</td>
<% end %>
<td class="context-item-desc"><%= values["a_desc"] %></td>
</tr>
<% end %><%# values["attributes"] %>
</table>
</div>
</div>
<% end %>
<!-- if method_list -->
<% if sections["method_list"] then %>
<div id="methods">
<% sections["method_list"].each do |method_list| %>
<% if method_list["methods"] then %>
<h3 class="section-bar"><%= method_list["type"] %> <%= method_list["category"] %> methods</h3>
<% method_list["methods"].each do |methods| %>
<div id="method-<%= methods["aref"] %>" class="method-detail">
<a name="<%= methods["aref"] %>"></a>
<div class="method-heading">
<% if methods["codeurl"] then %>
<a href="<%= methods["codeurl"] %>" target="Code" class="method-signature"
onclick="popupCode('<%= methods["codeurl"] %>');return false;">
<% end %>
<% if methods["sourcecode"] then %>
<a href="#<%= methods["aref"] %>" class="method-signature">
<% end %>
<% if methods["callseq"] then %>
<span class="method-name"><%= methods["callseq"] %></span>
<% end %>
<% unless methods["callseq"] then %>
<span class="method-name"><%= methods["name"] %></span><span class="method-args"><%= methods["params"] %></span>
<% end %>
<% if methods["codeurl"] then %>
</a>
<% end %>
<% if methods["sourcecode"] then %>
</a>
<% end %>
</div>
<div class="method-description">
<% if methods["m_desc"] then %>
<%= methods["m_desc"] %>
<% end %>
<% if methods["sourcecode"] then %>
<p><a class="source-toggle" href="#"
onclick="toggleCode('<%= methods["aref"] %>-source');return false;">[Source]</a></p>
<div class="method-source-code" id="<%= methods["aref"] %>-source">
<pre>
<%= methods["sourcecode"] %>
</pre>
</div>
<% end %>
</div>
</div>
<% end %><%# method_list["methods"] %>
<% end %>
<% end %><%# sections["method_list"] %>
</div>
<% end %>
<% end %><%# values["sections"] %>
EOF
##
# Body template
BODY = HEADER + %{
<%= template_include %> <!-- banner header -->
<div id="bodyContent">
} + METHOD_LIST + %{
</div>
} + FOOTER
##
# Source code template
SRC_PAGE = XHTML_PREAMBLE + <<-EOF
<html>
<head>
<title><%= values["title"] %></title>
<meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
<link rel="stylesheet" href="<%= values["style_url"] %>" type="text/css" media="screen" />
</head>
<body class="standalone-code">
<pre><%= values["code"] %></pre>
</body>
</html>
EOF
##
# Index file templates
FR_INDEX_BODY = %{
<%= template_include %>
}
FILE_INDEX = XHTML_PREAMBLE + <<-EOF
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title><%= values["list_title"] %></title>
<meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
<link rel="stylesheet" href="<%= values["style_url"] %>" type="text/css" />
<base target="docwin" />
</head>
<body>
<div class="index">
<h1 class="section-bar"><%= values["list_title"] %></h1>
<div class="index-entries">
<% values["entries"].each do |entries| %>
<a href="<%= entries["href"] %>"><%= entries["name"] %></a><br />
<% end %><%# values["entries"] %>
</div>
</div>
</body>
</html>
EOF
CLASS_INDEX = FILE_INDEX
METHOD_INDEX = FILE_INDEX
INDEX = <<-EOF
<?xml version="1.0" encoding="<%= values["charset"] %>"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title><%= values["title"] %></title>
<meta http-equiv="Content-Type" content="text/html; charset=<%= values["charset"] %>" />
</head>
<frameset rows="20%, 80%">
<frameset cols="45%,55%">
<frame src="fr_class_index.html" name="Classes" />
<frame src="fr_method_index.html" name="Methods" />
</frameset>
<frame src="<%= values["initial_page"] %>" name="docwin" />
</frameset>
</html>
EOF
end

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

@ -141,7 +141,7 @@ td { font-family: Verdana, Arial, Helvetica, sans-serif;
<div class="name-list">
<% values["requires"].each do |requires| %>
<%= href requires["aref"], requires["name"] %>
<% end # values["requires"] %>
<% end %><%# values["requires"] %>
<% end %>
</div>
@ -156,10 +156,10 @@ td { font-family: Verdana, Arial, Helvetica, sans-serif;
<div class="name-list">
<% method_list["methods"].each do |methods| %>
<a href="<%= methods["codeurl"] %>" target="source"><%= methods["name"] %></a>
<% end # values["methods"] %>
<% end %><%# values["methods"] %>
</div>
<% end %>
<% end # values["method_list"] %>
<% end %><%# values["method_list"] %>
<% end %>
<% if sections["attributes"] then %>
@ -178,10 +178,10 @@ td { font-family: Verdana, Arial, Helvetica, sans-serif;
<td class="attr-name"><%= attributes["name"] %></td>
<td><%= attributes["a_desc"] %></td>
</tr>
<% end # values["attributes"] %>
<% end %><%# values["attributes"] %>
</table>
<% end %>
<% end # values["sections"] %>
<% end %><%# values["sections"] %>
<% end %>
<% if values["classlist"] then %>
@ -237,7 +237,7 @@ td { font-family: Verdana, Arial, Helvetica, sans-serif;
<% if infiles["cvsurl"] then %>
&nbsp;(<a href="<%= infiles["cvsurl"] %>"><acronym title="Concurrent Versioning System">CVS</acronym></a>)
<% end %>
<% end # values["infiles"] %>
<% end %><%# values["infiles"] %>
</td>
</tr>
<% if values["parent"] then %>
@ -266,7 +266,7 @@ td { font-family: Verdana, Arial, Helvetica, sans-serif;
<div class="name-list">
<% values["includes"].each do |includes| %>
<span class="method-name"><%= href includes["aref"], includes["name"] %></span>
<% end # values["includes"] %>
<% end %><%# values["includes"] %>
</div>
<% end %>
@ -293,11 +293,11 @@ td { font-family: Verdana, Arial, Helvetica, sans-serif;
<%= method_list["m_desc"] %>
</div>
<% end %>
<% end # method_list["methods"] %>
<% end %><%# method_list["methods"] %>
<% end %>
<% end # sections["method_list"] %>
<% end %><%# sections["method_list"] %>
<% end %>
<% end # values["sections"] %>
<% end %><%# values["sections"] %>
<% end %>
EOF
@ -365,7 +365,7 @@ div.banner {
<div class="banner"><%= values["list_title"] %></div>
<% values["entries"].each do |entries| %>
<a href="<%= entries["href"] %>"><%= entries["name"] %></a><br />
<% end # values["entries"] %>
<% end %><%# values["entries"] %>
</body></html>
EOF

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

@ -7,8 +7,8 @@ require 'rdoc/generator/html/one_page_html'
# This is a template for RDoc that uses XHTML 1.0 Transitional and dictates a
# bit more of the appearance of the output to cascading stylesheets than the
# default. It was designed for clean inline code display, and uses DHTMl to
# toggle the visibility of each method's source with each click on the '[source]'
# link.
# toggle the visibility of each method's source with each click on the
# '[source]' link.
#
# == Authors
#
@ -16,10 +16,10 @@ require 'rdoc/generator/html/one_page_html'
#
# Copyright (c) 2002, 2003 The FaerieMUD Consortium. Some rights reserved.
#
# This work is licensed under the Creative Commons Attribution License. To view
# a copy of this license, visit http://creativecommons.org/licenses/by/1.0/ or
# send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California
# 94305, USA.
# This work is licensed under the Creative Commons Attribution License. To
# view a copy of this license, visit
# http://creativecommons.org/licenses/by/1.0/ or send a letter to Creative
# Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
module RDoc::Generator::HTML::HTML
@ -361,7 +361,7 @@ EOF
&nbsp;(<a href="<%= infiles["cvsurl"] %>"><acronym title="Concurrent Versioning System">CVS</acronym></a>)
<% end %>
<br />
<% end # values["infiles"] %>
<% end %><%# values["infiles"] %>
</td>
</tr>
@ -388,39 +388,38 @@ EOF
#####################################################################
METHOD_LIST = <<-EOF
<div id="contextContent">
<% if values["diagram"] then %>
<div id="diagram">
<%= values["diagram"] %>
</div>
<% end %>
<% end
<% if values["description"] then %>
if values["description"] then %>
<div id="description">
<%= values["description"] %>
</div>
<% end %>
<% end
<% if values["requires"] then %>
if values["requires"] then %>
<div id="requires-list">
<h3 class="section-bar">Required files</h3>
<div class="name-list">
<% values["requires"].each do |requires| %>
<%= href requires["aref"], requires["name"] %>&nbsp;&nbsp;
<% end # values["requires"] %>
<% end %><%# values["requires"] %>
</div>
</div>
<% end %>
<% end
<% if values["toc"] then %>
if values["toc"] then %>
<div id="contents-list">
<h3 class="section-bar">Contents</h3>
<ul>
<% values["toc"].each do |toc| %>
<li><a href="#<%= values["href"] %>"><%= values["secname"] %></a></li>
<% end # values["toc"] %>
<li><a href="#<%= toc["href"] %>"><%= toc["secname"] %></a></li>
<% end %><%# values["toc"] %>
</ul>
<% end %>
</div>
@ -430,16 +429,14 @@ EOF
<h3 class="section-bar">Methods</h3>
<div class="name-list">
<% values["methods"].each do |methods| %>
<% values["methods"].each do |methods| %>
<%= href methods["aref"], methods["name"] %>&nbsp;&nbsp;
<% end # values["methods"] %>
<% end %><%# values["methods"] %>
</div>
</div>
<% end %>
</div>
<!-- if includes -->
<% if values["includes"] then %>
<div id="includes">
@ -448,140 +445,137 @@ EOF
<div id="includes-list">
<% values["includes"].each do |includes| %>
<span class="include-name"><%= href includes["aref"], includes["name"] %></span>
<% end # values["includes"] %>
<% end %><%# values["includes"] %>
</div>
</div>
<% end %>
<% end
<% values["sections"].each do |sections| %>
values["sections"].each do |sections| %>
<div id="section">
<% if sections["sectitle"] then %>
<% if sections["sectitle"] then %>
<h2 class="section-title"><a name="<%= sections["secsequence"] %>"><%= sections["sectitle"] %></a></h2>
<% if sections["seccomment"] then %>
<% if sections["seccomment"] then %>
<div class="section-comment">
<%= sections["seccomment"] %>
</div>
<% end %>
<% end %>
<% end
end
<% if values["classlist"] then %>
if sections["classlist"] then %>
<div id="class-list">
<h3 class="section-bar">Classes and Modules</h3>
<%= values["classlist"] %>
<%= sections["classlist"] %>
</div>
<% end %>
<% end
<% if values["constants"] then %>
if sections["constants"] then %>
<div id="constants-list">
<h3 class="section-bar">Constants</h3>
<div class="name-list">
<table summary="Constants">
<% values["constants"].each do |constants| %>
<% sections["constants"].each do |constants| %>
<tr class="top-aligned-row context-row">
<td class="context-item-name"><%= constants["name"] %></td>
<td>=</td>
<td class="context-item-value"><%= constants["value"] %></td>
<% if values["desc"] then %>
<% if sections["desc"] then %>
<td width="3em">&nbsp;</td>
<td class="context-item-desc"><%= constants["desc"] %></td>
<% end %>
<% end %>
</tr>
<% end # values["constants"] %>
<% end %><%# sections["constants"] %>
</table>
</div>
</div>
<% end %>
<% end
<% if values["aliases"] then %>
if sections["aliases"] then %>
<div id="aliases-list">
<h3 class="section-bar">External Aliases</h3>
<div class="name-list">
<table summary="aliases">
<% values["aliases"].each do |aliases| $stderr.puts({ :aliases => aliases }.inspect) %>
<table summary="aliases">
<% sections["aliases"].each do |aliases| %>
<tr class="top-aligned-row context-row">
<td class="context-item-name"><%= values["old_name"] %></td>
<td class="context-item-name"><%= aliases["old_name"] %></td>
<td>-&gt;</td>
<td class="context-item-value"><%= values["new_name"] %></td>
<td class="context-item-value"><%= aliases["new_name"] %></td>
</tr>
<% if values["desc"] then %>
<% if aliases["desc"] then %>
<tr class="top-aligned-row context-row">
<td>&nbsp;</td>
<td colspan="2" class="context-item-desc"><%= values["desc"] %></td>
<td colspan="2" class="context-item-desc"><%= aliases["desc"] %></td>
</tr>
<% end %>
<% end # values["aliases"] %>
<% end
end %><%# sections["aliases"] %>
</table>
</div>
</div>
<% end %>
<% end %>
<% if values["attributes"] then %>
<% if sections["attributes"] then %>
<div id="attribute-list">
<h3 class="section-bar">Attributes</h3>
<div class="name-list">
<table>
<% values["attributes"].each do |attributes| $stderr.puts({ :attributes => attributes }.inspect) %>
<% sections["attributes"].each do |attribute| %>
<tr class="top-aligned-row context-row">
<td class="context-item-name"><%= values["name"] %></td>
<% if values["rw"] then %>
<td class="context-item-value">&nbsp;[<%= values["rw"] %>]&nbsp;</td>
<% end %>
<% unless values["rw"] then %>
<td class="context-item-name"><%= attribute["name"] %></td>
<% if attribute["rw"] then %>
<td class="context-item-value">&nbsp;[<%= attribute["rw"] %>]&nbsp;</td>
<% end
unless attribute["rw"] then %>
<td class="context-item-value">&nbsp;&nbsp;</td>
<% end %>
<td class="context-item-desc"><%= values["a_desc"] %></td>
<% end %>
<td class="context-item-desc"><%= attribute["a_desc"] %></td>
</tr>
<% end # values["attributes"] %>
<% end %><%# sections["attributes"] %>
</table>
</div>
</div>
<% end %>
<% end %>
<!-- if method_list -->
<% if sections["method_list"] then %>
<% if sections["method_list"] then %>
<div id="methods">
<% sections["method_list"].each do |method_list| %>
<% if method_list["methods"] then %>
<% sections["method_list"].each do |method_list|
if method_list["methods"] then %>
<h3 class="section-bar"><%= method_list["type"] %> <%= method_list["category"] %> methods</h3>
<% method_list["methods"].each do |methods| %>
<% method_list["methods"].each do |methods| %>
<div id="method-<%= methods["aref"] %>" class="method-detail">
<a name="<%= methods["aref"] %>"></a>
<div class="method-heading">
<% if methods["codeurl"] then %>
<% if methods["codeurl"] then %>
<a href="<%= methods["codeurl"] %>" target="Code" class="method-signature"
onclick="popupCode('<%= methods["codeurl"] %>');return false;">
<% end %>
<% if methods["sourcecode"] then %>
<% end
if methods["sourcecode"] then %>
<a href="#<%= methods["aref"] %>" class="method-signature">
<% end %>
<% if methods["callseq"] then %>
<% end
if methods["callseq"] then %>
<span class="method-name"><%= methods["callseq"] %></span>
<% end %>
<% unless methods["callseq"] then %>
<% end
unless methods["callseq"] then %>
<span class="method-name"><%= methods["name"] %></span><span class="method-args"><%= methods["params"] %></span>
<% end %>
<% if methods["codeurl"] then %>
<% end
if methods["codeurl"] then %>
</a>
<% end %>
<% if methods["sourcecode"] then %>
<% end
if methods["sourcecode"] then %>
</a>
<% end %>
<% end %>
</div>
<div class="method-description">
<% if methods["m_desc"] then %>
<% if methods["m_desc"] then %>
<%= methods["m_desc"] %>
<% end %>
<% if methods["sourcecode"] then %>
<% end
if methods["sourcecode"] then %>
<p><a class="source-toggle" href="#"
onclick="toggleCode('<%= methods["aref"] %>-source');return false;">[Source]</a></p>
<div class="method-source-code" id="<%= methods["aref"] %>-source">
@ -589,17 +583,17 @@ EOF
<%= methods["sourcecode"] %>
</pre>
</div>
<% end %>
<% end %>
</div>
</div>
<% end # method_list["methods"] %>
<% end %>
<% end # sections["method_list"] %>
<% end %><%# method_list["methods"] %><%
end
end %><%# sections["method_list"] %>
</div>
<% end %>
<% end # values["sections"] %>
<% end %>
<% end %><%# values["sections"] %>
EOF
#####################################################################
@ -663,7 +657,7 @@ EOF
<div id="index-entries">
<% values["entries"].each do |entries| %>
<a href="<%= entries["href"] %>"><%= entries["name"] %></a><br />
<% end # values["entries"] %>
<% end %><%# values["entries"] %>
</div>
</div>
</body>

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

@ -119,7 +119,7 @@ body,td,p { font-family: <%= values["fonts"] %>;
<div class="name-list">
<% values["requires"].each do |requires| %>
<%= href requires["aref"], requires["name"] %>
<% end # values["requires"] %>
<% end %><%# values["requires"] %>
<% end %>
</div>
@ -130,7 +130,7 @@ body,td,p { font-family: <%= values["fonts"] %>;
<div class="name-list">
<% values["methods"].each do |methods| %>
<%= href methods["aref"], methods["name"] %>,
<% end # values["methods"] %>
<% end %><%# values["methods"] %>
</div>
<% end %>
@ -162,7 +162,7 @@ body,td,p { font-family: <%= values["fonts"] %>;
<td class="attr-name"><%= attributes["name"] %></td>
<td><%= attributes["a_desc"] %></td>
</tr>
<% end # sections["attributes"] %>
<% end %><%# sections["attributes"] %>
</table>
<% end %>
@ -175,7 +175,7 @@ body,td,p { font-family: <%= values["fonts"] %>;
<%= template_include %> <!-- method descriptions -->
<% end # values["sections"] %>
<% end %><%# values["sections"] %>
</body>
</html>
@ -221,7 +221,7 @@ body,td,p { font-family: <%= values["fonts"] %>;
<% if infiles["cvsurl"] then %>
&nbsp;(<a href="<%= infiles["cvsurl"] %>"><acronym title="Concurrent Versioning System">CVS</acronym></a>)
<% end %>
<% end # values["infiles"] %>
<% end %><%# values["infiles"] %>
</td>
</tr>
<% if values["parent"] then %>
@ -250,7 +250,7 @@ body,td,p { font-family: <%= values["fonts"] %>;
<div class="name-list">
<% values["includes"].each do |includes| %>
<span class="method-name"><%= href includes["aref"], includes["name"] %></span>
<% end # values["includes"] %>
<% end %><%# values["includes"] %>
</div>
<% end %>
@ -285,7 +285,7 @@ body,td,p { font-family: <%= values["fonts"] %>;
This method is also aliased as
<% values["aka"].each do |aka| $stderr.puts({ :aka => aka }.inspect) %>
<a href="<%= values["aref"] %>"><%= values["name"] %></a>
<% end # values["aka"] %>
<% end %><%# values["aka"] %>
</div>
<% end %>
<% if values["sourcecode"] then %>
@ -293,9 +293,9 @@ This method is also aliased as
<%= values["sourcecode"] %>
</pre>
<% end %>
<% end # values["methods"] %>
<% end %><%# values["methods"] %>
<% end %>
<% end # values["method_list"] %>
<% end %><%# values["method_list"] %>
<% end %>
EOF
@ -364,7 +364,7 @@ div.banner {
<div class="banner"><%= values["list_title"] %></div>
<% values["entries"].each do |entries| %>
<a href="<%= entries["href"] %>"><%= entries["name"] %></a><br />
<% end # values["entries"] %>
<% end %><%# values["entries"] %>
</body></html>
EOF

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

@ -17,7 +17,7 @@ module RDoc::Generator::HTML::ONE_PAGE_HTML
<% unless requires["aref"] then %>
<li><%= requires["name"] %></li>
<% end %>
<% end # files["requires"] %>
<% end %><%# files["requires"] %>
</ul>
<% end %>
@ -31,7 +31,7 @@ module RDoc::Generator::HTML::ONE_PAGE_HTML
<% unless includes["aref"] then %>
<li><%= includes["name"] %></li>
<% end %>
<% end # classes["includes"] %>
<% end %><%# classes["includes"] %>
</ul>
<% end %>
@ -42,7 +42,7 @@ module RDoc::Generator::HTML::ONE_PAGE_HTML
<table>
<% sections["attributes"].each do |attributes| %>
<tr><td><%= attributes["name"] %></td><td><%= attributes["rw"] %></td><td><%= attributes["a_desc"] %></td></tr>
<% end # sections["attributes"] %>
<% end %><%# sections["attributes"] %>
</table>
<% end %>
@ -68,11 +68,11 @@ module RDoc::Generator::HTML::ONE_PAGE_HTML
<%= methods["sourcecode"] %>
</pre></blockquote>
<% end %>
<% end # method_list["methods"] %>
<% end %><%# method_list["methods"] %>
<% end %>
<% end # sections["method_list"] %>
<% end %><%# sections["method_list"] %>
<% end %>
<% end # classes["sections"] %>
<% end %><%# classes["sections"] %>
<% end %>
EOF
@ -91,7 +91,7 @@ module RDoc::Generator::HTML::ONE_PAGE_HTML
<tr><td>Modified:</td><td><%= files["dtm_modified"] %></td></tr>
</table>
} + CONTENTS_XML + %{
<% end # values["files"] %>
<% end %><%# values["files"] %>
<% if values["classes"] then %>
<h2>Classes</h2>
@ -107,11 +107,11 @@ module RDoc::Generator::HTML::ONE_PAGE_HTML
(in files
<% classes["infiles"].each do |infiles| %>
<%= href infiles["full_path_url"], infiles["full_path"] %>
<% end # classes["infiles"] %>
<% end %><%# classes["infiles"] %>
)
<% end %>
} + CONTENTS_XML + %{
<% end # values["classes"] %>
<% end %><%# values["classes"] %>
<% end %>
</body>
</html>

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

@ -45,7 +45,7 @@ class RDoc::Generator::RI
def process_class(from_class)
generate_class_info(from_class)
# now recurse into this classes constituent classes
# now recurse into this class' constituent classes
from_class.each_classmodule do |mod|
process_class(mod)
end

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

@ -0,0 +1,84 @@
require 'rdoc/rdoc'
require 'rdoc/generator'
require 'rdoc/markup/to_texinfo'
module RDoc
RDoc::GENERATORS['texinfo'] = RDoc::Generator.new("rdoc/generator/texinfo",
:Texinfo,
'texinfo')
module Generator
# This generates Texinfo files for viewing with GNU Info or Emacs
# from RDoc extracted from Ruby source files.
class Texinfo
# What should the .info file be named by default?
DEFAULT_INFO_FILENAME = 'rdoc.info'
include Generator::MarkUp
# Accept some options
def initialize(options)
@options = options
@options.inline_source = true
@options.op_name ||= 'rdoc.texinfo'
@options.formatter = ::RDoc::Markup::ToTexInfo.new
end
# Generate the +texinfo+ files
def generate(toplevels)
@toplevels = toplevels
@files, @classes = ::RDoc::Generator::Context.build_indicies(@toplevels,
@options)
(@files + @classes).each { |x| x.value_hash }
open(@options.op_name, 'w') do |f|
f.puts TexinfoTemplate.new('files' => @files,
'classes' => @classes,
'filename' => @options.op_name.gsub(/texinfo/, 'info'),
'title' => @options.title).render
end
# TODO: create info files and install?
end
class << self
# Factory? We don't need no stinkin' factory!
alias_method :for, :new
end
end
# Basically just a wrapper around ERB.
# Should probably use RDoc::TemplatePage instead
class TexinfoTemplate
BASE_DIR = ::File.expand_path(::File.dirname(__FILE__)) # have to calculate this when the file's loaded.
def initialize(values, file = 'texinfo.erb')
@v, @file = [values, file]
end
def template
::File.read(::File.join(BASE_DIR, 'texinfo', @file))
end
# Go!
def render
ERB.new(template).result binding
end
def href(location, text)
text # TODO: how does texinfo do hyperlinks?
end
def target(name, text)
text # TODO: how do hyperlink targets work?
end
# TODO: this is probably implemented elsewhere?
def method_prefix(section)
{ 'Class' => '.',
'Module' => '::',
'Instance' => '#',
}[section['category']]
end
end
end
end

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

@ -0,0 +1,44 @@
@node <%= @v['class']['full_name'].gsub(/::/, '-') %>
@chapter <%= @v['class']["classmod"] %> <%= @v['class']['full_name'] %>
<% if @v['class']["parent"] and @v['class']['par_url'] %>
Inherits <%= href @v['class']["par_url"], @v['class']["parent"] %><% end %>
<%= @v['class']["description"] %>
<% if @v['class']["includes"] %>
Includes
<% @v['class']["includes"].each do |include| %>
* <%= href include["aref"], include["name"] %>
<% end # @v['class']["includes"] %>
<% end %>
<% if @v['class']["sections"] %>
<% @v['class']["sections"].each do |section| %>
<% if section["attributes"] %>
Attributes
<% section["attributes"].each do |attributes| %>
* <%= attributes["name"] %> <%= attributes["rw"] %> <%= attributes["a_desc"] %>
<% end # section["attributes"] %>
<% end %>
<% end %>
<% @v['class']["sections"].each do |section| %>
<% if section["method_list"] %>
Methods
@menu
<% section["method_list"].each_with_index do |method_list, i| %>
<%= i %>
<% (method_list["methods"] || []).each do |method| %>
* <%= @v['class']['full_name'].gsub(/::/, '-') %><%= method_prefix method_list %><%= method['name'] %>::<% end %>
<% end %>
@end menu
<% section["method_list"].each do |method_list| %>
<% (method_list["methods"] || []).uniq.each do |method| %>
<%= TexinfoTemplate.new(@v.merge({'method' => method, 'list' => method_list}),
'method.texinfo.erb').render %><% end %>
<% end # section["method_list"] %>
<% end %>
<% end # @v['class']["sections"] %>
<% end %>

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

@ -0,0 +1,6 @@
<% if false %>
<h2>File: <%= @v['file']["short_name"] %></h2>
Path: <%= @v['file']["full_path"] %>
<%= TexinfoTemplate.new(@v, 'content.texinfo.erb').render %>
<% end %>

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

@ -0,0 +1,6 @@
@node <%= @v['class']['full_name'].gsub(/::/, '-') %><%= method_prefix @v['list'] %><%= @v['method']['name'] %>
@section <%= @v['class']["classmod"] %> <%= @v['class']['full_name'] %><%= method_prefix @v['list'] %><%= @v['method']['name'] %>
<%= @v['method']["type"] %> <%= @v['method']["category"] %> method:
<%= target @v['method']["aref"], @v['method']['callseq'] ||
@v['method']["name"] + @v['method']["params"] %>
<%= @v['method']["m_desc"] %>

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

@ -0,0 +1,28 @@
\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename <%= @v['filename'] %>
@settitle <%= @v['title'] %>
@c %**end of header
@contents @c TODO: whitespace is a mess... =\
@ifnottex
@node Top
@top <%= @v['title'] %>
@end ifnottex
<% if @f = @v['files'].detect { |f| f.name =~ /Readme/i } %>
<%= @f.values['description'] %><% end %>
@menu
<% @v['classes'].each do |klass| %>
* <%= klass.name.gsub(/::/, '-') %>::<% end %>
@c TODO: add files
@end menu
<% (@v['classes'] || []).each_with_index do |klass, i| %>
<%= TexinfoTemplate.new(@v.merge('class' => klass.values),
'class.texinfo.erb').render %><% end %>
@bye

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

@ -0,0 +1,69 @@
module RDoc
##
# Ruby's built-in classes, modules and exceptions
KNOWN_CLASSES = {
"rb_cArray" => "Array",
"rb_cBignum" => "Bignum",
"rb_cClass" => "Class",
"rb_cData" => "Data",
"rb_cDir" => "Dir",
"rb_cFalseClass" => "FalseClass",
"rb_cFile" => "File",
"rb_cFixnum" => "Fixnum",
"rb_cFloat" => "Float",
"rb_cHash" => "Hash",
"rb_cIO" => "IO",
"rb_cInteger" => "Integer",
"rb_cModule" => "Module",
"rb_cNilClass" => "NilClass",
"rb_cNumeric" => "Numeric",
"rb_cObject" => "Object",
"rb_cProc" => "Proc",
"rb_cRange" => "Range",
"rb_cRegexp" => "Regexp",
"rb_cRubyVM" => "RubyVM",
"rb_cString" => "String",
"rb_cStruct" => "Struct",
"rb_cSymbol" => "Symbol",
"rb_cThread" => "Thread",
"rb_cTime" => "Time",
"rb_cTrueClass" => "TrueClass",
"rb_eArgError" => "ArgError",
"rb_eEOFError" => "EOFError",
"rb_eException" => "Exception",
"rb_eFatal" => "Fatal",
"rb_eFloatDomainError" => "FloatDomainError",
"rb_eIOError" => "IOError",
"rb_eIndexError" => "IndexError",
"rb_eInterrupt" => "Interrupt",
"rb_eLoadError" => "LoadError",
"rb_eNameError" => "NameError",
"rb_eNoMemError" => "NoMemError",
"rb_eNotImpError" => "NotImpError",
"rb_eRangeError" => "RangeError",
"rb_eRuntimeError" => "RuntimeError",
"rb_eScriptError" => "ScriptError",
"rb_eSecurityError" => "SecurityError",
"rb_eSignal" => "Signal",
"rb_eStandardError" => "StandardError",
"rb_eSyntaxError" => "SyntaxError",
"rb_eSystemCallError" => "SystemCallError",
"rb_eSystemExit" => "SystemExit",
"rb_eTypeError" => "TypeError",
"rb_eZeroDivError" => "ZeroDivError",
"rb_mComparable" => "Comparable",
"rb_mEnumerable" => "Enumerable",
"rb_mErrno" => "Errno",
"rb_mFileTest" => "FileTest",
"rb_mGC" => "GC",
"rb_mKernel" => "Kernel",
"rb_mMath" => "Math",
"rb_mPrecision" => "Precision",
"rb_mProcess" => "Process"
}
end

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

@ -144,8 +144,6 @@ class RDoc::Markup::AttributeManager
add_html("b", :BOLD)
add_html("tt", :TT)
add_html("code", :TT)
add_special(/<!--(.*?)-->/, :COMMENT)
end
def add_word_pair(start, stop, name)

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

@ -11,8 +11,8 @@ class RDoc::Markup
attr_reader :level, :param, :txt
attr_accessor :type
######
# This is a simple factory system that lets us associate fragment
##
# This is a simple factory system that lets us associate fragement
# types (a string) with a subclass of fragment
TYPE_MAP = {}

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

@ -14,21 +14,25 @@ class RDoc::Markup::PreProcess
##
# Look for common options in a chunk of text. Options that we don't handle
# are passed back to our caller as |directive, param|
# are yielded to the caller.
def handle(text)
text.gsub!(/^([ \t#]*):(\w+):\s*(.+)?\n/) do
text.gsub!(/^([ \t]*#?[ \t]*):(\w+):([ \t]*)(.+)?\n/) do
next $& if $3.empty? and $4 and $4[0, 1] == ':'
prefix = $1
directive = $2.downcase
param = $3
param = $4
case directive
when "include"
when 'include' then
filename = param.split[0]
include_file(filename, prefix)
include_file filename, prefix
else
yield(directive, param)
result = yield directive, param
result = "#{prefix}:#{directive}: #{param}\n" unless result
result
end
end
end

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

@ -1,7 +1,6 @@
require 'rdoc/markup/formatter'
require 'rdoc/markup/fragments'
require 'rdoc/markup/inline'
require 'rdoc/generator'
require 'cgi'
@ -21,6 +20,11 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
def initialize
super
# @in_tt - tt nested levels count
# @tt_bit - cache
@in_tt = 0
@tt_bit = RDoc::Markup::Attribute.bitmap_for :TT
# external hyperlinks
@markup.add_special(/((link:|https?:|mailto:|ftp:|www\.)\S+\w)/, :HYPERLINK)
@ -30,6 +34,27 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
init_tags
end
##
# Converts a target url to one that is relative to a given path
def self.gen_relative_url(path, target)
from = File.dirname path
to, to_file = File.split target
from = from.split "/"
to = to.split "/"
while from.size > 0 and to.size > 0 and from[0] == to[0] do
from.shift
to.shift
end
from.fill ".."
from.concat to
from << to_file
File.join(*from)
end
##
# Generate a hyperlink for url, labeled with text. Handle the
# special cases for img: and link: described under handle_special_HYPEDLINK
@ -48,7 +73,7 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
url = if path[0, 1] == '#' then # is this meaningful?
path
else
RDoc::Generator.gen_url @from_path, path
self.class.gen_relative_url @from_path, path
end
end
@ -87,6 +112,20 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
gen_url url, label
end
##
# are we currently inside <tt> tags?
def in_tt?
@in_tt > 0
end
##
# is +tag+ a <tt> tag?
def tt?(tag)
tag.bit == @tt_bit
end
##
# Set up the standard mapping of attributes to HTML tags
@ -216,6 +255,7 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
@attr_tags.each do |tag|
if attr_mask & tag.bit != 0
res << annotate(tag.on)
@in_tt += 1 if tt?(tag)
end
end
end
@ -226,6 +266,7 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
@attr_tags.reverse_each do |tag|
if attr_mask & tag.bit != 0
@in_tt -= 1 if tt?(tag)
res << annotate(tag.off)
end
end
@ -251,27 +292,33 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
res
end
def convert_string(item)
in_tt? ? convert_string_simple(item) : convert_string_fancy(item)
end
def convert_string_simple(item)
CGI.escapeHTML item
end
##
# some of these patterns are taken from SmartyPants...
def convert_string(item)
CGI.escapeHTML(item).
def convert_string_fancy(item)
# convert -- to em-dash, (-- to en-dash)
gsub(/---?/, '&#8212;'). #gsub(/--/, '&#8211;').
item.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{([^ \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;').
gsub(%r{([^ \t\r\n\[\{\(])\'(?=\W)}, '\1&#8221;'). # }
# convert double opening quote
gsub(/'/, '&#8220;').
@ -281,7 +328,6 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
# convert and registered trademark
gsub(/\(r\)/, '&#174;')
end
def convert_special(special)

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

@ -14,6 +14,7 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
# correct relative paths for any hyperlinks that we find
def initialize(from_path, context, show_hash)
raise ArgumentError, 'from_path cannot be nil' if from_path.nil?
super()
# class names, variable names, or instance variables
@ -47,28 +48,43 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
def handle_special_CROSSREF(special)
name = special.text
return name if name =~ /\A[a-z]*\z/
return @seen[name] if @seen.include? name
if name[0,1] == '#' then
if name[0, 1] == '#' then
lookup = name[1..-1]
name = lookup unless @show_hash
else
lookup = name
end
# Find class, module, or method in class or module.
if /([A-Z]\w*)[.\#](\w+[!?=]?)/ =~ lookup then
#
# Do not, however, use an if/elsif/else chain to do so. Instead, test
# each possible pattern until one matches. The reason for this is that a
# string like "YAML.txt" could be the txt() class method of class YAML (in
# which case it would match the first pattern, which splits the string
# into container and method components and looks up both) or a filename
# (in which case it would match the last pattern, which just checks
# whether the string as a whole is a known symbol).
if /([A-Z][\w:]*)[.\#](\w+[!?=]?)/ =~ lookup then
container = $1
method = $2
ref = @context.find_symbol container, method
elsif /([A-Za-z]\w*)[.\#](\w+(\([\.\w+\*\/\+\-\=\<\>]+\))?)/ =~ lookup then
container = $1
method = $2
ref = @context.find_symbol container, method
else
ref = @context.find_symbol lookup
end
if !ref and
/([A-Za-z][\w:]*)[.\#](\w+(\([\.\w+\*\/\+\-\=\<\>]+\))?)/ =~ lookup then
container = $1
method = $2
ref = @context.find_symbol container, method
end
ref = @context.find_symbol lookup unless ref
out = if lookup =~ /^\\/ then
$'
elsif ref and ref.document_self then

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

@ -0,0 +1,69 @@
require 'rdoc/markup/formatter'
require 'rdoc/markup/fragments'
require 'rdoc/markup/inline'
require 'rdoc/markup'
require 'rdoc/markup/formatter'
##
# Convert SimpleMarkup to basic TexInfo format
#
# TODO: WTF is AttributeManager for?
#
class RDoc::Markup::ToTexInfo < RDoc::Markup::Formatter
def start_accepting
@text = []
end
def end_accepting
@text.join("\n")
end
def accept_paragraph(attributes, text)
@text << format(text)
end
def accept_verbatim(attributes, text)
@text << "@verb{|#{format(text)}|}"
end
def accept_heading(attributes, text)
heading = ['@majorheading', '@chapheading'][text.head_level - 1] || '@heading'
@text << "#{heading}{#{format(text)}}"
end
def accept_list_start(attributes, text)
@text << '@itemize @bullet'
end
def accept_list_end(attributes, text)
@text << '@end itemize'
end
def accept_list_item(attributes, text)
@text << "@item\n#{format(text)}"
end
def accept_blank_line(attributes, text)
@text << "\n"
end
def accept_rule(attributes, text)
@text << '-----'
end
def format(text)
text.txt.
gsub(/@/, "@@").
gsub(/\{/, "@{").
gsub(/\}/, "@}").
# gsub(/,/, "@,"). # technically only required in cross-refs
gsub(/\+([\w]+)\+/, "@code{\\1}").
gsub(/\<tt\>([^<]+)\<\/tt\>/, "@code{\\1}").
gsub(/\*([\w]+)\*/, "@strong{\\1}").
gsub(/\<b\>([^<]+)\<\/b\>/, "@strong{\\1}").
gsub(/_([\w]+)_/, "@emph{\\1}").
gsub(/\<em\>([^<]+)\<\/em\>/, "@emph{\\1}")
end
end

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

@ -39,7 +39,7 @@ class RDoc::Options
##
# Pattern for additional attr_... style methods
attr_reader :extra_accessors
attr_accessor :extra_accessors
##
# Should we draw fileboxes in diagrams
@ -61,6 +61,11 @@ class RDoc::Options
attr_accessor :generator
##
# Formatter to mark up text with
attr_accessor :formatter
##
# image format for diagrams
@ -95,7 +100,7 @@ class RDoc::Options
##
# The name to use for the output
attr_reader :op_name
attr_accessor :op_name
##
# Are we promiscuous about showing module contents across multiple files
@ -105,7 +110,7 @@ class RDoc::Options
##
# Don't display progress as we process the files
attr_reader :quiet
attr_accessor :quiet
##
# Array of directories to search for files to satisfy an :include:
@ -175,7 +180,6 @@ class RDoc::Options
@extra_accessor_flags = {}
@promiscuous = false
@force_update = false
@title = "RDoc Documentation"
@css = nil
@webcvs = nil
@ -513,6 +517,8 @@ Usage: #{opt.program_name} [options] [names...]
end
end
argv.insert(0, *ENV['RDOCOPT'].split) if ENV['RDOCOPT']
opts.parse! argv
@files = argv.dup

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

@ -0,0 +1,109 @@
require 'rdoc'
require 'rdoc/code_objects'
require 'rdoc/markup/preprocess'
require 'rdoc/stats'
##
# A parser is simple a class that implements
#
# #initialize(file_name, body, options)
#
# and
#
# #scan
#
# The initialize method takes a file name to be used, the body of the file,
# and an RDoc::Options object. The scan method is then called to return an
# appropriately parsed TopLevel code object.
#
# The ParseFactory is used to redirect to the correct parser given a
# filename extension. This magic works because individual parsers have to
# register themselves with us as they are loaded in. The do this using the
# following incantation
#
# require "rdoc/parser"
#
# class RDoc::Parser::Xyz < RDoc::Parser
# parse_files_matching /\.xyz$/ # <<<<
#
# def initialize(file_name, body, options)
# ...
# end
#
# def scan
# ...
# end
# end
#
# Just to make life interesting, if we suspect a plain text file, we also
# look for a shebang line just in case it's a potential shell script
class RDoc::Parser
@parsers = []
class << self
attr_reader :parsers
end
attr_writer :progress
##
# Alias an extension to another extension. After this call, files ending
# "new_ext" will be parsed using the same parser as "old_ext"
def self.alias_extension(old_ext, new_ext)
parser = can_parse "xxx.#{old_ext}"
return false unless parser
RDoc::Parser.parsers.unshift [/\.#{new_ext}$/, parser.last]
true
end
##
# Return a parser that can handle a particular extension
def self.can_parse(file_name)
RDoc::Parser.parsers.find { |regexp, parser| regexp =~ file_name }.last
end
##
# Find the correct parser for a particular file name. Return a SimpleParser
# for ones that we don't know
def self.for(top_level, file_name, body, options, stats)
# If no extension, look for shebang
if file_name !~ /\.\w+$/ && body =~ %r{\A#!(.+)} then
shebang = $1
case shebang
when %r{env\s+ruby}, %r{/ruby}
file_name = "dummy.rb"
end
end
parser = can_parse file_name
parser.new top_level, file_name, body, options, stats
end
##
# Record which file types this parser can understand.
def self.parse_files_matching(regexp)
RDoc::Parser.parsers.unshift [regexp, self]
end
def initialize(top_level, file_name, content, options, stats)
@top_level = top_level
@file_name = file_name
@content = content
@options = options
@stats = stats
@progress = $stderr unless options.quiet
end
end
require 'rdoc/parser/simple'

666
lib/rdoc/parser/c.rb Normal file
Просмотреть файл

@ -0,0 +1,666 @@
require 'rdoc/parser'
require 'rdoc/known_classes'
##
# We attempt to parse C extension files. Basically we look 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
# C source for the methods and extract comments, but if we fail
# we don't worry too much.
#
# The comments associated with a Ruby method are extracted from the C
# comment block associated with the routine that _implements_ that
# method, that is to say the method whose name is given in the
# <tt>rb_define_method</tt> call. For example, you might write:
#
# /*
# * Returns a new array that is a one-dimensional flattening of this
# * array (recursively). That is, for every element that is an array,
# * extract its elements into the new array.
# *
# * s = [ 1, 2, 3 ] #=> [1, 2, 3]
# * t = [ 4, 5, 6, [7, 8] ] #=> [4, 5, 6, [7, 8]]
# * a = [ s, t, 9, 10 ] #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10]
# * a.flatten #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# */
# static VALUE
# rb_ary_flatten(ary)
# VALUE ary;
# {
# ary = rb_obj_dup(ary);
# rb_ary_flatten_bang(ary);
# return ary;
# }
#
# ...
#
# void
# Init_Array()
# {
# ...
# rb_define_method(rb_cArray, "flatten", rb_ary_flatten, 0);
#
# Here RDoc will determine from the rb_define_method line that there's a
# method called "flatten" in class Array, and will look for the implementation
# in the method rb_ary_flatten. It will then use the comment from that
# method in the HTML output. This method must be in the same source file
# as the rb_define_method.
#
# C classes can be diagrammed (see /tc/dl/ruby/ruby/error.c), and RDoc
# integrates C and Ruby source into one tree
#
# 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-method: <i>name</i>]
# This comment documents the named method. Use when RDoc cannot
# automatically find the method from it's declaration
#
# [call-seq: <i>text up to an empty line</i>]
# Because C source doesn't give descripive names to Ruby-level parameters,
# you need to document the calling sequence explicitly
#
# In addition, RDoc assumes by default that the C method implementing a
# Ruby function is in the same source file as the rb_define_method call.
# If this isn't the case, add the comment:
#
# rb_define_method(....); // in: filename
#
# As an example, we might have an extension that defines multiple classes
# in its Init_xxx method. We could document them using
#
# /*
# * Document-class: MyClass
# *
# * Encapsulate the writing and reading of the configuration
# * file. ...
# */
#
# /*
# * Document-method: read_value
# *
# * call-seq:
# * cfg.read_value(key) -> value
# * cfg.read_value(key} { |key| } -> value
# *
# * Return the value corresponding to +key+ from the configuration.
# * In the second form, if the key isn't found, invoke the
# * block and return its value.
# */
class RDoc::Parser::C < RDoc::Parser
parse_files_matching(/\.(?:([CcHh])\1?|c([+xp])\2|y)\z/)
attr_writer :progress
@@enclosure_classes = {}
@@known_bodies = {}
##
# Prepare to parse a C file
def initialize(top_level, file_name, content, options, stats)
super
@known_classes = RDoc::KNOWN_CLASSES.dup
@content = handle_tab_width handle_ifdefs_in(@content)
@classes = Hash.new
@file_dir = File.dirname(@file_name)
end
def do_aliases
@content.scan(%r{rb_define_alias\s*\(\s*(\w+),\s*"([^"]+)",\s*"([^"]+)"\s*\)}m) do
|var_name, new_name, old_name|
@stats.num_methods += 1
class_name = @known_classes[var_name] || var_name
class_obj = find_class(var_name, class_name)
class_obj.add_alias RDoc::Alias.new("", old_name, new_name, "")
end
end
def do_classes
@content.scan(/(\w+)\s* = \s*rb_define_module\s*\(\s*"(\w+)"\s*\)/mx) do
|var_name, class_name|
handle_class_module(var_name, "module", class_name, nil, nil)
end
# The '.' lets us handle SWIG-generated files
@content.scan(/([\w\.]+)\s* = \s*rb_define_class\s*
\(
\s*"(\w+)",
\s*(\w+)\s*
\)/mx) do |var_name, class_name, parent|
handle_class_module(var_name, "class", class_name, parent, nil)
end
@content.scan(/(\w+)\s*=\s*boot_defclass\s*\(\s*"(\w+?)",\s*(\w+?)\s*\)/) do
|var_name, class_name, parent|
parent = nil if parent == "0"
handle_class_module(var_name, "class", class_name, parent, nil)
end
@content.scan(/(\w+)\s* = \s*rb_define_module_under\s*
\(
\s*(\w+),
\s*"(\w+)"
\s*\)/mx) do |var_name, in_module, class_name|
handle_class_module(var_name, "module", class_name, nil, in_module)
end
@content.scan(/([\w\.]+)\s* = \s*rb_define_class_under\s*
\(
\s*(\w+),
\s*"(\w+)",
\s*(\w+)\s*
\s*\)/mx) do |var_name, in_module, class_name, parent|
handle_class_module(var_name, "class", class_name, parent, in_module)
end
end
def do_constants
@content.scan(%r{\Wrb_define_
(
variable |
readonly_variable |
const |
global_const |
)
\s*\(
(?:\s*(\w+),)?
\s*"(\w+)",
\s*(.*?)\s*\)\s*;
}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);
def do_includes
@content.scan(/rb_include_module\s*\(\s*(\w+?),\s*(\w+?)\s*\)/) do |c,m|
if cls = @classes[c]
m = @known_classes[m] || m
cls.add_include RDoc::Include.new(m, "")
end
end
end
def do_methods
@content.scan(%r{rb_define_
(
singleton_method |
method |
module_function |
private_method
)
\s*\(\s*([\w\.]+),
\s*"([^"]+)",
\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|
# Ignore top-object and weird struct.c dynamic stuff
next if var_name == "ruby_top_self"
next if var_name == "nstr"
next if var_name == "envtbl"
next if var_name == "argf" # it'd be nice to handle this one
var_name = "rb_cObject" if var_name == "rb_mKernel"
handle_method(type, var_name, meth_name,
meth_body, param_count, 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*\(
\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|
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|
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
$1
elsif @content =~ %r{Document-attr:\s#{attr_name}\s*?\n((?>.*?\*/))}m
$1
else
''
end
end
##
# Find the C code corresponding to a Ruby method
def find_body(meth_name, meth_obj, body, quiet = false)
case body
when %r"((?>/\*.*?\*/\s*))(?:static\s+)?VALUE\s+#{meth_name}
\s*(\([^)]*\))\s*\{.*?^\}"xm
comment, params = $1, $2
body_text = $&
remove_private_comments(comment) if comment
# see if we can find the whole body
re = Regexp.escape(body_text) + '[^(]*^\{.*?^\}'
if Regexp.new(re, Regexp::MULTILINE).match(body)
body_text = $&
end
# The comment block may have been overridden with a 'Document-method'
# block. This happens in the interpreter when multiple methods are
# vectored through to the same C method but those methods are logically
# distinct (for example Kernel.hash and Kernel.object_id share the same
# implementation
override_comment = find_override_comment(meth_obj.name)
comment = override_comment if override_comment
find_modifiers(comment, meth_obj) if comment
# meth_obj.params = params
meth_obj.start_collecting_tokens
meth_obj.add_token(RDoc::RubyToken::Token.new(1,1).set_text(body_text))
meth_obj.comment = mangle_comment(comment)
when %r{((?>/\*.*?\*/\s*))^\s*\#\s*define\s+#{meth_name}\s+(\w+)}m
comment = $1
find_body($2, meth_obj, body, true)
find_modifiers(comment, meth_obj)
meth_obj.comment = mangle_comment(comment) + meth_obj.comment
when %r{^\s*\#\s*define\s+#{meth_name}\s+(\w+)}m
unless find_body($1, meth_obj, body, true)
warn "No definition for #{meth_name}" unless quiet
return false
end
else
# No body, but might still have an override comment
comment = find_override_comment(meth_obj.name)
if comment
find_modifiers(comment, meth_obj)
meth_obj.comment = mangle_comment(comment)
else
warn "No definition for #{meth_name}" unless quiet
return false
end
end
true
end
def find_class(raw_name, name)
unless @classes[raw_name]
if raw_name =~ /^rb_m/
container = @top_level.add_module RDoc::NormalModule, name
else
container = @top_level.add_class RDoc::NormalClass, name, nil
end
container.record_location @top_level
@classes[raw_name] = container
end
@classes[raw_name]
end
##
# Look for class or module documentation above Init_+class_name+(void),
# in a Document-class +class_name+ (or module) comment or above an
# rb_define_class (or module). If a comment is supplied above a matching
# Init_ and a rb_define_class the Init_ comment is used.
#
# /*
# * This is a comment for Foo
# */
# Init_Foo(void) {
# VALUE cFoo = rb_define_class("Foo", rb_cObject);
# }
#
# /*
# * Document-class: Foo
# * This is a comment for Foo
# */
# Init_foo(void) {
# VALUE cFoo = rb_define_class("Foo", rb_cObject);
# }
#
# /*
# * This is a comment for Foo
# */
# VALUE cFoo = rb_define_class("Foo", rb_cObject);
def find_class_comment(class_name, class_meth)
comment = nil
if @content =~ %r{((?>/\*.*?\*/\s+))
(static\s+)?void\s+Init_#{class_name}\s*(?:_\(\s*)?\(\s*(?:void\s*)\)}xmi
comment = $1
elsif @content =~ %r{Document-(class|module):\s#{class_name}\s*?\n((?>.*?\*/))}m
comment = $2
else
if @content =~ /rb_define_(class|module)/m then
class_name = class_name.split("::").last
comments = []
@content.split(/(\/\*.*?\*\/)\s*?\n/m).each_with_index do |chunk, index|
comments[index] = chunk
if chunk =~ /rb_define_(class|module).*?"(#{class_name})"/m then
comment = comments[index-1]
break
end
end
end
end
class_meth.comment = mangle_comment(comment) if comment
end
##
# Finds a comment matching +type+ and +const_name+ either above the
# 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
$1
elsif @content =~ %r{Document-(?:const|global|variable):\s#{const_name}\s*?\n((?>.*?\*/))}m
$1
else
''
end
end
##
# If the comment block contains a section that looks like:
#
# call-seq:
# Array.new
# Array.new(10)
#
# use it for the parameters.
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*/, '')
meth_obj.call_seq = seq
end
end
def find_override_comment(meth_name)
name = Regexp.escape(meth_name)
if @content =~ %r{Document-method:\s#{name}\s*?\n((?>.*?\*/))}m
$1
end
end
def handle_attr(var_name, attr_name, reader, writer)
rw = ''
if reader
#@stats.num_methods += 1
rw << 'R'
end
if writer
#@stats.num_methods += 1
rw << 'W'
end
class_name = @known_classes[var_name]
return unless class_name
class_obj = find_class(var_name, class_name)
if class_obj
comment = find_attr_comment(attr_name)
unless comment.empty?
comment = mangle_comment(comment)
end
att = RDoc::Attr.new '', attr_name, rw, comment
class_obj.add_attribute(att)
end
end
def handle_class_module(var_name, class_mod, class_name, parent, in_module)
progress(class_mod[0, 1])
parent_name = @known_classes[parent] || parent
if in_module
enclosure = @classes[in_module] || @@enclosure_classes[in_module]
unless enclosure
if enclosure = @known_classes[in_module]
handle_class_module(in_module, (/^rb_m/ =~ in_module ? "module" : "class"),
enclosure, nil, nil)
enclosure = @classes[in_module]
end
end
unless enclosure
warn("Enclosing class/module '#{in_module}' for " +
"#{class_mod} #{class_name} not known")
return
end
else
enclosure = @top_level
end
if class_mod == "class"
cm = enclosure.add_class RDoc::NormalClass, class_name, parent_name
@stats.num_classes += 1
else
cm = enclosure.add_module RDoc::NormalModule, class_name
@stats.num_modules += 1
end
cm.record_location(enclosure.toplevel)
find_class_comment(cm.full_name, cm)
@classes[var_name] = cm
@@enclosure_classes[var_name] = cm
@known_classes[var_name] = cm.full_name
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.
#
# /* 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 (\:).
def handle_constants(type, var_name, const_name, definition)
#@stats.num_constants += 1
class_name = @known_classes[var_name]
return unless class_name
class_obj = find_class(var_name, class_name)
unless class_obj
warn("Enclosing class/module '#{const_name}' for not known")
return
end
comment = find_const_comment(type, const_name)
# In the case of rb_define_const, the definition and comment are in
# "/* definition: comment */" form. The literal ':' and '\' characters
# can be escaped with a backslash.
if type.downcase == 'const' then
elements = mangle_comment(comment).split(':')
if elements.nil? or elements.empty? then
con = RDoc::Constant.new(const_name, definition,
mangle_comment(comment))
else
new_definition = elements[0..-2].join(':')
if new_definition.empty? then # Default to literal C definition
new_definition = definition
else
new_definition.gsub!("\:", ":")
new_definition.gsub!("\\", '\\')
end
new_definition.sub!(/\A(\s+)/, '')
new_comment = $1.nil? ? elements.last : "#{$1}#{elements.last.lstrip}"
con = RDoc::Constant.new(const_name, new_definition,
mangle_comment(new_comment))
end
else
con = RDoc::Constant.new const_name, definition, mangle_comment(comment)
end
class_obj.add_constant(con)
end
##
# Removes #ifdefs that would otherwise confuse us
def handle_ifdefs_in(body)
body.gsub(/^#ifdef HAVE_PROTOTYPES.*?#else.*?\n(.*?)#endif.*?\n/m, '\1')
end
def handle_method(type, var_name, meth_name, meth_body, param_count,
source_file = nil)
progress(".")
@stats.num_methods += 1
class_name = @known_classes[var_name]
return unless class_name
class_obj = find_class(var_name, class_name)
if class_obj
if meth_name == "initialize"
meth_name = "new"
type = "singleton_method"
end
meth_obj = RDoc::AnyMethod.new("", meth_name)
meth_obj.singleton =
%w{singleton_method module_function}.include?(type)
p_count = (Integer(param_count) rescue -1)
if p_count < 0
meth_obj.params = "(...)"
elsif p_count == 0
meth_obj.params = "()"
else
meth_obj.params = "(" + (1..p_count).map{|i| "p#{i}"}.join(", ") + ")"
end
if source_file
file_name = File.join(@file_dir, source_file)
body = (@@known_bodies[source_file] ||= File.read(file_name))
else
body = @content
end
if find_body(meth_body, meth_obj, body) and meth_obj.document_self
class_obj.add_method(meth_obj)
end
end
end
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)} && $~ #`
line
end .join("\n")
else
body
end
end
##
# Remove the /*'s and leading asterisks from C comments
def mangle_comment(comment)
comment.sub!(%r{/\*+}) { " " * $&.length }
comment.sub!(%r{\*+/}) { " " * $&.length }
comment.gsub!(/^[ \t]*\*/m) { " " * $&.length }
comment
end
def progress(char)
unless @options.quiet
@progress.print(char)
@progress.flush
end
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_}, '//')
end
def remove_private_comments(comment)
comment.gsub!(/\/?\*--(.*?)\/?\*\+\+/m, '')
comment.sub!(/\/?\*--.*/m, '')
end
##
# Extract the classes/modules and methods from a C file and return the
# corresponding top-level object
def scan
remove_commented_out_lines
do_classes
do_constants
do_methods
do_includes
do_aliases
@top_level
end
def warn(msg)
$stderr.puts
$stderr.puts msg
$stderr.flush
end
end

1837
lib/rdoc/parser/f95.rb Normal file

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

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

38
lib/rdoc/parser/simple.rb Normal file
Просмотреть файл

@ -0,0 +1,38 @@
require 'rdoc/parser'
##
# Parse a non-source file. We basically take the whole thing as one big
# comment. If the first character in the file is '#', we strip leading pound
# signs.
class RDoc::Parser::Simple < RDoc::Parser
parse_files_matching(//)
##
# Prepare to parse a plain 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 file contents and attach them to the toplevel as a comment
def scan
@top_level.comment = remove_private_comments(@content)
@top_level
end
def remove_private_comments(comment)
comment.gsub(/^--[^-].*?^\+\+/m, '').sub(/^--.*/m, '')
end
end

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

@ -1,775 +0,0 @@
# Classes and modules built in to the interpreter. We need
# these to define superclasses of user objects
require "rdoc/code_objects"
require "rdoc/parsers/parserfactory"
require "rdoc/rdoc"
module RDoc
##
# Ruby's built-in classes.
KNOWN_CLASSES = {
"rb_cObject" => "Object",
"rb_cArray" => "Array",
"rb_cBignum" => "Bignum",
"rb_cClass" => "Class",
"rb_cDir" => "Dir",
"rb_cData" => "Data",
"rb_cFalseClass" => "FalseClass",
"rb_cFile" => "File",
"rb_cFixnum" => "Fixnum",
"rb_cFloat" => "Float",
"rb_cHash" => "Hash",
"rb_cInteger" => "Integer",
"rb_cIO" => "IO",
"rb_cModule" => "Module",
"rb_cNilClass" => "NilClass",
"rb_cNumeric" => "Numeric",
"rb_cProc" => "Proc",
"rb_cRange" => "Range",
"rb_cRegexp" => "Regexp",
"rb_cString" => "String",
"rb_cSymbol" => "Symbol",
"rb_cThread" => "Thread",
"rb_cTime" => "Time",
"rb_cTrueClass" => "TrueClass",
"rb_cStruct" => "Struct",
"rb_cRubyVM" => "RubyVM",
"rb_eException" => "Exception",
"rb_eStandardError" => "StandardError",
"rb_eSystemExit" => "SystemExit",
"rb_eInterrupt" => "Interrupt",
"rb_eSignal" => "Signal",
"rb_eFatal" => "Fatal",
"rb_eArgError" => "ArgError",
"rb_eEOFError" => "EOFError",
"rb_eIndexError" => "IndexError",
"rb_eRangeError" => "RangeError",
"rb_eIOError" => "IOError",
"rb_eRuntimeError" => "RuntimeError",
"rb_eSecurityError" => "SecurityError",
"rb_eSystemCallError" => "SystemCallError",
"rb_eTypeError" => "TypeError",
"rb_eZeroDivError" => "ZeroDivError",
"rb_eNotImpError" => "NotImpError",
"rb_eNoMemError" => "NoMemError",
"rb_eFloatDomainError" => "FloatDomainError",
"rb_eScriptError" => "ScriptError",
"rb_eNameError" => "NameError",
"rb_eSyntaxError" => "SyntaxError",
"rb_eLoadError" => "LoadError",
"rb_mKernel" => "Kernel",
"rb_mComparable" => "Comparable",
"rb_mEnumerable" => "Enumerable",
"rb_mPrecision" => "Precision",
"rb_mErrno" => "Errno",
"rb_mFileTest" => "FileTest",
"rb_mGC" => "GC",
"rb_mMath" => "Math",
"rb_mProcess" => "Process"
}
##
# We attempt to parse C extension files. Basically we look 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
# C source for the methods and extract comments, but if we fail
# we don't worry too much.
#
# The comments associated with a Ruby method are extracted from the C
# comment block associated with the routine that _implements_ that
# method, that is to say the method whose name is given in the
# <tt>rb_define_method</tt> call. For example, you might write:
#
# /*
# * Returns a new array that is a one-dimensional flattening of this
# * array (recursively). That is, for every element that is an array,
# * extract its elements into the new array.
# *
# * s = [ 1, 2, 3 ] #=> [1, 2, 3]
# * t = [ 4, 5, 6, [7, 8] ] #=> [4, 5, 6, [7, 8]]
# * a = [ s, t, 9, 10 ] #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10]
# * a.flatten #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# */
# static VALUE
# rb_ary_flatten(ary)
# VALUE ary;
# {
# ary = rb_obj_dup(ary);
# rb_ary_flatten_bang(ary);
# return ary;
# }
#
# ...
#
# void
# Init_Array()
# {
# ...
# rb_define_method(rb_cArray, "flatten", rb_ary_flatten, 0);
#
# Here RDoc will determine from the rb_define_method line that there's a
# method called "flatten" in class Array, and will look for the implementation
# in the method rb_ary_flatten. It will then use the comment from that
# method in the HTML output. This method must be in the same source file
# as the rb_define_method.
#
# C classes can be diagrammed (see /tc/dl/ruby/ruby/error.c), and RDoc
# integrates C and Ruby source into one tree
#
# 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-method: <i>name</i>]
# This comment documents the named method. Use when RDoc cannot
# automatically find the method from it's declaration
#
# [call-seq: <i>text up to an empty line</i>]
# Because C source doesn't give descriptive names to Ruby-level parameters,
# you need to document the calling sequence explicitly
#
# In addition, RDoc assumes by default that the C method implementing a
# Ruby function is in the same source file as the rb_define_method call.
# If this isn't the case, add the comment
#
# rb_define_method(....); // in: filename
#
# As an example, we might have an extension that defines multiple classes
# in its Init_xxx method. We could document them using
#
#
# /*
# * Document-class: MyClass
# *
# * Encapsulate the writing and reading of the configuration
# * file. ...
# */
#
# /*
# * Document-method: read_value
# *
# * call-seq:
# * cfg.read_value(key) -> value
# * cfg.read_value(key} { |key| } -> value
# *
# * Return the value corresponding to +key+ from the configuration.
# * In the second form, if the key isn't found, invoke the
# * block and return its value.
# */
#
class C_Parser
attr_writer :progress
extend ParserFactory
parse_files_matching(/\.(?:([CcHh])\1?|c([+xp])\2|y)\z/)
@@enclosure_classes = {}
@@known_bodies = {}
# prepare to parse a C file
def initialize(top_level, file_name, body, options, stats)
@known_classes = KNOWN_CLASSES.dup
@options = options
@body = handle_tab_width(handle_ifdefs_in(body))
@stats = stats
@top_level = top_level
@classes = Hash.new
@file_dir = File.dirname(file_name)
@progress = $stderr unless @options.quiet
end
# Extract the classes/modules and methods from a C file
# and return the corresponding top-level object
def scan
remove_commented_out_lines
do_classes
do_constants
do_methods
do_includes
do_aliases
@top_level
end
#######
private
#######
def progress(char)
unless @options.quiet
@progress.print(char)
@progress.flush
end
end
def warn(msg)
$stderr.puts
$stderr.puts msg
$stderr.flush
end
def remove_private_comments(comment)
comment.gsub!(/\/?\*--(.*?)\/?\*\+\+/m, '')
comment.sub!(/\/?\*--.*/m, '')
end
##
# removes lines that are commented out that might otherwise get picked up
# when scanning for classes and methods
def remove_commented_out_lines
@body.gsub!(%r{//.*rb_define_}, '//')
end
def handle_class_module(var_name, class_mod, class_name, parent, in_module)
progress(class_mod[0, 1])
parent_name = @known_classes[parent] || parent
if in_module
enclosure = @classes[in_module] || @@enclosure_classes[in_module]
unless enclosure
if enclosure = @known_classes[in_module]
handle_class_module(in_module, (/^rb_m/ =~ in_module ? "module" : "class"),
enclosure, nil, nil)
enclosure = @classes[in_module]
end
end
unless enclosure
warn("Enclosing class/module '#{in_module}' for " +
"#{class_mod} #{class_name} not known")
return
end
else
enclosure = @top_level
end
if class_mod == "class"
cm = enclosure.add_class(NormalClass, class_name, parent_name)
@stats.num_classes += 1
else
cm = enclosure.add_module(NormalModule, class_name)
@stats.num_modules += 1
end
cm.record_location(enclosure.toplevel)
find_class_comment(cm.full_name, cm)
@classes[var_name] = cm
@@enclosure_classes[var_name] = cm
@known_classes[var_name] = cm.full_name
end
##
# Look for class or module documentation above Init_+class_name+(void),
# in a Document-class +class_name+ (or module) comment or above an
# rb_define_class (or module). If a comment is supplied above a matching
# Init_ and a rb_define_class the Init_ comment is used.
#
# /*
# * This is a comment for Foo
# */
# Init_Foo(void) {
# VALUE cFoo = rb_define_class("Foo", rb_cObject);
# }
#
# /*
# * Document-class: Foo
# * This is a comment for Foo
# */
# Init_foo(void) {
# VALUE cFoo = rb_define_class("Foo", rb_cObject);
# }
#
# /*
# * This is a comment for Foo
# */
# VALUE cFoo = rb_define_class("Foo", rb_cObject);
def find_class_comment(class_name, class_meth)
comment = nil
if @body =~ %r{((?>/\*.*?\*/\s+))
(static\s+)?void\s+Init_#{class_name}\s*(?:_\(\s*)?\(\s*(?:void\s*)\)}xmi
comment = $1
elsif @body =~ %r{Document-(class|module):\s#{class_name}\s*?\n((?>.*?\*/))}m
comment = $2
else
if @body =~ /rb_define_(class|module)/m then
class_name = class_name.split("::").last
comments = []
@body.split(/(\/\*.*?\*\/)\s*?\n/m).each_with_index do |chunk, index|
comments[index] = chunk
if chunk =~ /rb_define_(class|module).*?"(#{class_name})"/m then
comment = comments[index-1]
break
end
end
end
end
class_meth.comment = mangle_comment(comment) if comment
end
############################################################
def do_classes
@body.scan(/(\w+)\s* = \s*rb_define_module\s*\(\s*"(\w+)"\s*\)/mx) do
|var_name, class_name|
handle_class_module(var_name, "module", class_name, nil, nil)
end
# The '.' lets us handle SWIG-generated files
@body.scan(/([\w\.]+)\s* = \s*rb_define_class\s*
\(
\s*"(\w+)",
\s*(\w+)\s*
\)/mx) do
|var_name, class_name, parent|
handle_class_module(var_name, "class", class_name, parent, nil)
end
@body.scan(/(\w+)\s*=\s*boot_defclass\s*\(\s*"(\w+?)",\s*(\w+?)\s*\)/) do
|var_name, class_name, parent|
parent = nil if parent == "0"
handle_class_module(var_name, "class", class_name, parent, nil)
end
@body.scan(/(\w+)\s* = \s*rb_define_module_under\s*
\(
\s*(\w+),
\s*"(\w+)"
\s*\)/mx) do
|var_name, in_module, class_name|
handle_class_module(var_name, "module", class_name, nil, in_module)
end
@body.scan(/([\w\.]+)\s* = \s*rb_define_class_under\s*
\(
\s*(\w+),
\s*"(\w+)",
\s*(\w+)\s*
\s*\)/mx) do
|var_name, in_module, class_name, parent|
handle_class_module(var_name, "class", class_name, parent, in_module)
end
end
###########################################################
def do_constants
@body.scan(%r{\Wrb_define_
(
variable |
readonly_variable |
const |
global_const |
)
\s*\(
(?:\s*(\w+),)?
\s*"(\w+)",
\s*(.*?)\s*\)\s*;
}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
############################################################
def do_methods
@body.scan(%r{rb_define_
(
singleton_method |
method |
module_function |
private_method
)
\s*\(\s*([\w\.]+),
\s*"([^"]+)",
\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|
#"
# Ignore top-object and weird struct.c dynamic stuff
next if var_name == "ruby_top_self"
next if var_name == "nstr"
next if var_name == "envtbl"
next if var_name == "argf" # it'd be nice to handle this one
var_name = "rb_cObject" if var_name == "rb_mKernel"
handle_method(type, var_name, meth_name,
meth_body, param_count, source_file)
end
@body.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
@body.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|
handle_method("method", "rb_mKernel", meth_name,
meth_body, param_count, source_file)
end
@body.scan(/define_filetest_function\s*\(
\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 do_aliases
@body.scan(%r{rb_define_alias\s*\(\s*(\w+),\s*"([^"]+)",\s*"([^"]+)"\s*\)}m) do
|var_name, new_name, old_name|
@stats.num_methods += 1
class_name = @known_classes[var_name] || var_name
class_obj = find_class(var_name, class_name)
class_obj.add_alias(Alias.new("", old_name, new_name, ""))
end
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.
#
# /* 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 (\:).
def handle_constants(type, var_name, const_name, definition)
#@stats.num_constants += 1
class_name = @known_classes[var_name]
return unless class_name
class_obj = find_class(var_name, class_name)
unless class_obj
warn("Enclosing class/module '#{const_name}' for not known")
return
end
comment = find_const_comment(type, const_name)
# In the case of rb_define_const, the definition and comment are in
# "/* definition: comment */" form. The literal ':' and '\' characters
# can be escaped with a backslash.
if type.downcase == 'const' then
elements = mangle_comment(comment).split(':')
if elements.nil? or elements.empty? then
con = Constant.new(const_name, definition, mangle_comment(comment))
else
new_definition = elements[0..-2].join(':')
if new_definition.empty? then # Default to literal C definition
new_definition = definition
else
new_definition.gsub!("\:", ":")
new_definition.gsub!("\\", '\\')
end
new_definition.sub!(/\A(\s+)/, '')
new_comment = $1.nil? ? elements.last : "#{$1}#{elements.last.lstrip}"
con = Constant.new(const_name, new_definition,
mangle_comment(new_comment))
end
else
con = Constant.new(const_name, definition, mangle_comment(comment))
end
class_obj.add_constant(con)
end
##
# Finds a comment matching +type+ and +const_name+ either above the
# comment or in the matching Document- section.
def find_const_comment(type, const_name)
if @body =~ %r{((?>^\s*/\*.*?\*/\s+))
rb_define_#{type}\((?:\s*(\w+),)?\s*"#{const_name}"\s*,.*?\)\s*;}xmi
$1
elsif @body =~ %r{Document-(?:const|global|variable):\s#{const_name}\s*?\n((?>.*?\*/))}m
$1
else
''
end
end
###########################################################
def handle_attr(var_name, attr_name, reader, writer)
rw = ''
if reader
#@stats.num_methods += 1
rw << 'R'
end
if writer
#@stats.num_methods += 1
rw << 'W'
end
class_name = @known_classes[var_name]
return unless class_name
class_obj = find_class(var_name, class_name)
if class_obj
comment = find_attr_comment(attr_name)
unless comment.empty?
comment = mangle_comment(comment)
end
att = Attr.new('', attr_name, rw, comment)
class_obj.add_attribute(att)
end
end
###########################################################
def find_attr_comment(attr_name)
if @body =~ %r{((?>/\*.*?\*/\s+))
rb_define_attr\((?:\s*(\w+),)?\s*"#{attr_name}"\s*,.*?\)\s*;}xmi
$1
elsif @body =~ %r{Document-attr:\s#{attr_name}\s*?\n((?>.*?\*/))}m
$1
else
''
end
end
###########################################################
def handle_method(type, var_name, meth_name,
meth_body, param_count, source_file = nil)
progress(".")
@stats.num_methods += 1
class_name = @known_classes[var_name]
return unless class_name
class_obj = find_class(var_name, class_name)
if class_obj
if meth_name == "initialize"
meth_name = "new"
type = "singleton_method"
end
meth_obj = AnyMethod.new("", meth_name)
meth_obj.singleton =
%w{singleton_method module_function}.include?(type)
p_count = (Integer(param_count) rescue -1)
if p_count < 0
meth_obj.params = "(...)"
elsif p_count == 0
meth_obj.params = "()"
else
meth_obj.params = "(" +
(1..p_count).map{|i| "p#{i}"}.join(", ") +
")"
end
if source_file
file_name = File.join(@file_dir, source_file)
body = (@@known_bodies[source_file] ||= File.read(file_name))
else
body = @body
end
if find_body(meth_body, meth_obj, body) and meth_obj.document_self
class_obj.add_method(meth_obj)
end
end
end
############################################################
# Find the C code corresponding to a Ruby method
def find_body(meth_name, meth_obj, body, quiet = false)
case body
when %r"((?>/\*.*?\*/\s*))(?:static\s+)?VALUE\s+#{meth_name}
\s*(\([^)]*\))\s*\{.*?^\}"xm
comment, params = $1, $2
body_text = $&
remove_private_comments(comment) if comment
# see if we can find the whole body
re = Regexp.escape(body_text) + '[^(]*^\{.*?^\}'
if Regexp.new(re, Regexp::MULTILINE).match(body)
body_text = $&
end
# The comment block may have been overridden with a
# 'Document-method' block. This happens in the interpreter
# when multiple methods are vectored through to the same
# C method but those methods are logically distinct (for
# example Kernel.hash and Kernel.object_id share the same
# implementation
override_comment = find_override_comment(meth_obj.name)
comment = override_comment if override_comment
find_modifiers(comment, meth_obj) if comment
# meth_obj.params = params
meth_obj.start_collecting_tokens
meth_obj.add_token(RubyToken::Token.new(1,1).set_text(body_text))
meth_obj.comment = mangle_comment(comment)
when %r{((?>/\*.*?\*/\s*))^\s*\#\s*define\s+#{meth_name}\s+(\w+)}m
comment = $1
find_body($2, meth_obj, body, true)
find_modifiers(comment, meth_obj)
meth_obj.comment = mangle_comment(comment) + meth_obj.comment
when %r{^\s*\#\s*define\s+#{meth_name}\s+(\w+)}m
unless find_body($1, meth_obj, body, true)
warn "No definition for #{meth_name}" unless quiet
return false
end
else
# No body, but might still have an override comment
comment = find_override_comment(meth_obj.name)
if comment
find_modifiers(comment, meth_obj)
meth_obj.comment = mangle_comment(comment)
else
warn "No definition for #{meth_name}" unless quiet
return false
end
end
true
end
##
# If the comment block contains a section that looks like:
#
# call-seq:
# Array.new
# Array.new(10)
#
# use it for the parameters.
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*/, '')
meth_obj.call_seq = seq
end
end
############################################################
def find_override_comment(meth_name)
name = Regexp.escape(meth_name)
if @body =~ %r{Document-method:\s#{name}\s*?\n((?>.*?\*/))}m
$1
end
end
##
# Look for includes of the form:
#
# rb_include_module(rb_cArray, rb_mEnumerable);
def do_includes
@body.scan(/rb_include_module\s*\(\s*(\w+?),\s*(\w+?)\s*\)/) do |c,m|
if cls = @classes[c]
m = @known_classes[m] || m
cls.add_include(Include.new(m, ""))
end
end
end
##
# Remove the /*'s and leading asterisks from C comments
def mangle_comment(comment)
comment.sub!(%r{/\*+}) { " " * $&.length }
comment.sub!(%r{\*+/}) { " " * $&.length }
comment.gsub!(/^[ \t]*\*/m) { " " * $&.length }
comment
end
def find_class(raw_name, name)
unless @classes[raw_name]
if raw_name =~ /^rb_m/
@classes[raw_name] = @top_level.add_module(NormalModule, name)
else
@classes[raw_name] = @top_level.add_class(NormalClass, name, nil)
end
end
@classes[raw_name]
end
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)} && $~ #`
line
end .join("\n")
else
body
end
end
##
# Removes #ifdefs that would otherwise confuse us
def handle_ifdefs_in(body)
body.gsub(/^#ifdef HAVE_PROTOTYPES.*?#else.*?\n(.*?)#endif.*?\n/m, '\1')
end
end
end

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

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

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

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

@ -1,99 +0,0 @@
require "rdoc/parsers/parse_simple"
module RDoc
# A parser is simple a class that implements
#
# #initialize(file_name, body, options)
#
# and
#
# #scan
#
# The initialize method takes a file name to be used, the body of the
# file, and an RDoc::Options object. The scan method is then called
# to return an appropriately parsed TopLevel code object.
#
# The ParseFactory is used to redirect to the correct parser given a filename
# extension. This magic works because individual parsers have to register
# themselves with us as they are loaded in. The do this using the following
# incantation
#
#
# require "rdoc/parsers/parsefactory"
#
# module RDoc
#
# class XyzParser
# extend ParseFactory <<<<
# parse_files_matching /\.xyz$/ <<<<
#
# def initialize(file_name, body, options)
# ...
# end
#
# def scan
# ...
# end
# end
# end
#
# Just to make life interesting, if we suspect a plain text file, we
# also look for a shebang line just in case it's a potential
# shell script
module ParserFactory
@@parsers = []
Parsers = Struct.new(:regexp, :parser)
# Record the fact that a particular class parses files that
# match a given extension
def parse_files_matching(regexp)
@@parsers.unshift Parsers.new(regexp, self)
end
# Return a parser that can handle a particular extension
def ParserFactory.can_parse(file_name)
@@parsers.find {|p| p.regexp.match(file_name) }
end
# Alias an extension to another extension. After this call,
# files ending "new_ext" will be parsed using the same parser
# as "old_ext"
def ParserFactory.alias_extension(old_ext, new_ext)
parser = ParserFactory.can_parse("xxx.#{old_ext}")
return false unless parser
@@parsers.unshift Parsers.new(Regexp.new("\\.#{new_ext}$"), parser.parser)
true
end
# Find the correct parser for a particular file name. Return a
# SimpleParser for ones that we don't know
def ParserFactory.parser_for(top_level, file_name, body, options, stats)
# If no extension, look for shebang
if file_name !~ /\.\w+$/ && body =~ %r{\A#!(.+)}
shebang = $1
case shebang
when %r{env\s+ruby}, %r{/ruby}
file_name = "dummy.rb"
end
end
parser_description = can_parse(file_name)
if parser_description
parser = parser_description.parser
else
parser = SimpleParser
end
parser.new(top_level, file_name, body, options, stats)
end
end
end

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

@ -1,9 +1,12 @@
require 'rdoc'
require 'rdoc/parsers/parse_rb.rb'
require 'rdoc/parsers/parse_c.rb'
require 'rdoc/parsers/parse_f95.rb'
require 'rdoc/parsers/parse_simple.rb'
require 'rdoc/parser'
# Simple must come first
require 'rdoc/parser/simple'
require 'rdoc/parser/ruby'
require 'rdoc/parser/c'
require 'rdoc/parser/f95'
require 'rdoc/stats'
require 'rdoc/options'
@ -146,7 +149,10 @@ module RDoc
case type = stat.ftype
when "file"
next if @last_created and stat.mtime < @last_created
file_list << rel_file_name.sub(/^\.\//, '') if force_doc || ParserFactory.can_parse(rel_file_name)
if force_doc or ::RDoc::Parser.can_parse(rel_file_name) then
file_list << rel_file_name.sub(/^\.\//, '')
end
when "directory"
next if rel_file_name == "CVS" || rel_file_name == ".svn"
dot_doc = File.join(rel_file_name, DOT_DOC_FILENAME)
@ -198,14 +204,18 @@ module RDoc
File.read fn
end
if /coding:\s*(\S+)/ =~ content[/\A(?:.*\n){0,2}/]
if enc = Encoding.find($1)
content.force_encoding(enc)
if defined? Encoding then
if /coding:\s*(\S+)/ =~ content[/\A(?:.*\n){0,2}/]
if enc = ::Encoding.find($1)
content.force_encoding(enc)
end
end
end
top_level = TopLevel.new(fn)
parser = ParserFactory.parser_for(top_level, fn, content, options, @stats)
top_level = ::RDoc::TopLevel.new fn
parser = ::RDoc::Parser.for top_level, fn, content, options, @stats
file_info << parser.scan
@stats.num_files += 1
end
@ -241,17 +251,19 @@ module RDoc
file_info = parse_files @options
@options.title = "RDoc Documentation"
if file_info.empty?
$stderr.puts "\nNo newer files." unless @options.quiet
else
gen = @options.generator
@gen = @options.generator
$stderr.puts "\nGenerating #{gen.key.upcase}..." unless @options.quiet
$stderr.puts "\nGenerating #{@gen.key.upcase}..." unless @options.quiet
require gen.file_name
require @gen.file_name
gen_class = ::RDoc::Generator.const_get gen.class_name
gen = gen_class.for @options
gen_class = ::RDoc::Generator.const_get @gen.class_name
@gen = gen_class.for @options
pwd = Dir.pwd
@ -259,7 +271,7 @@ module RDoc
begin
Diagram.new(file_info, @options).draw if @options.diagram
gen.generate(file_info)
@gen.generate(file_info)
update_output_dir(".", start_time)
ensure
Dir.chdir(pwd)

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

@ -1,4 +1,8 @@
require 'rdoc'
module RDoc::RI; end
module RDoc::RI
class Error < RDoc::Error; end
end

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

@ -2,11 +2,10 @@ require 'yaml'
require 'rdoc/markup/fragments'
require 'rdoc/ri'
#--
##
# Descriptions are created by RDoc (in ri_generator) and written out in
# serialized form into the documentation tree. ri then reads these to generate
# the documentation
#++
class RDoc::RI::NamedThing
attr_reader :name

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

@ -11,6 +11,64 @@ require 'rdoc/markup/to_flow'
class RDoc::RI::Driver
class Hash < ::Hash
def self.convert(hash)
hash = new.update hash
hash.each do |key, value|
hash[key] = case value
when ::Hash then
convert value
when Array then
value = value.map do |v|
::Hash === v ? convert(v) : v
end
value
else
value
end
end
hash
end
def method_missing method, *args
self[method.to_s]
end
def merge_enums(other)
other.each do |k, v|
if self[k] then
case v
when Array then
# HACK dunno
if String === self[k] and self[k].empty? then
self[k] = v
else
self[k] += v
end
when Hash then
self[k].update v
else
# do nothing
end
else
self[k] = v
end
end
end
end
class Error < RDoc::RI::Error; end
class NotFoundError < Error
def message
"Nothing known about #{super}"
end
end
attr_accessor :homepath # :nodoc:
def self.process_args(argv)
options = {}
options[:use_stdout] = !$stdout.tty?
@ -234,7 +292,7 @@ Options may also be set in the 'RI' environment variable.
@class_cache = if up_to_date then
load_cache_for @class_cache_name
else
class_cache = {}
class_cache = RDoc::RI::Driver::Hash.new
classes = map_dirs('**/cdesc*.yaml', :sys) { |f| Dir[f] }
populate_class_cache class_cache, classes
@ -261,16 +319,24 @@ Options may also be set in the 'RI' environment variable.
def display_class(name)
klass = class_cache[name]
klass = RDoc::RI::Driver::Hash.convert klass
@display.display_class_info klass, class_cache
end
def get_info_for(arg)
@names = [arg]
run
end
def load_cache_for(klassname)
path = cache_file_for klassname
cache = nil
if File.exist? path and
File.mtime(path) >= File.mtime(class_cache_file_path) then
File.open path, 'rb' do |fp|
Marshal.load fp.read
cache = Marshal.load fp.read
end
else
class_cache = nil
@ -283,7 +349,7 @@ Options may also be set in the 'RI' environment variable.
return nil unless klass
method_files = klass["sources"]
cache = {}
cache = RDoc::RI::Driver::Hash.new
sys_dir = @sys_dirs.first
method_files.each do |f|
@ -296,12 +362,28 @@ Options may also be set in the 'RI' environment variable.
ext_path = f
ext_path = "gem #{$1}" if f =~ %r%gems/[\d.]+/doc/([^/]+)%
method["source_path"] = ext_path unless system_file
cache[name] = method
cache[name] = RDoc::RI::Driver::Hash.convert method
end
end
write_cache cache, path
end
RDoc::RI::Driver::Hash.convert cache
end
##
# Finds the method
def lookup_method(name, klass)
cache = load_cache_for klass
raise NotFoundError, name unless cache
method = cache[name.gsub('.', '#')]
method = cache[name.gsub('.', '::')] unless method
raise NotFoundError, name unless method
method
end
def map_dirs(file_name, system=false)
@ -318,6 +400,22 @@ Options may also be set in the 'RI' environment variable.
dirs.map { |dir| yield File.join(dir, file_name) }.flatten.compact
end
##
# Extract the class and method name parts from +name+ like Foo::Bar#baz
def parse_name(name)
parts = name.split(/(::|\#|\.)/)
if parts[-2] != '::' or parts.last !~ /^[A-Z]/ then
meth = parts.pop
parts.pop
end
klass = parts.join
[klass, meth]
end
def populate_class_cache(class_cache, classes, extension = false)
classes.each do |cdesc|
desc = read_yaml cdesc
@ -351,11 +449,6 @@ Options may also be set in the 'RI' environment variable.
YAML.load data
end
def get_info_for(arg)
@names = [arg]
run
end
def run
if @names.empty? then
@display.list_known_classes class_cache.keys.sort
@ -368,15 +461,10 @@ Options may also be set in the 'RI' environment variable.
else
meth = nil
parts = name.split(/::|\#|\./)
meth = parts.pop unless parts.last =~ /^[A-Z]/
klass = parts.join '::'
klass, meth = parse_name name
method = lookup_method name, klass
cache = load_cache_for klass
# HACK Does not support F.n
abort "Nothing known about #{name}" unless cache
method = cache[name.gsub(/\./, '#')]
abort "Nothing known about #{name}" unless method
@display.display_method_info method
end
else
@ -385,7 +473,7 @@ Options may also be set in the 'RI' environment variable.
else
methods = select_methods(/^#{name}/)
if methods.size == 0
abort "Nothing known about #{name}"
raise NotFoundError, name
elsif methods.size == 1
@display.display_method_info methods.first
else
@ -395,6 +483,8 @@ Options may also be set in the 'RI' environment variable.
end
end
end
rescue NotFoundError => e
abort e.message
end
def select_methods(pattern)
@ -422,31 +512,3 @@ Options may also be set in the 'RI' environment variable.
end
class Hash # HACK don't add stuff to Hash.
def method_missing method, *args
self[method.to_s]
end
def merge_enums(other)
other.each do |k,v|
if self[k] then
case v
when Array then
# HACK dunno
if String === self[k] and self[k].empty? then
self[k] = v
else
self[k] += v
end
when Hash then
self[k].merge! v
else
# do nothing
end
else
self[k] = v
end
end
end
end

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

@ -0,0 +1,179 @@
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib/'
require 'fileutils'
require 'test/unit'
require 'rdoc/generator/texinfo'
require 'yaml'
# From chapter 18 of the Pickaxe 3rd ed. and the TexInfo manual.
class TestRdocInfoFormatting < Test::Unit::TestCase
OUTPUT_DIR = "/tmp/rdoc-#{$$}"
def setup
# supress stdout
$stdout = File.new('/dev/null','w')
$stderr = File.new('/dev/null','w')
RDoc::RDoc.new.document(['--fmt=texinfo',
File.expand_path(__FILE__),
"--op=#{OUTPUT_DIR}"])
@text = File.read(OUTPUT_DIR + '/rdoc.texinfo')
# File.open('rdoc.texinfo', 'w') { |f| f.puts @text }
end
def teardown
$stdout = STDOUT
$stderr = STDERR
FileUtils.rm_rf OUTPUT_DIR
end
# Make sure tags like *this* do not make HTML
def test_descriptions_are_not_html
assert_no_match Regexp.new("\<b\>this\<\/b\>"), @text, "We had some HTML; icky!"
end
# Ensure we get a reasonable amount
#
# of space in between paragraphs.
def test_paragraphs_are_spaced
assert_match(/amount\n\n\nof space/, @text)
end
# @ and {} should be at-sign-prefixed
def test_escaping
assert_match(/@@ and @\{@\} should be at-sign-prefixed/)
end
# This tests that *bold* and <b>bold me</b> become @strong{bolded}
def test_bold
# Seems like a limitation of the Info format: @strong{bold}
# becomes *bold* when read in Info or M-x info. highly lame!
assert_match(/@strong\{bold\}/)
assert_match(/@strong\{bold me\}/)
end
# Test that _italics_ and <em>italicize me</em> becomes @emph{italicized}
def test_italics
assert_match(/@emph\{italics\}/)
assert_match(/@emph\{italicize me\}/)
end
# And that typewriter +text+ and <tt>typewriter me</tt> becomes @code{typewriter}
def test_tt
assert_match(/@code\{text\}/)
assert_match(/@code\{typewriter me\}/)
end
# Check that
# anything indented is
# verbatim @verb{|foo bar baz|}
def test_literal_code
assert_match("@verb{| anything indented is
verbatim @@verb@{|foo bar baz|@}
|}")
end
# = Huge heading should be a @majorheading
# == There is also @chapheading
# === Everything deeper becomes a regular @heading
# ====== Regardless of its nesting level
def test_headings
assert_match(/@majorheading\{Huge heading should be a @@majorheading\}/)
assert_match(/@chapheading\{There is also @@chapheading\}/)
assert_match(/@heading\{Everything deeper becomes a regular @@heading\}/)
assert_match(/@heading\{Regardless of its nesting level\}/)
end
# * list item
# * list item2
#
# with a paragraph in between
#
# - hyphen lists
# - are also allowed
# and items may flow over lines
def test_bullet_lists
assert_match("@itemize @bullet
@item
list item
@item
list item2
@end itemize")
assert_match("@itemize @bullet
@item
hyphen lists
@item
are also allowed and items may flow over lines
@end itemize")
end
# 2. numbered lists
# 8. are made by
# 9. a digit followed by a period
def test_numbered_lists
end
# a. alpha lists
# b. should be parsed too
def test_alpha_lists
end
# [cat] small domestic animal
# [+cat+] command to copy standard input
# to standard output
def test_labelled_lists
end
# * First item.
# * Inner item.
# * Second inner item.
# * Second outer item.
def test_nested_lists
assert_match("@itemize @bullet
@item
First item.
@itemize @bullet
@item
Inner item.
@item
Second inner item.
@end itemize
@item
Second outer item.
@end itemize")
end
def test_internal_hyperlinks
# be sure to test multi-word hyperlinks as well.
end
def test_hyperlink_targets
end
def test_web_links
# An example of the two-argument form: The official
# @uref{ftp://ftp.gnu.org/gnu, GNU ftp site} holds programs and texts.
# produces:
# The official GNU ftp site (ftp://ftp.gnu.org/gnu)
# holds programs and texts.
# and the HTML output is this:
# The official <a href="ftp://ftp.gnu.org/gnu">GNU ftp site</a>
# holds programs and texts.
end
# three or more hyphens
# ----
# should produce a horizontal rule
def test_horizontal_rule
# gah; not sure texinfo supports horizontal rules
end
private
# We don't want the whole string inspected if we pass our own
# message in.
def assert_match(regex, string = @text,
message = "Didn't find #{regex.inspect} in #{string}.")
assert string[regex] #, message
end
end

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

@ -0,0 +1,93 @@
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib/'
require 'fileutils'
require 'test/unit'
require 'rdoc/generator/texinfo'
require 'yaml'
# give us access to check this stuff before it's rendered
class RDoc::Generator::Texinfo; attr_reader :files, :classes; end
class RDoc::RDoc; attr_reader :options; attr_reader :gen; end
class TestRdocInfoSections < Test::Unit::TestCase
OUTPUT_DIR = "/tmp/rdoc-#{$$}"
def setup
# supress stdout
$stdout = File.new('/dev/null','w')
$stderr = File.new('/dev/null','w')
@rdoc = RDoc::RDoc.new
@rdoc.document(['--fmt=texinfo',
File.expand_path(File.dirname(__FILE__) + '/../lib/rdoc/generator/texinfo.rb'),
File.expand_path(File.dirname(__FILE__) + '/../README.txt'),
"--op=#{OUTPUT_DIR}"])
@text = File.read(OUTPUT_DIR + '/rdoc.texinfo')
end
def teardown
$stdout = STDOUT
$stderr = STDERR
FileUtils.rm_rf OUTPUT_DIR
end
def test_output_exists
assert ! @text.empty?
end
def test_each_class_has_a_chapter
assert_section "Class RDoc::Generator::Texinfo", '@chapter'
assert_section "Class RDoc::Generator::TexinfoTemplate", '@chapter'
end
def test_class_descriptions_are_given
assert_match(/This generates .*Texinfo.* files for viewing with GNU Info or Emacs from .*RDoc.* extracted from Ruby source files/, @text.gsub("\n", ' '))
end
def test_included_modules_are_given
assert_match(/Includes.* Generator::MarkUp/m, @text)
end
def test_class_methods_are_given
assert_match(/new\(options\)/, @text)
end
def test_classes_instance_methods_are_given
assert_section 'Class RDoc::Generator::Texinfo#generate'
assert_match(/generate\(toplevels\)/, @text)
end
def test_each_module_has_a_chapter
assert_section "RDoc", '@chapter'
assert_section "Generator", '@chapter'
end
def test_methods_are_shown_only_once
methods = @rdoc.gen.classes.map { |c| c.methods.map{ |m| c.name + '#' + m.name } }.flatten
assert_equal methods, methods.uniq
end
# if system "makeinfo --version > /dev/null"
# def test_compiles_to_info
# makeinfo_output = `cd #{OUTPUT_DIR} && makeinfo rdoc.texinfo`
# assert(File.exist?(File.join(OUTPUT_DIR, 'rdoc.info')),
# "Info file was not compiled: #{makeinfo_output}")
# end
# end
# def test_constants_are_documented_somehow
# assert_section 'DEFAULT_FILENAME' # what kind of section?
# assert_section 'DEFAULT_INFO_FILENAME'
# end
# def test_oh_yeah_dont_forget_files
# end
private
def assert_section(name, command = '@section')
assert_match Regexp.new("^#{command}.*#{Regexp.escape name}"), @text, "Could not find a #{command} #{name}"
end
# def puts(*args)
# @real_stdout.puts(*args)
# end
end

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

@ -0,0 +1,30 @@
require 'test/unit'
require 'rdoc/markup'
require 'rdoc/markup/to_html'
class TestRdocMarkupToHtml < Test::Unit::TestCase
def setup
@am = RDoc::Markup::AttributeManager.new
@th = RDoc::Markup::ToHtml.new
end
def test_tt_formatting
assert_equal "<p>\n<tt>--</tt> &#8212; <tt>(c)</tt> &#169;\n</p>\n",
util_format("<tt>--</tt> -- <tt>(c)</tt> (c)")
assert_equal "<p>\n<b>&#8212;</b>\n</p>\n", util_format("<b>--</b>")
end
def util_fragment(text)
RDoc::Markup::Fragment.new 0, nil, nil, text
end
def util_format(text)
fragment = util_fragment text
@th.start_accepting
@th.accept_paragraph @am, fragment
@th.end_accepting
end
end

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

@ -0,0 +1,18 @@
require 'test/unit'
require 'rdoc/generator'
require 'rdoc/markup/to_html_crossref'
class TestRdocMarkupToHtmlCrossref < Test::Unit::TestCase
def setup
@xref = RDoc::Markup::ToHtmlCrossref.new 'from_path', nil, nil
end
def test_handle_special_CROSSREF_no_underscore
out = @xref.convert 'foo'
assert_equal "<p>\nfoo\n</p>\n", out
end
end

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

@ -1,15 +1,16 @@
require 'stringio'
require 'tempfile'
require 'test/unit'
require 'rdoc/parsers/parse_c'
require 'rdoc/options'
require 'rdoc/parser/c'
class RDoc::C_Parser
class RDoc::Parser::C
attr_accessor :classes
public :do_classes, :do_constants
end
class TestRdocC_Parser < Test::Unit::TestCase
class TestRdocParserC < Test::Unit::TestCase
def setup
@tempfile = Tempfile.new self.class.name
@ -252,7 +253,7 @@ Init_Foo(void) {
end
def util_parser(content)
parser = RDoc::C_Parser.new @top_level, @fn, content, @options, @stats
parser = RDoc::Parser::C.new @top_level, @fn, content, @options, @stats
parser.progress = @progress
parser
end

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

@ -0,0 +1,500 @@
require 'stringio'
require 'tempfile'
require 'test/unit'
require 'rdoc/options'
require 'rdoc/parser/ruby'
require 'rdoc/stats'
class TestRdocParserRuby < Test::Unit::TestCase
def setup
@tempfile = Tempfile.new self.class.name
@filename = @tempfile.path
util_toplevel
@options = RDoc::Options.new Hash.new
@options.quiet = true
@stats = RDoc::Stats.new
@progress = StringIO.new
end
def teardown
@tempfile.unlink
end
def test_look_for_directives_in_commented
util_parser ""
comment = "# how to make a section:\n# # :section: new section\n"
@parser.look_for_directives_in @top_level, comment
section = @top_level.current_section
assert_equal nil, section.title
assert_equal nil, section.comment
assert_equal "# how to make a section:\n# # :section: new section\n",
comment
end
def test_look_for_directives_in_enddoc
util_parser ""
assert_throws :enddoc do
@parser.look_for_directives_in @top_level, "# :enddoc:\n"
end
end
def test_look_for_directives_in_main
util_parser ""
@parser.look_for_directives_in @top_level, "# :main: new main page\n"
assert_equal 'new main page', @options.main_page
end
def test_look_for_directives_in_method
util_parser ""
comment = "# :method: my_method\n"
@parser.look_for_directives_in @top_level, comment
assert_equal "# :method: my_method\n", comment
comment = "# :singleton-method: my_method\n"
@parser.look_for_directives_in @top_level, comment
assert_equal "# :singleton-method: my_method\n", comment
end
def test_look_for_directives_in_startdoc
util_parser ""
@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
util_parser ""
assert @top_level.document_self
assert @top_level.document_children
@parser.look_for_directives_in @top_level, "# :stopdoc:\n"
assert !@top_level.document_self
assert !@top_level.document_children
end
def test_look_for_directives_in_section
util_parser ""
comment = "# :section: new section\n# woo stuff\n"
@parser.look_for_directives_in @top_level, comment
section = @top_level.current_section
assert_equal 'new section', section.title
assert_equal "# woo stuff\n", section.comment
assert_equal '', comment
end
def test_look_for_directives_in_title
util_parser ""
@parser.look_for_directives_in @top_level, "# :title: new title\n"
assert_equal 'new title', @options.title
end
def test_look_for_directives_in_unhandled
util_parser ""
comment = "# :unhandled: \n# :title: hi\n"
@parser.look_for_directives_in @top_level, comment
assert_equal "# :unhandled: \n", comment
assert_equal 'hi', @options.title
end
def test_parse_meta_method
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
comment = "##\n# my method\n"
util_parser "add_my_method :foo, :bar\nadd_my_method :baz"
tk = @parser.get_tk
@parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
foo = klass.method_list.first
assert_equal 'foo', foo.name
assert_equal comment, foo.comment
assert_equal [], foo.aliases
assert_equal nil, foo.block_params
assert_equal nil, foo.call_seq
assert_equal true, foo.document_children
assert_equal true, foo.document_self
assert_equal false, foo.done_documenting
assert_equal false, foo.dont_rename_initialize
assert_equal false, foo.force_documentation
assert_equal nil, foo.is_alias_for
assert_equal '', foo.params
assert_equal klass, foo.parent
assert_equal false, foo.singleton
assert_equal 'add_my_method :foo', foo.text
assert_equal nil, foo.viewer
assert_equal :public, foo.visibility
assert_equal klass.current_section, foo.section
stream = [
tk(:COMMENT, 1, 1, nil, "# File #{@top_level.file_absolute_name}, line 1"),
RDoc::Parser::Ruby::NEWLINE_TOKEN,
tk(:SPACE, 1, 1, nil, ''),
tk(:IDENTIFIER, 1, 0, 'add_my_method', 'add_my_method'),
tk(:SPACE, 1, 13, nil, ' '),
tk(:SYMBOL, 1, 14, nil, ':foo'),
tk(:COMMA, 1, 18, nil, ','),
tk(:SPACE, 1, 19, nil, ' '),
tk(:SYMBOL, 1, 20, nil, ':bar'),
tk(:NL, 1, 24, nil, "\n"),
]
assert_equal stream, foo.token_stream
end
def test_parse_meta_method_name
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
comment = "##\n# :method: woo_hoo!\n# my method\n"
util_parser "add_my_method :foo, :bar\nadd_my_method :baz"
tk = @parser.get_tk
@parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
foo = klass.method_list.first
assert_equal 'woo_hoo!', foo.name
assert_equal "##\n# my method\n", foo.comment
end
def test_parse_meta_method_singleton
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
comment = "##\n# :singleton-method:\n# my method\n"
util_parser "add_my_method :foo, :bar\nadd_my_method :baz"
tk = @parser.get_tk
@parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
foo = klass.method_list.first
assert_equal 'foo', foo.name
assert_equal true, foo.singleton, 'singleton method'
assert_equal "##\n# my method\n", foo.comment
end
def test_parse_meta_method_singleton_name
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
comment = "##\n# :singleton-method: woo_hoo!\n# my method\n"
util_parser "add_my_method :foo, :bar\nadd_my_method :baz"
tk = @parser.get_tk
@parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
foo = klass.method_list.first
assert_equal 'woo_hoo!', foo.name
assert_equal true, foo.singleton, 'singleton method'
assert_equal "##\n# my method\n", foo.comment
end
def test_parse_meta_method_string_name
klass = RDoc::NormalClass.new 'Foo'
comment = "##\n# my method\n"
util_parser "add_my_method 'foo'"
tk = @parser.get_tk
@parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
foo = klass.method_list.first
assert_equal 'foo', foo.name
assert_equal comment, foo.comment
end
def test_parse_method
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
comment = "##\n# my method\n"
util_parser "def foo() :bar end"
tk = @parser.get_tk
@parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
foo = klass.method_list.first
assert_equal 'foo', foo.name
assert_equal comment, foo.comment
assert_equal [], foo.aliases
assert_equal nil, foo.block_params
assert_equal nil, foo.call_seq
assert_equal nil, foo.is_alias_for
assert_equal nil, foo.viewer
assert_equal true, foo.document_children
assert_equal true, foo.document_self
assert_equal '()', foo.params
assert_equal false, foo.done_documenting
assert_equal false, foo.dont_rename_initialize
assert_equal false, foo.force_documentation
assert_equal klass, foo.parent
assert_equal false, foo.singleton
assert_equal :public, foo.visibility
assert_equal 'def foo', foo.text
assert_equal klass.current_section, foo.section
stream = [
tk(:COMMENT, 1, 1, nil, "# File #{@top_level.file_absolute_name}, line 1"),
RDoc::Parser::Ruby::NEWLINE_TOKEN,
tk(:SPACE, 1, 1, nil, ''),
tk(:DEF, 1, 0, 'def', 'def'),
tk(:SPACE, 1, 3, nil, ' '),
tk(:IDENTIFIER, 1, 4, 'foo', 'foo'),
tk(:LPAREN, 1, 7, nil, '('),
tk(:RPAREN, 1, 8, nil, ')'),
tk(:SPACE, 1, 9, nil, ' '),
tk(:COLON, 1, 10, nil, ':'),
tk(:IDENTIFIER, 1, 11, 'bar', 'bar'),
tk(:SPACE, 1, 14, nil, ' '),
tk(:END, 1, 15, 'end', 'end'),
]
assert_equal stream, foo.token_stream
end
def test_parse_statements_comment
content = <<-EOF
class Foo
##
# :method: my_method
# my method comment
end
EOF
klass = RDoc::NormalClass.new 'Foo'
klass.parent = @top_level
comment = "##\n# :method: foo\n# my method\n"
util_parser "\n"
tk = @parser.get_tk
@parser.parse_comment klass, tk, comment
foo = klass.method_list.first
assert_equal 'foo', foo.name
assert_equal comment, foo.comment
assert_equal [], foo.aliases
assert_equal nil, foo.block_params
assert_equal nil, foo.call_seq
assert_equal nil, foo.is_alias_for
assert_equal nil, foo.viewer
assert_equal true, foo.document_children
assert_equal true, foo.document_self
assert_equal '', foo.params
assert_equal false, foo.done_documenting
assert_equal false, foo.dont_rename_initialize
assert_equal false, foo.force_documentation
assert_equal klass, foo.parent
assert_equal false, foo.singleton
assert_equal :public, foo.visibility
assert_equal "\n", foo.text
assert_equal klass.current_section, foo.section
stream = [
tk(:COMMENT, 1, 1, nil, "# File #{@top_level.file_absolute_name}, line 1"),
RDoc::Parser::Ruby::NEWLINE_TOKEN,
tk(:SPACE, 1, 1, nil, ''),
]
assert_equal stream, foo.token_stream
end
def test_parse_statements_identifier_meta_method
content = <<-EOF
class Foo
##
# this is my method
add_my_method :foo
end
EOF
util_parser content
@parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, ''
foo = @top_level.classes.first.method_list.first
assert_equal 'foo', foo.name
end
def test_parse_statements_identifier_alias_method
content = "class Foo def foo() end; alias_method :foo2, :foo end"
util_parser content
@parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, ''
foo2 = @top_level.classes.first.method_list.last
assert_equal 'foo2', foo2.name
assert_equal 'foo', foo2.is_alias_for.name
end
def test_parse_statements_identifier_attr
content = "class Foo; attr :foo; end"
util_parser content
@parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, ''
foo = @top_level.classes.first.attributes.first
assert_equal 'foo', foo.name
assert_equal 'R', foo.rw
end
def test_parse_statements_identifier_attr_accessor
content = "class Foo; attr_accessor :foo; end"
util_parser content
@parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, ''
foo = @top_level.classes.first.attributes.first
assert_equal 'foo', foo.name
assert_equal 'RW', foo.rw
end
def test_parse_statements_identifier_extra_accessors
@options.extra_accessors = /^my_accessor$/
content = "class Foo; my_accessor :foo; end"
util_parser content
@parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, ''
foo = @top_level.classes.first.attributes.first
assert_equal 'foo', foo.name
assert_equal '?', foo.rw
end
def test_parse_statements_identifier_include
content = "class Foo; include Bar; end"
util_parser content
@parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, ''
foo = @top_level.classes.first
assert_equal 'Foo', foo.name
assert_equal 1, foo.includes.length
end
def test_parse_statements_identifier_module_function
content = "module Foo def foo() end; module_function :foo; end"
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 :private, foo.visibility, 'instance method visibility'
assert_equal false, foo.singleton, 'instance method singleton'
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'
end
def test_parse_statements_identifier_private
content = "class Foo private; def foo() end end"
util_parser content
@parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, ''
foo = @top_level.classes.first.method_list.first
assert_equal 'foo', foo.name
assert_equal :private, foo.visibility
end
def test_parse_statements_identifier_require
content = "require 'bar'"
util_parser content
@parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, ''
assert_equal 1, @top_level.requires.length
end
def tk(klass, line, char, name, text)
klass = RDoc::RubyToken.const_get "Tk#{klass.to_s.upcase}"
token = if klass.instance_method(:initialize).arity == 2 then
raise ArgumentError, "name not used for #{klass}" unless name.nil?
klass.new line, char
else
klass.new line, char, name
end
token.set_text text
token
end
def util_parser(content)
@parser = RDoc::Parser::Ruby.new @top_level, @filename, content, @options,
@stats
@parser.progress = @progress
@parser
end
def util_toplevel
RDoc::TopLevel.reset
@top_level = RDoc::TopLevel.new @filename
end
end

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

@ -4,7 +4,7 @@ require 'rdoc/ri/formatter'
require 'rdoc/ri/display'
require 'rdoc/ri/driver'
class TestRDocRIDefaultDisplay < Test::Unit::TestCase
class TestRdocRiDefaultDisplay < Test::Unit::TestCase
def setup
@output = StringIO.new
@ -14,7 +14,7 @@ class TestRDocRIDefaultDisplay < Test::Unit::TestCase
@dd = RDoc::RI::DefaultDisplay.new RDoc::RI::Formatter, @width, true,
@output
@some_method = {
@some_method = h \
'aliases' => [{'name' => 'some_method_alias'}],
'block_params' => 'block_param',
'comment' => [RDoc::Markup::Flow::P.new('some comment')],
@ -23,13 +23,12 @@ class TestRDocRIDefaultDisplay < Test::Unit::TestCase
'name' => 'some_method',
'params' => '(arg1, arg2) {|block_param| ...}',
'source_path' => '/nonexistent',
'visibility' => 'public',
}
'visibility' => 'public'
end
def test_display_class_info
ri_reader = nil
klass = {
klass = h \
'attributes' => [
{ 'name' => 'attribute', 'rw' => 'RW',
'comment' => [RDoc::Markup::Flow::P.new('attribute comment')] },
@ -58,8 +57,7 @@ class TestRDocRIDefaultDisplay < Test::Unit::TestCase
'instance_method_extensions' => [
{ 'name' => 'instance_method_extension' },
],
'superclass_string' => 'Object',
}
'superclass_string' => 'Object'
@dd.display_class_info klass, ri_reader
@ -154,7 +152,7 @@ Attributes:
end
def test_display_method_info_singleton
method = {
method = RDoc::RI::Driver::Hash.new.update \
'aliases' => [],
'block_params' => nil,
'comment' => nil,
@ -162,8 +160,7 @@ Attributes:
'is_singleton' => true,
'name' => 'some_method',
'params' => '(arg1, arg2)',
'visibility' => 'public',
}
'visibility' => 'public'
@dd.display_method_info method
@ -179,7 +176,7 @@ Attributes:
def test_display_method_list
methods = [
{
RDoc::RI::Driver::Hash.new.update(
"aliases" => [],
"block_params" => nil,
"comment" => nil,
@ -187,9 +184,9 @@ Attributes:
"is_singleton" => false,
"name" => "some_method",
"params" => "()",
"visibility" => "public",
},
{
"visibility" => "public"
),
RDoc::RI::Driver::Hash.new.update(
"aliases" => [],
"block_params" => nil,
"comment" => nil,
@ -197,8 +194,8 @@ Attributes:
"is_singleton" => false,
"name" => "some_other_method",
"params" => "()",
"visibility" => "public",
},
"visibility" => "public"
),
]
@dd.display_method_list methods
@ -291,5 +288,9 @@ install an additional package, or ask the packager to enable ri generation.
assert_equal expected, @output.string
end
def h(hash)
RDoc::RI::Driver::Hash.convert hash
end
end

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

@ -0,0 +1,100 @@
require 'test/unit'
require 'tmpdir'
require 'rdoc/ri/driver'
class TestRDocRIDriver < Test::Unit::TestCase
def setup
@tmpdir = File.join Dir.tmpdir, "test_rdoc_ri_driver_#{$$}"
@home_ri = File.join @tmpdir, 'dot_ri'
@cache_dir = File.join @home_ri, 'cache'
@class_cache = File.join @cache_dir, 'classes'
FileUtils.mkdir_p @tmpdir
FileUtils.mkdir_p @home_ri
FileUtils.mkdir_p @cache_dir
@driver = RDoc::RI::Driver.new
@driver.homepath = @home_ri
end
def teardown
FileUtils.rm_rf @tmpdir
end
def test_lookup_method
def @driver.load_cache_for(klassname)
{ 'Foo#bar' => :found }
end
assert @driver.lookup_method('Foo#bar', 'Foo')
end
def test_lookup_method_class_method
def @driver.load_cache_for(klassname)
{ 'Foo::Bar' => :found }
end
assert @driver.lookup_method('Foo::Bar', 'Foo::Bar')
end
def test_lookup_method_class_missing
def @driver.load_cache_for(klassname) end
e = assert_raise RDoc::RI::Driver::NotFoundError do
@driver.lookup_method 'Foo#bar', 'Foo'
end
assert_equal 'Nothing known about Foo#bar', e.message
end
def test_lookup_method_dot_instance
def @driver.load_cache_for(klassname)
{ 'Foo#bar' => :instance, 'Foo::bar' => :klass }
end
assert_equal :instance, @driver.lookup_method('Foo.bar', 'Foo')
end
def test_lookup_method_dot_class
def @driver.load_cache_for(klassname)
{ 'Foo::bar' => :found }
end
assert @driver.lookup_method('Foo.bar', 'Foo')
end
def test_lookup_method_method_missing
def @driver.load_cache_for(klassname) {} end
e = assert_raise RDoc::RI::Driver::NotFoundError do
@driver.lookup_method 'Foo#bar', 'Foo'
end
assert_equal 'Nothing known about Foo#bar', e.message
end
def test_parse_name
klass, meth = @driver.parse_name 'Foo::Bar'
assert_equal 'Foo::Bar', klass, 'Foo::Bar class'
assert_equal nil, meth, 'Foo::Bar method'
klass, meth = @driver.parse_name 'Foo#Bar'
assert_equal 'Foo', klass, 'Foo#Bar class'
assert_equal 'Bar', meth, 'Foo#Bar method'
klass, meth = @driver.parse_name 'Foo.Bar'
assert_equal 'Foo', klass, 'Foo#Bar class'
assert_equal 'Bar', meth, 'Foo#Bar method'
klass, meth = @driver.parse_name 'Foo::bar'
assert_equal 'Foo', klass, 'Foo::bar class'
assert_equal 'bar', meth, 'Foo::bar method'
end
end