grape 1.6.1 → 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 (151) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +36 -0
  3. data/CONTRIBUTING.md +1 -1
  4. data/README.md +120 -19
  5. data/UPGRADING.md +19 -4
  6. data/lib/grape/api/instance.rb +1 -1
  7. data/lib/grape/dsl/api.rb +0 -2
  8. data/lib/grape/dsl/callbacks.rb +0 -2
  9. data/lib/grape/dsl/configuration.rb +0 -2
  10. data/lib/grape/dsl/desc.rb +0 -15
  11. data/lib/grape/dsl/helpers.rb +0 -2
  12. data/lib/grape/dsl/inside_route.rb +33 -29
  13. data/lib/grape/dsl/middleware.rb +0 -2
  14. data/lib/grape/dsl/parameters.rb +5 -7
  15. data/lib/grape/dsl/request_response.rb +0 -2
  16. data/lib/grape/dsl/routing.rb +4 -2
  17. data/lib/grape/dsl/settings.rb +0 -2
  18. data/lib/grape/dsl/validations.rb +0 -15
  19. data/lib/grape/error_formatter/json.rb +7 -1
  20. data/lib/grape/exceptions/base.rb +2 -2
  21. data/lib/grape/exceptions/missing_group_type.rb +8 -1
  22. data/lib/grape/exceptions/too_many_multipart_files.rb +11 -0
  23. data/lib/grape/exceptions/unsupported_group_type.rb +8 -1
  24. data/lib/grape/exceptions/validation.rb +0 -4
  25. data/lib/grape/locale/en.yml +9 -8
  26. data/lib/grape/middleware/auth/dsl.rb +0 -1
  27. data/lib/grape/middleware/error.rb +2 -2
  28. data/lib/grape/request.rb +2 -0
  29. data/lib/grape/validations/attributes_doc.rb +58 -0
  30. data/lib/grape/validations/params_scope.rb +66 -40
  31. data/lib/grape/validations/types/array_coercer.rb +2 -2
  32. data/lib/grape/validations/types/build_coercer.rb +94 -0
  33. data/lib/grape/validations/types/dry_type_coercer.rb +13 -8
  34. data/lib/grape/validations/types/json.rb +2 -0
  35. data/lib/grape/validations/types/primitive_coercer.rb +20 -10
  36. data/lib/grape/validations/types/set_coercer.rb +3 -2
  37. data/lib/grape/validations/types.rb +20 -26
  38. data/lib/grape/validations/validators/base.rb +7 -0
  39. data/lib/grape/validations.rb +16 -6
  40. data/lib/grape/version.rb +1 -1
  41. data/lib/grape.rb +20 -15
  42. data/spec/grape/api/custom_validations_spec.rb +41 -2
  43. data/spec/grape/api/deeply_included_options_spec.rb +0 -2
  44. data/spec/grape/api/defines_boolean_in_params_spec.rb +0 -2
  45. data/spec/grape/api/documentation_spec.rb +59 -0
  46. data/spec/grape/api/inherited_helpers_spec.rb +0 -2
  47. data/spec/grape/api/instance_spec.rb +0 -1
  48. data/spec/grape/api/invalid_format_spec.rb +0 -2
  49. data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -2
  50. data/spec/grape/api/nested_helpers_spec.rb +0 -2
  51. data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -2
  52. data/spec/grape/api/parameters_modification_spec.rb +0 -2
  53. data/spec/grape/api/patch_method_helpers_spec.rb +0 -2
  54. data/spec/grape/api/recognize_path_spec.rb +0 -2
  55. data/spec/grape/api/required_parameters_in_route_spec.rb +0 -2
  56. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -2
  57. data/spec/grape/api/routes_with_requirements_spec.rb +0 -2
  58. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +0 -2
  59. data/spec/grape/api/shared_helpers_spec.rb +0 -2
  60. data/spec/grape/api_remount_spec.rb +0 -1
  61. data/spec/grape/api_spec.rb +18 -5
  62. data/spec/grape/config_spec.rb +0 -2
  63. data/spec/grape/dsl/callbacks_spec.rb +0 -2
  64. data/spec/grape/dsl/configuration_spec.rb +0 -2
  65. data/spec/grape/dsl/desc_spec.rb +0 -2
  66. data/spec/grape/dsl/headers_spec.rb +2 -4
  67. data/spec/grape/dsl/helpers_spec.rb +0 -2
  68. data/spec/grape/dsl/inside_route_spec.rb +10 -12
  69. data/spec/grape/dsl/logger_spec.rb +0 -2
  70. data/spec/grape/dsl/middleware_spec.rb +0 -2
  71. data/spec/grape/dsl/parameters_spec.rb +0 -2
  72. data/spec/grape/dsl/request_response_spec.rb +6 -8
  73. data/spec/grape/dsl/routing_spec.rb +1 -3
  74. data/spec/grape/dsl/settings_spec.rb +0 -2
  75. data/spec/grape/dsl/validations_spec.rb +0 -17
  76. data/spec/grape/endpoint/declared_spec.rb +2 -4
  77. data/spec/grape/endpoint_spec.rb +22 -3
  78. data/spec/grape/entity_spec.rb +0 -1
  79. data/spec/grape/exceptions/base_spec.rb +16 -2
  80. data/spec/grape/exceptions/body_parse_errors_spec.rb +0 -2
  81. data/spec/grape/exceptions/invalid_accept_header_spec.rb +0 -2
  82. data/spec/grape/exceptions/invalid_formatter_spec.rb +0 -2
  83. data/spec/grape/exceptions/invalid_response_spec.rb +0 -2
  84. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +1 -3
  85. data/spec/grape/exceptions/missing_group_type_spec.rb +21 -0
  86. data/spec/grape/exceptions/missing_mime_type_spec.rb +0 -2
  87. data/spec/grape/exceptions/missing_option_spec.rb +1 -3
  88. data/spec/grape/exceptions/unknown_options_spec.rb +0 -2
  89. data/spec/grape/exceptions/unknown_validator_spec.rb +0 -2
  90. data/spec/grape/exceptions/unsupported_group_type_spec.rb +23 -0
  91. data/spec/grape/exceptions/validation_errors_spec.rb +0 -1
  92. data/spec/grape/exceptions/validation_spec.rb +1 -3
  93. data/spec/grape/extensions/param_builders/hash_spec.rb +0 -2
  94. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +0 -2
  95. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +0 -2
  96. data/spec/grape/integration/global_namespace_function_spec.rb +0 -2
  97. data/spec/grape/integration/rack_sendfile_spec.rb +0 -2
  98. data/spec/grape/integration/rack_spec.rb +0 -2
  99. data/spec/grape/loading_spec.rb +0 -2
  100. data/spec/grape/middleware/auth/base_spec.rb +0 -1
  101. data/spec/grape/middleware/auth/dsl_spec.rb +0 -2
  102. data/spec/grape/middleware/auth/strategies_spec.rb +0 -2
  103. data/spec/grape/middleware/base_spec.rb +0 -2
  104. data/spec/grape/middleware/error_spec.rb +6 -1
  105. data/spec/grape/middleware/exception_spec.rb +0 -2
  106. data/spec/grape/middleware/formatter_spec.rb +0 -2
  107. data/spec/grape/middleware/globals_spec.rb +0 -2
  108. data/spec/grape/middleware/stack_spec.rb +0 -2
  109. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +0 -2
  110. data/spec/grape/middleware/versioner/header_spec.rb +18 -4
  111. data/spec/grape/middleware/versioner/param_spec.rb +0 -2
  112. data/spec/grape/middleware/versioner/path_spec.rb +0 -2
  113. data/spec/grape/middleware/versioner_spec.rb +0 -2
  114. data/spec/grape/named_api_spec.rb +0 -2
  115. data/spec/grape/parser_spec.rb +0 -2
  116. data/spec/grape/path_spec.rb +0 -2
  117. data/spec/grape/presenters/presenter_spec.rb +0 -2
  118. data/spec/grape/request_spec.rb +0 -2
  119. data/spec/grape/util/inheritable_setting_spec.rb +0 -1
  120. data/spec/grape/util/inheritable_values_spec.rb +0 -1
  121. data/spec/grape/util/reverse_stackable_values_spec.rb +0 -1
  122. data/spec/grape/util/stackable_values_spec.rb +0 -1
  123. data/spec/grape/util/strict_hash_configuration_spec.rb +0 -1
  124. data/spec/grape/validations/attributes_doc_spec.rb +153 -0
  125. data/spec/grape/validations/attributes_iterator_spec.rb +0 -2
  126. data/spec/grape/validations/instance_behaivour_spec.rb +0 -2
  127. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +0 -2
  128. data/spec/grape/validations/params_scope_spec.rb +315 -86
  129. data/spec/grape/validations/single_attribute_iterator_spec.rb +0 -2
  130. data/spec/grape/validations/types/array_coercer_spec.rb +0 -2
  131. data/spec/grape/validations/types/primitive_coercer_spec.rb +20 -5
  132. data/spec/grape/validations/types/set_coercer_spec.rb +0 -2
  133. data/spec/grape/validations/types_spec.rb +28 -2
  134. data/spec/grape/validations/validators/all_or_none_spec.rb +0 -2
  135. data/spec/grape/validations/validators/allow_blank_spec.rb +0 -2
  136. data/spec/grape/validations/validators/at_least_one_of_spec.rb +0 -2
  137. data/spec/grape/validations/validators/coerce_spec.rb +0 -2
  138. data/spec/grape/validations/validators/default_spec.rb +0 -2
  139. data/spec/grape/validations/validators/exactly_one_of_spec.rb +0 -2
  140. data/spec/grape/validations/validators/except_values_spec.rb +0 -2
  141. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +0 -2
  142. data/spec/grape/validations/validators/presence_spec.rb +0 -2
  143. data/spec/grape/validations/validators/regexp_spec.rb +0 -2
  144. data/spec/grape/validations/validators/same_as_spec.rb +0 -2
  145. data/spec/grape/validations/validators/values_spec.rb +0 -2
  146. data/spec/grape/validations_spec.rb +50 -22
  147. data/spec/integration/multi_json/json_spec.rb +0 -2
  148. data/spec/integration/multi_xml/xml_spec.rb +0 -2
  149. data/spec/spec_helper.rb +9 -4
  150. metadata +17 -8
  151. data/spec/support/eager_load.rb +0 -19
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Validations::ParamsScope do
6
4
  subject do
