optout 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/README.rdoc +31 -8
  2. data/lib/optout.rb +238 -62
  3. data/spec/optout_spec.rb +369 -217
  4. metadata +9 -9
@@ -1,155 +1,225 @@
1
- require "optout"
2
- require "tempfile"
3
- require "fileutils"
4
- require "rbconfig"
5
-
6
- def create_optout(options = {})
7
- Optout.options(options) do
8
- on :x, "-x"
9
- on :y, "-y"
10
- end
11
- end
1
+ require "spec_helper"
12
2
 
13
- def optout_option(*options)
14
- Optout.options { on :x, "-x", *options }
15
- end
16
-
17
- class Optout
18
- class Option
19
- def unix?
20
- true
3
+ shared_examples_for "a validator" do
4
+ context "when the option is nil" do
5
+ it "should not be validated" do
6
+ lambda { subject.argv(:x => nil) }.should_not raise_exception
21
7
  end
22
8
  end
23
9
  end
24
10
 
25
11
  shared_examples_for "something that validates files" do
26
- before(:all) { @tmpdir = Dir.mktmpdir }
27
- after(:all) { FileUtils.rm_rf(@tmpdir) }
28
-
29
- def options
30
- { :x => @file }
31
- end
32
-
33
- it "should not raise an exception if a file does not exist but its directory does" do
34
- file = File.join(@tmpdir, "__bad__")
35
- optout = optout_option(@validator)
36
- proc { optout.argv(:x => file) }.should_not raise_exception
12
+ context "when the file does not exist but its directory does" do
13
+ it "should not raise an exception" do
14
+ no_file = File.join(File.dirname(file), "does_not_exist")
15
+ optout = optout_option(described_class)
16
+ lambda { optout.argv(:x => no_file) }.should_not raise_exception
17
+ end
37
18
  end
38
19
 
39
- describe "permissions" do
40
- # Only some chmod() modes work on Win
41
- if RbConfig::CONFIG["host_os"] !~ /mswin|mingw/i
42
- it "should raise an exception when user permissions don't match" do
43
- FileUtils.chmod(0100, @file)
44
- optout = optout_option(@validator.permissions("r"))
45
- proc { optout.argv(options) }.should raise_exception(Optout::OptionInvalid, /user permission/)
46
- end
47
-
48
- it "should not raise an exception when user permissions match" do
49
- checker = proc do |validator|
50
- proc { optout_option(validator).argv(options) }.should_not raise_exception
51
- end
52
-
53
- FileUtils.chmod(0100, @file)
54
- checker.call(@validator.permissions("x"))
55
-
56
- FileUtils.chmod(0200, @file)
57
- checker.call(@validator.permissions("w"))
58
-
59
- FileUtils.chmod(0400, @file)
60
- checker.call(@validator.permissions("r"))
61
-
62
- FileUtils.chmod(0700, @file)
63
- checker.call(@validator.permissions("rwx"))
20
+ # Only some chmod() modes work on Win
21
+ describe "#permissions", :skip_on_windows => true do
22
+ context "when the specified user permissions aren't set" do
23
+ it "should raise an OptionInvalid exception" do
24
+ FileUtils.chmod(0100, file)
25
+ optout = optout_option(described_class.permissions("r"))
26
+ lambda { optout.argv(options) }.should raise_exception(Optout::OptionInvalid, /user permission/)
64
27
  end
65
28
  end
66
- end
67
29
 
68
- describe "exists" do
69
- it "should raise an exception if the file does not exist" do
70
- optout = optout_option(@validator.exists)
71
- proc { optout.argv(:x => @file + "no_file") }.should raise_exception(Optout::OptionInvalid, /does not exist/)
72
- proc { optout.argv(options) }.should_not raise_exception
73
- end
74
- end
30
+ def chmod_and_check(mode, validator)
31
+ FileUtils.chmod(mode, file)
32
+ lambda { optout_option(validator).argv(options) }.should_not raise_exception
33
+ end
75
34
 
