aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_view/render
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_view/render')
-rw-r--r--actionpack/lib/action_view/render/layouts.rb83
-rw-r--r--actionpack/lib/action_view/render/partials.rb177
-rw-r--r--actionpack/lib/action_view/render/rendering.rb101
3 files changed, 62 insertions, 299 deletions
diff --git a/actionpack/lib/action_view/render/layouts.rb b/actionpack/lib/action_view/render/layouts.rb
deleted file mode 100644
index 08162f7fd5..0000000000
--- a/actionpack/lib/action_view/render/layouts.rb
+++ /dev/null
@@ -1,83 +0,0 @@
-module ActionView
- # = Action View Layouts
- module Layouts
- # 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) #:nodoc:
- name = args.first
-
- if name.is_a?(Symbol)
- @_content_for[name].html_safe
- elsif block
- capture(*args, &block)
- else
- @_content_for[:layout].html_safe
- end
- end
-
- # This is the method which actually finds the layout using details in the lookup
- # context object. If no layout is found, it checks if at least a layout with
- # the given name exists across all details before raising the error.
- def find_layout(layout, keys)
- begin
- with_layout_format do
- layout =~ /^\// ?
- with_fallbacks { find_template(layout, nil, false, keys) } : find_template(layout, nil, false, keys)
- end
- rescue ActionView::MissingTemplate => e
- update_details(:formats => nil) do
- raise unless template_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
diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb
index 4e03d43358..844c3e9572 100644
--- a/actionpack/lib/action_view/render/partials.rb
+++ b/actionpack/lib/action_view/render/partials.rb
@@ -210,181 +210,12 @@ module ActionView
# <%- end -%>
# <% end %>
module Partials
- extend ActiveSupport::Concern
-
- class PartialRenderer
- PARTIAL_NAMES = Hash.new {|h,k| h[k] = {} }
-
- def initialize(view_context, options, block)
- @view = view_context
- @partial_names = PARTIAL_NAMES[@view.controller.class.name]
- setup(options, block)
- end
-
- def setup(options, block)
- partial = options[:partial]
-
- @options = options
- @locals = options[:locals] || {}
- @block = block
-
- if String === partial
- @object = options[:object]
- @path = partial
- @collection = collection
- else
- @object = partial
-
- if @collection = collection_from_object || collection
- paths = @collection_data = @collection.map { |o| partial_path(o) }
- @path = paths.uniq.size == 1 ? paths.first : nil
- else
- @path = partial_path
- end
- end
-
- if @path
- @variable, @variable_counter = retrieve_variable(@path)
- else
- paths.map! { |path| retrieve_variable(path).unshift(path) }
- end
- end
-
- def retrieve_variable(path)
- variable = @options[:as] || path[%r'_?(\w+)(\.\w+)*$', 1].to_sym
- variable_counter = :"#{variable}_counter" if @collection
- [variable, variable_counter]
- end
-
- def render
- identifier = ((@template = find_partial) ? @template.identifier : @path)
-
- if @collection
- ActiveSupport::Notifications.instrument("render_collection.action_view",
- :identifier => identifier || "collection", :count => @collection.size) do
- render_collection
- end
- else
- if !@block && (layout = @options[:layout])
- layout = find_template(layout)
- end
-
- content = ActiveSupport::Notifications.instrument("render_partial.action_view",
- :identifier => identifier) do
- render_partial
- end
-
- content = @view._render_layout(layout, @locals){ content } if layout
- content
- end
- end
-
- def render_collection
- return nil if @collection.blank?
-
- if @options.key?(:spacer_template)
- spacer = find_template(@options[:spacer_template]).render(@view, @locals)
- end
-
- result = @template ? collection_with_template : collection_without_template
- result.join(spacer).html_safe
- end
-
- def collection_with_template
- segments, locals, template = [], @locals, @template
- as, counter = @variable, @variable_counter
-
- locals[counter] = -1
-
- @collection.each do |object|
- locals[counter] += 1
- locals[as] = object
- segments << template.render(@view, locals)
- end
-
- segments
- end
-
- def collection_without_template
- segments, locals, collection_data = [], @locals, @collection_data
- index, template, cache = -1, nil, {}
- keys = @locals.keys
-
- @collection.each_with_index do |object, i|
- path, *data = collection_data[i]
- template = (cache[path] ||= find_template(path, keys + data))
- locals[data[0]] = object
- locals[data[1]] = (index += 1)
- segments << template.render(@view, locals)
- end
-
- @template = template
- segments
- end
-
- def render_partial
- locals, view = @locals, @view
- object, as = @object, @variable
-
- object ||= locals[as]
- locals[as] = object
-
- @template.render(view, locals) do |*name|
- view._layout_for(*name, &@block)
- end
- end
-
- private
-
- def collection
- if @options.key?(:collection)
- @options[:collection] || []
- end
- end
-
- def collection_from_object
- if @object.respond_to?(:to_ary)
- @object
- end
- end
-
- def find_partial
- if path = @path
- locals = @locals.keys
- locals << @variable
- locals << @variable_counter if @collection
- find_template(path, locals)
- end
- end
-
- def find_template(path=@path, locals=@locals.keys)
- prefix = @view.controller_path unless path.include?(?/)
- @view.find_template(path, prefix, true, locals)
- end
-
- def partial_path(object = @object)
- @partial_names[object.class.name] ||= begin
- object = object.to_model if object.respond_to?(:to_model)
-
- object.class.model_name.partial_path.dup.tap do |partial|
- path = @view.controller_path
- partial.insert(0, "#{File.dirname(path)}/") if partial.include?(?/) && path.include?(?/)
- end
- end
- end
- end
-
def _render_partial(options, &block) #:nodoc:
- _wrap_formats(options[:partial]) do
- if defined?(@renderer)
- @renderer.setup(options, block)
- else
- @renderer = PartialRenderer.new(self, options, block)
- end
-
- @renderer.render
- end
+ _partial_renderer.setup(options, block).render
end
+ def _partial_renderer #:nodoc:
+ @_partial_renderer ||= PartialRenderer.new(self)
+ end
end
end
diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb
index 8e599c71df..adbb6bc626 100644
--- a/actionpack/lib/action_view/render/rendering.rb
+++ b/actionpack/lib/action_view/render/rendering.rb
@@ -21,11 +21,7 @@ module ActionView
elsif options.key?(:partial)
_render_partial(options)
else
- _wrap_formats(options[:template] || options[:file]) do
- template = _determine_template(options)
- lookup_context.freeze_formats(template.formats, true)
- _render_template(template, options[:layout], options)
- end
+ _render_template(options)
end
when :update
update_page(&block)
@@ -34,51 +30,70 @@ module ActionView
end
end
- # Checks if the given path contains a format and if so, change
- # the lookup context to take this new format into account.
- def _wrap_formats(value)
- return yield unless value.is_a?(String)
- @@formats_regexp ||= /\.(#{Mime::SET.symbols.join('|')})$/
+ # 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 value.sub!(@@formats_regexp, "")
- update_details(:formats => [$1.to_sym]){ yield }
+ if name.is_a?(Symbol)
+ @_content_for[name].html_safe
+ elsif block
+ capture(*args, &block)
else
- yield
+ @_content_for[:layout].html_safe
end
end
- # Determine the template to be rendered using the given options.
- def _determine_template(options) #:nodoc:
- keys = (options[:locals] ||= {}).keys
-
- if options.key?(:inline)
- handler = Template.handler_class_for_extension(options[:type] || "erb")
- Template.new(options[:inline], "inline template", handler, { :locals => keys })
- elsif options.key?(:text)
- Template::Text.new(options[:text], formats.try(:first))
- elsif options.key?(:file)
- with_fallbacks { find_template(options[:file], options[:prefix], false, keys) }
- elsif options.key?(:template)
- options[:template].respond_to?(:render) ?
- options[:template] : find_template(options[:template], options[:prefix], false, keys)
- end
+ def _render_template(options) #:nodoc:
+ _template_renderer.render(options)
end
- # Renders the given template. An string representing the layout can be
- # supplied as well.
- def _render_template(template, layout = nil, options = {}) #:nodoc:
- locals = options[:locals] || {}
- layout = find_layout(layout, locals.keys) if layout
-
- ActiveSupport::Notifications.instrument("render_template.action_view",
- :identifier => template.identifier, :layout => layout.try(:virtual_path)) do
-
- content = template.render(self, locals) { |*name| _layout_for(*name) }
- @_content_for[:layout] = content if layout
-
- content = _render_layout(layout, locals) if layout
- content
- end
+ def _template_renderer #:nodoc:
+ @_template_renderer ||= TemplateRenderer.new(self)
end
end
end