grape 1.3.0 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +119 -1
  3. data/LICENSE +1 -1
  4. data/README.md +123 -29
  5. data/UPGRADING.md +265 -39
  6. data/lib/grape/api/instance.rb +32 -31
  7. data/lib/grape/api.rb +5 -5
  8. data/lib/grape/content_types.rb +34 -0
  9. data/lib/grape/dsl/callbacks.rb +1 -1
  10. data/lib/grape/dsl/helpers.rb +2 -1
  11. data/lib/grape/dsl/inside_route.rb +77 -43
  12. data/lib/grape/dsl/parameters.rb +12 -8
  13. data/lib/grape/dsl/routing.rb +12 -11
  14. data/lib/grape/dsl/validations.rb +18 -1
  15. data/lib/grape/eager_load.rb +1 -1
  16. data/lib/grape/endpoint.rb +8 -6
  17. data/lib/grape/exceptions/base.rb +0 -4
  18. data/lib/grape/exceptions/validation.rb +1 -1
  19. data/lib/grape/exceptions/validation_errors.rb +12 -13
  20. data/lib/grape/http/headers.rb +26 -0
  21. data/lib/grape/middleware/auth/base.rb +3 -3
  22. data/lib/grape/middleware/base.rb +4 -5
  23. data/lib/grape/middleware/error.rb +11 -13
  24. data/lib/grape/middleware/formatter.rb +3 -3
  25. data/lib/grape/middleware/stack.rb +10 -2
  26. data/lib/grape/middleware/versioner/header.rb +4 -4
  27. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
  28. data/lib/grape/middleware/versioner/path.rb +1 -1
  29. data/lib/grape/namespace.rb +12 -2
  30. data/lib/grape/path.rb +13 -3
  31. data/lib/grape/request.rb +13 -8
  32. data/lib/grape/router/attribute_translator.rb +26 -5
  33. data/lib/grape/router/pattern.rb +17 -16
  34. data/lib/grape/router/route.rb +5 -24
  35. data/lib/grape/router.rb +26 -30
  36. data/lib/grape/{serve_file → serve_stream}/file_body.rb +1 -1
  37. data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +1 -1
  38. data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +8 -8
  39. data/lib/grape/util/base_inheritable.rb +15 -8
  40. data/lib/grape/util/cache.rb +20 -0
  41. data/lib/grape/util/lazy_object.rb +43 -0
  42. data/lib/grape/util/lazy_value.rb +1 -0
  43. data/lib/grape/util/reverse_stackable_values.rb +2 -0
  44. data/lib/grape/util/stackable_values.rb +7 -20
  45. data/lib/grape/validations/attributes_iterator.rb +8 -0
  46. data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
  47. data/lib/grape/validations/params_scope.rb +10 -8
  48. data/lib/grape/validations/single_attribute_iterator.rb +1 -1
  49. data/lib/grape/validations/types/array_coercer.rb +14 -5
  50. data/lib/grape/validations/types/build_coercer.rb +5 -8
  51. data/lib/grape/validations/types/custom_type_coercer.rb +16 -2
  52. data/lib/grape/validations/types/dry_type_coercer.rb +36 -1
  53. data/lib/grape/validations/types/file.rb +15 -12
  54. data/lib/grape/validations/types/invalid_value.rb +24 -0
  55. data/lib/grape/validations/types/json.rb +40 -36
  56. data/lib/grape/validations/types/primitive_coercer.rb +15 -6
  57. data/lib/grape/validations/types/set_coercer.rb +6 -4
  58. data/lib/grape/validations/types/variant_collection_coercer.rb +1 -1
  59. data/lib/grape/validations/types.rb +7 -9
  60. data/lib/grape/validations/validator_factory.rb +1 -1
  61. data/lib/grape/validations/validators/as.rb +1 -1
  62. data/lib/grape/validations/validators/base.rb +8 -8
  63. data/lib/grape/validations/validators/coerce.rb +11 -15
  64. data/lib/grape/validations/validators/default.rb +3 -5
  65. data/lib/grape/validations/validators/exactly_one_of.rb +4 -2
  66. data/lib/grape/validations/validators/except_values.rb +1 -1
  67. data/lib/grape/validations/validators/multiple_params_base.rb +2 -1
  68. data/lib/grape/validations/validators/regexp.rb +1 -1
  69. data/lib/grape/validations/validators/values.rb +1 -1
  70. data/lib/grape/version.rb +1 -1
  71. data/lib/grape.rb +5 -5
  72. data/spec/grape/api/instance_spec.rb +50 -0
  73. data/spec/grape/api_remount_spec.rb +9 -4
  74. data/spec/grape/api_spec.rb +82 -6
  75. data/spec/grape/dsl/inside_route_spec.rb +182 -33
  76. data/spec/grape/endpoint/declared_spec.rb +601 -0
  77. data/spec/grape/endpoint_spec.rb +0 -521
  78. data/spec/grape/entity_spec.rb +7 -1
  79. data/spec/grape/exceptions/validation_errors_spec.rb +2 -2
  80. data/spec/grape/integration/rack_sendfile_spec.rb +12 -8
  81. data/spec/grape/middleware/auth/strategies_spec.rb +1 -1
  82. data/spec/grape/middleware/error_spec.rb +1 -1
  83. data/spec/grape/middleware/formatter_spec.rb +3 -3
  84. data/spec/grape/middleware/stack_spec.rb +10 -0
  85. data/spec/grape/path_spec.rb +4 -4
  86. data/spec/grape/request_spec.rb +1 -1
  87. data/spec/grape/validations/instance_behaivour_spec.rb +1 -1
  88. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +13 -3
  89. data/spec/grape/validations/params_scope_spec.rb +26 -0
  90. data/spec/grape/validations/single_attribute_iterator_spec.rb +17 -6
  91. data/spec/grape/validations/types/array_coercer_spec.rb +35 -0
  92. data/spec/grape/validations/types/primitive_coercer_spec.rb +135 -0
  93. data/spec/grape/validations/types/set_coercer_spec.rb +34 -0
  94. data/spec/grape/validations/types_spec.rb +1 -1
  95. data/spec/grape/validations/validators/coerce_spec.rb +366 -86
  96. data/spec/grape/validations/validators/default_spec.rb +170 -0
  97. data/spec/grape/validations/validators/exactly_one_of_spec.rb +12 -12
  98. data/spec/grape/validations/validators/except_values_spec.rb +1 -0
  99. data/spec/grape/validations/validators/values_spec.rb +1 -1
  100. data/spec/grape/validations_spec.rb +298 -30
  101. data/spec/integration/eager_load/eager_load_spec.rb +15 -0
  102. data/spec/shared/versioning_examples.rb +20 -20
  103. data/spec/spec_helper.rb +3 -10
  104. data/spec/support/chunks.rb +14 -0
  105. data/spec/support/eager_load.rb +19 -0
  106. data/spec/support/versioned_helpers.rb +4 -6
  107. metadata +27 -10
  108. data/lib/grape/util/content_types.rb +0 -28