76
- describe "under a directory" do
77
- it "should raise an exception if not under the given directory" do
78
- optout = optout_option(@validator.under(File.join("wrong", "path")))
79
- proc { optout.argv(options) }.should raise_exception(Optout::OptionInvalid, /must be under/)
80
-
81
- optout = optout_option(@validator.under(@tmpdir))
82
- proc { optout.argv(options) }.should_not raise_exception
35
+ context "when user read is set" do
36
+ it "should not raise an exception" do
37
+ chmod_and_check(0400, described_class.permissions("r"))
38
+ end
83
39
  end
84
-
85
- it "should raise an exception if the parent directory does not match the given pattern" do
86
- # We need to respect the @file's type to ensure other validation rules implicitly applied by the @validator pass.
87
- # First create parent dirs to validate against
88
- tmp = File.join(@tmpdir, "a1", "b1")
89
- FileUtils.mkdir_p(tmp)
90
40
 
91
- # Then copy the target of the validation (file or directory) under the parent dir.
92
- FileUtils.cp_r(@file, tmp)
41
+ context "when user write is set" do
42
+ it "should not raise an exception" do
43
+ chmod_and_check(0200, described_class.permissions("w"))
44
+ end
45
+ end
93
46
 
94
- # And create the option's value
95
- tmp = File.join(tmp, File.basename(@file))
96
- options = { :x => tmp }
47
+ context "when user execute is set" do
48
+ it "should not raise an exception" do
49
+ chmod_and_check(0100, described_class.permissions("x"))
50
+ end
51
+ end
97
52
 
98
- optout = optout_option(@validator.under(/X$/))
99
- proc { optout.argv(options) }.should raise_exception(Optout::OptionInvalid, /must be under/)
53
+ context "when all permissions are set" do
54
+ it "should not raise an exception" do
55
+ chmod_and_check(0700, described_class.permissions("rwx"))
56
+ end
57
+ end
58
+ end
100
59
 
101
- [ %r|(/[a-z]\d){2}|, %r|[a-z]\d$| ].each do |r|
102
- optout = optout_option(@validator.under(r))
103
- proc { optout.argv(options) }.should_not raise_exception
60
+ describe "#exists" do
61
+ subject { optout_option(described_class.exists) }
62
+
63
+ context "when the file exists" do
64
+ it "does not raise an exception" do
65
+ lambda { subject.argv(options) }.should_not raise_exception
66
+ end
67
+ end
68
+
69
+ context "when the file does not exist" do
70
+ it "raises an OptionInvalid exception" do
71
+ lambda { subject.argv(:x => file + "no_file") }.should raise_exception(Optout::OptionInvalid, /does not exist/)
104
72
  end
105
73
  end
106
74
  end
107
75
 
