aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_view/renderer/partial_renderer.rb
diff options
context:
space:
mode:
authorJosé Valim <jose.valim@gmail.com>2010-10-10 11:03:18 +0200
committerJosé Valim <jose.valim@gmail.com>2010-10-10 12:43:26 +0200
commitb88f4ca93bcaef9a6bfd21d95acc8f432a3c8e5c (patch)
tree94ca53a9d78f749b18ab6b325afc54a1c991f1ca /actionpack/lib/action_view/renderer/partial_renderer.rb
parentab2f2b22a6d0656f719c294d40e35d21c752ba8c (diff)
downloadrails-b88f4ca93bcaef9a6bfd21d95acc8f432a3c8e5c.tar.gz
rails-b88f4ca93bcaef9a6bfd21d95acc8f432a3c8e5c.tar.bz2
rails-b88f4ca93bcaef9a6bfd21d95acc8f432a3c8e5c.zip
Clean up the house before moving in the new furniture.
This commit moves all the template rendering logic that was hanging around AV::Base to renderer objects.
Diffstat (limited to 'actionpack/lib/action_view/renderer/partial_renderer.rb')
-rw-r--r--actionpack/lib/action_view/renderer/partial_renderer.rb167
1 files changed, 167 insertions, 0 deletions
diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb
new file mode 100644
index 0000000000..3be1702f9e
--- /dev/null
+++ b/actionpack/lib/action_view/renderer/partial_renderer.rb
@@ -0,0 +1,167 @@
+require 'action_view/renderer/abstract_renderer'
+
+module ActionView
+ class PartialRenderer < AbstractRenderer #:nodoc:
+ N = ::ActiveSupport::Notifications
+ PARTIAL_NAMES = Hash.new {|h,k| h[k] = {} }
+
+ def initialize(view)
+ super
+ @partial_names = PARTIAL_NAMES[@view.controller.class.name]
+ 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
+
+ self
+ end
+
+ def render
+ wrap_formats(@path) do
+ identifier = ((@template = find_partial) ? @template.identifier : @path)
+
+ if @collection
+ N.instrument("render_collection.action_view", :identifier => identifier || "collection", :count => @collection.size) do
+ render_collection
+ end
+ else
+ N.instrument("render_partial.action_view", :identifier => identifier) do
+ render_partial
+ end
+ end
+ 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 render_partial
+ locals, view, block = @locals, @view, @block
+ object, as = @object, @variable
+
+ if !block && (layout = @options[:layout])
+ layout = find_template(layout)
+ end
+
+ object ||= locals[as]
+ locals[as] = object
+
+ content = @template.render(view, locals) do |*name|
+ view._layout_for(*name, &block)
+ end
+
+ content = render_layout(layout, locals){ content } if layout
+ content
+ 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?(?/)
+ @lookup_context.find_template(path, prefix, true, locals)
+ 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 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
+
+ def retrieve_variable(path)
+ variable = @options[:as] || path[%r'_?(\w+)(\.\w+)*$', 1].to_sym
+ variable_counter = :"#{variable}_counter" if @collection
+ [variable, variable_counter]
+ end
+ end
+end \ No newline at end of file