@@ -9,16 +9,23 @@ describe Grape::Validations do
9
9
  subject
10
10
  end
11
11
 
12
+ def declared_params
13
+ subject.namespace_stackable(:declared_params).flatten
14
+ end
15
+
12
16
  describe 'params' do
13
17
  context 'optional' do
14
- it 'validates when params is present' do
18
+ before do
15
19
  subject.params do
16
20
  optional :a_number, regexp: /^[0-9]+$/
21
+ optional :attachment, type: File
17
22
  end
18
23
  subject.get '/optional' do
19
24
  'optional works!'
20
25
  end
26
+ end
21
27
 
28
+ it 'validates when params is present' do
22
29
  get '/optional', a_number: 'string'
23
30
  expect(last_response.status).to eq(400)
24
31
  expect(last_response.body).to eq('a_number is invalid')
@@ -29,14 +36,7 @@ describe Grape::Validations do
29
36
  end
30
37
 
31
38
  it "doesn't validate when param not present" do
32
- subject.params do
33
- optional :a_number, regexp: /^[0-9]+$/
34
- end
35
- subject.get '/optional' do
36
- 'optional works!'
37
- end
38
-
39
- get '/optional'
39
+ get '/optional', a_number: nil, attachment: nil
40
40
  expect(last_response.status).to eq(200)
41
41
  expect(last_response.body).to eq('optional works!')
42
42
  end
@@ -45,7 +45,7 @@ describe Grape::Validations do
45
45
  subject.params do
46
46
  optional :some_param
47
47
  end
48
- expect(subject.route_setting(:declared_params)).to eq([:some_param])
48
+ expect(declared_params).to eq([:some_param])
49
49
  end
50
50
  end
51
51
 
