grape 1.5.2 → 1.7.0

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.
Files changed (210) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +75 -0
  3. data/CONTRIBUTING.md +2 -1
  4. data/README.md +152 -21
  5. data/UPGRADING.md +86 -2
  6. data/grape.gemspec +5 -5
  7. data/lib/grape/api/instance.rb +14 -18
  8. data/lib/grape/api.rb +18 -13
  9. data/lib/grape/cookies.rb +2 -0
  10. data/lib/grape/dry_types.rb +12 -0
  11. data/lib/grape/dsl/api.rb +0 -2
  12. data/lib/grape/dsl/callbacks.rb +0 -2
  13. data/lib/grape/dsl/configuration.rb +0 -2
  14. data/lib/grape/dsl/desc.rb +2 -19
  15. data/lib/grape/dsl/headers.rb +5 -2
  16. data/lib/grape/dsl/helpers.rb +7 -7
  17. data/lib/grape/dsl/inside_route.rb +43 -30
  18. data/lib/grape/dsl/middleware.rb +4 -6
  19. data/lib/grape/dsl/parameters.rb +8 -10
  20. data/lib/grape/dsl/request_response.rb +9 -8
  21. data/lib/grape/dsl/routing.rb +6 -4
  22. data/lib/grape/dsl/settings.rb +5 -7
  23. data/lib/grape/dsl/validations.rb +0 -15
  24. data/lib/grape/endpoint.rb +21 -36
  25. data/lib/grape/error_formatter/json.rb +9 -7
  26. data/lib/grape/error_formatter/xml.rb +2 -6
  27. data/lib/grape/exceptions/base.rb +2 -2
  28. data/lib/grape/exceptions/empty_message_body.rb +11 -0
  29. data/lib/grape/exceptions/missing_group_type.rb +8 -1
  30. data/lib/grape/exceptions/too_many_multipart_files.rb +11 -0
  31. data/lib/grape/exceptions/unsupported_group_type.rb +8 -1
  32. data/lib/grape/exceptions/validation.rb +1 -6
  33. data/lib/grape/formatter/json.rb +1 -0
  34. data/lib/grape/formatter/serializable_hash.rb +2 -1
  35. data/lib/grape/formatter/xml.rb +1 -0
  36. data/lib/grape/locale/en.yml +9 -8
  37. data/lib/grape/middleware/auth/dsl.rb +7 -2
  38. data/lib/grape/middleware/base.rb +3 -1
  39. data/lib/grape/middleware/error.rb +2 -2
  40. data/lib/grape/middleware/formatter.rb +4 -4
  41. data/lib/grape/middleware/stack.rb +2 -2
  42. data/lib/grape/middleware/versioner/accept_version_header.rb +3 -5
  43. data/lib/grape/middleware/versioner/header.rb +6 -4
  44. data/lib/grape/middleware/versioner/param.rb +1 -0
  45. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
  46. data/lib/grape/middleware/versioner/path.rb +2 -0
  47. data/lib/grape/parser/json.rb +1 -1
  48. data/lib/grape/parser/xml.rb +1 -1
  49. data/lib/grape/path.rb +1 -0
  50. data/lib/grape/request.rb +5 -0
  51. data/lib/grape/router/pattern.rb +1 -1
  52. data/lib/grape/router/route.rb +2 -2
  53. data/lib/grape/router.rb +6 -0
  54. data/lib/grape/util/inheritable_setting.rb +1 -3
  55. data/lib/grape/util/json.rb +2 -0
  56. data/lib/grape/util/lazy_value.rb +3 -2
  57. data/lib/grape/util/strict_hash_configuration.rb +1 -1
  58. data/lib/grape/validations/attributes_doc.rb +58 -0
  59. data/lib/grape/validations/params_scope.rb +137 -78
  60. data/lib/grape/validations/types/array_coercer.rb +0 -2
  61. data/lib/grape/validations/types/custom_type_coercer.rb +1 -2
  62. data/lib/grape/validations/types/dry_type_coercer.rb +4 -8
  63. data/lib/grape/validations/types/json.rb +2 -1
  64. data/lib/grape/validations/types/primitive_coercer.rb +16 -8
  65. data/lib/grape/validations/types/set_coercer.rb +0 -2
  66. data/lib/grape/validations/types.rb +98 -30
  67. data/lib/grape/validations/validators/all_or_none_of_validator.rb +16 -0
  68. data/lib/grape/validations/validators/allow_blank_validator.rb +20 -0
  69. data/lib/grape/validations/validators/as_validator.rb +14 -0
  70. data/lib/grape/validations/validators/at_least_one_of_validator.rb +15 -0
  71. data/lib/grape/validations/validators/base.rb +82 -70
  72. data/lib/grape/validations/validators/coerce_validator.rb +75 -0
  73. data/lib/grape/validations/validators/default_validator.rb +51 -0
  74. data/lib/grape/validations/validators/exactly_one_of_validator.rb +17 -0
  75. data/lib/grape/validations/validators/except_values_validator.rb +24 -0
  76. data/lib/grape/validations/validators/multiple_params_base.rb +24 -20
  77. data/lib/grape/validations/validators/mutual_exclusion_validator.rb +16 -0
  78. data/lib/grape/validations/validators/presence_validator.rb +15 -0
  79. data/lib/grape/validations/validators/regexp_validator.rb +16 -0
  80. data/lib/grape/validations/validators/same_as_validator.rb +29 -0
  81. data/lib/grape/validations/validators/values_validator.rb +88 -0
  82. data/lib/grape/validations.rb +16 -6
  83. data/lib/grape/version.rb +1 -1
  84. data/lib/grape.rb +70 -29
  85. data/spec/grape/api/custom_validations_spec.rb +116 -45
  86. data/spec/grape/api/deeply_included_options_spec.rb +3 -5
  87. data/spec/grape/api/defines_boolean_in_params_spec.rb +2 -3
  88. data/spec/grape/api/documentation_spec.rb +59 -0
  89. data/spec/grape/api/inherited_helpers_spec.rb +0 -2
  90. data/spec/grape/api/instance_spec.rb +0 -1
  91. data/spec/grape/api/invalid_format_spec.rb +2 -2
  92. data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -2
  93. data/spec/grape/api/nested_helpers_spec.rb +0 -2
  94. data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -2
  95. data/spec/grape/api/parameters_modification_spec.rb +0 -2
  96. data/spec/grape/api/patch_method_helpers_spec.rb +0 -2
  97. data/spec/grape/api/recognize_path_spec.rb +1 -3
  98. data/spec/grape/api/required_parameters_in_route_spec.rb +0 -2
  99. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -2
  100. data/spec/grape/api/routes_with_requirements_spec.rb +8 -10
  101. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +9 -17
  102. data/spec/grape/api/shared_helpers_spec.rb +0 -2
  103. data/spec/grape/api_remount_spec.rb +16 -16
  104. data/spec/grape/api_spec.rb +527 -224
  105. data/spec/grape/config_spec.rb +0 -2
  106. data/spec/grape/dsl/callbacks_spec.rb +2 -3
  107. data/spec/grape/dsl/configuration_spec.rb +0 -2
  108. data/spec/grape/dsl/desc_spec.rb +0 -2
  109. data/spec/grape/dsl/headers_spec.rb +39 -11
  110. data/spec/grape/dsl/helpers_spec.rb +3 -4
  111. data/spec/grape/dsl/inside_route_spec.rb +16 -16
  112. data/spec/grape/dsl/logger_spec.rb +15 -19
  113. data/spec/grape/dsl/middleware_spec.rb +2 -3
  114. data/spec/grape/dsl/parameters_spec.rb +2 -2
  115. data/spec/grape/dsl/request_response_spec.rb +7 -8
  116. data/spec/grape/dsl/routing_spec.rb +11 -10
  117. data/spec/grape/dsl/settings_spec.rb +0 -2
  118. data/spec/grape/dsl/validations_spec.rb +0 -17
  119. data/spec/grape/endpoint/declared_spec.rb +261 -16
  120. data/spec/grape/endpoint_spec.rb +98 -57
  121. data/spec/grape/entity_spec.rb +22 -23
  122. data/spec/grape/exceptions/base_spec.rb +16 -2
  123. data/spec/grape/exceptions/body_parse_errors_spec.rb +3 -2
  124. data/spec/grape/exceptions/invalid_accept_header_spec.rb +61 -24
  125. data/spec/grape/exceptions/invalid_formatter_spec.rb +0 -2
  126. data/spec/grape/exceptions/invalid_response_spec.rb +0 -2
  127. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +1 -3
  128. data/spec/grape/exceptions/missing_group_type_spec.rb +21 -0
  129. data/spec/grape/exceptions/missing_mime_type_spec.rb +0 -2
  130. data/spec/grape/exceptions/missing_option_spec.rb +1 -3
  131. data/spec/grape/exceptions/unknown_options_spec.rb +0 -2
  132. data/spec/grape/exceptions/unknown_validator_spec.rb +0 -2
  133. data/spec/grape/exceptions/unsupported_group_type_spec.rb +23 -0
  134. data/spec/grape/exceptions/validation_errors_spec.rb +13 -11
  135. data/spec/grape/exceptions/validation_spec.rb +5 -5
  136. data/spec/grape/extensions/param_builders/hash_spec.rb +7 -9
  137. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +8 -10
  138. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +8 -10
  139. data/spec/grape/integration/global_namespace_function_spec.rb +0 -2
  140. data/spec/grape/integration/rack_sendfile_spec.rb +1 -3
  141. data/spec/grape/integration/rack_spec.rb +0 -2
  142. data/spec/grape/loading_spec.rb +8 -10
  143. data/spec/grape/middleware/auth/base_spec.rb +0 -1
  144. data/spec/grape/middleware/auth/dsl_spec.rb +15 -8
  145. data/spec/grape/middleware/auth/strategies_spec.rb +60 -22
  146. data/spec/grape/middleware/base_spec.rb +24 -17
  147. data/spec/grape/middleware/error_spec.rb +8 -3
  148. data/spec/grape/middleware/exception_spec.rb +111 -163
  149. data/spec/grape/middleware/formatter_spec.rb +27 -8
  150. data/spec/grape/middleware/globals_spec.rb +7 -6
  151. data/spec/grape/middleware/stack_spec.rb +14 -14
  152. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +2 -3
  153. data/spec/grape/middleware/versioner/header_spec.rb +30 -15
  154. data/spec/grape/middleware/versioner/param_spec.rb +7 -3
  155. data/spec/grape/middleware/versioner/path_spec.rb +5 -3
  156. data/spec/grape/middleware/versioner_spec.rb +1 -3
  157. data/spec/grape/named_api_spec.rb +0 -2
  158. data/spec/grape/parser_spec.rb +4 -2
  159. data/spec/grape/path_spec.rb +52 -54
  160. data/spec/grape/presenters/presenter_spec.rb +7 -8
  161. data/spec/grape/request_spec.rb +6 -6
  162. data/spec/grape/util/inheritable_setting_spec.rb +7 -8
  163. data/spec/grape/util/inheritable_values_spec.rb +3 -3
  164. data/spec/grape/util/reverse_stackable_values_spec.rb +3 -2
  165. data/spec/grape/util/stackable_values_spec.rb +7 -6
  166. data/spec/grape/util/strict_hash_configuration_spec.rb +0 -1
  167. data/spec/grape/validations/attributes_doc_spec.rb +153 -0
  168. data/spec/grape/validations/attributes_iterator_spec.rb +0 -2
  169. data/spec/grape/validations/instance_behaivour_spec.rb +9 -12
  170. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +1 -2
  171. data/spec/grape/validations/params_scope_spec.rb +361 -96
  172. data/spec/grape/validations/single_attribute_iterator_spec.rb +2 -3
  173. data/spec/grape/validations/types/array_coercer_spec.rb +0 -2
  174. data/spec/grape/validations/types/primitive_coercer_spec.rb +24 -9
  175. data/spec/grape/validations/types/set_coercer_spec.rb +0 -2
  176. data/spec/grape/validations/types_spec.rb +36 -10
  177. data/spec/grape/validations/validators/all_or_none_spec.rb +50 -58
  178. data/spec/grape/validations/validators/allow_blank_spec.rb +135 -141
  179. data/spec/grape/validations/validators/at_least_one_of_spec.rb +50 -58
  180. data/spec/grape/validations/validators/coerce_spec.rb +99 -24
  181. data/spec/grape/validations/validators/default_spec.rb +72 -80
  182. data/spec/grape/validations/validators/exactly_one_of_spec.rb +71 -79
  183. data/spec/grape/validations/validators/except_values_spec.rb +3 -5
  184. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +71 -79
  185. data/spec/grape/validations/validators/presence_spec.rb +16 -3
  186. data/spec/grape/validations/validators/regexp_spec.rb +25 -33
  187. data/spec/grape/validations/validators/same_as_spec.rb +14 -22
  188. data/spec/grape/validations/validators/values_spec.rb +182 -179
  189. data/spec/grape/validations_spec.rb +149 -80
  190. data/spec/integration/eager_load/eager_load_spec.rb +2 -2
  191. data/spec/integration/multi_json/json_spec.rb +1 -3
  192. data/spec/integration/multi_xml/xml_spec.rb +1 -3
  193. data/spec/shared/versioning_examples.rb +12 -9
  194. data/spec/spec_helper.rb +21 -6
  195. data/spec/support/basic_auth_encode_helpers.rb +1 -1
  196. metadata +125 -115
  197. data/lib/grape/validations/validators/all_or_none.rb +0 -15
  198. data/lib/grape/validations/validators/allow_blank.rb +0 -18
  199. data/lib/grape/validations/validators/as.rb +0 -16
  200. data/lib/grape/validations/validators/at_least_one_of.rb +0 -14
  201. data/lib/grape/validations/validators/coerce.rb +0 -91
  202. data/lib/grape/validations/validators/default.rb +0 -48
  203. data/lib/grape/validations/validators/exactly_one_of.rb +0 -16
  204. data/lib/grape/validations/validators/except_values.rb +0 -22
  205. data/lib/grape/validations/validators/mutual_exclusion.rb +0 -15
  206. data/lib/grape/validations/validators/presence.rb +0 -12
  207. data/lib/grape/validations/validators/regexp.rb +0 -13
  208. data/lib/grape/validations/validators/same_as.rb +0 -26
  209. data/lib/grape/validations/validators/values.rb +0 -83
  210. data/spec/support/eager_load.rb +0 -19
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Validations::ParamsScope do
6
4
  subject do
