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 do
6
4
  subject { Class.new(Grape::API) }
7
5
 
@@ -45,7 +43,7 @@ describe Grape::Validations do
45
43
  subject.params do
46
44
  optional :some_param
47
45
  end
48
- expect(declared_params).to eq([:some_param])
46
+ expect(Grape::Validations::ParamsScope::Attr.attrs_keys(declared_params)).to eq([:some_param])
49
47
  end
50
48
  end
51
49
 
@@ -65,7 +63,7 @@ describe Grape::Validations do
65
63
 
66
64
  it 'adds entity documentation to declared params' do
67
65
  define_optional_using
68
- expect(declared_params).to eq(%i[field_a field_b])
66
+ expect(Grape::Validations::ParamsScope::Attr.attrs_keys(declared_params)).to eq(%i[field_a field_b])
69
67
  end
70
68
 
71
69
  it 'works when field_a and field_b are not present' do
@@ -112,7 +110,7 @@ describe Grape::Validations do
112
110
  subject.params do
113
111
  requires :some_param
114
112
  end
115
- expect(declared_params).to eq([:some_param])
113
+ expect(Grape::Validations::ParamsScope::Attr.attrs_keys(declared_params)).to eq([:some_param])
116
114
  end
117
115
 
118
116
  it 'works when required field is present but nil' do
@@ -197,7 +195,7 @@ describe Grape::Validations do
197
195
 
198
196
  it 'adds entity documentation to declared params' do
199
197
  define_requires_all
200
- expect(declared_params).to eq(%i[required_field optional_field])
198
+ expect(Grape::Validations::ParamsScope::Attr.attrs_keys(declared_params)).to eq(%i[required_field optional_field])
201
199
  end
202
200
 
203
201
  it 'errors when required_field is not present' do
@@ -232,7 +230,7 @@ describe Grape::Validations do
232
230
 
233
231
  it 'adds entity documentation to declared params' do
234
232
  define_requires_none
235
- expect(declared_params).to eq(%i[required_field optional_field])
233
+ expect(Grape::Validations::ParamsScope::Attr.attrs_keys(declared_params)).to eq(%i[required_field optional_field])
236
234
  end
237
235
 
238
236
  it 'errors when required_field is not present' do
@@ -262,7 +260,7 @@ describe Grape::Validations do
262
260
 
263
261
  it 'adds only the entity documentation to declared params, nothing more' do
264
262
  define_requires_all
265
- expect(declared_params).to eq(%i[required_field optional_field])
263
+ expect(Grape::Validations::ParamsScope::Attr.attrs_keys(declared_params)).to eq(%i[required_field optional_field])
266
264
  end
267
265
  end
268
266
 
@@ -328,7 +326,7 @@ describe Grape::Validations do
328
326
  requires :key
329
327
  end
330
328
  end
331
- expect(declared_params).to eq([items: [:key]])
329
+ expect(Grape::Validations::ParamsScope::Attr.attrs_keys(declared_params)).to eq([items: [:key]])
332
330
  end
333
331
  end
334
332
 
@@ -400,7 +398,7 @@ describe Grape::Validations do
400
398
  requires :key
401
399
  end
402
400
  end
403
- expect(declared_params).to eq([items: [:key]])
401
+ expect(Grape::Validations::ParamsScope::Attr.attrs_keys(declared_params)).to eq([items: [:key]])
404
402
  end
405
403
  end
406
404
 
@@ -463,7 +461,7 @@ describe Grape::Validations do
463
461
  requires :key
464
462
  end
465
463
  end
466
- expect(declared_params).to eq([items: [:key]])
464
+ expect(Grape::Validations::ParamsScope::Attr.attrs_keys(declared_params)).to eq([items: [:key]])
467
465
  end
468
466
  end
469
467
 
@@ -489,17 +487,24 @@ describe Grape::Validations do
489
487
  end
490
488
 
491
489
  context 'custom validator for a Hash' do
492
- module ValuesSpec
493
- module DateRangeValidations
494
- class DateRangeValidator < Grape::Validations::Base
495
- def validate_param!(attr_name, params)
496
- return if params[attr_name][:from] <= params[attr_name][:to]
497
- raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: "'from' must be lower or equal to 'to'")
498
- end
490
+ let(:date_range_validator) do
491
+ Class.new(Grape::Validations::Validators::Base) do
492
+ def validate_param!(attr_name, params)
493
+ return if params[attr_name][:from] <= params[attr_name][:to]
494
+
495
+ raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: "'from' must be lower or equal to 'to'")
499
496
  end
