1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Speed up performance in resolvers by adding fallbacks just when required.

This commit is contained in:
José Valim 2010-03-08 16:32:40 +01:00
parent 44ebab96da
commit 68cda695da
9 changed files with 53 additions and 69 deletions

View file

@ -142,8 +142,8 @@ module AbstractController
private private
# Normalize options, by converting render "foo" to render :template => "prefix/foo" # Normalize options by converting render "foo" to render :action => "foo" and
# and render "/foo" to render :file => "/foo". # render "foo/bar" to render :file => "foo/bar".
def _normalize_args(action=nil, options={}) def _normalize_args(action=nil, options={})
case action case action
when NilClass when NilClass
@ -151,14 +151,8 @@ module AbstractController
options, action = action, nil options, action = action, nil
when String, Symbol when String, Symbol
action = action.to_s action = action.to_s
case action.index("/") key = action.include?(?/) ? :file : :action
when NilClass options[key] = action
options[:action] = action
when 0
options[:file] = action
else
options[:template] = action
end
else else
options.merge!(:partial => action) options.merge!(:partial => action)
end end

View file

@ -173,48 +173,41 @@ module ActionView #:nodoc:
module Subclasses module Subclasses
end end
include Helpers, Rendering, Partials, Layouts, ::ERB::Util include Helpers, Rendering, Partials, Layouts, ::ERB::Util, Context
extend ActiveSupport::Memoizable
extend ActiveSupport::Memoizable
attr_accessor :base_path, :assigns, :template_extension
attr_internal :captures
class << self
delegate :erb_trim_mode=, :to => 'ActionView::Template::Handlers::ERB'
delegate :logger, :to => 'ActionController::Base', :allow_nil => true
end
# Specify whether RJS responses should be wrapped in a try/catch block # Specify whether RJS responses should be wrapped in a try/catch block
# that alert()s the caught exception (and then re-raises it). # that alert()s the caught exception (and then re-raises it).
cattr_accessor :debug_rjs cattr_accessor :debug_rjs
@@debug_rjs = false @@debug_rjs = false
# :nodoc: class_attribute :helpers
def self.xss_safe? attr_reader :helpers
true
class << self
delegate :erb_trim_mode=, :to => 'ActionView::Template::Handlers::ERB'
delegate :logger, :to => 'ActionController::Base', :allow_nil => true
end end
attr_internal :request, :layout attr_accessor :base_path, :assigns, :template_extension, :lookup_context
attr_internal :captures, :request, :layout, :controller, :template, :config
def controller_path delegate :find_template, :template_exists?, :formats, :formats=,
@controller_path ||= controller && controller.controller_path :view_paths, :view_paths=, :with_fallbacks, :update_details, :to => :lookup_context
end
delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers, delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers,
:flash, :action_name, :controller_name, :to => :controller :flash, :action_name, :controller_name, :to => :controller
delegate :logger, :to => :controller, :allow_nil => true delegate :logger, :to => :controller, :allow_nil => true
include Context def self.xss_safe? #:nodoc:
true
end
def self.process_view_paths(value) def self.process_view_paths(value)
ActionView::PathSet.new(Array(value)) ActionView::PathSet.new(Array(value))
end end
class_attribute :helpers
attr_reader :helpers
def self.for_controller(controller) def self.for_controller(controller)
@views ||= {} @views ||= {}
@ -260,12 +253,9 @@ module ActionView #:nodoc:
@lookup_context.formats = formats if formats @lookup_context.formats = formats if formats
end end
attr_internal :controller, :template, :config def controller_path
@controller_path ||= controller && controller.controller_path
attr_reader :lookup_context end
delegate :find_template, :template_exists?, :formats, :formats=,
:view_paths, :view_paths=, :update_details, :to => :lookup_context
def punctuate_body!(part) def punctuate_body!(part)
flush_output_buffer flush_output_buffer

View file

@ -6,6 +6,9 @@ module ActionView
class LookupContext #:nodoc: class LookupContext #:nodoc:
attr_reader :details, :view_paths attr_reader :details, :view_paths
mattr_accessor :fallbacks
@@fallbacks = [FileSystemResolver.new(""), FileSystemResolver.new("/")]
class DetailsKey #:nodoc: class DetailsKey #:nodoc:
attr_reader :details attr_reader :details
alias :eql? :equal? alias :eql? :equal?
@ -69,6 +72,19 @@ module ActionView
end end
end end
# Added fallbacks to the view paths. Useful in cases you are rendering a file.
def with_fallbacks
added_resolvers = 0
self.class.fallbacks.each do |resolver|
next if view_paths.include?(resolver)
view_paths.push(resolver)
added_resolvers += 1
end
yield
ensure
added_resolvers.times { view_paths.pop }
end
def find_template(name, prefix = nil, partial = false) def find_template(name, prefix = nil, partial = false)
@view_paths.find(name, details, prefix, partial || false, details_key) @view_paths.find(name, details, prefix, partial || false, details_key)
end end

View file

@ -33,7 +33,7 @@ module ActionView #:nodoc:
def typecast! def typecast!
each_with_index do |path, i| each_with_index do |path, i|
next unless path.is_a?(String) next unless path.is_a?(String)
self[i] = FileSystemResolverWithFallback.new(path) self[i] = FileSystemResolver.new(path)
end end
end end
end end

