| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040 | require 'optparse'### RDoc::Options handles the parsing and storage of options## == Saved Options## You can save some options like the markup format in the# <tt>.rdoc_options</tt> file in your gem.  The easiest way to do this is:##   rdoc --markup tomdoc --write-options## Which will automatically create the file and fill it with the options you# specified.## The following options will not be saved since they interfere with the user's# preferences or with the normal operation of RDoc:## * +--coverage-report+# * +--dry-run+# * +--encoding+# * +--force-update+# * +--format+# * +--pipe+# * +--quiet+# * +--template+# * +--verbose+class RDoc::Options  ##  # The deprecated options.  DEPRECATED = {    '--accessor'      => 'support discontinued',    '--diagram'       => 'support discontinued',    '--help-output'   => 'support discontinued',    '--image-format'  => 'was an option for --diagram',    '--inline-source' => 'source code is now always inlined',    '--merge'         => 'ri now always merges class information',    '--one-file'      => 'support discontinued',    '--op-name'       => 'support discontinued',    '--opname'        => 'support discontinued',    '--promiscuous'   => 'files always only document their content',    '--ri-system'     => 'Ruby installers use other techniques',  }  ##  # RDoc options ignored (or handled specially) by --write-options  SPECIAL = %w[    coverage_report    dry_run    encoding    files    force_output    force_update    generator    generator_name    generator_options    generators    op_dir    option_parser    pipe    rdoc_include    static_path    stylesheet_url    template    template_dir    update_output_dir    verbosity    write_options  ]  ##  # Path option validator for OptionParser  Path = Object.new  ##  # Array of Paths option validator for OptionParser  PathArray = Object.new  ##  # Template option validator for OptionParser  Template = Object.new  ##  # Character-set for HTML output.  #encoding is preferred over #charset  attr_accessor :charset  ##  # If true, RDoc will not write any files.  attr_accessor :dry_run  ##  # Encoding of output where.  This is set via --encoding.  attr_accessor :encoding  ##  # Files matching this pattern will be excluded  attr_accessor :exclude  ##  # The list of files to be processed  attr_accessor :files  ##  # Create the output even if the output directory does not look  # like an rdoc output directory  attr_accessor :force_output  ##  # Scan newer sources than the flag file if true.  attr_accessor :force_update  ##  # Formatter to mark up text with  attr_accessor :formatter  ##  # Description of the output generator (set with the <tt>--fmt</tt> option)  attr_accessor :generator  ##  # For #==  attr_reader :generator_name # :nodoc:  ##  # Loaded generator options.  Used to prevent --help from loading the same  # options multiple times.  attr_accessor :generator_options  ##  # Old rdoc behavior: hyperlink all words that match a method name,  # even if not preceded by '#' or '::'  attr_accessor :hyperlink_all  ##  # Include line numbers in the source code  attr_accessor :line_numbers  ##  # Name of the file, class or module to display in the initial index page (if  # not specified the first file we encounter is used)  attr_accessor :main_page  ##  # The default markup format.  The default is 'rdoc'.  'tomdoc' and 'rd' are  # also built-in.  attr_accessor :markup  ##  # If true, only report on undocumented files  attr_accessor :coverage_report  ##  # The name of the output directory  attr_accessor :op_dir  ##  # The OptionParser for this instance  attr_accessor :option_parser  ##  # Is RDoc in pipe mode?  attr_accessor :pipe  ##  # Array of directories to search for files to satisfy an :include:  attr_accessor :rdoc_include  ##  # Include the '#' at the front of hyperlinked instance method names  attr_accessor :show_hash  ##  # Directory to copy static files from  attr_accessor :static_path  ##  # The number of columns in a tab  attr_accessor :tab_width  ##  # Template to be used when generating output  attr_accessor :template  ##  # Directory the template lives in  attr_accessor :template_dir  ##  # Documentation title  attr_accessor :title  ##  # Should RDoc update the timestamps in the output dir?  attr_accessor :update_output_dir  ##  # Verbosity, zero means quiet  attr_accessor :verbosity  ##  # URL of web cvs frontend  attr_accessor :webcvs  ##  # Minimum visibility of a documented method. One of +:public+,  # +:protected+, +:private+. May be overridden on a per-method  # basis with the :doc: directive.  attr_accessor :visibility  def initialize # :nodoc:    init_ivars  end  def init_ivars # :nodoc:    @dry_run = false    @exclude = []    @files = nil    @force_output = false    @force_update = true    @generator = nil    @generator_name = nil    @generator_options = []    @generators = RDoc::RDoc::GENERATORS    @hyperlink_all = false    @line_numbers = false    @main_page = nil    @markup = 'rdoc'    @coverage_report = false    @op_dir = nil    @pipe = false    @rdoc_include = []    @show_hash = false    @static_path = []    @stylesheet_url = nil # TODO remove in RDoc 4    @tab_width = 8    @template = nil    @template_dir = nil    @title = nil    @update_output_dir = true    @verbosity = 1    @visibility = :protected    @webcvs = nil    @write_options = false    if Object.const_defined? :Encoding then      @encoding = Encoding.default_external      @charset = @encoding.to_s    else      @encoding = nil      @charset = 'UTF-8'    end  end  def init_with map # :nodoc:    init_ivars    encoding = map['encoding']    @encoding = if Object.const_defined? :Encoding then                  encoding ? Encoding.find(encoding) : encoding                end    @charset        = map['charset']    @exclude        = map['exclude']    @generator_name = map['generator_name']    @hyperlink_all  = map['hyperlink_all']    @line_numbers   = map['line_numbers']    @main_page      = map['main_page']    @markup         = map['markup']    @op_dir         = map['op_dir']    @show_hash      = map['show_hash']    @tab_width      = map['tab_width']    @template_dir   = map['template_dir']    @title          = map['title']    @visibility     = map['visibility']    @webcvs         = map['webcvs']    @rdoc_include = sanitize_path map['rdoc_include']    @static_path  = sanitize_path map['static_path']  end  def yaml_initialize tag, map # :nodoc:    init_with map  end  def == other # :nodoc:    self.class === other and      @encoding       == other.encoding       and      @generator_name == other.generator_name and      @hyperlink_all  == other.hyperlink_all  and      @line_numbers   == other.line_numbers   and      @main_page      == other.main_page      and      @markup         == other.markup         and      @op_dir         == other.op_dir         and      @rdoc_include   == other.rdoc_include   and      @show_hash      == other.show_hash      and      @static_path    == other.static_path    and      @tab_width      == other.tab_width      and      @template       == other.template       and      @title          == other.title          and      @visibility     == other.visibility     and      @webcvs         == other.webcvs  end  ##  # Check that the files on the command line exist  def check_files    @files.delete_if do |file|      if File.exist? file then        if File.readable? file then          false        else          warn "file '#{file}' not readable"          true        end      else        warn "file '#{file}' not found"        true      end    end  end  ##  # Ensure only one generator is loaded  def check_generator    if @generator then      raise OptionParser::InvalidOption,        "generator already set to #{@generator_name}"    end  end  ##  # Set the title, but only if not already set. Used to set the title  # from a source file, so that a title set from the command line  # will have the priority.  def default_title=(string)    @title ||= string  end  ##  # For dumping YAML  def encode_with coder # :nodoc:    encoding = @encoding ? @encoding.name : nil    coder.add 'encoding', encoding    coder.add 'static_path',  sanitize_path(@static_path)    coder.add 'rdoc_include', sanitize_path(@rdoc_include)    ivars = instance_variables.map { |ivar| ivar.to_s[1..-1] }    ivars -= SPECIAL    ivars.sort.each do |ivar|      coder.add ivar, instance_variable_get("@#{ivar}")    end  end  ##  # Completes any unfinished option setup business such as filtering for  # existent files, creating a regexp for #exclude and setting a default  # #template.  def finish    @op_dir ||= 'doc'    @rdoc_include << "." if @rdoc_include.empty?    if @exclude.nil? or Regexp === @exclude then      # done, #finish is being re-run    elsif @exclude.empty? then      @exclude = nil    else      @exclude = Regexp.new(@exclude.join("|"))    end    check_files    # If no template was specified, use the default template for the output    # formatter    unless @template then      @template     = @generator_name      @template_dir = template_dir_for @template    end    self  end  ##  # Returns a properly-space list of generators and their descriptions.  def generator_descriptions    lengths = []    generators = RDoc::RDoc::GENERATORS.map do |name, generator|      lengths << name.length      description = generator::DESCRIPTION if        generator.const_defined? :DESCRIPTION      [name, description]    end    longest = lengths.max    generators.sort.map do |name, description|      if description then        "  %-*s - %s" % [longest, name, description]      else        "  #{name}"      end    end.join "\n"  end  ##  # Parses command line options.  def parse argv    ignore_invalid = true    argv.insert(0, *ENV['RDOCOPT'].split) if ENV['RDOCOPT']    opts = OptionParser.new do |opt|      @option_parser = opt      opt.program_name = File.basename $0      opt.version = RDoc::VERSION      opt.release = nil      opt.summary_indent = ' ' * 4      opt.banner = <<-EOFUsage: #{opt.program_name} [options] [names...]  Files are parsed, and the information they contain collected, before any  output is produced. This allows cross references between all files to be  resolved. If a name is a directory, it is traversed. If no names are  specified, all Ruby files in the current directory (and subdirectories) are  processed.  How RDoc generates output depends on the output formatter being used, and on  the options you give.  Options can be specified via the RDOCOPT environment variable, which  functions similar to the RUBYOPT environment variable for ruby.    $ export RDOCOPT="--show-hash"  will make rdoc show hashes in method links by default.  Command-line options  always will override those in RDOCOPT.  Available formatters:#{generator_descriptions}  RDoc understands the following file formats:      EOF      parsers = Hash.new { |h,parser| h[parser] = [] }      RDoc::Parser.parsers.each do |regexp, parser|        parsers[parser.name.sub('RDoc::Parser::', '')] << regexp.source      end      parsers.sort.each do |parser, regexp|        opt.banner << "  - #{parser}: #{regexp.join ', '}\n"      end      opt.banner << "\n  The following options are deprecated:\n\n"      name_length = DEPRECATED.keys.sort_by { |k| k.length }.last.length      DEPRECATED.sort_by { |k,| k }.each do |name, reason|        opt.banner << "    %*1$2$s  %3$s\n" % [-name_length, name, reason]      end      opt.accept Template do |template|        template_dir = template_dir_for template        unless template_dir then          $stderr.puts "could not find template #{template}"          nil        else          [template, template_dir]        end      end      opt.accept Path do |directory|        directory = File.expand_path directory        raise OptionParser::InvalidArgument unless File.exist? directory        directory      end      opt.accept PathArray do |directories,|        directories = if directories then                        directories.split(',').map { |d| d unless d.empty? }                      end        directories.map do |directory|          directory = File.expand_path directory          raise OptionParser::InvalidArgument unless File.exist? directory          directory        end      end      opt.separator nil      opt.separator "Parsing options:"      opt.separator nil      if Object.const_defined? :Encoding then        opt.on("--encoding=ENCODING", "-e", Encoding.list.map { |e| e.name },               "Specifies the output encoding.  All files",               "read will be converted to this encoding.",               "Preferred over --charset") do |value|                 @encoding = Encoding.find value                 @charset = @encoding.to_s # may not be valid value               end        opt.separator nil      end      opt.on("--all", "-a",             "Synonym for --visibility=private.") do |value|        @visibility = :private      end      opt.separator nil      opt.on("--exclude=PATTERN", "-x", Regexp,             "Do not process files or directories",             "matching PATTERN.") do |value|        @exclude << value      end      opt.separator nil      opt.on("--extension=NEW=OLD", "-E",             "Treat files ending with .new as if they",             "ended with .old. Using '-E cgi=rb' will",             "cause xxx.cgi to be parsed as a Ruby file.") do |value|        new, old = value.split(/=/, 2)        unless new and old then          raise OptionParser::InvalidArgument, "Invalid parameter to '-E'"        end        unless RDoc::Parser.alias_extension old, new then          raise OptionParser::InvalidArgument, "Unknown extension .#{old} to -E"        end      end      opt.separator nil      opt.on("--[no-]force-update", "-U",             "Forces rdoc to scan all sources even if",             "newer than the flag file.") do |value|        @force_update = value      end      opt.separator nil      opt.on("--pipe",             "Convert RDoc on stdin to HTML") do        @pipe = true      end      opt.separator nil      opt.on("--tab-width=WIDTH", "-w", OptionParser::DecimalInteger,             "Set the width of tab characters.") do |value|        @tab_width = value      end      opt.separator nil      opt.on("--visibility=VISIBILITY", "-V", RDoc::VISIBILITIES,             "Minimum visibility to document a method.",             "One of 'public', 'protected' (the default)",             "or 'private'. Can be abbreviated.") do |value|        @visibility = value      end      opt.separator nil      markup_formats = RDoc::Text::MARKUP_FORMAT.keys.sort      opt.on("--markup=MARKUP", markup_formats,             "The markup format for the named files.",             "The default is rdoc.  Valid values are:",             markup_formats.join(', ')) do |value|        @markup = value      end      opt.separator nil      opt.separator "Common generator options:"      opt.separator nil      opt.on("--force-output", "-O",             "Forces rdoc to write the output files,",             "even if the output directory exists",             "and does not seem to have been created",             "by rdoc.") do |value|        @force_output = value      end      opt.separator nil      generator_text = @generators.keys.map { |name| "  #{name}" }.sort      opt.on("-f", "--fmt=FORMAT", "--format=FORMAT", @generators.keys,             "Set the output formatter.  One of:", *generator_text) do |value|        check_generator        @generator_name = value.downcase        setup_generator      end      opt.separator nil      opt.on("--include=DIRECTORIES", "-i", PathArray,             "Set (or add to) the list of directories to",             "be searched when satisfying :include:",             "requests. Can be used more than once.") do |value|        @rdoc_include.concat value.map { |dir| dir.strip }      end      opt.separator nil      opt.on("--[no-]coverage-report=[LEVEL]", "--[no-]dcov", "-C", Integer,             "Prints a report on undocumented items.",             "Does not generate files.") do |value|        value = 0 if value.nil? # Integer converts -C to nil        @coverage_report = value        @force_update = true if value      end      opt.separator nil      opt.on("--output=DIR", "--op", "-o",             "Set the output directory.") do |value|        @op_dir = value      end      opt.separator nil      opt.on("-d",             "Deprecated --diagram option.",             "Prevents firing debug mode",             "with legacy invocation.") do |value|      end      opt.separator nil      opt.separator 'HTML generator options:'      opt.separator nil      opt.on("--charset=CHARSET", "-c",             "Specifies the output HTML character-set.",             "Use --encoding instead of --charset if",             "available.") do |value|        @charset = value      end      opt.separator nil      opt.on("--hyperlink-all", "-A",             "Generate hyperlinks for all words that",             "correspond to known methods, even if they",             "do not start with '#' or '::' (legacy",             "behavior).") do |value|        @hyperlink_all = value      end      opt.separator nil      opt.on("--main=NAME", "-m",             "NAME will be the initial page displayed.") do |value|        @main_page = value      end      opt.separator nil      opt.on("--[no-]line-numbers", "-N",             "Include line numbers in the source code.",             "By default, only the number of the first",             "line is displayed, in a leading comment.") do |value|        @line_numbers = value      end      opt.separator nil      opt.on("--show-hash", "-H",             "A name of the form #name in a comment is a",             "possible hyperlink to an instance method",             "name. When displayed, the '#' is removed",             "unless this option is specified.") do |value|        @show_hash = value      end      opt.separator nil      opt.on("--template=NAME", "-T", Template,             "Set the template used when generating",             "output. The default depends on the",             "formatter used.") do |(template, template_dir)|        @template     = template        @template_dir = template_dir      end      opt.separator nil      opt.on("--title=TITLE", "-t",             "Set TITLE as the title for HTML output.") do |value|        @title = value      end      opt.separator nil      opt.on("--copy-files=PATH", Path,             "Specify a file or directory to copy static",             "files from.",             "If a file is given it will be copied into",             "the output dir.  If a directory is given the",             "entire directory will be copied.",             "You can use this multiple times") do |value|        @static_path << value      end      opt.separator nil      opt.on("--webcvs=URL", "-W",             "Specify a URL for linking to a web frontend",             "to CVS. If the URL contains a '\%s', the",             "name of the current file will be",             "substituted; if the URL doesn't contain a",             "'\%s', the filename will be appended to it.") do |value|        @webcvs = value      end      opt.separator nil      opt.separator "ri generator options:"      opt.separator nil      opt.on("--ri", "-r",             "Generate output for use by `ri`. The files",             "are stored in the '.rdoc' directory under",             "your home directory unless overridden by a",             "subsequent --op parameter, so no special",             "privileges are needed.") do |value|        check_generator        @generator_name = "ri"        @op_dir ||= RDoc::RI::Paths::HOMEDIR        setup_generator      end      opt.separator nil      opt.on("--ri-site", "-R",             "Generate output for use by `ri`. The files",             "are stored in a site-wide directory,",             "making them accessible to others, so",             "special privileges are needed.") do |value|        check_generator        @generator_name = "ri"        @op_dir = RDoc::RI::Paths::SITEDIR        setup_generator      end      opt.separator nil      opt.separator "Generic options:"      opt.separator nil      opt.on("--write-options",             "Write .rdoc_options to the current",             "directory with the given options.  Not all",             "options will be used.  See RDoc::Options",             "for details.") do |value|        @write_options = true      end      opt.separator nil      opt.on("--[no-]dry-run",             "Don't write any files") do |value|        @dry_run = value      end      opt.separator nil      opt.on("-D", "--[no-]debug",             "Displays lots on internal stuff.") do |value|        $DEBUG_RDOC = value      end      opt.separator nil      opt.on("--[no-]ignore-invalid",             "Ignore invalid options and continue",             "(default true).") do |value|        ignore_invalid = value      end      opt.separator nil      opt.on("--quiet", "-q",             "Don't show progress as we parse.") do |value|        @verbosity = 0      end      opt.separator nil      opt.on("--verbose", "-v",             "Display extra progress as RDoc parses") do |value|        @verbosity = 2      end      opt.separator nil      opt.on("--help",             "Display this help") do        RDoc::RDoc::GENERATORS.each_key do |generator|          setup_generator generator        end        puts opt.help        exit      end      opt.separator nil    end    setup_generator 'darkfish' if      argv.grep(/\A(-f|--fmt|--format|-r|-R|--ri|--ri-site)\b/).empty?    deprecated = []    invalid = []    begin      opts.parse! argv    rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e      if DEPRECATED[e.args.first] then        deprecated << e.args.first      elsif %w[--format --ri -r --ri-site -R].include? e.args.first then        raise      else        invalid << e.args.join(' ')      end      retry    end    unless @generator then      @generator = RDoc::Generator::Darkfish      @generator_name = 'darkfish'    end    if @pipe and not argv.empty? then      @pipe = false      invalid << '-p (with files)'    end    unless quiet then      deprecated.each do |opt|        $stderr.puts 'option ' << opt << ' is deprecated: ' << DEPRECATED[opt]      end      unless invalid.empty? then        invalid = "invalid options: #{invalid.join ', '}"        if ignore_invalid then          $stderr.puts invalid          $stderr.puts '(invalid options are ignored)'        else          $stderr.puts opts          $stderr.puts invalid          exit 1        end      end    end    @files = argv.dup    finish    if @write_options then      write_options      exit    end    self  end  ##  # Don't display progress as we process the files  def quiet    @verbosity.zero?  end  ##  # Set quietness to +bool+  def quiet= bool    @verbosity = bool ? 0 : 1  end  ##  # Removes directories from +path+ that are outside the current directory  def sanitize_path path    require 'pathname'    dot = Pathname.new('.').expand_path    path.reject do |item|      path = Pathname.new(item).expand_path      relative = path.relative_path_from(dot).to_s      relative.start_with? '..'    end  end  ##  # Set up an output generator for the named +generator_name+.  #  # If the found generator responds to :setup_options it will be called with  # the options instance.  This allows generators to add custom options or set  # default options.  def setup_generator generator_name = @generator_name    @generator = @generators[generator_name]    unless @generator then      raise OptionParser::InvalidArgument,            "Invalid output formatter #{generator_name}"    end    return if @generator_options.include? @generator    @generator_name = generator_name    @generator_options << @generator    if @generator.respond_to? :setup_options then      @option_parser ||= OptionParser.new      @generator.setup_options self    end  end  ##  # Finds the template dir for +template+  def template_dir_for template    template_path = File.join 'rdoc', 'generator', 'template', template    $LOAD_PATH.map do |path|      File.join File.expand_path(path), template_path    end.find do |dir|      File.directory? dir    end  end  ##  # This is compatibility code for syck  def to_yaml opts = {} # :nodoc:    return super if YAML.const_defined?(:ENGINE) and not YAML::ENGINE.syck?    YAML.quick_emit self, opts do |out|      out.map taguri, to_yaml_style do |map|        encode_with map      end    end  end  ##  # Displays a warning using Kernel#warn if we're being verbose  def warn message    super message if @verbosity > 1  end  ##  # Writes the YAML file .rdoc_options to the current directory containing the  # parsed options.  def write_options    RDoc.load_yaml    open '.rdoc_options', 'w' do |io|      io.set_encoding Encoding::UTF_8 if Object.const_defined? :Encoding      YAML.dump self, io    end  endend
 |