500
497
  end
501
498
  end
502
499
 
500
+ before do
501
+ described_class.register_validator('date_range', date_range_validator)
502
+ end
503
+
504
+ after do
505
+ described_class.deregister_validator('date_range')
506
+ end
507
+
503
508
  before do
504
509
  subject.params do
505
510
  optional :date_range, date_range: true, type: Hash do
@@ -817,7 +822,7 @@ describe Grape::Validations do
817
822
  requires :key
818
823
  end
819
824
  end
820
- expect(declared_params).to eq([items: [:key]])
825
+ expect(Grape::Validations::ParamsScope::Attr.attrs_keys(declared_params)).to eq([items: [:key]])
821
826
  end
822
827
  end
823
828
 
@@ -881,19 +886,19 @@ describe Grape::Validations do
881
886
  requires(:required_subitems, type: Array) { requires :value }
882
887
  end
883
888
  end
884
- expect(declared_params).to eq([items: [:key, { optional_subitems: [:value] }, { required_subitems: [:value] }]])
889
+ expect(Grape::Validations::ParamsScope::Attr.attrs_keys(declared_params)).to eq([items: [:key, { optional_subitems: [:value] }, { required_subitems: [:value] }]])
885
890
  end
886
891
 
887
892
  context <<~DESC do
888
893
  Issue occurs whenever:
889
894
  * param structure with at least three levels
890
- * 1st level item is a required Array that has >1 entry with an optional item present and >1 entry with an optional item missing
891
- * 2nd level is an optional Array or Hash
895
+ * 1st level item is a required Array that has >1 entry with an optional item present and >1 entry with an optional item missing#{' '}
896
+ * 2nd level is an optional Array or Hash#{' '}
892
897
  * 3rd level is a required item (can be any type)
893
898
  * additional levels do not effect the issue from occuring
894
899
  DESC
895
900
 
896
- it "example based off actual real world use case" do
901
+ it 'example based off actual real world use case' do
897
902
  subject.params do
898
903
  requires :orders, type: Array do
899
904
  requires :id, type: Integer
@@ -911,17 +916,17 @@ describe Grape::Validations do
911
916
 
912
917
  data = {
913
918
  orders: [
914
- { id: 77, drugs: [{batches: [{batch_no: "A1234567"}]}]},
919
+ { id: 77, drugs: [{ batches: [{ batch_no: 'A1234567' }] }] },
915
920
  { id: 70 }
916
921
  ]
917
922
  }
918
923
 
919
924
  get '/validate_required_arrays_under_optional_arrays', data
920
- expect(last_response.body).to eq("validate_required_arrays_under_optional_arrays works!")
925
+ expect(last_response.body).to eq('validate_required_arrays_under_optional_arrays works!')
921
926
  expect(last_response.status).to eq(200)
922
927
  end
923
928
 
924
- it "simplest example using Array -> Array -> Hash -> String" do
929
+ it 'simplest example using Array -> Array -> Hash -> String' do
925
930
  subject.params do
926
931
  requires :orders, type: Array do
927
932
  requires :id, type: Integer
@@ -937,17 +942,17 @@ describe Grape::Validations do
937
942
 
938
943
  data = {
939
944
  orders: [
940
- { id: 77, drugs: [{batch_no: "A1234567"}]},
945
+ { id: 77, drugs: [{ batch_no: 'A1234567' }] },
941
946
  { id: 70 }
942
947
  ]
943
948
  }
944
949
 
945
950
  get '/validate_required_arrays_under_optional_arrays', data
946
- expect(last_response.body).to eq("validate_required_arrays_under_optional_arrays works!")
951
+ expect(last_response.body).to eq('validate_required_arrays_under_optional_arrays works!')
947
952
  expect(last_response.status).to eq(200)
948
953
  end
949
954
 
950
- it "simplest example using Array -> Hash -> String" do
955
+ it 'simplest example using Array -> Hash -> String' do
951
956
  subject.params do
952
957
  requires :orders, type: Array do
953
958
  requires :id, type: Integer
@@ -963,17 +968,17 @@ describe Grape::Validations do
963
968
 
964
969
  data = {
965
970
  orders: [
966
- { id: 77, drugs: {batch_no: "A1234567"}},
971
+ { id: 77, drugs: { batch_no: 'A1234567' } },
967
972
  { id: 70 }
968
973
  ]
969
974
  }
970
975
 
971
976
  get '/validate_required_arrays_under_optional_arrays', data
