grape 1.5.2 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +75 -0
  3. data/CONTRIBUTING.md +2 -1
  4. data/README.md +152 -21
  5. data/UPGRADING.md +86 -2
  6. data/grape.gemspec +5 -5
  7. data/lib/grape/api/instance.rb +14 -18
  8. data/lib/grape/api.rb +18 -13
  9. data/lib/grape/cookies.rb +2 -0
  10. data/lib/grape/dry_types.rb +12 -0
  11. data/lib/grape/dsl/api.rb +0 -2
  12. data/lib/grape/dsl/callbacks.rb +0 -2
  13. data/lib/grape/dsl/configuration.rb +0 -2
  14. data/lib/grape/dsl/desc.rb +2 -19
  15. data/lib/grape/dsl/headers.rb +5 -2
  16. data/lib/grape/dsl/helpers.rb +7 -7
  17. data/lib/grape/dsl/inside_route.rb +43 -30
  18. data/lib/grape/dsl/middleware.rb +4 -6
  19. data/lib/grape/dsl/parameters.rb +8 -10
  20. data/lib/grape/dsl/request_response.rb +9 -8
  21. data/lib/grape/dsl/routing.rb +6 -4
  22. data/lib/grape/dsl/settings.rb +5 -7
  23. data/lib/grape/dsl/validations.rb +0 -15
  24. data/lib/grape/endpoint.rb +21 -36
  25. data/lib/grape/error_formatter/json.rb +9 -7
  26. data/lib/grape/error_formatter/xml.rb +2 -6
  27. data/lib/grape/exceptions/base.rb +2 -2
  28. data/lib/grape/exceptions/empty_message_body.rb +11 -0
  29. data/lib/grape/exceptions/missing_group_type.rb +8 -1
  30. data/lib/grape/exceptions/too_many_multipart_files.rb +11 -0
  31. data/lib/grape/exceptions/unsupported_group_type.rb +8 -1
  32. data/lib/grape/exceptions/validation.rb +1 -6
  33. data/lib/grape/formatter/json.rb +1 -0
  34. data/lib/grape/formatter/serializable_hash.rb +2 -1
  35. data/lib/grape/formatter/xml.rb +1 -0
  36. data/lib/grape/locale/en.yml +9 -8
  37. data/lib/grape/middleware/auth/dsl.rb +7 -2
  38. data/lib/grape/middleware/base.rb +3 -1
  39. data/lib/grape/middleware/error.rb +2 -2
  40. data/lib/grape/middleware/formatter.rb +4 -4
  41. data/lib/grape/middleware/stack.rb +2 -2
  42. data/lib/grape/middleware/versioner/accept_version_header.rb +3 -5
  43. data/lib/grape/middleware/versioner/header.rb +6 -4
  44. data/lib/grape/middleware/versioner/param.rb +1 -0
  45. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
  46. data/lib/grape/middleware/versioner/path.rb +2 -0
  47. data/lib/grape/parser/json.rb +1 -1
  48. data/lib/grape/parser/xml.rb +1 -1
  49. data/lib/grape/path.rb +1 -0
  50. data/lib/grape/request.rb +5 -0
  51. data/lib/grape/router/pattern.rb +1 -1
  52. data/lib/grape/router/route.rb +2 -2
  53. data/lib/grape/router.rb +6 -0
  54. data/lib/grape/util/inheritable_setting.rb +1 -3
  55. data/lib/grape/util/json.rb +2 -0
  56. data/lib/grape/util/lazy_value.rb +3 -2
  57. data/lib/grape/util/strict_hash_configuration.rb +1 -1
  58. data/lib/grape/validations/attributes_doc.rb +58 -0
  59. data/lib/grape/validations/params_scope.rb +137 -78
  60. data/lib/grape/validations/types/array_coercer.rb +0 -2
  61. data/lib/grape/validations/types/custom_type_coercer.rb +1 -2
  62. data/lib/grape/validations/types/dry_type_coercer.rb +4 -8
  63. data/lib/grape/validations/types/json.rb +2 -1
  64. data/lib/grape/validations/types/primitive_coercer.rb +16 -8
  65. data/lib/grape/validations/types/set_coercer.rb +0 -2
  66. data/lib/grape/validations/types.rb +98 -30
  67. data/lib/grape/validations/validators/all_or_none_of_validator.rb +16 -0
  68. data/lib/grape/validations/validators/allow_blank_validator.rb +20 -0
  69. data/lib/grape/validations/validators/as_validator.rb +14 -0
  70. data/lib/grape/validations/validators/at_least_one_of_validator.rb +15 -0
  71. data/lib/grape/validations/validators/base.rb +82 -70
  72. data/lib/grape/validations/validators/coerce_validator.rb +75 -0
  73. data/lib/grape/validations/validators/default_validator.rb +51 -0
  74. data/lib/grape/validations/validators/exactly_one_of_validator.rb +17 -0
  75. data/lib/grape/validations/validators/except_values_validator.rb +24 -0
  76. data/lib/grape/validations/validators/multiple_params_base.rb +24 -20
  77. data/lib/grape/validations/validators/mutual_exclusion_validator.rb +16 -0
  78. data/lib/grape/validations/validators/presence_validator.rb +15 -0
  79. data/lib/grape/validations/validators/regexp_validator.rb +16 -0
  80. data/lib/grape/validations/validators/same_as_validator.rb +29 -0
  81. data/lib/grape/validations/validators/values_validator.rb +88 -0
  82. data/lib/grape/validations.rb +16 -6
  83. data/lib/grape/version.rb +1 -1
  84. data/lib/grape.rb +70 -29
  85. data/spec/grape/api/custom_validations_spec.rb +116 -45
  86. data/spec/grape/api/deeply_included_options_spec.rb +3 -5
  87. data/spec/grape/api/defines_boolean_in_params_spec.rb +2 -3
  88. data/spec/grape/api/documentation_spec.rb +59 -0
  89. data/spec/grape/api/inherited_helpers_spec.rb +0 -2
  90. data/spec/grape/api/instance_spec.rb +0 -1
  91. data/spec/grape/api/invalid_format_spec.rb +2 -2
  92. data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -2
  93. data/spec/grape/api/nested_helpers_spec.rb +0 -2
  94. data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -2
  95. data/spec/grape/api/parameters_modification_spec.rb +0 -2
  96. data/spec/grape/api/patch_method_helpers_spec.rb +0 -2
  97. data/spec/grape/api/recognize_path_spec.rb +1 -3
  98. data/spec/grape/api/required_parameters_in_route_spec.rb +0 -2
  99. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -2
  100. data/spec/grape/api/routes_with_requirements_spec.rb +8 -10
  101. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +9 -17
  102. data/spec/grape/api/shared_helpers_spec.rb +0 -2
  103. data/spec/grape/api_remount_spec.rb +16 -16
  104. data/spec/grape/api_spec.rb +527 -224
  105. data/spec/grape/config_spec.rb +0 -2
  106. data/spec/grape/dsl/callbacks_spec.rb +2 -3
  107. data/spec/grape/dsl/configuration_spec.rb +0 -2
  108. data/spec/grape/dsl/desc_spec.rb +0 -2
  109. data/spec/grape/dsl/headers_spec.rb +39 -11
  110. data/spec/grape/dsl/helpers_spec.rb +3 -4
  111. data/spec/grape/dsl/inside_route_spec.rb +16 -16
  112. data/spec/grape/dsl/logger_spec.rb +15 -19
  113. data/spec/grape/dsl/middleware_spec.rb +2 -3
  114. data/spec/grape/dsl/parameters_spec.rb +2 -2
  115. data/spec/grape/dsl/request_response_spec.rb +7 -8
  116. data/spec/grape/dsl/routing_spec.rb +11 -10
  117. data/spec/grape/dsl/settings_spec.rb +0 -2
  118. data/spec/grape/dsl/validations_spec.rb +0 -17
  119. data/spec/grape/endpoint/declared_spec.rb +261 -16
  120. data/spec/grape/endpoint_spec.rb +98 -57
  121. data/spec/grape/entity_spec.rb +22 -23
  122. data/spec/grape/exceptions/base_spec.rb +16 -2
  123. data/spec/grape/exceptions/body_parse_errors_spec.rb +3 -2
  124. data/spec/grape/exceptions/invalid_accept_header_spec.rb +61 -24
  125. data/spec/grape/exceptions/invalid_formatter_spec.rb +0 -2
  126. data/spec/grape/exceptions/invalid_response_spec.rb +0 -2
  127. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +1 -3
  128. data/spec/grape/exceptions/missing_group_type_spec.rb +21 -0
  129. data/spec/grape/exceptions/missing_mime_type_spec.rb +0 -2
  130. data/spec/grape/exceptions/missing_option_spec.rb +1 -3
  131. data/spec/grape/exceptions/unknown_options_spec.rb +0 -2
  132. data/spec/grape/exceptions/unknown_validator_spec.rb +0 -2
  133. data/spec/grape/exceptions/unsupported_group_type_spec.rb +23 -0
  134. data/spec/grape/exceptions/validation_errors_spec.rb +13 -11
  135. data/spec/grape/exceptions/validation_spec.rb +5 -5
  136. data/spec/grape/extensions/param_builders/hash_spec.rb +7 -9
  137. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +8 -10
  138. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +8 -10
  139. data/spec/grape/integration/global_namespace_function_spec.rb +0 -2
  140. data/spec/grape/integration/rack_sendfile_spec.rb +1 -3
  141. data/spec/grape/integration/rack_spec.rb +0 -2
  142. data/spec/grape/loading_spec.rb +8 -10
  143. data/spec/grape/middleware/auth/base_spec.rb +0 -1
  144. data/spec/grape/middleware/auth/dsl_spec.rb +15 -8
  145. data/spec/grape/middleware/auth/strategies_spec.rb +60 -22
  146. data/spec/grape/middleware/base_spec.rb +24 -17
  147. data/spec/grape/middleware/error_spec.rb +8 -3
  148. data/spec/grape/middleware/exception_spec.rb +111 -163
  149. data/spec/grape/middleware/formatter_spec.rb +27 -8
  150. data/spec/grape/middleware/globals_spec.rb +7 -6
  151. data/spec/grape/middleware/stack_spec.rb +14 -14
  152. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +2 -3
  153. data/spec/grape/middleware/versioner/header_spec.rb +30 -15
  154. data/spec/grape/middleware/versioner/param_spec.rb +7 -3
  155. data/spec/grape/middleware/versioner/path_spec.rb +5 -3
  156. data/spec/grape/middleware/versioner_spec.rb +1 -3
  157. data/spec/grape/named_api_spec.rb +0 -2
  158. data/spec/grape/parser_spec.rb +4 -2
  159. data/spec/grape/path_spec.rb +52 -54
  160. data/spec/grape/presenters/presenter_spec.rb +7 -8
  161. data/spec/grape/request_spec.rb +6 -6
  162. data/spec/grape/util/inheritable_setting_spec.rb +7 -8
  163. data/spec/grape/util/inheritable_values_spec.rb +3 -3
  164. data/spec/grape/util/reverse_stackable_values_spec.rb +3 -2
  165. data/spec/grape/util/stackable_values_spec.rb +7 -6
  166. data/spec/grape/util/strict_hash_configuration_spec.rb +0 -1
  167. data/spec/grape/validations/attributes_doc_spec.rb +153 -0
  168. data/spec/grape/validations/attributes_iterator_spec.rb +0 -2
  169. data/spec/grape/validations/instance_behaivour_spec.rb +9 -12
  170. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +1 -2
  171. data/spec/grape/validations/params_scope_spec.rb +361 -96
  172. data/spec/grape/validations/single_attribute_iterator_spec.rb +2 -3
  173. data/spec/grape/validations/types/array_coercer_spec.rb +0 -2
  174. data/spec/grape/validations/types/primitive_coercer_spec.rb +24 -9
  175. data/spec/grape/validations/types/set_coercer_spec.rb +0 -2
  176. data/spec/grape/validations/types_spec.rb +36 -10
  177. data/spec/grape/validations/validators/all_or_none_spec.rb +50 -58
  178. data/spec/grape/validations/validators/allow_blank_spec.rb +135 -141
  179. data/spec/grape/validations/validators/at_least_one_of_spec.rb +50 -58
  180. data/spec/grape/validations/validators/coerce_spec.rb +99 -24
  181. data/spec/grape/validations/validators/default_spec.rb +72 -80
  182. data/spec/grape/validations/validators/exactly_one_of_spec.rb +71 -79
  183. data/spec/grape/validations/validators/except_values_spec.rb +3 -5
  184. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +71 -79
  185. data/spec/grape/validations/validators/presence_spec.rb +16 -3
  186. data/spec/grape/validations/validators/regexp_spec.rb +25 -33
  187. data/spec/grape/validations/validators/same_as_spec.rb +14 -22
  188. data/spec/grape/validations/validators/values_spec.rb +182 -179
  189. data/spec/grape/validations_spec.rb +149 -80
  190. data/spec/integration/eager_load/eager_load_spec.rb +2 -2
  191. data/spec/integration/multi_json/json_spec.rb +1 -3
  192. data/spec/integration/multi_xml/xml_spec.rb +1 -3
  193. data/spec/shared/versioning_examples.rb +12 -9
  194. data/spec/spec_helper.rb +21 -6
  195. data/spec/support/basic_auth_encode_helpers.rb +1 -1
  196. metadata +125 -115
  197. data/lib/grape/validations/validators/all_or_none.rb +0 -15
  198. data/lib/grape/validations/validators/allow_blank.rb +0 -18
  199. data/lib/grape/validations/validators/as.rb +0 -16
  200. data/lib/grape/validations/validators/at_least_one_of.rb +0 -14
  201. data/lib/grape/validations/validators/coerce.rb +0 -91
  202. data/lib/grape/validations/validators/default.rb +0 -48
  203. data/lib/grape/validations/validators/exactly_one_of.rb +0 -16
  204. data/lib/grape/validations/validators/except_values.rb +0 -22
  205. data/lib/grape/validations/validators/mutual_exclusion.rb +0 -15
  206. data/lib/grape/validations/validators/presence.rb +0 -12
  207. data/lib/grape/validations/validators/regexp.rb +0 -13
  208. data/lib/grape/validations/validators/same_as.rb +0 -26
  209. data/lib/grape/validations/validators/values.rb +0 -83
  210. data/spec/support/eager_load.rb +0 -19
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Middleware::Stack do
6
4
  module StackSpec