View file

@ -48,7 +48,8 @@ module ActionView
# the given name exists across all details before raising the error. # the given name exists across all details before raising the error.
def _find_layout(layout) #:nodoc: def _find_layout(layout) #:nodoc:
begin begin
find_template(layout) layout =~ /^\// ?
with_fallbacks { find_template(layout) } : find_template(layout)
rescue ActionView::MissingTemplate => e rescue ActionView::MissingTemplate => e
update_details(:formats => nil) do update_details(:formats => nil) do
raise unless template_exists?(layout) raise unless template_exists?(layout)

View file

@ -63,7 +63,7 @@ module ActionView
elsif options.key?(:text) elsif options.key?(:text)
Template::Text.new(options[:text], self.formats.try(:first)) Template::Text.new(options[:text], self.formats.try(:first))
elsif options.key?(:file) elsif options.key?(:file)
find_template(options[:file], options[:_prefix]) with_fallbacks { find_template(options[:file], options[:_prefix]) }
elsif options.key?(:template) elsif options.key?(:template)
find_template(options[:template], options[:_prefix]) find_template(options[:template], options[:_prefix])
end end

View file

@ -4,7 +4,6 @@ require "active_support/core_ext/array/wrap"
require "action_view/template" require "action_view/template"
module ActionView module ActionView
# Abstract superclass
class Resolver class Resolver
class_inheritable_accessor(:registered_details) class_inheritable_accessor(:registered_details)
@ -30,7 +29,7 @@ module ActionView
find_all(*args).first find_all(*args).first
end end
# Normalizes the arguments and passes it on to find_template # Normalizes the arguments and passes it on to find_template.
def find_all(name, details = {}, prefix = nil, partial = nil) def find_all(name, details = {}, prefix = nil, partial = nil)
details = normalize_details(details) details = normalize_details(details)
name, prefix = normalize_name(name, prefix) name, prefix = normalize_name(name, prefix)
@ -82,21 +81,20 @@ module ActionView
end end
class PathResolver < Resolver class PathResolver < Resolver
EXTENSION_ORDER = [:locale, :formats, :handlers] EXTENSION_ORDER = [:locale, :formats, :handlers]
def to_s def to_s
@path.to_s @path.to_s
end end
alias to_path to_s alias :to_path :to_s
private
def find_templates(name, details, prefix, partial) def find_templates(name, details, prefix, partial)
path = build_path(name, details, prefix, partial) path = build_path(name, details, prefix, partial)
query(path, EXTENSION_ORDER.map { |ext| details[ext] }) query(path, EXTENSION_ORDER.map { |ext| details[ext] })
end end
private
def build_path(name, details, prefix, partial) def build_path(name, details, prefix, partial)
path = "" path = ""
path << "#{prefix}/" unless prefix.empty? path << "#{prefix}/" unless prefix.empty?
@ -141,25 +139,10 @@ module ActionView
super() super()
@path = Pathname.new(path).expand_path @path = Pathname.new(path).expand_path
end end
end
# TODO: remove hack def eql?(resolver)
class FileSystemResolverWithFallback < Resolver self.class.equal?(resolver.class) && to_path == resolver.to_path
def initialize(path)
super()
@paths = [FileSystemResolver.new(path), FileSystemResolver.new(""), FileSystemResolver.new("/")]
end
def find_templates(*args)
@paths.each do |p|
template = p.find_templates(*args)
return template unless template.empty?
end
[]
end
def to_s
@paths.first.to_s
end end
alias :== :eql?
end end
end end

View file

@ -44,7 +44,7 @@ class CompiledTemplatesTest < Test::Unit::TestCase
end end
def render_without_cache(*args) def render_without_cache(*args)
path = ActionView::FileSystemResolverWithFallback.new(FIXTURE_LOAD_PATH) path = ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH)
view_paths = ActionView::Base.process_view_paths(path) view_paths = ActionView::Base.process_view_paths(path)
ActionView::Base.new(view_paths, {}).render(*args) ActionView::Base.new(view_paths, {}).render(*args)
end end

View file

@ -270,7 +270,7 @@ class CachedViewRenderTest < ActiveSupport::TestCase
# Ensure view path cache is primed # Ensure view path cache is primed
def setup def setup
view_paths = ActionController::Base.view_paths view_paths = ActionController::Base.view_paths
assert_equal ActionView::FileSystemResolverWithFallback, view_paths.first.class assert_equal ActionView::FileSystemResolver, view_paths.first.class
setup_view(view_paths) setup_view(view_paths)
end end
end end
@ -281,9 +281,9 @@ class LazyViewRenderTest < ActiveSupport::TestCase
# Test the same thing as above, but make sure the view path # Test the same thing as above, but make sure the view path
# is not eager loaded # is not eager loaded
def setup def setup
path = ActionView::FileSystemResolverWithFallback.new(FIXTURE_LOAD_PATH) path = ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH)
view_paths = ActionView::Base.process_view_paths(path) view_paths = ActionView::Base.process_view_paths(path)
assert_equal ActionView::FileSystemResolverWithFallback, view_paths.first.class assert_equal ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH), view_paths.first
setup_view(view_paths) setup_view(view_paths)
end end
end end