grape 1.5.2 → 1.6.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 (146) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +47 -0
  3. data/CONTRIBUTING.md +2 -1
  4. data/README.md +33 -3
  5. data/UPGRADING.md +71 -2
  6. data/grape.gemspec +5 -5
  7. data/lib/grape/api/instance.rb +13 -17
  8. data/lib/grape/api.rb +18 -13
  9. data/lib/grape/cookies.rb +2 -0
  10. data/lib/grape/dsl/desc.rb +3 -5
  11. data/lib/grape/dsl/headers.rb +5 -2
  12. data/lib/grape/dsl/helpers.rb +7 -5
  13. data/lib/grape/dsl/inside_route.rb +17 -8
  14. data/lib/grape/dsl/middleware.rb +4 -4
  15. data/lib/grape/dsl/parameters.rb +3 -3
  16. data/lib/grape/dsl/request_response.rb +9 -6
  17. data/lib/grape/dsl/routing.rb +2 -2
  18. data/lib/grape/dsl/settings.rb +5 -5
  19. data/lib/grape/endpoint.rb +21 -36
  20. data/lib/grape/error_formatter/json.rb +2 -6
  21. data/lib/grape/error_formatter/xml.rb +2 -6
  22. data/lib/grape/exceptions/empty_message_body.rb +11 -0
  23. data/lib/grape/exceptions/validation.rb +1 -2
  24. data/lib/grape/formatter/json.rb +1 -0
  25. data/lib/grape/formatter/serializable_hash.rb +2 -1
  26. data/lib/grape/formatter/xml.rb +1 -0
  27. data/lib/grape/locale/en.yml +1 -1
  28. data/lib/grape/middleware/auth/dsl.rb +7 -1
  29. data/lib/grape/middleware/base.rb +3 -1
  30. data/lib/grape/middleware/formatter.rb +4 -4
  31. data/lib/grape/middleware/stack.rb +2 -2
  32. data/lib/grape/middleware/versioner/accept_version_header.rb +3 -5
  33. data/lib/grape/middleware/versioner/header.rb +6 -4
  34. data/lib/grape/middleware/versioner/param.rb +1 -0
  35. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
  36. data/lib/grape/middleware/versioner/path.rb +2 -0
  37. data/lib/grape/parser/json.rb +1 -1
  38. data/lib/grape/parser/xml.rb +1 -1
  39. data/lib/grape/path.rb +1 -0
  40. data/lib/grape/request.rb +3 -0
  41. data/lib/grape/router/pattern.rb +1 -1
  42. data/lib/grape/router/route.rb +2 -2
  43. data/lib/grape/router.rb +6 -0
  44. data/lib/grape/util/inheritable_setting.rb +1 -3
  45. data/lib/grape/util/lazy_value.rb +3 -2
  46. data/lib/grape/util/strict_hash_configuration.rb +1 -1
  47. data/lib/grape/validations/params_scope.rb +88 -55
  48. data/lib/grape/validations/types/custom_type_coercer.rb +1 -2
  49. data/lib/grape/validations/types/dry_type_coercer.rb +1 -1
  50. data/lib/grape/validations/types/json.rb +2 -1
  51. data/lib/grape/validations/types/primitive_coercer.rb +3 -3
  52. data/lib/grape/validations/validators/all_or_none.rb +8 -5
  53. data/lib/grape/validations/validators/allow_blank.rb +9 -7
  54. data/lib/grape/validations/validators/as.rb +6 -8
  55. data/lib/grape/validations/validators/at_least_one_of.rb +7 -4
  56. data/lib/grape/validations/validators/base.rb +75 -70
  57. data/lib/grape/validations/validators/coerce.rb +63 -79
  58. data/lib/grape/validations/validators/default.rb +37 -34
  59. data/lib/grape/validations/validators/exactly_one_of.rb +9 -6
  60. data/lib/grape/validations/validators/except_values.rb +13 -11
  61. data/lib/grape/validations/validators/multiple_params_base.rb +24 -20
  62. data/lib/grape/validations/validators/mutual_exclusion.rb +8 -5
  63. data/lib/grape/validations/validators/presence.rb +7 -4
  64. data/lib/grape/validations/validators/regexp.rb +8 -5
  65. data/lib/grape/validations/validators/same_as.rb +18 -15
  66. data/lib/grape/validations/validators/values.rb +61 -56
  67. data/lib/grape/validations.rb +6 -0
  68. data/lib/grape/version.rb +1 -1
  69. data/lib/grape.rb +4 -1
  70. data/spec/grape/api/custom_validations_spec.rb +77 -45
  71. data/spec/grape/api/deeply_included_options_spec.rb +3 -3
  72. data/spec/grape/api/defines_boolean_in_params_spec.rb +2 -1
  73. data/spec/grape/api/invalid_format_spec.rb +2 -0
  74. data/spec/grape/api/recognize_path_spec.rb +1 -1
  75. data/spec/grape/api/routes_with_requirements_spec.rb +8 -8
  76. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +9 -15
  77. data/spec/grape/api_remount_spec.rb +16 -15
  78. data/spec/grape/api_spec.rb +510 -220
  79. data/spec/grape/dsl/callbacks_spec.rb +2 -1
  80. data/spec/grape/dsl/headers_spec.rb +39 -9
  81. data/spec/grape/dsl/helpers_spec.rb +3 -2
  82. data/spec/grape/dsl/inside_route_spec.rb +6 -4
  83. data/spec/grape/dsl/logger_spec.rb +16 -18
  84. data/spec/grape/dsl/middleware_spec.rb +2 -1
  85. data/spec/grape/dsl/parameters_spec.rb +2 -0
  86. data/spec/grape/dsl/request_response_spec.rb +1 -0
  87. data/spec/grape/dsl/routing_spec.rb +10 -7
  88. data/spec/grape/endpoint/declared_spec.rb +259 -12
  89. data/spec/grape/endpoint_spec.rb +77 -55
  90. data/spec/grape/entity_spec.rb +22 -22
  91. data/spec/grape/exceptions/body_parse_errors_spec.rb +3 -0
  92. data/spec/grape/exceptions/invalid_accept_header_spec.rb +61 -22
  93. data/spec/grape/exceptions/validation_errors_spec.rb +13 -10
  94. data/spec/grape/exceptions/validation_spec.rb +5 -3
  95. data/spec/grape/extensions/param_builders/hash_spec.rb +7 -7
  96. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +8 -8
  97. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +8 -8
  98. data/spec/grape/integration/rack_sendfile_spec.rb +1 -1
  99. data/spec/grape/loading_spec.rb +8 -8
  100. data/spec/grape/middleware/auth/dsl_spec.rb +15 -6
  101. data/spec/grape/middleware/auth/strategies_spec.rb +60 -20
  102. data/spec/grape/middleware/base_spec.rb +24 -15
  103. data/spec/grape/middleware/error_spec.rb +2 -2
  104. data/spec/grape/middleware/exception_spec.rb +111 -161
  105. data/spec/grape/middleware/formatter_spec.rb +27 -6
  106. data/spec/grape/middleware/globals_spec.rb +7 -4
  107. data/spec/grape/middleware/stack_spec.rb +14 -12
  108. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +2 -1
  109. data/spec/grape/middleware/versioner/header_spec.rb +14 -13
  110. data/spec/grape/middleware/versioner/param_spec.rb +7 -1
  111. data/spec/grape/middleware/versioner/path_spec.rb +5 -1
  112. data/spec/grape/middleware/versioner_spec.rb +1 -1
  113. data/spec/grape/parser_spec.rb +4 -0
  114. data/spec/grape/path_spec.rb +52 -52
  115. data/spec/grape/presenters/presenter_spec.rb +7 -6
  116. data/spec/grape/request_spec.rb +6 -4
  117. data/spec/grape/util/inheritable_setting_spec.rb +7 -7
  118. data/spec/grape/util/inheritable_values_spec.rb +3 -2
  119. data/spec/grape/util/reverse_stackable_values_spec.rb +3 -1
  120. data/spec/grape/util/stackable_values_spec.rb +7 -5
  121. data/spec/grape/validations/instance_behaivour_spec.rb +9 -10
  122. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +1 -0
  123. data/spec/grape/validations/params_scope_spec.rb +46 -10
  124. data/spec/grape/validations/single_attribute_iterator_spec.rb +2 -1
  125. data/spec/grape/validations/types/primitive_coercer_spec.rb +4 -4
  126. data/spec/grape/validations/types_spec.rb +8 -8
  127. data/spec/grape/validations/validators/all_or_none_spec.rb +50 -56
  128. data/spec/grape/validations/validators/allow_blank_spec.rb +136 -140
  129. data/spec/grape/validations/validators/at_least_one_of_spec.rb +50 -56
  130. data/spec/grape/validations/validators/coerce_spec.rb +99 -22
  131. data/spec/grape/validations/validators/default_spec.rb +72 -78
  132. data/spec/grape/validations/validators/exactly_one_of_spec.rb +71 -77
  133. data/spec/grape/validations/validators/except_values_spec.rb +3 -3
  134. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +71 -77
  135. data/spec/grape/validations/validators/presence_spec.rb +16 -1
  136. data/spec/grape/validations/validators/regexp_spec.rb +25 -31
  137. data/spec/grape/validations/validators/same_as_spec.rb +14 -20
  138. data/spec/grape/validations/validators/values_spec.rb +183 -178
  139. data/spec/grape/validations_spec.rb +99 -58
  140. data/spec/integration/eager_load/eager_load_spec.rb +2 -2
  141. data/spec/integration/multi_json/json_spec.rb +1 -1
  142. data/spec/integration/multi_xml/xml_spec.rb +1 -1
  143. data/spec/shared/versioning_examples.rb +12 -9
  144. data/spec/spec_helper.rb +12 -2
  145. data/spec/support/basic_auth_encode_helpers.rb +1 -1
  146. metadata +102 -101
