grape 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (42) hide show
  1. data/.yardopts +2 -0
  2. data/CHANGELOG.markdown +19 -0
  3. data/Gemfile +2 -0
  4. data/README.markdown +166 -131
  5. data/Rakefile +1 -3
  6. data/lib/grape.rb +0 -3
  7. data/lib/grape/api.rb +16 -4
  8. data/lib/grape/cookies.rb +32 -30
  9. data/lib/grape/endpoint.rb +25 -11
  10. data/lib/grape/entity.rb +5 -0
  11. data/lib/grape/error_formatter/base.rb +2 -1
  12. data/lib/grape/middleware/base.rb +9 -2
  13. data/lib/grape/middleware/error.rb +11 -11
  14. data/lib/grape/middleware/formatter.rb +8 -5
  15. data/lib/grape/middleware/versioner/header.rb +1 -3
  16. data/lib/grape/middleware/versioner/path.rb +15 -2
  17. data/lib/grape/util/deep_merge.rb +4 -4
  18. data/lib/grape/validations.rb +2 -3
  19. data/lib/grape/version.rb +1 -1
  20. data/spec/grape/api_spec.rb +316 -175
  21. data/spec/grape/endpoint_spec.rb +159 -57
  22. data/spec/grape/entity_spec.rb +80 -80
  23. data/spec/grape/middleware/auth/basic_spec.rb +3 -3
  24. data/spec/grape/middleware/auth/digest_spec.rb +4 -4
  25. data/spec/grape/middleware/auth/oauth2_spec.rb +4 -4
  26. data/spec/grape/middleware/base_spec.rb +9 -9
  27. data/spec/grape/middleware/error_spec.rb +4 -4
  28. data/spec/grape/middleware/exception_spec.rb +13 -13
  29. data/spec/grape/middleware/formatter_spec.rb +25 -25
  30. data/spec/grape/middleware/versioner/header_spec.rb +23 -23
  31. data/spec/grape/middleware/versioner/param_spec.rb +8 -8
  32. data/spec/grape/middleware/versioner/path_spec.rb +8 -8
  33. data/spec/grape/middleware/versioner_spec.rb +6 -3
  34. data/spec/grape/util/hash_stack_spec.rb +20 -20
  35. data/spec/grape/validations/presence_spec.rb +1 -1
  36. data/spec/grape/validations/regexp_spec.rb +2 -2
  37. data/spec/grape/validations_spec.rb +4 -4
  38. data/spec/shared/versioning_examples.rb +48 -20
  39. metadata +5 -7
  40. data/.document +0 -5
  41. data/lib/grape/middleware/prefixer.rb +0 -21
  42. data/spec/grape/middleware/prefixer_spec.rb +0 -30
@@ -3,11 +3,11 @@ class Hash
3
3
  # activesupport/lib/active_support/core_ext/hash/deep_merge.rb
4
4
  # Returns a new hash with +self+ and +other_hash+ merged recursively.
5
5
  #
6
- # h1 = {:x => {:y => [4,5,6]}, :z => [7,8,9]}
7
- # h2 = {:x => {:y => [7,8,9]}, :z => "xyz"}
6
+ # h1 = {:x => {:y => [4,5,6]}, :z => [7,8,9]}
7
+ # h2 = {:x => {:y => [7,8,9]}, :z => "xyz"}
8
8
  #
9
- # h1.deep_merge(h2) #=> { :x => {:y => [7, 8, 9]}, :z => "xyz" }
10
- # h2.deep_merge(h1) #=> { :x => {:y => [4, 5, 6]}, :z => [7, 8, 9] }
9
+ # h1.deep_merge(h2) #=> { :x => {:y => [7, 8, 9]}, :z => "xyz" }
10
+ # h2.deep_merge(h1) #=> { :x => {:y => [4, 5, 6]}, :z => [7, 8, 9] }
11
11
  def deep_merge(other_hash)
12
12
  dup.deep_merge!(other_hash)
13
13
  end
@@ -184,10 +184,9 @@ module Grape
184
184
  def document_attribute(names, opts)
185
185
  @last_description ||= {}
186
186
  @last_description[:params] ||= {}
187
-
188
187
  Array(names).each do |name|
189
- @last_description[:params][name[:name].to_s] ||= {}
190
- @last_description[:params][name[:name].to_s].merge!(opts).merge!({:full_name => name[:full_name]})
188
+ @last_description[:params][name[:full_name].to_s] ||= {}
189
+ @last_description[:params][name[:full_name].to_s].merge!(opts)
191
190
  end
192
191
  end
193
192
 
@@ -1,3 +1,3 @@
1
1
  module Grape
2
- VERSION = '0.2.3'
2
+ VERSION = '0.2.4'
3
3
  end
@@ -7,7 +7,18 @@ describe Grape::API do
7
7
  def app; subject end
8
8
 
9
9
  describe '.prefix' do
10
- it 'should route through with the prefix' do
10
+
11
+ it 'routes root through with the prefix' do
12
+ subject.prefix 'awesome/sauce'
13
+ subject.get do
14
+ "Hello there."
15
+ end
16
+
17
+ get 'awesome/sauce/'
18
+ last_response.body.should eql "Hello there."
19
+ end
20
+
21
+ it 'routes through with the prefix' do
11
22
  subject.prefix 'awesome/sauce'
12
23
  subject.get :hello do
13
24
  "Hello there."
@@ -19,18 +30,19 @@ describe Grape::API do
19
30
  get '/hello'
20
31
  last_response.status.should eql 404
21
32
  end
33
+
22
34
  end
23
35
 
24
36
  describe '.version' do
25
37
  context 'when defined' do
26
- it 'should return version value' do
38
+ it 'returns version value' do
27
39
  subject.version 'v1'
28
40
  subject.version.should == 'v1'
29
41
  end
30
42
  end
31
43
 
32
44
  context 'when not defined' do
33
- it 'should return nil' do
45
+ it 'returns nil' do
34
46
  subject.version.should be_nil
35
47
  end
36
48
  end
@@ -45,7 +57,6 @@ describe Grape::API do
45
57
  end
46
58
  end
47
59
  end
48
-
49
60
  describe '.version using param' do
50
61
  it_should_behave_like 'versioning' do
51
62
  let(:macro_options) do
@@ -76,23 +87,23 @@ describe Grape::API do
76
87
  # 'hello'
77
88
  # end
78
89
 
79
- # it 'should route' do
90
+ # it 'routes' do
80
91
  # get '/hello'
81
92
  # last_response.status.should eql 200
82
93
  # end
83
94
  end
84
95
 
85
- it 'should route if any media type is allowed' do
96
+ it 'routes if any media type is allowed' do
86
97
 
87
98
  end
88
99
  end
89
100
 
90
101
  describe '.represent' do
91
- it 'should require a :with option' do
102
+ it 'requires a :with option' do
92
103
  expect{ subject.represent Object, {} }.to raise_error(ArgumentError)
93
104
  end
94
105
 
95
- it 'should add the association to the :representations setting' do
106
+ it 'adds the association to the :representations setting' do
96
107
  klass = Class.new
97
108
  subject.represent Object, :with => klass
98
109
  subject.settings[:representations][Object].should == klass
@@ -100,13 +111,13 @@ describe Grape::API do
100
111
  end
101
112
 
102
113
  describe '.namespace' do
103
- it 'should be retrievable and converted to a path' do
114
+ it 'is retrievable and converted to a path' do
104
115
  subject.namespace :awesome do
105
116
  namespace.should == '/awesome'
106
117
  end
107
118
  end
108
119
 
109
- it 'should come after the prefix and version' do
120
+ it 'comes after the prefix and version' do
110
121
  subject.prefix :rad
111
122
  subject.version 'v1', :using => :path
112
123
 
@@ -118,7 +129,7 @@ describe Grape::API do
118
129
  last_response.body.should == "worked"