@@ -65,7 +65,7 @@ describe Grape::Validations do
65
65
 
66
66
  it 'adds entity documentation to declared params' do
67
67
  define_optional_using
68
- expect(subject.route_setting(:declared_params)).to eq(%i[field_a field_b])
68
+ expect(declared_params).to eq(%i[field_a field_b])
69
69
  end
70
70
 
71
71
  it 'works when field_a and field_b are not present' do
@@ -112,7 +112,7 @@ describe Grape::Validations do
112
112
  subject.params do
113
113
  requires :some_param
114
114
  end
115
- expect(subject.route_setting(:declared_params)).to eq([:some_param])
115
+ expect(declared_params).to eq([:some_param])
116
116
  end
117
117
 
118
118
  it 'works when required field is present but nil' do
@@ -197,7 +197,7 @@ describe Grape::Validations do
197
197
 
198
198
  it 'adds entity documentation to declared params' do
199
199
  define_requires_all
200
- expect(subject.route_setting(:declared_params)).to eq(%i[required_field optional_field])
200
+ expect(declared_params).to eq(%i[required_field optional_field])
201
201
  end
202
202
 
203
203
  it 'errors when required_field is not present' do
@@ -232,7 +232,7 @@ describe Grape::Validations do
232
232
 
233
233
  it 'adds entity documentation to declared params' do
234
234
  define_requires_none
235
- expect(subject.route_setting(:declared_params)).to eq(%i[required_field optional_field])
235
+ expect(declared_params).to eq(%i[required_field optional_field])
236
236
  end
237
237
 
238
238
  it 'errors when required_field is not present' do
@@ -262,7 +262,7 @@ describe Grape::Validations do
262
262
 
263
263
  it 'adds only the entity documentation to declared params, nothing more' do
264
264
  define_requires_all
265
- expect(subject.route_setting(:declared_params)).to eq(%i[required_field optional_field])
265
+ expect(declared_params).to eq(%i[required_field optional_field])
266
266
  end
267
267
  end
268
268
 
@@ -328,7 +328,7 @@ describe Grape::Validations do
328
328
  requires :key
329
329
  end
330
330
  end
331
- expect(subject.route_setting(:declared_params)).to eq([items: [:key]])
331
+ expect(declared_params).to eq([items: [:key]])
332
332
  end
333
333
  end
334
334
 
@@ -400,7 +400,7 @@ describe Grape::Validations do
400
400
  requires :key
401
401
  end
402
402
  end
403
- expect(subject.route_setting(:declared_params)).to eq([items: [:key]])
403
+ expect(declared_params).to eq([items: [:key]])
404
404
  end
405
405
  end
406
406
 
@@ -463,7 +463,7 @@ describe Grape::Validations do
463
463
  requires :key
464
464
  end
465
465
  end
466
- expect(subject.route_setting(:declared_params)).to eq([items: [:key]])
466
+ expect(declared_params).to eq([items: [:key]])
467
467
  end
468
468
  end
469
469
 
@@ -578,7 +578,7 @@ describe Grape::Validations do
578
578
  # NOTE: with body parameters in json or XML or similar this
579
579
  # should actually fail with: children[parents][name] is missing.
580
580
  expect(last_response.status).to eq(400)
581
- expect(last_response.body).to eq('children[1][parents] is missing')
581
+ expect(last_response.body).to eq('children[1][parents] is missing, children[0][parents][1][name] is missing, children[0][parents][1][name] is empty')
582
582
  end
583
583
 
584
584
  it 'errors when a parameter is not present in array within array' do
@@ -619,7 +619,7 @@ describe Grape::Validations do
619
619
 
620
620
  get '/within_array', children: [name: 'Jay']
621
621
  expect(last_response.status).to eq(400)
622
- expect(last_response.body).to eq('children[0][parents] is missing')
622
+ expect(last_response.body).to eq('children[0][parents] is missing, children[0][parents][0][name] is missing, children[0][parents][0][name] is empty')
623
623
  end
624
624
 
625
625
  it 'errors when param is not an Array' do
@@ -767,7 +767,7 @@ describe Grape::Validations do
767
767
  expect(last_response.status).to eq(200)
768
768
  put_with_json '/within_array', children: [name: 'Jay']
769
769
  expect(last_response.status).to eq(400)
770
- expect(last_response.body).to eq('children[0][parents] is missing')
770
+ expect(last_response.body).to eq('children[0][parents] is missing, children[0][parents][0][name] is missing')
771
771
  end
