parameters_schema 0.42 → 1.0.1
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.
- checksums.yaml +4 -4
- data/Gemfile +3 -3
- data/README.md +286 -286
- data/Rakefile +7 -7
- data/lib/parameters_schema/core_ext.rb +21 -21
- data/lib/parameters_schema/exceptions.rb +23 -23
- data/lib/parameters_schema/options.rb +79 -79
- data/lib/parameters_schema/schema.rb +295 -295
- data/lib/parameters_schema.rb +8 -8
- data/test/helpers.rb +56 -56
- data/test/test_options.rb +74 -74
- data/test/test_schema_allow.rb +114 -114
- data/test/test_schema_allow_empty.rb +29 -29
- data/test/test_schema_allow_nil.rb +33 -33
- data/test/test_schema_hash.rb +90 -90
- data/test/test_schema_required.rb +74 -74
- data/test/test_schema_simple.rb +58 -58
- data/test/test_schema_types.rb +452 -452
- data/test/test_schema_types_complex.rb +126 -126
- metadata +9 -10
@@ -1,296 +1,296 @@
|
|
1
|
-
module ParametersSchema
|
2
|
-
class Schema
|
3
|
-
def initialize(&schema)
|
4
|
-
@schema = schema
|
5
|
-
end
|
6
|
-
|
7
|
-
def validate!(params)
|
8
|
-
# Make sure we have params we can work with.
|
9
|
-
@params = __prepare_params(params)
|
10
|
-
|
11
|
-
# Parse and validate each param.
|
12
|
-
@sanitized_params = []
|
13
|
-
instance_eval(&@schema)
|
14
|
-
# Serve the params if valid, otherwise throw exception.
|
15
|
-
__handle_errors
|
16
|
-
__serve
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
def param(name, options = {}, &inner_params)
|
22
|
-
options[:required] = !options.has_key?(:required) || options[:required].present?
|
23
|
-
|
24
|
-
options[:type] = [options[:type] || String].flatten
|
25
|
-
options[:allow] = [options[:allow].present? ? options[:allow] : ParametersSchema::Options.any_keyword].flatten
|
26
|
-
options[:deny] = [options[:deny].present? ? options[:deny] : ParametersSchema::Options.none_keyword].flatten
|
27
|
-
|
28
|
-
[ParametersSchema::Options.any_keyword, ParametersSchema::Options.none_keyword].each do |dominant_value|
|
29
|
-
[:allow, :deny, :type].each do |key|
|
30
|
-
options[key] = [dominant_value] if options[key].include?(dominant_value)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
options[:array] = options[:array] || false
|
35
|
-
options[:parent] = options[:parent] || @params
|
36
|
-
|
37
|
-
options[:type].map! do |type|
|
38
|
-
# Limit to { key => value }
|
39
|
-
if type.kind_of?(Hash) && type.count > 1
|
40
|
-
type = { type.first[0] => type.first[1] }
|
41
|
-
end
|
42
|
-
|
43
|
-
# Limit to { Array => value }
|
44
|
-
if type.kind_of?(Hash) && type.first[0] != Array
|
45
|
-
type = type.first[0]
|
46
|
-
end
|
47
|
-
|
48
|
-
# Apply :array keyword if not already in the format { Array => value }
|
49
|
-
if options.delete(:array) && !type.kind_of?(Hash)
|
50
|
-
type = { Array => type }
|
51
|
-
end
|
52
|
-
|
53
|
-
# The format...
|
54
|
-
#
|
55
|
-
# param :potatoe do
|
56
|
-
# ...
|
57
|
-
# end
|
58
|
-
#
|
59
|
-
# ... is always an Hash.
|
60
|
-
if type.kind_of?(Hash) && inner_params.present?
|
61
|
-
type = { Array => Hash }
|
62
|
-
elsif inner_params.present?
|
63
|
-
type = Hash
|
64
|
-
end
|
65
|
-
|
66
|
-
type
|
67
|
-
end
|
68
|
-
|
69
|
-
@sanitized_params.push(__validate_param(name, options, inner_params))
|
70
|
-
end
|
71
|
-
|
72
|
-
def __prepare_params(params)
|
73
|
-
params ||= {}
|
74
|
-
params = {} unless params.kind_of?(Hash)
|
75
|
-
params = params.clone.with_indifferent_access
|
76
|
-
ParametersSchema::Options.skip_parameters.each{ |param| params.delete(param) }
|
77
|
-
params
|
78
|
-
end
|
79
|
-
|
80
|
-
def __validate_param(name, options, inner_params)
|
81
|
-
# Validate the presence of the parameter.
|
82
|
-
value, error = __validate_param_presence(name, options)
|
83
|
-
return __stop_validation(name, value, error, options) if error || (!options[:required] && value.nil?)
|
84
|
-
|
85
|
-
# Validate nil value.
|
86
|
-
value, error = __validate_param_value_nil(value, options)
|
87
|
-
return __stop_validation(name, value, error, options) if error || value.nil?
|
88
|
-
|
89
|
-
# Validate empty value (except hash).
|
90
|
-
value, error = __validate_param_value_empty(value, options)
|
91
|
-
return __stop_validation(name, value, error, options) if error || value.nil?
|
92
|
-
|
93
|
-
# Validate the type of the parameter.
|
94
|
-
[options[:type]].flatten.each do |type|
|
95
|
-
value, error = __validate_type_and_cast(value, type, options, inner_params)
|
96
|
-
break if error.blank?
|
97
|
-
end
|
98
|
-
return __stop_validation(name, value, error, options) if error || value.nil?
|
99
|
-
|
100
|
-
# Validate the allowed and denied values of the parameter
|
101
|
-
unless value.kind_of?(Array) || value.kind_of?(Hash)
|
102
|
-
[:allow, :deny].each do |allow_or_deny|
|
103
|
-
value, error = __validate_param_value_format(value, options, allow_or_deny)
|
104
|
-
return __stop_validation(name, value, error, options) if error || value.nil?
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
# Validate empty value for hash.
|
109
|
-
# This is done at this point to let the validation emit errors when inner parameters are missing.
|
110
|
-
# It is preferable that { key: {} } emit { key: { name: :missing } } than { key: :empty }.
|
111
|
-
value, error = __validate_param_value_hash_empty(value, options)
|
112
|
-
return __stop_validation(name, value, error, options) if error || value.nil?
|
113
|
-
|
114
|
-
__stop_validation(name, value, error, options)
|
115
|
-
end
|
116
|
-
|
117
|
-
def __validate_param_presence(name, options)
|
118
|
-
error = nil
|
119
|
-
|
120
|
-
if options[:required] && !options[:parent].has_key?(name)
|
121
|
-
error = ParametersSchema::ErrorCode::MISSING
|
122
|
-
elsif options[:parent].has_key?(name)
|
123
|
-
value = options[:parent][name]
|
124
|
-
end
|
125
|
-
|
126
|
-
[value, error]
|
127
|
-
end
|
128
|
-
|
129
|
-
def __validate_param_value_nil(value, options)
|
130
|
-
error = nil
|
131
|
-
|
132
|
-
if !options[:allow].include?(ParametersSchema::Options.nil_keyword) && value.nil?
|
133
|
-
error = ParametersSchema::ErrorCode::NIL
|
134
|
-
end
|
135
|
-
|
136
|
-
[value, error]
|
137
|
-
end
|
138
|
-
|
139
|
-
def __validate_param_value_empty(value, options)
|
140
|
-
error = nil
|
141
|
-
|
142
|
-
if !options[:allow].include?(ParametersSchema::Options.empty_keyword) && !value.kind_of?(Hash) && value.respond_to?(:empty?) && value.empty?
|
143
|
-
error = ParametersSchema::ErrorCode::EMPTY
|
144
|
-
end
|
145
|
-
|
146
|
-
[value, error]
|
147
|
-
end
|
148
|
-
|
149
|
-
def __validate_param_value_hash_empty(value, options)
|
150
|
-
error = nil
|
151
|
-
|
152
|
-
if !options[:allow].include?(ParametersSchema::Options.empty_keyword) && value.kind_of?(Hash) && value.empty?
|
153
|
-
error = ParametersSchema::ErrorCode::EMPTY
|
154
|
-
end
|
155
|
-
|
156
|
-
[value, error]
|
157
|
-
end
|
158
|
-
|
159
|
-
def __validate_param_value_format(value, options, allow_or_deny)
|
160
|
-
conditions = options[allow_or_deny] - [ParametersSchema::Options.empty_keyword, ParametersSchema::Options.nil_keyword]
|
161
|
-
inverse = allow_or_deny == :deny
|
162
|
-
accept_all_keyword = inverse ? ParametersSchema::Options.none_keyword : ParametersSchema::Options.any_keyword
|
163
|
-
refuse_all_keyword = inverse ? ParametersSchema::Options.any_keyword : ParametersSchema::Options.none_keyword
|
164
|
-
|
165
|
-
return [value, nil] if conditions.include?(accept_all_keyword)
|
166
|
-
return [value, ParametersSchema::ErrorCode::DISALLOWED] if conditions.include?(refuse_all_keyword)
|
167
|
-
|
168
|
-
error = nil
|
169
|
-
|
170
|
-
conditions.each do |condition|
|
171
|
-
error = nil
|
172
|
-
|
173
|
-
if condition.kind_of?(Range)
|
174
|
-
condition_passed = condition.include?(value)
|
175
|
-
condition_passed = !condition_passed if inverse
|
176
|
-
error = ParametersSchema::ErrorCode::DISALLOWED unless condition_passed
|
177
|
-
elsif condition.kind_of?(Regexp) && !value.kind_of?(String)
|
178
|
-
error = ParametersSchema::ErrorCode::DISALLOWED
|
179
|
-
elsif condition.kind_of?(Regexp) && value.kind_of?(String)
|
180
|
-
condition_passed = (condition =~ value).present?
|
181
|
-
condition_passed = !condition_passed if inverse
|
182
|
-
error = ParametersSchema::ErrorCode::DISALLOWED unless condition_passed
|
183
|
-
else
|
184
|
-
condition_passed = condition == value
|
185
|
-
condition_passed = !condition_passed if inverse
|
186
|
-
error = ParametersSchema::ErrorCode::DISALLOWED unless condition_passed
|
187
|
-
end
|
188
|
-
|
189
|
-
break if inverse ? error.present? : error.blank?
|
190
|
-
end
|
191
|
-
|
192
|
-
[value, error]
|
193
|
-
end
|
194
|
-
|
195
|
-
def __validate_type_and_cast(value, type, options, inner_params)
|
196
|
-
if type.kind_of?(Hash)
|
197
|
-
error = ParametersSchema::ErrorCode::DISALLOWED if !value.kind_of?(Array)
|
198
|
-
value, error = __validate_array(value, type.values.first, options, inner_params) unless error
|
199
|
-
elsif inner_params.present?
|
200
|
-
begin
|
201
|
-
inner_schema = ParametersSchema::Schema.new(&inner_params)
|
202
|
-
value = inner_schema.validate!(value)
|
203
|
-
rescue ParametersSchema::InvalidParameters => e
|
204
|
-
error = e.errors
|
205
|
-
end
|
206
|
-
elsif type == ParametersSchema::Options.boolean_keyword
|
207
|
-
value = true if ParametersSchema::Options.boolean_true_values.include?(value.kind_of?(String) ? value.downcase : value)
|
208
|
-
value = false if ParametersSchema::Options.boolean_false_values.include?(value.kind_of?(String) ? value.downcase : value)
|
209
|
-
error = ParametersSchema::ErrorCode::DISALLOWED if !value.kind_of?(TrueClass) && !value.kind_of?(FalseClass)
|
210
|
-
elsif type == Fixnum
|
211
|
-
error = ParametersSchema::ErrorCode::DISALLOWED if !value.numeric?
|
212
|
-
value = value.to_i if error.blank? # cast to right type.
|
213
|
-
elsif type == Float
|
214
|
-
error = ParametersSchema::ErrorCode::DISALLOWED if !value.numeric?
|
215
|
-
value = value.to_f if error.blank? # cast to right type.
|
216
|
-
elsif type == Regexp
|
217
|
-
error = ParametersSchema::ErrorCode::DISALLOWED unless value =~ options[:regex]
|
218
|
-
elsif type == ParametersSchema::Options.any_keyword
|
219
|
-
# No validation required.
|
220
|
-
elsif type == ParametersSchema::Options.none_keyword
|
221
|
-
# Always fail. Why would you want to do that?
|
222
|
-
error = ParametersSchema::ErrorCode::DISALLOWED
|
223
|
-
elsif type == String
|
224
|
-
error = ParametersSchema::ErrorCode::DISALLOWED unless value.kind_of?(String) || value.kind_of?(Symbol)
|
225
|
-
value = value.to_s if error.blank? # cast to right type.
|
226
|
-
elsif type == Symbol
|
227
|
-
error = ParametersSchema::ErrorCode::DISALLOWED unless value.respond_to?(:to_sym)
|
228
|
-
value = value.to_sym if error.blank? # cast to right type.
|
229
|
-
elsif type == Date
|
230
|
-
begin
|
231
|
-
value = value.kind_of?(String) ? Date.parse(value) : value.to_date
|
232
|
-
rescue
|
233
|
-
error = ParametersSchema::ErrorCode::DISALLOWED
|
234
|
-
end
|
235
|
-
elsif type == DateTime
|
236
|
-
begin
|
237
|
-
value = value.kind_of?(String) ? DateTime.parse(value) : value.to_datetime
|
238
|
-
rescue
|
239
|
-
error = ParametersSchema::ErrorCode::DISALLOWED
|
240
|
-
end
|
241
|
-
else
|
242
|
-
error = ParametersSchema::ErrorCode::DISALLOWED if !value.kind_of?(type)
|
243
|
-
end
|
244
|
-
|
245
|
-
[value, error]
|
246
|
-
end
|
247
|
-
|
248
|
-
def __validate_array(value, type, options, inner_params)
|
249
|
-
if !value.kind_of?(Array)
|
250
|
-
return [value, ParametersSchema::ErrorCode::DISALLOWED]
|
251
|
-
end
|
252
|
-
|
253
|
-
value_opts = {
|
254
|
-
required: true,
|
255
|
-
type: type,
|
256
|
-
parent: { value: nil },
|
257
|
-
allow: options[:allow],
|
258
|
-
deny: options[:deny]
|
259
|
-
}
|
260
|
-
|
261
|
-
value.map! do |v|
|
262
|
-
value_opts[:parent][:value] = v
|
263
|
-
__validate_param(:value, value_opts, inner_params)
|
264
|
-
end
|
265
|
-
|
266
|
-
# For now, take the first error.
|
267
|
-
[value.map{ |v| v[:value] }, value.find{ |v| v[:error].present? }.try(:[], :error)]
|
268
|
-
end
|
269
|
-
|
270
|
-
def __stop_validation(name, value, error, options)
|
271
|
-
{ param: name, error: error, value: value, keep_if_nil: options[:allow].include?(ParametersSchema::Options.nil_keyword) }
|
272
|
-
end
|
273
|
-
|
274
|
-
def __handle_errors
|
275
|
-
errors = @sanitized_params
|
276
|
-
.select{ |p| p[:error].present? }
|
277
|
-
.each_with_object({}.with_indifferent_access) do |p, h|
|
278
|
-
h[p[:param]] = p[:error] == :nested_errors ? p[:value] : p[:error]
|
279
|
-
end
|
280
|
-
|
281
|
-
(@params.keys.map(&:to_sym) - @sanitized_params.map{ |p| p[:param] }).each do |extra_param|
|
282
|
-
errors[extra_param] = ParametersSchema::ErrorCode::UNKNOWN
|
283
|
-
end
|
284
|
-
|
285
|
-
raise ParametersSchema::InvalidParameters.new(errors) if errors.any?
|
286
|
-
end
|
287
|
-
|
288
|
-
def __serve
|
289
|
-
@sanitized_params
|
290
|
-
.reject{ |p| p[:value].nil? && !p[:keep_if_nil] }
|
291
|
-
.each_with_object({}.with_indifferent_access) do |p, h|
|
292
|
-
h[p[:param]] = p[:value]
|
293
|
-
end
|
294
|
-
end
|
295
|
-
end
|
1
|
+
module ParametersSchema
|
2
|
+
class Schema
|
3
|
+
def initialize(&schema)
|
4
|
+
@schema = schema
|
5
|
+
end
|
6
|
+
|
7
|
+
def validate!(params)
|
8
|
+
# Make sure we have params we can work with.
|
9
|
+
@params = __prepare_params(params)
|
10
|
+
|
11
|
+
# Parse and validate each param.
|
12
|
+
@sanitized_params = []
|
13
|
+
instance_eval(&@schema)
|
14
|
+
# Serve the params if valid, otherwise throw exception.
|
15
|
+
__handle_errors
|
16
|
+
__serve
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def param(name, options = {}, &inner_params)
|
22
|
+
options[:required] = !options.has_key?(:required) || options[:required].present?
|
23
|
+
|
24
|
+
options[:type] = [options[:type] || String].flatten
|
25
|
+
options[:allow] = [options[:allow].present? ? options[:allow] : ParametersSchema::Options.any_keyword].flatten
|
26
|
+
options[:deny] = [options[:deny].present? ? options[:deny] : ParametersSchema::Options.none_keyword].flatten
|
27
|
+
|
28
|
+
[ParametersSchema::Options.any_keyword, ParametersSchema::Options.none_keyword].each do |dominant_value|
|
29
|
+
[:allow, :deny, :type].each do |key|
|
30
|
+
options[key] = [dominant_value] if options[key].include?(dominant_value)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
options[:array] = options[:array] || false
|
35
|
+
options[:parent] = options[:parent] || @params
|
36
|
+
|
37
|
+
options[:type].map! do |type|
|
38
|
+
# Limit to { key => value }
|
39
|
+
if type.kind_of?(Hash) && type.count > 1
|
40
|
+
type = { type.first[0] => type.first[1] }
|
41
|
+
end
|
42
|
+
|
43
|
+
# Limit to { Array => value }
|
44
|
+
if type.kind_of?(Hash) && type.first[0] != Array
|
45
|
+
type = type.first[0]
|
46
|
+
end
|
47
|
+
|
48
|
+
# Apply :array keyword if not already in the format { Array => value }
|
49
|
+
if options.delete(:array) && !type.kind_of?(Hash)
|
50
|
+
type = { Array => type }
|
51
|
+
end
|
52
|
+
|
53
|
+
# The format...
|
54
|
+
#
|
55
|
+
# param :potatoe do
|
56
|
+
# ...
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# ... is always an Hash.
|
60
|
+
if type.kind_of?(Hash) && inner_params.present?
|
61
|
+
type = { Array => Hash }
|
62
|
+
elsif inner_params.present?
|
63
|
+
type = Hash
|
64
|
+
end
|
65
|
+
|
66
|
+
type
|
67
|
+
end
|
68
|
+
|
69
|
+
@sanitized_params.push(__validate_param(name, options, inner_params))
|
70
|
+
end
|
71
|
+
|
72
|
+
def __prepare_params(params)
|
73
|
+
params ||= {}
|
74
|
+
params = {} unless params.kind_of?(Hash)
|
75
|
+
params = params.clone.with_indifferent_access
|
76
|
+
ParametersSchema::Options.skip_parameters.each{ |param| params.delete(param) }
|
77
|
+
params
|
78
|
+
end
|
79
|
+
|
80
|
+
def __validate_param(name, options, inner_params)
|
81
|
+
# Validate the presence of the parameter.
|
82
|
+
value, error = __validate_param_presence(name, options)
|
83
|
+
return __stop_validation(name, value, error, options) if error || (!options[:required] && value.nil?)
|
84
|
+
|
85
|
+
# Validate nil value.
|
86
|
+
value, error = __validate_param_value_nil(value, options)
|
87
|
+
return __stop_validation(name, value, error, options) if error || value.nil?
|
88
|
+
|
89
|
+
# Validate empty value (except hash).
|
90
|
+
value, error = __validate_param_value_empty(value, options)
|
91
|
+
return __stop_validation(name, value, error, options) if error || value.nil?
|
92
|
+
|
93
|
+
# Validate the type of the parameter.
|
94
|
+
[options[:type]].flatten.each do |type|
|
95
|
+
value, error = __validate_type_and_cast(value, type, options, inner_params)
|
96
|
+
break if error.blank?
|
97
|
+
end
|
98
|
+
return __stop_validation(name, value, error, options) if error || value.nil?
|
99
|
+
|
100
|
+
# Validate the allowed and denied values of the parameter
|
101
|
+
unless value.kind_of?(Array) || value.kind_of?(Hash)
|
102
|
+
[:allow, :deny].each do |allow_or_deny|
|
103
|
+
value, error = __validate_param_value_format(value, options, allow_or_deny)
|
104
|
+
return __stop_validation(name, value, error, options) if error || value.nil?
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Validate empty value for hash.
|
109
|
+
# This is done at this point to let the validation emit errors when inner parameters are missing.
|
110
|
+
# It is preferable that { key: {} } emit { key: { name: :missing } } than { key: :empty }.
|
111
|
+
value, error = __validate_param_value_hash_empty(value, options)
|
112
|
+
return __stop_validation(name, value, error, options) if error || value.nil?
|
113
|
+
|
114
|
+
__stop_validation(name, value, error, options)
|
115
|
+
end
|
116
|
+
|
117
|
+
def __validate_param_presence(name, options)
|
118
|
+
error = nil
|
119
|
+
|
120
|
+
if options[:required] && !options[:parent].has_key?(name)
|
121
|
+
error = ParametersSchema::ErrorCode::MISSING
|
122
|
+
elsif options[:parent].has_key?(name)
|
123
|
+
value = options[:parent][name]
|
124
|
+
end
|
125
|
+
|
126
|
+
[value, error]
|
127
|
+
end
|
128
|
+
|
129
|
+
def __validate_param_value_nil(value, options)
|
130
|
+
error = nil
|
131
|
+
|
132
|
+
if !options[:allow].include?(ParametersSchema::Options.nil_keyword) && value.nil?
|
133
|
+
error = ParametersSchema::ErrorCode::NIL
|
134
|
+
end
|
135
|
+
|
136
|
+
[value, error]
|
137
|
+
end
|
138
|
+
|
139
|
+
def __validate_param_value_empty(value, options)
|
140
|
+
error = nil
|
141
|
+
|
142
|
+
if !options[:allow].include?(ParametersSchema::Options.empty_keyword) && !value.kind_of?(Hash) && value.respond_to?(:empty?) && value.empty?
|
143
|
+
error = ParametersSchema::ErrorCode::EMPTY
|
144
|
+
end
|
145
|
+
|
146
|
+
[value, error]
|
147
|
+
end
|
148
|
+
|
149
|
+
def __validate_param_value_hash_empty(value, options)
|
150
|
+
error = nil
|
151
|
+
|
152
|
+
if !options[:allow].include?(ParametersSchema::Options.empty_keyword) && value.kind_of?(Hash) && value.empty?
|
153
|
+
error = ParametersSchema::ErrorCode::EMPTY
|
154
|
+
end
|
155
|
+
|
156
|
+
[value, error]
|
157
|
+
end
|
158
|
+
|
159
|
+
def __validate_param_value_format(value, options, allow_or_deny)
|
160
|
+
conditions = options[allow_or_deny] - [ParametersSchema::Options.empty_keyword, ParametersSchema::Options.nil_keyword]
|
161
|
+
inverse = allow_or_deny == :deny
|
162
|
+
accept_all_keyword = inverse ? ParametersSchema::Options.none_keyword : ParametersSchema::Options.any_keyword
|
163
|
+
refuse_all_keyword = inverse ? ParametersSchema::Options.any_keyword : ParametersSchema::Options.none_keyword
|
164
|
+
|
165
|
+
return [value, nil] if conditions.include?(accept_all_keyword)
|
166
|
+
return [value, ParametersSchema::ErrorCode::DISALLOWED] if conditions.include?(refuse_all_keyword)
|
167
|
+
|
168
|
+
error = nil
|
169
|
+
|
170
|
+
conditions.each do |condition|
|
171
|
+
error = nil
|
172
|
+
|
173
|
+
if condition.kind_of?(Range)
|
174
|
+
condition_passed = condition.include?(value)
|
175
|
+
condition_passed = !condition_passed if inverse
|
176
|
+
error = ParametersSchema::ErrorCode::DISALLOWED unless condition_passed
|
177
|
+
elsif condition.kind_of?(Regexp) && !value.kind_of?(String)
|
178
|
+
error = ParametersSchema::ErrorCode::DISALLOWED
|
179
|
+
elsif condition.kind_of?(Regexp) && value.kind_of?(String)
|
180
|
+
condition_passed = (condition =~ value).present?
|
181
|
+
condition_passed = !condition_passed if inverse
|
182
|
+
error = ParametersSchema::ErrorCode::DISALLOWED unless condition_passed
|
183
|
+
else
|
184
|
+
condition_passed = condition == value
|
185
|
+
condition_passed = !condition_passed if inverse
|
186
|
+
error = ParametersSchema::ErrorCode::DISALLOWED unless condition_passed
|
187
|
+
end
|
188
|
+
|
189
|
+
break if inverse ? error.present? : error.blank?
|
190
|
+
end
|
191
|
+
|
192
|
+
[value, error]
|
193
|
+
end
|
194
|
+
|
195
|
+
def __validate_type_and_cast(value, type, options, inner_params)
|
196
|
+
if type.kind_of?(Hash)
|
197
|
+
error = ParametersSchema::ErrorCode::DISALLOWED if !value.kind_of?(Array)
|
198
|
+
value, error = __validate_array(value, type.values.first, options, inner_params) unless error
|
199
|
+
elsif inner_params.present?
|
200
|
+
begin
|
201
|
+
inner_schema = ParametersSchema::Schema.new(&inner_params)
|
202
|
+
value = inner_schema.validate!(value)
|
203
|
+
rescue ParametersSchema::InvalidParameters => e
|
204
|
+
error = e.errors
|
205
|
+
end
|
206
|
+
elsif type == ParametersSchema::Options.boolean_keyword
|
207
|
+
value = true if ParametersSchema::Options.boolean_true_values.include?(value.kind_of?(String) ? value.downcase : value)
|
208
|
+
value = false if ParametersSchema::Options.boolean_false_values.include?(value.kind_of?(String) ? value.downcase : value)
|
209
|
+
error = ParametersSchema::ErrorCode::DISALLOWED if !value.kind_of?(TrueClass) && !value.kind_of?(FalseClass)
|
210
|
+
elsif type == Fixnum
|
211
|
+
error = ParametersSchema::ErrorCode::DISALLOWED if !value.numeric?
|
212
|
+
value = value.to_i if error.blank? # cast to right type.
|
213
|
+
elsif type == Float
|
214
|
+
error = ParametersSchema::ErrorCode::DISALLOWED if !value.numeric?
|
215
|
+
value = value.to_f if error.blank? # cast to right type.
|
216
|
+
elsif type == Regexp
|
217
|
+
error = ParametersSchema::ErrorCode::DISALLOWED unless value =~ options[:regex]
|
218
|
+
elsif type == ParametersSchema::Options.any_keyword
|
219
|
+
# No validation required.
|
220
|
+
elsif type == ParametersSchema::Options.none_keyword
|
221
|
+
# Always fail. Why would you want to do that?
|
222
|
+
error = ParametersSchema::ErrorCode::DISALLOWED
|
223
|
+
elsif type == String
|
224
|
+
error = ParametersSchema::ErrorCode::DISALLOWED unless value.kind_of?(String) || value.kind_of?(Symbol)
|
225
|
+
value = value.to_s if error.blank? # cast to right type.
|
226
|
+
elsif type == Symbol
|
227
|
+
error = ParametersSchema::ErrorCode::DISALLOWED unless value.respond_to?(:to_sym)
|
228
|
+
value = value.to_sym if error.blank? # cast to right type.
|
229
|
+
elsif type == Date
|
230
|
+
begin
|
231
|
+
value = value.kind_of?(String) ? Date.parse(value) : value.to_date
|
232
|
+
rescue
|
233
|
+
error = ParametersSchema::ErrorCode::DISALLOWED
|
234
|
+
end
|
235
|
+
elsif type == DateTime
|
236
|
+
begin
|
237
|
+
value = value.kind_of?(String) ? DateTime.parse(value) : value.to_datetime
|
238
|
+
rescue
|
239
|
+
error = ParametersSchema::ErrorCode::DISALLOWED
|
240
|
+
end
|
241
|
+
else
|
242
|
+
error = ParametersSchema::ErrorCode::DISALLOWED if !value.kind_of?(type)
|
243
|
+
end
|
244
|
+
|
245
|
+
[value, error]
|
246
|
+
end
|
247
|
+
|
248
|
+
def __validate_array(value, type, options, inner_params)
|
249
|
+
if !value.kind_of?(Array)
|
250
|
+
return [value, ParametersSchema::ErrorCode::DISALLOWED]
|
251
|
+
end
|
252
|
+
|
253
|
+
value_opts = {
|
254
|
+
required: true,
|
255
|
+
type: type,
|
256
|
+
parent: { value: nil },
|
257
|
+
allow: options[:allow],
|
258
|
+
deny: options[:deny]
|
259
|
+
}
|
260
|
+
|
261
|
+
value.map! do |v|
|
262
|
+
value_opts[:parent][:value] = v
|
263
|
+
__validate_param(:value, value_opts, inner_params)
|
264
|
+
end
|
265
|
+
|
266
|
+
# For now, take the first error.
|
267
|
+
[value.map{ |v| v[:value] }, value.find{ |v| v[:error].present? }.try(:[], :error)]
|
268
|
+
end
|
269
|
+
|
270
|
+
def __stop_validation(name, value, error, options)
|
271
|
+
{ param: name, error: error, value: value, keep_if_nil: options[:allow].include?(ParametersSchema::Options.nil_keyword) }
|
272
|
+
end
|
273
|
+
|
274
|
+
def __handle_errors
|
275
|
+
errors = @sanitized_params
|
276
|
+
.select{ |p| p[:error].present? }
|
277
|
+
.each_with_object({}.with_indifferent_access) do |p, h|
|
278
|
+
h[p[:param]] = p[:error] == :nested_errors ? p[:value] : p[:error]
|
279
|
+
end
|
280
|
+
|
281
|
+
(@params.keys.map(&:to_sym) - @sanitized_params.map{ |p| p[:param] }).each do |extra_param|
|
282
|
+
errors[extra_param] = ParametersSchema::ErrorCode::UNKNOWN
|
283
|
+
end
|
284
|
+
|
285
|
+
raise ParametersSchema::InvalidParameters.new(errors) if errors.any?
|
286
|
+
end
|
287
|
+
|
288
|
+
def __serve
|
289
|
+
@sanitized_params
|
290
|
+
.reject{ |p| p[:value].nil? && !p[:keep_if_nil] }
|
291
|
+
.each_with_object({}.with_indifferent_access) do |p, h|
|
292
|
+
h[p[:param]] = p[:value]
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
296
|
end
|
data/lib/parameters_schema.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
require 'active_support/core_ext/hash/indifferent_access'
|
2
|
-
require 'active_support/core_ext/object/blank'
|
3
|
-
require 'active_support/core_ext/object/try'
|
4
|
-
require 'date'
|
5
|
-
require 'parameters_schema/core_ext'
|
6
|
-
require 'parameters_schema/options'
|
7
|
-
require 'parameters_schema/exceptions'
|
8
|
-
require 'parameters_schema/schema'
|
1
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
2
|
+
require 'active_support/core_ext/object/blank'
|
3
|
+
require 'active_support/core_ext/object/try'
|
4
|
+
require 'date'
|
5
|
+
require 'parameters_schema/core_ext'
|
6
|
+
require 'parameters_schema/options'
|
7
|
+
require 'parameters_schema/exceptions'
|
8
|
+
require 'parameters_schema/schema'
|