grape 0.7.0 → 0.8.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.

Potentially problematic release.


This version of grape might be problematic. Click here for more details.

Files changed (62) hide show
  1. checksums.yaml +5 -13
  2. data/.rubocop.yml +6 -6
  3. data/.travis.yml +11 -2
  4. data/CHANGELOG.md +23 -1
  5. data/Gemfile +11 -10
  6. data/Guardfile +5 -6
  7. data/README.md +194 -13
  8. data/UPGRADING.md +3 -3
  9. data/grape.gemspec +1 -1
  10. data/grape.png +0 -0
  11. data/lib/grape/api.rb +21 -13
  12. data/lib/grape/endpoint.rb +31 -13
  13. data/lib/grape/exceptions/validation.rb +2 -2
  14. data/lib/grape/locale/en.yml +2 -0
  15. data/lib/grape/middleware/auth/oauth2.rb +69 -65
  16. data/lib/grape/middleware/error.rb +4 -2
  17. data/lib/grape/middleware/formatter.rb +2 -2
  18. data/lib/grape/middleware/versioner/accept_version_header.rb +1 -1
  19. data/lib/grape/middleware/versioner/header.rb +3 -3
  20. data/lib/grape/util/hash_stack.rb +1 -1
  21. data/lib/grape/validations.rb +22 -8
  22. data/lib/grape/validations/default.rb +1 -1
  23. data/lib/grape/validations/exactly_one_of.rb +26 -0
  24. data/lib/grape/validations/mutual_exclusion.rb +25 -0
  25. data/lib/grape/validations/presence.rb +1 -1
  26. data/lib/grape/validations/regexp.rb +2 -1
  27. data/lib/grape/validations/values.rb +7 -1
  28. data/lib/grape/version.rb +1 -1
  29. data/spec/grape/api_spec.rb +390 -333
  30. data/spec/grape/endpoint_spec.rb +129 -99
  31. data/spec/grape/entity_spec.rb +47 -27
  32. data/spec/grape/exceptions/invalid_formatter_spec.rb +1 -1
  33. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +1 -1
  34. data/spec/grape/exceptions/missing_mime_type_spec.rb +2 -2
  35. data/spec/grape/exceptions/missing_option_spec.rb +1 -1
  36. data/spec/grape/exceptions/unknown_options_spec.rb +1 -1
  37. data/spec/grape/exceptions/unknown_validator_spec.rb +1 -1
  38. data/spec/grape/middleware/auth/basic_spec.rb +3 -3
  39. data/spec/grape/middleware/auth/digest_spec.rb +4 -4
  40. data/spec/grape/middleware/auth/oauth2_spec.rb +11 -11
  41. data/spec/grape/middleware/base_spec.rb +9 -9
  42. data/spec/grape/middleware/error_spec.rb +4 -4
  43. data/spec/grape/middleware/exception_spec.rb +17 -17
  44. data/spec/grape/middleware/formatter_spec.rb +38 -38
  45. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +11 -11
  46. data/spec/grape/middleware/versioner/header_spec.rb +39 -39
  47. data/spec/grape/middleware/versioner/param_spec.rb +10 -10
  48. data/spec/grape/middleware/versioner/path_spec.rb +7 -7
  49. data/spec/grape/middleware/versioner_spec.rb +4 -4
  50. data/spec/grape/path_spec.rb +6 -6
  51. data/spec/grape/util/hash_stack_spec.rb +22 -22
  52. data/spec/grape/validations/coerce_spec.rb +34 -34
  53. data/spec/grape/validations/default_spec.rb +16 -16
  54. data/spec/grape/validations/exactly_one_of_spec.rb +71 -0
  55. data/spec/grape/validations/mutual_exclusion_spec.rb +61 -0
  56. data/spec/grape/validations/presence_spec.rb +34 -34
  57. data/spec/grape/validations/regexp_spec.rb +11 -4
  58. data/spec/grape/validations/values_spec.rb +34 -20
  59. data/spec/grape/validations_spec.rb +300 -147
  60. data/spec/shared/versioning_examples.rb +18 -18
  61. data/spec/spec_helper.rb +2 -1
  62. metadata +81 -38
@@ -46,7 +46,7 @@ module Grape
46
46
  #
47
47
  # @param key [Symbol] key to look for in hash frames
48
48
  # @return true if key exists, false otherwise
49
- def has_key?(key)
49
+ def key?(key)
50
50
  (@stack.length - 1).downto(0).each do |i|
51
51
  return true if @stack[i].key? key
52
52
  end
@@ -19,7 +19,7 @@ module Grape
19
19
  def validate!(params)
20
20
  attributes = AttributesIterator.new(self, @scope, params)
21
21
  attributes.each do |resource_params, attr_name|
22
- if @required || resource_params.has_key?(attr_name)
22
+ if @required || resource_params.key?(attr_name)
23
23
  validate_param!(attr_name, resource_params)
24
24
  end
25
25
  end
@@ -43,8 +43,6 @@ module Grape
43
43
  end
44
44
  end
45
45
 
46
- private
47
-
48
46
  def self.convert_to_short_name(klass)
49
47
  ret = klass.name.gsub(/::/, '/')
50
48
  .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
@@ -132,6 +130,14 @@ module Grape
132
130
  push_declared_params(attrs)
133
131
  end
134
132
 
133
+ def mutually_exclusive(*attrs)
134
+ validates(attrs, mutual_exclusion: true)
135
+ end
136
+
137
+ def exactly_one_of(*attrs)
138
+ validates(attrs, exactly_one_of: true)
139
+ end
140
+
135
141
  def group(*attrs, &block)
136
142
  requires(*attrs, &block)
137
143
  end
@@ -152,11 +158,12 @@ module Grape
152
158
 
153
159
  def use(*names)
154
160
  named_params = @api.settings[:named_params] || {}
161
+ options = names.last.is_a?(Hash) ? names.pop : {}
155
162
  names.each do |name|
156
163
  params_block = named_params.fetch(name) do
157
164
  raise "Params :#{name} not found!"
158
165
  end
159
- instance_eval(&params_block)
166
+ instance_exec(options, &params_block)
160
167
  end
161
168
  end
162
169
  alias_method :use_scope, :use
@@ -167,6 +174,10 @@ module Grape
167
174
  name.to_s
168
175
  end
169
176
 
177
+ def root?
178
+ !@parent
179
+ end
180
+
170
181
  protected
171
182
 
172
183
  def push_declared_params(attrs)
@@ -184,10 +195,13 @@ module Grape
184
195
  optional_fields = opts[:using].keys - required_fields
185
196
  end
186
197
  required_fields.each do |field|
187
- requires(field, opts[:using][field])
198
+ field_opts = opts[:using][field]
199
+ raise ArgumentError, "required field not exist: #{field}" unless field_opts
200
+ requires(field, field_opts)
188
201
  end
189
202
  optional_fields.each do |field|
190
- optional(field, opts[:using][field])
203
+ field_opts = opts[:using][field]
204
+ optional(field, field_opts) if field_opts
191
205
  end
192
206
  end
193
207
 
@@ -250,7 +264,7 @@ module Grape
250
264
  @api.document_attribute(full_attrs, doc_attrs)
251
265
 
252
266
  # Validate for presence before any other validators
253
- if validations.has_key?(:presence) && validations[:presence]
267
+ if validations.key?(:presence) && validations[:presence]
254
268
  validate('presence', validations[:presence], attrs, doc_attrs)
255
269
  validations.delete(:presence)
256
270
  end
@@ -258,7 +272,7 @@ module Grape
258
272
  # Before we run the rest of the validators, lets handle
259
273
  # whatever coercion so that we are working with correctly
260
274
  # type casted values
261
- if validations.has_key? :coerce
275
+ if validations.key? :coerce
262
276
  validate('coerce', validations[:coerce], attrs, doc_attrs)
263
277
  validations.delete(:coerce)
264
278
  end
@@ -7,7 +7,7 @@ module Grape
7
7
  end
8
8
 
9
9
  def validate_param!(attr_name, params)
10
- params[attr_name] = @default.is_a?(Proc) ? @default.call : @default unless params.has_key?(attr_name)
10
+ params[attr_name] = @default.is_a?(Proc) ? @default.call : @default unless params.key?(attr_name)
11
11
  end
12
12
 
13
13
  def validate!(params)
@@ -0,0 +1,26 @@
1
+ module Grape
2
+ module Validations
3
+ require 'grape/validations/mutual_exclusion'
4
+ class ExactlyOneOfValidator < MutualExclusionValidator
5
+ attr_reader :params
6
+
7
+ def validate!(params)
8
+ super
9
+ if none_of_restricted_params_is_present
10
+ raise Grape::Exceptions::Validation, param: "#{all_keys}", message_key: :exactly_one
11
+ end
12
+ params
13
+ end
14
+
15
+ private
16
+
17
+ def none_of_restricted_params_is_present
18
+ keys_in_common.length < 1
19
+ end
20
+
21
+ def all_keys
22
+ attrs.map(&:to_sym)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,25 @@
1
+ module Grape
2
+ module Validations
3
+ class MutualExclusionValidator < Validator
4
+ attr_reader :params
5
+
6
+ def validate!(params)
7
+ @params = params
8
+ if two_or_more_exclusive_params_are_present
9
+ raise Grape::Exceptions::Validation, param: "#{keys_in_common.map(&:to_sym)}", message_key: :mutual_exclusion
10
+ end
11
+ params
12
+ end
13
+
14
+ private
15
+
16
+ def two_or_more_exclusive_params_are_present
17
+ keys_in_common.length > 1
18
+ end
19
+
20
+ def keys_in_common
21
+ attrs.map(&:to_s) & params.stringify_keys.keys
22
+ end
23
+ end
24
+ end
25
+ end
@@ -7,7 +7,7 @@ module Grape
7
7
  end
8
8
 
9
9
  def validate_param!(attr_name, params)
10
- unless params.respond_to?(:has_key?) && params.has_key?(attr_name)
10
+ unless params.respond_to?(:key?) && params.key?(attr_name)
11
11
  raise Grape::Exceptions::Validation, param: @scope.full_name(attr_name), message_key: :presence
12
12
  end
13
13
  end
@@ -2,7 +2,8 @@ module Grape
2
2
  module Validations
3
3
  class RegexpValidator < SingleOptionValidator
4
4
  def validate_param!(attr_name, params)
5
- if params[attr_name] && !(params[attr_name].to_s =~ @option)
5
+ if params.key?(attr_name) &&
6
+ (params[attr_name].nil? || !(params[attr_name].to_s =~ @option))
6
7
  raise Grape::Exceptions::Validation, param: @scope.full_name(attr_name), message_key: :regexp
7
8
  end
8
9
  end
@@ -8,10 +8,16 @@ module Grape
8
8
  end
9
9
 
10
10
  def validate_param!(attr_name, params)
11
- if (params[attr_name] || @required) && !(@values.is_a?(Proc) ? @values.call : @values).include?(params[attr_name])
11
+ if (params[attr_name] || required_for_root_scope?) && !(@values.is_a?(Proc) ? @values.call : @values).include?(params[attr_name])
12
12
  raise Grape::Exceptions::Validation, param: @scope.full_name(attr_name), message_key: :values
13
13
  end
14
14
  end
15
+
16
+ private
17
+
18
+ def required_for_root_scope?
19
+ @required && @scope.root?
20
+ end
15
21
  end
16
22
  end
17
23
  end
data/lib/grape/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Grape
2
- VERSION = '0.7.0'
2
+ VERSION = '0.8.0'
3
3
  end
@@ -9,7 +9,6 @@ describe Grape::API do
9
9
  end
10
10
 
11
11
  describe '.prefix' do
12
-
13
12
  it 'routes root through with the prefix' do
14
13
  subject.prefix 'awesome/sauce'
15
14
  subject.get do
@@ -17,7 +16,7 @@ describe Grape::API do
17
16
  end
18
17
 
19
18
  get 'awesome/sauce/'
20
- last_response.body.should eql "Hello there."
19
+ expect(last_response.body).to eql "Hello there."
21
20
  end
22
21
 
23
22
  it 'routes through with the prefix' do
@@ -27,25 +26,24 @@ describe Grape::API do
27
26
  end
28
27
 
29
28
  get 'awesome/sauce/hello'
30
- last_response.body.should eql "Hello there."
29
+ expect(last_response.body).to eql "Hello there."
31
30
 
