grape 1.3.3 → 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 (165) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +111 -2
  3. data/CONTRIBUTING.md +2 -1
  4. data/README.md +135 -23
  5. data/UPGRADING.md +237 -46
  6. data/grape.gemspec +5 -5
  7. data/lib/grape/api/instance.rb +34 -42
  8. data/lib/grape/api.rb +21 -16
  9. data/lib/grape/cookies.rb +2 -0
  10. data/lib/grape/dsl/callbacks.rb +1 -1
  11. data/lib/grape/dsl/desc.rb +3 -5
  12. data/lib/grape/dsl/headers.rb +5 -2
  13. data/lib/grape/dsl/helpers.rb +8 -5
  14. data/lib/grape/dsl/inside_route.rb +72 -53
  15. data/lib/grape/dsl/middleware.rb +4 -4
  16. data/lib/grape/dsl/parameters.rb +11 -7
  17. data/lib/grape/dsl/request_response.rb +9 -6
  18. data/lib/grape/dsl/routing.rb +8 -9
  19. data/lib/grape/dsl/settings.rb +5 -5
  20. data/lib/grape/dsl/validations.rb +18 -1
  21. data/lib/grape/eager_load.rb +1 -1
  22. data/lib/grape/endpoint.rb +29 -42
  23. data/lib/grape/error_formatter/json.rb +2 -6
  24. data/lib/grape/error_formatter/xml.rb +2 -6
  25. data/lib/grape/exceptions/empty_message_body.rb +11 -0
  26. data/lib/grape/exceptions/validation.rb +2 -3
  27. data/lib/grape/exceptions/validation_errors.rb +1 -1
  28. data/lib/grape/formatter/json.rb +1 -0
  29. data/lib/grape/formatter/serializable_hash.rb +2 -1
  30. data/lib/grape/formatter/xml.rb +1 -0
  31. data/lib/grape/locale/en.yml +1 -1
  32. data/lib/grape/middleware/auth/base.rb +3 -3
  33. data/lib/grape/middleware/auth/dsl.rb +7 -1
  34. data/lib/grape/middleware/base.rb +6 -3
  35. data/lib/grape/middleware/error.rb +11 -13
  36. data/lib/grape/middleware/formatter.rb +7 -7
  37. data/lib/grape/middleware/stack.rb +10 -3
  38. data/lib/grape/middleware/versioner/accept_version_header.rb +3 -5
  39. data/lib/grape/middleware/versioner/header.rb +6 -4
  40. data/lib/grape/middleware/versioner/param.rb +1 -0
  41. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
  42. data/lib/grape/middleware/versioner/path.rb +2 -0
  43. data/lib/grape/parser/json.rb +1 -1
  44. data/lib/grape/parser/xml.rb +1 -1
  45. data/lib/grape/path.rb +1 -0
  46. data/lib/grape/request.rb +4 -1
  47. data/lib/grape/router/attribute_translator.rb +3 -3
  48. data/lib/grape/router/pattern.rb +1 -1
  49. data/lib/grape/router/route.rb +2 -2
  50. data/lib/grape/router.rb +31 -30
  51. data/lib/grape/{serve_file → serve_stream}/file_body.rb +1 -1
  52. data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +1 -1
  53. data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +8 -8
  54. data/lib/grape/util/base_inheritable.rb +2 -2
  55. data/lib/grape/util/inheritable_setting.rb +1 -3
  56. data/lib/grape/util/lazy_value.rb +4 -2
  57. data/lib/grape/util/strict_hash_configuration.rb +1 -1
  58. data/lib/grape/validations/attributes_iterator.rb +8 -0
  59. data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
  60. data/lib/grape/validations/params_scope.rb +97 -62
  61. data/lib/grape/validations/single_attribute_iterator.rb +1 -1
  62. data/lib/grape/validations/types/custom_type_coercer.rb +16 -3
  63. data/lib/grape/validations/types/dry_type_coercer.rb +1 -1
  64. data/lib/grape/validations/types/invalid_value.rb +24 -0
  65. data/lib/grape/validations/types/json.rb +2 -1
  66. data/lib/grape/validations/types/primitive_coercer.rb +4 -5
  67. data/lib/grape/validations/types.rb +1 -4
  68. data/lib/grape/validations/validator_factory.rb +1 -1
  69. data/lib/grape/validations/validators/all_or_none.rb +8 -5
  70. data/lib/grape/validations/validators/allow_blank.rb +9 -7
  71. data/lib/grape/validations/validators/as.rb +6 -8
  72. data/lib/grape/validations/validators/at_least_one_of.rb +7 -4
  73. data/lib/grape/validations/validators/base.rb +74 -69
  74. data/lib/grape/validations/validators/coerce.rb +63 -76
  75. data/lib/grape/validations/validators/default.rb +36 -34
  76. data/lib/grape/validations/validators/exactly_one_of.rb +9 -6
  77. data/lib/grape/validations/validators/except_values.rb +13 -11
  78. data/lib/grape/validations/validators/multiple_params_base.rb +24 -19
  79. data/lib/grape/validations/validators/mutual_exclusion.rb +8 -5
  80. data/lib/grape/validations/validators/presence.rb +7 -4
  81. data/lib/grape/validations/validators/regexp.rb +8 -5
  82. data/lib/grape/validations/validators/same_as.rb +18 -15
  83. data/lib/grape/validations/validators/values.rb +61 -56
  84. data/lib/grape/validations.rb +6 -0
  85. data/lib/grape/version.rb +1 -1
  86. data/lib/grape.rb +7 -3
  87. data/spec/grape/api/custom_validations_spec.rb +77 -45
  88. data/spec/grape/api/deeply_included_options_spec.rb +3 -3
  89. data/spec/grape/api/defines_boolean_in_params_spec.rb +2 -1
  90. data/spec/grape/api/invalid_format_spec.rb +2 -0
  91. data/spec/grape/api/recognize_path_spec.rb +1 -1
  92. data/spec/grape/api/routes_with_requirements_spec.rb +8 -8
  93. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +9 -15
  94. data/spec/grape/api_remount_spec.rb +25 -19
  95. data/spec/grape/api_spec.rb +576 -211
  96. data/spec/grape/dsl/callbacks_spec.rb +2 -1
  97. data/spec/grape/dsl/headers_spec.rb +39 -9
  98. data/spec/grape/dsl/helpers_spec.rb +3 -2
  99. data/spec/grape/dsl/inside_route_spec.rb +185 -34
  100. data/spec/grape/dsl/logger_spec.rb +16 -18
  101. data/spec/grape/dsl/middleware_spec.rb +2 -1
  102. data/spec/grape/dsl/parameters_spec.rb +2 -0
  103. data/spec/grape/dsl/request_response_spec.rb +1 -0
  104. data/spec/grape/dsl/routing_spec.rb +10 -7
  105. data/spec/grape/endpoint/declared_spec.rb +848 -0
  106. data/spec/grape/endpoint_spec.rb +77 -589
  107. data/spec/grape/entity_spec.rb +29 -23
  108. data/spec/grape/exceptions/body_parse_errors_spec.rb +3 -0
  109. data/spec/grape/exceptions/invalid_accept_header_spec.rb +61 -22
  110. data/spec/grape/exceptions/validation_errors_spec.rb +13 -10
  111. data/spec/grape/exceptions/validation_spec.rb +5 -3
  112. data/spec/grape/extensions/param_builders/hash_spec.rb +7 -7
  113. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +8 -8
  114. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +8 -8
  115. data/spec/grape/integration/rack_sendfile_spec.rb +13 -9
  116. data/spec/grape/loading_spec.rb +8 -8
  117. data/spec/grape/middleware/auth/dsl_spec.rb +15 -6
  118. data/spec/grape/middleware/auth/strategies_spec.rb +61 -21
  119. data/spec/grape/middleware/base_spec.rb +24 -15
  120. data/spec/grape/middleware/error_spec.rb +3 -3
  121. data/spec/grape/middleware/exception_spec.rb +111 -161
  122. data/spec/grape/middleware/formatter_spec.rb +28 -7
  123. data/spec/grape/middleware/globals_spec.rb +7 -4
  124. data/spec/grape/middleware/stack_spec.rb +15 -12
  125. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +2 -1
  126. data/spec/grape/middleware/versioner/header_spec.rb +14 -13
  127. data/spec/grape/middleware/versioner/param_spec.rb +7 -1
  128. data/spec/grape/middleware/versioner/path_spec.rb +5 -1
  129. data/spec/grape/middleware/versioner_spec.rb +1 -1
  130. data/spec/grape/parser_spec.rb +4 -0
  131. data/spec/grape/path_spec.rb +52 -52
  132. data/spec/grape/presenters/presenter_spec.rb +7 -6
  133. data/spec/grape/request_spec.rb +6 -4
  134. data/spec/grape/util/inheritable_setting_spec.rb +7 -7
  135. data/spec/grape/util/inheritable_values_spec.rb +3 -2
  136. data/spec/grape/util/reverse_stackable_values_spec.rb +3 -1
  137. data/spec/grape/util/stackable_values_spec.rb +7 -5
  138. data/spec/grape/validations/instance_behaivour_spec.rb +9 -10
  139. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +14 -3
  140. data/spec/grape/validations/params_scope_spec.rb +72 -10
  141. data/spec/grape/validations/single_attribute_iterator_spec.rb +18 -6
  142. data/spec/grape/validations/types/primitive_coercer_spec.rb +63 -7
  143. data/spec/grape/validations/types_spec.rb +8 -8
  144. data/spec/grape/validations/validators/all_or_none_spec.rb +50 -56
  145. data/spec/grape/validations/validators/allow_blank_spec.rb +136 -140
  146. data/spec/grape/validations/validators/at_least_one_of_spec.rb +50 -56
  147. data/spec/grape/validations/validators/coerce_spec.rb +248 -33
  148. data/spec/grape/validations/validators/default_spec.rb +121 -78
  149. data/spec/grape/validations/validators/exactly_one_of_spec.rb +71 -77
  150. data/spec/grape/validations/validators/except_values_spec.rb +4 -3
  151. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +71 -77
  152. data/spec/grape/validations/validators/presence_spec.rb +16 -1
  153. data/spec/grape/validations/validators/regexp_spec.rb +25 -31
  154. data/spec/grape/validations/validators/same_as_spec.rb +14 -20
  155. data/spec/grape/validations/validators/values_spec.rb +183 -178
  156. data/spec/grape/validations_spec.rb +342 -29
  157. data/spec/integration/eager_load/eager_load_spec.rb +15 -0
  158. data/spec/integration/multi_json/json_spec.rb +1 -1
  159. data/spec/integration/multi_xml/xml_spec.rb +1 -1
  160. data/spec/shared/versioning_examples.rb +32 -29
  161. data/spec/spec_helper.rb +12 -12
  162. data/spec/support/basic_auth_encode_helpers.rb +1 -1
  163. data/spec/support/chunks.rb +14 -0
  164. data/spec/support/versioned_helpers.rb +4 -6
  165. metadata +110 -102