119
130
  end
120
131
 
121
- it 'should cancel itself after the block is over' do
132
+ it 'cancels itself after the block is over' do
122
133
  subject.namespace :awesome do
123
134
  namespace.should == '/awesome'
124
135
  end
@@ -126,7 +137,7 @@ describe Grape::API do
126
137
  subject.namespace.should == '/'
127
138
  end
128
139
 
129
- it 'should be stackable' do
140
+ it 'is stackable' do
130
141
  subject.namespace :awesome do
131
142
  namespace :rad do
132
143
  namespace.should == '/awesome/rad'
@@ -136,9 +147,9 @@ describe Grape::API do
136
147
  subject.namespace.should == '/'
137
148
  end
138
149
 
139
- it 'should accept path segments correctly' do
150
+ it 'accepts path segments correctly' do
140
151
  subject.namespace :members do
141
- namespace "/:member_id" do
152
+ namespace '/:member_id' do
142
153
  namespace.should == '/members/:member_id'
143
154
  get '/' do
144
155
  params[:member_id]
@@ -149,7 +160,7 @@ describe Grape::API do
149
160
  last_response.body.should == "23"
150
161
  end
151
162
 
152
- it 'should be callable with nil just to push onto the stack' do
163
+ it 'is callable with nil just to push onto the stack' do
153
164
  subject.namespace do
154
165
  version 'v2', :using => :path
155
166
  get('/hello'){ "inner" }
@@ -163,7 +174,7 @@ describe Grape::API do
163
174
  end
164
175
 
165
176
  %w(group resource resources segment).each do |als|
166
- it "`.#{als}` should be an alias" do
177
+ it '`.#{als}` is an alias' do
167
178
  subject.send(als, :awesome) do
168
179
  namespace.should == "/awesome"
169
180
  end
@@ -172,7 +183,7 @@ describe Grape::API do
172
183
  end
173
184
 
174
185
  describe '.route' do
175
- it 'should allow for no path' do
186
+ it 'allows for no path' do
176
187
  subject.namespace :votes do
177
188
  get do
178
189
  "Votes"
@@ -189,7 +200,7 @@ describe Grape::API do
189
200
  last_response.body.should eql 'Created a Vote'
190
201
  end
191
202
 
192
- describe "root routes should work with" do
203
+ describe 'root routes should work with' do
193
204
  before do
194
205
  def subject.enable_root_route!
195
206
  self.get("/") {"root"}
@@ -200,43 +211,43 @@ describe Grape::API do
200
211
  last_response.body.should eql 'root'
201
212
  end
202
213
 
203
- describe "path versioned APIs" do
214
+ describe 'path versioned APIs' do
204
215
  before do
205
216
  subject.version 'v1', :using => :path
206
217
  subject.enable_root_route!
207
218
  end
208
219
 
209
- it "without a format" do
220
+ it 'without a format' do
210
221
  versioned_get "/", "v1", :using => :path
211
222
  end
212
223
 
213
- it "with a format" do
224
+ it 'with a format' do
214
225
  get "/v1/.json"
215
226
  end
216
227
  end
217
228
 
218
- it "header versioned APIs" do
229
+ it 'header versioned APIs' do
219
230
  subject.version 'v1', :using => :header, :vendor => 'test'
220
231
  subject.enable_root_route!
221
232
 
222
233
  versioned_get "/", "v1", :using => :header
223
234
  end
224
235
 
225
- it "param versioned APIs" do
236
+ it 'param versioned APIs' do
226
237
  subject.version 'v1', :using => :param
227
238
  subject.enable_root_route!
228
239
 
229
240
  versioned_get "/", "v1", :using => :param
230
241
  end
231
242
 
232
- it "unversioned APIs" do
243
+ it 'unversioned APIs' do
233
244
  subject.enable_root_route!
234
245
 
235
246
  get "/"
236
247
  end
237
248
  end
238
249
 
239
- it 'should allow for multiple paths' do
250
+ it 'allows for multiple paths' do
240
251
  subject.get(["/abc", "/def"]) do
241
252
  "foo"
242
253
  end
@@ -247,27 +258,27 @@ describe Grape::API do
247
258
  last_response.body.should eql 'foo'
248
259
  end
249
260
 
250
- context "format" do
261
+ context 'format' do
251
262
  before(:each) do
252
263
  subject.get("/abc") do
253
264
  RSpec::Mocks::Mock.new(:to_json => 'abc', :to_txt => 'def')
254
265
  end
255
266
  end
256
267
 
257
- it "should allow .json" do
268
+ it 'allows .json' do
258
269
  get '/abc.json'
259
270
  last_response.status.should == 200
260
271
  last_response.body.should eql 'abc' # json-encoded symbol
261
272
  end
262
273
 
263
- it "should allow .txt" do
274
+ it 'allows .txt' do
264
275
  get '/abc.txt'
265
276
  last_response.status.should == 200
266
277
  last_response.body.should eql 'def' # raw text
267
278
  end
268
279
  end
269
280
 
270
- it 'should allow for format without corrupting a param' do
281
+ it 'allows for format without corrupting a param' do
271
282
  subject.get('/:id') do
272
283
  {"id" => params[:id]}
273
284
  end
@@ -276,7 +287,7 @@ describe Grape::API do
276
287
  last_response.body.should eql '{"id":"awesome"}'
277
288
  end
278
289
 
279
- it 'should allow for format in namespace with no path' do
290
+ it 'allows for format in namespace with no path' do
280
291
  subject.namespace :abc do
281
292
  get do
282
293
  ["json"]
@@ -287,7 +298,7 @@ describe Grape::API do
287
298
  last_response.body.should eql '["json"]'
288
299
  end
289
300
 
290
- it 'should allow for multiple verbs' do
301
+ it 'allows for multiple verbs' do
291
302
  subject.route([:get, :post], '/abc') do
292
303
  "hiya"
293
304
  end
@@ -302,7 +313,7 @@ describe Grape::API do
302
313
  last_response.body.should eql 'hiya'
303
314
  end
304
315
 
305
- it 'should allow for multipart paths' do
316
+ it 'allows for multipart paths' do
306
317
 
307
318
  subject.route([:get, :post], '/:id/first') do
308
319
  "first"
@@ -328,7 +339,7 @@ describe Grape::API do
328
339
 
329
340
  end
330
341
 
331
- it 'should allow for :any as a verb' do
342
+ it 'allows for :any as a verb' do
332
343
  subject.route(:any, '/abc') do
333
344
  "lol"
334
345
  end
@@ -341,7 +352,7 @@ describe Grape::API do
341
352
 
342
353
  verbs = %w(post get head delete put options patch)
343
354
  verbs.each do |verb|
344
- it "should allow and properly constrain a #{verb.upcase} method" do
355
+ it 'allows and properly constrain a #{verb.upcase} method' do
345
356
  subject.send(verb, '/example') do
346
357
  verb
347
358
  end
@@ -353,7 +364,7 @@ describe Grape::API do
353
364
  end
354
365
  end
355
366
 
356
- it 'should return a 201 response code for POST by default' do
367
+ it 'returns a 201 response code for POST by default' do
357
368
  subject.post('example') do
358
369
  "Created"
359
370
  end
@@ -363,7 +374,7 @@ describe Grape::API do
363
374
  last_response.body.should eql 'Created'
364
375
  end
365
376
 
366
- it 'should return a 405 for an unsupported method' do
377
+ it 'returns a 405 for an unsupported method' do
367
378
  subject.get 'example' do
368
379
  "example"
369
380
  end
@@ -372,7 +383,7 @@ describe Grape::API do
372
383
  last_response.body.should eql ''
373
384
  end
374
385
 
375
- specify '405 responses should include an Allow header specifying supported methods' do
386
+ specify '405 responses includes an Allow header specifying supported methods' do
376
387
  subject.get 'example' do
