Migrate rdoc as bundled gems

This commit is contained in:
Hiroshi SHIBATA 2025-01-15 11:52:40 +09:00
parent e0be1b9025
commit 86d871d29c
Notes: git 2025-01-15 07:53:19 +00:00
292 changed files with 1 additions and 89919 deletions

View File

@ -39,3 +39,4 @@ ostruct 0.6.1 https://github.com/ruby/ostruct
pstore 0.1.4 https://github.com/ruby/pstore b563c4d354615e12a6fa54ffaa4ed711c3d1ba9f
benchmark 0.4.0 https://github.com/ruby/benchmark
logger 1.6.5 https://github.com/ruby/logger
rdoc 6.10.0 https://github.com/ruby/rdoc

View File

@ -1,211 +0,0 @@
# frozen_string_literal: true
$DEBUG_RDOC = nil
##
# 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.
#
# For a simple introduction to writing or generating documentation using RDoc
# see the README.
#
# == Roadmap
#
# If you think you found a bug in RDoc see CONTRIBUTING@Bugs
#
# 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 set the default markup format see
# RDoc::Markup@Markup+Formats
#
# If you want to store rdoc configuration in your gem (such as the default
# markup format) see RDoc::Options@Saved+Options
#
# 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 or other
# formats, 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 want an overview of how RDoc works see CONTRIBUTING
#
# == Credits
#
# RDoc is currently being maintained by Eric Hodel <drbrain@segment7.net>.
#
# Dave Thomas <dave@pragmaticprogrammer.com> is the original author of RDoc.
#
# * 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.
module RDoc
##
# Exception thrown by any rdoc error.
class Error < RuntimeError; end
require_relative 'rdoc/version'
##
# Method visibilities
VISIBILITIES = [:public, :protected, :private]
##
# Name of the dotfile that contains the description of files to be processed
# in the current directory
DOT_DOC_FILENAME = ".document"
##
# General RDoc modifiers
GENERAL_MODIFIERS = %w[nodoc].freeze
##
# RDoc modifiers for classes
CLASS_MODIFIERS = GENERAL_MODIFIERS
##
# RDoc modifiers for attributes
ATTR_MODIFIERS = GENERAL_MODIFIERS
##
# RDoc modifiers for constants
CONSTANT_MODIFIERS = GENERAL_MODIFIERS
##
# RDoc modifiers for methods
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 NameError => e # --disable-gems
raise unless e.name == :gem
rescue Gem::LoadError
end
begin
require 'psych'
rescue ::LoadError
ensure
require 'yaml'
end
end
##
# Searches and returns the directory for settings.
#
# 1. <tt>$HOME/.rdoc</tt> directory, if it exists.
# 2. The +rdoc+ directory under the path specified by the
# +XDG_DATA_HOME+ environment variable, if it is set.
# 3. <tt>$HOME/.local/share/rdoc</tt> directory.
#
# Other than the home directory, the containing directory will be
# created automatically.
def self.home
rdoc_dir = begin
File.expand_path('~/.rdoc')
rescue ArgumentError
end
if File.directory?(rdoc_dir)
rdoc_dir
else
require 'fileutils'
begin
# XDG
xdg_data_home = ENV["XDG_DATA_HOME"] || File.join(File.expand_path("~"), '.local', 'share')
unless File.exist?(xdg_data_home)
FileUtils.mkdir_p xdg_data_home
end
File.join xdg_data_home, "rdoc"
rescue Errno::EACCES
end
end
end
autoload :RDoc, "#{__dir__}/rdoc/rdoc"
autoload :CrossReference, "#{__dir__}/rdoc/cross_reference"
autoload :ERBIO, "#{__dir__}/rdoc/erbio"
autoload :ERBPartial, "#{__dir__}/rdoc/erb_partial"
autoload :Encoding, "#{__dir__}/rdoc/encoding"
autoload :Generator, "#{__dir__}/rdoc/generator"
autoload :Options, "#{__dir__}/rdoc/options"
autoload :Parser, "#{__dir__}/rdoc/parser"
autoload :Servlet, "#{__dir__}/rdoc/servlet"
autoload :RI, "#{__dir__}/rdoc/ri"
autoload :Stats, "#{__dir__}/rdoc/stats"
autoload :Store, "#{__dir__}/rdoc/store"
autoload :Task, "#{__dir__}/rdoc/task"
autoload :Text, "#{__dir__}/rdoc/text"
autoload :Markdown, "#{__dir__}/rdoc/markdown"
autoload :Markup, "#{__dir__}/rdoc/markup"
autoload :RD, "#{__dir__}/rdoc/rd"
autoload :TomDoc, "#{__dir__}/rdoc/tom_doc"
autoload :KNOWN_CLASSES, "#{__dir__}/rdoc/known_classes"
autoload :TokenStream, "#{__dir__}/rdoc/token_stream"
autoload :Comment, "#{__dir__}/rdoc/comment"
require_relative 'rdoc/i18n'
# code objects
#
# We represent the various high-level code constructs that appear in Ruby
# programs: classes, modules, methods, and so on.
autoload :CodeObject, "#{__dir__}/rdoc/code_object"
autoload :Context, "#{__dir__}/rdoc/code_object/context"
autoload :TopLevel, "#{__dir__}/rdoc/code_object/top_level"
autoload :AnonClass, "#{__dir__}/rdoc/code_object/anon_class"
autoload :ClassModule, "#{__dir__}/rdoc/code_object/class_module"
autoload :NormalClass, "#{__dir__}/rdoc/code_object/normal_class"
autoload :NormalModule, "#{__dir__}/rdoc/code_object/normal_module"
autoload :SingleClass, "#{__dir__}/rdoc/code_object/single_class"
autoload :Alias, "#{__dir__}/rdoc/code_object/alias"
autoload :AnyMethod, "#{__dir__}/rdoc/code_object/any_method"
autoload :MethodAttr, "#{__dir__}/rdoc/code_object/method_attr"
autoload :GhostMethod, "#{__dir__}/rdoc/code_object/ghost_method"
autoload :MetaMethod, "#{__dir__}/rdoc/code_object/meta_method"
autoload :Attr, "#{__dir__}/rdoc/code_object/attr"
autoload :Constant, "#{__dir__}/rdoc/code_object/constant"
autoload :Mixin, "#{__dir__}/rdoc/code_object/mixin"
autoload :Include, "#{__dir__}/rdoc/code_object/include"
autoload :Extend, "#{__dir__}/rdoc/code_object/extend"
autoload :Require, "#{__dir__}/rdoc/code_object/require"
end

View File

@ -1,427 +0,0 @@
# frozen_string_literal: true
##
# Base class for the RDoc code tree.
#
# We contain the common stuff for contexts (which are containers) and other
# elements (methods, attributes and so on)
#
# Here's the tree of the CodeObject subclasses:
#
# * RDoc::Context
# * RDoc::TopLevel
# * RDoc::ClassModule
# * RDoc::AnonClass (never used so far)
# * RDoc::NormalClass
# * RDoc::NormalModule
# * RDoc::SingleClass
# * RDoc::MethodAttr
# * RDoc::Attr
# * RDoc::AnyMethod
# * RDoc::GhostMethod
# * RDoc::MetaMethod
# * RDoc::Alias
# * RDoc::Constant
# * RDoc::Mixin
# * RDoc::Require
# * RDoc::Include
class RDoc::CodeObject
include RDoc::Text
##
# Our comment
attr_reader :comment
##
# Do we document our children?
attr_reader :document_children
##
# Do we document ourselves?
attr_reader :document_self
##
# Are we done documenting (ie, did we come across a :enddoc:)?
attr_reader :done_documenting
##
# Which file this code object was defined in
attr_reader :file
##
# Force documentation of this CodeObject
attr_reader :force_documentation
##
# Line in #file where this CodeObject was defined
attr_accessor :line
##
# Hash of arbitrary metadata for this CodeObject
attr_reader :metadata
##
# Sets the parent CodeObject
attr_writer :parent
##
# Did we ever receive a +:nodoc:+ directive?
attr_reader :received_nodoc
##
# Set the section this CodeObject is in
attr_writer :section
##
# The RDoc::Store for this object.
attr_reader :store
##
# We are the model of the code, but we know that at some point we will be
# worked on by viewers. By implementing the Viewable protocol, viewers can
# associated themselves with these objects.
attr_accessor :viewer
##
# When mixed-in to a class, this points to the Context in which it was originally defined.
attr_accessor :mixin_from
##
# Creates a new CodeObject that will document itself and its children
def initialize
@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
@track_visibility = true
@mixin_from = nil
initialize_visibility
end
##
# Initializes state for visibility of this CodeObject and its children.
def initialize_visibility # :nodoc:
@document_children = true
@document_self = true
@done_documenting = false
@force_documentation = false
@received_nodoc = false
@ignored = false
@suppressed = false
@track_visibility = true
end
##
# Replaces our comment with +comment+, unless it is empty.
def comment=(comment)
@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
# HACK correct fix is to have #initialize create @comment
# with the correct encoding
if String === @comment and @comment.empty? then
@comment = RDoc::Encoding.change_encoding @comment, comment.encoding
end
@comment
end
end
end
##
# Should this CodeObject be displayed in output?
#
# A code object should be displayed if:
#
# * The item didn't have a nodoc or wasn't in a container that had nodoc
# * The item wasn't ignored
# * The item has documentation and was not suppressed
def display?
@document_self and not @ignored and
(documented? or not @suppressed)
end
##
# Enables or disables documentation of this CodeObject's children unless it
# has been turned off by :enddoc:
def document_children=(document_children)
return unless @track_visibility
@document_children = document_children unless @done_documenting
end
##
# Enables or disables documentation of this CodeObject unless it has been
# turned off by :enddoc:. If the argument is +nil+ it means the
# documentation is turned off by +:nodoc:+.
def document_self=(document_self)
return unless @track_visibility
return if @done_documenting
@document_self = document_self
@received_nodoc = true if document_self.nil?
end
##
# Does this object have a comment with content or is #received_nodoc true?
def documented?
@received_nodoc or !@comment.empty?
end
##
# Turns documentation on/off, and turns on/off #document_self
# and #document_children.
#
# Once documentation has been turned off (by +:enddoc:+),
# the object will refuse to turn #document_self or
# #document_children on, so +:doc:+ and +:start_doc:+ directives
# will have no effect in the current file.
def done_documenting=(value)
return unless @track_visibility
@done_documenting = value
@document_self = !value
@document_children = @document_self
end
##
# Yields each parent of this CodeObject. See also
# RDoc::ClassModule#each_ancestor
def each_parent
code_object = self
while code_object = code_object.parent do
yield code_object
end
self
end
##
# File name where this CodeObject was found.
#
# See also RDoc::Context#in_files
def file_name
return unless @file
@file.absolute_name
end
##
# Force the documentation of this object unless documentation
# has been turned off by :enddoc:
#--
# HACK untested, was assigning to an ivar
def force_documentation=(value)
@force_documentation = value unless @done_documenting
end
##
# Sets the full_name overriding any computed full name.
#
# Set to +nil+ to clear RDoc's cached value
def full_name= full_name
@full_name = full_name
end
##
# Use this to ignore a CodeObject and all its children until found again
# (#record_location is called). An ignored item will not be displayed in
# documentation.
#
# See github issue #55
#
# The ignored status is temporary in order to allow implementation details
# to be hidden. At the end of processing a file RDoc allows all classes
# and modules to add new documentation to previously created classes.
#
# If a class was ignored (via stopdoc) then reopened later with additional
# documentation it should be displayed. If a class was ignored and never
# reopened it should not be displayed. The ignore flag allows this to
# occur.
def ignore
return unless @track_visibility
@ignored = true
stop_doc
end
##
# Has this class been ignored?
#
# See also #ignore
def ignored?
@ignored
end
##
# The options instance from the store this CodeObject is attached to, or a
# default options instance if the CodeObject is not attached.
#
# This is used by Text#snippet
def options
if @store and @store.rdoc then
@store.rdoc.options
else
RDoc::Options.new
end
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
def parent_file_name
@parent ? @parent.base_name : '(unknown)'
end
##
# Name of our parent
def parent_name
@parent ? @parent.full_name : '(unknown)'
end
##
# Records the RDoc::TopLevel (file) where this code object was defined
def record_location top_level
@ignored = false
@suppressed = false
@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 :enddoc:
def start_doc
return if @done_documenting
@document_self = true
@document_children = true
@ignored = false
@suppressed = false
end
##
# Disable capture of documentation
def stop_doc
return unless @track_visibility
@document_self = false
@document_children = false
end
##
# Sets the +store+ that contains this CodeObject
def store= store
@store = store
return unless @track_visibility
if :nodoc == options.visibility then
initialize_visibility
@track_visibility = false
end
end
##
# Use this to suppress a CodeObject and all its children until the next file
# it is seen in or documentation is discovered. A suppressed item with
# documentation will be displayed while an ignored item with documentation
# may not be displayed.
def suppress
return unless @track_visibility
@suppressed = true
stop_doc
end
##
# Has this class been suppressed?
#
# See also #suppress
def suppressed?
@suppressed
end
end

View File

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

View File

@ -1,10 +0,0 @@
# frozen_string_literal: true
##
# An anonymous class like:
#
# c = Class.new do end
#
# AnonClass is currently not used.
class RDoc::AnonClass < RDoc::ClassModule
end

View File

