aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport/lib/active_support')
-rw-r--r--activesupport/lib/active_support/cache.rb50
-rw-r--r--activesupport/lib/active_support/cache/file_store.rb36
-rw-r--r--activesupport/lib/active_support/cache/mem_cache_store.rb67
-rw-r--r--activesupport/lib/active_support/cache/strategy/local_cache.rb13
-rw-r--r--activesupport/lib/active_support/callbacks.rb9
-rw-r--r--activesupport/lib/active_support/core_ext/class/subclasses.rb5
-rw-r--r--activesupport/lib/active_support/core_ext/enumerable.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/module.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/module/attribute_accessors.rb12
-rw-r--r--activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb141
-rw-r--r--activesupport/lib/active_support/core_ext/module/qualified_const.rb42
-rw-r--r--activesupport/lib/active_support/core_ext/numeric/conversions.rb9
-rw-r--r--activesupport/lib/active_support/core_ext/range/conversions.rb17
-rw-r--r--activesupport/lib/active_support/core_ext/string/output_safety.rb6
-rw-r--r--activesupport/lib/active_support/core_ext/time/calculations.rb1
-rw-r--r--activesupport/lib/active_support/deprecation.rb2
-rw-r--r--activesupport/lib/active_support/deprecation/method_wrappers.rb6
-rw-r--r--activesupport/lib/active_support/evented_file_update_checker.rb (renamed from activesupport/lib/active_support/file_evented_update_checker.rb)17
-rw-r--r--activesupport/lib/active_support/gem_version.rb2
-rw-r--r--activesupport/lib/active_support/hash_with_indifferent_access.rb24
-rw-r--r--activesupport/lib/active_support/inflector/methods.rb2
-rw-r--r--activesupport/lib/active_support/locale/en.yml2
-rw-r--r--activesupport/lib/active_support/logger.rb26
-rw-r--r--activesupport/lib/active_support/logger_silence.rb27
-rw-r--r--activesupport/lib/active_support/message_verifier.rb2
-rw-r--r--activesupport/lib/active_support/multibyte/unicode.rb51
-rw-r--r--activesupport/lib/active_support/notifications/fanout.rb4
-rw-r--r--activesupport/lib/active_support/notifications/instrumenter.rb10
-rw-r--r--activesupport/lib/active_support/number_helper.rb10
-rw-r--r--activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb2
-rw-r--r--activesupport/lib/active_support/ordered_hash.rb2
-rw-r--r--activesupport/lib/active_support/per_thread_registry.rb5
-rw-r--r--activesupport/lib/active_support/test_case.rb10
-rw-r--r--activesupport/lib/active_support/testing/composite_filter.rb54
-rw-r--r--activesupport/lib/active_support/values/time_zone.rb3
35 files changed, 456 insertions, 216 deletions
diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb
index d0e53eaf05..610105f41c 100644
--- a/activesupport/lib/active_support/cache.rb
+++ b/activesupport/lib/active_support/cache.rb
@@ -8,6 +8,7 @@ require 'active_support/core_ext/numeric/bytes'
require 'active_support/core_ext/numeric/time'
require 'active_support/core_ext/object/to_param'
require 'active_support/core_ext/string/inflections'
+require 'active_support/core_ext/string/strip'
module ActiveSupport
# See ActiveSupport::Cache::Store for documentation.
@@ -254,10 +255,11 @@ module ActiveSupport
# end
# end
#
- # # val_1 => "new value 1"
- # # val_2 => "original value"
- # # sleep 10 # First thread extend the life of cache by another 10 seconds
- # # cache.fetch('foo') => "new value 1"
+ # cache.fetch('foo') # => "original value"
+ # sleep 10 # First thread extended the life of cache by another 10 seconds
+ # cache.fetch('foo') # => "new value 1"
+ # val_1 # => "new value 1"
+ # val_2 # => "original value"
#
# Other options will be handled by the specific cache store implementation.
# Internally, #fetch calls #read_entry, and calls #write_entry on a cache
@@ -275,20 +277,20 @@ module ActiveSupport
def fetch(name, options = nil)
if block_given?
options = merged_options(options)
- key = namespaced_key(name, options)
+ key = normalize_key(name, options)
+ entry = nil
instrument(:read, name, options) do |payload|
cached_entry = read_entry(key, options) unless options[:force]
- payload[:super_operation] = :fetch if payload
entry = handle_expired_entry(cached_entry, key, options)
+ payload[:super_operation] = :fetch if payload
+ payload[:hit] = !!entry if payload
+ end
- if entry
- payload[:hit] = true if payload
- get_entry_value(entry, name, options)
- else
- payload[:hit] = false if payload
- save_block_result_to_cache(name, options) { |_name| yield _name }
- end
+ if entry
+ get_entry_value(entry, name, options)
+ else
+ save_block_result_to_cache(name, options) { |_name| yield _name }
end
else
read(name, options)
@@ -302,7 +304,7 @@ module ActiveSupport
# Options are passed to the underlying cache implementation.
def read(name, options = nil)
options = merged_options(options)
- key = namespaced_key(name, options)
+ key = normalize_key(name, options)
instrument(:read, name, options) do |payload|
entry = read_entry(key, options)
if entry
@@ -334,7 +336,7 @@ module ActiveSupport
instrument_multi(:read, names, options) do |payload|
results = {}
names.each do |name|
- key = namespaced_key(name, options)
+ key = normalize_key(name, options)
entry = read_entry(key, options)
if entry
if entry.expired?
@@ -386,7 +388,7 @@ module ActiveSupport
instrument(:write, name, options) do
entry = Entry.new(value, options)
- write_entry(namespaced_key(name, options), entry, options)
+ write_entry(normalize_key(name, options), entry, options)
end
end
@@ -397,7 +399,7 @@ module ActiveSupport
options = merged_options(options)
instrument(:delete, name) do
- delete_entry(namespaced_key(name, options), options)
+ delete_entry(normalize_key(name, options), options)
end
end
@@ -408,7 +410,7 @@ module ActiveSupport
options = merged_options(options)
instrument(:exist?, name) do
- entry = read_entry(namespaced_key(name, options), options)
+ entry = read_entry(normalize_key(name, options), options)
(entry && !entry.expired?) || false
end
end
@@ -529,7 +531,7 @@ module ActiveSupport
# Prefix a key with the namespace. Namespace and key will be delimited
# with a colon.
- def namespaced_key(key, options)
+ def normalize_key(key, options)
key = expanded_key(key)
namespace = options[:namespace] if options
prefix = namespace.is_a?(Proc) ? namespace.call : namespace
@@ -537,8 +539,16 @@ module ActiveSupport
key
end
+ def namespaced_key(*args)
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
+ `namespaced_key` is deprecated and will be removed from Rails 5.1.
+ Please use `normalize_key` which will return a fully resolved key.
+ MESSAGE
+ normalize_key(*args)
+ end
+
def instrument(operation, key, options = nil)
- log { "Cache #{operation}: #{namespaced_key(key, options)}#{options.blank? ? "" : " (#{options.inspect})"}" }
+ log { "Cache #{operation}: #{normalize_key(key, options)}#{options.blank? ? "" : " (#{options.inspect})"}" }
payload = { :key => key }
payload.merge!(options) if options.is_a?(Hash)
diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb
index 705ea60cc8..99c55b1aa4 100644
--- a/activesupport/lib/active_support/cache/file_store.rb
+++ b/activesupport/lib/active_support/cache/file_store.rb
@@ -61,7 +61,7 @@ module ActiveSupport
matcher = key_matcher(matcher, options)
search_dir(cache_path) do |path|
key = file_path_key(path)
- delete_entry(key, options) if key.match(matcher)
+ delete_entry(path, options) if key.match(matcher)
end
end
end
@@ -69,9 +69,8 @@ module ActiveSupport
protected
def read_entry(key, options)
- file_name = key_file_path(key)
- if File.exist?(file_name)
- File.open(file_name) { |f| Marshal.load(f) }
+ if File.exist?(key)
+ File.open(key) { |f| Marshal.load(f) }
end
rescue => e
logger.error("FileStoreError (#{e}): #{e.message}") if logger
@@ -79,23 +78,21 @@ module ActiveSupport
end
def write_entry(key, entry, options)
- file_name = key_file_path(key)
- return false if options[:unless_exist] && File.exist?(file_name)
- ensure_cache_path(File.dirname(file_name))
- File.atomic_write(file_name, cache_path) {|f| Marshal.dump(entry, f)}
+ return false if options[:unless_exist] && File.exist?(key)
+ ensure_cache_path(File.dirname(key))
+ File.atomic_write(key, cache_path) {|f| Marshal.dump(entry, f)}
true
end
def delete_entry(key, options)
- file_name = key_file_path(key)
- if File.exist?(file_name)
+ if File.exist?(key)
begin
- File.delete(file_name)
- delete_empty_directories(File.dirname(file_name))
+ File.delete(key)
+ delete_empty_directories(File.dirname(key))
true
rescue => e
# Just in case the error was caused by another process deleting the file first.
- raise e if File.exist?(file_name)
+ raise e if File.exist?(key)
false
end
end
@@ -119,7 +116,8 @@ module ActiveSupport
end
# Translate a key into a file path.
- def key_file_path(key)
+ def normalize_key(key, options)
+ key = super
fname = URI.encode_www_form_component(key)
if fname.size > FILEPATH_MAX_SIZE
@@ -140,6 +138,14 @@ module ActiveSupport
File.join(cache_path, DIR_FORMATTER % dir_1, DIR_FORMATTER % dir_2, *fname_paths)
end
+ def key_file_path(key)
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
+ `key_file_path` is deprecated and will be removed from Rails 5.1.
+ Please use `normalize_key` which will return a fully resolved key or nothing.
+ MESSAGE
+ key
+ end
+
# Translate a file path into a key.
def file_path_key(path)
fname = path[cache_path.to_s.size..-1].split(File::SEPARATOR, 4).last
@@ -176,7 +182,7 @@ module ActiveSupport
# Modifies the amount of an already existing integer value that is stored in the cache.
# If the key is not found nothing is done.
def modify_value(name, amount, options)
- file_name = key_file_path(namespaced_key(name, options))
+ file_name = normalize_key(name, options)
lock_file(file_name) do
options = merged_options(options)
diff --git a/activesupport/lib/active_support/cache/mem_cache_store.rb b/activesupport/lib/active_support/cache/mem_cache_store.rb
index e2f536ef1e..174913365a 100644
--- a/activesupport/lib/active_support/cache/mem_cache_store.rb
+++ b/activesupport/lib/active_support/cache/mem_cache_store.rb
@@ -36,13 +36,13 @@ module ActiveSupport
end
def write_entry(key, entry, options) # :nodoc:
- retval = super
- if options[:raw] && local_cache && retval
+ if options[:raw] && local_cache
raw_entry = Entry.new(entry.value.to_s)
raw_entry.expires_at = entry.expires_at
- local_cache.write_entry(key, raw_entry, options)
+ super(key, raw_entry, options)
+ else
+ super
end
- retval
end
end
@@ -97,7 +97,7 @@ module ActiveSupport
options = merged_options(options)
instrument_multi(:read, names, options) do
- keys_to_names = Hash[names.map{|name| [escape_key(namespaced_key(name, options)), name]}]
+ keys_to_names = Hash[names.map{|name| [normalize_key(name, options), name]}]
raw_values = @data.get_multi(keys_to_names.keys, :raw => true)
values = {}
raw_values.each do |key, value|
@@ -115,11 +115,10 @@ module ActiveSupport
def increment(name, amount = 1, options = nil) # :nodoc:
options = merged_options(options)
instrument(:increment, name, :amount => amount) do
- @data.incr(escape_key(namespaced_key(name, options)), amount)
+ rescue_error_with nil do
+ @data.incr(normalize_key(name, options), amount)
+ end
end
- rescue Dalli::DalliError => e
- logger.error("DalliError (#{e}): #{e.message}") if logger
- nil
end
# Decrement a cached value. This method uses the memcached decr atomic
@@ -129,20 +128,16 @@ module ActiveSupport
def decrement(name, amount = 1, options = nil) # :nodoc:
options = merged_options(options)
instrument(:decrement, name, :amount => amount) do
- @data.decr(escape_key(namespaced_key(name, options)), amount)
+ rescue_error_with nil do
+ @data.decr(normalize_key(name, options), amount)
+ end
end
- rescue Dalli::DalliError => e
- logger.error("DalliError (#{e}): #{e.message}") if logger
- nil
end
# Clear the entire cache on all memcached servers. This method should
# be used with care when shared cache is being used.
def clear(options = nil)
- @data.flush_all
- rescue Dalli::DalliError => e
- logger.error("DalliError (#{e}): #{e.message}") if logger
- nil
+ rescue_error_with(nil) { @data.flush_all }
end
# Get the statistics from the memcached servers.
@@ -153,10 +148,7 @@ module ActiveSupport
protected
# Read an entry from the cache.
def read_entry(key, options) # :nodoc:
- deserialize_entry(@data.get(escape_key(key), options))
- rescue Dalli::DalliError => e
- logger.error("DalliError (#{e}): #{e.message}") if logger
- nil
+ rescue_error_with(nil) { deserialize_entry(@data.get(key, options)) }
end
# Write an entry to the cache.
@@ -168,18 +160,14 @@ module ActiveSupport
# Set the memcache expire a few minutes in the future to support race condition ttls on read
expires_in += 5.minutes
end
- @data.send(method, escape_key(key), value, expires_in, options)
- rescue Dalli::DalliError => e
- logger.error("DalliError (#{e}): #{e.message}") if logger
- false
+ rescue_error_with false do
+ @data.send(method, key, value, expires_in, options)
+ end
end
# Delete an entry from the cache.
def delete_entry(key, options) # :nodoc:
- @data.delete(escape_key(key))
- rescue Dalli::DalliError => e
- logger.error("DalliError (#{e}): #{e.message}") if logger
- false
+ rescue_error_with(false) { @data.delete(key) }
end
private
@@ -187,22 +175,35 @@ module ActiveSupport
# Memcache keys are binaries. So we need to force their encoding to binary
# before applying the regular expression to ensure we are escaping all
# characters properly.
- def escape_key(key)
- key = key.to_s.dup
+ def normalize_key(key, options)
+ key = super.dup
key = key.force_encoding(Encoding::ASCII_8BIT)
key = key.gsub(ESCAPE_KEY_CHARS){ |match| "%#{match.getbyte(0).to_s(16).upcase}" }
key = "#{key[0, 213]}:md5:#{Digest::MD5.hexdigest(key)}" if key.size > 250
key
end
+ def escape_key(key)
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
+ `escape_key` is deprecated and will be removed from Rails 5.1.
+ Please use `normalize_key` which will return a fully resolved key or nothing.
+ MESSAGE
+ key
+ end
+
def deserialize_entry(raw_value)
if raw_value
entry = Marshal.load(raw_value) rescue raw_value
entry.is_a?(Entry) ? entry : Entry.new(entry)
- else
- nil
end
end
+
+ def rescue_error_with(fallback)
+ yield
+ rescue Dalli::DalliError => e
+ logger.error("DalliError (#{e}): #{e.message}") if logger
+ fallback
+ end
end
end
end
diff --git a/activesupport/lib/active_support/cache/strategy/local_cache.rb b/activesupport/lib/active_support/cache/strategy/local_cache.rb
index fa007aad56..df38dbcf11 100644
--- a/activesupport/lib/active_support/cache/strategy/local_cache.rb
+++ b/activesupport/lib/active_support/cache/strategy/local_cache.rb
@@ -93,14 +93,14 @@ module ActiveSupport
def increment(name, amount = 1, options = nil) # :nodoc:
return super unless local_cache
value = bypass_local_cache{super}
- set_cache_value(value, name, amount, options)
+ write_cache_value(name, value, options)
value
end
def decrement(name, amount = 1, options = nil) # :nodoc:
return super unless local_cache
value = bypass_local_cache{super}
- set_cache_value(value, name, amount, options)
+ write_cache_value(name, value, options)
value
end
@@ -124,6 +124,15 @@ module ActiveSupport
end
def set_cache_value(value, name, amount, options) # :nodoc:
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
+ `set_cache_value` is deprecated and will be removed from Rails 5.1.
+ Please use `write_cache_value`
+ MESSAGE
+ write_cache_value name, value, options
+ end
+
+ def write_cache_value(name, value, options) # :nodoc:
+ name = normalize_key(name, options)
cache = local_cache
cache.mute do
if value
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index d43fde03a9..bf560ec1fa 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -295,6 +295,13 @@ module ActiveSupport
class Callback #:nodoc:#
def self.build(chain, filter, kind, options)
+ if filter.is_a?(String)
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ Passing string to define callback is deprecated and will be removed
+ in Rails 5.1 without replacement.
+ MSG
+ end
+
new chain.name, filter, kind, options, chain.config
end
@@ -575,7 +582,7 @@ module ActiveSupport
# set_callback :save, :before_meth
#
# The callback can be specified as a symbol naming an instance method; as a
- # proc, lambda, or block; as a string to be instance evaluated; or as an
+ # proc, lambda, or block; as a string to be instance evaluated(deprecated); or as an
# object that responds to a certain method determined by the <tt>:scope</tt>
# argument to +define_callbacks+.
#
diff --git a/activesupport/lib/active_support/core_ext/class/subclasses.rb b/activesupport/lib/active_support/core_ext/class/subclasses.rb
index 3c4bfc5f1e..b0f9a8be34 100644
--- a/activesupport/lib/active_support/core_ext/class/subclasses.rb
+++ b/activesupport/lib/active_support/core_ext/class/subclasses.rb
@@ -3,7 +3,8 @@ require 'active_support/core_ext/module/reachable'
class Class
begin
- ObjectSpace.each_object(Class.new) {}
+ # Test if this Ruby supports each_object against singleton_class
+ ObjectSpace.each_object(Numeric.singleton_class) {}
def descendants # :nodoc:
descendants = []
@@ -12,7 +13,7 @@ class Class
end
descendants
end
- rescue StandardError # JRuby
+ rescue StandardError # JRuby 9.0.4.0 and earlier
def descendants # :nodoc:
descendants = []
ObjectSpace.each_object(Class) do |k|
diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb
index fc7531d088..8a74ad4d66 100644
--- a/activesupport/lib/active_support/core_ext/enumerable.rb
+++ b/activesupport/lib/active_support/core_ext/enumerable.rb
@@ -21,7 +21,7 @@ module Enumerable
if block_given?
map(&block).sum(identity)
else
- inject { |sum, element| sum + element } || identity
+ inject(:+) || identity
end
end
diff --git a/activesupport/lib/active_support/core_ext/module.rb b/activesupport/lib/active_support/core_ext/module.rb
index b4efff8b24..ef038331c2 100644
--- a/activesupport/lib/active_support/core_ext/module.rb
+++ b/activesupport/lib/active_support/core_ext/module.rb
@@ -3,6 +3,7 @@ require 'active_support/core_ext/module/introspection'
require 'active_support/core_ext/module/anonymous'
require 'active_support/core_ext/module/reachable'
require 'active_support/core_ext/module/attribute_accessors'
+require 'active_support/core_ext/module/attribute_accessors_per_thread'
require 'active_support/core_ext/module/attr_internal'
require 'active_support/core_ext/module/concerning'
require 'active_support/core_ext/module/delegation'
diff --git a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
index 124f90dc0f..76825862d7 100644
--- a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
+++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
@@ -49,7 +49,7 @@ class Module
# include HairColors
# end
#
- # Person.hair_colors # => [:brown, :black, :blonde, :red]
+ # Person.new.hair_colors # => [:brown, :black, :blonde, :red]
def mattr_reader(*syms)
options = syms.extract_options!
syms.each do |sym|
@@ -105,7 +105,7 @@ class Module
#
# Also, you can pass a block to set up the attribute with a default value.
#
- # class HairColors
+ # module HairColors
# mattr_writer :hair_colors do
# [:brown, :black, :blonde, :red]
# end
@@ -150,8 +150,8 @@ class Module
# include HairColors
# end
#
- # Person.hair_colors = [:brown, :black, :blonde, :red]
- # Person.hair_colors # => [:brown, :black, :blonde, :red]
+ # HairColors.hair_colors = [:brown, :black, :blonde, :red]
+ # HairColors.hair_colors # => [:brown, :black, :blonde, :red]
# Person.new.hair_colors # => [:brown, :black, :blonde, :red]
#
# If a subclass changes the value then that would also change the value for
@@ -161,8 +161,8 @@ class Module
# class Male < Person
# end
#
- # Male.hair_colors << :blue
- # Person.hair_colors # => [:brown, :black, :blonde, :red, :blue]
+ # Male.new.hair_colors << :blue
+ # Person.new.hair_colors # => [:brown, :black, :blonde, :red, :blue]
#
# To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
# To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
diff --git a/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb b/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb
new file mode 100644
index 0000000000..8a7e6776da
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb
@@ -0,0 +1,141 @@
+require 'active_support/core_ext/array/extract_options'
+
+# Extends the module object with class/module and instance accessors for
+# class/module attributes, just like the native attr* accessors for instance
+# attributes, but does so on a per-thread basis.
+#
+# So the values are scoped within the Thread.current space under the class name
+# of the module.
+class Module
+ # Defines a per-thread class attribute and creates class and instance reader methods.
+ # The underlying per-thread class variable is set to +nil+, if it is not previously defined.
+ #
+ # module Current
+ # thread_mattr_reader :user
+ # end
+ #
+ # Current.user # => nil
+ # Thread.current[:attr_Current_user] = "DHH"
+ # Current.user # => "DHH"
+ #
+ # The attribute name must be a valid method name in Ruby.
+ #
+ # module Foo
+ # thread_mattr_reader :"1_Badname"
+ # end
+ # # => NameError: invalid attribute name: 1_Badname
+ #
+ # If you want to opt out the creation on the instance reader method, pass
+ # <tt>instance_reader: false</tt> or <tt>instance_accessor: false</tt>.
+ #
+ # class Current
+ # thread_mattr_reader :user, instance_reader: false
+ # end
+ #
+ # Current.new.user # => NoMethodError
+ def thread_mattr_reader(*syms)
+ options = syms.extract_options!
+
+ syms.each do |sym|
+ raise NameError.new("invalid attribute name: #{sym}") unless sym =~ /^[_A-Za-z]\w*$/
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
+ def self.#{sym}
+ Thread.current[:"attr_#{name}_#{sym}"]
+ end
+ EOS
+
+ unless options[:instance_reader] == false || options[:instance_accessor] == false
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
+ def #{sym}
+ Thread.current[:"attr_#{self.class.name}_#{sym}"]
+ end
+ EOS
+ end
+ end
+ end
+ alias :thread_cattr_reader :thread_mattr_reader
+
+ # Defines a per-thread class attribute and creates a class and instance writer methods to
+ # allow assignment to the attribute.
+ #
+ # module Current
+ # thread_mattr_writer :user
+ # end
+ #
+ # Current.user = "DHH"
+ # Thread.current[:attr_Current_user] # => "DHH"
+ #
+ # If you want to opt out the instance writer method, pass
+ # <tt>instance_writer: false</tt> or <tt>instance_accessor: false</tt>.
+ #
+ # class Current
+ # thread_mattr_writer :user, instance_writer: false
+ # end
+ #
+ # Current.new.user = "DHH" # => NoMethodError
+ def thread_mattr_writer(*syms)
+ options = syms.extract_options!
+ syms.each do |sym|
+ raise NameError.new("invalid attribute name: #{sym}") unless sym =~ /^[_A-Za-z]\w*$/
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
+ def self.#{sym}=(obj)
+ Thread.current[:"attr_#{name}_#{sym}"] = obj
+ end
+ EOS
+
+ unless options[:instance_writer] == false || options[:instance_accessor] == false
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
+ def #{sym}=(obj)
+ Thread.current[:"attr_#{self.class.name}_#{sym}"] = obj
+ end
+ EOS
+ end
+ end
+ end
+ alias :thread_cattr_writer :thread_mattr_writer
+
+ # Defines both class and instance accessors for class attributes.
+ #
+ # class Account
+ # thread_mattr_accessor :user
+ # end
+ #
+ # Account.user = "DHH"
+ # Account.user # => "DHH"
+ # Account.new.user # => "DHH"
+ #
+ # If a subclass changes the value, the parent class' value is not changed.
+ # Similarly, if the parent class changes the value, the value of subclasses
+ # is not changed.
+ #
+ # class Customer < Account
+ # end
+ #
+ # Customer.user = "Rafael"
+ # Customer.user # => "Rafael"
+ # Account.user # => "DHH"
+ #
+ # To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
+ # To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
+ #
+ # class Current
+ # thread_mattr_accessor :user, instance_writer: false, instance_reader: false
+ # end
+ #
+ # Current.new.user = "DHH" # => NoMethodError
+ # Current.new.user # => NoMethodError
+ #
+ # Or pass <tt>instance_accessor: false</tt>, to opt out both instance methods.
+ #
+ # class Current
+ # mattr_accessor :user, instance_accessor: false
+ # end
+ #
+ # Current.new.user = "DHH" # => NoMethodError
+ # Current.new.user # => NoMethodError
+ def thread_mattr_accessor(*syms, &blk)
+ thread_mattr_reader(*syms, &blk)
+ thread_mattr_writer(*syms, &blk)
+ end
+ alias :thread_cattr_accessor :thread_mattr_accessor
+end
diff --git a/activesupport/lib/active_support/core_ext/module/qualified_const.rb b/activesupport/lib/active_support/core_ext/module/qualified_const.rb
index 65525013db..3ea39d4267 100644
--- a/activesupport/lib/active_support/core_ext/module/qualified_const.rb
+++ b/activesupport/lib/active_support/core_ext/module/qualified_const.rb
@@ -3,13 +3,16 @@ require 'active_support/core_ext/string/inflections'
#--
# Allows code reuse in the methods below without polluting Module.
#++
-module QualifiedConstUtils
- def self.raise_if_absolute(path)
- raise NameError.new("wrong constant name #$&") if path =~ /\A::[^:]+/
- end
- def self.names(path)
- path.split('::')
+module ActiveSupport
+ module QualifiedConstUtils
+ def self.raise_if_absolute(path)
+ raise NameError.new("wrong constant name #$&") if path =~ /\A::[^:]+/
+ end
+
+ def self.names(path)
+ path.split('::')
+ end
end
end
@@ -24,9 +27,14 @@ end
#++
class Module
def qualified_const_defined?(path, search_parents=true)
- QualifiedConstUtils.raise_if_absolute(path)
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
+ Module#qualified_const_defined? is deprecated in favour of the builtin
+ Module#const_defined? and will be removed in Rails 5.1.
+ MESSAGE
- QualifiedConstUtils.names(path).inject(self) do |mod, name|
+ ActiveSupport::QualifiedConstUtils.raise_if_absolute(path)
+
+ ActiveSupport::QualifiedConstUtils.names(path).inject(self) do |mod, name|
return unless mod.const_defined?(name, search_parents)
mod.const_get(name)
end
@@ -34,19 +42,29 @@ class Module
end
def qualified_const_get(path)
- QualifiedConstUtils.raise_if_absolute(path)
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
+ Module#qualified_const_get is deprecated in favour of the builtin
+ Module#const_get and will be removed in Rails 5.1.
+ MESSAGE
+
+ ActiveSupport::QualifiedConstUtils.raise_if_absolute(path)
- QualifiedConstUtils.names(path).inject(self) do |mod, name|
+ ActiveSupport::QualifiedConstUtils.names(path).inject(self) do |mod, name|
mod.const_get(name)
end
end
def qualified_const_set(path, value)
- QualifiedConstUtils.raise_if_absolute(path)
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
+ Module#qualified_const_set is deprecated in favour of the builtin
+ Module#const_set and will be removed in Rails 5.1.
+ MESSAGE
+
+ ActiveSupport::QualifiedConstUtils.raise_if_absolute(path)
const_name = path.demodulize
mod_name = path.deconstantize
- mod = mod_name.empty? ? self : qualified_const_get(mod_name)
+ mod = mod_name.empty? ? self : const_get(mod_name)
mod.const_set(const_name, value)
end
end
diff --git a/activesupport/lib/active_support/core_ext/numeric/conversions.rb b/activesupport/lib/active_support/core_ext/numeric/conversions.rb
index 9a3651f29a..9d832897ed 100644
--- a/activesupport/lib/active_support/core_ext/numeric/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/numeric/conversions.rb
@@ -1,5 +1,6 @@
require 'active_support/core_ext/big_decimal/conversions'
require 'active_support/number_helper'
+require 'active_support/core_ext/module/deprecation'
module ActiveSupport::NumericWithFormat
@@ -75,6 +76,8 @@ module ActiveSupport::NumericWithFormat
# 1234567.to_s(:human_size) # => 1.18 MB
# 1234567890.to_s(:human_size) # => 1.15 GB
# 1234567890123.to_s(:human_size) # => 1.12 TB
+ # 1234567890123456.to_s(:human_size) # => 1.1 PB
+ # 1234567890123456789.to_s(:human_size) # => 1.07 EB
# 1234567.to_s(:human_size, precision: 2) # => 1.2 MB
# 483989.to_s(:human_size, precision: 2) # => 470 KB
# 1234567.to_s(:human_size, precision: 2, separator: ',') # => 1,2 MB
@@ -117,7 +120,11 @@ module ActiveSupport::NumericWithFormat
when :human_size
return ActiveSupport::NumberHelper.number_to_human_size(self, options)
else
- super
+ if is_a?(Float) || format.is_a?(Symbol)
+ super()
+ else
+ super
+ end
end
end
diff --git a/activesupport/lib/active_support/core_ext/range/conversions.rb b/activesupport/lib/active_support/core_ext/range/conversions.rb
index 83eced50bf..965436c23a 100644
--- a/activesupport/lib/active_support/core_ext/range/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/range/conversions.rb
@@ -1,34 +1,31 @@
-class Range
+module ActiveSupport::RangeWithFormat
RANGE_FORMATS = {
:db => Proc.new { |start, stop| "BETWEEN '#{start.to_s(:db)}' AND '#{stop.to_s(:db)}'" }
}
# Convert range to a formatted string. See RANGE_FORMATS for predefined formats.
#
- # This method is aliased to <tt>to_s</tt>.
- #
# range = (1..100) # => 1..100
#
- # range.to_formatted_s # => "1..100"
# range.to_s # => "1..100"
- #
- # range.to_formatted_s(:db) # => "BETWEEN '1' AND '100'"
# range.to_s(:db) # => "BETWEEN '1' AND '100'"
#
- # == Adding your own range formats to to_formatted_s
+ # == Adding your own range formats to to_s
# You can add your own formats to the Range::RANGE_FORMATS hash.
# Use the format name as the hash key and a Proc instance.
#
# # config/initializers/range_formats.rb
# Range::RANGE_FORMATS[:short] = ->(start, stop) { "Between #{start.to_s(:db)} and #{stop.to_s(:db)}" }
- def to_formatted_s(format = :default)
+ def to_s(format = :default)
if formatter = RANGE_FORMATS[format]
formatter.call(first, last)
else
- to_default_s
+ super()
end
end
alias_method :to_default_s, :to_s
- alias_method :to_s, :to_formatted_s
+ alias_method :to_formatted_s, :to_s
end
+
+Range.prepend(ActiveSupport::RangeWithFormat)
diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb
index 510fa48189..04ed8e7cd8 100644
--- a/activesupport/lib/active_support/core_ext/string/output_safety.rb
+++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb
@@ -5,7 +5,6 @@ class ERB
module Util
HTML_ESCAPE = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;', "'" => '&#39;' }
JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003e', '<' => '\u003c', "\u2028" => '\u2028', "\u2029" => '\u2029' }
- HTML_ESCAPE_REGEXP = /[&"'><]/
HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/
JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/u
@@ -37,7 +36,7 @@ class ERB
if s.html_safe?
s
else
- ActiveSupport::Multibyte::Unicode.tidy_bytes(s).gsub(HTML_ESCAPE_REGEXP, HTML_ESCAPE)
+ CGI.escapeHTML(ActiveSupport::Multibyte::Unicode.tidy_bytes(s))
end
end
module_function :unwrapped_html_escape
@@ -243,8 +242,7 @@ module ActiveSupport #:nodoc:
private
def html_escape_interpolated_argument(arg)
- (!html_safe? || arg.html_safe?) ? arg :
- arg.to_s.gsub(ERB::Util::HTML_ESCAPE_REGEXP, ERB::Util::HTML_ESCAPE)
+ (!html_safe? || arg.html_safe?) ? arg : CGI.escapeHTML(arg.to_s)
end
end
end
diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb
index 675db8a36b..768c9a1b2c 100644
--- a/activesupport/lib/active_support/core_ext/time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/time/calculations.rb
@@ -162,7 +162,6 @@ class Time
# Returns a new Time representing the start of the day (0:00)
def beginning_of_day
- #(self - seconds_since_midnight).change(usec: 0)
change(:hour => 0)
end
alias :midnight :beginning_of_day
diff --git a/activesupport/lib/active_support/deprecation.rb b/activesupport/lib/active_support/deprecation.rb
index 46e9996d59..24545d766c 100644
--- a/activesupport/lib/active_support/deprecation.rb
+++ b/activesupport/lib/active_support/deprecation.rb
@@ -32,7 +32,7 @@ module ActiveSupport
# and the second is a library name
#
# ActiveSupport::Deprecation.new('2.0', 'MyLibrary')
- def initialize(deprecation_horizon = '5.0', gem_name = 'Rails')
+ def initialize(deprecation_horizon = '5.1', gem_name = 'Rails')
self.gem_name = gem_name
self.deprecation_horizon = deprecation_horizon
# By default, warnings are not silenced and debugging is off.
diff --git a/activesupport/lib/active_support/deprecation/method_wrappers.rb b/activesupport/lib/active_support/deprecation/method_wrappers.rb
index 32fe8025fe..f5ea6669ce 100644
--- a/activesupport/lib/active_support/deprecation/method_wrappers.rb
+++ b/activesupport/lib/active_support/deprecation/method_wrappers.rb
@@ -21,15 +21,15 @@ module ActiveSupport
# # => [:aaa, :bbb, :ccc]
#
# Fred.aaa
- # # DEPRECATION WARNING: aaa is deprecated and will be removed from Rails 5.0. (called from irb_binding at (irb):10)
+ # # DEPRECATION WARNING: aaa is deprecated and will be removed from Rails 5.1. (called from irb_binding at (irb):10)
# # => nil
#
# Fred.bbb
- # # DEPRECATION WARNING: bbb is deprecated and will be removed from Rails 5.0 (use zzz instead). (called from irb_binding at (irb):11)
+ # # DEPRECATION WARNING: bbb is deprecated and will be removed from Rails 5.1 (use zzz instead). (called from irb_binding at (irb):11)
# # => nil
#
# Fred.ccc
- # # DEPRECATION WARNING: ccc is deprecated and will be removed from Rails 5.0 (use Bar#ccc instead). (called from irb_binding at (irb):12)
+ # # DEPRECATION WARNING: ccc is deprecated and will be removed from Rails 5.1 (use Bar#ccc instead). (called from irb_binding at (irb):12)
# # => nil
#
# Passing in a custom deprecator:
diff --git a/activesupport/lib/active_support/file_evented_update_checker.rb b/activesupport/lib/active_support/evented_file_update_checker.rb
index 638458c6ce..315be85fb3 100644
--- a/activesupport/lib/active_support/file_evented_update_checker.rb
+++ b/activesupport/lib/active_support/evented_file_update_checker.rb
@@ -1,9 +1,9 @@
-require 'listen'
require 'set'
require 'pathname'
+require 'concurrent/atomic/atomic_boolean'
module ActiveSupport
- class FileEventedUpdateChecker #:nodoc: all
+ class EventedFileUpdateChecker #:nodoc: all
def initialize(files, dirs = {}, &block)
@ph = PathHelper.new
@files = files.map { |f| @ph.xpath(f) }.to_set
@@ -14,22 +14,25 @@ module ActiveSupport
end
@block = block
- @updated = false
+ @updated = Concurrent::AtomicBoolean.new(false)
@lcsp = @ph.longest_common_subpath(@dirs.keys)
if (dtw = directories_to_watch).any?
+ # Loading listen triggers warnings. These are originated by a legit
+ # usage of attr_* macros for private attributes, but adds a lot of noise
+ # to our test suite. Thus, we lazy load it and disable warnings locally.
+ silence_warnings { require 'listen' }
Listen.to(*dtw, &method(:changed)).start
end
end
def updated?
- @updated
+ @updated.true?
end
def execute
+ @updated.make_false
@block.call
- ensure
- @updated = false
end
def execute_if_updated
@@ -43,7 +46,7 @@ module ActiveSupport
def changed(modified, added, removed)
unless updated?
- @updated = (modified + added + removed).any? { |f| watching?(f) }
+ @updated.make_true if (modified + added + removed).any? { |f| watching?(f) }
end
end
diff --git a/activesupport/lib/active_support/gem_version.rb b/activesupport/lib/active_support/gem_version.rb
index ece68bbcb6..7790a9b2c0 100644
--- a/activesupport/lib/active_support/gem_version.rb
+++ b/activesupport/lib/active_support/gem_version.rb
@@ -8,7 +8,7 @@ module ActiveSupport
MAJOR = 5
MINOR = 0
TINY = 0
- PRE = "alpha"
+ PRE = "beta1"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb
index 4ff35a45a1..b878f31e75 100644
--- a/activesupport/lib/active_support/hash_with_indifferent_access.rb
+++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb
@@ -68,12 +68,10 @@ module ActiveSupport
end
end
- def default(key = nil)
- if key.is_a?(Symbol) && include?(key = key.to_s)
- self[key]
- else
- super
- end
+ def default(*args)
+ key = args.first
+ args[0] = key.to_s if key.is_a?(Symbol)
+ super(*args)
end
def self.new_from_hash_copying_default(hash)
@@ -159,6 +157,20 @@ module ActiveSupport
alias_method :has_key?, :key?
alias_method :member?, :key?
+
+ # Same as <tt>Hash#[]</tt> where the key passed as argument can be
+ # either a string or a symbol:
+ #
+ # counters = ActiveSupport::HashWithIndifferentAccess.new
+ # counters[:foo] = 1
+ #
+ # counters['foo'] # => 1
+ # counters[:foo] # => 1
+ # counters[:zoo] # => nil
+ def [](key)
+ super(convert_key(key))
+ end
+
# Same as <tt>Hash#fetch</tt> where the key passed as argument can be
# either a string or a symbol:
#
diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb
index 595b0339cc..f741c0bfb8 100644
--- a/activesupport/lib/active_support/inflector/methods.rb
+++ b/activesupport/lib/active_support/inflector/methods.rb
@@ -173,7 +173,7 @@ module ActiveSupport
#
# Singular names are not handled correctly:
#
- # classify('calculus') # => "Calculu"
+ # classify('calculus') # => "Calculus"
def classify(table_name)
# strip out any leading schema name
camelize(singularize(table_name.to_s.sub(/.*\./, ''.freeze)))
diff --git a/activesupport/lib/active_support/locale/en.yml b/activesupport/lib/active_support/locale/en.yml
index a4563ace8f..c64b7598ee 100644
--- a/activesupport/lib/active_support/locale/en.yml
+++ b/activesupport/lib/active_support/locale/en.yml
@@ -106,6 +106,8 @@ en:
mb: "MB"
gb: "GB"
tb: "TB"
+ pb: "PB"
+ eb: "EB"
# Used in NumberHelper.number_to_human()
decimal_units:
format: "%n %u"
diff --git a/activesupport/lib/active_support/logger.rb b/activesupport/lib/active_support/logger.rb
index 33fccdcf95..7626b28108 100644
--- a/activesupport/lib/active_support/logger.rb
+++ b/activesupport/lib/active_support/logger.rb
@@ -1,4 +1,3 @@
-require 'active_support/core_ext/module/attribute_accessors'
require 'active_support/logger_silence'
require 'logger'
@@ -6,6 +5,17 @@ module ActiveSupport
class Logger < ::Logger
include LoggerSilence
+ # Returns true if the logger destination matches one of the sources
+ #
+ # logger = Logger.new(STDOUT)
+ # ActiveSupport::Logger.logger_outputs_to?(logger, STDOUT)
+ # # => true
+ def self.logger_outputs_to?(logger, *sources)
+ logdev = logger.instance_variable_get("@logdev")
+ logger_source = logdev.dev if logdev.respond_to?(:dev)
+ sources.any? { |source| source == logger_source }
+ end
+
# Broadcasts logs to multiple loggers.
def self.broadcast(logger) # :nodoc:
Module.new do
@@ -44,6 +54,20 @@ module ActiveSupport
def initialize(*args)
super
@formatter = SimpleFormatter.new
+ after_initialize if respond_to? :after_initialize
+ end
+
+ def add(severity, message = nil, progname = nil, &block)
+ return true if @logdev.nil? || (severity || UNKNOWN) < level
+ super
+ end
+
+ Logger::Severity.constants.each do |severity|
+ class_eval(<<-EOT, __FILE__, __LINE__ + 1)
+ def #{severity.downcase}? # def debug?
+ Logger::#{severity} >= level # DEBUG >= level
+ end # end
+ EOT
end
# Simple formatter which only displays the message.
diff --git a/activesupport/lib/active_support/logger_silence.rb b/activesupport/lib/active_support/logger_silence.rb
index a8efdef944..125d81d973 100644
--- a/activesupport/lib/active_support/logger_silence.rb
+++ b/activesupport/lib/active_support/logger_silence.rb
@@ -1,21 +1,42 @@
require 'active_support/concern'
+require 'active_support/core_ext/module/attribute_accessors'
+require 'concurrent'
module LoggerSilence
extend ActiveSupport::Concern
-
+
included do
cattr_accessor :silencer
+ attr_reader :local_levels
self.silencer = true
end
+ def after_initialize
+ @local_levels = Concurrent::Map.new(:initial_capacity => 2)
+ end
+
+ def local_log_id
+ Thread.current.__id__
+ end
+
+ def level
+ local_levels[local_log_id] || super
+ end
+
# Silences the logger for the duration of the block.
def silence(temporary_level = Logger::ERROR)
if silencer
begin
- old_logger_level, self.level = level, temporary_level
+ old_local_level = local_levels[local_log_id]
+ local_levels[local_log_id] = temporary_level
+
yield self
ensure
- self.level = old_logger_level
+ if old_local_level
+ local_levels[local_log_id] = old_local_level
+ else
+ local_levels.delete(local_log_id)
+ end
end
else
yield self
diff --git a/activesupport/lib/active_support/message_verifier.rb b/activesupport/lib/active_support/message_verifier.rb
index 64c5232cf4..854029bf83 100644
--- a/activesupport/lib/active_support/message_verifier.rb
+++ b/activesupport/lib/active_support/message_verifier.rb
@@ -15,7 +15,7 @@ module ActiveSupport
# In the authentication filter:
#
# id, time = @verifier.verify(cookies[:remember_me])
- # if time < Time.now
+ # if Time.now < time
# self.current_user = User.find(id)
# end
#
diff --git a/activesupport/lib/active_support/multibyte/unicode.rb b/activesupport/lib/active_support/multibyte/unicode.rb
index 586002b03b..72b20fff06 100644
--- a/activesupport/lib/active_support/multibyte/unicode.rb
+++ b/activesupport/lib/active_support/multibyte/unicode.rb
@@ -87,19 +87,44 @@ module ActiveSupport
pos += 1
previous = codepoints[pos-1]
current = codepoints[pos]
- if (
- # CR X LF
- ( previous == database.boundary[:cr] and current == database.boundary[:lf] ) or
- # L X (L|V|LV|LVT)
- ( database.boundary[:l] === previous and in_char_class?(current, [:l,:v,:lv,:lvt]) ) or
- # (LV|V) X (V|T)
- ( in_char_class?(previous, [:lv,:v]) and in_char_class?(current, [:v,:t]) ) or
- # (LVT|T) X (T)
- ( in_char_class?(previous, [:lvt,:t]) and database.boundary[:t] === current ) or
- # X Extend
- (database.boundary[:extend] === current)
- )
- else
+
+ should_break =
+ # GB3. CR X LF
+ if previous == database.boundary[:cr] and current == database.boundary[:lf]
+ false
+ # GB4. (Control|CR|LF) ÷
+ elsif previous and in_char_class?(previous, [:control,:cr,:lf])
+ true
+ # GB5. ÷ (Control|CR|LF)
+ elsif in_char_class?(current, [:control,:cr,:lf])
+ true
+ # GB6. L X (L|V|LV|LVT)
+ elsif database.boundary[:l] === previous and in_char_class?(current, [:l,:v,:lv,:lvt])
+ false
+ # GB7. (LV|V) X (V|T)
+ elsif in_char_class?(previous, [:lv,:v]) and in_char_class?(current, [:v,:t])
+ false
+ # GB8. (LVT|T) X (T)
+ elsif in_char_class?(previous, [:lvt,:t]) and database.boundary[:t] === current
+ false
+ # GB8a. Regional_Indicator X Regional_Indicator
+ elsif database.boundary[:regional_indicator] === previous and database.boundary[:regional_indicator] === current
+ false
+ # GB9. X Extend
+ elsif database.boundary[:extend] === current
+ false
+ # GB9a. X SpacingMark
+ elsif database.boundary[:spacingmark] === current
+ false
+ # GB9b. Prepend X
+ elsif database.boundary[:prepend] === previous
+ false
+ # GB10. Any ÷ Any
+ else
+ true
+ end
+
+ if should_break
unpacked << codepoints[marker..pos-1]
marker = pos
end
diff --git a/activesupport/lib/active_support/notifications/fanout.rb b/activesupport/lib/active_support/notifications/fanout.rb
index 7798c7ec60..c53f9c1039 100644
--- a/activesupport/lib/active_support/notifications/fanout.rb
+++ b/activesupport/lib/active_support/notifications/fanout.rb
@@ -42,8 +42,8 @@ module ActiveSupport
listeners_for(name).each { |s| s.start(name, id, payload) }
end
- def finish(name, id, payload)
- listeners_for(name).each { |s| s.finish(name, id, payload) }
+ def finish(name, id, payload, listeners = listeners_for(name))
+ listeners.each { |s| s.finish(name, id, payload) }
end
def publish(name, *args)
diff --git a/activesupport/lib/active_support/notifications/instrumenter.rb b/activesupport/lib/active_support/notifications/instrumenter.rb
index 075ddc2382..91f94cb2d7 100644
--- a/activesupport/lib/active_support/notifications/instrumenter.rb
+++ b/activesupport/lib/active_support/notifications/instrumenter.rb
@@ -15,14 +15,16 @@ module ActiveSupport
# and publish it. Notice that events get sent even if an error occurs
# in the passed-in block.
def instrument(name, payload={})
- start name, payload
+ # some of the listeners might have state
+ listeners_state = start name, payload
begin
yield payload
rescue Exception => e
payload[:exception] = [e.class.name, e.message]
+ payload[:exception_object] = e
raise e
ensure
- finish name, payload
+ finish_with_state listeners_state, name, payload
end
end
@@ -36,6 +38,10 @@ module ActiveSupport
@notifier.finish name, @id, payload
end
+ def finish_with_state(listeners_state, name, payload)
+ @notifier.finish name, @id, payload, listeners_state
+ end
+
private
def unique_id
diff --git a/activesupport/lib/active_support/number_helper.rb b/activesupport/lib/active_support/number_helper.rb
index 248521e677..64d9e71f37 100644
--- a/activesupport/lib/active_support/number_helper.rb
+++ b/activesupport/lib/active_support/number_helper.rb
@@ -47,6 +47,14 @@ module ActiveSupport
# Formats a +number+ into a currency string (e.g., $13.65). You
# can customize the format in the +options+ hash.
#
+ # The currency unit and number formatting of the current locale will be used
+ # unless otherwise specified in the provided options. No currency conversion
+ # is performed. If the user is given a way to change their locale, they will
+ # also be able to change the relative value of the currency displayed with
+ # this helper. If your application will ever support multiple locales, you
+ # may want to specify a constant <tt>:locale</tt> option or consider
+ # using a library capable of currency conversion.
+ #
# ==== Options
#
# * <tt>:locale</tt> - Sets the locale to be used for formatting
@@ -235,6 +243,8 @@ module ActiveSupport
# number_to_human_size(1234567) # => 1.18 MB
# number_to_human_size(1234567890) # => 1.15 GB
# number_to_human_size(1234567890123) # => 1.12 TB
+ # number_to_human_size(1234567890123456) # => 1.1 PB
+ # number_to_human_size(1234567890123456789) # => 1.07 EB
# number_to_human_size(1234567, precision: 2) # => 1.2 MB
# number_to_human_size(483989, precision: 2) # => 470 KB
# number_to_human_size(1234567, precision: 2, separator: ',') # => 1,2 MB
diff --git a/activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb b/activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb
index a4a8690bcd..a83b368b7f 100644
--- a/activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb
+++ b/activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb
@@ -1,7 +1,7 @@
module ActiveSupport
module NumberHelper
class NumberToHumanSizeConverter < NumberConverter #:nodoc:
- STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb]
+ STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb, :pb, :eb]
self.namespace = :human
self.validate_float = true
diff --git a/activesupport/lib/active_support/ordered_hash.rb b/activesupport/lib/active_support/ordered_hash.rb
index 4680d5acb7..b1658f0f27 100644
--- a/activesupport/lib/active_support/ordered_hash.rb
+++ b/activesupport/lib/active_support/ordered_hash.rb
@@ -5,7 +5,7 @@ YAML.add_builtin_type("omap") do |type, val|
end
module ActiveSupport
- # <tt>ActiveSupport::OrderedHash</tt> implements a hash that preserves
+ # DEPRECATED: <tt>ActiveSupport::OrderedHash</tt> implements a hash that preserves
# insertion order.
#
# oh = ActiveSupport::OrderedHash.new
diff --git a/activesupport/lib/active_support/per_thread_registry.rb b/activesupport/lib/active_support/per_thread_registry.rb
index 506dd950cb..88e2b12cc7 100644
--- a/activesupport/lib/active_support/per_thread_registry.rb
+++ b/activesupport/lib/active_support/per_thread_registry.rb
@@ -1,4 +1,9 @@
+require 'active_support/core_ext/module/delegation'
+
module ActiveSupport
+ # NOTE: This approach has been deprecated for end-user code in favor of thread_mattr_accessor and friends.
+ # Please use that approach instead.
+ #
# This module is used to encapsulate access to thread local variables.
#
# Instead of polluting the thread locals namespace:
diff --git a/activesupport/lib/active_support/test_case.rb b/activesupport/lib/active_support/test_case.rb
index ae6f00b861..d9a668c0ea 100644
--- a/activesupport/lib/active_support/test_case.rb
+++ b/activesupport/lib/active_support/test_case.rb
@@ -9,7 +9,6 @@ require 'active_support/testing/isolation'
require 'active_support/testing/constant_lookup'
require 'active_support/testing/time_helpers'
require 'active_support/testing/file_fixtures'
-require 'active_support/testing/composite_filter'
require 'active_support/core_ext/kernel/reporting'
module ActiveSupport
@@ -39,15 +38,6 @@ module ActiveSupport
def test_order
ActiveSupport.test_order ||= :random
end
-
- def run(reporter, options = {})
- if options[:patterns] && options[:patterns].any? { |p| p =~ /:\d+/ }
- options[:filter] = \
- Testing::CompositeFilter.new(self, options[:filter], options[:patterns])
- end
-
- super
- end
end
alias_method :method_name, :name
diff --git a/activesupport/lib/active_support/testing/composite_filter.rb b/activesupport/lib/active_support/testing/composite_filter.rb
deleted file mode 100644
index bde723e30b..0000000000
--- a/activesupport/lib/active_support/testing/composite_filter.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-require 'method_source'
-
-module ActiveSupport
- module Testing
- class CompositeFilter # :nodoc:
- def initialize(runnable, filter, patterns)
- @runnable = runnable
- @filters = [ derive_regexp(filter), *derive_line_filters(patterns) ].compact
- end
-
- def ===(method)
- @filters.any? { |filter| filter === method }
- end
-
- private
- def derive_regexp(filter)
- filter =~ %r%/(.*)/% ? Regexp.new($1) : filter
- end
-
- def derive_line_filters(patterns)
- patterns.map do |file_and_line|
- file, line = file_and_line.split(':')
- Filter.new(@runnable, file, line) if file
- end
- end
-
- class Filter # :nodoc:
- def initialize(runnable, file, line)
- @runnable, @file = runnable, File.expand_path(file)
- @line = line.to_i if line
- end
-
- def ===(method)
- return unless @runnable.method_defined?(method)
-
- if @line
- test_file, test_range = definition_for(@runnable.instance_method(method))
- test_file == @file && test_range.include?(@line)
- else
- @runnable.instance_method(method).source_location.first == @file
- end
- end
-
- private
- def definition_for(method)
- file, start_line = method.source_location
- end_line = method.source.count("\n") + start_line - 1
-
- return file, start_line..end_line
- end
- end
- end
- end
-end
diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb
index 6404f65612..7ca3592520 100644
--- a/activesupport/lib/active_support/values/time_zone.rb
+++ b/activesupport/lib/active_support/values/time_zone.rb
@@ -86,7 +86,8 @@ module ActiveSupport
"Paris" => "Europe/Paris",
"Amsterdam" => "Europe/Amsterdam",
"Berlin" => "Europe/Berlin",
- "Bern" => "Europe/Berlin",
+ "Bern" => "Europe/Zurich",
+ "Zurich" => "Europe/Zurich",
"Rome" => "Europe/Rome",
"Stockholm" => "Europe/Stockholm",
"Vienna" => "Europe/Vienna",