Skip to content

Commit

Permalink
Put back types as constants
Browse files Browse the repository at this point in the history
Add spec for SPECIAL types
Rename find_lazy_validator -> require_validator
Use const_get instead of constantize
Remove spec/support/eager_load.rb
  • Loading branch information
ericproulx committed Jan 2, 2022
1 parent 2f8e53e commit 38d7e42
Show file tree
Hide file tree
Showing 10 changed files with 81 additions and 87 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

#### Fixes

* [#2222](/~https://github.com/ruby-grape/grape/pull/2222): Fix autoload types and validators - [@ericproulx](/~https://github.com/ericproulx).
* [#2222](/~https://github.com/ruby-grape/grape/pull/2222): autoload types and validators - [@ericproulx](/~https://github.com/ericproulx).
* Your contribution here.

### 1.6.2 (2021/12/30)
Expand Down
3 changes: 0 additions & 3 deletions lib/grape.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
require 'active_support/core_ext/hash/reverse_merge'
require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/object/blank'
require 'active_support/inflector/methods'
require 'active_support/dependencies/autoload'
require 'active_support/notifications'
require 'i18n'
Expand Down Expand Up @@ -238,8 +237,6 @@ module Types

eager_autoload do
autoload :InvalidValue
autoload :File
autoload :Json
autoload :DryTypeCoercer
autoload :ArrayCoercer
autoload :SetCoercer
Expand Down
10 changes: 2 additions & 8 deletions lib/grape/validations.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
# frozen_string_literal: true

require 'grape/validations/attributes_iterator'
require 'grape/validations/single_attribute_iterator'
require 'grape/validations/multiple_attributes_iterator'
require 'grape/validations/params_scope'
require 'grape/validations/types'

module Grape
# Registry to store and locate known Validators.
module Validations
Expand All @@ -28,10 +22,10 @@ def deregister_validator(short_name)
end

# Find a validator and if not found will try to load it
def lazy_find_validator(short_name)
def require_validator(short_name)
str_name = short_name.to_s
validators.fetch(str_name) do
register_validator(str_name, "Grape::Validations::Validators::#{str_name.camelize}Validator".constantize)
Grape::Validations::Validators.const_get("#{str_name.camelize}Validator")
end
rescue NameError
raise Grape::Exceptions::UnknownValidator.new(short_name)
Expand Down
2 changes: 1 addition & 1 deletion lib/grape/validations/params_scope.rb
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ def validate(type, options, attrs, doc_attrs, opts)
required: doc_attrs[:required],
params_scope: self,
opts: opts,
validator_class: Validations.lazy_find_validator(type)
validator_class: Validations.require_validator(type)
}
@api.namespace_stackable(:validations, validator_options)
end
Expand Down
86 changes: 40 additions & 46 deletions lib/grape/validations/types.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# frozen_string_literal: true

require 'grape/validations/types/json'
require 'grape/validations/types/file'

module Grape
module Validations
# Module for code related to grape's system for
Expand All @@ -15,35 +18,45 @@ module Validations
module Types
module_function

PRIMITIVES = [
# Numerical
Integer,
Float,
BigDecimal,
Numeric,

# Date/time
Date,
DateTime,
Time,

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

# Types representing data structures.
STRUCTURES = [Hash, Array, Set].freeze

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

GROUPS = [Array, Hash, JSON, Array[JSON]].freeze

# 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 primitive?(type)
primitives.include?(type)
end

def primitives
@primitives ||= [
# Numerical
Integer,
Float,
BigDecimal,
Numeric,

# Date/time
Date,
DateTime,
Time,

# Misc
Grape::API::Boolean,
String,
Symbol,
TrueClass,
FalseClass
].freeze
PRIMITIVES.include?(type)
end

# Is the given class a standard data structure (collection or map)
Expand All @@ -53,12 +66,7 @@ def primitives
# @return [Boolean] whether or not the type is known by Grape as a valid
# data structure type
def structure?(type)
structures.include?(type)
end

# Types representing data structures.
def structures
@structures ||= [Hash, Array, Set].freeze
STRUCTURES.include?(type)
end

# Is the declared type in fact an array of multiple allowed types?
Expand All @@ -81,17 +89,7 @@ def multiple?(type)
# @param type [Class] type to check
# @return [Boolean] +true+ if special routines are available
def special?(type)
specials.key? type
end

def specials
# Special custom types provided by Grape.
@specials ||= {
JSON => Json,
Array[JSON] => JsonArray,
::File => File,
Rack::Multipart::UploadedFile => File
}.freeze
SPECIAL.key? type
end

# Is the declared type a supported group type?
Expand All @@ -100,11 +98,7 @@ def specials
# @param type [Array<Class>,Class] type to check
# @return [Boolean] +true+ if the type is a supported group type
def group?(type)
groups.include? type
end

def groups
@groups ||= [Array, Hash, JSON, Array[JSON]].freeze
GROUPS.include? type
end

# A valid custom type must implement a class-level `parse` method, taking
Expand Down Expand Up @@ -132,7 +126,7 @@ def collection_of_custom?(type)
end

def map_special(type)
specials.fetch(type, type)
SPECIAL.fetch(type, type)
end

# Chooses the best coercer for the given type. For example, if the type
Expand Down
2 changes: 1 addition & 1 deletion lib/grape/validations/types/dry_type_coercer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class << self
# #=> Grape::Validations::Types::ArrayCoercer
def collection_coercer_for(type)
collection_coercers.fetch(type) do
DryTypeCoercer.collection_coercers[type] = "Grape::Validations::Types::#{type.name.camelize}Coercer".constantize
DryTypeCoercer.collection_coercers[type] = Grape::Validations::Types.const_get("#{type.name.camelize}Coercer")
end
end

Expand Down
28 changes: 28 additions & 0 deletions spec/grape/validations/types_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,34 @@ def self.parse; end
end
end

describe 'special types' do
subject { described_class::SPECIAL[type] }

context 'when JSON' do
let(:type) { JSON }

it { is_expected.to eq(Grape::Validations::Types::Json) }
end

context 'when Array[JSON]' do
let(:type) { Array[JSON] }

it { is_expected.to eq(Grape::Validations::Types::JsonArray) }
end

context 'when File' do
let(:type) { File }

it { is_expected.to eq(Grape::Validations::Types::File) }
end

context 'when Rack::Multipart::UploadedFile' do
let(:type) { Rack::Multipart::UploadedFile }

it { is_expected.to eq(Grape::Validations::Types::File) }
end
end

describe '::custom?' do
it 'returns false if the type does not respond to :parse' do
expect(described_class).not_to be_custom(Object)
Expand Down
12 changes: 6 additions & 6 deletions spec/grape/validations/validators/coerce_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ def self.parse(_val)

context 'nil values' do
context 'primitive types' do
Grape::Validations::Types.primitives.each do |type|
Grape::Validations::Types::PRIMITIVES.each do |type|
it 'respects the nil value' do
subject.params do
requires :param, type: type
Expand All @@ -473,7 +473,7 @@ def self.parse(_val)
end

context 'structures types' do
Grape::Validations::Types.structures.each do |type|
Grape::Validations::Types::STRUCTURES.each do |type|
it 'respects the nil value' do
subject.params do
requires :param, type: type
Expand All @@ -490,7 +490,7 @@ def self.parse(_val)
end

context 'special types' do
Grape::Validations::Types.specials.each_key do |type|
Grape::Validations::Types::SPECIAL.each_key do |type|
it 'respects the nil value' do
subject.params do
requires :param, type: type
Expand Down Expand Up @@ -529,7 +529,7 @@ def self.parse(_val)

context 'empty string' do
context 'primitive types' do
(Grape::Validations::Types.primitives - [String]).each do |type|
(Grape::Validations::Types::PRIMITIVES - [String]).each do |type|
it "is coerced to nil for type #{type}" do
subject.params do
requires :param, type: type
Expand Down Expand Up @@ -559,7 +559,7 @@ def self.parse(_val)
end

context 'structures types' do
(Grape::Validations::Types.structures - [Hash]).each do |type|
(Grape::Validations::Types::STRUCTURES - [Hash]).each do |type|
it "is coerced to nil for type #{type}" do
subject.params do
requires :param, type: type
Expand All @@ -576,7 +576,7 @@ def self.parse(_val)
end

context 'special types' do
(Grape::Validations::Types.specials.keys - [File, Rack::Multipart::UploadedFile]).each do |type|
(Grape::Validations::Types::SPECIAL.keys - [File, Rack::Multipart::UploadedFile]).each do |type|
it "is coerced to nil for type #{type}" do
subject.params do
requires :param, type: type
Expand Down
4 changes: 2 additions & 2 deletions spec/grape/validations_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1976,8 +1976,8 @@ def validate_param!(attr_name, params)
end
end

describe 'lazy_find_validator' do
subject { described_class.lazy_find_validator(short_name) }
describe 'require_validator' do
subject { described_class.require_validator(short_name) }

context 'when found' do
let(:short_name) { :presence }
Expand Down
19 changes: 0 additions & 19 deletions spec/support/eager_load.rb

This file was deleted.

0 comments on commit 38d7e42

Please sign in to comment.