I am rather surprised by this declaration, because Rack response bodies do indeed behave like "IO objects": they respond to `each`. That's the only requirement. Guess what responds to `each`? IO.
The problem seems entirely self-inflicted by Rails: if it builds an eager, non-streaming Response object, that means you can't stream with it. But it's got nothing whatsoever to do with Rack. By comparison, Rack's own Response helper object does provide easy streaming access: calls to `Response#write` within the `Response#finish` block are streamed directly. Your code would look roughly like this in e.g. Sinatra (note: entirely untested):
response.finish do
100.times {
response.write "hello, world\n"
}
end
Alternatively, you could implement your own #each: class Stream
def each
100.times { yield "hello, world\n" }
end
end
get('/') { Stream.new }
this one is straight from the Sinatra docs[0], and aside from the `get` call it can trivially be converted to a raw Rack application: lambda do |env|
[200, {'Content-Type' => 'application/octet-stream'}, Stream.new]
end
[0] Sinatra also provides a `stream` helper method which does most of the wrapping and tries to make non-streaming-aware middleware play nicely, that can be used in stead of these lower-level calls: http://www.sinatrarb.com/contrib/streaming.html