trollop 1.4 → 1.5
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/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
|