module Roda::RodaPlugins::Chunked::InstanceMethods

def chunked(template, opts=OPTS, &block)

an overview. If a block is given, it is passed to #delay.
Render a response to the user in chunks. See Chunked for
def chunked(template, opts=OPTS, &block)
  unless defined?(@_chunked)
    @_chunked = !self.opts[:force_chunked_encoding] || @_request.http_version == "HTTP/1.1" 
  end
  if block
    delay(&block)
  end
  unless @_chunked
    # If chunking is disabled, do a normal rendering of the view.
    run_delayed_blocks
    return view(template, opts)
  end
  if template.is_a?(Hash)
    if opts.empty?
      opts = template
    else
      opts = Hash[opts].merge!(template)
    end
  end
  
  # Hack so that the arguments don't need to be passed
  # through the response and body objects.
  @_each_chunk_args = [template, opts]
  res = response
  headers = res.headers
  if chunk_headers = self.opts[:chunk_headers]
    headers.merge!(chunk_headers)
  end
  if self.opts[:force_chunked_encoding]
    res[RodaResponseHeaders::TRANSFER_ENCODING] = 'chunked'
    body = Body.new(self)
  else
    body = StreamBody.new(self)
  end
  throw :halt, res.finish_with_body(body)
end

def delay(&block)

content template is to be rendered.
Delay the execution of the block until right before the
def delay(&block)
  raise RodaError, "must pass a block to Roda#delay" unless block
  (@_delays ||= []) << block
end

def each_chunk

Yield each chunk of the template rendering separately.
def each_chunk
  response.body.each{|s| yield s}
  template, opts = @_each_chunk_args
  # Use a lambda for the flusher, so that a call to flush
  # by a template can result in this method yielding a chunk
  # of the response.
  @_flusher = lambda do
    yield @_out_buf
    @_out_buf = String.new
  end
  if layout_opts  = view_layout_opts(opts)
    @_out_buf = render_template(layout_opts) do
      flush
      run_delayed_blocks
      yield opts[:content] || render_template(template, opts)
      nil
    end
  else
    run_delayed_blocks
    yield view(template, opts)
  end
  flush
rescue => e
  handle_chunk_error(e)
end

def flush

things if chunking is not used.
is a no-op, so flush can be used inside views without breaking
Call the flusher if one is defined. If one is not defined, this
def flush
  @_flusher.call if @_flusher
end

def handle_chunk_error(e)

By default, raise the exception.
def handle_chunk_error(e)
  raise e
end

def no_chunk!

chunking is turned on by default.
Disable chunking for the current request. Mostly useful when
def no_chunk!
  @_chunked = false
end

def run_delayed_blocks

Run all delayed blocks
def run_delayed_blocks
  return unless @_delays
  @_delays.each(&:call)
end

def view(*a)

called and chunking is not specifically disabled.
If chunking by default, call chunked if it hasn't yet been
def view(*a)
  if opts[:chunk_by_default] && !defined?(@_chunked) && !defined?(yield)
    chunked(*a)
  else
    super
  end
end