972
- expect(last_response.body).to eq("validate_required_arrays_under_optional_arrays works!")
977
+ expect(last_response.body).to eq('validate_required_arrays_under_optional_arrays works!')
973
978
  expect(last_response.status).to eq(200)
974
979
  end
975
980
 
976
- it "correctly indexes invalida data" do
981
+ it 'correctly indexes invalida data' do
977
982
  subject.params do
978
983
  requires :orders, type: Array do
979
984
  requires :id, type: Integer
@@ -991,16 +996,16 @@ describe Grape::Validations do
991
996
  data = {
992
997
  orders: [
993
998
  { id: 70 },
994
- { id: 77, drugs: [{batch_no: "A1234567", quantity: 12}, {batch_no: "B222222"}]}
999
+ { id: 77, drugs: [{ batch_no: 'A1234567', quantity: 12 }, { batch_no: 'B222222' }] }
995
1000
  ]
996
1001
  }
997
1002
 
998
1003
  get '/correctly_indexes', data
999
- expect(last_response.body).to eq("orders[1][drugs][1][quantity] is missing")
1004
+ expect(last_response.body).to eq('orders[1][drugs][1][quantity] is missing')
1000
1005
  expect(last_response.status).to eq(400)
1001
1006
  end
1002
1007
 
1003
- context "multiple levels of optional and requires settings" do
1008
+ context 'multiple levels of optional and requires settings' do
1004
1009
  before do
1005
1010
  subject.params do
1006
1011
  requires :top, type: Array do
@@ -1022,53 +1027,62 @@ describe Grape::Validations do
1022
1027
  end
1023
1028
  end
1024
1029
 
1025
- it "with valid data" do
1030
+ it 'with valid data' do
1026
1031
  data = {
1027
1032
  top: [
1028
1033
  { top_id: 1, middle_1: [
1029
- {middle_1_id: 11}, {middle_1_id: 12, middle_2: [
1030
- {middle_2_id: 121}, {middle_2_id: 122, bottom: [{bottom_id: 1221}]}]}]},
1034
+ { middle_1_id: 11 }, { middle_1_id: 12, middle_2: [
1035
+ { middle_2_id: 121 }, { middle_2_id: 122, bottom: [{ bottom_id: 1221 }] }
1036
+ ] }
1037
+ ] },
1031
1038
  { top_id: 2, middle_1: [
1032
- {middle_1_id: 21}, {middle_1_id: 22, middle_2: [
1033
- {middle_2_id: 221}]}]},
1039
+ { middle_1_id: 21 }, { middle_1_id: 22, middle_2: [
1040
+ { middle_2_id: 221 }
1041
+ ] }
1042
+ ] },
1034
1043
  { top_id: 3, middle_1: [
1035
- {middle_1_id: 31}, {middle_1_id: 32}]},
1044
+ { middle_1_id: 31 }, { middle_1_id: 32 }
1045
+ ] },
1036
1046
  { top_id: 4 }
1037
1047
  ]
1038
1048
  }
1039
1049
 
1040
1050
  get '/multi_level', data
1041
- expect(last_response.body).to eq("multi_level works!")
1051
+ expect(last_response.body).to eq('multi_level works!')
1042
1052
  expect(last_response.status).to eq(200)
1043
1053
  end
1044
1054
 
1045
- it "with invalid data" do
1055
+ it 'with invalid data' do
1046
1056
  data = {
1047
1057
  top: [
1048
1058
  { top_id: 1, middle_1: [
1049
- {middle_1_id: 11}, {middle_1_id: 12, middle_2: [
1050
- {middle_2_id: 121}, {middle_2_id: 122, bottom: [{bottom_id: nil}]}]}]},
1059
+ { middle_1_id: 11 }, { middle_1_id: 12, middle_2: [
1060
+ { middle_2_id: 121 }, { middle_2_id: 122, bottom: [{ bottom_id: nil }] }
1061
+ ] }
1062
+ ] },
1051
1063
  { top_id: 2, middle_1: [
1052
- {middle_1_id: 21}, {middle_1_id: 22, middle_2: [{middle_2_id: nil}]}]},
1064
+ { middle_1_id: 21 }, { middle_1_id: 22, middle_2: [{ middle_2_id: nil }] }
1065
+ ] },
1053
1066
  { top_id: 3, middle_1: [
1054
- {middle_1_id: nil}, {middle_1_id: 32}]},
1067
+ { middle_1_id: nil }, { middle_1_id: 32 }
1068
+ ] },
1055
1069
  { top_id: nil, missing_top_id: 4 }
