зеркало из https://github.com/github/ruby.git
Import RDoc r101.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@18121 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
0af4a490b4
Коммит
fd25f74d64
|
@ -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.
|
||||
|
|
134
lib/rdoc.rb
134
lib/rdoc.rb
|
@ -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(/->/, '→')
|
||||
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(/->/, '→')
|
||||
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 = " ::" * level;
|
||||
prefix = ' ::' * 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 %>
|
||||
(<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 %>
|
||||
(<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"] %>
|
||||
<% 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"] %>
|
||||
<% 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"> </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>-></td>
|
||||
<td class="context-item-value"><%= values["new_name"] %></td>
|
||||
</tr>
|
||||
<% if values["desc"] then %>
|
||||
<tr class="top-aligned-row context-row">
|
||||
<td> </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"> [<%= values["rw"] %>] </td>
|
||||
<% end %>
|
||||
<% unless values["rw"] then %>
|
||||
<td class="context-item-value"> </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 %>
|
||||
(<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
|
|||
(<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"] %>
|
||||
<% 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"] %>
|
||||
<% 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"> </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>-></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> </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"> [<%= values["rw"] %>] </td>
|
||||
<% end %>
|
||||
<% unless values["rw"] then %>
|
||||
<td class="context-item-name"><%= attribute["name"] %></td>
|
||||
<% if attribute["rw"] then %>
|
||||
<td class="context-item-value"> [<%= attribute["rw"] %>] </td>
|
||||
<% end
|
||||
unless attribute["rw"] then %>
|
||||
<td class="context-item-value"> </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 %>
|
||||
(<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
|
|
@ -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(/---?/, '—'). #gsub(/--/, '–').
|
||||
item.gsub(/---?/, '—'). #gsub(/--/, '–').
|
||||
|
||||
# convert ... to elipsis (and make sure .... becomes .<elipsis>)
|
||||
gsub(/\.\.\.\./, '.…').gsub(/\.\.\./, '…').
|
||||
|
||||
# convert single closing quote
|
||||
gsub(%r{([^ \t\r\n\[\{\(])\'}, '\1’').
|
||||
gsub(%r{([^ \t\r\n\[\{\(])\'}, '\1’'). # }
|
||||
gsub(%r{\'(?=\W|s\b)}, '’').
|
||||
|
||||
# convert single opening quote
|
||||
gsub(/'/, '‘').
|
||||
|
||||
# convert double closing quote
|
||||
gsub(%r{([^ \t\r\n\[\{\(])\'(?=\W)}, '\1”').
|
||||
gsub(%r{([^ \t\r\n\[\{\(])\'(?=\W)}, '\1”'). # }
|
||||
|
||||
# convert double opening quote
|
||||
gsub(/'/, '“').
|
||||
|
@ -281,7 +328,6 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|||
|
||||
# convert and registered trademark
|
||||
gsub(/\(r\)/, '®')
|
||||
|
||||
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
|
||||
|
|
|
@ -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'
|
||||
|
|
@ -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
|
||||
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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> — <tt>(c)</tt> ©\n</p>\n",
|
||||
util_format("<tt>--</tt> -- <tt>(c)</tt> (c)")
|
||||
assert_equal "<p>\n<b>—</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
|
||||
|
Загрузка…
Ссылка в новой задаче