/
primitive_coercer.rb
73 lines (60 loc) · 2.56 KB
/
primitive_coercer.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
64
65
66
67
68
69
70
71
72
73
# frozen_string_literal: true
module Grape
module Validations
module Types
# Coerces the given value to a type defined via a +type+ argument during
# initialization. When +strict+ is true, it doesn't coerce a value but check
# that it has the proper type.
class PrimitiveCoercer < DryTypeCoercer
MAPPING = {
Grape::API::Boolean => DryTypes::Params::Bool,
BigDecimal => DryTypes::Params::Decimal,
Numeric => DryTypes::Params::Integer | DryTypes::Params::Float | DryTypes::Params::Decimal,
TrueClass => DryTypes::Params::Bool.constrained(eql: true),
FalseClass => DryTypes::Params::Bool.constrained(eql: false),
# unfortunately, a +Params+ scope doesn't contain String
String => DryTypes::Coercible::String
}.freeze
STRICT_MAPPING = {
Grape::API::Boolean => DryTypes::Strict::Bool,
BigDecimal => DryTypes::Strict::Decimal,
Numeric => DryTypes::Strict::Integer | DryTypes::Strict::Float | DryTypes::Strict::Decimal,
TrueClass => DryTypes::Strict::Bool.constrained(eql: true),
FalseClass => DryTypes::Strict::Bool.constrained(eql: false)
}.freeze
def initialize(type, strict = false)
super
@type = type
@coercer = (strict ? STRICT_MAPPING : MAPPING).fetch(type) do
scope.const_get(type.name, false)
rescue NameError
raise ArgumentError, "type #{type} should support coercion via `[]`" unless type.respond_to?(:[])
type
end
end
def call(val)
return InvalidValue.new if reject?(val)
return nil if val.nil? || treat_as_nil?(val)
super
end
protected
attr_reader :type
# This method maintains logic which was defined by Virtus. For example,
# dry-types is ok to convert an array or a hash to a string, it is supported,
# but Virtus wouldn't accept it. So, this method only exists to not introduce
# breaking changes.
def reject?(val)
(val.is_a?(Array) && type == String) ||
(val.is_a?(String) && type == Hash) ||
(val.is_a?(Hash) && type == String)
end
# Dry-Types treats an empty string as invalid. However, Grape considers an empty string as
# absence of a value and coerces it into nil. See a discussion there
# https://github.com/ruby-grape/grape/pull/2045
def treat_as_nil?(val)
val == '' && type != String
end
end
end
end
end