@@ -32,7 +32,7 @@ describe Grape::Entity do
32
32
  end
33
33
 
34
34
  it 'pulls a representation from the class options if it exists' do
35
- entity = Class.new(Grape::Entity)
35
+ entity = Class.new(described_class)
36
36
  allow(entity).to receive(:represent).and_return('Hiya')
37
37
 
38
38
  subject.represent Object, with: entity
@@ -44,7 +44,7 @@ describe Grape::Entity do
44
44
  end
45
45
 
46
46
  it 'pulls a representation from the class options if the presented object is a collection of objects' do
47
- entity = Class.new(Grape::Entity)
47
+ entity = Class.new(described_class)
48
48
  allow(entity).to receive(:represent).and_return('Hiya')
49
49
 
50
50
  module EntitySpec
@@ -75,7 +75,7 @@ describe Grape::Entity do
75
75
  end
76
76
 
77
77
  it 'pulls a representation from the class ancestor if it exists' do
78
- entity = Class.new(Grape::Entity)
78
+ entity = Class.new(described_class)
79
79
  allow(entity).to receive(:represent).and_return('Hiya')
80
80
 
81
81
  subclass = Class.new(Object)
@@ -90,7 +90,7 @@ describe Grape::Entity do
90
90
 
91
91
  it 'automatically uses Klass::Entity if that exists' do
