Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 71 additions & 2 deletions lib/rdoc/generator/aliki.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require 'uri'
require_relative 'compiled_template'

module RDoc
module Generator
Expand All @@ -13,12 +14,37 @@ module Generator
class Aliki < Generator::Darkfish
DESCRIPTION = 'HTML generator, written by Stan Lo'

TEMPLATE_DIR = (Pathname.new(__dir__) + 'template' + 'aliki').freeze # :nodoc:
# Pages include the assembled head's inputs; absent page objects are nil.
PAGE_INPUTS = %i[io rel_prefix asset_rel_prefix current klass file].freeze # :nodoc:
TEMPLATE_INPUTS = { # :nodoc:
'class.rhtml' => PAGE_INPUTS + [:breadcrumb],
'index.rhtml' => PAGE_INPUTS,
'page.rhtml' => PAGE_INPUTS,
'servlet_not_found.rhtml' => PAGE_INPUTS + [:message],
'servlet_root.rhtml' => PAGE_INPUTS + [:installed],
'_head.rhtml' => %i[rel_prefix asset_rel_prefix current klass file],
'_aside_toc.rhtml' => [],
'_footer.rhtml' => [:rel_prefix],
'_header.rhtml' => [:rel_prefix],
'_icons.rhtml' => [],
'_sidebar_ancestors.rhtml' => [:klass],
'_sidebar_classes.rhtml' => [:rel_prefix],
'_sidebar_extends.rhtml' => [:klass],
'_sidebar_includes.rhtml' => [:klass],
'_sidebar_installed.rhtml' => [:installed],
'_sidebar_methods.rhtml' => [:klass],
'_sidebar_pages.rhtml' => %i[rel_prefix current],
'_sidebar_search.rhtml' => [],
'_sidebar_sections.rhtml' => [:klass],
'_sidebar_toggle.rhtml' => [],
}.transform_values(&:freeze).freeze

RDoc.add_generator self

def initialize(store, options)
super
aliki_template_dir = File.expand_path(File.join(__dir__, 'template', 'aliki'))
@template_dir = Pathname.new(aliki_template_dir)
@template_dir = TEMPLATE_DIR
end

##
Expand Down Expand Up @@ -151,8 +177,51 @@ def resolve_url(rel_prefix, url)
"#{rel_prefix}/#{url}"
end

#: (Pathname, ?bool, ?Class[ERB]) -> ERB
def template_for(file, page = true, klass = ERB)
cached = @template_cache[file]
# String and streaming ERB compile different output operations. Replace
# only owned compiled templates; custom ERB caches keep legacy behavior.
if cached.is_a?(CompiledTemplate) && cached.class != klass
@template_cache.delete(file)
end

template = super
return template if template.is_a?(CompiledTemplate)
return template unless [ERB, ERBIO, ERBPartial].include?(template.class)

if inputs = builtin_template_inputs(file)
template.extend CompiledTemplate
template.generator = self
template.render_inputs = inputs
end
template
end

private

#: (Pathname, ?Pathname?, **untyped) -> untyped
def render_page_template(template_file, out_file = nil, **inputs, &block)
return super unless builtin_template_inputs(template_file)

erb_class = erb_class_for out_file
template = template_for template_file, true, erb_class
return super unless template.is_a?(CompiledTemplate)

render_template template_file, out_file do |io|
CompiledTemplate::Inputs.new(io: io, **inputs)
end
end

#: (Pathname) -> Array[Symbol]?
def builtin_template_inputs(file)
# Custom generators and templates retain their shared-binding behavior.
return unless self.class == Aliki && @template_dir.expand_path == TEMPLATE_DIR
return unless file.dirname.expand_path == TEMPLATE_DIR

TEMPLATE_INPUTS[file.basename.to_s]
end

def template_encoding
::Encoding::UTF_8
end
Expand Down
25 changes: 25 additions & 0 deletions lib/rdoc/generator/compiled_template.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# frozen_string_literal: true

module RDoc
module Generator
# Caches a renderer with declared inputs for an Aliki template. Ordinary
# bindings still use ERB's original evaluation and shared-local semantics.
module CompiledTemplate # :nodoc:

Inputs = Struct.new(
:io, :rel_prefix, :asset_rel_prefix, :current, :klass, :file,
:breadcrumb, :message, :installed, keyword_init: true
)

attr_writer :generator, :render_inputs

#: (?(Binding | Inputs)?) -> untyped
def result(context = nil)
return super unless context.is_a?(Inputs)

@compiled_renderer ||= def_module("render(#{@render_inputs.join(', ')})").instance_method(:render).bind(@generator)
@compiled_renderer.call(*@render_inputs.map { |name| context[name] })
end
end
end
end
38 changes: 30 additions & 8 deletions lib/rdoc/generator/darkfish.rb
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,8 @@ def generate_index
@title = @options.title
@main_page = @files.find { |f| f.full_name == @options.main_page }

render_template template_file, out_file do |io|
inputs = { rel_prefix: rel_prefix, asset_rel_prefix: asset_rel_prefix, current: @main_page }
render_page_template template_file, out_file, **inputs do |io|
here = binding
# suppress 1.9.3 warning
here.local_variable_set(:asset_rel_prefix, asset_rel_prefix)
Expand Down Expand Up @@ -333,7 +334,11 @@ def generate_class(klass, template_file = nil)
@title = "#{klass.type} #{klass.full_name} - #{@options.title}"

debug_msg " rendering #{out_file}"
render_template template_file, out_file do |io|
inputs = {
rel_prefix: rel_prefix, asset_rel_prefix: asset_rel_prefix,
current: current, klass: klass, breadcrumb: breadcrumb,
}
render_page_template template_file, out_file, **inputs do |io|
here = binding
# suppress 1.9.3 warning
here.local_variable_set(:asset_rel_prefix, asset_rel_prefix)
Expand Down Expand Up @@ -457,7 +462,11 @@ def generate_page(file)
@title = "#{file.page_name} - #{@options.title}"

debug_msg " rendering #{out_file}"
render_template template_file, out_file do |io|
inputs = {
rel_prefix: rel_prefix, asset_rel_prefix: asset_rel_prefix,
current: current, file: file,
}
render_page_template template_file, out_file, **inputs do |io|
here = binding
# suppress 1.9.3 warning
here.local_variable_set(:current, current)
Expand All @@ -483,7 +492,8 @@ def generate_servlet_not_found(message)

@title = 'Not Found'

render_template template_file do |io|
inputs = { rel_prefix: rel_prefix, asset_rel_prefix: asset_rel_prefix, message: message }
render_page_template template_file, **inputs do |io|
here = binding
# suppress 1.9.3 warning
here.local_variable_set(:asset_rel_prefix, asset_rel_prefix)
Expand Down Expand Up @@ -513,7 +523,8 @@ def generate_servlet_root(installed)

@title = 'Local RDoc Documentation'

render_template template_file do |io| binding end
inputs = { rel_prefix: rel_prefix, asset_rel_prefix: asset_rel_prefix, installed: installed }
render_page_template template_file, **inputs do |io| binding end
rescue => e
error = Error.new \
"error generating servlet_root: #{e.message} (#{e.class})"
Expand Down Expand Up @@ -642,12 +653,11 @@ def render(file_name)
# 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 ? ERBIO : ERB
erb_klass = erb_class_for out_file

template = template_for template_file, true, erb_klass

if io_output
if erb_klass == ERBIO
debug_msg "Outputting to %s" % [out_file.expand_path]

out_file.dirname.mkpath
Expand Down Expand Up @@ -809,6 +819,18 @@ def group_classes_by_namespace_for_sidebar(classes)

private

#: (Pathname?) -> Class[ERB]
def erb_class_for(out_file)
out_file && !@dry_run && @file_output ? ERBIO : ERB
end

# Themes can render with explicit inputs without changing the legacy
# render_template API or restricting the binding supplied by its caller.
#: (Pathname, ?Pathname?, **untyped) -> untyped
def render_page_template(template_file, out_file = nil, **inputs, &block)
render_template(template_file, out_file, &block)
end

def template_encoding
nil
end
Expand Down
2 changes: 1 addition & 1 deletion lib/rdoc/generator/template/aliki/_footer.rhtml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

<div class="footer-bottom">
<p>
Generated by <a href="https://ruby.github.io/rdoc/">RDoc <%= VERSION %></a>
Generated by <a href="https://ruby.github.io/rdoc/">RDoc <%= ::RDoc::VERSION %></a>
using the Aliki theme by <a href="http://st0012.dev">Stan Lo</a>
</p>
</div>
Expand Down
38 changes: 19 additions & 19 deletions lib/rdoc/generator/template/aliki/_head.rhtml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

<title><%= h @title %></title>

<%- if defined?(klass) %>
<%- if defined?(klass) && klass %>
<meta
name="keywords"
content="ruby,<%= h "#{klass.type},#{klass.full_name}" %>"
Expand All @@ -19,7 +19,7 @@
content="<%= h "#{klass.type} #{klass.full_name}: #{excerpt(klass.comment)}" %>"
>
<%- end %>
<%- elsif defined?(file) %>
<%- elsif defined?(file) && file %>
<meta name="keywords" content="ruby,documentation,<%= h file.page_name %>">
<meta
name="description"
Expand All @@ -39,15 +39,15 @@
<%- end %>

<%- if canonical_url = @options.canonical_root %>
<% canonical_url = current.canonical_url if defined?(current) %>
<% canonical_url = current.canonical_url if defined?(current) && current %>
<link rel="canonical" href="<%= canonical_url %>">
<%- end %>

<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:title" content="<%= h @title %>">

<%- if defined?(klass) %>
<%- if defined?(klass) && klass %>
<%- if klass.comment.empty? %>
<meta
property="og:description"
Expand All @@ -56,7 +56,7 @@
<%- else %>
<meta property="og:description" content="<%= h excerpt(klass.comment) %>">
<%- end %>
<%- elsif defined?(file) %>
<%- elsif defined?(file) && file %>
<%- if file.comment.empty? %>
<meta
property="og:description"
Expand All @@ -73,15 +73,15 @@
<%- end %>

<%- if canonical_url = @options.canonical_root %>
<% canonical_url = current.canonical_url if defined?(current) %>
<% canonical_url = current.canonical_url if defined?(current) && current %>
<meta property="og:url" content="<%= canonical_url %>">
<%- end %>

<!-- Twitter -->
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="<%= h @title %>">

<%- if defined?(klass) %>
<%- if defined?(klass) && klass %>
<%- if klass.comment.empty? %>
<meta
name="twitter:description"
Expand All @@ -90,7 +90,7 @@
<%- else %>
<meta name="twitter:description" content="<%= h excerpt(klass.comment) %>">
<%- end %>
<%- elsif defined?(file) %>
<%- elsif defined?(file) && file %>
<%- if file.comment.empty? %>
<meta
name="twitter:description"
Expand All @@ -112,57 +112,57 @@
</script>

<script
src="<%= h asset_rel_prefix %>/js/theme-toggle.js?v=<%= h VERSION %>"
src="<%= h asset_rel_prefix %>/js/theme-toggle.js?v=<%= h ::RDoc::VERSION %>"
></script>

<script
src="<%= h asset_rel_prefix %>/js/search_navigation.js?v=<%= h VERSION %>"
src="<%= h asset_rel_prefix %>/js/search_navigation.js?v=<%= h ::RDoc::VERSION %>"
defer
></script>

<script
src="<%= h asset_rel_prefix %>/js/search_data.js?v=<%= h VERSION %>"
src="<%= h asset_rel_prefix %>/js/search_data.js?v=<%= h ::RDoc::VERSION %>"
defer
></script>

<script
src="<%= h asset_rel_prefix %>/js/navigation.js?v=<%= h VERSION %>"
src="<%= h asset_rel_prefix %>/js/navigation.js?v=<%= h ::RDoc::VERSION %>"
defer
></script>

<script
src="<%= h asset_rel_prefix %>/js/search_ranker.js?v=<%= h VERSION %>"
src="<%= h asset_rel_prefix %>/js/search_ranker.js?v=<%= h ::RDoc::VERSION %>"
defer
></script>

<script
src="<%= h asset_rel_prefix %>/js/search_controller.js?v=<%= h VERSION %>"
src="<%= h asset_rel_prefix %>/js/search_controller.js?v=<%= h ::RDoc::VERSION %>"
defer
></script>

<script
src="<%= h asset_rel_prefix %>/js/c_highlighter.js?v=<%= h VERSION %>"
src="<%= h asset_rel_prefix %>/js/c_highlighter.js?v=<%= h ::RDoc::VERSION %>"
defer
></script>

<script
src="<%= h asset_rel_prefix %>/js/bash_highlighter.js?v=<%= h VERSION %>"
src="<%= h asset_rel_prefix %>/js/bash_highlighter.js?v=<%= h ::RDoc::VERSION %>"
defer
></script>

<script
src="<%= h asset_rel_prefix %>/js/aliki.js?v=<%= h VERSION %>"
src="<%= h asset_rel_prefix %>/js/aliki.js?v=<%= h ::RDoc::VERSION %>"
defer
></script>

<link
href="<%= h asset_rel_prefix %>/css/rdoc.css?v=<%= h VERSION %>"
href="<%= h asset_rel_prefix %>/css/rdoc.css?v=<%= h ::RDoc::VERSION %>"
rel="stylesheet"
>

<%- @options.template_stylesheets.each do |stylesheet| %>
<link
href="<%= h asset_rel_prefix %>/<%= h File.basename stylesheet %>?v=<%= h VERSION %>"
href="<%= h asset_rel_prefix %>/<%= h File.basename stylesheet %>?v=<%= h ::RDoc::VERSION %>"
rel="stylesheet"
>
<%- end %>
2 changes: 1 addition & 1 deletion lib/rdoc/generator/template/darkfish/_footer.rhtml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<footer id="validator-badges" role="contentinfo">
<p><a href="https://validator.w3.org/check/referer">Validate</a></p>
<p>Generated by <a href="https://ruby.github.io/rdoc/">RDoc</a> <%= VERSION %>.</p>
<p>Generated by <a href="https://ruby.github.io/rdoc/">RDoc</a> <%= ::RDoc::VERSION %>.</p>
<p>Based on <a href="http://deveiate.org/projects/Darkfish-RDoc/">Darkfish</a> by <a href="http://deveiate.org">Michael Granger</a>.</p>
</footer>
Loading
Loading