7
5
  Class.new(Grape::API)
@@ -11,86 +9,6 @@ describe Grape::Validations::ParamsScope do
11
9
  subject
12
10
  end
13
11
 
14
- context 'setting a default' do
15
- let(:documentation) { subject.routes.first.params }
16
-
17
- context 'when the default value is truthy' do
18
- before do
19
- subject.params do
20
- optional :int, type: Integer, default: 42
21
- end
22
- subject.get
23
- end
24
-
25
- it 'adds documentation about the default value' do
26
- expect(documentation).to have_key('int')
27
- expect(documentation['int']).to have_key(:default)
28
- expect(documentation['int'][:default]).to eq(42)
29
- end
30
- end
31
-
32
- context 'when the default value is false' do
33
- before do
34
- subject.params do
35
- optional :bool, type: Grape::API::Boolean, default: false
36
- end
37
- subject.get
38
- end
39
-
40
- it 'adds documentation about the default value' do
41
- expect(documentation).to have_key('bool')
42
- expect(documentation['bool']).to have_key(:default)
43
- expect(documentation['bool'][:default]).to eq(false)
44
- end
45
- end
46
-
47
- context 'when the default value is nil' do
48
- before do
49
- subject.params do
50
- optional :object, type: Object, default: nil
51
- end
52
- subject.get
53
- end
54
-
55
- it 'adds documentation about the default value' do
56
- expect(documentation).to have_key('object')
57
- expect(documentation['object']).to have_key(:default)
58
- expect(documentation['object'][:default]).to eq(nil)
59
- end
60
- end
61
- end
62
-
63
- context 'without a default' do
64
- before do
65
- subject.params do
66
- optional :object, type: Object
67
- end
68
- subject.get
69
- end
70
-
71
- it 'does not add documentation for the default value' do
72
- documentation = subject.routes.first.params
73
- expect(documentation).to have_key('object')
74
- expect(documentation['object']).not_to have_key(:default)
75
- end
76
- end
77
-
78
- context 'setting description' do
79
- %i[desc description].each do |description_type|
80
- it "allows setting #{description_type}" do
81
- subject.params do
82
- requires :int, type: Integer, description_type => 'My very nice integer'
83
- end
84
- subject.get '/single' do
85
- 'int works'
86
- end
87
- get '/single', int: 420
88
- expect(last_response.status).to eq(200)
89
- expect(last_response.body).to eq('int works')
90
- end
91
- end
92
- end
93
-
94
12
  context 'when using custom types' do