7
5
  class FooMiddleware; end
6
+
8
7
  class BarMiddleware; end
8
+
9
9
  class BlockMiddleware
10
10
  attr_reader :block
11
11
 
@@ -15,10 +15,10 @@ describe Grape::Middleware::Stack do
15
15
  end
16
16
  end
17
17
 
18
- let(:proc) { ->() {} }
19
- let(:others) { [[:use, StackSpec::BarMiddleware], [:insert_before, StackSpec::BarMiddleware, StackSpec::BlockMiddleware, proc]] }
18
+ subject { described_class.new }
20
19
 
21
- subject { Grape::Middleware::Stack.new }
20
+ let(:proc) { -> {} }
21
+ let(:others) { [[:use, StackSpec::BarMiddleware], [:insert_before, StackSpec::BarMiddleware, StackSpec::BlockMiddleware, proc]] }
22
22
 
23
23
  before do
24
24
  subject.use StackSpec::FooMiddleware
@@ -27,20 +27,20 @@ describe Grape::Middleware::Stack do
27
27
  describe '#use' do
28
28
  it 'pushes a middleware class onto the stack' do
29
29
  expect { subject.use StackSpec::BarMiddleware }
30
- .to change { subject.size }.by(1)
30
+ .to change(subject, :size).by(1)
31
31
  expect(subject.last).to eq(StackSpec::BarMiddleware)
