3 require 'rdoc/generator'
4 require 'rdoc/markup/to_html'
7 # We're responsible for generating all the HTML files from the object tree
8 # defined in code_objects.rb. We generate:
10 # [files] an html file for each input file given. These
11 # input files appear as objects of class
14 # [classes] an html file for each class or module encountered.
15 # These classes are not grouped by file: if a file
16 # contains four classes, we'll generate an html
17 # file for the file itself, and four html files
18 # for the individual classes.
20 # [indices] we generate three indices for files, classes,
21 # and methods. These are displayed in a browser
22 # like window with three index panes across the
23 # top and the selected description below
25 # Method descriptions appear in whatever entity (file, class, or module) that
28 # We generate files in a structure below a specified subdirectory, normally
34 # | |__ per file summaries
37 # |__ per class/module descriptions
39 # HTML is generated using the Template class.
41 class RDoc::Generator::HTML
43 include RDoc::Generator::MarkUp
46 # Generator may need to return specific subclasses depending on the
47 # options they are passed. Because of this we create them using a factory
50 RDoc::Generator::AllReferences.reset
51 RDoc::Generator::Method.reset
53 if options.all_one_file
54 RDoc::Generator::HTMLInOne.new options
65 # Set up a new HTML generator. Basically all we do here is load up the
66 # correct output temlate
68 def initialize(options) #:not-new:
75 # Build the initial indices and output objects
76 # based on an array of TopLevel objects containing
77 # the extracted information.
79 def generate(toplevels)
80 @toplevels = toplevels
93 # Load up the HTML template specified in the options.
94 # If the template name contains a slash, use it literally
96 def load_html_template
97 template = @options.template
99 unless template =~ %r{/|\\} then
100 template = File.join('rdoc', 'generator', @options.generator.key,
106 @template = self.class.const_get @options.template.upcase
107 @options.template_class = @template
110 $stderr.puts "Could not find HTML template '#{template}'"
115 # Write out the style sheet used by the main frames
117 def write_style_sheet
118 return unless @template.constants.include? :STYLE or
119 @template.constants.include? 'STYLE'
121 template = RDoc::TemplatePage.new @template::STYLE
123 unless @options.css then
124 open RDoc::Generator::CSS_NAME, 'w' do |f|
127 if @template.constants.include? :FONTS or
128 @template.constants.include? 'FONTS' then
129 values["fonts"] = @template::FONTS
132 template.write_html_on(f, values)
138 # See the comments at the top for a description of the directory structure
140 def gen_sub_directories
141 FileUtils.mkdir_p RDoc::Generator::FILE_DIR
142 FileUtils.mkdir_p RDoc::Generator::CLASS_DIR
144 $stderr.puts $!.message
149 @files, @classes = RDoc::Generator::Context.build_indicies(@toplevels,
154 # Generate all the HTML
157 # the individual descriptions for files and classes
161 # and the index files
167 # this method is defined in the template file
168 write_extra_pages if defined? write_extra_pages
172 @file_list ||= index_to_links @files
173 @class_list ||= index_to_links @classes
174 @method_list ||= index_to_links RDoc::Generator::Method.all_methods
177 next unless item.document_self
181 FileUtils.mkdir_p File.dirname(op_file)
183 open op_file, 'w' do |io|
184 item.write_on io, @file_list, @class_list, @method_list
190 gen_an_index @files, 'Files', @template::FILE_INDEX, "fr_file_index.html"
194 gen_an_index(@classes, 'Classes', @template::CLASS_INDEX,
195 "fr_class_index.html")
199 gen_an_index(RDoc::Generator::Method.all_methods, 'Methods',
200 @template::METHOD_INDEX, "fr_method_index.html")
203 def gen_an_index(collection, title, template, filename)
204 template = RDoc::TemplatePage.new @template::FR_INDEX_BODY, template
206 collection.sort.each do |f|
208 res << { "href" => f.path, "name" => f.index_name }
214 'list_title' => CGI.escapeHTML(title),
215 'index_url' => main_url,
216 'charset' => @options.charset,
217 'style_url' => style_url('', @options.css),
220 open filename, 'w' do |f|
221 template.write_html_on(f, values)
226 # The main index page is mostly a template frameset, but includes the
227 # initial page. If the <tt>--main</tt> option was given, we use this as
228 # our main page, otherwise we use the first file specified on the command
232 if @template.const_defined? :FRAMELESS then
233 main = @files.find do |file|
234 @main_page == file.name
238 main = @classes.find do |klass|
239 main_page == klass.context.full_name
243 main = RDoc::TemplatePage.new @template::INDEX
246 open 'index.html', 'w' do |f|
247 style_url = style_url '', @options.css
249 classes = @classes.sort.map { |klass| klass.value_hash }
252 'main_page' => @main_page,
253 'initial_page' => main_url,
254 'style_url' => style_url('', @options.css),
255 'title' => CGI.escapeHTML(@options.title),
256 'charset' => @options.charset,
257 'classes' => classes,
260 values['inline_source'] = @options.inline_source
262 if main.respond_to? :write_on then
263 main.write_on f, @file_list, @class_list, @method_list, values
265 main.write_html_on f, values
270 def index_to_links(collection)
271 collection.sort.map do |f|
272 next unless f.document_self
273 { "href" => f.path, "name" => f.index_name }
278 # Returns the url of the main page
281 @main_page = @options.main_page
285 @main_page_ref = RDoc::Generator::AllReferences[@main_page]
287 if @main_page_ref then
288 @main_page_path = @main_page_ref.path
290 $stderr.puts "Could not find main page #{@main_page}"
294 unless @main_page_path then
295 file = @files.find { |context| context.document_self }
296 @main_page_path = file.path if file
299 unless @main_page_path then
300 $stderr.puts "Couldn't find anything to document"
301 $stderr.puts "Perhaps you've used :stopdoc: in all classes"
310 class RDoc::Generator::HTMLInOne < RDoc::Generator::HTML
312 def initialize(*args)
317 # Build the initial indices and output objects
318 # based on an array of TopLevel objects containing
319 # the extracted information.
332 # * a list of RDoc::Generator::File objects for each TopLevel object.
333 # * a list of RDoc::Generator::Class objects for each first level
334 # class or module in the TopLevel objects
335 # * a complete list of all hyperlinkable terms (file,
336 # class, module, and method names)
339 @files, @classes = RDoc::Generator::Context.build_indices(@toplevels,
344 # Generate all the HTML. For the one-file case, we generate
345 # all the information in to one big hash
349 'charset' => @options.charset,
350 'files' => gen_into(@files),
351 'classes' => gen_into(@classes),
352 'title' => CGI.escapeHTML(@options.title),
355 # this method is defined in the template file
356 write_extra_pages if defined? write_extra_pages
358 template = RDoc::TemplatePage.new @template::ONE_PAGE
361 opfile = open @options.op_name, 'w'
365 template.write_html_on(opfile, values)
371 res << item.value_hash
377 gen_an_index(@files, 'Files')
381 gen_an_index(@classes, 'Classes')
385 gen_an_index(RDoc::Generator::Method.all_methods, 'Methods')
388 def gen_an_index(collection, title)
390 "entries" => index_to_links(collection),
391 'list_title' => title,
392 'index_url' => main_url,