mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
76 lines
1.8 KiB
Ruby
76 lines
1.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "active_support/core_ext/string/output_safety"
|
|
|
|
module ActionView
|
|
class OutputFlow #:nodoc:
|
|
attr_reader :content
|
|
|
|
def initialize
|
|
@content = Hash.new { |h, k| h[k] = ActiveSupport::SafeBuffer.new }
|
|
end
|
|
|
|
# Called by _layout_for to read stored values.
|
|
def get(key)
|
|
@content[key]
|
|
end
|
|
|
|
# Called by each renderer object to set the layout contents.
|
|
def set(key, value)
|
|
@content[key] = ActiveSupport::SafeBuffer.new(value)
|
|
end
|
|
|
|
# Called by content_for
|
|
def append(key, value)
|
|
@content[key] << value
|
|
end
|
|
alias_method :append!, :append
|
|
end
|
|
|
|
class StreamingFlow < OutputFlow #:nodoc:
|
|
def initialize(view, fiber)
|
|
@view = view
|
|
@parent = nil
|
|
@child = view.output_buffer
|
|
@content = view.view_flow.content
|
|
@fiber = fiber
|
|
@root = Fiber.current.object_id
|
|
end
|
|
|
|
# Try to get stored content. If the content
|
|
# is not available and we're inside the layout fiber,
|
|
# then it will begin waiting for the given key and yield.
|
|
def get(key)
|
|
return super if @content.key?(key)
|
|
|
|
if inside_fiber?
|
|
view = @view
|
|
|
|
begin
|
|
@waiting_for = key
|
|
view.output_buffer, @parent = @child, view.output_buffer
|
|
Fiber.yield
|
|
ensure
|
|
@waiting_for = nil
|
|
view.output_buffer, @child = @parent, view.output_buffer
|
|
end
|
|
end
|
|
|
|
super
|
|
end
|
|
|
|
# Appends the contents for the given key. This is called
|
|
# by providing and resuming back to the fiber,
|
|
# if that's the key it's waiting for.
|
|
def append!(key, value)
|
|
super
|
|
@fiber.resume if @waiting_for == key
|
|
end
|
|
|
|
private
|
|
|
|
def inside_fiber?
|
|
Fiber.current.object_id != @root
|
|
end
|
|
end
|
|
end
|