32
32
  end
33
33
 
34
34
  it 'pushes a middleware class with arguments onto the stack' do
35
35
  expect { subject.use StackSpec::BarMiddleware, false, my_arg: 42 }
36
- .to change { subject.size }.by(1)
36
+ .to change(subject, :size).by(1)
37
37
  expect(subject.last).to eq(StackSpec::BarMiddleware)
38
38
  expect(subject.last.args).to eq([false, { my_arg: 42 }])
39
39
  end
40
40
 
41
41
  it 'pushes a middleware class with block arguments onto the stack' do
42
42
  expect { subject.use StackSpec::BlockMiddleware, &proc }
43
- .to change { subject.size }.by(1)
43
+ .to change(subject, :size).by(1)
44
44
  expect(subject.last).to eq(StackSpec::BlockMiddleware)
45
45
  expect(subject.last.args).to eq([])
46
46
  expect(subject.last.block).to eq(proc)
@@ -50,7 +50,7 @@ describe Grape::Middleware::Stack do
50
50
  describe '#insert' do
51
51
  it 'inserts a middleware class at the integer index' do
52
52
  expect { subject.insert 0, StackSpec::BarMiddleware }
53
- .to change { subject.size }.by(1)
53
+ .to change(subject, :size).by(1)
54
54
  expect(subject[0]).to eq(StackSpec::BarMiddleware)
