ratatouille 1.3.8 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +14 -0
- data/lib/ratatouille/array.rb +43 -84
- data/lib/ratatouille/hash.rb +81 -79
- data/lib/ratatouille/ratifier.rb +52 -44
- data/lib/ratatouille/version.rb +1 -1
- data/spec/lib/ratatouille/array_spec.rb +125 -77
- data/spec/lib/ratatouille/hash_spec.rb +113 -87
- data/spec/lib/ratatouille/ratifier_spec.rb +31 -3
- metadata +6 -6
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
## 1.4.0
|
2
|
+
|
3
|
+
### Updates
|
4
|
+
|
5
|
+
* New global :skip option allows you to programmatically skip validation by passing in a value of true.
|
6
|
+
* min\_length and max\_length now call length\_between to perform validation
|
7
|
+
* is\_boolean now accepts :unwrap\_block option in addition to new :skip option
|
8
|
+
* 12 new tests
|
9
|
+
|
10
|
+
### Corrections
|
11
|
+
|
12
|
+
* Fixed some false negatives with Array length validation
|
13
|
+
* :unwrap\_block not applicable for given\_key if :required is set to true
|
14
|
+
|
1
15
|
## 1.3.8
|
2
16
|
|
3
17
|
### Updates
|
data/lib/ratatouille/array.rb
CHANGED
@@ -6,21 +6,23 @@ module Ratatouille
|
|
6
6
|
# Iterator method to encapsulate validation
|
7
7
|
#
|
8
8
|
# @note Method will NOT work without a block
|
9
|
-
# @param [Hash] options
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
# @option options [Integer] :max_length
|
9
|
+
# @param [Hash] options
|
10
|
+
# Accepts global options in addition to the following:
|
11
|
+
# @option options [Hash] :name (array_item)
|
12
|
+
# Name each ratifiable object for use in validation message.
|
14
13
|
# @return [void]
|
15
14
|
def ratify_each(options={}, &block)
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
15
|
+
parse_options(options)
|
16
|
+
|
17
|
+
unless @skip
|
18
|
+
if block_given?
|
19
|
+
@ratifiable_object.each_with_index do |obj, i|
|
20
|
+
options[:name] = options.fetch(:name, "array_item")
|
21
|
+
child_object = Ratatouille::Ratifier.new(obj, options, &block)
|
22
|
+
@errors["/"] << child_object.errors unless child_object.valid?
|
23
|
+
end
|
22
24
|
end
|
23
|
-
end
|
25
|
+
end#skip
|
24
26
|
end#ratify_each
|
25
27
|
|
26
28
|
|
@@ -33,14 +35,7 @@ module Ratatouille
|
|
33
35
|
# Useless unless block provided
|
34
36
|
# @return [void]
|
35
37
|
def min_length(min_size=0, options={}, &block)
|
36
|
-
|
37
|
-
|
38
|
-
unless @unwrap_block == true
|
39
|
-
# Wrapped Validation
|
40
|
-
return unless valid_min_length?(min_size)
|
41
|
-
end
|
42
|
-
|
43
|
-
instance_eval(&block) if block_given?
|
38
|
+
return length_between(min_size, nil, options, &block)
|
44
39
|
rescue Exception => e
|
45
40
|
validation_error("#{e.message}")
|
46
41
|
end#min_length
|
@@ -55,14 +50,7 @@ module Ratatouille
|
|
55
50
|
# Useless unless block provided
|
56
51
|
# @return [void]
|
57
52
|
def max_length(max_size=0, options={}, &block)
|
58
|
-
|
59
|
-
|
60
|
-
unless @unwrap_block == true
|
61
|
-
# Wrapped Validation
|
62
|
-
return unless valid_max_length?(max_size)
|
63
|
-
end
|
64
|
-
|
65
|
-
instance_eval(&block) if block_given?
|
53
|
+
return length_between(0, max_size, options, &block)
|
66
54
|
rescue Exception => e
|
67
55
|
validation_error("#{e.message}")
|
68
56
|
end#max_length
|
@@ -80,73 +68,44 @@ module Ratatouille
|
|
80
68
|
def length_between(min_size=0, max_size=nil, options={}, &block)
|
81
69
|
parse_options(options)
|
82
70
|
|
83
|
-
unless @
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
if min_size == 1
|
89
|
-
validation_error("Consider using is_not_empty")
|
71
|
+
unless @skip == true
|
72
|
+
unless @unwrap_block == true
|
73
|
+
# Minimum Length Validation
|
74
|
+
unless min_size.to_i >= 0
|
75
|
+
validation_error("min_length must be a number greater than or equal to 0")
|
90
76
|
return
|
91
77
|
end
|
92
|
-
else
|
93
|
-
return unless valid_max_length?(max_size)
|
94
78
|
|
95
|
-
|
96
|
-
validation_error("
|
79
|
+
unless @ratifiable_object.size >= min_size.to_i
|
80
|
+
validation_error("length must be #{min_size} or more")
|
97
81
|
return
|
98
82
|
end
|
99
83
|
|
100
|
-
|
101
|
-
|
102
|
-
|
84
|
+
# Maximum Length Validation
|
85
|
+
unless max_size.nil?
|
86
|
+
unless max_size.to_i >= 0
|
87
|
+
validation_error("max_size must be a number greater than or equal to 0")
|
88
|
+
return
|
89
|
+
end
|
90
|
+
|
91
|
+
if @ratifiable_object.size > max_size.to_i
|
92
|
+
validation_error("length must be less than #{max_size.to_i}")
|
93
|
+
return
|
94
|
+
end
|
95
|
+
|
96
|
+
unless max_size > min_size
|
97
|
+
validation_error("max_size must be greater than min_size")
|
98
|
+
return
|
99
|
+
end
|
103
100
|
end
|
104
|
-
end
|
105
|
-
end
|
101
|
+
end#unwrap_block
|
106
102
|
|
107
|
-
|
103
|
+
instance_eval(&block) if block_given?
|
104
|
+
end#skip
|
108
105
|
rescue Exception => e
|
109
106
|
validation_error("#{e.message}")
|
110
107
|
end#length_between
|
111
108
|
|
112
|
-
private
|
113
|
-
|
114
|
-
# @note Supporting Method
|
115
|
-
# @return [Boolean]
|
116
|
-
def valid_min_length?(min_size)
|
117
|
-
unless min_size.to_i >= 0
|
118
|
-
validation_error("min_length must be a number greater than or equal to 0")
|
119
|
-
return false
|
120
|
-
end
|
121
|
-
|
122
|
-
unless @ratifiable_object.size >= min_size.to_i
|
123
|
-
validation_error("length must be #{min_size} or more")
|
124
|
-
return false
|
125
|
-
end
|
126
|
-
return true
|
127
|
-
rescue Exception => e
|
128
|
-
validation_error("#{e.message}")
|
129
|
-
return false
|
130
|
-
end
|
131
|
-
|
132
|
-
# @note Supporting Method
|
133
|
-
# @return [Boolean]
|
134
|
-
def valid_max_length?(max_size)
|
135
|
-
unless max_size.to_i >= 0
|
136
|
-
validation_error("max_size must be a number greater than or equal to 0")
|
137
|
-
return false
|
138
|
-
end
|
139
|
-
|
140
|
-
if @ratifiable_object.size > max_size.to_i
|
141
|
-
validation_error("length must be less than #{max_size.to_i}")
|
142
|
-
return false
|
143
|
-
end
|
144
|
-
|
145
|
-
return true
|
146
|
-
rescue Exception => e
|
147
|
-
validation_error("#{e.message}")
|
148
|
-
return false
|
149
|
-
end
|
150
109
|
end#ArrayMethods
|
151
110
|
|
152
|
-
end
|
111
|
+
end#module
|
data/lib/ratatouille/hash.rb
CHANGED
@@ -24,35 +24,33 @@ module Ratatouille
|
|
24
24
|
# Name of ratifiable_object for use with validation error messages.
|
25
25
|
# @option options [Boolean] :required (false)
|
26
26
|
# Ensure that ratifiable_object has the given key
|
27
|
+
# @return [void]
|
28
|
+
# @note :unwrap_block option not applicable if key is required
|
27
29
|
def given_key(key, options={}, &block)
|
28
30
|
options[:name] = options.fetch(:name, (Symbol === key ? ":#{key}" : key.to_s) )
|
29
31
|
|
30
32
|
parse_options(options)
|
31
33
|
|
32
|
-
unless @
|
33
|
-
#
|
34
|
-
|
35
|
-
unless @ratifiable_object.has_key?(key)
|
34
|
+
unless @skip == true
|
35
|
+
unless @ratifiable_object.has_key?(key) # Key Not Found
|
36
|
+
if @required == true
|
36
37
|
validation_error("Missing key #{key.inspect}")
|
37
38
|
return
|
38
39
|
end
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
unless @is_a === @ratifiable_object[key]
|
47
|
-
validation_error("key value is not of type #{@is_a}")
|
48
|
-
return
|
40
|
+
else # Key Found
|
41
|
+
unless @unwrap_block == true
|
42
|
+
unless @is_a.nil?
|
43
|
+
unless @is_a === @ratifiable_object[key]
|
44
|
+
validation_error("key value is not of type #{@is_a}")
|
45
|
+
return
|
46
|
+
end
|
49
47
|
end
|
50
|
-
end
|
51
|
-
end
|
48
|
+
end#unwrap_block
|
52
49
|
|
53
|
-
|
54
|
-
|
55
|
-
|
50
|
+
if block_given?
|
51
|
+
child_object = Ratatouille::Ratifier.new(@ratifiable_object[key], options, &block)
|
52
|
+
@errors[key] = child_object.errors unless child_object.valid?
|
53
|
+
end
|
56
54
|
end
|
57
55
|
end
|
58
56
|
rescue Exception => e
|
@@ -106,31 +104,33 @@ module Ratatouille
|
|
106
104
|
def required_keys(options={}, &block)
|
107
105
|
parse_options(options)
|
108
106
|
|
109
|
-
unless @
|
110
|
-
|
107
|
+
unless @skip == true
|
108
|
+
unless @unwrap_block == true
|
109
|
+
req_keys = options.fetch(:key_list, [])
|
111
110
|
|
112
|
-
|
113
|
-
|
111
|
+
# Wrapped Validation
|
112
|
+
common_keys = (@ratifiable_object.keys & req_keys)
|
114
113
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
114
|
+
if @ratifiable_object.empty?
|
115
|
+
validation_error("Cannot find required keys")
|
116
|
+
return
|
117
|
+
end
|
119
118
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
119
|
+
if req_keys.nil? || req_keys.empty?
|
120
|
+
validation_error("No required keys given to compare against.")
|
121
|
+
return
|
122
|
+
end
|
124
123
|
|
125
|
-
|
126
|
-
|
127
|
-
|
124
|
+
unless common_keys.size == req_keys.size
|
125
|
+
(req_keys - common_keys).each do |missed|
|
126
|
+
validation_error("Missing #{missed.inspect}")
|
127
|
+
end
|
128
|
+
return
|
128
129
|
end
|
129
|
-
return
|
130
130
|
end
|
131
|
-
end
|
132
131
|
|
133
|
-
|
132
|
+
instance_eval(&block) if block_given?
|
133
|
+
end
|
134
134
|
rescue Exception => e
|
135
135
|
validation_error("#{e.message}")
|
136
136
|
end#required_keys
|
@@ -164,56 +164,58 @@ module Ratatouille
|
|
164
164
|
def choice_of(options={}, &block)
|
165
165
|
parse_options(options)
|
166
166
|
|
167
|
-
unless @
|
168
|
-
|
169
|
-
|
167
|
+
unless @skip == true
|
168
|
+
unless @unwrap_block == true
|
169
|
+
choice_size = options.fetch(:choice_size, 1)
|
170
|
+
key_list = options.fetch(:key_list, [])
|
170
171
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
172
|
+
# Wrapped Validation
|
173
|
+
if key_list.nil? || key_list.empty?
|
174
|
+
validation_error("choice_of requires a key list to choose from")
|
175
|
+
return
|
176
|
+
end
|
177
|
+
key_list.flatten!
|
178
|
+
|
179
|
+
# I can work with a non-zero integer or any object that responds
|
180
|
+
case choice_size
|
181
|
+
when Integer
|
182
|
+
unless choice_size > 0
|
183
|
+
validation_error("choice_of requires a positive integer for choice size")
|
184
|
+
return
|
185
|
+
end
|
186
|
+
else
|
187
|
+
unless choice_size.respond_to?(:to_i)
|
188
|
+
validation_error("choice_of requires an object that responds to :to_i for choice size")
|
189
|
+
return
|
190
|
+
end
|
191
|
+
choice_size = choice_size.to_i
|
192
|
+
end
|
177
193
|
|
178
|
-
# I can work with a non-zero integer or any object that responds
|
179
|
-
case choice_size
|
180
|
-
when Integer
|
181
194
|
unless choice_size > 0
|
182
|
-
validation_error("choice_of
|
195
|
+
validation_error("choice size for choice_of must be positive non-zero number")
|
196
|
+
return
|
197
|
+
end
|
198
|
+
|
199
|
+
unless key_list.size > choice_size
|
200
|
+
validation_error("Key list size for 'choice_of' should be larger than choice size. Consider using required_keys instead.")
|
183
201
|
return
|
184
202
|
end
|
185
|
-
|
186
|
-
|
187
|
-
|
203
|
+
|
204
|
+
common_keys = (@ratifiable_object.keys & key_list)
|
205
|
+
unless common_keys.size == choice_size
|
206
|
+
choices = key_list.collect{|a|
|
207
|
+
case a
|
208
|
+
when Symbol then ":#{a}"
|
209
|
+
when String then "#{a}"
|
210
|
+
end
|
211
|
+
}
|
212
|
+
validation_error("Require #{choice_size} of the following: #{choices.join(', ')}")
|
188
213
|
return
|
189
214
|
end
|
190
|
-
|
191
|
-
end
|
192
|
-
|
193
|
-
unless choice_size > 0
|
194
|
-
validation_error("choice size for choice_of must be positive non-zero number")
|
195
|
-
return
|
196
|
-
end
|
197
|
-
|
198
|
-
unless key_list.size > choice_size
|
199
|
-
validation_error("Key list size for 'choice_of' should be larger than choice size. Consider using required_keys instead.")
|
200
|
-
return
|
201
|
-
end
|
202
|
-
|
203
|
-
common_keys = (@ratifiable_object.keys & key_list)
|
204
|
-
unless common_keys.size == choice_size
|
205
|
-
choices = key_list.collect{|a|
|
206
|
-
case a
|
207
|
-
when Symbol then ":#{a}"
|
208
|
-
when String then "#{a}"
|
209
|
-
end
|
210
|
-
}
|
211
|
-
validation_error("Require #{choice_size} of the following: #{choices.join(', ')}")
|
212
|
-
return
|
213
|
-
end
|
214
|
-
end
|
215
|
+
end#unwrap_block
|
215
216
|
|
216
|
-
|
217
|
+
instance_eval(&block) if block_given?
|
218
|
+
end#skip
|
217
219
|
rescue Exception => e
|
218
220
|
validation_error("#{e.message}")
|
219
221
|
end#choice_of
|
data/lib/ratatouille/ratifier.rb
CHANGED
@@ -13,7 +13,7 @@ module Ratatouille
|
|
13
13
|
@ratifiable_object = obj
|
14
14
|
self.name = options[:name]
|
15
15
|
|
16
|
-
|
16
|
+
parse_options(options)
|
17
17
|
|
18
18
|
case obj
|
19
19
|
when Hash then extend Ratatouille::HashMethods
|
@@ -57,7 +57,7 @@ module Ratatouille
|
|
57
57
|
|
58
58
|
|
59
59
|
# Add validation error. Useful for custom validations.
|
60
|
-
# @param [String]
|
60
|
+
# @param [String] err_in
|
61
61
|
# @param [String] context
|
62
62
|
# @return [void]
|
63
63
|
def validation_error(err_in, context="/")
|
@@ -90,7 +90,7 @@ module Ratatouille
|
|
90
90
|
end#cleanup_errors
|
91
91
|
|
92
92
|
|
93
|
-
# @param [Hash]
|
93
|
+
# @param [Hash] item Hash to act upon.
|
94
94
|
# @return [Array]
|
95
95
|
def errors_array(item = @errors)
|
96
96
|
all_errs = []
|
@@ -150,13 +150,21 @@ module Ratatouille
|
|
150
150
|
# Any other class will result in a failed validation.
|
151
151
|
#
|
152
152
|
# @return [Boolean]
|
153
|
-
def is_boolean(&block)
|
154
|
-
|
155
|
-
|
153
|
+
def is_boolean(options={}, &block)
|
154
|
+
parse_options(options)
|
155
|
+
|
156
|
+
unless @skip == true
|
157
|
+
unless @unwrap_block == true
|
158
|
+
case @ratifiable_object
|
159
|
+
when TrueClass, FalseClass
|
160
|
+
# OK to enter block
|
161
|
+
else
|
162
|
+
validation_error("object is not a boolean")
|
163
|
+
return
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
156
167
|
instance_eval(&block) if block_given?
|
157
|
-
else
|
158
|
-
validation_error("object is not a boolean")
|
159
|
-
return
|
160
168
|
end
|
161
169
|
rescue Exception => e
|
162
170
|
validation_error("#{e.message}", "/")
|
@@ -169,12 +177,16 @@ module Ratatouille
|
|
169
177
|
# @param [Hash] options
|
170
178
|
# @option options [Class] :is_a (nil)
|
171
179
|
# @option options [Boolean] :required (false)
|
180
|
+
# @option options [Boolean] :skip (false)
|
172
181
|
# @option options [Boolean] :unwrap_block (false)
|
173
182
|
# Perform block validation only -- skip method validation logic.
|
174
183
|
def parse_options(options={})
|
175
|
-
|
176
|
-
|
177
|
-
|
184
|
+
if Hash === options
|
185
|
+
@is_a = options.fetch(:is_a, nil)
|
186
|
+
@required = options.fetch(:required, false)
|
187
|
+
@skip = options.fetch(:skip, false)
|
188
|
+
@unwrap_block = options.fetch(:unwrap_block, false)
|
189
|
+
end
|
178
190
|
end#parse_options
|
179
191
|
|
180
192
|
|
@@ -182,43 +194,39 @@ module Ratatouille
|
|
182
194
|
# methods called on incorrect objects (hash validation on arrays, etc.)
|
183
195
|
# as well as some catch-all methods for boolean validations (is_* and is_not_*)
|
184
196
|
def method_missing(id, *args, &block)
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
if @ratifiable_object.send("#{$1}?") == true
|
199
|
-
validation_error("is #{$1}")
|
200
|
-
return
|
197
|
+
parse_options(args.first)
|
198
|
+
|
199
|
+
unless @skip == true
|
200
|
+
case
|
201
|
+
when @unwrap_block == true
|
202
|
+
# Perform no validation logic
|
203
|
+
# Skip to block evaluation
|
204
|
+
when id.to_s =~ /^is_not_(.*)$/
|
205
|
+
if @ratifiable_object.respond_to?("#{$1}?")
|
206
|
+
if @ratifiable_object.send("#{$1}?") == true
|
207
|
+
validation_error("is #{$1}")
|
208
|
+
return
|
209
|
+
end
|
201
210
|
end
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
211
|
+
when id.to_s =~ /^is_(.*)$/
|
212
|
+
if @ratifiable_object.respond_to?("#{$1}?")
|
213
|
+
if @ratifiable_object.send("#{$1}?") == false
|
214
|
+
validation_error("is not #{$1}")
|
215
|
+
return
|
216
|
+
end
|
217
|
+
end
|
218
|
+
else
|
219
|
+
begin
|
220
|
+
super
|
207
221
|
return
|
222
|
+
rescue Exception => e
|
223
|
+
validation_error("#{id} is not supported for the given object (#{@ratifiable_object.class})")
|
224
|
+
return e
|
208
225
|
end
|
209
226
|
end
|
210
|
-
else
|
211
|
-
begin
|
212
|
-
super
|
213
|
-
return
|
214
|
-
rescue Exception => e
|
215
|
-
validation_error("#{id} is not supported for the given object (#{@ratifiable_object.class})")
|
216
|
-
return e
|
217
|
-
end
|
218
|
-
end
|
219
227
|
|
220
|
-
|
221
|
-
|
228
|
+
instance_eval(&block) if block_given?
|
229
|
+
end#skip
|
222
230
|
end#method_missing
|
223
231
|
|
224
232
|
|
data/lib/ratatouille/version.rb
CHANGED
@@ -14,130 +14,178 @@ describe "Ratatouille::ArrayMethods" do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
describe "ratify_each" do
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
context "with default options" do
|
18
|
+
it "should set block name to name in options" do
|
19
|
+
n = ""
|
20
|
+
RatifierTest.new(['foo', 'bar']) do
|
21
|
+
ratify_each { n = name }
|
22
|
+
end
|
23
|
+
n.should match /^(array_item)/i
|
24
|
+
|
25
|
+
RatifierTest.new(['foo', 'bar']) do
|
26
|
+
ratify_each(:name => "foo") { n = name }
|
27
|
+
end
|
28
|
+
n.should match /^foo/i
|
21
29
|
end
|
22
|
-
n.should match /^(array_item)/i
|
23
30
|
|
24
|
-
|
25
|
-
|
31
|
+
it "should be invalid for given array" do
|
32
|
+
r = RatifierTest.new(['bar', 'biz']) do
|
33
|
+
ratify_each(:is_a => String) do
|
34
|
+
validation_error("#{ro} is not 'bang'") unless ro == 'bang'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
r.errors_array.length.should == 2
|
26
38
|
end
|
27
|
-
n.should match /^foo/i
|
28
|
-
end
|
29
39
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
40
|
+
it "should be valid for given array" do
|
41
|
+
r = RatifierTest.new(['bar', 'biz']) do
|
42
|
+
ratify_each(:is_a => String) do
|
43
|
+
validation_error("too short") unless ro.size > 2
|
44
|
+
end
|
34
45
|
end
|
46
|
+
r.should be_valid
|
35
47
|
end
|
36
|
-
r.errors_array.length.should == 2
|
37
48
|
end
|
38
49
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
50
|
+
context "with :skip => true" do
|
51
|
+
it "should not enter block" do
|
52
|
+
n = false
|
53
|
+
RatifierTest.new(['foo', 'bar']) do
|
54
|
+
ratify_each(:skip => true) { n = true }
|
43
55
|
end
|
56
|
+
n.should be_false
|
44
57
|
end
|
45
|
-
r.should be_valid
|
46
58
|
end
|
47
59
|
end
|
48
60
|
|
49
61
|
describe "is_empty" do
|
50
|
-
|
51
|
-
|
62
|
+
context "with default options" do
|
63
|
+
it "should not be valid for non-empty array" do
|
64
|
+
RatifierTest.new(['bar']){ is_empty }.should_not be_valid
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should be valid for empty array" do
|
68
|
+
RatifierTest.new([]){ is_empty }.should be_valid
|
69
|
+
end
|
52
70
|
end
|
53
71
|
|
54
|
-
|
55
|
-
|
72
|
+
context "with :skip => true" do
|
73
|
+
it "should not run validation" do
|
74
|
+
RatifierTest.new(['bar']){ is_empty(:skip => true) }.should be_valid
|
75
|
+
end
|
56
76
|
end
|
57
77
|
end
|
58
78
|
|
59
79
|
describe "is_not_empty" do
|
60
|
-
|
61
|
-
|
80
|
+
context "with default options" do
|
81
|
+
it "should be valid for non-empty array" do
|
82
|
+
RatifierTest.new(['bar']){ is_not_empty }.should be_valid
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should not be valid for empty array" do
|
86
|
+
RatifierTest.new([]){ is_not_empty }.should_not be_valid
|
87
|
+
end
|
62
88
|
end
|
63
89
|
|
64
|
-
|
65
|
-
|
90
|
+
context "with :skip => true" do
|
91
|
+
it "should not run validation" do
|
92
|
+
RatifierTest.new([]){ is_not_empty(:skip => true) }.should be_valid
|
93
|
+
end
|
66
94
|
end
|
67
95
|
end
|
68
96
|
|
69
97
|
describe "length_between" do
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
98
|
+
let(:empty_array) { [] }
|
99
|
+
let(:one_element_array) { ['foo'] }
|
100
|
+
let(:two_element_array) { ['foo', 'bar'] }
|
101
|
+
|
102
|
+
context "with default options" do
|
103
|
+
context "for an empty array" do
|
104
|
+
it "should be valid with 0 min length and any positive, non-zero max_length" do
|
105
|
+
RatifierTest.new(empty_array) { length_between(0) }.should be_valid
|
106
|
+
RatifierTest.new(empty_array) { length_between(0, 0) }.should_not be_valid
|
107
|
+
RatifierTest.new(empty_array) { length_between(0, 1) }.should be_valid
|
108
|
+
end
|
74
109
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
110
|
+
it "should be invalid with 1 min_length and any max_length" do
|
111
|
+
RatifierTest.new(empty_array) { length_between(1) }.should_not be_valid
|
112
|
+
RatifierTest.new(empty_array) { length_between(1,1) }.should_not be_valid
|
113
|
+
RatifierTest.new(empty_array) { length_between(1,2) }.should_not be_valid
|
114
|
+
end
|
79
115
|
end
|
80
116
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
117
|
+
context "for a two-element array" do
|
118
|
+
it "should be valid with 1 min_length and any max_length above 1" do
|
119
|
+
RatifierTest.new(two_element_array) { length_between(1,1) }.should_not be_valid
|
120
|
+
RatifierTest.new(two_element_array) { length_between(1,2) }.should be_valid
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should be invalid with 0 min_length and any max_length less than 2" do
|
124
|
+
RatifierTest.new(two_element_array) { length_between(0,0) }.should_not be_valid
|
125
|
+
RatifierTest.new(two_element_array) { length_between(0,1) }.should_not be_valid
|
126
|
+
RatifierTest.new(two_element_array) { length_between(0,2) }.should be_valid
|
127
|
+
end
|
85
128
|
end
|
86
129
|
end
|
87
130
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
end
|
92
|
-
|
93
|
-
it "should be valid with 1 min_length and any max_length above 1" do
|
94
|
-
RatifierTest.new(@arr) { length_between(1,1) }.should_not be_valid
|
95
|
-
RatifierTest.new(@arr) { length_between(1,2) }.should be_valid
|
96
|
-
end
|
97
|
-
|
98
|
-
it "should be invalid with 0 min_length and any max_length less than 2" do
|
99
|
-
RatifierTest.new(@arr) { length_between(0,0) }.should_not be_valid
|
100
|
-
RatifierTest.new(@arr) { length_between(0,1) }.should_not be_valid
|
101
|
-
RatifierTest.new(@arr) { length_between(0,2) }.should be_valid
|
131
|
+
context "with :skip => true" do
|
132
|
+
it "should be valid if validation says otherwise" do
|
133
|
+
RatifierTest.new(empty_array) { length_between(1,2, :skip => true) }.should be_valid
|
102
134
|
end
|
103
135
|
end
|
104
136
|
end
|
105
137
|
|
106
138
|
describe "max_length" do
|
107
|
-
|
108
|
-
|
109
|
-
|
139
|
+
context "with default options" do
|
140
|
+
it "should be valid for proper length array with integer argument" do
|
141
|
+
RatifierTest.new([]) { max_length(1) }.should be_valid
|
142
|
+
RatifierTest.new(['foo']) { max_length(1) }.should be_valid
|
110
143
|
|
111
|
-
|
112
|
-
|
144
|
+
RatifierTest.new(['foo']) { max_length(0) }.should_not be_valid
|
145
|
+
end
|
113
146
|
|
114
|
-
|
115
|
-
|
147
|
+
it "should be invalid for non-numeric length" do
|
148
|
+
RatifierTest.new([]) { max_length({}) }.should_not be_valid
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should be valid for properly transformed float values" do
|
152
|
+
RatifierTest.new(['foo']) { max_length(0.3) }.should_not be_valid
|
153
|
+
RatifierTest.new(['foo']) { max_length(1.3) }.should be_valid
|
154
|
+
RatifierTest.new(['foo', 'bar']) { max_length(1.3) }.should_not be_valid
|
155
|
+
end
|
116
156
|
end
|
117
157
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
158
|
+
context "with :skip => true" do
|
159
|
+
it "should be valid when validation would say otherwise" do
|
160
|
+
RatifierTest.new(['foo', 'bar']) { max_length(1, :skip => true) }.should be_valid
|
161
|
+
end
|
122
162
|
end
|
123
|
-
end
|
163
|
+
end#max_length
|
124
164
|
|
125
165
|
describe "min_length" do
|
126
|
-
|
127
|
-
|
128
|
-
|
166
|
+
context "with default options" do
|
167
|
+
it "should be valid for proper length array with integer argument" do
|
168
|
+
RatifierTest.new([]) { min_length(0) }.should be_valid
|
169
|
+
RatifierTest.new([]) { min_length(1) }.should_not be_valid
|
129
170
|
|
130
|
-
|
131
|
-
|
132
|
-
|
171
|
+
RatifierTest.new(['foo']) { min_length(0) }.should be_valid
|
172
|
+
RatifierTest.new(['foo']) { min_length(1) }.should be_valid
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should be invalid for non-numeric length" do
|
176
|
+
RatifierTest.new([]) { min_length({}) }.should_not be_valid
|
177
|
+
end
|
133
178
|
|
134
|
-
|
135
|
-
|
179
|
+
it "should be valid for properly transformed float values" do
|
180
|
+
RatifierTest.new([]) { min_length(0.3) }.should be_valid
|
181
|
+
RatifierTest.new([]) { min_length(1.3) }.should_not be_valid
|
182
|
+
end
|
136
183
|
end
|
137
184
|
|
138
|
-
|
139
|
-
|
140
|
-
|
185
|
+
context "with :skip => true" do
|
186
|
+
it "should not perform validation" do
|
187
|
+
RatifierTest.new([]) { min_length(1, :skip => true) }.should be_valid
|
188
|
+
end
|
141
189
|
end
|
142
|
-
end
|
190
|
+
end#min_length
|
143
191
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe "Ratatouille::HashMethods" do
|
4
|
+
let(:empty_hash) { {} }
|
5
|
+
|
4
6
|
[ :choice_of,
|
5
7
|
:required_keys,
|
6
8
|
:required_key,
|
@@ -20,7 +22,7 @@ describe "Ratatouille::HashMethods" do
|
|
20
22
|
end
|
21
23
|
|
22
24
|
it "should be valid for empty Hash" do
|
23
|
-
RatifierTest.new(
|
25
|
+
RatifierTest.new(empty_hash){ is_empty }.should be_valid
|
24
26
|
end
|
25
27
|
|
26
28
|
describe "when :unwrap_block is true" do
|
@@ -40,12 +42,12 @@ describe "Ratatouille::HashMethods" do
|
|
40
42
|
end
|
41
43
|
|
42
44
|
it "should not be valid for empty hash" do
|
43
|
-
RatifierTest.new(
|
45
|
+
RatifierTest.new(empty_hash){ is_not_empty }.should_not be_valid
|
44
46
|
end
|
45
47
|
|
46
48
|
describe "when :unwrap_block is true" do
|
47
49
|
it "should be valid for empty hash" do
|
48
|
-
RatifierTest.new(
|
50
|
+
RatifierTest.new(empty_hash){
|
49
51
|
is_not_empty(:unwrap_block => true) do
|
50
52
|
# Nothing to validate, wrapper ignored
|
51
53
|
end
|
@@ -56,139 +58,163 @@ describe "Ratatouille::HashMethods" do
|
|
56
58
|
end
|
57
59
|
|
58
60
|
describe "choice_of" do
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
61
|
+
context "with default options" do
|
62
|
+
it "should be valid with no :choice_size given" do
|
63
|
+
RatifierTest.new({:foo => "bar"}) {
|
64
|
+
choice_of(:key_list => [:foo, :bar])
|
65
|
+
}.should be_valid
|
66
|
+
end
|
64
67
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
68
|
+
it "should be invalid if key list is empty" do
|
69
|
+
RatifierTest.new(empty_hash) {
|
70
|
+
choice_of(:choice_size => 1, :key_list => [])
|
71
|
+
}.should_not be_valid
|
72
|
+
end
|
70
73
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
74
|
+
it "should be invalid if choice size less than 1" do
|
75
|
+
RatifierTest.new(empty_hash) {
|
76
|
+
choice_of(:choice_size => 0, :key_list => [:foo])
|
77
|
+
}.should_not be_valid
|
78
|
+
end
|
76
79
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
80
|
+
it "should be invalid if choice list is not 1 more than choice size" do
|
81
|
+
RatifierTest.new(empty_hash) {
|
82
|
+
choice_of(:choice_size => 1, :key_list => [:foo])
|
83
|
+
}.should_not be_valid
|
84
|
+
end
|
82
85
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
86
|
+
it "should be valid when given hash has 1 key in a choice list of 2 or more" do
|
87
|
+
RatifierTest.new({:foo => "bar"}){
|
88
|
+
choice_of(:key_list => [:foo, :bar])
|
89
|
+
}.should be_valid
|
90
|
+
end
|
88
91
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
92
|
+
it "should be valid when given hash has 2 keys in choice list of 3 or more" do
|
93
|
+
RatifierTest.new({:foo => "foo", :bar => "bar"}){
|
94
|
+
choice_of(:choice_size => 2, :key_list => [:foo, :bar, :biz])
|
95
|
+
}.should be_valid
|
93
96
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
+
RatifierTest.new({:foo => "foo", :bar => "bar"}){
|
98
|
+
choice_of(:choice_size => 2, :key_list => [:foo, :bar, :biz, :bang])
|
99
|
+
}.should be_valid
|
100
|
+
end
|
97
101
|
end
|
98
102
|
|
99
|
-
|
103
|
+
context "with :unwrap_block => true" do
|
100
104
|
it "should be valid when used on empty Hash" do
|
101
|
-
RatifierTest.new(
|
105
|
+
RatifierTest.new(empty_hash){
|
102
106
|
choice_of(:key_list => [:foo, :bar], :unwrap_block => true) do
|
103
107
|
# Nothing to validate, wrapper ignored
|
104
108
|
end
|
105
109
|
}.should be_valid
|
106
110
|
|
107
|
-
RatifierTest.new(
|
111
|
+
RatifierTest.new(empty_hash){
|
108
112
|
choice_of(:key_list => [:foo, :bar]) do
|
109
113
|
# Nothing to validate, wrapper ignored
|
110
114
|
end
|
111
115
|
}.should_not be_valid
|
112
116
|
end
|
113
117
|
end
|
118
|
+
|
119
|
+
context "with :skip => true" do
|
120
|
+
context "with empty hash" do
|
121
|
+
it "should be valid" do
|
122
|
+
RatifierTest.new(empty_hash){
|
123
|
+
choice_of(:key_list => [:foo, :bar], :skip => true)
|
124
|
+
}.should be_valid
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
114
128
|
end
|
115
129
|
|
116
130
|
describe "required_keys" do
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
131
|
+
context "with default options" do
|
132
|
+
it "should be valid if Hash contains all required keys" do
|
133
|
+
RatifierTest.new({:foo => "foo", :bar => "bar"}) {
|
134
|
+
required_keys(:key_list => [:foo, :bar])
|
135
|
+
}.should be_valid
|
136
|
+
end
|
121
137
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
138
|
+
it "should be invalid if Hash is empty and key list is not" do
|
139
|
+
RatifierTest.new(empty_hash) {
|
140
|
+
required_keys(:key_list => [:foo])
|
141
|
+
}.should_not be_valid
|
142
|
+
end
|
126
143
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
144
|
+
it "should be invalid if Hash does not contain ALL keys in key list" do
|
145
|
+
RatifierTest.new({:foo => "foo"}) {
|
146
|
+
required_keys(:key_list => [:foo, :bar])
|
147
|
+
}.should_not be_valid
|
148
|
+
end
|
131
149
|
end
|
132
150
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
151
|
+
context "with :unwrap_block => true" do
|
152
|
+
context "when used on empty Hash" do
|
153
|
+
it "should be valid" do
|
154
|
+
RatifierTest.new(empty_hash){
|
155
|
+
required_keys(:key_list => [:foo, :bar], :unwrap_block => true) {}
|
156
|
+
}.should be_valid
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should enter block with required keys" do
|
160
|
+
entered_block = false
|
161
|
+
RatifierTest.new(empty_hash){
|
162
|
+
required_keys(:key_list => [:foo, :bar], :unwrap_block => true) do
|
163
|
+
entered_block = true
|
164
|
+
end
|
165
|
+
}
|
166
|
+
entered_block.should be_true
|
167
|
+
end
|
168
|
+
end
|
137
169
|
end
|
138
170
|
|
139
|
-
|
140
|
-
it "should be valid
|
141
|
-
RatifierTest.new({}){
|
142
|
-
required_keys(:key_list => [:foo, :bar], :
|
143
|
-
# Nothing to validate, wrapper ignored
|
144
|
-
end
|
171
|
+
context "with :skip => true" do
|
172
|
+
it "should be valid if Hash does not contain all required keys" do
|
173
|
+
RatifierTest.new({:foo => "foo"}) {
|
174
|
+
required_keys(:key_list => [:foo, :bar], :skip => true)
|
145
175
|
}.should be_valid
|
146
|
-
|
147
|
-
RatifierTest.new({}){
|
148
|
-
required_keys(:key_list => [:foo, :bar]) do
|
149
|
-
# Nothing to validate, wrapper ignored
|
150
|
-
end
|
151
|
-
}.should_not be_valid
|
152
176
|
end
|
153
177
|
end
|
154
178
|
end
|
155
179
|
|
156
180
|
describe "required_key" do
|
157
|
-
|
158
|
-
|
159
|
-
|
181
|
+
context "with default options" do
|
182
|
+
it "should be invalid when given a key for an empty hash" do
|
183
|
+
RatifierTest.new({}){ required_key(:foo) }.should_not be_valid
|
184
|
+
end
|
160
185
|
|
161
|
-
|
162
|
-
|
163
|
-
|
186
|
+
it "should be invalid when given a key that doesn't exist in the hash" do
|
187
|
+
RatifierTest.new({:foo => "foo"}){ required_key(:bar) }.should_not be_valid
|
188
|
+
end
|
164
189
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
190
|
+
it "should not progress into block if invalid" do
|
191
|
+
f = false
|
192
|
+
RatifierTest.new({}) do
|
193
|
+
required_key(:foo) { f = true }
|
194
|
+
end
|
195
|
+
f.should be_false
|
169
196
|
end
|
170
|
-
f.should be_false
|
171
|
-
end
|
172
197
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
198
|
+
it "should change the scope name to default to the key if no name passed as option" do
|
199
|
+
n = ""
|
200
|
+
RatifierTest.new({:foo => "bar"}) do
|
201
|
+
required_key(:foo) { n = name }
|
202
|
+
end
|
203
|
+
n.should == ":foo"
|
177
204
|
end
|
178
|
-
n.should == ":foo"
|
179
205
|
end
|
180
206
|
|
181
|
-
|
182
|
-
it "should be
|
207
|
+
context "with :unwrap_block => true" do
|
208
|
+
it "should be invalid when used on empty Hash" do
|
183
209
|
RatifierTest.new({}){
|
184
210
|
required_key(:foo, :unwrap_block => true) do
|
185
211
|
# Nothing to validate, wrapper ignored
|
186
212
|
end
|
187
|
-
}.
|
213
|
+
}.should_not be_valid
|
188
214
|
end
|
189
215
|
end
|
190
216
|
|
191
|
-
describe "
|
217
|
+
describe "with :is_a" do
|
192
218
|
it "should be valid with matching key value class" do
|
193
219
|
RatifierTest.new({:foo => "bar"}){
|
194
220
|
required_key(:foo, :class => String) do
|
@@ -144,15 +144,43 @@ describe Ratatouille::Ratifier do
|
|
144
144
|
end
|
145
145
|
|
146
146
|
describe "is_boolean" do
|
147
|
-
|
148
|
-
|
147
|
+
context "with default options" do
|
148
|
+
[true, false].each do |b|
|
149
|
+
it "should enter block for #{b} value" do
|
150
|
+
block_entered = false
|
151
|
+
RatifierTest.new(b) do
|
152
|
+
is_boolean { block_entered = true }
|
153
|
+
end
|
154
|
+
block_entered.should be_true
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should not enter block for non-boolean value" do
|
149
159
|
block_entered = false
|
150
|
-
RatifierTest.new(
|
160
|
+
RatifierTest.new("foo") do
|
151
161
|
is_boolean { block_entered = true }
|
152
162
|
end
|
163
|
+
block_entered.should be_false
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
context "with :unwrap_block => true" do
|
168
|
+
it "should enter block if ratifiable object is NOT boolean" do
|
169
|
+
block_entered = false
|
170
|
+
RatifierTest.new("foo") do
|
171
|
+
is_boolean(:unwrap_block => true) { block_entered = true }
|
172
|
+
end
|
153
173
|
block_entered.should be_true
|
154
174
|
end
|
155
175
|
end
|
176
|
+
|
177
|
+
context "with :skip => true" do
|
178
|
+
it "should be valid even if validation says otherwise" do
|
179
|
+
RatifierTest.new("foo") {
|
180
|
+
is_boolean(:skip => true)
|
181
|
+
}.should be_valid
|
182
|
+
end
|
183
|
+
end
|
156
184
|
end
|
157
185
|
|
158
186
|
describe "name" do
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ratatouille
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 7
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 1.
|
8
|
+
- 4
|
9
|
+
- 0
|
10
|
+
version: 1.4.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Ryan Johnson
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-05-
|
18
|
+
date: 2012-05-23 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: rspec
|
@@ -123,7 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
123
123
|
requirements: []
|
124
124
|
|
125
125
|
rubyforge_project: ratatouille
|
126
|
-
rubygems_version: 1.8.
|
126
|
+
rubygems_version: 1.8.24
|
127
127
|
signing_key:
|
128
128
|
specification_version: 3
|
129
129
|
summary: DSL for validating complex hashes
|