772
772
  end
773
773
 
@@ -817,7 +817,7 @@ describe Grape::Validations do
817
817
  requires :key
818
818
  end
819
819
  end
820
- expect(subject.route_setting(:declared_params)).to eq([items: [:key]])
820
+ expect(declared_params).to eq([items: [:key]])
821
821
  end
822
822
  end
823
823
 
@@ -842,7 +842,7 @@ describe Grape::Validations do
842
842
  it 'does internal validations if the outer group is present' do
843
843
  get '/nested_optional_group', items: [{ key: 'foo' }]
844
844
  expect(last_response.status).to eq(400)
845
- expect(last_response.body).to eq('items[0][required_subitems] is missing')
845
+ expect(last_response.body).to eq('items[0][required_subitems] is missing, items[0][required_subitems][0][value] is missing')
846
846
 
847
847
  get '/nested_optional_group', items: [{ key: 'foo', required_subitems: [{ value: 'bar' }] }]
848
848
  expect(last_response.status).to eq(200)
@@ -862,7 +862,7 @@ describe Grape::Validations do
862
862
  it 'handles validation within arrays' do
863
863
  get '/nested_optional_group', items: [{ key: 'foo' }]
864
864
  expect(last_response.status).to eq(400)
865
- expect(last_response.body).to eq('items[0][required_subitems] is missing')
865
+ expect(last_response.body).to eq('items[0][required_subitems] is missing, items[0][required_subitems][0][value] is missing')
866
866
 
867
867
  get '/nested_optional_group', items: [{ key: 'foo', required_subitems: [{ value: 'bar' }] }]
868
868
  expect(last_response.status).to eq(200)
@@ -881,7 +881,275 @@ describe Grape::Validations do
881
881
  requires(:required_subitems, type: Array) { requires :value }
882
882
  end
883
883
  end