92
92
  some_model = Class.new
93
- entity = Class.new(Grape::Entity)
93
+ entity = Class.new(described_class)
94
94
  allow(entity).to receive(:represent).and_return('Auto-detect!')
95
95
 
96
96
  some_model.const_set :Entity, entity
@@ -104,7 +104,7 @@ describe Grape::Entity do
104
104
 
105
105
  it 'automatically uses Klass::Entity based on the first object in the collection being presented' do
106
106
  some_model = Class.new
107
- entity = Class.new(Grape::Entity)
107
+ entity = Class.new(described_class)
108
108
  allow(entity).to receive(:represent).and_return('Auto-detect!')
109
109
 
110
110
  some_model.const_set :Entity, entity
@@ -116,8 +116,8 @@ describe Grape::Entity do
116
116
  expect(last_response.body).to eq('Auto-detect!')
117
117
  end
118
118
 
119
- it 'does not run autodetection for Entity when explicitely provided' do
120
- entity = Class.new(Grape::Entity)
119
+ it 'does not run autodetection for Entity when explicitly provided' do
120
+ entity = Class.new(described_class)
121
121
  some_array = []
122
122
 
123
123
  subject.get '/example' do
@@ -129,7 +129,7 @@ describe Grape::Entity do
129
129
  end
130
130
 
131
131
  it 'does not use #first method on ActiveRecord::Relation to prevent needless sql query' do
132
- entity = Class.new(Grape::Entity)
132
+ entity = Class.new(described_class)
133
133
  some_relation = Class.new
134
134
  some_model = Class.new
135
135
 
