Skip to content

Commit 5fec2a6

Browse files
committed
squash! un-deprecate stream-like objects
- fully deprecate file - add sendfile as replacement
1 parent 726b59d commit 5fec2a6

File tree

5 files changed

+165
-52
lines changed

5 files changed

+165
-52
lines changed

README.md

+12-2
Original file line numberDiff line numberDiff line change
@@ -3168,12 +3168,22 @@ end
31683168
31693169
Use `body false` to return `204 No Content` without any data or content-type.
31703170
3171-
You can also set the response to a file with `file` and it will be streamed using `Rack::Chunked`.
3171+
You can also set the response to a file with `sendfile`
31723172
31733173
```ruby
31743174
class API < Grape::API
31753175
get '/' do
3176-
file '/path/to/file'
3176+
sendfile '/path/to/file'
3177+
end
3178+
end
3179+
```
3180+
3181+
To stream a file use `stream`
3182+
3183+
```ruby
3184+
class API < Grape::API
3185+
get '/' do
3186+
stream '/path/to/file'
31773187
end
31783188
end
31793189
```

UPGRADING.md

+14-3
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,28 @@ Upgrading Grape
77

88
Previously in 0.16 stream-like objects were deprecated. This release restores their functionality for use-cases other than file streaming.
99

10-
For streaming files, use `file` always.
10+
This release also renamed `file` to `sendfile` to better document it's purpose.
1111

12+
To deliver a file via `sendfile` if available do this.
1213
```ruby
1314
class API < Grape::API
1415
get '/' do
15-
file '/path/to/file'
16+
sendfile '/path/to/file'
17+
end
18+
end
19+
```
20+
21+
Use `stream` to stream files
22+
23+
```ruby
24+
class API < Grape::API
25+
get '/' do
26+
stream '/path/to/file'
1627
end
1728
end
1829
```
1930

20-
Use `stream` to stream other kinds of content. In the following example a streamer class
31+
Or use `stream` to stream other kinds of content. In the following example a streamer class
2132
streams paginated data from a database.
2233

