optimist 3.1.0 → 3.2.1
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.
- checksums.yaml +4 -4
- data/.codeclimate.yml +1 -1
- data/.github/workflows/ci.yaml +4 -5
- data/CHANGELOG.md +235 -2
- data/examples/a_basic_example.rb +9 -0
- data/examples/alt_names.rb +20 -0
- data/examples/banners1.rb +11 -0
- data/examples/banners2.rb +12 -0
- data/examples/banners3.rb +14 -0
- data/examples/boolean.rb +9 -0
- data/examples/constraints.rb +28 -0
- data/examples/didyoumean.rb +26 -0
- data/examples/medium_example.rb +15 -0
- data/examples/partialmatch.rb +18 -0
- data/examples/permitted.rb +29 -0
- data/examples/types_custom.rb +43 -0
- data/lib/optimist.rb +347 -93
- data/optimist.gemspec +4 -4
- data/renovate.json +5 -0
- data/test/optimist/alt_names_test.rb +168 -0
- data/test/optimist/command_line_error_test.rb +2 -2
- data/test/optimist/help_needed_test.rb +2 -2
- data/test/optimist/parser_constraint_test.rb +141 -0
- data/test/optimist/parser_educate_test.rb +45 -12
- data/test/optimist/parser_opt_test.rb +2 -2
- data/test/optimist/parser_parse_test.rb +4 -4
- data/test/optimist/parser_permitted_test.rb +121 -0
- data/test/optimist/parser_test.rb +277 -176
- data/test/optimist/version_needed_test.rb +2 -2
- data/test/optimist_test.rb +6 -4
- data/test/support/assert_helpers.rb +10 -3
- metadata +27 -9
- data/History.txt +0 -175
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'stringio'
|
2
|
-
|
2
|
+
require_relative '../test_helper'
|
3
3
|
|
4
4
|
module Optimist
|
5
5
|
|
6
|
-
class ParserTest < ::
|
6
|
+
class ParserTest < ::Minitest::Test
|
7
7
|
def setup
|
8
8
|
@p = Parser.new
|
9
9
|
end
|
@@ -35,8 +35,6 @@ class ParserTest < ::MiniTest::Test
|
|
35
35
|
assert_equal "synopsis string", parser.synopsis
|
36
36
|
end
|
37
37
|
|
38
|
-
# def test_depends
|
39
|
-
# def test_conflicts
|
40
38
|
# def test_stop_on
|
41
39
|
# def test_stop_on_unknown
|
42
40
|
|
@@ -45,10 +43,57 @@ class ParserTest < ::MiniTest::Test
|
|
45
43
|
|
46
44
|
|
47
45
|
def test_unknown_arguments
|
48
|
-
|
46
|
+
assert_raises_errmatch(CommandlineError, /unknown argument '--arg'/) { @p.parse(%w(--arg)) }
|
49
47
|
@p.opt "arg"
|
50
48
|
@p.parse(%w(--arg))
|
51
|
-
|
49
|
+
assert_raises_errmatch(CommandlineError, /unknown argument '--arg2'/) { @p.parse(%w(--arg2)) }
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_unknown_arguments_with_suggestions
|
53
|
+
unless (Module::const_defined?("DidYouMean") &&
|
54
|
+
Module::const_defined?("DidYouMean::JaroWinkler") &&
|
55
|
+
Module::const_defined?("DidYouMean::Levenshtein"))
|
56
|
+
# if we cannot
|
57
|
+
skip("Skipping because DidYouMean was not found")
|
58
|
+
return false
|
59
|
+
end
|
60
|
+
sugp = Parser.new(:suggestions => true)
|
61
|
+
err = assert_raises(CommandlineError) { sugp.parse(%w(--bone)) }
|
62
|
+
assert_match(/unknown argument '--bone'$/, err.message)
|
63
|
+
|
64
|
+
sugp.opt "cone"
|
65
|
+
sugp.parse(%w(--cone))
|
66
|
+
|
67
|
+
# single letter mismatch
|
68
|
+
err = assert_raises(CommandlineError) { sugp.parse(%w(--bone)) }
|
69
|
+
assert_match(/unknown argument '--bone'. Did you mean: \[--cone\] \?$/, err.message)
|
70
|
+
|
71
|
+
# transposition
|
72
|
+
err = assert_raises(CommandlineError) { sugp.parse(%w(--ocne)) }
|
73
|
+
assert_match(/unknown argument '--ocne'. Did you mean: \[--cone\] \?$/, err.message)
|
74
|
+
|
75
|
+
# extra letter at end
|
76
|
+
err = assert_raises(CommandlineError) { sugp.parse(%w(--cones)) }
|
77
|
+
assert_match(/unknown argument '--cones'. Did you mean: \[--cone\] \?$/, err.message)
|
78
|
+
|
79
|
+
# too big of a mismatch to suggest (extra letters in front)
|
80
|
+
err = assert_raises(CommandlineError) { sugp.parse(%w(--snowcone)) }
|
81
|
+
assert_match(/unknown argument '--snowcone'$/, err.message)
|
82
|
+
|
83
|
+
# too big of a mismatch to suggest (nothing close)
|
84
|
+
err = assert_raises(CommandlineError) { sugp.parse(%w(--clown-nose)) }
|
85
|
+
assert_match(/unknown argument '--clown-nose'$/, err.message)
|
86
|
+
|
87
|
+
sugp.opt "zippy"
|
88
|
+
sugp.opt "zapzy"
|
89
|
+
# single letter mismatch, matches two
|
90
|
+
err = assert_raises(CommandlineError) { sugp.parse(%w(--zipzy)) }
|
91
|
+
assert_match(/unknown argument '--zipzy'. Did you mean: \[--zippy, --zapzy\] \?$/, err.message)
|
92
|
+
|
93
|
+
sugp.opt "big_bug"
|
94
|
+
# suggest common case of dash versus underscore in argnames
|
95
|
+
err = assert_raises(CommandlineError) { sugp.parse(%w(--big_bug)) }
|
96
|
+
assert_match(/unknown argument '--big_bug'. Did you mean: \[--big-bug\] \?$/, err.message)
|
52
97
|
end
|
53
98
|
|
54
99
|
def test_syntax_check
|
@@ -56,8 +101,8 @@ class ParserTest < ::MiniTest::Test
|
|
56
101
|
|
57
102
|
@p.parse(%w(--arg))
|
58
103
|
@p.parse(%w(arg))
|
59
|
-
|
60
|
-
|
104
|
+
assert_raises_errmatch(CommandlineError, /invalid argument syntax: '---arg'/) { @p.parse(%w(---arg)) }
|
105
|
+
assert_raises_errmatch(CommandlineError, /unknown argument '-r'/) { @p.parse(%w(-arg)) }
|
61
106
|
end
|
62
107
|
|
63
108
|
def test_required_flags_are_required
|
@@ -67,8 +112,9 @@ class ParserTest < ::MiniTest::Test
|
|
67
112
|
|
68
113
|
@p.parse(%w(--arg))
|
69
114
|
@p.parse(%w(--arg --arg2))
|
70
|
-
|
71
|
-
|
115
|
+
err_regex = %r/option --arg must be specified/
|
116
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--arg2)) }
|
117
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--arg2 --arg3)) }
|
72
118
|
end
|
73
119
|
|
74
120
|
## flags that take an argument error unless given one
|
@@ -77,8 +123,9 @@ class ParserTest < ::MiniTest::Test
|
|
77
123
|
@p.opt "goodarg2", "desc", :type => String
|
78
124
|
|
79
125
|
@p.parse(%w(--goodarg goat))
|
80
|
-
|
81
|
-
|
126
|
+
err_regex = %r/option '--goodarg' needs a parameter/
|
127
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--goodarg --goodarg2 goat)) }
|
128
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--goodarg)) }
|
82
129
|
end
|
83
130
|
|
84
131
|
## flags that don't take arguments ignore them
|
@@ -96,18 +143,23 @@ class ParserTest < ::MiniTest::Test
|
|
96
143
|
## types
|
97
144
|
def test_typed_args_refuse_args_of_other_types
|
98
145
|
@p.opt "goodarg", "desc", :type => :int
|
99
|
-
|
146
|
+
err_regex = %r/Unsupported argument type 'asdf', registry lookup 'asdf'/
|
147
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg", "desc", :type => :asdf }
|
100
148
|
|
101
149
|
@p.parse(%w(--goodarg 3))
|
102
|
-
|
103
|
-
|
150
|
+
err_regex = %r/option 'goodarg' needs an integer/
|
151
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--goodarg 4.2)) }
|
152
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--goodarg hello)) }
|
104
153
|
end
|
105
154
|
|
106
155
|
## type is correctly derived from :default
|
107
156
|
def test_type_correctly_derived_from_default
|
108
|
-
|
109
|
-
|
110
|
-
|
157
|
+
err_regex = %r/multiple argument type cannot be deduced from an empty array/
|
158
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg", "desc", :default => [] }
|
159
|
+
err_regex = %r/Unsupported argument type 'hashs', registry lookup 'hashs'/
|
160
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg3", "desc", :default => [{1 => 2}] }
|
161
|
+
err_regex = %r/Unsupported argument type 'hash', registry lookup 'hash'/
|
162
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg4", "desc", :default => Hash.new }
|
111
163
|
|
112
164
|
# single arg: int
|
113
165
|
@p.opt "argsi", "desc", :default => 0
|
@@ -119,9 +171,9 @@ class ParserTest < ::MiniTest::Test
|
|
119
171
|
assert_equal 4, opts["argsi"]
|
120
172
|
opts = @p.parse(%w(--argsi=-4))
|
121
173
|
assert_equal( -4, opts["argsi"])
|
122
|
-
|
123
|
-
|
124
|
-
|
174
|
+
err_regex = /option 'argsi' needs an integer/
|
175
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--argsi 4.2)) }
|
176
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--argsi hello)) }
|
125
177
|
|
126
178
|
# single arg: float
|
127
179
|
@p.opt "argsf", "desc", :default => 3.14
|
@@ -133,7 +185,8 @@ class ParserTest < ::MiniTest::Test
|
|
133
185
|
assert_equal 2, opts["argsf"]
|
134
186
|
opts = @p.parse(%w(--argsf 1.0e-2))
|
135
187
|
assert_equal 1.0e-2, opts["argsf"]
|
136
|
-
|
188
|
+
err_regex = /option 'argsf' needs a floating-point number/
|
189
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--argsf hello)) }
|
137
190
|
|
138
191
|
# single arg: date
|
139
192
|
date = Date.today
|
@@ -142,7 +195,8 @@ class ParserTest < ::MiniTest::Test
|
|
142
195
|
assert_equal Date.today, opts["argsd"]
|
143
196
|
opts = @p.parse(['--argsd', 'Jan 4, 2007'])
|
144
197
|
assert_equal Date.civil(2007, 1, 4), opts["argsd"]
|
145
|
-
|
198
|
+
err_regex = /option 'argsd' needs a date/
|
199
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--argsd hello)) }
|
146
200
|
|
147
201
|
# single arg: string
|
148
202
|
@p.opt "argss", "desc", :default => "foobar"
|
@@ -159,8 +213,9 @@ class ParserTest < ::MiniTest::Test
|
|
159
213
|
assert_equal [3, 5], opts["argmi"]
|
160
214
|
opts = @p.parse(%w(--argmi 4))
|
161
215
|
assert_equal [4], opts["argmi"]
|
162
|
-
|
163
|
-
|
216
|
+
err_regex = /option 'argmi' needs an integer/
|
217
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--argmi 4.2)) }
|
218
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--argmi hello)) }
|
164
219
|
|
165
220
|
# multi args: floats
|
166
221
|
@p.opt "argmf", "desc", :default => [3.34, 5.21]
|
@@ -170,7 +225,8 @@ class ParserTest < ::MiniTest::Test
|
|
170
225
|
assert_equal [2], opts["argmf"]
|
171
226
|
opts = @p.parse(%w(--argmf 4.0))
|
172
227
|
assert_equal [4.0], opts["argmf"]
|
173
|
-
|
228
|
+
err_regex = /option 'argmf' needs a floating-point number/
|
229
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--argmf hello)) }
|
174
230
|
|
175
231
|
# multi args: dates
|
176
232
|
dates = [Date.today, Date.civil(2007, 1, 4)]
|
@@ -179,7 +235,8 @@ class ParserTest < ::MiniTest::Test
|
|
179
235
|
assert_equal dates, opts["argmd"]
|
180
236
|
opts = @p.parse(['--argmd', 'Jan 4, 2007'])
|
181
237
|
assert_equal [Date.civil(2007, 1, 4)], opts["argmd"]
|
182
|
-
|
238
|
+
err_regex = /option 'argmd' needs a date/
|
239
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--argmd hello)) }
|
183
240
|
|
184
241
|
# multi args: strings
|
185
242
|
@p.opt "argmst", "desc", :default => %w(hello world)
|
@@ -193,10 +250,12 @@ class ParserTest < ::MiniTest::Test
|
|
193
250
|
|
194
251
|
## :type and :default must match if both are specified
|
195
252
|
def test_type_and_default_must_match
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
253
|
+
# Different versions of ruby raise different error messages.
|
254
|
+
err_regex = %r/(type specification and default type don't match|Unsupported argument type)/
|
255
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg", "desc", :type => :int, :default => "hello" }
|
256
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg2", "desc", :type => :String, :default => 4 }
|
257
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg2", "desc", :type => :String, :default => ["hi"] }
|
258
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg2", "desc", :type => :ints, :default => [3.14] }
|
200
259
|
|
201
260
|
@p.opt "argsi", "desc", :type => :int, :default => 4
|
202
261
|
@p.opt "argsf", "desc", :type => :float, :default => 3.14
|
@@ -239,10 +298,11 @@ class ParserTest < ::MiniTest::Test
|
|
239
298
|
@p.opt "argmf", "desc", :type => :floats, :default => []
|
240
299
|
@p.opt "argmd", "desc", :type => :dates, :default => []
|
241
300
|
@p.opt "argms", "desc", :type => :strings, :default => []
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
301
|
+
err_regex = %r/multiple argument type must be plural/
|
302
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badi", "desc", :type => :int, :default => [] }
|
303
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badf", "desc", :type => :float, :default => [] }
|
304
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badd", "desc", :type => :date, :default => [] }
|
305
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "bads", "desc", :type => :string, :default => [] }
|
246
306
|
opts = @p.parse([])
|
247
307
|
assert_equal(opts["argmi"], [])
|
248
308
|
assert_equal(opts["argmf"], [])
|
@@ -255,18 +315,20 @@ class ParserTest < ::MiniTest::Test
|
|
255
315
|
@p.opt "goodarg2", "desc", :long => "--two"
|
256
316
|
@p.opt "goodarg3", "desc", :long => "arg-3"
|
257
317
|
@p.opt "goodarg4", "desc", :long => "--good-arg-four"
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
318
|
+
err_regex = /invalid long option name/
|
319
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg", "desc", :long => "" }
|
320
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg2", "desc", :long => "--" }
|
321
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg3", "desc", :long => "-one" }
|
322
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg4", "desc", :long => "---toomany" }
|
262
323
|
end
|
263
324
|
|
264
325
|
def test_short_detects_bad_names
|
265
326
|
@p.opt "goodarg", "desc", :short => "a"
|
266
327
|
@p.opt "goodarg2", "desc", :short => "-b"
|
267
|
-
|
268
|
-
|
269
|
-
|
328
|
+
err_regex = /invalid short option name/
|
329
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg", "desc", :short => "" }
|
330
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg2", "desc", :short => "-ab" }
|
331
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg3", "desc", :short => "--t" }
|
270
332
|
end
|
271
333
|
|
272
334
|
def test_short_names_created_automatically
|
@@ -306,29 +368,33 @@ class ParserTest < ::MiniTest::Test
|
|
306
368
|
@p.opt "arg", "desc", :short => :none
|
307
369
|
@p.parse []
|
308
370
|
|
309
|
-
sio = StringIO.new
|
371
|
+
sio = StringIO.new
|
310
372
|
@p.educate sio
|
311
373
|
assert sio.string =~ /--arg\s+desc/
|
312
374
|
|
313
|
-
|
375
|
+
assert_raises_errmatch(CommandlineError, /unknown argument '-a'/) { @p.parse %w(-a) }
|
314
376
|
end
|
315
377
|
|
316
378
|
## two args can't have the same name
|
317
379
|
def test_conflicting_names_are_detected
|
318
380
|
@p.opt "goodarg"
|
319
|
-
|
381
|
+
err_regex = /you already have an argument named 'goodarg'/
|
382
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "goodarg" }
|
320
383
|
end
|
321
384
|
|
322
385
|
## two args can't have the same :long
|
323
386
|
def test_conflicting_longs_detected
|
324
387
|
@p.opt "goodarg", "desc", :long => "--goodarg"
|
325
|
-
|
388
|
+
err_regex = /long option name \"goodarg\" is already taken/
|
389
|
+
|
390
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg", "desc", :long => "--goodarg" }
|
326
391
|
end
|
327
392
|
|
328
393
|
## two args can't have the same :short
|
329
394
|
def test_conflicting_shorts_detected
|
330
395
|
@p.opt "goodarg", "desc", :short => "-g"
|
331
|
-
|
396
|
+
err_regex = /short option name \"g\" is already taken/
|
397
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg", "desc", :short => "-g" }
|
332
398
|
end
|
333
399
|
|
334
400
|
## note: this behavior has changed in optimist 2.0!
|
@@ -397,7 +463,7 @@ class ParserTest < ::MiniTest::Test
|
|
397
463
|
assert_equal false, opts[:no_default_true]
|
398
464
|
|
399
465
|
## disallow double negatives for reasons of sanity preservation
|
400
|
-
|
466
|
+
assert_raises_errmatch(CommandlineError, /unknown argument '--no-default-true'/) { @p.parse %w(--no-no-default-true) }
|
401
467
|
end
|
402
468
|
|
403
469
|
def test_short_options_combine
|
@@ -420,8 +486,9 @@ class ParserTest < ::MiniTest::Test
|
|
420
486
|
assert_equal true, opts[:arg2]
|
421
487
|
assert_equal 4, opts[:arg3]
|
422
488
|
|
423
|
-
|
424
|
-
|
489
|
+
err_regex = /option '-c' needs a parameter/
|
490
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse %w(-cab 4) }
|
491
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse %w(-cba 4) }
|
425
492
|
end
|
426
493
|
|
427
494
|
def test_doubledash_ends_option_processing
|
@@ -508,13 +575,15 @@ Options:
|
|
508
575
|
assert_equal(-0.1, opts[:arg])
|
509
576
|
opts = @p.parse %w(-f -.1)
|
510
577
|
assert_equal(-0.1, opts[:arg])
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
578
|
+
err_regex = %r/option 'arg' needs a floating-point number/
|
579
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse %w(-f a) }
|
580
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse %w(-f 1a) }
|
581
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse %w(-f 1.a) }
|
582
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse %w(-f a.1) }
|
583
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse %w(-f 1.0.0) }
|
584
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse %w(-f .) }
|
585
|
+
err_regex = %r/unknown argument '-.'/
|
586
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse %w(-f -.) }
|
518
587
|
end
|
519
588
|
|
520
589
|
def test_floating_point_formatting_default
|
@@ -532,23 +601,30 @@ Options:
|
|
532
601
|
end
|
533
602
|
|
534
603
|
def test_short_options_cant_be_numeric
|
535
|
-
|
604
|
+
err_regex = %r/short option name '1' can't be a number or a dash/
|
605
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt :arg, "desc", :short => "-1" }
|
536
606
|
@p.opt :a1b, "desc"
|
537
607
|
@p.opt :a2b, "desc"
|
538
|
-
|
608
|
+
@p.parse []
|
609
|
+
# testing private interface to ensure default
|
610
|
+
# short options did not become numeric
|
611
|
+
assert_equal @p.specs[:a1b].short.chars.first, 'a'
|
612
|
+
assert_equal @p.specs[:a2b].short.chars.first, 'b'
|
539
613
|
end
|
540
614
|
|
541
615
|
def test_short_options_can_be_weird
|
542
616
|
@p.opt :arg1, "desc", :short => "#"
|
543
617
|
@p.opt :arg2, "desc", :short => "."
|
544
|
-
|
618
|
+
err_regex = %r/short option name '-' can't be a number or a dash/
|
619
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt :arg3, "desc", :short => "-" }
|
545
620
|
end
|
546
621
|
|
547
622
|
def test_options_cant_be_set_multiple_times_if_not_specified
|
548
623
|
@p.opt :arg, "desc", :short => "-x"
|
549
624
|
@p.parse %w(-x)
|
550
|
-
|
551
|
-
|
625
|
+
err_regex = /option '-x' specified multiple times/
|
626
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse %w(-x -x) }
|
627
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse %w(-xx) }
|
552
628
|
end
|
553
629
|
|
554
630
|
def test_options_can_be_set_multiple_times_if_specified
|
@@ -632,7 +708,7 @@ Options:
|
|
632
708
|
assert_equal [4, 6, 9], opts[:arg3]
|
633
709
|
assert_equal [3.14, 2.41], opts[:arg4]
|
634
710
|
|
635
|
-
|
711
|
+
assert_raises_errmatch(CommandlineError, /option '-c' needs a parameter/) { opts = @p.parse %w(-abcd 3.14 2.41) }
|
636
712
|
end
|
637
713
|
|
638
714
|
def test_long_options_with_multiple_options
|
@@ -712,7 +788,7 @@ Options:
|
|
712
788
|
|
713
789
|
def test_auto_generated_long_names_convert_underscores_to_hyphens
|
714
790
|
@p.opt :hello_there
|
715
|
-
assert_equal "hello-there", @p.specs[:hello_there].long
|
791
|
+
assert_equal "hello-there", @p.specs[:hello_there].long.long
|
716
792
|
end
|
717
793
|
|
718
794
|
def test_arguments_passed_through_block
|
@@ -724,126 +800,37 @@ Options:
|
|
724
800
|
assert_equal @goat, boat
|
725
801
|
end
|
726
802
|
|
803
|
+
## test-only access reader method so that we dont have to
|
804
|
+
## expose settings in the public API.
|
805
|
+
class Optimist::Parser
|
806
|
+
def get_settings_for_testing ; return @settings ;end
|
807
|
+
end
|
808
|
+
|
809
|
+
def test_two_arguments_passed_through_block
|
810
|
+
newp = Parser.new(:abcd => 123, :efgh => "other" ) do |i|
|
811
|
+
end
|
812
|
+
assert_equal newp.get_settings_for_testing[:abcd], 123
|
813
|
+
assert_equal newp.get_settings_for_testing[:efgh], "other"
|
814
|
+
end
|
815
|
+
|
816
|
+
|
727
817
|
def test_version_and_help_override_errors
|
728
818
|
@p.opt :asdf, "desc", :type => String
|
729
819
|
@p.version "version"
|
730
820
|
@p.parse %w(--asdf goat)
|
731
|
-
|
821
|
+
assert_raises_errmatch(CommandlineError, /option '--asdf' needs a parameter/) { @p.parse %w(--asdf) }
|
732
822
|
assert_raises(HelpNeeded) { @p.parse %w(--asdf --help) }
|
733
823
|
assert_raises(VersionNeeded) { @p.parse %w(--asdf --version) }
|
734
824
|
end
|
735
825
|
|
736
|
-
def test_conflicts
|
737
|
-
@p.opt :one
|
738
|
-
assert_raises(ArgumentError) { @p.conflicts :one, :two }
|
739
|
-
@p.opt :two
|
740
|
-
@p.conflicts :one, :two
|
741
|
-
@p.parse %w(--one)
|
742
|
-
@p.parse %w(--two)
|
743
|
-
assert_raises(CommandlineError) { @p.parse %w(--one --two) }
|
744
|
-
|
745
|
-
@p.opt :hello
|
746
|
-
@p.opt :yellow
|
747
|
-
@p.opt :mellow
|
748
|
-
@p.opt :jello
|
749
|
-
@p.conflicts :hello, :yellow, :mellow, :jello
|
750
|
-
assert_raises(CommandlineError) { @p.parse %w(--hello --yellow --mellow --jello) }
|
751
|
-
assert_raises(CommandlineError) { @p.parse %w(--hello --mellow --jello) }
|
752
|
-
assert_raises(CommandlineError) { @p.parse %w(--hello --jello) }
|
753
|
-
|
754
|
-
@p.parse %w(--hello)
|
755
|
-
@p.parse %w(--jello)
|
756
|
-
@p.parse %w(--yellow)
|
757
|
-
@p.parse %w(--mellow)
|
758
|
-
|
759
|
-
@p.parse %w(--mellow --one)
|
760
|
-
@p.parse %w(--mellow --two)
|
761
|
-
|
762
|
-
assert_raises(CommandlineError) { @p.parse %w(--mellow --two --jello) }
|
763
|
-
assert_raises(CommandlineError) { @p.parse %w(--one --mellow --two --jello) }
|
764
|
-
end
|
765
|
-
|
766
|
-
def test_either
|
767
|
-
@p.opt :one
|
768
|
-
assert_raises(ArgumentError) { @p.either :one, :two }
|
769
|
-
@p.opt :two
|
770
|
-
@p.either :one, :two
|
771
|
-
@p.parse %w(--one)
|
772
|
-
@p.parse %w(--two)
|
773
|
-
assert_raises(CommandlineError) { @p.parse %w(--one --two) }
|
774
|
-
assert_raises(CommandlineError) { @p.parse %w() }
|
775
|
-
|
776
|
-
@p.opt :hello
|
777
|
-
@p.opt :yellow
|
778
|
-
@p.opt :mellow
|
779
|
-
@p.opt :jello
|
780
|
-
@p.either :hello, :yellow, :mellow, :jello
|
781
|
-
assert_raises(CommandlineError) { @p.parse %w(--hello --yellow --mellow --jello) }
|
782
|
-
assert_raises(CommandlineError) { @p.parse %w(--hello --mellow --jello) }
|
783
|
-
assert_raises(CommandlineError) { @p.parse %w(--hello --jello) }
|
784
|
-
|
785
|
-
@p.parse %w(--hello --one)
|
786
|
-
@p.parse %w(--jello --two)
|
787
|
-
@p.parse %w(--mellow --one)
|
788
|
-
@p.parse %w(--mellow --two)
|
789
|
-
|
790
|
-
assert_raises(CommandlineError) { @p.parse %w(--mellow --two --jello) }
|
791
|
-
assert_raises(CommandlineError) { @p.parse %w(--one --mellow --two --jello) }
|
792
|
-
end
|
793
|
-
|
794
|
-
def test_conflict_error_messages
|
795
|
-
@p.opt :one
|
796
|
-
@p.opt "two"
|
797
|
-
@p.conflicts :one, "two"
|
798
|
-
|
799
|
-
assert_raises(CommandlineError, /--one.*--two/) { @p.parse %w(--one --two) }
|
800
|
-
end
|
801
|
-
|
802
|
-
def test_depends
|
803
|
-
@p.opt :one
|
804
|
-
assert_raises(ArgumentError) { @p.depends :one, :two }
|
805
|
-
@p.opt :two
|
806
|
-
@p.depends :one, :two
|
807
|
-
@p.parse %w(--one --two)
|
808
|
-
assert_raises(CommandlineError) { @p.parse %w(--one) }
|
809
|
-
assert_raises(CommandlineError) { @p.parse %w(--two) }
|
810
|
-
|
811
|
-
@p.opt :hello
|
812
|
-
@p.opt :yellow
|
813
|
-
@p.opt :mellow
|
814
|
-
@p.opt :jello
|
815
|
-
@p.depends :hello, :yellow, :mellow, :jello
|
816
|
-
@p.parse %w(--hello --yellow --mellow --jello)
|
817
|
-
assert_raises(CommandlineError) { @p.parse %w(--hello --mellow --jello) }
|
818
|
-
assert_raises(CommandlineError) { @p.parse %w(--hello --jello) }
|
819
|
-
|
820
|
-
assert_raises(CommandlineError) { @p.parse %w(--hello) }
|
821
|
-
assert_raises(CommandlineError) { @p.parse %w(--mellow) }
|
822
|
-
|
823
|
-
@p.parse %w(--hello --yellow --mellow --jello --one --two)
|
824
|
-
@p.parse %w(--hello --yellow --mellow --jello --one --two a b c)
|
825
|
-
|
826
|
-
assert_raises(CommandlineError) { @p.parse %w(--mellow --two --jello --one) }
|
827
|
-
end
|
828
|
-
|
829
|
-
def test_depend_error_messages
|
830
|
-
@p.opt :one
|
831
|
-
@p.opt "two"
|
832
|
-
@p.depends :one, "two"
|
833
|
-
|
834
|
-
@p.parse %w(--one --two)
|
835
|
-
|
836
|
-
assert_raises(CommandlineError, /--one.*--two/) { @p.parse %w(--one) }
|
837
|
-
assert_raises(CommandlineError, /--one.*--two/) { @p.parse %w(--two) }
|
838
|
-
end
|
839
826
|
|
840
827
|
## courtesy neill zero
|
841
828
|
def test_two_required_one_missing_accuses_correctly
|
842
829
|
@p.opt "arg1", "desc1", :required => true
|
843
830
|
@p.opt "arg2", "desc2", :required => true
|
844
831
|
|
845
|
-
|
846
|
-
|
832
|
+
assert_raises_errmatch(CommandlineError, /arg2/) { @p.parse(%w(--arg1)) }
|
833
|
+
assert_raises_errmatch(CommandlineError, /arg1/) { @p.parse(%w(--arg2)) }
|
847
834
|
@p.parse(%w(--arg1 --arg2))
|
848
835
|
end
|
849
836
|
|
@@ -1005,7 +992,10 @@ Options:
|
|
1005
992
|
opts = @p.parse %w(--arg3 stdin)
|
1006
993
|
assert_equal $stdin, opts[:arg3]
|
1007
994
|
|
1008
|
-
|
995
|
+
err_regex = %r/file or url for option 'arg' cannot be opened: No such file or directory/
|
996
|
+
assert_raises_errmatch(CommandlineError, err_regex) {
|
997
|
+
opts = @p.parse %w(--arg /fdasfasef/fessafef/asdfasdfa/fesasf)
|
998
|
+
}
|
1009
999
|
end
|
1010
1000
|
|
1011
1001
|
def test_openstruct_style_access
|
@@ -1106,6 +1096,86 @@ Options:
|
|
1106
1096
|
assert opts[:ccd]
|
1107
1097
|
end
|
1108
1098
|
|
1099
|
+
def test_short_opts_not_implicitly_created
|
1100
|
+
newp = Parser.new(implicit_short_opts: false)
|
1101
|
+
newp.opt :user1, "user1"
|
1102
|
+
newp.opt :bag, "bag", :short => 'b'
|
1103
|
+
assert_raises_errmatch(CommandlineError, /unknown argument '-u'/) do
|
1104
|
+
newp.parse %w(-u)
|
1105
|
+
end
|
1106
|
+
opts = newp.parse %w(--user1)
|
1107
|
+
assert opts[:user1]
|
1108
|
+
opts = newp.parse %w(-b)
|
1109
|
+
assert opts[:bag]
|
1110
|
+
end
|
1111
|
+
|
1112
|
+
def test_short_opts_not_implicit_help_ver
|
1113
|
+
# When implicit_short_opts is false this implies the short options
|
1114
|
+
# for the built-in help/version are also not created.
|
1115
|
+
newp = Parser.new(implicit_short_opts: false)
|
1116
|
+
newp.opt :abc, "abc"
|
1117
|
+
newp.version "3.4.5"
|
1118
|
+
assert_raises_errmatch(CommandlineError, /unknown argument '-h'/) do
|
1119
|
+
newp.parse %w(-h)
|
1120
|
+
end
|
1121
|
+
assert_raises_errmatch(CommandlineError, /unknown argument '-v'/) do
|
1122
|
+
newp.parse %w(-v)
|
1123
|
+
end
|
1124
|
+
assert_raises(HelpNeeded) do
|
1125
|
+
newp.parse %w(--help)
|
1126
|
+
end
|
1127
|
+
assert_raises(VersionNeeded) do
|
1128
|
+
newp.parse %w(--version)
|
1129
|
+
end
|
1130
|
+
end
|
1131
|
+
|
1132
|
+
def test_inexact_match
|
1133
|
+
newp = Parser.new(exact_match: false)
|
1134
|
+
newp.opt :liberation, "liberate something", :type => :int
|
1135
|
+
newp.opt :evaluate, "evaluate something", :type => :string
|
1136
|
+
opts = newp.parse %w(--lib 5 --ev bar)
|
1137
|
+
assert_equal 5, opts[:liberation]
|
1138
|
+
assert_equal 'bar', opts[:evaluate]
|
1139
|
+
assert_nil opts[:eval]
|
1140
|
+
end
|
1141
|
+
|
1142
|
+
def test_exact_match
|
1143
|
+
newp = Parser.new()
|
1144
|
+
newp.opt :liberation, "liberate something", :type => :int
|
1145
|
+
newp.opt :evaluate, "evaluate something", :type => :string
|
1146
|
+
assert_raises_errmatch(CommandlineError, /unknown argument '--lib'/) do
|
1147
|
+
newp.parse %w(--lib 5)
|
1148
|
+
end
|
1149
|
+
assert_raises_errmatch(CommandlineError, /unknown argument '--ev'/) do
|
1150
|
+
newp.parse %w(--ev bar)
|
1151
|
+
end
|
1152
|
+
end
|
1153
|
+
|
1154
|
+
def test_inexact_collision
|
1155
|
+
newp = Parser.new(exact_match: false)
|
1156
|
+
newp.opt :bookname, "name of a book", :type => :string
|
1157
|
+
newp.opt :bookcost, "cost of the book", :type => :string
|
1158
|
+
opts = newp.parse %w(--bookn hairy_potsworth --bookc 10)
|
1159
|
+
assert_equal 'hairy_potsworth', opts[:bookname]
|
1160
|
+
assert_equal '10', opts[:bookcost]
|
1161
|
+
assert_raises_errmatch(CommandlineError, /ambiguous option '--book' matched keys \(bookname,bookcost\)/) do
|
1162
|
+
newp.parse %w(--book 5) # ambiguous
|
1163
|
+
end
|
1164
|
+
## partial match causes 'specified multiple times' error
|
1165
|
+
assert_raises_errmatch(CommandlineError, /specified multiple times/) do
|
1166
|
+
newp.parse %w(--bookc 17 --bookcost 22)
|
1167
|
+
end
|
1168
|
+
end
|
1169
|
+
|
1170
|
+
def test_inexact_collision_with_exact
|
1171
|
+
newp = Parser.new(exact_match: false)
|
1172
|
+
newp.opt :book, "name of a book", :type => :string, :default => "ABC"
|
1173
|
+
newp.opt :bookcost, "cost of the book", :type => :int, :default => 5
|
1174
|
+
opts = newp.parse %w(--book warthog --bookc 3)
|
1175
|
+
assert_equal 'warthog', opts[:book]
|
1176
|
+
assert_equal 3, opts[:bookcost]
|
1177
|
+
end
|
1178
|
+
|
1109
1179
|
def test_accepts_arguments_with_spaces
|
1110
1180
|
@p.opt :arg1, "arg", :type => String
|
1111
1181
|
@p.opt :arg2, "arg2", :type => String
|
@@ -1163,7 +1233,7 @@ Options:
|
|
1163
1233
|
end
|
1164
1234
|
|
1165
1235
|
def test_simple_interface_handles_die
|
1166
|
-
assert_stderr do
|
1236
|
+
assert_stderr(/Error: argument --potato is invalid/) do
|
1167
1237
|
::Optimist::options(%w(--potato)) do
|
1168
1238
|
opt :potato
|
1169
1239
|
end
|
@@ -1172,7 +1242,7 @@ Options:
|
|
1172
1242
|
end
|
1173
1243
|
|
1174
1244
|
def test_simple_interface_handles_die_without_message
|
1175
|
-
assert_stderr(/Error
|
1245
|
+
assert_stderr(/Error: potato\./) do
|
1176
1246
|
::Optimist::options(%w(--potato)) do
|
1177
1247
|
opt :potato
|
1178
1248
|
end
|
@@ -1181,7 +1251,7 @@ Options:
|
|
1181
1251
|
end
|
1182
1252
|
|
1183
1253
|
def test_invalid_option_with_simple_interface
|
1184
|
-
assert_stderr do
|
1254
|
+
assert_stderr(/Error: unknown argument \'--potato\'\./) do
|
1185
1255
|
assert_raises(SystemExit) do
|
1186
1256
|
::Optimist.options(%w(--potato))
|
1187
1257
|
end
|
@@ -1197,7 +1267,7 @@ Options:
|
|
1197
1267
|
end
|
1198
1268
|
|
1199
1269
|
def test_supports_callback_inline
|
1200
|
-
|
1270
|
+
assert_raises_errmatch(RuntimeError, "good") do
|
1201
1271
|
@p.opt :cb1 do |vals|
|
1202
1272
|
raise "good"
|
1203
1273
|
end
|
@@ -1206,7 +1276,7 @@ Options:
|
|
1206
1276
|
end
|
1207
1277
|
|
1208
1278
|
def test_supports_callback_param
|
1209
|
-
|
1279
|
+
assert_raises_errmatch(RuntimeError, "good") do
|
1210
1280
|
@p.opt :cb1, "with callback", :callback => lambda { |vals| raise "good" }
|
1211
1281
|
@p.parse(%w(--cb1))
|
1212
1282
|
end
|
@@ -1261,6 +1331,37 @@ Options:
|
|
1261
1331
|
assert opts[:arg1]
|
1262
1332
|
assert_equal %w{-bu potato}, @p.leftovers
|
1263
1333
|
end
|
1334
|
+
|
1335
|
+
# Due to strangeness in how the cloaker works, there were
|
1336
|
+
# cases where Optimist.parse would work, but Optimist.options
|
1337
|
+
# did not, depending on arguments given to the function.
|
1338
|
+
# These serve to validate different args given to Optimist.options
|
1339
|
+
def test_options_takes_hashy_settings
|
1340
|
+
passargs_copy = []
|
1341
|
+
settings_copy = []
|
1342
|
+
::Optimist.options(%w(--wig --pig), :fizz=>:buzz, :bear=>:cat) do |*passargs|
|
1343
|
+
opt :wig
|
1344
|
+
opt :pig
|
1345
|
+
passargs_copy = passargs.dup
|
1346
|
+
settings_copy = @settings
|
1347
|
+
end
|
1348
|
+
assert_equal [], passargs_copy
|
1349
|
+
assert_equal settings_copy[:fizz], :buzz
|
1350
|
+
assert_equal settings_copy[:bear], :cat
|
1351
|
+
end
|
1352
|
+
|
1353
|
+
def test_options_takes_some_other_data
|
1354
|
+
passargs_copy = []
|
1355
|
+
settings_copy = []
|
1356
|
+
::Optimist.options(%w(--nose --close), 1, 2, 3) do |*passargs|
|
1357
|
+
opt :nose
|
1358
|
+
opt :close
|
1359
|
+
passargs_copy = passargs.dup
|
1360
|
+
settings_copy = @settings
|
1361
|
+
end
|
1362
|
+
assert_equal [1,2,3], passargs_copy
|
1363
|
+
assert_equal(Optimist::Parser::DEFAULT_SETTINGS, settings_copy)
|
1364
|
+
end
|
1264
1365
|
end
|
1265
1366
|
|
1266
1367
|
end
|