grape 0.2.0 → 0.2.1

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.

@@ -107,7 +107,7 @@ describe Grape::Endpoint do
107
107
  ]
108
108
  end
109
109
  end
110
-
110
+
111
111
  describe '#params' do
112
112
  it 'should be available to the caller' do
113
113
  subject.get('/hey') do
@@ -134,6 +134,80 @@ describe Grape::Endpoint do
134
134
  get '/location?location[city]=Dallas'
135
135
  last_response.body.should == 'Dallas'
136
136
  end
137
+
138
+ context 'with special requirements' do
139
+ it 'should parse email param with provided requirements for params' do
140
+ subject.get('/:person_email', :requirements => { :person_email => /.*/ }) do
141
+ params[:person_email]
142
+ end
143
+
144
+ get '/rodzyn@grape.com'
145
+ last_response.body.should == 'rodzyn@grape.com'
146
+
147
+ get 'rodzyn@grape.com.pl'
148
+ last_response.body.should == 'rodzyn@grape.com.pl'
149
+ end
150
+
151
+ it 'should parse many params with provided regexps' do
152
+ subject.get('/:person_email/test/:number',
153
+ :requirements => {
154
+ :person_email => /rodzyn@(.*).com/,
155
+ :number => /[0-9]/ }) do
156
+ params[:person_email] << params[:number]
157
+ end
158
+
159
+ get '/rodzyn@grape.com/test/1'
160
+ last_response.body.should == 'rodzyn@grape.com1'
161
+
162
+ get '/rodzyn@testing.wrong/test/1'
163
+ last_response.status.should == 404
164
+
165
+ get 'rodzyn@test.com/test/wrong_number'
166
+ last_response.status.should == 404
167
+
168
+ get 'rodzyn@test.com/wrong_middle/1'
169
+ last_response.status.should == 404
170
+ end
171
+ end
172
+
173
+ context 'from body parameters' do
174
+ before(:each) do
175
+ subject.post '/request_body' do
176
+ params[:user]
177
+ end
178
+
179
+ subject.put '/request_body' do
180
+ params[:user]
181
+ end
182
+ end
183
+
184
+ it 'should convert JSON bodies to params' do
185
+ post '/request_body', MultiJson.encode(:user => 'Bobby T.'), {'CONTENT_TYPE' => 'application/json'}
186
+ last_response.body.should == 'Bobby T.'
187
+ end
188
+
189
+ it 'should convert JSON bodies to params' do
190
+ put '/request_body', MultiJson.encode(:user => 'Bobby T.'), {'CONTENT_TYPE' => 'application/json'}
191
+ last_response.body.should == 'Bobby T.'
192
+ end
193
+
194
+ it 'should convert XML bodies to params' do
195
+ post '/request_body', '<user>Bobby T.</user>', {'CONTENT_TYPE' => 'application/xml'}
196
+ last_response.body.should == 'Bobby T.'
197
+ end
198
+
199
+ it 'should convert XML bodies to params' do
200
+ put '/request_body', '<user>Bobby T.</user>', {'CONTENT_TYPE' => 'application/xml'}
201
+ last_response.body.should == 'Bobby T.'
202
+ end
203
+
204
+ it 'does not include parameters not defined by the body' do
205
+ subject.post '/omitted_params' do
206
+ body_params[:version].should == nil
207
+ end
208
+ post '/omitted_params', MultiJson.encode(:user => 'Blah'), {'CONTENT_TYPE' => 'application/json'}
209
+ end
210
+ end
137
211
  end
138
212
 
139
213
  describe '#error!' do
@@ -168,6 +242,37 @@ describe Grape::Endpoint do
168
242
  last_response.body.should == '{"dude":"rad"}'
169
243
  end
170
244
  end
245
+
246
+ describe "#redirect" do
247
+ it "should redirect to a url with status 302" do
248
+ subject.get('/hey') do
249
+ redirect "/ha"
250
+ end
251
+ get '/hey'
252
+ last_response.status.should eq 302
253
+ last_response.headers['Location'].should eq "/ha"
254
+ last_response.body.should eq ""
255
+ end
256
+
257
+ it "should have status code 303 if it is not get request and it is http 1.1" do
258
+ subject.post('/hey') do
259
+ redirect "/ha"
260
+ end
261
+ post '/hey', {}, 'HTTP_VERSION' => 'HTTP/1.1'
262
+ last_response.status.should eq 303
263
+ last_response.headers['Location'].should eq "/ha"
264
+ end
265
+
266
+ it "support permanent redirect" do
267
+ subject.get('/hey') do
268
+ redirect "/ha", :permanent => true
269
+ end
270
+ get '/hey'
271
+ last_response.status.should eq 304
272
+ last_response.headers['Location'].should eq "/ha"
273
+ last_response.body.should eq ""
274
+ end
275
+ end
171
276
 
