From 34905673a3018edeff71aafeceb64e487304d31d Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Thu, 27 Nov 2008 21:04:24 +0100 Subject: 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. --- actionpack/lib/action_controller/base.rb | 5 +- actionpack/lib/action_controller/dispatcher.rb | 1 + actionpack/lib/action_controller/layout.rb | 38 +++++++++++---- actionpack/lib/action_view/base.rb | 4 +- actionpack/lib/action_view/paths.rb | 67 +++++++------------------- actionpack/lib/action_view/renderable.rb | 2 +- 6 files changed, 52 insertions(+), 65 deletions(-) (limited to 'actionpack/lib') 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 layout "standard" 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 -- cgit v1.2.3