95
13
  module ParamsScopeSpec
96
14
  class CustomType
@@ -338,7 +256,7 @@ describe Grape::Validations::ParamsScope do
338
256
  requires :b
339
257
  end
340
258
  end
341
- end.to raise_error Grape::Exceptions::MissingGroupTypeError
259
+ end.to raise_error Grape::Exceptions::MissingGroupType
342
260
 
343
261
  expect do
344
262
  subject.params do
@@ -346,7 +264,7 @@ describe Grape::Validations::ParamsScope do
346
264
  requires :b
347
265
  end
348
266
  end
349
- end.to raise_error Grape::Exceptions::MissingGroupTypeError
267
+ end.to raise_error Grape::Exceptions::MissingGroupType
350
268
  end
351
269
 
352
270
  it 'allows Hash as type' do
@@ -406,7 +324,7 @@ describe Grape::Validations::ParamsScope do
406
324
  requires :b
407
325
  end
408
326
  end
409
- end.to raise_error Grape::Exceptions::UnsupportedGroupTypeError
327
+ end.to raise_error Grape::Exceptions::UnsupportedGroupType
410
328
 
411
329
  expect do
412
330
  subject.params do
@@ -414,7 +332,7 @@ describe Grape::Validations::ParamsScope do
414
332
  requires :b