7
5
  Class.new(Grape::API)
@@ -11,86 +9,6 @@ describe Grape::Validations::ParamsScope do
11
9
  subject
12
10
  end
13
11
 
14
- context 'setting a default' do
15
- let(:documentation) { subject.routes.first.params }
16
-
17
- context 'when the default value is truthy' do
18
- before do
19
- subject.params do
20
- optional :int, type: Integer, default: 42
21
- end
22
- subject.get
23
- end
24
-
25
- it 'adds documentation about the default value' do
26
- expect(documentation).to have_key('int')
27
- expect(documentation['int']).to have_key(:default)
28
- expect(documentation['int'][:default]).to eq(42)
29
- end
30
- end
31
-
32
- context 'when the default value is false' do
33
- before do
34
- subject.params do
35
- optional :bool, type: Grape::API::Boolean, default: false
36
- end
37
- subject.get
38
- end
39
-
40
- it 'adds documentation about the default value' do
41
- expect(documentation).to have_key('bool')
42
- expect(documentation['bool']).to have_key(:default)
43
- expect(documentation['bool'][:default]).to eq(false)
44
- end
45
- end
46
-
47
- context 'when the default value is nil' do
48
- before do
49
- subject.params do
50
- optional :object, type: Object, default: nil
51
- end
52
- subject.get
53
- end
54
-
55
- it 'adds documentation about the default value' do
56
- expect(documentation).to have_key('object')
57
- expect(documentation['object']).to have_key(:default)
58
- expect(documentation['object'][:default]).to eq(nil)
59
- end
60
- end
61
- end
62
-
63
- context 'without a default' do
64
- before do
65
- subject.params do
66
- optional :object, type: Object
67
- end
68
- subject.get
69
- end
70
-
71
- it 'does not add documentation for the default value' do
72
- documentation = subject.routes.first.params
73
- expect(documentation).to have_key('object')
74
- expect(documentation['object']).not_to have_key(:default)
75
- end
76
- end
77
-
78
- context 'setting description' do
79
- %i[desc description].each do |description_type|
80
- it "allows setting #{description_type}" do
81
- subject.params do
82
- requires :int, type: Integer, description_type => 'My very nice integer'
83
- end
84
- subject.get '/single' do
85
- 'int works'
86
- end
87
- get '/single', int: 420
88
- expect(last_response.status).to eq(200)
89
- expect(last_response.body).to eq('int works')
90
- end
91
- end
92
- end
93
-
94
12
  context 'when using custom types' do
