<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -867,9 +867,8 @@ module ActionController #:nodoc:
           end
         end
 
-        layout = pick_layout(options)
-        response.layout = layout.path_without_format_and_extension if layout
-        logger.info(&quot;Rendering template within #{layout.path_without_format_and_extension}&quot;) if logger &amp;&amp; layout
+        response.layout = layout = pick_layout(options)
+        logger.info(&quot;Rendering template within #{layout}&quot;) if logger &amp;&amp; layout
 
         if content_type = options[:content_type]
           response.content_type = content_type.to_s</diff>
      <filename>actionpack/lib/action_controller/base.rb</filename>
    </modified>
    <modified>
      <diff>@@ -137,6 +137,7 @@ module ActionController
       run_callbacks :prepare_dispatch
 
       Routing::Routes.reload
+      ActionController::Base.view_paths.reload!
       ActionView::Helpers::AssetTagHelper::AssetTag::Cache.clear
     end
 </diff>
      <filename>actionpack/lib/action_controller/dispatcher.rb</filename>
    </modified>
    <modified>
      <diff>@@ -175,12 +175,13 @@ module ActionController #:nodoc:
       def default_layout(format) #:nodoc:
         layout = read_inheritable_attribute(:layout)
         return layout unless read_inheritable_attribute(:auto_layout)
-        find_layout(layout, format)
+        @default_layout ||= {}
+        @default_layout[format] ||= default_layout_with_format(format, layout)
+        @default_layout[format]
       end
 
-      def find_layout(layout, *formats) #:nodoc:
-        return layout if layout.respond_to?(:render)
-        view_paths.find_template(layout.to_s =~ /layouts\// ? layout : &quot;layouts/#{layout}&quot;, *formats)
+      def layout_list #:nodoc:
+        Array(view_paths).sum([]) { |path| Dir[&quot;#{path}/layouts/**/*&quot;] }
       end
 
       private
@@ -188,7 +189,7 @@ module ActionController #:nodoc:
           inherited_without_layout(child)
           unless child.name.blank?
             layout_match = child.name.underscore.sub(/_controller$/, '').sub(/^controllers\//, '')
-            child.layout(layout_match, {}, true) if child.find_layout(layout_match, :all)
+            child.layout(layout_match, {}, true) unless child.layout_list.grep(%r{layouts/#{layout_match}(\.[a-z][0-9a-z]*)+$}).empty?
           end
         end
 
@@ -199,6 +200,15 @@ module ActionController #:nodoc:
         def normalize_conditions(conditions)
           conditions.inject({}) {|hash, (key, value)| hash.merge(key =&gt; [value].flatten.map {|action| action.to_s})}
         end
+
+        def default_layout_with_format(format, layout)
+          list = layout_list
+          if list.grep(%r{layouts/#{layout}\.#{format}(\.[a-z][0-9a-z]*)+$}).empty?
+            (!list.grep(%r{layouts/#{layout}\.([a-z][0-9a-z]*)+$}).empty? &amp;&amp; format == :html) ? layout : nil
+          else
+            layout
+          end
+        end
     end
 
     # Returns the name of the active layout. If the layout was specified as a method reference (through a symbol), this method
@@ -207,18 +217,20 @@ module ActionController #:nodoc:
     # weblog/standard, but &lt;tt&gt;layout &quot;standard&quot;&lt;/tt&gt; will return layouts/standard.
     def active_layout(passed_layout = nil)
       layout = passed_layout || self.class.default_layout(default_template_format)
-
       active_layout = case layout
+        when String then layout
         when Symbol then __send__(layout)
         when Proc   then layout.call(self)
-        else layout
       end
 
+      # Explicitly passed layout names with slashes are looked up relative to the template root,
+      # but auto-discovered layouts derived from a nested controller will contain a slash, though be relative
+      # to the 'layouts' directory so we have to check the file system to infer which case the layout name came from.
       if active_layout
-        if layout = self.class.find_layout(active_layout, @template.template_format)
-          layout
+        if active_layout.include?('/') &amp;&amp; ! layout_directory?(active_layout)
+          active_layout
         else
-          raise ActionView::MissingTemplate.new(self.class.view_paths, active_layout)
+          &quot;layouts/#{active_layout}&quot;
         end
       end
     end
@@ -259,6 +271,12 @@ module ActionController #:nodoc:
         end
       end
 
+      def layout_directory?(layout_name)
+        @template.__send__(:_pick_template, &quot;#{File.join('layouts', layout_name)}.#{@template.template_format}&quot;) ? true : false
+      rescue ActionView::MissingTemplate
+        false
+      end
+
       def default_template_format
         response.template.template_format
       end</diff>
      <filename>actionpack/lib/action_controller/layout.rb</filename>
    </modified>
    <modified>
      <diff>@@ -322,7 +322,9 @@ module ActionView #:nodoc:
         end
 
         # OPTIMIZE: Checks to lookup template in view path
-        if template = self.view_paths.find_template(template_file_name, template_format)
+        if template = self.view_paths[&quot;#{template_file_name}.#{template_format}&quot;]
+          template
+        elsif template = self.view_paths[template_file_name]
           template
         elsif (first_render = @_render_stack.first) &amp;&amp; first_render.respond_to?(:format_and_extension) &amp;&amp;
             (template = self.view_paths[&quot;#{template_file_name}.#{first_render.format_and_extension}&quot;])</diff>
      <filename>actionpack/lib/action_view/base.rb</filename>
    </modified>
    <modified>
      <diff>@@ -40,10 +40,18 @@ module ActionView #:nodoc:
     end
 
     class Path #:nodoc:
+      def self.eager_load_templates!
+        @eager_load_templates = true
+      end
+
+      def self.eager_load_templates?
+        @eager_load_templates || false
+      end
+
       attr_reader :path, :paths
       delegate :to_s, :to_str, :hash, :inspect, :to =&gt; :path
 
-      def initialize(path, load = false)
+      def initialize(path, load = true)
         raise ArgumentError, &quot;path already is a Path class&quot; if path.is_a?(Path)
         @path = path.freeze
         reload! if load
@@ -57,35 +65,9 @@ module ActionView #:nodoc:
         to_str == path.to_str
       end
 
-      # Returns a ActionView::Template object for the given path string. The
-      # input path should be relative to the view path directory,
-      # +hello/index.html.erb+. This method also has a special exception to
-      # match partial file names without a handler extension. So
-      # +hello/index.html+ will match the first template it finds with a
-      # known template extension, +hello/index.html.erb+. Template extensions
-      # should not be confused with format extensions +html+, +js+, +xml+,
-      # etc. A format must be supplied to match a formated file. +hello/index+
-      # will never match +hello/index.html.erb+.
-      #
-      # This method also has two different implementations, one that is &quot;lazy&quot;
-      # and makes file system calls every time and the other is cached,
-      # &quot;eager&quot; which looks up the template in an in memory index. The &quot;lazy&quot;
-      # version is designed for development where you want to automatically
-      # find new templates between requests. The &quot;eager&quot; version is designed
-      # for production mode and it is much faster but requires more time
-      # upfront to build the file index.
       def [](path)
-        if loaded?
-          @paths[path]
-        else
-          Dir.glob(&quot;#{@path}/#{path}*&quot;).each do |file|
-            template = create_template(file)
-            if path == template.path_without_extension || path == template.path
-              return template
-            end
-          end
-          nil
-        end
+        raise &quot;Unloaded view path! #{@path}&quot; unless @loaded
+        @paths[path]
       end
 
       def loaded?
@@ -102,7 +84,9 @@ module ActionView #:nodoc:
         @paths = {}
 
         templates_in_path do |template|
-          template.freeze
+          # Eager load memoized methods and freeze cached template
+          template.freeze if self.class.eager_load_templates?
+
           @paths[template.path] = template
           @paths[template.path_without_extension] ||= template
         end
@@ -114,13 +98,11 @@ module ActionView #:nodoc:
       private
         def templates_in_path
           (Dir.glob(&quot;#{@path}/**/*/**&quot;) | Dir.glob(&quot;#{@path}/**&quot;)).each do |file|
-            yield create_template(file) unless File.directory?(file)
+            unless File.directory?(file)
+              yield Template.new(file.split(&quot;#{self}/&quot;).last, self)
+            end
           end
         end
-
-        def create_template(file)
-          Template.new(file.split(&quot;#{self}/&quot;).last, self)
-        end
     end
 
     def load
@@ -139,20 +121,5 @@ module ActionView #:nodoc:
       end
       nil
     end
-
-    def find_template(path, *formats)
-      if formats &amp;&amp; formats.first == :all
-        formats = Mime::EXTENSION_LOOKUP.values.map(&amp;:to_sym)
-      end
-      formats.each do |format|
-        if template = self[&quot;#{path}.#{format}&quot;]
-          return template
-        end
-      end
-      if template = self[path]
-        return template
-      end
-      nil
-    end
   end
 end</diff>
      <filename>actionpack/lib/action_view/paths.rb</filename>
    </modified>
    <modified>
      <diff>@@ -96,7 +96,7 @@ module ActionView
       # The template will be compiled if the file has not been compiled yet, or
       # if local_assigns has a new key, which isn't supported by the compiled code yet.
       def recompile?(symbol)
-        !(frozen? &amp;&amp; Base::CompiledTemplates.method_defined?(symbol))
+        !(ActionView::PathSet::Path.eager_load_templates? &amp;&amp; Base::CompiledTemplates.method_defined?(symbol))
       end
   end
 end</diff>
      <filename>actionpack/lib/action_view/renderable.rb</filename>
    </modified>
    <modified>
      <diff>@@ -30,8 +30,8 @@ ActionController::Base.logger = nil
 ActionController::Routing::Routes.reload rescue nil
 
 FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures')
+ActionView::PathSet::Path.eager_load_templates!
 ActionController::Base.view_paths = FIXTURE_LOAD_PATH
-ActionController::Base.view_paths.load
 
 def uses_mocha(test_name)
   yield</diff>
      <filename>actionpack/test/abstract_unit.rb</filename>
    </modified>
    <modified>
      <diff>@@ -3,10 +3,6 @@ require 'abstract_unit'
 # The view_paths array must be set on Base and not LayoutTest so that LayoutTest's inherited
 # method has access to the view_paths array when looking for a layout to automatically assign.
 old_load_paths = ActionController::Base.view_paths
-
-ActionView::Template::register_template_handler :mab,
-  lambda { |template| template.source.inspect }
-
 ActionController::Base.view_paths = [ File.dirname(__FILE__) + '/../fixtures/layout_tests/' ]
 
 class LayoutTest &lt; ActionController::Base
@@ -35,6 +31,9 @@ end
 class MultipleExtensions &lt; LayoutTest
 end
 
+ActionView::Template::register_template_handler :mab,
+  lambda { |template| template.source.inspect }
+
 class LayoutAutoDiscoveryTest &lt; ActionController::TestCase
   def setup
     @request.host = &quot;www.nextangle.com&quot;
@@ -53,9 +52,10 @@ class LayoutAutoDiscoveryTest &lt; ActionController::TestCase
   end
 
   def test_third_party_template_library_auto_discovers_layout
+    ThirdPartyTemplateLibraryController.view_paths.reload!
     @controller = ThirdPartyTemplateLibraryController.new
     get :hello
-    assert_equal 'layouts/third_party_template_library.mab', @controller.active_layout.to_s
+    assert_equal 'layouts/third_party_template_library', @controller.active_layout
     assert_equal 'layouts/third_party_template_library', @response.layout
     assert_response :success
     assert_equal 'Mab', @response.body
@@ -64,14 +64,14 @@ class LayoutAutoDiscoveryTest &lt; ActionController::TestCase
   def test_namespaced_controllers_auto_detect_layouts
     @controller = ControllerNameSpace::NestedController.new
     get :hello
-    assert_equal 'layouts/controller_name_space/nested', @controller.active_layout.to_s
+    assert_equal 'layouts/controller_name_space/nested', @controller.active_layout
     assert_equal 'controller_name_space/nested.rhtml hello.rhtml', @response.body
   end
 
   def test_namespaced_controllers_auto_detect_layouts
     @controller = MultipleExtensions.new
     get :hello
-    assert_equal 'layouts/multiple_extensions.html.erb', @controller.active_layout.to_s
+    assert_equal 'layouts/multiple_extensions', @controller.active_layout
     assert_equal 'multiple_extensions.html.erb hello.rhtml', @response.body.strip
   end
 end</diff>
      <filename>actionpack/test/controller/layout_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -30,6 +30,15 @@ uses_mocha 'TestTemplateRecompilation' do
       assert_equal &quot;Hello world!&quot;, render(:file =&gt; &quot;test/hello_world.erb&quot;)
     end
 
+    def test_compiled_template_will_always_be_recompiled_when_eager_loaded_templates_is_off
+      ActionView::PathSet::Path.expects(:eager_load_templates?).times(4).returns(false)
+      assert_equal 0, @compiled_templates.instance_methods.size
+      assert_equal &quot;Hello world!&quot;, render(:file =&gt; &quot;#{FIXTURE_LOAD_PATH}/test/hello_world.erb&quot;)
+      ActionView::Template.any_instance.expects(:compile!).times(3)
+      3.times { assert_equal &quot;Hello world!&quot;, render(:file =&gt; &quot;#{FIXTURE_LOAD_PATH}/test/hello_world.erb&quot;) }
+      assert_equal 1, @compiled_templates.instance_methods.size
+    end
+
     private
       def render(*args)
         ActionView::Base.new(ActionController::Base.view_paths, {}).render(*args)</diff>
      <filename>actionpack/test/template/compiled_templates_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -4,9 +4,7 @@ require 'controller/fake_models'
 class ViewRenderTest &lt; Test::Unit::TestCase
   def setup
     @assigns = { :secret =&gt; 'in the sauce' }
-    view_paths = ActionController::Base.view_paths
-    @view = ActionView::Base.new(view_paths, @assigns)
-    assert view_paths.first.loaded?
+    @view = ActionView::Base.new(ActionController::Base.view_paths, @assigns)
   end
 
   def test_render_file
@@ -159,7 +157,7 @@ class ViewRenderTest &lt; Test::Unit::TestCase
   end
 
   def test_render_fallbacks_to_erb_for_unknown_types
-    assert_equal &quot;Hello, World!&quot;, @view.render(:inline =&gt; &quot;Hello, World!&quot;, :type =&gt; :bar)
+    assert_equal &quot;Hello, World!&quot;, @view.render(:inline =&gt; &quot;Hello, World!&quot;, :type =&gt; :foo)
   end
 
   CustomHandler = lambda do |template|
@@ -198,14 +196,3 @@ class ViewRenderTest &lt; Test::Unit::TestCase
       @view.render(:file =&gt; &quot;test/nested_layout.erb&quot;, :layout =&gt; &quot;layouts/yield&quot;)
   end
 end
-
-class LazyViewRenderTest &lt; ViewRenderTest
-  # Test the same thing as above, but make sure the view path
-  # is not eager loaded
-  def setup
-    @assigns = { :secret =&gt; 'in the sauce' }
-    view_paths = ActionView::Base.process_view_paths(FIXTURE_LOAD_PATH)
-    @view = ActionView::Base.new(view_paths, @assigns)
-    assert !view_paths.first.loaded?
-  end
-end</diff>
      <filename>actionpack/test/template/render_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -372,10 +372,9 @@ Run `rake gems:install` to install the missing gems.
 
     def load_view_paths
       if configuration.frameworks.include?(:action_view)
-        if configuration.cache_classes
-          ActionController::Base.view_paths.load if configuration.frameworks.include?(:action_controller)
-          ActionMailer::Base.template_root.load if configuration.frameworks.include?(:action_mailer)
-        end
+        ActionView::PathSet::Path.eager_load_templates! if configuration.cache_classes
+        ActionController::Base.view_paths.load if configuration.frameworks.include?(:action_controller)
+        ActionMailer::Base.template_root.load if configuration.frameworks.include?(:action_mailer)
       end
     end
 </diff>
      <filename>railties/lib/initializer.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>6fa9957e0e83f327aaffe34679a5752fc2343fae</id>
    </parent>
  </parents>
  <author>
    <name>David Heinemeier Hansson</name>
    <email>david@loudthinking.com</email>
  </author>
  <url>http://github.com/rails/rails/commit/5fa0457542b0ff541d0a80ff8c3561eec8e35959</url>
  <id>5fa0457542b0ff541d0a80ff8c3561eec8e35959</id>
  <committed-date>2008-11-27T12:04:24-08:00</committed-date>
  <authored-date>2008-11-27T12:04:24-08:00</authored-date>
  <message>Revert &quot;Super lazy load view paths in development mode (no indexing or caching at all). Switch layout finders to use view path api to take advantage of cache.&quot; as it killed dev mode reloading.

This reverts commit 4d910b033379727e5e7355590c50c72fc75e56db.</message>
  <tree>02264b718d54ffb2a513ad9a05bf2c7a6f572589</tree>
  <committer>
    <name>David Heinemeier Hansson</name>
    <email>david@loudthinking.com</email>
  </committer>
</commit>