415
333
  end
416
334
  end
417
- end.to raise_error Grape::Exceptions::UnsupportedGroupTypeError
335
+ end.to raise_error Grape::Exceptions::UnsupportedGroupType
418
336
  end
419
337
  end
420
338
 
@@ -746,6 +664,317 @@ describe Grape::Validations::ParamsScope do
746
664
  get '/nested', bar: { a: true, c: { b: 'yes' } }
747
665
  expect(JSON.parse(last_response.body)).to eq('bar' => { 'a' => 'true', 'c' => { 'b' => 'yes' } })
748
666
  end
667
+
668
+ context 'when the dependent parameter is not present #declared(params)' do
669
+ context 'lateral parameter' do
670
+ before do
671
+ [true, false].each do |evaluate_given|
672
+ subject.params do
673
+ optional :a
674
+ given :a do
675
+ optional :b
676
+ end
677
+ end
678
+ subject.get("/evaluate_given_#{evaluate_given}") { declared(params, evaluate_given: evaluate_given).to_json }
679
+ end
680
+ end
681
+
682
+ it 'evaluate_given_false' do
683
+ get '/evaluate_given_false', b: 'b'
684
+ expect(JSON.parse(last_response.body)).to eq('a' => nil, 'b' => 'b')
685
+ end
686
+
687
+ it 'evaluate_given_true' do
688
+ get '/evaluate_given_true', b: 'b'
689
+ expect(JSON.parse(last_response.body)).to eq('a' => nil)
690
+ end
691
+ end
692
+
693
+ context 'lateral hash parameter' do
694
+ before do
695
+ [true, false].each do |evaluate_given|
696
+ subject.params do
697
+ optional :a, values: %w[x y]
698
+ given a: ->(a) { a == 'x' } do
699
+ optional :b, type: Hash do
700
+ optional :c
701
+ end
702
+ optional :e
703
+ end
704
+ given a: ->(a) { a == 'y' } do
705
+ optional :b, type: Hash do
706
+ optional :d
707
+ end
708
+ optional :f
709
+ end
710
+ end
711
+ subject.get("/evaluate_given_#{evaluate_given}") { declared(params, evaluate_given: evaluate_given).to_json }
712
+ end
713
+ end
714
+
715
+ it 'evaluate_given_false' do
716
+ get '/evaluate_given_false', a: 'x'
717
+ expect(JSON.parse(last_response.body)).to eq('a' => 'x', 'b' => { 'd' => nil }, 'e' => nil, 'f' => nil)
718
+
719
+ get '/evaluate_given_false', a: 'y'
720
+ expect(JSON.parse(last_response.body)).to eq('a' => 'y', 'b' => { 'd' => nil }, 'e' => nil, 'f' => nil)
721
+ end
722
+
723
+ it 'evaluate_given_true' do
724
+ get '/evaluate_given_true', a: 'x'
725
+ expect(JSON.parse(last_response.body)).to eq('a' => 'x', 'b' => { 'c' => nil }, 'e' => nil)
726
+
727
+ get '/evaluate_given_true', a: 'y'
728
+ expect(JSON.parse(last_response.body)).to eq('a' => 'y', 'b' => { 'd' => nil }, 'f' => nil)
729
+ end
730
+ end
731
+
732
+ context 'lateral parameter within lateral hash parameter' do
733
+ before do
734
+ [true, false].each do |evaluate_given|
735
+ subject.params do
736
+ optional :a, values: %w[x y]
737
+ given a: ->(a) { a == 'x' } do
738
+ optional :b, type: Hash do
739
+ optional :c
740
+ given :c do
741
+ optional :g
742
+ optional :e, type: Hash do
743
+ optional :h
744
+ end
745
+ end
746
+ end
747
+ end
748
+ given a: ->(a) { a == 'y' } do
749
+ optional :b, type: Hash do
750
+ optional :d
751
+ given :d do
752
+ optional :f
753
+ optional :e, type: Hash do
754
+ optional :i
755
+ end
756
+ end
757
+ end
758
+ end
759
+ end
760
+ subject.get("/evaluate_given_#{evaluate_given}") { declared(params, evaluate_given: evaluate_given).to_json }
761
+ end
762
+ end
763
+
764
+ it 'evaluate_given_false' do
765
+ get '/evaluate_given_false', a: 'x'
766
+ expect(JSON.parse(last_response.body)).to eq('a' => 'x', 'b' => { 'd' => nil, 'f' => nil, 'e' => { 'i' => nil } })
767
+
768
+ get '/evaluate_given_false', a: 'x', b: { c: 'c' }
769
+ expect(JSON.parse(last_response.body)).to eq('a' => 'x', 'b' => { 'd' => nil, 'f' => nil, 'e' => { 'i' => nil } })
770
+
771
+ get '/evaluate_given_false', a: 'y'
772
+ expect(JSON.parse(last_response.body)).to eq('a' => 'y', 'b' => { 'd' => nil, 'f' => nil, 'e' => { 'i' => nil } })
773
+
774
+ get '/evaluate_given_false', a: 'y', b: { d: 'd' }
775
+ expect(JSON.parse(last_response.body)).to eq('a' => 'y', 'b' => { 'd' => 'd', 'f' => nil, 'e' => { 'i' => nil } })
776
+ end
777
+
778
+ it 'evaluate_given_true' do
779
+ get '/evaluate_given_true', a: 'x'
780
+ expect(JSON.parse(last_response.body)).to eq('a' => 'x', 'b' => { 'c' => nil })
781
+
782
+ get '/evaluate_given_true', a: 'x', b: { c: 'c' }
783
+ expect(JSON.parse(last_response.body)).to eq('a' => 'x', 'b' => { 'c' => 'c', 'g' => nil, 'e' => { 'h' => nil } })
784
+
785
+ get '/evaluate_given_true', a: 'y'
786
+ expect(JSON.parse(last_response.body)).to eq('a' => 'y', 'b' => { 'd' => nil })
787
+
788
+ get '/evaluate_given_true', a: 'y', b: { d: 'd' }
789
+ expect(JSON.parse(last_response.body)).to eq('a' => 'y', 'b' => { 'd' => 'd', 'f' => nil, 'e' => { 'i' => nil } })
790
+ end
791
+ end
792
+
793
+ context 'lateral parameter within an array param' do
794
+ before do
795
+ [true, false].each do |evaluate_given|
796
+ subject.params do
797
+ optional :array, type: Array do
798
+ optional :a
799
+ given :a do
800
+ optional :b
801
+ end
802
+ end
803
+ end
804
+ subject.post("/evaluate_given_#{evaluate_given}") do
805
+ declared(params, evaluate_given: evaluate_given).to_json
806
+ end
807
+ end
808
+ end
809
+
810
+ it 'evaluate_given_false' do
811
+ post '/evaluate_given_false', { array: [{ b: 'b' }, { a: 'a', b: 'b' }] }.to_json, 'CONTENT_TYPE' => 'application/json'
812
+ expect(JSON.parse(last_response.body)).to eq('array' => [{ 'a' => nil, 'b' => 'b' }, { 'a' => 'a', 'b' => 'b' }])
813
+ end
814
+
815
+ it 'evaluate_given_true' do
816
+ post '/evaluate_given_true', { array: [{ b: 'b' }, { a: 'a', b: 'b' }] }.to_json, 'CONTENT_TYPE' => 'application/json'
817
+ expect(JSON.parse(last_response.body)).to eq('array' => [{ 'a' => nil }, { 'a' => 'a', 'b' => 'b' }])
818
+ end
819
+ end
820
+
821
+ context 'nested given parameter' do
822
+ before do
823
+ [true, false].each do |evaluate_given|
824
+ subject.params do
825
+ optional :a
826
+ optional :c
827
+ given :a do
828
+ given :c do
829
+ optional :b
830
+ end
831
+ end
832
+ end
833
+ subject.post("/evaluate_given_#{evaluate_given}") do
834
+ declared(params, evaluate_given: evaluate_given).to_json
835
+ end
836
+ end
837
+ end
838
+
839
+ it 'evaluate_given_false' do
840
+ post '/evaluate_given_false', { a: 'a', b: 'b' }.to_json, 'CONTENT_TYPE' => 'application/json'
841
+ expect(JSON.parse(last_response.body)).to eq('a' => 'a', 'b' => 'b', 'c' => nil)
842
+
843
+ post '/evaluate_given_false', { c: 'c', b: 'b' }.to_json, 'CONTENT_TYPE' => 'application/json'
844
+ expect(JSON.parse(last_response.body)).to eq('a' => nil, 'b' => 'b', 'c' => 'c')
845
+
846
+ post '/evaluate_given_false', { a: 'a', c: 'c', b: 'b' }.to_json, 'CONTENT_TYPE' => 'application/json'
847
+ expect(JSON.parse(last_response.body)).to eq('a' => 'a', 'b' => 'b', 'c' => 'c')
848
+ end
849
+
850
+ it 'evaluate_given_true' do
851
+ post '/evaluate_given_true', { a: 'a', b: 'b' }.to_json, 'CONTENT_TYPE' => 'application/json'
852
+ expect(JSON.parse(last_response.body)).to eq('a' => 'a', 'c' => nil)
853
+
854
+ post '/evaluate_given_true', { c: 'c', b: 'b' }.to_json, 'CONTENT_TYPE' => 'application/json'
855
+ expect(JSON.parse(last_response.body)).to eq('a' => nil, 'c' => 'c')
856
+
857
+ post '/evaluate_given_true', { a: 'a', c: 'c', b: 'b' }.to_json, 'CONTENT_TYPE' => 'application/json'
858
+ expect(JSON.parse(last_response.body)).to eq('a' => 'a', 'b' => 'b', 'c' => 'c')
859
+ end
860
+ end
861
+
862
+ context 'nested given parameter within an array param' do
863
+ before do
864
+ [true, false].each do |evaluate_given|
865
+ subject.params do
866
+ optional :array, type: Array do
867
+ optional :a
868
+ optional :c
869
+ given :a do
870
+ given :c do
871
+ optional :b
872
+ end
873
+ end
874
+ end
875
+ end
876
+ subject.post("/evaluate_given_#{evaluate_given}") do
877
+ declared(params, evaluate_given: evaluate_given).to_json
878
+ end
879
+ end
880
+ end
881
+
882
+ let :evaluate_given_params do
883
+ {
884
+ array: [
885
+ { a: 'a', b: 'b' },
886
+ { c: 'c', b: 'b' },
887
+ { a: 'a', c: 'c', b: 'b' }
888
+ ]
889
+ }
890
+ end
891
+
892
+ it 'evaluate_given_false' do
893
+ post '/evaluate_given_false', evaluate_given_params.to_json, 'CONTENT_TYPE' => 'application/json'
894
+ expect(JSON.parse(last_response.body)).to eq('array' => [{ 'a' => 'a', 'b' => 'b', 'c' => nil }, { 'a' => nil, 'b' => 'b', 'c' => 'c' }, { 'a' => 'a', 'b' => 'b', 'c' => 'c' }])
895
+ end
896
+
897
+ it 'evaluate_given_true' do
898
+ post '/evaluate_given_true', evaluate_given_params.to_json, 'CONTENT_TYPE' => 'application/json'
899
+ expect(JSON.parse(last_response.body)).to eq('array' => [{ 'a' => 'a', 'c' => nil }, { 'a' => nil, 'c' => 'c' }, { 'a' => 'a', 'b' => 'b', 'c' => 'c' }])
900
+ end
901
+ end
902
+
903
+ context 'nested given parameter within a nested given parameter within an array param' do
904
+ before do
905
+ [true, false].each do |evaluate_given|
906
+ subject.params do
907
+ optional :array, type: Array do
908
+ optional :a
909
+ optional :c
910
+ given :a do
911
+ given :c do
912
+ optional :array, type: Array do
913
+ optional :a
914
+ optional :c
915
+ given :a do
916
+ given :c do
917
+ optional :b
918
+ end
919
+ end
920
+ end
921
+ end
922
+ end
923
+ end
924
+ end
925
+ subject.post("/evaluate_given_#{evaluate_given}") do
926
+ declared(params, evaluate_given: evaluate_given).to_json
927
+ end
928
+ end
929
+ end
930
+
931
+ let :evaluate_given_params do
932
+ {
933
+ array: [{
934
+ a: 'a',
935
+ c: 'c',
936
+ array: [
937
+ { a: 'a', b: 'b' },
938
+ { c: 'c', b: 'b' },
939
+ { a: 'a', c: 'c', b: 'b' }
940
+ ]
941
+ }]
942
+ }
943
+ end
944
+
945
+ it 'evaluate_given_false' do
946
+ expected_response_hash = {
947
+ 'array' => [{
948
+ 'a' => 'a',
949
+ 'c' => 'c',
950
+ 'array' => [
951
+ { 'a' => 'a', 'b' => 'b', 'c' => nil },
952
+ { 'a' => nil, 'c' => 'c', 'b' => 'b' },
953
+ { 'a' => 'a', 'c' => 'c', 'b' => 'b' }
954
+ ]
955
+ }]
956
+ }
957
+ post '/evaluate_given_false', evaluate_given_params.to_json, 'CONTENT_TYPE' => 'application/json'
958
+ expect(JSON.parse(last_response.body)).to eq(expected_response_hash)
959
+ end
960
+
961
+ it 'evaluate_given_true' do
962
+ expected_response_hash = {
963
+ 'array' => [{
964
+ 'a' => 'a',
965
+ 'c' => 'c',
966
+ 'array' => [
967
+ { 'a' => 'a', 'c' => nil },
968
+ { 'a' => nil, 'c' => 'c' },
969
+ { 'a' => 'a', 'b' => 'b', 'c' => 'c' }
970
+ ]
971
+ }]
972
+ }
973
+ post '/evaluate_given_true', evaluate_given_params.to_json, 'CONTENT_TYPE' => 'application/json'
974
+ expect(JSON.parse(last_response.body)).to eq(expected_response_hash)
975
+ end
976
+ end
977
+ end
749
978
  end