@@ -173,7 +173,7 @@ describe Grape::Entity do
173
173
 
174
174
  %i[json serializable_hash].each do |format|
175
175
  it "presents with #{format}" do
176
- entity = Class.new(Grape::Entity)
176
+ entity = Class.new(described_class)
177
177
  entity.root 'examples', 'example'
178
178
  entity.expose :id
179
179
 
@@ -181,6 +181,7 @@ describe Grape::Entity do
181
181
  subject.get '/example' do
182
182
  c = Class.new do
183
183
  attr_reader :id
184
+
184
185
  def initialize(id)
185
186
  @id = id
186
187
  end
@@ -194,7 +195,7 @@ describe Grape::Entity do
194
195
  end
195
196
 
196
197
  it "presents with #{format} collection" do
197
- entity = Class.new(Grape::Entity)
198
+ entity = Class.new(described_class)
198
199
  entity.root 'examples', 'example'
199
200
  entity.expose :id
200
201
 
@@ -202,6 +203,7 @@ describe Grape::Entity do
202
203
  subject.get '/examples' do
203
204
  c = Class.new do
204
205
  attr_reader :id
206
+
205
207
  def initialize(id)
206
208
  @id = id
207
209
  end
@@ -217,7 +219,7 @@ describe Grape::Entity do
217
219
  end
218
220
 
219
221
  it 'presents with xml' do
220
- entity = Class.new(Grape::Entity)
222
+ entity = Class.new(described_class)
221
223
  entity.root 'examples', 'example'
222
224
  entity.expose :name
223
225
 
@@ -226,6 +228,7 @@ describe Grape::Entity do
226
228
  subject.get '/example' do
227
229
  c = Class.new do
228
230
  attr_reader :name
231
+
229
232
  def initialize(args)
230
233
  @name = args[:name] || 'no name set'
231
234
  end
@@ -235,18 +238,18 @@ describe Grape::Entity do
235
238
  get '/example'
236
239
  expect(last_response.status).to eq(200)
237
240
  expect(last_response.headers['Content-type']).to eq('application/xml')
238
- expect(last_response.body).to eq <<-XML
239
- <?xml version="1.0" encoding="UTF-8"?>
240
- <hash>
241
- <example>
242
- <name>johnnyiller</name>
243
- </example>
244
- </hash>
245
- XML
241
+ expect(last_response.body).to eq <<~XML
242
+ <?xml version="1.0" encoding="UTF-8"?>
243
+ <hash>
244
+ <example>
245
+ <name>johnnyiller</name>
246
+ </example>
247
+ </hash>
248
+ XML
246
249
  end
247
250
 
248
251
  it 'presents with json' do
249
- entity = Class.new(Grape::Entity)
252
+ entity = Class.new(described_class)
250
253
  entity.root 'examples', 'example'
251
254
  entity.expose :name
252
255
 
@@ -255,6 +258,7 @@ XML
255
258
  subject.get '/example' do
256
259
  c = Class.new do
257
260
  attr_reader :name
261
+
258
262
  def initialize(args)
259
263
  @name = args[:name] || 'no name set'
260
264
  end
@@ -271,7 +275,7 @@ XML
271
275
  # Include JSONP middleware
272
276
  subject.use Rack::JSONP
273
277
 
274
- entity = Class.new(Grape::Entity)
278
+ entity = Class.new(described_class)
275
279
  entity.root 'examples', 'example'
276
280
  entity.expose :name
277
281
 
@@ -284,6 +288,7 @@ XML
284
288
  subject.get '/example' do
285
289
  c = Class.new do
286
290
  attr_reader :name
291
+
287
292
  def initialize(args)
288
293
  @name = args[:name] || 'no name set'
289
294
  end
@@ -302,6 +307,7 @@ XML
302
307
  it 'present with multiple entities using optional symbol' do
303
308
  user = Class.new do
304
309
  attr_reader :name
310
+
305
311
  def initialize(args)
306
312
  @name = args[:name] || 'no name set'
307
313
  end
@@ -309,7 +315,7 @@ XML
309
315
  user1 = user.new(name: 'user1')
310
316
  user2 = user.new(name: 'user2')
311
317
 
312
- entity = Class.new(Grape::Entity)
318
+ entity = Class.new(described_class)
313
319
  entity.expose :name
314
320
 
315
321
  subject.format :json
@@ -320,7 +326,7 @@ XML
320
326
  end
321
327
  get '/example'
322
328
  expect_response_json = {
323
- 'page' => 1,
329
+ 'page' => 1,
324
330
  'user1' => { 'name' => 'user1' },
325
331
  'user2' => { 'name' => 'user2' }
326
332
  }
