trollop 1.8.2 → 1.9
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.
- data/History.txt +9 -0
- data/Rakefile +1 -2
- data/lib/trollop.rb +176 -52
- data/test/test_trollop.rb +279 -8
- metadata +15 -6
data/History.txt
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
== 1.9 / 2008-08-20
|
2
|
+
* Added 'stop_on_unknown' command to stop parsing on any unknown argument.
|
3
|
+
This is useful for handling sub-commands when you don't know the entire
|
4
|
+
set of commands up front. (E.g. if the initial arguments can change it.)
|
5
|
+
* Added a :multi option for parameters, signifying that they can be specified
|
6
|
+
multiple times.
|
7
|
+
* Added :ints, :strings, :doubles, and :floats option types, which can take
|
8
|
+
multiple arguments.
|
9
|
+
|
1
10
|
== 1.8.2 / 2008-06-25
|
2
11
|
* Bugfix for #conflicts and #depends error messages
|
3
12
|
|
data/Rakefile
CHANGED
@@ -13,8 +13,7 @@ end # thanks to "Mike H"
|
|
13
13
|
Hoe.new('trollop', Trollop::VERSION) do |p|
|
14
14
|
p.rubyforge_name = 'trollop'
|
15
15
|
p.author = "William Morgan"
|
16
|
-
p.summary = "Trollop is
|
17
|
-
|
16
|
+
p.summary = "Trollop is a commandline option parser for Ruby that just gets out of your way. One line of code per option is all you need to write. For that, you get a nice automatically-generated help page, robust option parsing, command subcompletion, and sensible defaults for everything you don't specify."
|
18
17
|
p.description = p.paragraphs_of('README.txt', 4..5, 9..18).join("\n\n").gsub(/== SYNOPSIS/, "Synopsis")
|
19
18
|
p.url = "http://trollop.rubyforge.org"
|
20
19
|
p.changes = p.paragraphs_of('History.txt', 0..0).join("\n\n")
|
data/lib/trollop.rb
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
module Trollop
|
7
7
|
|
8
|
-
VERSION = "1.
|
8
|
+
VERSION = "1.9"
|
9
9
|
|
10
10
|
## Thrown by Parser in the event of a commandline error. Not needed if
|
11
11
|
## you're using the Trollop::options entry.
|
@@ -30,11 +30,25 @@ PARAM_RE = /^-(-|\.$|[^\d\.])/
|
|
30
30
|
## methods #opt, #banner and #version, #depends, and #conflicts will
|
31
31
|
## typically be called.
|
32
32
|
class Parser
|
33
|
+
|
34
|
+
## The set of values that indicate a flag type of option when one of
|
35
|
+
## the values is given to the :type parameter to #opt.
|
36
|
+
FLAG_TYPES = [:flag, :bool, :boolean]
|
37
|
+
|
38
|
+
## The set of values that indicate an option that takes a single
|
39
|
+
## parameter when one of the values is given to the :type parameter to
|
40
|
+
## #opt.
|
41
|
+
SINGLE_ARG_TYPES = [:int, :integer, :string, :double, :float]
|
42
|
+
|
43
|
+
## The set of values that indicate an option that takes multiple
|
44
|
+
## parameters when one of the values is given to the :type parameter to
|
45
|
+
## #opt.
|
46
|
+
MULTI_ARG_TYPES = [:ints, :integers, :strings, :doubles, :floats]
|
47
|
+
|
33
48
|
## The set of values specifiable as the :type parameter to #opt.
|
34
|
-
TYPES =
|
49
|
+
TYPES = FLAG_TYPES + SINGLE_ARG_TYPES + MULTI_ARG_TYPES
|
35
50
|
|
36
|
-
|
37
|
-
INVALID_SHORT_ARG_REGEX = /[\d-]/
|
51
|
+
INVALID_SHORT_ARG_REGEX = /[\d-]/ #:nodoc:
|
38
52
|
|
39
53
|
## The values from the commandline that were not interpreted by #parse.
|
40
54
|
attr_reader :leftovers
|
@@ -53,6 +67,7 @@ class Parser
|
|
53
67
|
@order = []
|
54
68
|
@constraints = []
|
55
69
|
@stop_words = []
|
70
|
+
@stop_on_unknown = false
|
56
71
|
|
57
72
|
#instance_eval(&b) if b # can't take arguments
|
58
73
|
cloaker(&b).bind(self).call(*a) if b
|
@@ -69,11 +84,14 @@ class Parser
|
|
69
84
|
## * :short: Specify the short form of the argument, i.e. the form
|
70
85
|
## with one dash. If unspecified, will be automatically derived
|
71
86
|
## based on the argument name.
|
72
|
-
## * :type: Require that the argument take a parameter
|
73
|
-
## 'type'.
|
74
|
-
##
|
75
|
-
##
|
76
|
-
##
|
87
|
+
## * :type: Require that the argument take a parameter or parameters
|
88
|
+
## of type 'type'. For a single parameter, the value can be a
|
89
|
+
## member of the SINGLE_ARG_TYPES constant or a corresponding class
|
90
|
+
## (e.g. Integer for :int). For multiple parameters, the value can
|
91
|
+
## be a member of the MULTI_ARG_TYPES constant. If unset, the
|
92
|
+
## default argument type is :flag, meaning that the argument does
|
93
|
+
## not take a parameter. The specification of :type is not
|
94
|
+
## necessary if :default is given.
|
77
95
|
## * :default: Set the default value for an argument. Without a
|
78
96
|
## default value, the hash returned by #parse (and thus
|
79
97
|
## Trollop#options) will not contain the argument unless it is
|
@@ -81,8 +99,11 @@ class Parser
|
|
81
99
|
## automatically from the class of the default value given, if
|
82
100
|
## any. Specifying a :flag argument on the commandline whose
|
83
101
|
## default value is true will change its value to false.
|
84
|
-
## * :required:
|
102
|
+
## * :required: If set to true, the argument must be provided on the
|
85
103
|
## commandline.
|
104
|
+
## * :multi: If set to true, allows multiple instances of the
|
105
|
+
## option. Otherwise, only a single instance of the option is
|
106
|
+
## allowed.
|
86
107
|
def opt name, desc="", opts={}
|
87
108
|
raise ArgumentError, "you already have an argument named '#{name}'" if @specs.member? name
|
88
109
|
|
@@ -91,8 +112,11 @@ class Parser
|
|
91
112
|
case opts[:type]
|
92
113
|
when :flag, :boolean, :bool; :flag
|
93
114
|
when :int, :integer; :int
|
115
|
+
when :ints, :integers; :ints
|
94
116
|
when :string; :string
|
117
|
+
when :strings; :strings
|
95
118
|
when :double, :float; :float
|
119
|
+
when :doubles, :floats; :floats
|
96
120
|
when Class
|
97
121
|
case opts[:type].to_s # sigh... there must be a better way to do this
|
98
122
|
when 'TrueClass', 'FalseClass'; :flag
|
@@ -113,6 +137,17 @@ class Parser
|
|
113
137
|
when Numeric; :float
|
114
138
|
when TrueClass, FalseClass; :flag
|
115
139
|
when String; :string
|
140
|
+
when Array
|
141
|
+
if opts[:default].empty?
|
142
|
+
raise ArgumentError, "multiple argument type cannot be deduced from an empty array for '#{opts[:default][0].class.name}'"
|
143
|
+
end
|
144
|
+
case opts[:default][0] # the first element determines the types
|
145
|
+
when Integer; :ints
|
146
|
+
when Numeric; :floats
|
147
|
+
when String; :strings
|
148
|
+
else
|
149
|
+
raise ArgumentError, "unsupported multiple argument type '#{opts[:default][0].class.name}'"
|
150
|
+
end
|
116
151
|
when nil; nil
|
117
152
|
else
|
118
153
|
raise ArgumentError, "unsupported argument type '#{opts[:default].class.name}'"
|
@@ -160,6 +195,9 @@ class Parser
|
|
160
195
|
## fill in :default for flags
|
161
196
|
opts[:default] = false if opts[:type] == :flag && opts[:default].nil?
|
162
197
|
|
198
|
+
## fill in :multi
|
199
|
+
opts[:multi] ||= false
|
200
|
+
|
163
201
|
opts[:desc] ||= desc
|
164
202
|
@long[opts[:long]] = name
|
165
203
|
@short[opts[:short]] = name if opts[:short]
|
@@ -201,6 +239,12 @@ class Parser
|
|
201
239
|
@stop_words = [*words].flatten
|
202
240
|
end
|
203
241
|
|
242
|
+
## Similar to stop_on, but stops on any unknown word when encountered (unless
|
243
|
+
## it is a parameter for an argument).
|
244
|
+
def stop_on_unknown
|
245
|
+
@stop_on_unknown = true
|
246
|
+
end
|
247
|
+
|
204
248
|
## yield successive arg, parameter pairs
|
205
249
|
def each_arg args # :nodoc:
|
206
250
|
remains = []
|
@@ -209,19 +253,28 @@ class Parser
|
|
209
253
|
until i >= args.length
|
210
254
|
if @stop_words.member? args[i]
|
211
255
|
remains += args[i .. -1]
|
212
|
-
|
256
|
+
return remains
|
213
257
|
end
|
214
258
|
case args[i]
|
215
259
|
when /^--$/ # arg terminator
|
216
260
|
remains += args[(i + 1) .. -1]
|
217
|
-
|
261
|
+
return remains
|
218
262
|
when /^--(\S+?)=(\S+)$/ # long argument with equals
|
219
|
-
yield "--#{$1}", $2
|
263
|
+
yield "--#{$1}", [$2]
|
220
264
|
i += 1
|
221
265
|
when /^--(\S+)$/ # long argument
|
222
|
-
|
223
|
-
|
224
|
-
i
|
266
|
+
params = collect_argument_parameters(args, i + 1)
|
267
|
+
unless params.empty?
|
268
|
+
num_params_taken = yield args[i], params
|
269
|
+
unless num_params_taken
|
270
|
+
if @stop_on_unknown
|
271
|
+
remains += args[i + 1 .. -1]
|
272
|
+
return remains
|
273
|
+
else
|
274
|
+
remains += params
|
275
|
+
end
|
276
|
+
end
|
277
|
+
i += 1 + num_params_taken
|
225
278
|
else # long argument no parameter
|
226
279
|
yield args[i], nil
|
227
280
|
i += 1
|
@@ -229,26 +282,44 @@ class Parser
|
|
229
282
|
when /^-(\S+)$/ # one or more short arguments
|
230
283
|
shortargs = $1.split(//)
|
231
284
|
shortargs.each_with_index do |a, j|
|
232
|
-
if j == (shortargs.length - 1)
|
233
|
-
|
234
|
-
|
285
|
+
if j == (shortargs.length - 1)
|
286
|
+
params = collect_argument_parameters(args, i + 1)
|
287
|
+
unless params.empty?
|
288
|
+
num_params_taken = yield "-#{a}", params
|
289
|
+
unless num_params_taken
|
290
|
+
if @stop_on_unknown
|
291
|
+
remains += args[i + 1 .. -1]
|
292
|
+
return remains
|
293
|
+
else
|
294
|
+
remains += params
|
295
|
+
end
|
296
|
+
end
|
297
|
+
i += 1 + num_params_taken
|
298
|
+
else # argument no parameter
|
299
|
+
yield "-#{a}", nil
|
300
|
+
i += 1
|
301
|
+
end
|
235
302
|
else
|
236
303
|
yield "-#{a}", nil
|
237
304
|
end
|
238
305
|
end
|
239
|
-
i += 1
|
240
306
|
else
|
241
|
-
|
242
|
-
|
307
|
+
if @stop_on_unknown
|
308
|
+
remains += args[i .. -1]
|
309
|
+
return remains
|
310
|
+
else
|
311
|
+
remains << args[i]
|
312
|
+
i += 1
|
313
|
+
end
|
243
314
|
end
|
244
315
|
end
|
316
|
+
|
245
317
|
remains
|
246
318
|
end
|
247
319
|
|
248
320
|
def parse cmdline #:nodoc:
|
249
321
|
vals = {}
|
250
322
|
required = {}
|
251
|
-
found = {}
|
252
323
|
|
253
324
|
opt :version, "Print version and exit" if @version unless @specs[:version] || @long["version"]
|
254
325
|
opt :help, "Show this message" unless @specs[:help] || @long["help"]
|
@@ -259,8 +330,8 @@ class Parser
|
|
259
330
|
end
|
260
331
|
|
261
332
|
## resolve symbols
|
262
|
-
|
263
|
-
@leftovers = each_arg cmdline do |arg,
|
333
|
+
given_args = {}
|
334
|
+
@leftovers = each_arg cmdline do |arg, params|
|
264
335
|
sym =
|
265
336
|
case arg
|
266
337
|
when /^-([^-])$/
|
@@ -271,57 +342,107 @@ class Parser
|
|
271
342
|
raise CommandlineError, "invalid argument syntax: '#{arg}'"
|
272
343
|
end
|
273
344
|
raise CommandlineError, "unknown argument '#{arg}'" unless sym
|
274
|
-
raise CommandlineError, "option '#{arg}' specified multiple times" if found[sym]
|
275
|
-
args << [sym, arg, param]
|
276
|
-
found[sym] = true
|
277
345
|
|
278
|
-
|
346
|
+
if given_args.include?(sym) && !@specs[sym][:multi]
|
347
|
+
raise CommandlineError, "option '#{arg}' specified multiple times"
|
348
|
+
end
|
349
|
+
|
350
|
+
given_args[sym] ||= {}
|
351
|
+
|
352
|
+
given_args[sym][:arg] = arg
|
353
|
+
given_args[sym][:params] ||= []
|
354
|
+
|
355
|
+
# The block returns the number of parameters taken.
|
356
|
+
num_params_taken = 0
|
357
|
+
|
358
|
+
unless params.nil?
|
359
|
+
if SINGLE_ARG_TYPES.include?(@specs[sym][:type])
|
360
|
+
given_args[sym][:params] << params[0, 1] # take the first parameter
|
361
|
+
num_params_taken = 1
|
362
|
+
elsif MULTI_ARG_TYPES.include?(@specs[sym][:type])
|
363
|
+
given_args[sym][:params] << params # take all the parameters
|
364
|
+
num_params_taken = params.size
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
num_params_taken
|
279
369
|
end
|
280
370
|
|
281
371
|
## check for version and help args
|
282
|
-
raise VersionNeeded if
|
283
|
-
raise HelpNeeded if
|
372
|
+
raise VersionNeeded if given_args.include? :version
|
373
|
+
raise HelpNeeded if given_args.include? :help
|
284
374
|
|
285
375
|
## check constraint satisfaction
|
286
376
|
@constraints.each do |type, syms|
|
287
|
-
constraint_sym = syms.find { |sym|
|
377
|
+
constraint_sym = syms.find { |sym| given_args[sym] }
|
288
378
|
next unless constraint_sym
|
289
379
|
|
290
380
|
case type
|
291
381
|
when :depends
|
292
|
-
syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym][:long]} requires --#{@specs[sym][:long]}" unless
|
382
|
+
syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym][:long]} requires --#{@specs[sym][:long]}" unless given_args.include? sym }
|
293
383
|
when :conflicts
|
294
|
-
syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym][:long]} conflicts with --#{@specs[sym][:long]}" if
|
384
|
+
syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym][:long]} conflicts with --#{@specs[sym][:long]}" if given_args.include?(sym) && (sym != constraint_sym) }
|
295
385
|
end
|
296
386
|
end
|
297
387
|
|
298
388
|
required.each do |sym, val|
|
299
|
-
raise CommandlineError, "option '#{sym}' must be specified" unless
|
389
|
+
raise CommandlineError, "option '#{sym}' must be specified" unless given_args.include? sym
|
300
390
|
end
|
301
391
|
|
302
392
|
## parse parameters
|
303
|
-
|
304
|
-
|
393
|
+
given_args.each do |sym, given_data|
|
394
|
+
arg = given_data[:arg]
|
395
|
+
params = given_data[:params]
|
305
396
|
|
306
|
-
|
397
|
+
opts = @specs[sym]
|
398
|
+
raise CommandlineError, "option '#{arg}' needs a parameter" if params.empty? && opts[:type] != :flag
|
307
399
|
|
308
400
|
case opts[:type]
|
309
401
|
when :flag
|
310
402
|
vals[sym] = !opts[:default]
|
311
|
-
when :int
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
vals[sym] =
|
317
|
-
|
318
|
-
|
403
|
+
when :int, :ints
|
404
|
+
vals[sym] = params.map { |pg| pg.map { |p| parse_integer_parameter p, arg } }
|
405
|
+
when :float, :floats
|
406
|
+
vals[sym] = params.map { |pg| pg.map { |p| parse_float_parameter p, arg } }
|
407
|
+
when :string, :strings
|
408
|
+
vals[sym] = params.map { |pg| pg.map { |p| p.to_s } }
|
409
|
+
end
|
410
|
+
|
411
|
+
if SINGLE_ARG_TYPES.include?(opts[:type])
|
412
|
+
unless opts[:multi] # single parameter
|
413
|
+
vals[sym] = vals[sym][0][0]
|
414
|
+
else # multiple options, each with a single parameter
|
415
|
+
vals[sym] = vals[sym].map { |p| p[0] }
|
416
|
+
end
|
417
|
+
elsif MULTI_ARG_TYPES.include?(opts[:type]) && !opts[:multi]
|
418
|
+
vals[sym] = vals[sym][0] # single option, with multiple parameters
|
319
419
|
end
|
420
|
+
# else: multiple options, with multiple parameters
|
320
421
|
end
|
321
422
|
|
322
423
|
vals
|
323
424
|
end
|
324
425
|
|
426
|
+
def parse_integer_parameter param, arg #:nodoc:
|
427
|
+
raise CommandlineError, "option '#{arg}' needs an integer" unless param =~ /^\d+$/
|
428
|
+
param.to_i
|
429
|
+
end
|
430
|
+
|
431
|
+
def parse_float_parameter param, arg #:nodoc:
|
432
|
+
raise CommandlineError, "option '#{arg}' needs a floating-point number" unless param =~ FLOAT_RE
|
433
|
+
param.to_f
|
434
|
+
end
|
435
|
+
|
436
|
+
def collect_argument_parameters args, start_at #:nodoc:
|
437
|
+
params = []
|
438
|
+
pos = start_at
|
439
|
+
while args[pos] && args[pos] !~ PARAM_RE && !@stop_words.member?(args[pos]) do
|
440
|
+
params << args[pos]
|
441
|
+
pos += 1
|
442
|
+
end
|
443
|
+
params
|
444
|
+
end
|
445
|
+
|
325
446
|
def width #:nodoc:
|
326
447
|
@width ||=
|
327
448
|
if $stdout.tty?
|
@@ -351,8 +472,11 @@ class Parser
|
|
351
472
|
case spec[:type]
|
352
473
|
when :flag; ""
|
353
474
|
when :int; " <i>"
|
475
|
+
when :ints; " <i+>"
|
354
476
|
when :string; " <s>"
|
477
|
+
when :strings; " <s+>"
|
355
478
|
when :float; " <f>"
|
479
|
+
when :floats; " <f+>"
|
356
480
|
end
|
357
481
|
end
|
358
482
|
|
@@ -427,9 +551,9 @@ class Parser
|
|
427
551
|
end
|
428
552
|
|
429
553
|
## The top-level entry method into Trollop. Creates a Parser object,
|
430
|
-
## passes the block to it, then parses
|
554
|
+
## passes the block to it, then parses +args+ with it, handling any
|
431
555
|
## errors or requests for help or version information appropriately
|
432
|
-
## (and then exiting). Modifies
|
556
|
+
## (and then exiting). Modifies +args+ in place. Returns a hash of
|
433
557
|
## option values.
|
434
558
|
##
|
435
559
|
## The block passed in should contain one or more calls to #opt
|
@@ -437,12 +561,12 @@ end
|
|
437
561
|
## probably a call to version (Parser#version).
|
438
562
|
##
|
439
563
|
## See the synopsis in README.txt for examples.
|
440
|
-
def options *a, &b
|
564
|
+
def options args = ARGV, *a, &b
|
441
565
|
@p = Parser.new(*a, &b)
|
442
566
|
begin
|
443
|
-
vals = @p.parse
|
444
|
-
|
445
|
-
@p.leftovers.each { |l|
|
567
|
+
vals = @p.parse args
|
568
|
+
args.clear
|
569
|
+
@p.leftovers.each { |l| args << l }
|
446
570
|
vals
|
447
571
|
rescue CommandlineError => e
|
448
572
|
$stderr.puts "Error: #{e.message}."
|
data/test/test_trollop.rb
CHANGED
@@ -76,20 +76,80 @@ class Trollop < ::Test::Unit::TestCase
|
|
76
76
|
|
77
77
|
## type is correctly derived from :default
|
78
78
|
def test_type_correctly_derived_from_default
|
79
|
-
assert_nothing_raised { @p.opt "goodarg", "desc", :default => 0 }
|
80
79
|
assert_raise(ArgumentError) { @p.opt "badarg", "desc", :default => [] }
|
81
80
|
|
82
|
-
|
83
|
-
|
84
|
-
|
81
|
+
opts = nil
|
82
|
+
|
83
|
+
# single arg: int
|
84
|
+
assert_nothing_raised { @p.opt "argsi", "desc", :default => 0 }
|
85
|
+
assert_nothing_raised { opts = @p.parse("--") }
|
86
|
+
assert_equal 0, opts["argsi"]
|
87
|
+
assert_nothing_raised { opts = @p.parse(%w(--argsi 4)) }
|
88
|
+
assert_equal 4, opts["argsi"]
|
89
|
+
assert_raise(CommandlineError) { @p.parse(%w(--argsi 4.2)) }
|
90
|
+
assert_raise(CommandlineError) { @p.parse(%w(--argsi hello)) }
|
91
|
+
|
92
|
+
# single arg: float
|
93
|
+
assert_nothing_raised { @p.opt "argsf", "desc", :default => 3.14 }
|
94
|
+
assert_nothing_raised { opts = @p.parse("--") }
|
95
|
+
assert_equal 3.14, opts["argsf"]
|
96
|
+
assert_nothing_raised { opts = @p.parse(%w(--argsf 2.41)) }
|
97
|
+
assert_equal 2.41, opts["argsf"]
|
98
|
+
assert_nothing_raised { opts = @p.parse(%w(--argsf 2)) }
|
99
|
+
assert_equal 2, opts["argsf"]
|
100
|
+
assert_raise(CommandlineError) { @p.parse(%w(--argsf hello)) }
|
101
|
+
|
102
|
+
# single arg: string
|
103
|
+
assert_nothing_raised { @p.opt "argss", "desc", :default => "foobar" }
|
104
|
+
assert_nothing_raised { opts = @p.parse("--") }
|
105
|
+
assert_equal "foobar", opts["argss"]
|
106
|
+
assert_nothing_raised { opts = @p.parse(%w(--argss 2.41)) }
|
107
|
+
assert_equal "2.41", opts["argss"]
|
108
|
+
assert_nothing_raised { opts = @p.parse(%w(--argss hello)) }
|
109
|
+
assert_equal "hello", opts["argss"]
|
110
|
+
|
111
|
+
# multi args: ints
|
112
|
+
assert_nothing_raised { @p.opt "argmi", "desc", :default => [3, 5] }
|
113
|
+
assert_nothing_raised { opts = @p.parse("--") }
|
114
|
+
assert_equal [3, 5], opts["argmi"]
|
115
|
+
assert_nothing_raised { opts = @p.parse(%w(--argmi 4)) }
|
116
|
+
assert_equal [4], opts["argmi"]
|
117
|
+
assert_raise(CommandlineError) { @p.parse(%w(--argmi 4.2)) }
|
118
|
+
assert_raise(CommandlineError) { @p.parse(%w(--argmi hello)) }
|
119
|
+
|
120
|
+
# multi args: floats
|
121
|
+
assert_nothing_raised { @p.opt "argmf", "desc", :default => [3.34, 5.21] }
|
122
|
+
assert_nothing_raised { opts = @p.parse("--") }
|
123
|
+
assert_equal [3.34, 5.21], opts["argmf"]
|
124
|
+
assert_nothing_raised { opts = @p.parse(%w(--argmf 2)) }
|
125
|
+
assert_equal [2], opts["argmf"]
|
126
|
+
assert_nothing_raised { opts = @p.parse(%w(--argmf 4.0)) }
|
127
|
+
assert_equal [4.0], opts["argmf"]
|
128
|
+
assert_raise(CommandlineError) { @p.parse(%w(--argmf hello)) }
|
129
|
+
|
130
|
+
# multi args: strings
|
131
|
+
assert_nothing_raised { @p.opt "argms", "desc", :default => %w(hello world) }
|
132
|
+
assert_nothing_raised { opts = @p.parse("--") }
|
133
|
+
assert_equal %w(hello world), opts["argms"]
|
134
|
+
assert_nothing_raised { opts = @p.parse(%w(--argms 3.4)) }
|
135
|
+
assert_equal ["3.4"], opts["argms"]
|
136
|
+
assert_nothing_raised { opts = @p.parse(%w(--argms goodbye)) }
|
137
|
+
assert_equal ["goodbye"], opts["argms"]
|
85
138
|
end
|
86
139
|
|
87
140
|
## :type and :default must match if both are specified
|
88
141
|
def test_type_and_default_must_match
|
89
|
-
assert_nothing_raised { @p.opt "goodarg", "desc", :type => :int, :default => 4 }
|
90
|
-
assert_nothing_raised { @p.opt "goodarg2", "desc", :type => :string, :default => "yo" }
|
91
142
|
assert_raise(ArgumentError) { @p.opt "badarg", "desc", :type => :int, :default => "hello" }
|
92
143
|
assert_raise(ArgumentError) { @p.opt "badarg2", "desc", :type => :String, :default => 4 }
|
144
|
+
assert_raise(ArgumentError) { @p.opt "badarg2", "desc", :type => :String, :default => ["hi"] }
|
145
|
+
assert_raise(ArgumentError) { @p.opt "badarg2", "desc", :type => :ints, :default => [3.14] }
|
146
|
+
|
147
|
+
assert_nothing_raised { @p.opt "argsi", "desc", :type => :int, :default => 4 }
|
148
|
+
assert_nothing_raised { @p.opt "argsf", "desc", :type => :float, :default => 3.14 }
|
149
|
+
assert_nothing_raised { @p.opt "argss", "desc", :type => :string, :default => "yo" }
|
150
|
+
assert_nothing_raised { @p.opt "argmi", "desc", :type => :ints, :default => [4] }
|
151
|
+
assert_nothing_raised { @p.opt "argmf", "desc", :type => :floats, :default => [3.14] }
|
152
|
+
assert_nothing_raised { @p.opt "argms", "desc", :type => :strings, :default => ["yo"] }
|
93
153
|
end
|
94
154
|
|
95
155
|
def test_long_detects_bad_names
|
@@ -306,13 +366,180 @@ EOM
|
|
306
366
|
assert_raises(ArgumentError) { @p.opt :arg3, "desc", :short => "-" }
|
307
367
|
end
|
308
368
|
|
309
|
-
def
|
369
|
+
def test_options_cant_be_set_multiple_times_if_not_specified
|
310
370
|
@p.opt :arg, "desc", :short => "-x"
|
311
371
|
assert_nothing_raised { @p.parse %w(-x) }
|
312
372
|
assert_raises(CommandlineError) { @p.parse %w(-x -x) }
|
313
373
|
assert_raises(CommandlineError) { @p.parse %w(-xx) }
|
314
374
|
end
|
315
375
|
|
376
|
+
def test_options_can_be_set_multiple_times_if_specified
|
377
|
+
assert_nothing_raised do
|
378
|
+
@p.opt :arg, "desc", :short => "-x", :multi => true
|
379
|
+
end
|
380
|
+
assert_nothing_raised { @p.parse %w(-x) }
|
381
|
+
assert_nothing_raised { @p.parse %w(-x -x) }
|
382
|
+
assert_nothing_raised { @p.parse %w(-xx) }
|
383
|
+
end
|
384
|
+
|
385
|
+
def test_short_options_with_multiple_options
|
386
|
+
opts = nil
|
387
|
+
|
388
|
+
assert_nothing_raised do
|
389
|
+
@p.opt :xarg, "desc", :short => "-x", :type => String, :multi => true
|
390
|
+
end
|
391
|
+
assert_nothing_raised { opts = @p.parse %w(-x a -x b) }
|
392
|
+
assert_equal %w(a b), opts[:xarg]
|
393
|
+
assert_equal [], @p.leftovers
|
394
|
+
end
|
395
|
+
|
396
|
+
def short_options_with_multiple_options_does_not_affect_flags_type
|
397
|
+
opts = nil
|
398
|
+
|
399
|
+
assert_nothing_raised do
|
400
|
+
@p.opt :xarg, "desc", :short => "-x", :type => :flag, :multi => true
|
401
|
+
end
|
402
|
+
|
403
|
+
assert_nothing_raised { opts = @p.parse %w(-x a) }
|
404
|
+
assert_equal true, opts[:xarg]
|
405
|
+
assert_equal %w(a), @p.leftovers
|
406
|
+
|
407
|
+
assert_nothing_raised { opts = @p.parse %w(-x a -x b) }
|
408
|
+
assert_equal true, opts[:xarg]
|
409
|
+
assert_equal %w(a b), @p.leftovers
|
410
|
+
|
411
|
+
assert_nothing_raised { opts = @p.parse %w(-xx a -x b) }
|
412
|
+
assert_equal true, opts[:xarg]
|
413
|
+
assert_equal %w(a b), @p.leftovers
|
414
|
+
end
|
415
|
+
|
416
|
+
def test_short_options_with_multiple_arguments
|
417
|
+
opts = nil
|
418
|
+
|
419
|
+
@p.opt :xarg, "desc", :type => :ints
|
420
|
+
assert_nothing_raised { opts = @p.parse %w(-x 3 4 0) }
|
421
|
+
assert_equal [3, 4, 0], opts[:xarg]
|
422
|
+
assert_equal [], @p.leftovers
|
423
|
+
|
424
|
+
@p.opt :yarg, "desc", :type => :floats
|
425
|
+
assert_nothing_raised { opts = @p.parse %w(-y 3.14 4.21 0.66) }
|
426
|
+
assert_equal [3.14, 4.21, 0.66], opts[:yarg]
|
427
|
+
assert_equal [], @p.leftovers
|
428
|
+
|
429
|
+
@p.opt :zarg, "desc", :type => :strings
|
430
|
+
assert_nothing_raised { opts = @p.parse %w(-z a b c) }
|
431
|
+
assert_equal %w(a b c), opts[:zarg]
|
432
|
+
assert_equal [], @p.leftovers
|
433
|
+
end
|
434
|
+
|
435
|
+
def test_short_options_with_multiple_options_and_arguments
|
436
|
+
opts = nil
|
437
|
+
|
438
|
+
@p.opt :xarg, "desc", :type => :ints, :multi => true
|
439
|
+
assert_nothing_raised { opts = @p.parse %w(-x 3 4 5 -x 6 7) }
|
440
|
+
assert_equal [[3, 4, 5], [6, 7]], opts[:xarg]
|
441
|
+
assert_equal [], @p.leftovers
|
442
|
+
|
443
|
+
@p.opt :yarg, "desc", :type => :floats, :multi => true
|
444
|
+
assert_nothing_raised { opts = @p.parse %w(-y 3.14 4.21 5.66 -y 6.99 7.01) }
|
445
|
+
assert_equal [[3.14, 4.21, 5.66], [6.99, 7.01]], opts[:yarg]
|
446
|
+
assert_equal [], @p.leftovers
|
447
|
+
|
448
|
+
@p.opt :zarg, "desc", :type => :strings, :multi => true
|
449
|
+
assert_nothing_raised { opts = @p.parse %w(-z a b c -z d e) }
|
450
|
+
assert_equal [%w(a b c), %w(d e)], opts[:zarg]
|
451
|
+
assert_equal [], @p.leftovers
|
452
|
+
end
|
453
|
+
|
454
|
+
def test_combined_short_options_with_multiple_arguments
|
455
|
+
@p.opt :arg1, "desc", :short => "a"
|
456
|
+
@p.opt :arg2, "desc", :short => "b"
|
457
|
+
@p.opt :arg3, "desc", :short => "c", :type => :ints
|
458
|
+
@p.opt :arg4, "desc", :short => "d", :type => :floats
|
459
|
+
|
460
|
+
opts = nil
|
461
|
+
|
462
|
+
assert_nothing_raised { opts = @p.parse %w(-abc 4 6 9) }
|
463
|
+
assert_equal true, opts[:arg1]
|
464
|
+
assert_equal true, opts[:arg2]
|
465
|
+
assert_equal [4, 6, 9], opts[:arg3]
|
466
|
+
|
467
|
+
assert_nothing_raised { opts = @p.parse %w(-ac 4 6 9 -bd 3.14 2.41) }
|
468
|
+
assert_equal true, opts[:arg1]
|
469
|
+
assert_equal true, opts[:arg2]
|
470
|
+
assert_equal [4, 6, 9], opts[:arg3]
|
471
|
+
assert_equal [3.14, 2.41], opts[:arg4]
|
472
|
+
|
473
|
+
assert_raises(CommandlineError) { opts = @p.parse %w(-abcd 3.14 2.41) }
|
474
|
+
end
|
475
|
+
|
476
|
+
def test_long_options_with_multiple_options
|
477
|
+
@p.opt :xarg, "desc", :type => String, :multi => true
|
478
|
+
opts = nil
|
479
|
+
assert_nothing_raised { opts = @p.parse %w(--xarg=a --xarg=b) }
|
480
|
+
assert_equal %w(a b), opts[:xarg]
|
481
|
+
assert_equal [], @p.leftovers
|
482
|
+
assert_nothing_raised { opts = @p.parse %w(--xarg a --xarg b) }
|
483
|
+
assert_equal %w(a b), opts[:xarg]
|
484
|
+
assert_equal [], @p.leftovers
|
485
|
+
end
|
486
|
+
|
487
|
+
def test_long_options_with_multiple_arguments
|
488
|
+
opts = nil
|
489
|
+
|
490
|
+
@p.opt :xarg, "desc", :type => :ints
|
491
|
+
assert_nothing_raised { opts = @p.parse %w(--xarg 3 2 5) }
|
492
|
+
assert_equal [3, 2, 5], opts[:xarg]
|
493
|
+
assert_equal [], @p.leftovers
|
494
|
+
assert_nothing_raised { opts = @p.parse %w(--xarg=3) }
|
495
|
+
assert_equal [3], opts[:xarg]
|
496
|
+
assert_equal [], @p.leftovers
|
497
|
+
|
498
|
+
@p.opt :yarg, "desc", :type => :floats
|
499
|
+
assert_nothing_raised { opts = @p.parse %w(--yarg 3.14 2.41 5.66) }
|
500
|
+
assert_equal [3.14, 2.41, 5.66], opts[:yarg]
|
501
|
+
assert_equal [], @p.leftovers
|
502
|
+
assert_nothing_raised { opts = @p.parse %w(--yarg=3.14) }
|
503
|
+
assert_equal [3.14], opts[:yarg]
|
504
|
+
assert_equal [], @p.leftovers
|
505
|
+
|
506
|
+
@p.opt :zarg, "desc", :type => :strings
|
507
|
+
assert_nothing_raised { opts = @p.parse %w(--zarg a b c) }
|
508
|
+
assert_equal %w(a b c), opts[:zarg]
|
509
|
+
assert_equal [], @p.leftovers
|
510
|
+
assert_nothing_raised { opts = @p.parse %w(--zarg=a) }
|
511
|
+
assert_equal %w(a), opts[:zarg]
|
512
|
+
assert_equal [], @p.leftovers
|
513
|
+
end
|
514
|
+
|
515
|
+
def test_long_options_with_multiple_options_and_arguments
|
516
|
+
opts = nil
|
517
|
+
|
518
|
+
@p.opt :xarg, "desc", :type => :ints, :multi => true
|
519
|
+
assert_nothing_raised { opts = @p.parse %w(--xarg 3 2 5 --xarg 2 1) }
|
520
|
+
assert_equal [[3, 2, 5], [2, 1]], opts[:xarg]
|
521
|
+
assert_equal [], @p.leftovers
|
522
|
+
assert_nothing_raised { opts = @p.parse %w(--xarg=3 --xarg=2) }
|
523
|
+
assert_equal [[3], [2]], opts[:xarg]
|
524
|
+
assert_equal [], @p.leftovers
|
525
|
+
|
526
|
+
@p.opt :yarg, "desc", :type => :floats, :multi => true
|
527
|
+
assert_nothing_raised { opts = @p.parse %w(--yarg 3.14 2.72 5 --yarg 2.41 1.41) }
|
528
|
+
assert_equal [[3.14, 2.72, 5], [2.41, 1.41]], opts[:yarg]
|
529
|
+
assert_equal [], @p.leftovers
|
530
|
+
assert_nothing_raised { opts = @p.parse %w(--yarg=3.14 --yarg=2.41) }
|
531
|
+
assert_equal [[3.14], [2.41]], opts[:yarg]
|
532
|
+
assert_equal [], @p.leftovers
|
533
|
+
|
534
|
+
@p.opt :zarg, "desc", :type => :strings, :multi => true
|
535
|
+
assert_nothing_raised { opts = @p.parse %w(--zarg a b c --zarg d e) }
|
536
|
+
assert_equal [%w(a b c), %w(d e)], opts[:zarg]
|
537
|
+
assert_equal [], @p.leftovers
|
538
|
+
assert_nothing_raised { opts = @p.parse %w(--zarg=a --zarg=d) }
|
539
|
+
assert_equal [%w(a), %w(d)], opts[:zarg]
|
540
|
+
assert_equal [], @p.leftovers
|
541
|
+
end
|
542
|
+
|
316
543
|
def test_long_options_also_take_equals
|
317
544
|
@p.opt :arg, "desc", :long => "arg", :type => String, :default => "hello"
|
318
545
|
opts = nil
|
@@ -389,7 +616,7 @@ EOM
|
|
389
616
|
assert_raises(HelpNeeded) { @p.parse(%w(--help)) }
|
390
617
|
end
|
391
618
|
|
392
|
-
def
|
619
|
+
def test_version_and_help_long_args_can_be_overridden
|
393
620
|
@p.opt :asdf, "desc", :long => "help"
|
394
621
|
@p.opt :asdf2, "desc2", :long => "version"
|
395
622
|
assert_nothing_raised { @p.parse %w() }
|
@@ -599,6 +826,50 @@ EOM
|
|
599
826
|
assert_equal cmd, "sub-command-1"
|
600
827
|
assert_equal @q.leftovers, []
|
601
828
|
end
|
829
|
+
|
830
|
+
def assert_parses_correctly(parser, commandline, expected_opts,
|
831
|
+
expected_leftovers)
|
832
|
+
opts = parser.parse commandline
|
833
|
+
assert_equal expected_opts, opts
|
834
|
+
assert_equal expected_leftovers, parser.leftovers
|
835
|
+
end
|
836
|
+
|
837
|
+
def test_unknown_subcommand
|
838
|
+
@p.opt :global_flag, "Global flag", :short => "-g", :type => :flag
|
839
|
+
@p.opt :global_param, "Global parameter", :short => "-p", :default => 5
|
840
|
+
@p.stop_on_unknown
|
841
|
+
|
842
|
+
expected_opts = { :global_flag =>true, :help =>false, :global_param =>5 }
|
843
|
+
expected_leftovers = [ "my_subcommand", "-c" ]
|
844
|
+
|
845
|
+
assert_parses_correctly @p, %w(--global-flag my_subcommand -c), \
|
846
|
+
expected_opts, expected_leftovers
|
847
|
+
assert_parses_correctly @p, %w(-g my_subcommand -c), \
|
848
|
+
expected_opts, expected_leftovers
|
849
|
+
|
850
|
+
expected_opts = { :global_flag =>false, :help =>false, :global_param =>5 }
|
851
|
+
expected_leftovers = [ "my_subcommand", "-c" ]
|
852
|
+
|
853
|
+
assert_parses_correctly @p, %w(-p 5 my_subcommand -c), \
|
854
|
+
expected_opts, expected_leftovers
|
855
|
+
assert_parses_correctly @p, %w(--global-param 5 my_subcommand -c), \
|
856
|
+
expected_opts, expected_leftovers
|
857
|
+
end
|
858
|
+
|
859
|
+
def test_alternate_args
|
860
|
+
args = %w(-a -b -c)
|
861
|
+
|
862
|
+
opts = ::Trollop.options(args) do
|
863
|
+
opt :alpher, "Ralph Alpher", :short => "-a"
|
864
|
+
opt :bethe, "Hans Bethe", :short => "-b"
|
865
|
+
opt :gamow, "George Gamow", :short => "-c"
|
866
|
+
end
|
867
|
+
|
868
|
+
physicists_with_humor = [:alpher, :bethe, :gamow]
|
869
|
+
physicists_with_humor.each do |physicist|
|
870
|
+
assert_equal true, opts[physicist]
|
871
|
+
end
|
872
|
+
end
|
602
873
|
end
|
603
874
|
|
604
875
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: trollop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: "1.9"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- William Morgan
|
@@ -9,10 +9,19 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-08-20 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: hoe
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.7.0
|
24
|
+
version:
|
16
25
|
description: "== DESCRIPTION Trollop is a commandline option parser for Ruby that just gets out of your way. One line of code per option is all you need to write. For that, you get a nice automatically-generated help page, robust option parsing, command subcompletion, and sensible defaults for everything you don't specify. #################### ###### simple ###### #################### require 'trollop' opts = Trollop::options do opt :monkey, \"Use monkey mode\" opt :goat, \"Use goat mode\", :default => true opt :num_limbs, \"Set number of limbs\", :default => 4 end p opts # { :monkey => false, :goat => true, :num_limbs => 4 } #################### ###### medium ###### #################### require 'trollop' opts = Trollop::options do version \"test 1.2.3 (c) 2007 William Morgan\" banner <<-EOS Test is an awesome program that does something very, very important. Usage: test [options] <filenames>+ where [options] are: EOS opt :ignore, \"Ignore incorrect values\" opt :file, \"Extra data filename to read in, with a very long option description like this one\", :type => String opt :volume, \"Volume level\", :default => 3.0 opt :iters, \"Number of iterations\", :default => 5 end Trollop::die :volume, \"must be non-negative\" if opts[:volume] < 0 Trollop::die :file, \"must exist\" unless File.exist?(opts[:file]) if opts[:file] ################################ ##### sub-command support ###### ################################ require 'trollop' global_opts = Trollop::options do opt :global_option, \"This is a global option\" stop_on %w(sub-command-1 sub-command-2) end cmd = ARGV.shift cmd_opts = Trollop::options do opt :cmd_option, \"This is an option only for the subcommand\" end p global_opts p cmd p cmd_opts"
|
17
26
|
email: wmorgan-trollop@masanjin.net
|
18
27
|
executables: []
|
@@ -55,9 +64,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
55
64
|
requirements: []
|
56
65
|
|
57
66
|
rubyforge_project: trollop
|
58
|
-
rubygems_version: 1.
|
67
|
+
rubygems_version: 1.2.0
|
59
68
|
signing_key:
|
60
69
|
specification_version: 2
|
61
|
-
summary: Trollop is
|
70
|
+
summary: Trollop is a commandline option parser for Ruby that just gets out of your way. One line of code per option is all you need to write. For that, you get a nice automatically-generated help page, robust option parsing, command subcompletion, and sensible defaults for everything you don't specify.
|
62
71
|
test_files:
|
63
72
|
- test/test_trollop.rb
|