377
388
  "example"
378
389
  end
@@ -383,7 +394,7 @@ describe Grape::API do
383
394
  last_response.headers['Allow'].should eql 'OPTIONS, GET, POST'
384
395
  end
385
396
 
386
- it 'should add an OPTIONS route that returns a 204 and an Allow header' do
397
+ it 'adds an OPTIONS route that returns a 204 and an Allow header' do
387
398
  subject.get 'example' do
388
399
  "example"
389
400
  end
@@ -395,7 +406,7 @@ describe Grape::API do
395
406
  end
396
407
 
397
408
  describe 'filters' do
398
- it 'should add a before filter' do
409
+ it 'adds a before filter' do
399
410
  subject.before { @foo = 'first' }
400
411
  subject.before { @bar = 'second' }
401
412
  subject.get '/' do
@@ -406,7 +417,7 @@ describe Grape::API do
406
417
  last_response.body.should eql 'first second'
407
418
  end
408
419
 
409
- it 'should add a after_validation filter' do
420
+ it 'adds a after_validation filter' do
410
421
  subject.after_validation { @foo = "first #{params[:id]}:#{params[:id].class}" }
411
422
  subject.after_validation { @bar = 'second' }
412
423
  subject.params do
@@ -420,7 +431,7 @@ describe Grape::API do
420
431
  last_response.body.should eql 'first 32:Fixnum second'
421
432
  end
422
433
 
423
- it 'should add a after filter' do
434
+ it 'adds a after filter' do
424
435
  m = double('after mock')
425
436
  subject.after { m.do_something! }
426
437
  subject.after { m.do_something! }
@@ -439,30 +450,30 @@ describe Grape::API do
439
450
  subject.get("/foo") { "bar" }
440
451
  end
441
452
 
442
- it 'should set content type for txt format' do
453
+ it 'sets content type for txt format' do
443
454
  get '/foo'
444
455
  last_response.headers['Content-Type'].should eql 'text/plain'
445
456
  end
446
457
 
447
- it 'should set content type for json' do
458
+ it 'sets content type for json' do
448
459
  get '/foo.json'
449
460
  last_response.headers['Content-Type'].should eql 'application/json'
450
461
  end
451
462
 
452
- it 'should set content type for error' do
463
+ it 'sets content type for error' do
453
464
  subject.get('/error') { error!('error in plain text', 500) }
454
465
  get '/error'
455
466
  last_response.headers['Content-Type'].should eql 'text/plain'
456
467
  end
457
468
 
458
- it 'should set content type for error' do
469
+ it 'sets content type for error' do
459
470
  subject.format :json
460
471
  subject.get('/error') { error!('error in json', 500) }
461
472
  get '/error.json'
462
473
  last_response.headers['Content-Type'].should eql 'application/json'
463
474
  end
464
475
 
465
- it 'should set content type for xml' do
476
+ it 'sets content type for xml' do
466
477
  subject.format :xml
467
478
  subject.get('/error') { error!('error in xml', 500) }
468
479
  get '/error.xml'
@@ -489,14 +500,14 @@ describe Grape::API do
489
500
  end
490
501
 
491
502
  describe '.middleware' do
492
- it 'should include middleware arguments from settings' do
503
+ it 'includes middleware arguments from settings' do
493
504
  settings = Grape::Util::HashStack.new
494
505
  settings.stub!(:stack).and_return([{:middleware => [[ApiSpec::PhonyMiddleware, 'abc', 123]]}])
495
506
  subject.stub!(:settings).and_return(settings)
496
507
  subject.middleware.should eql [[ApiSpec::PhonyMiddleware, 'abc', 123]]
497
508
  end
498
509
 
499
- it 'should include all middleware from stacked settings' do
510
+ it 'includes all middleware from stacked settings' do
500
511
  settings = Grape::Util::HashStack.new