32
31
  get '/hello'
33
- last_response.status.should eql 404
32
+ expect(last_response.status).to eql 404
34
33
  end
35
-
36
34
  end
37
35
 
38
36
  describe '.version' do
39
37
  context 'when defined' do
40
38
  it 'returns version value' do
41
39
  subject.version 'v1'
42
- subject.version.should == 'v1'
40
+ expect(subject.version).to eq('v1')
43
41
  end
44
42
  end
45
43
 
46
44
  context 'when not defined' do
47
45
  it 'returns nil' do
48
- subject.version.should be_nil
46
+ expect(subject.version).to be_nil
49
47
  end
50
48
  end
51
49
  end
@@ -117,7 +115,7 @@ describe Grape::API do
117
115
  it 'adds the association to the :representations setting' do
118
116
  klass = Class.new
119
117
  subject.represent Object, with: klass
120
- subject.settings[:representations][Object].should == klass
118
+ expect(subject.settings[:representations][Object]).to eq(klass)
121
119
  end
122
120
  end
123
121
 
@@ -137,7 +135,7 @@ describe Grape::API do
137
135
  end
138
136
 
139
137
  get "/rad/v1/awesome/hello"
140
- last_response.body.should == "worked"
138
+ expect(last_response.body).to eq("worked")
141
139
  end
142
140
 
143
141
  it 'cancels itself after the block is over' do
@@ -145,7 +143,7 @@ describe Grape::API do
145
143
  namespace.should == '/awesome'
146
144
  end
147
145
 
148
- subject.namespace.should == '/'
146
+ expect(subject.namespace).to eq('/')
149
147
  end
150
148
 
151
149
  it 'is stackable' do
@@ -155,7 +153,7 @@ describe Grape::API do
155
153
  end
156
154
  namespace.should == '/awesome'
157
155
  end
158
- subject.namespace.should == '/'
156
+ expect(subject.namespace).to eq('/')
159
157
  end
160
158
 
161
159
  it 'accepts path segments correctly' do
@@ -168,7 +166,7 @@ describe Grape::API do
168
166
  end
169
167
  end
170
168
  get '/members/23'
171
- last_response.body.should == "23"
169
+ expect(last_response.body).to eq("23")
172
170
  end
173
171
 
174
172
  it 'is callable with nil just to push onto the stack' do
@@ -179,9 +177,9 @@ describe Grape::API do
179
177
  subject.get('/hello') { "outer" }
180
178
 
181
179
  get '/v2/hello'
182
- last_response.body.should == "inner"
180
+ expect(last_response.body).to eq("inner")
183
181
  get '/hello'
184
- last_response.body.should == "outer"
182
+ expect(last_response.body).to eq("outer")
185
183
  end
186
184
 
187
185
  %w(group resource resources segment).each do |als|
@@ -204,7 +202,7 @@ describe Grape::API do
204
202
  end
205
203
 
206
204
  get '/users/23'
207
- last_response.body.should == '23'
205
+ expect(last_response.body).to eq('23')
208
206
  end
209
207
 
210
208
  it 'should be able to define requirements with a single hash' do
@@ -217,9 +215,9 @@ describe Grape::API do
217
215
  end
218
216
 
219
217
  get '/users/michael'
220
- last_response.status.should == 404
218
+ expect(last_response.status).to eq(404)
221
219
  get '/users/23'
222
- last_response.status.should == 200
220
+ expect(last_response.status).to eq(200)
223
221
  end
224
222
  end
225
223
 
@@ -235,15 +233,15 @@ describe Grape::API do
235
233
  end
236
234
 
237
235
  get '/votes'
238
- last_response.body.should eql 'Votes'
236
+ expect(last_response.body).to eql 'Votes'
239
237
  post '/votes'
240
- last_response.body.should eql 'Created a Vote'
238
+ expect(last_response.body).to eql 'Created a Vote'
241
239
  end
242
240
 
243
241
  it 'handles empty calls' do
244
242
  subject.get "/"
245
243
  get "/"
246
- last_response.body.should eql ""
244
+ expect(last_response.body).to eql ""
247
245
  end
248
246
 
249
247
  describe 'root routes should work with' do
@@ -255,7 +253,7 @@ describe Grape::API do
255
253
  end
256
254
 
257
255
  after do
258
- last_response.body.should eql "root"
256
+ expect(last_response.body).to eql "root"
259
257
  end
260
258
 
261
259
  describe 'path versioned APIs' do
@@ -315,9 +313,9 @@ describe Grape::API do
315
313
  end
316
314
 
317
315
  get '/abc'
318
- last_response.body.should eql 'foo'
316
+ expect(last_response.body).to eql 'foo'
319
317
  get '/def'
320
- last_response.body.should eql 'foo'
318
+ expect(last_response.body).to eql 'foo'
321
319
  end
322
320
 
323
321
  context 'format' do
@@ -329,14 +327,14 @@ describe Grape::API do
329
327
 
330
328
  it 'allows .json' do
331
329
  get '/abc.json'
332
- last_response.status.should == 200
333
- last_response.body.should eql 'abc' # json-encoded symbol
330
+ expect(last_response.status).to eq(200)
331
+ expect(last_response.body).to eql 'abc' # json-encoded symbol
334
332
  end
335
333
 
336
334
  it 'allows .txt' do
337
335
  get '/abc.txt'
338
- last_response.status.should == 200
339
- last_response.body.should eql 'def' # raw text
336
+ expect(last_response.status).to eq(200)
337
+ expect(last_response.body).to eql 'def' # raw text
340
338
  end
341
339
  end
342
340
 
@@ -346,7 +344,7 @@ describe Grape::API do
346
344
  end
347
345
 
348
346
  get '/awesome.json'
349
- last_response.body.should eql '{"id":"awesome"}'
347
+ expect(last_response.body).to eql '{"id":"awesome"}'
350
348
  end
351
349
 
352
350
  it 'allows for format in namespace with no path' do
@@ -357,7 +355,7 @@ describe Grape::API do
357
355
  end
358
356
 
359
357
  get '/abc.json'
360
- last_response.body.should eql '["json"]'
358
+ expect(last_response.body).to eql '["json"]'
361
359
  end
362
360
 
363
361
  it 'allows for multiple verbs' do
@@ -366,13 +364,13 @@ describe Grape::API do
366
364
  end
367
365
 
368
366
  subject.endpoints.first.routes.each do |route|
369
- route.route_path.should eql '/abc(.:format)'
367
+ expect(route.route_path).to eql '/abc(.:format)'
370
368
  end
371
369
 
372
370
  get '/abc'
373
- last_response.body.should eql 'hiya'
371
+ expect(last_response.body).to eql 'hiya'
374
372
  post '/abc'
375
- last_response.body.should eql 'hiya'
373
+ expect(last_response.body).to eql 'hiya'
376
374
  end
377
375
 
378
376
  [:put, :post].each do |verb|
@@ -384,9 +382,9 @@ describe Grape::API do
384
382
  env['api.request.body']
385
383
  end
386
384
  send verb, '/', MultiJson.dump(object), 'CONTENT_TYPE' => 'application/json'
387
- last_response.status.should == (verb == :post ? 201 : 200)
388
- last_response.body.should eql MultiJson.dump(object)
389
- last_request.params.should eql Hash.new
385
+ expect(last_response.status).to eq(verb == :post ? 201 : 200)
386
+ expect(last_response.body).to eql MultiJson.dump(object)
387
+ expect(last_request.params).to eql Hash.new
390
388
  end
391
389
  it "stores input in api.request.input" do
392
390
  subject.format :json
@@ -394,8 +392,8 @@ describe Grape::API do
394
392
  env['api.request.input']
395
393
  end
396
394
  send verb, '/', MultiJson.dump(object), 'CONTENT_TYPE' => 'application/json'
397
- last_response.status.should == (verb == :post ? 201 : 200)
398
- last_response.body.should eql MultiJson.dump(object).to_json
395
+ expect(last_response.status).to eq(verb == :post ? 201 : 200)
396
+ expect(last_response.body).to eql MultiJson.dump(object).to_json
399
397
  end
400
398
  context "chunked transfer encoding" do
401
399
  it "stores input in api.request.input" do
@@ -404,8 +402,8 @@ describe Grape::API do
404
402
  env['api.request.input']
405
403
  end
406
404
  send verb, '/', MultiJson.dump(object), 'CONTENT_TYPE' => 'application/json', 'HTTP_TRANSFER_ENCODING' => 'chunked', 'CONTENT_LENGTH' => nil
407
- last_response.status.should == (verb == :post ? 201 : 200)
408
- last_response.body.should eql MultiJson.dump(object).to_json
405
+ expect(last_response.status).to eq(verb == :post ? 201 : 200)
406
+ expect(last_response.body).to eql MultiJson.dump(object).to_json
409
407
  end
410
408
  end
411
409
  end
@@ -426,15 +424,15 @@ describe Grape::API do
426
424
  end
427
425
 
428
426
  get '/1'
429
- last_response.body.should eql 'ola'
427
+ expect(last_response.body).to eql 'ola'
430
428
  post '/1'
431
- last_response.body.should eql 'ola'
429
+ expect(last_response.body).to eql 'ola'
432
430
  get '/1/first'
433
- last_response.body.should eql 'first'
431
+ expect(last_response.body).to eql 'first'
434
432
  post '/1/first'
435
- last_response.body.should eql 'first'
433
+ expect(last_response.body).to eql 'first'
436
434
  get '/1/first/second'
437
- last_response.body.should eql 'second'
435
+ expect(last_response.body).to eql 'second'
438
436
 
439
437
  end
440
438
 
@@ -445,7 +443,7 @@ describe Grape::API do
445
443
 
446
444
  %w(get post put delete options patch).each do |m|
447
445
  send(m, '/abc')
448
- last_response.body.should eql 'lol'
446
+ expect(last_response.body).to eql 'lol'
449
447
  end
450
448
  end
451
449
 
@@ -456,10 +454,10 @@ describe Grape::API do
456
454
  verb
457
455
  end
458
456
  send(verb, '/example')
459
- last_response.body.should eql verb == 'head' ? '' : verb
457
+ expect(last_response.body).to eql verb == 'head' ? '' : verb
460
458
  # Call it with a method other than the properly constrained one.
461
459
  send(used_verb = verbs[(verbs.index(verb) + 2) % verbs.size], '/example')
462
- last_response.status.should eql used_verb == 'options' ? 204 : 405
460
+ expect(last_response.status).to eql used_verb == 'options' ? 204 : 405
463
461
  end
464
462
  end
465
463
 
@@ -469,8 +467,8 @@ describe Grape::API do
469
467
  end
470
468
 
471
469
  post '/example'
472
- last_response.status.should eql 201
473
- last_response.body.should eql 'Created'
470
+ expect(last_response.status).to eql 201
471
+ expect(last_response.body).to eql 'Created'
474
472
  end
475
473
 
476
474
  it 'returns a 405 for an unsupported method with an X-Custom-Header' do
@@ -479,9 +477,9 @@ describe Grape::API do
479
477
  "example"
480
478
  end
481
479
  put '/example'
482
- last_response.status.should eql 405
483
- last_response.body.should eql ''
484
- last_response.headers['X-Custom-Header'].should eql 'foo'
480
+ expect(last_response.status).to eql 405
481
+ expect(last_response.body).to eql ''
482
+ expect(last_response.headers['X-Custom-Header']).to eql 'foo'
485
483
  end
486
484
 
487
485
  specify '405 responses includes an Allow header specifying supported methods' do
@@ -492,7 +490,7 @@ describe Grape::API do
492
490
  "example"
493
491
  end
494
492
  put '/example'
495
- last_response.headers['Allow'].should eql 'OPTIONS, GET, POST, HEAD'
493
+ expect(last_response.headers['Allow']).to eql 'OPTIONS, GET, POST, HEAD'
496
494
  end
497
495
 
498
496
  specify '405 responses includes an Content-Type header' do
@@ -503,7 +501,7 @@ describe Grape::API do
503
501
  "example"
504
502
  end
505
503
  put '/example'
506
- last_response.headers['Content-Type'].should eql 'text/plain'
504
+ expect(last_response.headers['Content-Type']).to eql 'text/plain'
507
505
  end
508
506
 