172
277
  it 'should not persist params between calls' do
173
278
  subject.post('/new') do
@@ -304,8 +409,8 @@ describe Grape::Endpoint do
304
409
  verb
305
410
  end
306
411
  send(verb, '/example/and/some/more')
307
- last_response.status.should eql (verb == "post" ? 201 : 200)
308
- last_response.body.should eql verb
412
+ last_response.status.should eql verb == "post" ? 201 : 200
413
+ last_response.body.should eql verb == 'head' ? '' : verb
309
414
  end
310
415
  end
311
416
  end
@@ -24,6 +24,10 @@ describe Grape::Entity do
24
24
  expect{ subject.expose :name, :email, :as => :foo }.to raise_error(ArgumentError)
25
25
  expect{ subject.expose :name, :as => :foo }.not_to raise_error
26
26
  end
27
+
28
+ it 'should make sure that :format_with as a proc can not be used with a block' do
29
+ expect { subject.expose :name, :format_with => Proc.new {} do |object,options| end }.to raise_error(ArgumentError)
30
+ end
27
31
  end
28
32
 
29
33
  context 'with a block' do
@@ -67,6 +71,38 @@ describe Grape::Entity do
67
71
  child_class.exposures[:name].should have_key :proc
68
72
  end
69
73
  end
74
+
75
+ context 'register formatters' do
76
+ let(:date_formatter) { lambda {|date| date.strftime('%m/%d/%Y') }}
77
+
78
+ it 'should register a formatter' do
79
+ subject.format_with :timestamp, &date_formatter
80
+
81
+ subject.formatters[:timestamp].should_not be_nil
82
+ end
83
+
84
+ it 'should inherit formatters from ancestors' do
85
+ subject.format_with :timestamp, &date_formatter
86
+ child_class = Class.new(subject)
87
+
88
+ child_class.formatters.should == subject.formatters
89
+ end
90
+
91
+ it 'should not allow registering a formatter without a block' do
92
+ expect{ subject.format_with :foo }.to raise_error(ArgumentError)
93
+ end
94
+
95
+ it 'should format an exposure with a registered formatter' do
96
+ subject.format_with :timestamp do |date|
97
+ date.strftime('%m/%d/%Y')
98
+ end
99
+
100
+ subject.expose :birthday, :format_with => :timestamp
101
+
102
+ model = { :birthday => Time.gm(2012, 2, 27) }
103
+ subject.new(mock(model)).as_json[:birthday].should == '02/27/2012'
104
+ end
105
+ end
70
106
  end
71
107
 
72
108
  describe '.represent' do
@@ -201,11 +237,13 @@ describe Grape::Entity do
201
237
  context 'instance methods' do
202
238
  let(:model){ mock(attributes) }
203
239
  let(:attributes){ {
204
- :name => 'Bob Bobson',
240
+ :name => 'Bob Bobson',
205
241
  :email => 'bob@example.com',
242
+ :birthday => Time.gm(2012, 2, 27),
243
+ :fantasies => ['Unicorns', 'Double Rainbows', 'Nessy'],
206
244
  :friends => [
207
- mock(:name => "Friend 1", :email => 'friend1@example.com', :friends => []),
208
- mock(:name => "Friend 2", :email => 'friend2@example.com', :friends => [])
245
+ mock(:name => "Friend 1", :email => 'friend1@example.com', :fantasies => [], :birthday => Time.gm(2012, 2, 27), :friends => []),
246
+ mock(:name => "Friend 2", :email => 'friend2@example.com', :fantasies => [], :birthday => Time.gm(2012, 2, 27), :friends => [])
209
247
  ]
210
248
  } }
211
249
  subject{ fresh_class.new(model) }
@@ -229,6 +267,14 @@ describe Grape::Entity do
229
267
  expose :computed do |object, options|
230
268
  options[:awesome]
231
269
  end
270
+
271
+ expose :birthday, :format_with => :timestamp
272
+
273
+ def timestamp(date)
274
+ date.strftime('%m/%d/%Y')
275
+ end
276
+
277
+ expose :fantasies, :format_with => lambda {|f| f.reverse }
232
278
  end