@@ -5,6 +5,7 @@ require 'spec_helper'
5
5
  describe Grape::Exceptions::ValidationErrors do
6
6
  context 'api with rescue_from :all handler' do
7
7
  subject { Class.new(Grape::API) }
8
+
8
9
  before do
9
10
  subject.rescue_from :all do |_e|
10
11
  rack_response 'message was processed', 400
@@ -56,6 +57,7 @@ describe Grape::Exceptions::ValidationErrors do
56
57
 
57
58
  context 'api with rescue_from :grape_exceptions handler' do
58
59
  subject { Class.new(Grape::API) }
60
+
59
61
  before do
60
62
  subject.rescue_from :all do |_e|
61
63
  rack_response 'message was processed', 400
@@ -93,6 +95,7 @@ describe Grape::Exceptions::ValidationErrors do
93
95
 
94
96
  context 'api without a rescue handler' do
95
97
  subject { Class.new(Grape::API) }
98
+
96
99
  before do
97
100
  subject.params do
98
101
  requires :beer
@@ -7,6 +7,7 @@ describe Grape::Exceptions::InvalidAcceptHeader do
7
7
  it 'does return with status 200' do
8
8
  expect(last_response.status).to eq 200
9
9
  end
10
+
10
11
  it 'does return the expected result' do
11
12
  expect(last_response.body).to eq('beer received')
12
13
  end
@@ -20,6 +21,7 @@ describe Grape::Exceptions::InvalidAcceptHeader do
20
21
  it 'does not include the X-Cascade=pass header' do
21
22
  expect(last_response.headers['X-Cascade']).to be_nil
22
23
  end
24
+
23
25
  it 'does not accept the request' do
24
26
  expect(last_response.status).to eq 406
25
27
  end
@@ -28,6 +30,7 @@ describe Grape::Exceptions::InvalidAcceptHeader do
28
30
  it 'does not include the X-Cascade=pass header' do
29
31
  expect(last_response.headers['X-Cascade']).to be_nil
30
32
  end
33
+
31
34
  it 'does show rescue handler processing' do
32
35
  expect(last_response.status).to eq 400
33
36
  expect(last_response.body).to eq('message was processed')
@@ -36,6 +39,7 @@ describe Grape::Exceptions::InvalidAcceptHeader do
36
39
 
37
40
  context 'API with cascade=false and rescue_from :all handler' do
38
41
  subject { Class.new(Grape::API) }
42
+
39
43
  before do
40
44
  subject.version 'v99', using: :header, vendor: 'vendorname', format: :json, cascade: false
41
45
  subject.rescue_from :all do |e|
@@ -52,7 +56,8 @@ describe Grape::Exceptions::InvalidAcceptHeader do
52
56
 
53
57
  context 'that received a request with correct vendor and version' do
54
58
  before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v99' }
55
- it_should_behave_like 'a valid request'
59
+
60
+ it_behaves_like 'a valid request'
56
61
  end
57
62
 
58
63
  context 'that receives' do
@@ -61,13 +66,15 @@ describe Grape::Exceptions::InvalidAcceptHeader do
61
66
  get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.invalidvendor-v99',
62
67
  'CONTENT_TYPE' => 'application/json'
63
68
  end
64
- it_should_behave_like 'a rescued request'
69
+
70
+ it_behaves_like 'a rescued request'
65
71
  end
66
72
  end
67
73
  end
68
74
 
69
75
  context 'API with cascade=false and without a rescue handler' do
70
76
  subject { Class.new(Grape::API) }
77
+
71
78
  before do
72
79
  subject.version 'v99', using: :header, vendor: 'vendorname', format: :json, cascade: false
73
80
  subject.get '/beer' do
@@ -81,23 +88,28 @@ describe Grape::Exceptions::InvalidAcceptHeader do
81
88
 
82
89
  context 'that received a request with correct vendor and version' do
83
90
  before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v99' }
84
- it_should_behave_like 'a valid request'
91
+
92
+ it_behaves_like 'a valid request'
85
93
  end
86
94
 
87
95
  context 'that receives' do
88
96
  context 'an invalid version in the request' do
89
97
  before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v77' }
90
- it_should_behave_like 'a not-cascaded request'
98
+
99
+ it_behaves_like 'a not-cascaded request'
91
100
  end
101
+
92
102
  context 'an invalid vendor in the request' do
93
103
  before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.invalidvendor-v99' }
94
- it_should_behave_like 'a not-cascaded request'
104
+
105
+ it_behaves_like 'a not-cascaded request'
95
106
  end
96
107
  end
97
108
  end
98
109
 
99
110
  context 'API with cascade=false and with rescue_from :all handler and http_codes' do
100
111
  subject { Class.new(Grape::API) }
112
+
101
113
  before do
