Object
The commandline parser. In typical usage, the methods in this class will be handled internally by Trollop::options. In this case, only the #, # and #, #, and # methods will typically be called.
If you want to instantiate this class yourself (for more complicated argument-parsing logic), call # to actually produce the output hash, and consider calling it from within Trollop::with_standard_exception_handling.
The set of values that indicate a flag option when passed as the :type parameter of #.
The set of values that indicate a single-parameter (normal) option when passed as the :type parameter of #.
A value of io corresponds to a readable IO resource, including a filename, URI, or the strings ‘stdin’ or ’-’.
The set of values that indicate a multiple-parameter option (i.e., that takes multiple space-separated values on the commandline) when passed as the :type parameter of #.
The complete set of legal values for the :type parameter of #.
Initializes the parser, and instance-evaluates any block given.
# File lib/trollop.rb, line 70 70: def initialize *a, &b 71: @version = nil 72: @leftovers = [] 73: @specs = {} 74: @long = {} 75: @short = {} 76: @order = [] 77: @constraints = [] 78: @stop_words = [] 79: @stop_on_unknown = false 80: 81: #instance_eval(&b) if b # can't take arguments 82: cloaker(&b).bind(self).call(*a) if b 83: end
Marks two (or more!) options as conflicting.
# File lib/trollop.rb, line 255 255: def conflicts *syms 256: syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] } 257: @constraints << [:conflicts, syms] 258: end
Marks two (or more!) options as requiring each other. Only handles undirected (i.e., mutual) dependencies. Directed dependencies are better modeled with Trollop::die.
# File lib/trollop.rb, line 249 249: def depends *syms 250: syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] } 251: @constraints << [:depends, syms] 252: end
The per-parser version of Trollop::die (see that for documentation).
# File lib/trollop.rb, line 513 513: def die arg, msg 514: if msg 515: $stderr.puts "Error: argument --#{@specs[arg][:long]} #{msg}." 516: else 517: $stderr.puts "Error: #{arg}." 518: end 519: $stderr.puts "Try --help for help." 520: exit(1) 521: end
Print the help message to stream.
# File lib/trollop.rb, line 424 424: def educate stream=$stdout 425: width # just calculate it now; otherwise we have to be careful not to 426: # call this unless the cursor's at the beginning of a line. 427: 428: left = {} 429: @specs.each do |name, spec| 430: left[name] = "--#{spec[:long]}" + 431: (spec[:short] && spec[:short] != :none ? ", -#{spec[:short]}" : "") + 432: case spec[:type] 433: when :flag; "" 434: when :int; " <i>" 435: when :ints; " <i+>" 436: when :string; " <s>" 437: when :strings; " <s+>" 438: when :float; " <f>" 439: when :floats; " <f+>" 440: when :io; " <filename/uri>" 441: when :ios; " <filename/uri+>" 442: when :date; " <date>" 443: when :dates; " <date+>" 444: end 445: end 446: 447: leftcol_width = left.values.map { |s| s.length }.max || 0 448: rightcol_start = leftcol_width + 6 # spaces 449: 450: unless @order.size > 0 && @order.first.first == :text 451: stream.puts "#@version\n" if @version 452: stream.puts "Options:" 453: end 454: 455: @order.each do |what, opt| 456: if what == :text 457: stream.puts wrap(opt) 458: next 459: end 460: 461: spec = @specs[opt] 462: stream.printf " %#{leftcol_width}s: ", left[opt] 463: desc = spec[:desc] + begin 464: default_s = case spec[:default] 465: when $stdout; "<stdout>" 466: when $stdin; "<stdin>" 467: when $stderr; "<stderr>" 468: when Array 469: spec[:default].join(", ") 470: else 471: spec[:default].to_s 472: end 473: 474: if spec[:default] 475: if spec[:desc] =~ /\.$/ 476: " (Default: #{default_s})" 477: else 478: " (default: #{default_s})" 479: end 480: else 481: "" 482: end 483: end 484: stream.puts wrap(desc, :width => width - rightcol_start - 1, :prefix => rightcol_start) 485: end 486: end
Define an option. name is the option name, a unique identifier for the option that you will use internally, which should be a symbol or a string. desc is a string description which will be displayed in help messages.
Takes the following optional arguments:
Specify the long form of the argument, i.e. the form with two dashes. If unspecified, will be automatically derived based on the argument name by turning the name option into a string, and replacing any _’s by -’s.
Specify the short form of the argument, i.e. the form with one dash. If unspecified, will be automatically derived from name.
Require that the argument take a parameter or parameters of type type. For a single parameter, the value can be a member of SINGLE_ARG_TYPES, or a corresponding Ruby class (e.g. Integer for :int). For multiple-argument parameters, the value can be any member of MULTI_ARG_TYPES constant. If unset, the default argument type is :flag, meaning that the argument does not take a parameter. The specification of :type is not necessary if a :default is given.
Set the default value for an argument. Without a default value, the hash returned by # (and thus Trollop::options) will have a nil value for this key unless the argument is given on the commandline. The argument type is derived automatically from the class of the default value given, so specifying a :type is not necessary if a :default is given. (But see below for an important caveat when :multi: is specified too.) If the argument is a flag, and the default is set to true, then if it is specified on the the commandline the value will be false.
If set to true, the argument must be provided on the commandline.
If set to true, allows multiple occurrences of the option on the commandline. Otherwise, only a single instance of the option is allowed. (Note that this is different from taking multiple parameters. See below.)
Note that there are two types of argument multiplicity: an argument can take multiple values, e.g. “—arg 1 2 3”. An argument can also be allowed to occur multiple times, e.g. “—arg 1 —arg 2”.
Arguments that take multiple values should have a :type parameter drawn from MULTI_ARG_TYPES (e.g. :strings), or a :default: value of an array of the correct type (e.g. [String]). The value of this argument will be an array of the parameters on the commandline.
Arguments that can occur multiple times should be marked with :multi => true. The value of this argument will also be an array. In contrast with regular non-multi options, if not specified on the commandline, the default value will be [], not nil.
These two attributes can be combined (e.g. :type => :strings, :multi => true), in which case the value of the argument will be an array of arrays.
There’s one ambiguous case to be aware of: when :multi: is true and a :default is set to an array (of something), it’s ambiguous whether this is a multi-value argument as well as a multi-occurrence argument. In thise case, Trollop assumes that it’s not a multi-value argument. If you want a multi-value, multi-occurrence argument with a default value, you must specify :type as well.
# File lib/trollop.rb, line 125 125: def opt name, desc="", opts={} 126: raise ArgumentError, "you already have an argument named '#{name}'" if @specs.member? name 127: 128: ## fill in :type 129: opts[:type] = # normalize 130: case opts[:type] 131: when :boolean, :bool; :flag 132: when :integer; :int 133: when :integers; :ints 134: when :double; :float 135: when :doubles; :floats 136: when Class 137: case opts[:type].name 138: when 'TrueClass', 'FalseClass'; :flag 139: when 'String'; :string 140: when 'Integer'; :int 141: when 'Float'; :float 142: when 'IO'; :io 143: when 'Date'; :date 144: else 145: raise ArgumentError, "unsupported argument type '#{opts[:type].class.name}'" 146: end 147: when nil; nil 148: else 149: raise ArgumentError, "unsupported argument type '#{opts[:type]}'" unless TYPES.include?(opts[:type]) 150: opts[:type] 151: end 152: 153: ## for options with :multi => true, an array default doesn't imply 154: ## a multi-valued argument. for that you have to specify a :type 155: ## as well. (this is how we disambiguate an ambiguous situation; 156: ## see the docs for Parser#opt for details.) 157: disambiguated_default = 158: if opts[:multi] && opts[:default].is_a?(Array) && !opts[:type] 159: opts[:default].first 160: else 161: opts[:default] 162: end 163: 164: type_from_default = 165: case disambiguated_default 166: when Integer; :int 167: when Numeric; :float 168: when TrueClass, FalseClass; :flag 169: when String; :string 170: when IO; :io 171: when Date; :date 172: when Array 173: if opts[:default].empty? 174: raise ArgumentError, "multiple argument type cannot be deduced from an empty array for '#{opts[:default][0].class.name}'" 175: end 176: case opts[:default][0] # the first element determines the types 177: when Integer; :ints 178: when Numeric; :floats 179: when String; :strings 180: when IO; :ios 181: when Date; :dates 182: else 183: raise ArgumentError, "unsupported multiple argument type '#{opts[:default][0].class.name}'" 184: end 185: when nil; nil 186: else 187: raise ArgumentError, "unsupported argument type '#{opts[:default].class.name}'" 188: end 189: 190: raise ArgumentError, ":type specification and default type don't match (default type is #{type_from_default})" if opts[:type] && type_from_default && opts[:type] != type_from_default 191: 192: opts[:type] = opts[:type] || type_from_default || :flag 193: 194: ## fill in :long 195: opts[:long] = opts[:long] ? opts[:long].to_s : name.to_s.gsub("_", "-") 196: opts[:long] = 197: case opts[:long] 198: when /^--([^-].*)$/ 199: $1 200: when /^[^-]/ 201: opts[:long] 202: else 203: raise ArgumentError, "invalid long option name #{opts[:long].inspect}" 204: end 205: raise ArgumentError, "long option name #{opts[:long].inspect} is already taken; please specify a (different) :long" if @long[opts[:long]] 206: 207: ## fill in :short 208: opts[:short] = opts[:short].to_s if opts[:short] unless opts[:short] == :none 209: opts[:short] = case opts[:short] 210: when /^-(.)$/; $1 211: when nil, :none, /^.$/; opts[:short] 212: else raise ArgumentError, "invalid short option name '#{opts[:short].inspect}'" 213: end 214: 215: if opts[:short] 216: raise ArgumentError, "short option name #{opts[:short].inspect} is already taken; please specify a (different) :short" if @short[opts[:short]] 217: raise ArgumentError, "a short option name can't be a number or a dash" if opts[:short] =~ INVALID_SHORT_ARG_REGEX 218: end 219: 220: ## fill in :default for flags 221: opts[:default] = false if opts[:type] == :flag && opts[:default].nil? 222: 223: ## autobox :default for :multi (multi-occurrence) arguments 224: opts[:default] = [opts[:default]] if opts[:default] && opts[:multi] && !opts[:default].is_a?(Array) 225: 226: ## fill in :multi 227: opts[:multi] ||= false 228: 229: opts[:desc] ||= desc 230: @long[opts[:long]] = name 231: @short[opts[:short]] = name if opts[:short] && opts[:short] != :none 232: @specs[name] = opts 233: @order << [:opt, name] 234: end
Parses the commandline. Typically called by Trollop::options, but you can call it directly if you need more control.
throws CommandlineError, HelpNeeded, and VersionNeeded exceptions.
# File lib/trollop.rb, line 285 285: def parse cmdline=ARGV 286: vals = {} 287: required = {} 288: 289: opt :version, "Print version and exit" if @version unless @specs[:version] || @long["version"] 290: opt :help, "Show this message" unless @specs[:help] || @long["help"] 291: 292: @specs.each do |sym, opts| 293: required[sym] = true if opts[:required] 294: vals[sym] = opts[:default] 295: vals[sym] = [] if opts[:multi] && !opts[:default] # multi arguments default to [], not nil 296: end 297: 298: resolve_default_short_options 299: 300: ## resolve symbols 301: given_args = {} 302: @leftovers = each_arg cmdline do |arg, params| 303: sym = case arg 304: when /^-([^-])$/ 305: @short[$1] 306: when /^--([^-]\S*)$/ 307: @long[$1] 308: else 309: raise CommandlineError, "invalid argument syntax: '#{arg}'" 310: end 311: raise CommandlineError, "unknown argument '#{arg}'" unless sym 312: 313: if given_args.include?(sym) && !@specs[sym][:multi] 314: raise CommandlineError, "option '#{arg}' specified multiple times" 315: end 316: 317: given_args[sym] ||= {} 318: 319: given_args[sym][:arg] = arg 320: given_args[sym][:params] ||= [] 321: 322: # The block returns the number of parameters taken. 323: num_params_taken = 0 324: 325: unless params.nil? 326: if SINGLE_ARG_TYPES.include?(@specs[sym][:type]) 327: given_args[sym][:params] << params[0, 1] # take the first parameter 328: num_params_taken = 1 329: elsif MULTI_ARG_TYPES.include?(@specs[sym][:type]) 330: given_args[sym][:params] << params # take all the parameters 331: num_params_taken = params.size 332: end 333: end 334: 335: num_params_taken 336: end 337: 338: ## check for version and help args 339: raise VersionNeeded if given_args.include? :version 340: raise HelpNeeded if given_args.include? :help 341: 342: ## check constraint satisfaction 343: @constraints.each do |type, syms| 344: constraint_sym = syms.find { |sym| given_args[sym] } 345: next unless constraint_sym 346: 347: case type 348: when :depends 349: syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym][:long]} requires --#{@specs[sym][:long]}" unless given_args.include? sym } 350: when :conflicts 351: syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym][:long]} conflicts with --#{@specs[sym][:long]}" if given_args.include?(sym) && (sym != constraint_sym) } 352: end 353: end 354: 355: required.each do |sym, val| 356: raise CommandlineError, "option --#{@specs[sym][:long]} must be specified" unless given_args.include? sym 357: end 358: 359: ## parse parameters 360: given_args.each do |sym, given_data| 361: arg = given_data[:arg] 362: params = given_data[:params] 363: 364: opts = @specs[sym] 365: raise CommandlineError, "option '#{arg}' needs a parameter" if params.empty? && opts[:type] != :flag 366: 367: vals["#{sym}_given".intern] = true # mark argument as specified on the commandline 368: 369: case opts[:type] 370: when :flag 371: vals[sym] = !opts[:default] 372: when :int, :ints 373: vals[sym] = params.map { |pg| pg.map { |p| parse_integer_parameter p, arg } } 374: when :float, :floats 375: vals[sym] = params.map { |pg| pg.map { |p| parse_float_parameter p, arg } } 376: when :string, :strings 377: vals[sym] = params.map { |pg| pg.map { |p| p.to_s } } 378: when :io, :ios 379: vals[sym] = params.map { |pg| pg.map { |p| parse_io_parameter p, arg } } 380: when :date, :dates 381: vals[sym] = params.map { |pg| pg.map { |p| parse_date_parameter p, arg } } 382: end 383: 384: if SINGLE_ARG_TYPES.include?(opts[:type]) 385: unless opts[:multi] # single parameter 386: vals[sym] = vals[sym][0][0] 387: else # multiple options, each with a single parameter 388: vals[sym] = vals[sym].map { |p| p[0] } 389: end 390: elsif MULTI_ARG_TYPES.include?(opts[:type]) && !opts[:multi] 391: vals[sym] = vals[sym][0] # single option, with multiple parameters 392: end 393: # else: multiple options, with multiple parameters 394: end 395: 396: ## modify input in place with only those 397: ## arguments we didn't process 398: cmdline.clear 399: @leftovers.each { |l| cmdline << l } 400: 401: ## allow openstruct-style accessors 402: class << vals 403: def method_missing(m, *args) 404: self[m] || self[m.to_s] 405: end 406: end 407: vals 408: end
Defines a set of words which cause parsing to terminate when encountered, such that any options to the left of the word are parsed as usual, and options to the right of the word are left intact.
A typical use case would be for subcommand support, where these would be set to the list of subcommands. A subsequent Trollop invocation would then be used to parse subcommand options, after shifting the subcommand off of ARGV.
# File lib/trollop.rb, line 269 269: def stop_on *words 270: @stop_words = [*words].flatten 271: end
Similar to #, but stops on any unknown word when encountered (unless it is a parameter for an argument). This is useful for cases where you don’t know the set of subcommands ahead of time, i.e., without first parsing the global options.
# File lib/trollop.rb, line 277 277: def stop_on_unknown 278: @stop_on_unknown = true 279: end
instance_eval but with ability to handle block arguments thanks to why: redhanded.hobix.com/inspect/aBlockCostume.html
# File lib/trollop.rb, line 666 666: def cloaker &b 667: (class << self; self; end).class_eval do 668: define_method :cloaker_, &b 669: meth = instance_method :cloaker_ 670: remove_method :cloaker_ 671: meth 672: end 673: end
# File lib/trollop.rb, line 620 620: def collect_argument_parameters args, start_at 621: params = [] 622: pos = start_at 623: while args[pos] && args[pos] !~ PARAM_RE && !@stop_words.member?(args[pos]) do 624: params << args[pos] 625: pos += 1 626: end 627: params 628: end
yield successive arg, parameter pairs
# File lib/trollop.rb, line 526 526: def each_arg args 527: remains = [] 528: i = 0 529: 530: until i >= args.length 531: if @stop_words.member? args[i] 532: remains += args[i .. 1] 533: return remains 534: end 535: case args[i] 536: when /^--$/ # arg terminator 537: remains += args[(i + 1) .. 1] 538: return remains 539: when /^--(\S+?)=(.*)$/ # long argument with equals 540: yield "--#{$1}", [$2] 541: i += 1 542: when /^--(\S+)$/ # long argument 543: params = collect_argument_parameters(args, i + 1) 544: unless params.empty? 545: num_params_taken = yield args[i], params 546: unless num_params_taken 547: if @stop_on_unknown 548: remains += args[i + 1 .. 1] 549: return remains 550: else 551: remains += params 552: end 553: end 554: i += 1 + num_params_taken 555: else # long argument no parameter 556: yield args[i], nil 557: i += 1 558: end 559: when /^-(\S+)$/ # one or more short arguments 560: shortargs = $1.split(//) 561: shortargs.each_with_index do |a, j| 562: if j == (shortargs.length - 1) 563: params = collect_argument_parameters(args, i + 1) 564: unless params.empty? 565: num_params_taken = yield "-#{a}", params 566: unless num_params_taken 567: if @stop_on_unknown 568: remains += args[i + 1 .. 1] 569: return remains 570: else 571: remains += params 572: end 573: end 574: i += 1 + num_params_taken 575: else # argument no parameter 576: yield "-#{a}", nil 577: i += 1 578: end 579: else 580: yield "-#{a}", nil 581: end 582: end 583: else 584: if @stop_on_unknown 585: remains += args[i .. 1] 586: return remains 587: else 588: remains << args[i] 589: i += 1 590: end 591: end 592: end 593: 594: remains 595: end
# File lib/trollop.rb, line 602 602: def parse_float_parameter param, arg 603: raise CommandlineError, "option '#{arg}' needs a floating-point number" unless param =~ FLOAT_RE 604: param.to_f 605: end
# File lib/trollop.rb, line 597 597: def parse_integer_parameter param, arg 598: raise CommandlineError, "option '#{arg}' needs an integer" unless param =~ /^\d+$/ 599: param.to_i 600: end
# File lib/trollop.rb, line 607 607: def parse_io_parameter param, arg 608: case param 609: when /^(stdin|-)$/; $stdin 610: else 611: require 'open-uri' 612: begin 613: open param 614: rescue SystemCallError => e 615: raise CommandlineError, "file or url for option '#{arg}' cannot be opened: #{e.message}" 616: end 617: end 618: end
# File lib/trollop.rb, line 630 630: def resolve_default_short_options 631: @order.each do |type, name| 632: next unless type == :opt 633: opts = @specs[name] 634: next if opts[:short] 635: 636: c = opts[:long].split(//).find { |d| d !~ INVALID_SHORT_ARG_REGEX && !@short.member?(d) } 637: if c # found a character to use 638: opts[:short] = c 639: @short[c] = name 640: end 641: end 642: end
# File lib/trollop.rb, line 644 644: def wrap_line str, opts={} 645: prefix = opts[:prefix] || 0 646: width = opts[:width] || (self.width - 1) 647: start = 0 648: ret = [] 649: until start > str.length 650: nextt = 651: if start + width >= str.length 652: str.length 653: else 654: x = str.rindex(/\s/, start + width) 655: x = str.index(/\s/, start) if x && x < start 656: x || str.length 657: end 658: ret << (ret.empty? ? "" : " " * prefix) + str[start ... nextt] 659: start = nextt + 1 660: end 661: ret 662: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.