grape 2.0.0 → 2.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +61 -1
- data/README.md +362 -316
- data/UPGRADING.md +197 -7
- data/grape.gemspec +5 -6
- data/lib/grape/api/instance.rb +13 -10
- data/lib/grape/api.rb +17 -8
- data/lib/grape/content_types.rb +0 -2
- data/lib/grape/cookies.rb +2 -1
- data/lib/grape/dry_types.rb +0 -2
- data/lib/grape/dsl/desc.rb +22 -20
- data/lib/grape/dsl/headers.rb +1 -1
- data/lib/grape/dsl/inside_route.rb +42 -13
- data/lib/grape/dsl/parameters.rb +4 -3
- data/lib/grape/dsl/routing.rb +20 -4
- data/lib/grape/dsl/validations.rb +13 -0
- data/lib/grape/endpoint.rb +12 -15
- data/lib/grape/{util/env.rb → env.rb} +0 -5
- data/lib/grape/error_formatter/txt.rb +11 -10
- data/lib/grape/exceptions/base.rb +3 -3
- data/lib/grape/exceptions/validation.rb +0 -2
- data/lib/grape/exceptions/validation_array_errors.rb +1 -0
- data/lib/grape/exceptions/validation_errors.rb +1 -3
- data/lib/grape/extensions/hash.rb +5 -1
- data/lib/grape/http/headers.rb +18 -34
- data/lib/grape/{util/json.rb → json.rb} +1 -3
- data/lib/grape/locale/en.yml +3 -0
- data/lib/grape/middleware/auth/base.rb +0 -2
- data/lib/grape/middleware/auth/dsl.rb +0 -2
- data/lib/grape/middleware/base.rb +0 -2
- data/lib/grape/middleware/error.rb +55 -50
- data/lib/grape/middleware/formatter.rb +16 -13
- data/lib/grape/middleware/globals.rb +1 -3
- data/lib/grape/middleware/stack.rb +2 -3
- data/lib/grape/middleware/versioner/accept_version_header.rb +0 -2
- data/lib/grape/middleware/versioner/header.rb +17 -163
- data/lib/grape/middleware/versioner/param.rb +2 -4
- data/lib/grape/middleware/versioner/path.rb +1 -3
- data/lib/grape/namespace.rb +3 -4
- data/lib/grape/path.rb +24 -29
- data/lib/grape/request.rb +4 -12
- data/lib/grape/router/base_route.rb +39 -0
- data/lib/grape/router/greedy_route.rb +20 -0
- data/lib/grape/router/pattern.rb +39 -30
- data/lib/grape/router/route.rb +22 -59
- data/lib/grape/router.rb +32 -37
- data/lib/grape/util/accept/header.rb +19 -0
- data/lib/grape/util/accept_header_handler.rb +105 -0
- data/lib/grape/util/base_inheritable.rb +4 -4
- data/lib/grape/util/cache.rb +0 -3
- data/lib/grape/util/endpoint_configuration.rb +1 -1
- data/lib/grape/util/header.rb +13 -0
- data/lib/grape/util/inheritable_values.rb +0 -2
- data/lib/grape/util/lazy/block.rb +29 -0
- data/lib/grape/util/lazy/object.rb +45 -0
- data/lib/grape/util/lazy/value.rb +38 -0
- data/lib/grape/util/lazy/value_array.rb +21 -0
- data/lib/grape/util/lazy/value_enumerable.rb +34 -0
- data/lib/grape/util/lazy/value_hash.rb +21 -0
- data/lib/grape/util/media_type.rb +70 -0
- data/lib/grape/util/reverse_stackable_values.rb +1 -6
- data/lib/grape/util/stackable_values.rb +1 -6
- data/lib/grape/util/strict_hash_configuration.rb +3 -3
- data/lib/grape/validations/attributes_doc.rb +38 -36
- data/lib/grape/validations/contract_scope.rb +71 -0
- data/lib/grape/validations/params_scope.rb +10 -9
- data/lib/grape/validations/types/array_coercer.rb +0 -2
- data/lib/grape/validations/types/build_coercer.rb +69 -71
- data/lib/grape/validations/types/dry_type_coercer.rb +1 -11
- data/lib/grape/validations/types/json.rb +0 -2
- data/lib/grape/validations/types/primitive_coercer.rb +0 -2
- data/lib/grape/validations/types/set_coercer.rb +0 -3
- data/lib/grape/validations/types.rb +0 -3
- data/lib/grape/validations/validators/base.rb +1 -0
- data/lib/grape/validations/validators/default_validator.rb +5 -1
- data/lib/grape/validations/validators/length_validator.rb +42 -0
- data/lib/grape/validations/validators/values_validator.rb +6 -1
- data/lib/grape/validations.rb +3 -7
- data/lib/grape/version.rb +1 -1
- data/lib/grape/{util/xml.rb → xml.rb} +1 -1
- data/lib/grape.rb +30 -274
- metadata +31 -37
- data/lib/grape/eager_load.rb +0 -20
- data/lib/grape/middleware/versioner/parse_media_type_patch.rb +0 -24
- data/lib/grape/router/attribute_translator.rb +0 -63
- data/lib/grape/util/lazy_block.rb +0 -27
- data/lib/grape/util/lazy_object.rb +0 -43
- data/lib/grape/util/lazy_value.rb +0 -91
@@ -2,56 +2,58 @@
|
|
2
2
|
|
3
3
|
module Grape
|
4
4
|
module Validations
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
5
|
+
# Documents parameters of an endpoint. If documentation isn't needed (for instance, it is an
|
6
|
+
# internal API), the class only cleans up attributes to avoid junk in RAM.
|
7
|
+
|
8
|
+
class AttributesDoc
|
9
|
+
attr_accessor :type, :values
|
10
|
+
|
11
|
+
# @param api [Grape::API::Instance]
|
12
|
+
# @param scope [Validations::ParamsScope]
|
13
|
+
def initialize(api, scope)
|
14
|
+
@api = api
|
15
|
+
@scope = scope
|
16
|
+
@type = type
|
17
|
+
end
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
def extract_details(validations)
|
20
|
+
details[:required] = validations.key?(:presence)
|
21
21
|
|
22
|
-
|
22
|
+
desc = validations.delete(:desc) || validations.delete(:description)
|
23
23
|
|
24
|
-
|
24
|
+
details[:desc] = desc if desc
|
25
25
|
|
26
|
-
|
26
|
+
documentation = validations.delete(:documentation)
|
27
27
|
|
28
|
-
|
28
|
+
details[:documentation] = documentation if documentation
|
29
29
|
|
30
|
-
|
31
|
-
end
|
30
|
+
details[:default] = validations[:default] if validations.key?(:default)
|
32
31
|
|
33
|
-
|
34
|
-
|
32
|
+
details[:min_length] = validations[:length][:min] if validations.key?(:length) && validations[:length].key?(:min)
|
33
|
+
details[:max_length] = validations[:length][:max] if validations.key?(:length) && validations[:length].key?(:max)
|
34
|
+
end
|
35
35
|
|
36
|
-
|
37
|
-
|
36
|
+
def document(attrs)
|
37
|
+
return if @api.namespace_inheritable(:do_not_document)
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
end
|
39
|
+
details[:type] = type.to_s if type
|
40
|
+
details[:values] = values if values
|
42
41
|
|
43
|
-
|
42
|
+
documented_attrs = attrs.each_with_object({}) do |name, memo|
|
43
|
+
memo[@scope.full_name(name)] = details
|
44
44
|
end
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
@api.namespace_stackable(:params, documented_attrs)
|
47
|
+
end
|
48
|
+
|
49
|
+
def required
|
50
|
+
details[:required]
|
51
|
+
end
|
49
52
|
|
50
|
-
|
53
|
+
protected
|
51
54
|
|
52
|
-
|
53
|
-
|
54
|
-
end
|
55
|
+
def details
|
56
|
+
@details ||= {}
|
55
57
|
end
|
56
58
|
end
|
57
59
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grape
|
4
|
+
module Validations
|
5
|
+
class ContractScope
|
6
|
+
# Declare the contract to be used for the endpoint's parameters.
|
7
|
+
# @param api [API] the API endpoint to modify.
|
8
|
+
# @param contract the contract or schema to be used for validation. Optional.
|
9
|
+
# @yield a block yielding a new schema class. Optional.
|
10
|
+
def initialize(api, contract = nil, &block)
|
11
|
+
# When block is passed, the first arg is either schema or nil.
|
12
|
+
contract = Dry::Schema.Params(parent: contract, &block) if block
|
13
|
+
|
14
|
+
if contract.respond_to?(:schema)
|
15
|
+
# It's a Dry::Validation::Contract, then.
|
16
|
+
contract = contract.new
|
17
|
+
key_map = contract.schema.key_map
|
18
|
+
else
|
19
|
+
# Dry::Schema::Processor, hopefully.
|
20
|
+
key_map = contract.key_map
|
21
|
+
end
|
22
|
+
|
23
|
+
api.namespace_stackable(:contract_key_map, key_map)
|
24
|
+
|
25
|
+
validator_options = {
|
26
|
+
validator_class: Validator,
|
27
|
+
opts: { schema: contract }
|
28
|
+
}
|
29
|
+
|
30
|
+
api.namespace_stackable(:validations, validator_options)
|
31
|
+
end
|
32
|
+
|
33
|
+
class Validator
|
34
|
+
attr_reader :schema
|
35
|
+
|
36
|
+
def initialize(*_args, schema:)
|
37
|
+
@schema = schema
|
38
|
+
end
|
39
|
+
|
40
|
+
# Validates a given request.
|
41
|
+
# @param request [Grape::Request] the request currently being handled
|
42
|
+
# @raise [Grape::Exceptions::ValidationArrayErrors] if validation failed
|
43
|
+
# @return [void]
|
44
|
+
def validate(request)
|
45
|
+
res = schema.call(request.params)
|
46
|
+
|
47
|
+
if res.success?
|
48
|
+
request.params.deep_merge!(res.to_h)
|
49
|
+
return
|
50
|
+
end
|
51
|
+
|
52
|
+
errors = []
|
53
|
+
|
54
|
+
res.errors.messages.each do |message|
|
55
|
+
full_name = message.path.first.to_s
|
56
|
+
|
57
|
+
full_name += "[#{message.path[1..].join('][')}]" if message.path.size > 1
|
58
|
+
|
59
|
+
errors << Grape::Exceptions::Validation.new(params: [full_name], message: message.text)
|
60
|
+
end
|
61
|
+
|
62
|
+
raise Grape::Exceptions::ValidationArrayErrors.new(errors)
|
63
|
+
end
|
64
|
+
|
65
|
+
def fail_fast?
|
66
|
+
false
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'attributes_doc'
|
4
|
-
|
5
3
|
module Grape
|
6
4
|
module Validations
|
7
5
|
class ParamsScope
|
@@ -211,11 +209,11 @@ module Grape
|
|
211
209
|
|
212
210
|
def require_required_and_optional_fields(context, opts)
|
213
211
|
if context == :all
|
214
|
-
optional_fields = Array(opts[:except])
|
215
|
-
required_fields = opts[:using].keys
|
212
|
+
optional_fields = Array.wrap(opts[:except])
|
213
|
+
required_fields = opts[:using].keys.delete_if { |f| optional_fields.include?(f) }
|
216
214
|
else # context == :none
|
217
|
-
required_fields = Array(opts[:except])
|
218
|
-
optional_fields = opts[:using].keys
|
215
|
+
required_fields = Array.wrap(opts[:except])
|
216
|
+
optional_fields = opts[:using].keys.delete_if { |f| required_fields.include?(f) }
|
219
217
|
end
|
220
218
|
required_fields.each do |field|
|
221
219
|
field_opts = opts[:using][field]
|
@@ -231,7 +229,10 @@ module Grape
|
|
231
229
|
|
232
230
|
def require_optional_fields(context, opts)
|
233
231
|
optional_fields = opts[:using].keys
|
234
|
-
|
232
|
+
unless context == :all
|
233
|
+
except_fields = Array.wrap(opts[:except])
|
234
|
+
optional_fields.delete_if { |f| except_fields.include?(f) }
|
235
|
+
end
|
235
236
|
optional_fields.each do |field|
|
236
237
|
field_opts = opts[:using][field]
|
237
238
|
optional(field, field_opts) if field_opts
|
@@ -266,6 +267,7 @@ module Grape
|
|
266
267
|
parent: self,
|
267
268
|
optional: optional,
|
268
269
|
type: type || Array,
|
270
|
+
group: @group,
|
269
271
|
&block
|
270
272
|
)
|
271
273
|
end
|
@@ -463,8 +465,7 @@ module Grape
|
|
463
465
|
raise Grape::Exceptions::IncompatibleOptionValues.new(:default, default, :values, values) if values && !values.is_a?(Proc) && !Array(default).all? { |def_val| values.include?(def_val) }
|
464
466
|
|
465
467
|
if except_values && !except_values.is_a?(Proc) && Array(default).any? { |def_val| except_values.include?(def_val) }
|
466
|
-
raise Grape::Exceptions::IncompatibleOptionValues.new(:default, default, :except, except_values)
|
467
|
-
|
468
|
+
raise Grape::Exceptions::IncompatibleOptionValues.new(:default, default, :except, except_values)
|
468
469
|
end
|
469
470
|
|
470
471
|
return unless excepts && !excepts.is_a?(Proc)
|
@@ -1,94 +1,92 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'array_coercer'
|
4
|
-
require_relative 'set_coercer'
|
5
|
-
require_relative 'primitive_coercer'
|
6
|
-
|
7
3
|
module Grape
|
8
4
|
module Validations
|
9
5
|
module Types
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
6
|
+
module BuildCoercer
|
7
|
+
# Chooses the best coercer for the given type. For example, if the type
|
8
|
+
# is Integer, it will return a coercer which will be able to coerce a value
|
9
|
+
# to the integer.
|
10
|
+
#
|
11
|
+
# There are a few very special coercers which might be returned.
|
12
|
+
#
|
13
|
+
# +Grape::Types::MultipleTypeCoercer+ is a coercer which is returned when
|
14
|
+
# the given type implies values in an array with different types.
|
15
|
+
# For example, +[Integer, String]+ allows integer and string values in
|
16
|
+
# an array.
|
17
|
+
#
|
18
|
+
# +Grape::Types::CustomTypeCoercer+ is a coercer which is returned when
|
19
|
+
# a method is specified by a user with +coerce_with+ option or the user
|
20
|
+
# specifies a custom type which implements requirments of
|
21
|
+
# +Grape::Types::CustomTypeCoercer+.
|
22
|
+
#
|
23
|
+
# +Grape::Types::CustomTypeCollectionCoercer+ is a very similar to the
|
24
|
+
# previous one, but it expects an array or set of values having a custom
|
25
|
+
# type implemented by the user.
|
26
|
+
#
|
27
|
+
# There is also a group of custom types implemented by Grape, check
|
28
|
+
# +Grape::Validations::Types::SPECIAL+ to get the full list.
|
29
|
+
#
|
30
|
+
# @param type [Class] the type to which input strings
|
31
|
+
# should be coerced
|
32
|
+
# @param method [Class,#call] the coercion method to use
|
33
|
+
# @return [Object] object to be used
|
34
|
+
# for coercion and type validation
|
35
|
+
def self.build_coercer(type, method: nil, strict: false)
|
36
|
+
cache_instance(type, method, strict) do
|
37
|
+
create_coercer_instance(type, method, strict)
|
38
|
+
end
|
41
39
|
end
|
42
|
-
end
|
43
40
|
|
44
|
-
|
45
|
-
|
46
|
-
|
41
|
+
def self.create_coercer_instance(type, method, strict)
|
42
|
+
# Maps a custom type provided by Grape, it doesn't map types wrapped by collections!!!
|
43
|
+
type = Types.map_special(type)
|
47
44
|
|
48
|
-
|
49
|
-
|
50
|
-
|
45
|
+
# Use a special coercer for multiply-typed parameters.
|
46
|
+
if Types.multiple?(type)
|
47
|
+
MultipleTypeCoercer.new(type, method)
|
51
48
|
|
52
|
-
|
53
|
-
|
54
|
-
|
49
|
+
# Use a special coercer for custom types and coercion methods.
|
50
|
+
elsif method || Types.custom?(type)
|
51
|
+
CustomTypeCoercer.new(type, method)
|
55
52
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
53
|
+
# Special coercer for collections of types that implement a parse method.
|
54
|
+
# CustomTypeCoercer (above) already handles such types when an explicit coercion
|
55
|
+
# method is supplied.
|
56
|
+
elsif Types.collection_of_custom?(type)
|
57
|
+
Types::CustomTypeCollectionCoercer.new(
|
58
|
+
Types.map_special(type.first), type.is_a?(Set)
|
59
|
+
)
|
60
|
+
else
|
61
|
+
DryTypeCoercer.coercer_instance_for(type, strict)
|
62
|
+
end
|
65
63
|
end
|
66
|
-
end
|
67
64
|
|
68
|
-
|
69
|
-
|
65
|
+
def self.cache_instance(type, method, strict, &_block)
|
66
|
+
key = cache_key(type, method, strict)
|
70
67
|
|
71
|
-
|
68
|
+
return @__cache[key] if @__cache.key?(key)
|
72
69
|
|
73
|
-
|
70
|
+
instance = yield
|
74
71
|
|
75
|
-
|
76
|
-
|
77
|
-
|
72
|
+
@__cache_write_lock.synchronize do
|
73
|
+
@__cache[key] = instance
|
74
|
+
end
|
78
75
|
|
79
|
-
|
80
|
-
|
76
|
+
instance
|
77
|
+
end
|
81
78
|
|
82
|
-
|
83
|
-
|
84
|
-
|
79
|
+
def self.cache_key(type, method, strict)
|
80
|
+
[type, method, strict].each_with_object(+'_') do |val, memo|
|
81
|
+
next if val.nil?
|
85
82
|
|
86
|
-
|
83
|
+
memo << '_' << val.to_s
|
84
|
+
end
|
87
85
|
end
|
88
|
-
end
|
89
86
|
|
90
|
-
|
91
|
-
|
87
|
+
instance_variable_set(:@__cache, {})
|
88
|
+
instance_variable_set(:@__cache_write_lock, Mutex.new)
|
89
|
+
end
|
92
90
|
end
|
93
91
|
end
|
94
92
|
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'dry-types'
|
4
|
-
|
5
3
|
module DryTypes
|
6
4
|
# Call +Dry.Types()+ to add all registered types to +DryTypes+ which is
|
7
5
|
# a container in this case. Check documentation for more information
|
@@ -24,9 +22,7 @@ module Grape
|
|
24
22
|
# collection_coercer_for(Array)
|
25
23
|
# #=> Grape::Validations::Types::ArrayCoercer
|
26
24
|
def collection_coercer_for(type)
|
27
|
-
|
28
|
-
DryTypeCoercer.collection_coercers[type] = Grape::Validations::Types.const_get("#{type.name.camelize}Coercer")
|
29
|
-
end
|
25
|
+
Grape::Validations::Types.const_get(:"#{type.name.camelize}Coercer")
|
30
26
|
end
|
31
27
|
|
32
28
|
# Returns an instance of a coercer for a given type
|
@@ -37,12 +33,6 @@ module Grape
|
|
37
33
|
# so we need to figure out the actual type
|
38
34
|
collection_coercer_for(type.class).new(type, strict)
|
39
35
|
end
|
40
|
-
|
41
|
-
protected
|
42
|
-
|
43
|
-
def collection_coercers
|
44
|
-
@collection_coercers ||= {}
|
45
|
-
end
|
46
36
|
end
|
47
37
|
|
48
38
|
def initialize(type, strict = false)
|
@@ -11,7 +11,11 @@ module Grape
|
|
11
11
|
|
12
12
|
def validate_param!(attr_name, params)
|
13
13
|
params[attr_name] = if @default.is_a? Proc
|
14
|
-
@default.
|
14
|
+
if @default.parameters.empty?
|
15
|
+
@default.call
|
16
|
+
else
|
17
|
+
@default.call(params)
|
18
|
+
end
|
15
19
|
elsif @default.frozen? || !@default.duplicable?
|
16
20
|
@default
|
17
21
|
else
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grape
|
4
|
+
module Validations
|
5
|
+
module Validators
|
6
|
+
class LengthValidator < Base
|
7
|
+
def initialize(attrs, options, required, scope, **opts)
|
8
|
+
@min = options[:min]
|
9
|
+
@max = options[:max]
|
10
|
+
|
11
|
+
super
|
12
|
+
|
13
|
+
raise ArgumentError, 'min must be an integer greater than or equal to zero' if !@min.nil? && (!@min.is_a?(Integer) || @min.negative?)
|
14
|
+
raise ArgumentError, 'max must be an integer greater than or equal to zero' if !@max.nil? && (!@max.is_a?(Integer) || @max.negative?)
|
15
|
+
raise ArgumentError, "min #{@min} cannot be greater than max #{@max}" if !@min.nil? && !@max.nil? && @min > @max
|
16
|
+
end
|
17
|
+
|
18
|
+
def validate_param!(attr_name, params)
|
19
|
+
param = params[attr_name]
|
20
|
+
|
21
|
+
raise ArgumentError, "parameter #{param} does not support #length" unless param.respond_to?(:length)
|
22
|
+
|
23
|
+
return unless (!@min.nil? && param.length < @min) || (!@max.nil? && param.length > @max)
|
24
|
+
|
25
|
+
raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: build_message)
|
26
|
+
end
|
27
|
+
|
28
|
+
def build_message
|
29
|
+
if options_key?(:message)
|
30
|
+
@option[:message]
|
31
|
+
elsif @min && @max
|
32
|
+
format I18n.t(:length, scope: 'grape.errors.messages'), min: @min, max: @max
|
33
|
+
elsif @min
|
34
|
+
format I18n.t(:length_min, scope: 'grape.errors.messages'), min: @min
|
35
|
+
else
|
36
|
+
format I18n.t(:length_max, scope: 'grape.errors.messages'), max: @max
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -85,7 +85,12 @@ module Grape
|
|
85
85
|
end
|
86
86
|
|
87
87
|
def required_for_root_scope?
|
88
|
-
|
88
|
+
return false unless @required
|
89
|
+
|
90
|
+
scope = @scope
|
91
|
+
scope = scope.parent while scope.lateral?
|
92
|
+
|
93
|
+
scope.root?
|
89
94
|
end
|
90
95
|
|
91
96
|
def validation_exception(attr_name, message)
|
data/lib/grape/validations.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Grape
|
4
|
-
# Registry to store and locate known Validators.
|
5
4
|
module Validations
|
6
5
|
module_function
|
7
6
|
|
@@ -12,7 +11,7 @@ module Grape
|
|
12
11
|
# Register a new validator, so it can be used to validate parameters.
|
13
12
|
# @param short_name [String] all lower-case, no spaces
|
14
13
|
# @param klass [Class] the validator class. Should inherit from
|
15
|
-
# Validations::Base.
|
14
|
+
# Grape::Validations::Validators::Base.
|
16
15
|
def register_validator(short_name, klass)
|
17
16
|
validators[short_name] = klass
|
18
17
|
end
|
@@ -21,14 +20,11 @@ module Grape
|
|
21
20
|
validators.delete(short_name)
|
22
21
|
end
|
23
22
|
|
24
|
-
# Find a validator and if not found will try to load it
|
25
23
|
def require_validator(short_name)
|
26
24
|
str_name = short_name.to_s
|
27
|
-
validators.fetch(str_name)
|
28
|
-
Grape::Validations::Validators.const_get("#{str_name.camelize}Validator")
|
29
|
-
end
|
25
|
+
validators.fetch(str_name) { Grape::Validations::Validators.const_get(:"#{str_name.camelize}Validator") }
|
30
26
|
rescue NameError
|
31
|
-
raise Grape::Exceptions::UnknownValidator
|
27
|
+
raise Grape::Exceptions::UnknownValidator, short_name
|
32
28
|
end
|
33
29
|
end
|
34
30
|
end
|
data/lib/grape/version.rb
CHANGED