102
114
  subject.version 'v99', using: :header, vendor: 'vendorname', format: :json, cascade: false
103
115
  subject.rescue_from :all do |e|
@@ -119,7 +131,8 @@ describe Grape::Exceptions::InvalidAcceptHeader do
119
131
 
120
132
  context 'that received a request with correct vendor and version' do
121
133
  before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v99' }
122
- it_should_behave_like 'a valid request'
134
+
135
+ it_behaves_like 'a valid request'
123
136
  end
124
137
 
125
138
  context 'that receives' do
@@ -128,13 +141,15 @@ describe Grape::Exceptions::InvalidAcceptHeader do
128
141
  get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.invalidvendor-v99',
129
142
  'CONTENT_TYPE' => 'application/json'
130
143
  end
131
- it_should_behave_like 'a rescued request'
144
+
145
+ it_behaves_like 'a rescued request'
132
146
  end
133
147
  end
134
148
  end
135
149
 
136
150
  context 'API with cascade=false, http_codes but without a rescue handler' do
137
151
  subject { Class.new(Grape::API) }
152
+
138
153
  before do
139
154
  subject.version 'v99', using: :header, vendor: 'vendorname', format: :json, cascade: false
140
155
  subject.desc 'Get beer' do
@@ -153,23 +168,28 @@ describe Grape::Exceptions::InvalidAcceptHeader do
153
168
 
154
169
  context 'that received a request with correct vendor and version' do
155
170
  before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v99' }
156
- it_should_behave_like 'a valid request'
171
+
172
+ it_behaves_like 'a valid request'
157
173
  end
158
174
 
159
175
  context 'that receives' do
160
176
  context 'an invalid version in the request' do
161
177
  before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v77' }
162
- it_should_behave_like 'a not-cascaded request'
178
+
179
+ it_behaves_like 'a not-cascaded request'
163
180
  end
181
+
164
182
  context 'an invalid vendor in the request' do
165
183
  before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.invalidvendor-v99' }
166
- it_should_behave_like 'a not-cascaded request'
184
+
185
+ it_behaves_like 'a not-cascaded request'
167
186
  end
168
187
  end
169
188
  end
170
189
 
171
190
  context 'API with cascade=true and rescue_from :all handler' do
172
191
  subject { Class.new(Grape::API) }
192
+
173
193
  before do
174
194
  subject.version 'v99', using: :header, vendor: 'vendorname', format: :json, cascade: true
175
195
  subject.rescue_from :all do |e|
@@ -186,7 +206,8 @@ describe Grape::Exceptions::InvalidAcceptHeader do
186
206
 
187
207
  context 'that received a request with correct vendor and version' do
188
208
  before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v99' }
189
- it_should_behave_like 'a valid request'
209
+
210
+ it_behaves_like 'a valid request'
190
211
  end
191
212
 
192
213
  context 'that receives' do
@@ -195,20 +216,24 @@ describe Grape::Exceptions::InvalidAcceptHeader do
195
216
  get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v77',
196
217
  'CONTENT_TYPE' => 'application/json'
197
218
  end
198
- it_should_behave_like 'a cascaded request'
219
+
220
+ it_behaves_like 'a cascaded request'
199
221
  end
222
+
200
223
  context 'an invalid vendor in the request' do
201
224
  before do
202
225
  get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.invalidvendor-v99',
203
226
  'CONTENT_TYPE' => 'application/json'
204
227
  end
205
- it_should_behave_like 'a cascaded request'
228
+
229
+ it_behaves_like 'a cascaded request'
206
230
  end
207
231
  end
208
232
  end
209
233
 
210
234
  context 'API with cascade=true and without a rescue handler' do
211
235
  subject { Class.new(Grape::API) }
236
+
212
237
  before do
213
238
  subject.version 'v99', using: :header, vendor: 'vendorname', format: :json, cascade: true
214
239
  subject.get '/beer' do
@@ -222,23 +247,28 @@ describe Grape::Exceptions::InvalidAcceptHeader do
222
247
 
223
248
  context 'that received a request with correct vendor and version' do
224
249
  before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v99' }
225
- it_should_behave_like 'a valid request'
250
+
251
+ it_behaves_like 'a valid request'
226
252
  end
227
253
 
228
254
  context 'that receives' do
229
255
  context 'an invalid version in the request' do
230
256
  before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v77' }
231
- it_should_behave_like 'a cascaded request'
257
+
258
+ it_behaves_like 'a cascaded request'
232
259
  end
260
+
233
261
  context 'an invalid vendor in the request' do
234
262
  before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.invalidvendor-v99' }
235
- it_should_behave_like 'a cascaded request'
263
+
264
+ it_behaves_like 'a cascaded request'
236
265
  end
237
266
  end