108
- describe "basename" do
109
- it "should raise an exception if it does not equal the given value" do
110
- optout = optout_option(@validator.named("__bad__"))
111
- proc { optout.argv(options) }.should raise_exception(Optout::OptionInvalid, /name must match/)
112
-
113
- optout = optout_option(@validator.named(File.basename(@file)))
114
- proc { optout.argv(options) }.should_not raise_exception
76
+ describe "#under" do
77
+ context "when not under the given directory" do
78
+ it "should raise an OptionInvalid exception" do
79
+ optout = optout_option(described_class.under(File.join("wrong", "path")))
80
+ lambda { optout.argv(options) }.should raise_exception(Optout::OptionInvalid, /must be under/)
81
+ end
82
+ end
83
+
84
+ context "when under the given directory" do
85
+ it "should not raise an exception" do
86
+ optout = optout_option(described_class.under(File.dirname(file)))
87
+ lambda { optout.argv(options) }.should_not raise_exception
88
+ end
89
+ end
90
+
91
+ context "when the parent directory does not match the given regex" do
92
+ it "should raise an OptionInvalid exception" do
93
+ optout = optout_option(described_class.under(/_{20},#{Time.now.to_i}$/))
94
+ lambda { optout.argv(options) }.should raise_exception(Optout::OptionInvalid, /must be under/)
95
+ end
96
+ end
97
+
98
+ context "when the parent directory matches the given regex" do
99
+ it "should not raise an exception" do
100
+ ends_with = File.dirname(file)[-1,1]
101
+ optout = optout_option(described_class.under(/#{Regexp.quote(ends_with)}$/))
102
+ lambda { optout.argv(options) }.should_not raise_exception
103
+ end
104
+ end
105
+ end
106
+
107
+ describe "#named" do
108
+ context "when the basename matches the regex" do
109
+ it "should not raise an exception" do
110
+ ends_with = File.basename(subject)[-1,1]
111
+ optout = optout_option(described_class.named(/#{Regexp.quote(ends_with)}$/))
112
+ lambda { optout.argv(options) }.should_not raise_exception
113
+ end
114
+ end
115
+
116
+ context "when the basename does not match the regex" do
117
+ it "should raise an OptionInvalid exception" do
118
+ optout = optout_option(described_class.named(/\A#{Time.now.to_i}/))
119
+ lambda { optout.argv(options) }.should raise_exception(Optout::OptionInvalid, /name must match/)
120
+ end
115
121
  end
116
122
 
117
- it "should raise an exception if it does not match the given pattern" do
118
- optout = optout_option(@validator.named(/\A-_-_-_/))
119
- proc { optout.argv(options) }.should raise_exception(Optout::OptionInvalid, /name must match/)
123
+ context "when the basename is not equal" do
124
+ it "should raise an OptionInvalid exception" do
125
+ optout = optout_option(described_class.named(Time.now.to_s))
126
+ lambda { optout.argv(options) }.should raise_exception(Optout::OptionInvalid, /name must match/)
127
+ end
128
+ end
120
129
 
121
- ends_with = File.basename(@file)[/.{2}\z/]
122
- optout = optout_option(@validator.named(/#{Regexp.quote(ends_with)}\z/))
123
- proc { optout.argv(options) }.should_not raise_exception
130
+ context "when the basename is equal" do
131
+ it "should not raise an exception" do
132
+ optout = optout_option(described_class.named(File.basename(file)))
133
+ lambda { optout.argv(options) }.should_not raise_exception
134
+ end
124
135
  end
125
136
  end
126
137
  end
127
138
 
128
139
  describe Optout do
129
- describe "defining options" do
140
+ describe "#on" do
130
141
  before(:each) { @optout = Optout.new }
131
142
 
132
- it "should require the option's key" do
133
- proc { @optout.on }.should raise_exception(ArgumentError, /option key required/)
134
- proc { Optout.options { on } }.should raise_exception(ArgumentError, /option key required/)
143
+ it "requires the option's key" do
144
+ lambda { @optout.on }.should raise_exception(ArgumentError, /option key required/)
135
145
  end
136
-
146
+
137
147
  it "should not allow an option to be defined twice" do
138
148
  @optout.on :x
139
- proc { @optout.on :x }.should raise_exception(ArgumentError, /already defined/)
140
- proc do
141
- Optout.options do
142
- on :x
143
- on :x
149
+ [:x, "x"].each do |opt|
150
+ lambda { @optout.on opt }.should raise_exception(ArgumentError, /already defined/)
151
+ end
152
+ end
153
+
154
+ describe "the :required option" do
155
+ context "when true" do
156
+ subject { optout_option(:required => true) }
157
+
158
+ it "should raise an OptionRequired exception if the option is missing" do
159
+ lambda { subject.argv }.should raise_exception(Optout::OptionRequired, /'x'/)
160
+ lambda { subject.argv(:x => nil) }.should raise_exception(Optout::OptionRequired, /'x'/)
161
+ end
162
+
163
+ it "should not raise an exception if the option is not missing" do
164
+ lambda { subject.argv(:x => "x") }.should_not raise_exception
165
+ end
166
+ end
167
+
168
+ context "when false" do
169
+ it "should not raise an exception if the option is missing" do
170
+ optout = optout_option(:required => false)
171
+ lambda { optout.argv }.should_not raise_exception
172
+ end
173
+ end
174
+ end
175
+
176
+ describe "the :multiple option" do
177
+ let(:collection) do
178
+ [ :x => %w|a b|,
179
+ :x => { :a => "a", :b => "b" } ]
180
+ end
181
+
182
+ context "when false" do
183
+ subject { optout_option(:multiple => false) }
184
+
185
+ it "should raise an OptionInvalid exception if an option contains multiple values" do
186
+ collection.each do |options|
187
+ lambda { subject.argv(options) }.should raise_exception(Optout::OptionInvalid, /multiple values/)
188
+ end
189
+ end
190
+
191
+ it "should not raise an exception if an option contains a collection with only 1 element" do
192
+ [ :x => %w|a|,
193
+ :x => { :a => "a" } ].each do |options|
194
+ lambda { subject.argv(options) }.should_not raise_exception
195
+ end
196
+ end
197
+
198
+ it "should not raise an exception if an option contains a single value" do
199
+ lambda { subject.argv(:x => "x") }.should_not raise_exception
144
200
  end
145
- end.should raise_exception(ArgumentError, /already defined/)
201
+ end
202
+
203
+ context "when true" do
204
+ subject { optout_option(:multiple => true) }
205
+
206
+ it "should not raise an OptionInvalid exception if an option contains multiple values" do
207
+ collection.each do |options|
208
+ lambda { subject.argv(options) }.should_not raise_exception
209
+ end
210
+ end
211
+
212
+ it "should not raise an OptionInvalid exception if an option contains a single value" do
213
+ lambda { subject.argv(:x => "x") }.should_not raise_exception
214
+ end
215
+ end
146
216
  end
147
217
  end
148
218
 
149
219
  describe "creating options" do
150
220
  before(:each) { @optout = create_optout }
151
221
 
152
- context "as a string" do
222
+ context "as a string" do
153
223
  it "should only output the option's value if there's no switch" do
154
224
  optout = Optout.options { on :x }
155
225
  optout.shell(:x => "x").should eql("'x'")
@@ -159,45 +229,53 @@ describe Optout do
159
229
  @optout.shell({}).should be_empty
160
230
  end
161
231
 
162
- it "should only output the option's switch if its value if true" do
232
+ it "should raise an ArgumentError if the options are not a Hash" do
233
+ lambda { @optout.shell("optionz") }.should raise_exception(ArgumentError)
234
+ end
235
+
236
+ it "should only output the option's switch if its value if true" do
163
237
  @optout.shell(:x => true, :y => true).should eql("-x -y")
164
238
  end
165
239
 
166
- it "should not output the option if its value is false" do
240
+ it "should not output the option if its value is false" do
167
241
  @optout.shell(:x => false, :y => true).should eql("-y")
168
242
  end
169
243
 
170
- it "should only output the options that have a value" do
244
+ it "should only output the options that have a value" do
171
245
  @optout.shell(:x => "x", :y => nil).should eql("-x 'x'")
172
246
  end
173
-
174
- it "should output all of the options" do
247
+
248
+ it "should output all of the options" do
175
249
  @optout.shell(:x => "x", :y => "y").should eql("-x 'x' -y 'y'")
176
250
  end
177
251
 
178
- it "should escape the single quote char" do
252
+ it "should escape the single quote char" do
179
253
  @optout.shell(:x => "' a'b'c '").should eql(%q|-x ''\'' a'\''b'\''c '\'''|)
180
254
  end
181
255
 
182
- it "should not separate switches from their value" do
256
+ it "should not separate switches from their value" do
183
257
  optout = create_optout(:arg_separator => "")
184
258
  optout.shell(:x => "x", :y => "y").should eql("-x'x' -y'y'")
185
259
  end
186
-
260
+
187
261
  it "should seperate all switches from their value with a '='" do
188
262
  optout = create_optout(:arg_separator => "=")
189
263
  optout.shell(:x => "x", :y => "y").should eql("-x='x' -y='y'")
190
- end
264
+ end
191
265
 
192
- it "should join all options with multiple values on a delimiter" do
266
+ it "should join all options with multiple values on a delimiter" do
193
267
  optout = create_optout(:multiple => true)
194
268
  optout.shell(:x => %w|a b c|, :y => "y").should eql("-x 'a,b,c' -y 'y'")
195
269
  end
196
270
 
197
- it "should join all options with multiple values on a ':'" do
271
+ it "should join all options with multiple values on a ':'" do
198
272
  optout = create_optout(:multiple => ":")
199
273
  optout.shell(:x => %w|a b c|, :y => "y").should eql("-x 'a:b:c' -y 'y'")
200
- end
274
+ end
275
+
276
+ it "should not differentiate between a String key and a Symbol key" do
277
+ @optout.shell("x" => "x").should eql(@optout.shell(:x => "x"))
278
+ end
201
279
  end
202
280
 
203
281
  context "as an array" do
@@ -206,6 +284,10 @@ describe Optout do
206
284
  optout.argv(:x => "x").should eql(["x"])
207
285
  end
208
286
 
287
+ it "should raise an ArgumentError if the options are not a Hash" do
288
+ lambda { @optout.argv("optionz") }.should raise_exception(ArgumentError)
289
+ end
290
+
209
291
  it "should output an empty array if the option hash is empty" do
210
292
  @optout.argv({}).should be_empty
211
293
  end
@@ -218,7 +300,7 @@ describe Optout do
218
300
  @optout.argv(:x => false, :y => true).should eql(["-y"])
219
301
  end
220
302
 
221
- it "should only output the options that have a value" do
303
+ it "should only output the options that have a value" do
222
304
  @optout.argv(:x => "x", :y => nil).should eql(["-x", "x"])
223
305
  end
224
306
 
@@ -226,155 +308,225 @@ describe Optout do
226
308
  @optout.argv(:x => "x", :y => "y").should eql(["-x", "x", "-y", "y"])
227
309
  end
228
310
 
229
- it "should not escape the single quote char" do
311
+ it "should not escape the single quote char" do
230
312
  @optout.argv(:x => "' a'b'c '").should eql(["-x", "' a'b'c '"])
231
313
  end
232
314
 
233
- it "should not separate switches from their value" do
315
+ it "should not separate switches from their value" do
234
316
  optout = create_optout(:arg_separator => "")
235
317
  optout.argv(:x => "x", :y => "y").should eql(["-xx", "-yy"])
236
318
  end
237
319
 
238
320
  it "should seperate all of switches from their value with a '='" do
239
- optout = create_optout(:arg_separator => "=")
321
+ optout = create_optout(:arg_separator => "=")
240
322
  optout.argv(:x => "x", :y => "y").should eql(["-x=x", "-y=y"])
241
323
  end
242
324
 
243
- it "should join all options with multiple values on a delimiter" do
325
+ it "should join all options with multiple values on a delimiter" do
244
326
  optout = create_optout(:multiple => true)
245
327
  optout.argv(:x => %w|a b c|, :y => "y").should eql(["-x", "a,b,c", "-y", "y"])
246
328
  end
247
329
 
248
- it "should join all options with multiple values on a ':'" do
330
+ it "should join all options with multiple values on a ':'" do
249
331
  optout = create_optout(:multiple => ":")
250
332
  optout.argv(:x => %w|a b c|, :y => "y").should eql(["-x", "a:b:c", "-y", "y"])
251
- end
333
+ end
334
+
335
+ it "should not differentiate between a String key and a Symbol key" do
336
+ @optout.argv("x" => "x").should eql(@optout.argv(:x => "x"))
337
+ end
252
338
  end
253
339
  end
254
340
 
255
341
  # TODO: Check exception.key
256
- describe "validation rules" do
257
- it "should raise an exception if the option hash contains an unknown key" do
258
- optout = create_optout
259
- proc { optout.argv(:bad => 123) }.should raise_exception(Optout::OptionUnknown)
260
- end
261
-
262
- it "should not raise an exception if the option hash contains an unknown key" do
263
- optout = create_optout(:check_keys => false)
264
- proc { optout.argv(:bad => 123) }.should_not raise_exception
265
- end
342
+ describe "validation rules" do
343
+ describe "the :check_keys option" do
344
+ context "when true" do
345
+ it "raises an exception if the option hash contains an unknown key" do
346
+ optout = create_optout
347
+ lambda { optout.argv(:bad => 123) }.should raise_exception(Optout::OptionUnknown, /bad/)
348
+ end
349
+ end
266
350
 
267
- it "should raise an exception if an option is missing" do
268
- optout = create_optout(:required => true)
269
- proc { optout.argv(:x => 123) }.should raise_exception(Optout::OptionRequired, /'y'/)
351
+ context "when false" do
352
+ it "does not raise an exception if the option hash contains an unknown key" do
353
+ optout = create_optout(:check_keys => false)
354
+ lambda { optout.argv(:bad => 123) }.should_not raise_exception
355
+ end
356
+ end
270
357
  end
271
358
 
272
- it "should raise an exception if a required option is missing" do
273
- optout = Optout.options do
274
- on :x
275
- on :y, :required => true
359
+ describe "type checking" do
360
+ it_should_behave_like "a validator"
361
+ subject { optout_option(Float) }
362
+
363
+ context "when the type is correct" do
364
+ it "should not raise an exception" do
365
+ lambda { subject.argv(:x => 123.0) }.should_not raise_exception
366
+ end
276
367
  end
277
-
278
- [ { :x => 123 }, { :x => 123, :y => false } ].each do |options|
279
- proc { optout.argv(options) }.should raise_exception(Optout::OptionRequired, /'y'/)
368
+
369
+ context "when the type is incorrect" do
370
+ it "should raise an OptionInvalid exception" do
371
+ lambda { subject.argv(:x => 123) }.should raise_exception(Optout::OptionInvalid, /type Float/)
372
+ end
280
373
  end
281
374
  end
282
375
 
283
- it "should raise an exception if any option contains multiple values" do
284
- optout = create_optout(:multiple => false)
376
+ describe "restricting the option to a set of values " do
377
+ it_should_behave_like "a validator"
378
+ subject { optout_option(%w|sshaw skye|) }
285
379
 
286
- [ { :x => 123, :y => %w|a b c| },
287
- { :x => 123, :y => { :a => "b", :b => "c" }} ].each do |options|
288
- proc { optout.argv(options) }.should raise_exception(Optout::OptionInvalid)
380
+ context "when a value is included in the set" do
381
+ it "should not raise an exception" do
382
+ lambda { subject.argv(:x => "skye") }.should_not raise_exception
383
+ end
289
384
  end
290
385
 
291
- # An Array with 1 value is OK
292
- proc { optout.argv(:x => 123, :y => %w|a|) }.should_not raise_exception(Optout::OptionInvalid)
386
+ context "when a value is not included in the set" do
387
+ it "should raise an OptionInvalid exception" do
388
+ lambda { subject.argv(:x => "jay_kat") }.should raise_exception(Optout::OptionInvalid, /must be one of/)
389
+ end
390
+ end
293
391
  end
294
392
 
295
- it "should raise an exception if a single value option contains multiple values" do
296
- optout = Optout.options do
297
- on :x
298
- on :y, :multiple => false
393
+ describe "pattern matching" do
394
+ it_should_behave_like "a validator"
395
+ subject { optout_option(/X\d{2}/) }
396
+
397
+ context "when it matches" do
398
+ it "should not raise an exception" do
399
+ lambda { subject.argv(:x => "X21") }.should_not raise_exception
400
+ end
299
401
  end
300
402
 
301
- proc { optout.argv(:x => "x", :y => %w|a b c|) }.should raise_exception(Optout::OptionInvalid, /\by\b/)
302
- end
303
-
304
- it "should check the option's type" do
305
- optout = optout_option(Float)
306
- proc { optout.argv(:x => 123) }.should raise_exception(Optout::OptionInvalid, /type Float/)
307
- proc { optout.argv(:x => 123.0) }.should_not raise_exception(Optout::OptionInvalid)
403
+ context "when it does not match" do
404
+ it "should raise an OptionInvalid exception" do
405
+ lambda { subject.argv(:x => "X7") }.should raise_exception(Optout::OptionInvalid, /match pattern/)
406
+ end
407
+ end
308
408
  end
309
409
 
310
- it "should raise an exception if the option's value is not in the given set" do
311
- optout = optout_option(%w|sshaw skye|, :multiple => true)
410
+ describe Optout::Boolean do
411
+ it_should_behave_like "a validator"
412
+ subject { optout_option(Optout::Boolean) }
312
413
 
313
- [ "bob", [ "jack", "jill" ] ].each do |v|
314
- proc { optout.argv(:x => v) }.should raise_exception(Optout::OptionInvalid)
414
+ context "when the option's a boolean" do
415
+ it "should not raise an exception" do
416
+ [ false, true ].each do |v|
417
+ lambda { subject.argv(:x => v) }.should_not raise_exception
418
+ end
419
+ end
315
420
  end
316
421
 
317
- [ "sshaw", [ "sshaw", "skye" ] ].each do |v|
318
- proc { optout.argv(:x => v) }.should_not raise_exception
422
+ context "when the option's not a boolean" do
423
+ it "should raise an OptionInvalid exception" do
424
+ lambda { subject.argv(:x => "x") }.should raise_exception(Optout::OptionInvalid, /does not accept/)
425
+ end
426
+ end
427
+ end
428
+ end
429
+
430
+ describe "a custom validator" do
431
+ context "when it responds to :validate!" do
432
+ it "should be called" do
433
+ klass = mock("validator")
434
+ klass.should_receive(:validate!)
435
+ optout = optout_option(klass)
436
+ optout.argv(:x => "x")
319
437
  end
320
438
  end
321
-
322
- it "should raise an exception if the option's value does not match the given pattern" do
323
- optout = optout_option(/X\d{2}/)
324
- proc { optout.argv(:x => "X7") }.should raise_exception(Optout::OptionInvalid, /match pattern/)
325
- proc { optout.argv(:x => "X21") }.should_not raise_exception
439
+
440
+ context "when it does not respond to :validate!" do
441
+ it "should raise an ArgumentError" do
442
+ optout = optout_option(Class.new.new)
443
+ lambda { optout.argv(:x => "x") }.should raise_exception(ArgumentError, /don't know how to validate/)
444
+ end
445
+ end
446
+ end
447
+
448
+ describe "unknown validation rules" do
449
+ it "should raise an ArgumentError" do
450
+ optout = optout_option("whaaaaa")
451
+ lambda { optout.argv(:x => "x") }.should raise_exception(ArgumentError, /don't know how to validate/)
326
452
  end
327
-
328
- it "should raise an exception if the option has a non-boolean value" do
329
- optout = optout_option(Optout::Boolean)
330
- proc { optout.argv(:x => "x") }.should raise_exception(Optout::OptionInvalid, /does not accept/)
331
- [ false, true, nil ].each do |v|
332
- proc { optout.argv(:x => v) }.should_not raise_exception
453
+ end
454
+
455
+ describe "#required" do
456
+ before :all do
457
+ @optout = Optout.new
458
+ @optout.required do
459
+ on :x, "-x"
460
+ on :y, "-y"
333
461
  end
334
462
  end
335
-
336
- it "should call a custom validator" do
337
- klass = Class.new do
338
- def validate!(opt)
339
- raise "raise up!"
340
- end
463
+
464
+ context "when options are missing" do
465
+ it "should raise an OptionRequired exception" do
466
+ lambda { @optout.argv }.should raise_exception(Optout::OptionRequired, /'x|y'/)
467
+ lambda { @optout.argv :x => "x" }.should raise_exception(Optout::OptionRequired, /'y'/)
468
+ lambda { @optout.argv :y => "y" }.should raise_exception(Optout::OptionRequired, /'x'/)
341
469
  end
470
+ end
342
471
 
343
- optout = optout_option(klass.new)
344
- proc { optout.argv(:x => "x") }.should raise_exception(RuntimeError, "raise up!")
472
+ context "when no options are missing" do
473
+ it "should not raise an exception" do
474
+ lambda { @optout.argv :x => "x", :y => "y" }.should_not raise_exception
475
+ end
345
476
  end
477
+ end
346
478
 
347
- it "should raise an exception if an unknown validation rule is used" do
348
- optout = optout_option("whaaaaa")
349
- proc { optout.argv(:x => "x") }.should raise_exception(ArgumentError, /don't know how to validate/)
479
+ describe "#optional" do
480
+ before :all do
481
+ @optout = Optout.new
482
+ @optout.optional do
483
+ on :x, "-x"
484
+ on :y, "-y"
485
+ end
486
+ end
487
+
488
+ it "should not raise an exception if any options are missing" do
489
+ lambda { @optout.argv }.should_not raise_exception(Optout::OptionRequired)
490
+ lambda { @optout.argv(:x => "x", :y => "y") }.should_not raise_exception(Optout::OptionRequired)
350
491
  end
492
+ end
493
+ end
351
494
 
352
- context "when validating a file" do
353
- it_should_behave_like "something that validates files"
495
+ shared_context "file validation" do
496
+ before(:all) { @tmpdir = Dir.mktmpdir }
497
+ after(:all) { FileUtils.rm_rf(@tmpdir) }
498
+ end
354
499
 
355
- before(:all) do
356
- @file = Tempfile.new("", @tmpdir).path
357
- @validator = Optout::File
358
- end
500
+ describe Optout::File do
501
+ include_context "file validation"
502
+ it_should_behave_like "something that validates files"
359
503
 
360
- it "should raise an exception if it's not a file" do
361
- optout = optout_option(@validator)
362
- proc { optout.argv(:x => @tmpdir) }.should raise_exception(Optout::OptionInvalid, /can't create a file/)
363
- end
364
- end
504
+ before(:all) { @file = Tempfile.new("", @tmpdir) }
505
+ subject { @file.path }
365
506
 
366
- context "when validating a directory" do
367
- it_should_behave_like "something that validates files"
507
+ let(:file) { @file.path }
508
+ let(:options) { { :x => file } }
368
509
 
369
- before(:all) do
370
- @file = Dir.mktmpdir(nil, @tmpdir)
371
- @validator = Optout::Dir
372
- end
510
+ context "when the option is not a file" do
511
+ it "raises an OptionInvalid exception" do
512
+ optout = optout_option(described_class)
513
+ lambda { optout.argv(:x => @tmpdir) }.should raise_exception(Optout::OptionInvalid, /can't create a file/)
514
+ end
515
+ end
516
+ end
517
+
518
+ describe Optout::Dir do
519
+ include_context "file validation"
520
+ it_should_behave_like "something that validates files"
373
521
 
374
- it "should raise an exception if it's not a directory" do
375
- optout = optout_option(@validator)
376
- proc { optout.argv(:x => Tempfile.new("", @tmpdir).path) }.should raise_exception(Optout::OptionInvalid)
377
- end
522
+ subject { @tmpdir }
523
+ let(:file) { @tmpdir }
524
+ let(:options) { {:x => file} }
525
+
526
+ context "when the option is not a directory" do
527
+ it "raises an OptionInvalid exception" do
528
+ optout = optout_option(described_class)
529
+ lambda { optout.argv(:x => Tempfile.new("", @tmpdir).path) }.should raise_exception(Optout::OptionInvalid)
378
530
  end
379
531
  end
380
532
  end