class Grape::Validations::Types::CustomTypeCoercer
This class will detect type classes that implement a class-level parse
method. The method should accept one String
argument and should return the value coerced to the appropriate type. The method may raise an exception if there are any problems parsing the string.
Alternately an optional method
may be supplied (see the coerce_with
option of {Grape::Dsl::Parameters#requires}). This may be any class or object implementing parse
or call
, with the same contract as described above.
Type Checking
Calls to coerced?
will consult this class to check that the coerced value produced above is in fact of the expected type. By default this class performs a basic check against the type supplied, but this behaviour will be overridden if the class implements a class-level coerced?
or parsed?
method. This method will receive a single parameter that is the coerced value and should return true
if the value meets type expectations. Arbitrary assertions may be made here but the grape validation system should be preferred.
Alternately a proc or other object responding to call
may be supplied in place of a type. This should implement the same contract as coerced?
, and must be supplied with a coercion method
.
Public Class Methods
Source
# File lib/grape/validations/types/custom_type_coercer.rb, line 43 def initialize(type, method = nil) coercion_method = infer_coercion_method type, method @method = enforce_symbolized_keys type, coercion_method @type_check = infer_type_check(type) end
A new coercer for the given type specification and coercion method.
@param type [Class,#coerced?,#parsed?,#call?]
specifier for the target type. See class docs.
@param method [#parse,#call]
optional coercion method. See class docs.
Public Instance Methods
Source
# File lib/grape/validations/types/custom_type_coercer.rb, line 54 def call(val) coerced_val = @method.call(val) return coerced_val if coerced_val.is_a?(InvalidValue) return InvalidValue.new unless coerced?(coerced_val) coerced_val end
Coerces the given value.
@param value [String] value to be coerced, in grape
this should always be a string.
@return [Object] the coerced result
Source
# File lib/grape/validations/types/custom_type_coercer.rb, line 63 def coerced?(val) val.nil? || @type_check.call(val) end
Private Instance Methods
Source
# File lib/grape/validations/types/custom_type_coercer.rb, line 138 def enforce_symbolized_keys(type, method) # Collections have all values processed individually if [Array, Set].include?(type) lambda do |val| method.call(val).tap do |new_val| new_val.map do |item| item.is_a?(Hash) ? item.deep_symbolize_keys : item end end end # Hash objects are processed directly elsif type == Hash lambda do |val| method.call(val).deep_symbolize_keys end # Simple types are not processed. # This includes Array<primitive> types. else method end end
Enforce symbolized keys for complex types by wrapping the coercion method such that any Hash objects in the immediate heirarchy have their keys recursively symbolized. This helps common libs such as JSON to work easily.
@param type see new @param method see infer_coercion_method
@return [#call] method
wrapped in an additional
key-conversion step, or just returns +method+ itself if no conversion is deemed to be necessary.
Source
# File lib/grape/validations/types/custom_type_coercer.rb, line 75 def infer_coercion_method(type, method) if method if method.respond_to? :parse method.method :parse else method end else # Try to use parse() declared on the target type. # This may raise an exception, but we are out of ideas anyway. type.method :parse end end
Determine the coercion method we’re expected to use based on the parameters given.
@param type see new @param method see new @return [#call] coercion method
Source
# File lib/grape/validations/types/custom_type_coercer.rb, line 95 def infer_type_check(type) # First check for special class methods if type.respond_to? :coerced? type.method :coerced? elsif type.respond_to? :parsed? type.method :parsed? elsif type.respond_to? :call # Arbitrary proc passed for type validation. # Note that this will fail unless a method is also # passed, or if the type also implements a parse() method. type elsif type.is_a?(Enumerable) lambda do |value| value.is_a?(Enumerable) && value.all? do |val| recursive_type_check(type.first, val) end end else # By default, do a simple type check ->(value) { value.is_a? type } end end
Determine how the type validity of a coerced value should be decided.
@param type see new @return [#call] a procedure which accepts a single parameter
and returns +true+ if the passed object is of the correct type.
Source
# File lib/grape/validations/types/custom_type_coercer.rb, line 118 def recursive_type_check(type, value) if type.is_a?(Enumerable) && value.is_a?(Enumerable) value.all? { |val| recursive_type_check(type.first, val) } else !type.is_a?(Enumerable) && value.is_a?(type) end end