1056
1070
  ]
1057
1071
  }
1058
1072
  # debugger
1059
1073
  get '/multi_level', data
1060
- expect(last_response.body.split(", ")).to match_array([
1061
- "top[3][top_id] is empty",
1062
- "top[2][middle_1][0][middle_1_id] is empty",
1063
- "top[1][middle_1][1][middle_2][0][middle_2_id] is empty",
1064
- "top[0][middle_1][1][middle_2][1][bottom][0][bottom_id] is empty"
1065
- ])
1074
+ expect(last_response.body.split(', ')).to match_array([
1075
+ 'top[3][top_id] is empty',
1076
+ 'top[2][middle_1][0][middle_1_id] is empty',
1077
+ 'top[1][middle_1][1][middle_2][0][middle_2_id] is empty',
1078
+ 'top[0][middle_1][1][middle_2][1][bottom][0][bottom_id] is empty'
1079
+ ])
1066
1080
  expect(last_response.status).to eq(400)
1067
1081
  end
1068
1082
  end
1069
1083
  end
1070
1084
 
1071
- it "exactly_one_of" do
1085
+ it 'exactly_one_of' do
1072
1086
  subject.params do
1073
1087
  requires :orders, type: Array do
1074
1088
  requires :id, type: Integer
@@ -1086,17 +1100,17 @@ describe Grape::Validations do
1086
1100
 
1087
1101
  data = {
1088
1102
  orders: [
1089
- { id: 77, drugs: {batch_no: "A1234567"}},
1103
+ { id: 77, drugs: { batch_no: 'A1234567' } },
1090
1104
  { id: 70 }
1091
1105
  ]
1092
1106
  }
1093
1107
 
1094
1108
  get '/exactly_one_of', data
1095
- expect(last_response.body).to eq("exactly_one_of works!")
1109
+ expect(last_response.body).to eq('exactly_one_of works!')
1096
1110
  expect(last_response.status).to eq(200)
1097
1111
  end
1098
1112
 
1099
- it "at_least_one_of" do
1113
+ it 'at_least_one_of' do
1100
1114
  subject.params do
1101
1115
  requires :orders, type: Array do
1102
1116
  requires :id, type: Integer
@@ -1114,17 +1128,17 @@ describe Grape::Validations do
1114
1128
 
1115
1129
  data = {
1116
1130
  orders: [
1117
- { id: 77, drugs: {batch_no: "A1234567"}},
1131
+ { id: 77, drugs: { batch_no: 'A1234567' } },
1118
1132
  { id: 70 }
1119
1133
  ]
1120
1134
  }
1121
1135
 
1122
1136
  get '/at_least_one_of', data
1123
- expect(last_response.body).to eq("at_least_one_of works!")
1137
+ expect(last_response.body).to eq('at_least_one_of works!')
1124
1138
  expect(last_response.status).to eq(200)
1125
1139
  end
1126
1140
 
1127
- it "all_or_none_of" do
1141
+ it 'all_or_none_of' do
1128
1142
  subject.params do
1129
1143
  requires :orders, type: Array do
1130
1144
  requires :id, type: Integer
@@ -1142,13 +1156,13 @@ describe Grape::Validations do
1142
1156
 
1143
1157
  data = {
1144
1158
  orders: [
1145
- { id: 77, drugs: {batch_no: "A1234567", batch_id: "12"}},
1159
+ { id: 77, drugs: { batch_no: 'A1234567', batch_id: '12' } },
1146
1160
  { id: 70 }
1147
1161
  ]
1148
1162
  }
1149
1163
 
1150
1164
  get '/all_or_none_of', data
1151
- expect(last_response.body).to eq("all_or_none_of works!")
1165
+ expect(last_response.body).to eq('all_or_none_of works!')
1152
1166
  expect(last_response.status).to eq(200)
1153
1167
  end
1154
1168
  end
@@ -1173,15 +1187,24 @@ describe Grape::Validations do
1173
1187
  end
1174
1188
 
1175
1189
  context 'custom validation' do
1176
- module CustomValidations
1177
- class Customvalidator < Grape::Validations::Base
1190
+ let(:custom_validator) do
1191
+ Class.new(Grape::Validations::Validators::Base) do
1178
1192
  def validate_param!(attr_name, params)
1179
1193
  return if params[attr_name] == 'im custom'
1194
+
1180
1195
  raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: 'is not custom!')
1181
1196
  end
1182
1197
  end
1183
1198
  end
1184
1199
 