884
- expect(subject.route_setting(:declared_params)).to eq([items: [:key, { optional_subitems: [:value] }, { required_subitems: [:value] }]])
884
+ expect(declared_params).to eq([items: [:key, { optional_subitems: [:value] }, { required_subitems: [:value] }]])
885
+ end
886
+
887
+ context <<~DESC do
888
+ Issue occurs whenever:
889
+ * 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
892
+ * 3rd level is a required item (can be any type)
893
+ * additional levels do not effect the issue from occuring
894
+ DESC
895
+
896
+ it "example based off actual real world use case" do
897
+ subject.params do
898
+ requires :orders, type: Array do
899
+ requires :id, type: Integer
900
+ optional :drugs, type: Array do
901
+ requires :batches, type: Array do
902
+ requires :batch_no, type: String
903
+ end
904
+ end
905
+ end
906
+ end
907
+
908
+ subject.get '/validate_required_arrays_under_optional_arrays' do
909
+ 'validate_required_arrays_under_optional_arrays works!'
910
+ end
911
+
912
+ data = {
913
+ orders: [
914
+ { id: 77, drugs: [{batches: [{batch_no: "A1234567"}]}]},
915
+ { id: 70 }
916
+ ]
917
+ }
918
+
919
+ get '/validate_required_arrays_under_optional_arrays', data
920
+ expect(last_response.body).to eq("validate_required_arrays_under_optional_arrays works!")
921
+ expect(last_response.status).to eq(200)
922
+ end
923
+
924
+ it "simplest example using Array -> Array -> Hash -> String" do
925
+ subject.params do
926
+ requires :orders, type: Array do
927
+ requires :id, type: Integer
928
+ optional :drugs, type: Array do
929
+ requires :batch_no, type: String
930
+ end
931
+ end
932
+ end
933
+
934
+ subject.get '/validate_required_arrays_under_optional_arrays' do
935
+ 'validate_required_arrays_under_optional_arrays works!'
936
+ end
937
+
938
+ data = {
939
+ orders: [
940
+ { id: 77, drugs: [{batch_no: "A1234567"}]},
941
+ { id: 70 }
942
+ ]
943
+ }
944
+
945
+ get '/validate_required_arrays_under_optional_arrays', data
946
+ expect(last_response.body).to eq("validate_required_arrays_under_optional_arrays works!")
947
+ expect(last_response.status).to eq(200)
948
+ end
949
+
950
+ it "simplest example using Array -> Hash -> String" do
951
+ subject.params do
952
+ requires :orders, type: Array do
953
+ requires :id, type: Integer
954
+ optional :drugs, type: Hash do
955
+ requires :batch_no, type: String
956
+ end
957
+ end
958
+ end
959
+
960
+ subject.get '/validate_required_arrays_under_optional_arrays' do
961
+ 'validate_required_arrays_under_optional_arrays works!'
962
+ end
963
+
964
+ data = {
965
+ orders: [
966
+ { id: 77, drugs: {batch_no: "A1234567"}},
967
+ { id: 70 }
968
+ ]
969
+ }
970
+
971
+ get '/validate_required_arrays_under_optional_arrays', data
972
+ expect(last_response.body).to eq("validate_required_arrays_under_optional_arrays works!")
973
+ expect(last_response.status).to eq(200)
974
+ end
975
+
976
+ it "correctly indexes invalida data" do
977
+ subject.params do
978
+ requires :orders, type: Array do
979
+ requires :id, type: Integer
980
+ optional :drugs, type: Array do
981
+ requires :batch_no, type: String
982
+ requires :quantity, type: Integer
983
+ end
984
+ end
985
+ end
986
+
987
+ subject.get '/correctly_indexes' do
988
+ 'correctly_indexes works!'
989
+ end
990
+
991
+ data = {
992
+ orders: [
993
+ { id: 70 },
994
+ { id: 77, drugs: [{batch_no: "A1234567", quantity: 12}, {batch_no: "B222222"}]}
995
+ ]
996
+ }
997
+
998
+ get '/correctly_indexes', data
999
+ expect(last_response.body).to eq("orders[1][drugs][1][quantity] is missing")
1000
+ expect(last_response.status).to eq(400)
1001
+ end
1002
+
1003
+ context "multiple levels of optional and requires settings" do
1004
+ before do
1005
+ subject.params do
1006
+ requires :top, type: Array do
1007
+ requires :top_id, type: Integer, allow_blank: false
1008
+ optional :middle_1, type: Array do
1009
+ requires :middle_1_id, type: Integer, allow_blank: false
1010
+ optional :middle_2, type: Array do
1011
+ requires :middle_2_id, type: String, allow_blank: false
1012
+ optional :bottom, type: Array do
1013
+ requires :bottom_id, type: Integer, allow_blank: false
1014
+ end
1015
+ end
1016
+ end
1017
+ end
1018
+ end
1019
+
1020
+ subject.get '/multi_level' do
1021
+ 'multi_level works!'
1022
+ end
1023
+ end
1024
+
1025
+ it "with valid data" do
1026
+ data = {
1027
+ top: [
1028
+ { 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}]}]}]},
1031
+ { top_id: 2, middle_1: [
1032
+ {middle_1_id: 21}, {middle_1_id: 22, middle_2: [
1033
+ {middle_2_id: 221}]}]},
1034
+ { top_id: 3, middle_1: [
1035
+ {middle_1_id: 31}, {middle_1_id: 32}]},
1036
+ { top_id: 4 }
1037
+ ]
1038
+ }
1039
+
1040
+ get '/multi_level', data
1041
+ expect(last_response.body).to eq("multi_level works!")
1042
+ expect(last_response.status).to eq(200)
1043
+ end
1044
+
1045
+ it "with invalid data" do
1046
+ data = {
1047
+ top: [
1048
+ { 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}]}]}]},
1051
+ { top_id: 2, middle_1: [
1052
+ {middle_1_id: 21}, {middle_1_id: 22, middle_2: [{middle_2_id: nil}]}]},
1053
+ { top_id: 3, middle_1: [
1054
+ {middle_1_id: nil}, {middle_1_id: 32}]},
1055
+ { top_id: nil, missing_top_id: 4 }
1056
+ ]
1057
+ }
1058
+ # debugger
1059
+ 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
+ ])
1066
+ expect(last_response.status).to eq(400)
1067
+ end
1068
+ end
1069
+ end
1070
+
1071
+ it "exactly_one_of" do
1072
+ subject.params do
1073
+ requires :orders, type: Array do
1074
+ requires :id, type: Integer
1075
+ optional :drugs, type: Hash do
1076
+ optional :batch_no, type: String
1077
+ optional :batch_id, type: String
1078
+ exactly_one_of :batch_no, :batch_id
1079
+ end
1080
+ end
1081
+ end
1082
+
1083
+ subject.get '/exactly_one_of' do
1084
+ 'exactly_one_of works!'
1085
+ end
1086
+
1087
+ data = {
1088
+ orders: [
1089
+ { id: 77, drugs: {batch_no: "A1234567"}},
1090
+ { id: 70 }
1091
+ ]
1092
+ }
1093
+
1094
+ get '/exactly_one_of', data
1095
+ expect(last_response.body).to eq("exactly_one_of works!")
1096
+ expect(last_response.status).to eq(200)
1097
+ end
1098
+
1099
+ it "at_least_one_of" do
1100
+ subject.params do
1101
+ requires :orders, type: Array do
1102
+ requires :id, type: Integer
1103
+ optional :drugs, type: Hash do
1104
+ optional :batch_no, type: String
1105
+ optional :batch_id, type: String
1106
+ at_least_one_of :batch_no, :batch_id
1107
+ end
1108
+ end
1109
+ end
1110
+
1111
+ subject.get '/at_least_one_of' do
1112
+ 'at_least_one_of works!'
1113
+ end
1114
+
1115
+ data = {
1116
+ orders: [
1117
+ { id: 77, drugs: {batch_no: "A1234567"}},
1118
+ { id: 70 }
1119
+ ]
1120
+ }
1121
+
1122
+ get '/at_least_one_of', data
1123
+ expect(last_response.body).to eq("at_least_one_of works!")
1124
+ expect(last_response.status).to eq(200)
1125
+ end
1126
+
1127
+ it "all_or_none_of" do
1128
+ subject.params do
1129
+ requires :orders, type: Array do
1130
+ requires :id, type: Integer
1131
+ optional :drugs, type: Hash do
1132
+ optional :batch_no, type: String
1133
+ optional :batch_id, type: String
1134
+ all_or_none_of :batch_no, :batch_id
1135
+ end
1136
+ end
1137
+ end
1138
+
1139
+ subject.get '/all_or_none_of' do
1140
+ 'all_or_none_of works!'
1141
+ end
1142
+
1143
+ data = {
1144
+ orders: [
1145
+ { id: 77, drugs: {batch_no: "A1234567", batch_id: "12"}},
1146
+ { id: 70 }
1147
+ ]
1148
+ }
1149
+
1150
+ get '/all_or_none_of', data
1151
+ expect(last_response.body).to eq("all_or_none_of works!")
1152
+ expect(last_response.status).to eq(200)
885
1153
  end
