Module: Grape::Validations::Types
- Defined in:
- lib/grape/validations/types.rb,
lib/grape/validations/types/file.rb,
lib/grape/validations/types/json.rb,
lib/grape/validations/types/build_coercer.rb,
lib/grape/validations/types/custom_type_coercer.rb,
lib/grape/validations/types/multiple_type_coercer.rb,
lib/grape/validations/types/variant_collection_coercer.rb,
lib/grape/validations/types/custom_type_collection_coercer.rb
Overview
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 Dsl::Parameters#requires and Dsl::Parameters#optional. The main entry point for this process is Types.build_coercer.
Defined Under Namespace
Classes: CustomTypeCoercer, CustomTypeCollectionCoercer, File, InvalidValue, Json, JsonArray, MultipleTypeCoercer, VariantCollectionCoercer
Constant Summary collapse
- PRIMITIVES =
Types representing a single value, which are coerced through Virtus or special logic in Grape.
[ # Numerical Integer, Float, BigDecimal, Numeric, # Date/time Date, DateTime, Time, # Misc Virtus::Attribute::Boolean, String, Symbol, Rack::Multipart::UploadedFile ].freeze
- STRUCTURES =
Types representing data structures.
[ Hash, Array, Set ].freeze
- SPECIAL =
Types for which Grape provides special coercion and type-checking logic.
{ JSON => Json, Array[JSON] => JsonArray, ::File => File, Rack::Multipart::UploadedFile => File }.freeze
- GROUPS =
[ Array, Hash, JSON, Array[JSON] ].freeze
Class Method Summary collapse
-
.build_coercer(type, method = nil) ⇒ Virtus::Attribute
Work out the
Virtus::Attribute
object to use for coercing strings to the giventype
. - .cache_instance(type, method, &_block) ⇒ Object
- .cache_key(type, method) ⇒ Object
-
.collection_of_custom?(type) ⇒ Boolean
Is the declared type an
Array
orSet
of a #custom? type?. - .create_coercer_instance(type, method = nil) ⇒ Object
-
.custom?(type) ⇒ Boolean
A valid custom type must implement a class-level ‘parse` method, taking one String argument and returning the parsed value in its correct type.
-
.group?(type) ⇒ Boolean
Is the declared type a supported group type? Currently supported group types are Array, Hash, JSON, and Array.
-
.multiple?(type) ⇒ Boolean
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.
-
.primitive?(type) ⇒ Boolean
Is the given class a primitive type as recognized by Grape?.
-
.recognized?(type) ⇒ Boolean
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
andvirtus
. -
.special?(type) ⇒ Boolean
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.
-
.structure?(type) ⇒ Boolean
Is the given class a standard data structure (collection or map) as recognized by Grape?.
Class Method Details
.build_coercer(type, method = nil) ⇒ Virtus::Attribute
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.
22 23 24 25 26 |
# 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 |
.cache_instance(type, method, &_block) ⇒ Object
74 75 76 77 78 79 80 81 82 83 84 85 86 |
# 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 |
.cache_key(type, method) ⇒ Object
88 89 90 |
# File 'lib/grape/validations/types/build_coercer.rb', line 88 def self.cache_key(type, method) [type, method].compact.map(&:to_s).join('_') end |
.collection_of_custom?(type) ⇒ Boolean
Is the declared type an Array
or Set
of a #custom? type?
166 167 168 169 170 |
# 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 |
.create_coercer_instance(type, method = nil) ⇒ Object
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 |
# 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 = { 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) [:coercer] = Types::MultipleTypeCoercer.new(type, method) conversion_type = Object # Use a special coercer for custom types and coercion methods. elsif method || Types.custom?(type) [: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) [: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, ) end |
.custom?(type) ⇒ Boolean
A valid custom type must implement a class-level ‘parse` method, taking one String argument and returning the parsed value in its correct type.
151 152 153 154 155 156 157 158 159 |
# 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 |
.group?(type) ⇒ Boolean
Is the declared type a supported group type? Currently supported group types are Array, Hash, JSON, and Array
142 143 144 |
# File 'lib/grape/validations/types.rb', line 142 def self.group?(type) GROUPS.include? type end |
.multiple?(type) ⇒ Boolean
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.
103 104 105 |
# File 'lib/grape/validations/types.rb', line 103 def self.multiple?(type) (type.is_a?(Array) || type.is_a?(Set)) && type.size > 1 end |
.primitive?(type) ⇒ Boolean
Is the given class a primitive type as recognized by Grape?
79 80 81 |
# File 'lib/grape/validations/types.rb', line 79 def self.primitive?(type) PRIMITIVES.include?(type) end |
.recognized?(type) ⇒ Boolean
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?
.
118 119 120 121 122 123 124 |
# 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 |
.special?(type) ⇒ Boolean
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 SPECIAL.
133 134 135 |
# File 'lib/grape/validations/types.rb', line 133 def self.special?(type) SPECIAL.key? type end |
.structure?(type) ⇒ Boolean
This method does not yet consider ‘complex types’, which inherit Virtus.model.
Is the given class a standard data structure (collection or map) as recognized by Grape?
91 92 93 |
# File 'lib/grape/validations/types.rb', line 91 def self.structure?(type) STRUCTURES.include?(type) end |