diff --git a/CHANGELOG.md b/CHANGELOG.md index 51b0cc57a9..fbec4a5e61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ #### Fixes +* [#2219](https://github.com/ruby-grape/grape/pull/2219): Revert the changes for autoloading provided in 1.6.1 - [@dm1try](https://github.com/dm1try). * Your contribution here. ### 1.6.1 (2021/12/28) diff --git a/lib/grape.rb b/lib/grape.rb index 65333f0bc2..a48008e9da 100644 --- a/lib/grape.rb +++ b/lib/grape.rb @@ -12,14 +12,14 @@ require 'active_support/isolated_execution_state' if ActiveSupport::VERSION::MAJOR > 6 require 'active_support/core_ext/hash/indifferent_access' require 'active_support/core_ext/object/blank' -require 'active_support/core_ext/array/conversions' require 'active_support/core_ext/array/extract_options' require 'active_support/core_ext/array/wrap' -require 'active_support/core_ext/hash/conversions' +require 'active_support/core_ext/array/conversions' require 'active_support/core_ext/hash/deep_merge' -require 'active_support/core_ext/hash/except' require 'active_support/core_ext/hash/reverse_merge' +require 'active_support/core_ext/hash/except' require 'active_support/core_ext/hash/slice' +require 'active_support/core_ext/hash/conversions' require 'active_support/dependencies/autoload' require 'active_support/notifications' require 'i18n' @@ -45,7 +45,6 @@ module Grape autoload :Env, 'grape/util/env' autoload :Json, 'grape/util/json' autoload :Xml, 'grape/util/xml' - autoload :DryTypes end module Http @@ -219,59 +218,6 @@ module ServeStream autoload :StreamResponse end end - - module Validations - extend ::ActiveSupport::Autoload - - module Types - extend ::ActiveSupport::Autoload - - eager_autoload do - autoload :InvalidValue - autoload :File - autoload :Json - autoload :DryTypeCoercer - autoload :ArrayCoercer - autoload :SetCoercer - autoload :PrimitiveCoercer - autoload :CustomTypeCoercer - autoload :CustomTypeCollectionCoercer - autoload :MultipleTypeCoercer - autoload :VariantCollectionCoercer - end - end - - eager_autoload do - autoload :AttributesIterator - autoload :MultipleAttributesIterator - autoload :SingleAttributeIterator - autoload :ParamsScope - autoload :Types - autoload :ValidatorFactory - end - - module Validators - extend ::ActiveSupport::Autoload - - eager_autoload do - autoload :Base - autoload :MultipleParamsBase - autoload :AllOrNoneOfValidator - autoload :AllowBlankValidator - autoload :AsValidator - autoload :AtLeastOneOfValidator - autoload :CoerceValidator - autoload :DefaultValidator - autoload :ExactlyOneOfValidator - autoload :ExceptValuesValidator - autoload :MutualExclusionValidator - autoload :PresenceValidator - autoload :RegexpValidator - autoload :SameAsValidator - autoload :ValuesValidator - end - end - end end require 'grape/config' @@ -281,4 +227,25 @@ module Validators require 'grape/util/lazy_block' require 'grape/util/endpoint_configuration' +require 'grape/validations/validators/base' +require 'grape/validations/attributes_iterator' +require 'grape/validations/single_attribute_iterator' +require 'grape/validations/multiple_attributes_iterator' +require 'grape/validations/validators/allow_blank' +require 'grape/validations/validators/as' +require 'grape/validations/validators/at_least_one_of' +require 'grape/validations/validators/coerce' +require 'grape/validations/validators/default' +require 'grape/validations/validators/exactly_one_of' +require 'grape/validations/validators/mutual_exclusion' +require 'grape/validations/validators/presence' +require 'grape/validations/validators/regexp' +require 'grape/validations/validators/same_as' +require 'grape/validations/validators/values' +require 'grape/validations/validators/except_values' +require 'grape/validations/params_scope' +require 'grape/validations/validators/all_or_none' +require 'grape/validations/types' +require 'grape/validations/validator_factory' + require 'grape/version' diff --git a/lib/grape/dry_types.rb b/lib/grape/dry_types.rb deleted file mode 100644 index f0676c376d..0000000000 --- a/lib/grape/dry_types.rb +++ /dev/null @@ -1,12 +0,0 @@ -# frozen_string_literal: true - -require 'dry-types' - -module Grape - module DryTypes - # Call +Dry.Types()+ to add all registered types to +DryTypes+ which is - # a container in this case. Check documentation for more information - # https://dry-rb.org/gems/dry-types/1.2/getting-started/ - include Dry.Types() - end -end diff --git a/lib/grape/util/json.rb b/lib/grape/util/json.rb index 26695e92ac..9381d841a0 100644 --- a/lib/grape/util/json.rb +++ b/lib/grape/util/json.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'json' - module Grape if Object.const_defined? :MultiJson Json = ::MultiJson diff --git a/lib/grape/validations.rb b/lib/grape/validations.rb index bd55c0611f..c0736ef22c 100644 --- a/lib/grape/validations.rb +++ b/lib/grape/validations.rb @@ -1,5 +1,11 @@ # 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 diff --git a/lib/grape/validations/types.rb b/lib/grape/validations/types.rb index f822666e71..2240a7fa75 100644 --- a/lib/grape/validations/types.rb +++ b/lib/grape/validations/types.rb @@ -1,5 +1,14 @@ # frozen_string_literal: true +require_relative 'types/build_coercer' +require_relative 'types/custom_type_coercer' +require_relative 'types/custom_type_collection_coercer' +require_relative 'types/multiple_type_coercer' +require_relative 'types/variant_collection_coercer' +require_relative 'types/json' +require_relative 'types/file' +require_relative 'types/invalid_value' + module Grape module Validations # Module for code related to grape's system for @@ -134,89 +143,6 @@ def self.collection_of_custom?(type) def self.map_special(type) SPECIAL.fetch(type, type) end - - # 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. - # - # @param type [Class] the type to which input strings - # should be coerced - # @param method [Class,#call] the coercion method to use - # @return [Object] object to be used - # for coercion and type validation - def self.build_coercer(type, method: nil, strict: false) - cache_instance(type, method, strict) do - create_coercer_instance(type, method, strict) - end - end - - 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 - - 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 - - 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 - - instance_variable_set(:@__cache, {}) - instance_variable_set(:@__cache_write_lock, Mutex.new) end end end diff --git a/lib/grape/validations/types/array_coercer.rb b/lib/grape/validations/types/array_coercer.rb index 10a0761b68..d3aeb21464 100644 --- a/lib/grape/validations/types/array_coercer.rb +++ b/lib/grape/validations/types/array_coercer.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require_relative 'dry_type_coercer' + module Grape module Validations module Types diff --git a/lib/grape/validations/types/build_coercer.rb b/lib/grape/validations/types/build_coercer.rb new file mode 100644 index 0000000000..c55e048dbd --- /dev/null +++ b/lib/grape/validations/types/build_coercer.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +require_relative 'array_coercer' +require_relative 'set_coercer' +require_relative 'primitive_coercer' + +module Grape + module Validations + module Types + # 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. + # + # @param type [Class] the type to which input strings + # should be coerced + # @param method [Class,#call] the coercion method to use + # @return [Object] object to be used + # for coercion and type validation + def self.build_coercer(type, method: nil, strict: false) + cache_instance(type, method, strict) do + create_coercer_instance(type, method, strict) + end + end + + 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 + + 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 + + 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 + + instance_variable_set(:@__cache, {}) + instance_variable_set(:@__cache_write_lock, Mutex.new) + end + end +end diff --git a/lib/grape/validations/types/dry_type_coercer.rb b/lib/grape/validations/types/dry_type_coercer.rb index 3ecaea88b5..6b772378ef 100644 --- a/lib/grape/validations/types/dry_type_coercer.rb +++ b/lib/grape/validations/types/dry_type_coercer.rb @@ -1,5 +1,14 @@ # frozen_string_literal: true +require 'dry-types' + +module DryTypes + # Call +Dry.Types()+ to add all registered types to +DryTypes+ which is + # a container in this case. Check documentation for more information + # https://dry-rb.org/gems/dry-types/1.2/getting-started/ + include Dry.Types() +end + module Grape module Validations module Types @@ -43,7 +52,7 @@ def collection_coercers def initialize(type, strict = false) @type = type @strict = strict - @scope = strict ? Grape::DryTypes::Strict : Grape::DryTypes::Params + @scope = strict ? DryTypes::Strict : DryTypes::Params end # Coerces the given value to a type which was specified during diff --git a/lib/grape/validations/types/json.rb b/lib/grape/validations/types/json.rb index 61b01131ce..3240de27b6 100644 --- a/lib/grape/validations/types/json.rb +++ b/lib/grape/validations/types/json.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'json' + module Grape module Validations module Types diff --git a/lib/grape/validations/types/primitive_coercer.rb b/lib/grape/validations/types/primitive_coercer.rb index e6b02c63af..368ccff64e 100644 --- a/lib/grape/validations/types/primitive_coercer.rb +++ b/lib/grape/validations/types/primitive_coercer.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require_relative 'dry_type_coercer' + module Grape module Validations module Types @@ -8,16 +10,16 @@ module Types # that it has the proper type. class PrimitiveCoercer < DryTypeCoercer MAPPING = { - Grape::API::Boolean => Grape::DryTypes::Params::Bool, - BigDecimal => Grape::DryTypes::Params::Decimal, + Grape::API::Boolean => DryTypes::Params::Bool, + BigDecimal => DryTypes::Params::Decimal, # unfortunately, a +Params+ scope doesn't contain String - String => Grape::DryTypes::Coercible::String + String => DryTypes::Coercible::String }.freeze STRICT_MAPPING = { - Grape::API::Boolean => Grape::DryTypes::Strict::Bool, - BigDecimal => Grape::DryTypes::Strict::Decimal + Grape::API::Boolean => DryTypes::Strict::Bool, + BigDecimal => DryTypes::Strict::Decimal }.freeze def initialize(type, strict = false) diff --git a/lib/grape/validations/types/set_coercer.rb b/lib/grape/validations/types/set_coercer.rb index a6d80306d8..dc76fc7733 100644 --- a/lib/grape/validations/types/set_coercer.rb +++ b/lib/grape/validations/types/set_coercer.rb @@ -1,5 +1,8 @@ # frozen_string_literal: true +require 'set' +require_relative 'array_coercer' + module Grape module Validations module Types diff --git a/lib/grape/validations/validators/all_or_none_of_validator.rb b/lib/grape/validations/validators/all_or_none.rb similarity index 87% rename from lib/grape/validations/validators/all_or_none_of_validator.rb rename to lib/grape/validations/validators/all_or_none.rb index 2fe553a153..24dc4f8b63 100644 --- a/lib/grape/validations/validators/all_or_none_of_validator.rb +++ b/lib/grape/validations/validators/all_or_none.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'grape/validations/validators/multiple_params_base' + module Grape module Validations module Validators diff --git a/lib/grape/validations/validators/allow_blank_validator.rb b/lib/grape/validations/validators/allow_blank.rb similarity index 100% rename from lib/grape/validations/validators/allow_blank_validator.rb rename to lib/grape/validations/validators/allow_blank.rb diff --git a/lib/grape/validations/validators/as_validator.rb b/lib/grape/validations/validators/as.rb similarity index 100% rename from lib/grape/validations/validators/as_validator.rb rename to lib/grape/validations/validators/as.rb diff --git a/lib/grape/validations/validators/at_least_one_of_validator.rb b/lib/grape/validations/validators/at_least_one_of.rb similarity index 86% rename from lib/grape/validations/validators/at_least_one_of_validator.rb rename to lib/grape/validations/validators/at_least_one_of.rb index 3467e4f1db..6fedbef464 100644 --- a/lib/grape/validations/validators/at_least_one_of_validator.rb +++ b/lib/grape/validations/validators/at_least_one_of.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'grape/validations/validators/multiple_params_base' + module Grape module Validations module Validators diff --git a/lib/grape/validations/validators/coerce_validator.rb b/lib/grape/validations/validators/coerce.rb similarity index 100% rename from lib/grape/validations/validators/coerce_validator.rb rename to lib/grape/validations/validators/coerce.rb diff --git a/lib/grape/validations/validators/default_validator.rb b/lib/grape/validations/validators/default.rb similarity index 100% rename from lib/grape/validations/validators/default_validator.rb rename to lib/grape/validations/validators/default.rb diff --git a/lib/grape/validations/validators/exactly_one_of_validator.rb b/lib/grape/validations/validators/exactly_one_of.rb similarity index 89% rename from lib/grape/validations/validators/exactly_one_of_validator.rb rename to lib/grape/validations/validators/exactly_one_of.rb index 735c457019..84d6142fbf 100644 --- a/lib/grape/validations/validators/exactly_one_of_validator.rb +++ b/lib/grape/validations/validators/exactly_one_of.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'grape/validations/validators/multiple_params_base' + module Grape module Validations module Validators diff --git a/lib/grape/validations/validators/except_values_validator.rb b/lib/grape/validations/validators/except_values.rb similarity index 100% rename from lib/grape/validations/validators/except_values_validator.rb rename to lib/grape/validations/validators/except_values.rb diff --git a/lib/grape/validations/validators/mutual_exclusion_validator.rb b/lib/grape/validations/validators/mutual_exclusion.rb similarity index 86% rename from lib/grape/validations/validators/mutual_exclusion_validator.rb rename to lib/grape/validations/validators/mutual_exclusion.rb index 8d19da34c4..e0f49278b4 100644 --- a/lib/grape/validations/validators/mutual_exclusion_validator.rb +++ b/lib/grape/validations/validators/mutual_exclusion.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'grape/validations/validators/multiple_params_base' + module Grape module Validations module Validators diff --git a/lib/grape/validations/validators/presence_validator.rb b/lib/grape/validations/validators/presence.rb similarity index 100% rename from lib/grape/validations/validators/presence_validator.rb rename to lib/grape/validations/validators/presence.rb diff --git a/lib/grape/validations/validators/regexp_validator.rb b/lib/grape/validations/validators/regexp.rb similarity index 100% rename from lib/grape/validations/validators/regexp_validator.rb rename to lib/grape/validations/validators/regexp.rb diff --git a/lib/grape/validations/validators/same_as_validator.rb b/lib/grape/validations/validators/same_as.rb similarity index 100% rename from lib/grape/validations/validators/same_as_validator.rb rename to lib/grape/validations/validators/same_as.rb diff --git a/lib/grape/validations/validators/values_validator.rb b/lib/grape/validations/validators/values.rb similarity index 100% rename from lib/grape/validations/validators/values_validator.rb rename to lib/grape/validations/validators/values.rb