aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib')
-rw-r--r--actionpack/lib/action_controller/test_case.rb2
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb1
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb2
-rw-r--r--actionpack/lib/action_view/lookup_context.rb2
-rw-r--r--actionpack/lib/action_view/renderer/template_renderer.rb4
-rw-r--r--actionpack/lib/action_view/template/resolver.rb105
-rw-r--r--actionpack/lib/action_view/template/text.rb10
7 files changed, 96 insertions, 30 deletions
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 2fcff8a675..a1f29ea1bc 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -576,7 +576,7 @@ module ActionController
#
# The exception is stored in the exception accessor for further inspection.
module RaiseActionExceptions
- def self.included(base)
+ def self.included(base) #:nodoc:
unless base.method_defined?(:exception) && base.method_defined?(:exception=)
base.class_eval do
attr_accessor :exception
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index 7dd35f7357..ba2a26fd09 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -979,6 +979,7 @@ module ActionView
def telephone_field(object_name, method, options = {})
Tags::TelField.new(object_name, method, self, options).render
end
+ # aliases telephone_field
alias phone_field telephone_field
# Returns a text_field of type "date".
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index 7f5b3c8a0f..736f9fa2f0 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -23,7 +23,7 @@ module ActionView
include ActionDispatch::Routing::UrlFor
include TagHelper
- # We need to override url_optoins, _routes_context
+ # We need to override url_options, _routes_context
# and optimize_routes_generation? to consider the controller.
def url_options #:nodoc:
diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb
index b7945a23be..00989ec405 100644
--- a/actionpack/lib/action_view/lookup_context.rb
+++ b/actionpack/lib/action_view/lookup_context.rb
@@ -24,7 +24,7 @@ module ActionView
Accessors.send :define_method, :"default_#{name}", &block
Accessors.module_eval <<-METHOD, __FILE__, __LINE__ + 1
def #{name}
- @details[:#{name}]
+ @details.fetch(:#{name}, [])
end
def #{name}=(value)
diff --git a/actionpack/lib/action_view/renderer/template_renderer.rb b/actionpack/lib/action_view/renderer/template_renderer.rb
index 82892593f8..3c1b11396a 100644
--- a/actionpack/lib/action_view/renderer/template_renderer.rb
+++ b/actionpack/lib/action_view/renderer/template_renderer.rb
@@ -18,10 +18,10 @@ module ActionView
# Determine the template to be rendered using the given options.
def determine_template(options) #:nodoc:
- keys = options[:locals].try(:keys) || []
+ keys = options.fetch(:locals, {}).keys
if options.key?(:text)
- Template::Text.new(options[:text], formats.try(:first))
+ Template::Text.new(options[:text], formats.first)
elsif options.key?(:file)
with_fallbacks { find_template(options[:file], nil, false, keys, @details) }
elsif options.key?(:inline)
diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb
index fa2038f78d..2bb656fac9 100644
--- a/actionpack/lib/action_view/template/resolver.rb
+++ b/actionpack/lib/action_view/template/resolver.rb
@@ -2,12 +2,14 @@ require "pathname"
require "active_support/core_ext/class"
require "active_support/core_ext/class/attribute_accessors"
require "action_view/template"
+require "thread"
+require "mutex_m"
module ActionView
# = Action View Resolver
class Resolver
# Keeps all information about view path and builds virtual path.
- class Path < String
+ class Path
attr_reader :name, :prefix, :partial, :virtual
alias_method :partial?, :partial
@@ -19,8 +21,77 @@ module ActionView
end
def initialize(name, prefix, partial, virtual)
- @name, @prefix, @partial = name, prefix, partial
- super(virtual)
+ @name = name
+ @prefix = prefix
+ @partial = partial
+ @virtual = virtual
+ end
+
+ def to_str
+ @virtual
+ end
+ alias :to_s :to_str
+ end
+
+ # Threadsafe template cache
+ class Cache #:nodoc:
+ class CacheEntry
+ include Mutex_m
+
+ attr_accessor :templates
+ end
+
+ def initialize
+ @data = Hash.new { |h1,k1| h1[k1] = Hash.new { |h2,k2|
+ h2[k2] = Hash.new { |h3,k3| h3[k3] = Hash.new { |h4,k4| h4[k4] = {} } } } }
+ @mutex = Mutex.new
+ end
+
+ # Cache the templates returned by the block
+ def cache(key, name, prefix, partial, locals)
+ cache_entry = nil
+
+ # first obtain a lock on the main data structure to create the cache entry
+ @mutex.synchronize do
+ cache_entry = @data[key][name][prefix][partial][locals] ||= CacheEntry.new
+ end
+
+ # then to avoid a long lasting global lock, obtain a more granular lock
+ # on the CacheEntry itself
+ cache_entry.synchronize do
+ if Resolver.caching?
+ cache_entry.templates ||= yield
+ else
+ fresh_templates = yield
+
+ if templates_have_changed?(cache_entry.templates, fresh_templates)
+ cache_entry.templates = fresh_templates
+ else
+ cache_entry.templates ||= []
+ end
+ end
+ end
+ end
+
+ def clear
+ @mutex.synchronize do
+ @data.clear
+ end
+ end
+
+ private
+
+ def templates_have_changed?(cached_templates, fresh_templates)
+ # if either the old or new template list is empty, we don't need to (and can't)
+ # compare modification times, and instead just check whether the lists are different
+ if cached_templates.blank? || fresh_templates.blank?
+ return fresh_templates.blank? != cached_templates.blank?
+ end
+
+ cached_templates_max_updated_at = cached_templates.map(&:updated_at).max
+
+ # if a template has changed, it will be now be newer than all the cached templates
+ fresh_templates.any? { |t| t.updated_at > cached_templates_max_updated_at }
end
end
@@ -32,12 +103,11 @@ module ActionView
end
def initialize
- @cached = Hash.new { |h1,k1| h1[k1] = Hash.new { |h2,k2|
- h2[k2] = Hash.new { |h3,k3| h3[k3] = Hash.new { |h4,k4| h4[k4] = {} } } } }
+ @cache = Cache.new
end
def clear_cache
- @cached.clear
+ @cache.clear
end
# Normalizes the arguments and passes it on to find_template.
@@ -65,27 +135,18 @@ module ActionView
# Handles templates caching. If a key is given and caching is on
# always check the cache before hitting the resolver. Otherwise,
- # it always hits the resolver but check if the resolver is fresher
- # before returning it.
+ # it always hits the resolver but if the key is present, check if the
+ # resolver is fresher before returning it.
def cached(key, path_info, details, locals) #:nodoc:
name, prefix, partial = path_info
locals = locals.map { |x| x.to_s }.sort!
- if key && caching?
- @cached[key][name][prefix][partial][locals] ||= decorate(yield, path_info, details, locals)
- else
- fresh = decorate(yield, path_info, details, locals)
- return fresh unless key
-
- scope = @cached[key][name][prefix][partial]
- cache = scope[locals]
- mtime = cache && cache.map(&:updated_at).max
-
- if !mtime || fresh.empty? || fresh.any? { |t| t.updated_at > mtime }
- scope[locals] = fresh
- else
- cache
+ if key
+ @cache.cache(key, name, prefix, partial, locals) do
+ decorate(yield, path_info, details, locals)
end
+ else
+ decorate(yield, path_info, details, locals)
end
end
diff --git a/actionpack/lib/action_view/template/text.rb b/actionpack/lib/action_view/template/text.rb
index 4261c3b5e2..3af76dfcdb 100644
--- a/actionpack/lib/action_view/template/text.rb
+++ b/actionpack/lib/action_view/template/text.rb
@@ -1,11 +1,11 @@
module ActionView #:nodoc:
# = Action View Text Template
class Template
- class Text < String #:nodoc:
+ class Text #:nodoc:
attr_accessor :mime_type
def initialize(string, mime_type = nil)
- super(string.to_s)
+ @string = string.to_s
@mime_type = Mime[mime_type] || mime_type if mime_type
@mime_type ||= Mime::TEXT
end
@@ -18,8 +18,12 @@ module ActionView #:nodoc:
'text template'
end
+ def to_str
+ @string
+ end
+
def render(*args)
- to_s
+ to_str
end
def formats