@@ -2,73 +2,67 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Grape::Validations::AtLeastOneOfValidator do
6
- describe '#validate!' do
7
- subject(:validate) { post path, params }
8
-
9
- module ValidationsSpec
10
- module AtLeastOneOfValidatorSpec
11
- class API < Grape::API
12
- rescue_from Grape::Exceptions::ValidationErrors do |e|
13
- error!(e.errors.transform_keys! { |key| key.join(',') }, 400)
14
- end
5
+ describe Grape::Validations::Validators::AtLeastOneOfValidator do
6
+ let_it_be(:app) do
7
+ Class.new(Grape::API) do
8
+ rescue_from Grape::Exceptions::ValidationErrors do |e|
9
+ error!(e.errors.transform_keys! { |key| key.join(',') }, 400)
10
+ end
15
11
 
16
- params do
17
- optional :beer, :wine, :grapefruit
18
- at_least_one_of :beer, :wine, :grapefruit
19
- end
20
- post do
21
- end
12
+ params do
13
+ optional :beer, :wine, :grapefruit
14
+ at_least_one_of :beer, :wine, :grapefruit
15
+ end
16
+ post do
17
+ end
22
18
 
23
- params do
24
- optional :beer, :wine, :grapefruit, :other
25
- at_least_one_of :beer, :wine, :grapefruit
26
- end
27
- post 'mixed-params' do
28
- end
19
+ params do
20
+ optional :beer, :wine, :grapefruit, :other
21
+ at_least_one_of :beer, :wine, :grapefruit
22
+ end
23
+ post 'mixed-params' do
24
+ end
29
25
 
