trollop 1.4 → 1.5
Sign up to get free protection for your applications and to get access to all the features.
- data/FAQ.txt +6 -4
- data/History.txt +7 -0
- data/lib/trollop.rb +59 -26
- data/test/test_trollop.rb +73 -7
- metadata +2 -2
data/FAQ.txt
CHANGED
@@ -20,12 +20,14 @@ A: Because it's ambiguous whether these are arguments or negative
|
|
20
20
|
|
21
21
|
I could be very clever and detect when there are no arguments
|
22
22
|
that require floating-point parameters, and allow such short option
|
23
|
-
names in those cases, but
|
23
|
+
names in those cases, but opted for simplicity and consistency.
|
24
24
|
|
25
25
|
Q: Why does Trollop disallow options appearing multiple times, despite
|
26
26
|
the POSIX standard allowing it?
|
27
27
|
A: Because basically I think it's confusing, and more often than
|
28
28
|
not, a symptom of you making a mistake (e.g. getting lost in a long
|
29
|
-
command line and accidentally setting the same thing twice.)
|
30
|
-
|
31
|
-
|
29
|
+
command line and accidentally setting the same thing twice.)
|
30
|
+
I also don't see that much advantage to "-vvvvv" over "-v 5", so
|
31
|
+
Trollop will produce an error if you try to use the same argument
|
32
|
+
multiple times.
|
33
|
+
|
data/History.txt
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
== 1.5 / 2007-03-31
|
2
|
+
* --help and --version do the right thing even if the rest of the
|
3
|
+
command line is incorrect.
|
4
|
+
* Added #conflicts and #depends to model dependencies and exclusivity
|
5
|
+
between arguments.
|
6
|
+
* Minor bugfixes.
|
7
|
+
|
1
8
|
== 1.4 / 2007-03-26
|
2
9
|
* Disable short options with :short => :none.
|
3
10
|
* Minor bugfixes and error message improvements.
|
data/lib/trollop.rb
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
module Trollop
|
7
7
|
|
8
|
-
VERSION = "1.
|
8
|
+
VERSION = "1.5"
|
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.
|
@@ -47,6 +47,7 @@ class Parser
|
|
47
47
|
@long = {}
|
48
48
|
@short = {}
|
49
49
|
@order = []
|
50
|
+
@constraints = []
|
50
51
|
|
51
52
|
#instance_eval(&b) if b # can't take arguments
|
52
53
|
cloaker(&b).bind(self).call(*a) if b
|
@@ -170,6 +171,20 @@ class Parser
|
|
170
171
|
def banner s; @order << [:text, s] end
|
171
172
|
alias :text :banner
|
172
173
|
|
174
|
+
## Marks two (or more!) options as requiring each other. Only
|
175
|
+
## handles undirected dependcies. Directed dependencies are better
|
176
|
+
## modeled with #die.
|
177
|
+
def depends *syms
|
178
|
+
syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] }
|
179
|
+
@constraints << [:depends, syms]
|
180
|
+
end
|
181
|
+
|
182
|
+
## Marks two (or more!) options as conflicting.
|
183
|
+
def conflicts *syms
|
184
|
+
syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] }
|
185
|
+
@constraints << [:conflicts, syms]
|
186
|
+
end
|
187
|
+
|
173
188
|
## yield successive arg, parameter pairs
|
174
189
|
def each_arg args # :nodoc:
|
175
190
|
remains = []
|
@@ -210,7 +225,7 @@ class Parser
|
|
210
225
|
remains
|
211
226
|
end
|
212
227
|
|
213
|
-
def parse
|
228
|
+
def parse cmdline #:nodoc:
|
214
229
|
vals = {}
|
215
230
|
required = {}
|
216
231
|
found = {}
|
@@ -218,13 +233,15 @@ class Parser
|
|
218
233
|
opt :version, "Print version and exit" if @version unless @specs[:version] || @long["version"]
|
219
234
|
opt :help, "Show this message" unless @specs[:help] || @long["help"]
|
220
235
|
|
221
|
-
@specs.each do |
|
222
|
-
required[
|
223
|
-
vals[
|
236
|
+
@specs.each do |sym, opts|
|
237
|
+
required[sym] = true if opts[:required]
|
238
|
+
vals[sym] = opts[:default]
|
224
239
|
end
|
225
240
|
|
226
|
-
|
227
|
-
|
241
|
+
## resolve symbols
|
242
|
+
args = []
|
243
|
+
@leftovers = each_arg cmdline do |arg, param|
|
244
|
+
sym =
|
228
245
|
case arg
|
229
246
|
when /^-([^-])$/
|
230
247
|
@short[$1]
|
@@ -233,37 +250,53 @@ class Parser
|
|
233
250
|
else
|
234
251
|
raise CommandlineError, "invalid argument syntax: '#{arg}'"
|
235
252
|
end
|
236
|
-
raise CommandlineError, "unknown argument '#{arg}'" unless
|
237
|
-
raise CommandlineError, "option '#{arg}' specified multiple times" if found[
|
253
|
+
raise CommandlineError, "unknown argument '#{arg}'" unless sym
|
254
|
+
raise CommandlineError, "option '#{arg}' specified multiple times" if found[sym]
|
255
|
+
args << [sym, arg, param]
|
256
|
+
found[sym] = true
|
257
|
+
|
258
|
+
@specs[sym][:type] != :flag # take params on all except flags
|
259
|
+
end
|
260
|
+
|
261
|
+
## check for version and help args
|
262
|
+
raise VersionNeeded if args.any? { |sym, *a| sym == :version }
|
263
|
+
raise HelpNeeded if args.any? { |sym, *a| sym == :help }
|
264
|
+
|
265
|
+
## check constraint satisfaction
|
266
|
+
@constraints.each do |type, syms|
|
267
|
+
constraint_sym = syms.find { |sym| found[sym] }
|
268
|
+
next unless constraint_sym
|
269
|
+
|
270
|
+
case type
|
271
|
+
when :depends
|
272
|
+
syms.each { |sym| raise CommandlineError, "--#{@long[constraint_sym]} requires --#{@long[sym]}" unless found[sym] }
|
273
|
+
when :conflicts
|
274
|
+
syms.each { |sym| raise CommandlineError, "--#{@long[constraint_sym]} conflicts with --#{@long[sym]}" if found[sym] && sym != constraint_sym }
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
raise CommandlineError, "option '#{required.keys.first}' must be specified" if required.any? { |sym, x| !found[sym] }
|
238
279
|
|
239
|
-
|
240
|
-
|
280
|
+
## parse parameters
|
281
|
+
args.each do |sym, arg, param|
|
282
|
+
opts = @specs[sym]
|
241
283
|
|
242
|
-
|
243
|
-
opts = @specs[name]
|
284
|
+
raise CommandlineError, "option '#{arg}' needs a parameter" unless param || opts[:type] == :flag
|
244
285
|
|
245
286
|
case opts[:type]
|
246
287
|
when :flag
|
247
|
-
vals[
|
248
|
-
false
|
288
|
+
vals[sym] = !opts[:default]
|
249
289
|
when :int
|
250
|
-
raise CommandlineError, "option '#{arg}' needs a parameter" unless param
|
251
290
|
raise CommandlineError, "option '#{arg}' needs an integer" unless param =~ /^\d+$/
|
252
|
-
vals[
|
253
|
-
true
|
291
|
+
vals[sym] = param.to_i
|
254
292
|
when :float
|
255
|
-
raise CommandlineError, "option '#{arg}' needs a parameter" unless param
|
256
293
|
raise CommandlineError, "option '#{arg}' needs a floating-point number" unless param =~ FLOAT_RE
|
257
|
-
vals[
|
258
|
-
true
|
294
|
+
vals[sym] = param.to_f
|
259
295
|
when :string
|
260
|
-
|
261
|
-
vals[name] = param
|
262
|
-
true
|
296
|
+
vals[sym] = param.to_s
|
263
297
|
end
|
264
298
|
end
|
265
299
|
|
266
|
-
raise CommandlineError, "option '#{required.keys.first}' must be specified" if required.any? { |name, x| !found[name] }
|
267
300
|
vals
|
268
301
|
end
|
269
302
|
|
@@ -422,7 +455,7 @@ end
|
|
422
455
|
## Trollop::die "need at least one filename" if ARGV.empty?
|
423
456
|
def die arg, msg=nil
|
424
457
|
if msg
|
425
|
-
$stderr.puts "Error:
|
458
|
+
$stderr.puts "Error: argument --#{@p.specs[arg][:long]} #{msg}."
|
426
459
|
else
|
427
460
|
$stderr.puts "Error: #{arg}."
|
428
461
|
end
|
data/test/test_trollop.rb
CHANGED
@@ -17,13 +17,13 @@ class Trollop < ::Test::Unit::TestCase
|
|
17
17
|
|
18
18
|
def test_unknown_arguments
|
19
19
|
assert_raise(CommandlineError) { @p.parse(%w(--arg)) }
|
20
|
-
@p.opt "arg"
|
20
|
+
@p.opt "arg"
|
21
21
|
assert_nothing_raised { @p.parse(%w(--arg)) }
|
22
22
|
assert_raise(CommandlineError) { @p.parse(%w(--arg2)) }
|
23
23
|
end
|
24
24
|
|
25
25
|
def test_syntax_check
|
26
|
-
@p.opt "arg"
|
26
|
+
@p.opt "arg"
|
27
27
|
|
28
28
|
assert_nothing_raised { @p.parse(%w(--arg)) }
|
29
29
|
assert_nothing_raised { @p.parse(%w(arg)) }
|
@@ -54,8 +54,8 @@ class Trollop < ::Test::Unit::TestCase
|
|
54
54
|
|
55
55
|
## flags that don't take arguments ignore them
|
56
56
|
def test_arglessflags_refuse_args
|
57
|
-
@p.opt "goodarg"
|
58
|
-
@p.opt "goodarg2"
|
57
|
+
@p.opt "goodarg"
|
58
|
+
@p.opt "goodarg2"
|
59
59
|
assert_nothing_raised { @p.parse(%w(--goodarg)) }
|
60
60
|
assert_nothing_raised { @p.parse(%w(--goodarg --goodarg2)) }
|
61
61
|
opts = @p.parse %w(--goodarg a)
|
@@ -135,8 +135,8 @@ class Trollop < ::Test::Unit::TestCase
|
|
135
135
|
|
136
136
|
## two args can't have the same name
|
137
137
|
def test_conflicting_names_are_detected
|
138
|
-
assert_nothing_raised { @p.opt "goodarg"
|
139
|
-
assert_raise(ArgumentError) { @p.opt "goodarg"
|
138
|
+
assert_nothing_raised { @p.opt "goodarg" }
|
139
|
+
assert_raise(ArgumentError) { @p.opt "goodarg" }
|
140
140
|
end
|
141
141
|
|
142
142
|
## two args can't have the same :long
|
@@ -195,7 +195,7 @@ class Trollop < ::Test::Unit::TestCase
|
|
195
195
|
end
|
196
196
|
|
197
197
|
def test_version_only_appears_if_set
|
198
|
-
@p.opt "arg"
|
198
|
+
@p.opt "arg"
|
199
199
|
assert_raise(CommandlineError) { @p.parse %w(-v) }
|
200
200
|
@p.version "trollop 1.2.3.4"
|
201
201
|
assert_raise(VersionNeeded) { @p.parse %w(-v) }
|
@@ -376,6 +376,72 @@ EOM
|
|
376
376
|
assert_nothing_raised { @p.parse %w(-v) }
|
377
377
|
end
|
378
378
|
|
379
|
+
def test_version_and_help_override_errors
|
380
|
+
@p.opt :asdf, "desc", :type => String
|
381
|
+
@p.version "version"
|
382
|
+
assert_nothing_raised { @p.parse %w(--asdf goat) }
|
383
|
+
assert_raises(CommandlineError) { @p.parse %w(--asdf) }
|
384
|
+
assert_raises(HelpNeeded) { @p.parse %w(--asdf --help) }
|
385
|
+
assert_raises(VersionNeeded) { @p.parse %w(--asdf --version) }
|
386
|
+
end
|
387
|
+
|
388
|
+
def test_conflicts
|
389
|
+
@p.opt :one
|
390
|
+
assert_raises(ArgumentError) { @p.conflicts :one, :two }
|
391
|
+
@p.opt :two
|
392
|
+
assert_nothing_raised { @p.conflicts :one, :two }
|
393
|
+
assert_nothing_raised { @p.parse %w(--one) }
|
394
|
+
assert_nothing_raised { @p.parse %w(--two) }
|
395
|
+
assert_raises(CommandlineError) { opts = @p.parse %w(--one --two) }
|
396
|
+
|
397
|
+
@p.opt :hello
|
398
|
+
@p.opt :yellow
|
399
|
+
@p.opt :mellow
|
400
|
+
@p.opt :jello
|
401
|
+
@p.conflicts :hello, :yellow, :mellow, :jello
|
402
|
+
assert_raises(CommandlineError) { opts = @p.parse %w(--hello --yellow --mellow --jello) }
|
403
|
+
assert_raises(CommandlineError) { opts = @p.parse %w(--hello --mellow --jello) }
|
404
|
+
assert_raises(CommandlineError) { opts = @p.parse %w(--hello --jello) }
|
405
|
+
|
406
|
+
assert_nothing_raised { opts = @p.parse %w(--hello) }
|
407
|
+
assert_nothing_raised { opts = @p.parse %w(--jello) }
|
408
|
+
assert_nothing_raised { opts = @p.parse %w(--yellow) }
|
409
|
+
assert_nothing_raised { opts = @p.parse %w(--mellow) }
|
410
|
+
|
411
|
+
assert_nothing_raised { opts = @p.parse %w(--mellow --one) }
|
412
|
+
assert_nothing_raised { opts = @p.parse %w(--mellow --two) }
|
413
|
+
|
414
|
+
assert_raises(CommandlineError) { opts = @p.parse %w(--mellow --two --jello) }
|
415
|
+
assert_raises(CommandlineError) { opts = @p.parse %w(--one --mellow --two --jello) }
|
416
|
+
end
|
417
|
+
|
418
|
+
def test_depends
|
419
|
+
@p.opt :one
|
420
|
+
assert_raises(ArgumentError) { @p.depends :one, :two }
|
421
|
+
@p.opt :two
|
422
|
+
assert_nothing_raised { @p.depends :one, :two }
|
423
|
+
assert_nothing_raised { opts = @p.parse %w(--one --two) }
|
424
|
+
assert_raises(CommandlineError) { @p.parse %w(--one) }
|
425
|
+
assert_raises(CommandlineError) { @p.parse %w(--two) }
|
426
|
+
|
427
|
+
@p.opt :hello
|
428
|
+
@p.opt :yellow
|
429
|
+
@p.opt :mellow
|
430
|
+
@p.opt :jello
|
431
|
+
@p.depends :hello, :yellow, :mellow, :jello
|
432
|
+
assert_nothing_raised { opts = @p.parse %w(--hello --yellow --mellow --jello) }
|
433
|
+
assert_raises(CommandlineError) { opts = @p.parse %w(--hello --mellow --jello) }
|
434
|
+
assert_raises(CommandlineError) { opts = @p.parse %w(--hello --jello) }
|
435
|
+
|
436
|
+
assert_raises(CommandlineError) { opts = @p.parse %w(--hello) }
|
437
|
+
assert_raises(CommandlineError) { opts = @p.parse %w(--mellow) }
|
438
|
+
|
439
|
+
assert_nothing_raised { opts = @p.parse %w(--hello --yellow --mellow --jello --one --two) }
|
440
|
+
assert_nothing_raised { opts = @p.parse %w(--hello --yellow --mellow --jello --one --two a b c) }
|
441
|
+
|
442
|
+
assert_raises(CommandlineError) { opts = @p.parse %w(--mellow --two --jello --one) }
|
443
|
+
end
|
444
|
+
|
379
445
|
end
|
380
446
|
|
381
447
|
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: trollop
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: "1.
|
7
|
-
date: 2007-03-
|
6
|
+
version: "1.5"
|
7
|
+
date: 2007-03-31 00:00:00 -07:00
|
8
8
|
summary: Trollop is YAFCLAP --- yet another fine commandline argument processing library for Ruby. Trollop is designed to provide the maximal amount of GNU-style argument processing in the minimum number of lines of code (for you, the programmer).
|
9
9
|
require_paths:
|
10
10
|
- lib
|