233
279
  end
234
280
 
@@ -261,6 +307,31 @@ describe Grape::Entity do
261
307
  it 'should call through to the proc if there is one' do
262
308
  subject.send(:value_for, :computed, :awesome => 123).should == 123
263
309
  end
310
+
311
+ it 'should return a formatted value if format_with is passed' do
312
+ subject.send(:value_for, :birthday).should == '02/27/2012'
313
+ end
314
+
315
+ it 'should return a formatted value if format_with is passed a lambda' do
316
+ subject.send(:value_for, :fantasies).should == ['Nessy', 'Double Rainbows', 'Unicorns']
317
+ end
318
+ end
319
+
320
+ describe '#documentation' do
321
+ it 'should return an empty hash is no documentation is provided' do
322
+ fresh_class.expose :name
323
+
324
+ subject.documentation.should == {}
325
+ end
326
+
327
+ it 'should return each defined documentation hash' do
328
+ doc = {:type => "foo", :desc => "bar"}
329
+ fresh_class.expose :name, :documentation => doc
330
+ fresh_class.expose :email, :documentation => doc
331
+ fresh_class.expose :birthday
332
+
333
+ subject.documentation.should == {:name => doc, :email => doc}
334
+ end
264
335
  end
265
336
 
266
337
  describe '#key_for' do
@@ -10,7 +10,7 @@ describe Grape::Middleware::Formatter do
10
10
  it 'should look at the bodies for possibly serializable data' do
11
11
  @body = {"abc" => "def"}
12
12
  status, headers, bodies = *subject.call({'PATH_INFO' => '/somewhere', 'HTTP_ACCEPT' => 'application/json'})
13
- bodies.each{|b| b.should == MultiJson.encode(@body) }
13
+ bodies.each{|b| b.should == MultiJson.dump(@body) }
14
14
  end
15
15
 
16
16
  it 'should call #to_json first if it is available' do
@@ -82,11 +82,6 @@ describe Grape::Middleware::Formatter do
82
82
  subject.call({'PATH_INFO' => '/info.txt', 'HTTP_ACCEPT' => 'application/json'})
83
83
  subject.env['api.format'].should == :txt
84
84
  end
85
-
86
- it 'should throw an error on an unrecognized format' do
87
- err = catch(:error){ subject.call({'PATH_INFO' => '/info.barklar'}) }
88
- err.should == {:status => 406, :message => "The requested format is not supported."}
89
- end
90
85
  end
91
86
 
92
87
  context 'Accept header detection' do
@@ -121,6 +116,11 @@ describe Grape::Middleware::Formatter do
121
116
  subject.call({'PATH_INFO' => '/info', 'HTTP_ACCEPT' => 'application/vnd.test-v1+xml'})
122
117
  subject.env['api.format'].should == :xml
123
118
  end
119
+
120
+ it 'should properly parse headers with symbols as hash keys' do
121
+ subject.call({'PATH_INFO' => '/info', 'http_accept' => 'application/xml', :system_time => '091293'})
122
+ subject.env[:system_time].should == '091293'
123
+ end
124
124
  end
125
125
 
