提交 33cc001f 编写于 作者: J José Valim

More cleanup and moving responsibilities around.

上级 2f683fd8
......@@ -35,7 +35,6 @@ module ActionView
autoload :Helpers
autoload :LookupContext
autoload :PathSet
autoload :Rendering
autoload :Template
autoload :TestCase
......
......@@ -131,7 +131,7 @@ module ActionView #:nodoc:
#
# More builder documentation can be found at http://builder.rubyforge.org.
class Base
include Helpers, Rendering, ::ERB::Util, Context
include Helpers, ::ERB::Util, Context
# Specify the proc used to decorate input tags that refer to attributes with errors.
cattr_accessor :field_error_proc
......@@ -159,10 +159,10 @@ def cache_template_loading=(value)
end
end
attr_accessor :_view_flow
attr_internal :request, :controller, :config, :assigns, :lookup_context
attr_accessor :view_renderer
attr_internal :request, :controller, :config, :assigns
# TODO Consider removing those setters once we have the renderer in place.
delegate :lookup_context, :render, :render_body, :to => :view_renderer
delegate :formats, :formats=, :locale, :locale=, :view_paths, :view_paths=, :to => :lookup_context
delegate :request_forgery_protection_token, :params, :session, :cookies, :response, :headers,
......@@ -187,22 +187,21 @@ def initialize(lookup_context = nil, assigns_for_first_render = {}, controller =
assign(assigns_for_first_render)
self.helpers = Module.new unless self.class.helpers
@_config = {}
@_virtual_path = nil
@_view_flow = OutputFlow.new
@view_flow = OutputFlow.new
@output_buffer = nil
@virtual_path = nil
@_config = {}
if @_controller = controller
@_request = controller.request if controller.respond_to?(:request)
@_config = controller.config.inheritable_copy if controller.respond_to?(:config)
end
@_lookup_context = lookup_context.is_a?(ActionView::LookupContext) ?
_lookup_context = lookup_context.is_a?(ActionView::LookupContext) ?
lookup_context : ActionView::LookupContext.new(lookup_context)
@_lookup_context.formats = formats if formats
_lookup_context.formats = formats if formats
@view_renderer = ActionView::Renderer.new(@_lookup_context, self)
@view_renderer = ActionView::Renderer.new(_lookup_context, self)
end
def controller_path
......
......@@ -8,29 +8,69 @@ module CompiledTemplates #:nodoc:
# Action View contexts are supplied to Action Controller to render template.
# The default Action View context is ActionView::Base.
#
# In order to work with ActionController, a Context must implement:
#
# Context#render_partial[options]
# - responsible for setting options[:_template]
# - Returns String with the rendered partial
# options<Hash>:: see _render_partial in ActionView::Base
# Context#render_template[template, layout, options, partial]
# - Returns String with the rendered template
# template<ActionView::Template>:: The template to render
# layout<ActionView::Template>:: The layout to render around the template
# options<Hash>:: See _render_template_with_layout in ActionView::Base
# partial<Boolean>:: Whether or not the template to render is a partial
#
# An Action View context can also mix in Action View's helpers. In order to
# mix in helpers, a context must implement:
#
# Context#controller
# - Returns an instance of AbstractController
#
# In any case, a context must mix in ActionView::Context, which stores compiled
# template and provides the output buffer.
# In order to work with ActionController, a Context must just include this module.
module Context
include CompiledTemplates
attr_accessor :output_buffer, :view_renderer, :view_flow
attr_accessor :output_buffer, :view_flow
# Returns the contents that are yielded to a layout, given a name or a block.
#
# You can think of a layout as a method that is called with a block. If the user calls
# <tt>yield :some_name</tt>, the block, by default, returns <tt>content_for(:some_name)</tt>.
# If the user calls simply +yield+, the default block returns <tt>content_for(:layout)</tt>.
#
# The user can override this default by passing a block to the layout:
#
# # The template
# <%= render :layout => "my_layout" do %>
# Content
# <% end %>
#
# # The layout
# <html>
# <%= yield %>
# </html>
#
# In this case, instead of the default block, which would return <tt>content_for(:layout)</tt>,
# this method returns the block that was passed in to <tt>render :layout</tt>, and the response
# would be
#
# <html>
# Content
# </html>
#
# Finally, the block can take block arguments, which can be passed in by +yield+:
#
# # The template
# <%= render :layout => "my_layout" do |customer| %>
# Hello <%= customer.name %>
# <% end %>
#
# # The layout
# <html>
# <%= yield Struct.new(:name).new("David") %>
# </html>
#
# In this case, the layout would receive the block passed into <tt>render :layout</tt>,
# and the struct specified would be passed into the block as an argument. The result
# would be
#
# <html>
# Hello David
# </html>
#
def _layout_for(*args, &block)
name = args.first
if name.is_a?(Symbol)
view_flow.get(name).html_safe
elsif block
# TODO Import capture into AV::Context or
# leave it as implicit dependency?
capture(*args, &block)
else
view_flow.get(:layout).html_safe
end
end
end
end
\ No newline at end of file
......@@ -34,7 +34,7 @@ def initialize(view, fiber)
@view = view
@parent = nil
@child = view.output_buffer
@content = view._view_flow.content
@content = view.view_flow.content
@fiber = fiber
@root = Fiber.current.object_id
end
......
......@@ -135,7 +135,7 @@ def capture(*args)
# for elements that will be fragment cached.
def content_for(name, content = nil, &block)
content = capture(&block) if block_given?
result = @_view_flow.append(name, content) if content
result = @view_flow.append(name, content) if content
result unless content
end
......@@ -146,7 +146,7 @@ def content_for(name, content = nil, &block)
# the layout to stop looking for more contents.
def provide(name, content = nil, &block)
content = capture(&block) if block_given?
result = @_view_flow.append!(name, content) if content
result = @view_flow.append!(name, content) if content
result unless content
end
......@@ -169,7 +169,7 @@ def provide(name, content = nil, &block)
# </body>
# </html>
def content_for?(name)
@_view_flow.get(name).present?
@view_flow.get(name).present?
end
# Use an alternate output buffer for the duration of the block.
......
......@@ -106,7 +106,7 @@ def delayed_render(buffer, template, layout, view, locals)
# Set the view flow to support streaming. It will be aware
# when to stop rendering the layout because it needs to search
# something in the template and vice-versa.
view._view_flow = StreamingFlow.new(view, fiber)
view.view_flow = StreamingFlow.new(view, fiber)
# Yo! Start the fiber!
fiber.resume
......@@ -118,7 +118,7 @@ def delayed_render(buffer, template, layout, view, locals)
content = template.render(view, locals, &yielder)
# Once rendering the template is done, sets its content in the :layout key.
view._view_flow.set(:layout, content)
view.view_flow.set(:layout, content)
# In case the layout continues yielding, we need to resume
# the fiber until all yields are handled.
......
......@@ -46,7 +46,7 @@ def render_with_layout(path, locals) #:nodoc:
if layout
view = @view
view._view_flow.set(:layout, content)
view.view_flow.set(:layout, content)
layout.render(view, locals){ |*name| view._layout_for(*name) }
else
content
......
require 'active_support/core_ext/object/try'
module ActionView
# = Action View Rendering
module Rendering
# This is temporary until we remove the renderer dependency from AV.
delegate :render, :render_body, :to => :@view_renderer
# Returns the contents that are yielded to a layout, given a name or a block.
#
# You can think of a layout as a method that is called with a block. If the user calls
# <tt>yield :some_name</tt>, the block, by default, returns <tt>content_for(:some_name)</tt>.
# If the user calls simply +yield+, the default block returns <tt>content_for(:layout)</tt>.
#
# The user can override this default by passing a block to the layout:
#
# # The template
# <%= render :layout => "my_layout" do %>
# Content
# <% end %>
#
# # The layout
# <html>
# <%= yield %>
# </html>
#
# In this case, instead of the default block, which would return <tt>content_for(:layout)</tt>,
# this method returns the block that was passed in to <tt>render :layout</tt>, and the response
# would be
#
# <html>
# Content
# </html>
#
# Finally, the block can take block arguments, which can be passed in by +yield+:
#
# # The template
# <%= render :layout => "my_layout" do |customer| %>
# Hello <%= customer.name %>
# <% end %>
#
# # The layout
# <html>
# <%= yield Struct.new(:name).new("David") %>
# </html>
#
# In this case, the layout would receive the block passed into <tt>render :layout</tt>,
# and the struct specified would be passed into the block as an argument. The result
# would be
#
# <html>
# Hello David
# </html>
#
def _layout_for(*args, &block)
name = args.first
if name.is_a?(Symbol)
@_view_flow.get(name).html_safe
elsif block
capture(*args, &block)
else
@_view_flow.get(:layout).html_safe
end
end
end
end
......@@ -4,7 +4,7 @@ class CaptureHelperTest < ActionView::TestCase
def setup
super
@av = ActionView::Base.new
@_view_flow = ActionView::OutputFlow.new
@view_flow = ActionView::OutputFlow.new
end
def test_capture_captures_the_temporary_output_buffer_in_its_block
......@@ -49,14 +49,14 @@ def test_provide
assert !content_for?(:title)
provide :title, "hi"
assert content_for?(:title)
assert_equal "hi", @_view_flow.get(:title)
assert_equal "hi", @view_flow.get(:title)
provide :title, "<p>title</p>"
assert_equal "hi&lt;p&gt;title&lt;/p&gt;", @_view_flow.get(:title)
assert_equal "hi&lt;p&gt;title&lt;/p&gt;", @view_flow.get(:title)
@_view_flow = ActionView::OutputFlow.new
@view_flow = ActionView::OutputFlow.new
provide :title, "hi"
provide :title, "<p>title</p>".html_safe
assert_equal "hi<p>title</p>", @_view_flow.get(:title)
assert_equal "hi<p>title</p>", @view_flow.get(:title)
end
def test_with_output_buffer_swaps_the_output_buffer_given_no_argument
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册