Migrate rdoc as bundled gems
@ -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
|
||||
|
211
lib/rdoc.rb
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -1,6 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
##
|
||||
# GhostMethod represents a method referenced only by a comment
|
||||
|
||||
class RDoc::GhostMethod < RDoc::AnyMethod
|
||||
end
|
@ -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
|
@ -1,6 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
##
|
||||
# MetaMethod represents a meta-programmed method
|
||||
|
||||
class RDoc::MetaMethod < RDoc::AnyMethod
|
||||
end
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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'
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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>
|
@ -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 -%>
|
@ -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 -%>
|
@ -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>
|
@ -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 -%>
|
@ -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>
|
@ -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 -%>
|
@ -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>
|
@ -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 %>
|
@ -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>
|
@ -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 -%>
|
@ -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 -%>
|
@ -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>
|
@ -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 -%>
|
@ -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 -%>
|
@ -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">☰</span>
|
||||
</div>
|
@ -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">↑ 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(/(.*)[-=]>/, '\1→') %>
|
||||
</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>
|
@ -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.
|
||||
*/
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 733 B |
Before Width: | Height: | Size: 372 B |
Before Width: | Height: | Size: 452 B |
Before Width: | Height: | Size: 764 B |
Before Width: | Height: | Size: 774 B |
Before Width: | Height: | Size: 211 B |
Before Width: | Height: | Size: 207 B |
Before Width: | Height: | Size: 209 B |
Before Width: | Height: | Size: 626 B |
Before Width: | Height: | Size: 715 B |
Before Width: | Height: | Size: 659 B |
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 207 B |
Before Width: | Height: | Size: 853 B |
Before Width: | Height: | Size: 621 B |
Before Width: | Height: | Size: 342 B |
Before Width: | Height: | Size: 309 B |
Before Width: | Height: | Size: 591 B |
Before Width: | Height: | Size: 592 B |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 613 B |
Before Width: | Height: | Size: 97 B |
Before Width: | Height: | Size: 610 B |
Before Width: | Height: | Size: 584 B |
Before Width: | Height: | Size: 692 B |
@ -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>
|
@ -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();
|
||||
});
|
@ -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) + ';';
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
||||
—
|
||||
<span class="container"><%= method.parent.full_name %></span>
|
||||
<%- end -%>
|
||||
</ul>
|
||||
</main>
|
@ -1 +0,0 @@
|
||||
# ignore all files in this directory
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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
|
@ -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
|