501
512
  settings.stub!(:stack).and_return [
502
513
  {:middleware => [[ApiSpec::PhonyMiddleware, 123],[ApiSpec::PhonyMiddleware, 'abc']]},
@@ -513,12 +524,12 @@ describe Grape::API do
513
524
  end
514
525
 
515
526
  describe '.use' do
516
- it 'should add middleware' do
527
+ it 'adds middleware' do
517
528
  subject.use ApiSpec::PhonyMiddleware, 123
518
529
  subject.middleware.should eql [[ApiSpec::PhonyMiddleware, 123]]
519
530
  end
520
531
 
521
- it 'should not show up outside the namespace' do
532
+ it 'does not show up outside the namespace' do
522
533
  subject.use ApiSpec::PhonyMiddleware, 123
523
534
  subject.namespace :awesome do
524
535
  use ApiSpec::PhonyMiddleware, 'abc'
@@ -528,7 +539,7 @@ describe Grape::API do
528
539
  subject.middleware.should eql [[ApiSpec::PhonyMiddleware, 123]]
529
540
  end
530
541
 
531
- it 'should actually call the middleware' do
542
+ it 'calls the middleware' do
532
543
  subject.use ApiSpec::PhonyMiddleware, 'hello'
533
544
  subject.get '/' do
534
545
  env['phony.args'].first.first
@@ -538,13 +549,13 @@ describe Grape::API do
538
549
  last_response.body.should eql 'hello'
539
550
  end
540
551
 
541
- it 'should add a block if one is given' do
552
+ it 'adds a block if one is given' do
542
553
  block = lambda{ }
543
554
  subject.use ApiSpec::PhonyMiddleware, &block
544
555
  subject.middleware.should eql [[ApiSpec::PhonyMiddleware, block]]
545
556
  end
546
557
 
547
- it 'should use a block if one is given' do
558
+ it 'uses a block if one is given' do
548
559
  block = lambda{ }
549
560
  subject.use ApiSpec::PhonyMiddleware, &block
550
561
  subject.get '/' do
@@ -555,7 +566,7 @@ describe Grape::API do
555
566
  last_response.body.should == 'true'
556
567
  end
557
568
 
558
- it 'should not destroy the middleware settings on multiple runs' do
569
+ it 'does not destroy the middleware settings on multiple runs' do
559
570
  block = lambda{ }
560
571
  subject.use ApiSpec::PhonyMiddleware, &block
561
572
  subject.get '/' do
@@ -570,7 +581,7 @@ describe Grape::API do
570
581
  end
571
582
  end
572
583
  describe '.basic' do
573
- it 'should protect any resources on the same scope' do
584
+ it 'protects any resources on the same scope' do
574
585
  subject.http_basic do |u,p|
575
586
  u == 'allow'
576
587
  end
@@ -581,7 +592,7 @@ describe Grape::API do
581
592
  last_response.status.should eql 200
582
593
  end
583
594
 
584
- it 'should be scopable' do
595
+ it 'is scopable' do
585
596
  subject.get(:hello){ "Hello, world."}
586
597
  subject.namespace :admin do
587
598
  http_basic do |u,p|
@@ -597,7 +608,7 @@ describe Grape::API do
597
608
  last_response.status.should eql 401
598
609
  end
599
610
 
600
- it 'should be callable via .auth as well' do
611
+ it 'is callable via .auth as well' do
601
612
  subject.auth :http_basic do |u,p|
602
613
  u == 'allow'
603
614
  end
@@ -611,11 +622,11 @@ describe Grape::API do
611
622
  end
612
623
 
613
624
  describe '.logger' do
614
- it 'should return an instance of Logger class by default' do
625
+ it 'returns an instance of Logger class by default' do
615
626
  subject.logger.class.should eql Logger
616
627
  end
617
628
 
618
- it 'should allow setting a custom logger' do
629
+ it 'allows setting a custom logger' do
619
630
  mylogger = Class.new
620
631
  subject.logger mylogger
621
632
  mylogger.should_receive(:info).exactly(1).times
@@ -624,7 +635,7 @@ describe Grape::API do
624
635
  end
625
636
 
626
637
  describe '.helpers' do
627
- it 'should be accessible from the endpoint' do
638
+ it 'is accessible from the endpoint' do
628
639
  subject.helpers do
629
640
  def hello
630
641
  "Hello, world."
@@ -639,7 +650,7 @@ describe Grape::API do
639
650
  last_response.body.should eql 'Hello, world.'
640
651
  end
641
652
 
642
- it 'should be scopable' do
653
+ it 'is scopable' do
643
654
  subject.helpers do
644
655
  def generic
645
656
  'always there'
@@ -668,7 +679,7 @@ describe Grape::API do
668
679
  last_response.body.should eql 'always there:only in admin'
669
680
  end
670
681
 
671
- it 'should be reopenable' do
682
+ it 'is reopenable' do
672
683
  subject.helpers do
673
684
  def one
674
685
  1
@@ -688,7 +699,7 @@ describe Grape::API do
688
699
  lambda{get '/howdy'}.should_not raise_error
689
700
  end
690
701
 
691
- it 'should allow for modules' do
702
+ it 'allows for modules' do
692
703
  mod = Module.new do
693
704
  def hello
694
705
  "Hello, world."
@@ -704,7 +715,7 @@ describe Grape::API do
704
715
  last_response.body.should eql 'Hello, world.'
705
716
  end
706
717
 
707
- it 'should allow multiple calls with modules and blocks' do
718
+ it 'allows multiple calls with modules and blocks' do
708
719
  subject.helpers Module.new do
709
720
  def one
710
721
  1
@@ -730,7 +741,7 @@ describe Grape::API do
730
741
  describe '.scope' do
731
742
  # TODO: refactor this to not be tied to versioning. How about a generic
732
743
  # .setting macro?
733
- it 'should scope the various settings' do
744
+ it 'scopes the various settings' do
734
745
  subject.prefix 'new'
735
746
 
736
747
  subject.scope :legacy do
@@ -755,15 +766,15 @@ describe Grape::API do
755
766
  end
756
767
  end
757
768
 
758
- describe ".rescue_from" do
759
- it 'should not rescue errors when rescue_from is not set' do
769
+ describe '.rescue_from' do
770
+ it 'does not rescue errors when rescue_from is not set' do
760
771
  subject.get '/exception' do
761
772
  raise "rain!"
762
773
  end
763
774
  lambda { get '/exception' }.should raise_error
764
775
  end
765
776
 
766
- it 'should rescue all errors if rescue_from :all is called' do
777
+ it 'rescues all errors if rescue_from :all is called' do
767
778
  subject.rescue_from :all
768
779
  subject.get '/exception' do
769
780
  raise "rain!"
@@ -772,7 +783,7 @@ describe Grape::API do
772
783
  last_response.status.should eql 403
773
784
  end
774
785
 
775
- it 'should rescue only certain errors if rescue_from is called with specific errors' do
786
+ it 'rescues only certain errors if rescue_from is called with specific errors' do
776
787
  subject.rescue_from ArgumentError
777
788
  subject.get('/rescued'){ raise ArgumentError }
778
789
  subject.get('/unrescued'){ raise "beefcake" }
@@ -783,14 +794,14 @@ describe Grape::API do
783
794
  lambda{ get '/unrescued' }.should raise_error
784
795
  end
785
796
 
786
- it 'should not re-raise exceptions of type Grape::Exception::Base' do
797
+ it 'does not re-raise exceptions of type Grape::Exception::Base' do
787
798
  class CustomError < Grape::Exceptions::Base; end
788
799
  subject.get('/custom_exception'){ raise CustomError }
789
800
 
790
801
  lambda{ get '/custom_exception' }.should_not raise_error
791
802
  end
792
803
 
793
- it 'should rescue custom grape exceptions' do
804
+ it 'rescues custom grape exceptions' do
794
805
  class CustomError < Grape::Exceptions::Base; end
795
806
  subject.rescue_from CustomError do |e|
796
807
  rack_response('New Error', e.status)
@@ -805,8 +816,8 @@ describe Grape::API do
805
816
  end
806
817
  end
807
818
 
808
- describe ".rescue_from klass, block" do
809
- it 'should rescue Exception' do
819
+ describe '.rescue_from klass, block' do
820
+ it 'rescues Exception' do
810
821
  subject.rescue_from RuntimeError do |e|
811
822
  rack_response("rescued from #{e.message}", 202)
812
823
  end
@@ -817,7 +828,7 @@ describe Grape::API do
817
828
  last_response.status.should eql 202
818
829
  last_response.body.should == 'rescued from rain!'
819
830
  end
820
- it 'should rescue an error via rescue_from :all' do
831
+ it 'rescues an error via rescue_from :all' do
821
832
  class ConnectionError < RuntimeError; end
822
833
  subject.rescue_from :all do |e|
823
834
  rack_response("rescued from #{e.class.name}", 500)
@@ -829,7 +840,7 @@ describe Grape::API do
829
840
  last_response.status.should eql 500
830
841
  last_response.body.should == 'rescued from ConnectionError'
831
842
  end
832
- it 'should rescue a specific error' do
843
+ it 'rescues a specific error' do
833
844
  class ConnectionError < RuntimeError; end
834
845
  subject.rescue_from ConnectionError do |e|
835
846
  rack_response("rescued from #{e.class.name}", 500)
@@ -841,7 +852,7 @@ describe Grape::API do
841
852
  last_response.status.should eql 500
842
853
  last_response.body.should == 'rescued from ConnectionError'
843
854
  end
844
- it 'should rescue multiple specific errors' do
855
+ it 'rescues multiple specific errors' do
845
856
  class ConnectionError < RuntimeError; end
846
857
  class DatabaseError < RuntimeError; end
847
858
  subject.rescue_from ConnectionError do |e|
@@ -863,7 +874,7 @@ describe Grape::API do
863
874
  last_response.status.should eql 500
864
875
  last_response.body.should == 'rescued from DatabaseError'
865
876
  end
866
- it 'should not rescue a different error' do
877
+ it 'does not rescue a different error' do
867
878
  class CommunicationError < RuntimeError; end
868
879
  subject.rescue_from RuntimeError do |e|
869
880
  rack_response("rescued from #{e.class.name}", 500)
@@ -875,8 +886,8 @@ describe Grape::API do
875
886
  end
876
887
  end
877
888
 
878
- describe ".format for error" do
879
- it 'should rescue all errors and return :txt' do
889
+ describe '.error_format' do
890
+ it 'rescues all errors and return :txt' do
880
891
  subject.rescue_from :all
881
892
  subject.format :txt
882
893
  subject.get '/exception' do
@@ -886,7 +897,7 @@ describe Grape::API do
886
897
  last_response.body.should eql "rain!"
887
898
  end
888
899
 
889
- it 'should rescue all errors and return :txt with backtrace' do
900
+ it 'rescues all errors and return :txt with backtrace' do
890
901
  subject.rescue_from :all, :backtrace => true
891
902
  subject.format :txt
892
903
  subject.get '/exception' do
@@ -896,7 +907,32 @@ describe Grape::API do
896
907
  last_response.body.start_with?("rain!\r\n").should be_true
897
908
  end
898
909
 
899
- context "class" do
910
+ it 'rescues all errors with a default formatter' do
911
+ subject.default_format :foo
912
+ subject.content_type :foo, "text/foo"
913
+ subject.rescue_from :all
914
+ subject.get '/exception' do
915
+ raise "rain!"
916
+ end
917
+ get '/exception.foo'
918
+ last_response.body.should start_with "rain!"
919
+ end
920
+
921
+ it 'defaults the error formatter to format' do
922
+ subject.format :json
923
+ subject.rescue_from :all
924
+ subject.content_type :json, "application/json"
925
+ subject.content_type :foo, "text/foo"
926
+ subject.get '/exception' do
927
+ raise "rain!"
928
+ end
929
+ get '/exception.json'
930
+ last_response.body.should == '{"error":"rain!"}'
931
+ get '/exception.foo'
932
+ last_response.body.should == '{"error":"rain!"}'
933
+ end
934
+
935
+ context 'class' do
900
936
  before :each do
901
937
  class CustomErrorFormatter
902
938
  def self.call(message, backtrace, options, env)
@@ -904,7 +940,7 @@ describe Grape::API do
904
940
  end
905
941
  end
906
942
  end
907
- it 'should return a custom error format' do
943
+ it 'returns a custom error format' do
908
944
  subject.rescue_from :all, :backtrace => true
909
945
  subject.error_formatter :txt, CustomErrorFormatter
910
946
  subject.get '/exception' do
@@ -915,7 +951,7 @@ describe Grape::API do
915
951
  end
916
952
  end
917
953
 
918
- it 'should rescue all errors and return :json' do
954
+ it 'rescues all errors and return :json' do
919
955
  subject.rescue_from :all
920
956
  subject.format :json
921
957
  subject.get '/exception' do
@@ -924,7 +960,7 @@ describe Grape::API do
924
960
  get '/exception'
925
961
  last_response.body.should eql '{"error":"rain!"}'
926
962
  end
927
- it 'should rescue all errors and return :json with backtrace' do
963
+ it 'rescues all errors and return :json with backtrace' do
928
964
  subject.rescue_from :all, :backtrace => true
929
965
  subject.format :json
930
966
  subject.get '/exception' do
@@ -935,7 +971,7 @@ describe Grape::API do
935
971
  json["error"].should eql 'rain!'
936
972
  json["backtrace"].length.should > 0
937
973
  end
938
- it 'should rescue error! and return txt' do
974
+ it 'rescues error! and return txt' do
939
975
  subject.format :txt
940
976
  subject.get '/error' do
941
977
  error!("Access Denied", 401)
@@ -943,7 +979,7 @@ describe Grape::API do
943
979
  get '/error'
944
980
  last_response.body.should eql "Access Denied"
945
981
  end
946
- it 'should rescue error! and return json' do
982
+ it 'rescues error! and return json' do
947
983
  subject.format :json
948
984
  subject.get '/error' do
949
985
  error!("Access Denied", 401)
@@ -953,8 +989,8 @@ describe Grape::API do
953
989
  end
954
990
  end
955
991
 
956
- describe ".content_type" do
957
- it "sets additional content-type" do
992
+ describe '.content_type' do
993
+ it 'sets additional content-type' do
958
994
  subject.content_type :xls, "application/vnd.ms-excel"
959
995
  subject.get :excel do
960
996
  "some binary content"
@@ -962,7 +998,7 @@ describe Grape::API do
962
998
  get '/excel.xls'
963
999
  last_response.content_type.should == "application/vnd.ms-excel"
964
1000
  end
965
- it "allows to override content-type" do
1001
+ it 'allows to override content-type' do
966
1002
  subject.get :content do
967
1003
  content_type "text/javascript"
968
1004
  "var x = 1;"
@@ -970,7 +1006,7 @@ describe Grape::API do
970
1006
  get '/content'
971
1007
  last_response.content_type.should == "text/javascript"
972
1008
  end
973
- it "removes existing content types" do
1009
+ it 'removes existing content types' do
974
1010
  subject.content_type :xls, "application/vnd.ms-excel"
975
1011
  subject.get :excel do
976
1012
  "some binary content"
@@ -981,8 +1017,8 @@ describe Grape::API do
981
1017
  end
982
1018
  end
983
1019
 
984
- describe ".formatter" do
985
- context "multiple formatters" do
1020
+ describe '.formatter' do
1021
+ context 'multiple formatters' do
986
1022
  before :each do
987
1023
  subject.formatter :json, lambda { |object, env| "{\"custom_formatter\":\"#{object[:some]}\"}" }
988
1024
  subject.formatter :txt, lambda { |object, env| "custom_formatter: #{object[:some]}" }
@@ -999,7 +1035,7 @@ describe Grape::API do
999
1035
  last_response.body.should eql 'custom_formatter: hash'
1000
1036
  end
1001
1037
  end
1002
- context "custom formatter" do
1038
+ context 'custom formatter' do
1003
1039
  before :each do
1004
1040
  subject.content_type :json, 'application/json'
1005
1041
  subject.content_type :custom, 'application/custom'
@@ -1017,7 +1053,7 @@ describe Grape::API do
1017
1053
  last_response.body.should eql '{"custom_formatter":"hash"}'
1018
1054
  end
1019
1055
  end
1020
- context "custom formatter class" do
1056
+ context 'custom formatter class' do
1021
1057
  module CustomFormatter
1022
1058
  def self.call(object, env)
1023
1059
  "{\"custom_formatter\":\"#{object[:some]}\"}"
@@ -1042,8 +1078,8 @@ describe Grape::API do
1042
1078
  end
1043
1079
  end
1044
1080
 
1045
- describe ".default_error_status" do
1046
- it 'should allow setting default_error_status' do
1081
+ describe '.default_error_status' do
1082
+ it 'allows setting default_error_status' do
1047
1083
  subject.rescue_from :all
1048
1084
  subject.default_error_status 200
1049
1085
  subject.get '/exception' do
@@ -1052,7 +1088,7 @@ describe Grape::API do
1052
1088
  get '/exception'
1053
1089
  last_response.status.should eql 200
1054
1090
  end
1055
- it 'should have a default error status' do
1091
+ it 'has a default error status' do
1056
1092
  subject.rescue_from :all
1057
1093
  subject.get '/exception' do
1058
1094
  raise "rain!"
@@ -1062,19 +1098,19 @@ describe Grape::API do
1062
1098
  end
1063
1099
  end
1064
1100
 
1065
- context "routes" do
1066
- describe "empty api structure" do
1067
- it "returns an empty array of routes" do
1101
+ context 'routes' do
1102
+ describe 'empty api structure' do
1103
+ it 'returns an empty array of routes' do
1068
1104
  subject.routes.should == []
1069
1105
  end
1070
1106
  end
1071
- describe "single method api structure" do
1107
+ describe 'single method api structure' do
1072
1108
  before(:each) do
1073
1109
  subject.get :ping do
1074
1110
  'pong'
1075
1111
  end
1076
1112
  end
1077
- it "returns one route" do
1113
+ it 'returns one route' do
1078
1114
  subject.routes.size.should == 1
1079
1115
  route = subject.routes[0]
1080
1116
  route.route_version.should be_nil
@@ -1082,60 +1118,60 @@ describe Grape::API do
1082
1118
  route.route_method.should == "GET"
1083
1119
  end
1084
1120
  end
1085
- describe "api structure with two versions and a namespace" do
1121
+ describe 'api structure with two versions and a namespace' do
1086
1122
  before :each do
1087
1123
  subject.version 'v1', :using => :path
1088
- subject.get "version" do
1124
+ subject.get 'version' do
1089
1125
  api.version
1090
1126
  end
1091
1127
  # version v2
1092
1128
  subject.version 'v2', :using => :path
1093
1129
  subject.prefix 'p'
1094
- subject.namespace "n1" do
1095
- namespace "n2" do
1096
- get "version" do
1130
+ subject.namespace 'n1' do
1131
+ namespace 'n2' do
1132
+ get 'version' do
1097
1133
  api.version
1098
1134
  end
1099
1135
  end
1100
1136
  end
1101
1137
  end
1102
- it "should return the latest version set" do
1138
+ it 'returns the latest version set' do
1103
1139
  subject.version.should == 'v2'
1104
1140
  end
1105
- it "should return versions" do
1141
+ it 'returns versions' do
1106
1142
  subject.versions.should == [ 'v1', 'v2' ]
1107
1143
  end
1108
- it "should set route paths" do
1144
+ it 'sets route paths' do
1109
1145
  subject.routes.size.should >= 2
1110
1146
  subject.routes[0].route_path.should == "/:version/version(.:format)"
1111
1147
  subject.routes[1].route_path.should == "/p/:version/n1/n2/version(.:format)"
1112
1148
  end
1113
- it "should set route versions" do
1149
+ it 'sets route versions' do
1114
1150
  subject.routes[0].route_version.should == 'v1'
1115
1151
  subject.routes[1].route_version.should == 'v2'
1116
1152
  end
1117
- it "should set a nested namespace" do
1153
+ it 'sets a nested namespace' do
1118
1154
  subject.routes[1].route_namespace.should == "/n1/n2"
1119
1155
  end
1120
- it "should set prefix" do
1156
+ it 'sets prefix' do
1121
1157
  subject.routes[1].route_prefix.should == 'p'
1122
1158
  end
1123
1159
  end
1124
- describe "api structure with additional parameters" do
1160
+ describe 'api structure with additional parameters' do
1125
1161
  before(:each) do
1126
1162
  subject.get 'split/:string', { :params => { "token" => "a token" }, :optional_params => { "limit" => "the limit" } } do
1127
1163
  params[:string].split(params[:token], (params[:limit] || 0).to_i)
1128
1164
  end
1129
1165
  end
1130
- it "should split a string" do
1166
+ it 'splits a string' do
1131
1167
  get "/split/a,b,c.json", :token => ','
1132
1168
  last_response.body.should == '["a","b","c"]'
1133
1169
  end
1134
- it "should split a string with limit" do
1170
+ it 'splits a string with limit' do
1135
1171
  get "/split/a,b,c.json", :token => ',', :limit => '2'
1136
1172
  last_response.body.should == '["a","b,c"]'
1137
1173
  end
1138
- it "should set route_params" do
1174
+ it 'sets route_params' do
1139
1175
  subject.routes.map { |route|
1140
1176
  { :params => route.route_params, :optional_params => route.route_optional_params }
1141
1177
  }.should eq [
@@ -1145,15 +1181,15 @@ describe Grape::API do
1145
1181
  end
1146
1182
  end
1147
1183
 
1148
- context "desc" do
1149
- it "empty array of routes" do
1184
+ context 'desc' do
1185
+ it 'empty array of routes' do
1150
1186
  subject.routes.should == []
1151
1187
  end
1152
- it "empty array of routes" do
1188
+ it 'empty array of routes' do
1153
1189
  subject.desc "grape api"
1154
1190
  subject.routes.should == []
1155
1191
  end
1156
- it "should describe a method" do
1192
+ it 'describes a method' do
1157
1193
  subject.desc "first method"
1158
1194
  subject.get :first do ; end
1159
1195
  subject.routes.length.should == 1
@@ -1162,7 +1198,7 @@ describe Grape::API do
1162
1198
  route.route_foo.should be_nil
1163
1199
  route.route_params.should == { }
1164
1200
  end
1165
- it "should describe methods separately" do
1201
+ it 'describes methods separately' do
1166
1202
  subject.desc "first method"
1167
1203
  subject.get :first do ; end
1168
1204
  subject.desc "second method"
@@ -1175,7 +1211,7 @@ describe Grape::API do
1175
1211
  { :description => "second method", :params => {} }
1176
1212
  ]
1177
1213
  end
1178
- it "should reset desc" do
1214
+ it 'resets desc' do
1179
1215
  subject.desc "first method"
1180
1216
  subject.get :first do ; end
1181
1217
  subject.get :second do ; end
@@ -1186,10 +1222,10 @@ describe Grape::API do
1186
1222
  { :description => nil, :params => {} }
1187
1223
  ]
