HelloWorldFizzBuzz 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,863 @@
1
+ #! /bin/usr/env ruby
2
+
3
+ # lib/trollop.rb -- trollop command-line processing library
4
+ # Copyright (c) 2008-2014 William Morgan.
5
+ # Copyright (c) 2014 Red Hat, Inc.
6
+ # trollop is licensed under the MIT license.
7
+
8
+ require 'date'
9
+
10
+ module Trollop
11
+ # note: this is duplicated in gemspec
12
+ # please change over there too
13
+ VERSION = "2.1.2"
14
+
15
+ ## Thrown by Parser in the event of a commandline error. Not needed if
16
+ ## you're using the Trollop::options entry.
17
+ class CommandlineError < StandardError
18
+ attr_reader :error_code
19
+
20
+ def initialize(msg, error_code = nil)
21
+ super(msg)
22
+ @error_code = error_code
23
+ end
24
+ end
25
+
26
+ ## Thrown by Parser if the user passes in '-h' or '--help'. Handled
27
+ ## automatically by Trollop#options.
28
+ class HelpNeeded < StandardError
29
+ end
30
+
31
+ ## Thrown by Parser if the user passes in '-v' or '--version'. Handled
32
+ ## automatically by Trollop#options.
33
+ class VersionNeeded < StandardError
34
+ end
35
+
36
+ ## Regex for floating point numbers
37
+ FLOAT_RE = /^-?((\d+(\.\d+)?)|(\.\d+))([eE][-+]?[\d]+)?$/
38
+
39
+ ## Regex for parameters
40
+ PARAM_RE = /^-(-|\.$|[^\d\.])/
41
+
42
+ ## The commandline parser. In typical usage, the methods in this class
43
+ ## will be handled internally by Trollop::options. In this case, only the
44
+ ## #opt, #banner and #version, #depends, and #conflicts methods will
45
+ ## typically be called.
46
+ ##
47
+ ## If you want to instantiate this class yourself (for more complicated
48
+ ## argument-parsing logic), call #parse to actually produce the output hash,
49
+ ## and consider calling it from within
50
+ ## Trollop::with_standard_exception_handling.
51
+ class Parser
52
+ ## The set of values that indicate a flag option when passed as the
53
+ ## +:type+ parameter of #opt.
54
+ FLAG_TYPES = [:flag, :bool, :boolean]
55
+
56
+ ## The set of values that indicate a single-parameter (normal) option when
57
+ ## passed as the +:type+ parameter of #opt.
58
+ ##
59
+ ## A value of +io+ corresponds to a readable IO resource, including
60
+ ## a filename, URI, or the strings 'stdin' or '-'.
61
+ SINGLE_ARG_TYPES = [:int, :integer, :string, :double, :float, :io, :date]
62
+
63
+ ## The set of values that indicate a multiple-parameter option (i.e., that
64
+ ## takes multiple space-separated values on the commandline) when passed as
65
+ ## the +:type+ parameter of #opt.
66
+ MULTI_ARG_TYPES = [:ints, :integers, :strings, :doubles, :floats, :ios, :dates]
67
+
68
+ ## The complete set of legal values for the +:type+ parameter of #opt.
69
+ TYPES = FLAG_TYPES + SINGLE_ARG_TYPES + MULTI_ARG_TYPES
70
+
71
+ INVALID_SHORT_ARG_REGEX = /[\d-]/ #:nodoc:
72
+
73
+ ## The values from the commandline that were not interpreted by #parse.
74
+ attr_reader :leftovers
75
+
76
+ ## The complete configuration hashes for each option. (Mainly useful
77
+ ## for testing.)
78
+ attr_reader :specs
79
+
80
+ ## A flag that determines whether or not to raise an error if the parser is passed one or more
81
+ ## options that were not registered ahead of time. If 'true', then the parser will simply
82
+ ## ignore options that it does not recognize.
83
+ attr_accessor :ignore_invalid_options
84
+
85
+ ## Initializes the parser, and instance-evaluates any block given.
86
+ def initialize(*a, &b)
87
+ @version = nil
88
+ @leftovers = []
89
+ @specs = {}
90
+ @long = {}
91
+ @short = {}
92
+ @order = []
93
+ @constraints = []
94
+ @stop_words = []
95
+ @stop_on_unknown = false
96
+ @educate_on_error = false
97
+
98
+ # instance_eval(&b) if b # can't take arguments
99
+ cloaker(&b).bind(self).call(*a) if b
100
+ end
101
+
102
+ ## Define an option. +name+ is the option name, a unique identifier
103
+ ## for the option that you will use internally, which should be a
104
+ ## symbol or a string. +desc+ is a string description which will be
105
+ ## displayed in help messages.
106
+ ##
107
+ ## Takes the following optional arguments:
108
+ ##
109
+ ## [+: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.
110
+ ## [+:short+] Specify the short form of the argument, i.e. the form with one dash. If unspecified, will be automatically derived from +name+. Use :none: to not have a short value.
111
+ ## [+: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.
112
+ ## [+:default+] Set the default value for an argument. Without a default value, the hash returned by #parse (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+.
113
+ ## [+:required+] If set to +true+, the argument must be provided on the commandline.
114
+ ## [+: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.)
115
+ ##
116
+ ## Note that there are two types of argument multiplicity: an argument
117
+ ## can take multiple values, e.g. "--arg 1 2 3". An argument can also
118
+ ## be allowed to occur multiple times, e.g. "--arg 1 --arg 2".
119
+ ##
120
+ ## Arguments that take multiple values should have a +:type+ parameter
121
+ ## drawn from +MULTI_ARG_TYPES+ (e.g. +:strings+), or a +:default:+
122
+ ## value of an array of the correct type (e.g. [String]). The
123
+ ## value of this argument will be an array of the parameters on the
124
+ ## commandline.
125
+ ##
126
+ ## Arguments that can occur multiple times should be marked with
127
+ ## +:multi+ => +true+. The value of this argument will also be an array.
128
+ ## In contrast with regular non-multi options, if not specified on
129
+ ## the commandline, the default value will be [], not nil.
130
+ ##
131
+ ## These two attributes can be combined (e.g. +:type+ => +:strings+,
132
+ ## +:multi+ => +true+), in which case the value of the argument will be
133
+ ## an array of arrays.
134
+ ##
135
+ ## There's one ambiguous case to be aware of: when +:multi+: is true and a
136
+ ## +:default+ is set to an array (of something), it's ambiguous whether this
137
+ ## is a multi-value argument as well as a multi-occurrence argument.
138
+ ## In thise case, Trollop assumes that it's not a multi-value argument.
139
+ ## If you want a multi-value, multi-occurrence argument with a default
140
+ ## value, you must specify +:type+ as well.
141
+
142
+ def opt(name, desc = "", opts = {}, &b)
143
+ raise ArgumentError, "you already have an argument named '#{name}'" if @specs.member? name
144
+
145
+ ## fill in :type
146
+ opts[:type] = # normalize
147
+ case opts[:type]
148
+ when :boolean, :bool then :flag
149
+ when :integer then :int
150
+ when :integers then :ints
151
+ when :double then :float
152
+ when :doubles then :floats
153
+ when Class
154
+ case opts[:type].name
155
+ when 'TrueClass',
156
+ 'FalseClass' then :flag
157
+ when 'String' then :string
158
+ when 'Integer' then :int
159
+ when 'Float' then :float
160
+ when 'IO' then :io
161
+ when 'Date' then :date
162
+ else
163
+ raise ArgumentError, "unsupported argument type '#{opts[:type].class.name}'"
164
+ end
165
+ when nil then nil
166
+ else
167
+ raise ArgumentError, "unsupported argument type '#{opts[:type]}'" unless TYPES.include?(opts[:type])
168
+ opts[:type]
169
+ end
170
+
171
+ ## for options with :multi => true, an array default doesn't imply
172
+ ## a multi-valued argument. for that you have to specify a :type
173
+ ## as well. (this is how we disambiguate an ambiguous situation;
174
+ ## see the docs for Parser#opt for details.)
175
+ disambiguated_default = if opts[:multi] && opts[:default].kind_of?(Array) && !opts[:type]
176
+ opts[:default].first
177
+ else
178
+ opts[:default]
179
+ end
180
+
181
+ type_from_default =
182
+ case disambiguated_default
183
+ when Integer then :int
184
+ when Numeric then :float
185
+ when TrueClass,
186
+ FalseClass then :flag
187
+ when String then :string
188
+ when IO then :io
189
+ when Date then :date
190
+ when Array
191
+ if opts[:default].empty?
192
+ if opts[:type]
193
+ raise ArgumentError, "multiple argument type must be plural" unless MULTI_ARG_TYPES.include?(opts[:type])
194
+ nil
195
+ else
196
+ raise ArgumentError, "multiple argument type cannot be deduced from an empty array for '#{opts[:default][0].class.name}'"
197
+ end
198
+ else
199
+ case opts[:default][0] # the first element determines the types
200
+ when Integer then :ints
201
+ when Numeric then :floats
202
+ when String then :strings
203
+ when IO then :ios
204
+ when Date then :dates
205
+ else
206
+ raise ArgumentError, "unsupported multiple argument type '#{opts[:default][0].class.name}'"
207
+ end
208
+ end
209
+ when nil then nil
210
+ else
211
+ raise ArgumentError, "unsupported argument type '#{opts[:default].class.name}'"
212
+ end
213
+
214
+ 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
215
+
216
+ opts[:type] = opts[:type] || type_from_default || :flag
217
+
218
+ ## fill in :long
219
+ opts[:long] = opts[:long] ? opts[:long].to_s : name.to_s.gsub("_", "-")
220
+ opts[:long] = case opts[:long]
221
+ when /^--([^-].*)$/ then $1
222
+ when /^[^-]/ then opts[:long]
223
+ else raise ArgumentError, "invalid long option name #{opts[:long].inspect}"
224
+ end
225
+ raise ArgumentError, "long option name #{opts[:long].inspect} is already taken; please specify a (different) :long" if @long[opts[:long]]
226
+
227
+ ## fill in :short
228
+ opts[:short] = opts[:short].to_s if opts[:short] && opts[:short] != :none
229
+ opts[:short] = case opts[:short]
230
+ when /^-(.)$/ then $1
231
+ when nil, :none, /^.$/ then opts[:short]
232
+ else raise ArgumentError, "invalid short option name '#{opts[:short].inspect}'"
233
+ end
234
+
235
+ if opts[:short]
236
+ raise ArgumentError, "short option name #{opts[:short].inspect} is already taken; please specify a (different) :short" if @short[opts[:short]]
237
+ raise ArgumentError, "a short option name can't be a number or a dash" if opts[:short] =~ INVALID_SHORT_ARG_REGEX
238
+ end
239
+
240
+ ## fill in :default for flags
241
+ opts[:default] = false if opts[:type] == :flag && opts[:default].nil?
242
+
243
+ ## autobox :default for :multi (multi-occurrence) arguments
244
+ opts[:default] = [opts[:default]] if opts[:default] && opts[:multi] && !opts[:default].kind_of?(Array)
245
+
246
+ ## fill in :multi
247
+ opts[:multi] ||= false
248
+ opts[:callback] ||= b if block_given?
249
+ opts[:desc] ||= desc
250
+ @long[opts[:long]] = name
251
+ @short[opts[:short]] = name if opts[:short] && opts[:short] != :none
252
+ @specs[name] = opts
253
+ @order << [:opt, name]
254
+ end
255
+
256
+ ## Sets the version string. If set, the user can request the version
257
+ ## on the commandline. Should probably be of the form "<program name>
258
+ ## <version number>".
259
+ def version(s = nil)
260
+ s ? @version = s : @version
261
+ end
262
+
263
+ ## Sets the usage string. If set the message will be printed as the
264
+ ## first line in the help (educate) output and ending in two new
265
+ ## lines.
266
+ def usage(s = nil)
267
+ s ? @usage = s : @usage
268
+ end
269
+
270
+ ## Adds a synopsis (command summary description) right below the
271
+ ## usage line, or as the first line if usage isn't specified.
272
+ def synopsis(s = nil)
273
+ s ? @synopsis = s : @synopsis
274
+ end
275
+
276
+ ## Adds text to the help display. Can be interspersed with calls to
277
+ ## #opt to build a multi-section help page.
278
+ def banner(s)
279
+ @order << [:text, s]
280
+ end
281
+ alias_method :text, :banner
282
+
283
+ ## Marks two (or more!) options as requiring each other. Only handles
284
+ ## undirected (i.e., mutual) dependencies. Directed dependencies are
285
+ ## better modeled with Trollop::die.
286
+ def depends(*syms)
287
+ syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] }
288
+ @constraints << [:depends, syms]
289
+ end
290
+
291
+ ## Marks two (or more!) options as conflicting.
292
+ def conflicts(*syms)
293
+ syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] }
294
+ @constraints << [:conflicts, syms]
295
+ end
296
+
297
+ ## Defines a set of words which cause parsing to terminate when
298
+ ## encountered, such that any options to the left of the word are
299
+ ## parsed as usual, and options to the right of the word are left
300
+ ## intact.
301
+ ##
302
+ ## A typical use case would be for subcommand support, where these
303
+ ## would be set to the list of subcommands. A subsequent Trollop
304
+ ## invocation would then be used to parse subcommand options, after
305
+ ## shifting the subcommand off of ARGV.
306
+ def stop_on(*words)
307
+ @stop_words = [*words].flatten
308
+ end
309
+
310
+ ## Similar to #stop_on, but stops on any unknown word when encountered
311
+ ## (unless it is a parameter for an argument). This is useful for
312
+ ## cases where you don't know the set of subcommands ahead of time,
313
+ ## i.e., without first parsing the global options.
314
+ def stop_on_unknown
315
+ @stop_on_unknown = true
316
+ end
317
+
318
+ ## Instead of displaying "Try --help for help." on an error
319
+ ## display the usage (via educate)
320
+ def educate_on_error
321
+ @educate_on_error = true
322
+ end
323
+
324
+ ## Parses the commandline. Typically called by Trollop::options,
325
+ ## but you can call it directly if you need more control.
326
+ ##
327
+ ## throws CommandlineError, HelpNeeded, and VersionNeeded exceptions.
328
+ def parse(cmdline = ARGV)
329
+ vals = {}
330
+ required = {}
331
+
332
+ opt :version, "Print version and exit" if @version && ! (@specs[:version] || @long["version"])
333
+ opt :help, "Show this message" unless @specs[:help] || @long["help"]
334
+
335
+ @specs.each do |sym, opts|
336
+ required[sym] = true if opts[:required]
337
+ vals[sym] = opts[:default]
338
+ vals[sym] = [] if opts[:multi] && !opts[:default] # multi arguments default to [], not nil
339
+ end
340
+
341
+ resolve_default_short_options!
342
+
343
+ ## resolve symbols
344
+ given_args = {}
345
+ @leftovers = each_arg cmdline do |arg, params|
346
+ ## handle --no- forms
347
+ arg, negative_given = if arg =~ /^--no-([^-]\S*)$/
348
+ ["--#{$1}", true]
349
+ else
350
+ [arg, false]
351
+ end
352
+
353
+ sym = case arg
354
+ when /^-([^-])$/ then @short[$1]
355
+ when /^--([^-]\S*)$/ then @long[$1] || @long["no-#{$1}"]
356
+ else raise CommandlineError, "invalid argument syntax: '#{arg}'"
357
+ end
358
+
359
+ sym = nil if arg =~ /--no-/ # explicitly invalidate --no-no- arguments
360
+
361
+ next 0 if ignore_invalid_options && !sym
362
+ raise CommandlineError, "unknown argument '#{arg}'" unless sym
363
+
364
+ if given_args.include?(sym) && !@specs[sym][:multi]
365
+ raise CommandlineError, "option '#{arg}' specified multiple times"
366
+ end
367
+
368
+ given_args[sym] ||= {}
369
+ given_args[sym][:arg] = arg
370
+ given_args[sym][:negative_given] = negative_given
371
+ given_args[sym][:params] ||= []
372
+
373
+ # The block returns the number of parameters taken.
374
+ num_params_taken = 0
375
+
376
+ unless params.nil?
377
+ if SINGLE_ARG_TYPES.include?(@specs[sym][:type])
378
+ given_args[sym][:params] << params[0, 1] # take the first parameter
379
+ num_params_taken = 1
380
+ elsif MULTI_ARG_TYPES.include?(@specs[sym][:type])
381
+ given_args[sym][:params] << params # take all the parameters
382
+ num_params_taken = params.size
383
+ end
384
+ end
385
+
386
+ num_params_taken
387
+ end
388
+
389
+ ## check for version and help args
390
+ raise VersionNeeded if given_args.include? :version
391
+ raise HelpNeeded if given_args.include? :help
392
+
393
+ ## check constraint satisfaction
394
+ @constraints.each do |type, syms|
395
+ constraint_sym = syms.find { |sym| given_args[sym] }
396
+ next unless constraint_sym
397
+
398
+ case type
399
+ when :depends
400
+ syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym][:long]} requires --#{@specs[sym][:long]}" unless given_args.include? sym }
401
+ when :conflicts
402
+ syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym][:long]} conflicts with --#{@specs[sym][:long]}" if given_args.include?(sym) && (sym != constraint_sym) }
403
+ end
404
+ end
405
+
406
+ required.each do |sym, val|
407
+ raise CommandlineError, "option --#{@specs[sym][:long]} must be specified" unless given_args.include? sym
408
+ end
409
+
410
+ ## parse parameters
411
+ given_args.each do |sym, given_data|
412
+ arg, params, negative_given = given_data.values_at :arg, :params, :negative_given
413
+
414
+ opts = @specs[sym]
415
+ if params.empty? && opts[:type] != :flag
416
+ raise CommandlineError, "option '#{arg}' needs a parameter" unless opts[:default]
417
+ params << (opts[:default].kind_of?(Array) ? opts[:default].clone : [opts[:default]])
418
+ end
419
+
420
+ vals["#{sym}_given".intern] = true # mark argument as specified on the commandline
421
+
422
+ case opts[:type]
423
+ when :flag
424
+ vals[sym] = (sym.to_s =~ /^no_/ ? negative_given : !negative_given)
425
+ when :int, :ints
426
+ vals[sym] = params.map { |pg| pg.map { |p| parse_integer_parameter p, arg } }
427
+ when :float, :floats
428
+ vals[sym] = params.map { |pg| pg.map { |p| parse_float_parameter p, arg } }
429
+ when :string, :strings
430
+ vals[sym] = params.map { |pg| pg.map(&:to_s) }
431
+ when :io, :ios
432
+ vals[sym] = params.map { |pg| pg.map { |p| parse_io_parameter p, arg } }
433
+ when :date, :dates
434
+ vals[sym] = params.map { |pg| pg.map { |p| parse_date_parameter p, arg } }
435
+ end
436
+
437
+ if SINGLE_ARG_TYPES.include?(opts[:type])
438
+ if opts[:multi] # multiple options, each with a single parameter
439
+ vals[sym] = vals[sym].map { |p| p[0] }
440
+ else # single parameter
441
+ vals[sym] = vals[sym][0][0]
442
+ end
443
+ elsif MULTI_ARG_TYPES.include?(opts[:type]) && !opts[:multi]
444
+ vals[sym] = vals[sym][0] # single option, with multiple parameters
445
+ end
446
+ # else: multiple options, with multiple parameters
447
+
448
+ opts[:callback].call(vals[sym]) if opts.key?(:callback)
449
+ end
450
+
451
+ ## modify input in place with only those
452
+ ## arguments we didn't process
453
+ cmdline.clear
454
+ @leftovers.each { |l| cmdline << l }
455
+
456
+ ## allow openstruct-style accessors
457
+ class << vals
458
+ def method_missing(m, *_args)
459
+ self[m] || self[m.to_s]
460
+ end
461
+ end
462
+ vals
463
+ end
464
+
465
+ def parse_date_parameter(param, arg) #:nodoc:
466
+ begin
467
+ require 'chronic'
468
+ time = Chronic.parse(param)
469
+ rescue LoadError
470
+ # chronic is not available
471
+ end
472
+ time ? Date.new(time.year, time.month, time.day) : Date.parse(param)
473
+ rescue ArgumentError
474
+ raise CommandlineError, "option '#{arg}' needs a date"
475
+ end
476
+
477
+ ## Print the help message to +stream+.
478
+ def educate(stream = $stdout)
479
+ width # hack: calculate it now; otherwise we have to be careful not to
480
+ # call this unless the cursor's at the beginning of a line.
481
+ left = {}
482
+ @specs.each do |name, spec|
483
+ left[name] =
484
+ (spec[:short] && spec[:short] != :none ? "-#{spec[:short]}" : "") +
485
+ (spec[:short] && spec[:short] != :none ? ", " : "") + "--#{spec[:long]}" +
486
+ case spec[:type]
487
+ when :flag then ""
488
+ when :int then "=<i>"
489
+ when :ints then "=<i+>"
490
+ when :string then "=<s>"
491
+ when :strings then "=<s+>"
492
+ when :float then "=<f>"
493
+ when :floats then "=<f+>"
494
+ when :io then "=<filename/uri>"
495
+ when :ios then "=<filename/uri+>"
496
+ when :date then "=<date>"
497
+ when :dates then "=<date+>"
498
+ end +
499
+ (spec[:type] == :flag && spec[:default] ? ", --no-#{spec[:long]}" : "")
500
+ end
501
+
502
+ leftcol_width = left.values.map(&:length).max || 0
503
+ rightcol_start = leftcol_width + 6 # spaces
504
+
505
+ unless @order.size > 0 && @order.first.first == :text
506
+ command_name = File.basename($0).gsub(/\.[^.]+$/, '')
507
+ stream.puts "Usage: #{command_name} #{@usage}\n" if @usage
508
+ stream.puts "#{@synopsis}\n" if @synopsis
509
+ stream.puts if @usage || @synopsis
510
+ stream.puts "#{@version}\n" if @version
511
+ stream.puts "Options:"
512
+ end
513
+
514
+ @order.each do |what, opt|
515
+ if what == :text
516
+ stream.puts wrap(opt)
517
+ next
518
+ end
519
+
520
+ spec = @specs[opt]
521
+ stream.printf " %-#{leftcol_width}s ", left[opt]
522
+ desc = spec[:desc] + begin
523
+ default_s = case spec[:default]
524
+ when $stdout then "<stdout>"
525
+ when $stdin then "<stdin>"
526
+ when $stderr then "<stderr>"
527
+ when Array
528
+ spec[:default].join(", ")
529
+ else
530
+ spec[:default].to_s
531
+ end
532
+
533
+ if spec[:default]
534
+ if spec[:desc] =~ /\.$/
535
+ " (Default: #{default_s})"
536
+ else
537
+ " (default: #{default_s})"
538
+ end
539
+ else
540
+ ""
541
+ end
542
+ end
543
+ stream.puts wrap(desc, :width => width - rightcol_start - 1, :prefix => rightcol_start)
544
+ end
545
+ end
546
+
547
+ def width #:nodoc:
548
+ @width ||= if $stdout.tty?
549
+ begin
550
+ require 'io/console'
551
+ IO.console.winsize.last
552
+ rescue LoadError, NoMethodError, Errno::ENOTTY, Errno::EBADF, Errno::EINVAL
553
+ legacy_width
554
+ end
555
+ else
556
+ 80
557
+ end
558
+ end
559
+
560
+ def legacy_width
561
+ # Support for older Rubies where io/console is not available
562
+ `tput cols`.to_i
563
+ rescue Errno::ENOENT
564
+ 80
565
+ end
566
+ private :legacy_width
567
+
568
+ def wrap(str, opts = {}) # :nodoc:
569
+ if str == ""
570
+ [""]
571
+ else
572
+ inner = false
573
+ str.split("\n").map do |s|
574
+ line = wrap_line s, opts.merge(:inner => inner)
575
+ inner = true
576
+ line
577
+ end.flatten
578
+ end
579
+ end
580
+
581
+ ## The per-parser version of Trollop::die (see that for documentation).
582
+ def die(arg, msg = nil, error_code = nil)
583
+ if msg
584
+ $stderr.puts "Error: argument --#{@specs[arg][:long]} #{msg}."
585
+ else
586
+ $stderr.puts "Error: #{arg}."
587
+ end
588
+ if @educate_on_error
589
+ $stderr.puts
590
+ educate $stderr
591
+ else
592
+ $stderr.puts "Try --help for help."
593
+ end
594
+ exit(error_code || -1)
595
+ end
596
+
597
+ private
598
+
599
+ ## yield successive arg, parameter pairs
600
+ def each_arg(args)
601
+ remains = []
602
+ i = 0
603
+
604
+ until i >= args.length
605
+ return remains += args[i..-1] if @stop_words.member? args[i]
606
+ case args[i]
607
+ when /^--$/ # arg terminator
608
+ return remains += args[(i + 1)..-1]
609
+ when /^--(\S+?)=(.*)$/ # long argument with equals
610
+ yield "--#{$1}", [$2]
611
+ i += 1
612
+ when /^--(\S+)$/ # long argument
613
+ params = collect_argument_parameters(args, i + 1)
614
+ if params.empty?
615
+ yield args[i], nil
616
+ i += 1
617
+ else
618
+ num_params_taken = yield args[i], params
619
+ unless num_params_taken
620
+ if @stop_on_unknown
621
+ return remains += args[i + 1..-1]
622
+ else
623
+ remains += params
624
+ end
625
+ end
626
+ i += 1 + num_params_taken
627
+ end
628
+ when /^-(\S+)$/ # one or more short arguments
629
+ shortargs = $1.split(//)
630
+ shortargs.each_with_index do |a, j|
631
+ if j == (shortargs.length - 1)
632
+ params = collect_argument_parameters(args, i + 1)
633
+ if params.empty?
634
+ yield "-#{a}", nil
635
+ i += 1
636
+ else
637
+ num_params_taken = yield "-#{a}", params
638
+ unless num_params_taken
639
+ if @stop_on_unknown
640
+ return remains += args[i + 1..-1]
641
+ else
642
+ remains += params
643
+ end
644
+ end
645
+ i += 1 + num_params_taken
646
+ end
647
+ else
648
+ yield "-#{a}", nil
649
+ end
650
+ end
651
+ else
652
+ if @stop_on_unknown
653
+ return remains += args[i..-1]
654
+ else
655
+ remains << args[i]
656
+ i += 1
657
+ end
658
+ end
659
+ end
660
+
661
+ remains
662
+ end
663
+
664
+ def parse_integer_parameter(param, arg)
665
+ raise CommandlineError, "option '#{arg}' needs an integer" unless param =~ /^-?[\d_]+$/
666
+ param.to_i
667
+ end
668
+
669
+ def parse_float_parameter(param, arg)
670
+ raise CommandlineError, "option '#{arg}' needs a floating-point number" unless param =~ FLOAT_RE
671
+ param.to_f
672
+ end
673
+
674
+ def parse_io_parameter(param, arg)
675
+ if param =~ /^(stdin|-)$/i
676
+ $stdin
677
+ else
678
+ require 'open-uri'
679
+ begin
680
+ open param
681
+ rescue SystemCallError => e
682
+ raise CommandlineError, "file or url for option '#{arg}' cannot be opened: #{e.message}"
683
+ end
684
+ end
685
+ end
686
+
687
+ def collect_argument_parameters(args, start_at)
688
+ params = []
689
+ pos = start_at
690
+ while args[pos] && args[pos] !~ PARAM_RE && !@stop_words.member?(args[pos]) do
691
+ params << args[pos]
692
+ pos += 1
693
+ end
694
+ params
695
+ end
696
+
697
+ def resolve_default_short_options!
698
+ @order.each do |type, name|
699
+ opts = @specs[name]
700
+ next if type != :opt || opts[:short]
701
+
702
+ c = opts[:long].split(//).find { |d| d !~ INVALID_SHORT_ARG_REGEX && !@short.member?(d) }
703
+ if c # found a character to use
704
+ opts[:short] = c
705
+ @short[c] = name
706
+ end
707
+ end
708
+ end
709
+
710
+ def wrap_line(str, opts = {})
711
+ prefix = opts[:prefix] || 0
712
+ width = opts[:width] || (self.width - 1)
713
+ start = 0
714
+ ret = []
715
+ until start > str.length
716
+ nextt =
717
+ if start + width >= str.length
718
+ str.length
719
+ else
720
+ x = str.rindex(/\s/, start + width)
721
+ x = str.index(/\s/, start) if x && x < start
722
+ x || str.length
723
+ end
724
+ ret << ((ret.empty? && !opts[:inner]) ? "" : " " * prefix) + str[start...nextt]
725
+ start = nextt + 1
726
+ end
727
+ ret
728
+ end
729
+
730
+ ## instance_eval but with ability to handle block arguments
731
+ ## thanks to _why: http://redhanded.hobix.com/inspect/aBlockCostume.html
732
+ def cloaker(&b)
733
+ (class << self; self; end).class_eval do
734
+ define_method :cloaker_, &b
735
+ meth = instance_method :cloaker_
736
+ remove_method :cloaker_
737
+ meth
738
+ end
739
+ end
740
+ end
741
+
742
+ ## The easy, syntactic-sugary entry method into Trollop. Creates a Parser,
743
+ ## passes the block to it, then parses +args+ with it, handling any errors or
744
+ ## requests for help or version information appropriately (and then exiting).
745
+ ## Modifies +args+ in place. Returns a hash of option values.
746
+ ##
747
+ ## The block passed in should contain zero or more calls to +opt+
748
+ ## (Parser#opt), zero or more calls to +text+ (Parser#text), and
749
+ ## probably a call to +version+ (Parser#version).
750
+ ##
751
+ ## The returned block contains a value for every option specified with
752
+ ## +opt+. The value will be the value given on the commandline, or the
753
+ ## default value if the option was not specified on the commandline. For
754
+ ## every option specified on the commandline, a key "<option
755
+ ## name>_given" will also be set in the hash.
756
+ ##
757
+ ## Example:
758
+ ##
759
+ ## require 'trollop'
760
+ ## opts = Trollop::options do
761
+ ## opt :monkey, "Use monkey mode" # a flag --monkey, defaulting to false
762
+ ## opt :name, "Monkey name", :type => :string # a string --name <s>, defaulting to nil
763
+ ## opt :num_limbs, "Number of limbs", :default => 4 # an integer --num-limbs <i>, defaulting to 4
764
+ ## end
765
+ ##
766
+ ## ## if called with no arguments
767
+ ## p opts # => {:monkey=>false, :name=>nil, :num_limbs=>4, :help=>false}
768
+ ##
769
+ ## ## if called with --monkey
770
+ ## p opts # => {:monkey=>true, :name=>nil, :num_limbs=>4, :help=>false, :monkey_given=>true}
771
+ ##
772
+ ## See more examples at http://trollop.rubyforge.org.
773
+ def options(args = ARGV, *a, &b)
774
+ @last_parser = Parser.new(*a, &b)
775
+ with_standard_exception_handling(@last_parser) { @last_parser.parse args }
776
+ end
777
+
778
+ ## If Trollop::options doesn't do quite what you want, you can create a Parser
779
+ ## object and call Parser#parse on it. That method will throw CommandlineError,
780
+ ## HelpNeeded and VersionNeeded exceptions when necessary; if you want to
781
+ ## have these handled for you in the standard manner (e.g. show the help
782
+ ## and then exit upon an HelpNeeded exception), call your code from within
783
+ ## a block passed to this method.
784
+ ##
785
+ ## Note that this method will call System#exit after handling an exception!
786
+ ##
787
+ ## Usage example:
788
+ ##
789
+ ## require 'trollop'
790
+ ## p = Trollop::Parser.new do
791
+ ## opt :monkey, "Use monkey mode" # a flag --monkey, defaulting to false
792
+ ## opt :goat, "Use goat mode", :default => true # a flag --goat, defaulting to true
793
+ ## end
794
+ ##
795
+ ## opts = Trollop::with_standard_exception_handling p do
796
+ ## o = p.parse ARGV
797
+ ## raise Trollop::HelpNeeded if ARGV.empty? # show help screen
798
+ ## o
799
+ ## end
800
+ ##
801
+ ## Requires passing in the parser object.
802
+
803
+ def with_standard_exception_handling(parser)
804
+ yield
805
+ rescue CommandlineError => e
806
+ parser.die(e.message, nil, e.error_code)
807
+ rescue HelpNeeded
808
+ parser.educate
809
+ exit
810
+ rescue VersionNeeded
811
+ puts parser.version
812
+ exit
813
+ end
814
+
815
+ ## Informs the user that their usage of 'arg' was wrong, as detailed by
816
+ ## 'msg', and dies. Example:
817
+ ##
818
+ ## options do
819
+ ## opt :volume, :default => 0.0
820
+ ## end
821
+ ##
822
+ ## die :volume, "too loud" if opts[:volume] > 10.0
823
+ ## die :volume, "too soft" if opts[:volume] < 0.1
824
+ ##
825
+ ## In the one-argument case, simply print that message, a notice
826
+ ## about -h, and die. Example:
827
+ ##
828
+ ## options do
829
+ ## opt :whatever # ...
830
+ ## end
831
+ ##
832
+ ## Trollop::die "need at least one filename" if ARGV.empty?
833
+ def die(arg, msg = nil, error_code = nil)
834
+ if @last_parser
835
+ @last_parser.die arg, msg, error_code
836
+ else
837
+ raise ArgumentError, "Trollop::die can only be called after Trollop::options"
838
+ end
839
+ end
840
+
841
+ ## Displays the help message and dies. Example:
842
+ ##
843
+ ## options do
844
+ ## opt :volume, :default => 0.0
845
+ ## banner <<-EOS
846
+ ## Usage:
847
+ ## #$0 [options] <name>
848
+ ## where [options] are:
849
+ ## EOS
850
+ ## end
851
+ ##
852
+ ## Trollop::educate if ARGV.empty?
853
+ def educate
854
+ if @last_parser
855
+ @last_parser.educate
856
+ exit
857
+ else
858
+ raise ArgumentError, "Trollop::educate can only be called after Trollop::options"
859
+ end
860
+ end
861
+
862
+ module_function :options, :die, :educate, :with_standard_exception_handling
863
+ end # module