grape 1.5.3 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (207) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +67 -0
  3. data/CONTRIBUTING.md +2 -1
  4. data/README.md +150 -21
  5. data/UPGRADING.md +61 -4
  6. data/grape.gemspec +5 -5
  7. data/lib/grape/api/instance.rb +14 -18
  8. data/lib/grape/api.rb +17 -12
  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 +20 -35
  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/missing_group_type.rb +8 -1
  29. data/lib/grape/exceptions/too_many_multipart_files.rb +11 -0
  30. data/lib/grape/exceptions/unsupported_group_type.rb +8 -1
  31. data/lib/grape/exceptions/validation.rb +1 -6
  32. data/lib/grape/formatter/json.rb +1 -0
  33. data/lib/grape/formatter/serializable_hash.rb +2 -1
  34. data/lib/grape/formatter/xml.rb +1 -0
  35. data/lib/grape/locale/en.yml +9 -8
  36. data/lib/grape/middleware/auth/dsl.rb +7 -2
  37. data/lib/grape/middleware/base.rb +3 -1
  38. data/lib/grape/middleware/error.rb +2 -2
  39. data/lib/grape/middleware/formatter.rb +4 -4
  40. data/lib/grape/middleware/stack.rb +2 -2
  41. data/lib/grape/middleware/versioner/accept_version_header.rb +3 -5
  42. data/lib/grape/middleware/versioner/header.rb +6 -4
  43. data/lib/grape/middleware/versioner/param.rb +1 -0
  44. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
  45. data/lib/grape/middleware/versioner/path.rb +2 -0
  46. data/lib/grape/path.rb +1 -0
  47. data/lib/grape/request.rb +3 -0
  48. data/lib/grape/router/pattern.rb +1 -1
  49. data/lib/grape/router/route.rb +2 -2
  50. data/lib/grape/router.rb +6 -0
  51. data/lib/grape/util/inheritable_setting.rb +1 -3
  52. data/lib/grape/util/json.rb +2 -0
  53. data/lib/grape/util/lazy_value.rb +3 -2
  54. data/lib/grape/util/strict_hash_configuration.rb +1 -1
  55. data/lib/grape/validations/attributes_doc.rb +58 -0
  56. data/lib/grape/validations/params_scope.rb +137 -78
  57. data/lib/grape/validations/types/array_coercer.rb +0 -2
  58. data/lib/grape/validations/types/custom_type_coercer.rb +1 -0
  59. data/lib/grape/validations/types/dry_type_coercer.rb +4 -8
  60. data/lib/grape/validations/types/json.rb +2 -1
  61. data/lib/grape/validations/types/primitive_coercer.rb +16 -8
  62. data/lib/grape/validations/types/set_coercer.rb +0 -2
  63. data/lib/grape/validations/types.rb +98 -30
  64. data/lib/grape/validations/validators/all_or_none_of_validator.rb +16 -0
  65. data/lib/grape/validations/validators/allow_blank_validator.rb +20 -0
  66. data/lib/grape/validations/validators/as_validator.rb +14 -0
  67. data/lib/grape/validations/validators/at_least_one_of_validator.rb +15 -0
  68. data/lib/grape/validations/validators/base.rb +82 -70
  69. data/lib/grape/validations/validators/coerce_validator.rb +75 -0
  70. data/lib/grape/validations/validators/default_validator.rb +51 -0
  71. data/lib/grape/validations/validators/exactly_one_of_validator.rb +17 -0
  72. data/lib/grape/validations/validators/except_values_validator.rb +24 -0
  73. data/lib/grape/validations/validators/multiple_params_base.rb +24 -20
  74. data/lib/grape/validations/validators/mutual_exclusion_validator.rb +16 -0
  75. data/lib/grape/validations/validators/presence_validator.rb +15 -0
  76. data/lib/grape/validations/validators/regexp_validator.rb +16 -0
  77. data/lib/grape/validations/validators/same_as_validator.rb +29 -0
  78. data/lib/grape/validations/validators/values_validator.rb +88 -0
  79. data/lib/grape/validations.rb +16 -6
  80. data/lib/grape/version.rb +1 -1
  81. data/lib/grape.rb +69 -29
  82. data/spec/grape/api/custom_validations_spec.rb +116 -45
  83. data/spec/grape/api/deeply_included_options_spec.rb +3 -5
  84. data/spec/grape/api/defines_boolean_in_params_spec.rb +2 -3
  85. data/spec/grape/api/documentation_spec.rb +59 -0
  86. data/spec/grape/api/inherited_helpers_spec.rb +0 -2
  87. data/spec/grape/api/instance_spec.rb +0 -1
  88. data/spec/grape/api/invalid_format_spec.rb +2 -2
  89. data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -2
  90. data/spec/grape/api/nested_helpers_spec.rb +0 -2
  91. data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -2
  92. data/spec/grape/api/parameters_modification_spec.rb +0 -2
  93. data/spec/grape/api/patch_method_helpers_spec.rb +0 -2
  94. data/spec/grape/api/recognize_path_spec.rb +1 -3
  95. data/spec/grape/api/required_parameters_in_route_spec.rb +0 -2
  96. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -2
  97. data/spec/grape/api/routes_with_requirements_spec.rb +8 -10
  98. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +9 -17
  99. data/spec/grape/api/shared_helpers_spec.rb +0 -2
  100. data/spec/grape/api_remount_spec.rb +16 -16
  101. data/spec/grape/api_spec.rb +457 -231
  102. data/spec/grape/config_spec.rb +0 -2
  103. data/spec/grape/dsl/callbacks_spec.rb +2 -3
  104. data/spec/grape/dsl/configuration_spec.rb +0 -2
  105. data/spec/grape/dsl/desc_spec.rb +0 -2
  106. data/spec/grape/dsl/headers_spec.rb +39 -11
  107. data/spec/grape/dsl/helpers_spec.rb +3 -4
  108. data/spec/grape/dsl/inside_route_spec.rb +16 -16
  109. data/spec/grape/dsl/logger_spec.rb +15 -19
  110. data/spec/grape/dsl/middleware_spec.rb +2 -3
  111. data/spec/grape/dsl/parameters_spec.rb +2 -2
  112. data/spec/grape/dsl/request_response_spec.rb +7 -8
  113. data/spec/grape/dsl/routing_spec.rb +11 -10
  114. data/spec/grape/dsl/settings_spec.rb +0 -2
  115. data/spec/grape/dsl/validations_spec.rb +0 -17
  116. data/spec/grape/endpoint/declared_spec.rb +261 -16
  117. data/spec/grape/endpoint_spec.rb +86 -58
  118. data/spec/grape/entity_spec.rb +22 -23
  119. data/spec/grape/exceptions/base_spec.rb +16 -2
  120. data/spec/grape/exceptions/body_parse_errors_spec.rb +3 -2
  121. data/spec/grape/exceptions/invalid_accept_header_spec.rb +61 -24
  122. data/spec/grape/exceptions/invalid_formatter_spec.rb +0 -2
  123. data/spec/grape/exceptions/invalid_response_spec.rb +0 -2
  124. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +1 -3
  125. data/spec/grape/exceptions/missing_group_type_spec.rb +21 -0
  126. data/spec/grape/exceptions/missing_mime_type_spec.rb +0 -2
  127. data/spec/grape/exceptions/missing_option_spec.rb +1 -3
  128. data/spec/grape/exceptions/unknown_options_spec.rb +0 -2
  129. data/spec/grape/exceptions/unknown_validator_spec.rb +0 -2
  130. data/spec/grape/exceptions/unsupported_group_type_spec.rb +23 -0
  131. data/spec/grape/exceptions/validation_errors_spec.rb +13 -11
  132. data/spec/grape/exceptions/validation_spec.rb +5 -5
  133. data/spec/grape/extensions/param_builders/hash_spec.rb +7 -9
  134. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +8 -10
  135. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +8 -10
  136. data/spec/grape/integration/global_namespace_function_spec.rb +0 -2
  137. data/spec/grape/integration/rack_sendfile_spec.rb +1 -3
  138. data/spec/grape/integration/rack_spec.rb +0 -2
  139. data/spec/grape/loading_spec.rb +8 -10
  140. data/spec/grape/middleware/auth/base_spec.rb +0 -1
  141. data/spec/grape/middleware/auth/dsl_spec.rb +15 -8
  142. data/spec/grape/middleware/auth/strategies_spec.rb +60 -22
  143. data/spec/grape/middleware/base_spec.rb +24 -17
  144. data/spec/grape/middleware/error_spec.rb +8 -3
  145. data/spec/grape/middleware/exception_spec.rb +111 -163
  146. data/spec/grape/middleware/formatter_spec.rb +27 -8
  147. data/spec/grape/middleware/globals_spec.rb +7 -6
  148. data/spec/grape/middleware/stack_spec.rb +14 -14
  149. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +2 -3
  150. data/spec/grape/middleware/versioner/header_spec.rb +30 -15
  151. data/spec/grape/middleware/versioner/param_spec.rb +7 -3
  152. data/spec/grape/middleware/versioner/path_spec.rb +5 -3
  153. data/spec/grape/middleware/versioner_spec.rb +1 -3
  154. data/spec/grape/named_api_spec.rb +0 -2
  155. data/spec/grape/parser_spec.rb +4 -2
  156. data/spec/grape/path_spec.rb +52 -54
  157. data/spec/grape/presenters/presenter_spec.rb +7 -8
  158. data/spec/grape/request_spec.rb +6 -6
  159. data/spec/grape/util/inheritable_setting_spec.rb +7 -8
  160. data/spec/grape/util/inheritable_values_spec.rb +3 -3
  161. data/spec/grape/util/reverse_stackable_values_spec.rb +3 -2
  162. data/spec/grape/util/stackable_values_spec.rb +7 -6
  163. data/spec/grape/util/strict_hash_configuration_spec.rb +0 -1
  164. data/spec/grape/validations/attributes_doc_spec.rb +153 -0
  165. data/spec/grape/validations/attributes_iterator_spec.rb +0 -2
  166. data/spec/grape/validations/instance_behaivour_spec.rb +9 -12
  167. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +1 -2
  168. data/spec/grape/validations/params_scope_spec.rb +361 -96
  169. data/spec/grape/validations/single_attribute_iterator_spec.rb +2 -3
  170. data/spec/grape/validations/types/array_coercer_spec.rb +0 -2
  171. data/spec/grape/validations/types/primitive_coercer_spec.rb +24 -9
  172. data/spec/grape/validations/types/set_coercer_spec.rb +0 -2
  173. data/spec/grape/validations/types_spec.rb +36 -10
  174. data/spec/grape/validations/validators/all_or_none_spec.rb +50 -58
  175. data/spec/grape/validations/validators/allow_blank_spec.rb +135 -141
  176. data/spec/grape/validations/validators/at_least_one_of_spec.rb +50 -58
  177. data/spec/grape/validations/validators/coerce_spec.rb +23 -24
  178. data/spec/grape/validations/validators/default_spec.rb +72 -80
  179. data/spec/grape/validations/validators/exactly_one_of_spec.rb +71 -79
  180. data/spec/grape/validations/validators/except_values_spec.rb +3 -5
  181. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +71 -79
  182. data/spec/grape/validations/validators/presence_spec.rb +16 -3
  183. data/spec/grape/validations/validators/regexp_spec.rb +25 -33
  184. data/spec/grape/validations/validators/same_as_spec.rb +14 -22
  185. data/spec/grape/validations/validators/values_spec.rb +182 -179
  186. data/spec/grape/validations_spec.rb +149 -80
  187. data/spec/integration/eager_load/eager_load_spec.rb +2 -2
  188. data/spec/integration/multi_json/json_spec.rb +1 -3
  189. data/spec/integration/multi_xml/xml_spec.rb +1 -3
  190. data/spec/shared/versioning_examples.rb +12 -9
  191. data/spec/spec_helper.rb +21 -6
  192. data/spec/support/basic_auth_encode_helpers.rb +1 -1
  193. metadata +126 -117
  194. data/lib/grape/validations/validators/all_or_none.rb +0 -15
  195. data/lib/grape/validations/validators/allow_blank.rb +0 -18
  196. data/lib/grape/validations/validators/as.rb +0 -16
  197. data/lib/grape/validations/validators/at_least_one_of.rb +0 -14
  198. data/lib/grape/validations/validators/coerce.rb +0 -91
  199. data/lib/grape/validations/validators/default.rb +0 -48
  200. data/lib/grape/validations/validators/exactly_one_of.rb +0 -16
  201. data/lib/grape/validations/validators/except_values.rb +0 -22
  202. data/lib/grape/validations/validators/mutual_exclusion.rb +0 -15
  203. data/lib/grape/validations/validators/presence.rb +0 -12
  204. data/lib/grape/validations/validators/regexp.rb +0 -13
  205. data/lib/grape/validations/validators/same_as.rb +0 -26
  206. data/lib/grape/validations/validators/values.rb +0 -83
  207. 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