1200
+ before do
1201
+ described_class.register_validator('customvalidator', custom_validator)
1202
+ end
1203
+
1204
+ after do
1205
+ described_class.deregister_validator('customvalidator')
1206
+ end
1207
+
1185
1208
  context 'when using optional with a custom validator' do
1186
1209
  before do
1187
1210
  subject.params do
@@ -1321,15 +1344,24 @@ describe Grape::Validations do
1321
1344
  end
1322
1345
 
1323
1346
  context 'when using options on param' do
1324
- module CustomValidations
1325
- class CustomvalidatorWithOptions < Grape::Validations::Base
1347
+ let(:custom_validator_with_options) do
1348
+ Class.new(Grape::Validations::Validators::Base) do
1326
1349
  def validate_param!(attr_name, params)
1327
1350
  return if params[attr_name] == @option[:text]
1351
+
1328
1352
  raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message)
1329
1353
  end
1330
1354
  end
1331
1355
  end
1332
1356
 
1357
+ before do
1358
+ described_class.register_validator('customvalidator_with_options', custom_validator_with_options)
1359
+ end
1360
+
1361
+ after do
1362
+ described_class.deregister_validator('customvalidator_with_options')
1363
+ end
1364
+
1333
1365
  before do
1334
1366
  subject.params do
1335
1367
  optional :custom, customvalidator_with_options: { text: 'im custom with options', message: 'is not custom with options!' }
@@ -1394,14 +1426,14 @@ describe Grape::Validations do
1394
1426
  subject.params do
1395
1427
  use :pagination
1396
1428
  end
1397
- expect(declared_params).to eq %i[page per_page]
1429
+ expect(Grape::Validations::ParamsScope::Attr.attrs_keys(declared_params)).to eq %i[page per_page]
1398
1430
  end
1399
1431
 
1400
1432
  it 'by #use with multiple params' do
1401
1433
  subject.params do
1402
1434
  use :pagination, :period
1403
1435
  end
1404
- expect(declared_params).to eq %i[page per_page start_date end_date]
1436
+ expect(Grape::Validations::ParamsScope::Attr.attrs_keys(declared_params)).to eq %i[page per_page start_date end_date]
1405
1437
  end
1406
1438
  end
1407
1439
 
@@ -1424,21 +1456,25 @@ describe Grape::Validations do
1424
1456
  }
1425
1457
  end
1426
1458
  end
1459
+
1427
1460
  it 'returns defaults' do
1428
1461
  get '/order'
1429
1462
  expect(last_response.status).to eq(200)
1430
1463
  expect(last_response.body).to eq({ order: :asc, order_by: :created_at }.to_json)
1431
1464
  end
1465
+
1432
1466
  it 'overrides default value for order' do
1433
1467
  get '/order?order=desc'
1434
1468
  expect(last_response.status).to eq(200)
1435
1469
  expect(last_response.body).to eq({ order: :desc, order_by: :created_at }.to_json)
1436
1470
  end
1471
+
1437
1472
  it 'overrides default value for order_by' do
1438
1473
  get '/order?order_by=name'
1439
1474
  expect(last_response.status).to eq(200)
1440
1475
  expect(last_response.body).to eq({ order: :asc, order_by: :name }.to_json)
1441
1476
  end
1477
+
1442
1478
  it 'fails with invalid value' do
1443
1479
  get '/order?order=invalid'
1444
1480
  expect(last_response.status).to eq(400)
@@ -1447,23 +1483,35 @@ describe Grape::Validations do
1447
1483
  end
1448
1484
  end
1449
1485
 
1450
- context 'documentation' do
1451
- it 'can be included with a hash' do
1452
- documentation = { example: 'Joe' }
1453
-
1486
+ context 'with block and keyword argument' do
1487
+ before do
1488
+ subject.helpers do
1489
+ params :shared_params do |type:|
1490
+ optional :param, default: type
1491
+ end
1492
+ end
1493
+ subject.format :json
1454
1494
  subject.params do
1455
- requires 'first_name', documentation: documentation
1495
+ use :shared_params, type: 'value'
1456
1496
  end
1457
- subject.get '/' do
1497
+ subject.get '/shared_params' do
1498
+ {
1499
+ param: params[:param]
1500
+ }
1458
1501
  end
1502
+ end
1503
+
1504
+ it 'works' do
1505
+ get '/shared_params'
1459
1506
 
