123456789_123456789_123456789_123456789_123456789_

Module: Sinatra::Streaming

Relationships & Source Files
Namespace Children
Modules:
Defined in: sinatra-contrib/lib/sinatra/streaming.rb

Overview

::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

Instance Method Summary

Instance Method Details

#stream

[ GitHub ]

  
# File 'sinatra-contrib/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