886
1154
  end
887
1155
 
@@ -1126,14 +1394,14 @@ describe Grape::Validations do
1126
1394
  subject.params do
1127
1395
  use :pagination
1128
1396
  end
1129
- expect(subject.route_setting(:declared_params)).to eq %i[page per_page]
1397
+ expect(declared_params).to eq %i[page per_page]
1130
1398
  end
1131
1399
 
1132
1400
  it 'by #use with multiple params' do
1133
1401
  subject.params do
1134
1402
  use :pagination, :period
1135
1403
  end
1136
- expect(subject.route_setting(:declared_params)).to eq %i[page per_page start_date end_date]
1404
+ expect(declared_params).to eq %i[page per_page start_date end_date]
1137
1405
  end
1138
1406
  end
1139
1407
 
@@ -1422,7 +1690,7 @@ describe Grape::Validations do
1422
1690
  it 'errors when two or more are present' do
1423
1691
  get '/custom_message/exactly_one_of', beer: 'string', wine: 'anotherstring'
1424
1692
  expect(last_response.status).to eq(400)
1425
- expect(last_response.body).to eq 'beer, wine, juice are missing, exactly one parameter is required'
1693
+ expect(last_response.body).to eq 'beer, wine are missing, exactly one parameter is required'
1426
1694
  end
1427
1695
  end
1428
1696
 
@@ -1441,7 +1709,7 @@ describe Grape::Validations do
1441
1709
  it 'errors when two or more are present' do
1442
1710
  get '/exactly_one_of', beer: 'string', wine: 'anotherstring'
1443
1711
  expect(last_response.status).to eq(400)
1444
- expect(last_response.body).to eq 'beer, wine, juice are missing, exactly one parameter must be provided'
1712
+ expect(last_response.body).to eq 'beer, wine are mutually exclusive'
1445
1713
  end
1446
1714
  end
1447
1715
 
@@ -1481,7 +1749,7 @@ describe Grape::Validations do
1481
1749
  it 'errors when two or more are present' do
