diff options
author | Brice Figureau <brice-puppet@daysofwonder.com> | 2008-11-15 13:21:00 +0100 |
---|---|---|
committer | James Turnbull <james@lovedthanlost.net> | 2008-11-17 21:06:00 +1100 |
commit | dc192b00dc2c44b6174cb4a84663e8ad4e561d3c (patch) | |
tree | 03687997d058008de0a5a9d70a0bae76e24828f4 /lib/puppet/util/rdoc/generators | |
parent | 2c05a0abcb55347c179e66bb0c9d23698e729046 (diff) | |
download | puppet-dc192b00dc2c44b6174cb4a84663e8ad4e561d3c.tar.gz puppet-dc192b00dc2c44b6174cb4a84663e8ad4e561d3c.tar.xz puppet-dc192b00dc2c44b6174cb4a84663e8ad4e561d3c.zip |
Manifest documentation generation
There is currently two type of documentation generation
for manifests (module or modulepath):
* RDoc HTML generation for modules and global manifests
* console output for sole manifest
Both version handles classes, defines, nodes, global
variable assignements, and resources when --all is used.
The usage is the following:
For the rdoc variant:
$ puppetdoc --mode rdoc --outputdir doc
It uses the puppet.conf configuration file to get the modulepath
and manifestdir settings. Those are overridable on the
command line with --modulepath and --manifestdir.
For the console output version:
$ puppetdoc /path/to/manifests
Signed-off-by: Brice Figureau <brice-puppet@daysofwonder.com>
Diffstat (limited to 'lib/puppet/util/rdoc/generators')
-rw-r--r-- | lib/puppet/util/rdoc/generators/puppet_generator.rb | 829 | ||||
-rw-r--r-- | lib/puppet/util/rdoc/generators/template/puppet/puppet.rb | 1051 |
2 files changed, 1880 insertions, 0 deletions
diff --git a/lib/puppet/util/rdoc/generators/puppet_generator.rb b/lib/puppet/util/rdoc/generators/puppet_generator.rb new file mode 100644 index 000000000..22f001164 --- /dev/null +++ b/lib/puppet/util/rdoc/generators/puppet_generator.rb @@ -0,0 +1,829 @@ +require 'rdoc/generators/html_generator' +require 'puppet/util/rdoc/code_objects' +module Generators + + # This module holds all the classes needed to generate the HTML documentation + # of a bunch of puppet manifests. + # + # It works by traversing all the code objects defined by the Puppet RDoc::Parser + # and produces HTML counterparts objects that in turns are used by RDoc template engine + # to produce the final HTML. + # + # It is also responsible of creating the whole directory hierarchy, and various index + # files. + # + # It is to be noted that the whole system is built on top of ruby RDoc. As such there + # is an implicit mapping of puppet entities to ruby entitites: + # + # Puppet => Ruby + # ------------------------ + # Module Module + # Class Class + # Definition Method + # Resource + # Node + # Plugin + # Fact + + MODULE_DIR = "modules" + NODE_DIR = "nodes" + PLUGIN_DIR = "plugins" + + # This is a specialized HTMLGenerator tailored to Puppet manifests + class PuppetGenerator < HTMLGenerator + + def PuppetGenerator.for(options) + AllReferences::reset + HtmlMethod::reset + + if options.all_one_file + PuppetGeneratorInOne.new(options) + else + PuppetGenerator.new(options) + end + end + + def initialize(options) #:not-new: + @options = options + load_html_template + end + + # loads our own html template file + def load_html_template + begin + require 'puppet/util/rdoc/generators/template/puppet/puppet' + extend RDoc::Page + rescue LoadError + $stderr.puts "Could not find Puppet template '#{template}'" + exit 99 + end + end + + def gen_method_index + # we don't generate an all define index + # as the presentation is per module/per class + end + + # This is the central method, it generates the whole structures + # along with all the indices. + def generate_html + super + gen_into(@nodes) + gen_into(@plugins) + end + + ## + # Generate: + # the list of modules + # the list of classes and definitions of a specific module + # the list of all classes + # the list of nodes + # the list of resources + def build_indices + @allfiles = [] + @nodes = [] + @plugins = [] + + # contains all the seen modules + @modules = {} + @allclasses = {} + + # build the modules, classes and per modules classes and define list + @toplevels.each do |toplevel| + next unless toplevel.document_self + file = HtmlFile.new(toplevel, @options, FILE_DIR) + classes = [] + methods = [] + modules = [] + nodes = [] + + # find all classes of this toplevel + # store modules if we find one + toplevel.each_classmodule do |k| + generate_class_list(classes, modules, k, toplevel, CLASS_DIR) + end + + # find all defines belonging to this toplevel + HtmlMethod.all_methods.each do |m| + # find parent module, check this method is not already + # defined. + if m.context.parent.toplevel === toplevel + methods << m + end + end + + classes.each do |k| + @allclasses[k.index_name] = k if !@allclasses.has_key?(k.index_name) + end + + # generate nodes and plugins found + classes.each do |k| + if k.context.is_module? + k.context.each_node do |name,node| + nodes << HTMLPuppetNode.new(node, toplevel, NODE_DIR, @options) + @nodes << nodes.last + end + k.context.each_plugin do |plugin| + @plugins << HTMLPuppetPlugin.new(plugin, toplevel, PLUGIN_DIR, @options) + end + k.context.each_fact do |fact| + @plugins << HTMLPuppetPlugin.new(fact, toplevel, PLUGIN_DIR, @options) + end + end + end + + @files << file + @allfiles << { "file" => file, "modules" => modules, "classes" => classes, "methods" => methods, "nodes" => nodes } + end + + @classes = @allclasses.values + end + + # produce a class/module list of HTMLPuppetModule/HTMLPuppetClass + # based on the code object traversal. + def generate_class_list(classes, modules, from, html_file, class_dir) + if from.is_module? and !@modules.has_key?(from.name) + k = HTMLPuppetModule.new(from, html_file, class_dir, @options) + classes << k + @modules[from.name] = k + modules << @modules[from.name] + elsif from.is_module? + modules << @modules[from.name] + elsif !from.is_module? + k = HTMLPuppetClass.new(from, html_file, class_dir, @options) + classes << k + end + from.each_classmodule do |mod| + generate_class_list(classes, modules, mod, html_file, class_dir) + end + end + + # generate all the subdirectories, modules, classes and files + def gen_sub_directories + begin + super + File.makedirs(MODULE_DIR) + File.makedirs(NODE_DIR) + File.makedirs(PLUGIN_DIR) + rescue + $stderr.puts $!.message + exit 1 + end + end + + # generate the index of modules + def gen_file_index + gen_top_index(@modules.values, 'All Modules', RDoc::Page::TOP_INDEX, "fr_modules_index.html") + end + + # generate a top index + def gen_top_index(collection, title, template, filename) + template = TemplatePage.new(RDoc::Page::FR_INDEX_BODY, template) + res = [] + collection.sort.each do |f| + if f.document_self + res << { "classlist" => CGI.escapeHTML("#{MODULE_DIR}/fr_#{f.index_name}.html"), "module" => CGI.escapeHTML("#{CLASS_DIR}/#{f.index_name}.html"),"name" => CGI.escapeHTML(f.index_name) } + end + end + + values = { + "entries" => res, + 'list_title' => CGI.escapeHTML(title), + 'index_url' => main_url, + 'charset' => @options.charset, + 'style_url' => style_url('', @options.css), + } + + File.open(filename, "w") do |f| + template.write_html_on(f, values) + end + end + + # generate the all classes index file and the combo index + def gen_class_index + gen_an_index(@classes, 'All Classes', RDoc::Page::CLASS_INDEX, "fr_class_index.html") + @allfiles.each do |file| + unless file['file'].context.file_relative_name =~ /\.rb$/ + gen_composite_index(file, + RDoc::Page::COMBO_INDEX, + "#{MODULE_DIR}/fr_#{file["file"].context.module_name}.html") + end + end + end + + def gen_composite_index(collection, template, filename)\ + return if FileTest.exists?(filename) + + template = TemplatePage.new(RDoc::Page::FR_INDEX_BODY, template) + res1 = [] + collection['classes'].sort.each do |f| + if f.document_self + unless f.context.is_module? + res1 << { "href" => "../"+CGI.escapeHTML(f.path), "name" => CGI.escapeHTML(f.index_name) } + end + end + end + + res2 = [] + collection['methods'].sort.each do |f| + if f.document_self + res2 << { "href" => "../"+f.path, "name" => f.index_name.sub(/\(.*\)$/,'') } + end + end + + module_name = [] + res3 = [] + res4 = [] + collection['modules'].sort.each do |f| + module_name << { "href" => "../"+CGI.escapeHTML(f.path), "name" => CGI.escapeHTML(f.index_name) } + unless f.facts.nil? + f.facts.each do |fact| + res3 << {"href" => "../"+CGI.escapeHTML(AllReferences["PLUGIN(#{fact.name})"].path), "name" => CGI.escapeHTML(fact.name)} + end + end + unless f.plugins.nil? + f.plugins.each do |plugin| + res4 << {"href" => "../"+CGI.escapeHTML(AllReferences["PLUGIN(#{plugin.name})"].path), "name" => CGI.escapeHTML(plugin.name)} + end + end + end + + res5 = [] + collection['nodes'].sort.each do |f| + if f.document_self + res5 << { "href" => "../"+CGI.escapeHTML(f.path), "name" => CGI.escapeHTML(f.name) } + end + end + + values = { + "module" => module_name, + "classes" => res1, + 'classes_title' => CGI.escapeHTML("Classes"), + 'defines_title' => CGI.escapeHTML("Defines"), + 'facts_title' => CGI.escapeHTML("Custom Facts"), + 'plugins_title' => CGI.escapeHTML("Plugins"), + 'nodes_title' => CGI.escapeHTML("Nodes"), + 'index_url' => main_url, + 'charset' => @options.charset, + 'style_url' => style_url('', @options.css), + } + + values["defines"] = res2 if res2.size>0 + values["facts"] = res3 if res3.size>0 + values["plugins"] = res4 if res4.size>0 + values["nodes"] = res5 if res5.size>0 + + File.open(filename, "w") do |f| + template.write_html_on(f, values) + end + end + + # returns the initial_page url + def main_url + main_page = @options.main_page + ref = nil + if main_page + ref = AllReferences[main_page] + if ref + ref = ref.path + else + $stderr.puts "Could not find main page #{main_page}" + end + end + + unless ref + for file in @files + if file.document_self and file.context.global + ref = CGI.escapeHTML("#{CLASS_DIR}/#{file.context.module_name}.html") + break + end + end + end + + unless ref + for file in @files + if file.document_self and !file.context.global + ref = CGI.escapeHTML("#{CLASS_DIR}/#{file.context.module_name}.html") + break + end + end + end + + unless ref + $stderr.puts "Couldn't find anything to document" + $stderr.puts "Perhaps you've used :stopdoc: in all classes" + exit(1) + end + + ref + end + + end + + # This module is used to hold/generate a list of puppet resources + # this is used in HTMLPuppetClass and HTMLPuppetNode + module ResourceContainer + def collect_resources + list = @context.resource_list + @resources = list.collect {|m| HTMLPuppetResource.new(m, self, @options) } + end + + def build_resource_summary_list(path_prefix='') + collect_resources unless @resources + resources = @resources.sort + res = [] + resources.each do |r| + res << { + "name" => CGI.escapeHTML(r.name), + "aref" => "#{path_prefix}\##{r.aref}" + } + end + res + end + + def build_resource_detail_list(section) + outer = [] + resources = @resources.sort + resources.each do |r| + row = {} + if r.section == section and r.document_self + row["name"] = CGI.escapeHTML(r.name) + desc = r.description.strip + row["m_desc"] = desc unless desc.empty? + row["aref"] = r.aref + row["params"] = r.params + outer << row + end + end + outer + end + end + + class HTMLPuppetClass < HtmlClass + include ResourceContainer + + def value_hash + super + rl = build_resource_summary_list + @values["resources"] = rl unless rl.empty? + + @context.sections.each do |section| + secdata = @values["sections"].select { |secdata| secdata["secsequence"] == section.sequence } + if secdata.size == 1 + secdata = secdata[0] + + rdl = build_resource_detail_list(section) + secdata["resource_list"] = rdl unless rdl.empty? + end + end + @values + end + end + + class HTMLPuppetNode < ContextUser + include ResourceContainer + + attr_reader :path + + def initialize(context, html_file, prefix, options) + super(context, options) + + @html_file = html_file + @is_module = context.is_module? + @values = {} + + context.viewer = self + + if options.all_one_file + @path = context.full_name + else + @path = http_url(context.full_name, prefix) + end + + AllReferences.add("NODE(#{@context.full_name})", self) + end + + def name + @context.name + end + + # return the relative file name to store this class in, + # which is also its url + def http_url(full_name, prefix) + path = full_name.dup + if path['<<'] + path.gsub!(/<<\s*(\w*)/) { "from-#$1" } + end + File.join(prefix, path.split("::")) + ".html" + end + + def parent_name + @context.parent.full_name + end + + def index_name + name + end + + def write_on(f) + value_hash + template = TemplatePage.new(RDoc::Page::BODYINC, + RDoc::Page::NODE_PAGE, + RDoc::Page::METHOD_LIST) + template.write_html_on(f, @values) + end + + def value_hash + class_attribute_values + add_table_of_sections + + @values["charset"] = @options.charset + @values["style_url"] = style_url(path, @options.css) + + d = markup(@context.comment) + @values["description"] = d unless d.empty? + + ml = build_method_summary_list + @values["methods"] = ml unless ml.empty? + + rl = build_resource_summary_list + @values["resources"] = rl unless rl.empty? + + il = build_include_list(@context) + @values["includes"] = il unless il.empty? + + @values["sections"] = @context.sections.map do |section| + + secdata = { + "sectitle" => section.title, + "secsequence" => section.sequence, + "seccomment" => markup(section.comment) + } + + al = build_alias_summary_list(section) + secdata["aliases"] = al unless al.empty? + + co = build_constants_summary_list(section) + secdata["constants"] = co unless co.empty? + + al = build_attribute_list(section) + secdata["attributes"] = al unless al.empty? + + cl = build_class_list(0, @context, section) + secdata["classlist"] = cl unless cl.empty? + + mdl = build_method_detail_list(section) + secdata["method_list"] = mdl unless mdl.empty? + + rdl = build_resource_detail_list(section) + secdata["resource_list"] = rdl unless rdl.empty? + + secdata + end + + @values + end + + def build_attribute_list(section) + atts = @context.attributes.sort + res = [] + atts.each do |att| + next unless att.section == section + if att.visibility == :public || att.visibility == :protected || @options.show_all + entry = { + "name" => CGI.escapeHTML(att.name), + "rw" => att.rw, + "a_desc" => markup(att.comment, true) + } + unless att.visibility == :public || att.visibility == :protected + entry["rw"] << "-" + end + res << entry + end + end + res + end + + def class_attribute_values + h_name = CGI.escapeHTML(name) + + @values["classmod"] = "Node" + @values["title"] = "#{@values['classmod']}: #{h_name}" + + c = @context + c = c.parent while c and !c.diagram + + if c && c.diagram + @values["diagram"] = diagram_reference(c.diagram) + end + + @values["full_name"] = h_name + + parent_class = @context.superclass + + if parent_class + @values["parent"] = CGI.escapeHTML(parent_class) + + if parent_name + lookup = parent_name + "::" + parent_class + else + lookup = parent_class + end + lookup = "NODE(#{lookup})" + parent_url = AllReferences[lookup] || AllReferences[parent_class] + if parent_url and parent_url.document_self + @values["par_url"] = aref_to(parent_url.path) + end + end + + files = [] + @context.in_files.each do |f| + res = {} + full_path = CGI.escapeHTML(f.file_absolute_name) + + res["full_path"] = full_path + res["full_path_url"] = aref_to(f.viewer.path) if f.document_self + + if @options.webcvs + res["cvsurl"] = cvs_url( @options.webcvs, full_path ) + end + + files << res + end + + @values['infiles'] = files + end + + def <=>(other) + self.name <=> other.name + end + end + + class HTMLPuppetModule < HtmlClass + + def initialize(context, html_file, prefix, options) + super(context, html_file, prefix, options) + end + + def value_hash + @values = super + + fl = build_facts_summary_list + @values["facts"] = fl unless fl.empty? + + pl = build_plugins_summary_list + @values["plugins"] = pl unless pl.empty? + + nl = build_nodes_list(0, @context) + @values["nodelist"] = nl unless nl.empty? + + @values + end + + def build_nodes_list(level, context) + res = "" + prefix = " ::" * level; + + context.nodes.sort.each do |node| + if node.document_self + res << + prefix << + "Node " << + href(url(node.viewer.path), "link", node.full_name) << + "<br />\n" + end + end + res + end + + def build_facts_summary_list + potentially_referenced_list(context.facts) {|fn| ["PLUGIN(#{fn})"] } + end + + def build_plugins_summary_list + potentially_referenced_list(context.plugins) {|fn| ["PLUGIN(#{fn})"] } + end + + def facts + @context.facts + end + + def plugins + @context.plugins + end + + end + + class HTMLPuppetPlugin < ContextUser + attr_reader :path + + def initialize(context, html_file, prefix, options) + super(context, options) + + @html_file = html_file + @is_module = false + @values = {} + + context.viewer = self + + if options.all_one_file + @path = context.full_name + else + @path = http_url(context.full_name, prefix) + end + + AllReferences.add("PLUGIN(#{@context.full_name})", self) + end + + def name + @context.name + end + + # return the relative file name to store this class in, + # which is also its url + def http_url(full_name, prefix) + path = full_name.dup + if path['<<'] + path.gsub!(/<<\s*(\w*)/) { "from-#$1" } + end + File.join(prefix, path.split("::")) + ".html" + end + + def parent_name + @context.parent.full_name + end + + def index_name + name + end + + def write_on(f) + value_hash + template = TemplatePage.new(RDoc::Page::BODYINC, + RDoc::Page::PLUGIN_PAGE, + RDoc::Page::PLUGIN_LIST) + template.write_html_on(f, @values) + end + + def value_hash + attribute_values + add_table_of_sections + + @values["charset"] = @options.charset + @values["style_url"] = style_url(path, @options.css) + + d = markup(@context.comment) + @values["description"] = d unless d.empty? + + if context.is_fact? + unless context.confine.empty? + res = {} + res["type"] = context.confine[:type] + res["value"] = context.confine[:value] + @values["confine"] = [res] + end + else + @values["type"] = context.type + end + + @values["sections"] = @context.sections.map do |section| + secdata = { + "sectitle" => section.title, + "secsequence" => section.sequence, + "seccomment" => markup(section.comment) + } + secdata + end + + @values + end + + def attribute_values + h_name = CGI.escapeHTML(name) + + if @context.is_fact? + @values["classmod"] = "Fact" + else + @values["classmod"] = "Plugin" + end + @values["title"] = "#{@values['classmod']}: #{h_name}" + + c = @context + @values["full_name"] = h_name + + files = [] + @context.in_files.each do |f| + res = {} + full_path = CGI.escapeHTML(f.file_absolute_name) + + res["full_path"] = full_path + res["full_path_url"] = aref_to(f.viewer.path) if f.document_self + + if @options.webcvs + res["cvsurl"] = cvs_url( @options.webcvs, full_path ) + end + + files << res + end + + @values['infiles'] = files + end + + def <=>(other) + self.name <=> other.name + end + + end + + class HTMLPuppetResource + include MarkUp + + attr_reader :context + + @@seq = "R000000" + + def initialize(context, html_class, options) + @context = context + @html_class = html_class + @options = options + @@seq = @@seq.succ + @seq = @@seq + + context.viewer = self + + AllReferences.add(name, self) + end + + def as_href(from_path) + if @options.all_one_file + "#" + path + else + HTMLGenerator.gen_url(from_path, path) + end + end + + def name + @context.name + end + + def section + @context.section + end + + def index_name + "#{@context.name}" + end + + def params + @context.params + end + + def parent_name + if @context.parent.parent + @context.parent.parent.full_name + else + nil + end + end + + def aref + @seq + end + + def path + if @options.all_one_file + aref + else + @html_class.path + "#" + aref + end + end + + def description + markup(@context.comment) + end + + def <=>(other) + @context <=> other.context + end + + def document_self + @context.document_self + end + + def find_symbol(symbol, method=nil) + res = @context.parent.find_symbol(symbol, method) + if res + res = res.viewer + end + res + end + + end + + class PuppetGeneratorInOne < HTMLGeneratorInOne + def gen_method_index + gen_an_index(HtmlMethod.all_methods, 'Defines') + end + end + +end diff --git a/lib/puppet/util/rdoc/generators/template/puppet/puppet.rb b/lib/puppet/util/rdoc/generators/template/puppet/puppet.rb new file mode 100644 index 000000000..c71f81915 --- /dev/null +++ b/lib/puppet/util/rdoc/generators/template/puppet/puppet.rb @@ -0,0 +1,1051 @@ +# +# = CSS2 RDoc HTML template +# +# This is a template for RDoc that uses XHTML 1.0 Transitional and dictates a +# bit more of the appearance of the output to cascading stylesheets than the +# default. It was designed for clean inline code display, and uses DHTMl to +# toggle the visbility of each method's source with each click on the '[source]' +# link. +# +# == Authors +# +# * Michael Granger <ged@FaerieMUD.org> +# +# Copyright (c) 2002, 2003 The FaerieMUD Consortium. Some rights reserved. +# +# This work is licensed under the Creative Commons Attribution License. To view +# a copy of this license, visit http://creativecommons.org/licenses/by/1.0/ or +# send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California +# 94305, USA. +# + +module RDoc + module Page + + FONTS = "Verdana,Arial,Helvetica,sans-serif" + +STYLE = %{ +body { + font-family: Verdana,Arial,Helvetica,sans-serif; + font-size: 90%; + margin: 0; + margin-left: 40px; + padding: 0; + background: white; +} + +h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; } +h1 { font-size: 150%; } +h2,h3,h4 { margin-top: 1em; } + +a { background: #eef; color: #039; text-decoration: none; } +a:hover { background: #039; color: #eef; } + +/* Override the base stylesheet's Anchor inside a table cell */ +td > a { + background: transparent; + color: #039; + text-decoration: none; +} + +/* and inside a section title */ +.section-title > a { + background: transparent; + color: #eee; + text-decoration: none; +} + +/* === Structural elements =================================== */ + +div#index { + margin: 0; + margin-left: -40px; + padding: 0; + font-size: 90%; +} + + +div#index a { + margin-left: 0.7em; +} + +div#index .section-bar { + margin-left: 0px; + padding-left: 0.7em; + background: #ccc; + font-size: small; +} + + +div#classHeader, div#fileHeader { + width: auto; + color: white; + padding: 0.5em 1.5em 0.5em 1.5em; + margin: 0; + margin-left: -40px; + border-bottom: 3px solid #006; +} + +div#classHeader a, div#fileHeader a { + background: inherit; + color: white; +} + +div#classHeader td, div#fileHeader td { + background: inherit; + color: white; +} + + +div#fileHeader { + background: #057; +} + +div#classHeader { + background: #048; +} + +div#nodeHeader { + background: #7f7f7f; +} + +.class-name-in-header { + font-size: 180%; + font-weight: bold; +} + + +div#bodyContent { + padding: 0 1.5em 0 1.5em; +} + +div#description { + padding: 0.5em 1.5em; + background: #efefef; + border: 1px dotted #999; +} + +div#description h1,h2,h3,h4,h5,h6 { + color: #125;; + background: transparent; +} + +div#validator-badges { + text-align: center; +} +div#validator-badges img { border: 0; } + +div#copyright { + color: #333; + background: #efefef; + font: 0.75em sans-serif; + margin-top: 5em; + margin-bottom: 0; + padding: 0.5em 2em; +} + + +/* === Classes =================================== */ + +table.header-table { + color: white; + font-size: small; +} + +.type-note { + font-size: small; + color: #DEDEDE; +} + +.xxsection-bar { + background: #eee; + color: #333; + padding: 3px; +} + +.section-bar { + color: #333; + border-bottom: 1px solid #999; + margin-left: -20px; +} + + +.section-title { + background: #79a; + color: #eee; + padding: 3px; + margin-top: 2em; + margin-left: -30px; + border: 1px solid #999; +} + +.top-aligned-row { vertical-align: top } +.bottom-aligned-row { vertical-align: bottom } + +/* --- Context section classes ----------------------- */ + +.context-row { } +.context-item-name { font-family: monospace; font-weight: bold; color: black; } +.context-item-value { font-size: small; color: #448; } +.context-item-desc { color: #333; padding-left: 2em; } + +/* --- Method classes -------------------------- */ +.method-detail { + background: #efefef; + padding: 0; + margin-top: 0.5em; + margin-bottom: 1em; + border: 1px dotted #ccc; +} +.method-heading { + color: black; + background: #ccc; + border-bottom: 1px solid #666; + padding: 0.2em 0.5em 0 0.5em; +} +.method-signature { color: black; background: inherit; } +.method-name { font-weight: bold; } +.method-args { font-style: italic; } +.method-description { padding: 0 0.5em 0 0.5em; } + +/* --- Source code sections -------------------- */ + +a.source-toggle { font-size: 90%; } +div.method-source-code { + background: #262626; + color: #ffdead; + margin: 1em; + padding: 0.5em; + border: 1px dashed #999; + overflow: hidden; +} + +div.method-source-code pre { color: #ffdead; overflow: hidden; } + +/* --- Ruby keyword styles --------------------- */ + +.standalone-code { background: #221111; color: #ffdead; overflow: hidden; } + +.ruby-constant { color: #7fffd4; background: transparent; } +.ruby-keyword { color: #00ffff; background: transparent; } +.ruby-ivar { color: #eedd82; background: transparent; } +.ruby-operator { color: #00ffee; background: transparent; } +.ruby-identifier { color: #ffdead; background: transparent; } +.ruby-node { color: #ffa07a; background: transparent; } +.ruby-comment { color: #b22222; font-weight: bold; background: transparent; } +.ruby-regexp { color: #ffa07a; background: transparent; } +.ruby-value { color: #7fffd4; background: transparent; } +} + + +##################################################################### +### H E A D E R T E M P L A T E +##################################################################### + +XHTML_PREAMBLE = %{<?xml version="1.0" encoding="%charset%"?> +<!DOCTYPE html + PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +} + +HEADER = XHTML_PREAMBLE + %{ +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <title>%title%</title> + <meta http-equiv="Content-Type" content="text/html; charset=%charset%" /> + <meta http-equiv="Content-Script-Type" content="text/javascript" /> + <link rel="stylesheet" href="%style_url%" type="text/css" media="screen" /> + <script type="text/javascript"> + // <![CDATA[ + + function popupCode( url ) { + window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400") + } + + function toggleCode( id ) { + if ( document.getElementById ) + elem = document.getElementById( id ); + else if ( document.all ) + elem = eval( "document.all." + id ); + else + return false; + + elemStyle = elem.style; + + if ( elemStyle.display != "block" ) { + elemStyle.display = "block" + } else { + elemStyle.display = "none" + } + + return true; + } + + // Make codeblocks hidden by default + document.writeln( "<style type=\\"text/css\\">div.method-source-code { display: none }</style>" ) + + // ]]> + </script> + +</head> +<body> +} + + +##################################################################### +### C O N T E X T C O N T E N T T E M P L A T E +##################################################################### + +CONTEXT_CONTENT = %{ +} + + +##################################################################### +### F O O T E R T E M P L A T E +##################################################################### +FOOTER = %{ +<div id="validator-badges"> + <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p> +</div> + +</body> +</html> +} + + +##################################################################### +### F I L E P A G E H E A D E R T E M P L A T E +##################################################################### + +FILE_PAGE = %{ + <div id="fileHeader"> + <h1>%short_name%</h1> + <table class="header-table"> + <tr class="top-aligned-row"> + <td><strong>Path:</strong></td> + <td>%full_path% +IF:cvsurl + (<a href="%cvsurl%"><acronym title="Concurrent Versioning System">CVS</acronym></a>) +ENDIF:cvsurl + </td> + </tr> + <tr class="top-aligned-row"> + <td><strong>Last Update:</strong></td> + <td>%dtm_modified%</td> + </tr> + </table> + </div> +} + + +##################################################################### +### C L A S S P A G E H E A D E R T E M P L A T E +##################################################################### + +CLASS_PAGE = %{ + <div id="classHeader"> + <table class="header-table"> + <tr class="top-aligned-row"> + <td><strong>%classmod%</strong></td> + <td class="class-name-in-header">%full_name%</td> + </tr> + <tr class="top-aligned-row"> + <td><strong>In:</strong></td> + <td> +START:infiles +IF:full_path_url + <a href="%full_path_url%"> +ENDIF:full_path_url + %full_path% +IF:full_path_url + </a> +ENDIF:full_path_url +IF:cvsurl + (<a href="%cvsurl%"><acronym title="Concurrent Versioning System">CVS</acronym></a>) +ENDIF:cvsurl + <br /> +END:infiles + </td> + </tr> + +IF:parent + <tr class="top-aligned-row"> + <td><strong>Parent:</strong></td> + <td> +IF:par_url + <a href="%par_url%"> +ENDIF:par_url + %parent% +IF:par_url + </a> +ENDIF:par_url + </td> + </tr> +ENDIF:parent + </table> + </div> +} + +NODE_PAGE = %{ + <div id="nodeHeader"> + <table class="header-table"> + <tr class="top-aligned-row"> + <td><strong>%classmod%</strong></td> + <td class="class-name-in-header">%full_name%</td> + </tr> + <tr class="top-aligned-row"> + <td><strong>In:</strong></td> + <td> +START:infiles +IF:full_path_url + <a href="%full_path_url%"> +ENDIF:full_path_url + %full_path% +IF:full_path_url + </a> +ENDIF:full_path_url +IF:cvsurl + (<a href="%cvsurl%"><acronym title="Concurrent Versioning System">CVS</acronym></a>) +ENDIF:cvsurl + <br /> +END:infiles + </td> + </tr> + +IF:parent + <tr class="top-aligned-row"> + <td><strong>Parent:</strong></td> + <td> +IF:par_url + <a href="%par_url%"> +ENDIF:par_url + %parent% +IF:par_url + </a> +ENDIF:par_url + </td> + </tr> +ENDIF:parent + </table> + </div> +} + +PLUGIN_PAGE = %{ + <div id="classHeader"> + <table class="header-table"> + <tr class="top-aligned-row"> + <td><strong>%classmod%</strong></td> + <td class="class-name-in-header">%full_name%</td> + </tr> + <tr class="top-aligned-row"> + <td><strong>In:</strong></td> + <td> +START:infiles +IF:full_path_url + <a href="%full_path_url%"> +ENDIF:full_path_url + %full_path% +IF:full_path_url + </a> +ENDIF:full_path_url +IF:cvsurl + (<a href="%cvsurl%"><acronym title="Concurrent Versioning System">CVS</acronym></a>) +ENDIF:cvsurl + <br /> +END:infiles + </td> + </tr> + </table> + </div> +} + + +##################################################################### +### M E T H O D L I S T T E M P L A T E +##################################################################### + +PLUGIN_LIST = %{ + + <div id="contextContent"> +IF:description + <div id="description"> + %description% + </div> +ENDIF:description + + +IF:toc + <div id="contents-list"> + <h3 class="section-bar">Contents</h3> + <ul> +START:toc + <li><a href="#%href%">%secname%</a></li> +END:toc + </ul> +ENDIF:toc + </div> + + </div> + +<!-- Confine --> +IF:confine +START:confine + <div id="attribute-list"> + <h3 class="section-bar">Confine</h3> + %type% %value% + <div class="name-list"> + </div> + </div> +END:confine +ENDIF:confine + +<!-- Type --> +IF:type + <div id="attribute-list"> + <h3 class="section-bar">Type</h3> + %type% + <div class="name-list"> + </div> + </div> +ENDIF:type + +START:sections + <div id="section"> +IF:sectitle + <h2 class="section-title"><a name="%secsequence%">%sectitle%</a></h2> +IF:seccomment + <div class="section-comment"> + %seccomment% + </div> +ENDIF:seccomment +ENDIF:sectitle +END:sections +} + + +METHOD_LIST = %{ + + <div id="contextContent"> +IF:diagram + <div id="diagram"> + %diagram% + </div> +ENDIF:diagram + +IF:description + <div id="description"> + %description% + </div> +ENDIF:description + +IF:requires + <div id="requires-list"> + <h3 class="section-bar">Required files</h3> + + <div class="name-list"> +START:requires + HREF:aref:name: +END:requires + </div> + </div> +ENDIF:requires + +IF:toc + <div id="contents-list"> + <h3 class="section-bar">Contents</h3> + <ul> +START:toc + <li><a href="#%href%">%secname%</a></li> +END:toc + </ul> +ENDIF:toc + </div> + +IF:methods + <div id="method-list"> + <h3 class="section-bar">Defines</h3> + + <div class="name-list"> +START:methods + HREF:aref:name: +END:methods + </div> + </div> +ENDIF:methods + +IF:resources + <div id="method-list"> + <h3 class="section-bar">Resources</h3> + + <div class="name-list"> +START:resources + HREF:aref:name: +END:resources + </div> + </div> +ENDIF:resources + + </div> + + + <!-- if includes --> +IF:includes + <div id="includes"> + <h3 class="section-bar">Included Classes</h3> + + <div id="includes-list"> +START:includes + <span class="include-name">HREF:aref:name:</span> +END:includes + </div> + </div> +ENDIF:includes + +START:sections + <div id="section"> +IF:sectitle + <h2 class="section-title"><a name="%secsequence%">%sectitle%</a></h2> +IF:seccomment + <div class="section-comment"> + %seccomment% + </div> +ENDIF:seccomment +ENDIF:sectitle + + +<!-- if facts --> +IF:facts + <div id="class-list"> + <h3 class="section-bar">Custom Facts</h3> +START:facts + HREF:aref:name: +END:facts + </div> +ENDIF:facts + +<!-- if plugins --> +IF:plugins + <div id="class-list"> + <h3 class="section-bar">Plugins</h3> +START:plugins +HREF:aref:name: +END:plugins + </div> +ENDIF:plugins + +<!-- if nodes --> +IF:nodelist + <div id="class-list"> + <h3 class="section-bar">Nodes</h3> + + %nodelist% + </div> +ENDIF:nodelist + +<!-- if class --> +IF:classlist + <div id="class-list"> + <h3 class="section-bar">Classes and Modules</h3> + + %classlist% + </div> +ENDIF:classlist + +IF:constants + <div id="constants-list"> + <h3 class="section-bar">Global Variables</h3> + + <div class="name-list"> + <table summary="Variables"> +START:constants + <tr class="top-aligned-row context-row"> + <td class="context-item-name">%name%</td> + <td>=</td> + <td class="context-item-value">%value%</td> +IF:desc + <td width="3em"> </td> + <td class="context-item-desc">%desc%</td> +ENDIF:desc + </tr> +END:constants + </table> + </div> + </div> +ENDIF:constants + +IF:aliases + <div id="aliases-list"> + <h3 class="section-bar">External Aliases</h3> + + <div class="name-list"> + <table summary="aliases"> +START:aliases + <tr class="top-aligned-row context-row"> + <td class="context-item-name">%old_name%</td> + <td>-></td> + <td class="context-item-value">%new_name%</td> + </tr> +IF:desc + <tr class="top-aligned-row context-row"> + <td> </td> + <td colspan="2" class="context-item-desc">%desc%</td> + </tr> +ENDIF:desc +END:aliases + </table> + </div> + </div> +ENDIF:aliases + + +IF:attributes + <div id="attribute-list"> + <h3 class="section-bar">Attributes</h3> + + <div class="name-list"> + <table> +START:attributes + <tr class="top-aligned-row context-row"> + <td class="context-item-name">%name%</td> +IF:rw + <td class="context-item-value"> [%rw%] </td> +ENDIF:rw +IFNOT:rw + <td class="context-item-value"> </td> +ENDIF:rw + <td class="context-item-desc">%a_desc%</td> + </tr> +END:attributes + </table> + </div> + </div> +ENDIF:attributes + + + + <!-- if method_list --> +IF:method_list + <div id="methods"> +START:method_list +IF:methods + <h3 class="section-bar">Defines</h3> + +START:methods + <div id="method-%aref%" class="method-detail"> + <a name="%aref%"></a> + + <div class="method-heading"> +IF:codeurl + <a href="%codeurl%" target="Code" class="method-signature" + onclick="popupCode('%codeurl%');return false;"> +ENDIF:codeurl +IF:sourcecode + <a href="#%aref%" class="method-signature"> +ENDIF:sourcecode +IF:callseq + <span class="method-name">%callseq%</span> +ENDIF:callseq +IFNOT:callseq + <span class="method-name">%name%</span><span class="method-args">%params%</span> +ENDIF:callseq +IF:codeurl + </a> +ENDIF:codeurl +IF:sourcecode + </a> +ENDIF:sourcecode + </div> + + <div class="method-description"> +IF:m_desc + %m_desc% +ENDIF:m_desc +IF:sourcecode + <p><a class="source-toggle" href="#" + onclick="toggleCode('%aref%-source');return false;">[Source]</a></p> + <div class="method-source-code" id="%aref%-source"> +<pre> +%sourcecode% +</pre> + </div> +ENDIF:sourcecode + </div> + </div> + +END:methods +ENDIF:methods +END:method_list + + </div> +ENDIF:method_list + + + <!-- if resource_list --> +IF:resource_list + <div id="resources"> + <h3 class="section-bar">Resources</h3> +START:resource_list + + <div id="method-%aref%" class="method-detail"> + <a name="%aref%"></a> + + <div class="method-heading"> + <span class="method-name">%name%</span><br /> +IF:params +START:params + <span class="method-args">%name% => %value%</span><br /> +END:params +ENDIF:params + </div> + + <div class="method-description"> +IF:m_desc + %m_desc% +ENDIF:m_desc + </div> + </div> +END:resource_list + + </div> +ENDIF:resource_list + +END:sections +} + + +##################################################################### +### B O D Y T E M P L A T E +##################################################################### + +BODY = HEADER + %{ + +!INCLUDE! <!-- banner header --> + + <div id="bodyContent"> + +} + METHOD_LIST + %{ + + </div> + +} + FOOTER + +BODYINC = HEADER + %{ + +!INCLUDE! <!-- banner header --> + + <div id="bodyContent"> + +!INCLUDE! + + </div> + +} + FOOTER + + + +##################################################################### +### S O U R C E C O D E T E M P L A T E +##################################################################### + +SRC_PAGE = XHTML_PREAMBLE + %{ +<html> +<head> + <title>%title%</title> + <meta http-equiv="Content-Type" content="text/html; charset=%charset%" /> + <link rel="stylesheet" href="%style_url%" type="text/css" media="screen" /> +</head> +<body class="standalone-code"> + <pre>%code%</pre> +</body> +</html> +} + + +##################################################################### +### I N D E X F I L E T E M P L A T E S +##################################################################### + +FR_INDEX_BODY = %{ +!INCLUDE! +} + +FILE_INDEX = XHTML_PREAMBLE + %{ +<!-- + + %list_title% + + --> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <title>%list_title%</title> + <meta http-equiv="Content-Type" content="text/html; charset=%charset%" /> + <link rel="stylesheet" href="%style_url%" type="text/css" /> + <base target="docwin" /> +</head> +<body> +<div id="index"> + <h1 class="section-bar">%list_title%</h1> + <div id="index-entries"> +START:entries + <a href="%href%">%name%</a><br /> +END:entries + </div> +</div> +</body> +</html> +} + +TOP_INDEX = XHTML_PREAMBLE + %{ +<!-- + + %list_title% + + --> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <title>%list_title%</title> + <meta http-equiv="Content-Type" content="text/html; charset=%charset%" /> + <link rel="stylesheet" href="%style_url%" type="text/css" /> + <base target="classes" /> + <SCRIPT LANGUAGE="JavaScript"> + <!-- + function load(classlist,module) { + parent.classes.location.href = classlist; + parent.docwin.location.href = module; + } + //--></SCRIPT> +</head> +<body> +<div id="index"> + <h1 class="section-bar">%list_title%</h1> + <div id="index-entries"> +START:entries + <a href="%classlist%" onclick="load('%classlist%','%module%'); return true;">%name%</a><br /> +END:entries + </div> +</div> +</body> +</html> +} + + +CLASS_INDEX = FILE_INDEX +METHOD_INDEX = FILE_INDEX + +COMBO_INDEX = XHTML_PREAMBLE + %{ +<!-- + + %classes_title% & %defines_title% + + --> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <title>%classes_title% & %defines_title%</title> + <meta http-equiv="Content-Type" content="text/html; charset=%charset%" /> + <link rel="stylesheet" href="../%style_url%" type="text/css" /> + <base target="docwin" /> + <SCRIPT LANGUAGE="JavaScript"> + <!-- + function load(url) { + parent.docwin.location.href = url; + } + //--></SCRIPT> + +</head> +<body> +<div id="index"> + + <a href="../fr_class_index.html" target="classes">All Classes</a><br /> + + +<h1 class="section-bar">Module</h1> + <div id="index-entries"> +START:module + <a href="%href%" onclick="load('%href%'); return true;">%name%</a><br /> +END:module + </div> + </div> +<div id="index"> + +IF:nodes + <h1 class="section-bar">%nodes_title%</h1> + <div id="index-entries"> +START:nodes +<a href="%href%" onclick="load('%href%'); return true;">%name%</a><br /> +END:nodes + </div> +ENDIF:nodes + +IF:classes + <h1 class="section-bar">%classes_title%</h1> + <div id="index-entries"> +START:classes +<a href="%href%" onclick="load('%href%'); return true;">%name%</a><br /> +END:classes + </div> +ENDIF:classes + +IF:defines + <h1 class="section-bar">%defines_title%</h1> + <div id="index-entries"> +START:defines +<a href="%href%" onclick="load('%href%'); return true;">%name%</a><br /> +END:defines + </div> +ENDIF:defines + +IF:facts + <h1 class="section-bar">%facts_title%</h1> + <div id="index-entries"> +START:facts +<a href="%href%" onclick="load('%href%'); return true;">%name%</a><br /> +END:facts + </div> +ENDIF:facts + + +IF:plugins + <h1 class="section-bar">%plugins_title%</h1> + <div id="index-entries"> +START:plugins +<a href="%href%" onclick="load('%href%'); return true;">%name%</a><br /> +END:plugins + </div> +ENDIF:plugins + +</div> +</body> +</html> +} + +INDEX = %{<?xml version="1.0" encoding="%charset%"?> +<!DOCTYPE html + PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"> + +<!-- + + %title% + + --> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <title>%title%</title> + <meta http-equiv="Content-Type" content="text/html; charset=%charset%" /> +</head> +<frameset cols="20%, 80%"> + <frameset rows="30%,70%"> + <frame src="fr_modules_index.html" title="All Modules" /> + <frame src="fr_class_index.html" name="classes" title="Classes & Defines" /> + </frameset> + <frame src="%initial_page%" name="docwin" /> +</frameset> +</html> +} + + + + end # module Page +end # class RDoc + +require 'rdoc/generators/template/html/one_page_html' |