aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib')
-rw-r--r--actionpack/lib/abstract_controller/helpers.rb2
-rw-r--r--actionpack/lib/action_controller/metal/helpers.rb9
-rw-r--r--actionpack/lib/action_controller/metal/redirecting.rb5
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb1
-rw-r--r--actionpack/lib/action_dispatch/http/filter_parameters.rb10
-rw-r--r--actionpack/lib/action_dispatch/http/parameters.rb6
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb5
-rw-r--r--actionpack/lib/action_dispatch/routing/inspector.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb19
-rw-r--r--actionpack/lib/action_view/digestor.rb21
-rw-r--r--actionpack/lib/action_view/helpers/cache_helper.rb39
-rw-r--r--actionpack/lib/action_view/helpers/form_options_helper.rb1
-rw-r--r--actionpack/lib/action_view/helpers/tags/date_select.rb4
-rw-r--r--actionpack/lib/action_view/lookup_context.rb3
-rw-r--r--actionpack/lib/action_view/renderer/partial_renderer.rb6
-rw-r--r--actionpack/lib/action_view/template/resolver.rb59
16 files changed, 100 insertions, 92 deletions
diff --git a/actionpack/lib/abstract_controller/helpers.rb b/actionpack/lib/abstract_controller/helpers.rb
index d4e73bf257..36a0dcb2de 100644
--- a/actionpack/lib/abstract_controller/helpers.rb
+++ b/actionpack/lib/abstract_controller/helpers.rb
@@ -19,7 +19,7 @@ module AbstractController
def inherited(klass)
helpers = _helpers
klass._helpers = Module.new { include helpers }
- klass.class_eval { default_helper_module! unless anonymous? }
+ klass.class_eval { default_helper_module! } unless klass.anonymous?
super
end
diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb
index d2cbbd3330..35facd13c8 100644
--- a/actionpack/lib/action_controller/metal/helpers.rb
+++ b/actionpack/lib/action_controller/metal/helpers.rb
@@ -1,4 +1,3 @@
-
module ActionController
# The \Rails framework provides a large number of helpers for working with assets, dates, forms,
# numbers and model objects, to name a few. These helpers are available to all templates
@@ -91,11 +90,11 @@ module ActionController
end
def all_helpers_from_path(path)
- helpers = []
- Array(path).each do |_path|
- extract = /^#{Regexp.quote(_path.to_s)}\/?(.*)_helper.rb$/
+ helpers = Array(path).flat_map do |_path|
+ extract = /^#{Regexp.quote(_path.to_s)}\/?(.*)_helper.rb$/
names = Dir["#{_path}/**/*_helper.rb"].map { |file| file.sub(extract, '\1') }
- helpers += names.sort
+ names.sort!
+ names
end
helpers.uniq!
helpers
diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb
index b23938e7d9..091facfd8d 100644
--- a/actionpack/lib/action_controller/metal/redirecting.rb
+++ b/actionpack/lib/action_controller/metal/redirecting.rb
@@ -74,7 +74,7 @@ module ActionController
private
def _extract_redirect_to_status(options, response_status)
- status = if options.is_a?(Hash) && options.key?(:status)
+ if options.is_a?(Hash) && options.key?(:status)
Rack::Utils.status_code(options.delete(:status))
elsif response_status.key?(:status)
Rack::Utils.status_code(response_status[:status])
@@ -94,8 +94,7 @@ module ActionController
when String
request.protocol + request.host_with_port + options
when :back
- raise RedirectBackError unless refer = request.headers["Referer"]
- refer
+ request.headers["Referer"] or raise RedirectBackError
when Proc
_compute_redirect_to_location options.call
else
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index 25e72adbe0..8faa5f8a13 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -1,5 +1,6 @@
require 'active_support/concern'
require 'active_support/core_ext/hash/indifferent_access'
+require 'active_support/core_ext/array/wrap'
require 'active_support/rescuable'
module ActionController
diff --git a/actionpack/lib/action_dispatch/http/filter_parameters.rb b/actionpack/lib/action_dispatch/http/filter_parameters.rb
index 4a7df6b657..02ab49b44e 100644
--- a/actionpack/lib/action_dispatch/http/filter_parameters.rb
+++ b/actionpack/lib/action_dispatch/http/filter_parameters.rb
@@ -1,4 +1,3 @@
-require 'mutex_m'
require 'active_support/core_ext/hash/keys'
require 'active_support/core_ext/object/duplicable'
@@ -21,8 +20,6 @@ module ActionDispatch
# end
# => reverses the value to all keys matching /secret/i
module FilterParameters
- @@parameter_filter_for = {}.extend(Mutex_m)
-
ENV_MATCH = [/RAW_POST_DATA/, "rack.request.form_vars"] # :nodoc:
NULL_PARAM_FILTER = ParameterFilter.new # :nodoc:
NULL_ENV_FILTER = ParameterFilter.new ENV_MATCH # :nodoc:
@@ -65,11 +62,7 @@ module ActionDispatch
end
def parameter_filter_for(filters)
- @@parameter_filter_for.synchronize do
- # Do we *actually* need this cache? Constructing ParameterFilters
- # doesn't seem too expensive.
- @@parameter_filter_for[filters] ||= ParameterFilter.new(filters)
- end
+ ParameterFilter.new(filters)
end
KV_RE = '[^&;=]+'
@@ -79,7 +72,6 @@ module ActionDispatch
parameter_filter.filter([[$1, $2]]).first.join("=")
end
end
-
end
end
end
diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb
index 9a7b5bc8c7..6610315da7 100644
--- a/actionpack/lib/action_dispatch/http/parameters.rb
+++ b/actionpack/lib/action_dispatch/http/parameters.rb
@@ -12,7 +12,11 @@ module ActionDispatch
# Returns both GET and POST \parameters in a single hash.
def parameters
@env["action_dispatch.request.parameters"] ||= begin
- params = request_parameters.merge(query_parameters)
+ params = begin
+ request_parameters.merge(query_parameters)
+ rescue EOFError
+ query_parameters.dup
+ end
params.merge!(path_parameters)
encode_params(params).with_indifferent_access
end
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 3de927abc8..d60c8775af 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -205,8 +205,9 @@ module ActionDispatch
# work with raw requests directly.
def raw_post
unless @env.include? 'RAW_POST_DATA'
- @env['RAW_POST_DATA'] = body.read(@env['CONTENT_LENGTH'].to_i)
- body.rewind if body.respond_to?(:rewind)
+ raw_post_body = body
+ @env['RAW_POST_DATA'] = raw_post_body.read(@env['CONTENT_LENGTH'].to_i)
+ raw_post_body.rewind if raw_post_body.respond_to?(:rewind)
end
@env['RAW_POST_DATA']
end
diff --git a/actionpack/lib/action_dispatch/routing/inspector.rb b/actionpack/lib/action_dispatch/routing/inspector.rb
index c18dc94d4f..8d7461ecc3 100644
--- a/actionpack/lib/action_dispatch/routing/inspector.rb
+++ b/actionpack/lib/action_dispatch/routing/inspector.rb
@@ -51,7 +51,7 @@ module ActionDispatch
end
def internal?
- path =~ %r{/rails/info.*|^#{Rails.application.config.assets.prefix}}
+ controller =~ %r{\Arails/(info|welcome)} || path =~ %r{\A#{Rails.application.config.assets.prefix}}
end
def engine?
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 0f95daa790..eb9d4b24f1 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -1,5 +1,6 @@
require 'journey'
require 'forwardable'
+require 'thread_safe'
require 'active_support/core_ext/object/to_query'
require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/module/remove_method'
@@ -20,7 +21,7 @@ module ActionDispatch
def initialize(options={})
@defaults = options[:defaults]
@glob_param = options.delete(:glob)
- @controllers = {}
+ @controller_class_names = ThreadSafe::Cache.new
end
def call(env)
@@ -68,13 +69,8 @@ module ActionDispatch
private
def controller_reference(controller_param)
- controller_name = "#{controller_param.camelize}Controller"
-
- unless controller = @controllers[controller_param]
- controller = @controllers[controller_param] =
- ActiveSupport::Dependencies.reference(controller_name)
- end
- controller.get(controller_name)
+ const_name = @controller_class_names[controller_param] ||= "#{controller_param.camelize}Controller"
+ ActiveSupport::Dependencies.constantize(const_name)
end
def dispatch(controller, action, env)
@@ -130,6 +126,12 @@ module ActionDispatch
end
def clear!
+ @helpers.each do |helper|
+ @module.module_eval do
+ remove_possible_method helper
+ end
+ end
+
@routes.clear
@helpers.clear
end
@@ -288,7 +290,6 @@ module ActionDispatch
def clear!
@finalized = false
- @url_helpers = nil
named_routes.clear
set.clear
formatter.clear
diff --git a/actionpack/lib/action_view/digestor.rb b/actionpack/lib/action_view/digestor.rb
index 1c6eaf36f7..8bc69b9246 100644
--- a/actionpack/lib/action_view/digestor.rb
+++ b/actionpack/lib/action_view/digestor.rb
@@ -1,4 +1,4 @@
-require 'mutex_m'
+require 'thread_safe'
module ActionView
class Digestor
@@ -21,23 +21,12 @@ module ActionView
/x
cattr_reader(:cache)
- @@cache = Hash.new.extend Mutex_m
+ @@cache = ThreadSafe::Cache.new
def self.digest(name, format, finder, options = {})
- cache.synchronize do
- unsafe_digest name, format, finder, options
- end
- end
-
- ###
- # This method is NOT thread safe. DO NOT CALL IT DIRECTLY, instead call
- # Digestor.digest
- def self.unsafe_digest(name, format, finder, options = {}) # :nodoc:
- key = "#{name}.#{format}"
-
- cache.fetch(key) do
+ @@cache["#{name}.#{format}"] ||= begin
klass = options[:partial] || name.include?("/_") ? PartialDigestor : Digestor
- cache[key] = klass.new(name, format, finder).digest
+ klass.new(name, format, finder).digest
end
end
@@ -93,7 +82,7 @@ module ActionView
def dependency_digest
dependencies.collect do |template_name|
- Digestor.unsafe_digest(template_name, format, finder, partial: true)
+ Digestor.digest(template_name, format, finder, partial: true)
end.join("-")
end
diff --git a/actionpack/lib/action_view/helpers/cache_helper.rb b/actionpack/lib/action_view/helpers/cache_helper.rb
index 8693f4f0e4..995aa10afb 100644
--- a/actionpack/lib/action_view/helpers/cache_helper.rb
+++ b/actionpack/lib/action_view/helpers/cache_helper.rb
@@ -110,15 +110,8 @@ module ActionView
# <%= some_helper_method(person) %>
#
# Now all you'll have to do is change that timestamp when the helper method changes.
- #
- # ==== Conditional caching
- #
- # You can pass :if and :unless options, to conditionally perform or skip the cache.
- #
- # <%= cache @model, if: some_condition(@model) do %>
- #
def cache(name = {}, options = nil, &block)
- if controller.perform_caching && conditions_match?(options)
+ if controller.perform_caching
safe_concat(fragment_for(cache_fragment_name(name, options), options, &block))
else
yield
@@ -127,6 +120,32 @@ module ActionView
nil
end
+ # Cache fragments of a view if +condition+ is true
+ #
+ # <%= cache_if admin?, project do %>
+ # <b>All the topics on this project</b>
+ # <%= render project.topics %>
+ # <% end %>
+ def cache_if(condition, name = {}, options = nil, &block)
+ if condition
+ cache(name, options, &block)
+ else
+ yield
+ end
+
+ nil
+ end
+
+ # Cache fragments of a view unless +condition+ is true
+ #
+ # <%= cache_unless admin?, project do %>
+ # <b>All the topics on this project</b>
+ # <%= render project.topics %>
+ # <% end %>
+ def cache_unless(condition, name = {}, options = nil, &block)
+ cache_if !condition, name, options, &block
+ end
+
# This helper returns the name of a cache key for a given fragment cache
# call. By supplying skip_digest: true to cache, the digestion of cache
# fragments can be manually bypassed. This is useful when cache fragments
@@ -144,10 +163,6 @@ module ActionView
private
- def conditions_match?(options)
- !(options && (!options.fetch(:if, true) || options.fetch(:unless, false)))
- end
-
def fragment_name_with_digest(name) #:nodoc:
if @virtual_path
[
diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb
index c0e7ee1f8d..1b5b788a35 100644
--- a/actionpack/lib/action_view/helpers/form_options_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -2,6 +2,7 @@ require 'cgi'
require 'erb'
require 'action_view/helpers/form_helper'
require 'active_support/core_ext/string/output_safety'
+require 'active_support/core_ext/array/wrap'
module ActionView
# = Action View Form Option Helpers
diff --git a/actionpack/lib/action_view/helpers/tags/date_select.rb b/actionpack/lib/action_view/helpers/tags/date_select.rb
index 5d706087b0..6c400f85cb 100644
--- a/actionpack/lib/action_view/helpers/tags/date_select.rb
+++ b/actionpack/lib/action_view/helpers/tags/date_select.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/time/calculations'
+
module ActionView
module Helpers
module Tags
@@ -58,7 +60,7 @@ module ActionView
default[key] ||= time.send(key)
end
- Time.utc_time(
+ Time.utc(
default[:year], default[:month], default[:day],
default[:hour], default[:min], default[:sec]
)
diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb
index 76f4dea7b8..4e4816d983 100644
--- a/actionpack/lib/action_view/lookup_context.rb
+++ b/actionpack/lib/action_view/lookup_context.rb
@@ -1,3 +1,4 @@
+require 'thread_safe'
require 'active_support/core_ext/module/remove_method'
module ActionView
@@ -51,7 +52,7 @@ module ActionView
alias :object_hash :hash
attr_reader :hash
- @details_keys = Hash.new
+ @details_keys = ThreadSafe::Cache.new
def self.get(details)
@details_keys[details] ||= new
diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb
index 8fb9b6ff18..37f93a13fc 100644
--- a/actionpack/lib/action_view/renderer/partial_renderer.rb
+++ b/actionpack/lib/action_view/renderer/partial_renderer.rb
@@ -1,3 +1,5 @@
+require 'thread_safe'
+
module ActionView
# = Action View Partials
#
@@ -247,7 +249,9 @@ module ActionView
# <%- end -%>
# <% end %>
class PartialRenderer < AbstractRenderer
- PREFIXED_PARTIAL_NAMES = Hash.new { |h,k| h[k] = {} }
+ PREFIXED_PARTIAL_NAMES = ThreadSafe::Cache.new do |h, k|
+ h[k] = ThreadSafe::Cache.new
+ end
def initialize(*)
super
diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb
index fc77c1485d..8b23029bbc 100644
--- a/actionpack/lib/action_view/template/resolver.rb
+++ b/actionpack/lib/action_view/template/resolver.rb
@@ -3,7 +3,7 @@ require "active_support/core_ext/class"
require "active_support/core_ext/class/attribute_accessors"
require "action_view/template"
require "thread"
-require "mutex_m"
+require "thread_safe"
module ActionView
# = Action View Resolver
@@ -35,52 +35,51 @@ module ActionView
# Threadsafe template cache
class Cache #:nodoc:
- class CacheEntry
- include Mutex_m
-
- attr_accessor :templates
+ class SmallCache < ThreadSafe::Cache
+ def initialize(options = {})
+ super(options.merge(:initial_capacity => 2))
+ end
end
+ # preallocate all the default blocks for performance/memory consumption reasons
+ PARTIAL_BLOCK = lambda {|cache, partial| cache[partial] = SmallCache.new}
+ PREFIX_BLOCK = lambda {|cache, prefix| cache[prefix] = SmallCache.new(&PARTIAL_BLOCK)}
+ NAME_BLOCK = lambda {|cache, name| cache[name] = SmallCache.new(&PREFIX_BLOCK)}
+ KEY_BLOCK = lambda {|cache, key| cache[key] = SmallCache.new(&NAME_BLOCK)}
+
+ # usually a majority of template look ups return nothing, use this canonical preallocated array to safe memory
+ NO_TEMPLATES = [].freeze
+
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
+ @data = SmallCache.new(&KEY_BLOCK)
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
+ if Resolver.caching?
+ @data[key][name][prefix][partial][locals] ||= canonical_no_templates(yield)
+ else
+ fresh_templates = yield
+ cached_templates = @data[key][name][prefix][partial][locals]
+
+ if templates_have_changed?(cached_templates, fresh_templates)
+ @data[key][name][prefix][partial][locals] = canonical_no_templates(fresh_templates)
else
- fresh_templates = yield
-
- if templates_have_changed?(cache_entry.templates, fresh_templates)
- cache_entry.templates = fresh_templates
- else
- cache_entry.templates ||= []
- end
+ cached_templates || NO_TEMPLATES
end
end
end
def clear
- @mutex.synchronize do
- @data.clear
- end
+ @data.clear
end
private
+ def canonical_no_templates(templates)
+ templates.empty? ? NO_TEMPLATES : templates
+ end
+
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