From 0a85380966e47a38292242e6c3b259d77c738ab5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20Valim?= <jose.valim@gmail.com>
Date: Mon, 8 Mar 2010 11:32:01 +0100
Subject: Finally moved the find template logic to the views.

---
 actionpack/lib/abstract_controller/layouts.rb      |   7 +-
 actionpack/lib/abstract_controller/rendering.rb    | 232 +++++++++------------
 .../lib/action_controller/metal/compatibility.rb   |  11 +-
 .../lib/action_controller/metal/implicit_render.rb |   2 +-
 .../lib/action_controller/metal/rendering.rb       |  41 ++--
 actionpack/lib/action_view/render/rendering.rb     |  40 ++--
 actionpack/lib/action_view/template/text.rb        |   7 +-
 .../test/abstract/abstract_controller_test.rb      |   4 +-
 8 files changed, 152 insertions(+), 192 deletions(-)

(limited to 'actionpack')

diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb
index 648a2da795..6ac3806149 100644
--- a/actionpack/lib/abstract_controller/layouts.rb
+++ b/actionpack/lib/abstract_controller/layouts.rb
@@ -264,7 +264,7 @@ module AbstractController
 
             self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
               def _layout
-                if template_exists?("#{_implied_layout_name}", :_prefix => #{_prefix.inspect})
+                if template_exists?("#{_implied_layout_name}", #{_prefix.inspect})
                   "#{_implied_layout_name}"
                 else
                   super
@@ -277,7 +277,9 @@ module AbstractController
       end
     end
 
-    def render_to_body(options)
+    def _normalize_options(options)
+      super
+
       if _include_layout?(options)
         layout = options.key?(:layout) ? options[:layout] : :default
         value = _layout_for_option(layout)
@@ -288,7 +290,6 @@ module AbstractController
         # 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
-      super
     end
 
   private
diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb
index 9093e90c97..d9087ce294 100644
--- a/actionpack/lib/abstract_controller/rendering.rb
+++ b/actionpack/lib/abstract_controller/rendering.rb
@@ -10,7 +10,7 @@ module AbstractController
     end
   end
 
-  module Rendering
+  module ViewPaths
     extend ActiveSupport::Concern
 
     included do
@@ -21,21 +21,87 @@ module AbstractController
     delegate :formats, :formats=, :to => :template_lookup
     delegate :_view_paths, :to => :'self.class'
 
+    def template_lookup
+      @template_lookup ||= ActionView::Template::Lookup.new(_view_paths, details_for_lookup)
+    end
+
+    def details_for_lookup
+      { }
+    end
+
+    # The list of view paths for this controller. See ActionView::ViewPathSet for
+    # more details about writing custom view paths.
+    def view_paths
+      template_lookup.view_paths
+    end
+
+    def append_view_path(path)
+      template_lookup.view_paths.push(*path)
+    end
+
+    def prepend_view_path(path)
+      template_lookup.view_paths.unshift(*path)
+    end
+
+    protected
+
+    def template_exists?(*args)
+      template_lookup.exists?(*args)
+    end
+
+    def find_template(*args)
+      template_lookup.find(*args)
+    end
+
+    module ClassMethods
+      # Append a path to the list of view paths for this controller.
+      #
+      # ==== Parameters
+      # path<String, ViewPath>:: If a String is provided, it gets converted into
+      # the default view path. You may also provide a custom view path
+      # (see ActionView::ViewPathSet for more information)
+      def append_view_path(path)
+        self.view_paths = view_paths.dup + Array(path)
+      end
+
+      # Prepend a path to the list of view paths for this controller.
+      #
+      # ==== Parameters
+      # path<String, ViewPath>:: If a String is provided, it gets converted into
+      # the default view path. You may also provide a custom view path
+      # (see ActionView::ViewPathSet for more information)
+      def prepend_view_path(path)
+        self.view_paths = Array(path) + view_paths.dup
+      end
+
+      # A list of all of the default view paths for this controller.
+      def view_paths
+        _view_paths
+      end
+
+      # Set the view paths.
+      #
+      # ==== Parameters
+      # paths<ViewPathSet, Object>:: If a ViewPathSet is provided, use that;
+      #   otherwise, process the parameter into a ViewPathSet.
+      def view_paths=(paths)
+        self._view_paths = paths.is_a?(ActionView::PathSet) ? paths : ActionView::Base.process_view_paths(paths)
+        self._view_paths.freeze
+      end
+    end
+  end
+
+  module Rendering
+    extend ActiveSupport::Concern
+    include AbstractController::ViewPaths
+
     # An instance of a view class. The default view class is ActionView::Base
     #
     # The view class must have the following methods:
-    # View.for_controller[controller] Create a new ActionView instance for a
-    #   controller
-    # View#render_partial[options]
-    #   - responsible for setting options[:_template]
-    #   - Returns String with the rendered partial
-    #   options<Hash>:: see _render_partial in ActionView::Base
-    # View#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
+    # View.for_controller[controller]
+    #   Create a new ActionView instance for a controller
+    # View#render_template[options]
+    #   Returns String with the rendered template
     #
     # Override this method in a module to change the default behavior.
     def view_context
@@ -51,64 +117,23 @@ module AbstractController
     end
 
     # Raw rendering of a template to a Rack-compatible body.
-    #
-    # ==== Options
-    # _partial_object<Object>:: The object that is being rendered. If this
-    #   exists, we are in the special case of rendering an object as a partial.
-    #
     # :api: plugin
     def render_to_body(options = {})
-      # TODO: Refactor so we can just use the normal template logic for this
-      if options.key?(:partial)
-        _render_partial(options)
-      else
-        _determine_template(options)
-        _render_template(options)
-      end
+      _process_options(options)
+      _render_template(options)
     end
 
     # Raw rendering of a template to a string. Just convert the results of
     # render_to_body into a String.
-    #
     # :api: plugin
     def render_to_string(options={})
       _normalize_options(options)
       AbstractController::Rendering.body_to_s(render_to_body(options))
     end
 
-    # Renders the template from an object.
-    #
-    # ==== Options
-    # _template<ActionView::Template>:: The template to render
-    # _layout<ActionView::Template>:: The layout to wrap the template in (optional)
+    # Find and renders a template based on the options given.
     def _render_template(options)
-      view_context.render_template(options)
-    end
-
-    # Renders the given partial.
-    #
-    # ==== Options
-    # partial<String|Object>:: The partial name or the object to be rendered
-    def _render_partial(options)
-      view_context.render_partial(options)
-    end
-
-    def template_lookup
-      @template_lookup ||= ActionView::Template::Lookup.new(_view_paths, details_for_render)
-    end
-
-    # The list of view paths for this controller. See ActionView::ViewPathSet for
-    # more details about writing custom view paths.
-    def view_paths
-      template_lookup.view_paths
-    end
-
-    def append_view_path(path)
-      template_lookup.view_paths.push(*path)
-    end
-
-    def prepend_view_path(path)
-      template_lookup.view_paths.unshift(*path)
+      view_context.render_template(options) { |template| _with_template_hook(template) }
     end
 
     # The prefix used in render "foo" shortcuts.
@@ -134,59 +159,40 @@ module AbstractController
     # and render "/foo" to render :file => "/foo".
     def _normalize_args(action=nil, options={})
       case action
+      when NilClass
       when Hash
         options, action = action, nil
       when String, Symbol
         action = action.to_s
         case action.index("/")
         when NilClass
-          options[:_prefix] = _prefix
-          options[:_template_name] = action
+          options[:action] = action
         when 0
           options[:file] = action
         else
           options[:template] = action
         end
+      else
+        options.merge!(:partial => action)
       end
 
       options
     end
 
     def _normalize_options(options)
-    end
+      if options[:partial] == true
+        options[:partial] = action_name
+      end
 
-    # Take in a set of options and determine the template to render
-    #
-    # ==== Options
-    # _template<ActionView::Template>:: If this is provided, the search is over
-    # _template_name<#to_s>:: The name of the template to look up. Otherwise,
-    #   use the current action name.
-    # _prefix<String>:: The prefix to look inside of. In a file system, this corresponds
-    #   to a directory.
-    # _partial<TrueClass, FalseClass>:: Whether or not the file to look up is a partial
-    def _determine_template(options)
-      if options.key?(:text)
-        options[:_template] = ActionView::Template::Text.new(options[:text], format_for_text)
-      elsif options.key?(:inline)
-        handler  = ActionView::Template.handler_class_for_extension(options[:type] || "erb")
-        template = ActionView::Template.new(options[:inline], "inline template", handler, {})
-        options[:_template] = template
-      elsif options.key?(:template)
-        options[:_template_name] = options[:template]
-      elsif options.key?(:file)
-        options[:_template_name] = options[:file]
+      if (options.keys & [:partial, :file, :template]).empty?
+        options[:_prefix] ||= _prefix 
       end
-      name = (options[:_template_name] || options[:action] || action_name).to_s
-      options[:_prefix] ||= _prefix if (options.keys & [:partial, :file, :template]).empty?
+
+      options[:template] ||= (options[:action] || action_name).to_s
 
       details = _normalize_details(options)
       template_lookup.details = details
-
-      options[:_template] ||= find_template(name, options)
-    end
-
-    def details_for_render
-      {  }
+      options
     end
 
     def _normalize_details(options)
@@ -196,53 +202,11 @@ module AbstractController
       details
     end
 
-    def find_template(name, options)
-      template_lookup.find(name, options[:_prefix], options[:_partial])
-    end
-
-    def template_exists?(name, options)
-      template_lookup.exists?(name, options[:_prefix], options[:_partial])
-    end
-
-    def format_for_text
-      Mime[:text]
+    def _process_options(options)
     end
 
-    module ClassMethods
-      # Append a path to the list of view paths for this controller.
-      #
-      # ==== Parameters
-      # path<String, ViewPath>:: If a String is provided, it gets converted into
-      # the default view path. You may also provide a custom view path
-      # (see ActionView::ViewPathSet for more information)
-      def append_view_path(path)
-        self.view_paths = view_paths.dup + Array(path)
-      end
-
-      # Prepend a path to the list of view paths for this controller.
-      #
-      # ==== Parameters
-      # path<String, ViewPath>:: If a String is provided, it gets converted into
-      # the default view path. You may also provide a custom view path
-      # (see ActionView::ViewPathSet for more information)
-      def prepend_view_path(path)
-        self.view_paths = Array(path) + view_paths.dup
-      end
-
-      # A list of all of the default view paths for this controller.
-      def view_paths
-        _view_paths
-      end
-
-      # Set the view paths.
-      #
-      # ==== Parameters
-      # paths<ViewPathSet, Object>:: If a ViewPathSet is provided, use that;
-      #   otherwise, process the parameter into a ViewPathSet.
-      def view_paths=(paths)
-        self._view_paths = paths.is_a?(ActionView::PathSet) ? paths : ActionView::Base.process_view_paths(paths)
-        self._view_paths.freeze
-      end
+    def _with_template_hook(template)
+      self.formats = template.details[:formats]
     end
   end
 end
diff --git a/actionpack/lib/action_controller/metal/compatibility.rb b/actionpack/lib/action_controller/metal/compatibility.rb
index 0cb20b2f0f..5cad0814ca 100644
--- a/actionpack/lib/action_controller/metal/compatibility.rb
+++ b/actionpack/lib/action_controller/metal/compatibility.rb
@@ -49,14 +49,19 @@ module ActionController
       super
     end
 
-    def render_to_body(options)
-      if options.is_a?(Hash) && options.key?(:template)
-        options[:template].sub!(/^\//, '')
+    def _normalize_options(options)
+      # TODO Deprecate this. Rails 2.x allowed to give a template as action.
+      if options[:action] && options[:action].to_s.include?(?/)
+        options[:template] = options.delete(:action)
       end
 
       options[:text] = nil if options.delete(:nothing) == true
       options[:text] = " " if options.key?(:text) && options[:text].nil?
+      super
+    end
 
+    def render_to_body(options)
+      options[:template].sub!(/^\//, '') if options.key?(:template)
       super || " "
     end
 
diff --git a/actionpack/lib/action_controller/metal/implicit_render.rb b/actionpack/lib/action_controller/metal/implicit_render.rb
index c3e3b8fdf5..282dcf66b3 100644
--- a/actionpack/lib/action_controller/metal/implicit_render.rb
+++ b/actionpack/lib/action_controller/metal/implicit_render.rb
@@ -12,7 +12,7 @@ module ActionController
 
     def method_for_action(action_name)
       super || begin
-        if template_exists?(action_name.to_s, :_prefix => controller_path)
+        if template_exists?(action_name.to_s, _prefix)
           "default_render"
         end
       end
diff --git a/actionpack/lib/action_controller/metal/rendering.rb b/actionpack/lib/action_controller/metal/rendering.rb
index 60d61999de..f892bd9b91 100644
--- a/actionpack/lib/action_controller/metal/rendering.rb
+++ b/actionpack/lib/action_controller/metal/rendering.rb
@@ -6,46 +6,20 @@ module ActionController
     include AbstractController::Rendering
 
     def process(*)
-      self.formats = request.formats.map {|x| x.to_sym }
+      self.formats = request.formats.map { |x| x.to_sym }
       super
     end
 
     def render(*args)
       raise ::AbstractController::DoubleRenderError if response_body
-      args << {} unless args.last.is_a?(Hash)
-      super(*args)
-      self.content_type ||= args.last[:_template].mime_type.to_s
-      response_body
-    end
-
-    def render_to_body(options)
-      _process_options(options)
       super
+      response_body
     end
 
     private
 
-      def _render_partial(options)
-        options[:partial] = action_name if options[:partial] == true
-        options[:_details] = details_for_render
-        super
-      end
-
-      def format_for_text
-        formats.first
-      end
-
       def _normalize_args(action=nil, options={}, &blk)
-        case action
-        when NilClass
-        when Hash
-          options = super(action.delete(:action), action)
-        when String, Symbol
-          options = super
-        else
-          options.merge!(:partial => action)
-        end
-
+        options = super
         options[:update] = blk if block_given?
         options
       end
@@ -64,9 +38,18 @@ module ActionController
 
       def _process_options(options)
         status, content_type, location = options.values_at(:status, :content_type, :location)
+
         self.status = status if status
         self.content_type = content_type if content_type
         self.headers["Location"] = url_for(location) if location
+
+        super
       end
+
+      def _with_template_hook(template)
+        super
+        self.content_type ||= template.mime_type.to_s
+      end
+
   end
 end
diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb
index 17fb110eb4..c6d95e88e2 100644
--- a/actionpack/lib/action_view/render/rendering.rb
+++ b/actionpack/lib/action_view/render/rendering.rb
@@ -24,18 +24,8 @@ module ActionView
           return _render_partial(options)
         end
 
-        template = if options[:file]
-          find(options[:file])
-        elsif options[:inline]
-          handler = Template.handler_class_for_extension(options[:type] || "erb")
-          Template.new(options[:inline], "inline template", handler, {})
-        elsif options[:text]
-          Template::Text.new(options[:text])
-        end
-
-        if template
-          _render_template(template, layout, :locals => options[:locals])
-        end
+        template = _determine_template(options)
+        _render_template(template, layout, :locals => options[:locals]) if template
       when :update
         update_page(&block)
       else
@@ -87,8 +77,28 @@ module ActionView
     # _layout::   The layout, if any, to wrap the Template in
     def render_template(options)
       _evaluate_assigns_and_ivars
-      template, layout = options.values_at(:_template, :layout)
-      _render_template(template, layout, options)
+      if options.key?(:partial)
+        _render_partial(options)
+      else
+        template = _determine_template(options)
+        yield template if block_given?
+        _render_template(template, options[:layout], options)
+      end
+    end
+
+    def _determine_template(options)
+      if options.key?(:inline)
+        handler = Template.handler_class_for_extension(options[:type] || "erb")
+        Template.new(options[:inline], "inline template", handler, {})
+      elsif options.key?(:text)
+        Template::Text.new(options[:text], self.formats.try(:first))
+      elsif options.key?(:_template)
+        options[:_template]
+      elsif options.key?(:file)
+        find(options[:file], options[:_prefix])
+      elsif options.key?(:template)
+        find(options[:template], options[:_prefix])
+      end
     end
 
     def _find_layout(layout)
@@ -102,8 +112,6 @@ module ActionView
     end
 
     def _render_template(template, layout = nil, options = {})
-      self.formats = template.details[:formats]
-
       locals = options[:locals] || {}
       layout = _find_layout(layout) if layout
 
diff --git a/actionpack/lib/action_view/template/text.rb b/actionpack/lib/action_view/template/text.rb
index 2abb352d4e..5978a8a3ac 100644
--- a/actionpack/lib/action_view/template/text.rb
+++ b/actionpack/lib/action_view/template/text.rb
@@ -1,11 +1,10 @@
 module ActionView #:nodoc:
   class Template
     class Text < String #:nodoc:
-      HTML = Mime[:html]
-
-      def initialize(string, content_type = HTML)
+      def initialize(string, content_type = nil)
         super(string.to_s)
-        @content_type = Mime[content_type] || content_type
+        @content_type   = Mime[content_type] || content_type if content_type
+        @content_type ||= Mime::TEXT
       end
 
       def details
diff --git a/actionpack/test/abstract/abstract_controller_test.rb b/actionpack/test/abstract/abstract_controller_test.rb
index 4ad87d9762..f70d497481 100644
--- a/actionpack/test/abstract/abstract_controller_test.rb
+++ b/actionpack/test/abstract/abstract_controller_test.rb
@@ -59,11 +59,11 @@ module AbstractController
       end
 
       def rendering_to_body
-        self.response_body = render_to_body :_template_name => "naked_render.erb"
+        self.response_body = render_to_body :template => "naked_render.erb"
       end
 
       def rendering_to_string
-        self.response_body = render_to_string :_template_name => "naked_render.erb"
+        self.response_body = render_to_string :template => "naked_render.erb"
       end
     end
 
-- 
cgit v1.2.3