1482
1750
  get '/exactly_one_of_nested', nested: { beer_nested: 'string' }, nested2: [{ beer_nested2: 'string', wine_nested2: 'anotherstring' }]
1483
1751
  expect(last_response.status).to eq(400)
1484
- expect(last_response.body).to eq 'nested2[0][beer_nested2], nested2[0][wine_nested2], nested2[0][juice_nested2] are missing, exactly one parameter must be provided'
1752
+ expect(last_response.body).to eq 'nested2[0][beer_nested2], nested2[0][wine_nested2] are mutually exclusive'
1485
1753
  end
1486
1754
  end
1487
1755
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
4
+ require 'grape'
5
+
6
+ describe Grape do
7
+ it 'eager_load!' do
8
+ require 'grape/eager_load'
9
+ expect { Grape.eager_load! }.to_not raise_error
10
+ end
11
+
12
+ it 'compile!' do
13
+ expect { Class.new(Grape::API).compile! }.to_not raise_error
14
+ end
15
+ end
@@ -7,7 +7,7 @@ shared_examples_for 'versioning' do
7
7
  subject.get :hello do
8
8
  "Version: #{request.env['api.version']}"
9
9
  end
10
- versioned_get '/hello', 'v1', macro_options
10
+ versioned_get '/hello', 'v1', **macro_options
11
11
  expect(last_response.body).to eql 'Version: v1'
12
12
  end
13
13
 
@@ -18,7 +18,7 @@ shared_examples_for 'versioning' do
18
18
  subject.get :hello do
19
19
  "Version: #{request.env['api.version']}"
20
20
  end
21
- versioned_get '/hello', 'v1', macro_options.merge(prefix: 'api')
21
+ versioned_get '/hello', 'v1', **macro_options.merge(prefix: 'api')
22
22
  expect(last_response.body).to eql 'Version: v1'
23
23
  end
24
24
 
@@ -34,14 +34,14 @@ shared_examples_for 'versioning' do
34
34
  end
35
35
  end
36
36
 
37
- versioned_get '/awesome', 'v1', macro_options
37
+ versioned_get '/awesome', 'v1', **macro_options
38
38
  expect(last_response.status).to eql 404
39
39
 
40
- versioned_get '/awesome', 'v2', macro_options
40
+ versioned_get '/awesome', 'v2', **macro_options
41
41
  expect(last_response.status).to eql 200
42
- versioned_get '/legacy', 'v1', macro_options
42
+ versioned_get '/legacy', 'v1', **macro_options
43
43
  expect(last_response.status).to eql 200
44
- versioned_get '/legacy', 'v2', macro_options
44
+ versioned_get '/legacy', 'v2', **macro_options
45
45
  expect(last_response.status).to eql 404
46
46
  end
47
47
 
@@ -51,11 +51,11 @@ shared_examples_for 'versioning' do
51
51
  'I exist'
52
52
  end
53
53
 
54
- versioned_get '/awesome', 'v1', macro_options
54
+ versioned_get '/awesome', 'v1', **macro_options
55
55
  expect(last_response.status).to eql 200
56
- versioned_get '/awesome', 'v2', macro_options
56
+ versioned_get '/awesome', 'v2', **macro_options
57
57
  expect(last_response.status).to eql 200
58
- versioned_get '/awesome', 'v3', macro_options
58
+ versioned_get '/awesome', 'v3', **macro_options
59
59
  expect(last_response.status).to eql 404
60
60
  end
61
61
 
@@ -74,10 +74,10 @@ shared_examples_for 'versioning' do
74
74
  end
75
75
  end
76
76
 
77
- versioned_get '/version', 'v2', macro_options
77
+ versioned_get '/version', 'v2', **macro_options
78
78
  expect(last_response.status).to eq(200)
79
79
  expect(last_response.body).to eq('v2')
80
- versioned_get '/version', 'v1', macro_options
80
+ versioned_get '/version', 'v1', **macro_options
81
81
  expect(last_response.status).to eq(200)
82
82
  expect(last_response.body).to eq('version v1')
83
83
  end
@@ -98,11 +98,11 @@ shared_examples_for 'versioning' do
98
98
  end
99
99
  end
100
100
 
101
- versioned_get '/version', 'v1', macro_options.merge(prefix: subject.prefix)
101
+ versioned_get '/version', 'v1', **macro_options.merge(prefix: subject.prefix)
102
102
  expect(last_response.status).to eq(200)
