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