From 858a420ce18719c720b80508b336e37ce37a20bf Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 21 Dec 2008 17:23:53 -0600 Subject: Ensure the template format is always passed to the template finder. Now we can cleanup some nasty stuff. --- actionpack/lib/action_controller/base.rb | 30 +++++++++------ actionpack/lib/action_controller/layout.rb | 22 +++++++++-- actionpack/lib/action_view/base.rb | 62 +++--------------------------- actionpack/lib/action_view/partials.rb | 2 +- actionpack/lib/action_view/paths.rb | 41 +++++++------------- actionpack/lib/action_view/renderable.rb | 12 +++++- actionpack/lib/action_view/template.rb | 28 ++++++++++++++ 7 files changed, 93 insertions(+), 104 deletions(-) (limited to 'actionpack/lib') diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 3e001a2ed6..4d4793c4e3 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -502,7 +502,7 @@ module ActionController #:nodoc: protected :filter_parameters end - delegate :exempt_from_layout, :to => 'ActionView::Base' + delegate :exempt_from_layout, :to => 'ActionView::Template' end public @@ -860,7 +860,7 @@ module ActionController #:nodoc: raise DoubleRenderError, "Can only render or redirect once per action" if performed? if options.nil? - return render(:file => default_template_name, :layout => true) + return render(:file => default_template, :layout => true) elsif !extra_options.is_a?(Hash) raise RenderError, "You called render with invalid options : #{options.inspect}, #{extra_options.inspect}" else @@ -898,7 +898,7 @@ module ActionController #:nodoc: render_for_text(@template.render(options.merge(:layout => layout)), options[:status]) elsif action_name = options[:action] - render_for_file(default_template_name(action_name.to_s), options[:status], layout) + render_for_file(default_template(action_name.to_s), options[:status], layout) elsif xml = options[:xml] response.content_type ||= Mime::XML @@ -933,7 +933,7 @@ module ActionController #:nodoc: render_for_text(nil, options[:status]) else - render_for_file(default_template_name, options[:status], layout) + render_for_file(default_template, options[:status], layout) end end end @@ -1164,7 +1164,8 @@ module ActionController #:nodoc: private def render_for_file(template_path, status = nil, layout = nil, locals = {}) #:nodoc: - logger.info("Rendering #{template_path}" + (status ? " (#{status})" : '')) if logger + path = template_path.respond_to?(:path_without_format_and_extension) ? template_path.path_without_format_and_extension : template_path + logger.info("Rendering #{path}" + (status ? " (#{status})" : '')) if logger render_for_text @template.render(:file => template_path, :locals => locals, :layout => layout), status end @@ -1241,10 +1242,17 @@ module ActionController #:nodoc: elsif respond_to? :method_missing method_missing action_name default_render unless performed? - elsif template_exists? - default_render else - raise UnknownAction, "No action responded to #{action_name}. Actions: #{action_methods.sort.to_sentence}", caller + begin + default_render + rescue ActionView::MissingTemplate => e + # Was the implicit template missing, or was it another template? + if e.path == default_template_name + raise UnknownAction, "No action responded to #{action_name}. Actions: #{action_methods.sort.to_sentence}", caller + else + raise e + end + end end end @@ -1290,10 +1298,8 @@ module ActionController #:nodoc: @_session.close if @_session && @_session.respond_to?(:close) end - def template_exists?(template_name = default_template_name) - @template.send(:_pick_template, template_name) ? true : false - rescue ActionView::MissingTemplate - false + def default_template(action_name = self.action_name) + self.view_paths.find_template(default_template_name(action_name), default_template_format) end def default_template_name(action_name = self.action_name) diff --git a/actionpack/lib/action_controller/layout.rb b/actionpack/lib/action_controller/layout.rb index 54108df06d..159c5c7326 100644 --- a/actionpack/lib/action_controller/layout.rb +++ b/actionpack/lib/action_controller/layout.rb @@ -178,9 +178,15 @@ module ActionController #:nodoc: find_layout(layout, format) end + def layout_list #:nodoc: + Array(view_paths).sum([]) { |path| Dir["#{path}/layouts/**/*"] } + 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) + rescue ActionView::MissingTemplate + nil end private @@ -188,7 +194,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 @@ -225,8 +231,16 @@ module ActionController #:nodoc: private def candidate_for_layout?(options) - options.values_at(:text, :xml, :json, :file, :inline, :partial, :nothing, :update).compact.empty? && - !@template.__send__(:_exempt_from_layout?, options[:template] || default_template_name(options[:action])) + template = options[:template] || default_template(options[:action]) + if options.values_at(:text, :xml, :json, :file, :inline, :partial, :nothing, :update).compact.empty? + begin + !self.view_paths.find_template(template, default_template_format).exempt_from_layout? + rescue ActionView::MissingTemplate + true + end + end + rescue ActionView::MissingTemplate + false end def pick_layout(options) @@ -235,7 +249,7 @@ module ActionController #:nodoc: when FalseClass nil when NilClass, TrueClass - active_layout if action_has_layout? && !@template.__send__(:_exempt_from_layout?, default_template_name) + active_layout if action_has_layout? && candidate_for_layout?(:template => default_template_name) else active_layout(layout) end diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index 33517ffb7b..8958e61e9d 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -3,7 +3,10 @@ module ActionView #:nodoc: end class MissingTemplate < ActionViewError #:nodoc: + attr_reader :path + def initialize(paths, path, template_format = nil) + @path = path full_template_path = path.include?('.') ? path : "#{path}.erb" display_paths = paths.compact.join(":") template_type = (path =~ /layouts/i) ? 'layout' : 'template' @@ -172,17 +175,6 @@ module ActionView #:nodoc: delegate :logger, :to => 'ActionController::Base' end - # Templates that are exempt from layouts - @@exempt_from_layout = Set.new([/\.rjs$/]) - - # Don't render layouts for templates with the given extensions. - def self.exempt_from_layout(*extensions) - regexps = extensions.collect do |extension| - extension.is_a?(Regexp) ? extension : /\.#{Regexp.escape(extension.to_s)}$/ - end - @@exempt_from_layout.merge(regexps) - end - @@debug_rjs = false ## # :singleton-method: @@ -190,12 +182,6 @@ module ActionView #:nodoc: # that alert()s the caught exception (and then re-raises it). cattr_accessor :debug_rjs - @@warn_cache_misses = false - ## - # :singleton-method: - # A warning will be displayed whenever an action results in a cache miss on your view paths. - cattr_accessor :warn_cache_misses - attr_internal :request delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers, @@ -257,7 +243,8 @@ module ActionView #:nodoc: if options[:layout] _render_with_layout(options, local_assigns, &block) elsif options[:file] - _pick_template(options[:file]).render_template(self, options[:locals]) + tempalte = self.view_paths.find_template(options[:file], template_format) + tempalte.render_template(self, options[:locals]) elsif options[:partial] render_partial(options) elsif options[:inline] @@ -315,45 +302,6 @@ module ActionView #:nodoc: end end - def _pick_template(template_path) - return template_path if template_path.respond_to?(:render) - - path = template_path.sub(/^\//, '') - if m = path.match(/(.*)\.(\w+)$/) - template_file_name, template_file_extension = m[1], m[2] - else - template_file_name = path - end - - # OPTIMIZE: Checks to lookup template in view path - if template = self.view_paths.find_template(template_file_name, template_format) - 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}"]) - template - else - template = Template.new(template_path, view_paths) - - if self.class.warn_cache_misses && logger - logger.debug "[PERFORMANCE] Rendering a template that was " + - "not found in view path. Templates outside the view path are " + - "not cached and result in expensive disk operations. Move this " + - "file into #{view_paths.join(':')} or add the folder to your " + - "view path list" - end - - template - end - end - memoize :_pick_template - - def _exempt_from_layout?(template_path) #:nodoc: - template = _pick_template(template_path).to_s - @@exempt_from_layout.any? { |ext| template =~ ext } - rescue ActionView::MissingTemplate - return false - end - def _render_with_layout(options, local_assigns, &block) #:nodoc: partial_layout = options.delete(:layout) diff --git a/actionpack/lib/action_view/partials.rb b/actionpack/lib/action_view/partials.rb index bbc995a340..59e82b98a4 100644 --- a/actionpack/lib/action_view/partials.rb +++ b/actionpack/lib/action_view/partials.rb @@ -228,7 +228,7 @@ module ActionView path = "_#{partial_path}" end - _pick_template(path) + self.view_paths.find_template(path, self.template_format) end memoize :_pick_partial_template end diff --git a/actionpack/lib/action_view/paths.rb b/actionpack/lib/action_view/paths.rb index 623b9ff6b0..b030156889 100644 --- a/actionpack/lib/action_view/paths.rb +++ b/actionpack/lib/action_view/paths.rb @@ -2,13 +2,6 @@ module ActionView #:nodoc: class PathSet < Array #:nodoc: def self.type_cast(obj) if obj.is_a?(String) - if Base.warn_cache_misses && defined?(Rails) && Rails.initialized? - Base.logger.debug "[PERFORMANCE] Processing view path during a " + - "request. This an expense disk operation that should be done at " + - "boot. You can manually process this view path with " + - "ActionView::Base.process_view_paths(#{obj.inspect}) and set it " + - "as your view path" - end Path.new(obj) else obj @@ -92,7 +85,7 @@ module ActionView #:nodoc: else Dir.glob("#{@path}/#{path}*").each do |file| template = create_template(file) - if path == template.path_without_extension || path == template.path + if template.accessible_paths.include?(path) return template end end @@ -115,8 +108,9 @@ module ActionView #:nodoc: templates_in_path do |template| template.load! - @paths[template.path] = template - @paths[template.path_without_extension] ||= template + template.accessible_paths.each do |path| + @paths[path] = template + end end @paths.freeze @@ -143,28 +137,19 @@ module ActionView #:nodoc: each { |path| path.reload! } end - def [](template_path) - each do |path| - if template = path[template_path] - return template - end - end - nil - end + def find_template(original_template_path, format = nil) + return original_template_path if original_template_path.respond_to?(:render) + template_path = original_template_path.sub(/^\//, '') - 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}"] + each do |load_path| + if format && (template = load_path["#{template_path}.#{format}"]) + return template + elsif template = load_path[template_path] return template end end - if template = self[path] - return template - end - nil + + Template.new(original_template_path, self) end end end diff --git a/actionpack/lib/action_view/renderable.rb b/actionpack/lib/action_view/renderable.rb index 7c0e62f1d7..4a5b36d70a 100644 --- a/actionpack/lib/action_view/renderable.rb +++ b/actionpack/lib/action_view/renderable.rb @@ -22,6 +22,11 @@ module ActionView end memoize :compiled_source + def method_name_without_locals + ['_run', extension, method_segment].compact.join('_') + end + memoize :method_name_without_locals + def render(view, local_assigns = {}) compile(local_assigns) @@ -46,9 +51,12 @@ module ActionView def method_name(local_assigns) if local_assigns && local_assigns.any? - local_assigns_keys = "locals_#{local_assigns.keys.map { |k| k.to_s }.sort.join('_')}" + method_name = method_name_without_locals.dup + method_name << "_locals_#{local_assigns.keys.map { |k| k.to_s }.sort.join('_')}" + else + method_name = method_name_without_locals end - ['_run', extension, method_segment, local_assigns_keys].compact.join('_').to_sym + method_name.to_sym end private diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb index 93748638c3..5b384d0e4d 100644 --- a/actionpack/lib/action_view/template.rb +++ b/actionpack/lib/action_view/template.rb @@ -4,6 +4,17 @@ module ActionView #:nodoc: extend ActiveSupport::Memoizable include Renderable + # Templates that are exempt from layouts + @@exempt_from_layout = Set.new([/\.rjs$/]) + + # Don't render layouts for templates with the given extensions. + def self.exempt_from_layout(*extensions) + regexps = extensions.collect do |extension| + extension.is_a?(Regexp) ? extension : /\.#{Regexp.escape(extension.to_s)}$/ + end + @@exempt_from_layout.merge(regexps) + end + attr_accessor :filename, :load_path, :base_path, :name, :format, :extension delegate :to_s, :to => :path @@ -17,6 +28,18 @@ module ActionView #:nodoc: extend RenderablePartial if @name =~ /^_/ end + def accessible_paths + paths = [] + paths << path + paths << path_without_extension + if multipart? + formats = format.split(".") + paths << "#{path_without_format_and_extension}.#{formats.first}" + paths << "#{path_without_format_and_extension}.#{formats.second}" + end + paths + end + def format_and_extension (extensions = [format, extension].compact.join(".")).blank? ? nil : extensions end @@ -57,6 +80,10 @@ module ActionView #:nodoc: end memoize :relative_path + def exempt_from_layout? + @@exempt_from_layout.any? { |exempted| path =~ exempted } + end + def mtime File.mtime(filename) end @@ -94,6 +121,7 @@ module ActionView #:nodoc: def load! @loaded = true + compile({}) freeze end -- cgit v1.2.3