grape 1.6.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/CONTRIBUTING.md +1 -0
- data/README.md +9 -1
- data/lib/grape/api.rb +12 -0
- data/lib/grape/dry_types.rb +12 -0
- data/lib/grape/dsl/headers.rb +5 -2
- data/lib/grape/dsl/helpers.rb +1 -1
- data/lib/grape/middleware/auth/dsl.rb +7 -1
- data/lib/grape/middleware/base.rb +1 -1
- data/lib/grape/util/json.rb +2 -0
- data/lib/grape/util/strict_hash_configuration.rb +1 -1
- data/lib/grape/validations/types/array_coercer.rb +0 -2
- data/lib/grape/validations/types/dry_type_coercer.rb +1 -10
- data/lib/grape/validations/types/json.rb +0 -2
- data/lib/grape/validations/types/primitive_coercer.rb +5 -7
- data/lib/grape/validations/types/set_coercer.rb +0 -3
- data/lib/grape/validations/types.rb +83 -9
- data/lib/grape/validations/validators/all_or_none_of_validator.rb +16 -0
- data/lib/grape/validations/validators/allow_blank_validator.rb +20 -0
- data/lib/grape/validations/validators/as_validator.rb +14 -0
- data/lib/grape/validations/validators/at_least_one_of_validator.rb +15 -0
- data/lib/grape/validations/validators/base.rb +73 -71
- data/lib/grape/validations/validators/coerce_validator.rb +75 -0
- data/lib/grape/validations/validators/default_validator.rb +51 -0
- data/lib/grape/validations/validators/exactly_one_of_validator.rb +17 -0
- data/lib/grape/validations/validators/except_values_validator.rb +24 -0
- data/lib/grape/validations/validators/multiple_params_base.rb +24 -22
- data/lib/grape/validations/validators/mutual_exclusion_validator.rb +16 -0
- data/lib/grape/validations/validators/presence_validator.rb +15 -0
- data/lib/grape/validations/validators/regexp_validator.rb +16 -0
- data/lib/grape/validations/validators/same_as_validator.rb +29 -0
- data/lib/grape/validations/validators/values_validator.rb +88 -0
- data/lib/grape/version.rb +1 -1
- data/lib/grape.rb +59 -24
- data/spec/grape/api/custom_validations_spec.rb +77 -46
- data/spec/grape/api/deeply_included_options_spec.rb +3 -3
- data/spec/grape/api/defines_boolean_in_params_spec.rb +2 -1
- data/spec/grape/api/invalid_format_spec.rb +2 -0
- data/spec/grape/api/recognize_path_spec.rb +1 -1
- data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +9 -15
- data/spec/grape/api_remount_spec.rb +16 -15
- data/spec/grape/api_spec.rb +317 -193
- data/spec/grape/dsl/callbacks_spec.rb +1 -0
- data/spec/grape/dsl/headers_spec.rb +39 -9
- data/spec/grape/dsl/helpers_spec.rb +3 -2
- data/spec/grape/dsl/inside_route_spec.rb +6 -4
- data/spec/grape/dsl/logger_spec.rb +16 -18
- data/spec/grape/dsl/middleware_spec.rb +1 -0
- data/spec/grape/dsl/parameters_spec.rb +1 -0
- data/spec/grape/dsl/request_response_spec.rb +1 -0
- data/spec/grape/dsl/routing_spec.rb +9 -6
- data/spec/grape/endpoint/declared_spec.rb +12 -12
- data/spec/grape/endpoint_spec.rb +59 -50
- data/spec/grape/entity_spec.rb +13 -13
- data/spec/grape/exceptions/body_parse_errors_spec.rb +3 -0
- data/spec/grape/exceptions/invalid_accept_header_spec.rb +61 -22
- data/spec/grape/exceptions/validation_errors_spec.rb +13 -10
- data/spec/grape/exceptions/validation_spec.rb +5 -3
- data/spec/grape/extensions/param_builders/hash_spec.rb +7 -7
- data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +8 -8
- data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +8 -8
- data/spec/grape/integration/rack_sendfile_spec.rb +1 -1
- data/spec/grape/loading_spec.rb +8 -8
- data/spec/grape/middleware/auth/dsl_spec.rb +14 -5
- data/spec/grape/middleware/auth/strategies_spec.rb +60 -20
- data/spec/grape/middleware/base_spec.rb +24 -15
- data/spec/grape/middleware/error_spec.rb +1 -0
- data/spec/grape/middleware/exception_spec.rb +111 -161
- data/spec/grape/middleware/formatter_spec.rb +25 -4
- data/spec/grape/middleware/globals_spec.rb +7 -4
- data/spec/grape/middleware/stack_spec.rb +11 -11
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +2 -1
- data/spec/grape/middleware/versioner/header_spec.rb +14 -13
- data/spec/grape/middleware/versioner/param_spec.rb +7 -1
- data/spec/grape/middleware/versioner/path_spec.rb +5 -1
- data/spec/grape/middleware/versioner_spec.rb +1 -1
- data/spec/grape/parser_spec.rb +4 -0
- data/spec/grape/path_spec.rb +52 -52
- data/spec/grape/presenters/presenter_spec.rb +7 -6
- data/spec/grape/request_spec.rb +6 -4
- data/spec/grape/util/inheritable_setting_spec.rb +7 -7
- data/spec/grape/util/inheritable_values_spec.rb +3 -2
- data/spec/grape/util/reverse_stackable_values_spec.rb +3 -1
- data/spec/grape/util/stackable_values_spec.rb +7 -5
- data/spec/grape/validations/instance_behaivour_spec.rb +9 -10
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +1 -0
- data/spec/grape/validations/params_scope_spec.rb +9 -7
- data/spec/grape/validations/single_attribute_iterator_spec.rb +1 -0
- data/spec/grape/validations/types/primitive_coercer_spec.rb +2 -2
- data/spec/grape/validations/types_spec.rb +8 -8
- data/spec/grape/validations/validators/all_or_none_spec.rb +50 -56
- data/spec/grape/validations/validators/allow_blank_spec.rb +136 -140
- data/spec/grape/validations/validators/at_least_one_of_spec.rb +50 -56
- data/spec/grape/validations/validators/coerce_spec.rb +10 -12
- data/spec/grape/validations/validators/default_spec.rb +72 -78
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +71 -77
- data/spec/grape/validations/validators/except_values_spec.rb +1 -1
- data/spec/grape/validations/validators/mutual_exclusion_spec.rb +71 -77
- data/spec/grape/validations/validators/presence_spec.rb +16 -1
- data/spec/grape/validations/validators/regexp_spec.rb +25 -31
- data/spec/grape/validations/validators/same_as_spec.rb +14 -20
- data/spec/grape/validations/validators/values_spec.rb +172 -171
- data/spec/grape/validations_spec.rb +45 -16
- data/spec/integration/eager_load/eager_load_spec.rb +2 -2
- data/spec/integration/multi_json/json_spec.rb +1 -1
- data/spec/integration/multi_xml/xml_spec.rb +1 -1
- data/spec/shared/versioning_examples.rb +10 -7
- data/spec/spec_helper.rb +11 -1
- metadata +116 -116
- data/lib/grape/validations/types/build_coercer.rb +0 -94
- data/lib/grape/validations/validators/all_or_none.rb +0 -16
- data/lib/grape/validations/validators/allow_blank.rb +0 -18
- data/lib/grape/validations/validators/as.rb +0 -12
- data/lib/grape/validations/validators/at_least_one_of.rb +0 -15
- data/lib/grape/validations/validators/coerce.rb +0 -87
- data/lib/grape/validations/validators/default.rb +0 -49
- data/lib/grape/validations/validators/exactly_one_of.rb +0 -17
- data/lib/grape/validations/validators/except_values.rb +0 -22
- data/lib/grape/validations/validators/mutual_exclusion.rb +0 -16
- data/lib/grape/validations/validators/presence.rb +0 -13
- data/lib/grape/validations/validators/regexp.rb +0 -14
- data/lib/grape/validations/validators/same_as.rb +0 -27
- data/lib/grape/validations/validators/values.rb +0 -86
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1e8e622245d5871dfbaa651eac26abfd8bc4d36accd176f39fcc8ec09200cbe5
|
4
|
+
data.tar.gz: d92fe82ca78e6140bc98832671e682c2f090210e1ceaee907d9f3c4f812463b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eed721c5ebd94fa07d2fa2a5420f0a943959890e85c71a941d4b1caede3605dbff836d4f42fabf0e15dec2a3bda944c7cd29988dcc1b1fd13eeea350c81a62de
|
7
|
+
data.tar.gz: ac951a0fbcd4d467ecf6f9b25f0d0d460a7cd132bb4ae708e2e0f55623ccc40d77809ca9c5663bde77c5d59708b264288a7592158340f1ca8336621007c8787b
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
### 1.6.1 (2021/12/28)
|
2
|
+
|
3
|
+
#### Features
|
4
|
+
|
5
|
+
* [#2196](https://github.com/ruby-grape/grape/pull/2196): Add support for `passwords_hashed` param for `digest_auth` - [@lHydra](https://github.com/lhydra).
|
6
|
+
* [#2208](https://github.com/ruby-grape/grape/pull/2208): Added Rails 7 support - [@ericproulx](https://github.com/ericproulx).
|
7
|
+
|
8
|
+
#### Fixes
|
9
|
+
|
10
|
+
* [#2206](https://github.com/ruby-grape/grape/pull/2206): Require main active_support lib before any of its extension definitions - [@annih](https://github.com/Annih).
|
11
|
+
* [#2193](https://github.com/ruby-grape/grape/pull/2193): Fixed the broken ruby-head NoMethodError spec - [@Jack12816](https://github.com/Jack12816).
|
12
|
+
* [#2192](https://github.com/ruby-grape/grape/pull/2192): Memoize the result of Grape::Middleware::Base#response - [@Jack12816](https://github.com/Jack12816).
|
13
|
+
* [#2200](https://github.com/ruby-grape/grape/pull/2200): Add validators module to all validators - [@ericproulx](https://github.com/ericproulx).
|
14
|
+
* [#2202](https://github.com/ruby-grape/grape/pull/2202): Fix random mock spec error - [@ericproulx](https://github.com/ericproulx).
|
15
|
+
* [#2203](https://github.com/ruby-grape/grape/pull/2203): Add rubocop-rspec - [@ericproulx](https://github.com/ericproulx).
|
16
|
+
* [#2207](https://github.com/ruby-grape/grape/pull/2207): Autoload Validations/Validators - [@ericproulx](https://github.com/ericproulx).
|
17
|
+
* [#2209](https://github.com/ruby-grape/grape/pull/2209): Autoload Validations/Types - [@ericproulx](https://github.com/ericproulx).
|
18
|
+
|
1
19
|
### 1.6.0 (2021/10/04)
|
2
20
|
|
3
21
|
#### Features
|
data/CONTRIBUTING.md
CHANGED
data/README.md
CHANGED
@@ -158,7 +158,7 @@ content negotiation, versioning and much more.
|
|
158
158
|
|
159
159
|
## Stable Release
|
160
160
|
|
161
|
-
You're reading the documentation for the stable release of Grape, **1.6.
|
161
|
+
You're reading the documentation for the stable release of Grape, **1.6.1**.
|
162
162
|
Please read [UPGRADING](UPGRADING.md) when upgrading from a previous version.
|
163
163
|
|
164
164
|
## Project Resources
|
@@ -3296,12 +3296,20 @@ http_basic do |username, password|
|
|
3296
3296
|
end
|
3297
3297
|
```
|
3298
3298
|
|
3299
|
+
Digest auth supports clear-text passwords and password hashes.
|
3300
|
+
|
3299
3301
|
```ruby
|
3300
3302
|
http_digest({ realm: 'Test Api', opaque: 'app secret' }) do |username|
|
3301
3303
|
# lookup the user's password here
|
3302
3304
|
end
|
3303
3305
|
```
|
3304
3306
|
|
3307
|
+
```ruby
|
3308
|
+
http_digest(realm: { realm: 'Test Api', opaque: 'app secret', passwords_hashed: true }) do |username|
|
3309
|
+
# lookup the user's password hash here
|
3310
|
+
end
|
3311
|
+
```
|
3312
|
+
|
3305
3313
|
### Register custom middleware for authentication
|
3306
3314
|
|
3307
3315
|
Grape can use custom Middleware for authentication. How to implement these
|
data/lib/grape/api.rb
CHANGED
@@ -10,6 +10,18 @@ module Grape
|
|
10
10
|
# Class methods that we want to call on the API rather than on the API object
|
11
11
|
NON_OVERRIDABLE = (Class.new.methods + %i[call call! configuration compile! inherited]).freeze
|
12
12
|
|
13
|
+
class Boolean
|
14
|
+
def self.build(val)
|
15
|
+
return nil if val != true && val != false
|
16
|
+
|
17
|
+
new
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Instance
|
22
|
+
Boolean = Grape::API::Boolean
|
23
|
+
end
|
24
|
+
|
13
25
|
class << self
|
14
26
|
attr_accessor :base_instance, :instances
|
15
27
|
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dry-types'
|
4
|
+
|
5
|
+
module Grape
|
6
|
+
module DryTypes
|
7
|
+
# Call +Dry.Types()+ to add all registered types to +DryTypes+ which is
|
8
|
+
# a container in this case. Check documentation for more information
|
9
|
+
# https://dry-rb.org/gems/dry-types/1.2/getting-started/
|
10
|
+
include Dry.Types()
|
11
|
+
end
|
12
|
+
end
|
data/lib/grape/dsl/headers.rb
CHANGED
@@ -3,8 +3,11 @@
|
|
3
3
|
module Grape
|
4
4
|
module DSL
|
5
5
|
module Headers
|
6
|
-
#
|
7
|
-
#
|
6
|
+
# This method has four responsibilities:
|
7
|
+
# 1. Set a specifc header value by key
|
8
|
+
# 2. Retrieve a specifc header value by key
|
9
|
+
# 3. Retrieve all headers that have been set
|
10
|
+
# 4. Delete a specifc header key-value pair
|
8
11
|
def header(key = nil, val = nil)
|
9
12
|
if key
|
10
13
|
val ? header[key.to_s] = val : header.delete(key.to_s)
|
data/lib/grape/dsl/helpers.rb
CHANGED
@@ -32,7 +32,13 @@ module Grape
|
|
32
32
|
|
33
33
|
def http_digest(options = {}, &block)
|
34
34
|
options[:realm] ||= 'API Authorization'
|
35
|
-
|
35
|
+
|
36
|
+
if options[:realm].respond_to?(:values_at)
|
37
|
+
options[:realm][:opaque] ||= 'secret'
|
38
|
+
else
|
39
|
+
options[:opaque] ||= 'secret'
|
40
|
+
end
|
41
|
+
|
36
42
|
auth :http_digest, options, &block
|
37
43
|
end
|
38
44
|
end
|
@@ -60,7 +60,7 @@ module Grape
|
|
60
60
|
def response
|
61
61
|
return @app_response if @app_response.is_a?(Rack::Response)
|
62
62
|
|
63
|
-
Rack::Response.new(@app_response[2], @app_response[0], @app_response[1])
|
63
|
+
@app_response = Rack::Response.new(@app_response[2], @app_response[0], @app_response[1])
|
64
64
|
end
|
65
65
|
|
66
66
|
def content_type_for(format)
|
data/lib/grape/util/json.rb
CHANGED
@@ -1,14 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'dry-types'
|
4
|
-
|
5
|
-
module DryTypes
|
6
|
-
# Call +Dry.Types()+ to add all registered types to +DryTypes+ which is
|
7
|
-
# a container in this case. Check documentation for more information
|
8
|
-
# https://dry-rb.org/gems/dry-types/1.2/getting-started/
|
9
|
-
include Dry.Types()
|
10
|
-
end
|
11
|
-
|
12
3
|
module Grape
|
13
4
|
module Validations
|
14
5
|
module Types
|
@@ -52,7 +43,7 @@ module Grape
|
|
52
43
|
def initialize(type, strict = false)
|
53
44
|
@type = type
|
54
45
|
@strict = strict
|
55
|
-
@scope = strict ? DryTypes::Strict : DryTypes::Params
|
46
|
+
@scope = strict ? Grape::DryTypes::Strict : Grape::DryTypes::Params
|
56
47
|
end
|
57
48
|
|
58
49
|
# Coerces the given value to a type which was specified during
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'dry_type_coercer'
|
4
|
-
|
5
3
|
module Grape
|
6
4
|
module Validations
|
7
5
|
module Types
|
@@ -10,16 +8,16 @@ module Grape
|
|
10
8
|
# that it has the proper type.
|
11
9
|
class PrimitiveCoercer < DryTypeCoercer
|
12
10
|
MAPPING = {
|
13
|
-
Grape::API::Boolean => DryTypes::Params::Bool,
|
14
|
-
BigDecimal => DryTypes::Params::Decimal,
|
11
|
+
Grape::API::Boolean => Grape::DryTypes::Params::Bool,
|
12
|
+
BigDecimal => Grape::DryTypes::Params::Decimal,
|
15
13
|
|
16
14
|
# unfortunately, a +Params+ scope doesn't contain String
|
17
|
-
String => DryTypes::Coercible::String
|
15
|
+
String => Grape::DryTypes::Coercible::String
|
18
16
|
}.freeze
|
19
17
|
|
20
18
|
STRICT_MAPPING = {
|
21
|
-
Grape::API::Boolean => DryTypes::Strict::Bool,
|
22
|
-
BigDecimal => DryTypes::Strict::Decimal
|
19
|
+
Grape::API::Boolean => Grape::DryTypes::Strict::Bool,
|
20
|
+
BigDecimal => Grape::DryTypes::Strict::Decimal
|
23
21
|
}.freeze
|
24
22
|
|
25
23
|
def initialize(type, strict = false)
|
@@ -1,14 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'types/build_coercer'
|
4
|
-
require_relative 'types/custom_type_coercer'
|
5
|
-
require_relative 'types/custom_type_collection_coercer'
|
6
|
-
require_relative 'types/multiple_type_coercer'
|
7
|
-
require_relative 'types/variant_collection_coercer'
|
8
|
-
require_relative 'types/json'
|
9
|
-
require_relative 'types/file'
|
10
|
-
require_relative 'types/invalid_value'
|
11
|
-
|
12
3
|
module Grape
|
13
4
|
module Validations
|
14
5
|
# Module for code related to grape's system for
|
@@ -143,6 +134,89 @@ module Grape
|
|
143
134
|
def self.map_special(type)
|
144
135
|
SPECIAL.fetch(type, type)
|
145
136
|
end
|
137
|
+
|
138
|
+
# Chooses the best coercer for the given type. For example, if the type
|
139
|
+
# is Integer, it will return a coercer which will be able to coerce a value
|
140
|
+
# to the integer.
|
141
|
+
#
|
142
|
+
# There are a few very special coercers which might be returned.
|
143
|
+
#
|
144
|
+
# +Grape::Types::MultipleTypeCoercer+ is a coercer which is returned when
|
145
|
+
# the given type implies values in an array with different types.
|
146
|
+
# For example, +[Integer, String]+ allows integer and string values in
|
147
|
+
# an array.
|
148
|
+
#
|
149
|
+
# +Grape::Types::CustomTypeCoercer+ is a coercer which is returned when
|
150
|
+
# a method is specified by a user with +coerce_with+ option or the user
|
151
|
+
# specifies a custom type which implements requirments of
|
152
|
+
# +Grape::Types::CustomTypeCoercer+.
|
153
|
+
#
|
154
|
+
# +Grape::Types::CustomTypeCollectionCoercer+ is a very similar to the
|
155
|
+
# previous one, but it expects an array or set of values having a custom
|
156
|
+
# type implemented by the user.
|
157
|
+
#
|
158
|
+
# There is also a group of custom types implemented by Grape, check
|
159
|
+
# +Grape::Validations::Types::SPECIAL+ to get the full list.
|
160
|
+
#
|
161
|
+
# @param type [Class] the type to which input strings
|
162
|
+
# should be coerced
|
163
|
+
# @param method [Class,#call] the coercion method to use
|
164
|
+
# @return [Object] object to be used
|
165
|
+
# for coercion and type validation
|
166
|
+
def self.build_coercer(type, method: nil, strict: false)
|
167
|
+
cache_instance(type, method, strict) do
|
168
|
+
create_coercer_instance(type, method, strict)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def self.create_coercer_instance(type, method, strict)
|
173
|
+
# Maps a custom type provided by Grape, it doesn't map types wrapped by collections!!!
|
174
|
+
type = Types.map_special(type)
|
175
|
+
|
176
|
+
# Use a special coercer for multiply-typed parameters.
|
177
|
+
if Types.multiple?(type)
|
178
|
+
MultipleTypeCoercer.new(type, method)
|
179
|
+
|
180
|
+
# Use a special coercer for custom types and coercion methods.
|
181
|
+
elsif method || Types.custom?(type)
|
182
|
+
CustomTypeCoercer.new(type, method)
|
183
|
+
|
184
|
+
# Special coercer for collections of types that implement a parse method.
|
185
|
+
# CustomTypeCoercer (above) already handles such types when an explicit coercion
|
186
|
+
# method is supplied.
|
187
|
+
elsif Types.collection_of_custom?(type)
|
188
|
+
Types::CustomTypeCollectionCoercer.new(
|
189
|
+
Types.map_special(type.first), type.is_a?(Set)
|
190
|
+
)
|
191
|
+
else
|
192
|
+
DryTypeCoercer.coercer_instance_for(type, strict)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def self.cache_instance(type, method, strict, &_block)
|
197
|
+
key = cache_key(type, method, strict)
|
198
|
+
|
199
|
+
return @__cache[key] if @__cache.key?(key)
|
200
|
+
|
201
|
+
instance = yield
|
202
|
+
|
203
|
+
@__cache_write_lock.synchronize do
|
204
|
+
@__cache[key] = instance
|
205
|
+
end
|
206
|
+
|
207
|
+
instance
|
208
|
+
end
|
209
|
+
|
210
|
+
def self.cache_key(type, method, strict)
|
211
|
+
[type, method, strict].each_with_object(+'_') do |val, memo|
|
212
|
+
next if val.nil?
|
213
|
+
|
214
|
+
memo << '_' << val.to_s
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
instance_variable_set(:@__cache, {})
|
219
|
+
instance_variable_set(:@__cache_write_lock, Mutex.new)
|
146
220
|
end
|
147
221
|
end
|
148
222
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grape
|
4
|
+
module Validations
|
5
|
+
module Validators
|
6
|
+
class AllOrNoneOfValidator < MultipleParamsBase
|
7
|
+
def validate_params!(params)
|
8
|
+
keys = keys_in_common(params)
|
9
|
+
return if keys.empty? || keys.length == all_keys.length
|
10
|
+
|
11
|
+
raise Grape::Exceptions::Validation.new(params: all_keys, message: message(:all_or_none))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grape
|
4
|
+
module Validations
|
5
|
+
module Validators
|
6
|
+
class AllowBlankValidator < Base
|
7
|
+
def validate_param!(attr_name, params)
|
8
|
+
return if (options_key?(:value) ? @option[:value] : @option) || !params.is_a?(Hash)
|
9
|
+
|
10
|
+
value = params[attr_name]
|
11
|
+
value = value.strip if value.respond_to?(:strip)
|
12
|
+
|
13
|
+
return if value == false || value.present?
|
14
|
+
|
15
|
+
raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message(:blank))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grape
|
4
|
+
module Validations
|
5
|
+
module Validators
|
6
|
+
class AsValidator < Base
|
7
|
+
# We use a validator for renaming parameters. This is just a marker for
|
8
|
+
# the parameter scope to handle the renaming. No actual validation
|
9
|
+
# happens here.
|
10
|
+
def validate_param!(*); end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grape
|
4
|
+
module Validations
|
5
|
+
module Validators
|
6
|
+
class AtLeastOneOfValidator < MultipleParamsBase
|
7
|
+
def validate_params!(params)
|
8
|
+
return unless keys_in_common(params).empty?
|
9
|
+
|
10
|
+
raise Grape::Exceptions::Validation.new(params: all_keys, message: message(:at_least_one))
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -2,91 +2,93 @@
|
|
2
2
|
|
3
3
|
module Grape
|
4
4
|
module Validations
|
5
|
-
|
6
|
-
|
5
|
+
module Validators
|
6
|
+
class Base
|
7
|
+
attr_reader :attrs
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
9
|
+
# Creates a new Validator from options specified
|
10
|
+
# by a +requires+ or +optional+ directive during
|
11
|
+
# parameter definition.
|
12
|
+
# @param attrs [Array] names of attributes to which the Validator applies
|
13
|
+
# @param options [Object] implementation-dependent Validator options
|
14
|
+
# @param required [Boolean] attribute(s) are required or optional
|
15
|
+
# @param scope [ParamsScope] parent scope for this Validator
|
16
|
+
# @param opts [Array] additional validation options
|
17
|
+
def initialize(attrs, options, required, scope, *opts)
|
18
|
+
@attrs = Array(attrs)
|
19
|
+
@option = options
|
20
|
+
@required = required
|
21
|
+
@scope = scope
|
22
|
+
opts = opts.any? ? opts.shift : {}
|
23
|
+
@fail_fast = opts.fetch(:fail_fast, false)
|
24
|
+
@allow_blank = opts.fetch(:allow_blank, false)
|
25
|
+
end
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
27
|
+
# Validates a given request.
|
28
|
+
# @note Override #validate! unless you need to access the entire request.
|
29
|
+
# @param request [Grape::Request] the request currently being handled
|
30
|
+
# @raise [Grape::Exceptions::Validation] if validation failed
|
31
|
+
# @return [void]
|
32
|
+
def validate(request)
|
33
|
+
return unless @scope.should_validate?(request.params)
|
33
34
|
|
34
|
-
|
35
|
-
|
35
|
+
validate!(request.params)
|
36
|
+
end
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
38
|
+
# Validates a given parameter hash.
|
39
|
+
# @note Override #validate if you need to access the entire request.
|
40
|
+
# @param params [Hash] parameters to validate
|
41
|
+
# @raise [Grape::Exceptions::Validation] if validation failed
|
42
|
+
# @return [void]
|
43
|
+
def validate!(params)
|
44
|
+
attributes = SingleAttributeIterator.new(self, @scope, params)
|
45
|
+
# we collect errors inside array because
|
46
|
+
# there may be more than one error per field
|
47
|
+
array_errors = []
|
47
48
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
49
|
+
attributes.each do |val, attr_name, empty_val, skip_value|
|
50
|
+
next if skip_value
|
51
|
+
next if !@scope.required? && empty_val
|
52
|
+
next unless @scope.meets_dependency?(val, params)
|
52
53
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
54
|
+
begin
|
55
|
+
validate_param!(attr_name, val) if @required || (val.respond_to?(:key?) && val.key?(attr_name))
|
56
|
+
rescue Grape::Exceptions::Validation => e
|
57
|
+
array_errors << e
|
58
|
+
end
|
57
59
|
end
|
58
|
-
end
|
59
60
|
|
60
|
-
|
61
|
-
|
61
|
+
raise Grape::Exceptions::ValidationArrayErrors.new(array_errors) if array_errors.any?
|
62
|
+
end
|
62
63
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
64
|
+
def self.convert_to_short_name(klass)
|
65
|
+
ret = klass.name.gsub(/::/, '/')
|
66
|
+
ret.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
67
|
+
ret.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
|
68
|
+
ret.tr!('-', '_')
|
69
|
+
ret.downcase!
|
70
|
+
File.basename(ret, '_validator')
|
71
|
+
end
|
71
72
|
|
72
|
-
|
73
|
-
|
73
|
+
def self.inherited(klass)
|
74
|
+
return unless klass.name.present?
|
74
75
|
|
75
|
-
|
76
|
-
|
76
|
+
Validations.register_validator(convert_to_short_name(klass), klass)
|
77
|
+
end
|
77
78
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
79
|
+
def message(default_key = nil)
|
80
|
+
options = instance_variable_get(:@option)
|
81
|
+
options_key?(:message) ? options[:message] : default_key
|
82
|
+
end
|
82
83
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
84
|
+
def options_key?(key, options = nil)
|
85
|
+
options = instance_variable_get(:@option) if options.nil?
|
86
|
+
options.respond_to?(:key?) && options.key?(key) && !options[key].nil?
|
87
|
+
end
|
87
88
|
|
88
|
-
|
89
|
-
|
89
|
+
def fail_fast?
|
90
|
+
@fail_fast
|
91
|
+
end
|
90
92
|
end
|
91
93
|
end
|
92
94
|
end
|