30
- params do
31
- optional :beer, :wine, :grapefruit
32
- at_least_one_of :beer, :wine, :grapefruit, message: 'you should choose something'
33
- end
34
- post '/custom-message' do
35
- end
26
+ params do
27
+ optional :beer, :wine, :grapefruit
28
+ at_least_one_of :beer, :wine, :grapefruit, message: 'you should choose something'
29
+ end
30
+ post '/custom-message' do
31
+ end
36
32
 
37
- params do
38
- requires :item, type: Hash do
39
- optional :beer, :wine, :grapefruit
40
- at_least_one_of :beer, :wine, :grapefruit, message: 'fail'
41
- end
42
- end
43
- post '/nested-hash' do
44
- end
33
+ params do
34
+ requires :item, type: Hash do
35
+ optional :beer, :wine, :grapefruit
36
+ at_least_one_of :beer, :wine, :grapefruit, message: 'fail'
37
+ end
38
+ end
39
+ post '/nested-hash' do
40
+ end
45
41
 
46
- params do
47
- requires :items, type: Array do
48
- optional :beer, :wine, :grapefruit
49
- at_least_one_of :beer, :wine, :grapefruit, message: 'fail'
50
- end
51
- end
52
- post '/nested-array' do
53
- end
42
+ params do
43
+ requires :items, type: Array do
44
+ optional :beer, :wine, :grapefruit
45
+ at_least_one_of :beer, :wine, :grapefruit, message: 'fail'
46
+ end
47
+ end
48
+ post '/nested-array' do
49
+ end
54
50
 
