optconfig 0.4.4 → 0.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. data/lib/optconfig.rb +9 -14
  2. data/spec/optconfig_spec.rb +1006 -0
  3. metadata +38 -43
data/lib/optconfig.rb CHANGED
@@ -1,5 +1,5 @@
1
- # $Id$
2
- # Copyright (C) 2004-2009 TOMITA Masahiro
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2004-2011 TOMITA Masahiro
3
3
  # mailto:tommy@tmtm.org
4
4
  #
5
5
  # = OptConfig
@@ -13,16 +13,11 @@
13
13
  # * usage に使用する文字列を自動的に生成します。
14
14
  # * オプションの引数の形式を指定できます。
15
15
  #
16
- # == Download
17
- # * http://rubyforge.org/frs/?group_id=4777
18
- # * http://tmtm.org/downloads/ruby/optconfig/
19
- #
20
- # == Required
21
- # * StringValidator http://stringvalidator.rubyforge.org/
22
- #
23
16
  # == Install
24
- # $ make
25
- # # make install
17
+ # $ gem install optconfig
18
+ #
19
+ # == Repository
20
+ # https://github.com/tmtm/optconfig
26
21
  #
27
22
  # == Usage
28
23
  # require "optconfig"
@@ -149,7 +144,7 @@ class OptConfig
149
144
  @option_seq = []
150
145
  @options = {}
151
146
  @file = default_attr[:file]
152
- @section = default_attr[:section]
147
+ @section = default_attr[:section] && [default_attr[:section]].flatten
153
148
  @stop_at_non_option_argument = default_attr[:stop_at_non_option_argument]
154
149
  @ignore_unknown_file_option = default_attr.key?(:ignore_unknown_file_option) ? default_attr[:ignore_unknown_file_option] : true
155
150
  @obsolete_behavior = false
@@ -190,7 +185,7 @@ class OptConfig
190
185
  @option_seq.clear
191
186
  option.each do |k,v|
192
187
  v = [v] unless v.is_a? Array
193
- arg = k.to_a
188
+ arg = k.is_a?(Array) ? k : [k]
194
189
  arg.push({:format=>v[0], :default=>v[1]})
195
190
  opt = Option.new *arg
196
191
  opt.name.each do |n|
@@ -272,7 +267,7 @@ class OptConfig
272
267
  cur_sect = $1
273
268
  next
274
269
  end
275
- if @section.nil? or @section.empty? or @section.to_a.include? cur_sect
270
+ if @section.nil? or @section.empty? or @section.include? cur_sect
276
271
  name, value = line.split(/\s*=\s*|\s+/, 2)
277
272
  begin
278
273
  name, = long_option name, false