1188
1224
  end
1189
- it "should namespace and describe arbitrary parameters" do
1190
- subject.namespace "ns" do
1225
+ it 'namespaces and describe arbitrary parameters' do
1226
+ subject.namespace 'ns' do
1191
1227
  desc "ns second", :foo => "bar"
1192
- get "second" do ; end
1228
+ get 'second' do ; end
1193
1229
  end
1194
1230
  subject.routes.map { |route|
1195
1231
  { :description => route.route_description, :foo => route.route_foo, :params => route.route_params }
@@ -1197,20 +1233,20 @@ describe Grape::API do
1197
1233
  { :description => "ns second", :foo => "bar", :params => {} },
1198
1234
  ]
1199
1235
  end
1200
- it "should include details" do
1236
+ it 'includes details' do
1201
1237
  subject.desc "method", :details => "method details"
1202
- subject.get "method" do ; end
1238
+ subject.get 'method' do ; end
1203
1239
  subject.routes.map { |route|
1204
1240
  { :description => route.route_description, :details => route.route_details, :params => route.route_params }
1205
1241
  }.should eq [
1206
1242
  { :description => "method", :details => "method details", :params => {} },
1207
1243
  ]
1208
1244
  end
1209
- it "should describe a method with parameters" do
1245
+ it 'describes a method with parameters' do
1210
1246
  subject.desc "Reverses a string.", { :params =>
1211
1247
  { "s" => { :desc => "string to reverse", :type => "string" }}
1212
1248
  }
