module Grape::Validations::Types
Module for code related to grape's system for coercion and type validation of incoming request parameters.
Grape uses a number of tests and assertions
to work out exactly how a parameter should be handled, based on the
type
and coerce_with
options that may be supplied
to {Grape::Dsl::Parameters#requires} and {Grape::Dsl::Parameters#optional}.
The main entry point for this process is {Types.build_coercer}.
Constants
Public Class Methods
Work out the Virtus::Attribute
object to use for coercing
strings to the given type
. Coercion method
will
be inferred if none is supplied.
If a Virtus::Attribute
object already built with
Virtus::Attribute.build
is supplied as the type
it will be returned and method
will be ignored.
See {CustomTypeCoercer} for further details about coercion and type-checking inference.
@param type [Class] the type to which input strings
should be coerced
@param method [Class,#call] the coercion method to use @return [Virtus::Attribute] object to be used
for coercion and type validation
# File lib/grape/validations/types/build_coercer.rb, line 22 def self.build_coercer(type, method = nil) cache_instance(type, method) do create_coercer_instance(type, method) end end
# File lib/grape/validations/types/build_coercer.rb, line 74 def self.cache_instance(type, method, &_block) key = cache_key(type, method) return @__cache[key] if @__cache.key?(key) instance = yield @__cache_write_lock.synchronize do @__cache[key] = instance end instance end
# File lib/grape/validations/types/build_coercer.rb, line 88 def self.cache_key(type, method) [type, method].compact.map(&:to_s).join('_') end
Is the declared type an Array
or Set
of a
{#custom?} type?
@param type [Array<Class>,Class] type to check @return [Boolean] true
if type
is a collection of a type that implements
its own +#parse+ method.
# File lib/grape/validations/types.rb, line 166 def self.collection_of_custom?(type) (type.is_a?(Array) || type.is_a?(Set)) && type.length == 1 && custom?(type.first) end
# File lib/grape/validations/types/build_coercer.rb, line 28 def self.create_coercer_instance(type, method = nil) # Accept pre-rolled virtus attributes without interference return type if type.is_a? Virtus::Attribute converter_options = { nullify_blank: true } conversion_type = if method == JSON Object # because we want just parsed JSON content: # if type is Array and data is `"{}"` # result will be [] because Virtus converts hashes # to arrays else type end # Use a special coercer for multiply-typed parameters. if Types.multiple?(type) converter_options[:coercer] = Types::MultipleTypeCoercer.new(type, method) conversion_type = Object # Use a special coercer for custom types and coercion methods. elsif method || Types.custom?(type) converter_options[:coercer] = Types::CustomTypeCoercer.new(type, method) # Special coercer for collections of types that implement a parse method. # CustomTypeCoercer (above) already handles such types when an explicit coercion # method is supplied. elsif Types.collection_of_custom?(type) converter_options[:coercer] = Types::CustomTypeCollectionCoercer.new( type.first, type.is_a?(Set) ) # Grape swaps in its own Virtus::Attribute implementations # for certain special types that merit first-class support # (but not if a custom coercion method has been supplied). elsif Types.special?(type) conversion_type = Types::SPECIAL[type] end # Virtus will infer coercion and validation rules # for many common ruby types. Virtus::Attribute.build(conversion_type, converter_options) end
A valid custom type must implement a class-level `parse` method, taking one String argument and returning the parsed value in its correct type.
@param type [Class] type to check @return [Boolean] whether or not the type can be used as a custom type
# File lib/grape/validations/types.rb, line 151 def self.custom?(type) !primitive?(type) && !structure?(type) && !multiple?(type) && !recognized?(type) && !special?(type) && type.respond_to?(:parse) && type.method(:parse).arity == 1 end
Is the declared type a supported group type? Currently supported group types are Array, Hash, JSON, and Array
@param type [Array<Class>,Class] type to check @return [Boolean]
true
if the type is a supported group type
# File lib/grape/validations/types.rb, line 142 def self.group?(type) GROUPS.include? type end
Is the declared type in fact an array of multiple allowed types? For example the declaration +types: [Integer,String]+ will attempt first to coerce given values to integer, but will also accept any other string.
@param type [Array<Class>,Set<Class>] type (or type list!) to
check @return [Boolean] true
if the given value will be
treated as
a list of types.
# File lib/grape/validations/types.rb, line 103 def self.multiple?(type) (type.is_a?(Array) || type.is_a?(Set)) && type.size > 1 end
Does the given class implement a type system that Grape (i.e. the underlying virtus attribute
system) supports out-of-the-box? Currently supported are
axiom-types
and virtus
.
The type will be passed to Virtus::Attribute.build
, and the
resulting attribute object will be expected to respond correctly to
coerce
and value_coerced?
.
@param type [Class] type to check @return [Boolean] true
where
the type is recognized
# File lib/grape/validations/types.rb, line 118 def self.recognized?(type) return false if type.is_a?(Array) || type.is_a?(Set) type.is_a?(Virtus::Attribute) || type.ancestors.include?(Axiom::Types::Type) || type.include?(Virtus::Model::Core) end
Does Grape provide special coercion and validation routines for the given class? This does not include automatic handling for primitives, structures and otherwise recognized types. See {Types::SPECIAL}.
@param type [Class] type to check @return [Boolean] true
if
special routines are available
# File lib/grape/validations/types.rb, line 133 def self.special?(type) SPECIAL.key? type end
Is the given class a standard data structure (collection or map) as recognized by Grape?
@param type [Class] type to check @return [Boolean] whether or not the type is known by Grape as a valid
data structure type
@note This method does not yet consider 'complex types', which inherit
Virtus.model.
# File lib/grape/validations/types.rb, line 91 def self.structure?(type) STRUCTURES.include?(type) end