Skip to content

Commit 2ec51f7

Browse files
committed
Merge pull request #1026 from dblock/endpoint-file
Added file, explicitly set file-like response object.
2 parents 7a2761d + 1505d47 commit 2ec51f7

File tree

9 files changed

+110
-23
lines changed

9 files changed

+110
-23
lines changed

.rubocop_todo.yml

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,52 @@
11
# This configuration was generated by `rubocop --auto-gen-config`
2-
# on 2014-12-16 11:52:50 -0500 using RuboCop version 0.29.1.
2+
# on 2015-06-03 09:20:43 -0400 using RuboCop version 0.29.1.
33
# The point is for the user to remove these configuration records
44
# one by one as the offenses are removed from the code base.
55
# Note that changes in the inspected code, or installation of new
66
# versions of RuboCop, may require this file to be generated again.
77

8-
# Offense count: 29
8+
# Offense count: 33
99
# Cop supports --auto-correct.
1010
Lint/UnusedBlockArgument:
1111
Enabled: false
1212

13-
# Offense count: 26
13+
# Offense count: 27
1414
# Cop supports --auto-correct.
1515
Lint/UnusedMethodArgument:
1616
Enabled: false
1717

18-
# Offense count: 35
18+
# Offense count: 37
1919
Metrics/AbcSize:
20-
Max: 50
20+
Max: 48
2121

22-
# Offense count: 1
22+
# Offense count: 2
2323
Metrics/BlockNesting:
2424
Max: 4
2525

2626
# Offense count: 4
2727
# Configuration parameters: CountComments.
2828
Metrics/ClassLength:
29-
Max: 245
29+
Max: 246
3030

31-
# Offense count: 15
31+
# Offense count: 23
3232
Metrics/CyclomaticComplexity:
3333
Max: 20
3434

35-
# Offense count: 545
35+
# Offense count: 676
3636
# Configuration parameters: AllowURI, URISchemes.
3737
Metrics/LineLength:
3838
Max: 198
3939

40-
# Offense count: 42
40+
# Offense count: 44
4141
# Configuration parameters: CountComments.
4242
Metrics/MethodLength:
4343
Max: 35
4444

45-
# Offense count: 13
45+
# Offense count: 17
4646
Metrics/PerceivedComplexity:
4747
Max: 22
4848

49-
# Offense count: 26
49+
# Offense count: 46
5050
# Cop supports --auto-correct.
5151
Style/Blocks:
5252
Enabled: false
@@ -57,7 +57,7 @@ Style/Blocks:
5757
Style/ClassCheck:
5858
Enabled: false
5959

60-
# Offense count: 157
60+
# Offense count: 174
6161
Style/Documentation:
6262
Enabled: false
6363

@@ -73,7 +73,7 @@ Style/EachWithObject:
7373
Style/EmptyElse:
7474
Enabled: false
7575

76-
# Offense count: 14
76+
# Offense count: 15
7777
# Configuration parameters: MinBodyLength.
7878
Style/GuardClause:
7979
Enabled: false
@@ -89,7 +89,8 @@ Style/HashSyntax:
8989
Style/IndentArray:
9090
Enabled: false
9191

92-
# Offense count: 18
92+
# Offense count: 20
93+
# Cop supports --auto-correct.
9394
Style/Lambda:
9495
Enabled: false
9596

@@ -109,7 +110,7 @@ Style/PercentLiteralDelimiters:
109110
Style/PredicateName:
110111
Enabled: false
111112

112-
# Offense count: 9
113+
# Offense count: 13
113114
# Configuration parameters: EnforcedStyle, SupportedStyles.
114115
Style/RaiseArgs:
115116
Enabled: false
@@ -119,7 +120,7 @@ Style/RaiseArgs:
119120
Style/RegexpLiteral:
120121
Enabled: false
121122