1213
- subject.get "reverse" do
1249
+ subject.get 'reverse' do
1214
1250
  params[:s].reverse
1215
1251
  end
1216
1252
  subject.routes.map { |route|
@@ -1219,51 +1255,86 @@ describe Grape::API do
1219
1255
  { :description => "Reverses a string.", :params => { "s" => { :desc => "string to reverse", :type => "string" } } }
1220
1256
  ]
1221
1257
  end
1222
- it "should merge the parameters of the namespace with the parameters of the method" do
1258
+ it 'merges the parameters of the namespace with the parameters of the method' do
1223
1259
  subject.desc "namespace"
1224
1260
  subject.params do
1225
1261
  requires :ns_param, :desc => "namespace parameter"
1226
1262
  end
1227
- subject.namespace "ns" do
1263
+ subject.namespace 'ns' do
1228
1264
  desc "method"
1229
1265
  params do
1230
1266
  optional :method_param, :desc => "method parameter"
1231
1267
  end
1232
- get "method" do ; end
1268
+ get 'method' do ; end
1233
1269
  end
1234
1270
  subject.routes.map { |route|
1235
1271
  { :description => route.route_description, :params => route.route_params }
1236
1272
  }.should eq [
1237
- { :description => "method", :params => { "ns_param" => { :required => true, :desc => "namespace parameter", :full_name=>"ns_param" }, "method_param" => { :required => false, :desc => "method parameter", :full_name=>"method_param" } } }
1273
+ { :description => "method",
1274
+ :params => {
1275
+ "ns_param" => { :required => true, :desc => "namespace parameter" },
1276
+ "method_param" => { :required => false, :desc => "method parameter" }
1277
+ }
1278
+ }
1238
1279
  ]
1239
1280
  end
1240
- it "should merge the parameters of nested namespaces" do
1281
+ it 'merges the parameters of nested namespaces' do
1241
1282
  subject.desc "ns1"
1242
1283
  subject.params do
1243
1284
  optional :ns_param, :desc => "ns param 1"
1244
1285
  requires :ns1_param, :desc => "ns1 param"
1245
1286
  end
1246
- subject.namespace "ns1" do
1287
+ subject.namespace 'ns1' do
1247
1288
  desc "ns2"
1248
1289
  params do
1249
1290
  requires :ns_param, :desc => "ns param 2"
1250
1291
  requires :ns2_param, :desc => "ns2 param"
1251
1292
  end
1252
- namespace "ns2" do
1293
+ namespace 'ns2' do
1253
1294
  desc "method"
1254
1295
  params do
1255
1296
  optional :method_param, :desc => "method param"