@@ -0,0 +1,1006 @@
1
+ # -*- coding: utf-8 -*-
2
+ require "tempfile"
3
+
4
+ require "#{File.dirname __FILE__}/../lib/optconfig"
5
+
6
+ describe '未知のオプション指定' do
7
+ it 'UnknownOption' do
8
+ opt = OptConfig.new
9
+ opt.option "s", "long"
10
+ proc{opt.parse(["-z"])}.should raise_error(OptConfig::UnknownOption, 'unknown option: z')
11
+ proc{opt.parse(["--hoge"])}.should raise_error(OptConfig::UnknownOption, 'unknown option: hoge')
12
+ end
13
+ end
14
+
15
+ describe '短いオプション名で :argument=>false の場合' do
16
+ before do
17
+ @opt = OptConfig.new
18
+ @opt.option "s", :argument=>false
19
+ @opt.option "x", :argument=>false
20
+ end
21
+ it 'オプション指定で true' do
22
+ @opt.parse(["-s"])
23
+ @opt["s"].should == true
24
+ end
25
+ it 'オプションの次の引数はただの引数' do
26
+ arg = ["-s", "hoge"]
27
+ @opt.parse! arg
28
+ @opt["s"].should == true
29
+ arg.should == ["hoge"]
30
+ end
31
+ it 'オプション名に続いて文字列がある場合は別のオプション' do
32
+ @opt.parse ["-sx"]
33
+ @opt["s"].should == true
34
+ @opt["x"].should == true
35
+ end
36
+ end
37
+
38
+ describe '長いオプション名で :argument=>false の場合' do
39
+ before do
40
+ @opt = OptConfig.new
41
+ @opt.option "long", :argument=>false
42
+ end
43
+ it 'オプション指定で true' do
44
+ @opt.parse(["--long"])
45
+ @opt["long"].should == true
46
+ end
47
+ it 'オプションの次の引数はただの引数' do
48
+ arg = ["--long", "hoge"]
49
+ @opt.parse! arg
50
+ @opt["long"].should == true
51
+ arg.should == ["hoge"]
52
+ end
53
+ it '「=」でオプション引数指定は UnnecessaryArgument' do
54
+ proc{@opt.parse(["--long=hoge"])}.should raise_error(OptConfig::UnnecessaryArgument)
55
+ end
56
+ end
57
+
58
+ describe '短いオプション名で :argument=>true の場合' do
59
+ before do
60
+ @opt = OptConfig.new
61
+ @opt.option "s", :argument=>true
62
+ @opt.option "x", :argument=>false
63
+ end
64
+ it '引数がない指定で ArgumentRequired' do
65
+ proc{@opt.parse ["-s"]}.should raise_error(OptConfig::ArgumentRequired, "argument required: s")
66
+ end
67
+ it 'オプションの次の引数がオプション引数' do
68
+ arg = ["-s", "hoge", "fuga"]
69
+ @opt.parse! arg
70
+ @opt["s"].should == "hoge"
71
+ arg.should == ["fuga"]
72
+ end
73
+ it 'オプション名に続いて文字列がある場合はオプション引数' do
74
+ arg = ["-shoge", "fuga"]
75
+ @opt.parse! arg
76
+ @opt["s"].should == "hoge"
77
+ arg.should == ["fuga"]
78
+ end
79
+ end
80
+
81
+ describe '長いオプション名で :argument=>true の場合' do
82
+ before do
83
+ @opt = OptConfig.new
84
+ @opt.option "long", :argument=>true
85
+ end
86
+ it '引数がない指定で ArgumentRequired' do
87
+ proc{@opt.parse ["--long"]}.should raise_error(OptConfig::ArgumentRequired, "argument required: long")
88
+ end
89
+ it 'オプションの次の引数がオプション引数' do
90
+ arg = ["--long", "hoge", "fuga"]
91
+ @opt.parse! arg
92
+ @opt["long"].should == "hoge"
93
+ arg.should == ["fuga"]
94
+ end
95
+ it '「=」でオプション引数指定可能' do
96
+ arg = ["--long=hoge", "fuga"]
97
+ @opt.parse! arg
98
+ @opt["long"].should == "hoge"
99
+ arg.should == ["fuga"]
100
+ end
101
+ end
102
+
103
+ describe '短いオプション名で :argument=>:optional の場合' do
104
+ before do
105
+ @opt = OptConfig.new
106
+ @opt.option "s", :argument=>:optional
107
+ end
108
+ it '次の引数がない指定で true' do
109
+ @opt.parse ["-s"]
110
+ @opt["s"].should == true
111
+ end
112
+ it 'オプションの次の引数が普通の引数' do
113
+ arg = ["-s", "hoge"]
114
+ @opt.parse! arg
115
+ @opt["s"].should == true
116
+ arg.should == ["hoge"]
117
+ end
118
+ it 'オプション名に続いて文字列がある場合はオプション引数' do
119
+ arg = ["-shoge", "fuga"]
120
+ @opt.parse! arg
121
+ @opt["s"].should == "hoge"
122
+ arg.should == ["fuga"]
123
+ end
124
+ end
125
+
126
+ describe '長いオプション名で :argument=>:optional の場合' do
127
+ before do
128
+ @opt = OptConfig.new
129
+ @opt.option "long", :argument=>:optional
130
+ end
131
+ it '次の引数がない指定で true' do
132
+ @opt.parse ["--long"]
133
+ @opt["long"].should == true
134
+ end
135
+ it 'オプションの次の引数が普通の引数' do
136
+ arg = ["--long", "hoge"]
137
+ @opt.parse! arg
138
+ @opt["long"].should == true
139
+ arg.should == ["hoge"]
140
+ end
141
+ it '「=」でオプション引数指定可能' do
142
+ arg = ["--long=hoge", "fuga"]
143
+ @opt.parse! arg
144
+ @opt["long"].should == "hoge"
145
+ arg.should == ["fuga"]
146
+ end
147
+ end
148
+
149
+ describe ':argument=>nil & :format=>nil の場合' do
150
+ before do
151
+ @opt = OptConfig.new
152
+ @opt.option "s", :argument=>nil, :format=>nil
153
+ @opt.option "long", :argument=>nil, :format=>nil
154
+ end
155
+ it 'オプション引数を取らない' do
156
+ proc{@opt.parse ["--long=hoge"]}.should raise_error(OptConfig::UnnecessaryArgument, 'option argument is unnecessary: long')
157
+ end
158
+ end
159
+
160
+ describe ':argument=>nil & :format=>false の場合' do
161
+ before do
162
+ @opt = OptConfig.new
163
+ @opt.option "s", :argument=>nil, :format=>false
164
+ @opt.option "long", :argument=>nil, :format=>false
165
+ end
166
+ it 'オプション引数を取らない' do
167
+ proc{@opt.parse ["--long=hoge"]}.should raise_error(OptConfig::UnnecessaryArgument, 'option argument is unnecessary: long')
168
+ end
169
+ end
170
+
171
+ describe ':argument=>nil & :format=>true の場合' do
172
+ before do
173
+ @opt = OptConfig.new
174
+ @opt.option "s", :argument=>nil, :format=>true
175
+ @opt.option "long", :argument=>nil, :format=>true
176
+ end
177
+ it 'オプション引数を取る' do
178
+ @opt.parse ["--long=hoge"]
179
+ @opt["long"].should == "hoge"
180
+ proc{@opt.parse ["--long"]}.should raise_error(OptConfig::ArgumentRequired, 'argument required: long')
181
+ @opt.parse ["-shoge"]
182
+ @opt["s"].should == "hoge"
183
+ end
184
+ end
185
+
186
+ describe '同じオプションに短い名前と長い名前の2つを設定した場合' do
187
+ before do
188
+ @opt = OptConfig.new
189
+ @opt.option "s", "long"
190
+ end
191
+ it 'どちらのオプション名も有効' do
192
+ @opt.parse(["-s"])
193
+ @opt["s"].should == true
194
+ @opt["long"].should == true
195
+ @opt.parse(["--long"])
196
+ @opt["s"].should == true
197
+ @opt["long"].should == true
198
+ end
199
+ end
200
+
201
+ describe '同じオプションに長い名前2つを設定した場合' do
202
+ before do
203
+ @opt = OptConfig.new
204
+ @opt.option "long1", "long2"
205
+ end
206
+ it 'どちらのオプション名も有効' do
207
+ @opt.parse(["--long1"])
208
+ @opt["long1"].should == true
209
+ @opt["long2"].should == true
210
+ @opt.parse(["--long2"])
211
+ @opt["long1"].should == true
212
+ @opt["long2"].should == true
213
+ end
214
+ end
215
+
216
+ describe '不正なオプション名を設定した場合' do
217
+ it 'RuntimeError が発生する' do
218
+ opt = OptConfig.new
219
+ proc{opt.option "-abc"}.should raise_error(RuntimeError, 'invalid option name: "-abc"')
220
+ end
221
+ end
222
+
223
+ describe ':format=>Integer を指定した場合' do
224
+ before do
225
+ @opt = OptConfig.new
226
+ @opt.option "s", :format=>Integer
227
+ end
228
+ it '数字の引数は正当' do
229
+ @opt.parse(["-s123"])
230
+ @opt["s"].should == 123
231
+ end
232
+ it '文字列引数はエラー' do
233
+ proc{@opt.parse(["-sabc"])}.should raise_error(OptConfig::InvalidArgument, 'invalid argument for option `s\': not integer: abc')
234
+ end
235
+ it '引数なしはエラー' do
236
+ proc{@opt.parse(["-s"])}.should raise_error(OptConfig::ArgumentRequired, 'argument required: s')
237
+ end
238
+ end
239
+
240
+ describe ':format=>:boolean を指定した場合' do
241
+ before do
242
+ @opt = OptConfig.new
243
+ @opt.option "s", :format=>:boolean
244
+ end
245
+ it '1, true, enable, yes, y, on が true になる' do
246
+ @opt.parse(["-s","1"])
247
+ @opt["s"].should == true
248
+ @opt.parse(["-s","true"])
249
+ @opt["s"].should == true
250
+ @opt.parse(["-s","enable"])
251
+ @opt["s"].should == true
252
+ @opt.parse(["-s","yes"])
253
+ @opt["s"].should == true
254
+ @opt.parse(["-s","y"])
255
+ @opt["s"].should == true
256
+ @opt.parse(["-s","on"])
257
+ @opt["s"].should == true
258
+ end
259
+ it '0, false, disable, no, n, off が false になる' do
260
+ @opt.parse(["-s","0"])
261
+ @opt["s"].should == false
262
+ @opt.parse(["-s","false"])
263
+ @opt["s"].should == false
264
+ @opt.parse(["-s","disable"])
265
+ @opt["s"].should == false
266
+ @opt.parse(["-s","no"])
267
+ @opt["s"].should == false
268
+ @opt.parse(["-s","n"])
269
+ @opt["s"].should == false
270
+ @opt.parse(["-s","off"])
271
+ @opt["s"].should == false
272
+ end
273
+ it '不正な値で InvalidArgument 例外になる' do
274
+ proc{@opt.parse(["-s", "x"])}.should raise_error(OptConfig::InvalidArgument, 'invalid boolean value: s')
275
+ end
276
+ end
277
+
278
+ describe ':format=>:boolean & :argument=>:optional の場合' do
279
+ before do
280
+ @opt = OptConfig.new
281
+ @opt.option "s", "long", :format=>:boolean, :argument=>:optional
282
+ end
283
+ it 'オプション引数なしで true になる' do
284
+ @opt.parse(["--long"])
285
+ @opt["long"].should == true
286
+ @opt.parse(["-s"])
287
+ @opt["long"].should == true
288
+ end
289
+ it '"--no-" prefix で false になる' do
290
+ @opt.parse(["--no-long"])
291
+ @opt["long"].should == false
292
+ end
293
+ it '1文字のオプションには "--no-" prefix はつけられない' do
294
+ proc{@opt.parse(["--no-s"])}.should raise_error(OptConfig::UnknownOption)
295
+ end
296
+ end
297
+
298
+ describe ':format=>:boolean & :argument=>false の場合' do
299
+ before do
300
+ @opt = OptConfig.new
301
+ @opt.option "s", "long", :format=>:boolean, :argument=>false
302
+ end
303
+ it 'オプション引数なしで true になる' do
304
+ @opt.parse(["--long"])
305
+ @opt["long"].should == true
306
+ @opt.parse(["-s"])
307
+ @opt["long"].should == true
308
+ end
309
+ it '"--no-" prefix で false になる' do
310
+ @opt.parse(["--no-long"])
311
+ @opt["long"].should == false
312
+ end
313
+ it '1文字のオプションには "--no-" prefix はつけられない' do
314
+ proc{@opt.parse(["--no-s"])}.should raise_error(OptConfig::UnknownOption)
315
+ end
316
+ end
317
+
318
+ describe ':format=>:boolean & argument=>true の場合' do
319
+ before do
320
+ @opt = OptConfig.new
321
+ @opt.option "s", "long", :format=>:boolean, :argument=>true
322
+ end
323
+ it '"--no-long=true" で false になる' do
324
+ @opt.parse(["--no-long=true"])
325
+ @opt["long"].should == false
326
+ @opt.parse(["--no-long", "true"])
327
+ @opt["long"].should == false
328
+ end
329
+ it '"--no-long=false" で true になる' do
330
+ @opt.parse(["--no-long=false"])
331
+ @opt["long"].should == true
332
+ @opt.parse(["--no-long", "false"])
333
+ @opt["long"].should == true
334
+ end
335
+ it '1文字のオプションには "--no-" prefix はつけられない' do
336
+ proc{@opt.parse(["--no-s"])}.should raise_error(OptConfig::UnknownOption, "unknown option: no-s")
337
+ end
338
+ end
339
+
340
+ describe ':default を設定した場合' do
341
+ before do
342
+ @opt = OptConfig.new
343
+ @opt.option "s", :format=>true, :default=>"abc"
344
+ end
345
+ it 'オプションを指定すると指定した値になる' do
346
+ @opt.parse(["-s123"])
347
+ @opt["s"].should == "123"
348
+ end
349
+ it 'オプションを指定しないとデフォルト値になる' do
350
+ @opt.parse()
351
+ @opt["s"].should == "abc"
352
+ end
353
+ end
354
+
355
+ describe ':default 値が指定されて、:format が文字列を返さない場合' do
356
+ before do
357
+ @opt = OptConfig.new
358
+ @hostport = proc do |s|
359
+ h, p = s.split ":", 2
360
+ h = StringValidator.validate /\A[a-z0-9.-]+\z/, h.to_s
361
+ p = StringValidator.validate 1..65535, p.to_s
362
+ [h, p]
363
+ end
364
+ end
365
+ it 'デフォルト値もパースされる' do
366
+ @opt.option "s", :format=>@hostport, :default=>"localhost:123"
367
+ @opt.parse
368
+ @opt["s"].should == ["localhost", 123]
369
+ end
370
+ it 'usage の %s は文字列のまま' do
371
+ @opt.option "s", :format=>@hostport, :default=>"localhost:123", :description=>"%s"
372
+ @opt.usage.should == " -s localhost:123\n"
373
+ @opt.parse(["-s", "hoge:80"])
374
+ @opt.usage.should == " -s hoge:80\n"
375
+ @opt["s"].should == ["hoge", 80]
376
+ end
377
+ it ':format に合わない :default はそのまま' do
378
+ @opt.option "s", :format=>@hostport, :default=>"123"
379
+ @opt.parse
380
+ @opt["s"].should == "123"
381
+ end
382
+ it 'String でない :default もそのまま' do
383
+ @opt.option "s", :format=>@hostport, :default=>123
384
+ @opt.parse
385
+ @opt["s"].should == 123
386
+ end
387
+ end
388
+
389
+ describe '未知のオプションの値を取り出そうとした場合' do
390
+ it 'UnknownOption 例外になる' do
391
+ opt = OptConfig.new
392
+ proc{opt["hoge"]}.should raise_error(OptConfig::UnknownOption, 'unknown option: hoge')
393
+ end
394
+ end
395
+
396
+ describe '長いオプションが途中まで指定された場合' do
397
+ before do
398
+ @opt = OptConfig.new
399
+ @opt.option "longhoge"
400
+ @opt.option "longfuga"
401
+ end
402
+ it '曖昧でなければ補完する' do
403
+ @opt.parse(["--longh"])
404
+ @opt["longhoge"].should == true
405
+ @opt["longfuga"].should == nil
406
+ end
407
+ it '曖昧であれば AmbiguousOption 例外になる' do
408
+ proc{@opt.parse(["--long"])}.should raise_error(OptConfig::AmbiguousOption, 'ambiguous option: long (candidate are longfuga, longhoge)')
409
+ end
410
+ it ':completion=>false 指定時は補完対象にならない' do
411
+ opt = OptConfig.new
412
+ opt.option "longhoge", :completion=>false
413
+ opt.option "longfuga"
414
+ opt.parse(["--long"])
415
+ opt["longfuga"].should == true
416
+ end
417
+ end
418
+
419
+ describe '説明がないオプションの #usage' do
420
+ it '出力されない' do
421
+ opt = OptConfig.new
422
+ opt.option "x"
423
+ opt.usage.should == ""
424
+ end
425
+ end
426
+
427
+ describe '説明が空文字列のオプションの #usage' do
428
+ it 'オプション名のみ出力される' do
429
+ opt = OptConfig.new
430
+ opt.option "x", :description=>""
431
+ opt.usage.should == " -x\n"
432
+ end
433
+ end
434
+
435
+ describe '短いオプションの #usage' do
436
+ it '出力される' do
437
+ opt = OptConfig.new
438
+ opt.option "x", :description=>"x option description"
439
+ opt.usage.should == <<EOS
440
+ -x x option description
441
+ EOS
442
+ end
443
+ end
444
+
445
+ describe '長いオプションの #usage' do
446
+ it '出力される' do
447
+ opt = OptConfig.new
448
+ opt.option "long", :description=>"long option description"
449
+ opt.usage.should == <<EOS
450
+ --long long option description
451
+ EOS
452
+ end
453
+ end
454
+
455
+ describe '=付きの長いオプションの #usage' do
456
+ it '出力される' do
457
+ opt = OptConfig.new
458
+ opt.option "long=hoge", :description=>"long option description"
459
+ opt.usage.should == <<EOS
460
+ --long=hoge long option description
461
+ EOS
462
+ end
463
+ end
464
+
465
+ describe '短いオプションと長いオプションの混在 #usage' do
466
+ it '出力される' do
467
+ opt = OptConfig.new
468
+ opt.option "x", :description=>"x option description"
469
+ opt.option "long", :description=>"long option description"
470
+ opt.usage.should == <<EOS
471
+ -x x option description
472
+ --long long option description
473
+ EOS
474
+ end
475
+ end
476
+
477
+ describe '短い名前と長い名前を持つオプションの #usage' do
478
+ it '同じ行に出力される' do
479
+ opt = OptConfig.new
480
+ opt.option "x", "long", :description=>"option description"
481
+ opt.usage.should == <<EOS
482
+ -x, --long option description
483
+ EOS
484
+ end
485
+ end
486
+
487
+ describe '説明が複数行のオプションの #usage' do
488
+ it '正しくインデントされる' do
489
+ opt = OptConfig.new
490
+ opt.option "long", :description=>"long option\nhogehoge\nfugafuga"
491
+ opt.usage.should == <<EOS
492
+ --long long option
493
+ hogehoge
494
+ fugafuga
495
+ EOS
496
+ end
497
+ end
498
+
499
+ describe 'オプション名が長い場合の #usage' do
500
+ it '説明が次の行に送られる' do
501
+ opt = OptConfig.new
502
+ opt.option "x"
503
+ opt.option "s", "longlonglonglonglonglong", :description=>"option description"
504
+ opt.usage.should == <<EOS
505
+ -s, --longlonglonglonglonglong
506
+ option description
507
+ EOS
508
+ end
509
+ end
510
+
511
+ describe 'オプション説明中に %s があった場合' do
512
+ before do
513
+ @opt = OptConfig.new
514
+ @opt.option "s", :format=>true, :default=>"123", :description=>"short option (%s)"
515
+ end
516
+ it '#usage で %s がデフォルト値に置換される' do
517
+ @opt.usage.should == " -s short option (123)\n"
518
+ end
519
+ it 'parse 後は、#usage でオプション値に置換される' do
520
+ @opt.parse ["-s", "abc"]
521
+ @opt.usage.should == " -s short option (abc)\n"
522
+ end
523
+ end
524
+
525
+ describe 'オプションじゃない引数の後にオプションが書かれた場合' do
526
+ before do
527
+ @opt = OptConfig.new
528
+ @opt.option "a"
529
+ end
530
+ it 'オプションとみなされる' do
531
+ arg = ["arg", "-a"]
532
+ @opt.parse! arg
533
+ arg.should == ["arg"]
534
+ @opt["a"].should == true
535
+ end
536
+ it '-- の後はオプションではない' do
537
+ arg = ["arg", "--", "-a"]
538
+ @opt.parse! arg
539
+ arg.should == ["arg", "-a"]
540
+ @opt["a"].should == nil
541
+ end
542
+ it ':stop_at_non_option_argument=>true の場合は通常の引数とみなす' do
543
+ opt = OptConfig.new :stop_at_non_option_argument=>true
544
+ opt.option "a"
545
+ arg = ["arg", "-a"]
546
+ opt.parse! arg
547
+ arg.should == ["arg", "-a"]
548
+ opt["a"].should == nil
549
+ end
550
+ end
551
+
552
+ describe OptConfig, '#parse の戻り値' do
553
+ before do
554
+ @opt = OptConfig.new
555
+ @opt.option "a"
556
+ @opt.option "b", :format=>true
557
+ end
558
+ it 'オプションを除いた引数が返る' do
559
+ @opt.parse(["-a", "arg"]).should == ["arg"]
560
+ @opt.parse(["a", "-a", "b"]).should == ["a", "b"]
561
+ @opt.parse(["-abc", "def"]).should == ["def"]
562
+ @opt.parse(["-a", "-b", "hoge", "fuga"]).should == ["fuga"]
563
+ end
564
+ it '-- を含まない' do
565
+ @opt.parse(["--", "-a", "arg"]).should == ["-a", "arg"]
566
+ end
567
+ end
568
+
569
+ describe 'オプションをファイルで指定した場合' do
570
+ before do
571
+ @opt = OptConfig.new
572
+ @opt.option "s", "long", :argument=>true
573
+ @opt.option "no-arg", :argument=>false
574
+ end
575
+ it 'オプションがファイルから読み込まれる' do
576
+ tmpf = Tempfile.new "optconfig"
577
+ tmpf.puts <<EOS
578
+ # コメント
579
+ long = hoge
580
+ EOS
581
+ tmpf.close
582
+ @opt.file = tmpf.path
583
+ @opt.parse
584
+ @opt["long"].should == "hoge"
585
+ end
586
+ it '長いオプション名だけ有効' do
587
+ tmpf = Tempfile.new "optconfig"
588
+ tmpf.puts <<EOS
589
+ # コメント
590
+ s = hoge
591
+ EOS
592
+ tmpf.close
593
+ @opt.file = tmpf.path
594
+ @opt.parse
595
+ @opt["long"].should == nil
596
+ end
597
+ it 'オプション名の補完なし' do
598
+ tmpf = Tempfile.new "optconfig"
599
+ tmpf.puts <<EOS
600
+ # コメント
601
+ lo = hoge
602
+ EOS
603
+ tmpf.close
604
+ @opt.file = tmpf.path
605
+ @opt.parse
606
+ @opt["long"].should == nil
607
+ end
608
+ it '引数を取らないオプションもOK' do
609
+ tmpf = Tempfile.new "optconfig"
610
+ tmpf.puts <<EOS
611
+ # コメント
612
+ no-arg
613
+ EOS
614
+ tmpf.close
615
+ @opt.file = tmpf.path
616
+ @opt.parse
617
+ @opt["no-arg"].should == true
618
+ end
619
+ end
620
+
621
+ describe 'section を指定' do
622
+ before do
623
+ @opt = OptConfig.new
624
+ @opt.option "s", "long", :argument=>true
625
+ @opt.option "a", "long2", :argument=>true
626
+ end
627
+ it '指定したIDのセクションのみ読み込まれる' do
628
+ tmpf = Tempfile.new "optconfig"
629
+ tmpf.puts <<EOS
630
+ [x]
631
+ long = hoge
632
+ [y]
633
+ long2 = fuga
634
+ EOS
635
+ tmpf.close
636
+ @opt.file = tmpf.path
637
+ @opt.section = ["y"]
638
+ @opt.parse
639
+ @opt["long"].should == nil
640
+ @opt["long2"].should == "fuga"
641
+ end
642
+ end
643
+
644
+ describe 'オプション名が --long=value 形式の場合' do
645
+ it '= の前までをオプション名とみなし、オプション引数ありとみなす' do
646
+ opt = OptConfig.new
647
+ opt.option "long=value"
648
+ opt.instance_variable_get(:@options)["long"].argument.should == true
649
+ end
650
+ end
651
+
652
+ describe 'オプション名が --long[=value] 形式の場合' do
653
+ it '= の前までをオプション名とみなし、オプション引数が省略可能とみなす' do
654
+ opt = OptConfig.new
655
+ opt.option "long[=value]"
656
+ opt.instance_variable_get(:@options)["long"].argument.should == :optional
657
+ end
658
+ end
659
+
660
+ describe 'OptConfig#parse!' do
661
+ it '引数の配列が書き換わる' do
662
+ @opt = OptConfig.new
663
+ @opt.option "s"
664
+ a = ["-s", "a"]
665
+ @opt.parse!(a)
666
+ a.should == ["a"]
667
+ end
668
+ end
669
+
670
+ describe 'OptConfig#parse' do
671
+ it '引数の配列が書き換わらない' do
672
+ @opt = OptConfig.new
673
+ @opt.option "s"
674
+ a = ["-s", "a"]
675
+ @opt.parse(a)
676
+ a.should == ["-s", "a"]
677
+ end
678
+ end
679
+
680
+ describe 'OptConfig#ignore_unknown_file_option が true の場合' do
681
+ it 'ファイル中に未知のオプションがあっても無視される' do
682
+ @opt = OptConfig.new
683
+ @opt.ignore_unknown_file_option = true
684
+ @opt.option "s", "long", :argument=>true
685
+ tmpf = Tempfile.new "optconfig"
686
+ tmpf.puts <<EOS
687
+ long = hoge
688
+ long2 = fuga
689
+ EOS
690
+ tmpf.close
691
+ @opt.file = tmpf.path
692
+ @opt.parse
693
+ @opt["long"].should == "hoge"
694
+ end
695
+ end
696
+
697
+ describe 'OptConfig#ignore_unknown_file_option が false の場合' do
698
+ it 'ファイル中に未知のオプションがあれば OptConfig::UnknownOption 例外になる' do
699
+ @opt = OptConfig.new
700
+ @opt.ignore_unknown_file_option = false
701
+ @opt.option "s", "long", :argument=>true
702
+ tmpf = Tempfile.new "optconfig"
703
+ tmpf.puts <<EOS
704
+ long = hoge
705
+ long2 = fuga
706
+ EOS
707
+ tmpf.close
708
+ @opt.file = tmpf.path
709
+ proc{@opt.parse}.should raise_error(OptConfig::UnknownOption, "unknown option: long2")
710
+ end
711
+ it '定義済みのオプションでも :in_config=>false であれば OptConfig::UnknownOption 例外になる' do
712
+ @opt = OptConfig.new
713
+ @opt.ignore_unknown_file_option = false
714
+ @opt.option "s", "long", :argument=>true, :in_config=>false
715
+ tmpf = Tempfile.new "optconfig"
716
+ tmpf.puts <<EOS
717
+ long = hoge
718
+ EOS
719
+ tmpf.close
720
+ @opt.file = tmpf.path
721
+ proc{@opt.parse}.should raise_error(OptConfig::UnknownOption, "unknown option: long")
722
+ end
723
+ end
724
+
725
+ describe 'オプションの二重定義' do
726
+ it 'RuntimeError になる' do
727
+ opt = OptConfig.new
728
+ proc{opt.option "s"; opt.option "s"}.should raise_error(RuntimeError, 'option s is already defined')
729
+ end
730
+ end
731
+
732
+ describe ':multiple 指定なし' do
733
+ it '同じオプションの複数指定時、最後のオプションが有効' do
734
+ opt = OptConfig.new
735
+ opt.option "s", :format=>true
736
+ opt.parse(["-s","123","-s","abc"])
737
+ opt["s"].should == "abc"
738
+ end
739
+ end
740
+
741
+ describe ':multiple=>:last を指定' do
742
+ it '同じオプションの複数指定時、最後のオプションが有効' do
743
+ opt = OptConfig.new
744
+ opt.option "s", :format=>true, :multiple=>:last
745
+ opt.parse(["-s","123","-s","abc"])
746
+ opt["s"].should == "abc"
747
+ end
748
+ end
749
+
750
+ describe ':multiple=>false を指定' do
751
+ it '同じオプションの複数指定でエラー' do
752
+ opt = OptConfig.new
753
+ opt.option "s", :format=>true, :multiple=>false
754
+ proc{opt.parse(["-s","123","-s","abc"])}.should raise_error(OptConfig::DuplicatedOption, "duplicated option: s")
755
+ end
756
+ it '異なる名前でも同じオプションであれば複数指定でエラー' do
757
+ opt = OptConfig.new
758
+ opt.option "s", "long", :format=>true, :multiple=>false
759
+ proc{opt.parse(["-s","123","--long","abc"])}.should raise_error(OptConfig::DuplicatedOption, "duplicated option: long")
760
+ end
761
+ end
762
+
763
+ describe ':multiple=>true を指定' do
764
+ it '同じオプションの複数指定で配列が返る' do
765
+ opt = OptConfig.new
766
+ opt.option "s", :format=>true, :multiple=>true
767
+ opt.parse(["-s","123","-s","abc"])
768
+ opt["s"].should == ["123","abc"]
769
+ end
770
+ end
771
+
772
+ describe ':argument=>true を指定' do
773
+ before do
774
+ @opt = OptConfig.new
775
+ @opt.option "s", "long", :argument=>true
776
+ end
777
+ it '長いオプション名: 「=」があれば、それ以降がオプション引数' do
778
+ @opt.parse(["--long=hoge"])
779
+ @opt["long"].should == "hoge"
780
+ end
781
+ it '短いオプション名: オプション名以降に文字列があれば、それがオプション引数' do
782
+ @opt.parse(["-shoge"])
783
+ @opt["s"].should == "hoge"
784
+ end
785
+ it '次の引数が「-」で始まっていても、オプション引数' do
786
+ @opt.parse(["--long", "--hoge"])
787
+ @opt["long"].should == "--hoge"
788
+ @opt.parse(["-s", "--hoge"])
789
+ @opt["s"].should == "--hoge"
790
+ end
791
+ end
792
+
793
+ describe ':argument=>false を指定' do
794
+ before do
795
+ @opt = OptConfig.new
796
+ @opt.option "s", "long", :argument=>false
797
+ end
798
+ it 'オプション引数が指定されたらエラー' do
799
+ proc{@opt.parse(["--long=hoge"])}.should raise_error(OptConfig::UnnecessaryArgument, "option argument is unnecessary: long")
800
+ end
801
+ it 'オプションの次の引数はオプション引数でない' do
802
+ arg = ["-s", "hoge"]
803
+ @opt.parse!(arg)
804
+ arg.should == ["hoge"]
805
+ arg = ["--long", "hoge"]
806
+ @opt.parse!(arg)
807
+ arg.should == ["hoge"]
808
+ end
809
+ end
810
+
811
+ describe ':argument=>:optional を指定' do
812
+ before do
813
+ @opt = OptConfig.new
814
+ @opt.option "s", "long", :format=>true, :argument=>:optional
815
+ @opt.option "hoge"
816
+ end
817
+ it '長いオプション名: 「=」があれば、それ以降がオプション引数' do
818
+ @opt.parse(["--long=hoge"])
819
+ @opt["long"].should == "hoge"
820
+ end
821
+ it '長いオプション名: 「=」がなければ、オプション引数なし' do
822
+ @opt.parse(["--long", "hoge"])
823
+ @opt["long"].should == true
824
+ end
825
+ it '短いオプション名: オプション名以降に文字列があれば、それがオプション引数' do
826
+ @opt.parse(["-shoge"])
827
+ @opt["s"].should == "hoge"
828
+ end
829
+ it '短いオプション名: オプション名以降に文字列がなければ、オプション引数なし' do
830
+ @opt.parse(["-s", "hoge"])
831
+ @opt["s"].should == true
832
+ end
833
+ end
834
+
835
+ describe ':underscore_is_hyphen=>true を指定' do
836
+ before do
837
+ @opt = OptConfig.new
838
+ @opt.option "long-opt", :format=>true, :underscore_is_hyphen=>true
839
+ end
840
+ it '--long-opt が --long_opt でも有効' do
841
+ @opt.parse(["--long_opt=hoge"])
842
+ @opt["long-opt"].should == "hoge"
843
+ end
844
+ it 'conf ファイル中の long_opt が有効' do
845
+ tmpf = Tempfile.new "optconfig"
846
+ tmpf.puts <<EOS
847
+ long_opt = hoge
848
+ EOS
849
+ tmpf.close
850
+ @opt.file = tmpf.path
851
+ @opt.parse
852
+ @opt["long-opt"].should == "hoge"
853
+ end
854
+ end
855
+
856
+ describe ':underscore_is_hyphen=>true で "--no-" prefix の場合' do
857
+ before do
858
+ @opt = OptConfig.new
859
+ @opt.option "long-opt", :format=>:boolean, :argument=>false, :underscore_is_hyphen=>true
860
+ end
861
+ it '--long_opt 指定で true' do
862
+ @opt.parse(["--long_opt"])
863
+ @opt["long-opt"].should == true
864
+ end
865
+ it '--no_long_opt 指定で false' do
866
+ @opt.parse(["--no_long_opt"])
867
+ @opt["long-opt"].should == false
868
+ end
869
+ end
870
+
871
+ describe ':in_config=>false を指定' do
872
+ before do
873
+ @opt = OptConfig.new
874
+ @opt.option "long", :format=>"hoge", :in_config=>false
875
+ end
876
+ it '引数に書けば有効' do
877
+ @opt.parse(["--long", "hoge"])
878
+ @opt["long"].should == "hoge"
879
+ end
880
+ it '設定ファイルに書いても無効' do
881
+ tmpf = Tempfile.new "optconfig"
882
+ tmpf.puts <<EOS
883
+ long = hoge
884
+ EOS
885
+ tmpf.close
886
+ @opt.file = tmpf.path
887
+ @opt.parse
888
+ @opt["long"].should be_nil
889
+ end
890
+ it '設定ファイル内で形式違反の値が指定されていても無視' do
891
+ tmpf = Tempfile.new "optconfig"
892
+ tmpf.puts <<EOS
893
+ long = fuga
894
+ EOS
895
+ tmpf.close
896
+ @opt.file = tmpf.path
897
+ @opt.parse
898
+ @opt["long"].should be_nil
899
+ end
900
+ end
901
+
902
+ describe 'OptConfig.new でデフォルト属性を指定' do
903
+ it 'オプションの属性に適用される' do
904
+ opt = OptConfig.new :argument=>:optional, :completion=>false
905
+ opt.option "s"
906
+ opt.instance_variable_get(:@options)["s"].argument.should == :optional
907
+ opt.instance_variable_get(:@options)["s"].completion.should == false
908
+ end
909
+ end
910
+
911
+ describe ':proc' do
912
+ before do
913
+ @opt = OptConfig.new
914
+ @cnt = 0
915
+ block = proc do |name, opt, arg|
916
+ @cnt += 1
917
+ name.should == "p"
918
+ arg.should == "hoge"
919
+ "fuga"
920
+ end
921
+ @opt.option "p", "proc", :format=>"hoge", :proc=>block
922
+ end
923
+ it 'オプション毎に実行される' do
924
+ @opt.parse(["-p", "hoge", "-p", "hoge"])
925
+ @cnt.should == 2
926
+ end
927
+ it 'ブロックの結果が OptConfig#[] の戻り値になる' do
928
+ @opt.parse(["-p", "hoge"])
929
+ @opt["proc"].should == "fuga"
930
+ end
931
+ it 'オプション引数の正当性確認後に実行される' do
932
+ proc{@opt.parse(["-p", "fuga"])}.should raise_error(OptConfig::InvalidArgument, "invalid argument for option `p': invalid value: fuga")
933
+ @cnt.should == 0
934
+ end
935
+ end
936
+
937
+ describe ':pre_proc' do
938
+ before do
939
+ @opt = OptConfig.new
940
+ @cnt = 0
941
+ block = proc do |name, opt, arg|
942
+ @cnt += 1
943
+ name.should == "p"
944
+ arg == "fuga" ? "hoge" : arg
945
+ end
946
+ @opt.option "p", "proc", :format=>"hoge", :pre_proc=>block
947
+ end
948
+ it 'オプション毎に実行される' do
949
+ @opt.parse(["-p", "hoge", "-p", "hoge"])
950
+ @cnt.should == 2
951
+ end
952
+ it 'ブロックの結果をオプション引数とする' do
953
+ @opt.parse(["-p", "fuga"])
954
+ @opt["p"].should == "hoge"
955
+ end
956
+ it 'オプション引数の正当性確認前に実行される' do
957
+ proc{@opt.parse(["-p", "xxx"])}.should raise_error(OptConfig::InvalidArgument, "invalid argument for option `p': invalid value: xxx")
958
+ @cnt.should == 1
959
+ end
960
+ end
961
+
962
+ describe 'options= でオプション設定' do
963
+ before do
964
+ @opt = OptConfig.new
965
+ @opt.options = {
966
+ "a" => nil,
967
+ "b" => false,
968
+ "c" => true,
969
+ "long" => true,
970
+ "long2" => [true, "abc"],
971
+ "long3" => /abc/,
972
+ ["d", "long4"] => true,
973
+ }
974
+ end
975
+ it 'nil の場合は引数なし' do
976
+ @opt.parse(["-a", "a"]).should == 1
977
+ @opt["a"].should == true
978
+ end
979
+ it 'false の場合は引数なし' do
980
+ @opt.parse(["-b", "a"]).should == 1
981
+ @opt["b"].should == true
982
+ end
983
+ it 'true の場合は引数あり' do
984
+ @opt.parse(["-c", "a"]).should == 2
985
+ @opt["c"].should == "a"
986
+ end
987
+ it '長いオプション名も使用可能' do
988
+ @opt.parse(["--long", "a"]).should == 2
989
+ @opt["long"].should == "a"
990
+ end
991
+ it 'オプションが指定されなくても引数のデフォルト値が有効' do
992
+ @opt.parse(["a"]).should == 0
993
+ @opt["long2"].should == "abc"
994
+ end
995
+ it '引数の形式を指定可能' do
996
+ @opt.parse(["--long3", "bcabcab"]).should == 2
997
+ @opt["long3"].should == "bcabcab"
998
+ end
999
+ it '引数の形式に合わなければエラー' do
1000
+ proc{@opt.parse(["--long3", "hogehoge"])}.should raise_error(OptConfig::InvalidArgument, "invalid argument for option `long3': regexp mismatch: hogehoge")
1001
+ end
1002
+ it '同じオプションに短い名前と長い名前を指定可能' do
1003
+ @opt.parse(["-d", "a"]).should == 2
1004
+ @opt["long4"].should == "a"
1005
+ end
1006
+ end
metadata CHANGED
@@ -1,64 +1,59 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: optconfig
3
- version: !ruby/object:Gem::Version
4
- version: 0.4.4
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.5
5
+ prerelease:
5
6
  platform: ruby