122-
# Offense count: 4
123+
# Offense count: 11
123124
# Cop supports --auto-correct.
124125
# Configuration parameters: EnforcedStyle, SupportedStyles.
125126
Style/SpaceBeforeBlockBraces:

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
* [#952](https://github.com/intridea/grape/pull/952): Status method now raises error when called with invalid status code - [@dabrorius](https://github.com/dabrorius).
1212
* [#957](https://github.com/intridea/grape/pull/957): Regexp validator now supports `allow_blank`, `nil` value behavior changed - [@calfzhou](https://giihub.com/calfzhou).
1313
* [#962](https://github.com/intridea/grape/pull/962): The `default` attribute with `false` value is documented now - [@ajvondrak](https://github.com/ajvondrak).
14+
* [#1026](https://github.com/intridea/grape/pull/1026): Added `file` method, explicitly setting a file-like response object - [@dblock](https://github.com/dblock).
1415

1516
#### Fixes
1617

README.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2009,7 +2009,7 @@ class API < Grape::API
20092009
end
20102010
```
20112011
2012-
You can also set the response body explicitly with `body`.
2012+
You can set the response body explicitly with `body`.
20132013
20142014
```ruby
20152015
class API < Grape::API
@@ -2023,6 +2023,28 @@ end
20232023
20242024
Use `body false` to return `204 No Content` without any data or content-type.
20252025
2026+
You can also set the response to a file-like object with `file`.
2027+
2028+
```ruby
2029+
class FileStreamer
2030+
def initialize(file_path)
2031+
@file_path = file_path
2032+
end
2033+
2034+
def each(&blk)
2035+
File.open(@file_path, 'rb') do |file|
2036+
file.each(10, &blk)
2037+
end
2038+
end
2039+
end
2040+
2041+
class API < Grape::API
2042+
get '/' do
2043+
file FileStreamer.new('file.bin')
2044+
end
2045+
end
2046+
```
2047+
20262048
## Authentication
20272049
20282050
### Basic and Digest Auth

lib/grape/dsl/inside_route.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,22 @@ def body(value = nil)
169169
end
170170
end
171171

172+
# Allows you to define the response as a file-like object.
173+
#
174+
# @example
175+
# get '/file' do
176+
# file FileStreamer.new(...)
177+
# end
178+
#
179+
# GET /file # => "contents of file"
180+
def file(value = nil)
181+
if value
182+
@file = value
183+
else
184+
@file
185+
end
186+
end
187+
172188
# Allows you to make use of Grape Entities by setting
173189
# the response body to the serializable hash of the
174190
# entity provided in the `:with` option. This has the

lib/grape/endpoint.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,11 +248,13 @@ def run(env)
248248

249249
run_filters after_validations
250250

251-
response_text = @block ? @block.call(self) : nil
251+
response_object = @block ? @block.call(self) : nil
252252
run_filters afters
253253
cookies.write(header)
254254

255-
[status, header, [body || response_text]]
255+
# The Body commonly is an Array of Strings, the application instance itself, or a File-like object.
256+
response_object = file || [body || response_object]
257+
[status, header, response_object]
256258
end
257259

258260
def build_middleware

lib/grape/middleware/formatter.rb

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,13 @@ def after
2929
api_format = mime_types[headers[Grape::Http::Headers::CONTENT_TYPE]] || env['api.format']
3030
formatter = Grape::Formatter::Base.formatter_for api_format, options
3131
begin
32-
bodymap = bodies.collect do |body|
33-
formatter.call body, env
34-
end
32+
bodymap = if bodies.respond_to?(:collect)
33+
bodies.collect do |body|
34+
formatter.call body, env
35+
end
36+
else
37+
bodies
38+
end
3539
rescue Grape::Exceptions::InvalidFormatter => e
3640
throw :error, status: 500, message: e.message
3741
end

spec/grape/dsl/inside_route_spec.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,22 @@ def initialize
195195
end
196196
end
197197

198+
describe '#file' do
199+
describe 'set' do
200+
before do
201+
subject.file 'file'
202+
end
203+
204+
it 'returns value' do
205+
expect(subject.file).to eq 'file'
206+
end
207+
end
208+
209+
it 'returns default' do
210+
expect(subject.file).to be nil
211+
end
212+
end
213+
198214
describe '#route' do
199215
before do
200216
subject.env['rack.routing_args'] = {}

spec/grape/endpoint_spec.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -927,4 +927,18 @@ def memoized
927927
expect(last_response.status).to eq(406)
928928
end
929929
end
930+
931+
context 'binary' do
932+
before do
933+
subject.get do
934+
file FileStreamer.new(__FILE__)
935+
end
936+
end
937+
938+
it 'suports stream objects in response' do
939+
get '/'
940+
expect(last_response.status).to eq 200
941+
expect(last_response.body).to eq File.read(__FILE__)
942+
end
943+
end
930944
end

spec/support/file_streamer.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class FileStreamer
2+
def initialize(file_path)
3+
@file_path = file_path
4+
end
5+
6+
def each(&blk)
7+
File.open(@file_path, 'rb') do |file|
8+
file.each(10, &blk)
9+
end
10+
end
11+
end

0 commit comments

Comments
 (0)