55
- params do
56
- requires :items, type: Array do
57
- requires :nested_items, type: Array do
58
- optional :beer, :wine, :grapefruit
59
- at_least_one_of :beer, :wine, :grapefruit, message: 'fail'
60
- end
61
- end
62
- end
63
- post '/deeply-nested-array' do
51
+ params do
52
+ requires :items, type: Array do
53
+ requires :nested_items, type: Array do
54
+ optional :beer, :wine, :grapefruit
55
+ at_least_one_of :beer, :wine, :grapefruit, message: 'fail'
64
56
  end
65
57
  end
66
58
  end
59
+ post '/deeply-nested-array' do
60
+ end
67
61
  end
62
+ end
68
63
 
69
- def app
70
- ValidationsSpec::AtLeastOneOfValidatorSpec::API
71
- end
64
+ describe '#validate!' do
65
+ subject(:validate) { post path, params }
72
66
 
73
67
  context 'when all restricted params are present' do
74
68
  let(:path) { '/' }
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Grape::Validations::CoerceValidator do
5
+ describe Grape::Validations::Validators::CoerceValidator do
6
6
  subject do
7
7
  Class.new(Grape::API)
8
8
  end
@@ -23,7 +23,7 @@ describe Grape::Validations::CoerceValidator do
23
23
  end
24
24
 
25
25
  context 'i18n' do
26
- after :each do
26
+ after do
27
27
  I18n.available_locales = %i[en]
28
28
  I18n.locale = :en
29
29
  I18n.default_locale = :en
@@ -31,9 +31,9 @@ describe Grape::Validations::CoerceValidator do
31
31
 
32
32
  it 'i18n error on malformed input' do
33
33
  I18n.available_locales = %i[en zh-CN]
34
- I18n.load_path << File.expand_path('../zh-CN.yml', __FILE__)
34
+ I18n.load_path << File.expand_path('zh-CN.yml', __dir__)
35
35
  I18n.reload!
36
- I18n.locale = 'zh-CN'.to_sym
36
+ I18n.locale = :'zh-CN'
37
37
  subject.params do
38
38
  requires :age, type: Integer
39
39
  end
@@ -48,7 +48,7 @@ describe Grape::Validations::CoerceValidator do
48
48
 
49
49
  it 'gives an english fallback error when default locale message is blank' do
50
50
  I18n.available_locales = %i[en pt-BR]
51
- I18n.locale = 'pt-BR'.to_sym
51
+ I18n.locale = :'pt-BR'
52
52
  subject.params do
53
53
  requires :age, type: Integer
54
54
  end
@@ -83,10 +83,11 @@ describe Grape::Validations::CoerceValidator do
83
83
  context 'on custom coercion rules' do
