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.



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



72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/grape/validations/types/build_coercer.rb', line 72

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



86
87
88
89
90
91
92
# File 'lib/grape/validations/types/build_coercer.rb', line 86

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?



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
67
68
69
70
# 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)
    )
  elsif type.is_a?(Array)
    ArrayCoercer.new type, strict
  elsif type.is_a?(Set)
    SetCoercer.new type, strict
  else
    PrimitiveCoercer.new 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.



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



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.



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?



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.



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?



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

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