103
103
  expect(last_response.body).to eq('version v1')
104
104
 
105
- versioned_get '/version', 'v2', macro_options.merge(prefix: subject.prefix)
105
+ versioned_get '/version', 'v2', **macro_options.merge(prefix: subject.prefix)
106
106
  expect(last_response.status).to eq(200)
107
107
  expect(last_response.body).to eq('v2')
108
108
  end
@@ -131,11 +131,11 @@ shared_examples_for 'versioning' do
131
131
  end
132
132
  end
133
133
 
134
- versioned_get '/version', 'v1', macro_options.merge(prefix: subject.prefix)
134
+ versioned_get '/version', 'v1', **macro_options.merge(prefix: subject.prefix)
135
135
  expect(last_response.status).to eq(200)
136
136
  expect(last_response.body).to eq('v1-version')
137
137
 
138
- versioned_get '/version', 'v2', macro_options.merge(prefix: subject.prefix)
138
+ versioned_get '/version', 'v2', **macro_options.merge(prefix: subject.prefix)
139
139
  expect(last_response.status).to eq(200)
140
140
  expect(last_response.body).to eq('v2-version')
141
141
  end
@@ -148,7 +148,7 @@ shared_examples_for 'versioning' do
148
148
  subject.get :api_version_with_version_param do
149
149
  params[:version]
150
150
  end
151
- versioned_get '/api_version_with_version_param?version=1', 'v1', macro_options
151
+ versioned_get '/api_version_with_version_param?version=1', 'v1', **macro_options
152
152
  expect(last_response.body).to eql '1'
153
153
  end
154
154
 
@@ -183,13 +183,13 @@ shared_examples_for 'versioning' do
183
183
 
184
184
  context 'v1' do
185
185
  it 'finds endpoint' do
186
- versioned_get '/version', 'v1', macro_options
186
+ versioned_get '/version', 'v1', **macro_options
187
187
  expect(last_response.status).to eq(200)
188
188
  expect(last_response.body).to eq('v1')
189
189
  end
190
190
 
191
191
  it 'finds catch all' do
192
- versioned_get '/whatever', 'v1', macro_options
192
+ versioned_get '/whatever', 'v1', **macro_options
193
193
  expect(last_response.status).to eq(200)
194
194
  expect(last_response.body).to end_with 'whatever'
195
195
  end
@@ -197,13 +197,13 @@ shared_examples_for 'versioning' do
197
197
 
198
198
  context 'v2' do
199
199
  it 'finds endpoint' do
200
- versioned_get '/version', 'v2', macro_options
200
+ versioned_get '/version', 'v2', **macro_options
201
201
  expect(last_response.status).to eq(200)
202
202
  expect(last_response.body).to eq('v2')
203
203
  end
204
204
 
205
205
  it 'finds catch all' do
206
- versioned_get '/whatever', 'v2', macro_options
206
+ versioned_get '/whatever', 'v2', **macro_options
207
207
  expect(last_response.status).to eq(200)
208
208
  expect(last_response.body).to end_with 'whatever'
209
209
  end
data/spec/spec_helper.rb CHANGED
@@ -14,25 +14,18 @@ Dir["#{File.dirname(__FILE__)}/support/*.rb"].each do |file|
14
14
  require file
15
15
  end
16
16
 
17
+ eager_load!
18
+
17
19
  # The default value for this setting is true in a standard Rails app,
18
20
  # so it should be set to true here as well to reflect that.
19
21
  I18n.enforce_available_locales = true
20
22
 
21
- module Chunks
22
- def read_chunks(body)
23
- buffer = []
24
- body.each { |chunk| buffer << chunk }
25
-
26
- buffer
27
- end
28
- end
29
-
30
23
  RSpec.configure do |config|
31
- config.include Chunks
32
24
  config.include Rack::Test::Methods
33
25
  config.include Spec::Support::Helpers
34
26
  config.raise_errors_for_deprecations!
35
27
  config.filter_run_when_matching :focus
28
+ config.warnings = true
36
29
 
37
30
  config.before(:each) { Grape::Util::InheritableSetting.reset_global! }
38
31
 
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Chunks
4
+ def read_chunks(body)
5
+ buffer = []
6
+ body.each { |chunk| buffer << chunk }
7
+
8
+ buffer
9
+ end
10
+ end
11
+
12
+ RSpec.configure do |config|
13
+ config.include Chunks
14
+ end