aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
authorJosé Valim <jose.valim@gmail.com>2011-04-16 01:09:05 +0200
committerJosé Valim <jose.valim@gmail.com>2011-04-16 01:10:13 +0200
commitfad214b9e1c0a66f8fecde48fbd8d122e5c51e33 (patch)
tree3ca51e274e0992c460e28c81f501398757669899 /actionpack
parentc630750fa59e248fb5af96f850392333e341ccd7 (diff)
downloadrails-fad214b9e1c0a66f8fecde48fbd8d122e5c51e33.tar.gz
rails-fad214b9e1c0a66f8fecde48fbd8d122e5c51e33.tar.bz2
rails-fad214b9e1c0a66f8fecde48fbd8d122e5c51e33.zip
Initial work on fibered layout.
Diffstat (limited to 'actionpack')
-rw-r--r--actionpack/lib/action_view.rb1
-rw-r--r--actionpack/lib/action_view/base.rb53
-rw-r--r--actionpack/lib/action_view/helpers/capture_helper.rb6
-rw-r--r--actionpack/lib/action_view/renderer/fibered_template_renderer.rb35
-rw-r--r--actionpack/lib/action_view/renderer/partial_renderer.rb2
-rw-r--r--actionpack/lib/action_view/renderer/template_renderer.rb4
-rw-r--r--actionpack/lib/action_view/rendering.rb26
-rw-r--r--actionpack/test/template/capture_helper_test.rb2
-rw-r--r--actionpack/test/template/fibered_render_test.rb27
9 files changed, 137 insertions, 19 deletions
diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb
index 60665387b6..9b8b694646 100644
--- a/actionpack/lib/action_view.rb
+++ b/actionpack/lib/action_view.rb
@@ -44,6 +44,7 @@ module ActionView
autoload :AbstractRenderer
autoload :PartialRenderer
autoload :TemplateRenderer
+ autoload :FiberedTemplateRenderer
end
autoload_at "action_view/template/resolver" do
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index 7488127e35..10a523eeac 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -153,7 +153,7 @@ module ActionView #:nodoc:
end
end
- attr_accessor :_template
+ attr_accessor :_template, :_view_flow, :magic_medicine
attr_internal :request, :controller, :config, :assigns, :lookup_context
delegate :formats, :formats=, :locale, :locale=, :view_paths, :view_paths=, :to => :lookup_context
@@ -181,8 +181,8 @@ module ActionView #:nodoc:
self.helpers = Module.new unless self.class.helpers
@_config = {}
- @_content_for = Hash.new { |h,k| h[k] = ActiveSupport::SafeBuffer.new }
@_virtual_path = nil
+ @_view_flow = Flow.new
@output_buffer = nil
if @_controller = controller
@@ -195,10 +195,6 @@ module ActionView #:nodoc:
@_lookup_context.formats = formats if formats
end
- def store_content_for(key, value)
- @_content_for[key] = value
- end
-
def controller_path
@controller_path ||= controller && controller.controller_path
end
@@ -209,4 +205,49 @@ module ActionView #:nodoc:
ActiveSupport.run_load_hooks(:action_view, self)
end
+
+ class Flow
+ attr_reader :content
+
+ def initialize
+ @content = Hash.new { |h,k| h[k] = ActiveSupport::SafeBuffer.new }
+ end
+
+ def get(key)
+ @content[key]
+ end
+
+ def set(key, value)
+ @content[key] = value
+ end
+
+ def append(key, value)
+ @content[key] << value
+ end
+ end
+
+ class FiberedFlow < Flow
+ def initialize(flow, fiber)
+ @content = flow.content
+ @fiber = fiber
+ end
+
+ def get(key)
+ return super if @content.key?(key)
+
+ begin
+ @waiting_for = key
+ Fiber.yield
+ ensure
+ @waiting_for = nil
+ end
+
+ super
+ end
+
+ def set(key, value)
+ super
+ @fiber.resume if @waiting_for == key
+ end
+ end
end
diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb
index 3808e231f1..f8b5605ed9 100644
--- a/actionpack/lib/action_view/helpers/capture_helper.rb
+++ b/actionpack/lib/action_view/helpers/capture_helper.rb
@@ -135,8 +135,8 @@ module ActionView
# for elements that will be fragment cached.
def content_for(name, content = nil, &block)
content = capture(&block) if block_given?
- @_content_for[name] << content if content
- @_content_for[name] unless content
+ result = @_view_flow.append(name, content) if content
+ result unless content
end
# content_for? simply checks whether any content has been captured yet using content_for
@@ -158,7 +158,7 @@ module ActionView
# </body>
# </html>
def content_for?(name)
- @_content_for[name].present?
+ @_view_flow.get(name).present?
end
# Use an alternate output buffer for the duration of the block.
diff --git a/actionpack/lib/action_view/renderer/fibered_template_renderer.rb b/actionpack/lib/action_view/renderer/fibered_template_renderer.rb
new file mode 100644
index 0000000000..45f48cab76
--- /dev/null
+++ b/actionpack/lib/action_view/renderer/fibered_template_renderer.rb
@@ -0,0 +1,35 @@
+require 'action_view/renderer/template_renderer'
+require 'fiber'
+
+module ActionView
+ class FiberedTemplateRenderer < TemplateRenderer #:nodoc:
+ # Renders the given template. An string representing the layout can be
+ # supplied as well.
+ def render_template(template, layout_name = nil, locals = {}) #:nodoc:
+ view, locals = @view, locals || {}
+
+ final = nil
+ layout = layout_name && find_layout(layout_name, locals.keys)
+ yielder = lambda { |*name| view._layout_for(*name) }
+
+ instrument(:template, :identifier => template.identifier, :layout => layout.try(:virtual_path)) do
+ @fiber = Fiber.new do
+ final = if layout
+ layout.render(view, locals, &yielder)
+ else
+ view._layout_for
+ end
+ end
+
+ @view._view_flow = FiberedFlow.new(view._view_flow, @fiber)
+ @fiber.resume
+
+ content = template.render(view, locals, &yielder)
+ view._view_flow.set(:layout, content)
+ @fiber.resume while @fiber.alive?
+ end
+
+ final
+ end
+ end
+end
diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb
index 94c0a8a8fb..180afc27ac 100644
--- a/actionpack/lib/action_view/renderer/partial_renderer.rb
+++ b/actionpack/lib/action_view/renderer/partial_renderer.rb
@@ -79,7 +79,7 @@ module ActionView
locals[as] = object
content = @template.render(view, locals) do |*name|
- view._layout_for(*name, &block)
+ view._block_layout_for(*name, &block)
end
content = layout.render(view, locals){ content } if layout
diff --git a/actionpack/lib/action_view/renderer/template_renderer.rb b/actionpack/lib/action_view/renderer/template_renderer.rb
index 439a661dd3..10d8cc3b87 100644
--- a/actionpack/lib/action_view/renderer/template_renderer.rb
+++ b/actionpack/lib/action_view/renderer/template_renderer.rb
@@ -7,6 +7,7 @@ module ActionView
def render(options)
wrap_formats(options[:template] || options[:file]) do
template = determine_template(options)
+ freeze_formats(template.formats, true)
render_template(template, options[:layout], options[:locals])
end
end
@@ -31,7 +32,6 @@ module ActionView
# Renders the given template. An string representing the layout can be
# supplied as well.
def render_template(template, layout_name = nil, locals = {}) #:nodoc:
- freeze_formats(template.formats, true)
view, locals = @view, locals || {}
render_with_layout(layout_name, locals) do |layout|
@@ -47,7 +47,7 @@ module ActionView
if layout
view = @view
- view.store_content_for(:layout, content)
+ view._view_flow.set(:layout, content)
layout.render(view, locals){ |*name| view._layout_for(*name) }
else
content
diff --git a/actionpack/lib/action_view/rendering.rb b/actionpack/lib/action_view/rendering.rb
index 30c083a2bf..e3568e70e5 100644
--- a/actionpack/lib/action_view/rendering.rb
+++ b/actionpack/lib/action_view/rendering.rb
@@ -73,24 +73,38 @@ module ActionView
# Hello David
# </html>
#
- def _layout_for(*args, &block)
+ def _layout_for(*args)
+ name = args.first
+ name = :layout unless name.is_a?(Symbol)
+ @_view_flow.get(name).html_safe
+ end
+
+ # Returns the content from the Flow unless we have a block.
+ def _block_layout_for(*args, &block)
name = args.first
- if name.is_a?(Symbol)
- @_content_for[name].html_safe
- elsif block
+ if !name.is_a?(Symbol) && block
capture(*args, &block)
else
- @_content_for[:layout].html_safe
+ _layout_for(*args)
end
end
def _render_template(options) #:nodoc:
- _template_renderer.render(options)
+ if @magic_medicine
+ _fibered_template_renderer.render(options)
+ else
+ _template_renderer.render(options)
+ end
end
def _template_renderer #:nodoc:
@_template_renderer ||= TemplateRenderer.new(self)
end
+
+ def _fibered_template_renderer #:nodoc:
+ @_fibered_template_renderer ||= FiberedTemplateRenderer.new(self)
+ end
+
end
end
diff --git a/actionpack/test/template/capture_helper_test.rb b/actionpack/test/template/capture_helper_test.rb
index 03050485fa..ec252fa117 100644
--- a/actionpack/test/template/capture_helper_test.rb
+++ b/actionpack/test/template/capture_helper_test.rb
@@ -4,7 +4,7 @@ class CaptureHelperTest < ActionView::TestCase
def setup
super
@av = ActionView::Base.new
- @_content_for = Hash.new {|h,k| h[k] = "" }
+ @_view_flow = ActionView::Flow.new
end
def test_capture_captures_the_temporary_output_buffer_in_its_block
diff --git a/actionpack/test/template/fibered_render_test.rb b/actionpack/test/template/fibered_render_test.rb
new file mode 100644
index 0000000000..f62af10812
--- /dev/null
+++ b/actionpack/test/template/fibered_render_test.rb
@@ -0,0 +1,27 @@
+# encoding: utf-8
+require 'abstract_unit'
+require 'controller/fake_models'
+
+class TestController < ActionController::Base
+end
+
+
+class FiberedTest < ActiveSupport::TestCase
+
+ def setup
+ view_paths = ActionController::Base.view_paths
+ @assigns = { :secret => 'in the sauce' }
+ @view = ActionView::Base.new(view_paths, @assigns)
+ @view.magic_medicine = true
+ @controller_view = TestController.new.view_context
+ end
+
+ def test_render_template
+ assert_equal "Hello world!", @view.render(:template => "test/hello_world")
+ end
+
+ def test_render_with_layout
+ assert_equal %(<title></title>\nHello world!\n),
+ @view.render(:template => "test/hello_world.erb", :layout => "layouts/yield")
+ end
+end if defined?(Fiber) \ No newline at end of file