1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
|
# frozen_string_literal: true
include Helpers::ModuleHelper
def init
options.objects = objects = run_verifier(options.objects)
return serialize_onefile if options.onefile
generate_assets
serialize('_index.html')
options.files.each_with_index do |file, _i|
serialize_file(file, file.title)
end
options.delete(:objects)
options.delete(:files)
objects.each do |object|
begin
serialize(object)
rescue => e
path = options.serializer.serialized_path(object)
log.error "Exception occurred while generating '#{path}'"
log.backtrace(e)
end
end
end
# Generate an HTML document for the specified object. This method is used by
# most of the objects found in the Registry.
# @param [CodeObject] object to be saved to HTML
def serialize(object)
options.object = object
serialize_index(options) if object == '_index.html' && options.readme.nil?
Templates::Engine.with_serializer(object, options.serializer) do
T('layout').run(options)
end
end
# Generate the documentation output in one file (--one-file) which will load the
# contents of all the javascript and css and output the entire contents without
# depending on any additional files
def serialize_onefile
Templates::Engine.with_serializer('index.html', options.serializer) do
T('onefile').run(options)
end
end
# Generate the index document for the output
# @params [Hash] options contains data and flags that influence the output
def serialize_index(options)
Templates::Engine.with_serializer('index.html', options.serializer) do
T('layout').run(options.merge(:index => true))
end
end
# Generate a single HTML file with the layout template applied. This is generally
# the README file or files specified on the command-line.
#
# @param [File] file object to be saved to the output
# @param [String] title currently unused
#
# @see layout#diskfile
def serialize_file(file, title = nil) # rubocop:disable Lint/UnusedMethodArgument
options.object = Registry.root
options.file = file
outfile = 'file.' + file.name + '.html'
serialize_index(options) if file == options.readme
Templates::Engine.with_serializer(outfile, options.serializer) do
T('layout').run(options)
end
options.delete(:file)
end
#
# Generates a file to the output with the specified contents.
#
# @example saving a custom html file to the documentation root
#
# asset('my_custom.html','<html><body>Custom File</body></html>')
#
# @param [String] path relative to the document output where the file will be
# created.
# @param [String] content the contents that are saved to the file.
def asset(path, content)
if options.serializer
log.capture("Generating asset #{path}") do
options.serializer.serialize(path, content)
end
end
end
# @return [Array<String>] Stylesheet files that are additionally loaded for the
# searchable full lists, e.g., Class List, Method List, File List
# @since 0.7.0
def stylesheets_full_list
%w(css/full_list.css css/common.css)
end
# @return [Array<String>] Javascript files that are additionally loaded for the
# searchable full lists, e.g., Class List, Method List, File List.
# @since 0.7.0
def javascripts_full_list
%w(js/jquery.js js/full_list.js)
end
def menu_lists
Object.new.extend(T('layout')).menu_lists
end
# Generates all the javascript files, stylesheet files, menu lists
# (i.e. class, method, and file) based on the the values returned from the
# layout's menu_list method, and the frameset in the documentation output
#
def generate_assets
@object = Registry.root
layout = Object.new.extend(T('layout'))
(layout.javascripts + javascripts_full_list +
layout.stylesheets + stylesheets_full_list).uniq.each do |file|
asset(file, file(file, true))
end
layout.menu_lists.each do |list|
list_generator_method = "generate_#{list[:type]}_list"
if respond_to?(list_generator_method)
send(list_generator_method)
else
log.error "Unable to generate '#{list[:title]}' list because no method " \
"'#{list_generator_method}' exists"
end
end
generate_frameset
end
# Generate a searchable method list in the output
# @see ModuleHelper#prune_method_listing
def generate_method_list
@items = prune_method_listing(Registry.all(:method), false)
@items = @items.reject {|m| m.name.to_s =~ /=$/ && m.is_attribute? }
@items = @items.sort_by {|m| m.name.to_s }
@list_title = "Method List"
@list_type = "method"
generate_list_contents
end
# Generate a searchable class list in the output
def generate_class_list
@items = options.objects if options.objects
@list_title = "Class List"
@list_type = "class"
generate_list_contents
end
# Generate a searchable file list in the output
def generate_file_list
@file_list = true
@items = options.files
@list_title = "File List"
@list_type = "file"
generate_list_contents
@file_list = nil
end
def generate_list_contents
asset(url_for_list(@list_type), erb(:full_list))
end
# Generate the frame documentation in the output
def generate_frameset
@javascripts = javascripts_full_list
@stylesheets = stylesheets_full_list
asset(url_for_frameset, erb(:frames))
end
# @api private
class TreeContext
def initialize
@depth = 0
@even_odd = Alternator.new(:even, :odd)
end
def nest
@depth += 1
yield
@depth -= 1
end
# @return [String] Returns a css pixel offset, e.g. "30px"
def indent
"#{(@depth + 2) * 15}px"
end
def classes
classes = []
classes << 'collapsed' if @depth > 0
classes << @even_odd.next if @depth < 2
classes
end
class Alternator
def initialize(first, second)
@next = first
@after = second
end
def next
@next, @after = @after, @next
@after
end
end
end
# @return [String] HTML output of the classes to be displayed in the
# full_list_class template.
def class_list(root = Registry.root, tree = TreeContext.new)
out = String.new("")
children = run_verifier(root.children)
if root == Registry.root
children += @items.select {|o| o.namespace.is_a?(CodeObjects::Proxy) }
end
children.compact.sort_by(&:path).each do |child|
next unless child.is_a?(CodeObjects::NamespaceObject)
name = child.namespace.is_a?(CodeObjects::Proxy) ? child.path : child.name
has_children = run_verifier(child.children).any? {|o| o.is_a?(CodeObjects::NamespaceObject) }
out << "<li id='object_#{child.path}' class='#{tree.classes.join(' ')}'>"
out << "<div class='item' style='padding-left:#{tree.indent}'>"
out << "<a class='toggle'></a> " if has_children
out << linkify(child, name)
out << " < #{child.superclass.name}" if child.is_a?(CodeObjects::ClassObject) && child.superclass
out << "<small class='search_info'>"
out << child.namespace.title
out << "</small>"
out << "</div>"
tree.nest do
out << "<ul>#{class_list(child, tree)}</ul>" if has_children
end
out << "</li>"
end
out
end
|