95
13
  module ParamsScopeSpec
96
14
  class CustomType
@@ -98,6 +16,7 @@ describe Grape::Validations::ParamsScope do
98
16
 
99
17
  def self.parse(value)
100
18
  raise if value == 'invalid'
19
+
101
20
  new(value)
102
21
  end
103
22
 
@@ -144,7 +63,7 @@ describe Grape::Validations::ParamsScope do
144
63
  get '/renaming-coerced', foo: ' there we go '
145
64
 
146
65
  expect(last_response.status).to eq(200)
147
- expect(last_response.body).to eq('there we go-')
66
+ expect(last_response.body).to eq('-there we go')
148
67
  end
149
68
 
150
69
  it do
@@ -180,6 +99,28 @@ describe Grape::Validations::ParamsScope do
180
99
  expect(last_response.status).to eq(200)
181
100
  expect(last_response.body).to eq('{"baz":{"qux":"any"}}')
182
101
  end
102
+
103
+ it 'renaming can be defined before default' do
104
+ subject.params do
105
+ optional :foo, as: :bar, default: 'before'
106
+ end
107
+ subject.get('/rename-before-default') { declared(params)[:bar] }
108
+ get '/rename-before-default'
109
+
110
+ expect(last_response.status).to eq(200)
111
+ expect(last_response.body).to eq('before')
112
+ end
113
+
114
+ it 'renaming can be defined after default' do
115
+ subject.params do
116
+ optional :foo, default: 'after', as: :bar
117
+ end
118
+ subject.get('/rename-after-default') { declared(params)[:bar] }
119
+ get '/rename-after-default'
120
+
121
+ expect(last_response.status).to eq(200)
122
+ expect(last_response.body).to eq('after')
123
+ end
183
124
  end
