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

More refactoring on the views side of rendering.

上级 0a853809
...@@ -281,14 +281,9 @@ def _normalize_options(options) ...@@ -281,14 +281,9 @@ def _normalize_options(options)
super super
if _include_layout?(options) if _include_layout?(options)
layout = options.key?(:layout) ? options[:layout] : :default layout = options.key?(:layout) ? options.delete(:layout) : :default
value = _layout_for_option(layout) value = _layout_for_option(layout)
options[:layout] = (value =~ /\blayouts/ ? value : "layouts/#{value}") if value
# TODO Revisit this. Maybe we should pass a :layout_prefix?
options[:layout] = ((!value || value =~ /\blayouts/) ? value : "layouts/#{value}")
# TODO Revisit this. :layout with :partial from controllers are not the same as in views
options[:layout] = view_context._find_layout(options[:layout]) if options.key?(:partial)
end end
end end
......
...@@ -37,6 +37,7 @@ module ActionView ...@@ -37,6 +37,7 @@ module ActionView
autoload :Helpers autoload :Helpers
autoload_under "render" do autoload_under "render" do
autoload :Layouts
autoload :Partials autoload :Partials
autoload :Rendering autoload :Rendering
end end
......
...@@ -173,7 +173,7 @@ class Base ...@@ -173,7 +173,7 @@ class Base
module Subclasses module Subclasses
end end
include Helpers, Rendering, Partials, ::ERB::Util include Helpers, Rendering, Partials, Layouts, ::ERB::Util
extend ActiveSupport::Memoizable extend ActiveSupport::Memoizable
......
require 'active_support/core_ext/object/try'
module ActionView
module Layouts
# You can think of a layout as a method that is called with a block. _layout_for
# returns the contents that are yielded to the layout. If the user calls yield
# :some_name, the block, by default, returns content_for(:some_name). If the user
# calls yield, the default block returns content_for(:layout).
#
# The user can override this default by passing a block to the layout.
#
# ==== Example
#
# # 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 content_for(:layout),
# this method returns the block that was passed in to render layout, and the response
# would be <html>Content</html>.
#
# Finally, the block can take block arguments, which can be passed in by yield.
#
# ==== Example
#
# # 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 in the layout would be passed into the block. The result
# would be <html>Hello David</html>.
def _layout_for(name = nil, &block) #:nodoc:
if !block || name
@_content_for[name || :layout]
else
capture(&block)
end
end
# This is the method which actually finds the layout using details in the lookup
# context object. If no layout is found, it checkes if at least a layout with
# the given name exists across all details before raising the error.
def _find_layout(layout) #:nodoc:
begin
find(layout)
rescue ActionView::MissingTemplate => e
update_details(:formats => nil) do
raise unless template_lookup.exists?(layout)
end
end
end
# Contains the logic that actually renders the layout.
def _render_layout(layout, locals, &block) #:nodoc:
layout.render(self, locals){ |*name| _layout_for(*name, &block) }
end
end
end
...@@ -174,9 +174,6 @@ module Partials ...@@ -174,9 +174,6 @@ module Partials
class PartialRenderer class PartialRenderer
PARTIAL_NAMES = Hash.new {|h,k| h[k] = {} } PARTIAL_NAMES = Hash.new {|h,k| h[k] = {} }
TEMPLATES = Hash.new {|h,k| h[k] = {} }
attr_reader :template
def initialize(view_context, options, block) def initialize(view_context, options, block)
@view = view_context @view = view_context
...@@ -225,6 +222,7 @@ def render ...@@ -225,6 +222,7 @@ def render
if !@block && (layout = @options[:layout]) if !@block && (layout = @options[:layout])
content = @view._render_layout(find_template(layout), @locals){ content } content = @view._render_layout(find_template(layout), @locals){ content }
end end
content content
end end
end end
...@@ -241,9 +239,9 @@ def render_collection ...@@ -241,9 +239,9 @@ def render_collection
end end
def collection_with_template(template = @template) def collection_with_template(template = @template)
segments, locals, as = [], @locals, @options[:as] || template.variable_name segments, locals, as, template = [], @locals, @options[:as] || @template.variable_name, @template
counter_name = template.counter_name counter_name = template.counter_name
locals[counter_name] = -1 locals[counter_name] = -1
@collection.each do |object| @collection.each do |object|
...@@ -253,7 +251,6 @@ def collection_with_template(template = @template) ...@@ -253,7 +251,6 @@ def collection_with_template(template = @template)
segments << template.render(@view, locals) segments << template.render(@view, locals)
end end
@template = template
segments segments
end end
...@@ -274,7 +271,7 @@ def collection_without_template(collection_paths = @collection_paths) ...@@ -274,7 +271,7 @@ def collection_without_template(collection_paths = @collection_paths)
end end
def render_partial(object = @object) def render_partial(object = @object)
locals, view = @locals, @view locals, view, template = @locals, @view, @template
object ||= locals[template.variable_name] object ||= locals[template.variable_name]
locals[@options[:as] || template.variable_name] = object locals[@options[:as] || template.variable_name] = object
...@@ -285,6 +282,7 @@ def render_partial(object = @object) ...@@ -285,6 +282,7 @@ def render_partial(object = @object)
end end
private private
def collection def collection
if @object.respond_to?(:to_ary) if @object.respond_to?(:to_ary)
@object @object
...@@ -295,11 +293,7 @@ def collection ...@@ -295,11 +293,7 @@ def collection
def find_template(path=@path) def find_template(path=@path)
return path unless path.is_a?(String) return path unless path.is_a?(String)
prefix = @view.controller_path unless path.include?(?/)
if controller = @view.controller
prefix = controller.controller_path unless path.include?(?/)
end
@view.find(path, prefix, true) @view.find(path, prefix, true)
end end
...@@ -315,21 +309,8 @@ def partial_path(object = @object) ...@@ -315,21 +309,8 @@ def partial_path(object = @object)
end end
end end
def render_partial(options)
_evaluate_assigns_and_ivars
details = options[:_details]
# TODO This should happen automatically as well
self.formats = details[:formats] if details[:formats]
renderer = PartialRenderer.new(self, options, nil)
text = renderer.render
options[:_template] = renderer.template
text
end
def _render_partial(options, &block) #:nodoc: def _render_partial(options, &block) #:nodoc:
if defined? @renderer if defined?(@renderer)
@renderer.setup(options, block) @renderer.setup(options, block)
else else
@renderer = PartialRenderer.new(self, options, block) @renderer = PartialRenderer.new(self, options, block)
......
...@@ -15,17 +15,12 @@ module Rendering ...@@ -15,17 +15,12 @@ module Rendering
def render(options = {}, locals = {}, &block) #:nodoc: def render(options = {}, locals = {}, &block) #:nodoc:
case options case options
when Hash when Hash
layout = options[:layout]
options[:locals] ||= {}
if block_given? if block_given?
return safe_concat(_render_partial(options.merge(:partial => layout), &block)) content = _render_partial(options.merge(:partial => options[:layout]), &block)
elsif options.key?(:partial) safe_concat(content)
return _render_partial(options) else
_render(options)
end end
template = _determine_template(options)
_render_template(template, layout, :locals => options[:locals]) if template
when :update when :update
update_page(&block) update_page(&block)
else else
...@@ -33,50 +28,24 @@ def render(options = {}, locals = {}, &block) #:nodoc: ...@@ -33,50 +28,24 @@ def render(options = {}, locals = {}, &block) #:nodoc:
end end
end end
# You can think of a layout as a method that is called with a block. _layout_for
# returns the contents that are yielded to the layout. If the user calls yield
# :some_name, the block, by default, returns content_for(:some_name). If the user
# calls yield, the default block returns content_for(:layout).
#
# The user can override this default by passing a block to the layout.
#
# ==== Example
#
# # 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 content_for(:layout),
# this method returns the block that was passed in to render layout, and the response
# would be <html>Content</html>.
#
# Finally, the block can take block arguments, which can be passed in by yield.
#
# ==== Example
#
# # 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 in the layout would be passed into the block. The result
# would be <html>Hello David</html>.
def _layout_for(name = nil, &block)
return @_content_for[name || :layout] if !block_given? || name
capture(&block)
end
# This is the API to render a ViewContext's template from a controller. # This is the API to render a ViewContext's template from a controller.
# # TODO Review this name since it does not render only templates, but also
# Internal Options: # partials, files and so forth.
# _template:: The Template object to render def render_template(options, &block)
# _layout:: The layout, if any, to wrap the Template in
def render_template(options)
_evaluate_assigns_and_ivars _evaluate_assigns_and_ivars
# TODO Layout for partials should be handled here, because inside the
# partial renderer it looks for the layout as a partial.
if options.key?(:partial) && options[:layout]
options[:layout] = _find_layout(options[:layout])
end
_render(options, &block)
end
# This method holds the common render logic for both controllers and
# views rendering stacks.
def _render(options) #:nodoc:
if options.key?(:partial) if options.key?(:partial)
_render_partial(options) _render_partial(options)
else else
...@@ -86,14 +55,13 @@ def render_template(options) ...@@ -86,14 +55,13 @@ def render_template(options)
end end
end end
def _determine_template(options) # Determine the template to be rendered using the given options.
def _determine_template(options) #:nodoc:
if options.key?(:inline) if options.key?(:inline)
handler = Template.handler_class_for_extension(options[:type] || "erb") handler = Template.handler_class_for_extension(options[:type] || "erb")
Template.new(options[:inline], "inline template", handler, {}) Template.new(options[:inline], "inline template", handler, {})
elsif options.key?(:text) elsif options.key?(:text)
Template::Text.new(options[:text], self.formats.try(:first)) Template::Text.new(options[:text], self.formats.try(:first))
elsif options.key?(:_template)
options[:_template]
elsif options.key?(:file) elsif options.key?(:file)
find(options[:file], options[:_prefix]) find(options[:file], options[:_prefix])
elsif options.key?(:template) elsif options.key?(:template)
...@@ -101,24 +69,16 @@ def _determine_template(options) ...@@ -101,24 +69,16 @@ def _determine_template(options)
end end
end end
def _find_layout(layout) # Renders the given template. An string representing the layout can be
begin # supplied as well.
find(layout) def _render_template(template, layout = nil, options = {}) #:nodoc:
rescue ActionView::MissingTemplate => e
update_details(:formats => nil) do
raise unless template_lookup.exists?(layout)
end
end
end
def _render_template(template, layout = nil, options = {})
locals = options[:locals] || {} locals = options[:locals] || {}
layout = _find_layout(layout) if layout layout = _find_layout(layout) if layout
ActiveSupport::Notifications.instrument("action_view.render_template", ActiveSupport::Notifications.instrument("action_view.render_template",
:identifier => template.identifier, :layout => layout.try(:identifier)) do :identifier => template.identifier, :layout => layout.try(:identifier)) do
content = template.render(self, locals) {|*name| _layout_for(*name) } content = template.render(self, locals) { |*name| _layout_for(*name) }
@_content_for[:layout] = content @_content_for[:layout] = content
if layout if layout
...@@ -130,8 +90,5 @@ def _render_template(template, layout = nil, options = {}) ...@@ -130,8 +90,5 @@ def _render_template(template, layout = nil, options = {})
end end
end end
def _render_layout(layout, locals, &block)
layout.render(self, locals){ |*name| _layout_for(*name, &block) }
end
end end
end end
...@@ -8,41 +8,52 @@ class Base < AbstractController::Base ...@@ -8,41 +8,52 @@ class Base < AbstractController::Base
include AbstractController::Rendering include AbstractController::Rendering
include AbstractController::Layouts include AbstractController::Layouts
def _prefix
"template"
end
self.view_paths = [ActionView::FixtureResolver.new( self.view_paths = [ActionView::FixtureResolver.new(
"layouts/hello.erb" => "With String <%= yield %>",
"layouts/hello_override.erb" => "With Override <%= yield %>",
"abstract_controller_tests/layouts/with_string_implied_child.erb" => "abstract_controller_tests/layouts/with_string_implied_child.erb" =>
"With Implied <%= yield %>", "With Implied <%= yield %>",
"layouts/overwrite.erb" => "Overwrite <%= yield %>", "layouts/hello.erb" => "With String <%= yield %>",
"layouts/with_false_layout.erb" => "False Layout <%= yield %>" "layouts/hello_override.erb" => "With Override <%= yield %>",
"layouts/overwrite.erb" => "Overwrite <%= yield %>",
"layouts/with_false_layout.erb" => "False Layout <%= yield %>"
)] )]
end end
class Blank < Base class Blank < Base
self.view_paths = [] self.view_paths = ActionView::FixtureResolver.new("template/index.erb" => "Hello blank!")
def index def index
render :_template => ActionView::Template::Text.new("Hello blank!") render
end end
end end
class WithString < Base class WithString < Base
layout "hello" layout "hello"
append_view_path ActionView::FixtureResolver.new(
"template/index.erb" => "Hello string!",
"template/overwrite_default.erb" => "Hello string!",
"template/overwrite_false.erb" => "Hello string!",
"template/overwrite_string.erb" => "Hello string!"
)
def index def index
render :_template => ActionView::Template::Text.new("Hello string!") render
end end
def overwrite_default def overwrite_default
render :_template => ActionView::Template::Text.new("Hello string!"), :layout => :default render :layout => :default
end end
def overwrite_false def overwrite_false
render :_template => ActionView::Template::Text.new("Hello string!"), :layout => false render :layout => false
end end
def overwrite_string def overwrite_string
render :_template => ActionView::Template::Text.new("Hello string!"), :layout => "overwrite" render :layout => "overwrite"
end end
def overwrite_skip def overwrite_skip
...@@ -70,18 +81,28 @@ class WithChildOfImplied < WithStringImpliedChild ...@@ -70,18 +81,28 @@ class WithChildOfImplied < WithStringImpliedChild
class WithProc < Base class WithProc < Base
layout proc { |c| "overwrite" } layout proc { |c| "overwrite" }
append_view_path ActionView::FixtureResolver.new(
"template/index.erb" => "Hello proc!"
)
def index def index
render :_template => ActionView::Template::Text.new("Hello proc!") render
end end
end end
class WithSymbol < Base class WithSymbol < Base
layout :hello layout :hello
append_view_path ActionView::FixtureResolver.new(
"template/index.erb" => "Hello symbol!"
)
def index def index
render :_template => ActionView::Template::Text.new("Hello symbol!") render
end end
private
private
def hello def hello
"overwrite" "overwrite"
end end
...@@ -89,11 +110,17 @@ def hello ...@@ -89,11 +110,17 @@ def hello
class WithSymbolReturningString < Base class WithSymbolReturningString < Base
layout :no_hello layout :no_hello
append_view_path ActionView::FixtureResolver.new(
"template/index.erb" => "Hello missing symbol!"
)
def index def index
render :_template => ActionView::Template::Text.new("Hello missing symbol!") render
end end
private
private
def no_hello def no_hello
nil nil
end end
...@@ -101,19 +128,28 @@ def no_hello ...@@ -101,19 +128,28 @@ def no_hello
class WithSymbolReturningNil < Base class WithSymbolReturningNil < Base
layout :nilz layout :nilz
append_view_path ActionView::FixtureResolver.new(
"template/index.erb" => "Hello nilz!"
)
def index def index
render :_template => ActionView::Template::Text.new("Hello nilz!") render
end end
def nilz() end def nilz
end
end end
class WithSymbolReturningObj < Base class WithSymbolReturningObj < Base
layout :objekt layout :objekt
append_view_path ActionView::FixtureResolver.new(
"template/index.erb" => "Hello object!"
)
def index def index
render :_template => ActionView::Template::Text.new("Hello nilz!") render
end end
def objekt def objekt
...@@ -123,33 +159,49 @@ def objekt ...@@ -123,33 +159,49 @@ def objekt
class WithSymbolAndNoMethod < Base class WithSymbolAndNoMethod < Base
layout :no_method layout :no_method
append_view_path ActionView::FixtureResolver.new(
"template/index.erb" => "Hello boom!"
)
def index def index
render :_template => ActionView::Template::Text.new("Hello boom!") render
end end
end end
class WithMissingLayout < Base class WithMissingLayout < Base
layout "missing" layout "missing"
append_view_path ActionView::FixtureResolver.new(
"template/index.erb" => "Hello missing!"
)
def index def index
render :_template => ActionView::Template::Text.new("Hello missing!") render
end end
end end
class WithFalseLayout < Base class WithFalseLayout < Base
layout false layout false
append_view_path ActionView::FixtureResolver.new(
"template/index.erb" => "Hello false!"
)
def index def index
render :_template => ActionView::Template::Text.new("Hello false!") render
end end
end end
class WithNilLayout < Base class WithNilLayout < Base
layout nil layout nil
append_view_path ActionView::FixtureResolver.new(
"template/index.erb" => "Hello nil!"
)
def index def index
render :_template => ActionView::Template::Text.new("Hello nil!") render
end end
end end
......
...@@ -15,7 +15,6 @@ def _prefix ...@@ -15,7 +15,6 @@ def _prefix
"renderer/default.erb" => "With Default", "renderer/default.erb" => "With Default",
"renderer/string.erb" => "With String", "renderer/string.erb" => "With String",
"renderer/symbol.erb" => "With Symbol", "renderer/symbol.erb" => "With Symbol",
"renderer/template_name.erb" => "With Template Name",
"string/with_path.erb" => "With String With Path", "string/with_path.erb" => "With String With Path",
"some/file.erb" => "With File", "some/file.erb" => "With File",
"with_format.html.erb" => "With html format", "with_format.html.erb" => "With html format",
...@@ -56,14 +55,6 @@ def symbol ...@@ -56,14 +55,6 @@ def symbol
render :symbol render :symbol
end end
def template_name
render :_template_name => :template_name
end
def object
render :_template => ActionView::Template::Text.new("With Object")
end
def with_html_format def with_html_format
render :template => "with_format", :format => :html render :template => "with_format", :format => :html
end end
...@@ -127,16 +118,6 @@ def test_render_string_with_path ...@@ -127,16 +118,6 @@ def test_render_string_with_path
assert_equal "With String With Path", @controller.response_body assert_equal "With String With Path", @controller.response_body
end end
def test_render_template_name
@controller.process(:template_name)
assert_equal "With Template Name", @controller.response_body
end
def test_render_object
@controller.process(:object)
assert_equal "With Object", @controller.response_body
end
def test_render_with_html_format def test_render_with_html_format
@controller.process(:with_html_format) @controller.process(:with_html_format)
assert_equal "With html format", @controller.response_body assert_equal "With html format", @controller.response_body
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册