6
- authors:
7
+ authors:
7
8
  - Tomita Masahiro
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
-
12
- date: 2009-09-28 00:00:00 +09:00
13
- default_executable:
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
12
+ date: 2011-12-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
16
15
  name: stringvalidator
16
+ requirement: &78858330 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
17
22
  type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
20
- requirements:
21
- - - ">="
22
- - !ruby/object:Gem::Version
23
- version: "0"
24
- version:
23
+ prerelease: false
24
+ version_requirements: *78858330
25
25
  description: OptConfig is a parser of command line option
26
26
  email: tommy@tmtm.org
27
27
  executables: []
28
-
29
28
  extensions: []
30
-
31
29
  extra_rdoc_files: []
32
-
33
- files:
30
+ files:
34
31
  - lib/optconfig.rb
35
- has_rdoc: true
32
+ - spec/optconfig_spec.rb
36
33
  homepage: http://github.com/tmtm/optconfig
37
- licenses: []
38
-
34
+ licenses:
35
+ - Ruby's
39
36
  post_install_message:
40
- rdoc_options:
41
- - --charset=utf-8
42
- require_paths:
37
+ rdoc_options: []
38
+ require_paths:
43
39
  - lib
44
- required_ruby_version: !ruby/object:Gem::Requirement
45
- requirements:
46
- - - ">="
47
- - !ruby/object:Gem::Version
48
- version: "0"
49
- version:
50
- required_rubygems_version: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: "0"
55
- version:
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ required_rubygems_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
56
52
  requirements: []
57
-
58
- rubyforge_project: optconfig
59
- rubygems_version: 1.3.4
53
+ rubyforge_project:
54
+ rubygems_version: 1.8.11
60
55
  signing_key:
61
56
  specification_version: 3
62
57
  summary: OptConfig is a parser of command line option
63
- test_files: []
64
-
58
+ test_files:
59
+ - spec/optconfig_spec.rb