2334
```ruby

lib/grape/dsl/inside_route.rb

+21-8
Original file line numberDiff line numberDiff line change
@@ -279,21 +279,34 @@ def return_no_content
279279
body false
280280
end
281281

282-
# Allows you to define the response as a file-like object.
282+
# Deprecated method to send files to the client. Use `sendfile` or `stream`
283+
def file(value = nil)
284+
if value.is_a?(String)
285+
warn '[DEPRECATION] Use sendfile or stream to send files.'
286+
sendfile(value)
287+
elsif !value.is_a?(NilClass)
288+
warn '[DEPRECATION] Use stream to use a Stream object.'
289+
stream(value)
290+
else
291+
warn '[DEPRECATION] Use sendfile or stream to send files.'
292+
sendfile
293+
end
294+
end
295+
296+
# Allows you to send a file to the client via sendfile.
283297
#
284298
# @example
285299
# get '/file' do
286-
# file FileStreamer.new(...)
300+
# sendfile FileStreamer.new(...)
287301
# end
288302
#
289303
# GET /file # => "contents of file"
290-
def file(value = nil)
304+
def sendfile(value = nil)
291305
if value.is_a?(String)
292306
file_body = Grape::ServeStream::FileBody.new(value)
293-
stream(file_body)
307+
@stream = Grape::ServeStream::StreamResponse.new(file_body)
294308
elsif !value.is_a?(NilClass)
295-
warn '[DEPRECATION] Argument as FileStreamer-like object is deprecated. Use path to file instead or stream to use a Stream object.'
296-
stream(value)
309+
raise ArgumentError, 'Argument must be a file path'
297310
else
298311
stream
299312
end
@@ -319,8 +332,8 @@ def stream(value = nil)
319332
header 'Transfer-Encoding', nil
320333
header 'Cache-Control', 'no-cache' # Skips ETag generation (reading the response up front)
321334
if value.is_a?(String)
322-
warn '[DEPRECATION] Use `file file_path` to stream a file instead.'
323-
file(value)
335+
file_body = Grape::ServeStream::FileBody.new(value)
336+
@stream = Grape::ServeStream::StreamResponse.new(file_body)
324337
elsif value.respond_to?(:each)
325338
@stream = Grape::ServeStream::StreamResponse.new(value)
326339
elsif !value.is_a?(NilClass)

lib/grape/endpoint.rb

+3-3
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ def initialize(new_settings, options = {}, &block)
9999
@block = nil
100100

101101
@status = nil
102-
@file = nil
102+
@stream = nil
103103
@body = nil
104104
@proc = nil
105105

@@ -271,8 +271,8 @@ def run
271271
# status verifies body presence when DELETE
272272
@body ||= response_object
273273

274-
# The body commonly is an Array of Strings, the application instance itself, or a File-like object
275-
response_object = file || [body]
274+
# The body commonly is an Array of Strings, the application instance itself, or a Stream-like object
275+
response_object = stream || [body]
276276

277277
[status, header, response_object]
278278
ensure

spec/grape/dsl/inside_route_spec.rb

+115-36
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,60 @@ def initialize
203203
end
204204

205205
describe '#file' do
206+
before do
207+
allow(subject).to receive(:warn)
208+
end
209+
210+
describe 'set' do
211+
context 'as file path' do
212+
let(:file_path) { '/some/file/path' }
213+
214+
it 'emits a warning that this method is deprecated' do
215+
expect(subject).to receive(:warn).with(/Use sendfile or stream/)
216+
217+
subject.file file_path
218+
end
219+
220+
it 'forwards the call to sendfile' do
221+
expect(subject).to receive(:sendfile).with(file_path)
222+
223+
subject.file file_path
224+
end
225+
end
226+
227+
context 'as object (backward compatibility)' do
228+
let(:file_object) { double('StreamerObject', each: nil) }
229+
230+
it 'emits a warning that this method is deprecated' do
231+
expect(subject).to receive(:warn).with(/Use stream to use a Stream object/)
232+
233+
subject.file file_object
234+
end
235+
236+
it 'forwards the call to stream' do
237+
expect(subject).to receive(:stream).with(file_object)
238+
239+
subject.file file_object
240+
end
241+
end
242+
end
243+
244+
describe 'get' do
245+
it 'emits a warning that this method is deprecated' do
246+
expect(subject).to receive(:warn).with(/Use sendfile or stream/)
247+
248+
subject.file
249+
end
250+
251+
it 'fowards call to sendfile' do
252+
expect(subject).to receive(:sendfile)
253+
254+
subject.file
255+
end
256+
end
257+
end
258+
259+
describe '#sendfile' do
206260
describe 'set' do
207261
context 'as file path' do
208262
let(:file_path) { '/some/file/path' }
@@ -216,60 +270,56 @@ def initialize
216270
subject.header 'Cache-Control', 'cache'
217271
subject.header 'Content-Length', 123
218272
subject.header 'Transfer-Encoding', 'base64'
219-
220-
subject.file file_path
221273
end
222274

223-
it 'returns value wrapped in StreamResponse' do
224-
expect(subject.file).to eq file_response
225-
end
275+
it 'sends no deprecation warnings' do
276+
expect(subject).to_not receive(:warn)
226277

227-
it 'sets Cache-Control header to no-cache' do
228-
expect(subject.header['Cache-Control']).to eq 'no-cache'
278+
subject.sendfile file_path
229279
end
230280

231-
it 'sets Content-Length header to nil' do
232-
expect(subject.header['Content-Length']).to eq nil
233-
end
281+
it 'returns value wrapped in StreamResponse' do
282+
subject.sendfile file_path
234283

235-
it 'sets Transfer-Encoding header to nil' do
236-
expect(subject.header['Transfer-Encoding']).to eq nil
284+
expect(subject.sendfile).to eq file_response
237285
end
238-
end
239286

240-
context 'as object (backward compatibility)' do
241-
let(:file_object) { double('StreamerObject', each: nil) }
287+
it 'does not change the Cache-Control header' do
288+
subject.sendfile file_path
242289

243-
let(:file_response) do
244-
Grape::ServeStream::StreamResponse.new(file_object)
290+
expect(subject.header['Cache-Control']).to eq 'cache'
245291
end
246292

247-
before do
248-
allow(subject).to receive(:warn)
293+
it 'does not change the Content-Length header' do
294+
subject.sendfile file_path
295+
296+
expect(subject.header['Content-Length']).to eq 123
249297
end
250298

251-
it 'emits a warning that a stream object should be sent to the stream method' do
252-
expect(subject).to receive(:warn).with(/Argument as FileStreamer-like/)
299+
it 'does not change the Transfer-Encoding header' do
300+
subject.sendfile file_path
253301

254-
subject.file file_object
302+
expect(subject.header['Transfer-Encoding']).to eq 'base64'
255303
end
304+
end
256305

257-
it 'returns value wrapped in StreamResponse' do
258-
subject.file file_object
306+
context 'as object' do
307+
let(:file_object) { double('StreamerObject', each: nil) }
259308

260-
expect(subject.file).to eq file_response
309+
it 'raises an error that only a file path is supported' do
310+
expect { subject.sendfile file_object }.to raise_error(ArgumentError, /Argument must be a file path/)
261311
end
262312
end
263313
end
264314

265315
it 'returns default' do
266-
expect(subject.file).to be nil
316+
expect(subject.sendfile).to be nil
267317
end
268318
end
269319

270320
describe '#stream' do
271321
describe 'set' do
272-
context 'as a file path (backward compatibility)' do
322+
context 'as a file path' do
273323
let(:file_path) { '/some/file/path' }
274324

275325
let(:file_response) do
@@ -278,19 +328,39 @@ def initialize
278328
end
279329

280330
before do
281-
allow(subject).to receive(:warn)
331+
subject.header 'Cache-Control', 'cache'
332+
subject.header 'Content-Length', 123
333+
subject.header 'Transfer-Encoding', 'base64'
282334
end
283335

284-
it 'emits a warning to use file method to stream a file' do
285-
expect(subject).to receive(:warn).with(/file file_path/)
336+
it 'emits no deprecation warnings' do
337+
expect(subject).to_not receive(:warn)
286338

287339
subject.stream file_path
288340
end
289341

290-
it 'returns value wrapped in StreamResponse' do
342+
it 'returns file body wrapped in StreamResponse' do
343+
subject.stream file_path
344+
345+
expect(subject.stream).to eq file_response
346+
end
347+
348+
it 'sets Cache-Control header to no-cache' do
291349
subject.stream file_path
292350

293-
expect(subject.file).to eq file_response
351+
expect(subject.header['Cache-Control']).to eq 'no-cache'
352+
end
353+
354+
it 'sets Content-Length header to nil' do
355+
subject.stream file_path
356+
357+
expect(subject.header['Content-Length']).to eq nil
358+
end
359+
360+
it 'sets Transfer-Encoding header to nil' do
361+
subject.stream file_path
362+
363+
expect(subject.header['Transfer-Encoding']).to eq nil
294364
end
295365
end
296366

@@ -305,26 +375,35 @@ def initialize
305375
subject.header 'Cache-Control', 'cache'
306376
subject.header 'Content-Length', 123
307377
subject.header 'Transfer-Encoding', 'base64'
378+
end
379+
380+
it 'emits no deprecation warnings' do
381+
expect(subject).to_not receive(:warn)
382+
308383
subject.stream stream_object
309384
end
310385

311386
it 'returns value wrapped in StreamResponse' do
312-
expect(subject.stream).to eq stream_response
313-
end
387+
subject.stream stream_object
314388

315-
it 'also sets result of file to value wrapped in StreamResponse' do
316-
expect(subject.file).to eq stream_response
389+
expect(subject.stream).to eq stream_response
317390
end
318391

319392
it 'sets Cache-Control header to no-cache' do
393+
subject.stream stream_object
394+
320395
expect(subject.header['Cache-Control']).to eq 'no-cache'
321396
end
322397

323398
it 'sets Content-Length header to nil' do
399+
subject.stream stream_object
400+
324401
expect(subject.header['Content-Length']).to eq nil
325402
end
326403

327404
it 'sets Transfer-Encoding header to nil' do
405+
subject.stream stream_object
406+
328407
expect(subject.header['Transfer-Encoding']).to eq nil
329408
end
330409
end

0 commit comments

Comments
 (0)