184
125
 
185
126
  context 'array without coerce type explicitly given' do
@@ -269,7 +210,7 @@ describe Grape::Validations::ParamsScope do
269
210
  it 'does not raise an exception' do
270
211
  expect do
271
212
  subject.params { optional :numbers, type: Array[Integer], values: 0..2, default: 0..2 }
272
- end.to_not raise_error
213
+ end.not_to raise_error
273
214
  end
274
215
  end
275
216
 
@@ -277,7 +218,7 @@ describe Grape::Validations::ParamsScope do
277
218
  it 'does not raise an exception' do
278
219
  expect do
279
220
  subject.params { optional :numbers, type: Array[Integer], values: [0, 1, 2], default: [1, 0] }
280
- end.to_not raise_error
221
+ end.not_to raise_error
281
222
  end
282
223
  end
283
224
  end
@@ -315,7 +256,7 @@ describe Grape::Validations::ParamsScope do
315
256
  requires :b
316
257
  end
317
258
  end
318
- end.to raise_error Grape::Exceptions::MissingGroupTypeError
259
+ end.to raise_error Grape::Exceptions::MissingGroupType
319
260
 
320
261
  expect do
321
262
  subject.params do
@@ -323,7 +264,7 @@ describe Grape::Validations::ParamsScope do
323
264
  requires :b