126
126
  context 'Content-type' do
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+
3
+ describe Grape::Middleware::Versioner::Param do
4
+
5
+ let(:app) { lambda{|env| [200, env, env['api.version']]} }
6
+ subject { Grape::Middleware::Versioner::Param.new(app, @options || {}) }
7
+
8
+ it 'should set the API version based on the default param (apiver)' do
9
+ env = Rack::MockRequest.env_for("/awesome", {:params => {"apiver" => "v1"}})
10
+ subject.call(env)[1]["api.version"].should == 'v1'
11
+ end
12
+
13
+ it 'should cut (only) the version out of the params', :focus => true do
14
+ env = Rack::MockRequest.env_for("/awesome", {:params => {"apiver" => "v1", "other_param" => "5"}})
15
+ subject.call(env)[1]['rack.request.query_hash']["apiver"].should be_nil
16
+ subject.call(env)[1]['rack.request.query_hash']["other_param"].should == "5"
17
+ end
18
+
19
+ it 'should provide a nil version if no version is given' do
20
+ env = Rack::MockRequest.env_for("/")
21
+ subject.call(env).last.should be_nil
22
+ end
23
+
24
+ context 'with specified parameter name' do
25
+ before{ @options = {:parameter => ['v']}}
26
+ it 'should set the API version based on the custom parameter name' do
27
+ env = Rack::MockRequest.env_for("/awesome", {:params => {"v" => "v1"}})
28
+ s = subject.call(env)[1]["api.version"] == "v1"
29
+ end
30
+ it 'should not set the API version based on the default param' do
31
+ env = Rack::MockRequest.env_for("/awesome", {:params => {"apiver" => "v1"}})
32
+ s = subject.call(env)[1]["api.version"] == nil
33
+ end
34
+ end
35
+
36
+ context 'with specified versions' do
37
+ before{ @options = {:versions => ['v1', 'v2']}}
38
+ it 'should throw an error if a non-allowed version is specified' do
39
+ env = Rack::MockRequest.env_for("/awesome", {:params => {"apiver" => "v3"}})
40
+ catch(:error){subject.call(env)}[:status].should == 404
41
+ end
42
+
43
+ it 'should allow versions that have been specified' do
44
+ env = Rack::MockRequest.env_for("/awesome", {:params => {"apiver" => "v1"}})
45
+ subject.call(env)[1]["api.version"].should == 'v1'
46
+ end
47
+ end
48
+
49
+ it 'should return a 200 when no version is set (matches the first version found)' do
50
+ @options = {
51
+ :versions => ['v1'],
52
+ :version_options => {:using => :header}
53
+ }
54
+ env = Rack::MockRequest.env_for("/awesome", {:params => {}})
55
+ subject.call(env).first.should == 200
56
+ end
57
+
58
+ end
@@ -9,4 +9,8 @@ describe Grape::Middleware::Versioner do
9
9
  it 'should recognize :header' do
10
10
  klass.using(:header).should == Grape::Middleware::Versioner::Header
11
11
  end
12
+
13
+ it 'should recognize :param' do
14
+ klass.using(:param).should == Grape::Middleware::Versioner::Param
15
+ end
12
16
  end
@@ -6,6 +6,8 @@ def versioned_path(options = {})
6
6
  case options[:using]
7
7
  when :path
8
8
  File.join('/', options[:prefix] || '', options[:version], options[:path])
9
+ when :param
10
+ File.join('/', options[:prefix] || '', options[:path])
9
11
  when :header
10
12
  File.join('/', options[:prefix] || '', options[:path])
11
13
  else
@@ -17,6 +19,8 @@ def versioned_headers(options)
17
19
  case options[:using]
18
20
  when :path
19
21
  {} # no-op
22
+ when :param
23
+ {} # no-op
20
24
  when :header