@ -1,379 +0,0 @@
# frozen_string_literal: true
##
# AnyMethod is the base class for objects representing methods
class RDoc::AnyMethod < RDoc::MethodAttr
##
# 2::
# RDoc 4
# Added calls_super
# Added parent name and class
# Added section title
# 3::
# RDoc 4.1
# Added is_alias_for
MARSHAL_VERSION = 3 # :nodoc:
##
# Don't rename \#initialize to \::new
attr_accessor :dont_rename_initialize
##
# The C function that implements this method (if it was defined in a C file)
attr_accessor :c_function
# The section title of the method (if defined in a C file via +:category:+)
attr_accessor :section_title
# Parameters for this method
attr_accessor :params
##
# If true this method uses +super+ to call a superclass version
attr_accessor :calls_super
include RDoc::TokenStream
##
# Creates a new AnyMethod with a token stream +text+ and +name+
def initialize text, name
super
@c_function = nil
@dont_rename_initialize = false
@token_stream = nil
@calls_super = false
@superclass_method = nil
end
##
# Adds +an_alias+ as an alias for this method in +context+.
def add_alias an_alias, context = nil
method = self.class.new an_alias.text, an_alias.new_name
method.record_location an_alias.file
method.singleton = self.singleton
method.params = self.params
method.visibility = self.visibility
method.comment = an_alias.comment
method.is_alias_for = self
@aliases << method
context.add_method method if context
method
end
##
# Prefix for +aref+ is 'method'.
def aref_prefix
'method'
end
##
# The call_seq or the param_seq with method name, if there is no call_seq.
#
# Use this for displaying a method's argument lists.
def arglists
if @call_seq then
@call_seq
elsif @params then
"#{name}#{param_seq}"
end
end
##
# Different ways to call this method
def call_seq
unless call_seq = _call_seq
call_seq = is_alias_for._call_seq if is_alias_for
end
return unless call_seq
deduplicate_call_seq(call_seq)
end
##
# Sets the different ways you can call this method. If an empty +call_seq+
# is given nil is assumed.
#
# See also #param_seq
def call_seq= call_seq
return if call_seq.empty?
@call_seq = call_seq
end
##
# Whether the method has a call-seq.
def has_call_seq?
!!(@call_seq || is_alias_for&._call_seq)
end
##
# Loads is_alias_for from the internal name. Returns nil if the alias
# cannot be found.
def is_alias_for # :nodoc:
case @is_alias_for
when RDoc::MethodAttr then
@is_alias_for
when Array then
return nil unless @store
klass_name, singleton, method_name = @is_alias_for
return nil unless klass = @store.find_class_or_module(klass_name)
@is_alias_for = klass.find_method method_name, singleton
end
end
##
# Dumps this AnyMethod for use by ri. See also #marshal_load
def marshal_dump
aliases = @aliases.map do |a|
[a.name, parse(a.comment)]
end
is_alias_for = [
@is_alias_for.parent.full_name,
@is_alias_for.singleton,
@is_alias_for.name
] if @is_alias_for
[ MARSHAL_VERSION,
@name,
full_name,
@singleton,
@visibility,
parse(@comment),
@call_seq,
@block_params,
aliases,
@params,
@file.relative_name,
@calls_super,
@parent.name,
@parent.class,
@section.title,
is_alias_for,
]
end
##
# Loads this AnyMethod from +array+. For a loaded AnyMethod the following
# methods will return cached values:
#
# * #full_name
# * #parent_name
def marshal_load array
initialize_visibility
@dont_rename_initialize = 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]
# 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]
@is_alias_for = array[15]
array[8].each do |new_name, comment|
add_alias RDoc::Alias.new(nil, @name, new_name, comment, @singleton)
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
##
# Method name
#
# If the method has no assigned name, it extracts it from #call_seq.
def name
return @name if @name
@name =
@call_seq[/^.*?\.(\w+)/, 1] ||
@call_seq[/^.*?(\w+)/, 1] ||
@call_seq if @call_seq
end
##
# A list of this method's method and yield parameters. +call-seq+ params
# are preferred over parsed method and block params.
def param_list
if @call_seq then
params = @call_seq.split("\n").last
params = params.sub(/.*?\((.*)\)/, '\1')
params = params.sub(/(\{|do)\s*\|([^|]*)\|.*/, ',\2')
elsif @params then
params = @params.sub(/\((.*)\)/, '\1')
params << ",#{@block_params}" if @block_params
elsif @block_params then
params = @block_params
else
return []
end
if @block_params then
# If this method has explicit block parameters, remove any explicit
# &block
params = params.sub(/,?\s*&\w+/, '')
else
params = params.sub(/\&(\w+)/, '\1')
end
params = params.gsub(/\s+/, '').split(',').reject(&:empty?)
params.map { |param| param.sub(/=.*/, '') }
end
##
# Pretty parameter list for this method. If the method's parameters were
# given by +call-seq+ it is preferred over the parsed values.
def param_seq
if @call_seq then
params = @call_seq.split("\n").last
params = params.sub(/[^( ]+/, '')
params = params.sub(/(\|[^|]+\|)\s*\.\.\.\s*(end|\})/, '\1 \2')
elsif @params then
params = @params.gsub(/\s*\#.*/, '')
params = params.tr_s("\n ", " ")
params = "(#{params})" unless params[0] == ?(
else
params = ''
end
if @block_params then
# If this method has explicit block parameters, remove any explicit
# &block
params = params.sub(/,?\s*&\w+/, '')
block = @block_params.tr_s("\n ", " ")
if block[0] == ?(
block = block.sub(/^\(/, '').sub(/\)/, '')
end
params << " { |#{block}| ... }"
end
params
end
##
# Whether to skip the method description, true for methods that have
# aliases with a call-seq that doesn't include the method name.
def skip_description?
has_call_seq? && call_seq.nil? && !!(is_alias_for || !aliases.empty?)
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
protected
##
# call_seq without deduplication and alias lookup.
def _call_seq
@call_seq if defined?(@call_seq) && @call_seq
end
private
##
# call_seq with alias examples information removed, if this
# method is an alias method.
def deduplicate_call_seq(call_seq)
return call_seq unless is_alias_for || !aliases.empty?
method_name = self.name
method_name = method_name[0, 1] if method_name =~ /\A\[/
entries = call_seq.split "\n"
ignore = aliases.map(&:name)
if is_alias_for
ignore << is_alias_for.name
ignore.concat is_alias_for.aliases.map(&:name)
end
ignore.map! { |n| n =~ /\A\[/ ? /\[.*\]/ : n}
ignore.delete(method_name)
ignore = Regexp.union(ignore)
matching = entries.reject do |entry|
entry =~ /^\w*\.?#{ignore}[$\(\s]/ or
entry =~ /\s#{ignore}\s/
end
matching.empty? ? nil : matching.join("\n")
end
end

View File

@ -1,175 +0,0 @@
# frozen_string_literal: true
##
# An attribute created by \#attr, \#attr_reader, \#attr_writer or
# \#attr_accessor
class RDoc::Attr < RDoc::MethodAttr
##
# 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')?
attr_accessor :rw
##
# Creates a new Attr with body +text+, +name+, read/write status +rw+ and
# +comment+. +singleton+ marks this as a class attribute.
def initialize(text, name, rw, comment, singleton = false)
super text, name
@rw = rw
@singleton = singleton
self.comment = comment
end
##
# Attributes are equal when their names, singleton and rw are identical
def == other
self.class == other.class and
self.name == other.name and
self.rw == other.rw and
self.singleton == other.singleton
end
##
# Add +an_alias+ as an attribute in +context+.
def add_alias(an_alias, context)
new_attr = self.class.new(self.text, an_alias.new_name, self.rw,
self.comment, self.singleton)
new_attr.record_location an_alias.file
new_attr.visibility = self.visibility
new_attr.is_alias_for = self
@aliases << new_attr
context.add_attribute new_attr
new_attr
end
##
# The #aref prefix for attributes
def aref_prefix
'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.
def definition
case @rw
when 'RW' then 'attr_accessor'
when 'R' then 'attr_reader'
when 'W' then 'attr_writer'
end
end
def inspect # :nodoc:
alias_for = @is_alias_for ? " (alias for #{@is_alias_for.name})" : nil
visibility = self.visibility
visibility = "forced #{visibility}" if force_documentation
"#<%s:0x%x %s %s (%s)%s>" % [
self.class, object_id,
full_name,
rw,
visibility,
alias_for,
]
end
##
# Dumps this Attr for use by ri. See also #marshal_load
def marshal_dump
[ MARSHAL_VERSION,
@name,
full_name,
@rw,
@visibility,
parse(@comment),
singleton,
@file.relative_name,
@parent.full_name,
@parent.class,
@section.title
]
end
##
# Loads this Attr from +array+. For a loaded Attr the following
# methods will return cached values:
#
# * #full_name
# * #parent_name
def marshal_load array
initialize_visibility
@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.split('#', 2).first
end
def pretty_print q # :nodoc:
q.group 2, "[#{self.class.name} #{full_name} #{rw} #{visibility}", "]" do
unless comment.empty? then
q.breakable
q.text "comment:"
q.breakable
q.pp @comment
end
end
end
def to_s # :nodoc:
"#{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

View File

@ -1,868 +0,0 @@
# frozen_string_literal: true
##
# ClassModule is the base class for objects representing either a class or a
# module.
class RDoc::ClassModule < RDoc::Context
##
# 1::
# RDoc 3.7
# * Added visibility, singleton and file to attributes
# * 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 = 3 # :nodoc:
##
# Constants that are aliases for this class or module
attr_accessor :constant_aliases
##
# Comment and the location it came from. Use #add_comment to add comments
attr_accessor :comment_location
attr_accessor :diagram # :nodoc:
##
# Class or module this constant is an alias for
attr_accessor :is_alias_for
##
# Return a RDoc::ClassModule of class +class_type+ that is a copy
# of module +module+. Used to promote modules to classes.
#--
# TODO move to RDoc::NormalClass (I think)
def self.from_module class_type, mod
klass = class_type.new mod.name
mod.comment_location.each do |comment, location|
klass.add_comment comment, location
end
klass.parent = mod.parent
klass.section = mod.section
klass.viewer = mod.viewer
klass.attributes.concat mod.attributes
klass.method_list.concat mod.method_list
klass.aliases.concat mod.aliases
klass.external_aliases.concat mod.external_aliases
klass.constants.concat mod.constants
klass.includes.concat mod.includes
klass.extends.concat mod.extends
klass.methods_hash.update mod.methods_hash
klass.constants_hash.update mod.constants_hash
klass.current_section = mod.current_section
klass.in_files.concat mod.in_files
klass.sections.concat mod.sections
klass.unmatched_alias_lists = mod.unmatched_alias_lists
klass.current_section = mod.current_section
klass.visibility = mod.visibility
klass.classes_hash.update mod.classes_hash
klass.modules_hash.update mod.modules_hash
klass.metadata.update mod.metadata
klass.document_self = mod.received_nodoc ? nil : mod.document_self
klass.document_children = mod.document_children
klass.force_documentation = mod.force_documentation
klass.done_documenting = mod.done_documenting
# update the parent of all children
(klass.attributes +
klass.method_list +
klass.aliases +
klass.external_aliases +
klass.constants +
klass.includes +
klass.extends +
klass.classes +
klass.modules).each do |obj|
obj.parent = klass
obj.full_name = nil
end
klass
end
##
# Creates a new ClassModule with +name+ with optional +superclass+
#
# This is a constructor for subclasses, and must never be called directly.
def initialize(name, superclass = nil)
@constant_aliases = []
@diagram = nil
@is_alias_for = nil
@name = name
@superclass = superclass
@comment_location = [] # [[comment, location]]
super()
end
##
# Adds +comment+ to this ClassModule's list of comments at +location+. This
# method is preferred over #comment= since it allows ri data to be updated
# across multiple runs.
def add_comment comment, location
return unless document_self
original = comment
comment = case comment
when RDoc::Comment then
comment.normalize
else
normalize_comment comment
end
if location.parser == RDoc::Parser::C
@comment_location.delete_if { |(_, l)| l == location }
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).
#
# Returns the included classes or modules, not the includes
# themselves. The returned values are either String or
# RDoc::NormalModule instances (see RDoc::Include#module).
#
# The values are returned in reverse order of their inclusion,
# which is the order suitable for searching methods/attributes
# in the ancestors. The superclass, if any, comes last.
def ancestors
includes.map { |i| i.module }.reverse
end
def aref_prefix # :nodoc:
raise NotImplementedError, "missing aref_prefix for #{self.class}"
end
##
# HTML fragment reference for this module or class. See
# RDoc::NormalClass#aref and RDoc::NormalModule#aref
def aref
"#{aref_prefix}-#{full_name}"
end
##
# Ancestors of this class or module only
alias direct_ancestors ancestors
##
# Clears the comment. Used by the Ruby parser.
def clear_comment
@comment = ''
end
##
# This method is deprecated, use #add_comment instead.
#
# Appends +comment+ to the current comment, but separated by a rule. Works
# more like <tt>+=</tt>.
def comment= comment # :nodoc:
comment = case comment
when RDoc::Comment then
comment.normalize
else
normalize_comment comment
end
comment = "#{@comment.to_s}\n---\n#{comment.to_s}" unless @comment.empty?
super comment
end
##
# Prepares this ClassModule for use by a generator.
#
# See RDoc::Store#complete
def complete min_visibility
update_aliases
remove_nodoc_children
embed_mixins
update_includes
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
##
# Does this class or module have a comment with content or is
# #received_nodoc true?
def documented?
return true if @received_nodoc
return false if @comment_location.empty?
@comment_location.any? { |comment, _| not comment.empty? }
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
##
# Looks for a symbol in the #ancestors. See Context#find_local_symbol.
def find_ancestor_local_symbol symbol
each_ancestor do |m|
res = m.find_local_symbol(symbol)
return res if res
end
nil
end
##
# Finds a class or module with +name+ in this namespace or its descendants
def find_class_named name
return self if full_name == name
return self if @name == name
@classes.values.find do |klass|
next if klass == self
klass.find_class_named name
end
end
##
# Return the fully qualified name of this class or module
def full_name
@full_name ||= if RDoc::ClassModule === parent then
"#{parent.full_name}::#{@name}"
else
@name
end
end
##
# TODO: filter included items by #display?
def marshal_dump # :nodoc:
attrs = attributes.sort.map do |attr|
next unless attr.display?
[ attr.name, attr.rw,
attr.visibility, attr.singleton, attr.file_name,
]
end.compact
method_types = methods_by_type.map do |type, visibilities|
visibilities = visibilities.map do |visibility, methods|
method_names = methods.map do |method|
next unless method.display?
[method.name, method.file_name]
end.compact
[visibility, method_names.uniq]
end
[type, visibilities]
end
[ MARSHAL_VERSION,
@name,
full_name,
@superclass,
parse(@comment_location),
attrs,
constants.select { |constant| constant.display? },
includes.map do |incl|
next unless incl.display?
[incl.name, parse(incl.comment), incl.file_name]
end.compact,
method_types,
extends.map do |ext|
next unless ext.display?
[ext.name, parse(ext.comment), ext.file_name]
end.compact,
@sections.values,
@in_files.map do |tl|
tl.relative_name
end,
parent.full_name,
parent.class,
]
end
def marshal_load array # :nodoc:
initialize_visibility
initialize_methods_etc
@current_section = nil
@document_self = true
@done_documenting = false
@parent = nil
@temporary_section = nil
@visibility = nil
@classes = {}
@modules = {}
@name = array[1]
@full_name = array[2]
@superclass = array[3]
@comment = array[4]
@comment_location = if RDoc::Markup::Document === @comment.parts.first then
@comment
else
RDoc::Markup::Document.new @comment
end
array[5].each do |name, rw, visibility, singleton, file|
singleton ||= false
visibility ||= :public
attr = RDoc::Attr.new nil, name, rw, nil, singleton
add_attribute attr
attr.visibility = visibility
attr.record_location RDoc::TopLevel.new file
end
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|
incl = add_include RDoc::Include.new(name, comment)
incl.record_location RDoc::TopLevel.new file
end
array[8].each do |type, visibilities|
visibilities.each do |visibility, methods|
@visibility = visibility
methods.each do |name, file|
method = RDoc::AnyMethod.new nil, name
method.singleton = true if type == 'class'
method.record_location RDoc::TopLevel.new file
add_method method
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
##
# Merges +class_module+ into this ClassModule.
#
# 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
document = parse @comment_location
document = document.merge other_document
@comment = @comment_location = document
end
cm = class_module
other_files = cm.in_files
merge_collections attributes, cm.attributes, other_files do |add, attr|
if add then
add_attribute attr
else
@attributes.delete attr
@methods_hash.delete attr.pretty_name
end
end
merge_collections constants, cm.constants, other_files do |add, const|
if add then
add_constant const
else
@constants.delete const
@constants_hash.delete const.name
end
end
merge_collections includes, cm.includes, other_files do |add, incl|
if add then
add_include incl
else
@includes.delete incl
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
else
@method_list.delete meth
@methods_hash.delete meth.pretty_name
end
end
merge_sections cm
self
end
##
# Merges collection +mine+ with +other+ preferring other. +other_files+ is
# used to help determine which items should be deleted.
#
# Yields whether the item should be added or removed (true or false) and the
# item to be added or removed.
#
# merge_collections things, other.things, other.in_files do |add, thing|
# if add then
# # add the thing
# else
# # remove the thing
# end
# end
def merge_collections mine, other, other_files, &block # :nodoc:
my_things = mine. group_by { |thing| thing.file }
other_things = other.group_by { |thing| thing.file }
remove_things my_things, other_files, &block
add_things my_things, other_things, &block
end
##
# Merges the comments in this ClassModule with the comments in the other
# ClassModule +cm+.
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_sections.each do |group, sections|
if my_sections.include? group
my_sections[group].each do |my_section|
other_section = cm.sections_hash[group]
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
##
# Does this object represent a module?
def module?
false
end
##
# Allows overriding the initial name.
#
# Used for modules and classes that are constant aliases.
def name= new_name
@name = new_name
end
##
# Parses +comment_location+ into an RDoc::Markup::Document composed of
# multiple RDoc::Markup::Documents with their file set.
def parse comment_location
case comment_location
when String then
super
when Array then
docs = comment_location.map do |comment, location|
doc = super comment
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
raise ArgumentError, "unknown comment class #{comment_location.class}"
end
end
##
# Path to this class or module for use with HTML generator output.
def path
http_url @store.rdoc.generator.class_dir
end
##
# Name to use to generate the url:
# modules and classes that are aliases for another
# module or class return the name of the latter.
def name_for_path
is_alias_for ? is_alias_for.full_name : full_name
end
##
# Returns the classes and modules that are not constants
# aliasing another class or module. For use by formatters
# only (caches its result).
def non_aliases
@non_aliases ||= classes_and_modules.reject { |cm| cm.is_alias_for }
end
##
# Updates the child modules or classes of class/module +parent+ by
# deleting the ones that have been removed from the documentation.
#
# +parent_hash+ is either <tt>parent.modules_hash</tt> or
# <tt>parent.classes_hash</tt> and +all_hash+ is ::all_modules_hash or
# ::all_classes_hash.
def remove_nodoc_children
prefix = self.full_name + '::'
modules_hash.each_key do |name|
full_name = prefix + name
modules_hash.delete name unless @store.modules_hash[full_name]
end
classes_hash.each_key do |name|
full_name = prefix + 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
@store.find_class_named(@superclass) || @superclass
end
##
# Set the superclass of this class to +superclass+
#
# where +superclass+ is one of:
#
# - +nil+
# - a String containing the full name of the superclass
# - the RDoc::ClassModule representing the superclass
def superclass=(superclass)
raise NoMethodError, "#{full_name} is a module" if module?
case superclass
when RDoc::ClassModule
@superclass = superclass.full_name
when nil, String
@superclass = superclass
else
raise TypeError, "superclass must be a String or RDoc::ClassModule, not #{superclass.class}"
end
end
##
# Get all super classes of this class in an array. The last element might be
# a string if the name is unknown.
def super_classes
result = []
parent = self
while parent = parent.superclass
result << parent
return result if parent.is_a?(String)
end
result
end
def to_s # :nodoc:
if is_alias_for then
"#{self.class.name} #{self.full_name} -> #{is_alias_for}"
else
super
end
end
##
# 'module' or 'class'
def type
module? ? 'module' : 'class'
end
##
# Updates the child modules & classes by replacing the ones that are
# aliases through a constant.
#
# The aliased module/class is replaced in the children and in
# RDoc::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.
#
# Formatters can use the #non_aliases method to retrieve children that
# are not aliases, for instance to list the namespace content, since
# the aliased modules are included in the constants of the class/module,
# that are listed separately.
def update_aliases
constants.each do |const|
next unless cm = const.is_alias_for
cm_alias = cm.dup
cm_alias.name = const.name
# 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
@store.modules_hash[cm_alias.full_name] = cm_alias
modules_hash[const.name] = cm_alias
else
@store.classes_hash[cm_alias.full_name] = cm_alias
classes_hash[const.name] = cm_alias
end
cm.aliases << cm_alias
end
end
##
# Deletes from #includes those whose module has been removed from the
# documentation.
#--
# FIXME: includes are not reliably removed, see _possible_bug test case
def update_includes
includes.reject! do |include|
mod = include.module
!(String === mod) && @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
def embed_mixins
return unless options.embed_mixins
includes.each do |include|
next if String === include.module
include.module.method_list.each do |code_object|
add_method(prepare_to_embed(code_object))
end
include.module.constants.each do |code_object|
add_constant(prepare_to_embed(code_object))
end
include.module.attributes.each do |code_object|
add_attribute(prepare_to_embed(code_object))
end
end
extends.each do |ext|
next if String === ext.module
ext.module.method_list.each do |code_object|
add_method(prepare_to_embed(code_object, true))
end
ext.module.attributes.each do |code_object|
add_attribute(prepare_to_embed(code_object, true))
end
end
end
private
def prepare_to_embed(code_object, singleton=false)
code_object = code_object.dup
code_object.mixin_from = code_object.parent
code_object.singleton = true if singleton
set_current_section(code_object.section.title, code_object.section.comment)
# add_method and add_attribute will reassign self's visibility back to the method/attribute
# so we need to sync self's visibility with the object's to properly retain that information
self.visibility = code_object.visibility
code_object
end
end

View File

@ -1,186 +0,0 @@
# frozen_string_literal: true
##
# A constant
class RDoc::Constant < RDoc::CodeObject
MARSHAL_VERSION = 0 # :nodoc:
##
# Sets the module or class this is constant is an alias for.
attr_writer :is_alias_for
##
# The constant's name
attr_accessor :name
##
# The constant's value
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
@value = value
@is_alias_for = nil
@visibility = :public
self.comment = comment
end
##
# Constants are ordered by name
def <=> other
return unless self.class === other
[parent_name, name] <=> [other.parent_name, other.name]
end
##
# Constants are equal when their #parent and #name is the same
def == other
self.class == other.class and
@parent == other.parent and
@name == other.name
end
##
# A constant is documented if it has a comment, or is an alias
# for a documented class or module.
def documented?
return true if super
return false unless @is_alias_for
case @is_alias_for
when String then
found = @store.find_class_or_module @is_alias_for
return false unless found
@is_alias_for = found
end
@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,
parent_name, @name,
]
end
##
# 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.relative_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] || :public
@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
"constant #{parent_name}::#@name -> #{is_alias_for}"
else
"constant #{parent_name}::#@name"
end
end
end

File diff suppressed because it is too large Load Diff

View File

@ -1,233 +0,0 @@
# frozen_string_literal: true
require 'cgi/util'
##
# 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
##
# Creates a new section with +title+ and +comment+
def initialize parent, title, comment
@parent = parent
@title = title ? title.strip : title
@comments = []
add_comment comment
end
##
# Sections are equal when they have the same #title
def == other
self.class === other and @title == other.title
end
alias eql? ==
##
# 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
def hash # :nodoc:
@title.hash
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
end

View File

@ -1,9 +0,0 @@
# frozen_string_literal: true
##
# A Module extension to a class with \#extend
#
# RDoc::Extend.new 'Enumerable', 'comment ...'
class RDoc::Extend < RDoc::Mixin
end

View File

@ -1,6 +0,0 @@
# frozen_string_literal: true
##
# GhostMethod represents a method referenced only by a comment
class RDoc::GhostMethod < RDoc::AnyMethod
end

View File

@ -1,9 +0,0 @@
# frozen_string_literal: true
##
# A Module included in a class with \#include
#
# RDoc::Include.new 'Enumerable', 'comment ...'
class RDoc::Include < RDoc::Mixin
end

View File

@ -1,6 +0,0 @@
# frozen_string_literal: true
##
# MetaMethod represents a meta-programmed method
class RDoc::MetaMethod < RDoc::AnyMethod
end

View File

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

View File

@ -1,120 +0,0 @@
# frozen_string_literal: true
##
# A Mixin adds features from a module into another context. RDoc::Include and
# RDoc::Extend are both mixins.
class RDoc::Mixin < RDoc::CodeObject
##
# Name of included module
attr_accessor :name
##
# Creates a new Mixin for +name+ with +comment+
def initialize(name, comment)
super()
@name = name
self.comment = comment
@module = nil # cache for module if found
end
##
# Mixins 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? == # :nodoc:
##
# 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.%s %s>" % [
self.class,
object_id,
parent_name, self.class.name.downcase, @name,
]
end
##
# Attempts to locate the included module object. Returns the name if not
# known.
#
# The scoping rules of Ruby to resolve the name of an included module are:
# - first look into the children of the current context;
# - if not found, look into the children of included modules,
# in reverse inclusion order;
# - if still not found, go up the hierarchy of names.
#
# 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
# 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.includes.take_while { |i| i != self }.reverse
searched.each do |i|
inc = i.module
next if String === inc
full_name = inc.child_name(@name)
@module = @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:
"#{self.class.name.downcase} #@name in: #{parent}"
end
end

View File

@ -1,92 +0,0 @@
# frozen_string_literal: true
##
# A normal class, neither singleton nor anonymous
class RDoc::NormalClass < RDoc::ClassModule
##
# The ancestors of this class including modules. Unlike Module#ancestors,
# this class is not included in the result. The result will contain both
# RDoc::ClassModules and Strings.
def ancestors
if String === superclass then
super << superclass
elsif superclass then
ancestors = super
ancestors << superclass
ancestors.concat superclass.ancestors
else
super
end
end
def aref_prefix # :nodoc:
'class'
end
##
# The definition of this class, <tt>class MyClassName</tt>
def definition
"class #{full_name}"
end
def direct_ancestors
superclass ? super + [superclass] : super
end
def inspect # :nodoc:
superclass = @superclass ? " < #{@superclass}" : nil
"<%s:0x%x class %s%s includes: %p extends: %p attributes: %p methods: %p aliases: %p>" % [
self.class, object_id,
full_name, superclass, @includes, @extends, @attributes, @method_list, @aliases
]
end
def to_s # :nodoc:
display = "#{self.class.name} #{self.full_name}"
if superclass
display += ' < ' + (superclass.is_a?(String) ? superclass : superclass.full_name)
end
display += ' -> ' + is_alias_for.to_s if is_alias_for
display
end
def pretty_print q # :nodoc:
superclass = @superclass ? " < #{@superclass}" : nil
q.group 2, "[class #{full_name}#{superclass}", "]" do
q.breakable
q.text "includes:"
q.breakable
q.seplist @includes do |inc| q.pp inc end
q.breakable
q.text "constants:"
q.breakable
q.seplist @constants do |const| q.pp const end
q.breakable
q.text "attributes:"
q.breakable
q.seplist @attributes do |attr| q.pp attr end
q.breakable
q.text "methods:"
q.breakable
q.seplist @method_list do |meth| q.pp meth end
q.breakable
q.text "aliases:"
q.breakable
q.seplist @aliases do |aliaz| q.pp aliaz end
q.breakable
q.text "comment:"
q.breakable
q.pp comment
end
end
end

View File

@ -1,73 +0,0 @@
# frozen_string_literal: true
##
# A normal module, like NormalClass
class RDoc::NormalModule < RDoc::ClassModule
def aref_prefix # :nodoc:
'module'
end
def inspect # :nodoc:
"#<%s:0x%x module %s includes: %p extends: %p attributes: %p methods: %p aliases: %p>" % [
self.class, object_id,
full_name, @includes, @extends, @attributes, @method_list, @aliases
]
end
##
# The definition of this module, <tt>module MyModuleName</tt>
def definition
"module #{full_name}"
end
##
# This is a module, returns true
def module?
true
end
def pretty_print q # :nodoc:
q.group 2, "[module #{full_name}:", "]" do
q.breakable
q.text "includes:"
q.breakable
q.seplist @includes do |inc| q.pp inc end
q.breakable
q.breakable
q.text "constants:"
q.breakable
q.seplist @constants do |const| q.pp const end
q.text "attributes:"
q.breakable
q.seplist @attributes do |attr| q.pp attr end
q.breakable
q.text "methods:"
q.breakable
q.seplist @method_list do |meth| q.pp meth end
q.breakable
q.text "aliases:"
q.breakable
q.seplist @aliases do |aliaz| q.pp aliaz end
q.breakable
q.text "comment:"
q.breakable
q.pp comment
end
end
##
# Modules don't have one, raises NoMethodError
def superclass
raise NoMethodError, "#{full_name} is a module"
end
end

View File

@ -1,51 +0,0 @@
# frozen_string_literal: true
##
# A file loaded by \#require
class RDoc::Require < RDoc::CodeObject
##
# Name of the required file
attr_accessor :name
##
# Creates a new Require that loads +name+ with +comment+
def initialize(name, comment)
super()
@name = name.gsub(/'|"/, "") #'
@top_level = nil
self.comment = comment
end
def inspect # :nodoc:
"#<%s:0x%x require '%s' in %s>" % [
self.class,
object_id,
@name,
parent_file_name,
]
end
def to_s # :nodoc:
"require #{name} in: #{parent}"
end
##
# The RDoc::TopLevel corresponding to this require, or +nil+ if not found.
def top_level
@top_level ||= begin
tl = RDoc::TopLevel.all_files_hash[name + '.rb']
if tl.nil? and RDoc::TopLevel.all_files.first.full_name =~ %r(^lib/) then
# second chance
tl = RDoc::TopLevel.all_files_hash['lib/' + name + '.rb']
end
tl
end
end
end

View File

@ -1,30 +0,0 @@
# frozen_string_literal: true
##
# A singleton class
class RDoc::SingleClass < RDoc::ClassModule
##
# Adds the superclass to the included modules.
def ancestors
superclass ? super + [superclass] : super
end
def aref_prefix # :nodoc:
'sclass'
end
##
# The definition of this singleton class, <tt>class << MyClassName</tt>
def definition
"class << #{full_name}"
end
def pretty_print q # :nodoc:
q.group 2, "[class << #{full_name}", "]" do
next
end
end
end

View File

@ -1,291 +0,0 @@
# frozen_string_literal: true
##
# A TopLevel context is a representation of the contents of a single file
class RDoc::TopLevel < RDoc::Context
MARSHAL_VERSION = 0 # :nodoc:
##
# This TopLevel's File::Stat struct
attr_accessor :file_stat
##
# Relative name of this file
attr_accessor :relative_name
##
# Absolute name of this file
attr_accessor :absolute_name
##
# All the classes or modules that were declared in
# this file. These are assigned to either +#classes_hash+
# or +#modules_hash+ once we know what they really are.
attr_reader :classes_or_modules
attr_accessor :diagram # :nodoc:
##
# The parser class that processed this file
attr_reader :parser
##
# Creates a new TopLevel for the file at +absolute_name+. If documentation
# is being generated outside the source dir +relative_name+ is relative to
# the source directory.
def initialize absolute_name, relative_name = absolute_name
super()
@name = nil
@absolute_name = absolute_name
@relative_name = relative_name
@file_stat = File.stat(absolute_name) rescue nil # HACK for testing
@diagram = nil
@parser = nil
@classes_or_modules = []
end
##
# Sets the parser for this toplevel context, also the store.
def parser=(val)
@parser = val
@store.update_parser_of_file(absolute_name, val) if @store
@parser
end
##
# An RDoc::TopLevel is equal to another with the same relative_name
def == other
self.class === other and @relative_name == other.relative_name
end
alias eql? ==
##
# Adds +an_alias+ to +Object+ instead of +self+.
def add_alias(an_alias)
object_class.record_location self
return an_alias unless @document_self
object_class.add_alias an_alias
end
##
# Adds +constant+ to +Object+ instead of +self+.
def add_constant constant
object_class.record_location self
return constant unless @document_self
object_class.add_constant constant
end
##
# Adds +include+ to +Object+ instead of +self+.
def add_include(include)
object_class.record_location self
return include unless @document_self
object_class.add_include include
end
##
# Adds +method+ to +Object+ instead of +self+.
def add_method(method)
object_class.record_location self
return method unless @document_self
object_class.add_method method
end
##
# Adds class or module +mod+. Used in the building phase
# by the Ruby parser.
def add_to_classes_or_modules mod
@classes_or_modules << mod
end
##
# Base name of this file
def base_name
File.basename @relative_name
end
alias name base_name
##
# Only a TopLevel that contains text file) will be displayed. See also
# RDoc::CodeObject#display?
def display?
text? and super
end
##
# See RDoc::TopLevel::find_class_or_module
#--
# TODO Why do we search through all classes/modules found, not just the
# ones of this instance?
def find_class_or_module name
@store.find_class_or_module name
end
##
# Finds a class or module named +symbol+
def find_local_symbol(symbol)
find_class_or_module(symbol) || super
end
##
# Finds a module or class with +name+
def find_module_named(name)
find_class_or_module(name)
end
##
# Returns the relative name of this file
def full_name
@relative_name
end
##
# An RDoc::TopLevel has the same hash as another with the same
# relative_name
def hash
@relative_name.hash
end
##
# URL for this with a +prefix+
def http_url(prefix)
path = [prefix, @relative_name.tr('.', '_')]
File.join(*path.compact) + '.html'
end
def inspect # :nodoc:
"#<%s:0x%x %p modules: %p classes: %p>" % [
self.class, object_id,
base_name,
@modules.map { |n, m| m },
@classes.map { |n, c| c }
]
end
##
# Time this file was last modified, if known
def last_modified
@file_stat ? file_stat.mtime : nil
end
##
# Dumps this TopLevel for use by ri. See also #marshal_load
def marshal_dump
[
MARSHAL_VERSION,
@relative_name,
@parser,
parse(@comment),
]
end
##
# Loads this TopLevel from +array+.
def marshal_load array # :nodoc:
initialize array[1]
@parser = array[2]
@comment = array[3]
@file_stat = nil
end
##
# Returns the NormalClass "Object", creating it if not found.
#
# Records +self+ as a location in "Object".
def object_class
@object_class ||= begin
oc = @store.find_class_named('Object') || add_class(RDoc::NormalClass, 'Object')
oc.record_location self
oc
end
end
##
# Base name of this file without the extension
def page_name
basename = File.basename @relative_name
basename =~ /\.(rb|rdoc|txt|md)$/i
$` || basename
end
##
# Path to this file for use with HTML generator output.
def path
http_url @store.rdoc.generator.file_dir
end
def pretty_print q # :nodoc:
q.group 2, "[#{self.class}: ", "]" do
q.text "base name: #{base_name.inspect}"
q.breakable
items = @modules.map { |n, m| m }
items.concat @modules.map { |n, c| c }
q.seplist items do |mod| q.pp mod end
end
end
##
# Search record used by RDoc::Generator::JsonIndex
def search_record
return unless @parser < RDoc::Parser::Text
[
page_name,
'',
page_name,
'',
path,
'',
snippet(@comment),
]
end
##
# Is this TopLevel from a text file instead of a source code file?
def text?
@parser and @parser.include? RDoc::Parser::Text
end
def to_s # :nodoc:
"file #{full_name}"
end
end

View File

@ -1,5 +0,0 @@
# frozen_string_literal: true
# This file was used to load all the RDoc::CodeObject subclasses at once. Now
# autoload handles this.
require_relative '../rdoc'

View File

@ -1,229 +0,0 @@
# frozen_string_literal: true
##
# 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::MarkupReference@Directive+for+Specifying+RDoc+Source+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
##
# Line where this Comment was written
attr_accessor :line
##
# For duck-typing when merging classes at load time
alias file location # :nodoc:
##
# The text for this comment
attr_reader :text
##
# Alias for text
alias to_s 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, language = nil
@location = location
@text = text.nil? ? nil : text.dup
@language = language
@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 /^(?<S> ((?!\n)\s)*+ (?# whitespaces except newline))
:?call-seq:
(?<B> \g<S>(?<N>\n|\z) (?# trailing spaces))?
(?<seq>
(\g<S>(?!\w)\S.*\g<N>)*
(?>
(?<H> \g<S>\w+ (?# ' # ARGF' in the example above))
.*\g<N>)?
(\g<S>\S.*\g<N> (?# other non-blank line))*+
(\g<B>+(\k<H>.*\g<N> (?# ARGF.to_a lines))++)*+
)
(?m:^\s*$|\z)
/x =~ @text
seq = $~[:seq]
all_start, all_stop = $~.offset(0)
@text.slice! all_start...all_stop
seq.gsub!(/^\s*/, '')
method.call_seq = seq
end
method
end
##
# A comment is empty if its text String is empty.
def empty?
@text.empty?
end
##
# HACK dubious
def encode! encoding
@text = String.new @text, encoding: encoding
self
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.relative_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 = RDoc::Encoding.change_encoding empty, @text.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.nil? ? nil : text.dup
end
##
# Returns true if this comment is in TomDoc format.
def tomdoc?
@format == 'tomdoc'
end
end

View File

@ -1,228 +0,0 @@
# frozen_string_literal: true
require_relative 'markup/attribute_manager' # for PROTECT_ATTR
##
# RDoc::CrossReference is a reusable way to create cross references for names.
class RDoc::CrossReference
##
# Regular expression to match class references
#
# 1. There can be a '\\' in front of text to suppress the cross-reference
# 2. There can be a '::' in front of class names to reference from the
# top-level namespace.
# 3. The method can be followed by parenthesis (not recommended)
CLASS_REGEXP_STR = '\\\\?((?:\:{2})?[A-Z]\w*(?:\:\:\w+)*)'
##
# Regular expression to match a single method argument.
METHOD_ARG_REGEXP_STR = '[\w.+*/=<>-]+'
##
# Regular expression to match method arguments.
METHOD_ARGS_REGEXP_STR = /(?:\((?:#{METHOD_ARG_REGEXP_STR}(?:,\s*#{METHOD_ARG_REGEXP_STR})*)?\))?/.source
##
# Regular expression to match method references.
#
# See CLASS_REGEXP_STR
METHOD_REGEXP_STR = /(
(?!\d)[\w#{RDoc::Markup::AttributeManager::PROTECT_ATTR}]+[!?=]?|
%|=(?:==?|~)|![=~]|\[\]=?|<(?:<|=>?)?|>[>=]?|[-+!]@?|\*\*?|[\/%\`|&^~]
)#{METHOD_ARGS_REGEXP_STR}/.source.delete("\n ").freeze
##
# Regular expressions matching text that should potentially have
# cross-reference links generated are passed to add_regexp_handling. Note
# that these expressions are meant to pick up text for which cross-references
# have been suppressed, since the suppression characters are removed by the
# code that is triggered.
CROSSREF_REGEXP = /(?:^|[\s()])
(
(?:
# A::B::C.meth
#{CLASS_REGEXP_STR}(?:[.#]|::)#{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)
# Stand-alone method (preceded by a #)
| \\?\##{METHOD_REGEXP_STR}
# Stand-alone method (preceded by ::)
| ::#{METHOD_REGEXP_STR}
# 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<]
)
# labels for headings
(?:@[\w+%-]+(?:\.[\w|%-]+)?)?
)/x
##
# Version of CROSSREF_REGEXP used when <tt>--hyperlink-all</tt> is specified.
ALL_CROSSREF_REGEXP = /
(?:^|[\s()])
(
(?:
# A::B::C.meth
#{CLASS_REGEXP_STR}(?:[.#]|::)#{METHOD_REGEXP_STR}
# A::B::C
| #{CLASS_REGEXP_STR}(?=[@\s).?!,;<\000]|\z)
# Stand-alone method
| \\?#{METHOD_REGEXP_STR}
# Things that look like filenames
| (?:\.\.\/)*[-\/\w]+[_\/.][-\w\/.]+
# 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
##
# Allows cross-references to be created based on the given +context+
# (RDoc::Context).
def initialize context
@context = context
@store = context.store
@seen = {}
end
##
# Returns a method reference to +name+.
def resolve_method name
ref = nil
if /#{CLASS_REGEXP_STR}([.#]|::)#{METHOD_REGEXP_STR}/o =~ name then
type = $2
if '.' == type # will find either #method or ::method
method = $3
else
method = "#{type}#{$3}"
end
container = @context.find_symbol_module($1)
elsif /^([.#]|::)#{METHOD_REGEXP_STR}/o =~ name then
type = $1
if '.' == type
method = $2
else
method = "#{type}#{$2}"
end
container = @context
else
type = nil
container = nil
end
if container then
unless RDoc::TopLevel === container then
if '.' == type then
if 'new' == method then # AnyClassName.new will be class method
ref = container.find_local_symbol method
ref = container.find_ancestor_local_symbol method unless ref
else
ref = container.find_local_symbol "::#{method}"
ref = container.find_ancestor_local_symbol "::#{method}" unless ref
ref = container.find_local_symbol "##{method}" unless ref
ref = container.find_ancestor_local_symbol "##{method}" unless ref
end
else
ref = container.find_local_symbol method
ref = container.find_ancestor_local_symbol method unless ref
end
end
end
ref
end
##
# Returns a reference to +name+.
#
# If the reference is found and +name+ is not documented +text+ will be
# returned. If +name+ is escaped +name+ is returned. If +name+ is not
# found +text+ is returned.
def resolve name, text
return @seen[name] if @seen.include? name
ref = case name
when /^\\(#{CLASS_REGEXP_STR})$/o then
@context.find_symbol $1
else
@context.find_symbol name
end
ref = resolve_method name unless ref
# 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
elsif name =~ /^\\/ then
# we remove the \ only in front of what we know:
# other backslashes are treated later, only outside of <tt>
ref ? $' : name
elsif ref then
if ref.display? then
ref
else
text
end
else
text
end
@seen[name] = out
out
end
end

View File

@ -1,120 +0,0 @@
# coding: US-ASCII
# frozen_string_literal: true
##
# This class is a wrapper around File IO and Encoding that helps RDoc load
# files and convert them to the correct encoding.
module RDoc::Encoding
HEADER_REGEXP = /^
(?:
\A\#!.*\n
|
^\#\s+frozen[-_]string[-_]literal[=:].+\n
|
^\#[^\n]+\b(?:en)?coding[=:]\s*(?<name>[^\s;]+).*\n
|
<\?xml[^?]*encoding=(?<quote>["'])(?<name>.*?)\k<quote>.*\n
)+
/xi # :nodoc:
##
# Reads the contents of +filename+ and handles any encoding directives in
# the file.
#
# The content will be converted to the +encoding+. If the file cannot be
# converted a warning will be printed and nil will be returned.
#
# If +force_transcode+ is true the document will be transcoded and any
# unknown character in the target encoding will be replaced with '?'
def self.read_file filename, encoding, force_transcode = false
content = File.open filename, "rb" do |f| f.read end
content.gsub!("\r\n", "\n") if RUBY_PLATFORM =~ /mswin|mingw/
utf8 = content.sub!(/\A\xef\xbb\xbf/, '')
enc = RDoc::Encoding.detect_encoding content
content = RDoc::Encoding.change_encoding content, enc if enc
begin
encoding ||= Encoding.default_external
orig_encoding = content.encoding
if not orig_encoding.ascii_compatible? then
content = content.encode encoding
elsif utf8 then
content = RDoc::Encoding.change_encoding content, Encoding::UTF_8
content = content.encode encoding
else
# assume the content is in our output encoding
content = RDoc::Encoding.change_encoding content, encoding
end
unless content.valid_encoding? then
# revert and try to transcode
content = RDoc::Encoding.change_encoding content, orig_encoding
content = content.encode encoding
end
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 = RDoc::Encoding.change_encoding content, orig_encoding
content = content.encode(encoding,
:invalid => :replace,
:undef => :replace,
:replace => '?')
return content
else
warn "unable to convert #{e.message} for #{filename}, skipping"
return nil
end
end
content
rescue ArgumentError => e
raise unless e.message =~ /unknown encoding name - (.*)/
warn "unknown encoding name \"#{$1}\" for #{filename}, skipping"
nil
rescue Errno::EISDIR, Errno::ENOENT
nil
end
##
# Detects the encoding of +string+ based on the magic comment
def self.detect_encoding string
result = HEADER_REGEXP.match string
name = result && result[:name]
name ? Encoding.find(name) : nil
end
##
# Removes magic comments and shebang
def self.remove_magic_comment string
string.sub HEADER_REGEXP do |s|
s.gsub(/[^\n]/, '')
end
end
##
# Changes encoding based on +encoding+ without converting and returns new
# string
def self.change_encoding text, encoding
if text.kind_of? RDoc::Comment
text.encode! encoding
else
String.new text, encoding: encoding
end
end
end

View File

@ -1,18 +0,0 @@
# frozen_string_literal: true
##
# 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

View File

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

View File

@ -1,51 +0,0 @@
# frozen_string_literal: true
##
# RDoc uses generators to turn parsed source code in the form of an
# RDoc::CodeObject tree into some form of output. RDoc comes with the HTML
# generator RDoc::Generator::Darkfish and an ri data generator
# RDoc::Generator::RI.
#
# == Registering a Generator
#
# Generators are registered by calling RDoc::RDoc.add_generator with the class
# of the generator:
#
# class My::Awesome::Generator
# RDoc::RDoc.add_generator self
# end
#
# == Adding Options to +rdoc+
#
# Before option processing in +rdoc+, RDoc::Options will call ::setup_options
# on the generator class with an RDoc::Options instance. The generator can
# use RDoc::Options#option_parser to add command-line options to the +rdoc+
# tool. See 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
#
# After parsing, RDoc::RDoc will instantiate a generator by calling
# #initialize with an RDoc::Store instance and an RDoc::Options instance.
#
# 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, "#{__dir__}/generator/markup"
autoload :Darkfish, "#{__dir__}/generator/darkfish"
autoload :JsonIndex, "#{__dir__}/generator/json_index"
autoload :RI, "#{__dir__}/generator/ri"
autoload :POT, "#{__dir__}/generator/pot"
end

View File

@ -1,828 +0,0 @@
# frozen_string_literal: true
# -*- mode: ruby; ruby-indent-level: 2; tab-width: 2 -*-
require 'erb'
require 'fileutils'
require 'pathname'
require_relative 'markup'
##
# Darkfish RDoc HTML Generator
#
# $Id: darkfish.rb 52 2009-01-07 02:08:11Z deveiant $
#
# == Author/s
# * Michael Granger (ged@FaerieMUD.org)
#
# == Contributors
# * Mahlon E. Smith (mahlon@martini.nu)
# * Eric Hodel (drbrain@segment7.net)
#
# == License
#
# Copyright (c) 2007, 2008, Michael Granger. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of the author/s, nor the names of the project's
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# 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
RDoc::RDoc.add_generator self
include ERB::Util
##
# Stylesheets, fonts, etc. that are included in RDoc.
BUILTIN_STYLE_ITEMS = # :nodoc:
%w[
css/fonts.css
fonts/Lato-Light.ttf
fonts/Lato-LightItalic.ttf
fonts/Lato-Regular.ttf
fonts/Lato-RegularItalic.ttf
fonts/SourceCodePro-Bold.ttf
fonts/SourceCodePro-Regular.ttf
css/rdoc.css
]
##
# Path to this file's parent directory. Used to find templates and other
# resources.
GENERATOR_DIR = File.join 'rdoc', 'generator'
##
# Release Version
VERSION = '3'
##
# Description of this generator
DESCRIPTION = 'HTML generator, written by Michael Granger'
##
# The relative path to style sheets and javascript. By default this is set
# the same as the rel_prefix.
attr_accessor :asset_rel_path
##
# The path to generate files into, combined with <tt>--op</tt> from the
# options for a full path.
attr_reader :base_dir
##
# 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 directory where the template files live
attr_reader :template_dir # :nodoc:
##
# 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
def debug_msg *msg
return unless $DEBUG_RDOC
$stderr.puts(*msg)
end
##
# Directory where generated class HTML files live relative to the output
# dir.
def class_dir
nil
end
##
# Directory where generated class HTML files live relative to the output
# dir.
def file_dir
nil
end
##
# Create the directories the generated docs will live in if they don't
# already exist.
def gen_sub_directories
@outputdir.mkpath
end
##
# Copy over the stylesheet into the appropriate place in the output
# directory.
def write_style_sheet
debug_msg "Copying static files"
options = { :verbose => $DEBUG_RDOC, :noop => @dry_run }
BUILTIN_STYLE_ITEMS.each do |item|
install_rdoc_static_file @template_dir + item, "./#{item}", options
end
unless @options.template_stylesheets.empty?
FileUtils.cp @options.template_stylesheets, '.', **options
end
Dir[(@template_dir + "{js,images}/**/*").to_s].each do |path|
next if File.directory? path
next if File.basename(path) =~ /^\./
dst = Pathname.new(path).relative_path_from @template_dir
install_rdoc_static_file @template_dir + path, dst, options
end
end
##
# Build the initial indices and output objects based on an array of TopLevel
# objects containing the extracted information.
def generate
setup
write_style_sheet
generate_index
generate_class_files
generate_file_files
generate_table_of_contents
@json_index.generate
@json_index.generate_gzipped
copy_static
rescue => e
debug_msg "%s: %s\n %s" % [
e.class.name, e.message, e.backtrace.join("\n ")
]
raise
end
##
# 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
classes.select do |klass|
klass.display?
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 = @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
asset_rel_prefix = rel_prefix + @asset_rel_path
@title = @options.title
render_template template_file, out_file do |io|
here = binding
# suppress 1.9.3 warning
here.local_variable_set(:asset_rel_prefix, asset_rel_prefix)
here
end
rescue => e
error = RDoc::Error.new \
"error generating index.html: #{e.message} (#{e.class})"
error.set_backtrace e.backtrace
raise error
end
##
# 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
asset_rel_prefix = rel_prefix + @asset_rel_path
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|
here = binding
# suppress 1.9.3 warning
here.local_variable_set(:asset_rel_prefix, asset_rel_prefix)
here.local_variable_set(:svninfo, svninfo)
here
end
end
##
# Generate a documentation file for each class and module
def generate_class_files
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}"
current = nil
@classes.each do |klass|
current = klass
generate_class klass, template_file
end
rescue => e
error = RDoc::Error.new \
"error generating #{current.path}: #{e.message} (#{e.class})"
error.set_backtrace e.backtrace
raise error
end
##
# Generate a documentation file for each file
def generate_file_files
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|
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
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
render_template template_file, out_file do |io|
here = binding
# suppress 1.9.3 warning
here.local_variable_set(:asset_rel_prefix, asset_rel_prefix)
here.local_variable_set(:current, current)
here
end
end
rescue => e
error =
RDoc::Error.new "error generating #{out_file}: #{e.message} (#{e.class})"
error.set_backtrace e.backtrace
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
current = file
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|
here = binding
# suppress 1.9.3 warning
here.local_variable_set(:current, current)
here.local_variable_set(:asset_rel_prefix, asset_rel_prefix)
here
end
end
##
# Generates the 404 page for the RDoc servlet
def generate_servlet_not_found message
setup
template_file = @template_dir + 'servlet_not_found.rhtml'
return unless template_file.exist?
debug_msg "Rendering the servlet 404 Not Found page..."
rel_prefix = rel_prefix = ''
search_index_rel_prefix = rel_prefix
search_index_rel_prefix += @asset_rel_path if @file_output
asset_rel_prefix = ''
@title = 'Not Found'
render_template template_file do |io|
here = binding
# suppress 1.9.3 warning
here.local_variable_set(:asset_rel_prefix, asset_rel_prefix)
here
end
rescue => e
error = RDoc::Error.new \
"error generating servlet_not_found: #{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 = '.'
asset_rel_prefix = rel_prefix
search_index_rel_prefix = asset_rel_prefix
search_index_rel_prefix += @asset_rel_path if @file_output
@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
asset_rel_prefix = rel_prefix + @asset_rel_path
@title = "Table of Contents - #{@options.title}"
render_template template_file, out_file do |io|
here = binding
# suppress 1.9.3 warning
here.local_variable_set(:asset_rel_prefix, asset_rel_prefix)
here
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
def install_rdoc_static_file source, destination, options # :nodoc:
return unless source.exist?
begin
FileUtils.mkdir_p File.dirname(destination), **options
begin
FileUtils.ln source, destination, **options
rescue Errno::EEXIST
FileUtils.rm destination
retry
end
rescue
FileUtils.cp source, destination, **options
end
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.flat_map { |m| m.method_list }.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.
def time_delta_string seconds
return 'less than a minute' if seconds < 60
return "#{seconds / 60} minute#{seconds / 60 == 1 ? '' : 's'}" if
seconds < 3000 # 50 minutes
return 'about one hour' if seconds < 5400 # 90 minutes
return "#{seconds / 3600} hours" if seconds < 64800 # 18 hours
return 'one day' if seconds < 86400 # 1 day
return 'about one day' if seconds < 172800 # 2 days
return "#{seconds / 86400} days" if seconds < 604800 # 1 week
return 'about one week' if seconds < 1209600 # 2 week
return "#{seconds / 604800} weeks" if seconds < 7257600 # 3 months
return "#{seconds / 2419200} months" if seconds < 31536000 # 1 year
return "#{seconds / 31536000} years"
end
# %q$Id: darkfish.rb 52 2009-01-07 02:08:11Z deveiant $"
SVNID_PATTERN = /
\$Id:\s
(\S+)\s # filename
(\d+)\s # rev
(\d{4}-\d{2}-\d{2})\s # Date (YYYY-MM-DD)
(\d{2}:\d{2}:\d{2}Z)\s # Time (HH:MM:SSZ)
(\w+)\s # committer
\$$
/x
##
# Try to extract Subversion information out of the first constant whose
# value looks like a subversion Id tag. If no matching constant is found,
# and empty hash is returned.
def get_svninfo klass
constants = klass.constants or return {}
constants.find { |c| c.value =~ SVNID_PATTERN } or return {}
filename, rev, date, time, committer = $~.captures
commitdate = Time.parse "#{date} #{time}"
return {
:filename => filename,
:rev => Integer(rev),
:commitdate => commitdate,
:commitdelta => time_delta_string(Time.now - commitdate),
:committer => committer,
}
end
##
# 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'
<<-TEMPLATE
<!DOCTYPE html>
<html>
<head>
#{head_file.read}
#{body}
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+.
#
# Both +template_file+ and +out_file+ should be Pathname-like objects.
#
# An io will be yielded which must be captured by binding in the caller.
def render_template template_file, out_file = nil # :yield: io
io_output = out_file && !@dry_run && @file_output
erb_klass = io_output ? RDoc::ERBIO : ERB
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
@context = yield io
template_result template, @context, template_file
end
else
@context = yield nil
output = template_result template, @context, template_file
debug_msg " would have written %d characters to %s" % [
output.length, out_file.expand_path
] if @dry_run
output
end
end
##
# Creates the result for +template+ with +context+. If an error is raised a
# Pathname +template_file+ will indicate the file where the error occurred.
def template_result template, context, template_file
template.filename = template_file.to_s
template.result context
rescue NoMethodError => e
raise RDoc::Error, "Error while evaluating %s: %s" % [
template_file.expand_path,
e.message,
], e.backtrace
end
##
# Retrieves a cache template for +file+, if present, or fills the cache.
def template_for file, page = true, klass = ERB
template = @template_cache[file]
return template if template
if page then
template = assemble_template file
erbout = 'io'
else
template = file.read
template = template.encode @options.encoding
file_var = File.basename(file).sub(/\..*/, '')
erbout = "_erbout_#{file_var}"
end
template = klass.new template, trim_mode: '-', eoutvar: erbout
@template_cache[file] = template
template
end
# Returns an excerpt of the content for usage in meta description tags
def excerpt(content)
text = case content
when RDoc::Comment
content.text
when RDoc::Markup::Document
# This case is for page files that are not markdown nor rdoc
# We convert them to markdown for now as it's easier to extract the text
formatter = RDoc::Markup::ToMarkdown.new
formatter.start_accepting
formatter.accept_document(content)
formatter.end_accepting
else
content
end
# Match from a capital letter to the first period, discarding any links, so
# that we don't end up matching badges in the README
first_paragraph_match = text.match(/[A-Z][^\.:\/]+\./)
return text[0...150].gsub(/\n/, " ").squeeze(" ") unless first_paragraph_match
extracted_text = first_paragraph_match[0]
second_paragraph = first_paragraph_match.post_match.match(/[A-Z][^\.:\/]+\./)
extracted_text << " " << second_paragraph[0] if second_paragraph
extracted_text[0...150].gsub(/\n/, " ").squeeze(" ")
end
def generate_ancestor_list(ancestors, klass)
return '' if ancestors.empty?
ancestor = ancestors.shift
content = +'<ul><li>'
if ancestor.is_a?(RDoc::NormalClass)
content << "<a href=\"#{klass.aref_to ancestor.path}\">#{ancestor.full_name}</a>"
else
content << ancestor.to_s
end
# Recursively call the method for the remaining ancestors
content << generate_ancestor_list(ancestors, klass)
content << '</li></ul>'
end
end

View File

@ -1,300 +0,0 @@
# frozen_string_literal: true
require 'json'
begin
require 'zlib'
rescue LoadError
end
##
# 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
io.write 'var search_data = '
JSON.dump data, io, 0
end
unless ENV['SOURCE_DATE_EPOCH'].nil?
index_file.utime index_file.atime, Time.at(ENV['SOURCE_DATE_EPOCH'].to_i).gmtime
end
Dir.chdir @template_dir do
Dir['**/*.js'].each do |source|
dest = File.join out_dir, source
FileUtils.install source, dest, :mode => 0644, :preserve => true, :verbose => $DEBUG_RDOC
end
end
end
##
# Compress the search_index.js file using gzip
def generate_gzipped
return if @options.dry_run or not defined?(Zlib)
debug_msg "Compressing generated JSON index"
out_dir = @base_dir + @options.op_dir
search_index_file = out_dir + SEARCH_INDEX_FILE
outfile = out_dir + "#{search_index_file}.gz"
debug_msg "Reading the JSON index file from %s" % search_index_file
search_index = search_index_file.read(mode: 'r:utf-8')
debug_msg "Writing gzipped search index to %s" % outfile
Zlib::GzipWriter.open(outfile) do |gz|
gz.mtime = File.mtime(search_index_file)
gz.orig_name = search_index_file.basename.to_s
gz.write search_index
gz.close
end
# GZip the rest of the js files
Dir.chdir @template_dir do
Dir['**/*.js'].each do |source|
dest = out_dir + source
outfile = out_dir + "#{dest}.gz"
debug_msg "Reading the original js file from %s" % dest
data = dest.read
debug_msg "Writing gzipped file to %s" % outfile
Zlib::GzipWriter.open(outfile) do |gz|
gz.mtime = File.mtime(dest)
gz.orig_name = dest.basename.to_s
gz.write data
gz.close
end
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.flat_map do |klass|
klass.method_list
end.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

View File

@ -1,159 +0,0 @@
# frozen_string_literal: true
##
# 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
##
# Generates a relative URL from this object's path to +target_path+
def aref_to(target_path)
RDoc::Markup::ToHtml.gen_relative_url path, target_path
end
##
# Generates a relative URL from +from_path+ to this object's path
def as_href(from_path)
RDoc::Markup::ToHtml.gen_relative_url from_path, path
end
##
# Handy wrapper for marking up this object's comment
def description
markup @comment
end
##
# Creates an RDoc::Markup::ToHtmlCrossref formatter
def formatter
return @formatter if defined? @formatter
options = @store.rdoc.options
this = RDoc::Context === self ? self : @parent
@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
# will replace the %s using sprintf on the +url+.
def cvs_url(url, full_path)
if /%s/ =~ url then
sprintf url, full_path
else
url + full_path
end
end
end
class RDoc::CodeObject
include RDoc::Generator::Markup
end
class RDoc::MethodAttr
##
# Prepend +src+ with line numbers. Relies on the first line of a source
# code listing having:
#
# # File xxxxx, line dddd
#
# 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')
first = $3.to_i - 1
last = first + src.count("\n")
size = last.to_s.length
line = first
src.gsub!(/^/) do
res = if line == first then
" " * (size + 1)
else
"<span class=\"line-num\">%2$*1$d</span> " % [size, line]
end
line += 1
res
end
end
##
# Turns the method's token stream into HTML.
#
# Prepends line numbers if +options.line_numbers+ is true.
def markup_code
return '' unless @token_stream
src = RDoc::TokenStream.to_html @token_stream
# dedent the source
indent = src.length
lines = src.lines.to_a
lines.shift if src =~ /\A.*#\ *File/i # remove '# File' comment
lines.each do |line|
if line =~ /^ *(?=\S)/
n = $~.end(0)
indent = n if n < indent
break if n == 0
end
end
src.gsub!(/^#{' ' * indent}/, '') if indent > 0
add_line_numbers(src) if options.line_numbers
src
end
end
class RDoc::ClassModule
##
# Handy wrapper for marking up this class or module's comment
def description
markup @comment_location
end
end
class RDoc::Context::Section
include RDoc::Generator::Markup
end
class RDoc::TopLevel
##
# Returns a URL for this source file on some web repository. Use the -W
# command line option to set.
def cvs_url
url = @store.rdoc.options.webcvs
if /%s/ =~ url then
url % @relative_name
else
url + @relative_name
end
end
end

View File

@ -1,99 +0,0 @@
# frozen_string_literal: true
##
# Generates a POT file.
#
# Here is a translator work flow with the generator.
#
# == Create .pot
#
# You create .pot file by pot formatter:
#
# % rdoc --format pot
#
# It generates doc/rdoc.pot.
#
# == Create .po
#
# You create .po file from doc/rdoc.pot. This operation is needed only
# the first time. This work flow assumes that you are a translator
# for Japanese.
#
# You create locale/ja/rdoc.po from doc/rdoc.pot. You can use msginit
# provided by GNU gettext or rmsginit provided by gettext gem. This
# work flow uses gettext gem because it is more portable than GNU
# gettext for Rubyists. Gettext gem is implemented by pure Ruby.
#
# % gem install gettext
# % mkdir -p locale/ja
# % rmsginit --input doc/rdoc.pot --output locale/ja/rdoc.po --locale ja
#
# Translate messages in .po
#
# You translate messages in .po by a PO file editor. po-mode.el exists
# for Emacs users. There are some GUI tools such as GTranslator.
# There are some Web services such as POEditor and Tansifex. You can
# edit by your favorite text editor because .po is a text file.
# Generate localized documentation
#
# You can generate localized documentation with locale/ja/rdoc.po:
#
# % rdoc --locale ja
#
# You can find documentation in Japanese in doc/. Yay!
#
# == Update translation
#
# You need to update translation when your application is added or
# modified messages.
#
# You can update .po by the following command lines:
#
# % rdoc --format pot
# % rmsgmerge --update locale/ja/rdoc.po doc/rdoc.pot
#
# You edit locale/ja/rdoc.po to translate new messages.
class RDoc::Generator::POT
RDoc::RDoc.add_generator self
##
# Description of this generator
DESCRIPTION = 'creates .pot file'
##
# Set up a new .pot generator
def initialize store, options #:not-new:
@options = options
@store = store
end
##
# Writes .pot to disk.
def generate
po = extract_messages
pot_path = 'rdoc.pot'
File.open(pot_path, "w") do |pot|
pot.print(po.to_s)
end
end
# :nodoc:
def class_dir
nil
end
private
def extract_messages
extractor = MessageExtractor.new(@store)
extractor.extract
end
require_relative 'pot/message_extractor'
require_relative 'pot/po'
require_relative 'pot/po_entry'
end

View File

@ -1,68 +0,0 @@
# frozen_string_literal: true
##
# Extracts message from RDoc::Store
class RDoc::Generator::POT::MessageExtractor
##
# Creates a message extractor for +store+.
def initialize store
@store = store
@po = RDoc::Generator::POT::PO.new
end
##
# Extracts messages from +store+, stores them into
# RDoc::Generator::POT::PO and returns it.
def extract
@store.all_classes_and_modules.each do |klass|
extract_from_klass(klass)
end
@po
end
private
def extract_from_klass klass
extract_text(klass.comment_location, klass.full_name)
klass.each_section do |section, constants, attributes|
extract_text(section.title, "#{klass.full_name}: section title")
section.comments.each do |comment|
extract_text(comment, "#{klass.full_name}: #{section.title}")
end
end
klass.each_constant do |constant|
extract_text(constant.comment, constant.full_name)
end
klass.each_attribute do |attribute|
extract_text(attribute.comment, attribute.full_name)
end
klass.each_method do |method|
extract_text(method.comment, method.full_name)
end
end
def extract_text text, comment, location = nil
return if text.nil?
options = {
:extracted_comment => comment,
:references => [location].compact,
}
i18n_text = RDoc::I18n::Text.new(text)
i18n_text.extract_messages do |part|
@po.add(entry(part[:paragraph], options))
end
end
def entry msgid, options
RDoc::Generator::POT::POEntry.new(msgid, options)
end
end

View File

@ -1,84 +0,0 @@
# frozen_string_literal: true
##
# Generates a PO format text
class RDoc::Generator::POT::PO
##
# Creates an object that represents PO format.
def initialize
@entries = {}
add_header
end
##
# Adds a PO entry to the PO.
def add entry
existing_entry = @entries[entry.msgid]
if existing_entry
entry = existing_entry.merge(entry)
end
@entries[entry.msgid] = entry
end
##
# Returns PO format text for the PO.
def to_s
po = ''
sort_entries.each do |entry|
po += "\n" unless po.empty?
po += entry.to_s
end
po
end
private
def add_header
add(header_entry)
end
def header_entry
comment = <<-COMMENT
SOME DESCRIPTIVE TITLE.
Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
This file is distributed under the same license as the PACKAGE package.
FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
COMMENT
content = <<-CONTENT
Project-Id-Version: PACKAGE VERSEION
Report-Msgid-Bugs-To:
PO-Revision-Date: YEAR-MO_DA HO:MI+ZONE
Last-Translator: FULL NAME <EMAIL@ADDRESS>
Language-Team: LANGUAGE <LL@li.org>
Language:
MIME-Version: 1.0
Content-Type: text/plain; charset=CHARSET
Content-Transfer-Encoding: 8bit
Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;
CONTENT
options = {
:msgstr => content,
:translator_comment => comment,
:flags => ['fuzzy'],
}
RDoc::Generator::POT::POEntry.new('', options)
end
def sort_entries
headers, messages = @entries.values.partition do |entry|
entry.msgid.empty?
end
# TODO: sort by location
sorted_messages = messages.sort_by do |entry|
entry.msgid
end
headers + sorted_messages
end
end

View File

@ -1,141 +0,0 @@
# frozen_string_literal: true
##
# A PO entry in PO
class RDoc::Generator::POT::POEntry
# The msgid content
attr_reader :msgid
# The msgstr content
attr_reader :msgstr
# The comment content created by translator (PO editor)
attr_reader :translator_comment
# The comment content extracted from source file
attr_reader :extracted_comment
# The locations where the PO entry is extracted
attr_reader :references
# The flags of the PO entry
attr_reader :flags
##
# Creates a PO entry for +msgid+. Other values can be specified by
# +options+.
def initialize msgid, options = {}
@msgid = msgid
@msgstr = options[:msgstr] || ""
@translator_comment = options[:translator_comment]
@extracted_comment = options[:extracted_comment]
@references = options[:references] || []
@flags = options[:flags] || []
end
##
# Returns the PO entry in PO format.
def to_s
entry = ''
entry += format_translator_comment
entry += format_extracted_comment
entry += format_references
entry += format_flags
entry += <<-ENTRY
msgid #{format_message(@msgid)}
msgstr #{format_message(@msgstr)}
ENTRY
end
##
# Merges the PO entry with +other_entry+.
def merge other_entry
options = {
:extracted_comment => merge_string(@extracted_comment,
other_entry.extracted_comment),
:translator_comment => merge_string(@translator_comment,
other_entry.translator_comment),
:references => merge_array(@references,
other_entry.references),
:flags => merge_array(@flags,
other_entry.flags),
}
self.class.new(@msgid, options)
end
private
def format_comment mark, comment
return '' unless comment
return '' if comment.empty?
formatted_comment = ''
comment.each_line do |line|
formatted_comment += "#{mark} #{line}"
end
formatted_comment += "\n" unless formatted_comment.end_with?("\n")
formatted_comment
end
def format_translator_comment
format_comment('#', @translator_comment)
end
def format_extracted_comment
format_comment('#.', @extracted_comment)
end
def format_references
return '' if @references.empty?
formatted_references = ''
@references.sort.each do |file, line|
formatted_references += "\#: #{file}:#{line}\n"
end
formatted_references
end
def format_flags
return '' if @flags.empty?
formatted_flags = flags.join(",")
"\#, #{formatted_flags}\n"
end
def format_message message
return "\"#{escape(message)}\"" unless message.include?("\n")
formatted_message = '""'
message.each_line do |line|
formatted_message += "\n"
formatted_message += "\"#{escape(line)}\""
end
formatted_message
end
def escape string
string.gsub(/["\\\t\n]/) do |special_character|
case special_character
when "\t"
"\\t"
when "\n"
"\\n"
else
"\\#{special_character}"
end
end
end
def merge_string string1, string2
[string1, string2].compact.join("\n")
end
def merge_array array1, array2
(array1 + array2).uniq
end
end

View File

@ -1,30 +0,0 @@
# frozen_string_literal: true
##
# Generates ri data files
class RDoc::Generator::RI
RDoc::RDoc.add_generator self
##
# Description of this generator
DESCRIPTION = 'creates ri data files'
##
# Set up a new ri generator
def initialize store, options #:not-new:
@options = options
@store = store
@store.path = '.'
end
##
# Writes the parsed data store to disk for use by ri.
def generate
@store.save
end
end

View File

@ -1,5 +0,0 @@
<footer id="validator-badges" role="contentinfo">
<p><a href="https://validator.w3.org/check/referer">Validate</a>
<p>Generated by <a href="https://ruby.github.io/rdoc/">RDoc</a> <%= RDoc::VERSION %>.
<p>Based on <a href="http://deveiate.org/projects/Darkfish-RDoc/">Darkfish</a> by <a href="http://deveiate.org">Michael Granger</a>.
</footer>

View File

@ -1,43 +0,0 @@
<meta charset="<%= @options.charset %>">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title><%= h @title %></title>
<%- if defined?(klass) -%>
<meta name="keywords" content="ruby,<%= h "#{klass.type},#{klass.full_name}" %>">
<%- if klass.comment.empty? -%>
<meta name="description" content="Documentation for the <%= h "#{klass.full_name} #{klass.type}" %>">
<%- else -%>
<meta name="description" content="<%= h "#{klass.type} #{klass.full_name}: #{excerpt(klass.comment)}" %>">
<%- end -%>
<%- elsif defined?(file) -%>
<meta name="keywords" content="ruby,documentation,<%= h file.page_name %>">
<meta name="description" content="<%= h "#{file.page_name}: #{excerpt(file.comment)}" %>">
<%- elsif @title -%>
<meta name="keywords" content="ruby,documentation,<%= h @title %>">
<%- if @options.main_page and
main_page = @files.find { |f| f.full_name == @options.main_page } then %>
<meta name="description" content="<%= h "#{@title}: #{excerpt(main_page.comment)}" %>">
<%- else -%>
<meta name="description" content="Documentation for <%= h @title %>">
<%- end -%>
<%- end -%>
<script type="text/javascript">
var rdoc_rel_prefix = "<%= h asset_rel_prefix %>/";
var index_rel_prefix = "<%= h rel_prefix %>/";
</script>
<script src="<%= h asset_rel_prefix %>/js/navigation.js" defer></script>
<script src="<%= h asset_rel_prefix %>/js/search.js" defer></script>
<script src="<%= h asset_rel_prefix %>/js/search_index.js" defer></script>
<script src="<%= h asset_rel_prefix %>/js/searcher.js" defer></script>
<script src="<%= h asset_rel_prefix %>/js/darkfish.js" defer></script>
<link href="<%= h asset_rel_prefix %>/css/fonts.css" rel="stylesheet">
<link href="<%= h asset_rel_prefix %>/css/rdoc.css" rel="stylesheet">
<%- @options.template_stylesheets.each do |stylesheet| -%>
<link href="<%= h asset_rel_prefix %>/<%= File.basename stylesheet %>" rel="stylesheet">
<%- end -%>

View File

@ -1,19 +0,0 @@
<%- if !svninfo.empty? then %>
<div id="file-svninfo-section" class="nav-section">
<h3>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>
</div>
<%- end -%>

View File

@ -1,34 +0,0 @@
<div id="classindex-section" class="nav-section">
<h3>Class and Module Index</h3>
<%-
all_classes = @classes.group_by do |klass|
klass.full_name[/\A[^:]++(?:::[^:]++(?=::))*+(?=::[^:]*+\z)/]
end.delete_if do |_, klasses|
!klasses.any?(&:display?)
end
link = proc do |index_klass, display = index_klass.display?|
if display
-%><code><a href="<%= rel_prefix %>/<%= index_klass.path %>"><%= index_klass.name %></a></code><%-
else
-%><code><%= index_klass.name %></code><%-
end
end
if top = all_classes[nil]
solo = top.one? {|klass| klass.display?}
traverse = proc do |klasses| -%>
<ul class="link-list">
<%- klasses.uniq!(&:full_name) -%>
<%- klasses.each do |index_klass| -%>
<%- if children = all_classes[index_klass.full_name] -%>
<li><details<% if solo; solo = false %> open<% end %>><summary><% link.call(index_klass) %></summary>
<%- traverse.call(children) -%>
</ul></details>
<%- elsif index_klass.display? -%>
<li><% link.call(index_klass, true) %>
<%- end -%>
<%- end -%>
<%- end -%>
<%- traverse.call(top) -%>
<%- end -%>
</div>

View File

@ -1,15 +0,0 @@
<%- unless klass.extends.empty? then %>
<div id="extends-section" class="nav-section">
<h3>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>
</div>
<%- end -%>

View File

@ -1,9 +0,0 @@
<div id="file-list-section" class="nav-section">
<h3>Defined In</h3>
<ul>
<%- klass.in_files.each do |tl| -%>
<li><%= h tl.relative_name %>
<%- end -%>
</ul>
</div>

View File

@ -1,15 +0,0 @@
<%- unless klass.includes.empty? then %>
<div id="includes-section" class="nav-section">
<h3>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>
</div>
<%- end -%>

View File

@ -1,15 +0,0 @@
<div id="home-section" class="nav-section">
<h3>Documentation</h3>
<ul>
<%- installed.each do |name, href, exists, type, _| -%>
<%- next if type == :extra -%>
<li class="folder">
<%- if exists then -%>
<a href="<%= href %>"><%= h name %></a>
<%- else -%>
<%= h name %>
<%- end -%>
<%- end -%>
</ul>
</div>

View File

@ -1,21 +0,0 @@
<% if (class_methods = klass.class_method_list.sort).any? %>
<div class="nav-section">
<h3>Class Methods</h3>
<ul class="link-list" role="directory">
<%- class_methods.each do |meth| -%>
<li <%- if meth.calls_super %>class="calls-super" <%- end %>><a href="#<%= meth.aref %>"><%= h meth.name -%></a></li>
<%- end -%>
</ul>
</div>
<% end %>
<% if (instance_methods = klass.instance_methods.sort).any? %>
<div class="nav-section">
<h3>Instance Methods</h3>
<ul class="link-list" role="directory">
<%- instance_methods.each do |meth| -%>
<li <%- if meth.calls_super %>class="calls-super" <%- end %>><a href="#<%= meth.aref %>"><%= h meth.name -%></a></li>
<%- end -%>
</ul>
</div>
<% end %>

View File

@ -1,11 +0,0 @@
<div id="home-section" role="region" title="Quick navigation" class="nav-section">
<h2>
<a href="<%= rel_prefix %>/index.html" rel="home">Home</a>
</h2>
<div id="table-of-contents-navigation">
<a href="<%= rel_prefix %>/table_of_contents.html#pages">Pages</a>
<a href="<%= rel_prefix %>/table_of_contents.html#classes">Classes</a>
<a href="<%= rel_prefix %>/table_of_contents.html#methods">Methods</a>
</div>
</div>

View File

@ -1,32 +0,0 @@
<%- simple_files = @files.select { |f| f.text? } %>
<%- if defined?(current) -%>
<%- dir = current.full_name[%r{\A[^/]+(?=/)}] || current.page_name -%>
<%- end -%>
<%- unless simple_files.empty? then -%>
<div id="fileindex-section" class="nav-section">
<h3>Pages</h3>
<ul class="link-list">
<%- simple_files.group_by do |f| -%>
<%- f.full_name[%r{\A[^/]+(?=/)}] || f.page_name -%>
<%- end.each do |n, files| -%>
<%- f = files.shift -%>
<%- if files.empty? -%>
<li><a href="<%= rel_prefix %>/<%= h f.path %>"><%= h f.page_name %></a>
<%- next -%>
<%- end -%>
<li><details<% if dir == n %> open<% end %>><summary><%
if n == f.page_name
%><a href="<%= rel_prefix %>/<%= h f.path %>"><%= h n %></a><%
else
%><%= h n %><% files.unshift(f)
end %></summary>
<ul class="link-list">
<%- files.each do |f| -%>
<li><a href="<%= rel_prefix %>/<%= h f.path %>"><%= h f.page_name %></a>
<%- end -%>
</ul></details>
<%- end -%>
</ul>
</div>
<%- end -%>

View File

@ -1,6 +0,0 @@
<%- if klass.type == 'class' && (ancestors = klass.super_classes).any? -%>
<div id="parent-class-section" class="nav-section">
<h3>Ancestors</h3>
<%= generate_ancestor_list(ancestors, klass) %>
</div>
<%- end -%>

View File

@ -1,14 +0,0 @@
<div id="search-section" role="search" class="project-section initially-hidden">
<form action="#" method="get" accept-charset="utf-8">
<div id="search-field-wrapper">
<input id="search-field" role="combobox" aria-label="Search"
aria-autocomplete="list" aria-controls="search-results"
type="text" name="search" placeholder="Search (/) for a class, method, ..." spellcheck="false"
title="Type to search, Up and Down to navigate, Enter to load">
</div>
<ul id="search-results" aria-label="Search Results"
aria-busy="false" aria-expanded="false"
aria-atomic="false" class="initially-hidden"></ul>
</form>
</div>

View File

@ -1,11 +0,0 @@
<%- unless klass.sections.length == 1 then %>
<div id="sections-section" class="nav-section">
<h3>Sections</h3>
<ul class="link-list" role="directory">
<%- klass.sort_sections.each do |section| -%>
<li><a href="#<%= section.aref %>"><%= h section.title %></a></li>
<%- end -%>
</ul>
</div>
<%- end -%>

View File

@ -1,39 +0,0 @@
<%- comment = if current.respond_to? :comment_location then
current.comment_location
else
current.comment
end
table = current.parse(comment).table_of_contents.dup
if table.length > 1 then %>
<div class="nav-section">
<h3>Table of Contents</h3>
<%- display_link = proc do |heading| -%>
<a href="#<%= heading.label current %>"><%= heading.plain_html %></a>
<%- end -%>
<%- list_siblings = proc do -%>
<%- level = table.first&.level -%>
<%- while table.first && table.first.level >= level -%>
<%- heading = table.shift -%>
<%- if table.first.nil? || table.first.level <= heading.level -%>
<li><% display_link.call heading -%>
<%- else -%>
<li>
<details open>
<summary><%- display_link.call heading -%></summary>
<ul class="link-list" role="directory">
<% list_siblings.call %>
</ul>
</details>
</li>
<%- end -%>
<%- end -%>
<%- end -%>
<ul class="link-list" role="directory">
<% list_siblings.call %>
</ul>
</div>
<%- end -%>

View File

@ -1,3 +0,0 @@
<div id="navigation-toggle" role="button" tabindex="0" aria-label="Toggle sidebar" aria-expanded="true" aria-controls="navigation">
<span aria-hidden="true">&#9776;</span>
</div>

View File

@ -1,206 +0,0 @@
<body id="top" role="document" class="<%= klass.type %>">
<%= render '_sidebar_toggle.rhtml' %>
<nav id="navigation" role="navigation">
<div id="project-navigation">
<%= render '_sidebar_navigation.rhtml' %>
<%= render '_sidebar_search.rhtml' %>
</div>
<%= render '_sidebar_table_of_contents.rhtml' %>
<%= render '_sidebar_sections.rhtml' %>
<%= render '_sidebar_parent.rhtml' %>
<%= render '_sidebar_includes.rhtml' %>
<%= render '_sidebar_extends.rhtml' %>
<%= render '_sidebar_methods.rhtml' %>
<%= render '_footer.rhtml' %>
</nav>
<main role="main" aria-labelledby="<%=h klass.aref %>">
<h1 id="<%=h klass.aref %>" class="anchor-link <%= klass.type %>">
<%= klass.type %> <%= klass.full_name %>
</h1>
<section class="description">
<%= klass.description %>
</section>
<%- klass.each_section do |section, constants, attributes| -%>
<section id="<%= section.aref %>" class="documentation-section anchor-link">
<%- if section.title then -%>
<header class="documentation-section-title">
<h2>
<%= section.title %>
</h2>
<span class="section-click-top">
<a href="#top">&uarr; top</a>
</span>
</header>
<%- end -%>
<%- if section.comment then -%>
<div>
<%= section.description %>
</div>
<%- end -%>
<%- unless constants.empty? then -%>
<section class="constants-list">
<header>
<h3>Constants</h3>
</header>
<dl>
<%- constants.each do |const| -%>
<dt id="<%= const.name %>"><%= const.name %>
<%- if const.comment then -%>
<dd>
<%- if const.mixin_from then -%>
<div class="mixin-from">
Included from <a href="<%= klass.aref_to(const.mixin_from.path)%>"><%= const.mixin_from.full_name %></a>
</div>
<%- end -%>
<%= const.description.strip %>
<%- else -%>
<dd class="missing-docs">(Not documented)
<%- end -%>
<%- end -%>
</dl>
</section>
<%- end -%>
<%- unless attributes.empty? then -%>
<section class="attribute-method-details" class="method-section">
<header>
<h3>Attributes</h3>
</header>
<%- attributes.each do |attrib| -%>
<div id="<%= attrib.aref %>" class="method-detail anchor-link">
<div class="method-heading attribute-method-heading">
<a href="#<%= attrib.aref %>" title="Link to this attribute">
<span class="method-name"><%= h attrib.name %></span>
<span class="attribute-access-type">[<%= attrib.rw %>]</span>
</a>
</div>
<div class="method-description">
<%- if attrib.mixin_from then -%>
<div class="mixin-from">
<%= attrib.singleton ? "Extended" : "Included" %> from <a href="<%= klass.aref_to(attrib.mixin_from.path)%>"><%= attrib.mixin_from.full_name %></a>
</div>
<%- end -%>
<%- if attrib.comment then -%>
<%= attrib.description.strip %>
<%- else -%>
<p class="missing-docs">(Not documented)
<%- end -%>
</div>
</div>
<%- end -%>
</section>
<%- end -%>
<%- 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 anchor-link">
<header>
<h3><%= visibility.to_s.capitalize %> <%= type.capitalize %> Methods</h3>
</header>
<%- methods.each do |method| -%>
<div id="<%= method.aref %>" class="method-detail anchor-link <%= method.is_alias_for ? "method-alias" : '' %>">
<div class="method-header">
<%- if (call_seq = method.call_seq) then -%>
<%- call_seq.strip.split("\n").each_with_index do |call_seq, i| -%>
<div class="method-heading">
<a href="#<%= method.aref %>" title="Link to this method">
<span class="method-callseq">
<%= h(call_seq.strip.
gsub( /^\w+\./m, '')).
gsub(/(.*)[-=]&gt;/, '\1&rarr;') %>
</span>
</a>
</div>
<%- end -%>
<%- elsif method.has_call_seq? then -%>
<div class="method-heading">
<a href="#<%= method.aref %>" title="Link to this method">
<span class="method-name"><%= h method.name %></span>
</a>
</div>
<%- else -%>
<div class="method-heading">
<a href="#<%= method.aref %>" title="Link to this method">
<span class="method-name"><%= h method.name %></span>
<span class="method-args"><%= h method.param_seq %></span>
</a>
</div>
<%- end -%>
</div>
<%- if method.token_stream -%>
<div class="method-controls">
<details class="method-source-toggle">
<summary>Source</summary>
</details>
</div>
<%- end -%>
<%- unless method.skip_description? then -%>
<div class="method-description">
<%- if method.token_stream then -%>
<div class="method-source-code" id="<%= method.html_name %>-source">
<pre><%= method.markup_code %></pre>
</div>
<%- end -%>
<%- if method.mixin_from then -%>
<div class="mixin-from">
<%= method.singleton ? "Extended" : "Included" %> from <a href="<%= klass.aref_to(method.mixin_from.path)%>"><%= method.mixin_from.full_name %></a>
</div>
<%- end -%>
<%- 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 -%>
</div>
<%- end -%>
<%- 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>
<%- end -%>
</section>
<%- end
end %>
</section>
<%- end -%>
</main>

View File

@ -1,167 +0,0 @@
/*
* Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/),
* with Reserved Font Name "Source". All Rights Reserved. Source is a
* trademark of Adobe Systems Incorporated in the United States and/or other
* countries.
*
* This Font Software is licensed under the SIL Open Font License, Version
* 1.1.
*
* This license is copied below, and is also available with a FAQ at:
* http://scripts.sil.org/OFL
*/
@font-face {
font-family: "Source Code Pro";
font-style: normal;
font-weight: 400;
src: local("Source Code Pro"),
local("SourceCodePro-Regular"),
url("../fonts/SourceCodePro-Regular.ttf") format("truetype");
}
@font-face {
font-family: "Source Code Pro";
font-style: normal;
font-weight: 700;
src: local("Source Code Pro Bold"),
local("SourceCodePro-Bold"),
url("../fonts/SourceCodePro-Bold.ttf") format("truetype");
}
/*
* Copyright (c) 2010, Łukasz Dziedzic (dziedzic@typoland.com),
* with Reserved Font Name Lato.
*
* This Font Software is licensed under the SIL Open Font License, Version
* 1.1.
*
* This license is copied below, and is also available with a FAQ at:
* http://scripts.sil.org/OFL
*/
@font-face {
font-family: "Lato";
font-style: normal;
font-weight: 300;
src: local("Lato Light"),
local("Lato-Light"),
url("../fonts/Lato-Light.ttf") format("truetype");
}
@font-face {
font-family: "Lato";
font-style: italic;
font-weight: 300;
src: local("Lato Light Italic"),
local("Lato-LightItalic"),
url("../fonts/Lato-LightItalic.ttf") format("truetype");
}
@font-face {
font-family: "Lato";
font-style: normal;
font-weight: 700;
src: local("Lato Regular"),
local("Lato-Regular"),
url("../fonts/Lato-Regular.ttf") format("truetype");
}
@font-face {
font-family: "Lato";
font-style: italic;
font-weight: 700;
src: local("Lato Italic"),
local("Lato-Italic"),
url("../fonts/Lato-RegularItalic.ttf") format("truetype");
}
/*
* -----------------------------------------------------------
* SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
* -----------------------------------------------------------
*
* PREAMBLE
* The goals of the Open Font License (OFL) are to stimulate worldwide
* development of collaborative font projects, to support the font creation
* efforts of academic and linguistic communities, and to provide a free and
* open framework in which fonts may be shared and improved in partnership
* with others.
*
* The OFL allows the licensed fonts to be used, studied, modified and
* redistributed freely as long as they are not sold by themselves. The
* fonts, including any derivative works, can be bundled, embedded,
* redistributed and/or sold with any software provided that any reserved
* names are not used by derivative works. The fonts and derivatives,
* however, cannot be released under any other type of license. The
* requirement for fonts to remain under this license does not apply
* to any document created using the fonts or their derivatives.
*
* DEFINITIONS
* "Font Software" refers to the set of files released by the Copyright
* Holder(s) under this license and clearly marked as such. This may
* include source files, build scripts and documentation.
*
* "Reserved Font Name" refers to any names specified as such after the
* copyright statement(s).
*
* "Original Version" refers to the collection of Font Software components as
* distributed by the Copyright Holder(s).
*
* "Modified Version" refers to any derivative made by adding to, deleting,
* or substituting -- in part or in whole -- any of the components of the
* Original Version, by changing formats or by porting the Font Software to a
* new environment.
*
* "Author" refers to any designer, engineer, programmer, technical
* writer or other person who contributed to the Font Software.
*
* PERMISSION & CONDITIONS
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of the Font Software, to use, study, copy, merge, embed, modify,
* redistribute, and sell modified and unmodified copies of the Font
* Software, subject to the following conditions:
*
* 1) Neither the Font Software nor any of its individual components,
* in Original or Modified Versions, may be sold by itself.
*
* 2) Original or Modified Versions of the Font Software may be bundled,
* redistributed and/or sold with any software, provided that each copy
* contains the above copyright notice and this license. These can be
* included either as stand-alone text files, human-readable headers or
* in the appropriate machine-readable metadata fields within text or
* binary files as long as those fields can be easily viewed by the user.
*
* 3) No Modified Version of the Font Software may use the Reserved Font
* Name(s) unless explicit written permission is granted by the corresponding
* Copyright Holder. This restriction only applies to the primary font name as
* presented to the users.
*
* 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
* Software shall not be used to promote, endorse or advertise any
* Modified Version, except to acknowledge the contribution(s) of the
* Copyright Holder(s) and the Author(s) or with their explicit written
* permission.
*
* 5) The Font Software, modified or unmodified, in part or in whole,
* must be distributed entirely under this license, and must not be
* distributed under any other license. The requirement for fonts to
* remain under this license does not apply to any document created
* using the Font Software.
*
* TERMINATION
* This license becomes null and void if any of the above conditions are
* not met.
*
* DISCLAIMER
* THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
* OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
* DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
* OTHER DEALINGS IN THE FONT SOFTWARE.
*/

View File

@ -1,668 +0,0 @@
/*
* "Darkfish" RDoc CSS
* $Id: rdoc.css 54 2009-01-27 01:09:48Z deveiant $
*
* Author: Michael Granger <ged@FaerieMUD.org>
*
*/
/* vim: ft=css et sw=2 ts=2 sts=2 */
/* 1. Variables and Root Styles */
:root {
--sidebar-width: 300px;
--highlight-color: #cc342d; /* Reddish color for accents and headings */
--secondary-highlight-color: #c83045; /* Darker reddish color for secondary highlights */
--text-color: #505050; /* Dark bluish-grey for text */
--background-color: #fefefe; /* Near white background */
--code-block-background-color: #f6f6f3; /* Slightly darker grey for code blocks */
--link-color: #42405F; /* Dark bluish-grey for links */
--link-hover-color: var(--highlight-color); /* Reddish color on hover */
--border-color: #e0e0e0;; /* General border color */
--source-code-toggle-color: var(--secondary-highlight-color);
--scrollbar-thumb-hover-background: #505050; /* Hover color for scrollbar thumb */
--table-header-background-color: #eceaed;
--table-td-background-color: #f5f4f6;
/* Font family variables */
--font-primary: 'Segoe UI', 'Verdana', 'Arial', sans-serif;
--font-heading: 'Helvetica', 'Arial', sans-serif;
--font-code: monospace;
}
/* 2. Global Styles */
body {
background: var(--background-color);
font-family: var(--font-primary);
font-weight: 400;
color: var(--text-color);
line-height: 1.6;
/* Layout */
display: flex;
flex-direction: column;
min-height: 100vh;
margin: 0;
}
/* 3. Typography */
h1 span,
h2 span,
h3 span,
h4 span,
h5 span,
h6 span {
position: relative;
display: none;
padding-left: 1em;
line-height: 0;
vertical-align: baseline;
font-size: 10px;
}
h1 span { top: -1.3em; }
h2 span { top: -1.2em; }
h3 span { top: -1.0em; }
h4 span { top: -0.8em; }
h5 span { top: -0.5em; }
h6 span { top: -0.5em; }
h1:hover span,
h2:hover span,
h3:hover span,
h4:hover span,
h5:hover span,
h6:hover span {
display: inline;
}
h1:target,
h2:target,
h3:target,
h4:target,
h5:target,
h6:target {
margin-left: -10px;
border-left: 10px solid var(--border-color);
scroll-margin-top: 1rem;
}
main .anchor-link:target {
scroll-margin-top: 1rem;
}
/* 4. Links */
a {
color: var(--link-color);
transition: color 0.3s ease;
}
a:hover {
color: var(--link-hover-color);
}
a code:hover {
color: var(--link-hover-color);
}
/* 5. Code and Pre */
code,
pre {
font-family: var(--font-code);
background-color: var(--code-block-background-color);
border: 1px solid var(--border-color);
border-radius: 6px;
padding: 16px;
overflow-x: auto;
font-size: 15px;
line-height: 1.5;
margin: 1em 0;
}
code {
background-color: var(--code-block-background-color);
padding: 0.1em 0.3em;
border-radius: 3px;
font-size: 85%;
}
/* Tables */
table {
margin: 0;
border-spacing: 0;
border-collapse: collapse;
}
table tr th, table tr td {
padding: 0.2em 0.4em;
border: 1px solid var(--border-color);
}
table tr th {
background-color: var(--table-header-background-color);
}
table tr:nth-child(even) td {
background-color: var(--table-td-background-color);
}
/* 7. Navigation and Sidebar */
nav {
font-family: var(--font-heading);
font-size: 16px;
border-right: 1px solid var(--border-color);
position: fixed;
top: 0;
bottom: 0;
left: 0;
width: var(--sidebar-width);
background: var(--background-color); /* It needs an explicit background for toggling narrow screens */
overflow-y: auto;
z-index: 10;
display: flex;
flex-direction: column;
color: var(--text-color);
}
nav[hidden] {
display: none;
}
nav footer {
padding: 1em;
border-top: 1px solid var(--border-color);
}
nav footer a {
color: var(--secondary-highlight-color);
}
nav .nav-section {
margin-top: 1em;
padding: 0 1em;
}
nav h2, nav h3 {
margin: 0 0 0.5em;
padding: 0.5em 0;
color: var(--highlight-color);
border-bottom: 1px solid var(--border-color);
}
nav h2 {
font-size: 1.2em;
}
nav h3,
#table-of-contents-navigation {
font-size: 1em;
}
nav ul,
nav dl,
nav p {
padding: 0;
list-style: none;
margin: 0.5em 0;
}
nav ul li {
margin-bottom: 0.3em;
}
nav ul ul {
padding-left: 1em;
}
nav ul ul ul {
padding-left: 1em;
}
nav ul ul ul ul {
padding-left: 1em;
}
nav a {
color: var(--link-color);
text-decoration: none;
}
nav a:hover {
color: var(--link-hover-color);
text-decoration: underline;
}
#navigation-toggle {
z-index: 1000;
font-size: 2em;
display: block;
position: fixed;
top: 10px;
left: 20px;
cursor: pointer;
}
#navigation-toggle[aria-expanded="true"] {
top: 10px;
left: 250px;
}
nav ul li details {
position: relative;
padding-right: 1.5em; /* Add space for the marker on the right */
}
nav ul li details > summary {
list-style: none; /* Remove the default marker */
position: relative; /* So that the open/close triangle can position itself absolutely inside */
}
nav ul li details > summary::-webkit-details-marker {
display: none; /* Removes the default marker, in Safari 18. */
}
nav ul li details > summary::after {
content: '▶'; /* Unicode right-pointing triangle */
position: absolute;
font-size: 0.8em;
bottom: 0.1em;
margin-left: 0.3em;
transition: transform 0.2s ease;
}
nav ul li details[open] > summary::after {
transform: rotate(90deg); /* Rotate the triangle when open */
}
/* 8. Main Content */
main {
flex: 1;
display: block;
margin: 3em auto;
padding: 0 2em;
max-width: 800px;
font-size: 16px;
line-height: 1.6;
color: var(--text-color);
box-sizing: border-box;
}
@media (min-width: 1024px) {
main {
margin-left: var(--sidebar-width);
}
.table-of-contents main {
margin-left: 20em;
}
#navigation-toggle {
display: none;
}
}
main h1[class] {
margin-top: 0;
margin-bottom: 1em;
font-size: 2.5em;
color: var(--highlight-color);
}
main h1,
main h2,
main h3,
main h4,
main h5,
main h6 {
font-family: var(--font-heading);
color: var(--highlight-color);
}
/* Search */
#search-section {
padding: 1em;
background-color: var(--background-color);
border-bottom: 1px solid var(--border-color);
}
#search-field-wrapper {
position: relative;
display: flex;
align-items: center;
}
#search-field {
width: 100%;
padding: 0.5em 1em 0.5em 2.5em;
border: 1px solid var(--border-color);
border-radius: 20px;
font-size: 14px;
outline: none;
transition: border-color 0.3s ease;
color: var(--text-color);
}
#search-field:focus {
border-color: var(--highlight-color);
}
#search-field::placeholder {
color: var(--text-color);
}
#search-field-wrapper::before {
content: "\1F50D";
position: absolute;
left: 0.75em;
top: 50%;
transform: translateY(-50%);
font-size: 14px;
color: var(--text-color);
opacity: 0.6;
}
/* Search Results */
#search-results {
font-family: var(--font-primary);
font-weight: 300;
}
#search-results .search-match {
font-family: var(--font-heading);
font-weight: normal;
}
#search-results .search-selected {
background: var(--code-block-background-color);
border-bottom: 1px solid transparent;
}
#search-results li {
list-style: none;
border-bottom: 1px solid var(--border-color);
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-color: rgba(224, 108, 117, 0.1);
font-style: normal;
}
#search-results pre {
margin: 0.5em;
font-family: var(--font-code);
}
/* Syntax Highlighting - Gruvbox Light Scheme */
.ruby-constant { color: #AF3A03; } /* Dark Orange */
.ruby-keyword { color: #9D0006; } /* Dark Red */
.ruby-ivar { color: #B57614; } /* Brown */
.ruby-operator { color: #427B58; } /* Dark Teal */
.ruby-identifier { color: #076678; } /* Deep Teal */
.ruby-node { color: #8F3F71; } /* Plum */
.ruby-comment { color: #928374; font-style: italic; } /* Gray */
.ruby-regexp { color: #8F3F71; } /* Plum */
.ruby-value { color: #AF3A03; } /* Dark Orange */
.ruby-string { color: #79740E; } /* Olive */
/* Emphasis */
em {
text-decoration-color: rgba(52, 48, 64, 0.25);
text-decoration-line: underline;
text-decoration-style: dotted;
}
strong,
em {
color: var(--highlight-color);
background-color: rgba(255, 111, 97, 0.1); /* Light red background for emphasis */
}
/* Paragraphs */
main p {
line-height: 1.5em;
font-weight: 400;
}
/* Preformatted Text */
main pre {
margin: 1.2em 0.5em;
padding: 1em;
font-size: 0.8em;
}
/* Horizontal Rules */
main hr {
margin: 1.5em 1em;
border: 2px solid var(--border-color);
}
/* Blockquotes */
main blockquote {
margin: 0 2em 1.2em 1.2em;
padding-left: 0.5em;
border-left: 2px solid var(--border-color);
}
/* Lists */
main li > p {
margin: 0.5em;
}
/* Definition Lists */
main dl {
margin: 1em 0.5em;
}
main dt {
line-height: 1.5; /* matches `main p` */
font-weight: bold;
}
main dl.note-list dt {
margin-right: 1em;
float: left;
}
main dl.note-list dt:has(+ dt) {
margin-right: 0.25em;
}
main dl.note-list dt:has(+ dt)::after {
content: ', ';
font-weight: normal;
}
main dd {
margin: 0 0 1em 1em;
}
main dd p:first-child {
margin-top: 0;
}
/* Headers within Main */
main header h2 {
margin-top: 2em;
border-width: 0;
border-top: 4px solid var(--border-color);
font-size: 130%;
}
main header h3 {
margin: 2em 0 1.5em;
border-width: 0;
border-top: 3px solid var(--border-color);
font-size: 120%;
}
/* Utility Classes */
.hide { display: none !important; }
.initially-hidden { display: none; }
/* Table of Contents */
.table-of-contents ul {
margin: 1em;
list-style: none;
}
.table-of-contents ul ul {
margin-top: 0.25em;
}
.table-of-contents ul :link,
.table-of-contents ul :visited {
font-size: 16px;
}
.table-of-contents li {
margin-bottom: 0.25em;
}
/* Method Details */
main .method-source-code {
visibility: hidden;
max-height: 0;
overflow: auto;
transition-duration: 200ms;
transition-delay: 0ms;
transition-property: all;
transition-timing-function: ease-in-out;
}
main .method-source-code pre {
border-color: var(--source-code-toggle-color);
}
main .method-source-code.active-menu {
visibility: visible;
max-height: 100vh;
}
main .method-description .method-calls-super {
color: var(--text-color);
font-weight: bold;
}
main .method-detail {
margin-bottom: 2.5em;
}
main .method-detail:target {
margin-left: -10px;
border-left: 10px solid var(--border-color);
}
main .method-header {
display: inline-block;
}
main .method-heading {
position: relative;
font-family: var(--font-code);
font-size: 110%;
font-weight: bold;
}
main .method-heading::after {
content: '¶';
position: absolute;
visibility: hidden;
color: var(--highlight-color);
font-size: 0.5em;
}
main .method-heading:hover::after {
visibility: visible;
}
main .method-controls {
line-height: 20px;
float: right;
color: var(--source-code-toggle-color);
cursor: pointer;
}
main .method-description,
main .aliases {
margin-top: 0.75em;
color: var(--text-color);
}
main .aliases {
padding-top: 4px;
font-style: italic;
cursor: default;
}
main .aliases a {
color: var(--secondary-highlight-color);
}
main .mixin-from {
font-size: 80%;
font-style: italic;
margin-bottom: 0.75em;
}
main .method-description ul {
margin-left: 1.5em;
}
main #attribute-method-details .method-detail:hover {
background-color: transparent;
cursor: default;
}
main .attribute-access-type {
text-transform: uppercase;
}
/* Responsive Adjustments */
@media (max-width: 480px) {
nav {
width: 100%;
}
main {
margin: 1em auto;
padding: 0 1em;
max-width: 100%;
}
#navigation-toggle {
right: 10px;
left: auto;
}
#navigation-toggle[aria-expanded="true"] {
left: auto;
}
table {
display: block;
overflow-x: auto;
white-space: nowrap;
}
main .method-controls {
margin-top: 10px;
float: none;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 733 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 372 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 452 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 764 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 774 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 626 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 715 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 659 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 853 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 621 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 309 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 591 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 592 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 613 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 610 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 584 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 692 B

View File

@ -1,23 +0,0 @@
<body id="top" role="document" class="file">
<%= render '_sidebar_toggle.rhtml' %>
<nav id="navigation" role="navigation">
<div id="project-navigation">
<%= render '_sidebar_navigation.rhtml' %>
<%= render '_sidebar_search.rhtml' %>
</div>
<%= render '_sidebar_pages.rhtml' %>
<%= render '_sidebar_classes.rhtml' %>
<%= render '_footer.rhtml' %>
</nav>
<main role="main">
<%- if @options.main_page and
main_page = @files.find { |f| f.full_name == @options.main_page } then %>
<%= main_page.description %>
<%- else -%>
<p>This is the API documentation for <%= h @title %>.
<%- end -%>
</main>

View File

@ -1,120 +0,0 @@
/**
*
* Darkfish Page Functions
* $Id: darkfish.js 53 2009-01-07 02:52:03Z deveiant $
*
* Author: Michael Granger <mgranger@laika.com>
*
*/
/* Provide console simulation for firebug-less environments */
/*
if (!("console" in window) || !("firebug" in console)) {
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() {};
};
*/
function showSource( e ) {
var target = e.target;
while (!target.classList.contains('method-detail')) {
target = target.parentNode;
}
if (typeof target !== "undefined" && target !== null) {
target = target.querySelector('.method-source-code');
}
if (typeof target !== "undefined" && target !== null) {
target.classList.toggle('active-menu')
}
};
function hookSourceViews() {
document.querySelectorAll('.method-source-toggle').forEach(function (codeObject) {
codeObject.addEventListener('click', showSource);
});
};
function hookSearch() {
var input = document.querySelector('#search-field');
var result = document.querySelector('#search-results');
result.classList.remove("initially-hidden");
var search_section = document.querySelector('#search-section');
search_section.classList.remove("initially-hidden");
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="' + index_rel_prefix + this.escapeHTML(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) {
window.location.href = result.firstChild.firstChild.href;
}
search.scrollIntoView = search.scrollInWindow;
};
function hookFocus() {
document.addEventListener("keydown", (event) => {
if (document.activeElement.tagName === 'INPUT') {
return;
}
if (event.key === "/") {
event.preventDefault();
document.querySelector('#search-field').focus();
}
});
}
function hookSidebar() {
var navigation = document.querySelector('#navigation');
var navigationToggle = document.querySelector('#navigation-toggle');
navigationToggle.addEventListener('click', function() {
navigation.hidden = !navigation.hidden;
navigationToggle.ariaExpanded = navigationToggle.ariaExpanded !== 'true';
});
var isSmallViewport = window.matchMedia("(max-width: 1023px)").matches;
if (isSmallViewport) {
navigation.hidden = true;
navigationToggle.ariaExpanded = false;
document.addEventListener('click', (e) => {
if (e.target.closest('#navigation a')) {
navigation.hidden = true;
navigationToggle.ariaExpanded = false;
}
});
}
}
document.addEventListener('DOMContentLoaded', function() {
hookSourceViews();
hookSearch();
hookFocus();
hookSidebar();
});

View File

@ -1,110 +0,0 @@
Search = function(data, input, result) {
this.data = data;
this.input = input;
this.result = result;
this.current = null;
this.view = this.result.parentNode;
this.searcher = new Searcher(data.index);
this.init();
}
Search.prototype = Object.assign({}, Navigation, new function() {
var suid = 1;
this.init = function() {
var _this = this;
var observer = function(e) {
switch(e.key) {
case 'ArrowUp':
case 'ArrowDown':
return;
}
_this.search(_this.input.value);
};
this.input.addEventListener('keyup', observer);
this.input.addEventListener('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 = value.trim().toLowerCase();
if (value) {
this.setNavigationActive(true);
} else {
this.setNavigationActive(false);
}
if (value == '') {
this.lastQuery = value;
this.result.innerHTML = '';
this.result.setAttribute('aria-expanded', 'false');
this.setNavigationActive(false);
} else if (value != this.lastQuery) {
this.lastQuery = value;
this.result.setAttribute('aria-busy', 'true');
this.result.setAttribute('aria-expanded', 'true');
this.firstRun = true;
this.searcher.find(value);
}
}
this.addResults = function(results, isLast) {
var target = this.result;
if (this.firstRun && (results.length > 0 || isLast)) {
this.current = null;
this.result.innerHTML = '';
}
for (var i=0, l = results.length; i < l; i++) {
var item = this.renderItem.call(this, results[i]);
item.setAttribute('id', 'search-result-' + target.childElementCount);
target.appendChild(item);
};
if (this.firstRun && results.length > 0) {
this.firstRun = false;
this.current = target.firstChild;
this.current.classList.add('search-selected');
}
//TODO: ECMAScript
//if (jQuery.browser.msie) this.$element[0].className += '';
if (isLast) this.result.setAttribute('aria-busy', 'false');
}
this.move = function(isDown) {
if (!this.current) return;
var next = isDown ? this.current.nextElementSibling : this.current.previousElementSibling;
if (next) {
this.current.classList.remove('search-selected');
next.classList.add('search-selected');
this.input.setAttribute('aria-activedescendant', next.getAttribute('id'));
this.scrollIntoView(next, this.view);
this.current = next;
this.input.value = next.firstChild.firstChild.text;
this.input.select();
}
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) + ';';
});
}
});

View File

@ -1,18 +0,0 @@
<body id="top" role="document" class="file">
<%= render '_sidebar_toggle.rhtml' %>
<nav id="navigation" role="navigation">
<div id="project-navigation">
<%= render '_sidebar_navigation.rhtml' %>
<%= render '_sidebar_search.rhtml' %>
</div>
<%= render '_sidebar_table_of_contents.rhtml' %>
<%= render '_sidebar_pages.rhtml' %>
<%= render '_footer.rhtml' %>
</nav>
<main role="main" aria-label="Page <%=h file.full_name%>">
<%= file.description %>
</main>

View File

@ -1,20 +0,0 @@
<body role="document">
<%= render '_sidebar_toggle.rhtml' %>
<nav id="navigation" role="navigation">
<div id="project-navigation">
<%= render '_sidebar_navigation.rhtml' %>
<%= render '_sidebar_search.rhtml' %>
</div>
<%= render '_sidebar_pages.rhtml' %>
<%= render '_sidebar_classes.rhtml' %>
<%= render '_footer.rhtml' %>
</nav>
<main role="main">
<h1>Not Found</h1>
<p><%= message %>
</main>

View File

@ -1,65 +0,0 @@
<body role="document">
<%= render '_sidebar_toggle.rhtml' %>
<nav id="navigation" role="navigation">
<div id="project-navigation">
<div id="home-section" class="nav-section">
<h2>
<a href="<%= rel_prefix %>/" rel="home">Home</a>
</h2>
</div>
<%= render '_sidebar_search.rhtml' %>
</div>
<%= render '_sidebar_installed.rhtml' %>
<%= render '_footer.rhtml' %>
</nav>
<main role="main">
<h1>Local RDoc Documentation</h1>
<p>Here you can browse local documentation from the ruby standard library and
your installed gems.
<%- extra_dirs = installed.select { |_, _, _, type,| type == :extra } -%>
<%- unless extra_dirs.empty? -%>
<h2>Extra Documentation Directories</h2>
<p>The following additional documentation directories are available:</p>
<ol>
<%- extra_dirs.each do |name, href, exists, _, path| -%>
<li>
<%- if exists -%>
<a href="<%= href %>"><%= h name %></a> (<%= h path %>)
<%- else -%>
<%= h name %> (<%= h path %>; <i>not available</i>)
<%- end -%>
</li>
<%- end -%>
</ol>
<%- end -%>
<%- 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 -%>
</main>

View File

@ -1,70 +0,0 @@
<body id="top" class="table-of-contents">
<%= render '_sidebar_toggle.rhtml' %>
<nav id="navigation" role="navigation">
<div id="project-navigation">
<%= render '_sidebar_navigation.rhtml' %>
<%= render '_sidebar_search.rhtml' %>
</div>
<%= render '_footer.rhtml' %>
</nav>
<main role="main">
<h1 class="class"><%= h @title %></h1>
<%- simple_files = @files.select { |f| f.text? } -%>
<%- unless simple_files.empty? then -%>
<h2 id="pages">Pages</h2>
<ul>
<%- simple_files.sort.each do |file| -%>
<li class="file">
<a href="<%= h 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 %>
<ul>
<%- table.each do |heading| -%>
<li><a href="<%= h file.path %>#<%= heading.aref %>"><%= heading.plain_html %></a>
<%- end -%>
</ul>
<%- end -%>
</li>
<%- end -%>
</ul>
<%- end -%>
<h2 id="classes">Classes and 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_location).table_of_contents
table.concat klass.section_contents
unless table.empty? then %>
<ul>
<%- table.each do |item| -%>
<%- label = item.respond_to?(:label) ? item.label(klass) : item.aref -%>
<li><a href="<%= klass.path %>#<%= label %>"><%= item.plain_html %></a>
<%- end -%>
</ul>
<%- end -%>
</li>
<%- end -%>
</ul>
<h2 id="methods">Methods</h2>
<ul>
<%- @store.all_classes_and_modules.flat_map do |mod|
mod.method_list
end.sort.each do |method| %>
<li class="method">
<a href="<%= method.path %>"><%= h method.pretty_name %></a>
&mdash;
<span class="container"><%= method.parent.full_name %></span>
<%- end -%>
</ul>
</main>

View File

@ -1 +0,0 @@
# ignore all files in this directory

View File

@ -1,105 +0,0 @@
/*
* 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.addEventListener('keydown', function(e) {
_this.onkeydown(e);
});
this.navigationActive = true;
}
this.setNavigationActive = function(state) {
this.navigationActive = state;
}
this.onkeydown = function(e) {
if (!this.navigationActive) return;
switch(e.key) {
case 'ArrowLeft':
if (this.moveLeft()) e.preventDefault();
break;
case 'ArrowUp':
if (e.key == 'ArrowUp' || e.ctrlKey) {
if (this.moveUp()) e.preventDefault();
}
break;
case 'ArrowRight':
if (this.moveRight()) e.preventDefault();
break;
case 'ArrowDown':
if (e.key == 'ArrowDown' || e.ctrlKey) {
if (this.moveDown()) e.preventDefault();
}
break;
case 'Enter':
if (this.current) e.preventDefault();
this.select(this.current);
break;
}
if (e.ctrlKey && e.shiftKey) this.select(this.current);
}
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);
}
}
}

View File

@ -1,229 +0,0 @@
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 query.split(/(\s+|::?|\(\)?)/).filter(function(string) {
return string.match(/\S/);
});
}
function buildRegexps(queries) {
return queries.map(function(query) {
return new RegExp(query.replace(/(.)/g, '([$1])([^$1]*?)'), 'i');
});
}
function buildHilighters(queries) {
return queries.map(function(query) {
return query.split('').map(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];
result.badge = info[6];
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) {
this.handlers.forEach(function(fn) {
fn.call(this, results, isLast)
});
}
}

View File

@ -1,10 +0,0 @@
# frozen_string_literal: true
##
# This module provides i18n related features.
module RDoc::I18n
autoload :Locale, "#{__dir__}/i18n/locale"
require_relative 'i18n/text'
end

View File

@ -1,102 +0,0 @@
# frozen_string_literal: true
##
# A message container for a locale.
#
# This object provides the following two features:
#
# * Loads translated messages from .po file.
# * Translates a message into the locale.
class RDoc::I18n::Locale
@@locales = {} # :nodoc:
class << self
##
# Returns the locale object for +locale_name+.
def [](locale_name)
@@locales[locale_name] ||= new(locale_name)
end
##
# Sets the locale object for +locale_name+.
#
# Normally, this method is not used. This method is useful for
# testing.
def []=(locale_name, locale)
@@locales[locale_name] = locale
end
end
##
# The name of the locale. It uses IETF language tag format
# +[language[_territory][.codeset][@modifier]]+.
#
# See also {BCP 47 - Tags for Identifying
# Languages}[http://tools.ietf.org/rfc/bcp/bcp47.txt].
attr_reader :name
##
# Creates a new locale object for +name+ locale. +name+ must
# follow IETF language tag format.
def initialize(name)
@name = name
@messages = {}
end
##
# Loads translation messages from +locale_directory+/+@name+/rdoc.po
# or +locale_directory+/+@name+.po. The former has high priority.
#
# This method requires gettext gem for parsing .po file. If you
# don't have gettext gem, this method doesn't load .po file. This
# method warns and returns +false+.
#
# Returns +true+ if succeeded, +false+ otherwise.
def load(locale_directory)
return false if @name.nil?
po_file_candidates = [
File.join(locale_directory, @name, 'rdoc.po'),
File.join(locale_directory, "#{@name}.po"),
]
po_file = po_file_candidates.find do |po_file_candidate|
File.exist?(po_file_candidate)
end
return false unless po_file
begin
require 'gettext/po_parser'
require 'gettext/mo'
rescue LoadError
warn('Need gettext gem for i18n feature:')
warn(' gem install gettext')
return false
end
po_parser = GetText::POParser.new
messages = GetText::MO.new
po_parser.report_warning = false
po_parser.parse_file(po_file, messages)
@messages.merge!(messages)
true
end
##
# Translates the +message+ into locale. If there is no translation
# messages for +message+ in locale, +message+ itself is returned.
def translate(message)
@messages[message] || message
end
end

Some files were not shown because too many files have changed in this diff Show More