324
265
  end
325
266
  end
326
- end.to raise_error Grape::Exceptions::MissingGroupTypeError
267
+ end.to raise_error Grape::Exceptions::MissingGroupType
327
268
  end
328
269
 
329
270
  it 'allows Hash as type' do
@@ -383,7 +324,7 @@ describe Grape::Validations::ParamsScope do
383
324
  requires :b
384
325
  end
385
326
  end
386
- end.to raise_error Grape::Exceptions::UnsupportedGroupTypeError
327
+ end.to raise_error Grape::Exceptions::UnsupportedGroupType
387
328
 
388
329
  expect do
389
330
  subject.params do
@@ -391,7 +332,7 @@ describe Grape::Validations::ParamsScope do
391
332
  requires :b
392
333
  end
393
334
  end
394
- end.to raise_error Grape::Exceptions::UnsupportedGroupTypeError
335
+ end.to raise_error Grape::Exceptions::UnsupportedGroupType
395
336
  end
396
337
  end
397
338
 
@@ -501,7 +442,7 @@ describe Grape::Validations::ParamsScope do
501
442
  requires :c
502
443
  end
503
444
  end
504
- end.to_not raise_error
445
+ end.not_to raise_error
505
446
  end
506
447
 
507
448
  it 'does not raise an error if when using nested given' do
@@ -517,7 +458,7 @@ describe Grape::Validations::ParamsScope do
517
458
  end
518
459
  end
519
460
  end
520
- end.to_not raise_error
461
+ end.not_to raise_error
521
462
  end
522
463
 
523
464
  it 'allows nested dependent parameters' do
@@ -562,13 +503,13 @@ describe Grape::Validations::ParamsScope do
562
503
  body = JSON.parse(last_response.body)
563
504
 
564
505
  expect(body.keys).to include('c')
565
- expect(body.keys).to_not include('b')
506
+ expect(body.keys).not_to include('b')
566
507
  end
567
508
 
568
509
  it 'allows renaming of dependent on parameter' do
569
510
  subject.params do
570
511
  optional :a, as: :b
571
- given b: ->(val) { val == 'x' } do
512
+ given a: ->(val) { val == 'x' } do
572
513
  requires :c
573
514
  end
574
515
  end
@@ -582,7 +523,7 @@ describe Grape::Validations::ParamsScope do
582
523
  expect(last_response.status).to eq 200
583
524
  end
584
525
 
585
- it 'raises an error if the dependent parameter is not the renamed one' do
526
+ it 'does not raise if the dependent parameter is not the renamed one' do
586
527
  expect do
587
528
  subject.params do
588
529
  optional :a, as: :b
@@ -590,6 +531,17 @@ describe Grape::Validations::ParamsScope do
590
531
  requires :c
591
532
  end
592
533
  end
534
+ end.not_to raise_error
535
+ end
536
+
537
+ it 'raises an error if the dependent parameter is the renamed one' do
538
+ expect do
539
+ subject.params do
540
+ optional :a, as: :b
541
+ given :b do
542
+ requires :c
543
+ end
544
+ end
593
545
  end.to raise_error(Grape::Exceptions::UnknownParameter)
594
546
  end
595
547
 
@@ -712,6 +664,317 @@ describe Grape::Validations::ParamsScope do
712
664
  get '/nested', bar: { a: true, c: { b: 'yes' } }
713
665
  expect(JSON.parse(last_response.body)).to eq('bar' => { 'a' => 'true', 'c' => { 'b' => 'yes' } })
714
666
  end