238
267
  end
239
268
 
240
269
  context 'API with cascade=true and with rescue_from :all handler and http_codes' do
241
270
  subject { Class.new(Grape::API) }
271
+
242
272
  before do
243
273
  subject.version 'v99', using: :header, vendor: 'vendorname', format: :json, cascade: true
244
274
  subject.rescue_from :all do |e|
@@ -260,7 +290,8 @@ describe Grape::Exceptions::InvalidAcceptHeader do
260
290
 
261
291
  context 'that received a request with correct vendor and version' do
262
292
  before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v99' }
263
- it_should_behave_like 'a valid request'
293
+
294
+ it_behaves_like 'a valid request'
264
295
  end
265
296
 
266
297
  context 'that receives' do
@@ -269,20 +300,24 @@ describe Grape::Exceptions::InvalidAcceptHeader do
269
300
  get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v77',
270
301
  'CONTENT_TYPE' => 'application/json'
271
302
  end
272
- it_should_behave_like 'a cascaded request'
303
+
304
+ it_behaves_like 'a cascaded request'
273
305
  end
306
+
274
307
  context 'an invalid vendor in the request' do
275
308
  before do
276
309
  get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.invalidvendor-v99',
277
310
  'CONTENT_TYPE' => 'application/json'
278
311
  end
279
- it_should_behave_like 'a cascaded request'
312
+
313
+ it_behaves_like 'a cascaded request'
280
314
  end
281
315
  end
282
316
  end
283
317
 
284
318
  context 'API with cascade=true, http_codes but without a rescue handler' do
285
319
  subject { Class.new(Grape::API) }
320
+
286
321
  before do
287
322
  subject.version 'v99', using: :header, vendor: 'vendorname', format: :json, cascade: true
288
323
  subject.desc 'Get beer' do
@@ -301,17 +336,21 @@ describe Grape::Exceptions::InvalidAcceptHeader do
301
336
 
302
337
  context 'that received a request with correct vendor and version' do
303
338
  before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v99' }
304
- it_should_behave_like 'a valid request'
339
+
340
+ it_behaves_like 'a valid request'
305
341
  end
306
342
 
307
343
  context 'that receives' do
308
344
  context 'an invalid version in the request' do
309
345
  before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.vendorname-v77' }
310
- it_should_behave_like 'a cascaded request'
346
+
347
+ it_behaves_like 'a cascaded request'
311
348
  end
349
+
312
350
  context 'an invalid vendor in the request' do
313
351
  before { get '/beer', {}, 'HTTP_ACCEPT' => 'application/vnd.invalidvendor-v99' }
314
- it_should_behave_like 'a cascaded request'
352
+
353
+ it_behaves_like 'a cascaded request'
315
354
  end
316
355
  end
317
356
  end
@@ -5,30 +5,31 @@ require 'ostruct'
5
5
 
6
6
  describe Grape::Exceptions::ValidationErrors do
7
7
  let(:validation_message) { 'FooBar is invalid' }
8
- let(:validation_error) { OpenStruct.new(params: [validation_message]) }
8
+ let(:validation_error) { instance_double Grape::Exceptions::Validation, params: [validation_message], message: '' }
9
9
 
10
10
  context 'initialize' do
11
+ subject do
12
+ described_class.new(errors: [validation_error], headers: headers)
13
+ end
14
+
11
15
  let(:headers) do
12
16
  {
13
17
  'A-Header-Key' => 'A-Header-Value'
14
18
  }
15
19
  end
16
20
 
17
- subject do
18
- described_class.new(errors: [validation_error], headers: headers)
19
- end
20
-
21
- it 'should assign headers through base class' do
21
+ it 'assigns headers through base class' do
22
22
  expect(subject.headers).to eq(headers)
23
23
  end
24
24
  end
25
25
 
26
26
  context 'message' do
27
27
  context 'is not repeated' do
28
+ subject(:message) { error.message.split(',').map(&:strip) }
29
+
28
30
  let(:error) do
29
31
  described_class.new(errors: [validation_error, validation_error])
30
32
  end
31
- subject(:message) { error.message.split(',').map(&:strip) }
32
33
 
33
34
  it { expect(message).to include validation_message }
34
35
  it { expect(message.size).to eq 1 }
@@ -37,9 +38,10 @@ describe Grape::Exceptions::ValidationErrors do
37
38
 
38
39
  describe '#full_messages' do
39
40
  context 'with errors' do
41
+ subject { described_class.new(errors: [validation_error_1, validation_error_2]).full_messages }
42
+
40
43
  let(:validation_error_1) { Grape::Exceptions::Validation.new(params: ['id'], message: :presence) }
41
44
  let(:validation_error_2) { Grape::Exceptions::Validation.new(params: ['name'], message: :presence) }
