grape 1.3.3 → 1.6.2
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 +111 -2
- data/CONTRIBUTING.md +2 -1
- data/README.md +135 -23
- data/UPGRADING.md +237 -46
- data/grape.gemspec +5 -5
- data/lib/grape/api/instance.rb +34 -42
- data/lib/grape/api.rb +21 -16
- data/lib/grape/cookies.rb +2 -0
- data/lib/grape/dsl/callbacks.rb +1 -1
- data/lib/grape/dsl/desc.rb +3 -5
- data/lib/grape/dsl/headers.rb +5 -2
- data/lib/grape/dsl/helpers.rb +8 -5
- data/lib/grape/dsl/inside_route.rb +72 -53
- data/lib/grape/dsl/middleware.rb +4 -4
- data/lib/grape/dsl/parameters.rb +11 -7
- data/lib/grape/dsl/request_response.rb +9 -6
- data/lib/grape/dsl/routing.rb +8 -9
- data/lib/grape/dsl/settings.rb +5 -5
- data/lib/grape/dsl/validations.rb +18 -1
- data/lib/grape/eager_load.rb +1 -1
- data/lib/grape/endpoint.rb +29 -42
- data/lib/grape/error_formatter/json.rb +2 -6
- data/lib/grape/error_formatter/xml.rb +2 -6
- data/lib/grape/exceptions/empty_message_body.rb +11 -0
- data/lib/grape/exceptions/validation.rb +2 -3
- data/lib/grape/exceptions/validation_errors.rb +1 -1
- data/lib/grape/formatter/json.rb +1 -0
- data/lib/grape/formatter/serializable_hash.rb +2 -1
- data/lib/grape/formatter/xml.rb +1 -0
- data/lib/grape/locale/en.yml +1 -1
- data/lib/grape/middleware/auth/base.rb +3 -3
- data/lib/grape/middleware/auth/dsl.rb +7 -1
- data/lib/grape/middleware/base.rb +6 -3
- data/lib/grape/middleware/error.rb +11 -13
- data/lib/grape/middleware/formatter.rb +7 -7
- data/lib/grape/middleware/stack.rb +10 -3
- data/lib/grape/middleware/versioner/accept_version_header.rb +3 -5
- data/lib/grape/middleware/versioner/header.rb +6 -4
- data/lib/grape/middleware/versioner/param.rb +1 -0
- data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
- data/lib/grape/middleware/versioner/path.rb +2 -0
- data/lib/grape/parser/json.rb +1 -1
- data/lib/grape/parser/xml.rb +1 -1
- data/lib/grape/path.rb +1 -0
- data/lib/grape/request.rb +4 -1
- data/lib/grape/router/attribute_translator.rb +3 -3
- data/lib/grape/router/pattern.rb +1 -1
- data/lib/grape/router/route.rb +2 -2
- data/lib/grape/router.rb +31 -30
- data/lib/grape/{serve_file → serve_stream}/file_body.rb +1 -1
- data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +1 -1
- data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +8 -8
- data/lib/grape/util/base_inheritable.rb +2 -2
- data/lib/grape/util/inheritable_setting.rb +1 -3
- data/lib/grape/util/lazy_value.rb +4 -2
- data/lib/grape/util/strict_hash_configuration.rb +1 -1
- data/lib/grape/validations/attributes_iterator.rb +8 -0
- data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
- data/lib/grape/validations/params_scope.rb +97 -62
- data/lib/grape/validations/single_attribute_iterator.rb +1 -1
- data/lib/grape/validations/types/custom_type_coercer.rb +16 -3
- data/lib/grape/validations/types/dry_type_coercer.rb +1 -1
- data/lib/grape/validations/types/invalid_value.rb +24 -0
- data/lib/grape/validations/types/json.rb +2 -1
- data/lib/grape/validations/types/primitive_coercer.rb +4 -5
- data/lib/grape/validations/types.rb +1 -4
- data/lib/grape/validations/validator_factory.rb +1 -1
- data/lib/grape/validations/validators/all_or_none.rb +8 -5
- data/lib/grape/validations/validators/allow_blank.rb +9 -7
- data/lib/grape/validations/validators/as.rb +6 -8
- data/lib/grape/validations/validators/at_least_one_of.rb +7 -4
- data/lib/grape/validations/validators/base.rb +74 -69
- data/lib/grape/validations/validators/coerce.rb +63 -76
- data/lib/grape/validations/validators/default.rb +36 -34
- data/lib/grape/validations/validators/exactly_one_of.rb +9 -6
- data/lib/grape/validations/validators/except_values.rb +13 -11
- data/lib/grape/validations/validators/multiple_params_base.rb +24 -19
- data/lib/grape/validations/validators/mutual_exclusion.rb +8 -5
- data/lib/grape/validations/validators/presence.rb +7 -4
- data/lib/grape/validations/validators/regexp.rb +8 -5
- data/lib/grape/validations/validators/same_as.rb +18 -15
- data/lib/grape/validations/validators/values.rb +61 -56
- data/lib/grape/validations.rb +6 -0
- data/lib/grape/version.rb +1 -1
- data/lib/grape.rb +7 -3
- data/spec/grape/api/custom_validations_spec.rb +77 -45
- 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/routes_with_requirements_spec.rb +8 -8
- data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +9 -15
- data/spec/grape/api_remount_spec.rb +25 -19
- data/spec/grape/api_spec.rb +576 -211
- data/spec/grape/dsl/callbacks_spec.rb +2 -1
- 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 +185 -34
- data/spec/grape/dsl/logger_spec.rb +16 -18
- data/spec/grape/dsl/middleware_spec.rb +2 -1
- data/spec/grape/dsl/parameters_spec.rb +2 -0
- data/spec/grape/dsl/request_response_spec.rb +1 -0
- data/spec/grape/dsl/routing_spec.rb +10 -7
- data/spec/grape/endpoint/declared_spec.rb +848 -0
- data/spec/grape/endpoint_spec.rb +77 -589
- data/spec/grape/entity_spec.rb +29 -23
- 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 +13 -9
- data/spec/grape/loading_spec.rb +8 -8
- data/spec/grape/middleware/auth/dsl_spec.rb +15 -6
- data/spec/grape/middleware/auth/strategies_spec.rb +61 -21
- data/spec/grape/middleware/base_spec.rb +24 -15
- data/spec/grape/middleware/error_spec.rb +3 -3
- data/spec/grape/middleware/exception_spec.rb +111 -161
- data/spec/grape/middleware/formatter_spec.rb +28 -7
- data/spec/grape/middleware/globals_spec.rb +7 -4
- data/spec/grape/middleware/stack_spec.rb +15 -12
- 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 +14 -3
- data/spec/grape/validations/params_scope_spec.rb +72 -10
- data/spec/grape/validations/single_attribute_iterator_spec.rb +18 -6
- data/spec/grape/validations/types/primitive_coercer_spec.rb +63 -7
- 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 +248 -33
- data/spec/grape/validations/validators/default_spec.rb +121 -78
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +71 -77
- data/spec/grape/validations/validators/except_values_spec.rb +4 -3
- 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 +183 -178
- data/spec/grape/validations_spec.rb +342 -29
- data/spec/integration/eager_load/eager_load_spec.rb +15 -0
- 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 +32 -29
- data/spec/spec_helper.rb +12 -12
- data/spec/support/basic_auth_encode_helpers.rb +1 -1
- data/spec/support/chunks.rb +14 -0
- data/spec/support/versioned_helpers.rb +4 -6
- metadata +110 -102
data/spec/grape/request_spec.rb
CHANGED
@@ -21,7 +21,7 @@ module Grape
|
|
21
21
|
let(:env) { default_env }
|
22
22
|
|
23
23
|
let(:request) do
|
24
|
-
|
24
|
+
described_class.new(env)
|
25
25
|
end
|
26
26
|
|
27
27
|
describe '#params' do
|
@@ -38,7 +38,7 @@ module Grape
|
|
38
38
|
|
39
39
|
context 'when build_params_with: Grape::Extensions::Hash::ParamBuilder is specified' do
|
40
40
|
let(:request) do
|
41
|
-
|
41
|
+
described_class.new(env, build_params_with: Grape::Extensions::Hash::ParamBuilder)
|
42
42
|
end
|
43
43
|
|
44
44
|
it 'returns symbolized params' do
|
@@ -65,6 +65,8 @@ module Grape
|
|
65
65
|
end
|
66
66
|
|
67
67
|
describe 'when the param_builder is set to Hashie' do
|
68
|
+
subject(:request_params) { described_class.new(env, **opts).params }
|
69
|
+
|
68
70
|
before do
|
69
71
|
Grape.configure do |config|
|
70
72
|
config.param_builder = Grape::Extensions::Hashie::Mash::ParamBuilder
|
@@ -75,15 +77,15 @@ module Grape
|
|
75
77
|
Grape.config.reset
|
76
78
|
end
|
77
79
|
|
78
|
-
subject(:request_params) { Grape::Request.new(env, opts).params }
|
79
|
-
|
80
80
|
context 'when the API does not include a specific param builder' do
|
81
81
|
let(:opts) { {} }
|
82
|
+
|
82
83
|
it { is_expected.to be_a(Hashie::Mash) }
|
83
84
|
end
|
84
85
|
|
85
86
|
context 'when the API includes a specific param builder' do
|
86
87
|
let(:opts) { { build_params_with: Grape::Extensions::Hash::ParamBuilder } }
|
88
|
+
|
87
89
|
it { is_expected.to be_a(Hash) }
|
88
90
|
end
|
89
91
|
end
|
@@ -4,12 +4,12 @@ require 'spec_helper'
|
|
4
4
|
module Grape
|
5
5
|
module Util
|
6
6
|
describe InheritableSetting do
|
7
|
-
before
|
8
|
-
|
7
|
+
before do
|
8
|
+
described_class.reset_global!
|
9
9
|
end
|
10
10
|
|
11
11
|
let(:parent) do
|
12
|
-
|
12
|
+
described_class.new.tap do |settings|
|
13
13
|
settings.global[:global_thing] = :global_foo_bar
|
14
14
|
settings.namespace[:namespace_thing] = :namespace_foo_bar
|
15
15
|
settings.namespace_inheritable[:namespace_inheritable_thing] = :namespace_inheritable_foo_bar
|
@@ -20,7 +20,7 @@ module Grape
|
|
20
20
|
end
|
21
21
|
|
22
22
|
let(:other_parent) do
|
23
|
-
|
23
|
+
described_class.new.tap do |settings|
|
24
24
|
settings.namespace[:namespace_thing] = :namespace_foo_bar_other
|
25
25
|
settings.namespace_inheritable[:namespace_inheritable_thing] = :namespace_inheritable_foo_bar_other
|
26
26
|
settings.namespace_stackable[:namespace_stackable_thing] = :namespace_stackable_foo_bar_other
|
@@ -29,7 +29,7 @@ module Grape
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
before
|
32
|
+
before do
|
33
33
|
subject.inherit_from parent
|
34
34
|
end
|
35
35
|
|
@@ -50,7 +50,7 @@ module Grape
|
|
50
50
|
expect(parent.global[:global_thing]).to eq :global_new_foo_bar
|
51
51
|
end
|
52
52
|
|
53
|
-
it '
|
53
|
+
it 'handles different parents' do
|
54
54
|
subject.global[:global_thing] = :global_new_foo_bar
|
55
55
|
|
56
56
|
subject.inherit_from other_parent
|
@@ -89,7 +89,7 @@ module Grape
|
|
89
89
|
expect(subject.namespace_inheritable[:namespace_inheritable_thing]).to eq :namespace_inheritable_foo_bar
|
90
90
|
end
|
91
91
|
|
92
|
-
it '
|
92
|
+
it 'handles different parents' do
|
93
93
|
expect(subject.namespace_inheritable[:namespace_inheritable_thing]).to eq :namespace_inheritable_foo_bar
|
94
94
|
|
95
95
|
subject.inherit_from other_parent
|
@@ -4,8 +4,9 @@ require 'spec_helper'
|
|
4
4
|
module Grape
|
5
5
|
module Util
|
6
6
|
describe InheritableValues do
|
7
|
-
|
8
|
-
|
7
|
+
subject { described_class.new(parent) }
|
8
|
+
|
9
|
+
let(:parent) { described_class.new }
|
9
10
|
|
10
11
|
describe '#delete' do
|
11
12
|
it 'deletes a key' do
|
@@ -4,9 +4,10 @@ require 'spec_helper'
|
|
4
4
|
module Grape
|
5
5
|
module Util
|
6
6
|
describe ReverseStackableValues do
|
7
|
-
let(:parent) { described_class.new }
|
8
7
|
subject { described_class.new(parent) }
|
9
8
|
|
9
|
+
let(:parent) { described_class.new }
|
10
|
+
|
10
11
|
describe '#keys' do
|
11
12
|
it 'returns all keys' do
|
12
13
|
subject[:some_thing] = :foo_bar
|
@@ -102,6 +103,7 @@ module Grape
|
|
102
103
|
|
103
104
|
describe '#clone' do
|
104
105
|
let(:obj_cloned) { subject.clone }
|
106
|
+
|
105
107
|
it 'copies all values' do
|
106
108
|
parent = described_class.new
|
107
109
|
child = described_class.new parent
|
@@ -4,8 +4,9 @@ require 'spec_helper'
|
|
4
4
|
module Grape
|
5
5
|
module Util
|
6
6
|
describe StackableValues do
|
7
|
-
|
8
|
-
|
7
|
+
subject { described_class.new(parent) }
|
8
|
+
|
9
|
+
let(:parent) { described_class.new }
|
9
10
|
|
10
11
|
describe '#keys' do
|
11
12
|
it 'returns all keys' do
|
@@ -99,10 +100,11 @@ module Grape
|
|
99
100
|
|
100
101
|
describe '#clone' do
|
101
102
|
let(:obj_cloned) { subject.clone }
|
103
|
+
|
102
104
|
it 'copies all values' do
|
103
|
-
parent =
|
104
|
-
child =
|
105
|
-
grandchild =
|
105
|
+
parent = described_class.new
|
106
|
+
child = described_class.new parent
|
107
|
+
grandchild = described_class.new child
|
106
108
|
|
107
109
|
parent[:some_thing] = :foo
|
108
110
|
child[:some_thing] = %i[bar more]
|
@@ -4,7 +4,7 @@ require 'spec_helper'
|
|
4
4
|
|
5
5
|
describe 'Validator with instance variables' do
|
6
6
|
let(:validator_type) do
|
7
|
-
Class.new(Grape::Validations::Base) do
|
7
|
+
Class.new(Grape::Validations::Validators::Base) do
|
8
8
|
def validate_param!(_attr_name, _params)
|
9
9
|
if instance_variable_defined?(:@instance_variable) && @instance_variable
|
10
10
|
raise Grape::Exceptions::Validation.new(params: ['params'],
|
@@ -14,15 +14,6 @@ describe 'Validator with instance variables' do
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
17
|
-
|
18
|
-
before do
|
19
|
-
Grape::Validations.register_validator('instance_validator', validator_type)
|
20
|
-
end
|
21
|
-
|
22
|
-
after do
|
23
|
-
Grape::Validations.deregister_validator('instance_validator')
|
24
|
-
end
|
25
|
-
|
26
17
|
let(:app) do
|
27
18
|
Class.new(Grape::API) do
|
28
19
|
params do
|
@@ -35,6 +26,14 @@ describe 'Validator with instance variables' do
|
|
35
26
|
end
|
36
27
|
end
|
37
28
|
|
29
|
+
before do
|
30
|
+
Grape::Validations.register_validator('instance_validator', validator_type)
|
31
|
+
end
|
32
|
+
|
33
|
+
after do
|
34
|
+
Grape::Validations.deregister_validator('instance_validator')
|
35
|
+
end
|
36
|
+
|
38
37
|
it 'passes validation every time' do
|
39
38
|
expect(validator_type).to receive(:new).exactly(4).times.and_call_original
|
40
39
|
|
@@ -5,6 +5,7 @@ require 'spec_helper'
|
|
5
5
|
describe Grape::Validations::MultipleAttributesIterator do
|
6
6
|
describe '#each' do
|
7
7
|
subject(:iterator) { described_class.new(validator, scope, params) }
|
8
|
+
|
8
9
|
let(:scope) { Grape::Validations::ParamsScope.new(api: Class.new(Grape::API)) }
|
9
10
|
let(:validator) { double(attrs: %i[first second third]) }
|
10
11
|
|
@@ -13,8 +14,8 @@ describe Grape::Validations::MultipleAttributesIterator do
|
|
13
14
|
{ first: 'string', second: 'string' }
|
14
15
|
end
|
15
16
|
|
16
|
-
it 'yields the whole params hash without the list of attrs' do
|
17
|
-
expect { |b| iterator.each(&b) }.to yield_with_args(params)
|
17
|
+
it 'yields the whole params hash and the skipped flag without the list of attrs' do
|
18
|
+
expect { |b| iterator.each(&b) }.to yield_with_args(params, false)
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
@@ -24,7 +25,17 @@ describe Grape::Validations::MultipleAttributesIterator do
|
|
24
25
|
end
|
25
26
|
|
26
27
|
it 'yields each element of the array without the list of attrs' do
|
27
|
-
expect { |b| iterator.each(&b) }.to yield_successive_args(params[0], params[1])
|
28
|
+
expect { |b| iterator.each(&b) }.to yield_successive_args([params[0], false], [params[1], false])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'when params is empty optional placeholder' do
|
33
|
+
let(:params) do
|
34
|
+
[Grape::DSL::Parameters::EmptyOptionalValue, { first: 'string2', second: 'string2' }]
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'yields each element of the array without the list of attrs' do
|
38
|
+
expect { |b| iterator.each(&b) }.to yield_successive_args([Grape::DSL::Parameters::EmptyOptionalValue, true], [params[1], false])
|
28
39
|
end
|
29
40
|
end
|
30
41
|
end
|
@@ -98,6 +98,7 @@ describe Grape::Validations::ParamsScope do
|
|
98
98
|
|
99
99
|
def self.parse(value)
|
100
100
|
raise if value == 'invalid'
|
101
|
+
|
101
102
|
new(value)
|
102
103
|
end
|
103
104
|
|
@@ -144,7 +145,7 @@ describe Grape::Validations::ParamsScope do
|
|
144
145
|
get '/renaming-coerced', foo: ' there we go '
|
145
146
|
|
146
147
|
expect(last_response.status).to eq(200)
|
147
|
-
expect(last_response.body).to eq('there we go
|
148
|
+
expect(last_response.body).to eq('-there we go')
|
148
149
|
end
|
149
150
|
|
150
151
|
it do
|
@@ -180,6 +181,28 @@ describe Grape::Validations::ParamsScope do
|
|
180
181
|
expect(last_response.status).to eq(200)
|
181
182
|
expect(last_response.body).to eq('{"baz":{"qux":"any"}}')
|
182
183
|
end
|
184
|
+
|
185
|
+
it 'renaming can be defined before default' do
|
186
|
+
subject.params do
|
187
|
+
optional :foo, as: :bar, default: 'before'
|
188
|
+
end
|
189
|
+
subject.get('/rename-before-default') { declared(params)[:bar] }
|
190
|
+
get '/rename-before-default'
|
191
|
+
|
192
|
+
expect(last_response.status).to eq(200)
|
193
|
+
expect(last_response.body).to eq('before')
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'renaming can be defined after default' do
|
197
|
+
subject.params do
|
198
|
+
optional :foo, default: 'after', as: :bar
|
199
|
+
end
|
200
|
+
subject.get('/rename-after-default') { declared(params)[:bar] }
|
201
|
+
get '/rename-after-default'
|
202
|
+
|
203
|
+
expect(last_response.status).to eq(200)
|
204
|
+
expect(last_response.body).to eq('after')
|
205
|
+
end
|
183
206
|
end
|
184
207
|
|
185
208
|
context 'array without coerce type explicitly given' do
|
@@ -269,7 +292,7 @@ describe Grape::Validations::ParamsScope do
|
|
269
292
|
it 'does not raise an exception' do
|
270
293
|
expect do
|
271
294
|
subject.params { optional :numbers, type: Array[Integer], values: 0..2, default: 0..2 }
|
272
|
-
end.
|
295
|
+
end.not_to raise_error
|
273
296
|
end
|
274
297
|
end
|
275
298
|
|
@@ -277,7 +300,7 @@ describe Grape::Validations::ParamsScope do
|
|
277
300
|
it 'does not raise an exception' do
|
278
301
|
expect do
|
279
302
|
subject.params { optional :numbers, type: Array[Integer], values: [0, 1, 2], default: [1, 0] }
|
280
|
-
end.
|
303
|
+
end.not_to raise_error
|
281
304
|
end
|
282
305
|
end
|
283
306
|
end
|
@@ -501,7 +524,7 @@ describe Grape::Validations::ParamsScope do
|
|
501
524
|
requires :c
|
502
525
|
end
|
503
526
|
end
|
504
|
-
end.
|
527
|
+
end.not_to raise_error
|
505
528
|
end
|
506
529
|
|
507
530
|
it 'does not raise an error if when using nested given' do
|
@@ -517,7 +540,7 @@ describe Grape::Validations::ParamsScope do
|
|
517
540
|
end
|
518
541
|
end
|
519
542
|
end
|
520
|
-
end.
|
543
|
+
end.not_to raise_error
|
521
544
|
end
|
522
545
|
|
523
546
|
it 'allows nested dependent parameters' do
|
@@ -562,13 +585,13 @@ describe Grape::Validations::ParamsScope do
|
|
562
585
|
body = JSON.parse(last_response.body)
|
563
586
|
|
564
587
|
expect(body.keys).to include('c')
|
565
|
-
expect(body.keys).
|
588
|
+
expect(body.keys).not_to include('b')
|
566
589
|
end
|
567
590
|
|
568
591
|
it 'allows renaming of dependent on parameter' do
|
569
592
|
subject.params do
|
570
593
|
optional :a, as: :b
|
571
|
-
given
|
594
|
+
given a: ->(val) { val == 'x' } do
|
572
595
|
requires :c
|
573
596
|
end
|
574
597
|
end
|
@@ -582,7 +605,7 @@ describe Grape::Validations::ParamsScope do
|
|
582
605
|
expect(last_response.status).to eq 200
|
583
606
|
end
|
584
607
|
|
585
|
-
it '
|
608
|
+
it 'does not raise if the dependent parameter is not the renamed one' do
|
586
609
|
expect do
|
587
610
|
subject.params do
|
588
611
|
optional :a, as: :b
|
@@ -590,6 +613,17 @@ describe Grape::Validations::ParamsScope do
|
|
590
613
|
requires :c
|
591
614
|
end
|
592
615
|
end
|
616
|
+
end.not_to raise_error
|
617
|
+
end
|
618
|
+
|
619
|
+
it 'raises an error if the dependent parameter is the renamed one' do
|
620
|
+
expect do
|
621
|
+
subject.params do
|
622
|
+
optional :a, as: :b
|
623
|
+
given :b do
|
624
|
+
requires :c
|
625
|
+
end
|
626
|
+
end
|
593
627
|
end.to raise_error(Grape::Exceptions::UnknownParameter)
|
594
628
|
end
|
595
629
|
|
@@ -633,6 +667,32 @@ describe Grape::Validations::ParamsScope do
|
|
633
667
|
expect(last_response.status).to eq(200)
|
634
668
|
end
|
635
669
|
|
670
|
+
it 'detect unmet nested dependency' do
|
671
|
+
subject.params do
|
672
|
+
requires :a, type: String, allow_blank: false, values: %w[x y z]
|
673
|
+
given a: ->(val) { val == 'z' } do
|
674
|
+
requires :inner3, type: Array, allow_blank: false do
|
675
|
+
requires :bar, type: String, allow_blank: false
|
676
|
+
given bar: ->(val) { val == 'b' } do
|
677
|
+
requires :baz, type: Array do
|
678
|
+
optional :baz_category, type: String
|
679
|
+
end
|
680
|
+
end
|
681
|
+
given bar: ->(val) { val == 'c' } do
|
682
|
+
requires :baz, type: Array do
|
683
|
+
requires :baz_category, type: String
|
684
|
+
end
|
685
|
+
end
|
686
|
+
end
|
687
|
+
end
|
688
|
+
end
|
689
|
+
subject.get('/nested-dependency') { declared(params).to_json }
|
690
|
+
|
691
|
+
get '/nested-dependency', a: 'z', inner3: [{ bar: 'c', baz: [{ unrelated: 'nope' }] }]
|
692
|
+
expect(last_response.status).to eq(400)
|
693
|
+
expect(last_response.body).to eq 'inner3[0][baz][0][baz_category] is missing'
|
694
|
+
end
|
695
|
+
|
636
696
|
it 'includes the parameter within #declared(params)' do
|
637
697
|
get '/test', a: true, b: true
|
638
698
|
|
@@ -727,7 +787,7 @@ describe Grape::Validations::ParamsScope do
|
|
727
787
|
subject.get('/test') { 'ok' }
|
728
788
|
end
|
729
789
|
|
730
|
-
it '
|
790
|
+
it 'passes none Hash params' do
|
731
791
|
get '/test', foos: ['']
|
732
792
|
expect(last_response.status).to eq(200)
|
733
793
|
expect(last_response.body).to eq('ok')
|
@@ -903,6 +963,7 @@ describe Grape::Validations::ParamsScope do
|
|
903
963
|
expect(last_response.body).to eq('one is missing, two is missing, three is missing')
|
904
964
|
end
|
905
965
|
end
|
966
|
+
|
906
967
|
context 'when fail_fast is defined it stops the validation' do
|
907
968
|
it 'of other params' do
|
908
969
|
subject.params do
|
@@ -915,6 +976,7 @@ describe Grape::Validations::ParamsScope do
|
|
915
976
|
expect(last_response.status).to eq(400)
|
916
977
|
expect(last_response.body).to eq('one is missing')
|
917
978
|
end
|
979
|
+
|
918
980
|
it 'for a single param' do
|
919
981
|
subject.params do
|
920
982
|
requires :one, allow_blank: false, regexp: /[0-9]+/, fail_fast: true
|
@@ -965,7 +1027,7 @@ describe Grape::Validations::ParamsScope do
|
|
965
1027
|
end
|
966
1028
|
|
967
1029
|
it 'prioritizes parameter validation over group validation' do
|
968
|
-
expect(last_response.body).
|
1030
|
+
expect(last_response.body).not_to include('address is empty')
|
969
1031
|
end
|
970
1032
|
end
|
971
1033
|
end
|
@@ -5,6 +5,7 @@ require 'spec_helper'
|
|
5
5
|
describe Grape::Validations::SingleAttributeIterator do
|
6
6
|
describe '#each' do
|
7
7
|
subject(:iterator) { described_class.new(validator, scope, params) }
|
8
|
+
|
8
9
|
let(:scope) { Grape::Validations::ParamsScope.new(api: Class.new(Grape::API)) }
|
9
10
|
let(:validator) { double(attrs: %i[first second]) }
|
10
11
|
|
@@ -15,7 +16,7 @@ describe Grape::Validations::SingleAttributeIterator do
|
|
15
16
|
|
16
17
|
it 'yields params and every single attribute from the list' do
|
17
18
|
expect { |b| iterator.each(&b) }
|
18
|
-
.to yield_successive_args([params, :first, false], [params, :second, false])
|
19
|
+
.to yield_successive_args([params, :first, false, false], [params, :second, false, false])
|
19
20
|
end
|
20
21
|
end
|
21
22
|
|
@@ -26,8 +27,8 @@ describe Grape::Validations::SingleAttributeIterator do
|
|
26
27
|
|
27
28
|
it 'yields every single attribute from the list for each of the array elements' do
|
28
29
|
expect { |b| iterator.each(&b) }.to yield_successive_args(
|
29
|
-
[params[0], :first, false], [params[0], :second, false],
|
30
|
-
[params[1], :first, false], [params[1], :second, false]
|
30
|
+
[params[0], :first, false, false], [params[0], :second, false, false],
|
31
|
+
[params[1], :first, false, false], [params[1], :second, false, false]
|
31
32
|
)
|
32
33
|
end
|
33
34
|
|
@@ -36,9 +37,20 @@ describe Grape::Validations::SingleAttributeIterator do
|
|
36
37
|
|
37
38
|
it 'marks params with empty values' do
|
38
39
|
expect { |b| iterator.each(&b) }.to yield_successive_args(
|
39
|
-
[params[0], :first, true], [params[0], :second, true],
|
40
|
-
[params[1], :first, true], [params[1], :second, true],
|
41
|
-
[params[2], :first, false], [params[2], :second, false]
|
40
|
+
[params[0], :first, true, false], [params[0], :second, true, false],
|
41
|
+
[params[1], :first, true, false], [params[1], :second, true, false],
|
42
|
+
[params[2], :first, false, false], [params[2], :second, false, false]
|
43
|
+
)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'when missing optional value' do
|
48
|
+
let(:params) { [Grape::DSL::Parameters::EmptyOptionalValue, 10] }
|
49
|
+
|
50
|
+
it 'marks params with skipped values' do
|
51
|
+
expect { |b| iterator.each(&b) }.to yield_successive_args(
|
52
|
+
[params[0], :first, false, true], [params[0], :second, false, true],
|
53
|
+
[params[1], :first, false, false], [params[1], :second, false, false]
|
42
54
|
)
|
43
55
|
end
|
44
56
|
end
|
@@ -3,11 +3,23 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
describe Grape::Validations::Types::PrimitiveCoercer do
|
6
|
-
let(:strict) { false }
|
7
|
-
|
8
6
|
subject { described_class.new(type, strict) }
|
9
7
|
|
8
|
+
let(:strict) { false }
|
9
|
+
|
10
10
|
describe '#call' do
|
11
|
+
context 'BigDecimal' do
|
12
|
+
let(:type) { BigDecimal }
|
13
|
+
|
14
|
+
it 'coerces to BigDecimal' do
|
15
|
+
expect(subject.call(5)).to eq(BigDecimal('5'))
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'coerces an empty string to nil' do
|
19
|
+
expect(subject.call('')).to be_nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
11
23
|
context 'Boolean' do
|
12
24
|
let(:type) { Grape::API::Boolean }
|
13
25
|
|
@@ -32,19 +44,63 @@ describe Grape::Validations::Types::PrimitiveCoercer do
|
|
32
44
|
end
|
33
45
|
end
|
34
46
|
|
47
|
+
context 'DateTime' do
|
48
|
+
let(:type) { DateTime }
|
49
|
+
|
50
|
+
it 'coerces an empty string to nil' do
|
51
|
+
expect(subject.call('')).to be_nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'Float' do
|
56
|
+
let(:type) { Float }
|
57
|
+
|
58
|
+
it 'coerces an empty string to nil' do
|
59
|
+
expect(subject.call('')).to be_nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'Integer' do
|
64
|
+
let(:type) { Integer }
|
65
|
+
|
66
|
+
it 'coerces an empty string to nil' do
|
67
|
+
expect(subject.call('')).to be_nil
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'Numeric' do
|
72
|
+
let(:type) { Numeric }
|
73
|
+
|
74
|
+
it 'coerces an empty string to nil' do
|
75
|
+
expect(subject.call('')).to be_nil
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'Time' do
|
80
|
+
let(:type) { Time }
|
81
|
+
|
82
|
+
it 'coerces an empty string to nil' do
|
83
|
+
expect(subject.call('')).to be_nil
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
35
87
|
context 'String' do
|
36
88
|
let(:type) { String }
|
37
89
|
|
38
90
|
it 'coerces to String' do
|
39
91
|
expect(subject.call(10)).to eq('10')
|
40
92
|
end
|
93
|
+
|
94
|
+
it 'does not coerce an empty string to nil' do
|
95
|
+
expect(subject.call('')).to eq('')
|
96
|
+
end
|
41
97
|
end
|
42
98
|
|
43
|
-
context '
|
44
|
-
let(:type) {
|
99
|
+
context 'Symbol' do
|
100
|
+
let(:type) { Symbol }
|
45
101
|
|
46
|
-
it 'coerces to
|
47
|
-
expect(subject.call(
|
102
|
+
it 'coerces an empty string to nil' do
|
103
|
+
expect(subject.call('')).to be_nil
|
48
104
|
end
|
49
105
|
end
|
50
106
|
|
@@ -71,7 +127,7 @@ describe Grape::Validations::Types::PrimitiveCoercer do
|
|
71
127
|
end
|
72
128
|
|
73
129
|
it 'returns a value as it is when the given value is BigDecimal' do
|
74
|
-
expect(subject.call(BigDecimal(0))).to eq(BigDecimal(0))
|
130
|
+
expect(subject.call(BigDecimal('0'))).to eq(BigDecimal('0'))
|
75
131
|
end
|
76
132
|
end
|
77
133
|
end
|
@@ -20,13 +20,13 @@ describe Grape::Validations::Types do
|
|
20
20
|
Date, DateTime, Time
|
21
21
|
].each do |type|
|
22
22
|
it "recognizes #{type} as a primitive" do
|
23
|
-
expect(described_class.
|
23
|
+
expect(described_class).to be_primitive(type)
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
27
|
it 'identifies unknown types' do
|
28
|
-
expect(described_class.
|
29
|
-
expect(described_class.
|
28
|
+
expect(described_class).not_to be_primitive(Object)
|
29
|
+
expect(described_class).not_to be_primitive(TypesSpec::FooType)
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -35,7 +35,7 @@ describe Grape::Validations::Types do
|
|
35
35
|
Hash, Array, Set
|
36
36
|
].each do |type|
|
37
37
|
it "recognizes #{type} as a structure" do
|
38
|
-
expect(described_class.
|
38
|
+
expect(described_class).to be_structure(type)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
@@ -45,22 +45,22 @@ describe Grape::Validations::Types do
|
|
45
45
|
JSON, Array[JSON], File, Rack::Multipart::UploadedFile
|
46
46
|
].each do |type|
|
47
47
|
it "provides special handling for #{type.inspect}" do
|
48
|
-
expect(described_class.
|
48
|
+
expect(described_class).to be_special(type)
|
49
49
|
end
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
53
|
describe '::custom?' do
|
54
54
|
it 'returns false if the type does not respond to :parse' do
|
55
|
-
expect(described_class.
|
55
|
+
expect(described_class).not_to be_custom(Object)
|
56
56
|
end
|
57
57
|
|
58
58
|
it 'returns true if the type responds to :parse with one argument' do
|
59
|
-
expect(described_class.
|
59
|
+
expect(described_class).to be_custom(TypesSpec::FooType)
|
60
60
|
end
|
61
61
|
|
62
62
|
it 'returns false if the type\'s #parse method takes other than one argument' do
|
63
|
-
expect(described_class.
|
63
|
+
expect(described_class).not_to be_custom(TypesSpec::BarType)
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|