750
979
 
751
980
  context 'default value in given block' do
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Validations::SingleAttributeIterator do
6
4
  describe '#each' do
7
5
  subject(:iterator) { described_class.new(validator, scope, params) }
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Validations::Types::ArrayCoercer do
6
4
  subject { described_class.new(type) }
7
5
 
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Validations::Types::PrimitiveCoercer do
6
4
  subject { described_class.new(type, strict) }
7
5
 
@@ -25,13 +23,13 @@ describe Grape::Validations::Types::PrimitiveCoercer do
25
23
 
26
24
  [true, 'true', 1].each do |val|
27
25
  it "coerces '#{val}' to true" do
28
- expect(subject.call(val)).to eq(true)
26
+ expect(subject.call(val)).to be(true)
29
27
  end
30
28
  end
31
29
 
32
30
  [false, 'false', 0].each do |val|
33
31
  it "coerces '#{val}' to false" do
34
- expect(subject.call(val)).to eq(false)
32
+ expect(subject.call(val)).to be(false)
35
33
  end
36
34
  end
37
35
 
@@ -66,6 +64,10 @@ describe Grape::Validations::Types::PrimitiveCoercer do
66
64
  it 'coerces an empty string to nil' do
67
65
  expect(subject.call('')).to be_nil
68
66
  end