509
507
  it 'adds an OPTIONS route that returns a 204, an Allow header and a X-Custom-Header' do
@@ -512,10 +510,10 @@ describe Grape::API do
512
510
  "example"
513
511
  end
514
512
  options '/example'
515
- last_response.status.should eql 204
516
- last_response.body.should eql ''
517
- last_response.headers['Allow'].should eql 'OPTIONS, GET, HEAD'
518
- last_response.headers['X-Custom-Header'].should eql 'foo'
513
+ expect(last_response.status).to eql 204
514
+ expect(last_response.body).to eql ''
515
+ expect(last_response.headers['Allow']).to eql 'OPTIONS, GET, HEAD'
516
+ expect(last_response.headers['X-Custom-Header']).to eql 'foo'
519
517
  end
520
518
 
521
519
  it 'allows HEAD on a GET request' do
@@ -523,8 +521,8 @@ describe Grape::API do
523
521
  "example"
524
522
  end
525
523
  head '/example'
526
- last_response.status.should eql 200
527
- last_response.body.should eql ''
524
+ expect(last_response.status).to eql 200
525
+ expect(last_response.body).to eql ''
528
526
  end
529
527
 
530
528
  it 'overwrites the default HEAD request' do
@@ -535,7 +533,7 @@ describe Grape::API do
535
533
  "example"
536
534
  end
537
535
  head '/example'
538
- last_response.status.should eql 400
536
+ expect(last_response.status).to eql 400
539
537
  end
540
538
  end
541
539
 
@@ -548,13 +546,13 @@ describe Grape::API do
548
546
  end
549
547
  it 'options does not contain HEAD' do
550
548
  options '/example'
551
- last_response.status.should eql 204
552
- last_response.body.should eql ''
553
- last_response.headers['Allow'].should eql 'OPTIONS, GET'
549
+ expect(last_response.status).to eql 204
550
+ expect(last_response.body).to eql ''
551
+ expect(last_response.headers['Allow']).to eql 'OPTIONS, GET'
554
552
  end
555
553
  it 'does not allow HEAD on a GET request' do
556
554
  head '/example'
557
- last_response.status.should eql 405
555
+ expect(last_response.status).to eql 405
558
556
  end
559
557
  end
560
558
 
@@ -567,7 +565,7 @@ describe Grape::API do
567
565
  end
568
566
  it 'options does not exist' do
569
567
  options '/example'
570
- last_response.status.should eql 405
568
+ expect(last_response.status).to eql 405
571
569
  end
572
570
  end
573
571
 
@@ -580,7 +578,7 @@ describe Grape::API do
580
578
  end
581
579
 
582
580
  get '/'
583
- last_response.body.should eql 'first second'
581
+ expect(last_response.body).to eql 'first second'
584
582
  end
585
583
 
586
584
  it 'adds a before filter to current and child namespaces only' do
@@ -601,11 +599,11 @@ describe Grape::API do
601
599
  end
602
600
 
603
601
  get '/'
604
- last_response.body.should eql 'root - '
602
+ expect(last_response.body).to eql 'root - '
605
603
  get '/blah'
606
- last_response.body.should eql 'blah - foo'
604
+ expect(last_response.body).to eql 'blah - foo'
607
605
  get '/blah/bar'
608
- last_response.body.should eql 'blah - bar - foo'
606
+ expect(last_response.body).to eql 'blah - bar - foo'
609
607
  end
610
608
 
611
609
  it 'adds a after_validation filter' do
@@ -619,7 +617,7 @@ describe Grape::API do
619
617
  end
620
618
 
621
619
  get '/', id: "32"
622
- last_response.body.should eql 'first 32:Fixnum second'
620
+ expect(last_response.body).to eql 'first 32:Fixnum second'
623
621
  end
624
622
 
625
623
  it 'adds a after filter' do
@@ -630,9 +628,9 @@ describe Grape::API do
630
628
  @var ||= 'default'
631
629
  end
632
630
 
633
- m.should_receive(:do_something!).exactly(2).times
631
+ expect(m).to receive(:do_something!).exactly(2).times
634
632
  get '/'
635
- last_response.body.should eql 'default'
633
+ expect(last_response.body).to eql 'default'
636
634
  end
637
635
 
638
636
  it 'calls all filters when validation passes' do
@@ -654,14 +652,14 @@ describe Grape::API do
654
652
  end
655
653
  end
656
654
 
657
- a.should_receive(:do_something!).exactly(1).times
658
- b.should_receive(:do_something!).exactly(1).times
659
- c.should_receive(:do_something!).exactly(1).times
660
- d.should_receive(:do_something!).exactly(1).times
655
+ expect(a).to receive(:do_something!).exactly(1).times
656
+ expect(b).to receive(:do_something!).exactly(1).times
657
+ expect(c).to receive(:do_something!).exactly(1).times
658
+ expect(d).to receive(:do_something!).exactly(1).times
661
659
 
662
660
  get '/123'
663
- last_response.status.should eql 200
664
- last_response.body.should eql 'got it'
661
+ expect(last_response.status).to eql 200
662
+ expect(last_response.body).to eql 'got it'
665
663
  end
666
664
 
667
665
  it 'calls only before filters when validation fails' do
@@ -683,14 +681,14 @@ describe Grape::API do
683
681
  end
684
682
  end
685
683
 
686
- a.should_receive(:do_something!).exactly(1).times
687
- b.should_receive(:do_something!).exactly(1).times
688
- c.should_receive(:do_something!).exactly(0).times
689
- d.should_receive(:do_something!).exactly(0).times
684
+ expect(a).to receive(:do_something!).exactly(1).times
685
+ expect(b).to receive(:do_something!).exactly(1).times
686
+ expect(c).to receive(:do_something!).exactly(0).times
687
+ expect(d).to receive(:do_something!).exactly(0).times
690
688
 
691
689
  get '/abc'
692
- last_response.status.should eql 400
693
- last_response.body.should eql 'id is invalid'
690
+ expect(last_response.status).to eql 400
691
+ expect(last_response.body).to eql 'id is invalid'
694
692
  end
695
693
 
696
694
  it 'calls filters in the correct order' do
@@ -713,14 +711,14 @@ describe Grape::API do
713
711
  end
714
712
  end
715
713
 
716
- a.should_receive(:here).with(1).exactly(1).times
717
- b.should_receive(:here).with(2).exactly(1).times
718
- c.should_receive(:here).with(3).exactly(1).times
719
- d.should_receive(:here).with(4).exactly(1).times
714
+ expect(a).to receive(:here).with(1).exactly(1).times
715
+ expect(b).to receive(:here).with(2).exactly(1).times
716
+ expect(c).to receive(:here).with(3).exactly(1).times
717
+ expect(d).to receive(:here).with(4).exactly(1).times
720
718
 
721
719
  get '/123'
722
- last_response.status.should eql 200
723
- last_response.body.should eql 'got it'
720
+ expect(last_response.status).to eql 200
721
+ expect(last_response.body).to eql 'got it'
724
722
  end
725
723
  end
726
724
 
@@ -731,32 +729,32 @@ describe Grape::API do
731
729
 
732
730
  it 'sets content type for txt format' do
733
731
  get '/foo'
734
- last_response.headers['Content-Type'].should eql 'text/plain'
732
+ expect(last_response.headers['Content-Type']).to eql 'text/plain'
735
733
  end
736
734
 
737
735
  it 'sets content type for json' do
738
736
  get '/foo.json'
739
- last_response.headers['Content-Type'].should eql 'application/json'
737
+ expect(last_response.headers['Content-Type']).to eql 'application/json'
740
738
  end
741
739
 
742
740
  it 'sets content type for error' do
743
741
  subject.get('/error') { error!('error in plain text', 500) }
744
742
  get '/error'
745
- last_response.headers['Content-Type'].should eql 'text/plain'
743
+ expect(last_response.headers['Content-Type']).to eql 'text/plain'
746
744
  end
747
745
 
748
746
  it 'sets content type for error' do
749
747
  subject.format :json
750
748
  subject.get('/error') { error!('error in json', 500) }
751
749
  get '/error.json'
752
- last_response.headers['Content-Type'].should eql 'application/json'
750
+ expect(last_response.headers['Content-Type']).to eql 'application/json'
753
751
  end
754
752
 
755
753
  it 'sets content type for xml' do
756
754
  subject.format :xml
757
755
  subject.get('/error') { error!('error in xml', 500) }
758
756
  get '/error.xml'
759
- last_response.headers['Content-Type'].should eql 'application/xml'
757
+ expect(last_response.headers['Content-Type']).to eql 'application/xml'
760
758
  end
761
759
 
762
760
  context 'with a custom content_type' do
@@ -770,12 +768,48 @@ describe Grape::API do
770
768
 
771
769
  it 'sets content type' do
772
770
  get '/custom.custom'
773
- last_response.headers['Content-Type'].should eql 'application/custom'
771
+ expect(last_response.headers['Content-Type']).to eql 'application/custom'
774
772
  end
775
773
 
776
774
  it 'sets content type for error' do
777
775
  get '/error.custom'
778
- last_response.headers['Content-Type'].should eql 'application/custom'
776
+ expect(last_response.headers['Content-Type']).to eql 'application/custom'
777
+ end
778
+ end
779
+
780
+ context 'env["api.format"]' do
781
+ before do
782
+ subject.post "attachment" do
783
+ filename = params[:file][:filename]
784
+ content_type MIME::Types.type_for(filename)[0].to_s
785
+ env['api.format'] = :binary # there's no formatter for :binary, data will be returned "as is"
786
+ header "Content-Disposition", "attachment; filename*=UTF-8''#{URI.escape(filename)}"
787
+ params[:file][:tempfile].read
788
+ end
789
+ end
790
+
791
+ ['/attachment.png', 'attachment'].each do |url|
792
+ it "uploads and downloads a PNG file via #{url}" do
793
+ image_filename = "grape.png"
794
+ post url, file: Rack::Test::UploadedFile.new(image_filename, 'image/png', true)
795
+ last_response.status.should == 201
796
+ last_response.headers['Content-Type'].should == "image/png"
797
+ last_response.headers['Content-Disposition'].should == "attachment; filename*=UTF-8''grape.png"
798
+ File.open(image_filename, 'rb') do |io|
799
+ last_response.body.should eq io.read
800
+ end
801
+ end
802
+ end
803
+
804
+ it "uploads and downloads a Ruby file" do
805
+ filename = __FILE__
806
+ post "/attachment.rb", file: Rack::Test::UploadedFile.new(filename, 'application/x-ruby', true)
807
+ last_response.status.should == 201
808
+ last_response.headers['Content-Type'].should == "application/x-ruby"
809
+ last_response.headers['Content-Disposition'].should == "attachment; filename*=UTF-8''api_spec.rb"
810
+ File.open(filename, 'rb') do |io|
811
+ last_response.body.should eq io.read
812
+ end
779
813
  end
780
814
  end
781
815
  end
@@ -801,21 +835,21 @@ describe Grape::API do
801
835
  describe '.middleware' do
802
836
  it 'includes middleware arguments from settings' do
803
837
  settings = Grape::Util::HashStack.new
804
- settings.stub(:stack).and_return([{ middleware: [[ApiSpec::PhonyMiddleware, 'abc', 123]] }])
805
- subject.stub(:settings).and_return(settings)
806
- subject.middleware.should eql [[ApiSpec::PhonyMiddleware, 'abc', 123]]
838
+ allow(settings).to receive(:stack).and_return([{ middleware: [[ApiSpec::PhonyMiddleware, 'abc', 123]] }])
839
+ allow(subject).to receive(:settings).and_return(settings)
840
+ expect(subject.middleware).to eql [[ApiSpec::PhonyMiddleware, 'abc', 123]]
807
841
  end
808
842
 
809
843
  it 'includes all middleware from stacked settings' do
810
844
  settings = Grape::Util::HashStack.new
