summaryrefslogtreecommitdiff
path: root/lib/rdoc/generator/html.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rdoc/generator/html.rb')
-rw-r--r--lib/rdoc/generator/html.rb226
1 files changed, 137 insertions, 89 deletions
diff --git a/lib/rdoc/generator/html.rb b/lib/rdoc/generator/html.rb
index a9e030a896..d136de7b00 100644
--- a/lib/rdoc/generator/html.rb
+++ b/lib/rdoc/generator/html.rb
@@ -68,7 +68,6 @@ class RDoc::Generator::HTML
def initialize(options) #:not-new:
@options = options
load_html_template
- @main_page_path = nil
end
##
@@ -94,6 +93,15 @@ class RDoc::Generator::HTML
# If the template name contains a slash, use it literally
def load_html_template
+ #
+ # If the template is not a path, first look for it
+ # in rdoc's HTML template directory. Perhaps this behavior should
+ # be reversed (first try to include the template and, only if that
+ # fails, try to include it in the default template directory).
+ # One danger with reversing the behavior, however, is that
+ # if something like require 'html' could load up an
+ # unrelated file in the standard library or in a gem.
+ #
template = @options.template
unless template =~ %r{/|\\} then
@@ -101,14 +109,25 @@ class RDoc::Generator::HTML
template)
end
- require template
-
- @template = self.class.const_get @options.template.upcase
- @options.template_class = @template
+ begin
+ require template
+
+ @template = self.class.const_get @options.template.upcase
+ @options.template_class = @template
+ rescue LoadError => e
+ #
+ # The template did not exist in the default template directory, so
+ # see if require can find the template elsewhere (in a gem, for
+ # instance).
+ #
+ if(e.message[template] && template != @options.template)
+ template = @options.template
+ retry
+ end
- rescue LoadError
- $stderr.puts "Could not find HTML template '#{template}'"
- exit 99
+ $stderr.puts "Could not find HTML template '#{template}': #{e.message}"
+ exit 99
+ end
end
##
@@ -146,14 +165,16 @@ class RDoc::Generator::HTML
end
def build_indices
- @files, @classes = RDoc::Generator::Context.build_indicies(@toplevels,
- @options)
+ @files, @classes = RDoc::Generator::Context.build_indices(@toplevels,
+ @options)
end
##
# Generate all the HTML
def generate_html
+ @main_url = main_url
+
# the individual descriptions for files and classes
gen_into(@files)
gen_into(@classes)
@@ -165,23 +186,50 @@ class RDoc::Generator::HTML
gen_main_index
# this method is defined in the template file
- write_extra_pages if defined? write_extra_pages
+ values = {
+ 'title_suffix' => CGI.escapeHTML("[#{@options.title}]"),
+ 'charset' => @options.charset,
+ 'style_url' => style_url('', @options.css),
+ }
+
+ @template.write_extra_pages(values) if @template.respond_to?(:write_extra_pages)
end
def gen_into(list)
- @file_list ||= index_to_links @files
- @class_list ||= index_to_links @classes
- @method_list ||= index_to_links RDoc::Generator::Method.all_methods
+ #
+ # The file, class, and method lists technically should be regenerated
+ # for every output file, in order that the relative links be correct
+ # (we are worried here about frameless templates, which need this
+ # information for every generated page). Doing this is a bit slow,
+ # however. For a medium-sized gem, this increased rdoc's runtime by
+ # about 5% (using the 'time' command-line utility). While this is not
+ # necessarily a problem, I do not want to pessimize rdoc for large
+ # projects, however, and so we only regenerate the lists when the
+ # directory of the output file changes, which seems like a reasonable
+ # optimization.
+ #
+ file_list = {}
+ class_list = {}
+ method_list = {}
+ prev_op_dir = nil
list.each do |item|
next unless item.document_self
op_file = item.path
+ op_dir = File.dirname(op_file)
+
+ if(op_dir != prev_op_dir)
+ file_list = index_to_links op_file, @files
+ class_list = index_to_links op_file, @classes
+ method_list = index_to_links op_file, RDoc::Generator::Method.all_methods
+ end
+ prev_op_dir = op_dir
- FileUtils.mkdir_p File.dirname(op_file)
+ FileUtils.mkdir_p op_dir
open op_file, 'w' do |io|
- item.write_on io, @file_list, @class_list, @method_list
+ item.write_on io, file_list, class_list, method_list
end
end
end
@@ -211,8 +259,9 @@ class RDoc::Generator::HTML
values = {
"entries" => res,
+ 'title' => CGI.escapeHTML("#{title} [#{@options.title}]"),
'list_title' => CGI.escapeHTML(title),
- 'index_url' => main_url,
+ 'index_url' => @main_url,
'charset' => @options.charset,
'style_url' => style_url('', @options.css),
}
@@ -230,47 +279,55 @@ class RDoc::Generator::HTML
def gen_main_index
if @template.const_defined? :FRAMELESS then
- main = @files.find do |file|
- @main_page == file.name
- end
-
- if main.nil? then
- main = @classes.find do |klass|
- main_page == klass.context.full_name
- end
+ #
+ # If we're using a template without frames, then just redirect
+ # to it from index.html.
+ #
+ # One alternative to this, expanding the main page's template into
+ # index.html, is tricky because the relative URLs will be different
+ # (since index.html is located in at the site's root,
+ # rather than within a files or a classes subdirectory).
+ #
+ open 'index.html', 'w' do |f|
+ f.puts(%{<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">})
+ f.puts(%{<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
+ lang="en">})
+ f.puts(%{<head>})
+ f.puts(%{<title>#{CGI.escapeHTML(@options.title)}</title>})
+ f.puts(%{<meta http-equiv="refresh" content="0; url=#{@main_url}" />})
+ f.puts(%{</head>})
+ f.puts(%{<body></body>})
+ f.puts(%{</html>})
end
else
main = RDoc::TemplatePage.new @template::INDEX
- end
- open 'index.html', 'w' do |f|
- style_url = style_url '', @options.css
+ open 'index.html', 'w' do |f|
+ style_url = style_url '', @options.css
+
+ classes = @classes.sort.map { |klass| klass.value_hash }
+
+ values = {
+ 'initial_page' => @main_url,
+ 'style_url' => style_url('', @options.css),
+ 'title' => CGI.escapeHTML(@options.title),
+ 'charset' => @options.charset,
+ 'classes' => classes,
+ }
+
+ values['inline_source'] = @options.inline_source
- classes = @classes.sort.map { |klass| klass.value_hash }
-
- values = {
- 'main_page' => @main_page,
- 'initial_page' => main_url,
- 'style_url' => style_url('', @options.css),
- 'title' => CGI.escapeHTML(@options.title),
- 'charset' => @options.charset,
- 'classes' => classes,
- }
-
- values['inline_source'] = @options.inline_source
-
- if main.respond_to? :write_on then
- main.write_on f, @file_list, @class_list, @method_list, values
- else
main.write_html_on f, values
end
end
end
- def index_to_links(collection)
+ def index_to_links(output_path, collection)
collection.sort.map do |f|
next unless f.document_self
- { "href" => f.path, "name" => f.index_name }
+ { "href" => RDoc::Markup::ToHtml.gen_relative_url(output_path, f.path),
+ "name" => f.index_name }
end.compact
end
@@ -278,32 +335,48 @@ class RDoc::Generator::HTML
# Returns the url of the main page
def main_url
- @main_page = @options.main_page
- @main_page_ref = nil
-
- if @main_page then
- @main_page_ref = RDoc::Generator::AllReferences[@main_page]
-
- if @main_page_ref then
- @main_page_path = @main_page_ref.path
+ main_page = @options.main_page
+
+ #
+ # If a main page has been specified (--main), then search for it
+ # in the AllReferences array. This allows either files or classes
+ # to be used for the main page.
+ #
+ if main_page then
+ main_page_ref = RDoc::Generator::AllReferences[main_page]
+
+ if main_page_ref then
+ return main_page_ref.path
else
- $stderr.puts "Could not find main page #{@main_page}"
+ $stderr.puts "Could not find main page #{main_page}"
end
end
- unless @main_page_path then
- file = @files.find { |context| context.document_self }
- @main_page_path = file.path if file
+ #
+ # No main page has been specified, so just use the README.
+ #
+ @files.each do |file|
+ if file.name =~ /^README/ then
+ return file.path
+ end
end
- unless @main_page_path then
- $stderr.puts "Couldn't find anything to document"
- $stderr.puts "Perhaps you've used :stopdoc: in all classes"
- exit 1
+ #
+ # There's no README (shame! shame!). Just use the first file
+ # that will be documented.
+ #
+ @files.each do |file|
+ if file.document_self then
+ return file.path
+ end
end
- @main_page_path
+ #
+ # There are no files to be documented... Something seems very wrong.
+ #
+ raise RDoc::Error, "Couldn't find anything to document (perhaps :stopdoc: has been used in all classes)!"
end
+ private :main_url
end
@@ -349,12 +422,9 @@ class RDoc::Generator::HTMLInOne < RDoc::Generator::HTML
'charset' => @options.charset,
'files' => gen_into(@files),
'classes' => gen_into(@classes),
- 'title' => CGI.escapeHTML(@options.title),
+ 'title' => CGI.escapeHTML(@options.title),
}
- # this method is defined in the template file
- write_extra_pages if defined? write_extra_pages
-
template = RDoc::TemplatePage.new @template::ONE_PAGE
if @options.op_name
@@ -372,26 +442,4 @@ class RDoc::Generator::HTMLInOne < RDoc::Generator::HTML
end
res
end
-
- def gen_file_index
- gen_an_index(@files, 'Files')
- end
-
- def gen_class_index
- gen_an_index(@classes, 'Classes')
- end
-
- def gen_method_index
- gen_an_index(RDoc::Generator::Method.all_methods, 'Methods')
- end
-
- def gen_an_index(collection, title)
- return {
- "entries" => index_to_links(collection),
- 'list_title' => title,
- 'index_url' => main_url,
- }
- end
-
end
-