Change soft-fail to use the config, rather than env
[rbx.git] / lib / rdoc / generator / html.rb
bloba9e030a89658f25e2fa25a1b5b3c5ecbf9712f7d
1 require 'fileutils'
3 require 'rdoc/generator'
4 require 'rdoc/markup/to_html'
6 ##
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
12 #           TopLevel
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
26 # contains them.
28 # We generate files in a structure below a specified subdirectory, normally
29 # +doc+.
31 #  opdir
32 #     |
33 #     |___ files
34 #     |       |__  per file summaries
35 #     |
36 #     |___ classes
37 #             |__ per class/module descriptions
39 # HTML is generated using the Template class.
41 class RDoc::Generator::HTML
43   include RDoc::Generator::MarkUp
45   ##
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
49   def self.for(options)
50     RDoc::Generator::AllReferences.reset
51     RDoc::Generator::Method.reset
53     if options.all_one_file
54       RDoc::Generator::HTMLInOne.new options
55     else
56       new options
57     end
58   end
60   class << self
61     protected :new
62   end
64   ##
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:
69     @options = options
70     load_html_template
71     @main_page_path = nil
72   end
74   ##
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
81     @files      = []
82     @classes    = []
84     write_style_sheet
85     gen_sub_directories
86     build_indices
87     generate_html
88   end
90   private
92   ##
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,
101                            template)
102     end
104     require template
106     @template = self.class.const_get @options.template.upcase
107     @options.template_class = @template
109   rescue LoadError
110     $stderr.puts "Could not find HTML template '#{template}'"
111     exit 99
112   end
114   ##
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|
125         values = {}
127         if @template.constants.include? :FONTS or
128            @template.constants.include? 'FONTS' then
129           values["fonts"] = @template::FONTS
130         end
132         template.write_html_on(f, values)
133       end
134     end
135   end
137   ##
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
143   rescue
144     $stderr.puts $!.message
145     exit 1
146   end
148   def build_indices
149     @files, @classes = RDoc::Generator::Context.build_indicies(@toplevels,
150                                                                @options)
151   end
153   ##
154   # Generate all the HTML
156   def generate_html
157     # the individual descriptions for files and classes
158     gen_into(@files)
159     gen_into(@classes)
161     # and the index files
162     gen_file_index
163     gen_class_index
164     gen_method_index
165     gen_main_index
167     # this method is defined in the template file
168     write_extra_pages if defined? write_extra_pages
169   end
171   def gen_into(list)
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
176     list.each do |item|
177       next unless item.document_self
179       op_file = item.path
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
185       end
186     end
187   end
189   def gen_file_index
190     gen_an_index @files, 'Files', @template::FILE_INDEX, "fr_file_index.html"
191   end
193   def gen_class_index
194     gen_an_index(@classes, 'Classes', @template::CLASS_INDEX,
195                  "fr_class_index.html")
196   end
198   def gen_method_index
199     gen_an_index(RDoc::Generator::Method.all_methods, 'Methods',
200                  @template::METHOD_INDEX, "fr_method_index.html")
201   end
203   def gen_an_index(collection, title, template, filename)
204     template = RDoc::TemplatePage.new @template::FR_INDEX_BODY, template
205     res = []
206     collection.sort.each do |f|
207       if f.document_self
208         res << { "href" => f.path, "name" => f.index_name }
209       end
210     end
212     values = {
213       "entries"    => res,
214       'list_title' => CGI.escapeHTML(title),
215       'index_url'  => main_url,
216       'charset'    => @options.charset,
217       'style_url'  => style_url('', @options.css),
218     }
220     open filename, 'w' do |f|
221       template.write_html_on(f, values)
222     end
223   end
225   ##
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
229   # line.
231   def gen_main_index
232     if @template.const_defined? :FRAMELESS then
233       main = @files.find do |file|
234         @main_page == file.name
235       end
237       if main.nil? then
238         main = @classes.find do |klass|
239           main_page == klass.context.full_name
240         end
241       end
242     else
243       main = RDoc::TemplatePage.new @template::INDEX
244     end
246     open 'index.html', 'w'  do |f|
247       style_url = style_url '', @options.css
249       classes = @classes.sort.map { |klass| klass.value_hash }
251       values = {
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,
258       }
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
264       else
265         main.write_html_on f, values
266       end
267     end
268   end
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 }
274     end.compact
275   end
277   ##
278   # Returns the url of the main page
280   def main_url
281     @main_page = @options.main_page
282     @main_page_ref = nil
284     if @main_page then
285       @main_page_ref = RDoc::Generator::AllReferences[@main_page]
287       if @main_page_ref then
288         @main_page_path = @main_page_ref.path
289       else
290         $stderr.puts "Could not find main page #{@main_page}"
291       end
292     end
294     unless @main_page_path then
295       file = @files.find { |context| context.document_self }
296       @main_page_path = file.path if file
297     end
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"
302       exit 1
303     end
305     @main_page_path
306   end
310 class RDoc::Generator::HTMLInOne < RDoc::Generator::HTML
312   def initialize(*args)
313     super
314   end
316   ##
317   # Build the initial indices and output objects
318   # based on an array of TopLevel objects containing
319   # the extracted information.
321   def generate(info)
322     @toplevels  = info
323     @hyperlinks = {}
325     build_indices
326     generate_xml
327   end
329   ##
330   # Generate:
331   #
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)
338   def build_indices
339     @files, @classes = RDoc::Generator::Context.build_indices(@toplevels,
340                                                               @options)
341   end
343   ##
344   # Generate all the HTML. For the one-file case, we generate
345   # all the information in to one big hash
347   def generate_xml
348     values = {
349       'charset' => @options.charset,
350       'files'   => gen_into(@files),
351       'classes' => gen_into(@classes),
352       'title'        => CGI.escapeHTML(@options.title),
353     }
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
360     if @options.op_name
361       opfile = open @options.op_name, 'w'
362     else
363       opfile = $stdout
364     end
365     template.write_html_on(opfile, values)
366   end
368   def gen_into(list)
369     res = []
370     list.each do |item|
371       res << item.value_hash
372     end
373     res
374   end
376   def gen_file_index
377     gen_an_index(@files, 'Files')
378   end
380   def gen_class_index
381     gen_an_index(@classes, 'Classes')
382   end
384   def gen_method_index
385     gen_an_index(RDoc::Generator::Method.all_methods, 'Methods')
386   end
388   def gen_an_index(collection, title)
389     return {
390       "entries" => index_to_links(collection),
391       'list_title' => title,
392       'index_url'  => main_url,
393     }
394   end