aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Heinemeier Hansson <david@loudthinking.com>2008-11-27 21:04:24 +0100
committerDavid Heinemeier Hansson <david@loudthinking.com>2008-11-27 21:04:24 +0100
commit5fa0457542b0ff541d0a80ff8c3561eec8e35959 (patch)
tree02264b718d54ffb2a513ad9a05bf2c7a6f572589
parent6fa9957e0e83f327aaffe34679a5752fc2343fae (diff)
downloadrails-5fa0457542b0ff541d0a80ff8c3561eec8e35959.tar.gz
rails-5fa0457542b0ff541d0a80ff8c3561eec8e35959.tar.bz2
rails-5fa0457542b0ff541d0a80ff8c3561eec8e35959.zip
Revert "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." as it killed dev mode reloading.
This reverts commit 4d910b033379727e5e7355590c50c72fc75e56db.
-rw-r--r--actionpack/lib/action_controller/base.rb5
-rw-r--r--actionpack/lib/action_controller/dispatcher.rb1
-rw-r--r--actionpack/lib/action_controller/layout.rb38
-rw-r--r--actionpack/lib/action_view/base.rb4
-rw-r--r--actionpack/lib/action_view/paths.rb67
-rw-r--r--actionpack/lib/action_view/renderable.rb2
-rw-r--r--actionpack/test/abstract_unit.rb2
-rw-r--r--actionpack/test/controller/layout_test.rb14
-rw-r--r--actionpack/test/template/compiled_templates_test.rb9
-rw-r--r--actionpack/test/template/render_test.rb17
-rw-r--r--railties/lib/initializer.rb7
11 files changed, 74 insertions, 92 deletions
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index dca66ff0a5..7e38f95076 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -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("Rendering template within #{layout.path_without_format_and_extension}") if logger && layout
+ response.layout = layout = pick_layout(options)
+ logger.info("Rendering template within #{layout}") if logger && layout
if content_type = options[:content_type]
response.content_type = content_type.to_s
diff --git a/actionpack/lib/action_controller/dispatcher.rb b/actionpack/lib/action_controller/dispatcher.rb
index 6e4aba2280..1c7a4b0545 100644
--- a/actionpack/lib/action_controller/dispatcher.rb
+++ b/actionpack/lib/action_controller/dispatcher.rb
@@ -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 --git a/actionpack/lib/action_controller/layout.rb b/actionpack/lib/action_controller/layout.rb
index 54108df06d..3631ce86af 100644
--- a/actionpack/lib/action_controller/layout.rb
+++ b/actionpack/lib/action_controller/layout.rb
@@ -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 : "layouts/#{layout}", *formats)
+ def layout_list #:nodoc:
+ Array(view_paths).sum([]) { |path| Dir["#{path}/layouts/**/*"] }
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 => [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? && 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 <tt>layout "standard"</tt> 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?('/') && ! layout_directory?(active_layout)
+ active_layout
else
- raise ActionView::MissingTemplate.new(self.class.view_paths, active_layout)
+ "layouts/#{active_layout}"
end
end
end
@@ -259,6 +271,12 @@ module ActionController #:nodoc:
end
end
+ def layout_directory?(layout_name)
+ @template.__send__(:_pick_template, "#{File.join('layouts', layout_name)}.#{@template.template_format}") ? true : false
+ rescue ActionView::MissingTemplate
+ false
+ end
+
def default_template_format
response.template.template_format
end
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index da1f283deb..7697848713 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -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["#{template_file_name}.#{template_format}"]
+ template
+ elsif template = self.view_paths[template_file_name]
template
elsif (first_render = @_render_stack.first) && first_render.respond_to?(:format_and_extension) &&
(template = self.view_paths["#{template_file_name}.#{first_render.format_and_extension}"])
diff --git a/actionpack/lib/action_view/paths.rb b/actionpack/lib/action_view/paths.rb
index f01ed9e6e0..d6bf2137af 100644
--- a/actionpack/lib/action_view/paths.rb
+++ b/actionpack/lib/action_view/paths.rb
@@ -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 => :path
- def initialize(path, load = false)
+ def initialize(path, load = true)
raise ArgumentError, "path already is a Path class" 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 "lazy"
- # and makes file system calls every time and the other is cached,
- # "eager" which looks up the template in an in memory index. The "lazy"
- # version is designed for development where you want to automatically
- # find new templates between requests. The "eager" 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("#{@path}/#{path}*").each do |file|
- template = create_template(file)
- if path == template.path_without_extension || path == template.path
- return template
- end
- end
- nil
- end
+ raise "Unloaded view path! #{@path}" 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("#{@path}/**/*/**") | Dir.glob("#{@path}/**")).each do |file|
- yield create_template(file) unless File.directory?(file)
+ unless File.directory?(file)
+ yield Template.new(file.split("#{self}/").last, self)
+ end
end
end
-
- def create_template(file)
- Template.new(file.split("#{self}/").last, self)
- end
end
def load
@@ -139,20 +121,5 @@ module ActionView #:nodoc:
end
nil
end
-
- def find_template(path, *formats)
- if formats && formats.first == :all
- formats = Mime::EXTENSION_LOOKUP.values.map(&:to_sym)
- end
- formats.each do |format|
- if template = self["#{path}.#{format}"]
- return template
- end
- end
- if template = self[path]
- return template
- end
- nil
- end
end
end
diff --git a/actionpack/lib/action_view/renderable.rb b/actionpack/lib/action_view/renderable.rb
index c04399f2c9..5ff5569db6 100644
--- a/actionpack/lib/action_view/renderable.rb
+++ b/actionpack/lib/action_view/renderable.rb
@@ -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? && Base::CompiledTemplates.method_defined?(symbol))
+ !(ActionView::PathSet::Path.eager_load_templates? && Base::CompiledTemplates.method_defined?(symbol))
end
end
end
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index 24fdc03507..bee598e1ef 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -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 --git a/actionpack/test/controller/layout_test.rb b/actionpack/test/controller/layout_test.rb
index 18c01f755c..61c20f8299 100644
--- a/actionpack/test/controller/layout_test.rb
+++ b/actionpack/test/controller/layout_test.rb
@@ -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 < ActionController::Base
@@ -35,6 +31,9 @@ end
class MultipleExtensions < LayoutTest
end
+ActionView::Template::register_template_handler :mab,
+ lambda { |template| template.source.inspect }
+
class LayoutAutoDiscoveryTest < ActionController::TestCase
def setup
@request.host = "www.nextangle.com"
@@ -53,9 +52,10 @@ class LayoutAutoDiscoveryTest < 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 < 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 --git a/actionpack/test/template/compiled_templates_test.rb b/actionpack/test/template/compiled_templates_test.rb
index 0b3d039409..f7688b2072 100644
--- a/actionpack/test/template/compiled_templates_test.rb
+++ b/actionpack/test/template/compiled_templates_test.rb
@@ -30,6 +30,15 @@ uses_mocha 'TestTemplateRecompilation' do
assert_equal "Hello world!", render(:file => "test/hello_world.erb")
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 "Hello world!", render(:file => "#{FIXTURE_LOAD_PATH}/test/hello_world.erb")
+ ActionView::Template.any_instance.expects(:compile!).times(3)
+ 3.times { assert_equal "Hello world!", render(:file => "#{FIXTURE_LOAD_PATH}/test/hello_world.erb") }
+ assert_equal 1, @compiled_templates.instance_methods.size
+ end
+
private
def render(*args)
ActionView::Base.new(ActionController::Base.view_paths, {}).render(*args)
diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb
index 28d38b0c76..b316d5c23e 100644
--- a/actionpack/test/template/render_test.rb
+++ b/actionpack/test/template/render_test.rb
@@ -4,9 +4,7 @@ require 'controller/fake_models'
class ViewRenderTest < Test::Unit::TestCase
def setup
@assigns = { :secret => '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 < Test::Unit::TestCase
end
def test_render_fallbacks_to_erb_for_unknown_types
- assert_equal "Hello, World!", @view.render(:inline => "Hello, World!", :type => :bar)
+ assert_equal "Hello, World!", @view.render(:inline => "Hello, World!", :type => :foo)
end
CustomHandler = lambda do |template|
@@ -198,14 +196,3 @@ class ViewRenderTest < Test::Unit::TestCase
@view.render(:file => "test/nested_layout.erb", :layout => "layouts/yield")
end
end
-
-class LazyViewRenderTest < ViewRenderTest
- # Test the same thing as above, but make sure the view path
- # is not eager loaded
- def setup
- @assigns = { :secret => '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 --git a/railties/lib/initializer.rb b/railties/lib/initializer.rb
index a69898e2c5..0c06d1bf21 100644
--- a/railties/lib/initializer.rb
+++ b/railties/lib/initializer.rb
@@ -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