1require 'optparse' 2require 'pathname' 3 4## 5# RDoc::Options handles the parsing and storage of options 6# 7# == Saved Options 8# 9# You can save some options like the markup format in the 10# <tt>.rdoc_options</tt> file in your gem. The easiest way to do this is: 11# 12# rdoc --markup tomdoc --write-options 13# 14# Which will automatically create the file and fill it with the options you 15# specified. 16# 17# The following options will not be saved since they interfere with the user's 18# preferences or with the normal operation of RDoc: 19# 20# * +--coverage-report+ 21# * +--dry-run+ 22# * +--encoding+ 23# * +--force-update+ 24# * +--format+ 25# * +--pipe+ 26# * +--quiet+ 27# * +--template+ 28# * +--verbose+ 29# 30# == Custom Options 31# 32# Generators can hook into RDoc::Options to add generator-specific command 33# line options. 34# 35# When <tt>--format</tt> is encountered in ARGV, RDoc calls ::setup_options on 36# the generator class to add extra options to the option parser. Options for 37# custom generators must occur after <tt>--format</tt>. <tt>rdoc --help</tt> 38# will list options for all installed generators. 39# 40# Example: 41# 42# class RDoc::Generator::Spellcheck 43# RDoc::RDoc.add_generator self 44# 45# def self.setup_options rdoc_options 46# op = rdoc_options.option_parser 47# 48# op.on('--spell-dictionary DICTIONARY', 49# RDoc::Options::Path) do |dictionary| 50# rdoc_options.spell_dictionary = dictionary 51# end 52# end 53# end 54# 55# == Option Validators 56# 57# OptionParser validators will validate and cast user input values. In 58# addition to the validators that ship with OptionParser (String, Integer, 59# Float, TrueClass, FalseClass, Array, Regexp, Date, Time, URI, etc.), 60# RDoc::Options adds Path, PathArray and Template. 61 62class RDoc::Options 63 64 ## 65 # The deprecated options. 66 67 DEPRECATED = { 68 '--accessor' => 'support discontinued', 69 '--diagram' => 'support discontinued', 70 '--help-output' => 'support discontinued', 71 '--image-format' => 'was an option for --diagram', 72 '--inline-source' => 'source code is now always inlined', 73 '--merge' => 'ri now always merges class information', 74 '--one-file' => 'support discontinued', 75 '--op-name' => 'support discontinued', 76 '--opname' => 'support discontinued', 77 '--promiscuous' => 'files always only document their content', 78 '--ri-system' => 'Ruby installers use other techniques', 79 } 80 81 ## 82 # RDoc options ignored (or handled specially) by --write-options 83 84 SPECIAL = %w[ 85 coverage_report 86 dry_run 87 encoding 88 files 89 force_output 90 force_update 91 generator 92 generator_name 93 generator_options 94 generators 95 op_dir 96 option_parser 97 pipe 98 rdoc_include 99 root 100 static_path 101 stylesheet_url 102 template 103 template_dir 104 update_output_dir 105 verbosity 106 write_options 107 ] 108 109 ## 110 # Option validator for OptionParser that matches a directory that exists on 111 # the filesystem. 112 113 Directory = Object.new 114 115 ## 116 # Option validator for OptionParser that matches a file or directory that 117 # exists on the filesystem. 118 119 Path = Object.new 120 121 ## 122 # Option validator for OptionParser that matches a comma-separated list of 123 # files or directories that exist on the filesystem. 124 125 PathArray = Object.new 126 127 ## 128 # Option validator for OptionParser that matches a template directory for an 129 # installed generator that lives in 130 # <tt>"rdoc/generator/template/#{template_name}"</tt> 131 132 Template = Object.new 133 134 ## 135 # Character-set for HTML output. #encoding is preferred over #charset 136 137 attr_accessor :charset 138 139 ## 140 # If true, RDoc will not write any files. 141 142 attr_accessor :dry_run 143 144 ## 145 # The output encoding. All input files will be transcoded to this encoding. 146 # 147 # The default encoding is UTF-8. This is set via --encoding. 148 149 attr_accessor :encoding 150 151 ## 152 # Files matching this pattern will be excluded 153 154 attr_accessor :exclude 155 156 ## 157 # The list of files to be processed 158 159 attr_accessor :files 160 161 ## 162 # Create the output even if the output directory does not look 163 # like an rdoc output directory 164 165 attr_accessor :force_output 166 167 ## 168 # Scan newer sources than the flag file if true. 169 170 attr_accessor :force_update 171 172 ## 173 # Formatter to mark up text with 174 175 attr_accessor :formatter 176 177 ## 178 # Description of the output generator (set with the <tt>--format</tt> option) 179 180 attr_accessor :generator 181 182 ## 183 # For #== 184 185 attr_reader :generator_name # :nodoc: 186 187 ## 188 # Loaded generator options. Used to prevent --help from loading the same 189 # options multiple times. 190 191 attr_accessor :generator_options 192 193 ## 194 # Old rdoc behavior: hyperlink all words that match a method name, 195 # even if not preceded by '#' or '::' 196 197 attr_accessor :hyperlink_all 198 199 ## 200 # Include line numbers in the source code 201 202 attr_accessor :line_numbers 203 204 ## 205 # Name of the file, class or module to display in the initial index page (if 206 # not specified the first file we encounter is used) 207 208 attr_accessor :main_page 209 210 ## 211 # The default markup format. The default is 'rdoc'. 'markdown', 'tomdoc' 212 # and 'rd' are also built-in. 213 214 attr_accessor :markup 215 216 ## 217 # If true, only report on undocumented files 218 219 attr_accessor :coverage_report 220 221 ## 222 # The name of the output directory 223 224 attr_accessor :op_dir 225 226 ## 227 # The OptionParser for this instance 228 229 attr_accessor :option_parser 230 231 ## 232 # Directory where guides, FAQ, and other pages not associated with a class 233 # live. You may leave this unset if these are at the root of your project. 234 235 attr_accessor :page_dir 236 237 ## 238 # Is RDoc in pipe mode? 239 240 attr_accessor :pipe 241 242 ## 243 # Array of directories to search for files to satisfy an :include: 244 245 attr_accessor :rdoc_include 246 247 ## 248 # Root of the source documentation will be generated for. Set this when 249 # building documentation outside the source directory. Defaults to the 250 # current directory. 251 252 attr_accessor :root 253 254 ## 255 # Include the '#' at the front of hyperlinked instance method names 256 257 attr_accessor :show_hash 258 259 ## 260 # Directory to copy static files from 261 262 attr_accessor :static_path 263 264 ## 265 # The number of columns in a tab 266 267 attr_accessor :tab_width 268 269 ## 270 # Template to be used when generating output 271 272 attr_accessor :template 273 274 ## 275 # Directory the template lives in 276 277 attr_accessor :template_dir 278 279 ## 280 # Documentation title 281 282 attr_accessor :title 283 284 ## 285 # Should RDoc update the timestamps in the output dir? 286 287 attr_accessor :update_output_dir 288 289 ## 290 # Verbosity, zero means quiet 291 292 attr_accessor :verbosity 293 294 ## 295 # URL of web cvs frontend 296 297 attr_accessor :webcvs 298 299 ## 300 # Minimum visibility of a documented method. One of +:public+, 301 # +:protected+, +:private+. May be overridden on a per-method 302 # basis with the :doc: directive. 303 304 attr_accessor :visibility 305 306 def initialize # :nodoc: 307 init_ivars 308 end 309 310 def init_ivars # :nodoc: 311 @dry_run = false 312 @exclude = [] 313 @files = nil 314 @force_output = false 315 @force_update = true 316 @generator = nil 317 @generator_name = nil 318 @generator_options = [] 319 @generators = RDoc::RDoc::GENERATORS 320 @hyperlink_all = false 321 @line_numbers = false 322 @main_page = nil 323 @markup = 'rdoc' 324 @coverage_report = false 325 @op_dir = nil 326 @page_dir = nil 327 @pipe = false 328 @rdoc_include = [] 329 @root = Pathname(Dir.pwd) 330 @show_hash = false 331 @static_path = [] 332 @stylesheet_url = nil # TODO remove in RDoc 4 333 @tab_width = 8 334 @template = nil 335 @template_dir = nil 336 @title = nil 337 @update_output_dir = true 338 @verbosity = 1 339 @visibility = :protected 340 @webcvs = nil 341 @write_options = false 342 343 if Object.const_defined? :Encoding then 344 @encoding = Encoding::UTF_8 345 @charset = @encoding.name 346 else 347 @encoding = nil 348 @charset = 'UTF-8' 349 end 350 end 351 352 def init_with map # :nodoc: 353 init_ivars 354 355 encoding = map['encoding'] 356 @encoding = if Object.const_defined? :Encoding then 357 encoding ? Encoding.find(encoding) : encoding 358 end 359 360 @charset = map['charset'] 361 @exclude = map['exclude'] 362 @generator_name = map['generator_name'] 363 @hyperlink_all = map['hyperlink_all'] 364 @line_numbers = map['line_numbers'] 365 @main_page = map['main_page'] 366 @markup = map['markup'] 367 @op_dir = map['op_dir'] 368 @show_hash = map['show_hash'] 369 @tab_width = map['tab_width'] 370 @template_dir = map['template_dir'] 371 @title = map['title'] 372 @visibility = map['visibility'] 373 @webcvs = map['webcvs'] 374 375 @rdoc_include = sanitize_path map['rdoc_include'] 376 @static_path = sanitize_path map['static_path'] 377 end 378 379 def yaml_initialize tag, map # :nodoc: 380 init_with map 381 end 382 383 def == other # :nodoc: 384 self.class === other and 385 @encoding == other.encoding and 386 @generator_name == other.generator_name and 387 @hyperlink_all == other.hyperlink_all and 388 @line_numbers == other.line_numbers and 389 @main_page == other.main_page and 390 @markup == other.markup and 391 @op_dir == other.op_dir and 392 @rdoc_include == other.rdoc_include and 393 @show_hash == other.show_hash and 394 @static_path == other.static_path and 395 @tab_width == other.tab_width and 396 @template == other.template and 397 @title == other.title and 398 @visibility == other.visibility and 399 @webcvs == other.webcvs 400 end 401 402 ## 403 # Check that the files on the command line exist 404 405 def check_files 406 @files.delete_if do |file| 407 if File.exist? file then 408 if File.readable? file then 409 false 410 else 411 warn "file '#{file}' not readable" 412 413 true 414 end 415 else 416 warn "file '#{file}' not found" 417 418 true 419 end 420 end 421 end 422 423 ## 424 # Ensure only one generator is loaded 425 426 def check_generator 427 if @generator then 428 raise OptionParser::InvalidOption, 429 "generator already set to #{@generator_name}" 430 end 431 end 432 433 ## 434 # Set the title, but only if not already set. Used to set the title 435 # from a source file, so that a title set from the command line 436 # will have the priority. 437 438 def default_title=(string) 439 @title ||= string 440 end 441 442 ## 443 # For dumping YAML 444 445 def encode_with coder # :nodoc: 446 encoding = @encoding ? @encoding.name : nil 447 448 coder.add 'encoding', encoding 449 coder.add 'static_path', sanitize_path(@static_path) 450 coder.add 'rdoc_include', sanitize_path(@rdoc_include) 451 452 ivars = instance_variables.map { |ivar| ivar.to_s[1..-1] } 453 ivars -= SPECIAL 454 455 ivars.sort.each do |ivar| 456 coder.add ivar, instance_variable_get("@#{ivar}") 457 end 458 end 459 460 ## 461 # Completes any unfinished option setup business such as filtering for 462 # existent files, creating a regexp for #exclude and setting a default 463 # #template. 464 465 def finish 466 @op_dir ||= 'doc' 467 468 @rdoc_include << "." if @rdoc_include.empty? 469 470 if @exclude.nil? or Regexp === @exclude then 471 # done, #finish is being re-run 472 elsif @exclude.empty? then 473 @exclude = nil 474 else 475 @exclude = Regexp.new(@exclude.join("|")) 476 end 477 478 finish_page_dir 479 480 check_files 481 482 # If no template was specified, use the default template for the output 483 # formatter 484 485 unless @template then 486 @template = @generator_name 487 @template_dir = template_dir_for @template 488 end 489 490 self 491 end 492 493 ## 494 # Fixes the page_dir to be relative to the root_dir and adds the page_dir to 495 # the files list. 496 497 def finish_page_dir 498 return unless @page_dir 499 500 @files << @page_dir.to_s 501 502 page_dir = @page_dir.expand_path.relative_path_from @root 503 504 @page_dir = page_dir 505 end 506 507 ## 508 # Returns a properly-space list of generators and their descriptions. 509 510 def generator_descriptions 511 lengths = [] 512 513 generators = RDoc::RDoc::GENERATORS.map do |name, generator| 514 lengths << name.length 515 516 description = generator::DESCRIPTION if 517 generator.const_defined? :DESCRIPTION 518 519 [name, description] 520 end 521 522 longest = lengths.max 523 524 generators.sort.map do |name, description| 525 if description then 526 " %-*s - %s" % [longest, name, description] 527 else 528 " #{name}" 529 end 530 end.join "\n" 531 end 532 533 ## 534 # Parses command line options. 535 536 def parse argv 537 ignore_invalid = true 538 539 argv.insert(0, *ENV['RDOCOPT'].split) if ENV['RDOCOPT'] 540 541 opts = OptionParser.new do |opt| 542 @option_parser = opt 543 opt.program_name = File.basename $0 544 opt.version = RDoc::VERSION 545 opt.release = nil 546 opt.summary_indent = ' ' * 4 547 opt.banner = <<-EOF 548Usage: #{opt.program_name} [options] [names...] 549 550 Files are parsed, and the information they contain collected, before any 551 output is produced. This allows cross references between all files to be 552 resolved. If a name is a directory, it is traversed. If no names are 553 specified, all Ruby files in the current directory (and subdirectories) are 554 processed. 555 556 How RDoc generates output depends on the output formatter being used, and on 557 the options you give. 558 559 Options can be specified via the RDOCOPT environment variable, which 560 functions similar to the RUBYOPT environment variable for ruby. 561 562 $ export RDOCOPT="--show-hash" 563 564 will make rdoc show hashes in method links by default. Command-line options 565 always will override those in RDOCOPT. 566 567 Available formatters: 568 569#{generator_descriptions} 570 571 RDoc understands the following file formats: 572 573 EOF 574 575 parsers = Hash.new { |h,parser| h[parser] = [] } 576 577 RDoc::Parser.parsers.each do |regexp, parser| 578 parsers[parser.name.sub('RDoc::Parser::', '')] << regexp.source 579 end 580 581 parsers.sort.each do |parser, regexp| 582 opt.banner << " - #{parser}: #{regexp.join ', '}\n" 583 end 584 585 opt.banner << "\n The following options are deprecated:\n\n" 586 587 name_length = DEPRECATED.keys.sort_by { |k| k.length }.last.length 588 589 DEPRECATED.sort_by { |k,| k }.each do |name, reason| 590 opt.banner << " %*1$2$s %3$s\n" % [-name_length, name, reason] 591 end 592 593 opt.accept Template do |template| 594 template_dir = template_dir_for template 595 596 unless template_dir then 597 $stderr.puts "could not find template #{template}" 598 nil 599 else 600 [template, template_dir] 601 end 602 end 603 604 opt.accept Directory do |directory| 605 directory = File.expand_path directory 606 607 raise OptionParser::InvalidArgument unless File.directory? directory 608 609 directory 610 end 611 612 opt.accept Path do |path| 613 path = File.expand_path path 614 615 raise OptionParser::InvalidArgument unless File.exist? path 616 617 path 618 end 619 620 opt.accept PathArray do |paths,| 621 paths = if paths then 622 paths.split(',').map { |d| d unless d.empty? } 623 end 624 625 paths.map do |path| 626 path = File.expand_path path 627 628 raise OptionParser::InvalidArgument unless File.exist? path 629 630 path 631 end 632 end 633 634 opt.separator nil 635 opt.separator "Parsing options:" 636 opt.separator nil 637 638 if Object.const_defined? :Encoding then 639 opt.on("--encoding=ENCODING", "-e", Encoding.list.map { |e| e.name }, 640 "Specifies the output encoding. All files", 641 "read will be converted to this encoding.", 642 "The default encoding is UTF-8.", 643 "--encoding is preferred over --charset") do |value| 644 @encoding = Encoding.find value 645 @charset = @encoding.name # may not be valid value 646 end 647 648 opt.separator nil 649 end 650 651 opt.on("--all", "-a", 652 "Synonym for --visibility=private.") do |value| 653 @visibility = :private 654 end 655 656 opt.separator nil 657 658 opt.on("--exclude=PATTERN", "-x", Regexp, 659 "Do not process files or directories", 660 "matching PATTERN.") do |value| 661 @exclude << value 662 end 663 664 opt.separator nil 665 666 opt.on("--extension=NEW=OLD", "-E", 667 "Treat files ending with .new as if they", 668 "ended with .old. Using '-E cgi=rb' will", 669 "cause xxx.cgi to be parsed as a Ruby file.") do |value| 670 new, old = value.split(/=/, 2) 671 672 unless new and old then 673 raise OptionParser::InvalidArgument, "Invalid parameter to '-E'" 674 end 675 676 unless RDoc::Parser.alias_extension old, new then 677 raise OptionParser::InvalidArgument, "Unknown extension .#{old} to -E" 678 end 679 end 680 681 opt.separator nil 682 683 opt.on("--[no-]force-update", "-U", 684 "Forces rdoc to scan all sources even if", 685 "newer than the flag file.") do |value| 686 @force_update = value 687 end 688 689 opt.separator nil 690 691 opt.on("--pipe", "-p", 692 "Convert RDoc on stdin to HTML") do 693 @pipe = true 694 end 695 696 opt.separator nil 697 698 opt.on("--tab-width=WIDTH", "-w", OptionParser::DecimalInteger, 699 "Set the width of tab characters.") do |value| 700 @tab_width = value 701 end 702 703 opt.separator nil 704 705 opt.on("--visibility=VISIBILITY", "-V", RDoc::VISIBILITIES, 706 "Minimum visibility to document a method.", 707 "One of 'public', 'protected' (the default)", 708 "or 'private'. Can be abbreviated.") do |value| 709 @visibility = value 710 end 711 712 opt.separator nil 713 714 markup_formats = RDoc::Text::MARKUP_FORMAT.keys.sort 715 716 opt.on("--markup=MARKUP", markup_formats, 717 "The markup format for the named files.", 718 "The default is rdoc. Valid values are:", 719 markup_formats.join(', ')) do |value| 720 @markup = value 721 end 722 723 opt.separator nil 724 725 opt.on("--root=ROOT", Directory, 726 "Root of the source tree documentation", 727 "will be generated for. Set this when", 728 "building documentation outside the", 729 "source directory. Default is the", 730 "current directory.") do |root| 731 @root = Pathname(root) 732 end 733 734 opt.separator nil 735 736 opt.on("--page-dir=DIR", Directory, 737 "Directory where guides, your FAQ or", 738 "other pages not associated with a class", 739 "live. Set this when you don't store", 740 "such files at your project root.", 741 "NOTE: Do not use the same file name in", 742 "the page dir and the root of your project") do |page_dir| 743 @page_dir = Pathname(page_dir) 744 end 745 746 opt.separator nil 747 opt.separator "Common generator options:" 748 opt.separator nil 749 750 opt.on("--force-output", "-O", 751 "Forces rdoc to write the output files,", 752 "even if the output directory exists", 753 "and does not seem to have been created", 754 "by rdoc.") do |value| 755 @force_output = value 756 end 757 758 opt.separator nil 759 760 generator_text = @generators.keys.map { |name| " #{name}" }.sort 761 762 opt.on("-f", "--fmt=FORMAT", "--format=FORMAT", @generators.keys, 763 "Set the output formatter. One of:", *generator_text) do |value| 764 check_generator 765 766 @generator_name = value.downcase 767 setup_generator 768 end 769 770 opt.separator nil 771 772 opt.on("--include=DIRECTORIES", "-i", PathArray, 773 "Set (or add to) the list of directories to", 774 "be searched when satisfying :include:", 775 "requests. Can be used more than once.") do |value| 776 @rdoc_include.concat value.map { |dir| dir.strip } 777 end 778 779 opt.separator nil 780 781 opt.on("--[no-]coverage-report=[LEVEL]", "--[no-]dcov", "-C", Integer, 782 "Prints a report on undocumented items.", 783 "Does not generate files.") do |value| 784 value = 0 if value.nil? # Integer converts -C to nil 785 786 @coverage_report = value 787 @force_update = true if value 788 end 789 790 opt.separator nil 791 792 opt.on("--output=DIR", "--op", "-o", 793 "Set the output directory.") do |value| 794 @op_dir = value 795 end 796 797 opt.separator nil 798 799 opt.on("-d", 800 "Deprecated --diagram option.", 801 "Prevents firing debug mode", 802 "with legacy invocation.") do |value| 803 end 804 805 opt.separator nil 806 opt.separator 'HTML generator options:' 807 opt.separator nil 808 809 opt.on("--charset=CHARSET", "-c", 810 "Specifies the output HTML character-set.", 811 "Use --encoding instead of --charset if", 812 "available.") do |value| 813 @charset = value 814 end 815 816 opt.separator nil 817 818 opt.on("--hyperlink-all", "-A", 819 "Generate hyperlinks for all words that", 820 "correspond to known methods, even if they", 821 "do not start with '#' or '::' (legacy", 822 "behavior).") do |value| 823 @hyperlink_all = value 824 end 825 826 opt.separator nil 827 828 opt.on("--main=NAME", "-m", 829 "NAME will be the initial page displayed.") do |value| 830 @main_page = value 831 end 832 833 opt.separator nil 834 835 opt.on("--[no-]line-numbers", "-N", 836 "Include line numbers in the source code.", 837 "By default, only the number of the first", 838 "line is displayed, in a leading comment.") do |value| 839 @line_numbers = value 840 end 841 842 opt.separator nil 843 844 opt.on("--show-hash", "-H", 845 "A name of the form #name in a comment is a", 846 "possible hyperlink to an instance method", 847 "name. When displayed, the '#' is removed", 848 "unless this option is specified.") do |value| 849 @show_hash = value 850 end 851 852 opt.separator nil 853 854 opt.on("--template=NAME", "-T", Template, 855 "Set the template used when generating", 856 "output. The default depends on the", 857 "formatter used.") do |(template, template_dir)| 858 @template = template 859 @template_dir = template_dir 860 end 861 862 opt.separator nil 863 864 opt.on("--title=TITLE", "-t", 865 "Set TITLE as the title for HTML output.") do |value| 866 @title = value 867 end 868 869 opt.separator nil 870 871 opt.on("--copy-files=PATH", Path, 872 "Specify a file or directory to copy static", 873 "files from.", 874 "If a file is given it will be copied into", 875 "the output dir. If a directory is given the", 876 "entire directory will be copied.", 877 "You can use this multiple times") do |value| 878 @static_path << value 879 end 880 881 opt.separator nil 882 883 opt.on("--webcvs=URL", "-W", 884 "Specify a URL for linking to a web frontend", 885 "to CVS. If the URL contains a '\%s', the", 886 "name of the current file will be", 887 "substituted; if the URL doesn't contain a", 888 "'\%s', the filename will be appended to it.") do |value| 889 @webcvs = value 890 end 891 892 opt.separator nil 893 opt.separator "ri generator options:" 894 opt.separator nil 895 896 opt.on("--ri", "-r", 897 "Generate output for use by `ri`. The files", 898 "are stored in the '.rdoc' directory under", 899 "your home directory unless overridden by a", 900 "subsequent --op parameter, so no special", 901 "privileges are needed.") do |value| 902 check_generator 903 904 @generator_name = "ri" 905 @op_dir ||= RDoc::RI::Paths::HOMEDIR 906 setup_generator 907 end 908 909 opt.separator nil 910 911 opt.on("--ri-site", "-R", 912 "Generate output for use by `ri`. The files", 913 "are stored in a site-wide directory,", 914 "making them accessible to others, so", 915 "special privileges are needed.") do |value| 916 check_generator 917 918 @generator_name = "ri" 919 @op_dir = RDoc::RI::Paths::SITEDIR 920 setup_generator 921 end 922 923 opt.separator nil 924 opt.separator "Generic options:" 925 opt.separator nil 926 927 opt.on("--write-options", 928 "Write .rdoc_options to the current", 929 "directory with the given options. Not all", 930 "options will be used. See RDoc::Options", 931 "for details.") do |value| 932 @write_options = true 933 end 934 935 opt.separator nil 936 937 opt.on("--[no-]dry-run", 938 "Don't write any files") do |value| 939 @dry_run = value 940 end 941 942 opt.separator nil 943 944 opt.on("-D", "--[no-]debug", 945 "Displays lots on internal stuff.") do |value| 946 $DEBUG_RDOC = value 947 end 948 949 opt.separator nil 950 951 opt.on("--[no-]ignore-invalid", 952 "Ignore invalid options and continue", 953 "(default true).") do |value| 954 ignore_invalid = value 955 end 956 957 opt.separator nil 958 959 opt.on("--quiet", "-q", 960 "Don't show progress as we parse.") do |value| 961 @verbosity = 0 962 end 963 964 opt.separator nil 965 966 opt.on("--verbose", "-v", 967 "Display extra progress as RDoc parses") do |value| 968 @verbosity = 2 969 end 970 971 opt.separator nil 972 973 opt.on("--help", 974 "Display this help") do 975 RDoc::RDoc::GENERATORS.each_key do |generator| 976 setup_generator generator 977 end 978 979 puts opt.help 980 exit 981 end 982 983 opt.separator nil 984 end 985 986 setup_generator 'darkfish' if 987 argv.grep(/\A(-f|--fmt|--format|-r|-R|--ri|--ri-site)\b/).empty? 988 989 deprecated = [] 990 invalid = [] 991 992 begin 993 opts.parse! argv 994 rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e 995 if DEPRECATED[e.args.first] then 996 deprecated << e.args.first 997 elsif %w[--format --ri -r --ri-site -R].include? e.args.first then 998 raise 999 else 1000 invalid << e.args.join(' ') 1001 end 1002 1003 retry 1004 end 1005 1006 unless @generator then 1007 @generator = RDoc::Generator::Darkfish 1008 @generator_name = 'darkfish' 1009 end 1010 1011 if @pipe and not argv.empty? then 1012 @pipe = false 1013 invalid << '-p (with files)' 1014 end 1015 1016 unless quiet then 1017 deprecated.each do |opt| 1018 $stderr.puts 'option ' << opt << ' is deprecated: ' << DEPRECATED[opt] 1019 end 1020 1021 unless invalid.empty? then 1022 invalid = "invalid options: #{invalid.join ', '}" 1023 1024 if ignore_invalid then 1025 $stderr.puts invalid 1026 $stderr.puts '(invalid options are ignored)' 1027 else 1028 $stderr.puts opts 1029 $stderr.puts invalid 1030 exit 1 1031 end 1032 end 1033 end 1034 1035 @files = argv.dup 1036 1037 finish 1038 1039 if @write_options then 1040 write_options 1041 exit 1042 end 1043 1044 self 1045 end 1046 1047 ## 1048 # Don't display progress as we process the files 1049 1050 def quiet 1051 @verbosity.zero? 1052 end 1053 1054 ## 1055 # Set quietness to +bool+ 1056 1057 def quiet= bool 1058 @verbosity = bool ? 0 : 1 1059 end 1060 1061 ## 1062 # Removes directories from +path+ that are outside the current directory 1063 1064 def sanitize_path path 1065 require 'pathname' 1066 dot = Pathname.new('.').expand_path 1067 1068 path.reject do |item| 1069 path = Pathname.new(item).expand_path 1070 relative = path.relative_path_from(dot).to_s 1071 relative.start_with? '..' 1072 end 1073 end 1074 1075 ## 1076 # Set up an output generator for the named +generator_name+. 1077 # 1078 # If the found generator responds to :setup_options it will be called with 1079 # the options instance. This allows generators to add custom options or set 1080 # default options. 1081 1082 def setup_generator generator_name = @generator_name 1083 @generator = @generators[generator_name] 1084 1085 unless @generator then 1086 raise OptionParser::InvalidArgument, 1087 "Invalid output formatter #{generator_name}" 1088 end 1089 1090 return if @generator_options.include? @generator 1091 1092 @generator_name = generator_name 1093 @generator_options << @generator 1094 1095 if @generator.respond_to? :setup_options then 1096 @option_parser ||= OptionParser.new 1097 @generator.setup_options self 1098 end 1099 end 1100 1101 ## 1102 # Finds the template dir for +template+ 1103 1104 def template_dir_for template 1105 template_path = File.join 'rdoc', 'generator', 'template', template 1106 1107 $LOAD_PATH.map do |path| 1108 File.join File.expand_path(path), template_path 1109 end.find do |dir| 1110 File.directory? dir 1111 end 1112 end 1113 1114 ## 1115 # This is compatibility code for syck 1116 1117 def to_yaml opts = {} # :nodoc: 1118 return super if YAML.const_defined?(:ENGINE) and not YAML::ENGINE.syck? 1119 1120 YAML.quick_emit self, opts do |out| 1121 out.map taguri, to_yaml_style do |map| 1122 encode_with map 1123 end 1124 end 1125 end 1126 1127 ## 1128 # Displays a warning using Kernel#warn if we're being verbose 1129 1130 def warn message 1131 super message if @verbosity > 1 1132 end 1133 1134 ## 1135 # Writes the YAML file .rdoc_options to the current directory containing the 1136 # parsed options. 1137 1138 def write_options 1139 RDoc.load_yaml 1140 1141 open '.rdoc_options', 'w' do |io| 1142 io.set_encoding Encoding::UTF_8 if Object.const_defined? :Encoding 1143 1144 YAML.dump self, io 1145 end 1146 end 1147 1148end 1149 1150