diff options
Diffstat (limited to 'actionview/lib/action_view/flows.rb')
-rw-r--r-- | actionview/lib/action_view/flows.rb | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/actionview/lib/action_view/flows.rb b/actionview/lib/action_view/flows.rb new file mode 100644 index 0000000000..ba24510e56 --- /dev/null +++ b/actionview/lib/action_view/flows.rb @@ -0,0 +1,76 @@ +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] = 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 are inside the layout + # fiber, we set that we are 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 provides and resumes back to the fiber if it is + # the key it is 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 |