55
55
  expect(subject[1]).to eq(StackSpec::FooMiddleware)
56
56
  end
@@ -59,7 +59,7 @@ describe Grape::Middleware::Stack do
59
59
  describe '#insert_before' do
60
60
  it 'inserts a middleware before another middleware class' do
61
61
  expect { subject.insert_before StackSpec::FooMiddleware, StackSpec::BarMiddleware }
62
- .to change { subject.size }.by(1)
62
+ .to change(subject, :size).by(1)
63
63
  expect(subject[0]).to eq(StackSpec::BarMiddleware)
64
64
  expect(subject[1]).to eq(StackSpec::FooMiddleware)
65
65
  end
@@ -68,7 +68,7 @@ describe Grape::Middleware::Stack do
68
68
  subject.use Class.new(StackSpec::BlockMiddleware)
69
69
 
70
70
  expect { subject.insert_before StackSpec::BlockMiddleware, StackSpec::BarMiddleware }
71
- .to change { subject.size }.by(1)
71
+ .to change(subject, :size).by(1)
72
72
 
73
73
  expect(subject[1]).to eq(StackSpec::BarMiddleware)
74
74
  expect(subject[2]).to eq(StackSpec::BlockMiddleware)
@@ -83,7 +83,7 @@ describe Grape::Middleware::Stack do
83
83
  describe '#insert_after' do
84
84
  it 'inserts a middleware after another middleware class' do
85
85
  expect { subject.insert_after StackSpec::FooMiddleware, StackSpec::BarMiddleware }
86
- .to change { subject.size }.by(1)
86
+ .to change(subject, :size).by(1)
87
87
  expect(subject[1]).to eq(StackSpec::BarMiddleware)
88
88
  expect(subject[0]).to eq(StackSpec::FooMiddleware)
89
89
  end
@@ -92,7 +92,7 @@ describe Grape::Middleware::Stack do
92
92
  subject.use Class.new(StackSpec::BlockMiddleware)
93
93
 
94
94
  expect { subject.insert_after StackSpec::BlockMiddleware, StackSpec::BarMiddleware }
95
- .to change { subject.size }.by(1)
95
+ .to change(subject, :size).by(1)
96
96
 
97
97
  expect(subject[1]).to eq(StackSpec::BlockMiddleware)
98
98
  expect(subject[2]).to eq(StackSpec::BarMiddleware)
@@ -107,7 +107,7 @@ describe Grape::Middleware::Stack do
107
107
  describe '#merge_with' do
108
108
  it 'applies a collection of operations and middlewares' do
109
109
  expect { subject.merge_with(others) }
110
- .to change { subject.size }.by(2)
110
+ .to change(subject, :size).by(2)
111
111
  expect(subject[0]).to eq(StackSpec::FooMiddleware)
112
112
  expect(subject[1]).to eq(StackSpec::BlockMiddleware)
113
113
  expect(subject[2]).to eq(StackSpec::BarMiddleware)
@@ -1,10 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Middleware::Versioner::AcceptVersionHeader do
4
+ subject { described_class.new(app, **(@options || {})) }
5
+
6
6
  let(:app) { ->(env) { [200, env, env] } }
7
- subject { Grape::Middleware::Versioner::AcceptVersionHeader.new(app, **(@options || {})) }
8
7
 
9
8
  before do
