benry-cmdopt 2.3.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
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