forked from ruby-grape/grape
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor and extend coercion and type validation
Addresses ruby-grape#1164, ruby-grape#690, ruby-grape#689, ruby-grape#693. Depends on solnic/virtus#343 `Grape::ParameterTypes` is renamed `Grape::Validations::Types` to reflect that it should probably be bundled with an eventual `grape-validations` gem. It is expanded to include two new categories of types, 'special' and 'recognized' (see 'lib/grape/validations/types.rb'). `CoerceValidator` now makes use of `Virtus::Attribute::value_coerced?`, simplifying its internals. `CustomTypeCoercer` is introduced, attempting to standardize support for custom types by decoupling coercion and type-checking logic from the `type` class supplied to `Grape::Dsl::Parameters::requires`. `JSON`, `Array[JSON]` and `Rack::Multipart::UploadedFile (a.k.a `File`) are designated 'special' types, for which special implementations of `Virtus::Attribute` are provided. Instances of `Virtus::Attribute` built with `Virtus::Attribute.build` may now also be passed as the `type` parameter for `requires`. A number of pre-rolled attributes are available providing coercion for `Date` and `DateTime` objects from various formats in `lib/grape/validations/types/date.rb` and `date_time.rb`.
- Loading branch information
Showing
16 changed files
with
690 additions
and
144 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
require_relative 'types/custom_type_coercer' | ||
require_relative 'types/json' | ||
require_relative 'types/file' | ||
|
||
module Grape | ||
module Validations | ||
module Types | ||
# Types representing a single value, which are coerced through Virtus | ||
# or special logic in Grape. | ||
PRIMITIVES = [ | ||
# Numerical | ||
Integer, | ||
Float, | ||
BigDecimal, | ||
Numeric, | ||
|
||
# Date/time | ||
Date, | ||
DateTime, | ||
Time, | ||
|
||
# Misc | ||
Virtus::Attribute::Boolean, | ||
String, | ||
Symbol, | ||
Rack::Multipart::UploadedFile | ||
] | ||
|
||
# Types representing data structures. | ||
STRUCTURES = [ | ||
Hash, | ||
Array, | ||
Set | ||
] | ||
|
||
# Types for which Grape provides special coercion | ||
# and type-checking logic. | ||
SPECIAL = { | ||
JSON => Json, | ||
Array[JSON] => JsonArray, | ||
::File => File, | ||
Rack::Multipart::UploadedFile => File | ||
} | ||
|
||
# Is the given class a primitive type as recognized by Grape? | ||
# | ||
# @param type [Class] type to check | ||
# @return [Boolean] whether or not the type is known by Grape as a valid | ||
# type for a single value | ||
def self.primitive?(type) | ||
PRIMITIVES.include?(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. | ||
def self.structure?(type) | ||
STRUCTURES.include?(type) | ||
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 | ||
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 | ||
def self.special?(type) | ||
SPECIAL.key? type | ||
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 | ||
def self.custom_type?(type) | ||
!primitive?(type) && | ||
!structure?(type) && | ||
!recognized?(type) && | ||
!special?(type) && | ||
type.respond_to?(:parse) && | ||
type.method(:parse).arity == 1 | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.