Change soft-fail to use the config, rather than env
[rbx.git] / lib / rdoc / options.rb
blobd683a1402241ac9a0e19b0bb9a7c15d0fdae7c28
1 # We handle the parsing of options, and subsequently as a singleton
2 # object to be queried for option values
4 require "rdoc/ri/paths"
5 require 'optparse'
7 class RDoc::Options
9   ##
10   # Should the output be placed into a single file
12   attr_reader :all_one_file
14   ##
15   # Character-set
17   attr_reader :charset
19   ##
20   # URL of stylesheet
22   attr_reader :css
24   ##
25   # Should diagrams be drawn
27   attr_reader :diagram
29   ##
30   # Files matching this pattern will be excluded
32   attr_accessor :exclude
34   ##
35   # Additional attr_... style method flags
37   attr_reader :extra_accessor_flags
39   ##
40   # Pattern for additional attr_... style methods
42   attr_accessor :extra_accessors
44   ##
45   # Should we draw fileboxes in diagrams
47   attr_reader :fileboxes
49   ##
50   # The list of files to be processed
52   attr_accessor :files
54   ##
55   # Scan newer sources than the flag file if true.
57   attr_reader :force_update
59   ##
60   # Description of the output generator (set with the <tt>-fmt</tt> option)
62   attr_accessor :generator
64   ##
65   # Formatter to mark up text with
67   attr_accessor :formatter
68   
69   ##
70   # image format for diagrams
72   attr_reader :image_format
74   ##
75   # Include line numbers in the source listings
77   attr_reader :include_line_numbers
79   ##
80   # Should source code be included inline, or displayed in a popup
82   attr_accessor :inline_source
84   ##
85   # Name of the file, class or module to display in the initial index page (if
86   # not specified the first file we encounter is used)
88   attr_accessor :main_page
90   ##
91   # Merge into classes of the same name when generating ri
93   attr_reader :merge
95   ##
96   # The name of the output directory
98   attr_accessor :op_dir
100   ##
101   # The name to use for the output
103   attr_accessor :op_name
105   ##
106   # Are we promiscuous about showing module contents across multiple files
108   attr_reader :promiscuous
110   ##
111   # Array of directories to search for files to satisfy an :include:
113   attr_reader :rdoc_include
115   ##
116   # Include private and protected methods in the output
118   attr_accessor :show_all
120   ##
121   # Include the '#' at the front of hyperlinked instance method names
123   attr_reader :show_hash
125   ##
126   # The number of columns in a tab
128   attr_reader :tab_width
130   ##
131   # template to be used when generating output
133   attr_reader :template
135   ##
136   # Template class for file generation
137   #--
138   # HACK around dependencies in lib/rdoc/generator/html.rb
140   attr_accessor :template_class # :nodoc:
142   ##
143   # Documentation title
145   attr_reader :title
147   ##
148   # Verbosity, zero means quiet
150   attr_accessor :verbosity
152   ##
153   # URL of web cvs frontend
155   attr_reader :webcvs
157   def initialize(generators = {}) # :nodoc:
158     @op_dir = "doc"
159     @op_name = nil
160     @show_all = false
161     @main_page = nil
162     @merge = false
163     @exclude = []
164     @generators = generators
165     @generator_name = 'html'
166     @generator = @generators[@generator_name]
167     @rdoc_include = []
168     @title = nil
169     @template = nil
170     @template_class = nil
171     @diagram = false
172     @fileboxes = false
173     @show_hash = false
174     @image_format = 'png'
175     @inline_source = false
176     @all_one_file = false
177     @tab_width = 8
178     @include_line_numbers = false
179     @extra_accessor_flags = {}
180     @promiscuous = false
181     @force_update = false
182     @verbosity = 1
184     @css = nil
185     @webcvs = nil
187     @charset = 'iso-8859-1'
188   end
190   ##
191   # Parse command line options.
193   def parse(argv)
194     accessors = []
196     opts = OptionParser.new do |opt|
197       opt.program_name = File.basename $0
198       opt.version = RDoc::VERSION
199       opt.summary_indent = ' ' * 4
200       opt.banner = <<-EOF
201 Usage: #{opt.program_name} [options] [names...]
203   Files are parsed, and the information they contain collected, before any
204   output is produced. This allows cross references between all files to be
205   resolved. If a name is a directory, it is traversed. If no names are
206   specified, all Ruby files in the current directory (and subdirectories) are
207   processed.
209   How RDoc generates output depends on the output formatter being used, and on
210   the options you give.
212   - HTML output is normally produced into a number of separate files
213     (one per class, module, and file, along with various indices).
214     These files will appear in the directory given by the --op
215     option (doc/ by default).
217   - XML output by default is written to standard output. If a
218     --opname option is given, the output will instead be written
219     to a file with that name in the output directory.
221   - .chm files (Windows help files) are written in the --op directory.
222     If an --opname parameter is present, that name is used, otherwise
223     the file will be called rdoc.chm.
224       EOF
226       opt.separator nil
227       opt.separator "Options:"
228       opt.separator nil
230       opt.on("--accessor=ACCESSORS", "-A", Array,
231              "A comma separated list of additional class",
232              "methods that should be treated like",
233              "'attr_reader' and friends.",
234              " ",
235              "Option may be repeated.",
236              " ",
237              "Each accessorname may have '=text'",
238              "appended, in which case that text appears",
239              "where the r/w/rw appears for normal.",
240              "accessors") do |value|
241         value.each do |accessor|
242           if accessor =~ /^(\w+)(=(.*))?$/
243             accessors << $1
244             @extra_accessor_flags[$1] = $3
245           end
246         end
247       end
249       opt.separator nil
251       opt.on("--all", "-a",
252              "Include all methods (not just public) in",
253              "the output.") do |value|
254         @show_all = value
255       end
257       opt.separator nil
259       opt.on("--charset=CHARSET", "-c",
260              "Specifies the HTML character-set.") do |value|
261         @charset = value
262       end
264       opt.separator nil
266       opt.on("--debug", "-D",
267              "Displays lots on internal stuff.") do |value|
268         $DEBUG_RDOC = value
269       end
271       opt.separator nil
273       opt.on("--diagram", "-d",
274              "Generate diagrams showing modules and",
275              "classes. You need dot V1.8.6 or later to",
276              "use the --diagram option correctly. Dot is",
277              "available from http://graphviz.org") do |value|
278         check_diagram
279         @diagram = true
280       end
282       opt.separator nil
284       opt.on("--exclude=PATTERN", "-x", Regexp,
285              "Do not process files or directories",
286              "matching PATTERN. Files given explicitly",
287              "on the command line will never be",
288              "excluded.") do |value|
289         @exclude << value
290       end
292       opt.separator nil
294       opt.on("--extension=NEW=OLD", "-E",
295              "Treat files ending with .new as if they",
296              "ended with .old. Using '-E cgi=rb' will",
297              "cause xxx.cgi to be parsed as a Ruby file.") do |value|
298         new, old = value.split(/=/, 2)
300         unless new and old then
301           raise OptionParser::InvalidArgument, "Invalid parameter to '-E'"
302         end
304         unless RDoc::ParserFactory.alias_extension old, new then
305           raise OptionParser::InvalidArgument, "Unknown extension .#{old} to -E"
306         end
307       end
309       opt.separator nil
311       opt.on("--fileboxes", "-F",
312              "Classes are put in boxes which represents",
313              "files, where these classes reside. Classes",
314              "shared between more than one file are",
315              "shown with list of files that are sharing",
316              "them. Silently discarded if --diagram is",
317              "not given.") do |value|
318         @fileboxes = value
319       end
321       opt.separator nil
323       opt.on("--force-update", "-U",
324              "Forces rdoc to scan all sources even if",
325              "newer than the flag file.") do |value|
326         @force_update = value
327       end
329       opt.separator nil
331       opt.on("--fmt=FORMAT", "--format=FORMAT", "-f", @generators.keys,
332              "Set the output formatter.") do |value|
333         @generator_name = value.downcase
334         setup_generator
335       end
337       opt.separator nil
339       image_formats = %w[gif png jpg jpeg]
340       opt.on("--image-format=FORMAT", "-I", image_formats,
341              "Sets output image format for diagrams. Can",
342              "be #{image_formats.join ', '}. If this option",
343              "is omitted, png is used. Requires",
344              "diagrams.") do |value|
345         @image_format = value
346       end
348       opt.separator nil
350       opt.on("--include=DIRECTORIES", "-i", Array,
351              "set (or add to) the list of directories to",
352              "be searched when satisfying :include:",
353              "requests. Can be used more than once.") do |value|
354         @rdoc_include.concat value.map { |dir| dir.strip }
355       end
357       opt.separator nil
359       opt.on("--inline-source", "-S",
360              "Show method source code inline, rather than",
361              "via a popup link.") do |value|
362         @inline_source = value
363       end
365       opt.separator nil
367       opt.on("--line-numbers", "-N",
368              "Include line numbers in the source code.") do |value|
369         @include_line_numbers = value
370       end
372       opt.separator nil
374       opt.on("--main=NAME", "-m",
375              "NAME will be the initial page displayed.") do |value|
376         @main_page = value
377       end
379       opt.separator nil
381       opt.on("--merge", "-M",
382              "When creating ri output, merge previously",
383              "processed classes into previously",
384              "documented classes of the same name.") do |value|
385         @merge = value
386       end
388       opt.separator nil
390       opt.on("--one-file", "-1",
391              "Put all the output into a single file.") do |value|
392         @all_one_file = value
393         @inline_source = value if value
394         @template = 'one_page_html'
395       end
397       opt.separator nil
399       opt.on("--op=DIR", "-o",
400              "Set the output directory.") do |value|
401         @op_dir = value
402       end
404       opt.separator nil
406       opt.on("--opname=NAME", "-n",
407              "Set the NAME of the output. Has no effect",
408              "for HTML.") do |value|
409         @op_name = value
410       end
412       opt.separator nil
414       opt.on("--promiscuous", "-p",
415              "When documenting a file that contains a",
416              "module or class also defined in other",
417              "files, show all stuff for that module or",
418              "class in each files page. By default, only",
419              "show stuff defined in that particular file.") do |value|
420         @promiscuous = value
421       end
423       opt.separator nil
425       opt.on("--quiet", "-q",
426              "Don't show progress as we parse.") do |value|
427         @verbosity = 0
428       end
430       opt.on("--verbose", "-v",
431              "Display extra progress as we parse.") do |value|
432         @verbosity = 2
433       end
436       opt.separator nil
438       opt.on("--ri", "-r",
439              "Generate output for use by `ri`. The files",
440              "are stored in the '.rdoc' directory under",
441              "your home directory unless overridden by a",
442              "subsequent --op parameter, so no special",
443              "privileges are needed.") do |value|
444         @generator_name = "ri"
445         @op_dir = RDoc::RI::Paths::HOMEDIR
446         setup_generator
447       end
449       opt.separator nil
451       opt.on("--ri-site", "-R",
452              "Generate output for use by `ri`. The files",
453              "are stored in a site-wide directory,",
454              "making them accessible to others, so",
455              "special privileges are needed.") do |value|
456         @generator_name = "ri"
457         @op_dir = RDoc::RI::Paths::SITEDIR
458         setup_generator
459       end
461       opt.separator nil
463       opt.on("--ri-system", "-Y",
464              "Generate output for use by `ri`. The files",
465              "are stored in a site-wide directory,",
466              "making them accessible to others, so",
467              "special privileges are needed.  This",
468              "option is intended to be used during Ruby",
469              "installation.") do |value|
470         @generator_name = "ri"
471         @op_dir = RDoc::RI::Paths::SYSDIR
472         setup_generator
473       end
475       opt.separator nil
477       opt.on("--show-hash", "-H",
478              "A name of the form #name in a comment is a",
479              "possible hyperlink to an instance method",
480              "name. When displayed, the '#' is removed",
481              "unless this option is specified.") do |value|
482         @show_hash = value
483       end
485       opt.separator nil
487       opt.on("--style=URL", "-s",
488              "Specifies the URL of a separate stylesheet.") do |value|
489         @css = value
490       end
492       opt.separator nil
494       opt.on("--tab-width=WIDTH", "-w", OptionParser::DecimalInteger,
495              "Set the width of tab characters.") do |value|
496         @tab_width = value
497       end
499       opt.separator nil
501       opt.on("--template=NAME", "-T",
502              "Set the template used when generating",
503              "output.") do |value|
504         @template = value
505       end
507       opt.separator nil
509       opt.on("--title=TITLE", "-t",
510              "Set TITLE as the title for HTML output.") do |value|
511         @title = value
512       end
514       opt.separator nil
516       opt.on("--webcvs=URL", "-W",
517              "Specify a URL for linking to a web frontend",
518              "to CVS. If the URL contains a '\%s', the",
519              "name of the current file will be",
520              "substituted; if the URL doesn't contain a",
521              "'\%s', the filename will be appended to it.") do |value|
522         @webcvs = value
523       end
524     end
526     argv.insert(0, *ENV['RDOCOPT'].split) if ENV['RDOCOPT']
528     opts.parse! argv
530     @files = argv.dup
532     @rdoc_include << "." if @rdoc_include.empty?
534     if @exclude.empty? then
535       @exclude = nil
536     else
537       @exclude = Regexp.new(@exclude.join("|"))
538     end
540     check_files
542     # If no template was specified, use the default template for the output
543     # formatter
545     @template ||= @generator_name
547     # Generate a regexp from the accessors
548     unless accessors.empty? then
549       re = '^(' + accessors.map { |a| Regexp.quote a }.join('|') + ')$'
550       @extra_accessors = Regexp.new re
551     end
553   rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e
554     puts opts
555     puts
556     puts e
557     exit 1
558   end
560   ##
561   # Set the title, but only if not already set. This means that a title set
562   # from the command line trumps one set in a source file
564   def title=(string)
565     @title ||= string
566   end
568   ##
569   # Don't display progress as we process the files
571   def quiet
572     @verbosity.zero?
573   end
575   def quiet=(bool)
576     @verbosity = bool ? 0 : 1
577   end
579   private
581   ##
582   # Set up an output generator for the format in @generator_name
584   def setup_generator
585     @generator = @generators[@generator_name]
587     unless @generator then
588       raise OptionParser::InvalidArgument, "Invalid output formatter"
589     end
591     if @generator_name == "xml" then
592       @all_one_file = true
593       @inline_source = true
594     end
595   end
597   # Check that the right version of 'dot' is available.  Unfortunately this
598   # doesn't work correctly under Windows NT, so we'll bypass the test under
599   # Windows.
601   def check_diagram
602     return if RUBY_PLATFORM =~ /mswin|cygwin|mingw|bccwin/
604     ok = false
605     ver = nil
607     IO.popen "dot -V 2>&1" do |io|
608       ver = io.read
609       if ver =~ /dot.+version(?:\s+gviz)?\s+(\d+)\.(\d+)/ then
610         ok = ($1.to_i > 1) || ($1.to_i == 1 && $2.to_i >= 8)
611       end
612     end
614     unless ok then
615       if ver =~ /^dot.+version/ then
616         $stderr.puts "Warning: You may need dot V1.8.6 or later to use\n",
617           "the --diagram option correctly. You have:\n\n   ",
618           ver,
619           "\nDiagrams might have strange background colors.\n\n"
620       else
621         $stderr.puts "You need the 'dot' program to produce diagrams.",
622           "(see http://www.research.att.com/sw/tools/graphviz/)\n\n"
623         exit
624       end
625     end
626   end
628   ##
629   # Check that the files on the command line exist
631   def check_files
632     @files.each do |f|
633       stat = File.stat f
634       raise RDoc::Error, "file '#{f}' not readable" unless stat.readable?
635     end
636   end