1460
- expect(subject.routes.first.params['first_name'][:documentation]).to eq(documentation)
1507
+ expect(last_response.status).to eq(200)
1508
+ expect(last_response.body).to eq({ param: 'value' }.to_json)
1461
1509
  end
1462
1510
  end
1463
1511
 
1464
1512
  context 'all or none' do
1465
1513
  context 'optional params' do
1466
- before :each do
1514
+ before do
1467
1515
  subject.resource :custom_message do
1468
1516
  params do
1469
1517
  optional :beer
@@ -1476,17 +1524,20 @@ describe Grape::Validations do
1476
1524
  end
1477
1525
  end
1478
1526
  end
1527
+
1479
1528
  context 'with a custom validation message' do
1480
1529
  it 'errors when any one is present' do
1481
1530
  get '/custom_message/all_or_none', beer: 'string'
1482
1531
  expect(last_response.status).to eq(400)
1483
1532
  expect(last_response.body).to eq 'beer, wine, juice all params are required or none is required'
1484
1533
  end
1534
+
1485
1535
  it 'works when all params are present' do
1486
1536
  get '/custom_message/all_or_none', beer: 'string', wine: 'anotherstring', juice: 'anotheranotherstring'
1487
1537
  expect(last_response.status).to eq(200)
1488
1538
  expect(last_response.body).to eq 'all_or_none works!'
1489
1539
  end
1540
+
1490
1541
  it 'works when none are present' do
1491
1542
  get '/custom_message/all_or_none'
1492
1543
  expect(last_response.status).to eq(200)
@@ -1650,7 +1701,7 @@ describe Grape::Validations do
1650
1701
 
1651
1702
  context 'exactly one of' do
1652
1703
  context 'params' do
1653
- before :each do
1704
+ before do
1654
1705
  subject.resources :custom_message do
1655
1706
  params do
1656
1707
  optional :beer
@@ -1714,7 +1765,7 @@ describe Grape::Validations do
1714
1765
  end
1715
1766
 
1716
1767
  context 'nested params' do
1717
- before :each do
1768
+ before do
1718
1769
  subject.params do
1719
1770
  requires :nested, type: Hash do
1720
1771
  optional :beer_nested
@@ -1756,7 +1807,7 @@ describe Grape::Validations do
1756
1807
 
1757
1808
  context 'at least one of' do
1758
1809
  context 'params' do
1759
- before :each do
1810
+ before do
1760
1811
  subject.resources :custom_message do
1761
1812
  params do
1762
1813
  optional :beer
@@ -1820,7 +1871,7 @@ describe Grape::Validations do
1820
1871
  end
1821
1872
 
1822
1873
  context 'nested params' do
1823
- before :each do
1874
+ before do
1824
1875
  subject.params do
1825
1876
  requires :nested, type: Hash do
1826
1877
  optional :beer
@@ -1934,4 +1985,22 @@ describe Grape::Validations do
1934
1985
  end
1935
1986
  end
1936
1987
  end
1988
+
1989
+ describe 'require_validator' do
1990
+ subject { described_class.require_validator(short_name) }
1991
+
1992
+ context 'when found' do
1993
+ let(:short_name) { :presence }
1994
+
1995
+ it { is_expected.to be(Grape::Validations::Validators::PresenceValidator) }
1996
+ end
1997
+
1998
+ context 'when not found' do
1999
+ let(:short_name) { :test }
2000
+
2001
+ it 'raises an error' do
2002
+ expect { subject }.to raise_error(Grape::Exceptions::UnknownValidator)
2003
+ end
2004
+ end
2005
+ end
1937
2006
  end
@@ -6,10 +6,10 @@ require 'grape'
6
6
  describe Grape do
7
7
  it 'eager_load!' do
8
8
  require 'grape/eager_load'
9
- expect { Grape.eager_load! }.to_not raise_error
9
+ expect { described_class.eager_load! }.not_to raise_error
10
10
  end
11
11
 
12
12
  it 'compile!' do
13
- expect { Class.new(Grape::API).compile! }.to_not raise_error
13
+ expect { Class.new(Grape::API).compile! }.not_to raise_error
14
14
  end
15
15
  end
@@ -1,9 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Json do
6
4
  it 'uses multi_json' do
7
- expect(Grape::Json).to eq(::MultiJson)
5
+ expect(described_class).to eq(::MultiJson)
8
6
  end
9
7
  end
@@ -1,9 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Xml do
6
4
  it 'uses multi_xml' do
7
- expect(Grape::Xml).to eq(::MultiXml)
5
+ expect(described_class).to eq(::MultiXml)
8
6
  end
9
7
  end