84
84
  before do
85
85
  subject.params do
86
- requires :a, types: { value: [Boolean, String], message: 'type cast is invalid' }, coerce_with: (lambda do |val|
87
- if val == 'yup'
86
+ requires :a, types: { value: [Grape::API::Boolean, String], message: 'type cast is invalid' }, coerce_with: (lambda do |val|
87
+ case val
88
+ when 'yup'
88
89
  true
89
- elsif val == 'false'
90
+ when 'false'
90
91
  0
91
92
  else
92
93
  val
@@ -170,9 +171,9 @@ describe Grape::Validations::CoerceValidator do
170
171
  expect(last_response.body).to eq('BigDecimal 45.1')
171
172
  end
172
173
 
173
- it 'Boolean' do
174
+ it 'Grape::API::Boolean' do
174
175
  subject.params do
175
- requires :boolean, type: Boolean
176
+ requires :boolean, type: Grape::API::Boolean
176
177
  end
177
178
  subject.post '/boolean' do
178
179
  params[:boolean]
@@ -369,9 +370,9 @@ describe Grape::Validations::CoerceValidator do
369
370
  end
370
371
  end
371
372
 
372
- it 'Boolean' do
373
+ it 'Grape::API::Boolean' do
373
374
  subject.params do
374
- requires :boolean, type: Boolean
375
+ requires :boolean, type: Grape::API::Boolean
375
376
  end
376
377
  subject.get '/boolean' do
377
378
  params[:boolean].class
@@ -650,7 +651,7 @@ describe Grape::Validations::CoerceValidator do
650
651
 
651
652
  it 'parses parameters with Array[Array[String]] type and coerce_with' do
652
653
  subject.params do
653
- requires :values, type: Array[Array[String]], coerce_with: ->(val) { val.is_a?(String) ? [val.split(/,/).map(&:strip)] : val }
654
+ requires :values, type: Array[Array[String]], coerce_with: ->(val) { val.is_a?(String) ? [val.split(',').map(&:strip)] : val }
654
655
  end
655
656
  subject.post '/coerce_nested_strings' do
656
657
  params[:values]
@@ -706,6 +707,44 @@ describe Grape::Validations::CoerceValidator do
706
707
  expect(JSON.parse(last_response.body)).to eq([1, 1, 1, 1])
707
708
  end
708
709
 
710
+ context 'Array type and coerce_with should' do
711
+ before do
712
+ subject.params do
713
+ optional :arr, type: Array, coerce_with: (lambda do |val|
714
+ if val.nil?
715
+ []
716
+ else
717
+ val
718
+ end
719
+ end)
720
+ end
721
+ subject.get '/' do
722
+ params[:arr].class.to_s
723
+ end
724
+ end
725
+
726
+ it 'coerce nil value to array' do
727
+ get '/', arr: nil
728
+
729
+ expect(last_response.status).to eq(200)
730
+ expect(last_response.body).to eq('Array')
731
+ end
732
+
733
+ it 'not coerce missing field' do
734
+ get '/'
735
+
736
+ expect(last_response.status).to eq(200)
737
+ expect(last_response.body).to eq('NilClass')
738
+ end
739
+
740
+ it 'coerce array as array' do
741
+ get '/', arr: []
742
+
743
+ expect(last_response.status).to eq(200)
744
+ expect(last_response.body).to eq('Array')
745
+ end
746
+ end
747
+
709
748
  it 'uses parse where available' do
710
749
  subject.params do
711
750
  requires :ints, type: Array, coerce_with: JSON do
@@ -754,13 +793,52 @@ describe Grape::Validations::CoerceValidator do
754
793
  expect(last_response.body).to eq('3')
755
794
  end
756
795
 
796
+ context 'Integer type and coerce_with should' do
797
+ before do
798
+ subject.params do
799
+ optional :int, type: Integer, coerce_with: (lambda do |val|
800
+ if val.nil?
801
+ 0
802
+ else
803
+ val.to_i
804
+ end
805
+ end)
806
+ end
807
+ subject.get '/' do
808
+ params[:int].class.to_s
809
+ end
810
+ end
811
+
812
+ it 'coerce nil value to integer' do
813
+ get '/', int: nil
814
+
815
+ expect(last_response.status).to eq(200)
816
+ expect(last_response.body).to eq('Integer')
817
+ end
818
+
819
+ it 'not coerce missing field' do
820
+ get '/'
821
+
822
+ expect(last_response.status).to eq(200)
823
+ expect(last_response.body).to eq('NilClass')
824
+ end
825
+
826
+ it 'coerce integer as integer' do
827
+ get '/', int: 1
828
+
829
+ expect(last_response.status).to eq(200)
830
+ expect(last_response.body).to eq('Integer')
831
+ end
832
+ end
833
+
757
834
  context 'Integer type and coerce_with potentially returning nil' do
758
835
  before do
759
836
  subject.params do
760
837
  requires :int, type: Integer, coerce_with: (lambda do |val|
761
- if val == '0'
838
+ case val
839
+ when '0'
762
840
  nil
763
- elsif val.match?(/^-?\d+$/)
841
+ when /^-?\d+$/
764
842
  val.to_i
765
843
  else
766
844
  val
@@ -940,11 +1018,9 @@ describe Grape::Validations::CoerceValidator do
940
1018
  end
941
1019
 
942
1020
  context 'multiple types' do
943
- Boolean = Grape::API::Boolean
944
-
945
1021
  it 'coerces to first possible type' do
946
1022
  subject.params do
947
- requires :a, types: [Boolean, Integer, String]
1023
+ requires :a, types: [Grape::API::Boolean, Integer, String]
948
1024
  end
949
1025
  subject.get '/' do
950
1026
  params[:a].class.to_s
@@ -965,7 +1041,7 @@ describe Grape::Validations::CoerceValidator do
965
1041
 
966
1042
  it 'fails when no coercion is possible' do
967
1043
  subject.params do
968
- requires :a, types: [Boolean, Integer]
1044
+ requires :a, types: [Grape::API::Boolean, Integer]
969
1045
  end
970
1046
  subject.get '/' do
971
1047
  params[:a].class.to_s
@@ -1124,10 +1200,11 @@ describe Grape::Validations::CoerceValidator do
1124
1200
  context 'custom coercion rules' do
1125
1201
  before do
1126
1202
  subject.params do
1127
- requires :a, types: [Boolean, String], coerce_with: (lambda do |val|
1128
- if val == 'yup'
1203
+ requires :a, types: [Grape::API::Boolean, String], coerce_with: (lambda do |val|
1204
+ case val
1205
+ when 'yup'
1129
1206
  true
1130
- elsif val == 'false'
1207
+ when 'false'
1131
1208
  0
1132
1209
  else
1133
1210
  val
@@ -2,104 +2,98 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Grape::Validations::DefaultValidator do
6
- module ValidationsSpec
7
- module DefaultValidatorSpec
8
- class API < Grape::API
9
- default_format :json
10
-
11
- params do
12
- optional :id
13
- optional :type, default: 'default-type'
14
- end
15
- get '/' do
16
- { id: params[:id], type: params[:type] }
17
- end
5
+ describe Grape::Validations::Validators::DefaultValidator do
6
+ let_it_be(:app) do
7
+ Class.new(Grape::API) do
8
+ default_format :json
9
+
10
+ params do
11
+ optional :id
12
+ optional :type, default: 'default-type'
13
+ end
14
+ get '/' do
15
+ { id: params[:id], type: params[:type] }
16
+ end
18
17
 
19
- params do
20
- optional :type1, default: 'default-type1'
21
- optional :type2, default: 'default-type2'
22
- end
23
- get '/user' do
24
- { type1: params[:type1], type2: params[:type2] }
25
- end
18
+ params do
19
+ optional :type1, default: 'default-type1'
20
+ optional :type2, default: 'default-type2'
21
+ end
22
+ get '/user' do
23
+ { type1: params[:type1], type2: params[:type2] }
24
+ end
26
25
 
27
- params do
28
- requires :id
29
- optional :type1, default: 'default-type1'
30
- optional :type2, default: 'default-type2'
31
- end
26
+ params do
27
+ requires :id
28
+ optional :type1, default: 'default-type1'
29
+ optional :type2, default: 'default-type2'
30
+ end
32
31
 
33
- get '/message' do
34
- { id: params[:id], type1: params[:type1], type2: params[:type2] }
35
- end
32
+ get '/message' do
33
+ { id: params[:id], type1: params[:type1], type2: params[:type2] }
34
+ end
36
35
 
37
- params do
38
- optional :random, default: -> { Random.rand }
39
- optional :not_random, default: Random.rand
40
- end
41
- get '/numbers' do
42
- { random_number: params[:random], non_random_number: params[:non_random_number] }
43
- end
36
+ params do
37
+ optional :random, default: -> { Random.rand }
38
+ optional :not_random, default: Random.rand
39
+ end
40
+ get '/numbers' do
41
+ { random_number: params[:random], non_random_number: params[:non_random_number] }
42
+ end
44
43
 
45
- params do
46
- optional :array, type: Array do
47
- requires :name
48
- optional :with_default, default: 'default'
49
- end
50
- end
51
- get '/array' do
52
- { array: params[:array] }
44
+ params do
45
+ optional :array, type: Array do
46
+ requires :name
47
+ optional :with_default, default: 'default'
53
48
  end
49
+ end
50
+ get '/array' do
51
+ { array: params[:array] }
52
+ end
54
53
 
55
- params do
56
- requires :thing1
57
- optional :more_things, type: Array do
58
- requires :nested_thing
59
- requires :other_thing, default: 1
60
- end
61
- end
62
- get '/optional_array' do
63
- { thing1: params[:thing1] }
54
+ params do
55
+ requires :thing1
56
+ optional :more_things, type: Array do
57
+ requires :nested_thing
58
+ requires :other_thing, default: 1
64
59
  end
60
+ end
61
+ get '/optional_array' do
62
+ { thing1: params[:thing1] }
63
+ end
65
64
 
66
- params do
67
- requires :root, type: Hash do
68
- optional :some_things, type: Array do
69
- requires :foo
70
- optional :options, type: Array do
71
- requires :name, type: String
72
- requires :value, type: String
73
- end
65
+ params do
66
+ requires :root, type: Hash do
67
+ optional :some_things, type: Array do
68
+ requires :foo
69
+ optional :options, type: Array do
70
+ requires :name, type: String
71
+ requires :value, type: String
74
72
  end
75
73
  end
76
74
  end
77
- get '/nested_optional_array' do
78
- { root: params[:root] }
79
- end
75
+ end
76
+ get '/nested_optional_array' do
77
+ { root: params[:root] }
78
+ end
80
79
 
81
- params do
82
- requires :root, type: Hash do
83
- optional :some_things, type: Array do
84
- requires :foo
85
- optional :options, type: Array do
86
- optional :name, type: String
87
- optional :value, type: String
88
- end
80
+ params do
81
+ requires :root, type: Hash do
82
+ optional :some_things, type: Array do
83
+ requires :foo
84
+ optional :options, type: Array do
85
+ optional :name, type: String
86
+ optional :value, type: String
89
87
  end
90
88
  end
91
89
  end
92
- get '/another_nested_optional_array' do
93
- { root: params[:root] }
94
- end
90
+ end
91
+ get '/another_nested_optional_array' do
92
+ { root: params[:root] }
95
93
  end
96
94
  end
97
95
  end
98
96
 
99
- def app
100
- ValidationsSpec::DefaultValidatorSpec::API
101
- end
102
-
103
97
  it 'lets you leave required values nested inside an optional blank' do
104
98
  get '/optional_array', thing1: 'stuff'
105
99
  expect(last_response.status).to eq(200)