67
+
68
+ it 'accepts non-nil value' do
69
+ expect(subject.call(42)).to be_a(Integer)
70
+ end
69
71
  end
70
72
 
71
73
  context 'Numeric' do
@@ -74,6 +76,10 @@ describe Grape::Validations::Types::PrimitiveCoercer do
74
76
  it 'coerces an empty string to nil' do
75
77
  expect(subject.call('')).to be_nil
76
78
  end
79
+
80
+ it 'accepts a non-nil value' do
81
+ expect(subject.call(42)).to be_a(Numeric) # in fact Integer
82
+ end
77
83
  end
78
84
 
79
85
  context 'Time' do
@@ -104,6 +110,15 @@ describe Grape::Validations::Types::PrimitiveCoercer do
104
110
  end
105
111
  end
106
112
 
113
+ context 'a type unknown in Dry-types' do
114
+ let(:type) { Complex }
115
+
116
+ it 'raises error on init' do
117
+ expect(DryTypes::Params.constants).not_to include(type.name.to_sym)
118
+ expect { subject }.to raise_error(/type Complex should support coercion/)
119
+ end
120
+ end
121
+
107
122
  context 'the strict mode' do
108
123
  let(:strict) { true }
109
124
 
@@ -115,7 +130,7 @@ describe Grape::Validations::Types::PrimitiveCoercer do
115
130
  end