21
25
  {
22
26
  'HTTP_ACCEPT' => "application/vnd.#{options[:vendor]}-#{options[:version]}+#{options[:format]}"
@@ -29,6 +33,10 @@ end
29
33
  def versioned_get(path, version_name, version_options = {})
30
34
  path = versioned_path(version_options.merge(:version => version_name, :path => path))
31
35
  headers = versioned_headers(version_options.merge(:version => version_name))
32
- get path, {}, headers
36
+ params = {}
37
+ if version_options[:using] == :param
38
+ params = { version_options[:parameter] => version_name }
39
+ end
40
+ get path, params, headers
33
41
  end
34
42
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grape
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-28 00:00:00.000000000 Z
12
+ date: 2012-07-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
16
- requirement: &70235092969660 !ruby/object:Gem::Requirement
16
+ requirement: &70130298033500 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70235092969660
24
+ version_requirements: *70130298033500
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rack-mount
27
- requirement: &70235092968600 !ruby/object:Gem::Requirement
27
+ requirement: &70130298033080 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70235092968600
35
+ version_requirements: *70130298033080
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: multi_json
38
- requirement: &70235092967620 !ruby/object:Gem::Requirement
38
+ requirement: &70130298032660 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70235092967620
46
+ version_requirements: *70130298032660
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: multi_xml
49
- requirement: &70235092998440 !ruby/object:Gem::Requirement
49
+ requirement: &70130298032240 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *70235092998440
57
+ version_requirements: *70130298032240
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: hashie
60
- requirement: &70235092992580 !ruby/object:Gem::Requirement
60
+ requirement: &70130298031740 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '1.2'
66
66
  type: :runtime
67
67
  prerelease: false
68
- version_requirements: *70235092992580
68
+ version_requirements: *70130298031740
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rake
71
- requirement: &70235093020680 !ruby/object:Gem::Requirement
71
+ requirement: &70130298031320 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *70235093020680
79
+ version_requirements: *70130298031320
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: maruku
82
- requirement: &70235093014740 !ruby/object:Gem::Requirement
82
+ requirement: &70130298030860 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '0'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *70235093014740
90
+ version_requirements: *70130298030860
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: yard
93
- requirement: &70235093028820 !ruby/object:Gem::Requirement
93
+ requirement: &70130298030440 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: '0'
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *70235093028820
101
+ version_requirements: *70130298030440
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: rack-test
104
- requirement: &70235093028060 !ruby/object:Gem::Requirement
104
+ requirement: &70130298030020 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ! '>='
@@ -109,10 +109,10 @@ dependencies:
109
109
  version: '0'
110
110
  type: :development
111
111
  prerelease: false
112
- version_requirements: *70235093028060
112
+ version_requirements: *70130298030020
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: rspec
115
- requirement: &70235093027200 !ruby/object:Gem::Requirement
115
+ requirement: &70130298029520 !ruby/object:Gem::Requirement
116
116
  none: false
117
117
  requirements:
118
118
  - - ~>
@@ -120,10 +120,10 @@ dependencies:
120
120
  version: '2.9'
121
121
  type: :development
122
122
  prerelease: false
123
- version_requirements: *70235093027200
123
+ version_requirements: *70130298029520
124
124
  - !ruby/object:Gem::Dependency
125
125
  name: bundler
126
- requirement: &70235093025280 !ruby/object:Gem::Requirement
126
+ requirement: &70130298029100 !ruby/object:Gem::Requirement
127
127
  none: false
128
128
  requirements:
129
129
  - - ! '>='
@@ -131,7 +131,7 @@ dependencies:
131
131
  version: '0'
132
132
  type: :development
133
133
  prerelease: false
134
- version_requirements: *70235093025280
134
+ version_requirements: *70130298029100
135
135
  description: A Ruby framework for rapid API development with great conventions.
136
136
  email:
137
137
  - michael@intridea.com
@@ -143,6 +143,7 @@ files:
143
143
  - .gitignore
144
144
  - .rspec
145
145
  - .travis.yml
146
+ - CHANGELOG.markdown
146
147
  - Gemfile
147
148
  - Guardfile
148
149
  - LICENSE
@@ -164,6 +165,7 @@ files:
164
165
  - lib/grape/middleware/prefixer.rb
165
166
  - lib/grape/middleware/versioner.rb
166
167
  - lib/grape/middleware/versioner/header.rb
168
+ - lib/grape/middleware/versioner/param.rb
167
169
  - lib/grape/middleware/versioner/path.rb
168
170
  - lib/grape/route.rb
169
171
  - lib/grape/util/hash_stack.rb
@@ -180,6 +182,7 @@ files:
180
182
  - spec/grape/middleware/formatter_spec.rb
181
183
  - spec/grape/middleware/prefixer_spec.rb
182
184
  - spec/grape/middleware/versioner/header_spec.rb
185
+ - spec/grape/middleware/versioner/param_spec.rb
183
186
  - spec/grape/middleware/versioner/path_spec.rb
184
187
  - spec/grape/middleware/versioner_spec.rb
185
188
  - spec/grape/util/hash_stack_spec.rb
@@ -204,7 +207,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
204
207
  version: '0'
205
208
  segments:
206
209
  - 0
207
- hash: -1598569611300110668
210
+ hash: 2226649609976967092
208
211
  required_rubygems_version: !ruby/object:Gem::Requirement
209
212
  none: false
210
213
  requirements:
@@ -213,10 +216,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
213
216
  version: '0'
214
217
  segments:
215
218
  - 0
216
- hash: -1598569611300110668
219
+ hash: 2226649609976967092
217
220
  requirements: []
218
221
  rubyforge_project: grape
219
- rubygems_version: 1.8.11
222
+ rubygems_version: 1.8.10
220
223
  signing_key:
221
224
  specification_version: 3
222
225
  summary: A simple Ruby framework for building REST-like APIs.
@@ -233,6 +236,7 @@ test_files:
233
236
  - spec/grape/middleware/formatter_spec.rb
234
237
  - spec/grape/middleware/prefixer_spec.rb
235
238
  - spec/grape/middleware/versioner/header_spec.rb
239
+ - spec/grape/middleware/versioner/param_spec.rb
236
240
  - spec/grape/middleware/versioner/path_spec.rb
237
241
  - spec/grape/middleware/versioner_spec.rb
238
242
  - spec/grape/util/hash_stack_spec.rb