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:
parent
44ebab96da
commit
68cda695da
9 changed files with 53 additions and 69 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue