Skip to content

Commit 29978e0

Browse files
committed
Add Aliki HTML template
1 parent bb515ae commit 29978e0

31 files changed

Lines changed: 4505 additions & 6 deletions

Gemfile

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,34 @@
11
# frozen_string_literal: true
2+
23
source 'https://rubygems.org'
34

45
group :development do
5-
gem 'rspec'
6+
gem 'coveralls_reborn', :require => false if RUBY_VERSION >= '2.7.0'
7+
gem 'json'
68
gem 'rake'
79
gem 'rdoc', RUBY_VERSION < '2.7.0' ? '~> 6.0' : nil
8-
gem 'json'
10+
gem 'rspec'
911
gem 'simplecov' if RUBY_VERSION >= '2.7.0'
10-
gem 'coveralls_reborn', :require => false if RUBY_VERSION >= '2.7.0'
1112
gem 'webrick'
1213
end
1314

1415
group :asciidoc do
15-
gem 'logger' if RUBY_VERSION >= '2.3.0'
1616
gem 'asciidoctor'
17+
gem 'logger' if RUBY_VERSION >= '2.3.0'
1718
end
1819

1920
group :markdown do
20-
gem 'redcarpet'
2121
gem 'commonmarker'
22+
gem 'redcarpet'
2223
end
2324

2425
group :textile do
2526
gem 'RedCloth'
2627
end
2728

2829
group :server do
29-
gem 'rackup' if RUBY_VERSION >= '2.6.0'
3030
gem 'rack', '~> 2.0' if RUBY_VERSION < '2.6.0'
31+
gem 'rackup' if RUBY_VERSION >= '2.6.0'
3132
end
3233

3334
group :i18n do

LEGAL

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,8 @@ lib/yard/server/http_utils.rb:
9292
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9393
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9494
SUCH DAMAGE.
95+
96+
templates/aliki/layout/html/css/rdoc.css and templates/aliki/layout/html/js/*:
97+
98+
These files are adapted from RDoc's Aliki theme, written by Stan Lo and
99+
included under the MIT license.

spec/templates/aliki_spec.rb

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# frozen_string_literal: true
2+
3+
require File.expand_path('spec_helper', __dir__)
4+
require 'json'
5+
6+
class AlikiStringSerializer < YARD::Serializers::Base
7+
attr_reader :files, :output
8+
9+
def initialize
10+
super
11+
@files = []
12+
@output = {}
13+
@filesystem = YARD::Serializers::FileSystemSerializer.new
14+
end
15+
16+
def serialize(object, data)
17+
files << object
18+
output[serialized_path(object)] = data
19+
end
20+
21+
def serialized_path(object)
22+
@filesystem.serialized_path(object)
23+
end
24+
end
25+
26+
RSpec.describe "Aliki HTML template" do
27+
before do
28+
Registry.clear
29+
YARD.parse_string <<-RUBY
30+
# A test class.
31+
class A
32+
# Returns foo.
33+
# @return [String]
34+
def foo; 'foo' end
35+
end
36+
RUBY
37+
end
38+
39+
after do
40+
Registry.clear
41+
end
42+
43+
it "generates Aliki assets, pages, object output, and search data" do
44+
serializer = AlikiStringSerializer.new
45+
readme = CodeObjects::ExtraFileObject.new('README', '# Readme')
46+
47+
Templates::Engine.generate Registry.all(:class),
48+
:serializer => serializer,
49+
:template => :aliki,
50+
:format => :html,
51+
:readme => readme,
52+
:files => [readme]
53+
54+
expect(serializer.files).to include(
55+
'css/rdoc.css', 'css/yard.css', 'js/aliki.js', 'js/search_data.js'
56+
)
57+
expect(serializer.output['index.html']).to include('class="file has-toc"')
58+
expect(serializer.output['A.html']).to include('Classes and Modules')
59+
expect(serializer.output['A.html']).to include('<span class="nav-section-title">Pages</span>')
60+
expect(serializer.output['A.html']).to include('method-detail anchor-link')
61+
62+
search_data = serializer.output['js/search_data.js'].
63+
sub(/\Avar search_data = /, '').
64+
sub(/;\z/, '')
65+
index = JSON.parse(search_data).fetch('index')
66+
expect(index).to include(hash_including('name' => 'A', 'type' => 'class', 'path' => 'A.html'))
67+
expect(index).to include(
68+
hash_including(
69+
'name' => 'foo',
70+
'type' => 'instance_method',
71+
'path' => 'A.html#foo-instance_method'
72+
)
73+
)
74+
end
75+
end
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# frozen_string_literal: true
2+
3+
include Templates::Engine.template(:default, :class, :html)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# frozen_string_literal: true
2+
3+
include Templates::Engine.template(:default, :docstring, :html)
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# frozen_string_literal: true
2+
3+
require 'json'
4+
5+
include T('default/fulldoc/html')
6+
7+
def init
8+
options.objects = objects = run_verifier(options.objects)
9+
10+
return serialize_onefile if options.onefile
11+
12+
generate_assets
13+
serialize('_index.html')
14+
options.files.each_with_index do |file, _i|
15+
serialize_file(file, file.title)
16+
end
17+
18+
options.delete(:objects)
19+
20+
objects.each do |object|
21+
begin
22+
serialize(object)
23+
rescue StandardError => e
24+
path = options.serializer.serialized_path(object)
25+
log.error "Exception occurred while generating '#{path}'"
26+
log.backtrace(e)
27+
end
28+
end
29+
end
30+
31+
def generate_assets
32+
layout_template = Templates::Engine.template(:aliki, :layout, :html)
33+
layout = Object.new.extend(layout_template)
34+
(layout.javascripts + layout.stylesheets).uniq.each do |file|
35+
next if file == 'js/search_data.js'
36+
37+
asset(file, File.read(layout_template.find_file(file)))
38+
end
39+
40+
asset('js/search_data.js', aliki_search_data)
41+
end
42+
43+
def aliki_search_data
44+
entries = []
45+
searchable_objects.each do |object|
46+
entries << aliki_search_entry(object)
47+
end
48+
49+
"var search_data = #{JSON.generate(:index => entries.compact)};"
50+
end
51+
52+
def searchable_objects
53+
objects = Registry.all(:class, :module, :method, :constant, :classvariable)
54+
run_verifier(objects).reject do |object|
55+
object.respond_to?(:root?) && object.root?
56+
end
57+
end
58+
59+
def aliki_search_entry(object)
60+
path = url_for(object, nil, false)
61+
return unless path
62+
63+
{
64+
:name => aliki_search_name(object),
65+
:full_name => object.path,
66+
:type => aliki_search_type(object),
67+
:path => path
68+
}.tap do |entry|
69+
snippet = aliki_search_snippet(object)
70+
entry[:snippet] = snippet unless snippet.empty?
71+
end
72+
end
73+
74+
def aliki_search_name(object)
75+
if object.respond_to?(:name)
76+
object.name.to_s
77+
else
78+
object.path.to_s
79+
end
80+
end
81+
82+
def aliki_search_type(object)
83+
case object
84+
when CodeObjects::ClassObject
85+
'class'
86+
when CodeObjects::ModuleObject
87+
'module'
88+
when CodeObjects::MethodObject
89+
object.scope == :class ? 'class_method' : 'instance_method'
90+
when CodeObjects::ConstantObject, CodeObjects::ClassVariableObject
91+
'constant'
92+
else
93+
object.type.to_s
94+
end
95+
end
96+
97+
def aliki_search_snippet(object)
98+
return '' unless object.respond_to?(:docstring)
99+
100+
summary = object.docstring.summary.to_s.strip.gsub(/\s+/, ' ')
101+
h(summary)
102+
end
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<aside class="table-of-contents" role="complementary" aria-label="Table of Contents">
2+
<div class="toc-sticky">
3+
<h3 class="toc-heading">On This Page</h3>
4+
<nav class="toc-nav" id="toc-nav" aria-label="Page sections"></nav>
5+
</div>
6+
</aside>

0 commit comments

Comments
 (0)