diff options
Diffstat (limited to 'actionpack/lib')
-rw-r--r-- | actionpack/lib/action_controller/test_case.rb | 2 | ||||
-rw-r--r-- | actionpack/lib/action_view/helpers/form_helper.rb | 1 | ||||
-rw-r--r-- | actionpack/lib/action_view/helpers/url_helper.rb | 2 | ||||
-rw-r--r-- | actionpack/lib/action_view/lookup_context.rb | 2 | ||||
-rw-r--r-- | actionpack/lib/action_view/renderer/template_renderer.rb | 4 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/resolver.rb | 105 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/text.rb | 10 |
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 |