667
+
668
+ context 'when the dependent parameter is not present #declared(params)' do
669
+ context 'lateral parameter' do
670
+ before do
671
+ [true, false].each do |evaluate_given|
672
+ subject.params do
673
+ optional :a
674
+ given :a do
675
+ optional :b
676
+ end
677
+ end
678
+ subject.get("/evaluate_given_#{evaluate_given}") { declared(params, evaluate_given: evaluate_given).to_json }
679
+ end
680
+ end
681
+
682
+ it 'evaluate_given_false' do
683
+ get '/evaluate_given_false', b: 'b'
684
+ expect(JSON.parse(last_response.body)).to eq('a' => nil, 'b' => 'b')
685
+ end
686
+
687
+ it 'evaluate_given_true' do
688
+ get '/evaluate_given_true', b: 'b'
689
+ expect(JSON.parse(last_response.body)).to eq('a' => nil)
690
+ end
691
+ end
692
+
693
+ context 'lateral hash parameter' do
694
+ before do
695
+ [true, false].each do |evaluate_given|
696
+ subject.params do
697
+ optional :a, values: %w[x y]
698
+ given a: ->(a) { a == 'x' } do
699
+ optional :b, type: Hash do
700
+ optional :c
701
+ end
702
+ optional :e
703
+ end
704
+ given a: ->(a) { a == 'y' } do
705
+ optional :b, type: Hash do
706
+ optional :d
707
+ end
708
+ optional :f
709
+ end
710
+ end
711
+ subject.get("/evaluate_given_#{evaluate_given}") { declared(params, evaluate_given: evaluate_given).to_json }
712
+ end
713
+ end
714
+
715
+ it 'evaluate_given_false' do
716
+ get '/evaluate_given_false', a: 'x'
717
+ expect(JSON.parse(last_response.body)).to eq('a' => 'x', 'b' => { 'd' => nil }, 'e' => nil, 'f' => nil)
718
+
719
+ get '/evaluate_given_false', a: 'y'
720
+ expect(JSON.parse(last_response.body)).to eq('a' => 'y', 'b' => { 'd' => nil }, 'e' => nil, 'f' => nil)
721
+ end
722
+
723
+ it 'evaluate_given_true' do
724
+ get '/evaluate_given_true', a: 'x'
725
+ expect(JSON.parse(last_response.body)).to eq('a' => 'x', 'b' => { 'c' => nil }, 'e' => nil)
726
+
727
+ get '/evaluate_given_true', a: 'y'
728
+ expect(JSON.parse(last_response.body)).to eq('a' => 'y', 'b' => { 'd' => nil }, 'f' => nil)
729
+ end
730
+ end
731
+
732
+ context 'lateral parameter within lateral hash parameter' do
733
+ before do
734
+ [true, false].each do |evaluate_given|
735
+ subject.params do
736
+ optional :a, values: %w[x y]
737
+ given a: ->(a) { a == 'x' } do
738
+ optional :b, type: Hash do
739
+ optional :c
740
+ given :c do
741
+ optional :g
742
+ optional :e, type: Hash do
743
+ optional :h
744
+ end
745
+ end
746
+ end
747
+ end
748
+ given a: ->(a) { a == 'y' } do
749
+ optional :b, type: Hash do
750
+ optional :d
751
+ given :d do
752
+ optional :f
753
+ optional :e, type: Hash do
754
+ optional :i
755
+ end
756
+ end
757
+ end
758
+ end
759
+ end
760
+ subject.get("/evaluate_given_#{evaluate_given}") { declared(params, evaluate_given: evaluate_given).to_json }
761
+ end
762
+ end
763
+
764
+ it 'evaluate_given_false' do
765
+ get '/evaluate_given_false', a: 'x'
766
+ expect(JSON.parse(last_response.body)).to eq('a' => 'x', 'b' => { 'd' => nil, 'f' => nil, 'e' => { 'i' => nil } })
767
+
768
+ get '/evaluate_given_false', a: 'x', b: { c: 'c' }
769
+ expect(JSON.parse(last_response.body)).to eq('a' => 'x', 'b' => { 'd' => nil, 'f' => nil, 'e' => { 'i' => nil } })
770
+
771
+ get '/evaluate_given_false', a: 'y'
772
+ expect(JSON.parse(last_response.body)).to eq('a' => 'y', 'b' => { 'd' => nil, 'f' => nil, 'e' => { 'i' => nil } })
773
+
774
+ get '/evaluate_given_false', a: 'y', b: { d: 'd' }
775
+ expect(JSON.parse(last_response.body)).to eq('a' => 'y', 'b' => { 'd' => 'd', 'f' => nil, 'e' => { 'i' => nil } })
776
+ end
777
+
778
+ it 'evaluate_given_true' do
779
+ get '/evaluate_given_true', a: 'x'
780
+ expect(JSON.parse(last_response.body)).to eq('a' => 'x', 'b' => { 'c' => nil })
781
+
782
+ get '/evaluate_given_true', a: 'x', b: { c: 'c' }
783
+ expect(JSON.parse(last_response.body)).to eq('a' => 'x', 'b' => { 'c' => 'c', 'g' => nil, 'e' => { 'h' => nil } })
784
+
785
+ get '/evaluate_given_true', a: 'y'
786
+ expect(JSON.parse(last_response.body)).to eq('a' => 'y', 'b' => { 'd' => nil })
787
+
788
+ get '/evaluate_given_true', a: 'y', b: { d: 'd' }
789
+ expect(JSON.parse(last_response.body)).to eq('a' => 'y', 'b' => { 'd' => 'd', 'f' => nil, 'e' => { 'i' => nil } })
790
+ end
791
+ end
792
+
793
+ context 'lateral parameter within an array param' do
794
+ before do
795
+ [true, false].each do |evaluate_given|
796
+ subject.params do
797
+ optional :array, type: Array do
798
+ optional :a
799
+ given :a do
800
+ optional :b
801
+ end
802
+ end
803
+ end
804
+ subject.post("/evaluate_given_#{evaluate_given}") do
805
+ declared(params, evaluate_given: evaluate_given).to_json
806
+ end
807
+ end
808
+ end
809
+
810
+ it 'evaluate_given_false' do
811
+ post '/evaluate_given_false', { array: [{ b: 'b' }, { a: 'a', b: 'b' }] }.to_json, 'CONTENT_TYPE' => 'application/json'
812
+ expect(JSON.parse(last_response.body)).to eq('array' => [{ 'a' => nil, 'b' => 'b' }, { 'a' => 'a', 'b' => 'b' }])
813
+ end
814
+
815
+ it 'evaluate_given_true' do
816
+ post '/evaluate_given_true', { array: [{ b: 'b' }, { a: 'a', b: 'b' }] }.to_json, 'CONTENT_TYPE' => 'application/json'
817
+ expect(JSON.parse(last_response.body)).to eq('array' => [{ 'a' => nil }, { 'a' => 'a', 'b' => 'b' }])
818
+ end
819
+ end
820
+
821
+ context 'nested given parameter' do
822
+ before do
823
+ [true, false].each do |evaluate_given|
824
+ subject.params do
825
+ optional :a
826
+ optional :c
827
+ given :a do
828
+ given :c do
829
+ optional :b
830
+ end
831
+ end
832
+ end
833
+ subject.post("/evaluate_given_#{evaluate_given}") do
834
+ declared(params, evaluate_given: evaluate_given).to_json
835
+ end
836
+ end
837
+ end
838
+
839
+ it 'evaluate_given_false' do
840
+ post '/evaluate_given_false', { a: 'a', b: 'b' }.to_json, 'CONTENT_TYPE' => 'application/json'
841
+ expect(JSON.parse(last_response.body)).to eq('a' => 'a', 'b' => 'b', 'c' => nil)
842
+
843
+ post '/evaluate_given_false', { c: 'c', b: 'b' }.to_json, 'CONTENT_TYPE' => 'application/json'
844
+ expect(JSON.parse(last_response.body)).to eq('a' => nil, 'b' => 'b', 'c' => 'c')
845
+
846
+ post '/evaluate_given_false', { a: 'a', c: 'c', b: 'b' }.to_json, 'CONTENT_TYPE' => 'application/json'
847
+ expect(JSON.parse(last_response.body)).to eq('a' => 'a', 'b' => 'b', 'c' => 'c')
848
+ end
849
+
850
+ it 'evaluate_given_true' do
851
+ post '/evaluate_given_true', { a: 'a', b: 'b' }.to_json, 'CONTENT_TYPE' => 'application/json'
852
+ expect(JSON.parse(last_response.body)).to eq('a' => 'a', 'c' => nil)
853
+
854
+ post '/evaluate_given_true', { c: 'c', b: 'b' }.to_json, 'CONTENT_TYPE' => 'application/json'
855
+ expect(JSON.parse(last_response.body)).to eq('a' => nil, 'c' => 'c')
856
+
857
+ post '/evaluate_given_true', { a: 'a', c: 'c', b: 'b' }.to_json, 'CONTENT_TYPE' => 'application/json'
858
+ expect(JSON.parse(last_response.body)).to eq('a' => 'a', 'b' => 'b', 'c' => 'c')
859
+ end
860
+ end
861
+
862
+ context 'nested given parameter within an array param' do
863
+ before do
864
+ [true, false].each do |evaluate_given|
865
+ subject.params do
866
+ optional :array, type: Array do
867
+ optional :a
868
+ optional :c
869
+ given :a do
870
+ given :c do
871
+ optional :b
872
+ end
873
+ end
874
+ end
875
+ end
876
+ subject.post("/evaluate_given_#{evaluate_given}") do
877
+ declared(params, evaluate_given: evaluate_given).to_json
878
+ end
879
+ end
880
+ end
881
+
882
+ let :evaluate_given_params do
883
+ {
884
+ array: [
885
+ { a: 'a', b: 'b' },
886
+ { c: 'c', b: 'b' },
887
+ { a: 'a', c: 'c', b: 'b' }
888
+ ]
889
+ }
890
+ end
891
+
892
+ it 'evaluate_given_false' do
893
+ post '/evaluate_given_false', evaluate_given_params.to_json, 'CONTENT_TYPE' => 'application/json'
894
+ expect(JSON.parse(last_response.body)).to eq('array' => [{ 'a' => 'a', 'b' => 'b', 'c' => nil }, { 'a' => nil, 'b' => 'b', 'c' => 'c' }, { 'a' => 'a', 'b' => 'b', 'c' => 'c' }])
895
+ end
896
+
897
+ it 'evaluate_given_true' do
898
+ post '/evaluate_given_true', evaluate_given_params.to_json, 'CONTENT_TYPE' => 'application/json'
899
+ expect(JSON.parse(last_response.body)).to eq('array' => [{ 'a' => 'a', 'c' => nil }, { 'a' => nil, 'c' => 'c' }, { 'a' => 'a', 'b' => 'b', 'c' => 'c' }])
900
+ end
901
+ end
902
+
903
+ context 'nested given parameter within a nested given parameter within an array param' do
904
+ before do
905
+ [true, false].each do |evaluate_given|
906
+ subject.params do
907
+ optional :array, type: Array do
908
+ optional :a
909
+ optional :c
910
+ given :a do
911
+ given :c do
912
+ optional :array, type: Array do
913
+ optional :a
914
+ optional :c
915
+ given :a do
916
+ given :c do
917
+ optional :b
918
+ end
919
+ end
920
+ end
921
+ end
922
+ end
923
+ end
924
+ end
925
+ subject.post("/evaluate_given_#{evaluate_given}") do
926
+ declared(params, evaluate_given: evaluate_given).to_json
927
+ end
928
+ end
929
+ end
930
+
931
+ let :evaluate_given_params do
932
+ {
933
+ array: [{
934
+ a: 'a',
935
+ c: 'c',
936
+ array: [
937
+ { a: 'a', b: 'b' },
938
+ { c: 'c', b: 'b' },
939
+ { a: 'a', c: 'c', b: 'b' }
940
+ ]
941
+ }]
942
+ }
943
+ end
944
+
945
+ it 'evaluate_given_false' do
946
+ expected_response_hash = {
947
+ 'array' => [{
948
+ 'a' => 'a',
949
+ 'c' => 'c',
950
+ 'array' => [
951
+ { 'a' => 'a', 'b' => 'b', 'c' => nil },
952
+ { 'a' => nil, 'c' => 'c', 'b' => 'b' },
953
+ { 'a' => 'a', 'c' => 'c', 'b' => 'b' }
954
+ ]
955
+ }]
956
+ }
957
+ post '/evaluate_given_false', evaluate_given_params.to_json, 'CONTENT_TYPE' => 'application/json'
958
+ expect(JSON.parse(last_response.body)).to eq(expected_response_hash)
959
+ end
960
+
961
+ it 'evaluate_given_true' do
962
+ expected_response_hash = {
963
+ 'array' => [{
964
+ 'a' => 'a',
965
+ 'c' => 'c',
966
+ 'array' => [
967
+ { 'a' => 'a', 'c' => nil },
968
+ { 'a' => nil, 'c' => 'c' },
969
+ { 'a' => 'a', 'b' => 'b', 'c' => 'c' }
970
+ ]
971
+ }]
972
+ }
973
+ post '/evaluate_given_true', evaluate_given_params.to_json, 'CONTENT_TYPE' => 'application/json'
974
+ expect(JSON.parse(last_response.body)).to eq(expected_response_hash)
975
+ end
976
+ end
977
+ end
715
978
  end
716
979
 
717
980
  context 'default value in given block' do
@@ -753,7 +1016,7 @@ describe Grape::Validations::ParamsScope do
753
1016
  subject.get('/test') { 'ok' }
754
1017
  end
755
1018
 
756
- it 'should pass none Hash params' do
1019
+ it 'passes none Hash params' do
757
1020
  get '/test', foos: ['']
758
1021
  expect(last_response.status).to eq(200)
759
1022
  expect(last_response.body).to eq('ok')
@@ -929,6 +1192,7 @@ describe Grape::Validations::ParamsScope do
929
1192
  expect(last_response.body).to eq('one is missing, two is missing, three is missing')
930
1193
  end
931
1194
  end
1195
+
932
1196
  context 'when fail_fast is defined it stops the validation' do
933
1197
  it 'of other params' do
934
1198
  subject.params do
@@ -941,6 +1205,7 @@ describe Grape::Validations::ParamsScope do
941
1205
  expect(last_response.status).to eq(400)
942
1206
  expect(last_response.body).to eq('one is missing')
943
1207
  end
1208
+
944
1209
  it 'for a single param' do
945
1210
  subject.params do
946
1211
  requires :one, allow_blank: false, regexp: /[0-9]+/, fail_fast: true
@@ -991,7 +1256,7 @@ describe Grape::Validations::ParamsScope do
991
1256
  end
992
1257
 
993
1258
  it 'prioritizes parameter validation over group validation' do
994
- expect(last_response.body).to_not include('address is empty')
1259
+ expect(last_response.body).not_to include('address is empty')
995
1260
  end
996
1261
  end
997
1262
  end
@@ -1,10 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Validations::SingleAttributeIterator do
6
4
  describe '#each' do
7
5
  subject(:iterator) { described_class.new(validator, scope, params) }
6
+
8
7
  let(:scope) { Grape::Validations::ParamsScope.new(api: Class.new(Grape::API)) }
9
8
  let(:validator) { double(attrs: %i[first second]) }
10
9
 
@@ -49,7 +48,7 @@ describe Grape::Validations::SingleAttributeIterator do
49
48
  it 'marks params with skipped values' do
50
49
  expect { |b| iterator.each(&b) }.to yield_successive_args(
51
50
  [params[0], :first, false, true], [params[0], :second, false, true],
52
- [params[1], :first, false, false], [params[1], :second, false, false],
51
+ [params[1], :first, false, false], [params[1], :second, false, false]
53
52
  )
54
53
  end
55
54
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Validations::Types::ArrayCoercer do
6
4
  subject { described_class.new(type) }
7
5