PageRenderTime 165ms CodeModel.GetById 103ms app.highlight 54ms RepoModel.GetById 1ms app.codeStats 0ms

/tools/Ruby/lib/ruby/1.8/rdoc/options.rb

http://github.com/agross/netopenspace
Ruby | 586 lines | 417 code | 119 blank | 50 comment | 26 complexity | 2e9dddf8102229cb55c32890c0d68431 MD5 | raw file
  1# We handle the parsing of options, and subsequently as a singleton
  2# object to be queried for option values
  3
  4require "rdoc/ri/ri_paths"
  5
  6class Options
  7
  8  require 'singleton'
  9  require 'getoptlong'
 10
 11  include Singleton
 12
 13  # files matching this pattern will be excluded
 14  attr_accessor :exclude
 15
 16  # the name of the output directory
 17  attr_accessor :op_dir
 18  
 19  # the name to use for the output
 20  attr_reader :op_name
 21
 22  # include private and protected methods in the
 23  # output
 24  attr_accessor :show_all
 25  
 26  # name of the file, class or module to display in
 27  # the initial index page (if not specified
 28  # the first file we encounter is used)
 29  attr_accessor :main_page
 30
 31  # merge into classes of the name name when generating ri
 32  attr_reader :merge
 33
 34  # Don't display progress as we process the files
 35  attr_reader :quiet
 36
 37  # description of the output generator (set with the <tt>-fmt</tt>
 38  # option
 39  attr_accessor :generator
 40
 41  # and the list of files to be processed
 42  attr_reader :files
 43
 44  # array of directories to search for files to satisfy an :include:
 45  attr_reader :rdoc_include
 46
 47  # title to be used out the output
 48  #attr_writer :title
 49
 50  # template to be used when generating output
 51  attr_reader :template
 52
 53  # should diagrams be drawn
 54  attr_reader :diagram
 55
 56  # should we draw fileboxes in diagrams
 57  attr_reader :fileboxes
 58
 59  # include the '#' at the front of hyperlinked instance method names
 60  attr_reader :show_hash
 61
 62  # image format for diagrams
 63  attr_reader :image_format
 64
 65  # character-set
 66  attr_reader :charset
 67
 68  # should source code be included inline, or displayed in a popup
 69  attr_reader :inline_source
 70
 71  # should the output be placed into a single file
 72  attr_reader :all_one_file
 73
 74  # the number of columns in a tab
 75  attr_reader :tab_width
 76
 77  # include line numbers in the source listings
 78  attr_reader :include_line_numbers
 79
 80  # pattern for additional attr_... style methods
 81  attr_reader :extra_accessors
 82  attr_reader :extra_accessor_flags
 83
 84  # URL of stylesheet
 85  attr_reader :css
 86
 87  # URL of web cvs frontend
 88  attr_reader :webcvs
 89
 90  # Are we promiscuous about showing module contents across
 91  # multiple files
 92  attr_reader :promiscuous
 93
 94  # scan newer sources than the flag file if true.
 95  attr_reader :force_update
 96
 97  module OptionList
 98
 99    OPTION_LIST = [
100      [ "--accessor",      "-A",   "accessorname[,..]",
101        "comma separated list of additional class methods\n" +
102        "that should be treated like 'attr_reader' and\n" +
103        "friends. Option may be repeated. Each accessorname\n" +
104        "may have '=text' appended, in which case that text\n" +
105        "appears where the r/w/rw appears for normal accessors."],
106                                                                   
107      [ "--all",           "-a",   nil,
108        "include all methods (not just public)\nin the output" ],
109
110      [ "--charset",       "-c",   "charset",
111        "specifies HTML character-set" ],
112
113      [ "--debug",         "-D",   nil,
114        "displays lots on internal stuff" ],
115
116      [ "--diagram",       "-d",   nil,
117        "Generate diagrams showing modules and classes.\n" +
118        "You need dot V1.8.6 or later to use the --diagram\n" +
119        "option correctly. Dot is available from\n"+
120        "http://www.research.att.com/sw/tools/graphviz/" ],
121
122      [ "--exclude",       "-x",   "pattern",
123        "do not process files or directories matching\n" +
124        "pattern. Files given explicitly on the command\n" +
125        "line will never be excluded." ],
126
127      [ "--extension",     "-E",   "new=old",
128        "Treat files ending with .new as if they ended with\n" +
129        ".old. Using '-E cgi=rb' will cause xxx.cgi to be\n" +
130        "parsed as a Ruby file"],
131
132      [ "--fileboxes",     "-F",   nil,
133        "classes are put in boxes which represents\n" +
134        "files, where these classes reside. Classes\n" +
135        "shared between more than one file are\n" +
136        "shown with list of files that sharing them.\n" +
137        "Silently discarded if --diagram is not given\n" +
138        "Experimental." ],
139
140      [ "--force-update",  "-U",   nil,
141        "forces to scan all sources even if newer than\n" +
142        "the flag file." ],
143
144      [ "--fmt",           "-f",   "format name",
145        "set the output formatter (see below)" ],
146
147      [ "--help",          "-h",   nil,
148        "you're looking at it" ],
149
150      [ "--help-output",   "-O",   nil,
151        "explain the various output options" ],
152
153      [ "--image-format",  "-I",   "gif/png/jpg/jpeg",
154        "Sets output image format for diagrams. Can\n" +
155        "be png, gif, jpeg, jpg. If this option is\n" +
156        "omitted, png is used. Requires --diagram." ],
157
158      [ "--include",       "-i",   "dir[,dir...]",
159        "set (or add to) the list of directories\n" +
160        "to be searched when satisfying :include:\n" +
161        "requests. Can be used more than once." ],
162
163      [ "--inline-source", "-S",   nil,
164        "Show method source code inline, rather\n" +
165        "than via a popup link" ],
166
167      [ "--line-numbers", "-N", nil,
168        "Include line numbers in the source code" ],
169
170      [ "--main",          "-m",   "name",
171        "'name' will be the initial page displayed" ],
172
173      [ "--merge",         "-M",   nil,
174        "when creating ri output, merge processed classes\n" +
175        "into previously documented classes of the name name"],
176
177      [ "--one-file",      "-1",   nil,
178        "put all the output into a single file" ],
179
180      [ "--op",            "-o",   "dir",
181        "set the output directory" ],
182
183      [ "--opname",       "-n",    "name",
184        "Set the 'name' of the output. Has no\n" +
185        "effect for HTML." ],
186
187      [ "--promiscuous",   "-p",   nil,
188        "When documenting a file that contains a module\n" +
189        "or class also defined in other files, show\n" +
190        "all stuff for that module/class in each files\n" +
191        "page. By default, only show stuff defined in\n" +
192        "that particular file." ],
193
194      [ "--quiet",         "-q",   nil,
195        "don't show progress as we parse" ],
196
197      [ "--ri",            "-r",   nil,
198       "generate output for use by 'ri.' The files are\n" +
199       "stored in the '.rdoc' directory under your home\n"+
200       "directory unless overridden by a subsequent\n" +
201       "--op parameter, so no special privileges are needed." ],
202
203      [ "--ri-site",       "-R",   nil,
204       "generate output for use by 'ri.' The files are\n" +
205       "stored in a site-wide directory, making them accessible\n"+
206       "to others, so special privileges are needed." ],
207
208      [ "--ri-system",     "-Y",   nil,
209       "generate output for use by 'ri.' The files are\n" +
210       "stored in a system-level directory, making them accessible\n"+
211       "to others, so special privileges are needed. This option\n"+
212       "is intended to be used during Ruby installations" ],
213
214      [ "--show-hash",     "-H",   nil,
215        "A name of the form #name in a comment\n" +
216        "is a possible hyperlink to an instance\n" +
217        "method name. When displayed, the '#' is\n" +
218        "removed unless this option is specified" ],
219
220      [ "--style",         "-s",   "stylesheet url",
221        "specifies the URL of a separate stylesheet." ],
222
223      [ "--tab-width",     "-w",   "n",
224        "Set the width of tab characters (default 8)"],
225
226      [ "--template",      "-T",   "template name",
227        "Set the template used when generating output" ],
228
229      [ "--title",         "-t",   "text",
230        "Set 'txt' as the title for the output" ],
231
232      [ "--version",       "-v",   nil,
233        "display  RDoc's version" ],
234
235      [ "--webcvs",        "-W",   "url",
236        "Specify a URL for linking to a web frontend\n" +
237        "to CVS. If the URL contains a '\%s', the\n" +
238        "name of the current file will be substituted;\n" +
239        "if the URL doesn't contain a '\%s', the\n" +
240        "filename will be appended to it." ],
241    ]
242
243    def OptionList.options
244      OPTION_LIST.map do |long, short, arg,|
245        [ long, 
246          short, 
247          arg ? GetoptLong::REQUIRED_ARGUMENT : GetoptLong::NO_ARGUMENT 
248        ]
249      end
250    end
251
252
253    def OptionList.strip_output(text)
254      text =~ /^\s+/
255      leading_spaces = $&
256      text.gsub!(/^#{leading_spaces}/, '')
257      $stdout.puts text
258    end
259
260
261    # Show an error and exit
262
263    def OptionList.error(msg)
264      $stderr.puts
265      $stderr.puts msg
266      $stderr.puts "\nFor help on options, try 'rdoc --help'\n\n"
267      exit 1
268    end
269
270    # Show usage and exit
271    
272    def OptionList.usage(generator_names)
273      
274      puts
275      puts(VERSION_STRING)
276      puts
277
278      name = File.basename($0)
279      OptionList.strip_output(<<-EOT)
280          Usage:
281
282            #{name} [options]  [names...]
283
284          Files are parsed, and the information they contain
285          collected, before any output is produced. This allows cross
286          references between all files to be resolved. If a name is a
287          directory, it is traversed. If no names are specified, all
288          Ruby files in the current directory (and subdirectories) are
289          processed.
290
291          Options:
292
293      EOT
294
295      OPTION_LIST.each do |long, short, arg, desc|
296        opt = sprintf("%20s", "#{long}, #{short}")
297        oparg = sprintf("%-7s", arg)
298        print "#{opt} #{oparg}"
299        desc = desc.split("\n")
300        if arg.nil? || arg.length < 7
301          puts desc.shift
302        else
303          puts
304        end
305        desc.each do |line|
306          puts(" "*28 + line)
307        end
308        puts
309      end
310
311      puts "\nAvailable output formatters: " +
312        generator_names.sort.join(', ') + "\n\n"
313
314      puts "For information on where the output goes, use\n\n"
315      puts "   rdoc --help-output\n\n"
316
317      exit 0
318    end
319
320    def OptionList.help_output
321      OptionList.strip_output(<<-EOT)
322      How RDoc generates output depends on the output formatter being
323      used, and on the options you give.
324
325      - HTML output is normally produced into a number of separate files
326        (one per class, module, and file, along with various indices). 
327        These files will appear in the directory given by the --op
328        option (doc/ by default).
329
330      - XML output by default is written to standard output. If a
331        --opname option is given, the output will instead be written
332        to a file with that name in the output directory.
333
334      - .chm files (Windows help files) are written in the --op directory.
335        If an --opname parameter is present, that name is used, otherwise
336        the file will be called rdoc.chm.
337
338      For information on other RDoc options, use "rdoc --help".
339      EOT
340      exit 0
341    end
342  end
343
344  # Parse command line options. We're passed a hash containing
345  # output generators, keyed by the generator name
346
347  def parse(argv, generators)
348    old_argv = ARGV.dup
349    begin
350      ARGV.replace(argv)
351      @op_dir = "doc"
352      @op_name = nil
353      @show_all = false
354      @main_page = nil
355      @marge     = false
356      @exclude   = []
357      @quiet = false
358      @generator_name = 'html'
359      @generator = generators[@generator_name]
360      @rdoc_include = []
361      @title = nil
362      @template = nil
363      @diagram = false
364      @fileboxes = false
365      @show_hash = false
366      @image_format = 'png'
367      @inline_source = false
368      @all_one_file  = false
369      @tab_width = 8
370      @include_line_numbers = false
371      @extra_accessor_flags = {}
372      @promiscuous = false
373      @force_update = false
374
375      @css = nil
376      @webcvs = nil
377
378      @charset = case $KCODE
379                 when /^S/i
380                   'Shift_JIS'
381                 when /^E/i
382                   'EUC-JP'
383                 else
384                   'iso-8859-1'
385                 end
386
387      accessors = []
388
389      go = GetoptLong.new(*OptionList.options)
390      go.quiet = true
391
392      go.each do |opt, arg|
393	case opt
394        when "--all"           then @show_all      = true
395        when "--charset"       then @charset       = arg
396        when "--debug"         then $DEBUG         = true
397        when "--exclude"       then @exclude       << Regexp.new(arg)
398        when "--inline-source" then @inline_source = true
399        when "--line-numbers"  then @include_line_numbers = true
400        when "--main"          then @main_page     = arg
401        when "--merge"         then @merge         = true
402        when "--one-file"      then @all_one_file  = @inline_source = true
403        when "--op"            then @op_dir        = arg
404        when "--opname"        then @op_name       = arg
405        when "--promiscuous"   then @promiscuous   = true
406        when "--quiet"         then @quiet         = true
407        when "--show-hash"     then @show_hash     = true
408        when "--style"         then @css           = arg
409        when "--template"      then @template      = arg
410        when "--title"         then @title         = arg
411        when "--webcvs"        then @webcvs        = arg
412
413        when "--accessor" 
414          arg.split(/,/).each do |accessor|
415            if accessor =~ /^(\w+)(=(.*))?$/
416              accessors << $1
417              @extra_accessor_flags[$1] = $3
418            end
419          end
420
421        when "--diagram"
422          check_diagram
423          @diagram = true
424
425        when "--fileboxes"
426          @fileboxes = true if @diagram
427
428	when "--fmt"
429          @generator_name = arg.downcase
430          setup_generator(generators)
431
432        when "--help"      
433          OptionList.usage(generators.keys)
434
435        when "--help-output"      
436          OptionList.help_output
437
438        when "--image-format"
439          if ['gif', 'png', 'jpeg', 'jpg'].include?(arg)
440            @image_format = arg
441          else
442            raise GetoptLong::InvalidOption.new("unknown image format: #{arg}")
443          end
444
445        when "--include"   
446          @rdoc_include.concat arg.split(/\s*,\s*/)
447
448        when "--ri", "--ri-site", "--ri-system"
449          @generator_name = "ri"
450          @op_dir = case opt
451                    when "--ri" then RI::Paths::HOMEDIR 
452                    when "--ri-site" then RI::Paths::SITEDIR
453                    when "--ri-system" then RI::Paths::SYSDIR
454                    else fail opt
455                    end
456          setup_generator(generators)
457
458        when "--tab-width"
459          begin
460            @tab_width     = Integer(arg)
461          rescue 
462            $stderr.puts "Invalid tab width: '#{arg}'"
463            exit 1
464          end
465
466        when "--extension"
467          new, old = arg.split(/=/, 2)
468          OptionList.error("Invalid parameter to '-E'") unless new && old
469          unless RDoc::ParserFactory.alias_extension(old, new)
470            OptionList.error("Unknown extension .#{old} to -E")
471          end
472
473        when "--force-update"
474          @force_update = true
475
476	when "--version"
477	  puts VERSION_STRING
478	  exit
479	end
480
481      end
482
483      @files = ARGV.dup
484
485      @rdoc_include << "." if @rdoc_include.empty?
486
487      if @exclude.empty?
488        @exclude = nil
489      else
490        @exclude = Regexp.new(@exclude.join("|"))
491      end
492
493      check_files
494
495      # If no template was specified, use the default
496      # template for the output formatter
497
498      @template ||= @generator_name
499
500      # Generate a regexp from the accessors
501      unless accessors.empty?
502        re = '^(' + accessors.map{|a| Regexp.quote(a)}.join('|') + ')$' 
503        @extra_accessors = Regexp.new(re)
504      end
505
506    rescue GetoptLong::InvalidOption, GetoptLong::MissingArgument => error
507      OptionList.error(error.message)
508
509    ensure
510      ARGV.replace(old_argv)
511    end
512  end
513
514
515  def title
516    @title ||= "RDoc Documentation"
517  end
518  
519  # Set the title, but only if not already set. This means that a title set from 
520  # the command line trumps one set in a source file
521
522  def title=(string)
523    @title ||= string
524  end
525
526
527  private
528
529  # Set up an output generator for the format in @generator_name
530  def setup_generator(generators)
531    @generator = generators[@generator_name]
532    if !@generator
533      OptionList.error("Invalid output formatter")
534    end
535    
536    if @generator_name == "xml"
537      @all_one_file = true
538      @inline_source = true
539    end
540  end
541
542  # Check that the right version of 'dot' is available.
543  # Unfortuately this doesn't work correctly under Windows NT, 
544  # so we'll bypass the test under Windows
545
546  def check_diagram
547    return if RUBY_PLATFORM =~ /mswin|cygwin|mingw|bccwin/
548
549    ok = false
550    ver = nil
551    IO.popen("dot -V 2>&1") do |io|
552      ver = io.read
553      if ver =~ /dot.+version(?:\s+gviz)?\s+(\d+)\.(\d+)/
554        ok = ($1.to_i > 1) || ($1.to_i == 1 && $2.to_i >= 8)
555      end
556    end
557    unless ok
558      if ver =~ /^dot.+version/
559        $stderr.puts "Warning: You may need dot V1.8.6 or later to use\n",
560          "the --diagram option correctly. You have:\n\n   ",
561          ver,
562          "\nDiagrams might have strange background colors.\n\n"
563      else
564        $stderr.puts "You need the 'dot' program to produce diagrams.",
565          "(see http://www.research.att.com/sw/tools/graphviz/)\n\n"
566        exit
567      end
568#      exit
569    end
570  end
571  
572  # Check that the files on the command line exist
573  
574  def check_files
575    @files.each do |f|
576      stat = File.stat f rescue error("File not found: #{f}")
577      error("File '#{f}' not readable") unless stat.readable?
578    end
579  end
580
581  def error(str)
582    $stderr.puts str
583    exit(1)
584  end
585
586end