зеркало из https://github.com/github/ruby.git
* lib/rdoc*: Updated to RDoc 4.0 (pre-release)
* bin/rdoc: ditto * test/rdoc: ditto * NEWS: Updated with RDoc 4.0 information git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37889 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
c72f0daa87
Коммит
1c279a7d27
|
@ -1,3 +1,10 @@
|
|||
Tue Nov 27 13:27:46 2012 Eric Hodel <drbrain@segment7.net>
|
||||
|
||||
* lib/rdoc*: Updated to RDoc 4.0 (pre-release)
|
||||
* bin/rdoc: ditto
|
||||
* test/rdoc*: ditto
|
||||
* NEWS: Updated with RDoc 4.0 information
|
||||
|
||||
Tue Nov 27 12:17:11 2012 Koichi Sasada <ko1@atdot.net>
|
||||
|
||||
* thread.c (rb_thread_terminate_all): retry broadcast only when
|
||||
|
|
11
NEWS
11
NEWS
|
@ -272,6 +272,17 @@ with all sufficient information, see the ChangeLog file.
|
|||
http://rake.rubyforge.org/doc/release_notes/rake-0_9_4_rdoc.html for a list
|
||||
of changes in rake 0.9.3 and 0.9.4.
|
||||
|
||||
* rdoc
|
||||
* rdoc has been updated to version 4.0
|
||||
|
||||
This version is largely backwards-compatible with previous rdoc versions.
|
||||
The most notable change is an update to the ri data format (ri data must
|
||||
be regenerated for gems shared across rdoc versions). Further API changes
|
||||
are internal and won't affect most users.
|
||||
|
||||
See https://github.com/rdoc/rdoc/blob/master/History.rdoc for a list of
|
||||
changes in rdoc 4.0.
|
||||
|
||||
* resolv
|
||||
* new methods:
|
||||
* Resolv::DNS#timeouts=
|
||||
|
|
6
bin/rdoc
6
bin/rdoc
|
@ -5,8 +5,6 @@
|
|||
#
|
||||
# Copyright (c) 2003 Dave Thomas
|
||||
# Released under the same terms as Ruby
|
||||
#
|
||||
# $Revision$
|
||||
|
||||
begin
|
||||
gem 'rdoc'
|
||||
|
@ -20,6 +18,10 @@ require 'rdoc/rdoc'
|
|||
begin
|
||||
r = RDoc::RDoc.new
|
||||
r.document ARGV
|
||||
rescue Errno::ENOSPC
|
||||
$stderr.puts 'Ran out of space creating documentation'
|
||||
$stderr.puts
|
||||
$stderr.puts 'Please free up some space and try again'
|
||||
rescue SystemExit
|
||||
raise
|
||||
rescue Exception => e
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* utf8tbl.c - Convertion Table for nkf
|
||||
*
|
||||
* $Id: utf8tbl.c,v 1.23 2008/02/07 19:25:29 naruse Exp $
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
|
171
lib/rdoc.rb
171
lib/rdoc.rb
|
@ -1,86 +1,55 @@
|
|||
$DEBUG_RDOC = nil
|
||||
|
||||
# :main: README.txt
|
||||
# :main: README.rdoc
|
||||
|
||||
##
|
||||
# RDoc is a Ruby documentation system which contains RDoc::RDoc for generating
|
||||
# documentation, RDoc::RI for interactive documentation and RDoc::Markup for
|
||||
# text markup.
|
||||
# RDoc produces documentation for Ruby source files by parsing the source and
|
||||
# extracting the definition for classes, modules, methods, includes and
|
||||
# requires. It associates these with optional documentation contained in an
|
||||
# immediately preceding comment block then renders the result using an output
|
||||
# formatter.
|
||||
#
|
||||
# RDoc::RDoc produces documentation for Ruby source files. It works similarly
|
||||
# to JavaDoc, parsing the source and extracting the definition for classes,
|
||||
# modules, methods, includes and requires. It associates these with optional
|
||||
# documentation contained in an immediately preceding comment block then
|
||||
# renders the result using an output formatter.
|
||||
#
|
||||
# RDoc::Markup 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.
|
||||
#
|
||||
# RDoc::RI implements the +ri+ command-line tool which displays on-line
|
||||
# documentation for ruby classes, methods, etc. +ri+ features several output
|
||||
# formats and an interactive mode (<tt>ri -i</tt>). See <tt>ri --help</tt>
|
||||
# for further details.
|
||||
# For a simple introduction to writing or generating documentation using RDoc
|
||||
# see the README.
|
||||
#
|
||||
# == Roadmap
|
||||
#
|
||||
# * If you want to use RDoc to create documentation for your Ruby source files,
|
||||
# see RDoc::Markup and refer to <tt>rdoc --help</tt> for command line
|
||||
# usage.
|
||||
# * If you want to write documentation for Ruby files see RDoc::Parser::Ruby
|
||||
# * If you want to write documentation for extensions written in C see
|
||||
# RDoc::Parser::C
|
||||
# * If you want to generate documentation using <tt>rake</tt> see RDoc::Task.
|
||||
# * If you want to drive RDoc programmatically, see RDoc::RDoc.
|
||||
# * If you want to use the library to format text blocks into HTML, look at
|
||||
# RDoc::Markup.
|
||||
# * If you want to make an RDoc plugin such as a generator or directive
|
||||
# handler see RDoc::RDoc.
|
||||
# * If you want to write your own output generator see RDoc::Generator.
|
||||
# If you think you found a bug in RDoc see DEVELOPERS@Bugs
|
||||
#
|
||||
# == Summary
|
||||
# If you want to use RDoc to create documentation for your Ruby source files,
|
||||
# see RDoc::Markup and refer to <tt>rdoc --help</tt> for command line usage.
|
||||
#
|
||||
# Once installed, you can create documentation using the +rdoc+ command
|
||||
# If you want to set the default markup format see
|
||||
# RDoc::Markup@Supported+Formats
|
||||
#
|
||||
# % rdoc [options] [names...]
|
||||
# If you want to store rdoc configuration in your gem (such as the default
|
||||
# markup format) see RDoc::Options@Saved+Options
|
||||
#
|
||||
# For an up-to-date option summary, type
|
||||
# If you want to write documentation for Ruby files see RDoc::Parser::Ruby
|
||||
#
|
||||
# % rdoc --help
|
||||
# If you want to write documentation for extensions written in C see
|
||||
# RDoc::Parser::C
|
||||
#
|
||||
# A typical use might be to generate documentation for a package of Ruby
|
||||
# source (such as RDoc itself).
|
||||
# If you want to generate documentation using <tt>rake</tt> see RDoc::Task.
|
||||
#
|
||||
# % rdoc
|
||||
# If you want to drive RDoc programmatically, see RDoc::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+.
|
||||
# If you want to use the library to format text blocks into HTML or other
|
||||
# formats, look at RDoc::Markup.
|
||||
#
|
||||
# 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
|
||||
# If you want to make an RDoc plugin such as a generator or directive handler
|
||||
# see RDoc::RDoc.
|
||||
#
|
||||
# % rdoc --main README.txt
|
||||
# If you want to write your own output generator see RDoc::Generator.
|
||||
#
|
||||
# You'll find information on the various formatting tricks you can use
|
||||
# in comment blocks in the documentation this generates.
|
||||
# If you want an overview of how RDoc works see DEVELOPERS
|
||||
#
|
||||
# RDoc uses file extensions to determine how to process each file. File names
|
||||
# ending +.rb+ and +.rbw+ 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.
|
||||
#
|
||||
# == Other stuff
|
||||
# == Credits
|
||||
#
|
||||
# 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.
|
||||
|
@ -92,19 +61,10 @@ module RDoc
|
|||
|
||||
class Error < RuntimeError; end
|
||||
|
||||
def self.const_missing const_name # :nodoc:
|
||||
if const_name.to_s == 'RDocError' then
|
||||
warn "RDoc::RDocError is deprecated"
|
||||
return Error
|
||||
end
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
##
|
||||
# RDoc version you are using
|
||||
|
||||
VERSION = '3.9.4'
|
||||
VERSION = '4.0'
|
||||
|
||||
##
|
||||
# Method visibilities
|
||||
|
@ -143,5 +103,80 @@ module RDoc
|
|||
METHOD_MODIFIERS = GENERAL_MODIFIERS +
|
||||
%w[arg args yield yields notnew not-new not_new doc]
|
||||
|
||||
##
|
||||
# Loads the best available YAML library.
|
||||
|
||||
def self.load_yaml
|
||||
begin
|
||||
gem 'psych'
|
||||
rescue Gem::LoadError
|
||||
end
|
||||
|
||||
begin
|
||||
require 'psych'
|
||||
rescue ::LoadError
|
||||
ensure
|
||||
require 'yaml'
|
||||
end
|
||||
end
|
||||
|
||||
autoload :RDoc, 'rdoc/rdoc'
|
||||
|
||||
autoload :TestCase, 'rdoc/test_case'
|
||||
|
||||
autoload :CrossReference, 'rdoc/cross_reference'
|
||||
autoload :ERBIO, 'rdoc/erbio'
|
||||
autoload :ERBPartial, 'rdoc/erb_partial'
|
||||
autoload :Encoding, 'rdoc/encoding'
|
||||
autoload :Generator, 'rdoc/generator'
|
||||
autoload :Options, 'rdoc/options'
|
||||
autoload :Parser, 'rdoc/parser'
|
||||
autoload :Servlet, 'rdoc/servlet'
|
||||
autoload :RI, 'rdoc/ri'
|
||||
autoload :Stats, 'rdoc/stats'
|
||||
autoload :Store, 'rdoc/store'
|
||||
autoload :Task, 'rdoc/task'
|
||||
autoload :Text, 'rdoc/text'
|
||||
|
||||
autoload :Markdown, 'rdoc/markdown'
|
||||
autoload :Markup, 'rdoc/markup'
|
||||
autoload :RD, 'rdoc/rd'
|
||||
autoload :TomDoc, 'rdoc/tom_doc'
|
||||
|
||||
autoload :KNOWN_CLASSES, 'rdoc/known_classes'
|
||||
|
||||
autoload :RubyLex, 'rdoc/ruby_lex'
|
||||
autoload :RubyToken, 'rdoc/ruby_token'
|
||||
autoload :TokenStream, 'rdoc/token_stream'
|
||||
|
||||
autoload :Comment, 'rdoc/comment'
|
||||
|
||||
# code objects
|
||||
#
|
||||
# We represent the various high-level code constructs that appear in Ruby
|
||||
# programs: classes, modules, methods, and so on.
|
||||
autoload :CodeObject, 'rdoc/code_object'
|
||||
|
||||
autoload :Context, 'rdoc/context'
|
||||
autoload :TopLevel, 'rdoc/top_level'
|
||||
|
||||
autoload :AnonClass, 'rdoc/anon_class'
|
||||
autoload :ClassModule, 'rdoc/class_module'
|
||||
autoload :NormalClass, 'rdoc/normal_class'
|
||||
autoload :NormalModule, 'rdoc/normal_module'
|
||||
autoload :SingleClass, 'rdoc/single_class'
|
||||
|
||||
autoload :Alias, 'rdoc/alias'
|
||||
autoload :AnyMethod, 'rdoc/any_method'
|
||||
autoload :MethodAttr, 'rdoc/method_attr'
|
||||
autoload :GhostMethod, 'rdoc/ghost_method'
|
||||
autoload :MetaMethod, 'rdoc/meta_method'
|
||||
autoload :Attr, 'rdoc/attr'
|
||||
|
||||
autoload :Constant, 'rdoc/constant'
|
||||
autoload :Include, 'rdoc/include'
|
||||
autoload :Extend, 'rdoc/extend'
|
||||
autoload :Require, 'rdoc/require'
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
require 'rdoc/code_object'
|
||||
|
||||
##
|
||||
# Represent an alias, which is an old_name/new_name pair associated with a
|
||||
# particular context
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
require 'rdoc/class_module'
|
||||
|
||||
##
|
||||
# An anonymous class like:
|
||||
#
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
require 'rdoc/method_attr'
|
||||
require 'rdoc/token_stream'
|
||||
|
||||
##
|
||||
# AnyMethod is the base class for objects representing methods
|
||||
|
||||
class RDoc::AnyMethod < RDoc::MethodAttr
|
||||
|
||||
MARSHAL_VERSION = 1 # :nodoc:
|
||||
##
|
||||
# 2::
|
||||
# RDoc 4
|
||||
# Added calls_super
|
||||
# Added parent name and class
|
||||
# Added section title
|
||||
|
||||
MARSHAL_VERSION = 2 # :nodoc:
|
||||
|
||||
##
|
||||
# Don't rename \#initialize to \::new
|
||||
|
@ -28,6 +32,11 @@ class RDoc::AnyMethod < RDoc::MethodAttr
|
|||
|
||||
attr_accessor :params
|
||||
|
||||
##
|
||||
# If true this method uses +super+ to call a superclass version
|
||||
|
||||
attr_accessor :calls_super
|
||||
|
||||
include RDoc::TokenStream
|
||||
|
||||
##
|
||||
|
@ -39,6 +48,8 @@ class RDoc::AnyMethod < RDoc::MethodAttr
|
|||
@c_function = nil
|
||||
@dont_rename_initialize = false
|
||||
@token_stream = nil
|
||||
@calls_super = false
|
||||
@superclass_method = nil
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -97,6 +108,10 @@ class RDoc::AnyMethod < RDoc::MethodAttr
|
|||
aliases,
|
||||
@params,
|
||||
@file.absolute_name,
|
||||
@calls_super,
|
||||
@parent.name,
|
||||
@parent.class,
|
||||
@section.title,
|
||||
]
|
||||
end
|
||||
|
||||
|
@ -107,34 +122,44 @@ class RDoc::AnyMethod < RDoc::MethodAttr
|
|||
# * #full_name
|
||||
# * #parent_name
|
||||
|
||||
def marshal_load(array)
|
||||
def marshal_load array
|
||||
@dont_rename_initialize = nil
|
||||
@is_alias_for = nil
|
||||
@token_stream = nil
|
||||
@aliases = []
|
||||
@parent = nil
|
||||
@parent_name = nil
|
||||
@parent_class = nil
|
||||
@section = nil
|
||||
@file = nil
|
||||
|
||||
version = array[0]
|
||||
@name = array[1]
|
||||
@full_name = array[2]
|
||||
@singleton = array[3]
|
||||
@visibility = array[4]
|
||||
@comment = array[5]
|
||||
@call_seq = array[6]
|
||||
@block_params = array[7]
|
||||
version = array[0]
|
||||
@name = array[1]
|
||||
@full_name = array[2]
|
||||
@singleton = array[3]
|
||||
@visibility = array[4]
|
||||
@comment = array[5]
|
||||
@call_seq = array[6]
|
||||
@block_params = array[7]
|
||||
# 8 handled below
|
||||
@params = array[9]
|
||||
# 10 handled below
|
||||
@calls_super = array[11]
|
||||
@parent_name = array[12]
|
||||
@parent_title = array[13]
|
||||
@section_title = array[14]
|
||||
|
||||
array[8].each do |new_name, comment|
|
||||
add_alias RDoc::Alias.new(nil, @name, new_name, comment, @singleton)
|
||||
end
|
||||
|
||||
@params = array[9]
|
||||
|
||||
@parent_name = if @full_name =~ /#/ then
|
||||
$`
|
||||
else
|
||||
name = @full_name.split('::')
|
||||
name.pop
|
||||
name.join '::'
|
||||
end
|
||||
@parent_name ||= if @full_name =~ /#/ then
|
||||
$`
|
||||
else
|
||||
name = @full_name.split('::')
|
||||
name.pop
|
||||
name.join '::'
|
||||
end
|
||||
|
||||
@file = RDoc::TopLevel.new array[10] if version > 0
|
||||
end
|
||||
|
@ -169,7 +194,9 @@ class RDoc::AnyMethod < RDoc::MethodAttr
|
|||
return []
|
||||
end
|
||||
|
||||
params.gsub(/\s+/, '').split ','
|
||||
params = params.gsub(/\s+/, '').split ','
|
||||
|
||||
params.map { |param| param.sub(/=.*/, '') }
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -181,10 +208,12 @@ class RDoc::AnyMethod < RDoc::MethodAttr
|
|||
params = @call_seq.split("\n").last
|
||||
params = params.sub(/[^( ]+/, '')
|
||||
params = params.sub(/(\|[^|]+\|)\s*\.\.\.\s*(end|\})/, '\1 \2')
|
||||
else
|
||||
elsif @params then
|
||||
params = @params.gsub(/\s*\#.*/, '')
|
||||
params = params.tr("\n", " ").squeeze(" ")
|
||||
params = "(#{params})" unless params[0] == ?(
|
||||
else
|
||||
params = ''
|
||||
end
|
||||
|
||||
if @block_params then
|
||||
|
@ -203,5 +232,31 @@ class RDoc::AnyMethod < RDoc::MethodAttr
|
|||
params
|
||||
end
|
||||
|
||||
##
|
||||
# Sets the store for this method and its referenced code objects.
|
||||
|
||||
def store= store
|
||||
super
|
||||
|
||||
@file = @store.add_file @file.full_name if @file
|
||||
end
|
||||
|
||||
##
|
||||
# For methods that +super+, find the superclass method that would be called.
|
||||
|
||||
def superclass_method
|
||||
return unless @calls_super
|
||||
return @superclass_method if @superclass_method
|
||||
|
||||
parent.each_ancestor do |ancestor|
|
||||
if method = ancestor.method_list.find { |m| m.name == @name } then
|
||||
@superclass_method = method
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
@superclass_method
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
require 'rdoc/method_attr'
|
||||
|
||||
##
|
||||
# An attribute created by \#attr, \#attr_reader, \#attr_writer or
|
||||
# \#attr_accessor
|
||||
|
||||
class RDoc::Attr < RDoc::MethodAttr
|
||||
|
||||
MARSHAL_VERSION = 2 # :nodoc:
|
||||
##
|
||||
# 3::
|
||||
# RDoc 4
|
||||
# Added parent name and class
|
||||
# Added section title
|
||||
|
||||
MARSHAL_VERSION = 3 # :nodoc:
|
||||
|
||||
##
|
||||
# Is the attribute readable ('R'), writable ('W') or both ('RW')?
|
||||
|
@ -57,6 +61,16 @@ class RDoc::Attr < RDoc::MethodAttr
|
|||
'attribute'
|
||||
end
|
||||
|
||||
##
|
||||
# Attributes never call super. See RDoc::AnyMethod#calls_super
|
||||
#
|
||||
# An RDoc::Attr can show up in the method list in some situations (see
|
||||
# Gem::ConfigFile)
|
||||
|
||||
def calls_super # :nodoc:
|
||||
false
|
||||
end
|
||||
|
||||
##
|
||||
# Returns attr_reader, attr_writer or attr_accessor as appropriate.
|
||||
|
||||
|
@ -93,6 +107,9 @@ class RDoc::Attr < RDoc::MethodAttr
|
|||
parse(@comment),
|
||||
singleton,
|
||||
@file.absolute_name,
|
||||
@parent.full_name,
|
||||
@parent.class,
|
||||
@section.title
|
||||
]
|
||||
end
|
||||
|
||||
|
@ -104,17 +121,28 @@ class RDoc::Attr < RDoc::MethodAttr
|
|||
# * #parent_name
|
||||
|
||||
def marshal_load array
|
||||
version = array[0]
|
||||
@name = array[1]
|
||||
@full_name = array[2]
|
||||
@rw = array[3]
|
||||
@visibility = array[4]
|
||||
@comment = array[5]
|
||||
@singleton = array[6] || false # MARSHAL_VERSION == 0
|
||||
@aliases = []
|
||||
@parent = nil
|
||||
@parent_name = nil
|
||||
@parent_class = nil
|
||||
@section = nil
|
||||
@file = nil
|
||||
|
||||
version = array[0]
|
||||
@name = array[1]
|
||||
@full_name = array[2]
|
||||
@rw = array[3]
|
||||
@visibility = array[4]
|
||||
@comment = array[5]
|
||||
@singleton = array[6] || false # MARSHAL_VERSION == 0
|
||||
# 7 handled below
|
||||
@parent_name = array[8]
|
||||
@parent_class = array[9]
|
||||
@section_title = array[10]
|
||||
|
||||
@file = RDoc::TopLevel.new array[7] if version > 1
|
||||
|
||||
@parent_name = @full_name
|
||||
@parent_name ||= @full_name.split('#', 2).first
|
||||
end
|
||||
|
||||
def pretty_print q # :nodoc:
|
||||
|
@ -132,5 +160,14 @@ class RDoc::Attr < RDoc::MethodAttr
|
|||
"#{definition} #{name} in: #{parent}"
|
||||
end
|
||||
|
||||
##
|
||||
# Attributes do not have token streams.
|
||||
#
|
||||
# An RDoc::Attr can show up in the method list in some situations (see
|
||||
# Gem::ConfigFile)
|
||||
|
||||
def token_stream # :nodoc:
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
require 'rdoc/context'
|
||||
|
||||
##
|
||||
# ClassModule is the base class for objects representing either a class or a
|
||||
# module.
|
||||
|
@ -13,8 +11,17 @@ class RDoc::ClassModule < RDoc::Context
|
|||
# * Added file to constants
|
||||
# * Added file to includes
|
||||
# * Added file to methods
|
||||
# 2::
|
||||
# RDoc 3.13
|
||||
# * Added extends
|
||||
# 3::
|
||||
# RDoc 4.0
|
||||
# * Added sections
|
||||
# * Added in_files
|
||||
# * Added parent name
|
||||
# * Complete Constant dump
|
||||
|
||||
MARSHAL_VERSION = 1 # :nodoc:
|
||||
MARSHAL_VERSION = 3 # :nodoc:
|
||||
|
||||
##
|
||||
# Constants that are aliases for this class or module
|
||||
|
@ -56,6 +63,7 @@ class RDoc::ClassModule < RDoc::Context
|
|||
klass.external_aliases.concat mod.external_aliases
|
||||
klass.constants.concat mod.constants
|
||||
klass.includes.concat mod.includes
|
||||
klass.extends.concat mod.extends
|
||||
|
||||
klass.methods_hash.update mod.methods_hash
|
||||
klass.constants_hash.update mod.constants_hash
|
||||
|
@ -84,6 +92,7 @@ class RDoc::ClassModule < RDoc::Context
|
|||
klass.external_aliases +
|
||||
klass.constants +
|
||||
klass.includes +
|
||||
klass.extends +
|
||||
klass.classes +
|
||||
klass.modules).each do |obj|
|
||||
obj.parent = klass
|
||||
|
@ -115,16 +124,32 @@ class RDoc::ClassModule < RDoc::Context
|
|||
# across multiple runs.
|
||||
|
||||
def add_comment comment, location
|
||||
return if comment.empty? or not document_self
|
||||
return unless document_self
|
||||
|
||||
original = comment
|
||||
|
||||
comment = normalize_comment comment
|
||||
comment = case comment
|
||||
when RDoc::Comment then
|
||||
comment.normalize
|
||||
else
|
||||
normalize_comment comment
|
||||
end
|
||||
@comment_location << [comment, location]
|
||||
|
||||
self.comment = original
|
||||
end
|
||||
|
||||
def add_things my_things, other_things # :nodoc:
|
||||
other_things.each do |group, things|
|
||||
my_things[group].each { |thing| yield false, thing } if
|
||||
my_things.include? group
|
||||
|
||||
things.each do |thing|
|
||||
yield true, thing
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Ancestors list for this ClassModule: the list of included modules
|
||||
# (classes will add their superclass if any).
|
||||
|
@ -141,6 +166,11 @@ class RDoc::ClassModule < RDoc::Context
|
|||
includes.map { |i| i.module }.reverse
|
||||
end
|
||||
|
||||
##
|
||||
# Ancestors of this class or module only
|
||||
|
||||
alias direct_ancestors ancestors
|
||||
|
||||
##
|
||||
# Clears the comment. Used by the ruby parser.
|
||||
|
||||
|
@ -155,9 +185,13 @@ class RDoc::ClassModule < RDoc::Context
|
|||
# more like <tt>+=</tt>.
|
||||
|
||||
def comment= comment
|
||||
return if comment.empty?
|
||||
comment = case comment
|
||||
when RDoc::Comment then
|
||||
comment.normalize
|
||||
else
|
||||
normalize_comment comment
|
||||
end
|
||||
|
||||
comment = normalize_comment comment
|
||||
comment = "#{@comment}\n---\n#{comment}" unless @comment.empty?
|
||||
|
||||
super comment
|
||||
|
@ -166,7 +200,7 @@ class RDoc::ClassModule < RDoc::Context
|
|||
##
|
||||
# Prepares this ClassModule for use by a generator.
|
||||
#
|
||||
# See RDoc::TopLevel::complete
|
||||
# See RDoc::Store#complete
|
||||
|
||||
def complete min_visibility
|
||||
update_aliases
|
||||
|
@ -175,13 +209,23 @@ class RDoc::ClassModule < RDoc::Context
|
|||
remove_invisible min_visibility
|
||||
end
|
||||
|
||||
##
|
||||
# Does this ClassModule or any of its methods have document_self set?
|
||||
|
||||
def document_self_or_methods
|
||||
document_self || method_list.any?{ |m| m.document_self }
|
||||
end
|
||||
|
||||
##
|
||||
# Iterates the ancestors of this class or module for which an
|
||||
# RDoc::ClassModule exists.
|
||||
|
||||
def each_ancestor # :yields: module
|
||||
return enum_for __method__ unless block_given?
|
||||
|
||||
ancestors.each do |mod|
|
||||
next if String === mod
|
||||
next if self == mod
|
||||
yield mod
|
||||
end
|
||||
end
|
||||
|
@ -215,8 +259,8 @@ class RDoc::ClassModule < RDoc::Context
|
|||
# Return the fully qualified name of this class or module
|
||||
|
||||
def full_name
|
||||
@full_name ||= if RDoc::ClassModule === @parent then
|
||||
"#{@parent.full_name}::#{@name}"
|
||||
@full_name ||= if RDoc::ClassModule === parent then
|
||||
"#{parent.full_name}::#{@name}"
|
||||
else
|
||||
@name
|
||||
end
|
||||
|
@ -250,13 +294,20 @@ class RDoc::ClassModule < RDoc::Context
|
|||
@superclass,
|
||||
parse(@comment_location),
|
||||
attrs,
|
||||
constants.map do |const|
|
||||
[const.name, parse(const.comment), const.file_name]
|
||||
end,
|
||||
constants,
|
||||
includes.map do |incl|
|
||||
[incl.name, parse(incl.comment), incl.file_name]
|
||||
end,
|
||||
method_types,
|
||||
extends.map do |ext|
|
||||
[ext.name, parse(ext.comment), ext.file_name]
|
||||
end,
|
||||
@sections.values,
|
||||
@in_files.map do |tl|
|
||||
tl.absolute_name
|
||||
end,
|
||||
parent.full_name,
|
||||
parent.class,
|
||||
]
|
||||
end
|
||||
|
||||
|
@ -268,6 +319,8 @@ class RDoc::ClassModule < RDoc::Context
|
|||
@parent = nil
|
||||
@temporary_section = nil
|
||||
@visibility = nil
|
||||
@classes = {}
|
||||
@modules = {}
|
||||
|
||||
@name = array[1]
|
||||
@full_name = array[2]
|
||||
|
@ -291,9 +344,14 @@ class RDoc::ClassModule < RDoc::Context
|
|||
attr.record_location RDoc::TopLevel.new file
|
||||
end
|
||||
|
||||
array[6].each do |name, comment, file|
|
||||
const = add_constant RDoc::Constant.new(name, nil, comment)
|
||||
const.record_location RDoc::TopLevel.new file
|
||||
array[6].each do |constant, comment, file|
|
||||
case constant
|
||||
when RDoc::Constant then
|
||||
add_constant constant
|
||||
else
|
||||
constant = add_constant RDoc::Constant.new(constant, nil, comment)
|
||||
constant.record_location RDoc::TopLevel.new file
|
||||
end
|
||||
end
|
||||
|
||||
array[7].each do |name, comment, file|
|
||||
|
@ -313,6 +371,27 @@ class RDoc::ClassModule < RDoc::Context
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
array[9].each do |name, comment, file|
|
||||
ext = add_extend RDoc::Extend.new(name, comment)
|
||||
ext.record_location RDoc::TopLevel.new file
|
||||
end if array[9] # Support Marshal version 1
|
||||
|
||||
sections = (array[10] || []).map do |section|
|
||||
[section.title, section]
|
||||
end
|
||||
|
||||
@sections = Hash[*sections.flatten]
|
||||
@current_section = add_section nil
|
||||
|
||||
@in_files = []
|
||||
|
||||
(array[11] || []).each do |filename|
|
||||
record_location RDoc::TopLevel.new filename
|
||||
end
|
||||
|
||||
@parent_name = array[12]
|
||||
@parent_class = array[13]
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -321,6 +400,9 @@ class RDoc::ClassModule < RDoc::Context
|
|||
# The data in +class_module+ is preferred over the receiver.
|
||||
|
||||
def merge class_module
|
||||
@parent = class_module.parent
|
||||
@parent_name = class_module.parent_name
|
||||
|
||||
other_document = parse class_module.comment_location
|
||||
|
||||
if other_document then
|
||||
|
@ -360,6 +442,18 @@ class RDoc::ClassModule < RDoc::Context
|
|||
end
|
||||
end
|
||||
|
||||
@includes.uniq! # clean up
|
||||
|
||||
merge_collections extends, cm.extends, other_files do |add, ext|
|
||||
if add then
|
||||
add_extend ext
|
||||
else
|
||||
@extends.delete ext
|
||||
end
|
||||
end
|
||||
|
||||
@extends.uniq! # clean up
|
||||
|
||||
merge_collections method_list, cm.method_list, other_files do |add, meth|
|
||||
if add then
|
||||
add_method meth
|
||||
|
@ -369,6 +463,8 @@ class RDoc::ClassModule < RDoc::Context
|
|||
end
|
||||
end
|
||||
|
||||
merge_sections cm
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
|
@ -391,22 +487,46 @@ class RDoc::ClassModule < RDoc::Context
|
|||
my_things = mine. group_by { |thing| thing.file }
|
||||
other_things = other.group_by { |thing| thing.file }
|
||||
|
||||
my_things.delete_if do |file, things|
|
||||
next false unless other_files.include? file
|
||||
remove_things my_things, other_files, &block
|
||||
add_things my_things, other_things, &block
|
||||
end
|
||||
|
||||
things.each do |thing|
|
||||
yield false, thing
|
||||
end
|
||||
##
|
||||
# Merges the comments in this ClassModule with the comments in the other
|
||||
# ClassModule +cm+.
|
||||
|
||||
true
|
||||
def merge_sections cm # :nodoc:
|
||||
my_sections = sections.group_by { |section| section.title }
|
||||
other_sections = cm.sections.group_by { |section| section.title }
|
||||
|
||||
other_files = cm.in_files
|
||||
|
||||
remove_things my_sections, other_files do |_, section|
|
||||
@sections.delete section.title
|
||||
end
|
||||
|
||||
other_things.each do |file, things|
|
||||
my_things[file].each { |thing| yield false, thing } if
|
||||
my_things.include?(file)
|
||||
other_sections.each do |group, sections|
|
||||
if my_sections.include? group
|
||||
my_sections[group].each do |my_section|
|
||||
other_section = cm.sections_hash[group]
|
||||
|
||||
things.each do |thing|
|
||||
yield true, thing
|
||||
my_comments = my_section.comments
|
||||
other_comments = other_section.comments
|
||||
|
||||
other_files = other_section.in_files
|
||||
|
||||
merge_collections my_comments, other_comments, other_files do |add, comment|
|
||||
if add then
|
||||
my_section.add_comment comment
|
||||
else
|
||||
my_section.remove_comment comment
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
sections.each do |section|
|
||||
add_section group, section.comments
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -438,11 +558,15 @@ class RDoc::ClassModule < RDoc::Context
|
|||
when Array then
|
||||
docs = comment_location.map do |comment, location|
|
||||
doc = super comment
|
||||
doc.file = location.absolute_name
|
||||
doc.file = location
|
||||
doc
|
||||
end
|
||||
|
||||
RDoc::Markup::Document.new(*docs)
|
||||
when RDoc::Comment then
|
||||
doc = super comment_location.text, comment_location.format
|
||||
doc.file = comment_location.location
|
||||
doc
|
||||
when RDoc::Markup::Document then
|
||||
return comment_location
|
||||
else
|
||||
|
@ -451,10 +575,10 @@ class RDoc::ClassModule < RDoc::Context
|
|||
end
|
||||
|
||||
##
|
||||
# Path to this class or module
|
||||
# Path to this class or module for use with HTML generator output.
|
||||
|
||||
def path
|
||||
http_url RDoc::RDoc.current.generator.class_dir
|
||||
http_url @store.rdoc.generator.class_dir
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -488,21 +612,61 @@ class RDoc::ClassModule < RDoc::Context
|
|||
|
||||
modules_hash.each_key do |name|
|
||||
full_name = prefix + name
|
||||
modules_hash.delete name unless RDoc::TopLevel.all_modules_hash[full_name]
|
||||
modules_hash.delete name unless @store.modules_hash[full_name]
|
||||
end
|
||||
|
||||
classes_hash.each_key do |name|
|
||||
full_name = prefix + name
|
||||
classes_hash.delete name unless RDoc::TopLevel.all_classes_hash[full_name]
|
||||
classes_hash.delete name unless @store.classes_hash[full_name]
|
||||
end
|
||||
end
|
||||
|
||||
def remove_things my_things, other_files # :nodoc:
|
||||
my_things.delete_if do |file, things|
|
||||
next false unless other_files.include? file
|
||||
|
||||
things.each do |thing|
|
||||
yield false, thing
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Search record used by RDoc::Generator::JsonIndex
|
||||
|
||||
def search_record
|
||||
[
|
||||
name,
|
||||
full_name,
|
||||
full_name,
|
||||
'',
|
||||
path,
|
||||
'',
|
||||
snippet(@comment_location),
|
||||
]
|
||||
end
|
||||
|
||||
##
|
||||
# Sets the store for this class or module and its contained code objects.
|
||||
|
||||
def store= store
|
||||
super
|
||||
|
||||
@attributes .each do |attr| attr.store = store end
|
||||
@constants .each do |const| const.store = store end
|
||||
@includes .each do |incl| incl.store = store end
|
||||
@extends .each do |ext| ext.store = store end
|
||||
@method_list.each do |meth| meth.store = store end
|
||||
end
|
||||
|
||||
##
|
||||
# Get the superclass of this class. Attempts to retrieve the superclass
|
||||
# object, returns the name if it is not known.
|
||||
|
||||
def superclass
|
||||
RDoc::TopLevel.find_class_named(@superclass) || @superclass
|
||||
@store.find_class_named(@superclass) || @superclass
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -533,7 +697,7 @@ class RDoc::ClassModule < RDoc::Context
|
|||
# aliases through a constant.
|
||||
#
|
||||
# The aliased module/class is replaced in the children and in
|
||||
# RDoc::TopLevel::all_modules_hash or RDoc::TopLevel::all_classes_hash
|
||||
# RDoc::Store#modules_hash or RDoc::Store#classes_hash
|
||||
# by a copy that has <tt>RDoc::ClassModule#is_alias_for</tt> set to
|
||||
# the aliased module/class, and this copy is added to <tt>#aliases</tt>
|
||||
# of the aliased module/class.
|
||||
|
@ -548,16 +712,21 @@ class RDoc::ClassModule < RDoc::Context
|
|||
next unless cm = const.is_alias_for
|
||||
cm_alias = cm.dup
|
||||
cm_alias.name = const.name
|
||||
cm_alias.parent = self
|
||||
cm_alias.full_name = nil # force update for new parent
|
||||
|
||||
# Don't move top-level aliases under Object, they look ugly there
|
||||
unless RDoc::TopLevel === cm_alias.parent then
|
||||
cm_alias.parent = self
|
||||
cm_alias.full_name = nil # force update for new parent
|
||||
end
|
||||
|
||||
cm_alias.aliases.clear
|
||||
cm_alias.is_alias_for = cm
|
||||
|
||||
if cm.module? then
|
||||
RDoc::TopLevel.all_modules_hash[cm_alias.full_name] = cm_alias
|
||||
@store.modules_hash[cm_alias.full_name] = cm_alias
|
||||
modules_hash[const.name] = cm_alias
|
||||
else
|
||||
RDoc::TopLevel.all_classes_hash[cm_alias.full_name] = cm_alias
|
||||
@store.classes_hash[cm_alias.full_name] = cm_alias
|
||||
classes_hash[const.name] = cm_alias
|
||||
end
|
||||
|
||||
|
@ -574,8 +743,26 @@ class RDoc::ClassModule < RDoc::Context
|
|||
def update_includes
|
||||
includes.reject! do |include|
|
||||
mod = include.module
|
||||
!(String === mod) && RDoc::TopLevel.all_modules_hash[mod.full_name].nil?
|
||||
!(String === mod) && @store.modules_hash[mod.full_name].nil?
|
||||
end
|
||||
|
||||
includes.uniq!
|
||||
end
|
||||
|
||||
##
|
||||
# Deletes from #extends those whose module has been removed from the
|
||||
# documentation.
|
||||
#--
|
||||
# FIXME: like update_includes, extends are not reliably removed
|
||||
|
||||
def update_extends
|
||||
extends.reject! do |ext|
|
||||
mod = ext.module
|
||||
|
||||
!(String === mod) && @store.modules_hash[mod.full_name].nil?
|
||||
end
|
||||
|
||||
extends.uniq!
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
require 'rdoc'
|
||||
require 'rdoc/text'
|
||||
|
||||
##
|
||||
# Base class for the RDoc code tree.
|
||||
#
|
||||
|
@ -78,9 +75,9 @@ class RDoc::CodeObject
|
|||
attr_accessor :offset
|
||||
|
||||
##
|
||||
# Our parent CodeObject
|
||||
# Sets the parent CodeObject
|
||||
|
||||
attr_accessor :parent
|
||||
attr_writer :parent
|
||||
|
||||
##
|
||||
# Did we ever receive a +:nodoc:+ directive?
|
||||
|
@ -88,9 +85,14 @@ class RDoc::CodeObject
|
|||
attr_reader :received_nodoc
|
||||
|
||||
##
|
||||
# Which section are we in
|
||||
# Set the section this CodeObject is in
|
||||
|
||||
attr_accessor :section
|
||||
attr_writer :section
|
||||
|
||||
##
|
||||
# The RDoc::Store for this object.
|
||||
|
||||
attr_accessor :store
|
||||
|
||||
##
|
||||
# We are the model of the code, but we know that at some point we will be
|
||||
|
@ -103,11 +105,16 @@ class RDoc::CodeObject
|
|||
# Creates a new CodeObject that will document itself and its children
|
||||
|
||||
def initialize
|
||||
@metadata = {}
|
||||
@comment = ''
|
||||
@parent = nil
|
||||
@file = nil
|
||||
@full_name = nil
|
||||
@metadata = {}
|
||||
@comment = ''
|
||||
@parent = nil
|
||||
@parent_name = nil # for loading
|
||||
@parent_class = nil # for loading
|
||||
@section = nil
|
||||
@section_title = nil # for loading
|
||||
@file = nil
|
||||
@full_name = nil
|
||||
@store = nil
|
||||
|
||||
@document_children = true
|
||||
@document_self = true
|
||||
|
@ -124,11 +131,11 @@ class RDoc::CodeObject
|
|||
@comment = case comment
|
||||
when NilClass then ''
|
||||
when RDoc::Markup::Document then comment
|
||||
when RDoc::Comment then comment.normalize
|
||||
else
|
||||
if comment and not comment.empty? then
|
||||
normalize_comment comment
|
||||
else
|
||||
# TODO is this sufficient?
|
||||
# HACK correct fix is to have #initialize create @comment
|
||||
# with the correct encoding
|
||||
if String === @comment and
|
||||
|
@ -216,7 +223,7 @@ class RDoc::CodeObject
|
|||
|
||||
##
|
||||
# Force the documentation of this object unless documentation
|
||||
# has been turned off by :endoc:
|
||||
# has been turned off by :enddoc:
|
||||
#--
|
||||
# HACK untested, was assigning to an ivar
|
||||
|
||||
|
@ -261,6 +268,29 @@ class RDoc::CodeObject
|
|||
@ignored
|
||||
end
|
||||
|
||||
##
|
||||
# Our parent CodeObject. The parent may be missing for classes loaded from
|
||||
# legacy RI data stores.
|
||||
|
||||
def parent
|
||||
return @parent if @parent
|
||||
return nil unless @parent_name
|
||||
|
||||
if @parent_class == RDoc::TopLevel then
|
||||
@parent = @store.add_file @parent_name
|
||||
else
|
||||
@parent = @store.find_class_or_module @parent_name
|
||||
|
||||
return @parent if @parent
|
||||
|
||||
begin
|
||||
@parent = @store.load_class @parent_name
|
||||
rescue RDoc::Store::MissingFileError
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# File name of our parent
|
||||
|
||||
|
@ -283,9 +313,19 @@ class RDoc::CodeObject
|
|||
@file = top_level
|
||||
end
|
||||
|
||||
##
|
||||
# The section this CodeObject is in. Sections allow grouping of constants,
|
||||
# attributes and methods inside a class or module.
|
||||
|
||||
def section
|
||||
return @section if @section
|
||||
|
||||
@section = parent.add_section @section_title if parent
|
||||
end
|
||||
|
||||
##
|
||||
# Enable capture of documentation unless documentation has been
|
||||
# turned off by :endoc:
|
||||
# turned off by :enddoc:
|
||||
|
||||
def start_doc
|
||||
return if @done_documenting
|
||||
|
|
|
@ -1,23 +1,5 @@
|
|||
# We represent the various high-level code constructs that appear in Ruby
|
||||
# programs: classes, modules, methods, and so on.
|
||||
# This file was used to load all the RDoc::CodeObject subclasses at once. Now
|
||||
# autoload handles this.
|
||||
|
||||
require 'rdoc/code_object'
|
||||
require 'rdoc/context'
|
||||
require 'rdoc/top_level'
|
||||
|
||||
require 'rdoc/class_module'
|
||||
require 'rdoc/normal_class'
|
||||
require 'rdoc/normal_module'
|
||||
require 'rdoc/anon_class'
|
||||
require 'rdoc/single_class'
|
||||
|
||||
require 'rdoc/any_method'
|
||||
require 'rdoc/alias'
|
||||
require 'rdoc/ghost_method'
|
||||
require 'rdoc/meta_method'
|
||||
|
||||
require 'rdoc/attr'
|
||||
require 'rdoc/constant'
|
||||
require 'rdoc/require'
|
||||
require 'rdoc/include'
|
||||
require 'rdoc'
|
||||
|
||||
|
|
|
@ -0,0 +1,232 @@
|
|||
##
|
||||
# A comment holds the text comment for a RDoc::CodeObject and provides a
|
||||
# unified way of cleaning it up and parsing it into an RDoc::Markup::Document.
|
||||
#
|
||||
# Each comment may have a different markup format set by #format=. By default
|
||||
# 'rdoc' is used. The :markup: directive tells RDoc which format to use.
|
||||
#
|
||||
# See RDoc::Markup@Other+directives for instructions on adding an alternate
|
||||
# format.
|
||||
|
||||
class RDoc::Comment
|
||||
|
||||
include RDoc::Text
|
||||
|
||||
##
|
||||
# The format of this comment. Defaults to RDoc::Markup
|
||||
|
||||
attr_reader :format
|
||||
|
||||
##
|
||||
# The RDoc::TopLevel this comment was found in
|
||||
|
||||
attr_accessor :location
|
||||
|
||||
##
|
||||
# For duck-typing when merging classes at load time
|
||||
|
||||
alias file location # :nodoc:
|
||||
|
||||
##
|
||||
# The text for this comment
|
||||
|
||||
attr_reader :text
|
||||
|
||||
##
|
||||
# Overrides the content returned by #parse. Use when there is no #text
|
||||
# source for this comment
|
||||
|
||||
attr_writer :document
|
||||
|
||||
##
|
||||
# Creates a new comment with +text+ that is found in the RDoc::TopLevel
|
||||
# +location+.
|
||||
|
||||
def initialize text = nil, location = nil
|
||||
@location = location
|
||||
@text = text
|
||||
|
||||
@document = nil
|
||||
@format = 'rdoc'
|
||||
@normalized = false
|
||||
end
|
||||
|
||||
##
|
||||
#--
|
||||
# TODO deep copy @document
|
||||
|
||||
def initialize_copy copy # :nodoc:
|
||||
@text = copy.text.dup
|
||||
end
|
||||
|
||||
def == other # :nodoc:
|
||||
self.class === other and
|
||||
other.text == @text and other.location == @location
|
||||
end
|
||||
|
||||
##
|
||||
# Look for a 'call-seq' in the comment to override the normal parameter
|
||||
# handling. The :call-seq: is indented from the baseline. All lines of the
|
||||
# same indentation level and prefix are consumed.
|
||||
#
|
||||
# For example, all of the following will be used as the :call-seq:
|
||||
#
|
||||
# # :call-seq:
|
||||
# # ARGF.readlines(sep=$/) -> array
|
||||
# # ARGF.readlines(limit) -> array
|
||||
# # ARGF.readlines(sep, limit) -> array
|
||||
# #
|
||||
# # ARGF.to_a(sep=$/) -> array
|
||||
# # ARGF.to_a(limit) -> array
|
||||
# # ARGF.to_a(sep, limit) -> array
|
||||
|
||||
def extract_call_seq method
|
||||
# we must handle situations like the above followed by an unindented first
|
||||
# comment. The difficulty is to make sure not to match lines starting
|
||||
# with ARGF at the same indent, but that are after the first description
|
||||
# paragraph.
|
||||
if @text =~ /^\s*:?call-seq:(.*?(?:\S).*?)^\s*$/m then
|
||||
all_start, all_stop = $~.offset(0)
|
||||
seq_start, seq_stop = $~.offset(1)
|
||||
|
||||
# we get the following lines that start with the leading word at the
|
||||
# same indent, even if they have blank lines before
|
||||
if $1 =~ /(^\s*\n)+^(\s*\w+)/m then
|
||||
leading = $2 # ' * ARGF' in the example above
|
||||
re = %r%
|
||||
\A(
|
||||
(^\s*\n)+
|
||||
(^#{Regexp.escape leading}.*?\n)+
|
||||
)+
|
||||
^\s*$
|
||||
%xm
|
||||
|
||||
if @text[seq_stop..-1] =~ re then
|
||||
all_stop = seq_stop + $~.offset(0).last
|
||||
seq_stop = seq_stop + $~.offset(1).last
|
||||
end
|
||||
end
|
||||
|
||||
seq = @text[seq_start..seq_stop]
|
||||
seq.gsub!(/^\s*(\S|\n)/m, '\1')
|
||||
@text.slice! all_start...all_stop
|
||||
|
||||
method.call_seq = seq.chomp
|
||||
|
||||
elsif @text.sub!(/^\s*:?call-seq:(.*?)(^\s*$|\z)/m, '') then
|
||||
seq = $1
|
||||
seq.gsub!(/^\s*/, '')
|
||||
method.call_seq = seq
|
||||
end
|
||||
#elsif @text.sub!(/\A\/\*\s*call-seq:(.*?)\*\/\Z/, '') then
|
||||
# method.call_seq = $1.strip
|
||||
#end
|
||||
|
||||
method
|
||||
end
|
||||
|
||||
##
|
||||
# A comment is empty if its text String is empty.
|
||||
|
||||
def empty?
|
||||
@text.empty?
|
||||
end
|
||||
|
||||
##
|
||||
# HACK dubious
|
||||
|
||||
def force_encoding encoding
|
||||
@text.force_encoding encoding
|
||||
end
|
||||
|
||||
##
|
||||
# Sets the format of this comment and resets any parsed document
|
||||
|
||||
def format= format
|
||||
@format = format
|
||||
@document = nil
|
||||
end
|
||||
|
||||
def inspect # :nodoc:
|
||||
location = @location ? @location.absolute_name : '(unknown)'
|
||||
|
||||
"#<%s:%x %s %p>" % [self.class, object_id, location, @text]
|
||||
end
|
||||
|
||||
##
|
||||
# Normalizes the text. See RDoc::Text#normalize_comment for details
|
||||
|
||||
def normalize
|
||||
return self unless @text
|
||||
return self if @normalized # TODO eliminate duplicate normalization
|
||||
|
||||
@text = normalize_comment @text
|
||||
|
||||
@normalized = true
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
##
|
||||
# Was this text normalized?
|
||||
|
||||
def normalized? # :nodoc:
|
||||
@normalized
|
||||
end
|
||||
|
||||
##
|
||||
# Parses the comment into an RDoc::Markup::Document. The parsed document is
|
||||
# cached until the text is changed.
|
||||
|
||||
def parse
|
||||
return @document if @document
|
||||
|
||||
@document = super @text, @format
|
||||
@document.file = @location
|
||||
@document
|
||||
end
|
||||
|
||||
##
|
||||
# Removes private sections from this comment. Private sections are flush to
|
||||
# the comment marker and start with <tt>--</tt> and end with <tt>++</tt>.
|
||||
# For C-style comments, a private marker may not start at the opening of the
|
||||
# comment.
|
||||
#
|
||||
# /*
|
||||
# *--
|
||||
# * private
|
||||
# *++
|
||||
# * public
|
||||
# */
|
||||
|
||||
def remove_private
|
||||
# Workaround for gsub encoding for Ruby 1.9.2 and earlier
|
||||
empty = ''
|
||||
empty.force_encoding @text.encoding if Object.const_defined? :Encoding
|
||||
|
||||
@text = @text.gsub(%r%^\s*([#*]?)--.*?^\s*(\1)\+\+\n?%m, empty)
|
||||
@text = @text.sub(%r%^\s*[#*]?--.*%m, '')
|
||||
end
|
||||
|
||||
##
|
||||
# Replaces this comment's text with +text+ and resets the parsed document.
|
||||
#
|
||||
# An error is raised if the comment contains a document but no text.
|
||||
|
||||
def text= text
|
||||
raise RDoc::Error, 'replacing document-only comment is not allowed' if
|
||||
@text.nil? and @document
|
||||
|
||||
@document = nil
|
||||
@text = text
|
||||
end
|
||||
|
||||
##
|
||||
# Returns true if this comment is in TomDoc format.
|
||||
|
||||
def tomdoc?
|
||||
@format == 'tomdoc'
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -1,16 +1,14 @@
|
|||
require 'rdoc/code_object'
|
||||
|
||||
##
|
||||
# A constant
|
||||
|
||||
class RDoc::Constant < RDoc::CodeObject
|
||||
|
||||
##
|
||||
# If this constant is an alias for a module or class,
|
||||
# this is the RDoc::ClassModule it is an alias for.
|
||||
# +nil+ otherwise.
|
||||
MARSHAL_VERSION = 0 # :nodoc:
|
||||
|
||||
attr_accessor :is_alias_for
|
||||
##
|
||||
# Sets the module or class this is constant is an alias for.
|
||||
|
||||
attr_writer :is_alias_for
|
||||
|
||||
##
|
||||
# The constant's name
|
||||
|
@ -22,14 +20,23 @@ class RDoc::Constant < RDoc::CodeObject
|
|||
|
||||
attr_accessor :value
|
||||
|
||||
##
|
||||
# The constant's visibility
|
||||
|
||||
attr_accessor :visibility
|
||||
|
||||
##
|
||||
# Creates a new constant with +name+, +value+ and +comment+
|
||||
|
||||
def initialize(name, value, comment)
|
||||
super()
|
||||
@name = name
|
||||
|
||||
@name = name
|
||||
@value = value
|
||||
|
||||
@is_alias_for = nil
|
||||
@visibility = nil
|
||||
|
||||
self.comment = comment
|
||||
end
|
||||
|
||||
|
@ -59,6 +66,27 @@ class RDoc::Constant < RDoc::CodeObject
|
|||
super or is_alias_for && is_alias_for.documented?
|
||||
end
|
||||
|
||||
##
|
||||
# Full constant name including namespace
|
||||
|
||||
def full_name
|
||||
@full_name ||= "#{parent_name}::#{@name}"
|
||||
end
|
||||
|
||||
##
|
||||
# The module or class this constant is an alias for
|
||||
|
||||
def is_alias_for
|
||||
case @is_alias_for
|
||||
when String then
|
||||
found = @store.find_class_or_module @is_alias_for
|
||||
@is_alias_for = found if found
|
||||
@is_alias_for
|
||||
else
|
||||
@is_alias_for
|
||||
end
|
||||
end
|
||||
|
||||
def inspect # :nodoc:
|
||||
"#<%s:0x%x %s::%s>" % [
|
||||
self.class, object_id,
|
||||
|
@ -67,12 +95,76 @@ class RDoc::Constant < RDoc::CodeObject
|
|||
end
|
||||
|
||||
##
|
||||
# Path to this constant
|
||||
# Dumps this Constant for use by ri. See also #marshal_load
|
||||
|
||||
def marshal_dump
|
||||
alias_name = case found = is_alias_for
|
||||
when RDoc::CodeObject then found.full_name
|
||||
else found
|
||||
end
|
||||
|
||||
[ MARSHAL_VERSION,
|
||||
@name,
|
||||
full_name,
|
||||
@visibility,
|
||||
alias_name,
|
||||
parse(@comment),
|
||||
@file.absolute_name,
|
||||
parent.name,
|
||||
parent.class,
|
||||
section.title,
|
||||
]
|
||||
end
|
||||
|
||||
##
|
||||
# Loads this Constant from +array+. For a loaded Constant the following
|
||||
# methods will return cached values:
|
||||
#
|
||||
# * #full_name
|
||||
# * #parent_name
|
||||
|
||||
def marshal_load array
|
||||
initialize array[1], nil, array[5]
|
||||
|
||||
@full_name = array[2]
|
||||
@visibility = array[3]
|
||||
@is_alias_for = array[4]
|
||||
# 5 handled above
|
||||
# 6 handled below
|
||||
@parent_name = array[7]
|
||||
@parent_class = array[8]
|
||||
@section_title = array[9]
|
||||
|
||||
@file = RDoc::TopLevel.new array[6]
|
||||
end
|
||||
|
||||
##
|
||||
# Path to this constant for use with HTML generator output.
|
||||
|
||||
def path
|
||||
"#{@parent.path}##{@name}"
|
||||
end
|
||||
|
||||
def pretty_print q # :nodoc:
|
||||
q.group 2, "[#{self.class.name} #{full_name}", "]" do
|
||||
unless comment.empty? then
|
||||
q.breakable
|
||||
q.text "comment:"
|
||||
q.breakable
|
||||
q.pp @comment
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Sets the store for this class or module and its contained code objects.
|
||||
|
||||
def store= store
|
||||
super
|
||||
|
||||
@file = @store.add_file @file.full_name if @file
|
||||
end
|
||||
|
||||
def to_s # :nodoc:
|
||||
parent_name = parent ? parent.full_name : '(unknown)'
|
||||
if is_alias_for
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'rdoc/code_object'
|
||||
require 'cgi'
|
||||
|
||||
##
|
||||
# A Context is something that can hold modules, classes, methods, attributes,
|
||||
|
@ -14,6 +14,12 @@ class RDoc::Context < RDoc::CodeObject
|
|||
|
||||
TYPES = %w[class instance]
|
||||
|
||||
##
|
||||
# If a context has these titles it will be sorted in this order.
|
||||
|
||||
TOMDOC_TITLES = [nil, 'Public', 'Internal', 'Deprecated'] # :nodoc:
|
||||
TOMDOC_TITLES_SORT = TOMDOC_TITLES.sort_by { |title| title.to_s } # :nodoc:
|
||||
|
||||
##
|
||||
# Class/module aliases
|
||||
|
||||
|
@ -24,6 +30,11 @@ class RDoc::Context < RDoc::CodeObject
|
|||
|
||||
attr_reader :attributes
|
||||
|
||||
##
|
||||
# Block params to be used in the next MethodAttr parsed under this context
|
||||
|
||||
attr_accessor :block_params
|
||||
|
||||
##
|
||||
# Constants defined
|
||||
|
||||
|
@ -44,6 +55,11 @@ class RDoc::Context < RDoc::CodeObject
|
|||
|
||||
attr_reader :includes
|
||||
|
||||
##
|
||||
# Modules this context is extended with
|
||||
|
||||
attr_reader :extends
|
||||
|
||||
##
|
||||
# Methods defined in this context
|
||||
|
||||
|
@ -72,7 +88,7 @@ class RDoc::Context < RDoc::CodeObject
|
|||
attr_accessor :unmatched_alias_lists
|
||||
|
||||
##
|
||||
# Aliases that could not eventually be resolved.
|
||||
# Aliases that could not be resolved.
|
||||
|
||||
attr_reader :external_aliases
|
||||
|
||||
|
@ -87,123 +103,16 @@ class RDoc::Context < RDoc::CodeObject
|
|||
|
||||
attr_reader :methods_hash
|
||||
|
||||
##
|
||||
# Params to be used in the next MethodAttr parsed under this context
|
||||
|
||||
attr_accessor :params
|
||||
|
||||
##
|
||||
# Hash of registered constants.
|
||||
|
||||
attr_reader :constants_hash
|
||||
|
||||
##
|
||||
# A section of documentation like:
|
||||
#
|
||||
# # :section: The title
|
||||
# # The body
|
||||
#
|
||||
# Sections can be referenced multiple times and will be collapsed into a
|
||||
# single section.
|
||||
|
||||
class Section
|
||||
|
||||
include RDoc::Text
|
||||
|
||||
##
|
||||
# Section comment
|
||||
|
||||
attr_reader :comment
|
||||
|
||||
##
|
||||
# Context this Section lives in
|
||||
|
||||
attr_reader :parent
|
||||
|
||||
##
|
||||
# Section title
|
||||
|
||||
attr_reader :title
|
||||
|
||||
@@sequence = "SEC00000"
|
||||
|
||||
##
|
||||
# Creates a new section with +title+ and +comment+
|
||||
|
||||
def initialize parent, title, comment
|
||||
@parent = parent
|
||||
@title = title ? title.strip : title
|
||||
|
||||
@@sequence.succ!
|
||||
@sequence = @@sequence.dup
|
||||
|
||||
@comment = extract_comment comment
|
||||
end
|
||||
|
||||
##
|
||||
# Sections are equal when they have the same #title
|
||||
|
||||
def == other
|
||||
self.class === other and @title == other.title
|
||||
end
|
||||
|
||||
##
|
||||
# Anchor reference for linking to this section
|
||||
|
||||
def aref
|
||||
title = @title || '[untitled]'
|
||||
|
||||
CGI.escape(title).gsub('%', '-').sub(/^-/, '')
|
||||
end
|
||||
|
||||
##
|
||||
# Appends +comment+ to the current comment separated by a rule.
|
||||
|
||||
def comment= comment
|
||||
comment = extract_comment comment
|
||||
|
||||
return if comment.empty?
|
||||
|
||||
if @comment then
|
||||
@comment += "\n# ---\n#{comment}"
|
||||
else
|
||||
@comment = comment
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Extracts 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
|
||||
# # The body
|
||||
|
||||
def extract_comment comment
|
||||
if comment =~ /^#[ \t]*:section:.*\n/ then
|
||||
start = $`
|
||||
rest = $'
|
||||
|
||||
if start.empty? then
|
||||
rest
|
||||
else
|
||||
rest.sub(/#{start.chomp}\Z/, '')
|
||||
end
|
||||
else
|
||||
comment
|
||||
end
|
||||
end
|
||||
|
||||
def inspect # :nodoc:
|
||||
"#<%s:0x%x %p>" % [self.class, object_id, title]
|
||||
end
|
||||
|
||||
##
|
||||
# Section sequence number (deprecated)
|
||||
|
||||
def sequence
|
||||
warn "RDoc::Context::Section#sequence is deprecated, use #aref"
|
||||
@sequence
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
##
|
||||
# Creates an unnamed empty context with public current visibility
|
||||
|
||||
|
@ -235,6 +144,7 @@ class RDoc::Context < RDoc::CodeObject
|
|||
@aliases = []
|
||||
@requires = []
|
||||
@includes = []
|
||||
@extends = []
|
||||
@constants = []
|
||||
@external_aliases = []
|
||||
|
||||
|
@ -242,8 +152,12 @@ class RDoc::Context < RDoc::CodeObject
|
|||
# a method not yet encountered).
|
||||
@unmatched_alias_lists = {}
|
||||
|
||||
@methods_hash = {}
|
||||
@methods_hash = {}
|
||||
@constants_hash = {}
|
||||
|
||||
@params = nil
|
||||
|
||||
@store ||= nil
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -366,12 +280,12 @@ class RDoc::Context < RDoc::CodeObject
|
|||
if full_name =~ /^(.+)::(\w+)$/ then
|
||||
name = $2
|
||||
ename = $1
|
||||
enclosing = RDoc::TopLevel.classes_hash[ename] ||
|
||||
RDoc::TopLevel.modules_hash[ename]
|
||||
enclosing = @store.classes_hash[ename] || @store.modules_hash[ename]
|
||||
# HACK: crashes in actionpack/lib/action_view/helpers/form_helper.rb (metaprogramming)
|
||||
unless enclosing then
|
||||
# try the given name at top level (will work for the above example)
|
||||
enclosing = RDoc::TopLevel.classes_hash[given_name] || RDoc::TopLevel.modules_hash[given_name]
|
||||
enclosing = @store.classes_hash[given_name] ||
|
||||
@store.modules_hash[given_name]
|
||||
return enclosing if enclosing
|
||||
# not found: create the parent(s)
|
||||
names = ename.split('::')
|
||||
|
@ -410,7 +324,7 @@ class RDoc::Context < RDoc::CodeObject
|
|||
end
|
||||
|
||||
# did we believe it was a module?
|
||||
mod = RDoc::TopLevel.modules_hash.delete superclass
|
||||
mod = @store.modules_hash.delete superclass
|
||||
|
||||
upgrade_to_class mod, RDoc::NormalClass, mod.parent if mod
|
||||
|
||||
|
@ -418,7 +332,7 @@ class RDoc::Context < RDoc::CodeObject
|
|||
superclass = nil if superclass == full_name
|
||||
end
|
||||
|
||||
klass = RDoc::TopLevel.classes_hash[full_name]
|
||||
klass = @store.classes_hash[full_name]
|
||||
|
||||
if klass then
|
||||
# if TopLevel, it may not be registered in the classes:
|
||||
|
@ -435,7 +349,7 @@ class RDoc::Context < RDoc::CodeObject
|
|||
end
|
||||
else
|
||||
# this is a new class
|
||||
mod = RDoc::TopLevel.modules_hash.delete full_name
|
||||
mod = @store.modules_hash.delete full_name
|
||||
|
||||
if mod then
|
||||
klass = upgrade_to_class mod, RDoc::NormalClass, enclosing
|
||||
|
@ -445,10 +359,12 @@ class RDoc::Context < RDoc::CodeObject
|
|||
klass = class_type.new name, superclass
|
||||
|
||||
enclosing.add_class_or_module(klass, enclosing.classes_hash,
|
||||
RDoc::TopLevel.classes_hash)
|
||||
@store.classes_hash)
|
||||
end
|
||||
end
|
||||
|
||||
klass.parent = self
|
||||
|
||||
klass
|
||||
end
|
||||
|
||||
|
@ -463,6 +379,7 @@ class RDoc::Context < RDoc::CodeObject
|
|||
mod.section = current_section # TODO declaring context? something is
|
||||
# wrong here...
|
||||
mod.parent = self
|
||||
mod.store = @store
|
||||
|
||||
unless @done_documenting then
|
||||
self_hash[mod.name] = mod
|
||||
|
@ -504,12 +421,20 @@ class RDoc::Context < RDoc::CodeObject
|
|||
# Adds included module +include+ which should be an RDoc::Include
|
||||
|
||||
def add_include include
|
||||
add_to @includes, include unless
|
||||
@includes.map { |i| i.full_name }.include? include.full_name
|
||||
add_to @includes, include
|
||||
|
||||
include
|
||||
end
|
||||
|
||||
##
|
||||
# Adds extension module +ext+ which should be an RDoc::Extend
|
||||
|
||||
def add_extend ext
|
||||
add_to @extends, ext
|
||||
|
||||
ext
|
||||
end
|
||||
|
||||
##
|
||||
# Adds +method+ if not already there. If it is (as method or attribute),
|
||||
# updates the comment if it was empty.
|
||||
|
@ -523,6 +448,10 @@ class RDoc::Context < RDoc::CodeObject
|
|||
|
||||
if known then
|
||||
known.comment = method.comment if known.comment.empty?
|
||||
previously = ", previously in #{known.file}" unless
|
||||
method.file == known.file
|
||||
@store.rdoc.options.warn \
|
||||
"Duplicate method #{known.full_name} in #{method.file}#{previously}"
|
||||
else
|
||||
@methods_hash[key] = method
|
||||
method.visibility = @visibility
|
||||
|
@ -542,9 +471,9 @@ class RDoc::Context < RDoc::CodeObject
|
|||
return mod if mod
|
||||
|
||||
full_name = child_name name
|
||||
mod = RDoc::TopLevel.modules_hash[full_name] || class_type.new(name)
|
||||
mod = @store.modules_hash[full_name] || class_type.new(name)
|
||||
|
||||
add_class_or_module(mod, @modules, RDoc::TopLevel.modules_hash)
|
||||
add_class_or_module mod, @modules, @store.modules_hash
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -554,31 +483,34 @@ class RDoc::Context < RDoc::CodeObject
|
|||
def add_module_alias from, name, file
|
||||
return from if @done_documenting
|
||||
|
||||
to_name = child_name(name)
|
||||
to_name = child_name name
|
||||
|
||||
# if we already know this name, don't register an alias:
|
||||
# see the metaprogramming in lib/active_support/basic_object.rb,
|
||||
# where we already know BasicObject as a class when we find
|
||||
# where we already know BasicObject is a class when we find
|
||||
# BasicObject = BlankSlate
|
||||
return from if RDoc::TopLevel.find_class_or_module(to_name)
|
||||
return from if @store.find_class_or_module to_name
|
||||
|
||||
if from.module? then
|
||||
RDoc::TopLevel.modules_hash[to_name] = from
|
||||
@modules[name] = from
|
||||
to = from.dup
|
||||
to.name = name
|
||||
to.full_name = nil
|
||||
|
||||
if to.module? then
|
||||
@store.modules_hash[to_name] = to
|
||||
@modules[name] = to
|
||||
else
|
||||
RDoc::TopLevel.classes_hash[to_name] = from
|
||||
@classes[name] = from
|
||||
@store.classes_hash[to_name] = to
|
||||
@classes[name] = to
|
||||
end
|
||||
|
||||
# HACK: register a constant for this alias:
|
||||
# constant value and comment will be updated after,
|
||||
# when the Ruby parser adds the constant
|
||||
const = RDoc::Constant.new name, nil, ''
|
||||
# Registers a constant for this alias. The constant value and comment
|
||||
# will be updated later, when the Ruby parser adds the constant
|
||||
const = RDoc::Constant.new name, nil, to.comment
|
||||
const.record_location file
|
||||
const.is_alias_for = from
|
||||
add_constant const
|
||||
|
||||
from
|
||||
to
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -602,9 +534,9 @@ class RDoc::Context < RDoc::CodeObject
|
|||
#
|
||||
# See also RDoc::Context::Section
|
||||
|
||||
def add_section title, comment
|
||||
def add_section title, comment = nil
|
||||
if section = @sections[title] then
|
||||
section.comment = comment
|
||||
section.add_comment comment if comment
|
||||
else
|
||||
section = Section.new self, title, comment
|
||||
@sections[title] = section
|
||||
|
@ -616,9 +548,11 @@ class RDoc::Context < RDoc::CodeObject
|
|||
##
|
||||
# Adds +thing+ to the collection +array+
|
||||
|
||||
def add_to(array, thing)
|
||||
def add_to array, thing
|
||||
array << thing if @document_self
|
||||
thing.parent = self
|
||||
|
||||
thing.parent = self
|
||||
thing.store = @store if @store
|
||||
thing.section = current_section
|
||||
end
|
||||
|
||||
|
@ -628,7 +562,7 @@ class RDoc::Context < RDoc::CodeObject
|
|||
# This means any of: comment, aliases, methods, attributes, external
|
||||
# aliases, require, constant.
|
||||
#
|
||||
# Includes are also checked unless <tt>includes == false</tt>.
|
||||
# Includes and extends are also checked unless <tt>includes == false</tt>.
|
||||
|
||||
def any_content(includes = true)
|
||||
@any_content ||= !(
|
||||
|
@ -640,7 +574,7 @@ class RDoc::Context < RDoc::CodeObject
|
|||
@requires.empty? &&
|
||||
@constants.empty?
|
||||
)
|
||||
@any_content || (includes && !@includes.empty?)
|
||||
@any_content || (includes && !(@includes + @extends).empty? )
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -723,6 +657,9 @@ class RDoc::Context < RDoc::CodeObject
|
|||
##
|
||||
# Iterator for ancestors for duck-typing. Does nothing. See
|
||||
# RDoc::ClassModule#each_ancestor.
|
||||
#
|
||||
# This method exists to make it easy to work with Context subclasses that
|
||||
# aren't part of RDoc.
|
||||
|
||||
def each_ancestor # :nodoc:
|
||||
end
|
||||
|
@ -755,11 +692,20 @@ class RDoc::Context < RDoc::CodeObject
|
|||
@includes.each do |i| yield i end
|
||||
end
|
||||
|
||||
##
|
||||
# Iterator for extension modules
|
||||
|
||||
def each_extend # :yields: extend
|
||||
@extends.each do |e| yield e end
|
||||
end
|
||||
|
||||
##
|
||||
# Iterator for methods
|
||||
|
||||
def each_method # :yields: method
|
||||
@method_list.sort.each {|m| yield m}
|
||||
return enum_for __method__ unless block_given?
|
||||
|
||||
@method_list.sort.each { |m| yield m }
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -773,13 +719,15 @@ class RDoc::Context < RDoc::CodeObject
|
|||
# NOTE: Do not edit collections yielded by this method
|
||||
|
||||
def each_section # :yields: section, constants, attributes
|
||||
constants = @constants.group_by do |constant| constant.section end
|
||||
constants.default = []
|
||||
return enum_for __method__ unless block_given?
|
||||
|
||||
constants = @constants.group_by do |constant| constant.section end
|
||||
attributes = @attributes.group_by do |attribute| attribute.section end
|
||||
|
||||
constants.default = []
|
||||
attributes.default = []
|
||||
|
||||
@sections.sort_by { |title, _| title.to_s }.each do |_, section|
|
||||
sort_sections.each do |section|
|
||||
yield section, constants[section].sort, attributes[section].sort
|
||||
end
|
||||
end
|
||||
|
@ -851,8 +799,8 @@ class RDoc::Context < RDoc::CodeObject
|
|||
##
|
||||
# Finds a file with +name+ in this context
|
||||
|
||||
def find_file_named(name)
|
||||
top_level.class.find_file_named(name)
|
||||
def find_file_named name
|
||||
@store.find_file_named name
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -922,21 +870,21 @@ class RDoc::Context < RDoc::CodeObject
|
|||
# look for a class or module 'symbol'
|
||||
case symbol
|
||||
when /^::/ then
|
||||
result = RDoc::TopLevel.find_class_or_module(symbol)
|
||||
result = @store.find_class_or_module symbol
|
||||
when /^(\w+):+(.+)$/
|
||||
suffix = $2
|
||||
top = $1
|
||||
searched = self
|
||||
loop do
|
||||
while searched do
|
||||
mod = searched.find_module_named(top)
|
||||
break unless mod
|
||||
result = RDoc::TopLevel.find_class_or_module(mod.full_name + '::' + suffix)
|
||||
result = @store.find_class_or_module "#{mod.full_name}::#{suffix}"
|
||||
break if result || searched.is_a?(RDoc::TopLevel)
|
||||
searched = searched.parent
|
||||
end
|
||||
else
|
||||
searched = self
|
||||
loop do
|
||||
while searched do
|
||||
result = searched.find_module_named(symbol)
|
||||
break if result || searched.is_a?(RDoc::TopLevel)
|
||||
searched = searched.parent
|
||||
|
@ -985,6 +933,8 @@ class RDoc::Context < RDoc::CodeObject
|
|||
|
||||
##
|
||||
# Instance methods
|
||||
#--
|
||||
# TODO rename to instance_methods
|
||||
|
||||
def instance_method_list
|
||||
@instance_method_list ||= method_list.reject { |a| a.singleton }
|
||||
|
@ -1098,24 +1048,23 @@ class RDoc::Context < RDoc::CodeObject
|
|||
##
|
||||
# Only called when min_visibility == :public or :private
|
||||
|
||||
def remove_invisible_in(array, min_visibility) # :nodoc:
|
||||
if min_visibility == :public
|
||||
def remove_invisible_in array, min_visibility # :nodoc:
|
||||
if min_visibility == :public then
|
||||
array.reject! { |e|
|
||||
e.visibility != :public and not e.force_documentation
|
||||
}
|
||||
else
|
||||
array.reject! { |e|
|
||||
e.visibility == :private and
|
||||
not e.force_documentation
|
||||
e.visibility == :private and not e.force_documentation
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Tries to resolve unmatched aliases when a method
|
||||
# or attribute has just been added.
|
||||
# Tries to resolve unmatched aliases when a method or attribute has just
|
||||
# been added.
|
||||
|
||||
def resolve_aliases(added)
|
||||
def resolve_aliases added
|
||||
# resolve any pending unmatched aliases
|
||||
key = added.pretty_name
|
||||
unmatched_alias_list = @unmatched_alias_lists[key]
|
||||
|
@ -1127,6 +1076,31 @@ class RDoc::Context < RDoc::CodeObject
|
|||
@unmatched_alias_lists.delete key
|
||||
end
|
||||
|
||||
##
|
||||
# Returns RDoc::Context::Section objects referenced in this context for use
|
||||
# in a table of contents.
|
||||
|
||||
def section_contents
|
||||
used_sections = {}
|
||||
|
||||
each_method do |method|
|
||||
next unless method.display?
|
||||
|
||||
used_sections[method.section] = true
|
||||
end
|
||||
|
||||
# order found sections
|
||||
sections = sort_sections.select do |section|
|
||||
used_sections[section]
|
||||
end
|
||||
|
||||
# only the default section is used
|
||||
return [] if
|
||||
sections.length == 1 and not sections.first.title
|
||||
|
||||
sections
|
||||
end
|
||||
|
||||
##
|
||||
# Sections in this context
|
||||
|
||||
|
@ -1155,6 +1129,26 @@ class RDoc::Context < RDoc::CodeObject
|
|||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Sorts sections alphabetically (default) or in TomDoc fashion (none,
|
||||
# Public, Internal, Deprecated)
|
||||
|
||||
def sort_sections
|
||||
titles = @sections.map { |title, _| title }
|
||||
|
||||
if titles.length > 1 and
|
||||
TOMDOC_TITLES_SORT ==
|
||||
(titles | TOMDOC_TITLES).sort_by { |title| title.to_s } then
|
||||
@sections.values_at(*TOMDOC_TITLES).compact
|
||||
else
|
||||
@sections.sort_by { |title, _|
|
||||
title.to_s
|
||||
}.map { |_, section|
|
||||
section
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def to_s # :nodoc:
|
||||
"#{self.class.name} #{self.full_name}"
|
||||
end
|
||||
|
@ -1179,13 +1173,16 @@ class RDoc::Context < RDoc::CodeObject
|
|||
enclosing.modules_hash.delete mod.name
|
||||
|
||||
klass = RDoc::ClassModule.from_module class_type, mod
|
||||
klass.store = @store
|
||||
|
||||
# if it was there, then we keep it even if done_documenting
|
||||
RDoc::TopLevel.classes_hash[mod.full_name] = klass
|
||||
enclosing.classes_hash[mod.name] = klass
|
||||
@store.classes_hash[mod.full_name] = klass
|
||||
enclosing.classes_hash[mod.name] = klass
|
||||
|
||||
klass
|
||||
end
|
||||
|
||||
autoload :Section, 'rdoc/context/section'
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,238 @@
|
|||
##
|
||||
# A section of documentation like:
|
||||
#
|
||||
# # :section: The title
|
||||
# # The body
|
||||
#
|
||||
# Sections can be referenced multiple times and will be collapsed into a
|
||||
# single section.
|
||||
|
||||
class RDoc::Context::Section
|
||||
|
||||
include RDoc::Text
|
||||
|
||||
MARSHAL_VERSION = 0 # :nodoc:
|
||||
|
||||
##
|
||||
# Section comment
|
||||
|
||||
attr_reader :comment
|
||||
|
||||
##
|
||||
# Section comments
|
||||
|
||||
attr_reader :comments
|
||||
|
||||
##
|
||||
# Context this Section lives in
|
||||
|
||||
attr_reader :parent
|
||||
|
||||
##
|
||||
# Section title
|
||||
|
||||
attr_reader :title
|
||||
|
||||
@@sequence = "SEC00000"
|
||||
|
||||
##
|
||||
# Creates a new section with +title+ and +comment+
|
||||
|
||||
def initialize parent, title, comment
|
||||
@parent = parent
|
||||
@title = title ? title.strip : title
|
||||
|
||||
@@sequence.succ!
|
||||
@sequence = @@sequence.dup
|
||||
|
||||
@comments = []
|
||||
|
||||
add_comment comment
|
||||
end
|
||||
|
||||
##
|
||||
# Sections are equal when they have the same #title
|
||||
|
||||
def == other
|
||||
self.class === other and @title == other.title
|
||||
end
|
||||
|
||||
##
|
||||
# Adds +comment+ to this section
|
||||
|
||||
def add_comment comment
|
||||
comment = extract_comment comment
|
||||
|
||||
return if comment.empty?
|
||||
|
||||
case comment
|
||||
when RDoc::Comment then
|
||||
@comments << comment
|
||||
when RDoc::Markup::Document then
|
||||
@comments.concat comment.parts
|
||||
when Array then
|
||||
@comments.concat comment
|
||||
else
|
||||
raise TypeError, "unknown comment type: #{comment.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Anchor reference for linking to this section
|
||||
|
||||
def aref
|
||||
title = @title || '[untitled]'
|
||||
|
||||
CGI.escape(title).gsub('%', '-').sub(/^-/, '')
|
||||
end
|
||||
|
||||
##
|
||||
# Extracts 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
|
||||
# # The body
|
||||
|
||||
def extract_comment comment
|
||||
case comment
|
||||
when Array then
|
||||
comment.map do |c|
|
||||
extract_comment c
|
||||
end
|
||||
when nil
|
||||
RDoc::Comment.new ''
|
||||
when RDoc::Comment then
|
||||
if comment.text =~ /^#[ \t]*:section:.*\n/ then
|
||||
start = $`
|
||||
rest = $'
|
||||
|
||||
comment.text = if start.empty? then
|
||||
rest
|
||||
else
|
||||
rest.sub(/#{start.chomp}\Z/, '')
|
||||
end
|
||||
end
|
||||
|
||||
comment
|
||||
when RDoc::Markup::Document then
|
||||
comment
|
||||
else
|
||||
raise TypeError, "unknown comment #{comment.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
def inspect # :nodoc:
|
||||
"#<%s:0x%x %p>" % [self.class, object_id, title]
|
||||
end
|
||||
|
||||
##
|
||||
# The files comments in this section come from
|
||||
|
||||
def in_files
|
||||
return [] if @comments.empty?
|
||||
|
||||
case @comments
|
||||
when Array then
|
||||
@comments.map do |comment|
|
||||
comment.file
|
||||
end
|
||||
when RDoc::Markup::Document then
|
||||
@comment.parts.map do |document|
|
||||
document.file
|
||||
end
|
||||
else
|
||||
raise RDoc::Error, "BUG: unknown comment class #{@comments.class}"
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Serializes this Section. The title and parsed comment are saved, but not
|
||||
# the section parent which must be restored manually.
|
||||
|
||||
def marshal_dump
|
||||
[
|
||||
MARSHAL_VERSION,
|
||||
@title,
|
||||
parse,
|
||||
]
|
||||
end
|
||||
|
||||
##
|
||||
# De-serializes this Section. The section parent must be restored manually.
|
||||
|
||||
def marshal_load array
|
||||
@parent = nil
|
||||
|
||||
@title = array[1]
|
||||
@comments = array[2]
|
||||
end
|
||||
|
||||
##
|
||||
# Parses +comment_location+ into an RDoc::Markup::Document composed of
|
||||
# multiple RDoc::Markup::Documents with their file set.
|
||||
|
||||
def parse
|
||||
case @comments
|
||||
when String then
|
||||
super
|
||||
when Array then
|
||||
docs = @comments.map do |comment, location|
|
||||
doc = super comment
|
||||
doc.file = location if location
|
||||
doc
|
||||
end
|
||||
|
||||
RDoc::Markup::Document.new(*docs)
|
||||
when RDoc::Comment then
|
||||
doc = super @comments.text, comments.format
|
||||
doc.file = @comments.location
|
||||
doc
|
||||
when RDoc::Markup::Document then
|
||||
return @comments
|
||||
else
|
||||
raise ArgumentError, "unknown comment class #{comments.class}"
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# The section's title, or 'Top Section' if the title is nil.
|
||||
#
|
||||
# This is used by the table of contents template so the name is silly.
|
||||
|
||||
def plain_html
|
||||
@title || 'Top Section'
|
||||
end
|
||||
|
||||
##
|
||||
# Removes a comment from this section if it is from the same file as
|
||||
# +comment+
|
||||
|
||||
def remove_comment comment
|
||||
return if @comments.empty?
|
||||
|
||||
case @comments
|
||||
when Array then
|
||||
@comments.delete_if do |my_comment|
|
||||
my_comment.file == comment.file
|
||||
end
|
||||
when RDoc::Markup::Document then
|
||||
@comments.parts.delete_if do |document|
|
||||
document.file == comment.file.name
|
||||
end
|
||||
else
|
||||
raise RDoc::Error, "BUG: unknown comment class #{@comments.class}"
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Section sequence number (deprecated)
|
||||
|
||||
def sequence
|
||||
warn "RDoc::Context::Section#sequence is deprecated, use #aref"
|
||||
@sequence
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -18,7 +18,7 @@ class RDoc::CrossReference
|
|||
#
|
||||
# See CLASS_REGEXP_STR
|
||||
|
||||
METHOD_REGEXP_STR = '([a-z]\w*[!?=]?)(?:\([\w.+*/=<>-]*\))?'
|
||||
METHOD_REGEXP_STR = '([a-z]\w*[!?=]?|%)(?:\([\w.+*/=<>-]*\))?'
|
||||
|
||||
##
|
||||
# Regular expressions matching text that should potentially have
|
||||
|
@ -27,63 +27,79 @@ class RDoc::CrossReference
|
|||
# have been suppressed, since the suppression characters are removed by the
|
||||
# code that is triggered.
|
||||
|
||||
CROSSREF_REGEXP = /(
|
||||
# A::B::C.meth
|
||||
#{CLASS_REGEXP_STR}(?:[.#]|::)#{METHOD_REGEXP_STR}
|
||||
CROSSREF_REGEXP = /(?:^|\s)
|
||||
(
|
||||
(?:
|
||||
# A::B::C.meth
|
||||
#{CLASS_REGEXP_STR}(?:[.#]|::)#{METHOD_REGEXP_STR}
|
||||
|
||||
# Stand-alone method (preceded by a #)
|
||||
| \\?\##{METHOD_REGEXP_STR}
|
||||
# Stand-alone method (preceded by a #)
|
||||
| \\?\##{METHOD_REGEXP_STR}
|
||||
|
||||
# Stand-alone method (preceded by ::)
|
||||
| ::#{METHOD_REGEXP_STR}
|
||||
# Stand-alone method (preceded by ::)
|
||||
| ::#{METHOD_REGEXP_STR}
|
||||
|
||||
# A::B::C
|
||||
# The stuff after CLASS_REGEXP_STR is a
|
||||
# nasty hack. CLASS_REGEXP_STR unfortunately matches
|
||||
# words like dog and cat (these are legal "class"
|
||||
# names in Fortran 95). When a word is flagged as a
|
||||
# potential cross-reference, limitations in the markup
|
||||
# engine suppress other processing, such as typesetting.
|
||||
# This is particularly noticeable for contractions.
|
||||
# In order that words like "can't" not
|
||||
# be flagged as potential cross-references, only
|
||||
# flag potential class cross-references if the character
|
||||
# after the cross-reference is a space, sentence
|
||||
# punctuation, tag start character, or attribute
|
||||
# marker.
|
||||
| #{CLASS_REGEXP_STR}(?=[\s\)\.\?\!\,\;<\000]|\z)
|
||||
# A::B::C
|
||||
# The stuff after CLASS_REGEXP_STR is a
|
||||
# nasty hack. CLASS_REGEXP_STR unfortunately matches
|
||||
# words like dog and cat (these are legal "class"
|
||||
# names in Fortran 95). When a word is flagged as a
|
||||
# potential cross-reference, limitations in the markup
|
||||
# engine suppress other processing, such as typesetting.
|
||||
# This is particularly noticeable for contractions.
|
||||
# In order that words like "can't" not
|
||||
# be flagged as potential cross-references, only
|
||||
# flag potential class cross-references if the character
|
||||
# after the cross-reference is a space, sentence
|
||||
# punctuation, tag start character, or attribute
|
||||
# marker.
|
||||
| #{CLASS_REGEXP_STR}(?=[@\s).?!,;<\000]|\z)
|
||||
|
||||
# Things that look like filenames
|
||||
# The key thing is that there must be at least
|
||||
# one special character (period, slash, or
|
||||
# underscore).
|
||||
| (?:\.\.\/)*[-\/\w]+[_\/\.][-\w\/\.]+
|
||||
# Things that look like filenames
|
||||
# The key thing is that there must be at least
|
||||
# one special character (period, slash, or
|
||||
# underscore).
|
||||
| (?:\.\.\/)*[-\/\w]+[_\/.][-\w\/.]+
|
||||
|
||||
# Things that have markup suppressed
|
||||
# Don't process things like '\<' in \<tt>, though.
|
||||
# TODO: including < is a hack, not very satisfying.
|
||||
| \\[^\s<]
|
||||
)/x
|
||||
# Things that have markup suppressed
|
||||
# Don't process things like '\<' in \<tt>, though.
|
||||
# TODO: including < is a hack, not very satisfying.
|
||||
| \\[^\s<]
|
||||
)
|
||||
|
||||
# labels for headings
|
||||
(?:@[\w+%-]+(?:\.[\w|%-]+)?)?
|
||||
)/x
|
||||
|
||||
##
|
||||
# Version of CROSSREF_REGEXP used when <tt>--hyperlink-all</tt> is specified.
|
||||
|
||||
ALL_CROSSREF_REGEXP = /(
|
||||
# A::B::C.meth
|
||||
#{CLASS_REGEXP_STR}(?:[.#]|::)#{METHOD_REGEXP_STR}
|
||||
ALL_CROSSREF_REGEXP = /
|
||||
(?:^|\s)
|
||||
(
|
||||
(?:
|
||||
# A::B::C.meth
|
||||
#{CLASS_REGEXP_STR}(?:[.#]|::)#{METHOD_REGEXP_STR}
|
||||
|
||||
# Stand-alone method
|
||||
| \\?#{METHOD_REGEXP_STR}
|
||||
# Stand-alone method
|
||||
| \\?#{METHOD_REGEXP_STR}
|
||||
|
||||
# A::B::C
|
||||
| #{CLASS_REGEXP_STR}(?=[\s\)\.\?\!\,\;<\000]|\z)
|
||||
# A::B::C
|
||||
| #{CLASS_REGEXP_STR}(?=[@\s).?!,;<\000]|\z)
|
||||
|
||||
# Things that look like filenames
|
||||
| (?:\.\.\/)*[-\/\w]+[_\/\.][-\w\/\.]+
|
||||
# Things that look like filenames
|
||||
| (?:\.\.\/)*[-\/\w]+[_\/.][-\w\/.]+
|
||||
|
||||
# Things that have markup suppressed
|
||||
| \\[^\s<]
|
||||
)/x
|
||||
# Things that have markup suppressed
|
||||
| \\[^\s<]
|
||||
)
|
||||
|
||||
# labels for headings
|
||||
(?:@[\w+%-]+)?
|
||||
)/x
|
||||
|
||||
##
|
||||
# Hash of references that have been looked-up to their replacements
|
||||
|
||||
attr_accessor :seen
|
||||
|
||||
|
@ -93,6 +109,7 @@ class RDoc::CrossReference
|
|||
|
||||
def initialize context
|
||||
@context = context
|
||||
@store = context.store
|
||||
|
||||
@seen = {}
|
||||
end
|
||||
|
@ -107,16 +124,6 @@ class RDoc::CrossReference
|
|||
def resolve name, text
|
||||
return @seen[name] if @seen.include? name
|
||||
|
||||
# Find class, module, or method in class or module.
|
||||
#
|
||||
# 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 /#{CLASS_REGEXP_STR}([.#]|::)#{METHOD_REGEXP_STR}/o =~ name then
|
||||
type = $2
|
||||
type = '' if type == '.' # will find either #method or ::method
|
||||
|
@ -141,12 +148,15 @@ class RDoc::CrossReference
|
|||
|
||||
ref = case name
|
||||
when /^\\(#{CLASS_REGEXP_STR})$/o then
|
||||
ref = @context.find_symbol $1
|
||||
@context.find_symbol $1
|
||||
else
|
||||
ref = @context.find_symbol name
|
||||
@context.find_symbol name
|
||||
end unless ref
|
||||
|
||||
ref = nil if RDoc::Alias === ref # external alias: can't link to it
|
||||
# Try a page name
|
||||
ref = @store.page name if not ref and name =~ /^\w+$/
|
||||
|
||||
ref = nil if RDoc::Alias === ref # external alias, can't link to it
|
||||
|
||||
out = if name == '\\' then
|
||||
name
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# coding: US-ASCII
|
||||
|
||||
require 'rdoc'
|
||||
|
||||
##
|
||||
# This class is a wrapper around File IO and Encoding that helps RDoc load
|
||||
# files and convert them to the correct encoding.
|
||||
|
@ -27,26 +25,40 @@ module RDoc::Encoding
|
|||
RDoc::Encoding.set_encoding content
|
||||
|
||||
if Object.const_defined? :Encoding then
|
||||
encoding ||= Encoding.default_external
|
||||
orig_encoding = content.encoding
|
||||
begin
|
||||
encoding ||= Encoding.default_external
|
||||
orig_encoding = content.encoding
|
||||
|
||||
if utf8 then
|
||||
content.force_encoding Encoding::UTF_8
|
||||
content.encode! encoding
|
||||
else
|
||||
# assume the content is in our output encoding
|
||||
content.force_encoding encoding
|
||||
end
|
||||
if utf8 then
|
||||
content.force_encoding Encoding::UTF_8
|
||||
content.encode! encoding
|
||||
else
|
||||
# assume the content is in our output encoding
|
||||
content.force_encoding encoding
|
||||
end
|
||||
|
||||
unless content.valid_encoding? then
|
||||
# revert and try to transcode
|
||||
content.force_encoding orig_encoding
|
||||
content.encode! encoding
|
||||
end
|
||||
unless content.valid_encoding? then
|
||||
# revert and try to transcode
|
||||
content.force_encoding orig_encoding
|
||||
content.encode! encoding
|
||||
end
|
||||
|
||||
unless content.valid_encoding? then
|
||||
warn "unable to convert #{filename} to #{encoding}, skipping"
|
||||
content = nil
|
||||
unless content.valid_encoding? then
|
||||
warn "unable to convert #{filename} to #{encoding}, skipping"
|
||||
content = nil
|
||||
end
|
||||
rescue Encoding::InvalidByteSequenceError,
|
||||
Encoding::UndefinedConversionError => e
|
||||
if force_transcode then
|
||||
content.force_encoding orig_encoding
|
||||
content.encode!(encoding,
|
||||
:invalid => :replace, :undef => :replace,
|
||||
:replace => '?')
|
||||
return content
|
||||
else
|
||||
warn "unable to convert #{e.message} for #{filename}, skipping"
|
||||
return nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -55,15 +67,6 @@ module RDoc::Encoding
|
|||
raise unless e.message =~ /unknown encoding name - (.*)/
|
||||
warn "unknown encoding name \"#{$1}\" for #{filename}, skipping"
|
||||
nil
|
||||
rescue Encoding::UndefinedConversionError => e
|
||||
if force_transcode then
|
||||
content.force_encoding orig_encoding
|
||||
content.encode! encoding, :undef => :replace, :replace => '?'
|
||||
content
|
||||
else
|
||||
warn "unable to convert #{e.message} for #{filename}, skipping"
|
||||
nil
|
||||
end
|
||||
rescue Errno::EISDIR, Errno::ENOENT
|
||||
nil
|
||||
end
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
##
|
||||
# Allows an ERB template to be rendered in the context (binding) of an
|
||||
# existing ERB template evaluation.
|
||||
|
||||
class RDoc::ERBPartial < ERB
|
||||
|
||||
##
|
||||
# Overrides +compiler+ startup to set the +eoutvar+ to an empty string only
|
||||
# if it isn't already set.
|
||||
|
||||
def set_eoutvar compiler, eoutvar = '_erbout'
|
||||
super
|
||||
|
||||
compiler.pre_cmd = ["#{eoutvar} ||= ''"]
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
##
|
||||
# A Module extension in a class with \#extend
|
||||
|
||||
class RDoc::Extend < RDoc::CodeObject
|
||||
|
||||
##
|
||||
# Name of extension module
|
||||
|
||||
attr_accessor :name
|
||||
|
||||
##
|
||||
# Creates a new Extend for +name+ with +comment+
|
||||
|
||||
def initialize(name, comment)
|
||||
super()
|
||||
@name = name
|
||||
self.comment = comment
|
||||
@module = nil # cache for module if found
|
||||
end
|
||||
|
||||
##
|
||||
# Extends are sorted by name
|
||||
|
||||
def <=> other
|
||||
return unless self.class === other
|
||||
|
||||
name <=> other.name
|
||||
end
|
||||
|
||||
def == other # :nodoc:
|
||||
self.class === other and @name == other.name
|
||||
end
|
||||
|
||||
alias eql? ==
|
||||
|
||||
##
|
||||
# Full name based on #module
|
||||
|
||||
def full_name
|
||||
m = self.module
|
||||
RDoc::ClassModule === m ? m.full_name : @name
|
||||
end
|
||||
|
||||
def hash # :nodoc:
|
||||
[@name, self.module].hash
|
||||
end
|
||||
|
||||
def inspect # :nodoc:
|
||||
"#<%s:0x%x %s.extend %s>" % [
|
||||
self.class,
|
||||
object_id,
|
||||
parent_name, @name,
|
||||
]
|
||||
end
|
||||
|
||||
##
|
||||
# Attempts to locate the extend module object. Returns the name if not
|
||||
# known.
|
||||
#
|
||||
# The scoping rules of Ruby to resolve the name of an extension module are:
|
||||
# - first look into the children of the current context;
|
||||
# - if not found, look into the children of extension modules,
|
||||
# in reverse extend order;
|
||||
# - if still not found, go up the hierarchy of names.
|
||||
#
|
||||
# This method has <code>O(n!)</code> behavior when the module calling
|
||||
# extend is referencing nonexistent modules. Avoid calling #module until
|
||||
# after all the files are parsed. This behavior is due to ruby's constant
|
||||
# lookup behavior.
|
||||
|
||||
def module
|
||||
return @module if @module
|
||||
|
||||
# search the current context
|
||||
return @name unless parent
|
||||
full_name = parent.child_name(@name)
|
||||
@module = @store.modules_hash[full_name]
|
||||
return @module if @module
|
||||
return @name if @name =~ /^::/
|
||||
|
||||
# search the includes before this one, in reverse order
|
||||
searched = parent.extends.take_while { |i| i != self }.reverse
|
||||
searched.each do |i|
|
||||
ext = i.module
|
||||
next if String === ext
|
||||
full_name = ext.child_name(@name)
|
||||
@module = @store.modules_hash[full_name]
|
||||
return @module if @module
|
||||
end
|
||||
|
||||
# go up the hierarchy of names
|
||||
up = parent.parent
|
||||
while up
|
||||
full_name = up.child_name(@name)
|
||||
@module = @store.modules_hash[full_name]
|
||||
return @module if @module
|
||||
up = up.parent
|
||||
end
|
||||
|
||||
@name
|
||||
end
|
||||
|
||||
##
|
||||
# Sets the store for this class or module and its contained code objects.
|
||||
|
||||
def store= store
|
||||
super
|
||||
|
||||
@file = @store.add_file @file.full_name if @file
|
||||
end
|
||||
|
||||
def to_s # :nodoc:
|
||||
"extend #@name in: #{parent}"
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -1,12 +1,10 @@
|
|||
require 'rdoc'
|
||||
|
||||
##
|
||||
# RDoc uses generators to turn parsed source code in the form of an
|
||||
# RDoc::CodeObject tree into some form of output. RDoc comes with the HTML
|
||||
# generator RDoc::Generator::Darkfish and an ri data generator
|
||||
# RDoc::Generator::RI.
|
||||
#
|
||||
# = Registering a Generator
|
||||
# == Registering a Generator
|
||||
#
|
||||
# Generators are registered by calling RDoc::RDoc.add_generator with the class
|
||||
# of the generator:
|
||||
|
@ -15,26 +13,38 @@ require 'rdoc'
|
|||
# RDoc::RDoc.add_generator self
|
||||
# end
|
||||
#
|
||||
# = Adding Options to +rdoc+
|
||||
# == Adding Options to +rdoc+
|
||||
#
|
||||
# Before option processing in +rdoc+, RDoc::Options will call ::setup_options
|
||||
# on the generator class with an RDoc::Options instance. The generator can
|
||||
# use RDoc::Options#option_parser to add command-line options to the +rdoc+
|
||||
# tool. See OptionParser for details on how to add options.
|
||||
# tool. See RDoc::Options@Custom+Options for an example and see OptionParser
|
||||
# for details on how to add options.
|
||||
#
|
||||
# You can extend the RDoc::Options instance with additional accessors for your
|
||||
# generator.
|
||||
#
|
||||
# = Generator Instantiation
|
||||
# == Generator Instantiation
|
||||
#
|
||||
# After parsing, RDoc::RDoc will instantiate a generator by calling
|
||||
# #initialize with an RDoc::Options instance.
|
||||
# #initialize with an RDoc::Store instance and an RDoc::Options instance.
|
||||
#
|
||||
# RDoc will then call #generate on the generator instance and pass in an Array
|
||||
# of RDoc::TopLevel instances, each representing a parsed file. You can use
|
||||
# the various class methods on RDoc::TopLevel and in the RDoc::CodeObject tree
|
||||
# to create your desired output format.
|
||||
# The RDoc::Store instance holds documentation for parsed source code. In
|
||||
# RDoc 3 and earlier the RDoc::TopLevel class held this data. When upgrading
|
||||
# a generator from RDoc 3 and earlier you should only need to replace
|
||||
# RDoc::TopLevel with the store instance.
|
||||
#
|
||||
# RDoc will then call #generate on the generator instance. You can use the
|
||||
# various methods on RDoc::Store and in the RDoc::CodeObject tree to create
|
||||
# your desired output format.
|
||||
|
||||
module RDoc::Generator
|
||||
|
||||
autoload :Markup, 'rdoc/generator/markup'
|
||||
|
||||
autoload :Darkfish, 'rdoc/generator/darkfish'
|
||||
autoload :JsonIndex, 'rdoc/generator/json_index'
|
||||
autoload :RI, 'rdoc/generator/ri'
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
# -*- mode: ruby; ruby-indent-level: 2; tab-width: 2 -*-
|
||||
|
||||
require 'pathname'
|
||||
require 'erb'
|
||||
require 'fileutils'
|
||||
require 'rdoc/erbio'
|
||||
|
||||
require 'pathname'
|
||||
require 'rdoc/generator/markup'
|
||||
|
||||
##
|
||||
|
@ -46,6 +45,11 @@ require 'rdoc/generator/markup'
|
|||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# == Attributions
|
||||
#
|
||||
# Darkfish uses the {Silk Icons}[http://www.famfamfam.com/lab/icons/silk/] set
|
||||
# by Mark James.
|
||||
|
||||
class RDoc::Generator::Darkfish
|
||||
|
||||
|
@ -53,6 +57,7 @@ class RDoc::Generator::Darkfish
|
|||
|
||||
include ERB::Util
|
||||
|
||||
##
|
||||
# Path to this file's parent directory. Used to find templates and other
|
||||
# resources.
|
||||
|
||||
|
@ -61,7 +66,7 @@ class RDoc::Generator::Darkfish
|
|||
##
|
||||
# Release Version
|
||||
|
||||
VERSION = '2'
|
||||
VERSION = '3'
|
||||
|
||||
##
|
||||
# Description of this generator
|
||||
|
@ -69,25 +74,87 @@ class RDoc::Generator::Darkfish
|
|||
DESCRIPTION = 'HTML generator, written by Michael Granger'
|
||||
|
||||
##
|
||||
# Initialize a few instance variables before we start
|
||||
# The relative path to style sheets and javascript. By default this is set
|
||||
# the same as the rel_prefix.
|
||||
|
||||
def initialize options
|
||||
@options = options
|
||||
attr_accessor :asset_rel_path
|
||||
|
||||
@template_dir = Pathname.new options.template_dir
|
||||
@template_cache = {}
|
||||
##
|
||||
# The path to generate files into, combined with <tt>--op</tt> from the
|
||||
# options for a full path.
|
||||
|
||||
@files = nil
|
||||
@classes = nil
|
||||
attr_reader :base_dir
|
||||
|
||||
@basedir = Pathname.pwd.expand_path
|
||||
end
|
||||
##
|
||||
# Classes and modules to be used by this generator, not necessarily
|
||||
# displayed. See also #modsort
|
||||
|
||||
attr_reader :classes
|
||||
|
||||
##
|
||||
# No files will be written when dry_run is true.
|
||||
|
||||
attr_accessor :dry_run
|
||||
|
||||
##
|
||||
# When false the generate methods return a String instead of writing to a
|
||||
# file. The default is true.
|
||||
|
||||
attr_accessor :file_output
|
||||
|
||||
##
|
||||
# Files to be displayed by this generator
|
||||
|
||||
attr_reader :files
|
||||
|
||||
##
|
||||
# The JSON index generator for this Darkfish generator
|
||||
|
||||
attr_reader :json_index
|
||||
|
||||
##
|
||||
# Methods to be displayed by this generator
|
||||
|
||||
attr_reader :methods
|
||||
|
||||
##
|
||||
# Sorted list of classes and modules to be displayed by this generator
|
||||
|
||||
attr_reader :modsort
|
||||
|
||||
##
|
||||
# The RDoc::Store that is the source of the generated content
|
||||
|
||||
attr_reader :store
|
||||
|
||||
##
|
||||
# The output directory
|
||||
|
||||
attr_reader :outputdir
|
||||
|
||||
##
|
||||
# Initialize a few instance variables before we start
|
||||
|
||||
def initialize store, options
|
||||
@store = store
|
||||
@options = options
|
||||
|
||||
@asset_rel_path = ''
|
||||
@base_dir = Pathname.pwd.expand_path
|
||||
@dry_run = @options.dry_run
|
||||
@file_output = true
|
||||
@template_dir = Pathname.new options.template_dir
|
||||
@template_cache = {}
|
||||
|
||||
@classes = nil
|
||||
@context = nil
|
||||
@files = nil
|
||||
@methods = nil
|
||||
@modsort = nil
|
||||
|
||||
@json_index = RDoc::Generator::JsonIndex.new self, options
|
||||
end
|
||||
|
||||
##
|
||||
# Output progress information if debugging is enabled
|
||||
|
||||
|
@ -126,7 +193,7 @@ class RDoc::Generator::Darkfish
|
|||
|
||||
def write_style_sheet
|
||||
debug_msg "Copying static files"
|
||||
options = { :verbose => $DEBUG_RDOC, :noop => @options.dry_run }
|
||||
options = { :verbose => $DEBUG_RDOC, :noop => @dry_run }
|
||||
|
||||
FileUtils.cp @template_dir + 'rdoc.css', '.', options
|
||||
|
||||
|
@ -134,7 +201,7 @@ class RDoc::Generator::Darkfish
|
|||
next if File.directory? path
|
||||
next if File.basename(path) =~ /^\./
|
||||
|
||||
dst = Pathname.new(path).relative_path_from @template_dir
|
||||
dst = Pathname.new(path).relative_path_from @template_dir
|
||||
|
||||
# I suck at glob
|
||||
dst_dir = dst.dirname
|
||||
|
@ -148,19 +215,17 @@ class RDoc::Generator::Darkfish
|
|||
# Build the initial indices and output objects based on an array of TopLevel
|
||||
# objects containing the extracted information.
|
||||
|
||||
def generate top_levels
|
||||
@outputdir = Pathname.new(@options.op_dir).expand_path(@basedir)
|
||||
def generate
|
||||
setup
|
||||
|
||||
@files = top_levels.sort
|
||||
@classes = RDoc::TopLevel.all_classes_and_modules.sort
|
||||
@methods = @classes.map { |m| m.method_list }.flatten.sort
|
||||
@modsort = get_sorted_module_list(@classes)
|
||||
|
||||
# Now actually write the output
|
||||
write_style_sheet
|
||||
generate_index
|
||||
generate_class_files
|
||||
generate_file_files
|
||||
generate_table_of_contents
|
||||
@json_index.generate
|
||||
|
||||
copy_static
|
||||
|
||||
rescue => e
|
||||
debug_msg "%s: %s\n %s" % [
|
||||
|
@ -170,42 +235,64 @@ class RDoc::Generator::Darkfish
|
|||
raise
|
||||
end
|
||||
|
||||
protected
|
||||
##
|
||||
# Copies static files from the static_path into the output directory
|
||||
|
||||
def copy_static
|
||||
return if @options.static_path.empty?
|
||||
|
||||
fu_options = { :verbose => $DEBUG_RDOC, :noop => @dry_run }
|
||||
|
||||
@options.static_path.each do |path|
|
||||
unless File.directory? path then
|
||||
FileUtils.install path, @outputdir, fu_options.merge(:mode => 0644)
|
||||
next
|
||||
end
|
||||
|
||||
Dir.chdir path do
|
||||
Dir[File.join('**', '*')].each do |entry|
|
||||
dest_file = @outputdir + entry
|
||||
|
||||
if File.directory? entry then
|
||||
FileUtils.mkdir_p entry, fu_options
|
||||
else
|
||||
FileUtils.install entry, dest_file, fu_options.merge(:mode => 0644)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Return a list of the documented modules sorted by salience first, then
|
||||
# by name.
|
||||
|
||||
def get_sorted_module_list(classes)
|
||||
nscounts = classes.inject({}) do |counthash, klass|
|
||||
top_level = klass.full_name.gsub(/::.*/, '')
|
||||
counthash[top_level] ||= 0
|
||||
counthash[top_level] += 1
|
||||
|
||||
counthash
|
||||
end
|
||||
|
||||
# Sort based on how often the top level namespace occurs, and then on the
|
||||
# name of the module -- this works for projects that put their stuff into
|
||||
# a namespace, of course, but doesn't hurt if they don't.
|
||||
classes.sort_by do |klass|
|
||||
top_level = klass.full_name.gsub( /::.*/, '' )
|
||||
[nscounts[top_level] * -1, klass.full_name]
|
||||
end.select do |klass|
|
||||
def get_sorted_module_list classes
|
||||
classes.select do |klass|
|
||||
klass.display?
|
||||
end
|
||||
end.sort
|
||||
end
|
||||
|
||||
##
|
||||
# Generate an index page which lists all the classes which are documented.
|
||||
|
||||
def generate_index
|
||||
setup
|
||||
|
||||
template_file = @template_dir + 'index.rhtml'
|
||||
return unless template_file.exist?
|
||||
|
||||
debug_msg "Rendering the index page..."
|
||||
|
||||
out_file = @basedir + @options.op_dir + 'index.html'
|
||||
out_file = @base_dir + @options.op_dir + 'index.html'
|
||||
rel_prefix = @outputdir.relative_path_from out_file.dirname
|
||||
search_index_rel_prefix = rel_prefix
|
||||
search_index_rel_prefix += @asset_rel_path if @file_output
|
||||
|
||||
# suppress 1.9.3 warning
|
||||
asset_rel_prefix = asset_rel_prefix = rel_prefix + @asset_rel_path
|
||||
|
||||
@title = @options.title
|
||||
|
||||
render_template template_file, out_file do |io| binding end
|
||||
rescue => e
|
||||
|
@ -217,10 +304,40 @@ class RDoc::Generator::Darkfish
|
|||
end
|
||||
|
||||
##
|
||||
# Generate a documentation file for each class
|
||||
# Generates a class file for +klass+
|
||||
|
||||
def generate_class klass, template_file = nil
|
||||
setup
|
||||
|
||||
current = klass
|
||||
|
||||
template_file ||= @template_dir + 'class.rhtml'
|
||||
|
||||
debug_msg " working on %s (%s)" % [klass.full_name, klass.path]
|
||||
out_file = @outputdir + klass.path
|
||||
rel_prefix = @outputdir.relative_path_from out_file.dirname
|
||||
search_index_rel_prefix = rel_prefix
|
||||
search_index_rel_prefix += @asset_rel_path if @file_output
|
||||
|
||||
# suppress 1.9.3 warning
|
||||
asset_rel_prefix = asset_rel_prefix = rel_prefix + @asset_rel_path
|
||||
svninfo = svninfo = get_svninfo(current)
|
||||
|
||||
@title = "#{klass.type} #{klass.full_name} - #{@options.title}"
|
||||
|
||||
debug_msg " rendering #{out_file}"
|
||||
render_template template_file, out_file do |io| binding end
|
||||
end
|
||||
|
||||
##
|
||||
# Generate a documentation file for each class and module
|
||||
|
||||
def generate_class_files
|
||||
template_file = @template_dir + 'classpage.rhtml'
|
||||
setup
|
||||
|
||||
template_file = @template_dir + 'class.rhtml'
|
||||
template_file = @template_dir + 'classpage.rhtml' unless
|
||||
template_file.exist?
|
||||
return unless template_file.exist?
|
||||
debug_msg "Generating class documentation in #{@outputdir}"
|
||||
|
||||
|
@ -228,14 +345,8 @@ class RDoc::Generator::Darkfish
|
|||
|
||||
@classes.each do |klass|
|
||||
current = klass
|
||||
debug_msg " working on %s (%s)" % [klass.full_name, klass.path]
|
||||
out_file = @outputdir + klass.path
|
||||
# suppress 1.9.3 warning
|
||||
rel_prefix = rel_prefix = @outputdir.relative_path_from(out_file.dirname)
|
||||
svninfo = svninfo = self.get_svninfo(klass)
|
||||
|
||||
debug_msg " rendering #{out_file}"
|
||||
render_template template_file, out_file do |io| binding end
|
||||
generate_class klass, template_file
|
||||
end
|
||||
rescue => e
|
||||
error = RDoc::Error.new \
|
||||
|
@ -249,19 +360,56 @@ class RDoc::Generator::Darkfish
|
|||
# Generate a documentation file for each file
|
||||
|
||||
def generate_file_files
|
||||
template_file = @template_dir + 'filepage.rhtml'
|
||||
return unless template_file.exist?
|
||||
setup
|
||||
|
||||
page_file = @template_dir + 'page.rhtml'
|
||||
fileinfo_file = @template_dir + 'fileinfo.rhtml'
|
||||
|
||||
# for legacy templates
|
||||
filepage_file = @template_dir + 'filepage.rhtml' unless
|
||||
page_file.exist? or fileinfo_file.exist?
|
||||
|
||||
return unless
|
||||
page_file.exist? or fileinfo_file.exist? or filepage_file.exist?
|
||||
|
||||
debug_msg "Generating file documentation in #{@outputdir}"
|
||||
|
||||
out_file = nil
|
||||
current = nil
|
||||
|
||||
@files.each do |file|
|
||||
out_file = @outputdir + file.path
|
||||
debug_msg " working on %s (%s)" % [file.full_name, out_file]
|
||||
# suppress 1.9.3 warning
|
||||
rel_prefix = rel_prefix = @outputdir.relative_path_from(out_file.dirname)
|
||||
current = file
|
||||
|
||||
if file.text? and page_file.exist? then
|
||||
generate_page file
|
||||
next
|
||||
end
|
||||
|
||||
template_file = nil
|
||||
out_file = @outputdir + file.path
|
||||
debug_msg " working on %s (%s)" % [file.full_name, out_file]
|
||||
rel_prefix = @outputdir.relative_path_from out_file.dirname
|
||||
search_index_rel_prefix = rel_prefix
|
||||
search_index_rel_prefix += @asset_rel_path if @file_output
|
||||
|
||||
# suppress 1.9.3 warning
|
||||
asset_rel_prefix = asset_rel_prefix = rel_prefix + @asset_rel_path
|
||||
|
||||
unless filepage_file then
|
||||
if file.text? then
|
||||
next unless page_file.exist?
|
||||
template_file = page_file
|
||||
@title = file.page_name
|
||||
else
|
||||
next unless fileinfo_file.exist?
|
||||
template_file = fileinfo_file
|
||||
@title = "File: #{file.base_name}"
|
||||
end
|
||||
end
|
||||
|
||||
@title += " - #{@options.title}"
|
||||
template_file ||= filepage_file
|
||||
|
||||
debug_msg " rendering #{out_file}"
|
||||
render_template template_file, out_file do |io| binding end
|
||||
end
|
||||
rescue => e
|
||||
|
@ -272,6 +420,134 @@ class RDoc::Generator::Darkfish
|
|||
raise error
|
||||
end
|
||||
|
||||
##
|
||||
# Generate a page file for +file+
|
||||
|
||||
def generate_page file
|
||||
setup
|
||||
|
||||
template_file = @template_dir + 'page.rhtml'
|
||||
|
||||
out_file = @outputdir + file.path
|
||||
debug_msg " working on %s (%s)" % [file.full_name, out_file]
|
||||
rel_prefix = @outputdir.relative_path_from out_file.dirname
|
||||
search_index_rel_prefix = rel_prefix
|
||||
search_index_rel_prefix += @asset_rel_path if @file_output
|
||||
|
||||
# suppress 1.9.3 warning
|
||||
current = current = file
|
||||
asset_rel_prefix = asset_rel_prefix = rel_prefix + @asset_rel_path
|
||||
|
||||
@title = "#{file.page_name} - #{@options.title}"
|
||||
|
||||
debug_msg " rendering #{out_file}"
|
||||
render_template template_file, out_file do |io| binding end
|
||||
end
|
||||
|
||||
##
|
||||
# Generates the 404 page for the RDoc servlet
|
||||
|
||||
def generate_servlet_not_found path
|
||||
setup
|
||||
|
||||
template_file = @template_dir + 'servlet_not_found.rhtml'
|
||||
return unless template_file.exist?
|
||||
|
||||
debug_msg "Rendering the servlet root page..."
|
||||
|
||||
rel_prefix = rel_prefix = ''
|
||||
search_index_rel_prefix = rel_prefix
|
||||
search_index_rel_prefix += @asset_rel_path if @file_output
|
||||
|
||||
# suppress 1.9.3 warning
|
||||
asset_rel_prefix = asset_rel_prefix = ''
|
||||
|
||||
@title = 'Not Found'
|
||||
|
||||
render_template template_file do |io| binding end
|
||||
rescue => e
|
||||
error = RDoc::Error.new \
|
||||
"error generating servlet_root: #{e.message} (#{e.class})"
|
||||
error.set_backtrace e.backtrace
|
||||
|
||||
raise error
|
||||
end
|
||||
|
||||
##
|
||||
# Generates the servlet root page for the RDoc servlet
|
||||
|
||||
def generate_servlet_root installed
|
||||
setup
|
||||
|
||||
template_file = @template_dir + 'servlet_root.rhtml'
|
||||
return unless template_file.exist?
|
||||
|
||||
debug_msg 'Rendering the servlet root page...'
|
||||
|
||||
rel_prefix = rel_prefix = ''
|
||||
search_index_rel_prefix = rel_prefix
|
||||
search_index_rel_prefix += @asset_rel_path if @file_output
|
||||
|
||||
# suppress 1.9.3 warning
|
||||
asset_rel_prefix = asset_rel_prefix = ''
|
||||
|
||||
@title = 'Local RDoc Documentation'
|
||||
|
||||
render_template template_file do |io| binding end
|
||||
rescue => e
|
||||
error = RDoc::Error.new \
|
||||
"error generating servlet_root: #{e.message} (#{e.class})"
|
||||
error.set_backtrace e.backtrace
|
||||
|
||||
raise error
|
||||
end
|
||||
|
||||
##
|
||||
# Generate an index page which lists all the classes which are documented.
|
||||
|
||||
def generate_table_of_contents
|
||||
setup
|
||||
|
||||
template_file = @template_dir + 'table_of_contents.rhtml'
|
||||
return unless template_file.exist?
|
||||
|
||||
debug_msg "Rendering the Table of Contents..."
|
||||
|
||||
out_file = @outputdir + 'table_of_contents.html'
|
||||
rel_prefix = @outputdir.relative_path_from out_file.dirname
|
||||
search_index_rel_prefix = rel_prefix
|
||||
search_index_rel_prefix += @asset_rel_path if @file_output
|
||||
|
||||
# suppress 1.9.3 warning
|
||||
asset_rel_prefix = asset_rel_prefix = rel_prefix + @asset_rel_path
|
||||
|
||||
@title = "Table of Contents - #{@options.title}"
|
||||
|
||||
render_template template_file, out_file do |io| binding end
|
||||
rescue => e
|
||||
error = RDoc::Error.new \
|
||||
"error generating table_of_contents.html: #{e.message} (#{e.class})"
|
||||
error.set_backtrace e.backtrace
|
||||
|
||||
raise error
|
||||
end
|
||||
|
||||
##
|
||||
# Prepares for generation of output from the current directory
|
||||
|
||||
def setup
|
||||
return if instance_variable_defined? :@outputdir
|
||||
|
||||
@outputdir = Pathname.new(@options.op_dir).expand_path @base_dir
|
||||
|
||||
return unless @store
|
||||
|
||||
@classes = @store.all_classes_and_modules.sort
|
||||
@files = @store.all_files.sort
|
||||
@methods = @classes.map { |m| m.method_list }.flatten.sort
|
||||
@modsort = get_sorted_module_list @classes
|
||||
end
|
||||
|
||||
##
|
||||
# Return a string describing the amount of time in the given number of
|
||||
# seconds in terms a human can understand easily.
|
||||
|
@ -324,6 +600,46 @@ class RDoc::Generator::Darkfish
|
|||
}
|
||||
end
|
||||
|
||||
##
|
||||
# Creates a template from its components and the +body_file+.
|
||||
#
|
||||
# For backwards compatibility, if +body_file+ contains "<html" the body is
|
||||
# used directly.
|
||||
|
||||
def assemble_template body_file
|
||||
body = body_file.read
|
||||
return body if body =~ /<html/
|
||||
|
||||
head_file = @template_dir + '_head.rhtml'
|
||||
footer_file = @template_dir + '_footer.rhtml'
|
||||
|
||||
<<-TEMPLATE
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
#{head_file.read}
|
||||
|
||||
#{body}
|
||||
|
||||
#{footer_file.read}
|
||||
TEMPLATE
|
||||
end
|
||||
|
||||
##
|
||||
# Renders the ERb contained in +file_name+ relative to the template
|
||||
# directory and returns the result based on the current context.
|
||||
|
||||
def render file_name
|
||||
template_file = @template_dir + file_name
|
||||
|
||||
template = template_for template_file, false, RDoc::ERBPartial
|
||||
|
||||
template.filename = template_file.to_s
|
||||
|
||||
template.result @context
|
||||
end
|
||||
|
||||
##
|
||||
# Load and render the erb template in the given +template_file+ and write
|
||||
# it out to +out_file+.
|
||||
|
@ -332,28 +648,33 @@ class RDoc::Generator::Darkfish
|
|||
#
|
||||
# An io will be yielded which must be captured by binding in the caller.
|
||||
|
||||
def render_template template_file, out_file # :yield: io
|
||||
template = template_for template_file
|
||||
def render_template template_file, out_file = nil # :yield: io
|
||||
io_output = out_file && !@dry_run && @file_output
|
||||
erb_klass = io_output ? RDoc::ERBIO : ERB
|
||||
|
||||
unless @options.dry_run then
|
||||
template = template_for template_file, true, erb_klass
|
||||
|
||||
if io_output then
|
||||
debug_msg "Outputting to %s" % [out_file.expand_path]
|
||||
|
||||
out_file.dirname.mkpath
|
||||
out_file.open 'w', 0644 do |io|
|
||||
io.set_encoding @options.encoding if Object.const_defined? :Encoding
|
||||
|
||||
context = yield io
|
||||
@context = yield io
|
||||
|
||||
template_result template, context, template_file
|
||||
template_result template, @context, template_file
|
||||
end
|
||||
else
|
||||
context = yield nil
|
||||
@context = yield nil
|
||||
|
||||
output = template_result template, context, template_file
|
||||
output = template_result template, @context, template_file
|
||||
|
||||
debug_msg " would have written %d characters to %s" % [
|
||||
output.length, out_file.expand_path
|
||||
]
|
||||
] if @dry_run
|
||||
|
||||
output
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -374,14 +695,25 @@ class RDoc::Generator::Darkfish
|
|||
##
|
||||
# Retrieves a cache template for +file+, if present, or fills the cache.
|
||||
|
||||
def template_for file
|
||||
def template_for file, page = true, klass = ERB
|
||||
template = @template_cache[file]
|
||||
|
||||
return template if template
|
||||
|
||||
klass = @options.dry_run ? ERB : RDoc::ERBIO
|
||||
template = if page then
|
||||
assemble_template file
|
||||
else
|
||||
file.read
|
||||
end
|
||||
|
||||
template = klass.new file.read, nil, '<>'
|
||||
erbout = if page then
|
||||
'io'
|
||||
else
|
||||
file_var = File.basename(file).sub(/\..*/, '')
|
||||
"_erbout_#{file_var}"
|
||||
end
|
||||
|
||||
template = klass.new template, nil, '<>', erbout
|
||||
@template_cache[file] = template
|
||||
template
|
||||
end
|
||||
|
|
|
@ -0,0 +1,248 @@
|
|||
require 'json'
|
||||
|
||||
##
|
||||
# The JsonIndex generator is designed to complement an HTML generator and
|
||||
# produces a JSON search index. This generator is derived from sdoc by
|
||||
# Vladimir Kolesnikov and contains verbatim code written by him.
|
||||
#
|
||||
# This generator is designed to be used with a regular HTML generator:
|
||||
#
|
||||
# class RDoc::Generator::Darkfish
|
||||
# def initialize options
|
||||
# # ...
|
||||
# @base_dir = Pathname.pwd.expand_path
|
||||
#
|
||||
# @json_index = RDoc::Generator::JsonIndex.new self, options
|
||||
# end
|
||||
#
|
||||
# def generate
|
||||
# # ...
|
||||
# @json_index.generate
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# == Index Format
|
||||
#
|
||||
# The index is output as a JSON file assigned to the global variable
|
||||
# +search_data+. The structure is:
|
||||
#
|
||||
# var search_data = {
|
||||
# "index": {
|
||||
# "searchIndex":
|
||||
# ["a", "b", ...],
|
||||
# "longSearchIndex":
|
||||
# ["a", "a::b", ...],
|
||||
# "info": [
|
||||
# ["A", "A", "A.html", "", ""],
|
||||
# ["B", "A::B", "A::B.html", "", ""],
|
||||
# ...
|
||||
# ]
|
||||
# }
|
||||
# }
|
||||
#
|
||||
# The same item is described across the +searchIndex+, +longSearchIndex+ and
|
||||
# +info+ fields. The +searchIndex+ field contains the item's short name, the
|
||||
# +longSearchIndex+ field contains the full_name (when appropriate) and the
|
||||
# +info+ field contains the item's name, full_name, path, parameters and a
|
||||
# snippet of the item's comment.
|
||||
#
|
||||
# == LICENSE
|
||||
#
|
||||
# Copyright (c) 2009 Vladimir Kolesnikov
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
class RDoc::Generator::JsonIndex
|
||||
|
||||
include RDoc::Text
|
||||
|
||||
##
|
||||
# Where the search index lives in the generated output
|
||||
|
||||
SEARCH_INDEX_FILE = File.join 'js', 'search_index.js'
|
||||
|
||||
attr_reader :index # :nodoc:
|
||||
|
||||
##
|
||||
# Creates a new generator. +parent_generator+ is used to determine the
|
||||
# class_dir and file_dir of links in the output index.
|
||||
#
|
||||
# +options+ are the same options passed to the parent generator.
|
||||
|
||||
def initialize parent_generator, options
|
||||
@parent_generator = parent_generator
|
||||
@store = parent_generator.store
|
||||
@options = options
|
||||
|
||||
@template_dir = File.expand_path '../template/json_index', __FILE__
|
||||
@base_dir = @parent_generator.base_dir
|
||||
|
||||
@classes = nil
|
||||
@files = nil
|
||||
@index = nil
|
||||
end
|
||||
|
||||
##
|
||||
# Builds the JSON index as a Hash.
|
||||
|
||||
def build_index
|
||||
reset @store.all_files.sort, @store.all_classes_and_modules.sort
|
||||
|
||||
index_classes
|
||||
index_methods
|
||||
index_pages
|
||||
|
||||
{ :index => @index }
|
||||
end
|
||||
|
||||
##
|
||||
# Output progress information if debugging is enabled
|
||||
|
||||
def debug_msg *msg
|
||||
return unless $DEBUG_RDOC
|
||||
$stderr.puts(*msg)
|
||||
end
|
||||
|
||||
##
|
||||
# Writes the JSON index to disk
|
||||
|
||||
def generate
|
||||
debug_msg "Generating JSON index"
|
||||
|
||||
debug_msg " writing search index to %s" % SEARCH_INDEX_FILE
|
||||
data = build_index
|
||||
|
||||
return if @options.dry_run
|
||||
|
||||
out_dir = @base_dir + @options.op_dir
|
||||
index_file = out_dir + SEARCH_INDEX_FILE
|
||||
|
||||
FileUtils.mkdir_p index_file.dirname, :verbose => $DEBUG_RDOC
|
||||
|
||||
index_file.open 'w', 0644 do |io|
|
||||
io.set_encoding Encoding::UTF_8 if Object.const_defined? :Encoding
|
||||
io.write 'var search_data = '
|
||||
|
||||
JSON.dump data, io, 0
|
||||
end
|
||||
|
||||
Dir.chdir @template_dir do
|
||||
Dir['**/*.js'].each do |source|
|
||||
dest = File.join out_dir, source
|
||||
|
||||
FileUtils.install source, dest, :mode => 0644, :verbose => $DEBUG_RDOC
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Adds classes and modules to the index
|
||||
|
||||
def index_classes
|
||||
debug_msg " generating class search index"
|
||||
|
||||
documented = @classes.uniq.select do |klass|
|
||||
klass.document_self_or_methods
|
||||
end
|
||||
|
||||
documented.each do |klass|
|
||||
debug_msg " #{klass.full_name}"
|
||||
record = klass.search_record
|
||||
@index[:searchIndex] << search_string(record.shift)
|
||||
@index[:longSearchIndex] << search_string(record.shift)
|
||||
@index[:info] << record
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Adds methods to the index
|
||||
|
||||
def index_methods
|
||||
debug_msg " generating method search index"
|
||||
|
||||
list = @classes.uniq.map do |klass|
|
||||
klass.method_list
|
||||
end.flatten.sort_by do |method|
|
||||
[method.name, method.parent.full_name]
|
||||
end
|
||||
|
||||
list.each do |method|
|
||||
debug_msg " #{method.full_name}"
|
||||
record = method.search_record
|
||||
@index[:searchIndex] << "#{search_string record.shift}()"
|
||||
@index[:longSearchIndex] << "#{search_string record.shift}()"
|
||||
@index[:info] << record
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Adds pages to the index
|
||||
|
||||
def index_pages
|
||||
debug_msg " generating pages search index"
|
||||
|
||||
pages = @files.select do |file|
|
||||
file.text?
|
||||
end
|
||||
|
||||
pages.each do |page|
|
||||
debug_msg " #{page.page_name}"
|
||||
record = page.search_record
|
||||
@index[:searchIndex] << search_string(record.shift)
|
||||
@index[:longSearchIndex] << ''
|
||||
record.shift
|
||||
@index[:info] << record
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# The directory classes are written to
|
||||
|
||||
def class_dir
|
||||
@parent_generator.class_dir
|
||||
end
|
||||
|
||||
##
|
||||
# The directory files are written to
|
||||
|
||||
def file_dir
|
||||
@parent_generator.file_dir
|
||||
end
|
||||
|
||||
def reset files, classes # :nodoc:
|
||||
@files = files
|
||||
@classes = classes
|
||||
|
||||
@index = {
|
||||
:searchIndex => [],
|
||||
:longSearchIndex => [],
|
||||
:info => []
|
||||
}
|
||||
end
|
||||
|
||||
##
|
||||
# Removes whitespace and downcases +string+
|
||||
|
||||
def search_string string
|
||||
string.downcase.gsub(/\s/, '')
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -1,14 +1,8 @@
|
|||
# This file is loaded by generators. It allows RDoc's CodeObject tree to
|
||||
# avoid loading generator code to increase startup time (for ri).
|
||||
|
||||
require 'rdoc/text'
|
||||
require 'rdoc/code_objects'
|
||||
require 'rdoc/generator'
|
||||
require 'rdoc/markup/to_html_crossref'
|
||||
require 'rdoc/ruby_token'
|
||||
|
||||
##
|
||||
# Handle common RDoc::Markup tasks for various CodeObjects
|
||||
#
|
||||
# This module is loaded by generators. It allows RDoc's CodeObject tree to
|
||||
# avoid loading generator code to improve startup time for +ri+.
|
||||
|
||||
module RDoc::Generator::Markup
|
||||
|
||||
|
@ -39,18 +33,18 @@ module RDoc::Generator::Markup
|
|||
def formatter
|
||||
return @formatter if defined? @formatter
|
||||
|
||||
show_hash = RDoc::RDoc.current.options.show_hash
|
||||
hyperlink_all = RDoc::RDoc.current.options.hyperlink_all
|
||||
options = @store.rdoc.options
|
||||
this = RDoc::Context === self ? self : @parent
|
||||
|
||||
@formatter = RDoc::Markup::ToHtmlCrossref.new(this.path, this, show_hash,
|
||||
hyperlink_all)
|
||||
@formatter = RDoc::Markup::ToHtmlCrossref.new options, this.path, this
|
||||
@formatter.code_object = self
|
||||
@formatter
|
||||
end
|
||||
|
||||
##
|
||||
# Build a webcvs URL starting for the given +url+ with +full_path+ appended
|
||||
# as the destination path. If +url+ contains '%s' +full_path+ will be
|
||||
# sprintf'd into +url+ instead.
|
||||
# will replace the %s using sprintf on the +url+.
|
||||
|
||||
def cvs_url(url, full_path)
|
||||
if /%s/ =~ url then
|
||||
|
@ -62,10 +56,14 @@ module RDoc::Generator::Markup
|
|||
|
||||
end
|
||||
|
||||
class RDoc::AnyMethod
|
||||
class RDoc::CodeObject
|
||||
|
||||
include RDoc::Generator::Markup
|
||||
|
||||
end
|
||||
|
||||
class RDoc::MethodAttr
|
||||
|
||||
@add_line_numbers = false
|
||||
|
||||
class << self
|
||||
|
@ -82,7 +80,8 @@ class RDoc::AnyMethod
|
|||
#
|
||||
# # File xxxxx, line dddd
|
||||
#
|
||||
# If it has, line numbers are added an ', line dddd' is removed.
|
||||
# If it has this comment then line numbers are added to +src+ and the <tt>,
|
||||
# line dddd</tt> portion of the comment is removed.
|
||||
|
||||
def add_line_numbers(src)
|
||||
return unless src.sub!(/\A(.*)(, line (\d+))/, '\1')
|
||||
|
@ -111,32 +110,7 @@ class RDoc::AnyMethod
|
|||
def markup_code
|
||||
return '' unless @token_stream
|
||||
|
||||
src = ""
|
||||
|
||||
@token_stream.each do |t|
|
||||
next unless t
|
||||
|
||||
style = case t
|
||||
when RDoc::RubyToken::TkCONSTANT then 'ruby-constant'
|
||||
when RDoc::RubyToken::TkKW then 'ruby-keyword'
|
||||
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'
|
||||
when RDoc::RubyToken::TkREGEXP then 'ruby-regexp'
|
||||
when RDoc::RubyToken::TkSTRING then 'ruby-string'
|
||||
when RDoc::RubyToken::TkVal then 'ruby-value'
|
||||
end
|
||||
|
||||
text = CGI.escapeHTML t.text
|
||||
|
||||
if style then
|
||||
src << "<span class=\"#{style}\">#{text}</span>"
|
||||
else
|
||||
src << text
|
||||
end
|
||||
end
|
||||
src = RDoc::TokenStream.to_html @token_stream
|
||||
|
||||
# dedent the source
|
||||
indent = src.length
|
||||
|
@ -151,34 +125,21 @@ class RDoc::AnyMethod
|
|||
end
|
||||
src.gsub!(/^#{' ' * indent}/, '') if indent > 0
|
||||
|
||||
add_line_numbers(src) if self.class.add_line_numbers
|
||||
add_line_numbers(src) if RDoc::MethodAttr.add_line_numbers
|
||||
|
||||
src
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class RDoc::Attr
|
||||
class RDoc::ClassModule
|
||||
|
||||
include RDoc::Generator::Markup
|
||||
##
|
||||
# Handy wrapper for marking up this class or module's comment
|
||||
|
||||
end
|
||||
|
||||
class RDoc::Alias
|
||||
|
||||
include RDoc::Generator::Markup
|
||||
|
||||
end
|
||||
|
||||
class RDoc::Constant
|
||||
|
||||
include RDoc::Generator::Markup
|
||||
|
||||
end
|
||||
|
||||
class RDoc::Context
|
||||
|
||||
include RDoc::Generator::Markup
|
||||
def description
|
||||
markup @comment_location
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
@ -195,7 +156,7 @@ class RDoc::TopLevel
|
|||
# command line option to set.
|
||||
|
||||
def cvs_url
|
||||
url = RDoc::RDoc.current.options.webcvs
|
||||
url = @store.rdoc.options.webcvs
|
||||
|
||||
if /%s/ =~ url then
|
||||
url % @absolute_name
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
require 'rdoc/generator'
|
||||
require 'rdoc/ri'
|
||||
|
||||
##
|
||||
# Generates ri data files
|
||||
|
||||
|
@ -16,70 +13,17 @@ class RDoc::Generator::RI
|
|||
##
|
||||
# Set up a new ri generator
|
||||
|
||||
def initialize options #:not-new:
|
||||
@options = options
|
||||
@old_siginfo = nil
|
||||
@current = nil
|
||||
|
||||
@store = RDoc::RI::Store.new '.'
|
||||
@store.dry_run = @options.dry_run
|
||||
@store.encoding = @options.encoding if @options.respond_to? :encoding
|
||||
def initialize store, options #:not-new:
|
||||
@options = options
|
||||
@store = store
|
||||
@store.path = '.'
|
||||
end
|
||||
|
||||
##
|
||||
# Build the initial indices and output objects based on an array of TopLevel
|
||||
# objects containing the extracted information.
|
||||
# Writes the parsed data store to disk for use by ri.
|
||||
|
||||
def generate top_levels
|
||||
install_siginfo_handler
|
||||
|
||||
@store.load_cache
|
||||
|
||||
RDoc::TopLevel.all_classes_and_modules.each do |klass|
|
||||
@current = "#{klass.class}: #{klass.full_name}"
|
||||
|
||||
@store.save_class klass
|
||||
|
||||
klass.each_method do |method|
|
||||
@current = "#{method.class}: #{method.full_name}"
|
||||
@store.save_method klass, method
|
||||
end
|
||||
|
||||
klass.each_attribute do |attribute|
|
||||
@store.save_method klass, attribute
|
||||
end
|
||||
end
|
||||
|
||||
@current = 'saving cache'
|
||||
|
||||
@store.save_cache
|
||||
|
||||
ensure
|
||||
@current = nil
|
||||
|
||||
remove_siginfo_handler
|
||||
end
|
||||
|
||||
##
|
||||
# Installs a siginfo handler that prints the current filename.
|
||||
|
||||
def install_siginfo_handler
|
||||
return unless Signal.list.key? 'INFO'
|
||||
|
||||
@old_siginfo = trap 'INFO' do
|
||||
puts @current if @current
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Removes a siginfo handler and replaces the previous
|
||||
|
||||
def remove_siginfo_handler
|
||||
return unless Signal.list.key? 'INFO'
|
||||
|
||||
handler = @old_siginfo || 'DEFAULT'
|
||||
|
||||
trap 'INFO', handler
|
||||
def generate
|
||||
@store.save
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<footer id="validator-badges">
|
||||
<p><a href="http://validator.w3.org/check/referer">[Validate]</a>
|
||||
<p>Generated by <a href="https://github.com/rdoc/rdoc">RDoc</a> <%= RDoc::VERSION %>.
|
||||
<p>Generated with the <a href="http://deveiate.org/projects/Darkfish-Rdoc/">Darkfish Rdoc Generator</a> <%= RDoc::Generator::Darkfish::VERSION %>.
|
||||
</footer>
|
|
@ -0,0 +1,16 @@
|
|||
<meta content="text/html; charset=<%= @options.charset %>" http-equiv="Content-Type">
|
||||
|
||||
<title><%= h @title %></title>
|
||||
|
||||
<link type="text/css" media="screen" href="<%= asset_rel_prefix %>/rdoc.css" rel="stylesheet">
|
||||
|
||||
<script type="text/javascript">
|
||||
var rdoc_rel_prefix = "<%= rel_prefix %>/";
|
||||
</script>
|
||||
|
||||
<script type="text/javascript" charset="utf-8" src="<%= asset_rel_prefix %>/js/jquery.js"></script>
|
||||
<script type="text/javascript" charset="utf-8" src="<%= asset_rel_prefix %>/js/navigation.js"></script>
|
||||
<script type="text/javascript" charset="utf-8" src="<%= search_index_rel_prefix %>/js/search_index.js"></script>
|
||||
<script type="text/javascript" charset="utf-8" src="<%= asset_rel_prefix %>/js/search.js"></script>
|
||||
<script type="text/javascript" charset="utf-8" src="<%= asset_rel_prefix %>/js/searcher.js"></script>
|
||||
<script type="text/javascript" charset="utf-8" src="<%= asset_rel_prefix %>/js/darkfish.js"></script>
|
|
@ -0,0 +1,18 @@
|
|||
<% if !svninfo.empty? then %>
|
||||
<nav id="file-svninfo-section" class="section">
|
||||
<h3 class="section-header">VCS Info</h3>
|
||||
<div class="section-body">
|
||||
<dl class="svninfo">
|
||||
<dt>Rev
|
||||
<dd><%= svninfo[:rev] %>
|
||||
|
||||
<dt>Last Checked In
|
||||
<dd><%= svninfo[:commitdate].strftime('%Y-%m-%d %H:%M:%S') %>
|
||||
(<%= svninfo[:commitdelta] %> ago)
|
||||
|
||||
<dt>Checked in by
|
||||
<dd><%= svninfo[:committer] %>
|
||||
</dl>
|
||||
</div>
|
||||
</nav>
|
||||
<% end %>
|
|
@ -0,0 +1,9 @@
|
|||
<nav id="classindex-section" class="section project-section">
|
||||
<h3 class="section-header">Class and Module Index</h3>
|
||||
|
||||
<ul class="link-list">
|
||||
<% @modsort.each do |index_klass| %>
|
||||
<li><a href="<%= rel_prefix %>/<%= index_klass.path %>"><%= index_klass.full_name %></a>
|
||||
<% end %>
|
||||
</ul>
|
||||
</nav>
|
|
@ -0,0 +1,16 @@
|
|||
<% unless klass.extends.empty? then %>
|
||||
<!-- Extension Modules -->
|
||||
<nav id="extends-section" class="section">
|
||||
<h3 class="section-header">Extended With Modules</h3>
|
||||
|
||||
<ul class="link-list">
|
||||
<% klass.each_extend do |ext| %>
|
||||
<% unless String === ext.module then %>
|
||||
<li><a class="extend" href="<%= klass.aref_to ext.module.path %>"><%= ext.module.full_name %></a>
|
||||
<% else %>
|
||||
<li><span class="extend"><%= ext.name %></span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</ul>
|
||||
</nav>
|
||||
<% end %>
|
|
@ -0,0 +1,8 @@
|
|||
<nav id="file-list-section" class="section">
|
||||
<h3 class="section-header">Defined In</h3>
|
||||
<ul>
|
||||
<% klass.in_files.each do |tl| %>
|
||||
<li><%= h tl.absolute_name %>
|
||||
<% end %>
|
||||
</ul>
|
||||
</nav>
|
|
@ -0,0 +1,16 @@
|
|||
<% unless klass.includes.empty? then %>
|
||||
<!-- Included Modules -->
|
||||
<nav id="includes-section" class="section">
|
||||
<h3 class="section-header">Included Modules</h3>
|
||||
|
||||
<ul class="link-list">
|
||||
<% klass.each_include do |inc| %>
|
||||
<% unless String === inc.module then %>
|
||||
<li><a class="include" href="<%= klass.aref_to inc.module.path %>"><%= inc.module.full_name %></a>
|
||||
<% else %>
|
||||
<li><span class="include"><%= inc.name %></span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</ul>
|
||||
</nav>
|
||||
<% end %>
|
|
@ -0,0 +1,14 @@
|
|||
<nav id="home-section" class="section">
|
||||
<h3 class="section-header">Documentation</h3>
|
||||
|
||||
<ul>
|
||||
<% installed.each do |name, href, exists| %>
|
||||
<li class="folder">
|
||||
<% if exists then %>
|
||||
<a href="<%= href %>"><%= h name %></a>
|
||||
<% else %>
|
||||
<%= h name %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</ul>
|
||||
</nav>
|
|
@ -0,0 +1,12 @@
|
|||
<% unless klass.method_list.empty? then %>
|
||||
<!-- Method Quickref -->
|
||||
<nav id="method-list-section" class="section">
|
||||
<h3 class="section-header">Methods</h3>
|
||||
|
||||
<ul class="link-list">
|
||||
<% klass.each_method do |meth| %>
|
||||
<li <% if meth.calls_super %>class="calls-super" <% end %>><a href="#<%= meth.aref %>"><%= meth.singleton ? '::' : '#' %><%= h meth.name %></a>
|
||||
<% end %>
|
||||
</ul>
|
||||
</nav>
|
||||
<% end %>
|
|
@ -0,0 +1,7 @@
|
|||
<nav id="home-section" class="section">
|
||||
<h3 class="section-header">
|
||||
<a href="<%= rel_prefix %>/index.html">Home</a>
|
||||
<a href="<%= rel_prefix %>/table_of_contents.html#classes">Classes</a>
|
||||
<a href="<%= rel_prefix %>/table_of_contents.html#methods">Methods</a>
|
||||
</h3>
|
||||
</nav>
|
|
@ -0,0 +1,12 @@
|
|||
<% simple_files = @files.select { |f| f.text? } %>
|
||||
<% unless simple_files.empty? then %>
|
||||
<nav id="fileindex-section" class="section project-section">
|
||||
<h3 class="section-header">Pages</h3>
|
||||
|
||||
<ul>
|
||||
<% simple_files.each do |f| %>
|
||||
<li class="file"><a href="<%= rel_prefix %>/<%= f.path %>"><%= h f.page_name %></a>
|
||||
<% end %>
|
||||
</ul>
|
||||
</nav>
|
||||
<% end %>
|
|
@ -0,0 +1,10 @@
|
|||
<% if klass.type == 'class' then %>
|
||||
<nav id="parent-class-section" class="section">
|
||||
<h3 class="section-header">Parent</h3>
|
||||
<% if klass.superclass and not String === klass.superclass then %>
|
||||
<p class="link"><a href="<%= klass.aref_to klass.superclass.path %>"><%= klass.superclass.full_name %></a>
|
||||
<% else %>
|
||||
<p class="link"><%= klass.superclass %>
|
||||
<% end %>
|
||||
</nav>
|
||||
<% end %>
|
|
@ -0,0 +1,10 @@
|
|||
<nav id="search-section" class="section project-section" class="initially-hidden">
|
||||
<form action="#" method="get" accept-charset="utf-8">
|
||||
<h3 class="section-header">
|
||||
<input type="text" name="search" placeholder="Search" id="search-field"
|
||||
title="Type to search, Up and Down to navigate, Enter to load">
|
||||
</h3>
|
||||
</form>
|
||||
|
||||
<ul id="search-results" class="initially-hidden"></ul>
|
||||
</nav>
|
|
@ -0,0 +1,10 @@
|
|||
<% unless klass.sections.length == 1 then %>
|
||||
<nav id="sections-section" class="section">
|
||||
<h3 class="section-header">Sections</h3>
|
||||
<ul class="link-list">
|
||||
<% klass.sort_sections.each do |section| %>
|
||||
<li><a href="#<%= section.aref %>"><%= h section.title %></a></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</nav>
|
||||
<% end %>
|
|
@ -0,0 +1,13 @@
|
|||
<% table = current.parse(current.comment).table_of_contents
|
||||
if table.length > 1 then %>
|
||||
<div id="table-of-contents">
|
||||
<nav class="section">
|
||||
<h3 class="section-header">Table of Contents</h3>
|
||||
<ul>
|
||||
<% table.each do |heading| %>
|
||||
<li><a href="#<%= heading.aref %>"><%= heading.plain_html %></a>
|
||||
<% end %>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<% end %>
|
|
@ -0,0 +1,179 @@
|
|||
<body id="top" class="<%= klass.type %>">
|
||||
<nav id="metadata">
|
||||
<%= render '_sidebar_navigation.rhtml' %>
|
||||
|
||||
<%= render '_sidebar_search.rhtml' %>
|
||||
|
||||
<%= render '_sidebar_table_of_contents.rhtml' %>
|
||||
|
||||
<div id="file-metadata">
|
||||
<%= render '_sidebar_in_files.rhtml' %>
|
||||
<%= render '_sidebar_VCS_info.rhtml' %>
|
||||
</div>
|
||||
|
||||
<div id="class-metadata">
|
||||
<%= render '_sidebar_sections.rhtml' %>
|
||||
<%= render '_sidebar_parent.rhtml' %>
|
||||
<%= render '_sidebar_includes.rhtml' %>
|
||||
<%= render '_sidebar_extends.rhtml' %>
|
||||
<%= render '_sidebar_methods.rhtml' %>
|
||||
</div>
|
||||
|
||||
<div id="project-metadata">
|
||||
<%= render '_sidebar_pages.rhtml' %>
|
||||
<%= render '_sidebar_classes.rhtml' %>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div id="documentation">
|
||||
<h1 class="<%= klass.type %>"><%= klass.type %> <%= klass.full_name %></h1>
|
||||
|
||||
<div id="description" class="description">
|
||||
<%= klass.description %>
|
||||
</div><!-- description -->
|
||||
|
||||
<% klass.each_section do |section, constants, attributes| %>
|
||||
<% constants = constants.select { |const| const.display? } %>
|
||||
<% attributes = attributes.select { |attr| attr.display? } %>
|
||||
<section id="<%= section.aref %>" class="documentation-section">
|
||||
<% if section.title then %>
|
||||
<div class="documentation-section-title">
|
||||
<h2 class="section-header">
|
||||
<%= section.title %>
|
||||
</h2>
|
||||
<span class="section-click-top">
|
||||
<a href="#top">↑ top</a>
|
||||
</span>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if section.comment then %>
|
||||
<div class="description">
|
||||
<%= section.description %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% unless constants.empty? then %>
|
||||
<!-- Constants -->
|
||||
<section id="constants-list" class="section">
|
||||
<h3 class="section-header">Constants</h3>
|
||||
<dl>
|
||||
<% constants.each do |const| %>
|
||||
<dt id="<%= const.name %>"><%= const.name %>
|
||||
<% if const.comment then %>
|
||||
<dd class="description"><%= const.description.strip %>
|
||||
<% else %>
|
||||
<dd class="description missing-docs">(Not documented)
|
||||
<% end %>
|
||||
<% end %>
|
||||
</dl>
|
||||
</section>
|
||||
<% end %>
|
||||
|
||||
<% unless attributes.empty? then %>
|
||||
<!-- Attributes -->
|
||||
<section id="attribute-method-details" class="method-section section">
|
||||
<h3 class="section-header">Attributes</h3>
|
||||
|
||||
<% attributes.each do |attrib| %>
|
||||
<div id="<%= attrib.aref %>" class="method-detail">
|
||||
<div class="method-heading attribute-method-heading">
|
||||
<span class="method-name"><%= h attrib.name %></span><span
|
||||
class="attribute-access-type">[<%= attrib.rw %>]</span>
|
||||
</div>
|
||||
|
||||
<div class="method-description">
|
||||
<% if attrib.comment then %>
|
||||
<%= attrib.description.strip %>
|
||||
<% else %>
|
||||
<p class="missing-docs">(Not documented)
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</section><!-- attribute-method-details -->
|
||||
<% end %>
|
||||
|
||||
<!-- Methods -->
|
||||
<% klass.methods_by_type(section).each do |type, visibilities|
|
||||
next if visibilities.empty?
|
||||
visibilities.each do |visibility, methods|
|
||||
next if methods.empty? %>
|
||||
<section id="<%= visibility %>-<%= type %>-<%= section.aref %>-method-details" class="method-section section">
|
||||
<h3 class="section-header"><%= visibility.to_s.capitalize %> <%= type.capitalize %> Methods</h3>
|
||||
|
||||
<% methods.each do |method| %>
|
||||
<div id="<%= method.aref %>" class="method-detail <%= method.is_alias_for ? "method-alias" : '' %>">
|
||||
<% if method.call_seq then %>
|
||||
<% method.call_seq.strip.split("\n").each_with_index do |call_seq, i| %>
|
||||
<div class="method-heading">
|
||||
<span class="method-callseq">
|
||||
<%= h(call_seq.strip.
|
||||
gsub( /^\w+\./m, '')).
|
||||
gsub(/(.*)[-=]>/, '\1→') %>
|
||||
</span>
|
||||
<% if i == 0 and method.token_stream then %>
|
||||
<span class="method-click-advice">click to toggle source</span>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<div class="method-heading">
|
||||
<span class="method-name"><%= h method.name %></span><span
|
||||
class="method-args"><%= method.param_seq %></span>
|
||||
<% if method.token_stream then %>
|
||||
<span class="method-click-advice">click to toggle source</span>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="method-description">
|
||||
<% if method.comment then %>
|
||||
<%= method.description.strip %>
|
||||
<% else %>
|
||||
<p class="missing-docs">(Not documented)
|
||||
<% end %>
|
||||
<% if method.calls_super then %>
|
||||
<div class="method-calls-super">
|
||||
Calls superclass method
|
||||
<%=
|
||||
method.superclass_method ?
|
||||
method.formatter.link(method.superclass_method.full_name, method.superclass_method.full_name) : nil
|
||||
%>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if method.token_stream then %>
|
||||
<div class="method-source-code" id="<%= method.html_name %>-source">
|
||||
<pre><%= method.markup_code %></pre>
|
||||
</div><!-- <%= method.html_name %>-source -->
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% unless method.aliases.empty? then %>
|
||||
<div class="aliases">
|
||||
Also aliased as: <%= method.aliases.map do |aka|
|
||||
if aka.parent then # HACK lib/rexml/encodings
|
||||
%{<a href="#{klass.aref_to aka.path}">#{h aka.name}</a>}
|
||||
else
|
||||
h aka.name
|
||||
end
|
||||
end.join ", " %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if method.is_alias_for then %>
|
||||
<div class="aliases">
|
||||
Alias for: <a href="<%= klass.aref_to method.is_alias_for.path %>"><%= h method.is_alias_for.name %></a>
|
||||
</div>
|
||||
<% end %>
|
||||
</div><!-- <%= method.html_name %>-method -->
|
||||
|
||||
<% end %>
|
||||
</section><!-- <%= visibility %>-<%= type %>-method-details -->
|
||||
<% end
|
||||
end %>
|
||||
</section><!-- <%= section.aref %> -->
|
||||
<% end %>
|
||||
|
||||
</div><!-- documentation -->
|
|
@ -1,321 +0,0 @@
|
|||
<?xml version="1.0" encoding="<%= @options.charset %>"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta content="text/html; charset=<%= @options.charset %>" http-equiv="Content-Type" />
|
||||
|
||||
<title><%= klass.type.capitalize %>: <%= klass.full_name %></title>
|
||||
|
||||
<link rel="stylesheet" href="<%= rel_prefix %>/rdoc.css" type="text/css" media="screen" />
|
||||
|
||||
<script src="<%= rel_prefix %>/js/jquery.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="<%= rel_prefix %>/js/thickbox-compressed.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="<%= rel_prefix %>/js/quicksearch.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="<%= rel_prefix %>/js/darkfish.js" type="text/javascript" charset="utf-8"></script>
|
||||
|
||||
</head>
|
||||
<body id="top" class="<%= klass.type %>">
|
||||
|
||||
<div id="metadata">
|
||||
<div id="home-metadata">
|
||||
<div id="home-section" class="section">
|
||||
<h3 class="section-header">
|
||||
<a href="<%= rel_prefix %>/index.html">Home</a>
|
||||
<a href="<%= rel_prefix %>/index.html#classes">Classes</a>
|
||||
<a href="<%= rel_prefix %>/index.html#methods">Methods</a>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="file-metadata">
|
||||
<div id="file-list-section" class="section">
|
||||
<h3 class="section-header">In Files</h3>
|
||||
<div class="section-body">
|
||||
<ul>
|
||||
<% klass.in_files.each do |tl| %>
|
||||
<li><a href="<%= rel_prefix %>/<%= h tl.path %>?TB_iframe=true&height=550&width=785"
|
||||
class="thickbox" title="<%= h tl.absolute_name %>"><%= h tl.absolute_name %></a></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% if !svninfo.empty? then %>
|
||||
<div id="file-svninfo-section" class="section">
|
||||
<h3 class="section-header">Subversion Info</h3>
|
||||
<div class="section-body">
|
||||
<dl class="svninfo">
|
||||
<dt>Rev</dt>
|
||||
<dd><%= svninfo[:rev] %></dd>
|
||||
|
||||
<dt>Last Checked In</dt>
|
||||
<dd><%= svninfo[:commitdate].strftime('%Y-%m-%d %H:%M:%S') %>
|
||||
(<%= svninfo[:commitdelta] %> ago)</dd>
|
||||
|
||||
<dt>Checked in by</dt>
|
||||
<dd><%= svninfo[:committer] %></dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div id="class-metadata">
|
||||
<% if klass.type == 'class' then %>
|
||||
<!-- Parent Class -->
|
||||
<div id="parent-class-section" class="section">
|
||||
<h3 class="section-header">Parent</h3>
|
||||
<% if klass.superclass and not String === klass.superclass then %>
|
||||
<p class="link"><a href="<%= klass.aref_to klass.superclass.path %>"><%= klass.superclass.full_name %></a></p>
|
||||
<% else %>
|
||||
<p class="link"><%= klass.superclass %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% unless klass.sections.length == 1 then %>
|
||||
<!-- Sections -->
|
||||
<div id="sections-section" class="section">
|
||||
<h3 class="section-header">Sections</h3>
|
||||
<ul class="link-list">
|
||||
<% klass.sections.sort_by { |s| s.title.to_s }.each do |section| %>
|
||||
<li><a href="#<%= section.aref %>"><%= h section.title %></a></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% unless klass.classes_and_modules.empty? then %>
|
||||
<!-- Namespace Contents -->
|
||||
<div id="namespace-list-section" class="section">
|
||||
<h3 class="section-header">Namespace</h3>
|
||||
<ul class="link-list">
|
||||
<% (klass.modules.sort + klass.classes.sort).each do |mod| %>
|
||||
<li><span class="type"><%= mod.type.upcase %></span> <a href="<%= klass.aref_to mod.path %>"><%= mod.full_name %></a></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% unless klass.method_list.empty? then %>
|
||||
<!-- Method Quickref -->
|
||||
<div id="method-list-section" class="section">
|
||||
<h3 class="section-header">Methods</h3>
|
||||
<ul class="link-list">
|
||||
<% klass.each_method do |meth| %>
|
||||
<li><a href="#<%= meth.aref %>"><%= meth.singleton ? '::' : '#' %><%= meth.name %></a></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% unless klass.includes.empty? then %>
|
||||
<!-- Included Modules -->
|
||||
<div id="includes-section" class="section">
|
||||
<h3 class="section-header">Included Modules</h3>
|
||||
<ul class="link-list">
|
||||
<% klass.each_include do |inc| %>
|
||||
<% unless String === inc.module then %>
|
||||
<li><a class="include" href="<%= klass.aref_to inc.module.path %>"><%= inc.module.full_name %></a></li>
|
||||
<% else %>
|
||||
<li><span class="include"><%= inc.name %></span></li>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div id="project-metadata">
|
||||
<% simple_files = @files.select {|tl| tl.parser == RDoc::Parser::Simple } %>
|
||||
<% unless simple_files.empty? then %>
|
||||
<div id="fileindex-section" class="section project-section">
|
||||
<h3 class="section-header">Files</h3>
|
||||
<ul>
|
||||
<% simple_files.each do |file| %>
|
||||
<li class="file"><a href="<%= rel_prefix %>/<%= file.path %>"><%= h file.base_name %></a></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div id="classindex-section" class="section project-section">
|
||||
<h3 class="section-header">Class/Module Index
|
||||
<span class="search-toggle"><img src="<%= rel_prefix %>/images/find.png"
|
||||
height="16" width="16" alt="[+]"
|
||||
title="show/hide quicksearch" /></span></h3>
|
||||
<form action="#" method="get" accept-charset="utf-8" class="initially-hidden">
|
||||
<fieldset>
|
||||
<legend>Quicksearch</legend>
|
||||
<input type="text" name="quicksearch" value=""
|
||||
class="quicksearch-field" />
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<ul class="link-list">
|
||||
<% @modsort.each do |index_klass| %>
|
||||
<li><a href="<%= rel_prefix %>/<%= index_klass.path %>"><%= index_klass.full_name %></a></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<div id="no-class-search-results" style="display: none;">No matching classes.</div>
|
||||
</div>
|
||||
|
||||
<% if $DEBUG_RDOC then %>
|
||||
<div id="debugging-toggle"><img src="<%= rel_prefix %>/images/bug.png"
|
||||
alt="toggle debugging" height="16" width="16" /></div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="documentation">
|
||||
<h1 class="<%= klass.type %>"><%= klass.full_name %></h1>
|
||||
|
||||
<div id="description" class="description">
|
||||
<%= klass.description %>
|
||||
</div><!-- description -->
|
||||
|
||||
<% klass.each_section do |section, constants, attributes| %>
|
||||
<% constants = constants.select { |const| const.display? } %>
|
||||
<% attributes = attributes.select { |attr| attr.display? } %>
|
||||
<div id="<%= section.aref %>" class="documentation-section">
|
||||
<% if section.title then %>
|
||||
<h2 class="section-header">
|
||||
<%= section.title %>
|
||||
<a href="#top">↑ top</a>
|
||||
</h2>
|
||||
<% end %>
|
||||
|
||||
<% if section.comment then %>
|
||||
<div class="description">
|
||||
<%= section.description %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% unless constants.empty? then %>
|
||||
<!-- Constants -->
|
||||
<div id="constants-list" class="section">
|
||||
<h3 class="section-header">Constants</h3>
|
||||
<dl>
|
||||
<% constants.each do |const| %>
|
||||
<dt><a name="<%= const.name %>"><%= const.name %></a></dt>
|
||||
<% if const.comment then %>
|
||||
<dd class="description"><%= const.description.strip %></dd>
|
||||
<% else %>
|
||||
<dd class="description missing-docs">(Not documented)</dd>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</dl>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% unless attributes.empty? then %>
|
||||
<!-- Attributes -->
|
||||
<div id="attribute-method-details" class="method-section section">
|
||||
<h3 class="section-header">Attributes</h3>
|
||||
|
||||
<% attributes.each do |attrib| %>
|
||||
<div id="<%= attrib.html_name %>-attribute-method" class="method-detail">
|
||||
<a name="<%= h attrib.name %>"></a>
|
||||
<% if attrib.rw =~ /w/i then %>
|
||||
<a name="<%= h attrib.name %>="></a>
|
||||
<% end %>
|
||||
<div class="method-heading attribute-method-heading">
|
||||
<span class="method-name"><%= h attrib.name %></span><span
|
||||
class="attribute-access-type">[<%= attrib.rw %>]</span>
|
||||
</div>
|
||||
|
||||
<div class="method-description">
|
||||
<% if attrib.comment then %>
|
||||
<%= attrib.description.strip %>
|
||||
<% else %>
|
||||
<p class="missing-docs">(Not documented)</p>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div><!-- attribute-method-details -->
|
||||
<% end %>
|
||||
|
||||
<!-- Methods -->
|
||||
<% klass.methods_by_type(section).each do |type, visibilities|
|
||||
next if visibilities.empty?
|
||||
visibilities.each do |visibility, methods|
|
||||
next if methods.empty? %>
|
||||
<div id="<%= visibility %>-<%= type %>-method-details" class="method-section section">
|
||||
<h3 class="section-header"><%= visibility.to_s.capitalize %> <%= type.capitalize %> Methods</h3>
|
||||
|
||||
<% methods.each do |method| %>
|
||||
<div id="<%= method.html_name %>-method" class="method-detail <%= method.is_alias_for ? "method-alias" : '' %>">
|
||||
<a name="<%= h method.aref %>"></a>
|
||||
|
||||
<% if method.call_seq then %>
|
||||
<% method.call_seq.strip.split("\n").each_with_index do |call_seq, i| %>
|
||||
<div class="method-heading">
|
||||
<span class="method-callseq"><%= call_seq.strip.gsub(/->/, '→').gsub( /^\w+\./m, '') %></span>
|
||||
<% if i == 0 then %>
|
||||
<span class="method-click-advice">click to toggle source</span>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<div class="method-heading">
|
||||
<span class="method-name"><%= h method.name %></span><span
|
||||
class="method-args"><%= method.params %></span>
|
||||
<span class="method-click-advice">click to toggle source</span>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="method-description">
|
||||
<% if method.comment then %>
|
||||
<%= method.description.strip %>
|
||||
<% else %>
|
||||
<p class="missing-docs">(Not documented)</p>
|
||||
<% end %>
|
||||
|
||||
<% if method.token_stream then %>
|
||||
<div class="method-source-code" id="<%= method.html_name %>-source">
|
||||
<pre>
|
||||
<%= method.markup_code %>
|
||||
</pre>
|
||||
</div><!-- <%= method.html_name %>-source -->
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% unless method.aliases.empty? then %>
|
||||
<div class="aliases">
|
||||
Also aliased as: <%= method.aliases.map do |aka|
|
||||
if aka.parent then # HACK lib/rexml/encodings
|
||||
%{<a href="#{klass.aref_to aka.path}">#{h aka.name}</a>}
|
||||
else
|
||||
h aka.name
|
||||
end
|
||||
end.join ", " %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if method.is_alias_for then %>
|
||||
<div class="aliases">
|
||||
Alias for: <a href="<%= klass.aref_to method.is_alias_for.path %>"><%= h method.is_alias_for.name %></a>
|
||||
</div>
|
||||
<% end %>
|
||||
</div><!-- <%= method.html_name %>-method -->
|
||||
|
||||
<% end %>
|
||||
</div><!-- <%= visibility %>-<%= type %>-method-details -->
|
||||
<% end
|
||||
end %>
|
||||
</div><!-- <%= section.aref %> -->
|
||||
<% end %>
|
||||
|
||||
</div><!-- documentation -->
|
||||
|
||||
<div id="validator-badges">
|
||||
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
|
||||
<p><small>Generated with the <a href="http://deveiate.org/projects/Darkfish-Rdoc/">Darkfish
|
||||
Rdoc Generator</a> <%= RDoc::Generator::Darkfish::VERSION %></small>.</p>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta content="text/html; charset=<%= @options.charset %>" http-equiv="Content-Type" />
|
||||
|
||||
<title>File: <%= file.base_name %> [<%= @options.title %>]</title>
|
||||
|
||||
<link type="text/css" media="screen" href="<%= rel_prefix %>/rdoc.css" rel="stylesheet" />
|
||||
|
||||
<script src="<%= rel_prefix %>/js/jquery.js" type="text/javascript"
|
||||
charset="utf-8"></script>
|
||||
<script src="<%= rel_prefix %>/js/thickbox-compressed.js" type="text/javascript"
|
||||
charset="utf-8"></script>
|
||||
<script src="<%= rel_prefix %>/js/quicksearch.js" type="text/javascript"
|
||||
charset="utf-8"></script>
|
||||
<script src="<%= rel_prefix %>/js/darkfish.js" type="text/javascript"
|
||||
charset="utf-8"></script>
|
||||
</head>
|
||||
|
||||
<% if file.parser == RDoc::Parser::Simple %>
|
||||
<body class="file">
|
||||
<div id="metadata">
|
||||
<div id="home-metadata">
|
||||
<div id="home-section" class="section">
|
||||
<h3 class="section-header">
|
||||
<a href="<%= rel_prefix %>/index.html">Home</a>
|
||||
<a href="<%= rel_prefix %>/index.html#classes">Classes</a>
|
||||
<a href="<%= rel_prefix %>/index.html#methods">Methods</a>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="project-metadata">
|
||||
<% simple_files = @files.select { |f| f.parser == RDoc::Parser::Simple } %>
|
||||
<% unless simple_files.empty? then %>
|
||||
<div id="fileindex-section" class="section project-section">
|
||||
<h3 class="section-header">Files</h3>
|
||||
<ul>
|
||||
<% simple_files.each do |f| %>
|
||||
<li class="file"><a href="<%= rel_prefix %>/<%= f.path %>"><%= h f.base_name %></a></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div id="classindex-section" class="section project-section">
|
||||
<h3 class="section-header">Class Index
|
||||
<span class="search-toggle"><img src="<%= rel_prefix %>/images/find.png"
|
||||
height="16" width="16" alt="[+]"
|
||||
title="show/hide quicksearch" /></span></h3>
|
||||
<form action="#" method="get" accept-charset="utf-8" class="initially-hidden">
|
||||
<fieldset>
|
||||
<legend>Quicksearch</legend>
|
||||
<input type="text" name="quicksearch" value=""
|
||||
class="quicksearch-field" />
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<ul class="link-list">
|
||||
<% @modsort.each do |index_klass| %>
|
||||
<li><a href="<%= rel_prefix %>/<%= index_klass.path %>"><%= index_klass.full_name %></a></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<div id="no-class-search-results" style="display: none;">No matching classes.</div>
|
||||
</div>
|
||||
|
||||
<% if $DEBUG_RDOC %>
|
||||
<div id="debugging-toggle"><img src="<%= rel_prefix %>/images/bug.png"
|
||||
alt="toggle debugging" height="16" width="16" /></div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="documentation">
|
||||
<%= file.description %>
|
||||
</div>
|
||||
|
||||
<div id="validator-badges">
|
||||
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
|
||||
<p><small>Generated with the <a href="http://deveiate.org/projects/Darkfish-Rdoc/">Darkfish
|
||||
Rdoc Generator</a> <%= RDoc::Generator::Darkfish::VERSION %></small>.</p>
|
||||
</div>
|
||||
</body>
|
||||
<% else %>
|
||||
<body class="file file-popup">
|
||||
<div id="metadata">
|
||||
<dl>
|
||||
<dt class="modified-date">Last Modified</dt>
|
||||
<dd class="modified-date"><%= file.last_modified %></dd>
|
||||
|
||||
<% if file.requires %>
|
||||
<dt class="requires">Requires</dt>
|
||||
<dd class="requires">
|
||||
<ul>
|
||||
<% file.requires.each do |require| %>
|
||||
<li><%= require.name %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</dd>
|
||||
<% end %>
|
||||
|
||||
<% if @options.webcvs %>
|
||||
<dt class="scs-url">Trac URL</dt>
|
||||
<dd class="scs-url"><a target="_top"
|
||||
href="<%= file.cvs_url %>"><%= file.cvs_url %></a></dd>
|
||||
<% end %>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div id="documentation">
|
||||
<% if file.comment %>
|
||||
<div class="description">
|
||||
<h2>Description</h2>
|
||||
<%= file.description %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</body>
|
||||
<% end %>
|
||||
</html>
|
||||
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 733 B |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 372 B |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 715 B |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 1.8 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 97 B |
|
@ -1,64 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
|
||||
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
<body>
|
||||
<nav id="metadata">
|
||||
<%= render '_sidebar_navigation.rhtml' %>
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
||||
<head>
|
||||
<meta content="text/html; charset=<%= @options.charset %>" http-equiv="Content-Type" />
|
||||
<%= render '_sidebar_search.rhtml' %>
|
||||
|
||||
<title><%= h @options.title %></title>
|
||||
|
||||
<link type="text/css" media="screen" href="rdoc.css" rel="stylesheet" />
|
||||
|
||||
<script src="js/jquery.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="js/thickbox-compressed.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="js/quicksearch.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="js/darkfish.js" type="text/javascript" charset="utf-8"></script>
|
||||
|
||||
</head>
|
||||
<body class="indexpage">
|
||||
|
||||
<% $stderr.sync = true %>
|
||||
<h1><%= h @options.title %></h1>
|
||||
|
||||
<% if @options.main_page && main_page = @files.find { |f| f.full_name == @options.main_page } then %>
|
||||
<div id="main">
|
||||
<%= main_page.description.sub(%r{^\s*<h1.*?/h1>}i, '') %>
|
||||
<div id="project-metadata">
|
||||
<%= render '_sidebar_pages.rhtml' %>
|
||||
<%= render '_sidebar_classes.rhtml' %>
|
||||
</div>
|
||||
<% else %>
|
||||
<p>This is the API documentation for '<%= @options.title %>'.</p>
|
||||
<% end %>
|
||||
</nav>
|
||||
|
||||
<% simple_files = @files.select {|tl| tl.parser == RDoc::Parser::Simple } %>
|
||||
<% unless simple_files.empty? then %>
|
||||
<h2>Files</h2>
|
||||
<ul>
|
||||
<% simple_files.sort.each do |file| %>
|
||||
<li class="file"><a href="<%= file.path %>"><%= h file.base_name %></a></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
|
||||
<h2 id="classes">Classes/Modules</h2>
|
||||
<ul>
|
||||
<% @modsort.each do |klass| %>
|
||||
<li class="<%= klass.type %>"><a href="<%= klass.path %>"><%= klass.full_name %></a></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
|
||||
<h2 id="methods">Methods</h2>
|
||||
<ul>
|
||||
<% RDoc::TopLevel.all_classes_and_modules.map do |mod|
|
||||
mod.method_list
|
||||
end.flatten.sort.each do |method| %>
|
||||
<li><a href="<%= method.path %>"><%= method.pretty_name %> — <%= method.parent.full_name %></a></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
|
||||
<div id="validator-badges">
|
||||
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
|
||||
<p><small>Generated with the <a href="http://deveiate.org/projects/Darkfish-Rdoc/">Darkfish
|
||||
Rdoc Generator</a> <%= RDoc::Generator::Darkfish::VERSION %></small>.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<div id="documentation" class="description">
|
||||
<% if @options.main_page && main_page = @files.find { |f| f.full_name == @options.main_page } then %>
|
||||
<%= main_page.description %>
|
||||
<% else %>
|
||||
<p>This is the API documentation for <%= @title %>.
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
|
@ -9,12 +9,12 @@
|
|||
|
||||
/* Provide console simulation for firebug-less environments */
|
||||
if (!("console" in window) || !("firebug" in console)) {
|
||||
var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
|
||||
var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
|
||||
"group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
|
||||
|
||||
window.console = {};
|
||||
for (var i = 0; i < names.length; ++i)
|
||||
window.console[names[i]] = function() {};
|
||||
window.console = {};
|
||||
for (var i = 0; i < names.length; ++i)
|
||||
window.console[names[i]] = function() {};
|
||||
};
|
||||
|
||||
|
||||
|
@ -23,94 +23,131 @@ if (!("console" in window) || !("firebug" in console)) {
|
|||
*/
|
||||
$.fn.unwrap = function( expr ) {
|
||||
return this.each( function() {
|
||||
$(this).parents( expr ).eq( 0 ).after( this ).remove();
|
||||
$(this).parents( expr ).eq( 0 ).after( this ).remove();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
function showSource( e ) {
|
||||
var target = e.target;
|
||||
var codeSections = $(target).
|
||||
parents('.method-detail').
|
||||
find('.method-source-code');
|
||||
var target = e.target;
|
||||
var codeSections = $(target).
|
||||
parents('.method-detail').
|
||||
find('.method-source-code');
|
||||
|
||||
$(target).
|
||||
parents('.method-detail').
|
||||
find('.method-source-code').
|
||||
slideToggle();
|
||||
$(target).
|
||||
parents('.method-detail').
|
||||
find('.method-source-code').
|
||||
slideToggle();
|
||||
};
|
||||
|
||||
function hookSourceViews() {
|
||||
$('.method-description,.method-heading').click( showSource );
|
||||
$('.method-heading').click( showSource );
|
||||
};
|
||||
|
||||
function toggleDebuggingSection() {
|
||||
$('.debugging-section').slideToggle();
|
||||
$('.debugging-section').slideToggle();
|
||||
};
|
||||
|
||||
function hookDebuggingToggle() {
|
||||
$('#debugging-toggle img').click( toggleDebuggingSection );
|
||||
$('#debugging-toggle img').click( toggleDebuggingSection );
|
||||
};
|
||||
|
||||
function hookQuickSearch() {
|
||||
$('.quicksearch-field').each( function() {
|
||||
var searchElems = $(this).parents('.section').find( 'li' );
|
||||
var toggle = $(this).parents('.section').find('h3 .search-toggle');
|
||||
// console.debug( "Toggle is: %o", toggle );
|
||||
var qsbox = $(this).parents('form').get( 0 );
|
||||
function hookTableOfContentsToggle() {
|
||||
$('.indexpage li .toc-toggle').each( function() {
|
||||
$(this).click( function() {
|
||||
$(this).toggleClass('open');
|
||||
});
|
||||
|
||||
$(this).quicksearch( this, searchElems, {
|
||||
noSearchResultsIndicator: 'no-class-search-results',
|
||||
focusOnLoad: false
|
||||
});
|
||||
$(toggle).click( function() {
|
||||
// console.debug( "Toggling qsbox: %o", qsbox );
|
||||
$(qsbox).toggle();
|
||||
});
|
||||
});
|
||||
var section = $(this).next();
|
||||
|
||||
$(this).click( function() {
|
||||
section.slideToggle();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function hookSearch() {
|
||||
var input = $('#search-field').eq(0);
|
||||
var result = $('#search-results').eq(0);
|
||||
$(result).show();
|
||||
|
||||
var search_section = $('#search-section').get(0);
|
||||
$(search_section).show();
|
||||
|
||||
var search = new Search(search_data, input, result);
|
||||
|
||||
search.renderItem = function(result) {
|
||||
var li = document.createElement('li');
|
||||
var html = '';
|
||||
|
||||
// TODO add relative path to <script> per-page
|
||||
html += '<p class="search-match"><a href="' + rdoc_rel_prefix + result.path + '">' + this.hlt(result.title);
|
||||
if (result.params)
|
||||
html += '<span class="params">' + result.params + '</span>';
|
||||
html += '</a>';
|
||||
|
||||
|
||||
if (result.namespace)
|
||||
html += '<p class="search-namespace">' + this.hlt(result.namespace);
|
||||
|
||||
if (result.snippet)
|
||||
html += '<div class="search-snippet">' + result.snippet + '</div>';
|
||||
|
||||
li.innerHTML = html;
|
||||
|
||||
return li;
|
||||
}
|
||||
|
||||
search.select = function(result) {
|
||||
var result_element = result.get(0);
|
||||
window.location.href = result_element.firstChild.firstChild.href;
|
||||
}
|
||||
|
||||
search.scrollIntoView = search.scrollInWindow;
|
||||
};
|
||||
|
||||
function highlightTarget( anchor ) {
|
||||
console.debug( "Highlighting target '%s'.", anchor );
|
||||
console.debug( "Highlighting target '%s'.", anchor );
|
||||
|
||||
$("a[name=" + anchor + "]").each( function() {
|
||||
if ( !$(this).parent().parent().hasClass('target-section') ) {
|
||||
console.debug( "Wrapping the target-section" );
|
||||
$('div.method-detail').unwrap( 'div.target-section' );
|
||||
$(this).parent().wrap( '<div class="target-section"></div>' );
|
||||
} else {
|
||||
console.debug( "Already wrapped." );
|
||||
}
|
||||
});
|
||||
$("a[name=" + anchor + "]").each( function() {
|
||||
if ( !$(this).parent().parent().hasClass('target-section') ) {
|
||||
console.debug( "Wrapping the target-section" );
|
||||
$('div.method-detail').unwrap( 'div.target-section' );
|
||||
$(this).parent().wrap( '<div class="target-section"></div>' );
|
||||
} else {
|
||||
console.debug( "Already wrapped." );
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function highlightLocationTarget() {
|
||||
console.debug( "Location hash: %s", window.location.hash );
|
||||
if ( ! window.location.hash || window.location.hash.length == 0 ) return;
|
||||
console.debug( "Location hash: %s", window.location.hash );
|
||||
if ( ! window.location.hash || window.location.hash.length == 0 ) return;
|
||||
|
||||
var anchor = window.location.hash.substring(1);
|
||||
console.debug( "Found anchor: %s; matching %s", anchor, "a[name=" + anchor + "]" );
|
||||
var anchor = window.location.hash.substring(1);
|
||||
console.debug( "Found anchor: %s; matching %s", anchor, "a[name=" + anchor + "]" );
|
||||
|
||||
highlightTarget( anchor );
|
||||
highlightTarget( anchor );
|
||||
};
|
||||
|
||||
function highlightClickTarget( event ) {
|
||||
console.debug( "Highlighting click target for event %o", event.target );
|
||||
try {
|
||||
var anchor = $(event.target).attr( 'href' ).substring(1);
|
||||
console.debug( "Found target anchor: %s", anchor );
|
||||
highlightTarget( anchor );
|
||||
} catch ( err ) {
|
||||
console.error( "Exception while highlighting: %o", err );
|
||||
};
|
||||
console.debug( "Highlighting click target for event %o", event.target );
|
||||
try {
|
||||
var anchor = $(event.target).attr( 'href' ).substring(1);
|
||||
console.debug( "Found target anchor: %s", anchor );
|
||||
highlightTarget( anchor );
|
||||
} catch ( err ) {
|
||||
console.error( "Exception while highlighting: %o", err );
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
$(document).ready( function() {
|
||||
hookSourceViews();
|
||||
hookDebuggingToggle();
|
||||
hookQuickSearch();
|
||||
highlightLocationTarget();
|
||||
hookSourceViews();
|
||||
hookDebuggingToggle();
|
||||
hookSearch();
|
||||
highlightLocationTarget();
|
||||
hookTableOfContentsToggle();
|
||||
|
||||
$('ul.link-list a').bind( "click", highlightClickTarget );
|
||||
$('ul.link-list a').bind( "click", highlightClickTarget );
|
||||
});
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,114 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* JQuery QuickSearch - Hook up a form field to hide non-matching elements.
|
||||
* $Id: quicksearch.js 53 2009-01-07 02:52:03Z deveiant $
|
||||
*
|
||||
* Author: Michael Granger <mgranger@laika.com>
|
||||
*
|
||||
*/
|
||||
jQuery.fn.quicksearch = function( target, searchElems, options ) {
|
||||
// console.debug( "Quicksearch fn" );
|
||||
|
||||
var settings = {
|
||||
delay: 250,
|
||||
clearButton: false,
|
||||
highlightMatches: false,
|
||||
focusOnLoad: false,
|
||||
noSearchResultsIndicator: null
|
||||
};
|
||||
if ( options ) $.extend( settings, options );
|
||||
|
||||
return jQuery(this).each( function() {
|
||||
// console.debug( "Creating a new quicksearch on %o for %o", this, searchElems );
|
||||
new jQuery.quicksearch( this, searchElems, settings );
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
jQuery.quicksearch = function( searchBox, searchElems, settings ) {
|
||||
var timeout;
|
||||
var boxdiv = $(searchBox).parents('div').eq(0);
|
||||
|
||||
function init() {
|
||||
setupKeyEventHandlers();
|
||||
focusOnLoad();
|
||||
};
|
||||
|
||||
function setupKeyEventHandlers() {
|
||||
// console.debug( "Hooking up the 'keypress' event to %o", searchBox );
|
||||
$(searchBox).
|
||||
unbind( 'keyup' ).
|
||||
keyup( function(e) { return onSearchKey( e.keyCode ); });
|
||||
$(searchBox).
|
||||
unbind( 'keypress' ).
|
||||
keypress( function(e) {
|
||||
switch( e.which ) {
|
||||
// Execute the search on Enter, Tab, or Newline
|
||||
case 9:
|
||||
case 13:
|
||||
case 10:
|
||||
clearTimeout( timeout );
|
||||
e.preventDefault();
|
||||
doQuickSearch();
|
||||
break;
|
||||
|
||||
// Allow backspace
|
||||
case 8:
|
||||
return true;
|
||||
break;
|
||||
|
||||
// Only allow valid search characters
|
||||
default:
|
||||
return validQSChar( e.charCode );
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function focusOnLoad() {
|
||||
if ( !settings.focusOnLoad ) return false;
|
||||
$(searchBox).focus();
|
||||
};
|
||||
|
||||
function onSearchKey ( code ) {
|
||||
clearTimeout( timeout );
|
||||
// console.debug( "...scheduling search." );
|
||||
timeout = setTimeout( doQuickSearch, settings.delay );
|
||||
};
|
||||
|
||||
function validQSChar( code ) {
|
||||
var c = String.fromCharCode( code );
|
||||
return (
|
||||
(c == ':') ||
|
||||
(c >= 'a' && c <= 'z') ||
|
||||
(c >= 'A' && c <= 'Z')
|
||||
);
|
||||
};
|
||||
|
||||
function doQuickSearch() {
|
||||
var searchText = searchBox.value;
|
||||
var pat = new RegExp( searchText, "im" );
|
||||
var shownCount = 0;
|
||||
|
||||
if ( settings.noSearchResultsIndicator ) {
|
||||
$('#' + settings.noSearchResultsIndicator).hide();
|
||||
}
|
||||
|
||||
// All elements start out hidden
|
||||
$(searchElems).each( function(index) {
|
||||
var str = $(this).text();
|
||||
|
||||
if ( pat.test(str) ) {
|
||||
shownCount += 1;
|
||||
$(this).fadeIn();
|
||||
} else {
|
||||
$(this).hide();
|
||||
}
|
||||
});
|
||||
|
||||
if ( shownCount == 0 && settings.noSearchResultsIndicator ) {
|
||||
$('#' + settings.noSearchResultsIndicator).slideDown();
|
||||
}
|
||||
};
|
||||
|
||||
init();
|
||||
};
|
|
@ -0,0 +1,94 @@
|
|||
Search = function(data, input, result) {
|
||||
this.data = data;
|
||||
this.$input = $(input);
|
||||
this.$result = $(result);
|
||||
|
||||
this.$current = null;
|
||||
this.$view = this.$result.parent();
|
||||
this.searcher = new Searcher(data.index);
|
||||
this.init();
|
||||
}
|
||||
|
||||
Search.prototype = $.extend({}, Navigation, new function() {
|
||||
var suid = 1;
|
||||
|
||||
this.init = function() {
|
||||
var _this = this;
|
||||
var observer = function() {
|
||||
_this.search(_this.$input[0].value);
|
||||
};
|
||||
this.$input.keyup(observer);
|
||||
this.$input.click(observer); // mac's clear field
|
||||
|
||||
this.searcher.ready(function(results, isLast) {
|
||||
_this.addResults(results, isLast);
|
||||
})
|
||||
|
||||
this.initNavigation();
|
||||
this.setNavigationActive(false);
|
||||
}
|
||||
|
||||
this.search = function(value, selectFirstMatch) {
|
||||
value = jQuery.trim(value).toLowerCase();
|
||||
if (value) {
|
||||
this.setNavigationActive(true);
|
||||
} else {
|
||||
this.setNavigationActive(false);
|
||||
}
|
||||
|
||||
if (value == '') {
|
||||
this.lastQuery = value;
|
||||
this.$result.empty();
|
||||
this.setNavigationActive(false);
|
||||
} else if (value != this.lastQuery) {
|
||||
this.lastQuery = value;
|
||||
this.firstRun = true;
|
||||
this.searcher.find(value);
|
||||
}
|
||||
}
|
||||
|
||||
this.addResults = function(results, isLast) {
|
||||
var target = this.$result.get(0);
|
||||
if (this.firstRun && (results.length > 0 || isLast)) {
|
||||
this.$current = null;
|
||||
this.$result.empty();
|
||||
}
|
||||
|
||||
for (var i=0, l = results.length; i < l; i++) {
|
||||
target.appendChild(this.renderItem.call(this, results[i]));
|
||||
};
|
||||
|
||||
if (this.firstRun && results.length > 0) {
|
||||
this.firstRun = false;
|
||||
this.$current = $(target.firstChild);
|
||||
this.$current.addClass('current');
|
||||
}
|
||||
if (jQuery.browser.msie) this.$element[0].className += '';
|
||||
}
|
||||
|
||||
this.move = function(isDown) {
|
||||
if (!this.$current) return;
|
||||
var $next = this.$current[isDown ? 'next' : 'prev']();
|
||||
if ($next.length) {
|
||||
this.$current.removeClass('current');
|
||||
$next.addClass('current');
|
||||
this.scrollIntoView($next[0], this.$view[0]);
|
||||
this.$current = $next;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
this.hlt = function(html) {
|
||||
return this.escapeHTML(html).
|
||||
replace(/\u0001/g, '<em>').
|
||||
replace(/\u0002/g, '</em>');
|
||||
}
|
||||
|
||||
this.escapeHTML = function(html) {
|
||||
return html.replace(/[&<>]/g, function(c) {
|
||||
return '&#' + c.charCodeAt(0) + ';';
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -0,0 +1,18 @@
|
|||
<body class="file">
|
||||
<nav id="metadata">
|
||||
<%= render '_sidebar_navigation.rhtml' %>
|
||||
|
||||
<%= render '_sidebar_search.rhtml' %>
|
||||
|
||||
<%= render '_sidebar_table_of_contents.rhtml' %>
|
||||
|
||||
<div id="project-metadata">
|
||||
<%= render '_sidebar_pages.rhtml' %>
|
||||
<%= render '_sidebar_classes.rhtml' %>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div id="documentation" class="description">
|
||||
<%= file.description %>
|
||||
</div>
|
||||
|
|
@ -6,15 +6,14 @@
|
|||
*
|
||||
*/
|
||||
|
||||
/* vim: ft=css et sw=2 ts=2 sts=2 */
|
||||
/* Base Green is: #6C8C22 */
|
||||
|
||||
*{ padding: 0; margin: 0; }
|
||||
* { padding: 0; margin: 0; }
|
||||
|
||||
body {
|
||||
background: #efefef;
|
||||
font: 14px "Helvetica Neue", Helvetica, Tahoma, sans-serif;
|
||||
}
|
||||
body.class, body.module, body.file {
|
||||
margin-left: 40px;
|
||||
}
|
||||
body.file-popup {
|
||||
|
@ -44,6 +43,15 @@ pre {
|
|||
padding: 0.5em 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
background: #ddd;
|
||||
margin: 1em;
|
||||
padding: 0.25em;
|
||||
}
|
||||
|
||||
blockquote > :first-child {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
/* @group Generic Classes */
|
||||
|
||||
|
@ -51,16 +59,21 @@ pre {
|
|||
display: none;
|
||||
}
|
||||
|
||||
.quicksearch-field {
|
||||
#search-field {
|
||||
width: 98%;
|
||||
background: #ddd;
|
||||
border: 1px solid #aaa;
|
||||
background: #eee;
|
||||
border: none;
|
||||
height: 1.5em;
|
||||
-webkit-border-radius: 4px;
|
||||
}
|
||||
.quicksearch-field:focus {
|
||||
#search-field:focus {
|
||||
background: #f1edba;
|
||||
}
|
||||
#search-field:-moz-placeholder,
|
||||
#search-field::-webkit-input-placeholder {
|
||||
font-weight: bold;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.missing-docs {
|
||||
font-size: 120%;
|
||||
|
@ -86,28 +99,8 @@ pre {
|
|||
|
||||
/* @end */
|
||||
|
||||
|
||||
/* @group Index Page, Standalone file pages */
|
||||
body.indexpage {
|
||||
margin: 1em 3em;
|
||||
}
|
||||
body.indexpage p,
|
||||
body.indexpage div,
|
||||
body.file p {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.indexpage .rdoc-list p, .file .rdoc-list p {
|
||||
margin: 0em 0;
|
||||
}
|
||||
|
||||
.indexpage ol,
|
||||
.file #documentation ol {
|
||||
line-height: 160%;
|
||||
}
|
||||
|
||||
.indexpage ul,
|
||||
.file #documentation ul {
|
||||
.indexpage ul {
|
||||
line-height: 160%;
|
||||
list-style: none;
|
||||
}
|
||||
|
@ -116,25 +109,16 @@ body.file p {
|
|||
font-size: 16px;
|
||||
}
|
||||
|
||||
.indexpage li,
|
||||
.file #documentation li {
|
||||
.indexpage li {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.indexpage ol,
|
||||
.file #documentation ol {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.indexpage ol > li,
|
||||
.file #documentation ol > li {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.indexpage ul > li,
|
||||
.file #documentation ul > li {
|
||||
.indexpage ul > li {
|
||||
background: url(images/bullet_black.png) no-repeat left 4px;
|
||||
}
|
||||
.indexpage li.method {
|
||||
background: url(images/plugin.png) no-repeat left 4px;
|
||||
}
|
||||
.indexpage li.module {
|
||||
background: url(images/package.png) no-repeat left 4px;
|
||||
}
|
||||
|
@ -144,36 +128,37 @@ body.file p {
|
|||
.indexpage li.file {
|
||||
background: url(images/page_white_text.png) no-repeat left 4px;
|
||||
}
|
||||
.file li p,
|
||||
.indexpage li p {
|
||||
margin: 0 0;
|
||||
.indexpage li li {
|
||||
background: url(images/tag_blue.png) no-repeat left 4px;
|
||||
}
|
||||
.indexpage li .toc-toggle {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: url(images/add.png) no-repeat;
|
||||
}
|
||||
|
||||
.indexpage li .toc-toggle.open {
|
||||
background: url(images/delete.png) no-repeat;
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
/* @group Top-Level Structure */
|
||||
|
||||
.class #metadata,
|
||||
.file #metadata,
|
||||
.module #metadata {
|
||||
#metadata {
|
||||
float: left;
|
||||
width: 260px;
|
||||
}
|
||||
|
||||
.class #documentation,
|
||||
.file #documentation,
|
||||
.module #documentation {
|
||||
#documentation {
|
||||
margin: 2em 1em 5em 300px;
|
||||
min-width: 340px;
|
||||
}
|
||||
|
||||
.file #metadata {
|
||||
margin: 0.8em;
|
||||
}
|
||||
|
||||
#validator-badges {
|
||||
clear: both;
|
||||
margin: 1em 1em 2em;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
@ -184,7 +169,7 @@ body.file p {
|
|||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
border: 1px solid #aaa;
|
||||
margin: 0 8px 16px;
|
||||
margin: 0 8px 8px;
|
||||
font-size: 90%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
@ -210,11 +195,24 @@ body.file p {
|
|||
list-style: none;
|
||||
}
|
||||
|
||||
#file-metadata {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
#file-metadata ul {
|
||||
padding-left: 28px;
|
||||
list-style-image: url(images/page_green.png);
|
||||
}
|
||||
|
||||
#table-of-contents {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
#table-of-contents ul {
|
||||
padding-left: 28px;
|
||||
list-style-image: url(images/tag_blue.png);
|
||||
}
|
||||
|
||||
dl.svninfo {
|
||||
color: #666;
|
||||
margin: 0;
|
||||
|
@ -225,7 +223,9 @@ dl.svninfo dt {
|
|||
|
||||
ul.link-list li {
|
||||
white-space: nowrap;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
ul.link-list .type {
|
||||
font-size: 8px;
|
||||
text-transform: uppercase;
|
||||
|
@ -235,16 +235,21 @@ ul.link-list .type {
|
|||
-webkit-border-radius: 5px;
|
||||
}
|
||||
|
||||
.calls-super {
|
||||
background: url(images/arrow_up.png) no-repeat right center;
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
/* @group Class Metadata Section */
|
||||
#class-metadata {
|
||||
margin-top: 2em;
|
||||
}
|
||||
/* @end */
|
||||
|
||||
/* @group Project Metadata Section */
|
||||
#project-metadata {
|
||||
margin-top: 3em;
|
||||
}
|
||||
|
||||
.file #project-metadata {
|
||||
margin-top: 0em;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
#project-metadata .section {
|
||||
|
@ -254,33 +259,14 @@ ul.link-list .type {
|
|||
border-bottom: 1px solid #aaa;
|
||||
position: relative;
|
||||
}
|
||||
#project-metadata h3.section-header .search-toggle {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
|
||||
#project-metadata form {
|
||||
color: #777;
|
||||
background: #ccc;
|
||||
padding: 8px 8px 16px;
|
||||
border-bottom: 1px solid #bbb;
|
||||
}
|
||||
#project-metadata fieldset {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
#no-class-search-results {
|
||||
margin: 0 auto 1em;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
|
||||
/* @group Documentation Section */
|
||||
.description {
|
||||
font-size: 100%;
|
||||
|
@ -295,34 +281,44 @@ ul.link-list .type {
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
.description ol,
|
||||
.description ul {
|
||||
margin-left: 1.5em;
|
||||
}
|
||||
.description ol li,
|
||||
.description ul li {
|
||||
line-height: 1.4em;
|
||||
}
|
||||
|
||||
.description dl,
|
||||
#documentation dl {
|
||||
.note-list {
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.label-list {
|
||||
margin: 8px 1.5em;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
.description dl {
|
||||
.description .label-list {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.description dt,
|
||||
#documentation dt {
|
||||
.note-list dt {
|
||||
font-weight: bold;
|
||||
}
|
||||
.note-list dd {
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.label-list dt {
|
||||
padding: 2px 4px;
|
||||
font-weight: bold;
|
||||
background: #ddd;
|
||||
}
|
||||
.description dd,
|
||||
#documentation dd {
|
||||
.label-list dd {
|
||||
padding: 2px 12px;
|
||||
}
|
||||
.description dd + dt,
|
||||
#documentation dd + dt {
|
||||
.label-list dd + dt,
|
||||
.note-list dd + dt {
|
||||
margin-top: 0.7em;
|
||||
}
|
||||
|
||||
|
@ -331,8 +327,8 @@ ul.link-list .type {
|
|||
}
|
||||
|
||||
#documentation h2.section-header {
|
||||
margin-top: 2em;
|
||||
padding: 0.75em 0.5em;
|
||||
margin-top: 1em;
|
||||
padding: 0.25em 0.5em;
|
||||
background: #ccc;
|
||||
color: #333;
|
||||
font-size: 175%;
|
||||
|
@ -341,8 +337,25 @@ ul.link-list .type {
|
|||
-webkit-border-radius: 3px;
|
||||
}
|
||||
|
||||
.documentation-section-title {
|
||||
position: relative;
|
||||
}
|
||||
.documentation-section-title .section-click-top {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 12px;
|
||||
font-size: 10px;
|
||||
color: #9b9877;
|
||||
visibility: hidden;
|
||||
padding-right: 0.5px;
|
||||
}
|
||||
|
||||
.documentation-section-title:hover .section-click-top {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
#documentation h3.section-header {
|
||||
margin-top: 2em;
|
||||
margin-top: 1em;
|
||||
padding: 0.25em 0.5em;
|
||||
background-color: #dedede;
|
||||
color: #333;
|
||||
|
@ -398,6 +411,11 @@ ul.link-list .type {
|
|||
display: none;
|
||||
}
|
||||
|
||||
#documentation .method-description .method-calls-super {
|
||||
color: #333;
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
#documentation .method-detail {
|
||||
margin: 0.5em 0;
|
||||
padding: 0.5em 0;
|
||||
|
@ -429,7 +447,7 @@ ul.link-list .type {
|
|||
line-height: 20px;
|
||||
background: url(images/zoom.png) no-repeat right top;
|
||||
}
|
||||
#documentation .method-detail:hover .method-click-advice {
|
||||
#documentation .method-heading:hover .method-click-advice {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
|
@ -455,14 +473,14 @@ ul.link-list .type {
|
|||
cursor: default;
|
||||
}
|
||||
#documentation .method-description p {
|
||||
padding: 0;
|
||||
}
|
||||
#documentation .method-description p + p {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
#documentation .method-description ul {
|
||||
margin-left: 1.5em;
|
||||
}
|
||||
pre {
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
|
||||
#documentation .attribute-method-heading {
|
||||
background: url(images/tag_green.png) no-repeat left bottom;
|
||||
|
@ -481,27 +499,19 @@ ul.link-list .type {
|
|||
|
||||
/* @end */
|
||||
|
||||
|
||||
|
||||
/* @group Source Code */
|
||||
|
||||
div.method-source-code {
|
||||
background: #262626;
|
||||
color: #efefef;
|
||||
margin: 1em;
|
||||
padding: 0.5em;
|
||||
border: 1px dashed #999;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
div.method-source-code pre {
|
||||
background: inherit;
|
||||
padding: 0;
|
||||
color: white;
|
||||
pre {
|
||||
overflow: auto;
|
||||
background: #262626;
|
||||
color: white;
|
||||
border: 1px dashed #999;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
/* @group Ruby keyword styles */
|
||||
.description pre {
|
||||
margin: 0 0.4em;
|
||||
}
|
||||
|
||||
.ruby-constant { color: #7fffd4; background: transparent; }
|
||||
.ruby-keyword { color: #00ffff; background: transparent; }
|
||||
|
@ -509,255 +519,56 @@ div.method-source-code pre {
|
|||
.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-comment { color: #dc0000; font-weight: bold; background: transparent; }
|
||||
.ruby-regexp { color: #ffa07a; background: transparent; }
|
||||
.ruby-value { color: #7fffd4; background: transparent; }
|
||||
|
||||
/* @end */
|
||||
/* @end */
|
||||
|
||||
|
||||
/* @group File Popup Contents */
|
||||
|
||||
.file #metadata,
|
||||
.file-popup #metadata {
|
||||
/* @group search results */
|
||||
#search-results h1 {
|
||||
font-size: 1em;
|
||||
font-weight: normal;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
.file-popup dl {
|
||||
font-size: 80%;
|
||||
padding: 0.75em;
|
||||
background-color: #dedede;
|
||||
color: #333;
|
||||
border: 1px solid #bbb;
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
}
|
||||
.file dt {
|
||||
font-weight: bold;
|
||||
padding-left: 22px;
|
||||
line-height: 20px;
|
||||
background: url(images/page_white_width.png) no-repeat left top;
|
||||
}
|
||||
.file dt.modified-date {
|
||||
background: url(images/date.png) no-repeat left top;
|
||||
}
|
||||
.file dt.requires {
|
||||
background: url(images/plugin.png) no-repeat left top;
|
||||
}
|
||||
.file dt.scs-url {
|
||||
background: url(images/wrench.png) no-repeat left top;
|
||||
}
|
||||
|
||||
.file dl dd {
|
||||
margin: 0 0 1em 0;
|
||||
}
|
||||
.file #metadata dl dd ul {
|
||||
list-style: circle;
|
||||
margin-left: 20px;
|
||||
padding-top: 0;
|
||||
}
|
||||
.file #metadata dl dd ul li {
|
||||
}
|
||||
|
||||
|
||||
.file h2 {
|
||||
margin-top: 2em;
|
||||
padding: 0.75em 0.5em;
|
||||
background-color: #dedede;
|
||||
color: #333;
|
||||
font-size: 120%;
|
||||
border: 1px solid #bbb;
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
|
||||
|
||||
|
||||
/* @group ThickBox Styles */
|
||||
#TB_window {
|
||||
font: 12px Arial, Helvetica, sans-serif;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
#TB_secondLine {
|
||||
font: 10px Arial, Helvetica, sans-serif;
|
||||
color:#666666;
|
||||
}
|
||||
|
||||
#TB_window :link,
|
||||
#TB_window :visited { color: #666666; }
|
||||
#TB_window :link:hover,
|
||||
#TB_window :visited:hover { color: #000; }
|
||||
#TB_window :link:active,
|
||||
#TB_window :visited:active { color: #666666; }
|
||||
#TB_window :link:focus,
|
||||
#TB_window :visited:focus { color: #666666; }
|
||||
|
||||
#TB_overlay {
|
||||
position: fixed;
|
||||
z-index:100;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
height:100%;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.TB_overlayMacFFBGHack {background: url(images/macFFBgHack.png) repeat;}
|
||||
.TB_overlayBG {
|
||||
background-color:#000;
|
||||
filter:alpha(opacity=75);
|
||||
-moz-opacity: 0.75;
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
* html #TB_overlay { /* ie6 hack */
|
||||
position: absolute;
|
||||
height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
|
||||
}
|
||||
|
||||
#TB_window {
|
||||
position: fixed;
|
||||
background: #ffffff;
|
||||
z-index: 102;
|
||||
color:#000000;
|
||||
display:none;
|
||||
border: 4px solid #525252;
|
||||
text-align:left;
|
||||
top:50%;
|
||||
left:50%;
|
||||
}
|
||||
|
||||
* html #TB_window { /* ie6 hack */
|
||||
position: absolute;
|
||||
margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px');
|
||||
}
|
||||
|
||||
#TB_window img#TB_Image {
|
||||
display:block;
|
||||
margin: 15px 0 0 15px;
|
||||
border-right: 1px solid #ccc;
|
||||
border-bottom: 1px solid #ccc;
|
||||
border-top: 1px solid #666;
|
||||
border-left: 1px solid #666;
|
||||
}
|
||||
|
||||
#TB_caption{
|
||||
height:25px;
|
||||
padding:7px 30px 10px 25px;
|
||||
float:left;
|
||||
}
|
||||
|
||||
#TB_closeWindow{
|
||||
height:25px;
|
||||
padding:11px 25px 10px 0;
|
||||
float:right;
|
||||
}
|
||||
|
||||
#TB_closeAjaxWindow{
|
||||
padding:7px 10px 5px 0;
|
||||
margin-bottom:1px;
|
||||
text-align:right;
|
||||
float:right;
|
||||
}
|
||||
|
||||
#TB_ajaxWindowTitle{
|
||||
float:left;
|
||||
padding:7px 0 5px 10px;
|
||||
margin-bottom:1px;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
#TB_title{
|
||||
background-color: #6C8C22;
|
||||
color: #dedede;
|
||||
height:40px;
|
||||
}
|
||||
#TB_title :link,
|
||||
#TB_title :visited {
|
||||
color: white !important;
|
||||
border-bottom: 1px dotted #dedede;
|
||||
}
|
||||
|
||||
#TB_ajaxContent{
|
||||
clear:both;
|
||||
padding:2px 15px 15px 15px;
|
||||
overflow:auto;
|
||||
text-align:left;
|
||||
line-height:1.4em;
|
||||
}
|
||||
|
||||
#TB_ajaxContent.TB_modal{
|
||||
padding:15px;
|
||||
}
|
||||
|
||||
#TB_ajaxContent p{
|
||||
padding:5px 0px 5px 0px;
|
||||
}
|
||||
|
||||
#TB_load{
|
||||
position: fixed;
|
||||
display:none;
|
||||
height:13px;
|
||||
width:208px;
|
||||
z-index:103;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin: -6px 0 0 -104px; /* -height/2 0 0 -width/2 */
|
||||
}
|
||||
|
||||
* html #TB_load { /* ie6 hack */
|
||||
position: absolute;
|
||||
margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px');
|
||||
}
|
||||
|
||||
#TB_HideSelect{
|
||||
z-index:99;
|
||||
position:fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color:#fff;
|
||||
border:none;
|
||||
filter:alpha(opacity=0);
|
||||
-moz-opacity: 0;
|
||||
opacity: 0;
|
||||
height:100%;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
* html #TB_HideSelect { /* ie6 hack */
|
||||
position: absolute;
|
||||
height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
|
||||
}
|
||||
|
||||
#TB_iframeContent{
|
||||
clear:both;
|
||||
border:none;
|
||||
margin-bottom:-1px;
|
||||
margin-top:1px;
|
||||
_margin-bottom:1px;
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
/* @group Debugging Section */
|
||||
|
||||
#debugging-toggle {
|
||||
text-align: center;
|
||||
}
|
||||
#debugging-toggle img {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#rdoc-debugging-section-dump {
|
||||
display: none;
|
||||
margin: 0 2em 2em;
|
||||
#search-results .current {
|
||||
background: #ccc;
|
||||
border: 1px solid #999;
|
||||
border-bottom: 1px solid transparent;
|
||||
}
|
||||
|
||||
#search-results li {
|
||||
list-style: none;
|
||||
border-bottom: 1px solid #aaa;
|
||||
-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
#search-results li:last-child {
|
||||
border-bottom: none;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#search-results li p {
|
||||
padding: 0;
|
||||
margin: 0.5em;
|
||||
}
|
||||
|
||||
#search-results .search-namespace {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#search-results li em {
|
||||
background: yellow;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
#search-results pre {
|
||||
margin: 0.5em;
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
<body>
|
||||
<nav id="metadata">
|
||||
<%= render '_sidebar_navigation.rhtml' %>
|
||||
|
||||
<%= render '_sidebar_search.rhtml' %>
|
||||
|
||||
<div id="project-metadata">
|
||||
<%= render '_sidebar_pages.rhtml' %>
|
||||
<%= render '_sidebar_classes.rhtml' %>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div id="documentation" class="description">
|
||||
<h1>Not Found</h1>
|
||||
|
||||
<p>The page <kbd><%=h path %></kbd> was not found
|
||||
</div>
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<body>
|
||||
<nav id="metadata">
|
||||
<%= render '_sidebar_search.rhtml' %>
|
||||
|
||||
<%= render '_sidebar_installed.rhtml' %>
|
||||
</nav>
|
||||
|
||||
<div id="documentation" class="description">
|
||||
<h1>Local RDoc Documentation</h1>
|
||||
|
||||
<p>Here you can browse local documentation from the ruby standard library and
|
||||
your installed gems.
|
||||
|
||||
<% gems = installed.select { |_, _, _, type,| type == :gem } %>
|
||||
<% missing = gems.reject { |_, _, exists,| exists } %>
|
||||
<% unless missing.empty? then %>
|
||||
<h2>Missing Gem Documentation</h2>
|
||||
|
||||
<p>You are missing documentation for some of your installed gems.
|
||||
You can install missing documentation for gems by running
|
||||
<kbd>gem rdoc --all</kbd>. After installing the missing documentation you
|
||||
only need to reload this page. The newly created documentation will
|
||||
automatically appear.
|
||||
|
||||
<p>You can also install documentation for a specific gem by running one of
|
||||
the following commands.
|
||||
|
||||
<ul>
|
||||
<% names = missing.map { |name,| name.sub(/-([^-]*)$/, '') }.uniq %>
|
||||
<% names.each do |name| %>
|
||||
<li><kbd>gem rdoc <%=h name %></kbd>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
|
||||
</div>
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
<body class="indexpage">
|
||||
<h1><%= h @title %></h1>
|
||||
|
||||
<% simple_files = @files.select { |f| f.text? } %>
|
||||
<% unless simple_files.empty? then %>
|
||||
<h2>Pages</h2>
|
||||
<ul>
|
||||
<% simple_files.sort.each do |file| %>
|
||||
<li class="file">
|
||||
<a href="<%= file.path %>"><%= h file.page_name %></a>
|
||||
<%
|
||||
# HACK table_of_contents should not exist on Document
|
||||
table = file.parse(file.comment).table_of_contents
|
||||
unless table.empty? then %>
|
||||
<img class="toc-toggle" src="images/transparent.png" alt="" title="toggle headings">
|
||||
<ul class="initially-hidden">
|
||||
<% table.each do |heading| %>
|
||||
<li><a href="<%= file.path %>#<%= heading.aref %>"><%= heading.plain_html %></a>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
|
||||
<h2 id="classes">Classes/Modules</h2>
|
||||
<ul>
|
||||
<% @modsort.each do |klass| %>
|
||||
<li class="<%= klass.type %>">
|
||||
<a href="<%= klass.path %>"><%= klass.full_name %></a>
|
||||
<% table = []
|
||||
table.concat klass.parse(klass.comment).table_of_contents
|
||||
table.concat klass.section_contents
|
||||
|
||||
unless table.empty? then %>
|
||||
<img class="toc-toggle" src="images/transparent.png" alt="" title="toggle headings">
|
||||
<ul class="initially-hidden">
|
||||
<% table.each do |item| %>
|
||||
<li><a href="<%= klass.path %>#<%= item.aref %>"><%= item.plain_html %></a>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
|
||||
<h2 id="methods">Methods</h2>
|
||||
<ul>
|
||||
<% @store.all_classes_and_modules.map do |mod|
|
||||
mod.method_list
|
||||
end.flatten.sort.each do |method| %>
|
||||
<li class="method"><a href="<%= method.path %>"><%= method.pretty_name %> — <%= method.parent.full_name %></a>
|
||||
<% end %>
|
||||
</ul>
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Navigation allows movement using the arrow keys through the search results.
|
||||
*
|
||||
* When using this library you will need to set scrollIntoView to the
|
||||
* appropriate function for your layout. Use scrollInWindow if the container
|
||||
* is not scrollable and scrollInElement if the container is a separate
|
||||
* scrolling region.
|
||||
*/
|
||||
Navigation = new function() {
|
||||
this.initNavigation = function() {
|
||||
var _this = this;
|
||||
|
||||
$(document).keydown(function(e) {
|
||||
_this.onkeydown(e);
|
||||
}).keyup(function(e) {
|
||||
_this.onkeyup(e);
|
||||
});
|
||||
|
||||
this.navigationActive = true;
|
||||
}
|
||||
|
||||
this.setNavigationActive = function(state) {
|
||||
this.navigationActive = state;
|
||||
this.clearMoveTimeout();
|
||||
}
|
||||
|
||||
this.onkeyup = function(e) {
|
||||
if (!this.navigationActive) return;
|
||||
|
||||
switch(e.keyCode) {
|
||||
case 37: //Event.KEY_LEFT:
|
||||
case 38: //Event.KEY_UP:
|
||||
case 39: //Event.KEY_RIGHT:
|
||||
case 40: //Event.KEY_DOWN:
|
||||
this.clearMoveTimeout();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.onkeydown = function(e) {
|
||||
if (!this.navigationActive) return;
|
||||
switch(e.keyCode) {
|
||||
case 37: //Event.KEY_LEFT:
|
||||
if (this.moveLeft()) e.preventDefault();
|
||||
break;
|
||||
case 38: //Event.KEY_UP:
|
||||
if (e.keyCode == 38 || e.ctrlKey) {
|
||||
if (this.moveUp()) e.preventDefault();
|
||||
this.startMoveTimeout(false);
|
||||
}
|
||||
break;
|
||||
case 39: //Event.KEY_RIGHT:
|
||||
if (this.moveRight()) e.preventDefault();
|
||||
break;
|
||||
case 40: //Event.KEY_DOWN:
|
||||
if (e.keyCode == 40 || e.ctrlKey) {
|
||||
if (this.moveDown()) e.preventDefault();
|
||||
this.startMoveTimeout(true);
|
||||
}
|
||||
break;
|
||||
case 13: //Event.KEY_RETURN:
|
||||
if (this.$current)
|
||||
e.preventDefault();
|
||||
this.select(this.$current);
|
||||
break;
|
||||
}
|
||||
if (e.ctrlKey && e.shiftKey) this.select(this.$current);
|
||||
}
|
||||
|
||||
this.clearMoveTimeout = function() {
|
||||
clearTimeout(this.moveTimeout);
|
||||
this.moveTimeout = null;
|
||||
}
|
||||
|
||||
this.startMoveTimeout = function(isDown) {
|
||||
if (!$.browser.mozilla && !$.browser.opera) return;
|
||||
if (this.moveTimeout) this.clearMoveTimeout();
|
||||
var _this = this;
|
||||
|
||||
var go = function() {
|
||||
if (!_this.moveTimeout) return;
|
||||
_this[isDown ? 'moveDown' : 'moveUp']();
|
||||
_this.moveTimout = setTimeout(go, 100);
|
||||
}
|
||||
this.moveTimeout = setTimeout(go, 200);
|
||||
}
|
||||
|
||||
this.moveRight = function() {
|
||||
}
|
||||
|
||||
this.moveLeft = function() {
|
||||
}
|
||||
|
||||
this.move = function(isDown) {
|
||||
}
|
||||
|
||||
this.moveUp = function() {
|
||||
return this.move(false);
|
||||
}
|
||||
|
||||
this.moveDown = function() {
|
||||
return this.move(true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Scrolls to the given element in the scrollable element view.
|
||||
*/
|
||||
this.scrollInElement = function(element, view) {
|
||||
var offset, viewHeight, viewScroll, height;
|
||||
offset = element.offsetTop;
|
||||
height = element.offsetHeight;
|
||||
viewHeight = view.offsetHeight;
|
||||
viewScroll = view.scrollTop;
|
||||
|
||||
if (offset - viewScroll + height > viewHeight) {
|
||||
view.scrollTop = offset - viewHeight + height;
|
||||
}
|
||||
if (offset < viewScroll) {
|
||||
view.scrollTop = offset;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Scrolls to the given element in the window. The second argument is
|
||||
* ignored
|
||||
*/
|
||||
this.scrollInWindow = function(element, ignored) {
|
||||
var offset, viewHeight, viewScroll, height;
|
||||
offset = element.offsetTop;
|
||||
height = element.offsetHeight;
|
||||
viewHeight = window.innerHeight;
|
||||
viewScroll = window.scrollY;
|
||||
|
||||
if (offset - viewScroll + height > viewHeight) {
|
||||
window.scrollTo(window.scrollX, offset - viewHeight + height);
|
||||
}
|
||||
if (offset < viewScroll) {
|
||||
window.scrollTo(window.scrollX, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,228 @@
|
|||
Searcher = function(data) {
|
||||
this.data = data;
|
||||
this.handlers = [];
|
||||
}
|
||||
|
||||
Searcher.prototype = new function() {
|
||||
// search is performed in chunks of 1000 for non-blocking user input
|
||||
var CHUNK_SIZE = 1000;
|
||||
// do not try to find more than 100 results
|
||||
var MAX_RESULTS = 100;
|
||||
var huid = 1;
|
||||
var suid = 1;
|
||||
var runs = 0;
|
||||
|
||||
this.find = function(query) {
|
||||
var queries = splitQuery(query);
|
||||
var regexps = buildRegexps(queries);
|
||||
var highlighters = buildHilighters(queries);
|
||||
var state = { from: 0, pass: 0, limit: MAX_RESULTS, n: suid++};
|
||||
var _this = this;
|
||||
|
||||
this.currentSuid = state.n;
|
||||
|
||||
if (!query) return;
|
||||
|
||||
var run = function() {
|
||||
// stop current search thread if new search started
|
||||
if (state.n != _this.currentSuid) return;
|
||||
|
||||
var results =
|
||||
performSearch(_this.data, regexps, queries, highlighters, state);
|
||||
var hasMore = (state.limit > 0 && state.pass < 4);
|
||||
|
||||
triggerResults.call(_this, results, !hasMore);
|
||||
if (hasMore) {
|
||||
setTimeout(run, 2);
|
||||
}
|
||||
runs++;
|
||||
};
|
||||
runs = 0;
|
||||
|
||||
// start search thread
|
||||
run();
|
||||
}
|
||||
|
||||
/* ----- Events ------ */
|
||||
this.ready = function(fn) {
|
||||
fn.huid = huid;
|
||||
this.handlers.push(fn);
|
||||
}
|
||||
|
||||
/* ----- Utilities ------ */
|
||||
function splitQuery(query) {
|
||||
return jQuery.grep(query.split(/(\s+|::?|\(\)?)/), function(string) {
|
||||
return string.match(/\S/)
|
||||
});
|
||||
}
|
||||
|
||||
function buildRegexps(queries) {
|
||||
return jQuery.map(queries, function(query) {
|
||||
return new RegExp(query.replace(/(.)/g, '([$1])([^$1]*?)'), 'i')
|
||||
});
|
||||
}
|
||||
|
||||
function buildHilighters(queries) {
|
||||
return jQuery.map(queries, function(query) {
|
||||
return jQuery.map(query.split(''), function(l, i) {
|
||||
return '\u0001$' + (i*2+1) + '\u0002$' + (i*2+2);
|
||||
}).join('');
|
||||
});
|
||||
}
|
||||
|
||||
// function longMatchRegexp(index, longIndex, regexps) {
|
||||
// for (var i = regexps.length - 1; i >= 0; i--){
|
||||
// if (!index.match(regexps[i]) && !longIndex.match(regexps[i])) return false;
|
||||
// };
|
||||
// return true;
|
||||
// }
|
||||
|
||||
|
||||
/* ----- Mathchers ------ */
|
||||
|
||||
/*
|
||||
* This record matches if the index starts with queries[0] and the record
|
||||
* matches all of the regexps
|
||||
*/
|
||||
function matchPassBeginning(index, longIndex, queries, regexps) {
|
||||
if (index.indexOf(queries[0]) != 0) return false;
|
||||
for (var i=1, l = regexps.length; i < l; i++) {
|
||||
if (!index.match(regexps[i]) && !longIndex.match(regexps[i]))
|
||||
return false;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* This record matches if the longIndex starts with queries[0] and the
|
||||
* longIndex matches all of the regexps
|
||||
*/
|
||||
function matchPassLongIndex(index, longIndex, queries, regexps) {
|
||||
if (longIndex.indexOf(queries[0]) != 0) return false;
|
||||
for (var i=1, l = regexps.length; i < l; i++) {
|
||||
if (!longIndex.match(regexps[i]))
|
||||
return false;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* This record matches if the index contains queries[0] and the record
|
||||
* matches all of the regexps
|
||||
*/
|
||||
function matchPassContains(index, longIndex, queries, regexps) {
|
||||
if (index.indexOf(queries[0]) == -1) return false;
|
||||
for (var i=1, l = regexps.length; i < l; i++) {
|
||||
if (!index.match(regexps[i]) && !longIndex.match(regexps[i]))
|
||||
return false;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* This record matches if regexps[0] matches the index and the record
|
||||
* matches all of the regexps
|
||||
*/
|
||||
function matchPassRegexp(index, longIndex, queries, regexps) {
|
||||
if (!index.match(regexps[0])) return false;
|
||||
for (var i=1, l = regexps.length; i < l; i++) {
|
||||
if (!index.match(regexps[i]) && !longIndex.match(regexps[i]))
|
||||
return false;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* ----- Highlighters ------ */
|
||||
function highlightRegexp(info, queries, regexps, highlighters) {
|
||||
var result = createResult(info);
|
||||
for (var i=0, l = regexps.length; i < l; i++) {
|
||||
result.title = result.title.replace(regexps[i], highlighters[i]);
|
||||
result.namespace = result.namespace.replace(regexps[i], highlighters[i]);
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
function hltSubstring(string, pos, length) {
|
||||
return string.substring(0, pos) + '\u0001' + string.substring(pos, pos + length) + '\u0002' + string.substring(pos + length);
|
||||
}
|
||||
|
||||
function highlightQuery(info, queries, regexps, highlighters) {
|
||||
var result = createResult(info);
|
||||
var pos = 0;
|
||||
var lcTitle = result.title.toLowerCase();
|
||||
|
||||
pos = lcTitle.indexOf(queries[0]);
|
||||
if (pos != -1) {
|
||||
result.title = hltSubstring(result.title, pos, queries[0].length);
|
||||
}
|
||||
|
||||
result.namespace = result.namespace.replace(regexps[0], highlighters[0]);
|
||||
for (var i=1, l = regexps.length; i < l; i++) {
|
||||
result.title = result.title.replace(regexps[i], highlighters[i]);
|
||||
result.namespace = result.namespace.replace(regexps[i], highlighters[i]);
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
function createResult(info) {
|
||||
var result = {};
|
||||
result.title = info[0];
|
||||
result.namespace = info[1];
|
||||
result.path = info[2];
|
||||
result.params = info[3];
|
||||
result.snippet = info[4];
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ----- Searching ------ */
|
||||
function performSearch(data, regexps, queries, highlighters, state) {
|
||||
var searchIndex = data.searchIndex;
|
||||
var longSearchIndex = data.longSearchIndex;
|
||||
var info = data.info;
|
||||
var result = [];
|
||||
var i = state.from;
|
||||
var l = searchIndex.length;
|
||||
var togo = CHUNK_SIZE;
|
||||
var matchFunc, hltFunc;
|
||||
|
||||
while (state.pass < 4 && state.limit > 0 && togo > 0) {
|
||||
if (state.pass == 0) {
|
||||
matchFunc = matchPassBeginning;
|
||||
hltFunc = highlightQuery;
|
||||
} else if (state.pass == 1) {
|
||||
matchFunc = matchPassLongIndex;
|
||||
hltFunc = highlightQuery;
|
||||
} else if (state.pass == 2) {
|
||||
matchFunc = matchPassContains;
|
||||
hltFunc = highlightQuery;
|
||||
} else if (state.pass == 3) {
|
||||
matchFunc = matchPassRegexp;
|
||||
hltFunc = highlightRegexp;
|
||||
}
|
||||
|
||||
for (; togo > 0 && i < l && state.limit > 0; i++, togo--) {
|
||||
if (info[i].n == state.n) continue;
|
||||
if (matchFunc(searchIndex[i], longSearchIndex[i], queries, regexps)) {
|
||||
info[i].n = state.n;
|
||||
result.push(hltFunc(info[i], queries, regexps, highlighters));
|
||||
state.limit--;
|
||||
}
|
||||
};
|
||||
if (searchIndex.length <= i) {
|
||||
state.pass++;
|
||||
i = state.from = 0;
|
||||
} else {
|
||||
state.from = i;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function triggerResults(results, isLast) {
|
||||
jQuery.each(this.handlers, function(i, fn) {
|
||||
fn.call(this, results, isLast)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
require 'rdoc/any_method'
|
||||
|
||||
##
|
||||
# GhostMethod represents a method referenced only by a comment
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
require 'rdoc/code_object'
|
||||
|
||||
##
|
||||
# A Module include in a class with \#include
|
||||
|
||||
|
@ -17,7 +15,7 @@ class RDoc::Include < RDoc::CodeObject
|
|||
super()
|
||||
@name = name
|
||||
self.comment = comment
|
||||
@module = nil # cache for module if found
|
||||
@module = nil # cache for module if found
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -30,10 +28,11 @@ class RDoc::Include < RDoc::CodeObject
|
|||
end
|
||||
|
||||
def == other # :nodoc:
|
||||
self.class == other.class and
|
||||
self.name == other.name
|
||||
self.class === other and @name == other.name
|
||||
end
|
||||
|
||||
alias eql? ==
|
||||
|
||||
##
|
||||
# Full name based on #module
|
||||
|
||||
|
@ -42,6 +41,10 @@ class RDoc::Include < RDoc::CodeObject
|
|||
RDoc::ClassModule === m ? m.full_name : @name
|
||||
end
|
||||
|
||||
def hash # :nodoc:
|
||||
[@name, self.module].hash
|
||||
end
|
||||
|
||||
def inspect # :nodoc:
|
||||
"#<%s:0x%x %s.include %s>" % [
|
||||
self.class,
|
||||
|
@ -59,6 +62,13 @@ class RDoc::Include < RDoc::CodeObject
|
|||
# - if not found, look into the children of included modules,
|
||||
# in reverse inclusion order;
|
||||
# - if still not found, go up the hierarchy of names.
|
||||
#
|
||||
# This method has <code>O(n!)</code> behavior when the module calling
|
||||
# include is referencing nonexistent modules. Avoid calling #module until
|
||||
# after all the files are parsed. This behavior is due to ruby's constant
|
||||
# lookup behavior.
|
||||
#
|
||||
# As of the beginning of October, 2011, no gem includes nonexistent modules.
|
||||
|
||||
def module
|
||||
return @module if @module
|
||||
|
@ -66,7 +76,7 @@ class RDoc::Include < RDoc::CodeObject
|
|||
# search the current context
|
||||
return @name unless parent
|
||||
full_name = parent.child_name(@name)
|
||||
@module = RDoc::TopLevel.modules_hash[full_name]
|
||||
@module = @store.modules_hash[full_name]
|
||||
return @module if @module
|
||||
return @name if @name =~ /^::/
|
||||
|
||||
|
@ -76,22 +86,31 @@ class RDoc::Include < RDoc::CodeObject
|
|||
inc = i.module
|
||||
next if String === inc
|
||||
full_name = inc.child_name(@name)
|
||||
@module = RDoc::TopLevel.modules_hash[full_name]
|
||||
@module = @store.modules_hash[full_name]
|
||||
return @module if @module
|
||||
end
|
||||
|
||||
# go up the hierarchy of names
|
||||
p = parent.parent
|
||||
while p
|
||||
full_name = p.child_name(@name)
|
||||
@module = RDoc::TopLevel.modules_hash[full_name]
|
||||
up = parent.parent
|
||||
while up
|
||||
full_name = up.child_name(@name)
|
||||
@module = @store.modules_hash[full_name]
|
||||
return @module if @module
|
||||
p = p.parent
|
||||
up = up.parent
|
||||
end
|
||||
|
||||
@name
|
||||
end
|
||||
|
||||
##
|
||||
# Sets the store for this class or module and its contained code objects.
|
||||
|
||||
def store= store
|
||||
super
|
||||
|
||||
@file = @store.add_file @file.full_name if @file
|
||||
end
|
||||
|
||||
def to_s # :nodoc:
|
||||
"include #@name in: #{parent}"
|
||||
end
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,417 @@
|
|||
# coding: UTF-8
|
||||
# :markup: markdown
|
||||
|
||||
##
|
||||
#--
|
||||
# This set of literals is for ruby 1.9 regular expressions and gives full
|
||||
# unicode support.
|
||||
#
|
||||
# Unlike peg-markdown, this set of literals recognizes Unicode alphanumeric
|
||||
# characters, newlines and spaces.
|
||||
class RDoc::Markdown::Literals
|
||||
# :stopdoc:
|
||||
|
||||
# This is distinct from setup_parser so that a standalone parser
|
||||
# can redefine #initialize and still have access to the proper
|
||||
# parser setup code.
|
||||
def initialize(str, debug=false)
|
||||
setup_parser(str, debug)
|
||||
end
|
||||
|
||||
|
||||
|
||||
# Prepares for parsing +str+. If you define a custom initialize you must
|
||||
# call this method before #parse
|
||||
def setup_parser(str, debug=false)
|
||||
@string = str
|
||||
@pos = 0
|
||||
@memoizations = Hash.new { |h,k| h[k] = {} }
|
||||
@result = nil
|
||||
@failed_rule = nil
|
||||
@failing_rule_offset = -1
|
||||
|
||||
setup_foreign_grammar
|
||||
end
|
||||
|
||||
attr_reader :string
|
||||
attr_reader :failing_rule_offset
|
||||
attr_accessor :result, :pos
|
||||
|
||||
|
||||
def current_column(target=pos)
|
||||
if c = string.rindex("\n", target-1)
|
||||
return target - c - 1
|
||||
end
|
||||
|
||||
target + 1
|
||||
end
|
||||
|
||||
def current_line(target=pos)
|
||||
cur_offset = 0
|
||||
cur_line = 0
|
||||
|
||||
string.each_line do |line|
|
||||
cur_line += 1
|
||||
cur_offset += line.size
|
||||
return cur_line if cur_offset >= target
|
||||
end
|
||||
|
||||
-1
|
||||
end
|
||||
|
||||
def lines
|
||||
lines = []
|
||||
string.each_line { |l| lines << l }
|
||||
lines
|
||||
end
|
||||
|
||||
|
||||
|
||||
def get_text(start)
|
||||
@string[start..@pos-1]
|
||||
end
|
||||
|
||||
def show_pos
|
||||
width = 10
|
||||
if @pos < width
|
||||
"#{@pos} (\"#{@string[0,@pos]}\" @ \"#{@string[@pos,width]}\")"
|
||||
else
|
||||
"#{@pos} (\"... #{@string[@pos - width, width]}\" @ \"#{@string[@pos,width]}\")"
|
||||
end
|
||||
end
|
||||
|
||||
def failure_info
|
||||
l = current_line @failing_rule_offset
|
||||
c = current_column @failing_rule_offset
|
||||
|
||||
if @failed_rule.kind_of? Symbol
|
||||
info = self.class::Rules[@failed_rule]
|
||||
"line #{l}, column #{c}: failed rule '#{info.name}' = '#{info.rendered}'"
|
||||
else
|
||||
"line #{l}, column #{c}: failed rule '#{@failed_rule}'"
|
||||
end
|
||||
end
|
||||
|
||||
def failure_caret
|
||||
l = current_line @failing_rule_offset
|
||||
c = current_column @failing_rule_offset
|
||||
|
||||
line = lines[l-1]
|
||||
"#{line}\n#{' ' * (c - 1)}^"
|
||||
end
|
||||
|
||||
def failure_character
|
||||
l = current_line @failing_rule_offset
|
||||
c = current_column @failing_rule_offset
|
||||
lines[l-1][c-1, 1]
|
||||
end
|
||||
|
||||
def failure_oneline
|
||||
l = current_line @failing_rule_offset
|
||||
c = current_column @failing_rule_offset
|
||||
|
||||
char = lines[l-1][c-1, 1]
|
||||
|
||||
if @failed_rule.kind_of? Symbol
|
||||
info = self.class::Rules[@failed_rule]
|
||||
"@#{l}:#{c} failed rule '#{info.name}', got '#{char}'"
|
||||
else
|
||||
"@#{l}:#{c} failed rule '#{@failed_rule}', got '#{char}'"
|
||||
end
|
||||
end
|
||||
|
||||
class ParseError < RuntimeError
|
||||
end
|
||||
|
||||
def raise_error
|
||||
raise ParseError, failure_oneline
|
||||
end
|
||||
|
||||
def show_error(io=STDOUT)
|
||||
error_pos = @failing_rule_offset
|
||||
line_no = current_line(error_pos)
|
||||
col_no = current_column(error_pos)
|
||||
|
||||
io.puts "On line #{line_no}, column #{col_no}:"
|
||||
|
||||
if @failed_rule.kind_of? Symbol
|
||||
info = self.class::Rules[@failed_rule]
|
||||
io.puts "Failed to match '#{info.rendered}' (rule '#{info.name}')"
|
||||
else
|
||||
io.puts "Failed to match rule '#{@failed_rule}'"
|
||||
end
|
||||
|
||||
io.puts "Got: #{string[error_pos,1].inspect}"
|
||||
line = lines[line_no-1]
|
||||
io.puts "=> #{line}"
|
||||
io.print(" " * (col_no + 3))
|
||||
io.puts "^"
|
||||
end
|
||||
|
||||
def set_failed_rule(name)
|
||||
if @pos > @failing_rule_offset
|
||||
@failed_rule = name
|
||||
@failing_rule_offset = @pos
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :failed_rule
|
||||
|
||||
def match_string(str)
|
||||
len = str.size
|
||||
if @string[pos,len] == str
|
||||
@pos += len
|
||||
return str
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
def scan(reg)
|
||||
if m = reg.match(@string[@pos..-1])
|
||||
width = m.end(0)
|
||||
@pos += width
|
||||
return true
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
if "".respond_to? :getbyte
|
||||
def get_byte
|
||||
if @pos >= @string.size
|
||||
return nil
|
||||
end
|
||||
|
||||
s = @string.getbyte @pos
|
||||
@pos += 1
|
||||
s
|
||||
end
|
||||
else
|
||||
def get_byte
|
||||
if @pos >= @string.size
|
||||
return nil
|
||||
end
|
||||
|
||||
s = @string[@pos]
|
||||
@pos += 1
|
||||
s
|
||||
end
|
||||
end
|
||||
|
||||
def parse(rule=nil)
|
||||
# We invoke the rules indirectly via apply
|
||||
# instead of by just calling them as methods because
|
||||
# if the rules use left recursion, apply needs to
|
||||
# manage that.
|
||||
|
||||
if !rule
|
||||
apply(:_root)
|
||||
else
|
||||
method = rule.gsub("-","_hyphen_")
|
||||
apply :"_#{method}"
|
||||
end
|
||||
end
|
||||
|
||||
class MemoEntry
|
||||
def initialize(ans, pos)
|
||||
@ans = ans
|
||||
@pos = pos
|
||||
@result = nil
|
||||
@set = false
|
||||
@left_rec = false
|
||||
end
|
||||
|
||||
attr_reader :ans, :pos, :result, :set
|
||||
attr_accessor :left_rec
|
||||
|
||||
def move!(ans, pos, result)
|
||||
@ans = ans
|
||||
@pos = pos
|
||||
@result = result
|
||||
@set = true
|
||||
@left_rec = false
|
||||
end
|
||||
end
|
||||
|
||||
def external_invoke(other, rule, *args)
|
||||
old_pos = @pos
|
||||
old_string = @string
|
||||
|
||||
@pos = other.pos
|
||||
@string = other.string
|
||||
|
||||
begin
|
||||
if val = __send__(rule, *args)
|
||||
other.pos = @pos
|
||||
other.result = @result
|
||||
else
|
||||
other.set_failed_rule "#{self.class}##{rule}"
|
||||
end
|
||||
val
|
||||
ensure
|
||||
@pos = old_pos
|
||||
@string = old_string
|
||||
end
|
||||
end
|
||||
|
||||
def apply_with_args(rule, *args)
|
||||
memo_key = [rule, args]
|
||||
if m = @memoizations[memo_key][@pos]
|
||||
@pos = m.pos
|
||||
if !m.set
|
||||
m.left_rec = true
|
||||
return nil
|
||||
end
|
||||
|
||||
@result = m.result
|
||||
|
||||
return m.ans
|
||||
else
|
||||
m = MemoEntry.new(nil, @pos)
|
||||
@memoizations[memo_key][@pos] = m
|
||||
start_pos = @pos
|
||||
|
||||
ans = __send__ rule, *args
|
||||
|
||||
lr = m.left_rec
|
||||
|
||||
m.move! ans, @pos, @result
|
||||
|
||||
# Don't bother trying to grow the left recursion
|
||||
# if it's failing straight away (thus there is no seed)
|
||||
if ans and lr
|
||||
return grow_lr(rule, args, start_pos, m)
|
||||
else
|
||||
return ans
|
||||
end
|
||||
|
||||
return ans
|
||||
end
|
||||
end
|
||||
|
||||
def apply(rule)
|
||||
if m = @memoizations[rule][@pos]
|
||||
@pos = m.pos
|
||||
if !m.set
|
||||
m.left_rec = true
|
||||
return nil
|
||||
end
|
||||
|
||||
@result = m.result
|
||||
|
||||
return m.ans
|
||||
else
|
||||
m = MemoEntry.new(nil, @pos)
|
||||
@memoizations[rule][@pos] = m
|
||||
start_pos = @pos
|
||||
|
||||
ans = __send__ rule
|
||||
|
||||
lr = m.left_rec
|
||||
|
||||
m.move! ans, @pos, @result
|
||||
|
||||
# Don't bother trying to grow the left recursion
|
||||
# if it's failing straight away (thus there is no seed)
|
||||
if ans and lr
|
||||
return grow_lr(rule, nil, start_pos, m)
|
||||
else
|
||||
return ans
|
||||
end
|
||||
|
||||
return ans
|
||||
end
|
||||
end
|
||||
|
||||
def grow_lr(rule, args, start_pos, m)
|
||||
while true
|
||||
@pos = start_pos
|
||||
@result = m.result
|
||||
|
||||
if args
|
||||
ans = __send__ rule, *args
|
||||
else
|
||||
ans = __send__ rule
|
||||
end
|
||||
return nil unless ans
|
||||
|
||||
break if @pos <= m.pos
|
||||
|
||||
m.move! ans, @pos, @result
|
||||
end
|
||||
|
||||
@result = m.result
|
||||
@pos = m.pos
|
||||
return m.ans
|
||||
end
|
||||
|
||||
class RuleInfo
|
||||
def initialize(name, rendered)
|
||||
@name = name
|
||||
@rendered = rendered
|
||||
end
|
||||
|
||||
attr_reader :name, :rendered
|
||||
end
|
||||
|
||||
def self.rule_info(name, rendered)
|
||||
RuleInfo.new(name, rendered)
|
||||
end
|
||||
|
||||
|
||||
# :startdoc:
|
||||
# :stopdoc:
|
||||
def setup_foreign_grammar; end
|
||||
|
||||
# Alphanumeric = /\p{Word}/
|
||||
def _Alphanumeric
|
||||
_tmp = scan(/\A(?-mix:\p{Word})/)
|
||||
set_failed_rule :_Alphanumeric unless _tmp
|
||||
return _tmp
|
||||
end
|
||||
|
||||
# AlphanumericAscii = /[A-Za-z0-9]/
|
||||
def _AlphanumericAscii
|
||||
_tmp = scan(/\A(?-mix:[A-Za-z0-9])/)
|
||||
set_failed_rule :_AlphanumericAscii unless _tmp
|
||||
return _tmp
|
||||
end
|
||||
|
||||
# BOM = "uFEFF"
|
||||
def _BOM
|
||||
_tmp = match_string("uFEFF")
|
||||
set_failed_rule :_BOM unless _tmp
|
||||
return _tmp
|
||||
end
|
||||
|
||||
# Newline = /\n|\r\n?|\p{Zl}|\p{Zp}/
|
||||
def _Newline
|
||||
_tmp = scan(/\A(?-mix:\n|\r\n?|\p{Zl}|\p{Zp})/)
|
||||
set_failed_rule :_Newline unless _tmp
|
||||
return _tmp
|
||||
end
|
||||
|
||||
# NonAlphanumeric = /\p{^Word}/
|
||||
def _NonAlphanumeric
|
||||
_tmp = scan(/\A(?-mix:\p{^Word})/)
|
||||
set_failed_rule :_NonAlphanumeric unless _tmp
|
||||
return _tmp
|
||||
end
|
||||
|
||||
# Spacechar = /\t|\p{Zs}/
|
||||
def _Spacechar
|
||||
_tmp = scan(/\A(?-mix:\t|\p{Zs})/)
|
||||
set_failed_rule :_Spacechar unless _tmp
|
||||
return _tmp
|
||||
end
|
||||
|
||||
Rules = {}
|
||||
Rules[:_Alphanumeric] = rule_info("Alphanumeric", "/\\p{Word}/")
|
||||
Rules[:_AlphanumericAscii] = rule_info("AlphanumericAscii", "/[A-Za-z0-9]/")
|
||||
Rules[:_BOM] = rule_info("BOM", "\"uFEFF\"")
|
||||
Rules[:_Newline] = rule_info("Newline", "/\\n|\\r\\n?|\\p{Zl}|\\p{Zp}/")
|
||||
Rules[:_NonAlphanumeric] = rule_info("NonAlphanumeric", "/\\p{^Word}/")
|
||||
Rules[:_Spacechar] = rule_info("Spacechar", "/\\t|\\p{Zs}/")
|
||||
# :startdoc:
|
||||
end
|
|
@ -1,5 +1,3 @@
|
|||
require 'rdoc'
|
||||
|
||||
##
|
||||
# RDoc::Markup parses plain text documents and attempts to decompose them into
|
||||
# their constituent parts. Some of these parts are high-level: paragraphs,
|
||||
|
@ -8,11 +6,44 @@ require 'rdoc'
|
|||
# is similar in spirit to that used on WikiWiki webs, where folks create web
|
||||
# pages using a simple set of formatting rules.
|
||||
#
|
||||
# RDoc::Markup itself does no output formatting: this is left to a different
|
||||
# set of classes.
|
||||
# RDoc::Markup and other markup formats do no output formatting, this is
|
||||
# handled by the RDoc::Markup::Formatter subclasses.
|
||||
#
|
||||
# RDoc::Markup is extendable at runtime: you can add \new markup elements to
|
||||
# be recognised in the documents that RDoc::Markup parses.
|
||||
# = Supported Formats
|
||||
#
|
||||
# Besides the RDoc::Markup format, the following formats are built in to RDoc:
|
||||
#
|
||||
# markdown::
|
||||
# The markdown format as described by
|
||||
# http://daringfireball.net/projects/markdown/. See RDoc::Markdown for
|
||||
# details on the parser and supported extensions.
|
||||
# rd::
|
||||
# The rdtool format. See RDoc::RD for details on the parser and format.
|
||||
# tomdoc::
|
||||
# The TomDoc format as described by http://tomdoc.org/. See RDoc::TomDoc
|
||||
# for details on the parser and supported extensions.
|
||||
#
|
||||
# You can choose a markup format using the following methods:
|
||||
#
|
||||
# per project::
|
||||
# If you build your documentation with rake use RDoc::Task#markup.
|
||||
#
|
||||
# If you build your documentation by hand run:
|
||||
#
|
||||
# rdoc --markup your_favorite_format --write-options
|
||||
#
|
||||
# and commit <tt>.rdoc_options</tt> and ship it with your packaged gem.
|
||||
# per file::
|
||||
# At the top of the file use the <tt>:markup:</tt> directive to set the
|
||||
# default format for the rest of the file.
|
||||
# per comment::
|
||||
# Use the <tt>:markup:</tt> directive at the top of a comment you want
|
||||
# to write in a different format.
|
||||
#
|
||||
# = RDoc::Markup
|
||||
#
|
||||
# RDoc::Markup is extensible at runtime: you can add \new markup elements to
|
||||
# be recognized in the documents that RDoc::Markup parses.
|
||||
#
|
||||
# RDoc::Markup is intended to be the basis for a family of tools which share
|
||||
# the common requirement that simple, plain-text should be rendered in a
|
||||
|
@ -26,21 +57,20 @@ require 'rdoc'
|
|||
# the +convert+ method, so you can use the same RDoc::Markup converter to
|
||||
# convert multiple input strings.
|
||||
#
|
||||
# require 'rdoc/markup/to_html'
|
||||
# require 'rdoc'
|
||||
#
|
||||
# h = RDoc::Markup::ToHtml.new
|
||||
#
|
||||
# puts h.convert(input_string)
|
||||
#
|
||||
# You can extend the RDoc::Markup parser to recognise new markup
|
||||
# You can extend the RDoc::Markup parser to recognize new markup
|
||||
# sequences, and to add special processing for text that matches a
|
||||
# regular expression. Here we make WikiWords significant to the parser,
|
||||
# and also make the sequences {word} and \<no>text...</no> signify
|
||||
# strike-through text. We then subclass the HTML output class to deal
|
||||
# with these:
|
||||
#
|
||||
# require 'rdoc/markup'
|
||||
# require 'rdoc/markup/to_html'
|
||||
# require 'rdoc'
|
||||
#
|
||||
# class WikiHtml < RDoc::Markup::ToHtml
|
||||
# def handle_special_WIKIWORD(special)
|
||||
|
@ -96,7 +126,12 @@ require 'rdoc'
|
|||
# have been removed. In addition, the verbatim text has been shifted
|
||||
# left, so the amount of indentation of verbatim text is unimportant.
|
||||
#
|
||||
# === Headers and Rules
|
||||
# For HTML output RDoc makes a small effort to determine if a verbatim section
|
||||
# contains ruby source code. If so, the verbatim block will be marked up as
|
||||
# HTML. Triggers include "def", "class", "module", "require", the "hash
|
||||
# rocket"# (=>) or a block call with a parameter.
|
||||
#
|
||||
# === Headers
|
||||
#
|
||||
# A line starting with an equal sign (=) is treated as a
|
||||
# heading. Level one headings have one equals sign, level two headings
|
||||
|
@ -104,7 +139,36 @@ require 'rdoc'
|
|||
# (seven hyphens or more result in a level six heading).
|
||||
#
|
||||
# For example, the above header was obtained with:
|
||||
# == Headers and Rules
|
||||
#
|
||||
# === Headers
|
||||
#
|
||||
# In HTML output headers have an id matching their name. The above example's
|
||||
# HTML is:
|
||||
#
|
||||
# <h3 id="label-Headers">Headers</h3>
|
||||
#
|
||||
# If a heading is inside a method body the id will be prefixed with the
|
||||
# method's id. If the above header where in the documentation for a method
|
||||
# such as:
|
||||
#
|
||||
# ##
|
||||
# # This method does fun things
|
||||
# #
|
||||
# # = Example
|
||||
# #
|
||||
# # Example of fun things goes here ...
|
||||
#
|
||||
# def do_fun_things
|
||||
# end
|
||||
#
|
||||
# The header's id would be:
|
||||
#
|
||||
# <h1 id="method-i-do_fun_things-label-Example">Example</h3>
|
||||
#
|
||||
# The label can be linked-to using <tt>SomeClass@Headers</tt>. See
|
||||
# {Links}[RDoc::Markup@Links] for further details.
|
||||
#
|
||||
# === Rules
|
||||
#
|
||||
# A line starting with three or more hyphens (at the current indent)
|
||||
# generates a horizontal rule. The more hyphens, the thicker the rule
|
||||
|
@ -240,7 +304,6 @@ require 'rdoc'
|
|||
# verbatim text outside of the list (the list is therefore closed)
|
||||
# regular paragraph after the list
|
||||
#
|
||||
#
|
||||
# == Text Markup
|
||||
#
|
||||
# === Bold, Italic, Typewriter Text
|
||||
|
@ -272,15 +335,26 @@ require 'rdoc'
|
|||
# === Links
|
||||
#
|
||||
# Links to starting with +http:+, +https:+, +mailto:+, +ftp:+ or +www.+
|
||||
# are recognized. An HTTP url that references an external image file is
|
||||
# converted into an inline image element.
|
||||
# are recognized. An HTTP url that references an external image is converted
|
||||
# into an inline image element.
|
||||
#
|
||||
# Links starting with <tt>rdoc-ref:</tt> will link to the referenced class,
|
||||
# module, method, file, etc. If the referenced item is not documented the
|
||||
# text will be and no link will be generated.
|
||||
# Classes and methods will be automatically linked to their definition. For
|
||||
# example, <tt>RDoc::Markup</tt> will link to this documentation. By default
|
||||
# methods will only be automatically linked if they contain an <tt>_</tt> (all
|
||||
# methods can be automatically linked through the <tt>--hyperlink-all</tt>
|
||||
# command line option).
|
||||
#
|
||||
# Links starting with +link:+ refer to local files whose path is relative to
|
||||
# the <tt>--op</tt> directory.
|
||||
# Single-word methods can be linked by using the <tt>#</tt> character for
|
||||
# instance methods or <tt>::</tt> for class methods. For example,
|
||||
# <tt>#convert</tt> links to #convert. A class or method may be combined like
|
||||
# <tt>RDoc::Markup#convert</tt>.
|
||||
#
|
||||
# A heading inside the documentation can be linked by following the class
|
||||
# or method by an <tt>@</tt> then the heading name.
|
||||
# <tt>RDoc::Markup@Links</tt> will link to this section like this:
|
||||
# RDoc::Markup@Links. Spaces in headings with multiple words must be escaped
|
||||
# with <tt>+</tt> like <tt>RDoc::Markup@Escaping+Text+Markup</tt>.
|
||||
# Punctuation and other special characters must be escaped like CGI.escape.
|
||||
#
|
||||
# Links can also be of the form <tt>label[url]</tt>, in which case +label+ is
|
||||
# used in the displayed text, and +url+ is used as the target. If +label+
|
||||
|
@ -293,6 +367,11 @@ require 'rdoc'
|
|||
# no link will be generated and <tt>rdoc-ref:</tt> will be removed from the
|
||||
# resulting text.
|
||||
#
|
||||
# Links starting with <tt>rdoc-label:label_name</tt> will link to the
|
||||
# +label_name+. You can create a label for the current link (for
|
||||
# bidirectional links) by supplying a name for the current link like
|
||||
# <tt>rdoc-label:label-other:label-mine</tt>.
|
||||
#
|
||||
# Links starting with +link:+ refer to local files whose path is relative to
|
||||
# the <tt>--op</tt> directory. Use <tt>rdoc-ref:</tt> instead of
|
||||
# <tt>link:</tt> to link to files generated by RDoc as the link target may
|
||||
|
@ -492,27 +571,54 @@ require 'rdoc'
|
|||
# so you won't see the documentation unless you use the +-a+ command line
|
||||
# option.
|
||||
#
|
||||
# === Other directives
|
||||
# === Method arguments
|
||||
#
|
||||
# [+:include:+ _filename_]
|
||||
# Include the contents of the named file at this point. This directive
|
||||
# must appear alone on one line, possibly preceded by spaces. In this
|
||||
# position, it can be escaped with a \ in front of the first colon.
|
||||
# [+:arg:+ or +:args:+ _parameters_]
|
||||
# Overrides the default argument handling with exactly these parameters.
|
||||
#
|
||||
# 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.
|
||||
# ##
|
||||
# # :args: a, b
|
||||
#
|
||||
# [+: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).
|
||||
# def some_method(*a)
|
||||
# end
|
||||
#
|
||||
# [+:main:+ _name_]
|
||||
# Equivalent to the <tt>--main</tt> command line parameter.
|
||||
# [+:yield:+ or +:yields:+ _parameters_]
|
||||
# Overrides the default yield discovery with these parameters.
|
||||
#
|
||||
# [<tt>:category: section</tt>]
|
||||
# ##
|
||||
# # :yields: key, value
|
||||
#
|
||||
# def each_thing &block
|
||||
# @things.each(&block)
|
||||
# end
|
||||
#
|
||||
# [+:call-seq:+]
|
||||
# Lines up to the next blank line or lines with a common prefix in the
|
||||
# comment are treated as the method's calling sequence, overriding the
|
||||
# default parsing of method parameters and yield arguments.
|
||||
#
|
||||
# Multiple lines may be used.
|
||||
#
|
||||
# # :call-seq:
|
||||
# # ARGF.readlines(sep=$/) -> array
|
||||
# # ARGF.readlines(limit) -> array
|
||||
# # ARGF.readlines(sep, limit) -> array
|
||||
# #
|
||||
# # ARGF.to_a(sep=$/) -> array
|
||||
# # ARGF.to_a(limit) -> array
|
||||
# # ARGF.to_a(sep, limit) -> array
|
||||
# #
|
||||
# # The remaining lines are documentation ...
|
||||
#
|
||||
# === Sections
|
||||
#
|
||||
# Sections allow you to group methods in a class into sensible containers. If
|
||||
# you use the sections 'Public', 'Internal' and 'Deprecated' (the three
|
||||
# allowed method statuses from TomDoc) the sections will be displayed in that
|
||||
# order placing the most useful methods at the top. Otherwise, sections will
|
||||
# be displayed in alphabetical order.
|
||||
#
|
||||
# [+:category:+ _section_]
|
||||
# Adds this item to the named +section+ overriding the current section. Use
|
||||
# this to group methods by section in RDoc output while maintaining a
|
||||
# sensible ordering (like alphabetical).
|
||||
|
@ -541,7 +647,7 @@ require 'rdoc'
|
|||
# Use the :section: directive to provide introductory text for a section of
|
||||
# documentation.
|
||||
#
|
||||
# [<tt>:section: title</tt>]
|
||||
# [+:section:+ _title_]
|
||||
# Provides section introductory text in RDoc output. The title following
|
||||
# +:section:+ is used as the section name and the remainder of the comment
|
||||
# containing the section is used as introductory text. A section's comment
|
||||
|
@ -573,12 +679,60 @@ require 'rdoc'
|
|||
# # ...
|
||||
# end
|
||||
#
|
||||
# [+: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.
|
||||
# === Other directives
|
||||
#
|
||||
# [+:markup:+ _type_]
|
||||
# Overrides the default markup type for this comment with the specified
|
||||
# markup type. For ruby files, if the first comment contains this directive
|
||||
# it is applied automatically to all comments in the file.
|
||||
#
|
||||
# Unless you are converting between markup formats you should use a
|
||||
# <code>.rdoc_options</code> file to specify the default documentation
|
||||
# format for your entire project. See RDoc::Options@Saved+Options for
|
||||
# instructions.
|
||||
#
|
||||
# At the top of a file the +:markup:+ directive applies to the entire file:
|
||||
#
|
||||
# # coding: UTF-8
|
||||
# # :markup: TomDoc
|
||||
#
|
||||
# # TomDoc comment here ...
|
||||
#
|
||||
# class MyClass
|
||||
# # ...
|
||||
#
|
||||
# For just one comment:
|
||||
#
|
||||
# # ...
|
||||
# end
|
||||
#
|
||||
# # :markup: RDoc
|
||||
# #
|
||||
# # This is a comment in RDoc markup format ...
|
||||
#
|
||||
# def some_method
|
||||
# # ...
|
||||
#
|
||||
# See Markup@DEVELOPERS for instructions on adding a new markup format.
|
||||
#
|
||||
# [+:include:+ _filename_]
|
||||
# Include the contents of the named file at this point. This directive
|
||||
# must appear alone on one line, possibly preceded by spaces. In this
|
||||
# position, it can be escaped with a \ in front of the first colon.
|
||||
#
|
||||
# The file will be searched for in the directories listed by the +--include+
|
||||
# option, or in the current directory by default. The contents of the file
|
||||
# will be shifted to have the same indentation as the ':' at the start of
|
||||
# the +:include:+ directive.
|
||||
#
|
||||
# [+:title:+ _text_]
|
||||
# Sets the title for the document. Equivalent to the <tt>--title</tt>
|
||||
# command line parameter. (The command line parameter overrides any :title:
|
||||
# directive in the source).
|
||||
#
|
||||
# [+:main:+ _name_]
|
||||
# Equivalent to the <tt>--main</tt> command line parameter.
|
||||
#
|
||||
# Further directives can be found in RDoc::Parser::Ruby and RDoc::Parser::C.
|
||||
#--
|
||||
# Original Author:: Dave Thomas, dave@pragmaticprogrammer.com
|
||||
# License:: Ruby license
|
||||
|
@ -590,6 +744,34 @@ class RDoc::Markup
|
|||
|
||||
attr_reader :attribute_manager
|
||||
|
||||
##
|
||||
# Parses +str+ into an RDoc::Markup::Document.
|
||||
|
||||
def self.parse str
|
||||
RDoc::Markup::Parser.parse str
|
||||
rescue RDoc::Markup::Parser::Error => e
|
||||
$stderr.puts <<-EOF
|
||||
While parsing markup, RDoc encountered a #{e.class}:
|
||||
|
||||
#{e}
|
||||
\tfrom #{e.backtrace.join "\n\tfrom "}
|
||||
|
||||
---8<---
|
||||
#{text}
|
||||
---8<---
|
||||
|
||||
RDoc #{RDoc::VERSION}
|
||||
|
||||
Ruby #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL} #{RUBY_RELEASE_DATE}
|
||||
|
||||
Please file a bug report with the above information at:
|
||||
|
||||
https://github.com/rdoc/rdoc/issues
|
||||
|
||||
EOF
|
||||
raise
|
||||
end
|
||||
|
||||
##
|
||||
# Take a block of text and use various heuristics to determine its
|
||||
# structure (paragraphs, lists, and so on). Invoke an event handler as we
|
||||
|
@ -644,9 +826,47 @@ class RDoc::Markup
|
|||
document.accept formatter
|
||||
end
|
||||
|
||||
autoload :Parser, 'rdoc/markup/parser'
|
||||
autoload :PreProcess, 'rdoc/markup/pre_process'
|
||||
|
||||
# Inline markup classes
|
||||
autoload :AttrChanger, 'rdoc/markup/attr_changer'
|
||||
autoload :AttrSpan, 'rdoc/markup/attr_span'
|
||||
autoload :Attributes, 'rdoc/markup/attributes'
|
||||
autoload :AttributeManager, 'rdoc/markup/attribute_manager'
|
||||
autoload :Special, 'rdoc/markup/special'
|
||||
|
||||
# RDoc::Markup AST
|
||||
autoload :BlankLine, 'rdoc/markup/blank_line'
|
||||
autoload :BlockQuote, 'rdoc/markup/block_quote'
|
||||
autoload :Document, 'rdoc/markup/document'
|
||||
autoload :HardBreak, 'rdoc/markup/hard_break'
|
||||
autoload :Heading, 'rdoc/markup/heading'
|
||||
autoload :Include, 'rdoc/markup/include'
|
||||
autoload :IndentedParagraph, 'rdoc/markup/indented_paragraph'
|
||||
autoload :List, 'rdoc/markup/list'
|
||||
autoload :ListItem, 'rdoc/markup/list_item'
|
||||
autoload :Paragraph, 'rdoc/markup/paragraph'
|
||||
autoload :Raw, 'rdoc/markup/raw'
|
||||
autoload :Rule, 'rdoc/markup/rule'
|
||||
autoload :Verbatim, 'rdoc/markup/verbatim'
|
||||
|
||||
# Formatters
|
||||
autoload :Formatter, 'rdoc/markup/formatter'
|
||||
autoload :FormatterTestCase, 'rdoc/markup/formatter_test_case'
|
||||
autoload :TextFormatterTestCase, 'rdoc/markup/text_formatter_test_case'
|
||||
|
||||
autoload :ToAnsi, 'rdoc/markup/to_ansi'
|
||||
autoload :ToBs, 'rdoc/markup/to_bs'
|
||||
autoload :ToHtml, 'rdoc/markup/to_html'
|
||||
autoload :ToHtmlCrossref, 'rdoc/markup/to_html_crossref'
|
||||
autoload :ToHtmlSnippet, 'rdoc/markup/to_html_snippet'
|
||||
autoload :ToLabel, 'rdoc/markup/to_label'
|
||||
autoload :ToMarkdown, 'rdoc/markup/to_markdown'
|
||||
autoload :ToRdoc, 'rdoc/markup/to_rdoc'
|
||||
autoload :ToTableOfContents, 'rdoc/markup/to_table_of_contents'
|
||||
autoload :ToTest, 'rdoc/markup/to_test'
|
||||
autoload :ToTtOnly, 'rdoc/markup/to_tt_only'
|
||||
|
||||
end
|
||||
|
||||
require 'rdoc/markup/parser'
|
||||
require 'rdoc/markup/attribute_manager'
|
||||
require 'rdoc/markup/inline'
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
class RDoc::Markup
|
||||
|
||||
AttrChanger = Struct.new :turn_on, :turn_off # :nodoc:
|
||||
|
||||
end
|
||||
|
||||
##
|
||||
# An AttrChanger records a change in attributes. It contains a bitmap of the
|
||||
# attributes to turn on, and a bitmap of those to turn off.
|
||||
|
||||
class RDoc::Markup::AttrChanger
|
||||
|
||||
def to_s # :nodoc:
|
||||
"Attr: +#{turn_on}/-#{turn_off}"
|
||||
end
|
||||
|
||||
def inspect # :nodoc:
|
||||
'+%d/-%d' % [turn_on, turn_off]
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
##
|
||||
# An array of attributes which parallels the characters in a string.
|
||||
|
||||
class RDoc::Markup::AttrSpan
|
||||
|
||||
##
|
||||
# Creates a new AttrSpan for +length+ characters
|
||||
|
||||
def initialize(length)
|
||||
@attrs = Array.new(length, 0)
|
||||
end
|
||||
|
||||
##
|
||||
# Toggles +bits+ from +start+ to +length+
|
||||
def set_attrs(start, length, bits)
|
||||
for i in start ... (start+length)
|
||||
@attrs[i] |= bits
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Accesses flags for character +n+
|
||||
|
||||
def [](n)
|
||||
@attrs[n]
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -22,6 +22,11 @@ class RDoc::Markup::AttributeManager
|
|||
|
||||
PROTECT_ATTR = A_PROTECT.chr # :nodoc:
|
||||
|
||||
##
|
||||
# The attributes enabled for this markup object.
|
||||
|
||||
attr_reader :attributes
|
||||
|
||||
##
|
||||
# This maps delimiters that occur around words (such as *bold* or +tt+)
|
||||
# where the start and end delimiters and the same. This lets us optimize
|
||||
|
@ -60,8 +65,9 @@ class RDoc::Markup::AttributeManager
|
|||
@html_tags = {}
|
||||
@matching_word_pairs = {}
|
||||
@protectable = %w[<]
|
||||
@special = {}
|
||||
@special = []
|
||||
@word_pair_map = {}
|
||||
@attributes = RDoc::Markup::Attributes.new
|
||||
|
||||
add_word_pair "*", "*", :BOLD
|
||||
add_word_pair "_", "_", :EM
|
||||
|
@ -96,11 +102,11 @@ class RDoc::Markup::AttributeManager
|
|||
def changed_attribute_by_name current_set, new_set
|
||||
current = new = 0
|
||||
current_set.each do |name|
|
||||
current |= RDoc::Markup::Attribute.bitmap_for(name)
|
||||
current |= @attributes.bitmap_for(name)
|
||||
end
|
||||
|
||||
new_set.each do |name|
|
||||
new |= RDoc::Markup::Attribute.bitmap_for(name)
|
||||
new |= @attributes.bitmap_for(name)
|
||||
end
|
||||
|
||||
change_attribute(current, new)
|
||||
|
@ -161,12 +167,15 @@ class RDoc::Markup::AttributeManager
|
|||
##
|
||||
# Converts special sequences to RDoc attributes
|
||||
|
||||
def convert_specials(str, attrs)
|
||||
def convert_specials str, attrs
|
||||
unless @special.empty?
|
||||
@special.each do |regexp, attr|
|
||||
@special.each do |regexp, attribute|
|
||||
str.scan(regexp) do
|
||||
attrs.set_attrs($`.length, $&.length,
|
||||
attr | RDoc::Markup::Attribute::SPECIAL)
|
||||
capture = $~.size == 1 ? 0 : 1
|
||||
|
||||
s, e = $~.offset capture
|
||||
|
||||
attrs.set_attrs s, e - s, attribute | @attributes.special
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -200,7 +209,7 @@ class RDoc::Markup::AttributeManager
|
|||
raise ArgumentError, "Word flags may not start with '<'" if
|
||||
start[0,1] == '<'
|
||||
|
||||
bitmap = RDoc::Markup::Attribute.bitmap_for name
|
||||
bitmap = @attributes.bitmap_for name
|
||||
|
||||
if start == stop then
|
||||
@matching_word_pairs[start] = bitmap
|
||||
|
@ -220,7 +229,7 @@ class RDoc::Markup::AttributeManager
|
|||
# am.add_html 'em', :EM
|
||||
|
||||
def add_html(tag, name)
|
||||
@html_tags[tag.downcase] = RDoc::Markup::Attribute.bitmap_for name
|
||||
@html_tags[tag.downcase] = @attributes.bitmap_for name
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -229,14 +238,14 @@ class RDoc::Markup::AttributeManager
|
|||
#
|
||||
# @am.add_special(/((https?:)\S+\w)/, :HYPERLINK)
|
||||
|
||||
def add_special(pattern, name)
|
||||
@special[pattern] = RDoc::Markup::Attribute.bitmap_for name
|
||||
def add_special pattern, name
|
||||
@special << [pattern, @attributes.bitmap_for(name)]
|
||||
end
|
||||
|
||||
##
|
||||
# Processes +str+ converting attributes, HTML and specials
|
||||
|
||||
def flow(str)
|
||||
def flow str
|
||||
@str = str
|
||||
|
||||
mask_protected_sequences
|
||||
|
@ -303,9 +312,9 @@ class RDoc::Markup::AttributeManager
|
|||
res << change_attribute(current_attr, new_attr)
|
||||
current_attr = new_attr
|
||||
|
||||
if (current_attr & RDoc::Markup::Attribute::SPECIAL) != 0 then
|
||||
if (current_attr & @attributes.special) != 0 then
|
||||
i += 1 while
|
||||
i < str_len and (@attrs[i] & RDoc::Markup::Attribute::SPECIAL) != 0
|
||||
i < str_len and (@attrs[i] & @attributes.special) != 0
|
||||
|
||||
res << RDoc::Markup::Special.new(current_attr,
|
||||
copy_string(start_pos, i))
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
##
|
||||
# We manage a set of attributes. Each attribute has a symbol name and a bit
|
||||
# value.
|
||||
|
||||
class RDoc::Markup::Attributes
|
||||
|
||||
##
|
||||
# The special attribute type. See RDoc::Markup#add_special
|
||||
|
||||
attr_reader :special
|
||||
|
||||
##
|
||||
# Creates a new attributes set.
|
||||
|
||||
def initialize
|
||||
@special = 1
|
||||
|
||||
@name_to_bitmap = [
|
||||
[:_SPECIAL_, @special],
|
||||
]
|
||||
|
||||
@next_bitmap = @special << 1
|
||||
end
|
||||
|
||||
##
|
||||
# Returns a unique bit for +name+
|
||||
|
||||
def bitmap_for name
|
||||
bitmap = @name_to_bitmap.assoc name
|
||||
|
||||
unless bitmap then
|
||||
bitmap = @next_bitmap
|
||||
@next_bitmap <<= 1
|
||||
@name_to_bitmap << [name, bitmap]
|
||||
else
|
||||
bitmap = bitmap.last
|
||||
end
|
||||
|
||||
bitmap
|
||||
end
|
||||
|
||||
##
|
||||
# Returns a string representation of +bitmap+
|
||||
|
||||
def as_string bitmap
|
||||
return 'none' if bitmap.zero?
|
||||
res = []
|
||||
|
||||
@name_to_bitmap.each do |name, bit|
|
||||
res << name if (bitmap & bit) != 0
|
||||
end
|
||||
|
||||
res.join ','
|
||||
end
|
||||
|
||||
##
|
||||
# yields each attribute name in +bitmap+
|
||||
|
||||
def each_name_of bitmap
|
||||
return enum_for __method__, bitmap unless block_given?
|
||||
|
||||
@name_to_bitmap.each do |name, bit|
|
||||
next if bit == @special
|
||||
|
||||
yield name.to_s if (bitmap & bit) != 0
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
##
|
||||
# A quoted section which contains markup items.
|
||||
|
||||
class RDoc::Markup::BlockQuote < RDoc::Markup::Raw
|
||||
|
||||
##
|
||||
# Calls #accept_block_quote on +visitor+
|
||||
|
||||
def accept visitor
|
||||
visitor.accept_block_quote self
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -3,11 +3,13 @@
|
|||
|
||||
class RDoc::Markup::Document
|
||||
|
||||
include Enumerable
|
||||
|
||||
##
|
||||
# The file this document was created from. See also
|
||||
# RDoc::ClassModule#add_comment
|
||||
|
||||
attr_accessor :file
|
||||
attr_reader :file
|
||||
|
||||
##
|
||||
# The parts of the Document
|
||||
|
@ -19,7 +21,7 @@ class RDoc::Markup::Document
|
|||
|
||||
def initialize *parts
|
||||
@parts = []
|
||||
@parts.push(*parts)
|
||||
@parts.concat parts
|
||||
|
||||
@file = nil
|
||||
end
|
||||
|
@ -31,7 +33,7 @@ class RDoc::Markup::Document
|
|||
case part
|
||||
when RDoc::Markup::Document then
|
||||
unless part.empty? then
|
||||
parts.push(*part.parts)
|
||||
parts.concat part.parts
|
||||
parts << RDoc::Markup::BlankLine.new
|
||||
end
|
||||
when String then
|
||||
|
@ -67,6 +69,20 @@ class RDoc::Markup::Document
|
|||
visitor.end_accepting
|
||||
end
|
||||
|
||||
##
|
||||
# Concatenates the given +parts+ onto the document
|
||||
|
||||
def concat parts
|
||||
self.parts.concat parts
|
||||
end
|
||||
|
||||
##
|
||||
# Enumerator for the parts of this document
|
||||
|
||||
def each &block
|
||||
@parts.each(&block)
|
||||
end
|
||||
|
||||
##
|
||||
# Does this document have no parts?
|
||||
|
||||
|
@ -74,6 +90,18 @@ class RDoc::Markup::Document
|
|||
@parts.empty? or (@parts.length == 1 and merged? and @parts.first.empty?)
|
||||
end
|
||||
|
||||
##
|
||||
# The file this Document was created from.
|
||||
|
||||
def file= location
|
||||
@file = case location
|
||||
when RDoc::TopLevel then
|
||||
location.absolute_name
|
||||
else
|
||||
location
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# When this is a collection of documents (#file is not set and this document
|
||||
# contains only other documents as its direct children) #merge replaces
|
||||
|
@ -120,7 +148,16 @@ class RDoc::Markup::Document
|
|||
# Appends +parts+ to the document
|
||||
|
||||
def push *parts
|
||||
self.parts.push(*parts)
|
||||
self.parts.concat parts
|
||||
end
|
||||
|
||||
##
|
||||
# Returns an Array of headings in the document.
|
||||
#
|
||||
# Require 'rdoc/markup/formatter' before calling this method.
|
||||
|
||||
def table_of_contents
|
||||
accept RDoc::Markup::ToTableOfContents.to_toc
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
require 'rdoc/markup'
|
||||
|
||||
##
|
||||
# Base class for RDoc markup formatters
|
||||
#
|
||||
# Formatters use a visitor pattern to convert content into output.
|
||||
# Formatters are a visitor that converts an RDoc::Markup tree (from a comment)
|
||||
# into some kind of output. RDoc ships with formatters for converting back to
|
||||
# rdoc, ANSI text, HTML, a Table of Contents and other formats.
|
||||
#
|
||||
# If you'd like to write your own Formatter use
|
||||
# RDoc::Markup::FormatterTestCase. If you're writing a text-output formatter
|
||||
|
@ -20,14 +20,21 @@ class RDoc::Markup::Formatter
|
|||
##
|
||||
# Creates a new Formatter
|
||||
|
||||
def initialize markup = nil
|
||||
def initialize options, markup = nil
|
||||
@options = options
|
||||
|
||||
@markup = markup || RDoc::Markup.new
|
||||
@am = @markup.attribute_manager
|
||||
@am.add_special(/<br>/, :HARD_BREAK)
|
||||
|
||||
@attributes = @am.attributes
|
||||
|
||||
@attr_tags = []
|
||||
|
||||
@in_tt = 0
|
||||
@tt_bit = RDoc::Markup::Attribute.bitmap_for :TT
|
||||
@tt_bit = @attributes.bitmap_for :TT
|
||||
|
||||
@hard_break = ''
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -44,7 +51,7 @@ class RDoc::Markup::Formatter
|
|||
# tags for flexibility
|
||||
|
||||
def add_tag(name, start, stop)
|
||||
attr = RDoc::Markup::Attribute.bitmap_for name
|
||||
attr = @attributes.bitmap_for name
|
||||
@attr_tags << InlineTag.new(attr, start, stop)
|
||||
end
|
||||
|
||||
|
@ -58,7 +65,7 @@ class RDoc::Markup::Formatter
|
|||
##
|
||||
# Marks up +content+
|
||||
|
||||
def convert(content)
|
||||
def convert content
|
||||
@markup.convert content, self
|
||||
end
|
||||
|
||||
|
@ -93,7 +100,7 @@ class RDoc::Markup::Formatter
|
|||
|
||||
handled = false
|
||||
|
||||
RDoc::Markup::Attribute.each_name_of special.type do |name|
|
||||
@attributes.each_name_of special.type do |name|
|
||||
method_name = "handle_special_#{name}"
|
||||
|
||||
if respond_to? method_name then
|
||||
|
@ -102,7 +109,11 @@ class RDoc::Markup::Formatter
|
|||
end
|
||||
end
|
||||
|
||||
raise "Unhandled special: #{special}" unless handled
|
||||
unless handled then
|
||||
special_name = @attributes.as_string special.type
|
||||
|
||||
raise RDoc::Error, "Unhandled special #{special_name}: #{special}"
|
||||
end
|
||||
|
||||
special.text
|
||||
end
|
||||
|
@ -114,6 +125,17 @@ class RDoc::Markup::Formatter
|
|||
string
|
||||
end
|
||||
|
||||
##
|
||||
# Use ignore in your subclass to ignore the content of a node.
|
||||
#
|
||||
# ##
|
||||
# # We don't support raw nodes in ToNoRaw
|
||||
#
|
||||
# alias accept_raw ignore
|
||||
|
||||
def ignore *node
|
||||
end
|
||||
|
||||
##
|
||||
# Are we currently inside tt tags?
|
||||
|
||||
|
@ -160,10 +182,3 @@ class RDoc::Markup::Formatter
|
|||
|
||||
end
|
||||
|
||||
class RDoc::Markup
|
||||
autoload :ToAnsi, 'rdoc/markup/to_ansi'
|
||||
autoload :ToBs, 'rdoc/markup/to_bs'
|
||||
autoload :ToHtml, 'rdoc/markup/to_html'
|
||||
autoload :ToHtmlCrossref, 'rdoc/markup/to_html_crossref'
|
||||
autoload :ToRdoc, 'rdoc/markup/to_rdoc'
|
||||
end
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
require 'minitest/unit'
|
||||
require 'rdoc/markup/formatter'
|
||||
|
||||
##
|
||||
# Test case for creating new RDoc::Markup formatters. See
|
||||
|
@ -35,7 +34,7 @@ require 'rdoc/markup/formatter'
|
|||
#
|
||||
# end
|
||||
|
||||
class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
|
||||
class RDoc::Markup::FormatterTestCase < RDoc::TestCase
|
||||
|
||||
##
|
||||
# Call #setup when inheriting from this test case.
|
||||
|
@ -54,8 +53,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
|
|||
def setup
|
||||
super
|
||||
|
||||
@m = RDoc::Markup.new
|
||||
@RM = RDoc::Markup
|
||||
@options = RDoc::Options.new
|
||||
|
||||
@m = @RM.new
|
||||
|
||||
@bullet_list = @RM::List.new(:BULLET,
|
||||
@RM::ListItem.new(nil, @RM::Paragraph.new('l1')),
|
||||
|
@ -86,7 +86,7 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
|
|||
# Call to add the visitor tests to your test case
|
||||
|
||||
def self.add_visitor_tests
|
||||
self.class_eval do
|
||||
class_eval do
|
||||
|
||||
##
|
||||
# Calls start_accepting which needs to verify startup state
|
||||
|
@ -119,6 +119,16 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
|
|||
accept_blank_line
|
||||
end
|
||||
|
||||
##
|
||||
# Calls accept_block_quote
|
||||
|
||||
def test_accept_block_quote
|
||||
@to.start_accepting
|
||||
|
||||
@to.accept_block_quote block para 'quote'
|
||||
|
||||
accept_block_quote
|
||||
end
|
||||
##
|
||||
# Test case that calls <tt>@to.accept_document</tt>
|
||||
|
||||
|
@ -233,6 +243,29 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
|
|||
accept_paragraph_b
|
||||
end
|
||||
|
||||
##
|
||||
# Calls accept_paragraph_br with a RDoc::Markup::Paragraph containing
|
||||
# a \<br>
|
||||
|
||||
def test_accept_paragraph_br
|
||||
@to.start_accepting
|
||||
|
||||
@to.accept_paragraph para 'one<br>two'
|
||||
|
||||
accept_paragraph_br
|
||||
end
|
||||
|
||||
##
|
||||
# Calls accept_paragraph with a Paragraph containing a hard break
|
||||
|
||||
def test_accept_paragraph_break
|
||||
@to.start_accepting
|
||||
|
||||
@to.accept_paragraph para('hello', hard_break, 'world')
|
||||
|
||||
accept_paragraph_break
|
||||
end
|
||||
|
||||
##
|
||||
# Calls accept_paragraph_i with a RDoc::Markup::Paragraph containing
|
||||
# emphasized words
|
||||
|
@ -374,9 +407,9 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
|
|||
# Calls accept_list_item_start_note_2
|
||||
|
||||
def test_accept_list_item_start_note_2
|
||||
list = @RM::List.new(:NOTE,
|
||||
@RM::ListItem.new('<tt>teletype</tt>',
|
||||
@RM::Paragraph.new('teletype description')))
|
||||
list = list(:NOTE,
|
||||
item('<tt>teletype</tt>',
|
||||
para('teletype description')))
|
||||
|
||||
@to.start_accepting
|
||||
|
||||
|
@ -387,6 +420,41 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
|
|||
accept_list_item_start_note_2
|
||||
end
|
||||
|
||||
##
|
||||
# Calls accept_list_item_start_note_multi_description
|
||||
|
||||
def test_accept_list_item_start_note_multi_description
|
||||
list = list(:NOTE,
|
||||
item(%w[label],
|
||||
para('description one')),
|
||||
item(nil, para('description two')))
|
||||
|
||||
@to.start_accepting
|
||||
|
||||
list.accept @to
|
||||
|
||||
@to.end_accepting
|
||||
|
||||
accept_list_item_start_note_multi_description
|
||||
end
|
||||
|
||||
##
|
||||
# Calls accept_list_item_start_note_multi_label
|
||||
|
||||
def test_accept_list_item_start_note_multi_label
|
||||
list = list(:NOTE,
|
||||
item(%w[one two],
|
||||
para('two headers')))
|
||||
|
||||
@to.start_accepting
|
||||
|
||||
list.accept @to
|
||||
|
||||
@to.end_accepting
|
||||
|
||||
accept_list_item_start_note_multi_label
|
||||
end
|
||||
|
||||
##
|
||||
# Calls accept_list_item_start_number
|
||||
|
||||
|
@ -635,7 +703,7 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
|
|||
end
|
||||
|
||||
##
|
||||
# Calls accept_list_end_ulpha
|
||||
# Calls accept_list_end_ualpha
|
||||
|
||||
def test_accept_list_end_ualpha
|
||||
@to.start_accepting
|
||||
|
@ -670,28 +738,28 @@ class RDoc::Markup::FormatterTestCase < MiniTest::Unit::TestCase
|
|||
# Calls list_verbatim with a list containing a verbatim block
|
||||
|
||||
def test_list_verbatim # HACK overblown
|
||||
doc = @RM::Document.new(
|
||||
@RM::List.new(:BULLET,
|
||||
@RM::ListItem.new(nil,
|
||||
@RM::Paragraph.new('list', 'stuff'),
|
||||
@RM::BlankLine.new,
|
||||
@RM::Verbatim.new("* list\n",
|
||||
" with\n",
|
||||
"\n",
|
||||
" second\n",
|
||||
"\n",
|
||||
" 1. indented\n",
|
||||
" 2. numbered\n",
|
||||
"\n",
|
||||
" third\n",
|
||||
"\n",
|
||||
"* second\n"))))
|
||||
doc =
|
||||
doc(
|
||||
list(:BULLET,
|
||||
item(nil,
|
||||
para('list stuff'),
|
||||
blank_line,
|
||||
verb("* list\n",
|
||||
" with\n",
|
||||
"\n",
|
||||
" second\n",
|
||||
"\n",
|
||||
" 1. indented\n",
|
||||
" 2. numbered\n",
|
||||
"\n",
|
||||
" third\n",
|
||||
"\n",
|
||||
"* second\n"))))
|
||||
|
||||
doc.accept @to
|
||||
|
||||
list_verbatim
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
##
|
||||
# A hard-break in the middle of a paragraph.
|
||||
|
||||
class RDoc::Markup::HardBreak
|
||||
|
||||
@instance = new
|
||||
|
||||
##
|
||||
# RDoc::Markup::HardBreak is a singleton
|
||||
|
||||
def self.new
|
||||
@instance
|
||||
end
|
||||
|
||||
##
|
||||
# Calls #accept_hard_break on +visitor+
|
||||
|
||||
def accept visitor
|
||||
visitor.accept_hard_break self
|
||||
end
|
||||
|
||||
def == other # :nodoc:
|
||||
self.class === other
|
||||
end
|
||||
|
||||
def pretty_print q # :nodoc:
|
||||
q.text "[break]"
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -3,6 +3,35 @@
|
|||
|
||||
class RDoc::Markup::Heading < Struct.new :level, :text
|
||||
|
||||
@to_html = nil
|
||||
@to_label = nil
|
||||
|
||||
##
|
||||
# A singleton RDoc::Markup::ToLabel formatter for headings.
|
||||
|
||||
def self.to_label
|
||||
@to_label ||= RDoc::Markup::ToLabel.new
|
||||
end
|
||||
|
||||
##
|
||||
# A singleton plain HTML formatter for headings. Used for creating labels
|
||||
# for the Table of Contents
|
||||
|
||||
def self.to_html
|
||||
return @to_html if @to_html
|
||||
|
||||
markup = RDoc::Markup.new
|
||||
markup.add_special RDoc::CrossReference::CROSSREF_REGEXP, :CROSSREF
|
||||
|
||||
@to_html = RDoc::Markup::ToHtml.new nil
|
||||
|
||||
def @to_html.handle_special_CROSSREF special
|
||||
special.text.sub(/^\\/, '')
|
||||
end
|
||||
|
||||
@to_html
|
||||
end
|
||||
|
||||
##
|
||||
# Calls #accept_heading on +visitor+
|
||||
|
||||
|
@ -10,6 +39,21 @@ class RDoc::Markup::Heading < Struct.new :level, :text
|
|||
visitor.accept_heading self
|
||||
end
|
||||
|
||||
##
|
||||
# An HTML-safe anchor reference for this header.
|
||||
|
||||
def aref
|
||||
"label-#{self.class.to_label.convert text.dup}"
|
||||
end
|
||||
|
||||
##
|
||||
# HTML markup of the text of this label without the surrounding header
|
||||
# element.
|
||||
|
||||
def plain_html
|
||||
self.class.to_html.to_html(text.dup)
|
||||
end
|
||||
|
||||
def pretty_print q # :nodoc:
|
||||
q.group 2, "[head: #{level} ", ']' do
|
||||
q.pp text
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
##
|
||||
# A file included at generation time. Objects of this class are created by
|
||||
# RDoc::RD for an extension-less include.
|
||||
#
|
||||
# This implementation in incomplete.
|
||||
|
||||
class RDoc::Markup::Include
|
||||
|
||||
##
|
||||
# The filename to be included, without extension
|
||||
|
||||
attr_reader :file
|
||||
|
||||
##
|
||||
# Directories to search for #file
|
||||
|
||||
attr_reader :include_path
|
||||
|
||||
##
|
||||
# Creates a new include that will import +file+ from +include_path+
|
||||
|
||||
def initialize file, include_path
|
||||
@file = file
|
||||
@include_path = include_path
|
||||
end
|
||||
|
||||
def == other # :nodoc:
|
||||
self.class === other and
|
||||
@file == other.file and @include_path == other.include_path
|
||||
end
|
||||
|
||||
def pretty_print q # :nodoc:
|
||||
q.group 2, '[incl ', ']' do
|
||||
q.text file
|
||||
q.breakable
|
||||
q.text 'from '
|
||||
q.pp include_path
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -29,5 +29,19 @@ class RDoc::Markup::IndentedParagraph < RDoc::Markup::Raw
|
|||
visitor.accept_indented_paragraph self
|
||||
end
|
||||
|
||||
##
|
||||
# Joins the raw paragraph text and converts inline HardBreaks to the
|
||||
# +hard_break+ text followed by the indent.
|
||||
|
||||
def text hard_break = nil
|
||||
@parts.map do |part|
|
||||
if RDoc::Markup::HardBreak === part then
|
||||
'%1$s%3$*2$s' % [hard_break, @indent, ' '] if hard_break
|
||||
else
|
||||
part
|
||||
end
|
||||
end.join
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -1,144 +1 @@
|
|||
require 'rdoc'
|
||||
class RDoc::Markup
|
||||
|
||||
##
|
||||
# We manage a set of attributes. Each attribute has a symbol name and a bit
|
||||
# value.
|
||||
|
||||
class Attribute
|
||||
|
||||
##
|
||||
# Special attribute type. See RDoc::Markup#add_special
|
||||
|
||||
SPECIAL = 1
|
||||
|
||||
@@name_to_bitmap = { :_SPECIAL_ => SPECIAL }
|
||||
@@next_bitmap = 2
|
||||
|
||||
##
|
||||
# Returns a unique bit for +name+
|
||||
|
||||
def self.bitmap_for(name)
|
||||
bitmap = @@name_to_bitmap[name]
|
||||
unless bitmap then
|
||||
bitmap = @@next_bitmap
|
||||
@@next_bitmap <<= 1
|
||||
@@name_to_bitmap[name] = bitmap
|
||||
end
|
||||
bitmap
|
||||
end
|
||||
|
||||
##
|
||||
# Returns a string representation of +bitmap+
|
||||
|
||||
def self.as_string(bitmap)
|
||||
return "none" if bitmap.zero?
|
||||
res = []
|
||||
@@name_to_bitmap.each do |name, bit|
|
||||
res << name if (bitmap & bit) != 0
|
||||
end
|
||||
res.join(",")
|
||||
end
|
||||
|
||||
##
|
||||
# yields each attribute name in +bitmap+
|
||||
|
||||
def self.each_name_of(bitmap)
|
||||
@@name_to_bitmap.each do |name, bit|
|
||||
next if bit == SPECIAL
|
||||
yield name.to_s if (bitmap & bit) != 0
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
AttrChanger = Struct.new :turn_on, :turn_off # :nodoc:
|
||||
|
||||
##
|
||||
# An AttrChanger records a change in attributes. It contains a bitmap of the
|
||||
# attributes to turn on, and a bitmap of those to turn off.
|
||||
|
||||
class AttrChanger
|
||||
def to_s # :nodoc:
|
||||
"Attr: +#{Attribute.as_string turn_on}/-#{Attribute.as_string turn_off}"
|
||||
end
|
||||
|
||||
def inspect # :nodoc:
|
||||
"+%s/-%s" % [
|
||||
Attribute.as_string(turn_on),
|
||||
Attribute.as_string(turn_off),
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# An array of attributes which parallels the characters in a string.
|
||||
|
||||
class AttrSpan
|
||||
|
||||
##
|
||||
# Creates a new AttrSpan for +length+ characters
|
||||
|
||||
def initialize(length)
|
||||
@attrs = Array.new(length, 0)
|
||||
end
|
||||
|
||||
##
|
||||
# Toggles +bits+ from +start+ to +length+
|
||||
def set_attrs(start, length, bits)
|
||||
for i in start ... (start+length)
|
||||
@attrs[i] |= bits
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Accesses flags for character +n+
|
||||
|
||||
def [](n)
|
||||
@attrs[n]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
##
|
||||
# Hold details of a special sequence
|
||||
|
||||
class Special
|
||||
|
||||
##
|
||||
# Special type
|
||||
|
||||
attr_reader :type
|
||||
|
||||
##
|
||||
# Special text
|
||||
|
||||
attr_accessor :text
|
||||
|
||||
##
|
||||
# Creates a new special sequence of +type+ with +text+
|
||||
|
||||
def initialize(type, text)
|
||||
@type, @text = type, text
|
||||
end
|
||||
|
||||
##
|
||||
# Specials are equal when the have the same text and type
|
||||
|
||||
def ==(o)
|
||||
self.text == o.text && self.type == o.type
|
||||
end
|
||||
|
||||
def inspect # :nodoc:
|
||||
"#<RDoc::Markup::Special:0x%x @type=%p, name=%p @text=%p>" % [
|
||||
object_id, @type, RDoc::Markup::Attribute.as_string(type), text.dump]
|
||||
end
|
||||
|
||||
def to_s # :nodoc:
|
||||
"Special: type=#{type}, name=#{RDoc::Markup::Attribute.as_string type}, text=#{text.dump}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
warn "requiring rdoc/markup/inline is deprecated and will be removed in RDoc 4." if $-w
|
||||
|
|
|
@ -1,5 +1,24 @@
|
|||
##
|
||||
# A List of ListItems
|
||||
# A List is a homogeneous set of ListItems.
|
||||
#
|
||||
# The supported list types include:
|
||||
#
|
||||
# :BULLET::
|
||||
# An unordered list
|
||||
# :LABEL::
|
||||
# An unordered definition list, but using an alternate RDoc::Markup syntax
|
||||
# :LALPHA::
|
||||
# An ordered list using increasing lowercase English letters
|
||||
# :NOTE::
|
||||
# An unordered definition list
|
||||
# :NUMBER::
|
||||
# An ordered list using increasing Arabic numerals
|
||||
# :UALPHA::
|
||||
# An ordered list using increasing uppercase English letters
|
||||
#
|
||||
# Definition lists behave like HTML definition lists. Each list item can
|
||||
# describe multiple terms. See RDoc::Markup::ListItem for how labels and
|
||||
# definition are stored as list items.
|
||||
|
||||
class RDoc::Markup::List
|
||||
|
||||
|
@ -14,12 +33,13 @@ class RDoc::Markup::List
|
|||
attr_reader :items
|
||||
|
||||
##
|
||||
# Creates a new list of +type+ with +items+
|
||||
# Creates a new list of +type+ with +items+. Valid list types are:
|
||||
# +:BULLET+, +:LABEL+, +:LALPHA+, +:NOTE+, +:NUMBER+, +:UALPHA+
|
||||
|
||||
def initialize type = nil, *items
|
||||
@type = type
|
||||
@items = []
|
||||
@items.push(*items)
|
||||
@items.concat items
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -74,7 +94,7 @@ class RDoc::Markup::List
|
|||
# Appends +items+ to the list
|
||||
|
||||
def push *items
|
||||
@items.push(*items)
|
||||
@items.concat items
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
##
|
||||
# An item within a List that contains paragraphs, headings, etc.
|
||||
#
|
||||
# For BULLET, NUMBER, LALPHA and UALPHA lists, the label will always be nil.
|
||||
# For NOTE and LABEL lists, the list label may contain:
|
||||
#
|
||||
# * a single String for a single label
|
||||
# * an Array of Strings for a list item with multiple terms
|
||||
# * nil for an extra description attached to a previously labeled list item
|
||||
|
||||
class RDoc::Markup::ListItem
|
||||
|
||||
|
@ -19,7 +26,7 @@ class RDoc::Markup::ListItem
|
|||
def initialize label = nil, *parts
|
||||
@label = label
|
||||
@parts = []
|
||||
@parts.push(*parts)
|
||||
@parts.concat parts
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -64,8 +71,14 @@ class RDoc::Markup::ListItem
|
|||
|
||||
def pretty_print q # :nodoc:
|
||||
q.group 2, '[item: ', ']' do
|
||||
if @label then
|
||||
q.text @label
|
||||
case @label
|
||||
when Array then
|
||||
q.pp @label
|
||||
q.text ';'
|
||||
q.breakable
|
||||
when String then
|
||||
q.pp @label
|
||||
q.text ';'
|
||||
q.breakable
|
||||
end
|
||||
|
||||
|
@ -79,7 +92,7 @@ class RDoc::Markup::ListItem
|
|||
# Adds +parts+ to the ListItem
|
||||
|
||||
def push *parts
|
||||
@parts.push(*parts)
|
||||
@parts.concat parts
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -10,5 +10,19 @@ class RDoc::Markup::Paragraph < RDoc::Markup::Raw
|
|||
visitor.accept_paragraph self
|
||||
end
|
||||
|
||||
##
|
||||
# Joins the raw paragraph text and converts inline HardBreaks to the
|
||||
# +hard_break+ text.
|
||||
|
||||
def text hard_break = ''
|
||||
@parts.map do |part|
|
||||
if RDoc::Markup::HardBreak === part then
|
||||
hard_break
|
||||
else
|
||||
part
|
||||
end
|
||||
end.join
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
require 'strscan'
|
||||
require 'rdoc/text'
|
||||
|
||||
##
|
||||
# A recursive-descent parser for RDoc markup.
|
||||
|
@ -52,7 +51,9 @@ class RDoc::Markup::Parser
|
|||
attr_reader :tokens
|
||||
|
||||
##
|
||||
# Parses +str+ into a Document
|
||||
# Parses +str+ into a Document.
|
||||
#
|
||||
# Use RDoc::Markup#parse instead of this method.
|
||||
|
||||
def self.parse str
|
||||
parser = new
|
||||
|
@ -74,12 +75,15 @@ class RDoc::Markup::Parser
|
|||
# Creates a new Parser. See also ::parse
|
||||
|
||||
def initialize
|
||||
@tokens = []
|
||||
@current_token = nil
|
||||
@debug = false
|
||||
|
||||
@line = 0
|
||||
@line_pos = 0
|
||||
@binary_input = nil
|
||||
@current_token = nil
|
||||
@debug = false
|
||||
@have_encoding = Object.const_defined? :Encoding
|
||||
@input_encoding = nil
|
||||
@line = 0
|
||||
@line_pos = 0
|
||||
@s = nil
|
||||
@tokens = []
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -107,13 +111,13 @@ class RDoc::Markup::Parser
|
|||
p :list_start => margin if @debug
|
||||
|
||||
list = RDoc::Markup::List.new
|
||||
label = nil
|
||||
|
||||
until @tokens.empty? do
|
||||
type, data, column, = get
|
||||
|
||||
case type
|
||||
when :BULLET, :LABEL, :LALPHA, :NOTE, :NUMBER, :UALPHA then
|
||||
|
||||
when *LIST_TOKENS then
|
||||
if column < margin || (list.type && list.type != type) then
|
||||
unget
|
||||
break
|
||||
|
@ -124,6 +128,8 @@ class RDoc::Markup::Parser
|
|||
|
||||
case type
|
||||
when :NOTE, :LABEL then
|
||||
label = [] unless label
|
||||
|
||||
if peek_type == :NEWLINE then
|
||||
# description not on the same line as LABEL/NOTE
|
||||
# skip the trailing newline & any blank lines below
|
||||
|
@ -146,32 +152,35 @@ class RDoc::Markup::Parser
|
|||
# In all cases, we have an empty description.
|
||||
# In the last case only, we continue.
|
||||
if peek_type.nil? || column < margin then
|
||||
empty = 1
|
||||
empty = true
|
||||
elsif column == margin then
|
||||
case peek_type
|
||||
when type
|
||||
empty = 2 # continue
|
||||
empty = :continue
|
||||
when *LIST_TOKENS
|
||||
empty = 1
|
||||
empty = true
|
||||
else
|
||||
empty = 0
|
||||
empty = false
|
||||
end
|
||||
else
|
||||
empty = 0
|
||||
empty = false
|
||||
end
|
||||
|
||||
if empty > 0 then
|
||||
item = RDoc::Markup::ListItem.new(data)
|
||||
item << RDoc::Markup::BlankLine.new
|
||||
list << item
|
||||
break if empty == 1
|
||||
next
|
||||
if empty then
|
||||
label << data
|
||||
next if empty == :continue
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
data = nil
|
||||
end
|
||||
|
||||
if label then
|
||||
data = label << data
|
||||
label = nil
|
||||
end
|
||||
|
||||
list_item = RDoc::Markup::ListItem.new data
|
||||
parse list_item, column
|
||||
list << list_item
|
||||
|
@ -184,7 +193,13 @@ class RDoc::Markup::Parser
|
|||
|
||||
p :list_end => margin if @debug
|
||||
|
||||
return nil if list.empty?
|
||||
if list.empty? then
|
||||
return nil unless label
|
||||
return nil unless [:LABEL, :NOTE].include? list.type
|
||||
|
||||
list_item = RDoc::Markup::ListItem.new label, RDoc::Markup::BlankLine.new
|
||||
list << list_item
|
||||
end
|
||||
|
||||
list
|
||||
end
|
||||
|
@ -200,15 +215,20 @@ class RDoc::Markup::Parser
|
|||
until @tokens.empty? do
|
||||
type, data, column, = get
|
||||
|
||||
if type == :TEXT && column == margin then
|
||||
if type == :TEXT and column == margin then
|
||||
paragraph << data
|
||||
skip :NEWLINE
|
||||
|
||||
break if peek_token.first == :BREAK
|
||||
|
||||
data << ' ' if skip :NEWLINE
|
||||
else
|
||||
unget
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
paragraph.parts.last.sub!(/ \z/, '') # cleanup
|
||||
|
||||
p :paragraph_end => margin if @debug
|
||||
|
||||
paragraph
|
||||
|
@ -267,7 +287,7 @@ class RDoc::Markup::Parser
|
|||
peek_column ||= column + width
|
||||
indent = peek_column - column - width
|
||||
line << ' ' * indent
|
||||
when :TEXT then
|
||||
when :BREAK, :TEXT then
|
||||
line << data
|
||||
else # *LIST_TOKENS
|
||||
list_marker = case type
|
||||
|
@ -297,6 +317,19 @@ class RDoc::Markup::Parser
|
|||
verbatim
|
||||
end
|
||||
|
||||
##
|
||||
# The character offset for the input string at the given +byte_offset+
|
||||
|
||||
def char_pos byte_offset
|
||||
if @have_encoding then
|
||||
matched = @binary_input[0, byte_offset]
|
||||
matched.force_encoding @input_encoding
|
||||
matched.length
|
||||
else
|
||||
byte_offset
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Pulls the next token from the stream.
|
||||
|
||||
|
@ -321,7 +354,12 @@ class RDoc::Markup::Parser
|
|||
until @tokens.empty? do
|
||||
type, data, column, = get
|
||||
|
||||
if type == :NEWLINE then
|
||||
case type
|
||||
when :BREAK then
|
||||
parent << RDoc::Markup::BlankLine.new
|
||||
skip :NEWLINE, false
|
||||
next
|
||||
when :NEWLINE then
|
||||
# trailing newlines are skipped below, so this is a blank line
|
||||
parent << RDoc::Markup::BlankLine.new
|
||||
skip :NEWLINE, false
|
||||
|
@ -372,6 +410,21 @@ class RDoc::Markup::Parser
|
|||
token
|
||||
end
|
||||
|
||||
##
|
||||
# Creates the StringScanner
|
||||
|
||||
def setup_scanner input
|
||||
@line = 0
|
||||
@line_pos = 0
|
||||
|
||||
if @have_encoding then
|
||||
@input_encoding = input.encoding
|
||||
@binary_input = input.dup.force_encoding Encoding::BINARY
|
||||
end
|
||||
|
||||
@s = StringScanner.new input
|
||||
end
|
||||
|
||||
##
|
||||
# Skips the next token if its type is +token_type+.
|
||||
#
|
||||
|
@ -389,58 +442,55 @@ class RDoc::Markup::Parser
|
|||
# Turns text +input+ into a stream of tokens
|
||||
|
||||
def tokenize input
|
||||
s = StringScanner.new input
|
||||
setup_scanner input
|
||||
|
||||
@line = 0
|
||||
@line_pos = 0
|
||||
|
||||
until s.eos? do
|
||||
pos = s.pos
|
||||
until @s.eos? do
|
||||
pos = @s.pos
|
||||
|
||||
# leading spaces will be reflected by the column of the next token
|
||||
# the only thing we loose are trailing spaces at the end of the file
|
||||
next if s.scan(/ +/)
|
||||
next if @s.scan(/ +/)
|
||||
|
||||
# note: after BULLET, LABEL, etc.,
|
||||
# indent will be the column of the next non-newline token
|
||||
|
||||
@tokens << case
|
||||
# [CR]LF => :NEWLINE
|
||||
when s.scan(/\r?\n/) then
|
||||
token = [:NEWLINE, s.matched, *token_pos(pos)]
|
||||
@line_pos = s.pos
|
||||
when @s.scan(/\r?\n/) then
|
||||
token = [:NEWLINE, @s.matched, *token_pos(pos)]
|
||||
@line_pos = char_pos @s.pos
|
||||
@line += 1
|
||||
token
|
||||
# === text => :HEADER then :TEXT
|
||||
when s.scan(/(=+)(\s*)/) then
|
||||
level = s[1].length
|
||||
when @s.scan(/(=+)(\s*)/) then
|
||||
level = @s[1].length
|
||||
header = [:HEADER, level, *token_pos(pos)]
|
||||
|
||||
if s[2] =~ /^\r?\n/ then
|
||||
s.pos -= s[2].length
|
||||
if @s[2] =~ /^\r?\n/ then
|
||||
@s.pos -= @s[2].length
|
||||
header
|
||||
else
|
||||
pos = s.pos
|
||||
s.scan(/.*/)
|
||||
pos = @s.pos
|
||||
@s.scan(/.*/)
|
||||
@tokens << header
|
||||
[:TEXT, s.matched.sub(/\r$/, ''), *token_pos(pos)]
|
||||
[:TEXT, @s.matched.sub(/\r$/, ''), *token_pos(pos)]
|
||||
end
|
||||
# --- (at least 3) and nothing else on the line => :RULE
|
||||
when s.scan(/(-{3,}) *$/) then
|
||||
[:RULE, s[1].length - 2, *token_pos(pos)]
|
||||
when @s.scan(/(-{3,}) *\r?$/) then
|
||||
[:RULE, @s[1].length - 2, *token_pos(pos)]
|
||||
# * or - followed by white space and text => :BULLET
|
||||
when s.scan(/([*-]) +(\S)/) then
|
||||
s.pos -= s[2].bytesize # unget \S
|
||||
[:BULLET, s[1], *token_pos(pos)]
|
||||
when @s.scan(/([*-]) +(\S)/) then
|
||||
@s.pos -= @s[2].bytesize # unget \S
|
||||
[:BULLET, @s[1], *token_pos(pos)]
|
||||
# A. text, a. text, 12. text => :UALPHA, :LALPHA, :NUMBER
|
||||
when s.scan(/([a-z]|\d+)\. +(\S)/i) then
|
||||
when @s.scan(/([a-z]|\d+)\. +(\S)/i) then
|
||||
# FIXME if tab(s), the column will be wrong
|
||||
# either support tabs everywhere by first expanding them to
|
||||
# spaces, or assume that they will have been replaced
|
||||
# before (and provide a check for that at least in debug
|
||||
# mode)
|
||||
list_label = s[1]
|
||||
s.pos -= s[2].bytesize # unget \S
|
||||
list_label = @s[1]
|
||||
@s.pos -= @s[2].bytesize # unget \S
|
||||
list_type =
|
||||
case list_label
|
||||
when /[a-z]/ then :LALPHA
|
||||
|
@ -451,14 +501,21 @@ class RDoc::Markup::Parser
|
|||
end
|
||||
[list_type, list_label, *token_pos(pos)]
|
||||
# [text] followed by spaces or end of line => :LABEL
|
||||
when s.scan(/\[(.*?)\]( +|$)/) then
|
||||
[:LABEL, s[1], *token_pos(pos)]
|
||||
when @s.scan(/\[(.*?)\]( +|\r?$)/) then
|
||||
[:LABEL, @s[1], *token_pos(pos)]
|
||||
# text:: followed by spaces or end of line => :NOTE
|
||||
when s.scan(/(.*?)::( +|$)/) then
|
||||
[:NOTE, s[1], *token_pos(pos)]
|
||||
when @s.scan(/(.*?)::( +|\r?$)/) then
|
||||
[:NOTE, @s[1], *token_pos(pos)]
|
||||
# anything else: :TEXT
|
||||
else s.scan(/.*/)
|
||||
[:TEXT, s.matched.sub(/\r$/, ''), *token_pos(pos)]
|
||||
else @s.scan(/(.*?)( )?\r?$/)
|
||||
token = [:TEXT, @s[1], *token_pos(pos)]
|
||||
|
||||
if @s[2] then
|
||||
@tokens << token
|
||||
[:BREAK, @s[2], *token_pos(pos + @s[1].length)]
|
||||
else
|
||||
token
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -466,9 +523,12 @@ class RDoc::Markup::Parser
|
|||
end
|
||||
|
||||
##
|
||||
# Calculates the column and line of the current token based on +offset+.
|
||||
# Calculates the column (by character) and line of the current token from
|
||||
# +scanner+ based on +byte_offset+.
|
||||
|
||||
def token_pos byte_offset
|
||||
offset = char_pos byte_offset
|
||||
|
||||
def token_pos offset
|
||||
[offset - @line_pos, @line]
|
||||
end
|
||||
|
||||
|
@ -484,14 +544,3 @@ class RDoc::Markup::Parser
|
|||
|
||||
end
|
||||
|
||||
require 'rdoc/markup/blank_line'
|
||||
require 'rdoc/markup/document'
|
||||
require 'rdoc/markup/heading'
|
||||
require 'rdoc/markup/list'
|
||||
require 'rdoc/markup/list_item'
|
||||
require 'rdoc/markup/raw'
|
||||
require 'rdoc/markup/paragraph'
|
||||
require 'rdoc/markup/indented_paragraph'
|
||||
require 'rdoc/markup/rule'
|
||||
require 'rdoc/markup/verbatim'
|
||||
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
require 'rdoc/markup'
|
||||
require 'rdoc/encoding'
|
||||
|
||||
##
|
||||
# Handle common directives that can occur in a block of text:
|
||||
#
|
||||
|
@ -9,18 +6,48 @@ require 'rdoc/encoding'
|
|||
# Directives can be escaped by preceding them with a backslash.
|
||||
#
|
||||
# RDoc plugin authors can register additional directives to be handled by
|
||||
# using RDoc::Markup::PreProcess::register
|
||||
# using RDoc::Markup::PreProcess::register.
|
||||
#
|
||||
# Any directive that is not built-in to RDoc (including those registered via
|
||||
# plugins) will be stored in the metadata hash on the CodeObject the comment
|
||||
# is attached to. See RDoc::Markup@Directives for the list of built-in
|
||||
# directives.
|
||||
|
||||
class RDoc::Markup::PreProcess
|
||||
|
||||
##
|
||||
# An RDoc::Options instance that will be filled in with overrides from
|
||||
# directives
|
||||
|
||||
attr_accessor :options
|
||||
|
||||
@registered = {}
|
||||
##
|
||||
# Adds a post-process handler for directives. The handler will be called
|
||||
# with the result RDoc::Comment (or text String) and the code object for the
|
||||
# comment (if any).
|
||||
|
||||
def self.post_process &block
|
||||
@post_processors << block
|
||||
end
|
||||
|
||||
##
|
||||
# Registered post-processors
|
||||
|
||||
def self.post_processors
|
||||
@post_processors
|
||||
end
|
||||
|
||||
##
|
||||
# Registers +directive+ as one handled by RDoc. If a block is given the
|
||||
# directive will be replaced by the result of the block, otherwise the
|
||||
# directive will be removed from the processed text.
|
||||
#
|
||||
# The block will be called with the directive name and the directive
|
||||
# parameter:
|
||||
#
|
||||
# RDoc::Markup::PreProcess.register 'my-directive' do |directive, param|
|
||||
# # replace text, etc.
|
||||
# end
|
||||
|
||||
def self.register directive, &block
|
||||
@registered[directive] = block
|
||||
|
@ -33,6 +60,16 @@ class RDoc::Markup::PreProcess
|
|||
@registered
|
||||
end
|
||||
|
||||
##
|
||||
# Clears all registered directives and post-processors
|
||||
|
||||
def self.reset
|
||||
@post_processors = []
|
||||
@registered = {}
|
||||
end
|
||||
|
||||
reset
|
||||
|
||||
##
|
||||
# Creates a new pre-processor for +input_file_name+ that will look for
|
||||
# included files in +include_path+
|
||||
|
@ -44,7 +81,7 @@ class RDoc::Markup::PreProcess
|
|||
end
|
||||
|
||||
##
|
||||
# Look for directives in a chunk of +text+.
|
||||
# Look for directives in the given +text+.
|
||||
#
|
||||
# Options that we don't handle are yielded. If the block returns false the
|
||||
# directive is restored to the text. If the block returns nil or no block
|
||||
|
@ -54,27 +91,56 @@ class RDoc::Markup::PreProcess
|
|||
# If no matching directive was registered the directive is restored to the
|
||||
# text.
|
||||
#
|
||||
# If +code_object+ is given and the param is set as metadata on the
|
||||
# +code_object+. See RDoc::CodeObject#metadata
|
||||
# If +code_object+ is given and the directive is unknown then the
|
||||
# directive's parameter is set as metadata on the +code_object+. See
|
||||
# RDoc::CodeObject#metadata for details.
|
||||
|
||||
def handle text, code_object = nil, &block
|
||||
encoding = if defined?(Encoding) then text.encoding else nil end
|
||||
if RDoc::Comment === text then
|
||||
comment = text
|
||||
text = text.text
|
||||
end
|
||||
|
||||
encoding = text.encoding if defined?(Encoding)
|
||||
|
||||
# regexp helper (square brackets for optional)
|
||||
# $1 $2 $3 $4 $5
|
||||
# [prefix][\]:directive:[spaces][param]newline
|
||||
text.gsub!(/^([ \t]*(?:#|\/?\*)?[ \t]*)(\\?):(\w+):([ \t]*)(.+)?\n/) do
|
||||
text.gsub!(/^([ \t]*(?:#|\/?\*)?[ \t]*)(\\?):(\w+):([ \t]*)(.+)?(\r?\n|$)/) do
|
||||
# skip something like ':toto::'
|
||||
next $& if $4.empty? and $5 and $5[0, 1] == ':'
|
||||
|
||||
# skip if escaped
|
||||
next "#$1:#$3:#$4#$5\n" unless $2.empty?
|
||||
|
||||
# This is not in handle_directive because I didn't want to pass another
|
||||
# argument into it
|
||||
if comment and $3 == 'markup' then
|
||||
next "#{$1.strip}\n" unless $5
|
||||
comment.format = $5.downcase
|
||||
next "#{$1.strip}\n"
|
||||
end
|
||||
|
||||
handle_directive $1, $3, $5, code_object, encoding, &block
|
||||
end
|
||||
|
||||
comment = text unless comment
|
||||
|
||||
self.class.post_processors.each do |handler|
|
||||
handler.call comment, code_object
|
||||
end
|
||||
|
||||
text
|
||||
end
|
||||
|
||||
##
|
||||
# Performs the actions described by +directive+ and its parameter +param+.
|
||||
#
|
||||
# +code_object+ is used for directives that operate on a class or module.
|
||||
# +prefix+ is used to ensure the replacement for handled directives is
|
||||
# correct. +encoding+ is used for the <tt>include</tt> directive.
|
||||
#
|
||||
# For a list of directives in RDoc see RDoc::Markup.
|
||||
#--
|
||||
# When 1.8.7 support is ditched prefix can be defaulted to ''
|
||||
|
||||
|
@ -92,7 +158,7 @@ class RDoc::Markup::PreProcess
|
|||
blankline
|
||||
when 'category' then
|
||||
if RDoc::Context === code_object then
|
||||
section = code_object.add_section param, ''
|
||||
section = code_object.add_section param
|
||||
code_object.temporary_section = section
|
||||
end
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ class RDoc::Markup::Raw
|
|||
|
||||
def initialize *parts
|
||||
@parts = []
|
||||
@parts.push(*parts)
|
||||
@parts.concat parts
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -24,7 +24,7 @@ class RDoc::Markup::Raw
|
|||
end
|
||||
|
||||
def == other # :nodoc:
|
||||
self.class == other.class and text == other.text
|
||||
self.class == other.class and @parts == other.parts
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -38,11 +38,11 @@ class RDoc::Markup::Raw
|
|||
# Appends +other+'s parts
|
||||
|
||||
def merge other
|
||||
@parts.push(*other.parts)
|
||||
@parts.concat other.parts
|
||||
end
|
||||
|
||||
def pretty_print q # :nodoc:
|
||||
self.class.name =~ /.*::(\w{4})/i
|
||||
self.class.name =~ /.*::(\w{1,4})/i
|
||||
|
||||
q.group 2, "[#{$1.downcase}: ", ']' do
|
||||
q.seplist @parts do |part|
|
||||
|
@ -55,7 +55,7 @@ class RDoc::Markup::Raw
|
|||
# Appends +texts+ onto this Paragraph
|
||||
|
||||
def push *texts
|
||||
self.parts.push(*texts)
|
||||
self.parts.concat texts
|
||||
end
|
||||
|
||||
##
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
##
|
||||
# Hold details of a special sequence
|
||||
|
||||
class RDoc::Markup::Special
|
||||
|
||||
##
|
||||
# Special type
|
||||
|
||||
attr_reader :type
|
||||
|
||||
##
|
||||
# Special text
|
||||
|
||||
attr_accessor :text
|
||||
|
||||
##
|
||||
# Creates a new special sequence of +type+ with +text+
|
||||
|
||||
def initialize(type, text)
|
||||
@type, @text = type, text
|
||||
end
|
||||
|
||||
##
|
||||
# Specials are equal when the have the same text and type
|
||||
|
||||
def ==(o)
|
||||
self.text == o.text && self.type == o.type
|
||||
end
|
||||
|
||||
def inspect # :nodoc:
|
||||
"#<RDoc::Markup::Special:0x%x @type=%p, @text=%p>" % [
|
||||
object_id, @type, text.dump]
|
||||
end
|
||||
|
||||
def to_s # :nodoc:
|
||||
"Special: type=#{type} text=#{text.dump}"
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
require 'rdoc/markup/formatter_test_case'
|
||||
|
||||
##
|
||||
# Test case for creating new plain-text RDoc::Markup formatters. See also
|
||||
# RDoc::Markup::FormatterTestCase
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
require 'rdoc/markup/to_rdoc'
|
||||
|
||||
##
|
||||
# Outputs RDoc markup with vibrant ANSI color!
|
||||
|
||||
|
@ -34,6 +32,11 @@ class RDoc::Markup::ToAnsi < RDoc::Markup::ToRdoc
|
|||
when :BULLET then
|
||||
2
|
||||
when :NOTE, :LABEL then
|
||||
if @prefix then
|
||||
@res << @prefix.strip
|
||||
@prefix = nil
|
||||
end
|
||||
|
||||
@res << "\n" unless res.length == 1
|
||||
2
|
||||
else
|
||||
|
@ -53,7 +56,13 @@ class RDoc::Markup::ToAnsi < RDoc::Markup::ToRdoc
|
|||
when :BULLET then
|
||||
'*'
|
||||
when :NOTE, :LABEL then
|
||||
attributes(list_item.label) + ":\n"
|
||||
labels = Array(list_item.label).map do |label|
|
||||
attributes(label).strip
|
||||
end.join "\n"
|
||||
|
||||
labels << ":\n" unless labels.empty?
|
||||
|
||||
labels
|
||||
else
|
||||
@list_index.last.to_s + '.'
|
||||
end
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
require 'rdoc/markup/to_rdoc'
|
||||
|
||||
##
|
||||
# Outputs RDoc markup with hot backspace action! You will probably need a
|
||||
# pager to use this output format.
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
require 'rdoc/markup/formatter'
|
||||
require 'rdoc/markup/inline'
|
||||
|
||||
require 'cgi'
|
||||
|
||||
##
|
||||
# Outputs RDoc markup as HTML
|
||||
# Outputs RDoc markup as HTML.
|
||||
|
||||
class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
||||
|
||||
|
@ -16,18 +13,24 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|||
# Maps RDoc::Markup::Parser::LIST_TOKENS types to HTML tags
|
||||
|
||||
LIST_TYPE_TO_HTML = {
|
||||
:BULLET => ['<ul>', '</ul>'],
|
||||
:LABEL => ['<dl class="rdoc-list">', '</dl>'],
|
||||
:LALPHA => ['<ol style="display: lower-alpha">', '</ol>'],
|
||||
:NOTE => ['<table class="rdoc-list">', '</table>'],
|
||||
:NUMBER => ['<ol>', '</ol>'],
|
||||
:UALPHA => ['<ol style="display: upper-alpha">', '</ol>'],
|
||||
:BULLET => ['<ul>', '</ul>'],
|
||||
:LABEL => ['<dl class="rdoc-list label-list">', '</dl>'],
|
||||
:LALPHA => ['<ol style="list-style-type: lower-alpha">', '</ol>'],
|
||||
:NOTE => ['<dl class="rdoc-list note-list">', '</dl>'],
|
||||
:NUMBER => ['<ol>', '</ol>'],
|
||||
:UALPHA => ['<ol style="list-style-type: upper-alpha">', '</ol>'],
|
||||
}
|
||||
|
||||
attr_reader :res # :nodoc:
|
||||
attr_reader :in_list_entry # :nodoc:
|
||||
attr_reader :list # :nodoc:
|
||||
|
||||
##
|
||||
# The RDoc::CodeObject HTML is being generated for. This is used to
|
||||
# generate namespaced URI fragments
|
||||
|
||||
attr_accessor :code_object
|
||||
|
||||
##
|
||||
# Path to this document for relative links
|
||||
|
||||
|
@ -62,19 +65,31 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|||
##
|
||||
# Creates a new formatter that will output HTML
|
||||
|
||||
def initialize markup = nil
|
||||
def initialize options, markup = nil
|
||||
super
|
||||
|
||||
@th = nil
|
||||
@code_object = nil
|
||||
@from_path = ''
|
||||
@in_list_entry = nil
|
||||
@list = nil
|
||||
@from_path = ''
|
||||
@th = nil
|
||||
@hard_break = "<br>\n"
|
||||
|
||||
# external links
|
||||
@markup.add_special(/((link:|https?:|mailto:|ftp:|www\.)\S+\w)/, :HYPERLINK)
|
||||
@markup.add_special(/(?:link:|https?:|mailto:|ftp:|irc:|www\.)\S+\w/,
|
||||
:HYPERLINK)
|
||||
|
||||
# internal links
|
||||
@markup.add_special(/rdoc-[a-z]+:\S+/, :RDOCLINK)
|
||||
|
||||
# and links of the form <text>[<url>]
|
||||
@markup.add_special(/(((\{.*?\})|\b\S+?)\[\S+?\])/, :TIDYLINK)
|
||||
@markup.add_special(/(?:
|
||||
\{.*?\} | # multi-word label
|
||||
\b[^\s{}]+? # single-word label
|
||||
)
|
||||
|
||||
\[\S+?\] # link target
|
||||
/x, :TIDYLINK)
|
||||
|
||||
init_tags
|
||||
end
|
||||
|
@ -83,6 +98,13 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|||
#
|
||||
# These methods handle special markup added by RDoc::Markup#add_special.
|
||||
|
||||
##
|
||||
# +special+ is a <code><br></code>
|
||||
|
||||
def handle_special_HARD_BREAK special
|
||||
'<br>'
|
||||
end
|
||||
|
||||
##
|
||||
# +special+ is a potential link. The following schemes are handled:
|
||||
#
|
||||
|
@ -101,6 +123,39 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|||
gen_url url, url
|
||||
end
|
||||
|
||||
##
|
||||
# +special+ is an rdoc-schemed link that will be converted into a hyperlink.
|
||||
#
|
||||
# For the +rdoc-ref+ scheme the named reference will be returned without
|
||||
# creating a link.
|
||||
#
|
||||
# For the +rdoc-label+ scheme the footnote and label prefixes are stripped
|
||||
# when creating a link. All other contents will be linked verbatim.
|
||||
|
||||
def handle_special_RDOCLINK special
|
||||
url = special.text
|
||||
|
||||
case url
|
||||
when /\Ardoc-ref:/
|
||||
$'
|
||||
when /\Ardoc-label:/
|
||||
text = $'
|
||||
|
||||
text = case text
|
||||
when /\Alabel-/ then $'
|
||||
when /\Afootmark-/ then "^#{$'}"
|
||||
when /\Afoottext-/ then "*#{$'}"
|
||||
else text
|
||||
end
|
||||
|
||||
gen_url url, text
|
||||
else
|
||||
url =~ /\Ardoc-[a-z]+:/
|
||||
|
||||
$'
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# This +special+ is a link where the label is different from the URL
|
||||
# <tt>label[url]</tt> or <tt>{long label}[url]</tt>
|
||||
|
@ -135,22 +190,48 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|||
@res.join
|
||||
end
|
||||
|
||||
##
|
||||
# Adds +block_quote+ to the output
|
||||
|
||||
def accept_block_quote block_quote
|
||||
@res << "\n<blockquote>"
|
||||
|
||||
block_quote.parts.each do |part|
|
||||
part.accept self
|
||||
end
|
||||
|
||||
@res << "</blockquote>\n"
|
||||
end
|
||||
|
||||
##
|
||||
# Adds +paragraph+ to the output
|
||||
|
||||
def accept_paragraph(paragraph)
|
||||
def accept_paragraph paragraph
|
||||
@res << "\n<p>"
|
||||
@res << wrap(to_html(paragraph.text))
|
||||
text = paragraph.text @hard_break
|
||||
@res << wrap(to_html(text))
|
||||
@res << "</p>\n"
|
||||
end
|
||||
|
||||
##
|
||||
# Adds +verbatim+ to the output
|
||||
|
||||
def accept_verbatim(verbatim)
|
||||
@res << "\n<pre>"
|
||||
@res << CGI.escapeHTML(verbatim.text.rstrip)
|
||||
@res << "</pre>\n"
|
||||
def accept_verbatim verbatim
|
||||
text = verbatim.text.rstrip
|
||||
|
||||
@res << if verbatim.ruby? or parseable? text then
|
||||
begin
|
||||
tokens = RDoc::RubyLex.tokenize text, @options
|
||||
|
||||
html = RDoc::TokenStream.to_html tokens
|
||||
|
||||
"\n<pre class=\"ruby\">#{html}</pre>\n"
|
||||
rescue RDoc::RubyLex::Error
|
||||
"\n<pre>#{CGI.escapeHTML text}</pre>\n"
|
||||
end
|
||||
else
|
||||
"\n<pre>#{CGI.escapeHTML text}</pre>\n"
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -208,12 +289,19 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|||
end
|
||||
|
||||
##
|
||||
# Adds +heading+ to the output
|
||||
# Adds +heading+ to the output. The headings greater than 6 are trimmed to
|
||||
# level 6.
|
||||
|
||||
def accept_heading(heading)
|
||||
@res << "\n<h#{heading.level}>"
|
||||
def accept_heading heading
|
||||
level = [6, heading.level].min
|
||||
|
||||
label = heading.aref
|
||||
label = [@code_object.aref, label].compact.join '-' if
|
||||
@code_object and @code_object.respond_to? :aref
|
||||
|
||||
@res << "\n<h#{level} id=\"#{label}\">"
|
||||
@res << to_html(heading.text)
|
||||
@res << "</h#{heading.level}>\n"
|
||||
@res << "</h#{level}>\n"
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -226,18 +314,22 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|||
# :section: Utilities
|
||||
|
||||
##
|
||||
# CGI escapes +text+
|
||||
# CGI-escapes +text+
|
||||
|
||||
def convert_string(text)
|
||||
CGI.escapeHTML text
|
||||
end
|
||||
|
||||
##
|
||||
# Generate a link for +url+, labeled with +text+. Handles the special cases
|
||||
# Generate a link to +url+ with content +text+. Handles the special cases
|
||||
# for img: and link: described under handle_special_HYPERLINK
|
||||
|
||||
def gen_url(url, text)
|
||||
if url =~ /([A-Za-z]+):(.*)/ then
|
||||
def gen_url url, text
|
||||
if url =~ /^rdoc-label:([^:]*)(?::(.*))?/ then
|
||||
type = "link"
|
||||
path = "##{$1}"
|
||||
id = " id=\"#{$2}\"" if $2
|
||||
elsif url =~ /([A-Za-z]+):(.*)/ then
|
||||
type = $1
|
||||
path = $2
|
||||
else
|
||||
|
@ -258,7 +350,7 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|||
url =~ /\.(gif|png|jpg|jpeg|bmp)$/ then
|
||||
"<img src=\"#{url}\" />"
|
||||
else
|
||||
"<a href=\"#{url}\">#{text.sub(%r{^#{type}:/*}, '')}</a>"
|
||||
"<a#{id} href=\"#{url}\">#{text.sub(%r{^#{type}:/*}, '')}</a>"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -275,9 +367,9 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|||
# Maps attributes to HTML tags
|
||||
|
||||
def init_tags
|
||||
add_tag :BOLD, "<b>", "</b>"
|
||||
add_tag :TT, "<tt>", "</tt>"
|
||||
add_tag :EM, "<em>", "</em>"
|
||||
add_tag :BOLD, "<strong>", "</strong>"
|
||||
add_tag :TT, "<code>", "</code>"
|
||||
add_tag :EM, "<em>", "</em>"
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -288,10 +380,10 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|||
case list_type
|
||||
when :BULLET, :LALPHA, :NUMBER, :UALPHA then
|
||||
"<li>"
|
||||
when :LABEL then
|
||||
"<dt>#{to_html list_item.label}</dt>\n<dd>"
|
||||
when :NOTE then
|
||||
"<tr><td class=\"rdoc-term\"><p>#{to_html list_item.label}</p></td>\n<td>"
|
||||
when :LABEL, :NOTE then
|
||||
Array(list_item.label).map do |label|
|
||||
"<dt>#{to_html label}\n"
|
||||
end.join << "<dd>"
|
||||
else
|
||||
raise RDoc::Error, "Invalid list type: #{list_type.inspect}"
|
||||
end
|
||||
|
@ -304,15 +396,21 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|||
case list_type
|
||||
when :BULLET, :LALPHA, :NUMBER, :UALPHA then
|
||||
"</li>"
|
||||
when :LABEL then
|
||||
when :LABEL, :NOTE then
|
||||
"</dd>"
|
||||
when :NOTE then
|
||||
"</td></tr>"
|
||||
else
|
||||
raise RDoc::Error, "Invalid list type: #{list_type.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Returns true if Ripper is available it can create a sexp from +text+
|
||||
|
||||
def parseable? text
|
||||
text =~ /\b(def|class|module|require) |=>|\{\s?\||do \|/ and
|
||||
text !~ /<%|%>/
|
||||
end
|
||||
|
||||
##
|
||||
# Converts +item+ to HTML using RDoc::Text#to_html
|
||||
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
require 'rdoc/markup/to_html'
|
||||
require 'rdoc/cross_reference'
|
||||
|
||||
##
|
||||
# Subclass of the RDoc::Markup::ToHtml class that supports looking up method
|
||||
# names, classes, etc to create links. RDoc::CrossReference is used to
|
||||
|
@ -31,21 +28,20 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
|
|||
# references are removed unless +show_hash+ is true. Only method names
|
||||
# preceded by '#' or '::' are linked, unless +hyperlink_all+ is true.
|
||||
|
||||
def initialize(from_path, context, show_hash, hyperlink_all = false,
|
||||
markup = nil)
|
||||
def initialize(options, from_path, context, markup = nil)
|
||||
raise ArgumentError, 'from_path cannot be nil' if from_path.nil?
|
||||
super markup
|
||||
|
||||
crossref_re = hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP
|
||||
|
||||
@cross_reference = RDoc::CrossReference.new context
|
||||
|
||||
@markup.add_special crossref_re, :CROSSREF
|
||||
@markup.add_special(/rdoc-ref:\S+\w/, :HYPERLINK)
|
||||
super options, markup
|
||||
|
||||
@context = context
|
||||
@from_path = from_path
|
||||
@hyperlink_all = hyperlink_all
|
||||
@show_hash = show_hash
|
||||
@hyperlink_all = @options.hyperlink_all
|
||||
@show_hash = @options.show_hash
|
||||
|
||||
crossref_re = @hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP
|
||||
@markup.add_special crossref_re, :CROSSREF
|
||||
|
||||
@cross_reference = RDoc::CrossReference.new @context
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -57,6 +53,8 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
|
|||
|
||||
name = name[1..-1] unless @show_hash if name[0, 1] == '#'
|
||||
|
||||
name = "#{CGI.unescape $'} at #{$1}" if name =~ /(.*[^#:])@/
|
||||
|
||||
text = name unless text
|
||||
|
||||
link lookup, text
|
||||
|
@ -72,6 +70,8 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
|
|||
def handle_special_CROSSREF(special)
|
||||
name = special.text
|
||||
|
||||
return name if name =~ /@[\w-]+\.[\w-]/ # labels that look like emails
|
||||
|
||||
unless @hyperlink_all then
|
||||
# This ensures that words entirely consisting of lowercase letters will
|
||||
# not have cross-references generated (to suppress lots of erroneous
|
||||
|
@ -92,6 +92,25 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
|
|||
super
|
||||
end
|
||||
|
||||
##
|
||||
# +special+ is an rdoc-schemed link that will be converted into a hyperlink.
|
||||
# For the rdoc-ref scheme the cross-reference will be looked up and the
|
||||
# given name will be used.
|
||||
#
|
||||
# All other contents are handled by
|
||||
# {the superclass}[rdoc-ref:RDoc::Markup::ToHtml#handle_special_RDOCLINK]
|
||||
|
||||
def handle_special_RDOCLINK special
|
||||
url = special.text
|
||||
|
||||
case url
|
||||
when /\Ardoc-ref:/ then
|
||||
cross_reference $'
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Generates links for <tt>rdoc-ref:</tt> scheme URLs and allows
|
||||
# RDoc::Markup::ToHtml to handle other schemes.
|
||||
|
@ -106,13 +125,31 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
|
|||
# Creates an HTML link to +name+ with the given +text+.
|
||||
|
||||
def link name, text
|
||||
original_name = name
|
||||
|
||||
if name =~ /(.*[^#:])@/ then
|
||||
name = $1
|
||||
label = $'
|
||||
end
|
||||
|
||||
ref = @cross_reference.resolve name, text
|
||||
|
||||
text = ref.output_name @context if
|
||||
RDoc::MethodAttr === ref and text == original_name
|
||||
|
||||
case ref
|
||||
when String then
|
||||
ref
|
||||
else
|
||||
"<a href=\"#{ref.as_href @from_path}\">#{text}</a>"
|
||||
path = ref.as_href @from_path
|
||||
|
||||
if path =~ /#/ then
|
||||
path << "-label-#{label}"
|
||||
else
|
||||
path << "#label-#{label}"
|
||||
end if label
|
||||
|
||||
"<a href=\"#{path}\">#{text}</a>"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,284 @@
|
|||
##
|
||||
# Outputs RDoc markup as paragraphs with inline markup only.
|
||||
|
||||
class RDoc::Markup::ToHtmlSnippet < RDoc::Markup::ToHtml
|
||||
|
||||
##
|
||||
# After this many characters the input will be cut off.
|
||||
|
||||
attr_reader :character_limit
|
||||
|
||||
##
|
||||
# The number of characters seen so far.
|
||||
|
||||
attr_reader :characters # :nodoc:
|
||||
|
||||
##
|
||||
# The attribute bitmask
|
||||
|
||||
attr_reader :mask
|
||||
|
||||
##
|
||||
# After this many paragraphs the input will be cut off.
|
||||
|
||||
attr_reader :paragraph_limit
|
||||
|
||||
##
|
||||
# Count of paragraphs found
|
||||
|
||||
attr_reader :paragraphs
|
||||
|
||||
##
|
||||
# Creates a new ToHtmlSnippet formatter that will cut off the input on the
|
||||
# next word boundary after the given number of +characters+ or +paragraphs+
|
||||
# of text have been encountered.
|
||||
|
||||
def initialize options, characters = 100, paragraphs = 3, markup = nil
|
||||
super options, markup
|
||||
|
||||
@character_limit = characters
|
||||
@paragraph_limit = paragraphs
|
||||
|
||||
@characters = 0
|
||||
@mask = 0
|
||||
@paragraphs = 0
|
||||
|
||||
@markup.add_special RDoc::CrossReference::CROSSREF_REGEXP, :CROSSREF
|
||||
end
|
||||
|
||||
##
|
||||
# Adds +heading+ to the output as a paragraph
|
||||
|
||||
def accept_heading heading
|
||||
@res << "<p>#{to_html heading.text}\n"
|
||||
|
||||
add_paragraph
|
||||
end
|
||||
|
||||
##
|
||||
# Raw sections are untrusted and ignored
|
||||
|
||||
alias accept_raw ignore
|
||||
|
||||
##
|
||||
# Rules are ignored
|
||||
|
||||
alias accept_rule ignore
|
||||
|
||||
def accept_paragraph paragraph
|
||||
para = @in_list_entry.last || "<p>"
|
||||
|
||||
text = paragraph.text @hard_break
|
||||
|
||||
@res << "#{para}#{wrap to_html text}\n"
|
||||
|
||||
add_paragraph
|
||||
end
|
||||
|
||||
##
|
||||
# Finishes consumption of +list_item+
|
||||
|
||||
def accept_list_item_end list_item
|
||||
end
|
||||
|
||||
##
|
||||
# Prepares the visitor for consuming +list_item+
|
||||
|
||||
def accept_list_item_start list_item
|
||||
@res << list_item_start(list_item, @list.last)
|
||||
end
|
||||
|
||||
##
|
||||
# Prepares the visitor for consuming +list+
|
||||
|
||||
def accept_list_start list
|
||||
@list << list.type
|
||||
@res << html_list_name(list.type, true)
|
||||
@in_list_entry.push ''
|
||||
end
|
||||
|
||||
##
|
||||
# Adds +verbatim+ to the output
|
||||
|
||||
def accept_verbatim verbatim
|
||||
throw :done if @characters >= @character_limit
|
||||
input = verbatim.text.rstrip
|
||||
|
||||
text = truncate input
|
||||
text << ' ...' unless text == input
|
||||
|
||||
super RDoc::Markup::Verbatim.new text
|
||||
|
||||
add_paragraph
|
||||
end
|
||||
|
||||
##
|
||||
# Prepares the visitor for HTML snippet generation
|
||||
|
||||
def start_accepting
|
||||
super
|
||||
|
||||
@characters = 0
|
||||
end
|
||||
|
||||
##
|
||||
# Removes escaping from the cross-references in +special+
|
||||
|
||||
def handle_special_CROSSREF special
|
||||
special.text.sub(/\A\\/, '')
|
||||
end
|
||||
|
||||
##
|
||||
# +special+ is a <code><br></code>
|
||||
|
||||
def handle_special_HARD_BREAK special
|
||||
@characters -= 4
|
||||
'<br>'
|
||||
end
|
||||
|
||||
##
|
||||
# Lists are paragraphs, but notes and labels have a separator
|
||||
|
||||
def list_item_start list_item, list_type
|
||||
throw :done if @characters >= @character_limit
|
||||
|
||||
case list_type
|
||||
when :BULLET, :LALPHA, :NUMBER, :UALPHA then
|
||||
"<p>"
|
||||
when :LABEL, :NOTE then
|
||||
labels = Array(list_item.label).map do |label|
|
||||
to_html label
|
||||
end.join ', '
|
||||
|
||||
labels << " — " unless labels.empty?
|
||||
|
||||
start = "<p>#{labels}"
|
||||
@characters += 1 # try to include the label
|
||||
start
|
||||
else
|
||||
raise RDoc::Error, "Invalid list type: #{list_type.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Returns just the text of +link+, +url+ is only used to determine the link
|
||||
# type.
|
||||
|
||||
def gen_url url, text
|
||||
if url =~ /^rdoc-label:([^:]*)(?::(.*))?/ then
|
||||
type = "link"
|
||||
elsif url =~ /([A-Za-z]+):(.*)/ then
|
||||
type = $1
|
||||
else
|
||||
type = "http"
|
||||
end
|
||||
|
||||
if (type == "http" or type == "https" or type == "link") and
|
||||
url =~ /\.(gif|png|jpg|jpeg|bmp)$/ then
|
||||
''
|
||||
else
|
||||
text.sub(%r%^#{type}:/*%, '')
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# In snippets, there are no lists
|
||||
|
||||
def html_list_name list_type, open_tag
|
||||
''
|
||||
end
|
||||
|
||||
##
|
||||
# Throws +:done+ when paragraph_limit paragraphs have been encountered
|
||||
|
||||
def add_paragraph
|
||||
@paragraphs += 1
|
||||
|
||||
throw :done if @paragraphs >= @paragraph_limit
|
||||
end
|
||||
|
||||
##
|
||||
# Marks up +content+
|
||||
|
||||
def convert content
|
||||
catch :done do
|
||||
return super
|
||||
end
|
||||
|
||||
end_accepting
|
||||
end
|
||||
|
||||
##
|
||||
# Converts flow items +flow+
|
||||
|
||||
def convert_flow flow
|
||||
throw :done if @characters >= @character_limit
|
||||
|
||||
res = []
|
||||
@mask = 0
|
||||
|
||||
flow.each do |item|
|
||||
case item
|
||||
when RDoc::Markup::AttrChanger then
|
||||
off_tags res, item
|
||||
on_tags res, item
|
||||
when String then
|
||||
text = convert_string item
|
||||
res << truncate(text)
|
||||
when RDoc::Markup::Special then
|
||||
text = convert_special item
|
||||
res << truncate(text)
|
||||
else
|
||||
raise "Unknown flow element: #{item.inspect}"
|
||||
end
|
||||
|
||||
if @characters >= @character_limit then
|
||||
off_tags res, RDoc::Markup::AttrChanger.new(0, @mask)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
res << ' ...' if @characters >= @character_limit
|
||||
|
||||
res.join
|
||||
end
|
||||
|
||||
##
|
||||
# Maintains a bitmask to allow HTML elements to be closed properly. See
|
||||
# RDoc::Markup::Formatter.
|
||||
|
||||
def on_tags res, item
|
||||
@mask ^= item.turn_on
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
##
|
||||
# Maintains a bitmask to allow HTML elements to be closed properly. See
|
||||
# RDoc::Markup::Formatter.
|
||||
|
||||
def off_tags res, item
|
||||
@mask ^= item.turn_off
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
##
|
||||
# Truncates +text+ at the end of the first word after the character_limit.
|
||||
|
||||
def truncate text
|
||||
length = text.length
|
||||
characters = @characters
|
||||
@characters += length
|
||||
|
||||
return text if @characters < @character_limit
|
||||
|
||||
remaining = @character_limit - characters
|
||||
|
||||
text =~ /\A(.{#{remaining},}?)(\s|$)/m # TODO word-break instead of \s?
|
||||
|
||||
$1
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
##
|
||||
# Joins the parts of an RDoc::Markup::Paragraph into a single String.
|
||||
#
|
||||
# This allows for easier maintenance and testing of Markdown support.
|
||||
#
|
||||
# This formatter only works on Paragraph instances. Attempting to process
|
||||
# other markup syntax items will not work.
|
||||
|
||||
class RDoc::Markup::ToJoinedParagraph < RDoc::Markup::Formatter
|
||||
|
||||
def initialize # :nodoc:
|
||||
super nil
|
||||
end
|
||||
|
||||
def start_accepting
|
||||
end
|
||||
|
||||
def end_accepting
|
||||
end
|
||||
|
||||
def accept_paragraph paragraph
|
||||
parts = []
|
||||
string = false
|
||||
|
||||
paragraph.parts.each do |part|
|
||||
if String === part then
|
||||
if string then
|
||||
string << part
|
||||
else
|
||||
parts << part
|
||||
string = part
|
||||
end
|
||||
else
|
||||
parts << part
|
||||
string = false
|
||||
end
|
||||
end
|
||||
|
||||
parts = parts.map do |part|
|
||||
if String === part then
|
||||
part.rstrip
|
||||
else
|
||||
part
|
||||
end
|
||||
end
|
||||
|
||||
# TODO use Enumerable#chunk when ruby 1.8 support is dropped
|
||||
#parts = paragraph.parts.chunk do |part|
|
||||
# String === part
|
||||
#end.map do |string, chunk|
|
||||
# string ? chunk.join.rstrip : chunk
|
||||
#end.flatten
|
||||
|
||||
paragraph.parts.replace parts
|
||||
end
|
||||
|
||||
alias accept_block_quote ignore
|
||||
alias accept_heading ignore
|
||||
alias accept_list_end ignore
|
||||
alias accept_list_item_end ignore
|
||||
alias accept_list_item_start ignore
|
||||
alias accept_list_start ignore
|
||||
alias accept_raw ignore
|
||||
alias accept_rule ignore
|
||||
alias accept_verbatim ignore
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
require 'cgi'
|
||||
|
||||
##
|
||||
# Creates HTML-safe labels suitable for use in id attributes. Tidylinks are
|
||||
# converted to their link part and cross-reference links have the suppression
|
||||
# marks removed (\\SomeClass is converted to SomeClass).
|
||||
|
||||
class RDoc::Markup::ToLabel < RDoc::Markup::Formatter
|
||||
|
||||
attr_reader :res # :nodoc:
|
||||
|
||||
##
|
||||
# Creates a new formatter that will output HTML-safe labels
|
||||
|
||||
def initialize markup = nil
|
||||
super nil, markup
|
||||
|
||||
@markup.add_special RDoc::CrossReference::CROSSREF_REGEXP, :CROSSREF
|
||||
@markup.add_special(/(((\{.*?\})|\b\S+?)\[\S+?\])/, :TIDYLINK)
|
||||
|
||||
add_tag :BOLD, '', ''
|
||||
add_tag :TT, '', ''
|
||||
add_tag :EM, '', ''
|
||||
|
||||
@res = []
|
||||
end
|
||||
|
||||
##
|
||||
# Converts +text+ to an HTML-safe label
|
||||
|
||||
def convert text
|
||||
label = convert_flow @am.flow text
|
||||
|
||||
CGI.escape label
|
||||
end
|
||||
|
||||
##
|
||||
# Converts the CROSSREF +special+ to plain text, removing the suppression
|
||||
# marker, if any
|
||||
|
||||
def handle_special_CROSSREF special
|
||||
text = special.text
|
||||
|
||||
text.sub(/^\\/, '')
|
||||
end
|
||||
|
||||
##
|
||||
# Converts the TIDYLINK +special+ to just the text part
|
||||
|
||||
def handle_special_TIDYLINK special
|
||||
text = special.text
|
||||
|
||||
return text unless text =~ /\{(.*?)\}\[(.*?)\]/ or text =~ /(\S+)\[(.*?)\]/
|
||||
|
||||
$1
|
||||
end
|
||||
|
||||
alias accept_blank_line ignore
|
||||
alias accept_block_quote ignore
|
||||
alias accept_heading ignore
|
||||
alias accept_list_end ignore
|
||||
alias accept_list_item_end ignore
|
||||
alias accept_list_item_start ignore
|
||||
alias accept_list_start ignore
|
||||
alias accept_paragraph ignore
|
||||
alias accept_raw ignore
|
||||
alias accept_rule ignore
|
||||
alias accept_verbatim ignore
|
||||
alias end_accepting ignore
|
||||
alias handle_special_HARD_BREAK ignore
|
||||
alias start_accepting ignore
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
# :markup: markdown
|
||||
|
||||
##
|
||||
# Outputs parsed markup as Markdown
|
||||
|
||||
class RDoc::Markup::ToMarkdown < RDoc::Markup::ToRdoc
|
||||
|
||||
##
|
||||
# Creates a new formatter that will output Markdown format text
|
||||
|
||||
def initialize markup = nil
|
||||
super
|
||||
|
||||
@headings[1] = ['# ', '']
|
||||
@headings[2] = ['## ', '']
|
||||
@headings[3] = ['### ', '']
|
||||
@headings[4] = ['#### ', '']
|
||||
@headings[5] = ['##### ', '']
|
||||
@headings[6] = ['###### ', '']
|
||||
|
||||
@hard_break = " \n"
|
||||
end
|
||||
|
||||
##
|
||||
# Maps attributes to HTML sequences
|
||||
|
||||
def init_tags
|
||||
add_tag :BOLD, '**', '**'
|
||||
add_tag :EM, '*', '*'
|
||||
add_tag :TT, '`', '`'
|
||||
end
|
||||
|
||||
##
|
||||
# Adds a newline to the output
|
||||
|
||||
def handle_special_HARD_BREAK special
|
||||
" \n"
|
||||
end
|
||||
|
||||
##
|
||||
# Finishes consumption of `list`
|
||||
|
||||
def accept_list_end list
|
||||
@res << "\n"
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
##
|
||||
# Finishes consumption of `list_item`
|
||||
|
||||
def accept_list_item_end list_item
|
||||
width = case @list_type.last
|
||||
when :BULLET then
|
||||
4
|
||||
when :NOTE, :LABEL then
|
||||
use_prefix
|
||||
|
||||
4
|
||||
else
|
||||
@list_index[-1] = @list_index.last.succ
|
||||
4
|
||||
end
|
||||
|
||||
@indent -= width
|
||||
end
|
||||
|
||||
##
|
||||
# Prepares the visitor for consuming `list_item`
|
||||
|
||||
def accept_list_item_start list_item
|
||||
type = @list_type.last
|
||||
|
||||
case type
|
||||
when :NOTE, :LABEL then
|
||||
bullets = Array(list_item.label).map do |label|
|
||||
attributes(label).strip
|
||||
end.join "\n"
|
||||
|
||||
bullets << "\n:"
|
||||
|
||||
@prefix = ' ' * @indent
|
||||
@indent += 4
|
||||
@prefix << bullets + (' ' * (@indent - 1))
|
||||
else
|
||||
bullet = type == :BULLET ? '*' : @list_index.last.to_s + '.'
|
||||
@prefix = (' ' * @indent) + bullet.ljust(4)
|
||||
|
||||
@indent += 4
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Prepares the visitor for consuming `list`
|
||||
|
||||
def accept_list_start list
|
||||
case list.type
|
||||
when :BULLET, :LABEL, :NOTE then
|
||||
@list_index << nil
|
||||
when :LALPHA, :NUMBER, :UALPHA then
|
||||
@list_index << 1
|
||||
else
|
||||
raise RDoc::Error, "invalid list type #{list.type}"
|
||||
end
|
||||
|
||||
@list_width << 4
|
||||
@list_type << list.type
|
||||
end
|
||||
|
||||
##
|
||||
# Adds `rule` to the output
|
||||
|
||||
def accept_rule rule
|
||||
use_prefix or @res << ' ' * @indent
|
||||
@res << '-' * 3
|
||||
@res << "\n"
|
||||
end
|
||||
|
||||
##
|
||||
# Outputs `verbatim` indented 4 columns
|
||||
|
||||
def accept_verbatim verbatim
|
||||
indent = ' ' * (@indent + 4)
|
||||
|
||||
verbatim.parts.each do |part|
|
||||
@res << indent unless part == "\n"
|
||||
@res << part
|
||||
end
|
||||
|
||||
@res << "\n" unless @res =~ /\n\z/
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -1,6 +1,3 @@
|
|||
require 'rdoc/markup/formatter'
|
||||
require 'rdoc/markup/inline'
|
||||
|
||||
##
|
||||
# Outputs RDoc markup as RDoc markup! (mostly)
|
||||
|
||||
|
@ -45,7 +42,7 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
|
|||
# Creates a new formatter that will output (mostly) \RDoc markup
|
||||
|
||||
def initialize markup = nil
|
||||
super
|
||||
super nil, markup
|
||||
|
||||
@markup.add_special(/\\\S/, :SUPPRESSED_CROSSREF)
|
||||
@width = 78
|
||||
|
@ -60,6 +57,8 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
|
|||
@headings[4] = ['==== ', '']
|
||||
@headings[5] = ['===== ', '']
|
||||
@headings[6] = ['====== ', '']
|
||||
|
||||
@hard_break = "\n"
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -78,6 +77,21 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
|
|||
@res << "\n"
|
||||
end
|
||||
|
||||
##
|
||||
# Adds +paragraph+ to the output
|
||||
|
||||
def accept_block_quote block_quote
|
||||
@indent += 2
|
||||
|
||||
block_quote.parts.each do |part|
|
||||
@prefix = '> '
|
||||
|
||||
part.accept self
|
||||
end
|
||||
|
||||
@indent -= 2
|
||||
end
|
||||
|
||||
##
|
||||
# Adds +heading+ to the output
|
||||
|
||||
|
@ -106,6 +120,11 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
|
|||
when :BULLET then
|
||||
2
|
||||
when :NOTE, :LABEL then
|
||||
if @prefix then
|
||||
@res << @prefix.strip
|
||||
@prefix = nil
|
||||
end
|
||||
|
||||
@res << "\n"
|
||||
2
|
||||
else
|
||||
|
@ -125,10 +144,15 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
|
|||
|
||||
case type
|
||||
when :NOTE, :LABEL then
|
||||
bullet = attributes(list_item.label) + ":\n"
|
||||
bullets = Array(list_item.label).map do |label|
|
||||
attributes(label).strip
|
||||
end.join "\n"
|
||||
|
||||
bullets << ":\n" unless bullets.empty?
|
||||
|
||||
@prefix = ' ' * @indent
|
||||
@indent += 2
|
||||
@prefix << bullet + (' ' * @indent)
|
||||
@prefix << bullets + (' ' * @indent)
|
||||
else
|
||||
bullet = type == :BULLET ? '*' : @list_index.last.to_s + '.'
|
||||
@prefix = (' ' * @indent) + bullet.ljust(bullet.length + 1)
|
||||
|
@ -168,7 +192,8 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
|
|||
# Adds +paragraph+ to the output
|
||||
|
||||
def accept_paragraph paragraph
|
||||
wrap attributes(paragraph.text)
|
||||
text = paragraph.text @hard_break
|
||||
wrap attributes text
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -176,7 +201,8 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
|
|||
|
||||
def accept_indented_paragraph paragraph
|
||||
@indent += paragraph.indent
|
||||
wrap attributes(paragraph.text)
|
||||
text = paragraph.text @hard_break
|
||||
wrap attributes text
|
||||
@indent -= paragraph.indent
|
||||
end
|
||||
|
||||
|
@ -234,6 +260,13 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
|
|||
text
|
||||
end
|
||||
|
||||
##
|
||||
# Adds a newline to the output
|
||||
|
||||
def handle_special_HARD_BREAK special
|
||||
"\n"
|
||||
end
|
||||
|
||||
##
|
||||
# Prepares the visitor for text generation
|
||||
|
||||
|
@ -252,8 +285,7 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
|
|||
# prefix for later consumption.
|
||||
|
||||
def use_prefix
|
||||
prefix = @prefix
|
||||
@prefix = nil
|
||||
prefix, @prefix = @prefix, nil
|
||||
@res << prefix if prefix
|
||||
|
||||
prefix
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
##
|
||||
# Extracts just the RDoc::Markup::Heading elements from a
|
||||
# RDoc::Markup::Document to help build a table of contents
|
||||
|
||||
class RDoc::Markup::ToTableOfContents < RDoc::Markup::Formatter
|
||||
|
||||
@to_toc = nil
|
||||
|
||||
##
|
||||
# Singleton for table-of-contents generation
|
||||
|
||||
def self.to_toc
|
||||
@to_toc ||= new
|
||||
end
|
||||
|
||||
##
|
||||
# Output accumulator
|
||||
|
||||
attr_reader :res
|
||||
|
||||
def initialize # :nodoc:
|
||||
super nil
|
||||
end
|
||||
|
||||
##
|
||||
# Adds +heading+ to the table of contents
|
||||
|
||||
def accept_heading heading
|
||||
@res << heading
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the table of contents
|
||||
|
||||
def end_accepting
|
||||
@res
|
||||
end
|
||||
|
||||
##
|
||||
# Prepares the visitor for text generation
|
||||
|
||||
def start_accepting
|
||||
@res = []
|
||||
end
|
||||
|
||||
# :stopdoc:
|
||||
alias accept_block_quote ignore
|
||||
alias accept_raw ignore
|
||||
alias accept_rule ignore
|
||||
alias accept_blank_line ignore
|
||||
alias accept_paragraph ignore
|
||||
alias accept_verbatim ignore
|
||||
alias accept_list_end ignore
|
||||
alias accept_list_item_start ignore
|
||||
alias accept_list_item_end ignore
|
||||
alias accept_list_end_bullet ignore
|
||||
alias accept_list_start ignore
|
||||
# :startdoc:
|
||||
|
||||
end
|
||||
|
|
@ -1,6 +1,3 @@
|
|||
require 'rdoc/markup'
|
||||
require 'rdoc/markup/formatter'
|
||||
|
||||
##
|
||||
# This Markup outputter is used for testing purposes.
|
||||
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
require 'rdoc/markup/formatter'
|
||||
require 'rdoc/markup/inline'
|
||||
|
||||
##
|
||||
# Extracts sections of text enclosed in plus, tt or code. Used to discover
|
||||
# undocumented parameters.
|
||||
|
@ -21,11 +18,18 @@ class RDoc::Markup::ToTtOnly < RDoc::Markup::Formatter
|
|||
# Creates a new tt-only formatter.
|
||||
|
||||
def initialize markup = nil
|
||||
super
|
||||
super nil, markup
|
||||
|
||||
add_tag :TT, nil, nil
|
||||
end
|
||||
|
||||
##
|
||||
# Adds tts from +block_quote+ to the output
|
||||
|
||||
def accept_block_quote block_quote
|
||||
tt_sections block_quote.text
|
||||
end
|
||||
|
||||
##
|
||||
# Pops the list type for +list+ from #list_type
|
||||
|
||||
|
@ -46,7 +50,9 @@ class RDoc::Markup::ToTtOnly < RDoc::Markup::Formatter
|
|||
def accept_list_item_start list_item
|
||||
case @list_type.last
|
||||
when :NOTE, :LABEL then
|
||||
tt_sections(list_item.label)
|
||||
Array(list_item.label).map do |label|
|
||||
tt_sections label
|
||||
end.flatten
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче