benry-cmdopt 2.3.0 → 2.4.0

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/test/cmdopt_test.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'oktest'
4
5
 
@@ -8,1392 +9,6 @@ require 'benry/cmdopt'
8
9
  Oktest.scope do
9
10
 
10
11
 
11
- def new_sample_schema()
12
- sc = Benry::CmdOpt::Schema.new
13
- sc.add(:help , "-h, --help" , "show help message.")
14
- sc.add(:version, "--version" , "print version")
15
- sc.add(:file , "-f, --file=<FILE>" , "filename")
16
- sc.add(:indent , "-i, --indent[=<WIDTH>]", "enable indent", type: Integer)
17
- sc.add(:mode , "-m, --mode=<MODE>" , "mode", enum: ['verbose', 'quiet'])
18
- sc.add(:libpath, "-I, --path=<PATH>" , "library path (multiple ok)") do |optdef, key, val|
19
- File.directory?(val) or raise "Directory not exist."
20
- arr = optdef[key] || []
21
- arr << val
22
- arr
23
- end
24
- sc
25
- end
26
-
27
-
28
-
29
- topic Benry::CmdOpt::Schema do
30
-
31
-
32
- topic '#parse()' do
33
-
34
- before do
35
- @schema = Benry::CmdOpt::Schema.new
36
- end
37
-
38
- spec "[!qw0ac] parses command option definition string." do
39
- sc = @schema
40
- tuple = sc.__send__(:parse_optdef, "-h, --help")
41
- ok {tuple} == ['h', 'help', nil, nil]
42
- tuple = sc.__send__(:parse_optdef, "-h")
43
- ok {tuple} == ['h', nil, nil, nil]
44
- tuple = sc.__send__(:parse_optdef, "--help")
45
- ok {tuple} == [nil, 'help', nil, nil]
46
- end
47
-
48
- spec "[!ae733] parses command option definition which has a required param." do
49
- sc = @schema
50
- tuple = sc.__send__(:parse_optdef, "-f, --file=<FILE>")
51
- ok {tuple} == ['f', 'file', '<FILE>', true]
52
- tuple = sc.__send__(:parse_optdef, "-f <FILE>")
53
- ok {tuple} == ['f', nil, '<FILE>', true]
54
- tuple = sc.__send__(:parse_optdef, "--file=<FILE>")
55
- ok {tuple} == [nil, 'file', '<FILE>', true]
56
- end
57
-
58
- spec "[!4h05c] parses command option definition which has an optional param." do
59
- sc = @schema
60
- tuple = sc.__send__(:parse_optdef, "-i, --indent[=<WIDTH>]")
61
- ok {tuple} == ['i', 'indent', '<WIDTH>', false]
62
- tuple = sc.__send__(:parse_optdef, "-i[<WIDTH>]")
63
- ok {tuple} == ['i', nil, '<WIDTH>', false]
64
- tuple = sc.__send__(:parse_optdef, "--indent[=<WIDTH>]")
65
- ok {tuple} == [nil, 'indent', '<WIDTH>', false]
66
- end
67
-
68
- spec "[!b7jo3] raises SchemaError when command option definition is invalid." do
69
- sc = @schema
70
- pr = proc {
71
- tuple = sc.__send__(:parse_optdef, "-i, --indent <WIDTH>")
72
- }
73
- ok {pr}.raise?(Benry::CmdOpt::SchemaError,
74
- "-i, --indent <WIDTH>: Invalid option definition (use '=--indent' instead of ' --indent').")
75
- end
76
-
77
- end
78
-
79
-
80
- topic '#dup()' do
81
-
82
- before do
83
- @schema = Benry::CmdOpt::Schema.new
84
- @schema.add(:help , "-h" , "print help")
85
- end
86
-
87
- spec "[!lxb0o] copies self object." do
88
- this = @schema
89
- other = @schema.dup()
90
- #
91
- this_items = this.instance_variable_get(:@items)
92
- other_items = other.instance_variable_get(:@items)
93
- ok {this_items} != nil
94
- ok {other_items} != nil
95
- ok {other_items} == this_items
96
- ok {other_items.object_id} != this_items.object_id
97
- #
98
- this.add(:silent, "-s", "silent")
99
- other.add(:quiet, "-q", "quiet")
100
- ok {this.option_help()} == (" -h : print help\n" +
101
- " -s : silent\n")
102
- ok {other.option_help()} == (" -h : print help\n" +
103
- " -q : quiet\n")
104
- end
105
-
106
- end
107
-
108
-
109
- topic '#copy_from()' do
110
-
111
- before do
112
- @schema1 = Benry::CmdOpt::Schema.new
113
- @schema1.add(:help, "-h" , "print help")
114
- @schema2 = Benry::CmdOpt::Schema.new
115
- @schema2.add(:version, "-v" , "print version")
116
- @schema2.add(:debug , "-D" , "debug mode")
117
- end
118
-
119
- spec "[!6six3] copy schema items from others." do
120
- @schema1.copy_from(@schema2)
121
- tuples = @schema1.each.collect {|x| [x.key, x.optdef, x.desc] }
122
- ok {tuples} == [
123
- [:help , "-h", "print help"],
124
- [:version, "-v", "print version"],
125
- [:debug , "-D", "debug mode"],
126
- ]
127
- end
128
-
129
- spec "[!vt88s] copy schema items except items specified by 'except:' kwarg." do
130
- @schema1.copy_from(@schema2, except: [:debug])
131
- tuples = @schema1.each.collect {|x| [x.key, x.optdef, x.desc] }
132
- ok {tuples} == [
133
- [:help, "-h", "print help"],
134
- [:version, "-v", "print version"],
135
- ]
136
- end
137
-
138
- end
139
-
140
-
141
- topic '#add()' do
142
-
143
- before do
144
- @schema = Benry::CmdOpt::Schema.new
145
- end
146
-
147
- spec "[!7hi2d] takes command option definition string." do
148
- sc = @schema
149
- sc.add(:indent, "-i, --indent=<WIDTH>", "print help")
150
- items = sc.instance_eval { @items }
151
- ok {items.length} == 1
152
- ok {items[0]}.is_a?(Benry::CmdOpt::SchemaItem)
153
- ok {items[0].key} == :indent
154
- ok {items[0].short} == 'i'
155
- ok {items[0].long} == 'indent'
156
- ok {items[0].param} == '<WIDTH>'
157
- ok {items[0].required?} == true
158
- ok {items[0].type} == nil
159
- ok {items[0].rexp} == nil
160
- ok {items[0].enum} == nil
161
- ok {items[0].callback} == nil
162
- end
163
-
164
- spec "[!p9924] option key is omittable only when long option specified." do
165
- sc = @schema
166
- sc.add(nil, "-m, --max-num=<N>", nil)
167
- items = sc.instance_eval { @items }
168
- ok {items[0].key} == :max_num
169
- end
170
-
171
- spec "[!jtp7z] raises SchemaError when key is nil and no long option." do
172
- sc = @schema
173
- pr = proc { sc.add(nil, "-i <N>", nil) }
174
- msg = "add(nil, \"-i <N>\"): Long option required when option key (1st arg) not specified."
175
- ok {pr}.raise?(Benry::CmdOpt::SchemaError, msg)
176
- end
177
-
178
- spec "[!rpl98] when long option is 'foo-bar' then key name is ':foo_bar'." do
179
- sc = @schema
180
- sc.add(nil, "--foo-bar", nil)
181
- items = sc.instance_eval { @items }
182
- ok {items[0].key} == :foo_bar
183
- end
184
-
185
- spec "[!97sn0] raises SchemaError when ',' is missing between short and long options." do
186
- sc = @schema
187
- pr = proc { sc.add(:exec, '-x --exec=ARG', "exec") }
188
- msg = "add(:exec, \"-x --exec=ARG\"): Missing ',' between short option and long options."
189
- ok {pr}.raise?(Benry::CmdOpt::SchemaError, msg)
190
- end
191
-
192
- spec "[!yht0v] keeps command option definitions." do
193
- sc = @schema
194
- sc.add(:indent, "-i, --indent[=<WIDTH>]", "indent width",
195
- range: (1..2), value: 8, detail: "(description)", tag: :ab,
196
- type: Integer, rexp: /\A\d+\z/, enum: [2, 4, 8]) {|v| v.to_i }
197
- items = sc.instance_eval { @items }
198
- ok {items.length} == 1
199
- ok {items[0]}.is_a?(Benry::CmdOpt::SchemaItem)
200
- ok {items[0].key} == :indent
201
- ok {items[0].short} == 'i'
202
- ok {items[0].long} == 'indent'
203
- ok {items[0].param} == '<WIDTH>'
204
- ok {items[0].required?} == false
205
- ok {items[0].type} == Integer
206
- ok {items[0].rexp} == /\A\d+\z/
207
- ok {items[0].enum} == [2, 4, 8]
208
- ok {items[0].range} == (1..2)
209
- ok {items[0].detail} == "(description)"
210
- ok {items[0].value} == 8
211
- ok {items[0].tag} == :ab
212
- ok {items[0].callback}.is_a?(Proc)
213
- ok {items[0].callback.arity} == 1
214
- end
215
-
216
- spec "[!kuhf9] type, rexp, enum, and range are can be passed as positional args as well as keyword args." do
217
- sc = @schema
218
- sc.add(:key, "--optdef=xx", "desc", Integer, /\A\d+\z/, [2,4,8], (2..8))
219
- item = sc.each.first
220
- ok {item.type} == Integer
221
- ok {item.rexp} == /\A\d+\z/
222
- ok {item.enum} == [2,4,8]
223
- ok {item.range} == (2..8)
224
- end
225
-
226
- spec "[!e3emy] raises error when positional arg is not one of class, regexp, array, nor range." do
227
- sc = @schema
228
- pr = proc { sc.add(:key, "--optdef=xx", "desc", "value") }
229
- ok {pr}.raise?(Benry::CmdOpt::SchemaError,
230
- '"value": Expected one of class, regexp, array or range, but got String.')
231
- end
232
-
233
- spec "[!rhhji] raises SchemaError when key is not a Symbol." do
234
- sc = @schema
235
- pr = proc {
236
- sc.add("-i, --indent[=<WIDTH>]", "indent width", nil)
237
- }
238
- ok {pr}.raise?(Benry::CmdOpt::SchemaError,
239
- 'add("-i, --indent[=<WIDTH>]", "indent width"): The first arg should be a Symbol as an option key.')
240
- end
241
-
242
- spec "[!vq6eq] raises SchemaError when help message is missing." do
243
- sc = @schema
244
- pr = proc {
245
- begin
246
- sc.add(:indent, "-i, --indent[=<WIDTH>]", type: Array) # Ruby 2
247
- rescue ArgumentError
248
- sc.add(:indent, "-i, --indent[=<WIDTH>]", {type: Array}) # Ruby 3
249
- end
250
- }
251
- ok {pr}.raise?(Benry::CmdOpt::SchemaError,
252
- 'add(:indent, "-i, --indent[=<WIDTH>]"): Help message required as 3rd argument.')
253
- end
254
-
255
-
256
- end
257
-
258
-
259
- topic '#add_item()' do
260
-
261
- spec "[!qyjp9] raises SchemaError if invalid item added." do
262
- sc = Benry::CmdOpt::Schema.new
263
- sc.add(:quiet, "-q, --quiet", "quiet mode")
264
- #
265
- item1 = Benry::CmdOpt::SchemaItem.new(:quiet, "-q", "quiet", "q", nil, nil, false)
266
- pr = proc { sc.add_item(item1) }
267
- ok {pr}.raise?(Benry::CmdOpt::SchemaError,
268
- "quiet: Option key duplicated.")
269
- #
270
- item2 = Benry::CmdOpt::SchemaItem.new(:quiet2, "-q", "quiet", "q", nil, nil, false)
271
- pr = proc { sc.add_item(item2) }
272
- ok {pr}.raise?(Benry::CmdOpt::SchemaError,
273
- "-q: Short option duplicated (key: quiet2 and quiet).")
274
- #
275
- item3 = Benry::CmdOpt::SchemaItem.new(:quiet3, "--quiet", "quiet", nil, "quiet", nil, false)
276
- pr = proc { sc.add_item(item3) }
277
- ok {pr}.raise?(Benry::CmdOpt::SchemaError,
278
- "--quiet: Long option duplicated (key: quiet3 and quiet).")
279
- end
280
-
281
- spec "[!a693h] adds option item into current schema." do
282
- item = Benry::CmdOpt::SchemaItem.new(:quiet, "-q", "quiet", "q", nil, nil, false)
283
- sc = Benry::CmdOpt::Schema.new
284
- sc.add_item(item)
285
- ok {sc.to_s} == <<"END"
286
- -q : quiet
287
- END
288
- end
289
-
290
- end
291
-
292
-
293
- topic '#_validate_item()' do
294
-
295
- before do
296
- @schema = Benry::CmdOpt::Schema.new
297
- @schema.add(:quiet, "-q, --quiet", "quiet mode")
298
- end
299
-
300
- spec "[!ewl20] returns error message if option key duplicated." do
301
- item = Benry::CmdOpt::SchemaItem.new(:quiet, "-q", "quiet mode", "q", nil, nil, false)
302
- ret = @schema.__send__(:_validate_item, item)
303
- ok {ret} == "quiet: Option key duplicated."
304
- end
305
-
306
- spec "[!xg56v] returns error message if short option duplicated." do
307
- item = Benry::CmdOpt::SchemaItem.new(:quiet2, "-q", "quiet mode", "q", nil, nil, false)
308
- ret = @schema.__send__(:_validate_item, item)
309
- ok {ret} == "-q: Short option duplicated (key: quiet2 and quiet)."
310
- end
311
-
312
- spec "[!izezi] returns error message if long option duplicated." do
313
- item = Benry::CmdOpt::SchemaItem.new(:quiet3, "--quiet", "quiet mode", nil, "quiet", nil, false)
314
- ret = @schema.__send__(:_validate_item, item)
315
- ok {ret} == "--quiet: Long option duplicated (key: quiet3 and quiet)."
316
- end
317
-
318
- end
319
-
320
-
321
- topic '#option_help()' do
322
-
323
- before do
324
- sc = Benry::CmdOpt::Schema.new
325
- sc.add(:help , "-h, --help" , "show help message.")
326
- sc.add(:version, " --version" , "print version")
327
- sc.add(:file , "-f, --file=<FILE>" , "filename")
328
- sc.add(:indent , "-i, --indent[=<WIDTH>]", "enable indent", type: Integer)
329
- sc.add(:debug , "-d, --debug" , nil)
330
- @schema = sc
331
- end
332
-
333
- spec "[!0aq0i] can take integer as width." do
334
- helpmsg = @schema.option_help(41)
335
- ok {helpmsg} == <<END
336
- -h, --help : show help message.
337
- --version : print version
338
- -f, --file=<FILE> : filename
339
- -i, --indent[=<WIDTH>] : enable indent
340
- END
341
- s = helpmsg.each_line.first.split(':')[0]
342
- ok {s.length} == 41+3
343
- end
344
-
345
- spec "[!pcsah] can take format string." do
346
- helpmsg = @schema.option_help("%-42s: %s")
347
- ok {helpmsg} == <<END
348
- -h, --help : show help message.
349
- --version : print version
350
- -f, --file=<FILE> : filename
351
- -i, --indent[=<WIDTH>] : enable indent
352
- END
353
- s = helpmsg.each_line.first.split(':')[0]
354
- ok {s.length} == 42+0
355
- end
356
-
357
- spec "[!dndpd] detects option width automatically when nothing specified." do
358
- helpmsg = @schema.option_help()
359
- ok {helpmsg} == <<END
360
- -h, --help : show help message.
361
- --version : print version
362
- -f, --file=<FILE> : filename
363
- -i, --indent[=<WIDTH>] : enable indent
364
- END
365
- s = helpmsg.each_line.to_a.last.split(':')[0]
366
- ok {s.length} == 25
367
- end
368
-
369
- spec "[!v7z4x] skips option help if help message is not specified." do
370
- helpmsg = @schema.option_help()
371
- ok {helpmsg} !~ /debug/
372
- end
373
-
374
- spec "[!to1th] includes all option help when `all` is true." do
375
- helpmsg = @schema.option_help(nil, all: true)
376
- ok {helpmsg} =~ /debug/
377
- ok {helpmsg} == <<END
378
- -h, --help : show help message.
379
- --version : print version
380
- -f, --file=<FILE> : filename
381
- -i, --indent[=<WIDTH>] : enable indent
382
- -d, --debug :
383
- END
384
- end
385
-
386
- spec "[!848rm] supports multi-lines help message." do
387
- sc = Benry::CmdOpt::Schema.new
388
- sc.add(:mode, "-m, --mode=<MODE>", "output mode",
389
- detail: <<"END")
390
- v, verbose: print many output
391
- q, quiet: print litte output
392
- c, compact: print summary output
393
- END
394
- actual = sc.option_help()
395
- expected = <<END
396
- -m, --mode=<MODE> : output mode
397
- v, verbose: print many output
398
- q, quiet: print litte output
399
- c, compact: print summary output
400
- END
401
- ok {actual} == expected
402
- end
403
-
404
- spec "[!a4qe4] option should not be hidden if description is empty string." do
405
- sc = Benry::CmdOpt::Schema.new
406
- sc.add(:debug , "-D", nil) # hidden
407
- sc.add(:trace, "-T", "trace", hidden: true) # hidden
408
- sc.add(:what , "-W", "") # NOT hidden!
409
- ok {sc.option_help()} == <<END
410
- -W :
411
- END
412
- end
413
-
414
- fixture :schema_with_importance do
415
- sc = Benry::CmdOpt::Schema.new
416
- sc.add(:help , "-h, --help" , "help message")
417
- sc.add(:trace , "-T, --trace", "trace" , important: true)
418
- sc.add(:debug , "-D, --debug", "debug mode" , important: false)
419
- sc.add(:quiet , "-q, --quiet", "quiet mode")
420
- sc
421
- end
422
-
423
- spec "[!jrwb6] decorates help message according to `important:` value of option." do
424
- |schema_with_importance|
425
- sc = schema_with_importance
426
- ok {sc.option_help()} == <<END
427
- -h, --help : help message
428
- \e[1m -T, --trace : trace\e[0m
429
- \e[2m -D, --debug : debug mode\e[0m
430
- -q, --quiet : quiet mode
431
- END
432
- end
433
-
434
- spec "[!9nlfb] not decorate help message when stdout is not a tty." do
435
- |schema_with_importance|
436
- sc = schema_with_importance
437
- output = nil
438
- capture_sio() {
439
- ok {$stdout}.NOT.tty?
440
- output = sc.option_help()
441
- }
442
- ok {output} == <<END
443
- -h, --help : help message
444
- -T, --trace : trace
445
- -D, --debug : debug mode
446
- -q, --quiet : quiet mode
447
- END
448
- end
449
-
450
- end
451
-
452
-
453
- topic '#_default_format()' do
454
-
455
- before do
456
- sc = Benry::CmdOpt::Schema.new
457
- sc.add(:help , "-h, --help" , "show help message.")
458
- sc.add(:version, " --version" , "print version")
459
- sc.add(:file , "-f, --file=<FILE>" , "filename")
460
- sc.add(:indent , "-i, --indent[=<WIDTH>]", "enable indent", type: Integer)
461
- sc.add(:debug , "-d, --debug" , nil)
462
- @schema = sc
463
- end
464
-
465
- spec "[!kkh9t] returns format string." do
466
- ret = @schema.__send__(:_default_format)
467
- ok {ret} == " %-22s : %s"
468
- end
469
-
470
- spec "[!hr45y] detects preffered option width." do
471
- ret = @schema.__send__(:_default_format, 10, 20)
472
- ok {ret} == " %-20s : %s"
473
- ret = @schema.__send__(:_default_format, 30, 40)
474
- ok {ret} == " %-30s : %s"
475
- ret = @schema.__send__(:_default_format, 10, 40)
476
- ok {ret} == " %-22s : %s"
477
- end
478
-
479
- spec "[!bmr7d] changes min_with according to options." do
480
- sc = Benry::CmdOpt::Schema.new
481
- sc.add(:help , '-h', "help")
482
- sc.add(:version, '-v', "version")
483
- ok {sc.__send__(:_default_format, nil, 40)} == " %-8s : %s"
484
- #
485
- sc.add(:file , '-f <FILE>', "filename")
486
- ok {sc.__send__(:_default_format, nil, 40)} == " %-14s : %s"
487
- #
488
- sc.add(:force , '--force', "forcedly")
489
- ok {sc.__send__(:_default_format, nil, 40)} == " %-14s : %s"
490
- #
491
- sc.add(:mode , '-m, --mode=<MODE>', "verbose/quiet")
492
- ok {sc.__send__(:_default_format, nil, 40)} == " %-20s : %s"
493
- end
494
-
495
- end
496
-
497
-
498
- topic '#_preferred_option_width()' do
499
-
500
- spec "[!kl91t] shorten option help min width when only single options which take no arg." do
501
- sc = Benry::CmdOpt::Schema.new
502
- sc.add(:help , '-h', "help")
503
- sc.add(:version, '-v', "version")
504
- ok {sc.__send__(:_preferred_option_width)} == 8
505
- end
506
-
507
- spec "[!0koqb] widen option help min width when any option takes an arg." do
508
- sc = Benry::CmdOpt::Schema.new
509
- sc.add(:help , '-h', "help")
510
- sc.add(:indent , '-i[<N>]', "indent")
511
- ok {sc.__send__(:_preferred_option_width)} == 14
512
- end
513
-
514
- spec "[!kl91t] widen option help min width when long option exists." do
515
- sc = Benry::CmdOpt::Schema.new
516
- sc.add(:help , '-h', "help")
517
- sc.add(:version, '-v, --version', "version")
518
- ok {sc.__send__(:_preferred_option_width)} == 14
519
- #
520
- sc.add(:file, '--file=<FILE>', "filename")
521
- ok {sc.__send__(:_preferred_option_width)} == 20
522
- end
523
-
524
- end
525
-
526
-
527
- topic '#to_s()' do
528
-
529
- spec "[!rrapd] '#to_s' is an alias to '#option_help()'." do
530
- schema = Benry::CmdOpt::Schema.new
531
- schema.add(:help , "-h, --help" , "show help message")
532
- schema.add(:version, " --version" , "print version")
533
- ok {schema.to_s} == schema.option_help()
534
- end
535
-
536
- end
537
-
538
-
539
- topic '#each_option_and_desc()' do
540
-
541
- before do
542
- sc = Benry::CmdOpt::Schema.new
543
- sc.add(:help, "-h, --help", "show help message")
544
- sc.add(:version, " --version", "print version")
545
- sc.add(:debug , "-d, --debug" , nil) # hidden
546
- sc.add(:DEBUG , "-D, --DEBUG" , "debug mode", hidden: true) # hidden
547
- @schema = sc
548
- end
549
-
550
- spec "[!4b911] yields each optin definition str and help message." do
551
- pairs = []
552
- @schema.each_option_and_desc {|opt, desc| pairs << [opt, desc] }
553
- ok {pairs} == [
554
- ["-h, --help" , "show help message"], # not hiddden
555
- [" --version" , "print version"], # not hidden
556
- ]
557
- end
558
-
559
- spec "[!cl8zy] when 'all' flag is false, not yield hidden items." do
560
- pairs = []
561
- @schema.each_option_and_desc(all: false) {|opt, desc| pairs << [opt, desc] }
562
- ok {pairs} == [
563
- ["-h, --help" , "show help message"], # not hiddden
564
- [" --version" , "print version"], # not hidden
565
- ]
566
- end
567
-
568
- spec "[!tc4bk] when 'all' flag is true, yields even hidden items." do
569
- pairs = []
570
- @schema.each_option_and_desc(all: true) {|opt, desc| pairs << [opt, desc] }
571
- ok {pairs} == [
572
- ["-h, --help" , "show help message"], # not hiddden
573
- [" --version" , "print version"], # not hidden
574
- ["-d, --debug" , nil], # hidden
575
- ["-D, --DEBUG" , "debug mode"], # hidden
576
- ]
577
- end
578
-
579
- spec "[!03sux] returns enumerator object if block not given." do
580
- ## when 'all: true'
581
- xs = @schema.each_option_and_desc(all: true)
582
- ok {xs}.is_a?(Enumerator)
583
- ok {xs.collect {|x, _| x }} == ["-h, --help", " --version", "-d, --debug", "-D, --DEBUG"]
584
- ## when 'all: false'
585
- xs = @schema.each_option_and_desc(all: false)
586
- ok {xs}.is_a?(Enumerator)
587
- ok {xs.collect {|x, _| x }} == ["-h, --help", " --version"]
588
- end
589
-
590
- spec "[!zbxyv] returns self." do
591
- ret = @schema.each_option_and_desc { nil }
592
- ok {ret}.same? @schema
593
- end
594
-
595
- end
596
-
597
-
598
- topic '#each()' do
599
-
600
- before do
601
- @schema = Benry::CmdOpt::Schema.new
602
- @schema.add(:help , "-h, --help" , "help message")
603
- @schema.add(:version, " --version", "print version")
604
- end
605
-
606
- spec "[!y4k1c] yields each option item." do
607
- items = []
608
- @schema.each {|x| items << x }
609
- ok {items.length} == 2
610
- ok {items[0]}.is_a?(Benry::CmdOpt::SchemaItem)
611
- ok {items[1]}.is_a?(Benry::CmdOpt::SchemaItem)
612
- ok {items[0].key} == :help
613
- ok {items[1].key} == :version
614
- keys = @schema.each.collect {|x| x.key }
615
- ok {keys} == [:help, :version]
616
- end
617
-
618
- end
619
-
620
-
621
- topic '#empty?()' do
622
-
623
- spec "[!um8am] returns false if any item exists, else returns true." do
624
- schema = Benry::CmdOpt::Schema.new
625
- ok {schema.empty?()} == true
626
- schema.add(:help , "-h, --help" , "help message")
627
- ok {schema.empty?()} == false
628
- end
629
-
630
- spec "[!icvm1] ignores hidden items if 'all: false' kwarg specified." do
631
- schema = Benry::CmdOpt::Schema.new
632
- schema.add(:debug , "-D", nil)
633
- schema.add(:trace, "-T", "trace", hidden: true)
634
- ok {schema.empty?()} == false
635
- ok {schema.empty?(all: true)} == false
636
- ok {schema.empty?(all: false)} == true
637
- end
638
-
639
- end
640
-
641
-
642
- topic '#get()' do
643
-
644
- before do
645
- @schema = Benry::CmdOpt::Schema.new
646
- @schema.add(:help , "-h, --help" , "help message")
647
- @schema.add(:version, " --version", "print version")
648
- end
649
-
650
- spec "[!3wjfp] finds option item object by key." do
651
- item = @schema.get(:help)
652
- ok {item.key} == :help
653
- item = @schema.get(:version)
654
- ok {item.key} == :version
655
- end
656
-
657
- spec "[!0spll] returns nil if key not found." do
658
- ok {@schema.get(:debug)} == nil
659
- end
660
-
661
- end
662
-
663
-
664
- topic '#delete()' do
665
-
666
- before do
667
- @schema = Benry::CmdOpt::Schema.new
668
- @schema.add(:help , "-h, --help" , "help message")
669
- @schema.add(:version, " --version", "print version")
670
- end
671
-
672
- spec "[!l86rb] deletes option item corresponding to key." do
673
- keys = @schema.each.collect {|x| x.key }
674
- ok {keys} == [:help, :version]
675
- @schema.delete(:help)
676
- keys = @schema.each.collect {|x| x.key }
677
- ok {keys} == [:version]
678
- end
679
-
680
- spec "[!rq0aa] returns deleted item." do
681
- item = @schema.delete(:version)
682
- ok {item} != nil
683
- ok {item.key} == :version
684
- end
685
-
686
- end
687
-
688
-
689
- topic '#find_short_option()' do
690
-
691
- before do
692
- @schema = new_sample_schema()
693
- end
694
-
695
- spec "[!b4js1] returns option definition matched to short name." do
696
- x = @schema.find_short_option('h')
697
- ok {x.key} == :help
698
- x = @schema.find_short_option('f')
699
- ok {x.key} == :file
700
- x = @schema.find_short_option('i')
701
- ok {x.key} == :indent
702
- end
703
-
704
- spec "[!s4d1y] returns nil when nothing found." do
705
- ok {@schema.find_short_option('v')} == nil
706
- end
707
-
708
- end
709
-
710
-
711
- topic '#find_long_option()' do
712
-
713
- before do
714
- @schema = new_sample_schema()
715
- end
716
-
717
- spec "[!atmf9] returns option definition matched to long name." do
718
- x = @schema.find_long_option('help')
719
- ok {x.key} == :help
720
- x = @schema.find_long_option('file')
721
- ok {x.key} == :file
722
- x = @schema.find_long_option('indent')
723
- ok {x.key} == :indent
724
- end
725
-
726
- spec "[!6haoo] returns nil when nothing found." do
727
- ok {@schema.find_long_option('lib')} == nil
728
- end
729
-
730
- end
731
-
732
-
733
- end
734
-
735
-
736
-
737
- topic Benry::CmdOpt::SchemaItem do
738
-
739
- ITEMS = [
740
- Benry::CmdOpt::SchemaItem.new(:help, "-h, --help", "help msg",
741
- "h", "help", nil, nil),
742
- Benry::CmdOpt::SchemaItem.new(:file, "-f, --file=<file>", "filename",
743
- "f", "file", "<file>", true),
744
- Benry::CmdOpt::SchemaItem.new(:indent, "-i, --indent[=<N>]", "indent width",
745
- "i", "indent", "<N>", false),
746
- ]
747
-
748
-
749
- topic '#initialize()' do
750
-
751
- before do
752
- @schema = Benry::CmdOpt::Schema.new
753
- end
754
-
755
- spec "[!nn4cp] freezes enum object." do
756
- item = Benry::CmdOpt::SchemaItem.new(:foo, "--foo", "desc", nil, "foo", "<val>",
757
- true, enum: ["x", "y", "z"])
758
- ok {item.enum} == ["x", "y", "z"]
759
- ok {item.enum}.frozen?
760
- end
761
-
762
- case_when "[!wy2iv] when 'type:' specified..." do
763
-
764
- spec "[!7xmr5] raises SchemaError when type is not registered." do
765
- sc = @schema
766
- pr = proc {
767
- sc.add(:indent, "-i, --indent[=<WIDTH>]", "indent width", type: Array)
768
- }
769
- ok {pr}.raise?(Benry::CmdOpt::SchemaError,
770
- "Array: Unregistered type.")
771
- end
772
-
773
- spec "[!s2aaj] raises SchemaError when option has no params but type specified." do
774
- sc = @schema
775
- pr = proc {
776
- sc.add(:indent, "-i, --indent", "indent width", type: Integer)
777
- }
778
- ok {pr}.raise?(Benry::CmdOpt::SchemaError,
779
- "Integer: Type specified in spite of option has no params.")
780
- end
781
-
782
- spec "[!sz8x2] not raise error when no params but value specified." do
783
- sc = @schema
784
- pr = proc {
785
- sc.add(:indent, "-i, --indent", "indent width", type: Integer, value: 0)
786
- }
787
- ok {pr}.NOT.raise?(Exception)
788
- end
789
-
790
- spec "[!70ogf] not raise error when no params but TrueClass specified." do
791
- sc = @schema
792
- pr = proc {
793
- sc.add(:indent, "-i, --indent", "indent width", type: TrueClass)
794
- }
795
- ok {pr}.NOT.raise?(Exception)
796
- end
797
-
798
- end
799
-
800
- case_when "[!6y8s2] when 'rexp:' specified..." do
801
-
802
- spec "[!bi2fh] raises SchemaError when pattern is not a regexp." do
803
- sc = @schema
804
- pr = proc {
805
- sc.add(:indent, "-x, --indent[=<WIDTH>]", "indent width", rexp: '\A\d+\z')
806
- }
807
- ok {pr}.raise?(Benry::CmdOpt::SchemaError,
808
- '"\\\\A\\\\d+\\\\z": Regexp pattern expected.')
809
- end
810
-
811
- spec "[!01fmt] raises SchmeaError when option has no params but pattern specified." do
812
- sc = @schema
813
- pr = proc {
814
- sc.add(:indent, "-i, --indent", "indent width", rexp: /\A\d+\z/)
815
- }
816
- ok {pr}.raise?(Benry::CmdOpt::SchemaError,
817
- '/\A\d+\z/: Regexp pattern specified in spite of option has no params.')
818
- end
819
-
820
- end
821
-
822
- case_when "[!5nrvq] when 'enum:' specified..." do
823
-
824
- spec "[!melyd] raises SchemaError when enum is not an Array nor Set." do
825
- sc = @schema
826
- sc.add(:indent1, "-i <N>", "indent width", enum: ["2", "4", "8"])
827
- sc.add(:indent2, "-j <N>", "indent width", enum: Set.new(["2", "4", "8"]))
828
- pr = proc {
829
- sc.add(:indent3, "-k <N>", "indent width", enum: "2,4,8")
830
- }
831
- ok {pr}.raise?(Benry::CmdOpt::SchemaError,
832
- '"2,4,8": Array or set expected.')
833
- end
834
-
835
- spec "[!xqed8] raises SchemaError when enum specified for no param option." do
836
- sc = @schema
837
- pr = proc {
838
- sc.add(:indent, "-i", "enable indent", enum: [2, 4, 8])
839
- }
840
- ok {pr}.raise?(Benry::CmdOpt::SchemaError,
841
- "[2, 4, 8]: Enum specified in spite of option has no params.")
842
- end
843
-
844
- spec "[!zuthh] raises SchemaError when enum element value is not instance of type class." do
845
- sc = @schema
846
- pr = proc {
847
- sc.add(:indent, "-i <N>", "enable indent", type: Integer, enum: ['2', '4', '8'])
848
- }
849
- ok {pr}.raise?(Benry::CmdOpt::SchemaError,
850
- '["2", "4", "8"]: Enum element value should be instance of Integer, but "2" is not.')
851
- end
852
-
853
- end
854
-
855
- case_when "[!hk4nw] when 'range:' specified..." do
856
-
857
- spec "[!z20ky] raises SchemaError when range is not a Range object." do
858
- pr = proc {
859
- @schema.add(:indent, "-i <N>", "indent", type: Integer, range: [1,8])
860
- }
861
- ok {pr}.raise?(Benry::CmdOpt::SchemaError,
862
- "[1, 8]: Range object expected.")
863
- end
864
-
865
- spec "[!gp025] raises SchemaError when range specified with `type: TrueClass`." do
866
- pr = proc {
867
- @schema.add(:indent, "-i <N>", "indent", type: TrueClass, range: 0..1)
868
- }
869
- ok {pr}.raise?(Benry::CmdOpt::SchemaError,
870
- "0..1: Range is not available with `type: TrueClass`.")
871
- end
872
-
873
- spec "[!7njd5] range beginning/end value should be expected type." do
874
- pr = proc {
875
- @schema.add(:indent, "-i <N>", "indent", range: (1..8))
876
- }
877
- ok {pr}.raise?(Benry::CmdOpt::SchemaError,
878
- "1..8: Range value should be String, but not.")
879
- pr = proc {
880
- @schema.add(:indent, "-i <N>", "indent", type: Date, range: (1..8))
881
- }
882
- ok {pr}.raise?(Benry::CmdOpt::SchemaError,
883
- "1..8: Range value should be Date, but not.")
884
- end
885
-
886
- spec "[!uymig] range object can be endless." do
887
- begin
888
- range1 = eval "(1..)" # Ruby >= 2.6
889
- range2 = eval "(..3)" # Ruby >= 2.6
890
- rescue SyntaxError
891
- range1 = nil # Ruby < 2.6
892
- range2 = nil # Ruby < 2.6
893
- end
894
- if range1
895
- pr = proc {
896
- @schema.add(:indent1, "-i <N>", "indent", type: Integer, range: range1)
897
- @schema.add(:indent2, "-j <N>", "indent", type: Integer, range: range2)
898
- }
899
- ok {pr}.NOT.raise?(Exception)
900
- end
901
- end
902
-
903
- end
904
-
905
- case_when "[!a0g52] when 'value:' specified..." do
906
-
907
- spec "[!435t6] raises SchemaError when 'value:' is specified on argument-required option." do
908
- sc = @schema
909
- pr = proc {
910
- sc.add(:flag, "--flag=<on|off>", "flag", type: TrueClass, value: true)
911
- }
912
- ok {pr}.raise?(Benry::CmdOpt::SchemaError,
913
- "true: 'value:' is meaningless when option has required argument (hint: change to optional argument instead).")
914
- end
915
-
916
- spec "[!6vwqv] raises SchemaError when type is TrueClass but value is not true nor false." do
917
- sc = @schema
918
- pr = proc {
919
- sc.add(:flag, "--flag[=<on|off>]", "flag", type: TrueClass, value: 0)
920
- }
921
- ok {pr}.raise?(Benry::CmdOpt::SchemaError,
922
- "0: Value should be true or false when `type: TrueClass` specified.")
923
- end
924
-
925
- spec "[!c6i2o] raises SchemaError when value is not a kind of type." do
926
- sc = @schema
927
- pr = proc {
928
- sc.add(:flag, "--flag[=<on|off>]", "flag", type: Integer, value: false)
929
- }
930
- ok {pr}.raise?(Benry::CmdOpt::SchemaError,
931
- "Type mismatched between `type: Integer` and `value: false`.")
932
- end
933
-
934
- spec "[!lnhp6] not raise error when type is not specified." do
935
- sc = @schema
936
- pr = proc {
937
- sc.add(:flag, "--flag[=<on|off>]", "flag", value: false)
938
- }
939
- ok {pr}.NOT.raise?(Exception)
940
- end
941
-
942
- spec "[!6xb8o] value should be included in enum values." do
943
- sc = @schema
944
- pr = proc {
945
- sc.add(:lang, "--lang[=<en|fr|it>]", "language", enum: ["en", "fr", "it"], value: "ja")
946
- }
947
- ok {pr}.raise?(Benry::CmdOpt::SchemaError,
948
- "ja: Value should be included in enum values, but not.")
949
- end
950
-
951
- end
952
-
953
- end
954
-
955
-
956
- topic '#required?' do
957
-
958
- spec "[!svxny] returns nil if option takes no arguments." do
959
- item, _, _ = ITEMS
960
- ok {item.required?} == nil
961
- end
962
-
963
- spec "[!togcx] returns true if argument is required." do
964
- _, item, _ = ITEMS
965
- ok {item.required?} == true
966
- end
967
-
968
- spec "[!uwbgc] returns false if argument is optional." do
969
- _, _, item = ITEMS
970
- ok {item.required?} == false
971
- end
972
-
973
- end
974
-
975
-
976
- topic '#arg_requireness()' do
977
-
978
- spec "[!kmo28] returns :none if option takes no arguments." do
979
- item, _, _ = ITEMS
980
- ok {item.arg_requireness()} == :none
981
- end
982
-
983
- spec "[!s8gxl] returns :required if argument is required." do
984
- _, item, _ = ITEMS
985
- ok {item.arg_requireness()} == :required
986
- end
987
-
988
- spec "[!owpba] returns :optional if argument is optional." do
989
- _, _, item = ITEMS
990
- ok {item.arg_requireness()} == :optional
991
- end
992
-
993
- end
994
-
995
-
996
- topic '#hidden?()' do
997
-
998
- spec "[!no6ov] returns true if @hidden is true." do
999
- item = Benry::CmdOpt::SchemaItem.new(:debug, "-D", "debug mode", "D", nil, nil, nil, hidden: true)
1000
- ok {item.hidden?} == true
1001
- end
1002
-
1003
- spec "[!ej8ot] returns false if @hidden is false." do
1004
- item = Benry::CmdOpt::SchemaItem.new(:debug, "-D", "debug mode", "D", nil, nil, nil, hidden: false)
1005
- ok {item.hidden?} == false
1006
- end
1007
-
1008
- spec "[!h0uxs] returns true if desc is nil." do
1009
- desc = nil
1010
- item = Benry::CmdOpt::SchemaItem.new(:debug, "-D", desc, "D", nil, nil, nil)
1011
- ok {item.hidden?} == true
1012
- end
1013
-
1014
- spec "[!28vzx] returns false if else." do
1015
- desc = "debug mode"
1016
- item = Benry::CmdOpt::SchemaItem.new(:debug, "-D", desc, "D", nil, nil, nil)
1017
- ok {item.hidden?} == false
1018
- end
1019
-
1020
- end
1021
-
1022
-
1023
- topic '#important?()' do
1024
-
1025
- spec "[!ua8kt] returns true/false if `important:` kwarg passed to constructor." do
1026
- item1 = Benry::CmdOpt::SchemaItem.new(:debug, "-D", "debug mode", "D", nil, nil, nil, important: true)
1027
- ok {item1.important?} == true
1028
- item2 = Benry::CmdOpt::SchemaItem.new(:debug, "-D", "debug mode", "D", nil, nil, nil, important: false)
1029
- ok {item2.important?} == false
1030
- end
1031
-
1032
- spec "[!hz9sx] returns nil if `important:` kwarg not passed to constructor." do
1033
- item3 = Benry::CmdOpt::SchemaItem.new(:debug, "-D", "debug mode", "D", nil, nil, nil)
1034
- ok {item3.important?} == nil
1035
- end
1036
-
1037
- end
1038
-
1039
-
1040
- topic '#validate_and_convert()' do
1041
-
1042
- def new_item(key, optstr, desc, short, long, param, required,
1043
- type: nil, rexp: nil, enum: nil, range: nil, value: nil, &callback)
1044
- return Benry::CmdOpt::SchemaItem.new(key, optstr, desc, short, long, param, required,
1045
- type: type, rexp: rexp, enum: enum, range: range, value: value, &callback)
1046
- end
1047
-
1048
- spec "[!h0s0o] raises RuntimeError when value not matched to pattern." do
1049
- x = new_item(:indent, "", "indent width", "i", "indent", "<WIDTH>", false, rexp: /\A\d+\z/)
1050
- optdict = {}
1051
- pr = proc { x.validate_and_convert("abc", optdict) }
1052
- ok {pr}.raise?(RuntimeError, "Pattern unmatched.")
1053
- end
1054
-
1055
- spec "[!5jrdf] raises RuntimeError when value not in enum." do
1056
- x = new_item(:indent, "", "indent width", "i", "indent", "<WIDTH>", false, enum: ['2', '4', '8'])
1057
- optdict = {}
1058
- pr = proc { x.validate_and_convert("10", optdict) }
1059
- ok {pr}.raise?(RuntimeError, "Expected one of 2/4/8.")
1060
- end
1061
-
1062
- spec "[!5falp] raise RuntimeError when value not in range." do
1063
- x = new_item(:indent, "-i[=<N>]", "indent", "i", nil, "<N>", false,
1064
- type: Integer, range: 2..8)
1065
- optdict = {}
1066
- pr = proc { x.validate_and_convert("1", optdict) }
1067
- ok {pr}.raise?(RuntimeError, "Too small (min: 2)")
1068
- pr = proc { x.validate_and_convert("9", optdict) }
1069
- ok {pr}.raise?(RuntimeError, "Too large (max: 8)")
1070
- ## when min==0
1071
- x = new_item(:indent, "-i[=<N>]", "indent", "i", nil, "<N>", false,
1072
- type: Integer, range: 0..8)
1073
- optdict = {}
1074
- pr = proc { x.validate_and_convert("-1", optdict) }
1075
- ok {pr}.raise?(RuntimeError, "Positive value (>= 0) expected.")
1076
- ## when min==1
1077
- x = new_item(:indent, "-i[=<N>]", "indent", "i", nil, "<N>", false,
1078
- type: Integer, range: 1..8)
1079
- optdict = {}
1080
- pr = proc { x.validate_and_convert("0", optdict) }
1081
- ok {pr}.raise?(RuntimeError, "Positive value (>= 1) expected.")
1082
- end
1083
-
1084
- spec "[!a0rej] supports endless range." do
1085
- begin
1086
- range1 = eval "(2..)" # Ruby >= 2.6
1087
- range2 = eval "(..8)"
1088
- rescue SyntaxError
1089
- range1 = nil # Ruby < 2.6
1090
- range2 = nil
1091
- end
1092
- if range1
1093
- x = new_item(:indent, "-i[=<N>]", "indent", "i", nil, "<N>", false,
1094
- type: Integer, range: range1)
1095
- optdict = {}
1096
- pr = proc { x.validate_and_convert("1", optdict) }
1097
- ok {pr}.raise?(RuntimeError, "Too small (min: 2)")
1098
- pr = proc { x.validate_and_convert("9", optdict) }
1099
- ok {pr}.NOT.raise?(RuntimeError)
1100
- end
1101
- if range2
1102
- x = new_item(:indent, "-i[=<N>]", "indent", "i", nil, "<N>", false,
1103
- type: Integer, range: range2)
1104
- optdict = {}
1105
- pr = proc { x.validate_and_convert("1", optdict) }
1106
- ok {pr}.NOT.raise?(RuntimeError)
1107
- pr = proc { x.validate_and_convert("9", optdict) }
1108
- ok {pr}.raise?(RuntimeError, "Too large (max: 8)")
1109
- end
1110
- end
1111
-
1112
- spec "[!j4fuz] calls type-specific callback when type specified." do
1113
- x = new_item(:indent, "", "indent width", "i", "indent", "<WIDTH>", false, type: Integer)
1114
- optdict = {}
1115
- pr = proc { x.validate_and_convert("abc", optdict) }
1116
- ok {pr}.raise?(RuntimeError, "Integer expected.")
1117
- end
1118
-
1119
- spec "[!jn9z3] calls callback when callback specified." do
1120
- called = false
1121
- x = new_item(:indent, "", "indent width", "i", "indent", "<WIDTH>", false) {|va|
1122
- called = true
1123
- }
1124
- optdict = {}
1125
- x.validate_and_convert("abc", optdict)
1126
- ok {called} == true
1127
- end
1128
-
1129
- spec "[!iqalh] calls callback with different number of args according to arity." do
1130
- args1 = nil
1131
- x = new_item(:indent, "", "indent width", "i", "indent", "<WIDTH>", false) {|val|
1132
- args1 = val
1133
- }
1134
- optdict = {}
1135
- x.validate_and_convert("123", optdict)
1136
- ok {args1} == "123"
1137
- #
1138
- args2 = nil
1139
- x = new_item(:indent, "", "indent width", "i", "indent", "<WIDTH>", false) {|optdict, key, val|
1140
- args2 = [optdict, key, val]
1141
- }
1142
- optdict = {}
1143
- x.validate_and_convert("123", optdict)
1144
- ok {args2} == [optdict, :indent, "123"]
1145
- end
1146
-
1147
- spec "[!x066l] returns new value." do
1148
- x = new_item(:indent, "", "indent width", "i", "indent", "<WIDTH>", false, type: Integer)
1149
- ok {x.validate_and_convert("123", {})} == 123
1150
- #
1151
- x = new_item(:indent, "", "indent width", "i", "indent", "<WIDTH>", false, type: Integer) {|val|
1152
- val * 2
1153
- }
1154
- ok {x.validate_and_convert("123", {})} == 246
1155
- end
1156
-
1157
- spec "[!eafem] returns default value (if specified) instead of true value." do
1158
- x1 = new_item(:flag, "", "desc", "f", "flag", nil, false, value: nil)
1159
- ok {x1.validate_and_convert(true, {})} == true
1160
- x2 = new_item(:flag, "", "desc", "f", "flag", nil, false, value: "blabla")
1161
- ok {x2.validate_and_convert(true, {})} == "blabla"
1162
- x3 = new_item(:flag, "", "desc", "f", "flag", nil, false, value: false)
1163
- ok {x3.validate_and_convert(true, {})} == false
1164
- end
1165
-
1166
- end
1167
-
1168
- end
1169
-
1170
-
1171
-
1172
- topic Benry::CmdOpt::Parser do
1173
-
1174
-
1175
- topic '#parse_options()' do
1176
-
1177
- before do
1178
- @parser = Benry::CmdOpt::Parser.new(new_sample_schema())
1179
- end
1180
-
1181
- spec "[!3wmsy] returns command option values as a dict." do
1182
- argv = ["-h", "--version"]
1183
- d = @parser.parse(argv)
1184
- ok {d} == {help: true, version: true}
1185
- end
1186
-
1187
- spec "[!uh7j8] parses long options." do
1188
- argv = ["--help", "--file=foo.png", "--indent=10"]
1189
- d = @parser.parse(argv)
1190
- ok {d} == {help: true, file: "foo.png", indent: 10}
1191
- end
1192
-
1193
- spec "[!nwnjc] parses short options." do
1194
- argv = ["-h", "-f", "foo.png", "-i10"]
1195
- d = @parser.parse(argv)
1196
- ok {d} == {help: true, file: "foo.png", indent: 10}
1197
- end
1198
-
1199
- spec "[!5s5b6] treats '-' as an argument, not an option." do
1200
- argv = ["-h", "-", "xxx", "yyy"]
1201
- d = @parser.parse(argv)
1202
- ok {d} == {help: true}
1203
- ok {argv} == ["-", "xxx", "yyy"]
1204
- end
1205
-
1206
- spec "[!q8356] parses options even after arguments when `all: true`." do
1207
- argv = ["-h", "arg1", "-f", "foo.png", "arg2", "-i10", "arg3"]
1208
- d = @parser.parse(argv, all: true)
1209
- ok {d} == {help: true, file: "foo.png", indent: 10}
1210
- ok {argv} == ["arg1", "arg2", "arg3"]
1211
- #
1212
- argv = ["-h", "arg1", "-f", "foo.png", "arg2", "-i10", "arg3"]
1213
- d = @parser.parse(argv)
1214
- ok {d} == {help: true, file: "foo.png", indent: 10}
1215
- ok {argv} == ["arg1", "arg2", "arg3"]
1216
- end
1217
-
1218
- spec "[!ryra3] doesn't parse options after arguments when `all: false`." do
1219
- argv = ["-h", "arg1", "-f", "foo.png", "arg2", "-i10", "arg3"]
1220
- d = @parser.parse(argv, all: false)
1221
- ok {d} == {help: true}
1222
- ok {argv} == ["arg1", "-f", "foo.png", "arg2", "-i10", "arg3"]
1223
- end
1224
-
1225
- spec "[!y04um] skips rest options when '--' found in argv." do
1226
- argv = ["-h", "--", "-f", "foo.png", "-i10"]
1227
- d = @parser.parse(argv)
1228
- ok {d} == {help: true}
1229
- ok {argv} == ["-f", "foo.png", "-i10"]
1230
- end
1231
-
1232
- spec "[!qpuxh] handles only OptionError when block given." do
1233
- errmsg = nil
1234
- errcls = nil
1235
- @parser.parse(["-ix"]) {|err|
1236
- errmsg = err.message
1237
- errcls = err.class
1238
- }
1239
- ok {errmsg} == "-ix: Integer expected."
1240
- ok {errcls} == Benry::CmdOpt::OptionError
1241
- #
1242
- sc = Benry::CmdOpt::Schema.new
1243
- sc.add(:file, "--file=<FILE>", "file") do |val|
1244
- File.open(val) {|f| f.read }
1245
- end
1246
- parser = Benry::CmdOpt::Parser.new(sc)
1247
- pr = proc { parser.parse(["--file=/foo/bar/baz.png"]) }
1248
- ok {pr}.raise?(Errno::ENOENT, /No such file or directory/)
1249
- end
1250
-
1251
- spec "[!dhpw1] returns nil when OptionError handled." do
1252
- ret = @parser.parse(["-dx"]) {|err| 1 }
1253
- ok {ret} == nil
1254
- end
1255
-
1256
- end
1257
-
1258
-
1259
- topic '#parse_long_option()' do
1260
-
1261
- before do
1262
- @parser = Benry::CmdOpt::Parser.new(new_sample_schema())
1263
- end
1264
-
1265
- spec "[!3i994] raises OptionError when invalid long option format." do
1266
- argv = ["--f/o/o"]
1267
- pr = proc { @parser.parse(argv) }
1268
- ok {pr}.raise?(Benry::CmdOpt::OptionError, "--f/o/o: Invalid long option.")
1269
- end
1270
-
1271
- spec "[!1ab42] invokes error handler method when unknown long option." do
1272
- def @parser.handle_unknown_long_option(optstr, name, val)
1273
- (@_called_ ||= []) << [optstr, name, val]
1274
- end
1275
- ret = @parser.parse(["--xx=XX", "--yy=YY", "--zz"])
1276
- ok {ret} == {}
1277
- ok {@parser.instance_variable_get('@_called_')} == [
1278
- ["--xx=XX", "xx", "XX"],
1279
- ["--yy=YY", "yy", "YY"],
1280
- ["--zz" , "zz", nil],
1281
- ]
1282
- end
1283
-
1284
- spec "[!er7h4] default behavior is to raise OptionError when unknown long option." do
1285
- argv = ["--foo"]
1286
- pr = proc { @parser.parse(argv) }
1287
- ok {pr}.raise?(Benry::CmdOpt::OptionError, "--foo: Unknown long option.")
1288
- end
1289
-
1290
- spec "[!2jd9w] raises OptionError when no arguments specified for arg required long option." do
1291
- argv = ["--file"]
1292
- pr = proc { @parser.parse(argv) }
1293
- ok {pr}.raise?(Benry::CmdOpt::OptionError, "--file: Argument required.")
1294
- end
1295
-
1296
- spec "[!qyq8n] raises optionError when an argument specified for no arg long option." do
1297
- argv = ["--version=1.0.0"]
1298
- pr = proc { @parser.parse(argv) }
1299
- ok {pr}.raise?(Benry::CmdOpt::OptionError, "--version=1.0.0: Unexpected argument.")
1300
- end
1301
-
1302
- spec "[!o596x] validates argument value." do
1303
- argv = ["--indent=abc"]
1304
- pr = proc { @parser.parse(argv) }
1305
- ok {pr}.raise?(Benry::CmdOpt::OptionError, "--indent=abc: Integer expected.")
1306
- #
1307
- argv = ["--path=/foo/bar"]
1308
- pr = proc { @parser.parse(argv) }
1309
- ok {pr}.raise?(Benry::CmdOpt::OptionError, "--path=/foo/bar: Directory not exist.")
1310
-
1311
- end
1312
-
1313
- end
1314
-
1315
-
1316
- topic '#parse_short_option()' do
1317
-
1318
- before do
1319
- @parser = Benry::CmdOpt::Parser.new(new_sample_schema())
1320
- end
1321
-
1322
- spec "[!4eh49] raises OptionError when unknown short option specified." do
1323
- argv = ["-hxf", "foo.png"]
1324
- pr = proc { @parser.parse(argv) }
1325
- ok {pr}.raise?(Benry::CmdOpt::OptionError, "-x: Unknown option.")
1326
- end
1327
-
1328
- spec "[!utdbf] raises OptionError when argument required but not specified." do
1329
- argv = ["-hf"]
1330
- pr = proc { @parser.parse(argv) }
1331
- ok {pr}.raise?(Benry::CmdOpt::OptionError, "-f: Argument required.")
1332
- end
1333
-
1334
- spec "[!f63hf] short option arg can be specified without space separator." do
1335
- argv = ["-hfabc.png", "xx"]
1336
- d = @parser.parse(argv)
1337
- ok {d} == {help: true, file: "abc.png"}
1338
- ok {argv} == ["xx"]
1339
- end
1340
-
1341
- spec "[!yjq6b] optional arg should be specified without space separator." do
1342
- argv = ["-hi123", "xx"]
1343
- d = @parser.parse(argv)
1344
- ok {d} == {help: true, indent: 123}
1345
- ok {argv} == ['xx']
1346
- end
1347
-
1348
- spec "[!wape4] otpional arg can be omit." do
1349
- argv = ["-hi", "xx"]
1350
- d = @parser.parse(argv)
1351
- ok {d} == {help: true, indent: true}
1352
- ok {argv} == ['xx']
1353
- end
1354
-
1355
- spec "[!yu0kc] validates short option argument." do
1356
- argv = ["-iaaa"]
1357
- pr = proc { @parser.parse(argv) }
1358
- ok {pr}.raise?(Benry::CmdOpt::OptionError, "-iaaa: Integer expected.")
1359
- #
1360
- argv = ["-I", "/foo/bar"]
1361
- pr = proc { @parser.parse(argv) }
1362
- ok {pr}.raise?(Benry::CmdOpt::OptionError, "-I /foo/bar: Directory not exist.")
1363
- end
1364
-
1365
- end
1366
-
1367
-
1368
- topic '#new_options_dict()' do
1369
-
1370
- spec "[!vm6h0] returns new hash object." do
1371
- parser = Benry::CmdOpt::Parser.new(new_sample_schema())
1372
- ret = parser.__send__(:new_options_dict)
1373
- ok {ret}.is_a?(Hash)
1374
- ok {ret} == {}
1375
- end
1376
-
1377
- end
1378
-
1379
-
1380
- topic '#handle_unknown_long_option()' do
1381
-
1382
- spec "[!0q78a] raises OptionError." do
1383
- parser = Benry::CmdOpt::Parser.new(new_sample_schema())
1384
- pr = proc {
1385
- parser.__send__(:handle_unknown_long_option, "--xx=XX", "xx", "XX")
1386
- }
1387
- ok {pr}.raise?(Benry::CmdOpt::OptionError, "--xx=XX: Unknown long option.")
1388
- end
1389
-
1390
- end
1391
-
1392
-
1393
- end
1394
-
1395
-
1396
-
1397
12
  topic Benry::CmdOpt do
1398
13
 
1399
14
 
@@ -1557,192 +172,4 @@ END
1557
172
  end
1558
173
 
1559
174
 
1560
-
1561
- topic Benry::CmdOpt::Facade do
1562
-
1563
-
1564
- topic '#add()' do
1565
-
1566
- spec "[!vmb3r] defines command option." do
1567
- cmdopt = Benry::CmdOpt.new()
1568
- cmdopt.add(:help, "-h, --help", "show help message", detail: "(text)", tag: :important)
1569
- items = cmdopt.instance_eval { @schema.instance_variable_get('@items') }
1570
- ok {items}.is_a?(Array)
1571
- ok {items.length} == 1
1572
- ok {items[0].key} == :help
1573
- ok {items[0].short} == 'h'
1574
- ok {items[0].long} == 'help'
1575
- ok {items[0].desc} == 'show help message'
1576
- ok {items[0].detail} == '(text)'
1577
- ok {items[0].tag} == :important
1578
- end
1579
-
1580
- spec "[!71cvg] type, rexp, enum, and range are can be passed as positional args as well as keyword args." do
1581
- cmdopt = Benry::CmdOpt.new()
1582
- cmdopt.add(:key, "--optdef[=xx]", "desc", Integer, /\A\d+\z/, [2,4,8], (2..8), value: 4)
1583
- items = cmdopt.instance_eval { @schema.instance_variable_get('@items') }
1584
- item = items.first
1585
- ok {item.type} == Integer
1586
- ok {item.rexp} == /\A\d+\z/
1587
- ok {item.enum} == [2,4,8]
1588
- ok {item.range} == (2..8)
1589
- ok {item.value} == 4
1590
- end
1591
-
1592
- spec "[!tu4k3] returns self." do
1593
- cmdopt = Benry::CmdOpt.new()
1594
- x = cmdopt.add(:version, "-v, --version", "version")
1595
- ok {x}.same?(cmdopt)
1596
- end
1597
-
1598
- end
1599
-
1600
-
1601
- topic '#option_help()' do
1602
-
1603
- before do
1604
- @cmdopt = Benry::CmdOpt.new
1605
- @cmdopt.add(:help , "-h, --help" , "show help message")
1606
- @cmdopt.add(:version, " --version" , "print version")
1607
- @cmdopt.add(:file , "-f, --file=<FILE>" , "filename")
1608
- end
1609
-
1610
- spec "[!dm4p8] returns option help message." do
1611
- helpmsg = @cmdopt.option_help()
1612
- ok {helpmsg} == <<END
1613
- -h, --help : show help message
1614
- --version : print version
1615
- -f, --file=<FILE> : filename
1616
- END
1617
- end
1618
-
1619
- end
1620
-
1621
-
1622
- topic '#to_s()' do
1623
-
1624
- spec "[!s61vo] '#to_s' is an alias to '#option_help()'." do
1625
- cmdopt = Benry::CmdOpt.new
1626
- cmdopt.add(:help , "-h, --help" , "show help message")
1627
- cmdopt.add(:version, " --version" , "print version")
1628
- ok {cmdopt.to_s} == cmdopt.option_help()
1629
- end
1630
-
1631
- end
1632
-
1633
-
1634
- topic '#each_option_and_desc()' do
1635
-
1636
- before do
1637
- @cmdopt = Benry::CmdOpt.new
1638
- @cmdopt.add(:help , "-h, --help" , "show help message")
1639
- @cmdopt.add(:version, " --version" , "print version")
1640
- @cmdopt.add(:debug , "-D" , nil) # hidden option
1641
- @cmdopt.add(:trace , "-T" , "trace", hidden: true) # hidden option
1642
- end
1643
-
1644
- spec "[!bw9qx] yields each option definition string and help message." do
1645
- pairs = []
1646
- @cmdopt.each_option_and_desc {|opt, desc| pairs << [opt, desc] }
1647
- ok {pairs} == [
1648
- ["-h, --help" , "show help message"],
1649
- [" --version", "print version"],
1650
- ]
1651
- end
1652
-
1653
- spec "[!kunfw] yields all items (including hidden items) if `all: true` specified." do
1654
- ## when 'all: true'
1655
- pairs = []
1656
- @cmdopt.each_option_and_desc(all: true) {|opt, desc| pairs << [opt, desc] }
1657
- ok {pairs} == [
1658
- ["-h, --help" , "show help message"],
1659
- [" --version", "print version"],
1660
- ["-D" , nil],
1661
- ["-T" , "trace"],
1662
- ]
1663
- ## when 'all: false'
1664
- pairs = []
1665
- @cmdopt.each_option_and_desc(all: false) {|opt, desc| pairs << [opt, desc] }
1666
- ok {pairs} == [
1667
- ["-h, --help" , "show help message"],
1668
- [" --version", "print version"],
1669
- ]
1670
- end
1671
-
1672
- spec "[!wght5] returns enumerator object if block not given." do
1673
- ## when 'all: true'
1674
- xs = @cmdopt.each_option_and_desc(all: true)
1675
- ok {xs}.is_a?(Enumerator)
1676
- ok {xs.collect {|x, _| x }} == ["-h, --help", " --version", "-D", "-T"]
1677
- ## when 'all: false'
1678
- xs = @cmdopt.each_option_and_desc(all: false)
1679
- ok {xs}.is_a?(Enumerator)
1680
- ok {xs.collect {|x, _| x }} == ["-h, --help", " --version"]
1681
- end
1682
-
1683
- end
1684
-
1685
-
1686
- topic '#parse()' do
1687
-
1688
- before do
1689
- @cmdopt = Benry::CmdOpt.new()
1690
- @cmdopt.add(:file, "-f, --file=<FILE>", "file") do |val|
1691
- File.open(val) {|f| f.read }
1692
- end
1693
- @cmdopt.add(:debug, "-d, --debug[=<LEVEL>]", "debug", type: Integer)
1694
- end
1695
-
1696
- spec "[!7gc2m] parses command options." do
1697
- args = ["-d", "x", "y"]
1698
- @cmdopt.parse(args)
1699
- ok {args} == ["x", "y"]
1700
- end
1701
-
1702
- spec "[!no4xu] returns option values as dict." do
1703
- args = ["-d", "x"]
1704
- ok {@cmdopt.parse(args)} == {:debug=>true}
1705
- end
1706
-
1707
- spec "[!areof] handles only OptionError when block given." do
1708
- errmsg = nil
1709
- errcls = nil
1710
- @cmdopt.parse(["-dx"]) {|err|
1711
- errmsg = err.message
1712
- errcls = err.class
1713
- }
1714
- ok {errmsg} == "-dx: Integer expected."
1715
- ok {errcls} == Benry::CmdOpt::OptionError
1716
- #
1717
- pr = proc do
1718
- @cmdopt.parse(["-f", "/foo/bar/baz.png"])
1719
- end
1720
- ok {pr}.raise?(Errno::ENOENT, /No such file or directory/)
1721
- end
1722
-
1723
- spec "[!peuva] returns nil when OptionError handled." do
1724
- ret = @cmdopt.parse(["-dx"]) {|err| 1 }
1725
- ok {ret} == nil
1726
- end
1727
-
1728
- spec "[!za9at] parses options only before args when `all: false`." do
1729
- argv = ["aaa", "-d3", "bbb"]
1730
- #
1731
- argv1 = argv.dup
1732
- opts1 = @cmdopt.parse(argv1)
1733
- ok {opts1} == {:debug=>3}
1734
- ok {argv1} == ["aaa", "bbb"]
1735
- #
1736
- argv2 = argv.dup
1737
- opts2 = @cmdopt.parse(argv2, all: false)
1738
- ok {opts2} == {}
1739
- ok {argv2} == ["aaa", "-d3", "bbb"]
1740
- end
1741
-
1742
- end
1743
-
1744
-
1745
- end
1746
-
1747
-
1748
175
  end