diff options
Diffstat (limited to 'lib/rdoc/generator/html.rb')
-rw-r--r-- | lib/rdoc/generator/html.rb | 226 |
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 - |