module Sinatra::Streaming
Sinatra::Streaming
Sinatra 1.3 introduced the
stream
helper. This addon improves the streaming API by making
the stream object imitate an IO object, turning it into a real Deferrable
and making the body play nicer with middleware unaware of streaming.
IO-like behavior
This is useful when passing the stream object to a library expecting an IO or StringIO object.
get '/' do stream do |out| out.puts "Hello World!", "How are you?" out.write "Written #{out.pos} bytes so far!\n" out.putc(65) unless out.closed? out.flush end end
Better Middleware Handling
Blocks passed to map! or map will actually be applied when streaming takes place (as you might have suspected, map! applies modifications to the current body, while map creates a new one):
class StupidMiddleware def initialize(app) @app = app end def call(env) status, headers, body = @app.call(env) body.map! { |e| e.upcase } [status, headers, body] end end use StupidMiddleware get '/' do stream do |out| out.puts "still" sleep 1 out.puts "streaming" end end
Even works if each is used to generate an Enumerator:
def call(env) status, headers, body = @app.call(env) body = body.each.map { |s| s.upcase } [status, headers, body] end
Note that both examples violate the Rack specification.
Setup
In a classic application:
require "sinatra" require "sinatra/streaming"
In a modular application:
require "sinatra/base" require "sinatra/streaming" class MyApp < Sinatra::Base helpers Sinatra::Streaming end
Public Instance Methods
stream(*)
click to toggle source
Calls superclass method
# File lib/sinatra/streaming.rb, line 79 def stream(*) stream = super stream.extend Stream stream.app = self env['async.close'].callback { stream.close } if env.key? 'async.close' stream end