811
- settings.stub(:stack).and_return [
845
+ allow(settings).to receive(:stack).and_return [
812
846
  { middleware: [[ApiSpec::PhonyMiddleware, 123], [ApiSpec::PhonyMiddleware, 'abc']] },
813
847
  { middleware: [[ApiSpec::PhonyMiddleware, 'foo']] }
814
848
  ]
815
849
 
816
- subject.stub(:settings).and_return(settings)
850
+ allow(subject).to receive(:settings).and_return(settings)
817
851
 
818
- subject.middleware.should eql [
852
+ expect(subject.middleware).to eql [
819
853
  [ApiSpec::PhonyMiddleware, 123],
820
854
  [ApiSpec::PhonyMiddleware, 'abc'],
821
855
  [ApiSpec::PhonyMiddleware, 'foo']
@@ -826,7 +860,7 @@ describe Grape::API do
826
860
  describe '.use' do
827
861
  it 'adds middleware' do
828
862
  subject.use ApiSpec::PhonyMiddleware, 123
829
- subject.middleware.should eql [[ApiSpec::PhonyMiddleware, 123]]
863
+ expect(subject.middleware).to eql [[ApiSpec::PhonyMiddleware, 123]]
830
864
  end
831
865
 
832
866
  it 'does not show up outside the namespace' do
@@ -836,7 +870,7 @@ describe Grape::API do
836
870
  middleware.should == [[ApiSpec::PhonyMiddleware, 123], [ApiSpec::PhonyMiddleware, 'abc']]
837
871
  end
838
872
 
839
- subject.middleware.should eql [[ApiSpec::PhonyMiddleware, 123]]
873
+ expect(subject.middleware).to eql [[ApiSpec::PhonyMiddleware, 123]]
840
874
  end
841
875
 
842
876
  it 'calls the middleware' do
@@ -846,13 +880,13 @@ describe Grape::API do
846
880
  end
847
881
 
848
882
  get '/'
849
- last_response.body.should eql 'hello'
883
+ expect(last_response.body).to eql 'hello'
850
884
  end
851
885
 
852
886
  it 'adds a block if one is given' do
853
887
  block = lambda {}
854
888
  subject.use ApiSpec::PhonyMiddleware, &block
855
- subject.middleware.should eql [[ApiSpec::PhonyMiddleware, block]]
889
+ expect(subject.middleware).to eql [[ApiSpec::PhonyMiddleware, block]]
856
890
  end
857
891
 
858
892
  it 'uses a block if one is given' do
@@ -863,7 +897,7 @@ describe Grape::API do
863
897
  end
864
898
 
865
899
  get '/'
866
- last_response.body.should == 'true'
900
+ expect(last_response.body).to eq('true')
867
901
  end
868
902
 
869
903
  it 'does not destroy the middleware settings on multiple runs' do
@@ -875,7 +909,7 @@ describe Grape::API do
875
909
 
876
910
  2.times do
877
911
  get '/'
878
- last_response.body.should == 'true'
912
+ expect(last_response.body).to eq('true')
879
913
  end
880
914
  end
881
915
 
@@ -889,8 +923,8 @@ describe Grape::API do
889
923
  subject.get "/" do
890
924
  end
891
925
  get "/"
892
- last_response.status.should == 400
893
- last_response.body.should == "Caught in the Net"
926
+ expect(last_response.status).to eq(400)
927
+ expect(last_response.body).to eq("Caught in the Net")
894
928
  end
895
929
  end
896
930
  end
@@ -901,9 +935,9 @@ describe Grape::API do
901
935
  end
902
936
  subject.get(:hello) { "Hello, world." }
903
937
  get '/hello'
904
- last_response.status.should eql 401
938
+ expect(last_response.status).to eql 401
905
939
  get '/hello', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('allow', 'whatever')
906
- last_response.status.should eql 200
940
+ expect(last_response.status).to eql 200
907
941
  end
908
942
 
909
943
  it 'is scopable' do
@@ -917,9 +951,9 @@ describe Grape::API do
917
951
  end
918
952
 
919
953
  get '/hello'
920
- last_response.status.should eql 200
954
+ expect(last_response.status).to eql 200
921
955
  get '/admin/hello'
922
- last_response.status.should eql 401
956
+ expect(last_response.status).to eql 401
923
957
  end
924
958
 
925
959
  it 'is callable via .auth as well' do
@@ -929,9 +963,9 @@ describe Grape::API do
929
963
 
930
964
  subject.get(:hello) { "Hello, world." }
931
965
  get '/hello'
932
- last_response.status.should eql 401
966
+ expect(last_response.status).to eql 401
933
967
  get '/hello', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('allow', 'whatever')
934
- last_response.status.should eql 200
968
+ expect(last_response.status).to eql 200
935
969
  end
936
970
 
937
971
  it 'has access to the current endpoint' do
@@ -945,7 +979,7 @@ describe Grape::API do
945
979
 
946
980
  subject.get(:hello) { "Hello, world." }
947
981
  get '/hello', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('allow', 'whatever')
948
- basic_auth_context.should be_an_instance_of(Grape::Endpoint)
982
+ expect(basic_auth_context).to be_an_instance_of(Grape::Endpoint)
949
983
  end
950
984
 
951
985
  it 'has access to helper methods' do
@@ -961,9 +995,9 @@ describe Grape::API do
961
995
 
962
996
  subject.get(:hello) { "Hello, world." }
963
997
  get '/hello', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('allow', 'whatever')
964
- last_response.status.should eql 200
998
+ expect(last_response.status).to eql 200
965
999
  get '/hello', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('disallow', 'whatever')
966
- last_response.status.should eql 401
1000
+ expect(last_response.status).to eql 401
967
1001
  end
968
1002
 
969
1003
  it 'can set instance variables accessible to routes' do
@@ -975,27 +1009,27 @@ describe Grape::API do
975
1009
 
976
1010
  subject.get(:hello) { @hello }
977
1011
  get '/hello', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('allow', 'whatever')
978
- last_response.status.should eql 200
979
- last_response.body.should eql "Hello, world."
1012
+ expect(last_response.status).to eql 200
1013
+ expect(last_response.body).to eql "Hello, world."
980
1014
  end
981
1015
  end
982
1016
 
983
1017
  describe '.logger' do
984
1018
  it 'returns an instance of Logger class by default' do
985
- subject.logger.class.should eql Logger
1019
+ expect(subject.logger.class).to eql Logger
986
1020
  end
987
1021
 
988
1022
  it 'allows setting a custom logger' do
989
1023
  mylogger = Class.new
990
1024
  subject.logger mylogger
991
- mylogger.should_receive(:info).exactly(1).times
1025
+ expect(mylogger).to receive(:info).exactly(1).times
992
1026
  subject.logger.info "this will be logged"
993
1027
  end
994
1028
 
995
1029
  it "defaults to a standard logger log format" do
996
1030
  t = Time.at(100)
997
- Time.stub(:now).and_return(t)
998
- STDOUT.should_receive(:write).with("I, [#{Logger::Formatter.new.send(:format_datetime, t)}\##{Process.pid}] INFO -- : this will be logged\n")
1031
+ allow(Time).to receive(:now).and_return(t)
1032
+ expect(STDOUT).to receive(:write).with("I, [#{Logger::Formatter.new.send(:format_datetime, t)}\##{Process.pid}] INFO -- : this will be logged\n")
999
1033
  subject.logger.info "this will be logged"
1000
1034
  end
1001
1035
  end
@@ -1013,7 +1047,7 @@ describe Grape::API do
1013
1047
  end
1014
1048
 
1015
1049
  get '/howdy'
1016
- last_response.body.should eql 'Hello, world.'
1050
+ expect(last_response.body).to eql 'Hello, world.'
1017
1051
  end
1018
1052
 
1019
1053
  it 'is scopable' do
@@ -1040,9 +1074,9 @@ describe Grape::API do
1040
1074
  end
1041
1075
 
1042
1076
  get '/generic'
1043
- last_response.body.should eql 'always there:false'
1077
+ expect(last_response.body).to eql 'always there:false'
1044
1078
  get '/admin/secret'
1045
- last_response.body.should eql 'always there:only in admin'
1079
+ expect(last_response.body).to eql 'always there:only in admin'
1046
1080
  end
1047
1081
 
1048
1082
  it 'is reopenable' do
@@ -1062,7 +1096,7 @@ describe Grape::API do
1062
1096
  [one, two]
1063
1097
  end
1064
1098
 
1065
- lambda { get '/howdy' }.should_not raise_error
1099
+ expect { get '/howdy' }.not_to raise_error
1066
1100
  end
1067
1101
 
1068
1102
  it 'allows for modules' do
@@ -1078,7 +1112,7 @@ describe Grape::API do
1078
1112
  end
1079
1113
 
1080
1114
  get '/howdy'
1081
- last_response.body.should eql 'Hello, world.'
1115
+ expect(last_response.body).to eql 'Hello, world.'
1082
1116
  end
1083
1117
 
1084
1118
  it 'allows multiple calls with modules and blocks' do
@@ -1100,7 +1134,7 @@ describe Grape::API do
1100
1134
  subject.get 'howdy' do
1101
1135
  [one, two, three]
1102
1136
  end
1103
- lambda { get '/howdy' }.should_not raise_error
1137
+ expect { get '/howdy' }.not_to raise_error
1104
1138
  end
1105
1139
  end
1106
1140
 
@@ -1122,13 +1156,13 @@ describe Grape::API do
1122
1156
  end
1123
1157
 
1124
1158
  get '/new/abc'
1125
- last_response.status.should eql 404
1159
+ expect(last_response.status).to eql 404
1126
1160
  get '/legacy/abc'
1127
- last_response.status.should eql 200
1161
+ expect(last_response.status).to eql 200
1128
1162
  get '/legacy/def'
1129
- last_response.status.should eql 404
1163
+ expect(last_response.status).to eql 404
1130
1164
  get '/new/def'
1131
- last_response.status.should eql 200
1165
+ expect(last_response.status).to eql 200
1132
1166
  end
1133
1167
  end
1134
1168
 
@@ -1137,7 +1171,7 @@ describe Grape::API do
1137
1171
  subject.get '/exception' do
1138
1172
  raise "rain!"
1139
1173
  end
1140
- lambda { get '/exception' }.should raise_error
1174
+ expect { get '/exception' }.to raise_error
1141
1175
  end
1142
1176
 
1143
1177
  it 'rescues all errors if rescue_from :all is called' do
@@ -1146,7 +1180,7 @@ describe Grape::API do
1146
1180
  raise "rain!"
1147
1181
  end
1148
1182
  get '/exception'
1149
- last_response.status.should eql 500
1183
+ expect(last_response.status).to eql 500
1150
1184
  end
1151
1185
 
1152
1186
  it 'rescues only certain errors if rescue_from is called with specific errors' do
@@ -1155,9 +1189,9 @@ describe Grape::API do
1155
1189
  subject.get('/unrescued') { raise "beefcake" }
1156
1190
 
1157
1191
  get '/rescued'
1158
- last_response.status.should eql 500
1192
+ expect(last_response.status).to eql 500
1159
1193
 
1160
- lambda { get '/unrescued' }.should raise_error
1194
+ expect { get '/unrescued' }.to raise_error
1161
1195
  end
1162
1196
 
1163
1197
  context 'CustomError subclass of Grape::Exceptions::Base' do
@@ -1168,7 +1202,7 @@ describe Grape::API do
1168
1202
  it 'does not re-raise exceptions of type Grape::Exceptions::Base' do
1169
1203
  subject.get('/custom_exception') { raise CustomError }
1170
1204
 
1171
- lambda { get '/custom_exception' }.should_not raise_error
1205
+ expect { get '/custom_exception' }.not_to raise_error
1172
1206
  end
1173
1207
 
1174
1208
  it 'rescues custom grape exceptions' do
@@ -1180,15 +1214,15 @@ describe Grape::API do
1180
1214
  end
1181
1215
 
1182
1216
  get '/custom_error'
1183
- last_response.status.should == 400
1184
- last_response.body.should == 'New Error'
1217
+ expect(last_response.status).to eq(400)
1218
+ expect(last_response.body).to eq('New Error')
1185
1219
  end
1186
1220
  end
1187
1221
 
1188
1222
  it 'can rescue exceptions raised in the formatter' do
1189
1223
  formatter = double(:formatter)
1190
- formatter.stub(:call) { raise StandardError }
1191
- Grape::Formatter::Base.stub(:formatter_for) { formatter }
1224
+ allow(formatter).to receive(:call) { raise StandardError }
1225
+ allow(Grape::Formatter::Base).to receive(:formatter_for) { formatter }
1192
1226
 
1193
1227
  subject.rescue_from :all do |e|
1194
1228
  rack_response('Formatter Error', 500)
@@ -1196,8 +1230,8 @@ describe Grape::API do
1196
1230
  subject.get('/formatter_exception') { 'Hello world' }
1197
1231
 
1198
1232
  get '/formatter_exception'
1199
- last_response.status.should eql 500
1200
- last_response.body.should == 'Formatter Error'
1233
+ expect(last_response.status).to eql 500
1234
+ expect(last_response.body).to eq('Formatter Error')
1201
1235
  end
1202
1236
  end
1203
1237
 
@@ -1210,8 +1244,8 @@ describe Grape::API do
1210
1244
  raise "rain!"
1211
1245
  end
1212
1246
  get '/exception'
1213
- last_response.status.should eql 202
1214
- last_response.body.should == 'rescued from rain!'
1247
+ expect(last_response.status).to eql 202
1248
+ expect(last_response.body).to eq('rescued from rain!')
1215
1249
  end
1216
1250
 
1217
1251
  context 'custom errors' do
@@ -1229,8 +1263,8 @@ describe Grape::API do
1229
1263
  raise ConnectionError
1230
1264
  end
1231
1265
  get '/exception'
1232
- last_response.status.should eql 500
1233
- last_response.body.should == 'rescued from ConnectionError'
1266
+ expect(last_response.status).to eql 500
1267
+ expect(last_response.body).to eq('rescued from ConnectionError')
1234
1268
  end
1235
1269
  it 'rescues a specific error' do
1236
1270
  subject.rescue_from ConnectionError do |e|
@@ -1240,8 +1274,19 @@ describe Grape::API do
1240
1274
  raise ConnectionError
1241
1275
  end
1242
1276
  get '/exception'
1243
- last_response.status.should eql 500
1244
- last_response.body.should == 'rescued from ConnectionError'
1277
+ expect(last_response.status).to eql 500
1278
+ expect(last_response.body).to eq('rescued from ConnectionError')
1279
+ end
1280
+ it 'rescues a subclass of an error by default' do
1281
+ subject.rescue_from RuntimeError do |e|
1282
+ rack_response("rescued from #{e.class.name}", 500)
1283
+ end
1284
+ subject.get '/exception' do
1285
+ raise ConnectionError
1286
+ end
1287
+ get '/exception'
1288
+ expect(last_response.status).to eql 500
1289
+ expect(last_response.body).to eq('rescued from ConnectionError')
1245
1290
  end
1246
1291
  it 'rescues multiple specific errors' do
1247
1292
  subject.rescue_from ConnectionError do |e|
@@ -1257,11 +1302,11 @@ describe Grape::API do
1257
1302
  raise DatabaseError
1258
1303
  end
1259
1304
  get '/connection'
1260
- last_response.status.should eql 500
1261
- last_response.body.should == 'rescued from ConnectionError'
1305
+ expect(last_response.status).to eql 500
1306
+ expect(last_response.body).to eq('rescued from ConnectionError')
1262
1307
  get '/database'
1263
- last_response.status.should eql 500
1264
- last_response.body.should == 'rescued from DatabaseError'
1308
+ expect(last_response.status).to eql 500
1309
+ expect(last_response.body).to eq('rescued from DatabaseError')
1265
1310
  end
1266
1311
  it 'does not rescue a different error' do
1267
1312
  subject.rescue_from RuntimeError do |e|
@@ -1270,7 +1315,7 @@ describe Grape::API do
1270
1315
  subject.get '/uncaught' do
1271
1316
  raise CommunicationError
1272
1317
  end
1273
- lambda { get '/uncaught' }.should raise_error(CommunicationError)
1318
+ expect { get '/uncaught' }.to raise_error(CommunicationError)
1274
1319
  end
1275
1320
  end
1276
1321
  end
@@ -1283,8 +1328,8 @@ describe Grape::API do
1283
1328
  subject.get('/rescue_lambda') { raise ArgumentError }
1284
1329
 
1285
1330
  get '/rescue_lambda'
1286
- last_response.status.should == 400
1287
- last_response.body.should == "rescued with a lambda"
1331
+ expect(last_response.status).to eq(400)
1332
+ expect(last_response.body).to eq("rescued with a lambda")
1288
1333
  end
1289
1334
 
1290
1335
  it 'can execute the lambda with an argument' do
@@ -1294,8 +1339,8 @@ describe Grape::API do
1294
1339
  subject.get('/rescue_lambda') { raise ArgumentError, 'lambda takes an argument' }
1295
1340
 
1296
1341
  get '/rescue_lambda'
1297
- last_response.status.should == 400
1298
- last_response.body.should == 'lambda takes an argument'
1342
+ expect(last_response.status).to eq(400)
1343
+ expect(last_response.body).to eq('lambda takes an argument')
1299
1344
  end
1300
1345
  end
1301
1346
 
@@ -1309,8 +1354,8 @@ describe Grape::API do
1309
1354
  subject.get('/rescue_method') { raise ArgumentError }
1310
1355
 
1311
1356
  get '/rescue_method'
1312
- last_response.status.should == 400
1313
- last_response.body.should == 'rescued with a method'
1357
+ expect(last_response.status).to eq(400)
1358
+ expect(last_response.body).to eq('rescued with a method')
1314
1359
  end
1315
1360
  end
1316
1361
 
@@ -1337,10 +1382,22 @@ describe Grape::API do
1337
1382
  end
1338
1383
 
1339
1384
  get '/caught_child'
1340
- last_response.status.should eql 500
1385
+ expect(last_response.status).to eql 500
1341
1386
  get '/caught_parent'
1342
- last_response.status.should eql 500
1343
- lambda { get '/uncaught_parent' }.should raise_error(StandardError)
1387
+ expect(last_response.status).to eql 500
1388
+ expect { get '/uncaught_parent' }.to raise_error(StandardError)
1389
+ end
1390
+
1391
+ it 'sets rescue_subclasses to true by default' do
1392
+ subject.rescue_from APIErrors::ParentError do |e|
1393
+ rack_response("rescued from #{e.class.name}", 500)
1394
+ end
1395
+ subject.get '/caught_child' do
1396
+ raise APIErrors::ChildError
1397
+ end
1398
+
1399
+ get '/caught_child'
1400
+ expect(last_response.status).to eql 500
1344
1401
  end
1345
1402
 
1346
1403
  it 'does not rescue child errors if rescue_subclasses is false' do
@@ -1350,7 +1407,7 @@ describe Grape::API do
1350
1407
  subject.get '/uncaught' do
1351
1408
  raise APIErrors::ChildError
1352
1409
  end
1353
- lambda { get '/uncaught' }.should raise_error(APIErrors::ChildError)
1410
+ expect { get '/uncaught' }.to raise_error(APIErrors::ChildError)
1354
1411
  end
1355
1412
  end
1356
1413
 
@@ -1362,7 +1419,7 @@ describe Grape::API do
1362
1419
  raise "rain!"
1363
1420
  end
1364
1421
  get '/exception'
1365
- last_response.body.should eql "rain!"
1422
+ expect(last_response.body).to eql "rain!"
1366
1423
  end
1367
1424
 
1368
1425
  it 'rescues all errors and return :txt with backtrace' do
@@ -1372,7 +1429,7 @@ describe Grape::API do
1372
1429
  raise "rain!"
1373
1430
  end
1374
1431
  get '/exception'
1375
- last_response.body.start_with?("rain!\r\n").should be true
1432
+ expect(last_response.body.start_with?("rain!\r\n")).to be true
1376
1433
  end
1377
1434
 
1378
1435
  it 'rescues all errors with a default formatter' do
@@ -1383,7 +1440,7 @@ describe Grape::API do
1383
1440
  raise "rain!"
1384
1441
  end
1385
1442
  get '/exception.foo'
1386
- last_response.body.should start_with "rain!"
1443
+ expect(last_response.body).to start_with "rain!"
1387
1444
  end
1388
1445
 
1389
1446
  it 'defaults the error formatter to format' do
@@ -1395,9 +1452,9 @@ describe Grape::API do
1395
1452
  raise "rain!"
1396
1453
  end
1397
1454
  get '/exception.json'
1398
- last_response.body.should == '{"error":"rain!"}'
1455
+ expect(last_response.body).to eq('{"error":"rain!"}')
1399
1456
  get '/exception.foo'
1400
- last_response.body.should == '{"error":"rain!"}'
1457
+ expect(last_response.body).to eq('{"error":"rain!"}')
1401
1458
  end
1402
1459
 
1403
1460
  context 'class' do
@@ -1415,7 +1472,7 @@ describe Grape::API do
1415
1472
  raise "rain!"
1416
1473
  end
1417
1474
  get '/exception'
1418
- last_response.body.should == "message: rain! @backtrace"
1475
+ expect(last_response.body).to eq("message: rain! @backtrace")
1419
1476
  end
1420
1477
  end
1421
1478
 
@@ -1435,7 +1492,7 @@ describe Grape::API do
1435
1492
  subject.get('/exception') { raise "rain!" }
1436
1493
 
1437
1494
  get '/exception'
1438
- last_response.body.should == 'message: rain! @backtrace'
1495
+ expect(last_response.body).to eq('message: rain! @backtrace')
1439
1496
  end
1440
1497
  end
1441
1498
  end
@@ -1447,7 +1504,7 @@ describe Grape::API do
1447
1504
  raise "rain!"
1448
1505
  end
1449
1506
  get '/exception'
1450
- last_response.body.should eql '{"error":"rain!"}'
1507
+ expect(last_response.body).to eql '{"error":"rain!"}'
1451
1508
  end
1452
1509
  it 'rescues all errors and return :json with backtrace' do
1453
1510
  subject.rescue_from :all, backtrace: true
@@ -1457,8 +1514,8 @@ describe Grape::API do
1457
1514
  end
1458
1515
  get '/exception'
1459
1516
  json = MultiJson.load(last_response.body)
1460
- json["error"].should eql 'rain!'
1461
- json["backtrace"].length.should > 0
1517
+ expect(json["error"]).to eql 'rain!'
1518
+ expect(json["backtrace"].length).to be > 0
1462
1519
  end
1463
1520
  it 'rescues error! and return txt' do
1464
1521
  subject.format :txt
@@ -1466,7 +1523,7 @@ describe Grape::API do
1466
1523
  error!("Access Denied", 401)
1467
1524
  end
1468
1525
  get '/error'
1469
- last_response.body.should eql "Access Denied"
1526
+ expect(last_response.body).to eql "Access Denied"
1470
1527
  end
1471
1528
  it 'rescues error! and return json' do
1472
1529
  subject.format :json
@@ -1474,7 +1531,7 @@ describe Grape::API do
1474
1531
  error!("Access Denied", 401)
1475
1532
  end
1476
1533
  get '/error'
1477
- last_response.body.should eql '{"error":"Access Denied"}'
1534
+ expect(last_response.body).to eql '{"error":"Access Denied"}'
1478
1535
  end
1479
1536
  end
1480
1537
 
@@ -1485,7 +1542,7 @@ describe Grape::API do
1485
1542
  "some binary content"
1486
1543
  end
1487
1544
  get '/excel.xls'
1488
- last_response.content_type.should == "application/vnd.ms-excel"
1545
+ expect(last_response.content_type).to eq("application/vnd.ms-excel")
1489
1546
  end
1490
1547
  it 'allows to override content-type' do
1491
1548
  subject.get :content do
@@ -1493,7 +1550,7 @@ describe Grape::API do
1493
1550
  "var x = 1;"
1494
1551
  end
1495
1552
  get '/content'
1496
- last_response.content_type.should == "text/javascript"
1553
+ expect(last_response.content_type).to eq("text/javascript")
1497
1554
  end
1498
1555
  it 'removes existing content types' do
1499
1556
  subject.content_type :xls, "application/vnd.ms-excel"
@@ -1501,8 +1558,8 @@ describe Grape::API do
1501
1558
  "some binary content"
1502
1559
  end
1503
1560
  get '/excel.json'
1504
- last_response.status.should == 406
1505
- last_response.body.should == "The requested format 'txt' is not supported."
1561
+ expect(last_response.status).to eq(406)
1562
+ expect(last_response.body).to eq("The requested format 'txt' is not supported.")
1506
1563
  end
1507
1564
  end
1508
1565
 
@@ -1517,11 +1574,11 @@ describe Grape::API do
1517
1574
  end
1518
1575
  it 'sets one formatter' do
1519
1576
  get '/simple.json'
1520
- last_response.body.should eql '{"custom_formatter":"hash"}'
1577
+ expect(last_response.body).to eql '{"custom_formatter":"hash"}'
1521
1578
  end
1522
1579
  it 'sets another formatter' do
1523
1580
  get '/simple.txt'
1524
- last_response.body.should eql 'custom_formatter: hash'
1581
+ expect(last_response.body).to eql 'custom_formatter: hash'
1525
1582
  end
1526
1583
  end
1527
1584
  context 'custom formatter' do
@@ -1535,11 +1592,11 @@ describe Grape::API do
1535
1592
  end
1536
1593
  it 'uses json' do
1537
1594
  get '/simple.json'
1538
- last_response.body.should eql '{"some":"hash"}'
1595
+ expect(last_response.body).to eql '{"some":"hash"}'
1539
1596
  end
1540
1597
  it 'uses custom formatter' do
1541
1598
  get '/simple.custom', 'HTTP_ACCEPT' => 'application/custom'
1542
- last_response.body.should eql '{"custom_formatter":"hash"}'
1599
+ expect(last_response.body).to eql '{"custom_formatter":"hash"}'
1543
1600
  end
1544
1601
  end
1545
1602
  context 'custom formatter class' do
@@ -1558,11 +1615,11 @@ describe Grape::API do
1558
1615
  end
1559
1616
  it 'uses json' do
1560
1617
  get '/simple.json'
1561
- last_response.body.should eql '{"some":"hash"}'
1618
+ expect(last_response.body).to eql '{"some":"hash"}'
1562
1619
  end
1563
1620
  it 'uses custom formatter' do
1564
1621
  get '/simple.custom', 'HTTP_ACCEPT' => 'application/custom'
1565
- last_response.body.should eql '{"custom_formatter":"hash"}'
1622
+ expect(last_response.body).to eql '{"custom_formatter":"hash"}'
1566
1623
  end
1567
1624
  end
1568
1625
  end
@@ -1574,8 +1631,8 @@ describe Grape::API do
1574
1631
  { x: params[:x] }
1575
1632
  end
1576
1633
  post "/data", '{"x":42}', 'CONTENT_TYPE' => 'application/json'
1577
- last_response.status.should == 201
1578
- last_response.body.should == '{"x":42}'
1634
+ expect(last_response.status).to eq(201)
1635
+ expect(last_response.body).to eq('{"x":42}')
1579
1636
  end
1580
1637
  context 'lambda parser' do
1581
1638
  before :each do
@@ -1589,8 +1646,8 @@ describe Grape::API do
1589
1646
  ["text/custom", "text/custom; charset=UTF-8"].each do |content_type|
1590
1647
  it "uses parser for #{content_type}" do
1591
1648
  put '/simple', "simple", "CONTENT_TYPE" => content_type
1592
- last_response.status.should == 200
1593
- last_response.body.should eql "elpmis"
1649
+ expect(last_response.status).to eq(200)
1650
+ expect(last_response.body).to eql "elpmis"
1594
1651
  end
1595
1652
  end
1596
1653
  end
@@ -1610,8 +1667,8 @@ describe Grape::API do
1610
1667
  end
1611
1668
  it 'uses custom parser' do
1612
1669
  put '/simple', "simple", "CONTENT_TYPE" => "text/custom"
1613
- last_response.status.should == 200
1614
- last_response.body.should eql "elpmis"
1670
+ expect(last_response.status).to eq(200)
1671
+ expect(last_response.body).to eql "elpmis"
1615
1672
  end
1616
1673
  end
1617
1674
  context "multi_xml" do
@@ -1620,8 +1677,8 @@ describe Grape::API do
1620
1677
  params[:tag]
1621
1678
  end
1622
1679
  put '/yaml', '<tag type="symbol">a123</tag>', "CONTENT_TYPE" => "application/xml"
1623
- last_response.status.should == 400
1624
- last_response.body.should eql 'Disallowed type attribute: "symbol"'
1680
+ expect(last_response.status).to eq(400)
1681
+ expect(last_response.body).to eql 'Disallowed type attribute: "symbol"'
1625
1682
  end
1626
1683
  end
1627
1684
  context "none parser class" do
@@ -1633,8 +1690,8 @@ describe Grape::API do
1633
1690
  end
1634
1691
  it "does not parse data" do
1635
1692
  put '/data', 'not valid json', "CONTENT_TYPE" => "application/json"
1636
- last_response.status.should == 200
1637
- last_response.body.should == "body: not valid json"
1693
+ expect(last_response.status).to eq(200)
1694
+ expect(last_response.body).to eq("body: not valid json")
1638
1695
  end
1639
1696
  end
1640
1697
  end
@@ -1649,16 +1706,16 @@ describe Grape::API do
1649
1706
  { x: 42 }
1650
1707
  end
1651
1708
  get "/data"
1652
- last_response.status.should == 200
1653
- last_response.body.should == '{"x":42}'
1709
+ expect(last_response.status).to eq(200)
1710
+ expect(last_response.body).to eq('{"x":42}')
1654
1711
  end
1655
1712
  it 'parses data in default format' do
1656
1713
  subject.post '/data' do
1657
1714
  { x: params[:x] }
1658
1715
  end
1659
1716
  post "/data", '{"x":42}', "CONTENT_TYPE" => ""
1660
- last_response.status.should == 201
1661
- last_response.body.should == '{"x":42}'
1717
+ expect(last_response.status).to eq(201)
1718
+ expect(last_response.body).to eq('{"x":42}')
1662
1719
  end
1663
1720
  end
1664
1721
 
@@ -1670,7 +1727,7 @@ describe Grape::API do
1670
1727
  raise "rain!"
1671
1728
  end
1672
1729
  get '/exception'
1673
- last_response.status.should eql 200
1730
+ expect(last_response.status).to eql 200
1674
1731
  end
1675
1732
  it 'has a default error status' do
1676
1733
  subject.rescue_from :all
@@ -1678,7 +1735,7 @@ describe Grape::API do
1678
1735
  raise "rain!"
1679
1736
  end
1680
1737
  get '/exception'
1681
- last_response.status.should eql 500
1738
+ expect(last_response.status).to eql 500
1682
1739
  end
1683
1740
  it 'uses the default error status in error!' do
1684
1741
  subject.rescue_from :all
@@ -1687,14 +1744,14 @@ describe Grape::API do
1687
1744
  error! "rain!"
1688
1745
  end
1689
1746
  get '/exception'
1690
- last_response.status.should eql 400
1747
+ expect(last_response.status).to eql 400
1691
1748
  end
1692
1749
  end
1693
1750
 
1694
1751
  context 'routes' do
1695
1752
  describe 'empty api structure' do
1696
1753
  it 'returns an empty array of routes' do
1697
- subject.routes.should == []
1754
+ expect(subject.routes).to eq([])
1698
1755
  end
1699
1756
  end
1700
1757
  describe 'single method api structure' do
@@ -1704,11 +1761,11 @@ describe Grape::API do
1704
1761
  end
1705
1762
  end
1706
1763
  it 'returns one route' do
1707
- subject.routes.size.should == 1
1764
+ expect(subject.routes.size).to eq(1)
1708
1765
  route = subject.routes[0]
1709
- route.route_version.should be_nil
1710
- route.route_path.should == "/ping(.:format)"
1711
- route.route_method.should == "GET"
1766
+ expect(route.route_version).to be_nil
1767
+ expect(route.route_path).to eq("/ping(.:format)")
1768
+ expect(route.route_method).to eq("GET")
1712
1769
  end
1713
1770
  end
1714
1771
  describe 'api structure with two versions and a namespace' do
@@ -1729,25 +1786,25 @@ describe Grape::API do
1729
1786
  end
1730
1787
  end
1731
1788
  it 'returns the latest version set' do
1732
- subject.version.should == 'v2'
1789
+ expect(subject.version).to eq('v2')
1733
1790
  end
1734
1791
  it 'returns versions' do
1735
- subject.versions.should == ['v1', 'v2']
1792
+ expect(subject.versions).to eq(['v1', 'v2'])
1736
1793
  end
1737
1794
  it 'sets route paths' do
1738
- subject.routes.size.should >= 2
1739
- subject.routes[0].route_path.should == "/:version/version(.:format)"
1740
- subject.routes[1].route_path.should == "/p/:version/n1/n2/version(.:format)"
1795
+ expect(subject.routes.size).to be >= 2
1796
+ expect(subject.routes[0].route_path).to eq("/:version/version(.:format)")
1797
+ expect(subject.routes[1].route_path).to eq("/p/:version/n1/n2/version(.:format)")
1741
1798
  end
1742
1799
  it 'sets route versions' do
1743
- subject.routes[0].route_version.should == 'v1'
1744
- subject.routes[1].route_version.should == 'v2'
1800
+ expect(subject.routes[0].route_version).to eq('v1')
1801
+ expect(subject.routes[1].route_version).to eq('v2')
1745
1802
  end
1746
1803
  it 'sets a nested namespace' do
1747
- subject.routes[1].route_namespace.should == "/n1/n2"
1804
+ expect(subject.routes[1].route_namespace).to eq("/n1/n2")
1748
1805
  end
1749
1806
  it 'sets prefix' do
1750
- subject.routes[1].route_prefix.should == 'p'
1807
+ expect(subject.routes[1].route_prefix).to eq('p')
1751
1808
  end
1752
1809
  end
1753
1810
  describe 'api structure with additional parameters' do
@@ -1758,16 +1815,16 @@ describe Grape::API do
1758
1815
  end
1759
1816
  it 'splits a string' do
1760
1817
  get "/split/a,b,c.json", token: ','
1761
- last_response.body.should == '["a","b","c"]'
1818
+ expect(last_response.body).to eq('["a","b","c"]')
1762
1819
  end
1763
1820
  it 'splits a string with limit' do
1764
1821
  get "/split/a,b,c.json", token: ',', limit: '2'
1765
- last_response.body.should == '["a","b,c"]'
1822
+ expect(last_response.body).to eq('["a","b,c"]')
1766
1823
  end
1767
1824
  it 'sets route_params' do
1768
- subject.routes.map { |route|
1825
+ expect(subject.routes.map { |route|
1769
1826
  { params: route.route_params, optional_params: route.route_optional_params }
1770
- }.should eq [
1827
+ }).to eq [
1771
1828
  { params: { "string" => "", "token" => "a token" }, optional_params: { "limit" => "the limit" } }
1772
1829
  ]
1773
1830
  end
@@ -1776,30 +1833,30 @@ describe Grape::API do
1776
1833
 
1777
1834
  context 'desc' do
1778
1835
  it 'empty array of routes' do
1779
- subject.routes.should == []
1836
+ expect(subject.routes).to eq([])
1780
1837
  end
1781
1838
  it 'empty array of routes' do
1782
1839
  subject.desc "grape api"
1783
- subject.routes.should == []
1840
+ expect(subject.routes).to eq([])
1784
1841
  end
1785
1842
  it 'describes a method' do
1786
1843
  subject.desc "first method"
1787
1844
  subject.get :first do ; end
1788
- subject.routes.length.should == 1
1845
+ expect(subject.routes.length).to eq(1)
1789
1846
  route = subject.routes.first
1790
- route.route_description.should == "first method"
1791
- route.route_foo.should be_nil
1792
- route.route_params.should == {}
1847
+ expect(route.route_description).to eq("first method")
1848
+ expect(route.route_foo).to be_nil
1849
+ expect(route.route_params).to eq({})
1793
1850
  end
1794
1851
  it 'describes methods separately' do
1795
1852
  subject.desc "first method"
1796
1853
  subject.get :first do ; end
1797
1854
  subject.desc "second method"
1798
1855
  subject.get :second do ; end
1799
- subject.routes.count.should == 2
1800
- subject.routes.map { |route|
1856
+ expect(subject.routes.count).to eq(2)
1857
+ expect(subject.routes.map { |route|
1801
1858
  { description: route.route_description, params: route.route_params }
1802
- }.should eq [
1859
+ }).to eq [
1803
1860
  { description: "first method", params: {} },
1804
1861
  { description: "second method", params: {} }
1805
1862
  ]
@@ -1808,9 +1865,9 @@ describe Grape::API do
1808
1865
  subject.desc "first method"
1809
1866
  subject.get :first do ; end
1810
1867
  subject.get :second do ; end
1811
- subject.routes.map { |route|
1868
+ expect(subject.routes.map { |route|
1812
1869
  { description: route.route_description, params: route.route_params }
1813
- }.should eq [
1870
+ }).to eq [
1814
1871
  { description: "first method", params: {} },
1815
1872
  { description: nil, params: {} }
1816
1873
  ]
@@ -1820,19 +1877,19 @@ describe Grape::API do
1820
1877
  desc "ns second", foo: "bar"
1821
1878
  get 'second' do ; end
1822
1879
  end
1823
- subject.routes.map { |route|
1880
+ expect(subject.routes.map { |route|
1824
1881
  { description: route.route_description, foo: route.route_foo, params: route.route_params }
1825
- }.should eq [
1826
- { description: "ns second", foo: "bar", params: {} },
1882
+ }).to eq [
1883
+ { description: "ns second", foo: "bar", params: {} }
1827
1884
  ]
1828
1885
  end
1829
1886
  it 'includes details' do
1830
1887
  subject.desc "method", details: "method details"
1831
1888
  subject.get 'method' do ; end
1832
- subject.routes.map { |route|
1889
+ expect(subject.routes.map { |route|
1833
1890
  { description: route.route_description, details: route.route_details, params: route.route_params }
1834
- }.should eq [
1835
- { description: "method", details: "method details", params: {} },
1891
+ }).to eq [
1892
+ { description: "method", details: "method details", params: {} }
1836
1893
  ]
1837
1894
  end
1838
1895
  it 'describes a method with parameters' do
@@ -1840,9 +1897,9 @@ describe Grape::API do
1840
1897
  subject.get 'reverse' do
1841
1898
  params[:s].reverse
1842
1899
  end
1843
- subject.routes.map { |route|
1900
+ expect(subject.routes.map { |route|
1844
1901
  { description: route.route_description, params: route.route_params }
1845
- }.should eq [
1902
+ }).to eq [
1846
1903
  { description: "Reverses a string.", params: { "s" => { desc: "string to reverse", type: "string" } } }
1847
1904
  ]
1848
1905
  end
@@ -1858,9 +1915,9 @@ describe Grape::API do
1858
1915
  end
1859
1916
  get 'method' do ; end
1860
1917
  end
1861
- subject.routes.map { |route|
1918
+ expect(subject.routes.map { |route|
1862
1919
  { description: route.route_description, params: route.route_params }
1863
- }.should eq [
1920
+ }).to eq [
1864
1921
  { description: "method",
1865
1922
  params: {
1866
1923
  "ns_param" => { required: true, desc: "namespace parameter" },
@@ -1889,9 +1946,9 @@ describe Grape::API do
1889
1946
  get 'method' do ; end
1890
1947
  end
1891
1948
  end
1892
- subject.routes.map { |route|
1949
+ expect(subject.routes.map { |route|
1893
1950
  { description: route.route_description, params: route.route_params }
1894
- }.should eq [
1951
+ }).to eq [
1895
1952
  { description: "method",
1896
1953
  params: {
1897
1954
  "ns_param" => { required: true, desc: "ns param 2" },
@@ -1916,9 +1973,9 @@ describe Grape::API do
1916
1973
  end
1917
1974
  subject.get "method" do ; end
1918
1975
 
1919
- subject.routes.map { |route|
1976
+ expect(subject.routes.map { |route|
1920
1977
  route.route_params
1921
- }.should eq [{
1978
+ }).to eq [{
1922
1979
  "group1" => { required: true, type: "Array" },
1923
1980
  "group1[param1]" => { required: false, desc: "group1 param1 desc" },
1924
1981
  "group1[param2]" => { required: true, desc: "group1 param2 desc" },
@@ -1936,9 +1993,9 @@ describe Grape::API do
1936
1993
  end
1937
1994
  end
1938
1995
  subject.get 'method' do ; end
1939
- subject.routes.map { |route|
1996
+ expect(subject.routes.map { |route|
1940
1997
  { description: route.route_description, params: route.route_params }
1941
- }.should eq [
1998
+ }).to eq [
1942
1999
  { description: "nesting",
1943
2000
  params: {
1944
2001
  "root_param" => { required: true, desc: "root param" },
@@ -1960,9 +2017,9 @@ describe Grape::API do
1960
2017
  requires :one_param, desc: "one param"
1961
2018
  end
1962
2019
  subject.get 'method' do ; end
1963
- subject.routes.map { |route|
2020
+ expect(subject.routes.map { |route|
1964
2021
  { description: route.route_description, params: route.route_params }
1965
- }.should eq [
2022
+ }).to eq [
1966
2023
  { description: nil, params: { "one_param" => { required: true, desc: "one param" } } }
1967
2024
  ]
1968
2025
  end
@@ -1971,9 +2028,9 @@ describe Grape::API do
1971
2028
  subject.get 'reverse/:s' do
1972
2029
  params[:s].reverse
1973
2030
  end
1974
- subject.routes.map { |route|
2031
+ expect(subject.routes.map { |route|
1975
2032
  { description: route.route_description, params: route.route_params }
1976
- }.should eq [
2033
+ }).to eq [
1977
2034
  { description: "Reverses a string.", params: { "s" => { desc: "string to reverse", type: "string" } } }
1978
2035
  ]
1979
2036
  end
@@ -1989,12 +2046,12 @@ describe Grape::API do
1989
2046
 
1990
2047
  it 'makes a bare Rack app available at the endpoint' do
1991
2048
  get '/mounty'
1992
- last_response.body.should == 'MOUNTED'
2049
+ expect(last_response.body).to eq('MOUNTED')
1993
2050
  end
1994
2051
 
1995
2052
  it 'anchors the routes, passing all subroutes to it' do
1996
2053
  get '/mounty/awesome'
1997
- last_response.body.should == 'MOUNTED'
2054
+ expect(last_response.body).to eq('MOUNTED')
1998
2055
  end
1999
2056
 
2000
2057
  it 'is able to cascade' do
@@ -2005,9 +2062,9 @@ describe Grape::API do
2005
2062
  } => '/'
2006
2063
 
2007
2064
  get '/boo'
2008
- last_response.body.should == 'Farfegnugen'
2065
+ expect(last_response.body).to eq('Farfegnugen')
2009
2066
  get '/mounty'
2010
- last_response.body.should == 'MOUNTED'
2067
+ expect(last_response.body).to eq('MOUNTED')
2011
2068
  end
2012
2069
  end
2013
2070
 
@@ -2015,7 +2072,7 @@ describe Grape::API do
2015
2072
  it 'calls through setting the route to "/"' do
2016
2073
  subject.mount mounted_app
2017
2074
  get '/'
2018
- last_response.body.should == 'MOUNTED'
2075
+ expect(last_response.body).to eq('MOUNTED')
2019
2076
  end
2020
2077
  end
2021
2078
 
@@ -2033,7 +2090,7 @@ describe Grape::API do
2033
2090
  end
2034
2091
 
2035
2092
  get '/v1/cool/awesome'
2036
- last_response.body.should == 'yo'
2093
+ expect(last_response.body).to eq('yo')
2037
2094
  end
2038
2095
 
2039
2096
  it 'applies the settings to nested mounted apis' do
@@ -2051,7 +2108,7 @@ describe Grape::API do
2051
2108
  end
2052
2109
 
2053
2110
  get '/v1/cool/awesome'
2054
- last_response.body.should == 'yo'
2111
+ expect(last_response.body).to eq('yo')
2055
2112
  end
2056
2113
 
2057
2114
  it 'inherits rescues even when some defined by mounted' do
@@ -2065,8 +2122,8 @@ describe Grape::API do
2065
2122
  mount app
2066
2123
  end
2067
2124
  get '/mounted/fail'
2068
- last_response.status.should eql 202
2069
- last_response.body.should == 'rescued from doh!'
2125
+ expect(last_response.status).to eql 202
2126
+ expect(last_response.body).to eq('rescued from doh!')
2070
2127
  end
2071
2128
 
2072
2129
  it 'collects the routes of the mounted api' do
@@ -2076,9 +2133,9 @@ describe Grape::API do
2076
2133
  app.post('/sauce') {}
2077
2134
  mount app
2078
2135
  end
2079
- subject.routes.size.should == 2
2080
- subject.routes.first.route_path.should =~ %r{\/cool\/awesome}
2081
- subject.routes.last.route_path.should =~ %r{\/cool\/sauce}
2136
+ expect(subject.routes.size).to eq(2)
2137
+ expect(subject.routes.first.route_path).to match(%r{\/cool\/awesome})
2138
+ expect(subject.routes.last.route_path).to match(%r{\/cool\/sauce})
2082
2139
  end
2083
2140
 
2084
2141
  it 'mounts on a path' do
@@ -2090,8 +2147,8 @@ describe Grape::API do
2090
2147
  mount app => '/mounted'
2091
2148
  end
2092
2149
  get "/mounted/cool/awesome"
2093
- last_response.status.should == 200
2094
- last_response.body.should == "sauce"
2150
+ expect(last_response.status).to eq(200)
2151
+ expect(last_response.body).to eq("sauce")
2095
2152
  end
2096
2153
 
2097
2154
  it 'mounts on a nested path' do
@@ -2104,10 +2161,10 @@ describe Grape::API do
2104
2161
  subject.mount app1 => '/app1'
2105
2162
  app1.mount app2 => '/app2'
2106
2163
  get "/app1/app2/nice"
2107
- last_response.status.should == 200
2108
- last_response.body.should == "play"
2164
+ expect(last_response.status).to eq(200)
2165
+ expect(last_response.body).to eq("play")
2109
2166
  options "/app1/app2/nice"
2110
- last_response.status.should == 204
2167
+ expect(last_response.status).to eq(204)
2111
2168
  end
2112
2169
 
2113
2170
  it 'responds to options' do
@@ -2124,15 +2181,15 @@ describe Grape::API do
2124
2181
  mount app
2125
2182
  end
2126
2183
  get '/apples/colour'
2127
- last_response.status.should eql 200
2128
- last_response.body.should == 'red'
2184
+ expect(last_response.status).to eql 200
2185
+ expect(last_response.body).to eq('red')
2129
2186
  options '/apples/colour'
2130
- last_response.status.should eql 204
2187
+ expect(last_response.status).to eql 204
2131
2188
  get '/apples/pears/colour'
2132
- last_response.status.should eql 200
2133
- last_response.body.should == 'green'
2189
+ expect(last_response.status).to eql 200
2190
+ expect(last_response.body).to eq('green')
2134
2191
  options '/apples/pears/colour'
2135
- last_response.status.should eql 204
2192
+ expect(last_response.status).to eql 204
2136
2193
  end
2137
2194
 
2138
2195
  it 'responds to options with path versioning' do
@@ -2146,10 +2203,10 @@ describe Grape::API do
2146
2203
  end
2147
2204
 
2148
2205
  get '/v1/apples/colour'
2149
- last_response.status.should eql 200
2150
- last_response.body.should == 'red'
2206
+ expect(last_response.status).to eql 200
2207
+ expect(last_response.body).to eq('red')
2151
2208
  options '/v1/apples/colour'
2152
- last_response.status.should eql 204
2209
+ expect(last_response.status).to eql 204
2153
2210
  end
2154
2211
 
2155
2212
  end
@@ -2159,15 +2216,15 @@ describe Grape::API do
2159
2216
  it 'adds one for each route created' do
2160
2217
  subject.get '/'
2161
2218
  subject.post '/'
2162
- subject.endpoints.size.should == 2
2219
+ expect(subject.endpoints.size).to eq(2)
2163
2220
  end
2164
2221
  end
2165
2222
 
2166
2223
  describe '.compile' do
2167
2224
  it 'sets the instance' do
2168
- subject.instance.should be_nil
2225
+ expect(subject.instance).to be_nil
2169
2226
  subject.compile
2170
- subject.instance.should be_kind_of(subject)
2227
+ expect(subject.instance).to be_kind_of(subject)
2171
2228
  end
2172
2229
  end
2173
2230
 
@@ -2175,7 +2232,7 @@ describe Grape::API do
2175
2232
  it 'invalidates any compiled instance' do
2176
2233
  subject.compile
2177
2234
  subject.change!
2178
- subject.instance.should be_nil
2235
+ expect(subject.instance).to be_nil
2179
2236
  end
2180
2237
  end
2181
2238
 
@@ -2192,9 +2249,9 @@ describe Grape::API do
2192
2249
  it 'path' do
2193
2250
  get '/endpoint/options'
2194
2251
  options = MultiJson.load(last_response.body)
2195
- options["path"].should == ["/endpoint/options"]
2196
- options["source_location"][0].should include "api_spec.rb"
2197
- options["source_location"][1].to_i.should > 0
2252
+ expect(options["path"]).to eq(["/endpoint/options"])
2253
+ expect(options["source_location"][0]).to include "api_spec.rb"
2254
+ expect(options["source_location"][1].to_i).to be > 0
2198
2255
  end
2199
2256
  end
2200
2257
 
@@ -2210,9 +2267,9 @@ describe Grape::API do
2210
2267
  end
2211
2268
  it 'provides access to route info' do
2212
2269
  get '/'
2213
- last_response.body.should == "/(.:format)"
2270
+ expect(last_response.body).to eq("/(.:format)")
2214
2271
  get '/path'
2215
- last_response.body.should == "/path(.:format)"
2272
+ expect(last_response.body).to eq("/path(.:format)")
2216
2273
  end
2217
2274
  end
2218
2275
  context 'with desc' do
@@ -2228,11 +2285,11 @@ describe Grape::API do
2228
2285
  end
2229
2286
  it 'returns route description' do
2230
2287
  get '/description'
2231
- last_response.body.should == "returns description"
2288
+ expect(last_response.body).to eq("returns description")
2232
2289
  end
2233
2290
  it 'returns route parameters' do
2234
2291
  get '/params/x'
2235
- last_response.body.should == "y"
2292
+ expect(last_response.body).to eq("y")
2236
2293
  end
2237
2294
  end
2238
2295
  end
@@ -2247,15 +2304,15 @@ describe Grape::API do
2247
2304
  end
2248
2305
  it 'forces txt without an extension' do
2249
2306
  get '/meaning_of_life'
2250
- last_response.body.should == { meaning_of_life: 42 }.to_s
2307
+ expect(last_response.body).to eq({ meaning_of_life: 42 }.to_s)
2251
2308
  end
2252
2309
  it 'does not force txt with an extension' do
2253
2310
  get '/meaning_of_life.json'
2254
- last_response.body.should == { meaning_of_life: 42 }.to_json
2311
+ expect(last_response.body).to eq({ meaning_of_life: 42 }.to_json)
2255
2312
  end
2256
2313
  it 'forces txt from a non-accepting header' do
2257
2314
  get '/meaning_of_life', {}, 'HTTP_ACCEPT' => 'application/json'
2258
- last_response.body.should == { meaning_of_life: 42 }.to_s
2315
+ expect(last_response.body).to eq({ meaning_of_life: 42 }.to_s)
2259
2316
  end
2260
2317
  end
2261
2318
  context ':txt only' do
@@ -2267,15 +2324,15 @@ describe Grape::API do
2267
2324
  end
2268
2325
  it 'forces txt without an extension' do
2269
2326
  get '/meaning_of_life'
2270
- last_response.body.should == { meaning_of_life: 42 }.to_s
2327
+ expect(last_response.body).to eq({ meaning_of_life: 42 }.to_s)
2271
2328
  end
2272
2329
  it 'forces txt with the wrong extension' do
2273
2330
  get '/meaning_of_life.json'
2274
- last_response.body.should == { meaning_of_life: 42 }.to_s
2331
+ expect(last_response.body).to eq({ meaning_of_life: 42 }.to_s)
2275
2332
  end
2276
2333
  it 'forces txt from a non-accepting header' do
2277
2334
  get '/meaning_of_life', {}, 'HTTP_ACCEPT' => 'application/json'
2278
- last_response.body.should == { meaning_of_life: 42 }.to_s
2335
+ expect(last_response.body).to eq({ meaning_of_life: 42 }.to_s)
2279
2336
  end
2280
2337
  end
2281
2338
  context ':json' do
@@ -2288,15 +2345,15 @@ describe Grape::API do
2288
2345
  end
2289
2346
  it 'forces json without an extension' do
2290
2347
  get '/meaning_of_life'
2291
- last_response.body.should == { meaning_of_life: 42 }.to_json
2348
+ expect(last_response.body).to eq({ meaning_of_life: 42 }.to_json)
2292
2349
  end
2293
2350
  it 'does not force json with an extension' do
2294
2351
  get '/meaning_of_life.txt'
2295
- last_response.body.should == { meaning_of_life: 42 }.to_s
2352
+ expect(last_response.body).to eq({ meaning_of_life: 42 }.to_s)
2296
2353
  end
2297
2354
  it 'forces json from a non-accepting header' do
2298
2355
  get '/meaning_of_life', {}, 'HTTP_ACCEPT' => 'text/html'
2299
- last_response.body.should == { meaning_of_life: 42 }.to_json
2356
+ expect(last_response.body).to eq({ meaning_of_life: 42 }.to_json)
2300
2357
  end
2301
2358
  it 'can be overwritten with an explicit content type' do
2302
2359
  subject.get '/meaning_of_life_with_content_type' do
@@ -2304,7 +2361,7 @@ describe Grape::API do
2304
2361
  { meaning_of_life: 42 }.to_s
2305
2362
  end
2306
2363
  get '/meaning_of_life_with_content_type'
2307
- last_response.body.should == { meaning_of_life: 42 }.to_s
2364
+ expect(last_response.body).to eq({ meaning_of_life: 42 }.to_s)
2308
2365
  end
2309
2366
  it 'raised :error from middleware' do
2310
2367
  middleware = Class.new(Grape::Middleware::Base) do
@@ -2317,8 +2374,8 @@ describe Grape::API do
2317
2374
 
2318
2375
  end
2319
2376
  get "/"
2320
- last_response.status.should == 42
2321
- last_response.body.should == { error: "Unauthorized" }.to_json
2377
+ expect(last_response.status).to eq(42)
2378
+ expect(last_response.body).to eq({ error: "Unauthorized" }.to_json)
2322
2379
  end
2323
2380
 
2324
2381
  end
@@ -2336,21 +2393,21 @@ describe Grape::API do
2336
2393
  SerializableHashExample.new
2337
2394
  end
2338
2395
  get '/example'
2339
- last_response.body.should == '{"abc":"def"}'
2396
+ expect(last_response.body).to eq('{"abc":"def"}')
2340
2397
  end
2341
2398
  it 'root' do
2342
2399
  subject.get '/example' do
2343
2400
  { "root" => SerializableHashExample.new }
2344
2401
  end
2345
2402
  get '/example'
2346
- last_response.body.should == '{"root":{"abc":"def"}}'
2403
+ expect(last_response.body).to eq('{"root":{"abc":"def"}}')
2347
2404
  end
2348
2405
  it 'array' do
2349
2406
  subject.get '/examples' do
2350
2407
  [SerializableHashExample.new, SerializableHashExample.new]
2351
2408
  end
2352
2409
  get '/examples'
2353
- last_response.body.should == '[{"abc":"def"},{"abc":"def"}]'
2410
+ expect(last_response.body).to eq('[{"abc":"def"},{"abc":"def"}]')
2354
2411
  end
2355
2412
  end
2356
2413
  context ":xml" do
@@ -2362,8 +2419,8 @@ describe Grape::API do
2362
2419
  "example"
2363
2420
  end
2364
2421
  get '/example'
2365
- last_response.status.should == 500
2366
- last_response.body.should == <<-XML
2422
+ expect(last_response.status).to eq(500)
2423
+ expect(last_response.body).to eq <<-XML
2367
2424
  <?xml version="1.0" encoding="UTF-8"?>
2368
2425
  <error>
2369
2426
  <message>cannot convert String to xml</message>
@@ -2378,8 +2435,8 @@ XML
2378
2435
  ]
2379
2436
  end
2380
2437
  get '/example'
2381
- last_response.status.should == 200
2382
- last_response.body.should == <<-XML
2438
+ expect(last_response.status).to eq(200)
2439
+ expect(last_response.body).to eq <<-XML
2383
2440
  <?xml version="1.0" encoding="UTF-8"?>
2384
2441
  <hash>
2385
2442
  <example1>example1</example1>
@@ -2392,8 +2449,8 @@ XML
2392
2449
  ["example1", "example2"]
2393
2450
  end
2394
2451
  get '/example'
2395
- last_response.status.should == 200
2396
- last_response.body.should == <<-XML
2452
+ expect(last_response.status).to eq(200)
2453
+ expect(last_response.body).to eq <<-XML
2397
2454
  <?xml version="1.0" encoding="UTF-8"?>
2398
2455
  <strings type="array">
2399
2456
  <string>example1</string>
@@ -2412,8 +2469,8 @@ XML
2412
2469
 
2413
2470
  end
2414
2471
  get "/"
2415
- last_response.status.should == 42
2416
- last_response.body.should == <<-XML
2472
+ expect(last_response.status).to eq(42)
2473
+ expect(last_response.body).to eq <<-XML
2417
2474
  <?xml version="1.0" encoding="UTF-8"?>
2418
2475
  <error>
2419
2476
  <message>Unauthorized</message>
@@ -2444,14 +2501,14 @@ XML
2444
2501
  error!("Unrecognized request path: #{params[:path] } - #{env['PATH_INFO'] }#{env['SCRIPT_NAME'] }", 404)
2445
2502
  end
2446
2503
  get "/v1/hello"
2447
- last_response.status.should == 200
2448
- last_response.body.should == "v1"
2504
+ expect(last_response.status).to eq(200)
2505
+ expect(last_response.body).to eq("v1")
2449
2506
  get "/v2/hello"
2450
- last_response.status.should == 200
2451
- last_response.body.should == "v2"
2507
+ expect(last_response.status).to eq(200)
2508
+ expect(last_response.body).to eq("v2")
2452
2509
  get "/foobar"
2453
- last_response.status.should == 404
2454
- last_response.body.should == "Unrecognized request path: foobar - /foobar"
2510
+ expect(last_response.status).to eq(404)
2511
+ expect(last_response.body).to eq("Unrecognized request path: foobar - /foobar")
2455
2512
  end
2456
2513
  end
2457
2514
  end
@@ -2461,28 +2518,28 @@ XML
2461
2518
  it "cascades" do
2462
2519
  subject.version 'v1', using: :path, cascade: true
2463
2520
  get "/v1/hello"
2464
- last_response.status.should == 404
2465
- last_response.headers["X-Cascade"].should == "pass"
2521
+ expect(last_response.status).to eq(404)
2522
+ expect(last_response.headers["X-Cascade"]).to eq("pass")
2466
2523
  end
2467
2524
  it "does not cascade" do
2468
2525
  subject.version 'v2', using: :path, cascade: false
2469
2526
  get "/v2/hello"
2470
- last_response.status.should == 404
2471
- last_response.headers.keys.should_not include "X-Cascade"
2527
+ expect(last_response.status).to eq(404)
2528
+ expect(last_response.headers.keys).not_to include "X-Cascade"
2472
2529
  end
2473
2530
  end
2474
2531
  context "via endpoint" do
2475
2532
  it "cascades" do
2476
2533
  subject.cascade true
2477
2534
  get "/hello"
2478
- last_response.status.should == 404
2479
- last_response.headers["X-Cascade"].should == "pass"
2535
+ expect(last_response.status).to eq(404)
2536
+ expect(last_response.headers["X-Cascade"]).to eq("pass")
2480
2537
  end
2481
2538
  it "does not cascade" do
2482
2539
  subject.cascade false
2483
2540
  get "/hello"
2484
- last_response.status.should == 404
2485
- last_response.headers.keys.should_not include "X-Cascade"
2541
+ expect(last_response.status).to eq(404)
2542
+ expect(last_response.headers.keys).not_to include "X-Cascade"
2486
2543
  end
2487
2544
  end
2488
2545
  end
@@ -2495,8 +2552,8 @@ XML
2495
2552
  'foo'
2496
2553
  end
2497
2554
  get '/something'
2498
- last_response.status.should == 406
2499
- last_response.body.should == "{\"error\":\"The requested format 'txt' is not supported.\"}"
2555
+ expect(last_response.status).to eq(406)
2556
+ expect(last_response.body).to eq("{\"error\":\"The requested format 'txt' is not supported.\"}")
2500
2557
  end
2501
2558
  end
2502
2559
  end