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/set_coercer.rb,
lib/grape/validations/types/array_coercer.rb,
lib/grape/validations/types/build_coercer.rb,
lib/grape/validations/types/dry_type_coercer.rb,
lib/grape/validations/types/primitive_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: ArrayCoercer, CustomTypeCoercer, CustomTypeCollectionCoercer, DryTypeCoercer, File, InvalidValue, Json, JsonArray, MultipleTypeCoercer, PrimitiveCoercer, SetCoercer, VariantCollectionCoercer

Constant Summary collapse

PRIMITIVES =

Types representing a single value, which are coerced.

[
  # Numerical
  Integer,
  Float,
  BigDecimal,
  Numeric,

  # Date/time
  Date,
  DateTime,
  Time,

  # Misc
  Grape::API::Boolean,
  String,
  Symbol,
  TrueClass,
  FalseClass
].freeze
STRUCTURES =

Types representing data structures.

[
  Hash,
  Array,
  Set
].freeze
SPECIAL =

Special custom types provided by Grape.

{
  JSON => Json,
  Array[JSON] => JsonArray,
  ::File => File,
  Rack::Multipart::UploadedFile => File
}.freeze
GROUPS =
[
  Array,
  Hash,
  JSON,
  Array[JSON]
].freeze

Class Method Summary collapse

Class Method Details

.build_coercer(type, method: nil, strict: false) ⇒ Object

Chooses the best coercer for the given type. For example, if the type is Integer, it will return a coercer which will be able to coerce a value to the integer.

There are a few very special coercers which might be returned.

Grape::Types::MultipleTypeCoercer is a coercer which is returned when the given type implies values in an array with different types. For example, [Integer, String] allows integer and string values in an array.

Grape::Types::CustomTypeCoercer is a coercer which is returned when a method is specified by a user with coerce_with option or the user specifies a custom type which implements requirments of Grape::Types::CustomTypeCoercer.

Grape::Types::CustomTypeCollectionCoercer is a very similar to the previous one, but it expects an array or set of values having a custom type implemented by the user.

There is also a group of custom types implemented by Grape, check Grape::Validations::Types::SPECIAL to get the full list.

Parameters:

  • type (Class)

    the type to which input strings should be coerced

  • method (Class, #call) (defaults to: nil)

    the coercion method to use

Returns:

  • (Object)

    object to be used for coercion and type validation



38
39
40
41
42
# File 'lib/grape/validations/types/build_coercer.rb', line 38

def self.build_coercer(type, method: nil, strict: false)
  cache_instance(type, method, strict) do
    create_coercer_instance(type, method, strict)
  end
end

.cache_instance(type, method, strict, &_block) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/grape/validations/types/build_coercer.rb', line 68

def self.cache_instance(type, method, strict, &_block)
  key = cache_key(type, method, strict)

  return @__cache[key] if @__cache.key?(key)

  instance = yield

  @__cache_write_lock.synchronize do
    @__cache[key] = instance
  end

  instance
end

.cache_key(type, method, strict) ⇒ Object



82
83
84
85
86
87
88
# File 'lib/grape/validations/types/build_coercer.rb', line 82

def self.cache_key(type, method, strict)
  [type, method, strict].each_with_object(+'_') do |val, memo|
    next if val.nil?

    memo << '_' << val.to_s
  end
end

.collection_of_custom?(type) ⇒ Boolean

Is the declared type an Array or Set of a #custom? type?

Parameters:

  • type (Array<Class>, Class)

    type to check

Returns:

  • (Boolean)

    true if type is a collection of a type that implements its own #parse method.



140
141
142
143
144
# File 'lib/grape/validations/types.rb', line 140

def self.collection_of_custom?(type)
  (type.is_a?(Array) || type.is_a?(Set)) &&
    type.length == 1 &&
    (custom?(type.first) || special?(type.first))
end

.create_coercer_instance(type, method, strict) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/grape/validations/types/build_coercer.rb', line 44

def self.create_coercer_instance(type, method, strict)
  # Maps a custom type provided by Grape, it doesn't map types wrapped by collections!!!
  type = Types.map_special(type)

  # Use a special coercer for multiply-typed parameters.
  if Types.multiple?(type)
    MultipleTypeCoercer.new(type, method)

  # Use a special coercer for custom types and coercion methods.
  elsif method || Types.custom?(type)
    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)
    Types::CustomTypeCollectionCoercer.new(
      Types.map_special(type.first), type.is_a?(Set)
    )
  else
    DryTypeCoercer.coercer_instance_for(type, strict)
  end
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.

Parameters:

  • type (Class)

    type to check

Returns:

  • (Boolean)

    whether or not the type can be used as a custom type



127
128
129
130
131
132
133
# File 'lib/grape/validations/types.rb', line 127

def self.custom?(type)
  !primitive?(type) &&
    !structure?(type) &&
    !multiple?(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

Parameters:

  • type (Array<Class>, Class)

    type to check

Returns:

  • (Boolean)

    true if the type is a supported group type



118
119
120
# File 'lib/grape/validations/types.rb', line 118

def self.group?(type)
  GROUPS.include? type
end

.map_special(type) ⇒ Object



146
147
148
# File 'lib/grape/validations/types.rb', line 146

def self.map_special(type)
  SPECIAL.fetch(type, 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.

Parameters:

  • type (Array<Class>, Set<Class>)

    type (or type list!) to check

Returns:

  • (Boolean)

    true if the given value will be treated as a list of types.



98
99
100
# File 'lib/grape/validations/types.rb', line 98

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?

Parameters:

  • type (Class)

    type to check

Returns:

  • (Boolean)

    whether or not the type is known by Grape as a valid type for a single value



76
77
78
# File 'lib/grape/validations/types.rb', line 76

def self.primitive?(type)
  PRIMITIVES.include?(type)
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.

Parameters:

  • type (Class)

    type to check

Returns:

  • (Boolean)

    true if special routines are available



109
110
111
# File 'lib/grape/validations/types.rb', line 109

def self.special?(type)
  SPECIAL.key? type
end

.structure?(type) ⇒ Boolean

Is the given class a standard data structure (collection or map) as recognized by Grape?

Parameters:

  • type (Class)

    type to check

Returns:

  • (Boolean)

    whether or not the type is known by Grape as a valid data structure type



86
87
88
# File 'lib/grape/validations/types.rb', line 86

def self.structure?(type)
  STRUCTURES.include?(type)
end