Sync RDoc 6.14.0

This commit is contained in:
Stan Lo 2025-05-22 22:49:04 +01:00 committed by Takashi Kokubun
parent ca1ea95784
commit 03eb777c69
185 changed files with 2008 additions and 1655 deletions

View file

@ -73,12 +73,6 @@ class RDoc::Generator::Darkfish
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
@ -156,7 +150,7 @@ class RDoc::Generator::Darkfish
##
# Initialize a few instance variables before we start
def initialize store, options
def initialize(store, options)
@store = store
@options = options
@ -184,22 +178,6 @@ class RDoc::Generator::Darkfish
$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.
@ -291,7 +269,7 @@ class RDoc::Generator::Darkfish
# Return a list of the documented modules sorted by salience first, then
# by name.
def get_sorted_module_list classes
def get_sorted_module_list(classes)
classes.select do |klass|
klass.display?
end.sort
@ -301,8 +279,6 @@ class RDoc::Generator::Darkfish
# 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?
@ -316,11 +292,14 @@ class RDoc::Generator::Darkfish
asset_rel_prefix = rel_prefix + @asset_rel_path
@title = @options.title
@main_page = @files.find { |f| f.full_name == @options.main_page }
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)
# some partials rely on the presence of current variable to render
here.local_variable_set(:current, @main_page) if @main_page
here
end
rescue => e
@ -334,9 +313,7 @@ class RDoc::Generator::Darkfish
##
# Generates a class file for +klass+
def generate_class klass, template_file = nil
setup
def generate_class(klass, template_file = nil)
current = klass
template_file ||= @template_dir + 'class.rhtml'
@ -348,7 +325,9 @@ class RDoc::Generator::Darkfish
search_index_rel_prefix += @asset_rel_path if @file_output
asset_rel_prefix = rel_prefix + @asset_rel_path
svninfo = get_svninfo(current)
breadcrumb = # used in templates
breadcrumb = generate_nesting_namespaces_breadcrumb(current, rel_prefix)
@title = "#{klass.type} #{klass.full_name} - #{@options.title}"
@ -357,7 +336,6 @@ class RDoc::Generator::Darkfish
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
@ -366,8 +344,6 @@ class RDoc::Generator::Darkfish
# 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?
@ -393,8 +369,6 @@ class RDoc::Generator::Darkfish
# Generate a documentation file for each file
def generate_file_files
setup
page_file = @template_dir + 'page.rhtml'
fileinfo_file = @template_dir + 'fileinfo.rhtml'
@ -461,9 +435,7 @@ class RDoc::Generator::Darkfish
##
# Generate a page file for +file+
def generate_page file
setup
def generate_page(file)
template_file = @template_dir + 'page.rhtml'
out_file = @outputdir + file.path
@ -490,9 +462,7 @@ class RDoc::Generator::Darkfish
##
# Generates the 404 page for the RDoc servlet
def generate_servlet_not_found message
setup
def generate_servlet_not_found(message)
template_file = @template_dir + 'servlet_not_found.rhtml'
return unless template_file.exist?
@ -523,9 +493,7 @@ class RDoc::Generator::Darkfish
##
# Generates the servlet root page for the RDoc servlet
def generate_servlet_root installed
setup
def generate_servlet_root(installed)
template_file = @template_dir + 'servlet_root.rhtml'
return unless template_file.exist?
@ -551,8 +519,6 @@ class RDoc::Generator::Darkfish
# 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?
@ -581,7 +547,7 @@ class RDoc::Generator::Darkfish
raise error
end
def install_rdoc_static_file source, destination, options # :nodoc:
def install_rdoc_static_file(source, destination, options) # :nodoc:
return unless source.exist?
begin
@ -614,65 +580,13 @@ class RDoc::Generator::Darkfish
@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
def assemble_template(body_file)
body = body_file.read
return body if body =~ /<html/
@ -681,7 +595,7 @@ class RDoc::Generator::Darkfish
<<-TEMPLATE
<!DOCTYPE html>
<html>
<html lang="#{@options.locale&.name || 'en'}">
<head>
#{head_file.read}
@ -693,7 +607,7 @@ class RDoc::Generator::Darkfish
# 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
def render(file_name)
template_file = @template_dir + file_name
template = template_for template_file, false, RDoc::ERBPartial
@ -711,7 +625,7 @@ class RDoc::Generator::Darkfish
#
# An io will be yielded which must be captured by binding in the caller.
def render_template template_file, out_file = nil # :yield: io
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
@ -745,7 +659,7 @@ class RDoc::Generator::Darkfish
# 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
def template_result(template, context, template_file)
template.filename = template_file.to_s
template.result context
rescue NoMethodError => e
@ -758,7 +672,7 @@ class RDoc::Generator::Darkfish
##
# Retrieves a cache template for +file+, if present, or fills the cache.
def template_for file, page = true, klass = ERB
def template_for(file, page = true, klass = ERB)
template = @template_cache[file]
return template if template
@ -780,32 +694,39 @@ class RDoc::Generator::Darkfish
template
end
# Returns an excerpt of the content for usage in meta description tags
def excerpt(content)
text = case content
# :stopdoc:
ParagraphExcerptRegexpOther = %r[\b\w[^./:]++\.]
# use \p/\P{letter} instead of \w/\W in Unicode
ParagraphExcerptRegexpUnicode = %r[\b\p{letter}[^./:]++\.]
# :startdoc:
# Returns an excerpt of the comment for usage in meta description tags
def excerpt(comment)
text = case comment
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
comment.text
else
content
comment
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
pattern = ParagraphExcerptRegexpUnicode
begin
first_paragraph_match = text.match(pattern)
rescue Encoding::CompatibilityError
# The doc is non-ASCII text and encoded in other than Unicode base encodings.
raise if pattern == ParagraphExcerptRegexpOther
pattern = ParagraphExcerptRegexpOther
retry
end
return text[0...150].tr_s("\n", " ").squeeze(" ") unless first_paragraph_match
extracted_text = first_paragraph_match[0]
second_paragraph = first_paragraph_match.post_match.match(/[A-Z][^\.:\/]+\./)
second_paragraph = text.match(pattern, first_paragraph_match.end(0))
extracted_text << " " << second_paragraph[0] if second_paragraph
extracted_text[0...150].gsub(/\n/, " ").squeeze(" ")
extracted_text[0...150].tr_s("\n", " ").squeeze(" ")
end
def generate_ancestor_list(ancestors, klass)
@ -825,4 +746,67 @@ class RDoc::Generator::Darkfish
content << '</li></ul>'
end
def generate_class_link(klass, rel_prefix)
if klass.display?
%(<code><a href="#{rel_prefix}/#{klass.path}">#{klass.name}</a></code>)
else
%(<code>#{klass.name}</code>)
end
end
def generate_class_index_content(classes, rel_prefix)
grouped_classes = group_classes_by_namespace_for_sidebar(classes)
return '' unless top = grouped_classes[nil]
solo = top.one? { |klass| klass.display? }
traverse_classes(top, grouped_classes, rel_prefix, solo)
end
def traverse_classes(klasses, grouped_classes, rel_prefix, solo = false)
content = +'<ul class="link-list">'
klasses.each do |index_klass|
if children = grouped_classes[index_klass.full_name]
content << %(<li><details#{solo ? ' open' : ''}><summary>#{generate_class_link(index_klass, rel_prefix)}</summary>)
content << traverse_classes(children, grouped_classes, rel_prefix)
content << '</details></li>'
solo = false
elsif index_klass.display?
content << %(<li>#{generate_class_link(index_klass, rel_prefix)}</li>)
end
end
"#{content}</ul>"
end
def group_classes_by_namespace_for_sidebar(classes)
grouped_classes = classes.group_by do |klass|
klass.full_name[/\A[^:]++(?:::[^:]++(?=::))*+(?=::[^:]*+\z)/]
end.select do |_, klasses|
klasses.any?(&:display?)
end
grouped_classes.values.each(&:uniq!)
grouped_classes
end
private
def nesting_namespaces_to_class_modules(klass)
tree = {}
klass.nesting_namespaces.zip(klass.fully_qualified_nesting_namespaces) do |ns, fqns|
tree[ns] = @store.classes_hash[fqns] || @store.modules_hash[fqns]
end
tree
end
def generate_nesting_namespaces_breadcrumb(klass, rel_prefix)
nesting_namespaces_to_class_modules(klass).map do |namespace, class_module|
path = class_module ? (rel_prefix + class_module.path).to_s : ""
{ name: namespace, path: path, self: klass.full_name == class_module&.full_name }
end
end
end

View file

@ -86,12 +86,10 @@ class RDoc::Generator::JsonIndex
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.
#
# Creates a new generator.
# +options+ are the same options passed to the parent generator.
def initialize parent_generator, options
def initialize(parent_generator, options)
@parent_generator = parent_generator
@store = parent_generator.store
@options = options
@ -265,21 +263,7 @@ class RDoc::Generator::JsonIndex
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:
def reset(files, classes) # :nodoc:
@files = files
@classes = classes
@ -293,7 +277,7 @@ class RDoc::Generator::JsonIndex
##
# Removes whitespace and downcases +string+
def search_string string
def search_string(string)
string.downcase.gsub(/\s/, '')
end

View file

@ -34,7 +34,7 @@ module RDoc::Generator::Markup
def formatter
return @formatter if defined? @formatter
options = @store.rdoc.options
options = @store.options
this = RDoc::Context === self ? self : @parent
@formatter = RDoc::Markup::ToHtmlCrossref.new options, this.path, this
@ -55,6 +55,18 @@ module RDoc::Generator::Markup
end
end
##
# The preferred URL for this object.
def canonical_url
options = @store.options
if path
File.join(options.canonical_root, path.to_s)
else
options.canonical_root
end
end
end
class RDoc::CodeObject
@ -147,7 +159,7 @@ class RDoc::TopLevel
# command line option to set.
def cvs_url
url = @store.rdoc.options.webcvs
url = @store.options.webcvs
if /%s/ =~ url then
url % @relative_name

View file

@ -65,7 +65,7 @@ class RDoc::Generator::POT
##
# Set up a new .pot generator
def initialize store, options #:not-new:
def initialize(store, options) #:not-new:
@options = options
@store = store
end
@ -81,11 +81,6 @@ class RDoc::Generator::POT
end
end
# :nodoc:
def class_dir
nil
end
private
def extract_messages
extractor = MessageExtractor.new(@store)

View file

@ -7,7 +7,7 @@ class RDoc::Generator::POT::MessageExtractor
##
# Creates a message extractor for +store+.
def initialize store
def initialize(store)
@store = store
@po = RDoc::Generator::POT::PO.new
end
@ -25,7 +25,7 @@ class RDoc::Generator::POT::MessageExtractor
private
def extract_from_klass klass
def extract_from_klass(klass)
extract_text(klass.comment_location, klass.full_name)
klass.each_section do |section, constants, attributes|
@ -35,11 +35,11 @@ class RDoc::Generator::POT::MessageExtractor
end
end
klass.each_constant do |constant|
klass.constants.each do |constant|
extract_text(constant.comment, constant.full_name)
end
klass.each_attribute do |attribute|
klass.attributes.each do |attribute|
extract_text(attribute.comment, attribute.full_name)
end
@ -48,7 +48,7 @@ class RDoc::Generator::POT::MessageExtractor
end
end
def extract_text text, comment, location = nil
def extract_text(text, comment, location = nil)
return if text.nil?
options = {
@ -61,7 +61,7 @@ class RDoc::Generator::POT::MessageExtractor
end
end
def entry msgid, options
def entry(msgid, options)
RDoc::Generator::POT::POEntry.new(msgid, options)
end

View file

@ -15,7 +15,7 @@ class RDoc::Generator::POT::PO
##
# Adds a PO entry to the PO.
def add entry
def add(entry)
existing_entry = @entries[entry.msgid]
if existing_entry
entry = existing_entry.merge(entry)

View file

@ -26,7 +26,7 @@ class RDoc::Generator::POT::POEntry
# Creates a PO entry for +msgid+. Other values can be specified by
# +options+.
def initialize msgid, options = {}
def initialize(msgid, options = {})
@msgid = msgid
@msgstr = options[:msgstr] || ""
@translator_comment = options[:translator_comment]
@ -53,7 +53,7 @@ msgstr #{format_message(@msgstr)}
##
# Merges the PO entry with +other_entry+.
def merge other_entry
def merge(other_entry)
options = {
:extracted_comment => merge_string(@extracted_comment,
other_entry.extracted_comment),
@ -69,7 +69,7 @@ msgstr #{format_message(@msgstr)}
private
def format_comment mark, comment
def format_comment(mark, comment)
return '' unless comment
return '' if comment.empty?
@ -106,7 +106,7 @@ msgstr #{format_message(@msgstr)}
"\#, #{formatted_flags}\n"
end
def format_message message
def format_message(message)
return "\"#{escape(message)}\"" unless message.include?("\n")
formatted_message = '""'
@ -117,7 +117,7 @@ msgstr #{format_message(@msgstr)}
formatted_message
end
def escape string
def escape(string)
string.gsub(/["\\\t\n]/) do |special_character|
case special_character
when "\t"
@ -130,11 +130,11 @@ msgstr #{format_message(@msgstr)}
end
end
def merge_string string1, string2
def merge_string(string1, string2)
[string1, string2].compact.join("\n")
end
def merge_array array1, array2
def merge_array(array1, array2)
(array1 + array2).uniq
end

View file

@ -14,7 +14,7 @@ class RDoc::Generator::RI
##
# Set up a new ri generator
def initialize store, options #:not-new:
def initialize(store, options) #:not-new:
@options = options
@store = store
@store.path = '.'

View file

@ -25,6 +25,11 @@
<%- end -%>
<%- end -%>
<%- if canonical_url = @options.canonical_root -%>
<% canonical_url = current.canonical_url if defined?(current) %>
<link rel="canonical" href="<%= canonical_url %>">
<%- end -%>
<script type="text/javascript">
var rdoc_rel_prefix = "<%= h asset_rel_prefix %>/";
var index_rel_prefix = "<%= h rel_prefix %>/";

View file

@ -1,19 +0,0 @@
<%- if !svninfo.empty? then %>
<div id="file-svninfo-section" class="nav-section">
<h3>VCS Info</h3>
<div class="section-body">
<dl class="svninfo">
<dt>Rev
<dd><%= svninfo[:rev] %>
<dt>Last Checked In
<dd><%= svninfo[:commitdate].strftime('%Y-%m-%d %H:%M:%S') %>
(<%= svninfo[:commitdelta] %> ago)
<dt>Checked in by
<dd><%= svninfo[:committer] %>
</dl>
</div>
</div>
<%- end -%>

View file

@ -1,34 +1,5 @@
<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 -%>
<%= generate_class_index_content(@classes, rel_prefix) %>
</div>

View file

@ -3,7 +3,7 @@
<h3>Extended With Modules</h3>
<ul class="link-list">
<%- klass.each_extend do |ext| -%>
<%- klass.extends.each do |ext| -%>
<%- unless String === ext.module then -%>
<li><a class="extend" href="<%= klass.aref_to ext.module.path %>"><%= ext.module.full_name %></a>
<%- else -%>

View file

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

View file

@ -3,7 +3,7 @@
<h3>Included Modules</h3>
<ul class="link-list">
<%- klass.each_include do |inc| -%>
<%- klass.includes.each do |inc| -%>
<%- unless String === inc.module then -%>
<li><a class="include" href="<%= klass.aref_to inc.module.path %>"><%= inc.module.full_name %></a>
<%- else -%>

View file

@ -18,6 +18,21 @@
</nav>
<main role="main" aria-labelledby="<%=h klass.aref %>">
<%# If nesting level is 1, breadcrumb list is not needed %>
<% if breadcrumb.size > 1 %>
<ol role="navigation" aria-label="breadcrumb" class="breadcrumb">
<% breadcrumb.each do |namespace| %>
<li>
<% if namespace[:self] %>
<span><%= namespace[:name] %></span>
<% else %>
<a href="<%= namespace[:path] %>"><%= namespace[:name] %></a><span>::</span>
<% end %>
</li>
<% end %>
</ol>
<% end %>
<h1 id="<%=h klass.aref %>" class="anchor-link <%= klass.type %>">
<%= klass.type %> <%= klass.full_name %>
</h1>

View file

@ -96,6 +96,8 @@ main .anchor-link:target {
a {
color: var(--link-color);
transition: color 0.3s ease;
text-decoration: underline;
text-underline-offset: 0.2em; /* Make sure it doesn't overlap with underscores in a method name. */
}
a:hover {
@ -199,6 +201,19 @@ nav h3,
font-size: 1em;
}
ol.breadcrumb {
display: flex;
padding: 0;
margin: 0 0 1em;
}
ol.breadcrumb li {
display: block;
list-style: none;
font-size: 125%;
}
nav ul,
nav dl,
nav p {

View file

@ -7,6 +7,7 @@
<%= render '_sidebar_search.rhtml' %>
</div>
<%= render '_sidebar_table_of_contents.rhtml' if defined?(current) %>
<%= render '_sidebar_pages.rhtml' %>
<%= render '_sidebar_classes.rhtml' %>
@ -14,10 +15,9 @@
</nav>
<main role="main">
<%- if @options.main_page and
main_page = @files.find { |f| f.full_name == @options.main_page } then %>
<%= main_page.description %>
<%- if @main_page %>
<%= @main_page.description %>
<%- else -%>
<p>This is the API documentation for <%= h @title %>.
<p>This is the API documentation for <%= h @title %>.
<%- end -%>
</main>