1256
1297
  end
1257
- get "method" do ; end
1298
+ get 'method' do ; end
1258
1299
  end
1259
1300
  end
1260
1301
  subject.routes.map { |route|
1261
1302
  { :description => route.route_description, :params => route.route_params }
1262
1303
  }.should eq [
1263
- { :description => "method", :params => { "ns_param" => { :required => true, :desc => "ns param 2", :full_name=>"ns_param" }, "ns1_param" => { :required => true, :desc => "ns1 param", :full_name=>"ns1_param" }, "ns2_param" => { :required => true, :desc => "ns2 param", :full_name=>"ns2_param" }, "method_param" => { :required => false, :desc => "method param", :full_name=>"method_param" } } }
1304
+ { :description => "method",
1305
+ :params => {
1306
+ "ns_param" => { :required => true, :desc => "ns param 2" },
1307
+ "ns1_param" => { :required => true, :desc => "ns1 param" },
1308
+ "ns2_param" => { :required => true, :desc => "ns2 param" },
1309
+ "method_param" => { :required => false, :desc => "method param" }
1310
+ }
1311
+ }
1264
1312
  ]
1265
1313
  end
1266
- it "should provide a full_name for parameters in nested groups" do
1314
+ it "groups nested params and prevents overwriting of params with same name in different groups" do
1315
+ subject.desc "method"
1316
+ subject.params do
1317
+ group :group1 do
1318
+ optional :param1, :desc => "group1 param1 desc"
1319
+ requires :param2, :desc => "group1 param2 desc"
1320
+ end
1321
+ group :group2 do
1322
+ optional :param1, :desc => "group2 param1 desc"
1323
+ requires :param2, :desc => "group2 param2 desc"
1324
+ end
1325
+ end
1326
+ subject.get "method" do ; end
1327
+
1328
+ subject.routes.map { |route|
1329
+ route.route_params
1330
+ }.should eq [{
1331
+ "group1[param1]" => { :required => false, :desc => "group1 param1 desc" },
1332
+ "group1[param2]" => { :required => true, :desc => "group1 param2 desc" },
1333
+ "group2[param1]" => { :required => false, :desc => "group2 param1 desc" },
1334
+ "group2[param2]" => { :required => true, :desc => "group2 param2 desc" }
1335
+ }]
1336
+ end
1337
+ it 'uses full name of parameters in nested groups' do
1267
1338
  subject.desc "nesting"
1268
1339
  subject.params do
1269
1340
  requires :root_param, :desc => "root param"
@@ -1271,29 +1342,34 @@ describe Grape::API do
1271
1342
  requires :nested_param, :desc => "nested param"
1272
1343
  end
1273
1344
  end
1274
- subject.get "method" do ; end
1345
+ subject.get 'method' do ; end
1275
1346
  subject.routes.map { |route|
1276
1347
  { :description => route.route_description, :params => route.route_params }
1277
1348
  }.should eq [
1278
- { :description => "nesting", :params => { "root_param" => { :required => true, :desc => "root param", :full_name=>"root_param" }, "nested_param" => { :required => true, :desc => "nested param", :full_name=>"nested[nested_param]" } } }
1349
+ { :description => "nesting",
1350
+ :params => {
1351
+ "root_param" => { :required => true, :desc => "root param" },
1352
+ "nested[nested_param]" => { :required => true, :desc => "nested param" }
1353
+ }
1354
+ }
1279
1355
  ]
1280
1356
  end
1281
- it "should parse parameters when no description is given" do
1357
+ it 'parses parameters when no description is given' do
1282
1358
  subject.params do
1283
1359
  requires :one_param, :desc => "one param"
1284
1360
  end
1285
- subject.get "method" do ; end
1361
+ subject.get 'method' do ; end
1286
1362
  subject.routes.map { |route|
1287
1363
  { :description => route.route_description, :params => route.route_params }
1288
1364
  }.should eq [
1289
- { :description => nil, :params => { "one_param" => { :required => true, :desc => "one param", :full_name=>"one_param" } } }
1365
+ { :description => nil, :params => { "one_param" => { :required => true, :desc => "one param" } } }
1290
1366
  ]
1291
1367
  end
1292
- it "should not symbolize params" do
1368
+ it 'does not symbolize params' do
1293
1369
  subject.desc "Reverses a string.", { :params =>
1294
1370
  { "s" => { :desc => "string to reverse", :type => "string" }}
1295
1371
  }
1296
- subject.get "reverse/:s" do
1372
+ subject.get 'reverse/:s' do
1297
1373
  params[:s].reverse
1298
1374
  end
