-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Copy pathcoerce.rb
63 lines (54 loc) · 1.81 KB
/
coerce.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
module Grape
class API
Boolean = Virtus::Attribute::Boolean # rubocop:disable ConstantName
end
module Validations
class CoerceValidator < SingleOptionValidator
def validate_param!(attr_name, params)
raise Grape::Exceptions::Validation, param: @scope.full_name(attr_name), message_key: :coerce unless params.is_a? Hash
new_value = coerce_value(@option, params[attr_name])
if valid_type?(new_value)
params[attr_name] = new_value
else
raise Grape::Exceptions::Validation, param: @scope.full_name(attr_name), message_key: :coerce
end
end
class InvalidValue; end
private
def _valid_array_type?(type, values)
values.all? do |val|
_valid_single_type?(type, val)
end
end
def _valid_single_type?(klass, val)
# allow nil, to ignore when a parameter is absent
return true if val.nil?
if klass == Virtus::Attribute::Boolean
val.is_a?(TrueClass) || val.is_a?(FalseClass)
elsif klass == Rack::Multipart::UploadedFile
val.is_a?(Hashie::Mash) && val.key?(:tempfile)
else
val.is_a?(klass)
end
end
def valid_type?(val)
if @option.is_a?(Array)
_valid_array_type?(@option[0], val)
else
_valid_single_type?(@option, val)
end
end
def coerce_value(type, val)
# Don't coerce things other than nil to Arrays or Hashes
return val || [] if type == Array
return val || {} if type == Hash
converter = Virtus::Attribute.build(type)
converter.coerce(val)
# not the prettiest but some invalid coercion can currently trigger
# errors in Virtus (see coerce_spec.rb:75)
rescue
InvalidValue.new
end
end
end
end