In Files

Parent

Namespace

Trollop::Parser

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.

Constants

FLAG_TYPES

The set of values that indicate a flag option when passed as the :type parameter of #.

SINGLE_ARG_TYPES

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 ’-’.

MULTI_ARG_TYPES

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 #.

TYPES

The complete set of legal values for the :type parameter of #.

Attributes

leftovers[R]

The values from the commandline that were not interpreted by #.

specs[R]

The complete configuration hashes for each option. (Mainly useful for testing.)

Public Class Methods

new(*a, &b) click to toggle source

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

Public Instance Methods

conflicts(*syms) click to toggle source

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
depends(*syms) click to toggle source

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
die(arg, msg) click to toggle source

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
educate(stream=$stdout) click to toggle source

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
opt(name, desc="", opts={}) click to toggle source

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:

:long

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.

:short

Specify the short form of the argument, i.e. the form with one dash. If unspecified, will be automatically derived from name.

:type

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.

:default

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.

:required

If set to true, the argument must be provided on the commandline.

:multi

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
parse(cmdline=ARGV) click to toggle source

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
stop_on(*words) click to toggle source

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
stop_on_unknown() click to toggle source

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
text(s;) click to toggle source
Alias for: banner
version(s=nil;) click to toggle source

Sets the version string. If set, the user can request the version on the commandline. Should probably be of the form “ ”.

     # File lib/trollop.rb, line 239
239:   def version s=nil; @version = s if s; @version end

Private Instance Methods

cloaker(&b) click to toggle source

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
collect_argument_parameters(args, start_at) click to toggle source
     # 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
each_arg(args) click to toggle source

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
parse_float_parameter(param, arg) click to toggle source
     # 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
parse_integer_parameter(param, arg) click to toggle source
     # 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
parse_io_parameter(param, arg) click to toggle source
     # 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
resolve_default_short_options() click to toggle source
     # 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
wrap_line(str, opts={}) click to toggle source
     # 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.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.