10
9
  @options = {
@@ -1,10 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Middleware::Versioner::Header do
4
+ subject { described_class.new(app, **(@options || {})) }
5
+
6
6
  let(:app) { ->(env) { [200, env, env] } }
7
- subject { Grape::Middleware::Versioner::Header.new(app, **(@options || {})) }
8
7
 
9
8
  before do
10
9
  @options = {
@@ -47,7 +46,7 @@ describe Grape::Middleware::Versioner::Header do
47
46
 
48
47
  it 'is nil if not provided' do
49
48
  status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor')
50
- expect(env['api.format']).to eql nil
49
+ expect(env['api.format']).to be_nil
51
50
  expect(status).to eq(200)
52
51
  end
53
52
 
@@ -65,7 +64,7 @@ describe Grape::Middleware::Versioner::Header do
65
64
 
66
65
  it 'is nil if not provided' do
67
66
  status, _, env = subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v1')
68
- expect(env['api.format']).to eql nil
67
+ expect(env['api.format']).to be_nil
69
68
  expect(status).to eq(200)
70
69
  end
71
70
  end
@@ -90,7 +89,7 @@ describe Grape::Middleware::Versioner::Header do
90
89
  .to raise_exception do |exception|
91
90
  expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
92
91
  expect(exception.headers).to eql('X-Cascade' => 'pass')
93
- expect(exception.status).to eql 406
92
+ expect(exception.status).to be 406
94
93
  expect(exception.message).to include 'API vendor not found'
95
94
  end
96
95
  end
@@ -117,7 +116,7 @@ describe Grape::Middleware::Versioner::Header do
117
116
  .to raise_exception do |exception|
118
117
  expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
119
118
  expect(exception.headers).to eql('X-Cascade' => 'pass')
120
- expect(exception.status).to eql 406
119
+ expect(exception.status).to be 406
121
120
  expect(exception.message).to include('API vendor not found')
122
121
  end
123
122
  end
@@ -145,7 +144,7 @@ describe Grape::Middleware::Versioner::Header do
145
144
  expect { subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v2+json').last }.to raise_exception do |exception|
146
145
  expect(exception).to be_a(Grape::Exceptions::InvalidVersionHeader)
147
146
  expect(exception.headers).to eql('X-Cascade' => 'pass')
148
- expect(exception.status).to eql 406
147
+ expect(exception.status).to be 406
149
148
  expect(exception.message).to include('API version not found')
150
149
  end
151
150
  end
@@ -178,7 +177,7 @@ describe Grape::Middleware::Versioner::Header do
178
177
  expect { subject.call({}).last }.to raise_exception do |exception|
179
178
  expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
180
179
  expect(exception.headers).to eql('X-Cascade' => 'pass')
181
- expect(exception.status).to eql 406
180
+ expect(exception.status).to be 406
182
181
  expect(exception.message).to include('Accept header must be set.')
183
182
  end
184
183
  end
@@ -187,7 +186,7 @@ describe Grape::Middleware::Versioner::Header do
187
186
  expect { subject.call('HTTP_ACCEPT' => '').last }.to raise_exception do |exception|
188
187
  expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
189
188
  expect(exception.headers).to eql('X-Cascade' => 'pass')
190
- expect(exception.status).to eql 406
189
+ expect(exception.status).to be 406
191
190
  expect(exception.message).to include('Accept header must be set.')
192
191
  end
193
192
  end
@@ -208,7 +207,7 @@ describe Grape::Middleware::Versioner::Header do
208
207
  expect { subject.call({}).last }.to raise_exception do |exception|
209
208
  expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
210
209
  expect(exception.headers).to eql({})
211
- expect(exception.status).to eql 406
210
+ expect(exception.status).to be 406
212
211
  expect(exception.message).to include('Accept header must be set.')
213
212
  end
214
213
  end
@@ -218,7 +217,7 @@ describe Grape::Middleware::Versioner::Header do
218
217
  .to raise_exception do |exception|
219
218
  expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
220
219
  expect(exception.headers).to eql({})
221
- expect(exception.status).to eql 406
220
+ expect(exception.status).to be 406
222
221
  expect(exception.message).to include('API vendor or version not found.')
223
222
  end
224
223
  end
@@ -227,7 +226,7 @@ describe Grape::Middleware::Versioner::Header do
227
226
  expect { subject.call('HTTP_ACCEPT' => '').last }.to raise_exception do |exception|
228
227
  expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
229
228
  expect(exception.headers).to eql({})
230
- expect(exception.status).to eql 406
229
+ expect(exception.status).to be 406
231
230
  expect(exception.message).to include('Accept header must be set.')
232
231
  end
233
232
  end
@@ -237,7 +236,7 @@ describe Grape::Middleware::Versioner::Header do
237
236
  .to raise_exception do |exception|
238
237
  expect(exception).to be_a(Grape::Exceptions::InvalidAcceptHeader)
239
238
  expect(exception.headers).to eql({})
240
- expect(exception.status).to eql 406
239
+ expect(exception.status).to be 406
241
240
  expect(exception.message).to include('API vendor or version not found.')
242
241
  end
243
242
  end
@@ -264,7 +263,7 @@ describe Grape::Middleware::Versioner::Header do
264
263
  expect { subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v3+json') }.to raise_exception do |exception|
265
264
  expect(exception).to be_a(Grape::Exceptions::InvalidVersionHeader)
266
265
  expect(exception.headers).to eql('X-Cascade' => 'pass')
267
- expect(exception.status).to eql 406
266
+ expect(exception.status).to be 406
268
267
  expect(exception.message).to include('API version not found')
269
268
  end
270
269
  end
@@ -327,4 +326,20 @@ describe Grape::Middleware::Versioner::Header do
327
326
  end
328
327
  end
329
328
  end
329
+
330
+ context 'with missing vendor option' do
331
+ subject do
332
+ Class.new(Grape::API) do
333
+ version 'v1', using: :header
334
+ end
335
+ end
336
+
337
+ def app
338
+ subject
339
+ end
340
+
341
+ it 'fails' do
342
+ expect { versioned_get '/', 'v1', using: :header }.to raise_error Grape::Exceptions::MissingVendorOption
343
+ end
344
+ end
330
345
  end
@@ -1,11 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Middleware::Versioner::Param do
4
+ subject { described_class.new(app, **options) }
5
+
6
6
  let(:app) { ->(env) { [200, env, env['api.version']] } }
7
7
  let(:options) { {} }
8
- subject { Grape::Middleware::Versioner::Param.new(app, **options) }
9
8
 
10
9
  it 'sets the API version based on the default param (apiver)' do
11
10
  env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v1' })
@@ -26,10 +25,12 @@ describe Grape::Middleware::Versioner::Param do
26
25
 
27
26
  context 'with specified parameter name' do
28
27
  let(:options) { { version_options: { parameter: 'v' } } }
28
+
29
29
  it 'sets the API version based on the custom parameter name' do
30
30
  env = Rack::MockRequest.env_for('/awesome', params: { 'v' => 'v1' })
31
31
  expect(subject.call(env)[1]['api.version']).to eq('v1')
32
32
  end
33
+
33
34
  it 'does not set the API version based on the default param' do
34
35
  env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v1' })
35
36
  expect(subject.call(env)[1]['api.version']).to be_nil
@@ -38,10 +39,12 @@ describe Grape::Middleware::Versioner::Param do
38
39
 
39
40
  context 'with specified versions' do
40
41
  let(:options) { { versions: %w[v1 v2] } }
42
+
41
43
  it 'throws an error if a non-allowed version is specified' do
42
44
  env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v3' })
43
45
  expect(catch(:error) { subject.call(env) }[:status]).to eq(404)
44
46
  end
47
+
45
48
  it 'allows versions that have been specified' do
46
49
  env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v1' })
47
50
  expect(subject.call(env)[1]['api.version']).to eq('v1')
@@ -55,6 +58,7 @@ describe Grape::Middleware::Versioner::Param do
55
58
  version_options: { using: :header }
56
59
  }
57
60
  end
61
+
58
62
  it 'returns a 200 (matches the first version found)' do
59
63
  env = Rack::MockRequest.env_for('/awesome', params: {})
60
64
  expect(subject.call(env).first).to eq(200)
@@ -1,11 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Middleware::Versioner::Path do
4
+ subject { described_class.new(app, **options) }
5
+
6
6
  let(:app) { ->(env) { [200, env, env['api.version']] } }
7
7
  let(:options) { {} }
8
- subject { Grape::Middleware::Versioner::Path.new(app, **options) }
9
8
 
10
9
  it 'sets the API version based on the first path' do
11
10
  expect(subject.call('PATH_INFO' => '/v1/awesome').last).to eq('v1')
@@ -21,6 +20,7 @@ describe Grape::Middleware::Versioner::Path do
21
20
 
22
21
  context 'with a pattern' do
23
22
  let(:options) { { pattern: /v./i } }
23
+
24
24
  it 'sets the version if it matches' do
25
25
  expect(subject.call('PATH_INFO' => '/v1/awesome').last).to eq('v1')
26
26
  end
@@ -46,6 +46,7 @@ describe Grape::Middleware::Versioner::Path do
46
46
 
47
47
  context 'with prefix, but requested version is not matched' do
48
48
  let(:options) { { prefix: '/v1', pattern: /v./i } }
49
+
49
50
  it 'recognizes potential version' do
50
51
  expect(subject.call('PATH_INFO' => '/v3/foo').last).to eq('v3')
51
52
  end
@@ -53,6 +54,7 @@ describe Grape::Middleware::Versioner::Path do
53
54
 
54
55
  context 'with mount path' do
55
56
  let(:options) { { mount_path: '/mounted', versions: [:v1] } }
57
+
56
58
  it 'recognizes potential version' do
57
59
  expect(subject.call('PATH_INFO' => '/mounted/v1/foo').last).to eq('v1')
58
60
  end
@@ -1,9 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Middleware::Versioner do
6
- let(:klass) { Grape::Middleware::Versioner }
4
+ let(:klass) { described_class }
7
5
 
8
6
  it 'recognizes :path' do
9
7
  expect(klass.using(:path)).to eq(Grape::Middleware::Versioner::Path)
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe 'A named API' do
6
4
  subject(:api_name) { NamedAPI.endpoints.last.options[:for].to_s }
7
5
 
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Parser do
6
4
  subject { described_class }
7
5
 
@@ -26,6 +24,7 @@ describe Grape::Parser do
26
24
 
27
25
  context 'with :parsers option' do
28
26
  let(:parsers) { { customized: Class.new } }
27
+
29
28
  it 'includes passed :parsers values' do
30
29
  expect(subject.parsers(parsers: parsers)).to include(parsers)
31
30
  end
@@ -33,7 +32,9 @@ describe Grape::Parser do
33
32
 
34
33
  context 'with added parser by using `register` keyword' do
35
34
  let(:added_parser) { Class.new }
35
+
36
36
  before { subject.register :added, added_parser }
37
+
37
38
  it 'includes added parser' do
38
39
  expect(subject.parsers(**{})).to include(added: added_parser)
39
40
  end
@@ -54,6 +55,7 @@ describe Grape::Parser do
54
55
 
55
56
  context 'when parser is available' do
56
57
  before { subject.register :customized_json, Grape::Parser::Json }
58
+
57
59
  it 'returns registered parser if available' do
58
60
  expect(subject.parser_for(:customized_json)).to eq(Grape::Parser::Json)
59
61
  end
@@ -1,68 +1,66 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  module Grape
6
4
  describe Path do
7
5
  describe '#initialize' do
8
6
  it 'remembers the path' do
9
- path = Path.new('/:id', anything, anything)
7
+ path = described_class.new('/:id', anything, anything)
10
8
  expect(path.raw_path).to eql('/:id')
11
9
  end
12
10
 
13
11
  it 'remembers the namespace' do
14
- path = Path.new(anything, '/users', anything)
12
+ path = described_class.new(anything, '/users', anything)
15
13
  expect(path.namespace).to eql('/users')
16
14
  end
17
15
 
18
16
  it 'remebers the settings' do
19
- path = Path.new(anything, anything, foo: 'bar')
17
+ path = described_class.new(anything, anything, foo: 'bar')
20
18
  expect(path.settings).to eql(foo: 'bar')
21
19
  end
22
20
  end
23
21
 
24
22
  describe '#mount_path' do
25
23
  it 'is nil when no mount path setting exists' do
26
- path = Path.new(anything, anything, {})
24
+ path = described_class.new(anything, anything, {})
27
25
  expect(path.mount_path).to be_nil
28
26
  end
29
27
 
30
28
  it 'is nil when the mount path is nil' do
31
- path = Path.new(anything, anything, mount_path: nil)
29
+ path = described_class.new(anything, anything, mount_path: nil)
32
30
  expect(path.mount_path).to be_nil
33
31
  end
34
32
 
35
33
  it 'splits the mount path' do
36
- path = Path.new(anything, anything, mount_path: %w[foo bar])
34
+ path = described_class.new(anything, anything, mount_path: %w[foo bar])
37
35
  expect(path.mount_path).to eql(%w[foo bar])
38
36
  end
39
37
  end
40
38
 
41
39
  describe '#root_prefix' do
42
40
  it 'is nil when no root prefix setting exists' do
43
- path = Path.new(anything, anything, {})
41
+ path = described_class.new(anything, anything, {})
44
42
  expect(path.root_prefix).to be_nil
45
43
  end
46
44
 
47
45
  it 'is nil when the mount path is nil' do
48
- path = Path.new(anything, anything, root_prefix: nil)
46
+ path = described_class.new(anything, anything, root_prefix: nil)
49
47
  expect(path.root_prefix).to be_nil
50
48
  end
51
49
 
52
50
  it 'splits the mount path' do
53
- path = Path.new(anything, anything, root_prefix: 'hello/world')
51
+ path = described_class.new(anything, anything, root_prefix: 'hello/world')
54
52
  expect(path.root_prefix).to eql(%w[hello world])
55
53
  end
56
54
  end
57
55
 
58
56
  describe '#uses_path_versioning?' do
59
57
  it 'is false when the version setting is nil' do
60
- path = Path.new(anything, anything, version: nil)
58
+ path = described_class.new(anything, anything, version: nil)
61
59
  expect(path.uses_path_versioning?).to be false
62
60
  end
63
61
 
64
62
  it 'is false when the version option is header' do
65
- path = Path.new(
63
+ path = described_class.new(
66
64
  anything,
67
65
  anything,
68
66
  version: 'v1',
@@ -73,7 +71,7 @@ module Grape
73
71
  end
74
72
 
75
73
  it 'is true when the version option is path' do
76
- path = Path.new(
74
+ path = described_class.new(
77
75
  anything,
78
76
  anything,
79
77
  version: 'v1',
@@ -86,44 +84,44 @@ module Grape
86
84
 
87
85
  describe '#namespace?' do
88
86
  it 'is false when the namespace is nil' do
89
- path = Path.new(anything, nil, anything)
90
- expect(path.namespace?).to be_falsey
87
+ path = described_class.new(anything, nil, anything)
88
+ expect(path).not_to be_namespace
91
89
  end
92
90
 
93
91
  it 'is false when the namespace starts with whitespace' do
94
- path = Path.new(anything, ' /foo', anything)
95
- expect(path.namespace?).to be_falsey
92
+ path = described_class.new(anything, ' /foo', anything)
93
+ expect(path).not_to be_namespace
96
94
  end
97
95
 
98
96
  it 'is false when the namespace is the root path' do
99
- path = Path.new(anything, '/', anything)
97
+ path = described_class.new(anything, '/', anything)
100
98
  expect(path.namespace?).to be false
101
99
  end
102
100
 
103
101
  it 'is true otherwise' do
104
- path = Path.new(anything, '/world', anything)
102
+ path = described_class.new(anything, '/world', anything)
105
103
  expect(path.namespace?).to be true
106
104
  end
107
105
  end
108
106
 
109
107
  describe '#path?' do
110
108
  it 'is false when the path is nil' do
111
- path = Path.new(nil, anything, anything)
112
- expect(path.path?).to be_falsey
109
+ path = described_class.new(nil, anything, anything)
110
+ expect(path).not_to be_path
113
111
  end
114
112
 
115
113
  it 'is false when the path starts with whitespace' do
116
- path = Path.new(' /foo', anything, anything)
117
- expect(path.path?).to be_falsey
114
+ path = described_class.new(' /foo', anything, anything)
115
+ expect(path).not_to be_path
118
116
  end
119
117
 
120
118
  it 'is false when the path is the root path' do
121
- path = Path.new('/', anything, anything)
119
+ path = described_class.new('/', anything, anything)
122
120
  expect(path.path?).to be false
123
121
  end
124
122
 
125
123
  it 'is true otherwise' do
126
- path = Path.new('/hello', anything, anything)
124
+ path = described_class.new('/hello', anything, anything)
127
125
  expect(path.path?).to be true
128
126
  end
129
127
  end
@@ -131,24 +129,24 @@ module Grape
131
129
  describe '#path' do
132
130
  context 'mount_path' do
133
131
  it 'is not included when it is nil' do
134
- path = Path.new(nil, nil, mount_path: '/foo/bar')
132
+ path = described_class.new(nil, nil, mount_path: '/foo/bar')
135
133
  expect(path.path).to eql '/foo/bar'
136
134
  end
137
135
 
138
136
  it 'is included when it is not nil' do
139
- path = Path.new(nil, nil, {})
137
+ path = described_class.new(nil, nil, {})
140
138
  expect(path.path).to eql('/')
141
139
  end
142
140
  end
143
141
 
144
142
  context 'root_prefix' do
145
143
  it 'is not included when it is nil' do
146
- path = Path.new(nil, nil, {})
144
+ path = described_class.new(nil, nil, {})
147
145
  expect(path.path).to eql('/')
148
146
  end
149
147
 
150
148
  it 'is included after the mount path' do
151
- path = Path.new(
149
+ path = described_class.new(
152
150
  nil,
153
151
  nil,
154
152
  mount_path: '/foo',
@@ -160,7 +158,7 @@ module Grape
160
158
  end
161
159
 
162
160
  it 'uses the namespace after the mount path and root prefix' do
163
- path = Path.new(
161
+ path = described_class.new(
164
162
  nil,
165
163
  'namespace',
166
164
  mount_path: '/foo',
@@ -171,7 +169,7 @@ module Grape
171
169
  end
172
170
 
173
171
  it 'uses the raw path after the namespace' do
174
- path = Path.new(
172
+ path = described_class.new(
175
173
  'raw_path',
176
174
  'namespace',
177
175
  mount_path: '/foo',
@@ -185,9 +183,9 @@ module Grape
185
183
  describe '#suffix' do
186
184
  context 'when using a specific format' do
187
185
  it 'accepts specified format' do
188
- path = Path.new(nil, nil, {})
189
- allow(path).to receive(:uses_specific_format?) { true }
190
- allow(path).to receive(:settings) { { format: :json } }
186
+ path = described_class.new(nil, nil, {})
187
+ allow(path).to receive(:uses_specific_format?).and_return(true)
188
+ allow(path).to receive(:settings).and_return({ format: :json })
191
189
 
192
190
  expect(path.suffix).to eql('(.json)')
193
191
  end
@@ -195,9 +193,9 @@ module Grape
195
193
 
196
194
  context 'when path versioning is used' do
197
195
  it "includes a '/'" do
198
- path = Path.new(nil, nil, {})
199
- allow(path).to receive(:uses_specific_format?) { false }
200
- allow(path).to receive(:uses_path_versioning?) { true }
196
+ path = described_class.new(nil, nil, {})
197
+ allow(path).to receive(:uses_specific_format?).and_return(false)
198
+ allow(path).to receive(:uses_path_versioning?).and_return(true)
201
199
 
202
200
  expect(path.suffix).to eql('(/.:format)')
203
201
  end
@@ -205,25 +203,25 @@ module Grape
205
203
 
206
204
  context 'when path versioning is not used' do
207
205
  it "does not include a '/' when the path has a namespace" do
208
- path = Path.new(nil, 'namespace', {})
209
- allow(path).to receive(:uses_specific_format?) { false }
210
- allow(path).to receive(:uses_path_versioning?) { true }
206
+ path = described_class.new(nil, 'namespace', {})
207
+ allow(path).to receive(:uses_specific_format?).and_return(false)
208
+ allow(path).to receive(:uses_path_versioning?).and_return(true)
211
209
 
212
210
  expect(path.suffix).to eql('(.:format)')
213
211
  end
214
212
 
215
213
  it "does not include a '/' when the path has a path" do
216
- path = Path.new('/path', nil, {})
217
- allow(path).to receive(:uses_specific_format?) { false }
218
- allow(path).to receive(:uses_path_versioning?) { true }
214
+ path = described_class.new('/path', nil, {})
215
+ allow(path).to receive(:uses_specific_format?).and_return(false)
216
+ allow(path).to receive(:uses_path_versioning?).and_return(true)
219
217
 
220
218
  expect(path.suffix).to eql('(.:format)')
221
219
  end
222
220
 
223
221
  it "includes a '/' otherwise" do
224
- path = Path.new(nil, nil, {})
225
- allow(path).to receive(:uses_specific_format?) { false }
226
- allow(path).to receive(:uses_path_versioning?) { true }
222
+ path = described_class.new(nil, nil, {})
223
+ allow(path).to receive(:uses_specific_format?).and_return(false)
224
+ allow(path).to receive(:uses_path_versioning?).and_return(true)
227
225
 
228
226
  expect(path.suffix).to eql('(/.:format)')
229
227
  end
@@ -232,19 +230,19 @@ module Grape
232
230
 
233
231
  describe '#path_with_suffix' do
234
232
  it 'combines the path and suffix' do
235
- path = Path.new(nil, nil, {})
236
- allow(path).to receive(:path) { '/the/path' }
237
- allow(path).to receive(:suffix) { 'suffix' }
233
+ path = described_class.new(nil, nil, {})
234
+ allow(path).to receive(:path).and_return('/the/path')
235
+ allow(path).to receive(:suffix).and_return('suffix')
238
236
 
239
237
  expect(path.path_with_suffix).to eql('/the/pathsuffix')
240
238
  end
241
239
 
242
240
  context 'when using a specific format' do
243
241
  it 'might have a suffix with specified format' do
244
- path = Path.new(nil, nil, {})
245
- allow(path).to receive(:path) { '/the/path' }
246
- allow(path).to receive(:uses_specific_format?) { true }
247
- allow(path).to receive(:settings) { { format: :json } }
242
+ path = described_class.new(nil, nil, {})
243
+ allow(path).to receive(:path).and_return('/the/path')
244
+ allow(path).to receive(:uses_specific_format?).and_return(true)
245
+ allow(path).to receive(:settings).and_return({ format: :json })
248
246
 
249
247
  expect(path.path_with_suffix).to eql('/the/path(.json)')
250
248
  end