optconfig 0.4.4 → 0.4.5

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