pebble/devsite/lib/pebble_documentation_pebblekit_ios.rb
2025-02-24 18:58:29 -08:00

240 lines
6.6 KiB
Ruby

# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
require 'zip'
require 'nokogiri'
require 'slugize'
require 'open-uri'
module Pebble
# PebbleKit iOS documentation processing class.
class DocumentationPebbleKitIos < Documentation
def initialize(site, source, root)
super(site)
@site = site
@url_root = root
open(source) do |zf|
Zip::File.open(zf.path) do |zipfile|
zipfile.each { |entry| process_entry(entry) }
end
end
end
private
def language
'pebblekit_ios'
end
def process_entry(entry)
return unless File.extname(entry.name) == '.html'
doc = Nokogiri::HTML(entry.get_input_stream.read)
process_index(doc) if File.basename(entry.name) == 'index.html'
process_normal_entry(doc, entry)
end
def process_normal_entry(doc, entry)
doc_entry = DocEntryPebbleKitIos.new(entry, doc, @url_root)
add_symbol(doc_entry.to_symbol)
doc_entry.anchor_symbols.map { |symbol| add_symbol(symbol) }
@pages << doc_entry.create_page(@site)
end
def process_index(doc)
headers = doc.at_css('#content').css('h2').map(&:content)
lists = doc.at_css('#content').css('ul').map { | list | list.css('li') }
headers.each_with_index do |header, index|
process_index_header(header, index, lists)
end
end
def process_index_header(header, index, lists)
tree_item = {
name: header,
url: "#{@url_root}##{header.slugize}",
children: []
}
lists[index].each { |item| process_index_header_item(tree_item, item) }
@tree << tree_item
end
def process_index_header_item(tree_item, item)
tree_item[:children] << {
name: item.content,
url: "#{@url_root}#{item.at_css('a')['href'].sub('.html', '/').gsub('+', '%2B')}",
path: [item.content],
children: []
}
end
end
# DocEntryIos is an iOS documentation class used to process a single page
# of the iOS documentation.
class DocEntryPebbleKitIos
def initialize(entry, doc, url_root)
@entry = entry
@doc = doc
@url_root = url_root
end
def to_symbol
{ name: name, url: url.gsub('+', '%2B') }
end
def anchor_symbols
@doc.css('a[name^="//api"][title]').map do |anchor|
anchor_to_symbol(anchor)
end
end
def create_page(site)
return nil if @doc.at_css('#content').nil?
contents = @doc.at_css('#content')
title = @doc.at_css('.title').content
group = { 'path' => [File.basename(path)] }
PageDocPebbleKitIos.new(site, url, title, contents, group)
end
private
def name
File.basename(@entry.name).sub('.html', '')
end
def url
@url_root + path
end
def path
@entry.name.sub('.html', '/')
end
def anchor_to_symbol(anchor)
summary = @doc.at_css("a[name=\"#{anchor['name']}\"] + h3 + div")
{
name: anchor['title'],
url: (url + '#' + anchor['name']).gsub('+', '%2B'),
summary: summary.content
}
end
end
# Jekyll Page subclass for rendering the iOS documentation pages.
class PageDocPebbleKitIos < Jekyll::Page
attr_reader :group
def initialize(site, dir, title, contents, group)
@site = site
@base = site.source
@dir = dir
@name = 'index.html'
@contents = contents
@group = group
process(@name)
process_contents
read_yaml(File.join(@base, '_layouts', 'docs'), 'pebblekit-ios.html')
data['title'] = title
end
def to_liquid(attrs = ATTRIBUTES_FOR_LIQUID)
super(attrs + %w(
contents
group
))
end
def contents
@contents.to_html
end
private
def process_contents
# Clean up links
@contents.css('a').each { |link| process_page_link(link) }
remove_duplicated_title
switch_specification_section_table_headers_to_normal_cells
clean_up_method_titles
switch_parameter_tables_into_definition_lists
remove_footer
end
def process_page_link(link)
process_page_link_class(link) unless link['name'].nil?
process_page_link_href(link) unless link['href'].nil?
end
def process_page_link_class(link)
link['class'] = '' if link['class'].nil?
link['class'] << ' anchor'
end
def process_page_link_href(link)
link['href'] = link['href'].gsub('../', '../../')
link['href'] = link['href'].gsub('.html', '/')
link['href'] = link['href'].gsub('+', '%2B')
end
def remove_duplicated_title
@contents.css('h1').each(&:remove)
end
def switch_specification_section_table_headers_to_normal_cells
@contents.css('.section-specification th').each do |n|
n.node_name = 'td'
n['class'] = 'specification-title'
end
end
def clean_up_method_titles
# Remove the <code><a> tags inside h3.method-title nodes, strip nbsp and
# add the subsubtitle class.
@contents.css('h3.method-title').each do |n|
method_title = n.at_css('code a')
n.content = method_title.content.gsub(/\A\u00A0+/, '') if method_title
n['class'] = 'subsubtitle method-title'
end
end
def switch_parameter_tables_into_definition_lists
# Change the table node into a definition list
# For each row recover the parameter name and the description, and add
# them to the list as term and definition.
@contents.css('table.argument-def').each do |table|
table.node_name = 'dl'
parameters = table.css('tr').map do |row|
parameter = row.at_css('th.argument-name code')
parameter.node_name = 'em'
dt = Nokogiri::XML::Element.new('dt', table.document)
dt.add_child parameter
definition = row.at_css('td:not(.argument-name)').content
dd = Nokogiri::XML::Element.new('dd', table.document)
dd.children = definition
[dt, dd]
end.flatten(1)
table.children.unlink
parameters.each { |p| table.add_child p }
end
end
def remove_footer
@contents.css('footer').each(&:remove)
end
end
end