ratatouille 1.3.8 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|