116
131
 
117
132
  it 'returns a value as it is when the given value is Boolean' do
118
- expect(subject.call(true)).to eq(true)
133
+ expect(subject.call(true)).to be(true)
119
134
  end
120
135
  end
121
136
 
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Validations::Types::SetCoercer do
6
4
  subject { described_class.new(type) }
7
5
 
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Validations::Types do
6
4
  module TypesSpec
7
5
  class FooType
@@ -50,6 +48,34 @@ describe Grape::Validations::Types do
50
48
  end
51
49
  end
52
50
 
51
+ describe 'special types' do
52
+ subject { described_class::SPECIAL[type] }
53
+
54
+ context 'when JSON' do
55
+ let(:type) { JSON }
56
+
57
+ it { is_expected.to eq(Grape::Validations::Types::Json) }
58
+ end
59
+
60
+ context 'when Array[JSON]' do
61
+ let(:type) { Array[JSON] }
62
+
63
+ it { is_expected.to eq(Grape::Validations::Types::JsonArray) }
64
+ end
65
+
66
+ context 'when File' do
67
+ let(:type) { File }
68
+
69
+ it { is_expected.to eq(Grape::Validations::Types::File) }
70
+ end
71
+
72
+ context 'when Rack::Multipart::UploadedFile' do
73
+ let(:type) { Rack::Multipart::UploadedFile }
74
+
75
+ it { is_expected.to eq(Grape::Validations::Types::File) }
76
+ end
77
+ end
78
+
53
79
  describe '::custom?' do
54
80
  it 'returns false if the type does not respond to :parse' do
55
81
  expect(described_class).not_to be_custom(Object)
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Validations::Validators::AllOrNoneOfValidator do
6
4
  let_it_be(:app) do
7
5
  Class.new(Grape::API) do
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Validations::Validators::AllowBlankValidator do
6
4
  let_it_be(:app) do
7
5
  Class.new(Grape::API) do
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Validations::Validators::AtLeastOneOfValidator do
6
4
  let_it_be(:app) do
7
5
  Class.new(Grape::API) do
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Validations::Validators::CoerceValidator do
6
4
  subject do
7
5
  Class.new(Grape::API)
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Validations::Validators::DefaultValidator do
6
4
  let_it_be(:app) do
7
5
  Class.new(Grape::API) do
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Validations::Validators::ExactlyOneOfValidator do
6
4
  let_it_be(:app) do
7
5
  Class.new(Grape::API) do
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Validations::Validators::ExceptValuesValidator do
6
4
  module ValidationsSpec
7
5
  class ExceptValuesModel
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Validations::Validators::MutualExclusionValidator do
6
4
  let_it_be(:app) do
7
5
  Class.new(Grape::API) do
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Validations::Validators::PresenceValidator do
6
4
  subject do
7
5
  Class.new(Grape::API) do
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Validations::Validators::RegexpValidator do
6
4
  let_it_be(:app) do
7
5
  Class.new(Grape::API) do
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Validations::Validators::SameAsValidator do
6
4
  let_it_be(:app) do
7
5
  Class.new(Grape::API) do