1299
1375
  subject.routes.map { |route|
@@ -1312,17 +1388,17 @@ describe Grape::API do
1312
1388
  subject.mount mounted_app => '/mounty'
1313
1389
  end
1314
1390
 
1315
- it 'should make a bare Rack app available at the endpoint' do
1391
+ it 'makes a bare Rack app available at the endpoint' do
1316
1392
  get '/mounty'
1317
1393
  last_response.body.should == 'MOUNTED'
1318
1394
  end
1319
1395
 
1320
- it 'should anchor the routes, passing all subroutes to it' do
1396
+ it 'anchors the routes, passing all subroutes to it' do
1321
1397
  get '/mounty/awesome'
1322
1398
  last_response.body.should == 'MOUNTED'
1323
1399
  end
1324
1400
 
1325
- it 'should be able to cascade' do
1401
+ it 'is able to cascade' do
1326
1402
  subject.mount lambda{ |env|
1327
1403
  headers = {}
1328
1404
  headers['X-Cascade'] == 'pass' unless env['PATH_INFO'].include?('boo')
@@ -1337,7 +1413,7 @@ describe Grape::API do
1337
1413
  end
1338
1414
 
1339
1415
  context 'without a hash' do
1340
- it 'should call through setting the route to "/"' do
1416
+ it 'calls through setting the route to "/"' do
1341
1417
  subject.mount mounted_app
1342
1418
  get '/'
1343
1419
  last_response.body.should == 'MOUNTED'
@@ -1345,7 +1421,7 @@ describe Grape::API do
1345
1421
  end
1346
1422
 
1347
1423
  context 'mounting an API' do
1348
- it 'should apply the settings of the mounting api' do
1424
+ it 'applies the settings of the mounting api' do
1349
1425
  subject.version 'v1', :using => :path
1350
1426
 
1351
1427
  subject.namespace :cool do
@@ -1360,7 +1436,7 @@ describe Grape::API do
1360
1436
  last_response.body.should == 'yo'
1361
1437
  end
1362
1438
 
1363
- it 'should inherit rescues even when some defined by mounted' do
1439
+ it 'inherits rescues even when some defined by mounted' do
1364
1440
  subject.rescue_from :all do |e|
1365
1441
  rack_response("rescued from #{e.message}", 202)
1366
1442
  end
@@ -1374,11 +1450,23 @@ describe Grape::API do
1374
1450
  last_response.status.should eql 202
1375
1451
  last_response.body.should == 'rescued from doh!'
1376
1452
  end
1453
+
1454
+ it 'collects the routes of the mounted api' do
1455
+ subject.namespace :cool do
1456
+ app = Class.new(Grape::API)
1457
+ app.get('/awesome') {}
1458
+ app.post('/sauce') {}
1459
+ mount app
1460
+ end
1461
+ subject.routes.size.should == 2
1462
+ subject.routes.first.route_path.should =~ /\/cool\/awesome/
1463
+ subject.routes.last.route_path.should =~ /\/cool\/sauce/
1464
+ end
1377
1465
  end
1378
1466
  end
1379
1467
 
1380
1468
  describe '.endpoints' do
1381
- it 'should add one for each route created' do
1469
+ it 'adds one for each route created' do
1382
1470
  subject.get '/'
1383
1471
  subject.post '/'
1384
1472
  subject.endpoints.size.should == 2
@@ -1386,7 +1474,7 @@ describe Grape::API do
1386
1474
  end
1387
1475
 
1388
1476
  describe '.compile' do
1389
- it 'should set the instance' do
1477
+ it 'sets the instance' do
1390
1478
  subject.instance.should be_nil
1391
1479
  subject.compile
1392
1480
  subject.instance.should be_kind_of(subject)
@@ -1394,15 +1482,34 @@ describe Grape::API do
1394
1482
  end
1395
1483
 
1396
1484
  describe '.change!' do
1397
- it 'should invalidate any compiled instance' do
1485
+ it 'invalidates any compiled instance' do
1398
1486
  subject.compile
1399
1487
  subject.change!
1400
1488
  subject.instance.should be_nil
1401
1489
  end
1402
1490
  end
1403
1491
 
1404
- describe ".route" do
1405
- context "plain" do
1492
+ describe ".endpoint" do
1493
+ before(:each) do
1494
+ subject.format :json
1495
+ subject.get '/endpoint/options' do
1496
+ {
1497
+ :path => options[:path],
1498
+ :source_location => source.source_location
1499
+ }
1500
+ end
1501
+ end
1502
+ it 'path' do
1503
+ get '/endpoint/options'
1504
+ options = MultiJson.load(last_response.body)
1505
+ options["path"].should == ["/endpoint/options"]
1506
+ options["source_location"][0].should include "api_spec.rb"
1507
+ options["source_location"][1].to_i.should > 0
1508
+ end
1509
+ end
1510
+
1511
+ describe '.route' do
1512
+ context 'plain' do
1406
1513
  before(:each) do
1407
1514
  subject.get '/' do
1408
1515
  route.route_path
@@ -1411,14 +1518,14 @@ describe Grape::API do
1411
1518
  route.route_path
1412
1519
  end
1413
1520
  end
1414
- it 'should provide access to route info' do
1521
+ it 'provides access to route info' do
1415
1522
  get '/'
1416
1523
  last_response.body.should == "/(.:format)"
1417
1524
  get '/path'
1418
1525
  last_response.body.should == "/path(.:format)"
1419
1526
  end
1420
1527
  end
1421
- context "with desc" do
1528
+ context 'with desc' do
1422
1529
  before(:each) do
1423
1530
  subject.desc 'returns description'
1424
1531
  subject.get '/description' do
@@ -1429,58 +1536,58 @@ describe Grape::API do
1429
1536
  route.route_params[params[:id]]
1430
1537
  end
1431
1538
  end
1432
- it 'should return route description' do
1539
+ it 'returns route description' do
1433
1540
  get '/description'
1434
1541
  last_response.body.should == "returns description"
1435
1542
  end
1436
- it 'should return route parameters' do
1543
+ it 'returns route parameters' do
1437
1544
  get '/params/x'
1438
1545
  last_response.body.should == "y"
1439
1546
  end
1440
1547
  end
1441
1548
  end
1442
- context "format" do
1443
- context ":txt" do
1549
+ context 'format' do
1550
+ context ':txt' do
1444
1551
  before(:each) do
1445
1552
  subject.format :txt
1446
1553
  subject.get '/meaning_of_life' do
1447
1554
  { :meaning_of_life => 42 }
1448
1555
  end
1449
1556
  end
1450
- it "should force txt without an extension" do
1557
+ it 'forces txt without an extension' do
1451
1558
  get '/meaning_of_life'
1452
1559
  last_response.body.should == { :meaning_of_life => 42 }.to_s
1453
1560
  end
1454
- it "should not force txt with an extension" do
1561
+ it 'does not force txt with an extension' do
1455
1562
  get '/meaning_of_life.json'
1456
1563
  last_response.body.should == { :meaning_of_life => 42 }.to_json
1457
1564
  end
1458
- it "should force txt from a non-accepting header" do
1565
+ it 'forces txt from a non-accepting header' do
1459
1566
  get '/meaning_of_life', {}, { 'HTTP_ACCEPT' => 'application/json' }
1460
1567
  last_response.body.should == { :meaning_of_life => 42 }.to_s
1461
1568
  end
1462
1569
  end
1463
- context ":json" do
1570
+ context ':json' do
1464
1571
  before(:each) do
1465
1572
  subject.format :json
1466
1573
  subject.get '/meaning_of_life' do
1467
1574
  { :meaning_of_life => 42 }
1468
1575
  end
1469
1576
  end
1470
- it "should force json without an extension" do
1577
+ it 'forces json without an extension' do
1471
1578
  get '/meaning_of_life'
1472
1579
  last_response.body.should == { :meaning_of_life => 42 }.to_json
1473
1580
  end
1474
- it "should not force json with an extension" do
1581
+ it 'does not force json with an extension' do
1475
1582
  get '/meaning_of_life.txt'
1476
1583
  last_response.body.should == { :meaning_of_life => 42 }.to_s
1477
1584
  end
1478
- it "should force json from a non-accepting header" do
1585
+ it 'forces json from a non-accepting header' do
1479
1586
  get '/meaning_of_life', {}, { 'HTTP_ACCEPT' => 'text/html' }
1480
1587
  last_response.body.should == { :meaning_of_life => 42 }.to_json
1481
1588
  end
1482
1589
  end
1483
- context ":serializable_hash" do
1590
+ context ':serializable_hash' do
1484
1591
  before(:each) do
1485
1592
  class SimpleExample
1486
1593
  def serializable_hash
@@ -1489,21 +1596,21 @@ describe Grape::API do
1489
1596
  end
1490
1597
  subject.format :serializable_hash
1491
1598
  end
1492
- it "instance" do
1599
+ it 'instance' do
1493
1600
  subject.get '/example' do
1494
1601
  SimpleExample.new
1495
1602
  end
1496
1603
  get '/example'
1497
1604
  last_response.body.should == '{"abc":"def"}'
1498
1605
  end
1499
- it "root" do
1606
+ it 'root' do
1500
1607
  subject.get '/example' do
1501
1608
  { "root" => SimpleExample.new }
1502
1609
  end
1503
1610
  get '/example'
1504
1611
  last_response.body.should == '{"root":{"abc":"def"}}'
1505
1612
  end
1506
- it "array" do
1613
+ it 'array' do
1507
1614
  subject.get '/examples' do
1508
1615
  [ SimpleExample.new, SimpleExample.new ]
1509
1616
  end
@@ -1512,4 +1619,38 @@ describe Grape::API do
1512
1619
  end
1513
1620
  end
1514
1621
  end
1622
+
1623
+ context "catch-all" do
1624
+ before do
1625
+ api1 = Class.new(Grape::API)
1626
+ api1.version 'v1', :using => :path
1627
+ api1.get "hello" do
1628
+ "v1"
1629
+ end
1630
+ api2 = Class.new(Grape::API)
1631
+ api2.version 'v2', :using => :path
1632
+ api2.get "hello" do
1633
+ "v2"
1634
+ end
1635
+ subject.mount api1
1636
+ subject.mount api2
1637
+ end
1638
+ [ true, false ].each do |anchor|
1639
+ it "anchor=#{anchor}" do
1640
+ subject.route :any, '*path', :anchor => anchor do
1641
+ error!("Unrecognized request path: #{params[:path]} - #{env['PATH_INFO']}#{env['SCRIPT_NAME']}", 404)
1642
+ end
1643
+ get "/v1/hello"
1644
+ last_response.status.should == 200
1645
+ last_response.body.should == "v1"
1646
+ get "/v2/hello"
1647
+ last_response.status.should == 200
1648
+ last_response.body.should == "v2"
1649
+ get "/foobar"
1650
+ last_response.status.should == 404
1651
+ last_response.body.should == "Unrecognized request path: foobar - /foobar"
1652
+ end
1653
+ end
1654
+ end
1655
+
1515
1656
  end