42
- subject { described_class.new(errors: [validation_error_1, validation_error_2]).full_messages }
43
45
 
44
46
  it 'returns an array with each errors full message' do
45
47
  expect(subject).to contain_exactly('id is missing', 'name is missing')
@@ -47,9 +49,10 @@ describe Grape::Exceptions::ValidationErrors do
47
49
  end
48
50
 
49
51
  context 'when attributes is an array of symbols' do
50
- let(:validation_error) { Grape::Exceptions::Validation.new(params: [:admin_field], message: 'Can not set admin-only field') }
51
52
  subject { described_class.new(errors: [validation_error]).full_messages }
52
53
 
54
+ let(:validation_error) { Grape::Exceptions::Validation.new(params: [:admin_field], message: 'Can not set admin-only field') }
55
+
53
56
  it 'returns an array with an error full message' do
54
57
  expect(subject.first).to eq('admin_field Can not set admin-only field')
55
58
  end
@@ -65,7 +68,7 @@ describe Grape::Exceptions::ValidationErrors do
65
68
 
66
69
  it 'can return structured json with separate fields' do
67
70
  subject.format :json
68
- subject.rescue_from Grape::Exceptions::ValidationErrors do |e|
71
+ subject.rescue_from described_class do |e|
69
72
  error!(e, 400)
70
73
  end
71
74
  subject.params do
@@ -4,16 +4,18 @@ require 'spec_helper'
4
4
 
5
5
  describe Grape::Exceptions::Validation do
6
6
  it 'fails when params are missing' do
7
- expect { Grape::Exceptions::Validation.new(message: 'presence') }.to raise_error(ArgumentError, /missing keyword:.+?params/)
7
+ expect { described_class.new(message: 'presence') }.to raise_error(ArgumentError, /missing keyword:.+?params/)
8
8
  end
9
+
9
10
  context 'when message is a symbol' do
10
11
  it 'stores message_key' do
11
- expect(Grape::Exceptions::Validation.new(params: ['id'], message: :presence).message_key).to eq(:presence)
12
+ expect(described_class.new(params: ['id'], message: :presence).message_key).to eq(:presence)
12
13
  end
13
14
  end
15
+
14
16
  context 'when message is a String' do
15
17
  it 'does not store the message_key' do
16
- expect(Grape::Exceptions::Validation.new(params: ['id'], message: 'presence').message_key).to eq(nil)
18
+ expect(described_class.new(params: ['id'], message: 'presence').message_key).to eq(nil)
17
19
  end
18
20
  end
19
21
  end
@@ -10,10 +10,10 @@ describe Grape::Extensions::Hash::ParamBuilder do
10
10
  end
11
11
 
12
12
  describe 'in an endpoint' do
13
- context '#params' do
13
+ describe '#params' do
14
14
  before do
15
15
  subject.params do
16
- build_with Grape::Extensions::Hash::ParamBuilder
16
+ build_with Grape::Extensions::Hash::ParamBuilder # rubocop:disable RSpec/DescribedClass
17
17
  end
18
18
 
19
19
  subject.get do
@@ -21,7 +21,7 @@ describe Grape::Extensions::Hash::ParamBuilder do
21
21
  end
22
22
  end
23
23
 
24
- it 'should be of type Hash' do
24
+ it 'is of type Hash' do
25
25
  get '/'
26
26
  expect(last_response.status).to eq(200)
27
27
  expect(last_response.body).to eq('Hash')
@@ -31,17 +31,17 @@ describe Grape::Extensions::Hash::ParamBuilder do
31
31
 
32
32
  describe 'in an api' do
33
33
  before do
34
- subject.send(:include, Grape::Extensions::Hash::ParamBuilder)
34
+ subject.send(:include, Grape::Extensions::Hash::ParamBuilder) # rubocop:disable RSpec/DescribedClass
35
35
  end
36
36
 
37
- context '#params' do
37
+ describe '#params' do
38
38
  before do
39
39
  subject.get do
40
40
  params.class
41
41
  end
42
42
  end
43
43
 
44
- it 'should be Hash' do
44
+ it 'is Hash' do
45
45
  get '/'
46
46
  expect(last_response.status).to eq(200)
47
47
  expect(last_response.body).to eq('Hash')
@@ -69,7 +69,7 @@ describe Grape::Extensions::Hash::ParamBuilder do
69
69
 
70
70
  it 'symbolizes the params' do
71
71
  subject.params do
72
- build_with Grape::Extensions::Hash::ParamBuilder
72
+ build_with Grape::Extensions::Hash::ParamBuilder # rubocop:disable RSpec/DescribedClass
73
73
  requires :a, type: String
74
74
  end
75
75