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/backtrace_cleaner.rb23
-rw-r--r--activesupport/lib/active_support/cache/file_store.rb16
-rw-r--r--activesupport/lib/active_support/callbacks.rb8
-rw-r--r--activesupport/lib/active_support/core_ext/array.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/array/extract.rb21
-rw-r--r--activesupport/lib/active_support/core_ext/integer/multiple.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/object/try.rb18
-rw-r--r--activesupport/lib/active_support/core_ext/string/output_safety.rb4
-rw-r--r--activesupport/lib/active_support/dependencies.rb25
-rw-r--r--activesupport/lib/active_support/i18n_railtie.rb14
-rw-r--r--activesupport/lib/active_support/number_helper.rb5
-rw-r--r--activesupport/lib/active_support/tagged_logging.rb11
-rw-r--r--activesupport/lib/active_support/test_case.rb4
-rw-r--r--activesupport/lib/active_support/testing/method_call_assertions.rb29
-rw-r--r--activesupport/lib/active_support/testing/parallelization.rb24
-rw-r--r--activesupport/lib/active_support/testing/time_helpers.rb3
-rw-r--r--activesupport/lib/active_support/time_with_zone.rb12
17 files changed, 182 insertions, 38 deletions
diff --git a/activesupport/lib/active_support/backtrace_cleaner.rb b/activesupport/lib/active_support/backtrace_cleaner.rb
index 16dd733ddb..1796956bd7 100644
--- a/activesupport/lib/active_support/backtrace_cleaner.rb
+++ b/activesupport/lib/active_support/backtrace_cleaner.rb
@@ -31,6 +31,9 @@ module ActiveSupport
class BacktraceCleaner
def initialize
@filters, @silencers = [], []
+ add_gem_filter
+ add_gem_silencer
+ add_stdlib_silencer
end
# Returns the backtrace after all filters and silencers have been run
@@ -82,6 +85,26 @@ module ActiveSupport
end
private
+
+ FORMATTED_GEMS_PATTERN = /\A[^\/]+ \([\w.]+\) /
+
+ def add_gem_filter
+ gems_paths = (Gem.path | [Gem.default_dir]).map { |p| Regexp.escape(p) }
+ return if gems_paths.empty?
+
+ gems_regexp = %r{(#{gems_paths.join('|')})/(bundler/)?gems/([^/]+)-([\w.]+)/(.*)}
+ gems_result = '\3 (\4) \5'.freeze
+ add_filter { |line| line.sub(gems_regexp, gems_result) }
+ end
+
+ def add_gem_silencer
+ add_silencer { |line| FORMATTED_GEMS_PATTERN.match?(line) }
+ end
+
+ def add_stdlib_silencer
+ add_silencer { |line| line.start_with?(RbConfig::CONFIG["rubylibdir"]) }
+ end
+
def filter_backtrace(backtrace)
@filters.each do |f|
backtrace = backtrace.map { |line| f.call(line) }
diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb
index a0f44aac0f..04c54c30d0 100644
--- a/activesupport/lib/active_support/cache/file_store.rb
+++ b/activesupport/lib/active_support/cache/file_store.rb
@@ -127,15 +127,19 @@ module ActiveSupport
hash = Zlib.adler32(fname)
hash, dir_1 = hash.divmod(0x1000)
dir_2 = hash.modulo(0x1000)
- fname_paths = []
# Make sure file name doesn't exceed file system limits.
- begin
- fname_paths << fname[0, FILENAME_MAX_SIZE]
- fname = fname[FILENAME_MAX_SIZE..-1]
- end until fname.blank?
+ if fname.length < FILENAME_MAX_SIZE
+ fname_paths = fname
+ else
+ fname_paths = []
+ begin
+ fname_paths << fname[0, FILENAME_MAX_SIZE]
+ fname = fname[FILENAME_MAX_SIZE..-1]
+ end until fname.blank?
+ end
- File.join(cache_path, DIR_FORMATTER % dir_1, DIR_FORMATTER % dir_2, *fname_paths)
+ File.join(cache_path, DIR_FORMATTER % dir_1, DIR_FORMATTER % dir_2, fname_paths)
end
# Translate a file path into a key.
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index c266b432c0..487fe79f41 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -657,9 +657,17 @@ module ActiveSupport
# * <tt>:if</tt> - A symbol or an array of symbols, each naming an instance
# method or a proc; the callback will be called only when they all return
# a true value.
+ #
+ # If a proc is given, its body is evaluated in the context of the
+ # current object. It can also optionally accept the current object as
+ # an argument.
# * <tt>:unless</tt> - A symbol or an array of symbols, each naming an
# instance method or a proc; the callback will be called only when they
# all return a false value.
+ #
+ # If a proc is given, its body is evaluated in the context of the
+ # current object. It can also optionally accept the current object as
+ # an argument.
# * <tt>:prepend</tt> - If +true+, the callback will be prepended to the
# existing chain rather than appended.
def set_callback(name, *filter_list, &block)
diff --git a/activesupport/lib/active_support/core_ext/array.rb b/activesupport/lib/active_support/core_ext/array.rb
index 6d83b76882..a2569c798b 100644
--- a/activesupport/lib/active_support/core_ext/array.rb
+++ b/activesupport/lib/active_support/core_ext/array.rb
@@ -3,6 +3,7 @@
require "active_support/core_ext/array/wrap"
require "active_support/core_ext/array/access"
require "active_support/core_ext/array/conversions"
+require "active_support/core_ext/array/extract"
require "active_support/core_ext/array/extract_options"
require "active_support/core_ext/array/grouping"
require "active_support/core_ext/array/prepend_and_append"
diff --git a/activesupport/lib/active_support/core_ext/array/extract.rb b/activesupport/lib/active_support/core_ext/array/extract.rb
new file mode 100644
index 0000000000..cc5a8a3f88
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/array/extract.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class Array
+ # Removes and returns the elements for which the block returns a true value.
+ # If no block is given, an Enumerator is returned instead.
+ #
+ # numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+ # odd_numbers = numbers.extract! { |number| number.odd? } # => [1, 3, 5, 7, 9]
+ # numbers # => [0, 2, 4, 6, 8]
+ def extract!
+ return to_enum(:extract!) { size } unless block_given?
+
+ extracted_elements = []
+
+ reject! do |element|
+ extracted_elements << element if yield(element)
+ end
+
+ extracted_elements
+ end
+end
diff --git a/activesupport/lib/active_support/core_ext/integer/multiple.rb b/activesupport/lib/active_support/core_ext/integer/multiple.rb
index e7606662d3..bd57a909c5 100644
--- a/activesupport/lib/active_support/core_ext/integer/multiple.rb
+++ b/activesupport/lib/active_support/core_ext/integer/multiple.rb
@@ -7,6 +7,6 @@ class Integer
# 6.multiple_of?(5) # => false
# 10.multiple_of?(2) # => true
def multiple_of?(number)
- number != 0 ? self % number == 0 : zero?
+ number == 0 ? self == 0 : self % number == 0
end
end
diff --git a/activesupport/lib/active_support/core_ext/object/try.rb b/activesupport/lib/active_support/core_ext/object/try.rb
index c874691629..aa6896af32 100644
--- a/activesupport/lib/active_support/core_ext/object/try.rb
+++ b/activesupport/lib/active_support/core_ext/object/try.rb
@@ -4,19 +4,27 @@ require "delegate"
module ActiveSupport
module Tryable #:nodoc:
- def try(*a, &b)
- try!(*a, &b) if a.empty? || respond_to?(a.first)
+ def try(method_name = nil, *args, &b)
+ if method_name.nil? && block_given?
+ if b.arity == 0
+ instance_eval(&b)
+ else
+ yield self
+ end
+ elsif respond_to?(method_name)
+ public_send(method_name, *args, &b)
+ end
end
- def try!(*a, &b)
- if a.empty? && block_given?
+ def try!(method_name = nil, *args, &b)
+ if method_name.nil? && block_given?
if b.arity == 0
instance_eval(&b)
else
yield self
end
else
- public_send(*a, &b)
+ public_send(method_name, *args, &b)
end
end
end
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 f3bdc2977e..d837bb10aa 100644
--- a/activesupport/lib/active_support/core_ext/string/output_safety.rb
+++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb
@@ -149,9 +149,7 @@ module ActiveSupport #:nodoc:
end
def [](*args)
- if args.size < 2
- super
- elsif html_safe?
+ if html_safe?
new_safe_buffer = super
if new_safe_buffer
diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb
index 9dc2c46880..238a9f0ee6 100644
--- a/activesupport/lib/active_support/dependencies.rb
+++ b/activesupport/lib/active_support/dependencies.rb
@@ -79,6 +79,12 @@ module ActiveSupport #:nodoc:
# to allow arbitrary constants to be marked for unloading.
mattr_accessor :explicitly_unloadable_constants, default: []
+ # The logger used when tracing autoloads.
+ mattr_accessor :logger
+
+ # If true, trace autoloads with +logger.debug+.
+ mattr_accessor :verbose, default: false
+
# The WatchStack keeps a stack of the modules being watched as files are
# loaded. If a file in the process of being loaded (parent.rb) triggers the
# load of another file (child.rb) the stack will ensure that child.rb
@@ -416,7 +422,7 @@ module ActiveSupport #:nodoc:
# Search for a file in autoload_paths matching the provided suffix.
def search_for_file(path_suffix)
- path_suffix = path_suffix.sub(/(\.rb)?$/, ".rb".freeze)
+ path_suffix += ".rb" unless path_suffix.ends_with?(".rb")
autoload_paths.each do |root|
path = File.join(root, path_suffix)
@@ -450,6 +456,7 @@ module ActiveSupport #:nodoc:
return nil unless base_path = autoloadable_module?(path_suffix)
mod = Module.new
into.const_set const_name, mod
+ log("constant #{qualified_name} autoloaded (module autovivified from #{File.join(base_path, path_suffix)})")
autoloaded_constants << qualified_name unless autoload_once_paths.include?(base_path)
autoloaded_constants.uniq!
mod
@@ -491,7 +498,7 @@ module ActiveSupport #:nodoc:
raise ArgumentError, "A copy of #{from_mod} has been removed from the module tree but is still active!"
end
- qualified_name = qualified_name_for from_mod, const_name
+ qualified_name = qualified_name_for(from_mod, const_name)
path_suffix = qualified_name.underscore
file_path = search_for_file(path_suffix)
@@ -504,8 +511,13 @@ module ActiveSupport #:nodoc:
raise "Circular dependency detected while autoloading constant #{qualified_name}"
else
require_or_load(expanded, qualified_name)
- raise LoadError, "Unable to autoload constant #{qualified_name}, expected #{file_path} to define it" unless from_mod.const_defined?(const_name, false)
- return from_mod.const_get(const_name)
+
+ if from_mod.const_defined?(const_name, false)
+ log("constant #{qualified_name} autoloaded from #{expanded}.rb")
+ return from_mod.const_get(const_name)
+ else
+ raise LoadError, "Unable to autoload constant #{qualified_name}, expected #{file_path} to define it"
+ end
end
elsif mod = autoload_module!(from_mod, const_name, qualified_name, path_suffix)
return mod
@@ -554,6 +566,7 @@ module ActiveSupport #:nodoc:
# as the environment will be in an inconsistent state, e.g. other constants
# may have already been unloaded and not accessible.
def remove_unloadable_constants!
+ log("removing unloadable constants")
autoloaded_constants.each { |const| remove_constant const }
autoloaded_constants.clear
Reference.clear!
@@ -743,6 +756,10 @@ module ActiveSupport #:nodoc:
# The constant is no longer reachable, just skip it.
end
end
+
+ def log(message)
+ logger.debug("autoloading: #{message}") if logger && verbose
+ end
end
end
diff --git a/activesupport/lib/active_support/i18n_railtie.rb b/activesupport/lib/active_support/i18n_railtie.rb
index 93bde57f6a..584930e413 100644
--- a/activesupport/lib/active_support/i18n_railtie.rb
+++ b/activesupport/lib/active_support/i18n_railtie.rb
@@ -87,9 +87,21 @@ module I18n
when Hash, Array
Array.wrap(fallbacks)
else # TrueClass
- []
+ [I18n.default_locale]
end
+ if args.empty? || args.first.is_a?(Hash)
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ Using I18n fallbacks with an empty `defaults` sets the defaults to
+ include the `default_locale`. This behavior will change in Rails 6.1.
+ If you desire the default locale to be included in the defaults, please
+ explicitly configure it with `config.i18n.fallbacks.defaults =
+ [I18n.default_locale]` or `config.i18n.fallbacks = [I18n.default_locale,
+ {...}]`
+ MSG
+ args.unshift I18n.default_locale
+ end
+
I18n.fallbacks = I18n::Locale::Fallbacks.new(*args)
end
diff --git a/activesupport/lib/active_support/number_helper.rb b/activesupport/lib/active_support/number_helper.rb
index 8fd6e932f1..c75ad52b0c 100644
--- a/activesupport/lib/active_support/number_helper.rb
+++ b/activesupport/lib/active_support/number_helper.rb
@@ -85,6 +85,9 @@ module ActiveSupport
# number given by <tt>:format</tt>). Accepts the same fields
# than <tt>:format</tt>, except <tt>%n</tt> is here the
# absolute value of the number.
+ # * <tt>:strip_insignificant_zeros</tt> - If +true+ removes
+ # insignificant zeros after the decimal separator (defaults to
+ # +false+).
#
# ==== Examples
#
@@ -100,6 +103,8 @@ module ActiveSupport
# # => "&pound;1234567890,50"
# number_to_currency(1234567890.50, unit: '&pound;', separator: ',', delimiter: '', format: '%n %u')
# # => "1234567890,50 &pound;"
+ # number_to_currency(1234567890.50, strip_insignificant_zeros: true)
+ # # => "$1,234,567,890.5"
def number_to_currency(number, options = {})
NumberToCurrencyConverter.convert(number, options)
end
diff --git a/activesupport/lib/active_support/tagged_logging.rb b/activesupport/lib/active_support/tagged_logging.rb
index b069ac94d4..dd72da500c 100644
--- a/activesupport/lib/active_support/tagged_logging.rb
+++ b/activesupport/lib/active_support/tagged_logging.rb
@@ -61,8 +61,15 @@ module ActiveSupport
end
def self.new(logger)
- # Ensure we set a default formatter so we aren't extending nil!
- logger.formatter ||= ActiveSupport::Logger::SimpleFormatter.new
+ logger = logger.dup
+
+ if logger.formatter
+ logger.formatter = logger.formatter.dup
+ else
+ # Ensure we set a default formatter so we aren't extending nil!
+ logger.formatter = ActiveSupport::Logger::SimpleFormatter.new
+ end
+
logger.formatter.extend Formatter
logger.extend(self)
end
diff --git a/activesupport/lib/active_support/test_case.rb b/activesupport/lib/active_support/test_case.rb
index f17743b6db..ef12c6b9b0 100644
--- a/activesupport/lib/active_support/test_case.rb
+++ b/activesupport/lib/active_support/test_case.rb
@@ -65,8 +65,8 @@ module ActiveSupport
#
# parallelize(workers: 2, with: :threads)
#
- # The threaded parallelization uses Minitest's parallel executor directly.
- # The processes parallelization uses a Ruby Drb server.
+ # The threaded parallelization uses minitest's parallel executor directly.
+ # The processes parallelization uses a Ruby DRb server.
def parallelize(workers: 2, with: :processes)
workers = ENV["PARALLEL_WORKERS"].to_i if ENV["PARALLEL_WORKERS"]
diff --git a/activesupport/lib/active_support/testing/method_call_assertions.rb b/activesupport/lib/active_support/testing/method_call_assertions.rb
index c6358002ea..fdc70e1cd3 100644
--- a/activesupport/lib/active_support/testing/method_call_assertions.rb
+++ b/activesupport/lib/active_support/testing/method_call_assertions.rb
@@ -35,6 +35,35 @@ module ActiveSupport
assert_called(object, method_name, message, times: 0, &block)
end
+ # TODO: No need to resort to #send once support for Ruby 2.4 is
+ # dropped.
+ def assert_called_on_instance_of(klass, method_name, message = nil, times: 1, returns: nil)
+ times_called = 0
+ klass.send(:define_method, "stubbed_#{method_name}") do |*|
+ times_called += 1
+
+ returns
+ end
+
+ klass.send(:alias_method, "original_#{method_name}", method_name)
+ klass.send(:alias_method, method_name, "stubbed_#{method_name}")
+
+ yield
+
+ error = "Expected #{method_name} to be called #{times} times, but was called #{times_called} times"
+ error = "#{message}.\n#{error}" if message
+
+ assert_equal times, times_called, error
+ ensure
+ klass.send(:alias_method, method_name, "original_#{method_name}")
+ klass.send(:undef_method, "original_#{method_name}")
+ klass.send(:undef_method, "stubbed_#{method_name}")
+ end
+
+ def assert_not_called_on_instance_of(klass, method_name, message = nil, &block)
+ assert_called_on_instance_of(klass, method_name, message, times: 0, &block)
+ end
+
def stub_any_instance(klass, instance: klass.new)
klass.stub(:new, instance) { yield instance }
end
diff --git a/activesupport/lib/active_support/testing/parallelization.rb b/activesupport/lib/active_support/testing/parallelization.rb
index 1caac1feb3..beeb470659 100644
--- a/activesupport/lib/active_support/testing/parallelization.rb
+++ b/activesupport/lib/active_support/testing/parallelization.rb
@@ -65,22 +65,24 @@ module ActiveSupport
def start
@pool = @queue_size.times.map do |worker|
fork do
- DRb.stop_service
+ begin
+ DRb.stop_service
- after_fork(worker)
+ after_fork(worker)
- queue = DRbObject.new_with_uri(@url)
+ queue = DRbObject.new_with_uri(@url)
- while job = queue.pop
- klass = job[0]
- method = job[1]
- reporter = job[2]
- result = Minitest.run_one_method(klass, method)
+ while job = queue.pop
+ klass = job[0]
+ method = job[1]
+ reporter = job[2]
+ result = Minitest.run_one_method(klass, method)
- queue.record(reporter, result)
+ queue.record(reporter, result)
+ end
+ ensure
+ run_cleanup(worker)
end
-
- run_cleanup(worker)
end
end
end
diff --git a/activesupport/lib/active_support/testing/time_helpers.rb b/activesupport/lib/active_support/testing/time_helpers.rb
index 801ea2909b..f160e66971 100644
--- a/activesupport/lib/active_support/testing/time_helpers.rb
+++ b/activesupport/lib/active_support/testing/time_helpers.rb
@@ -158,7 +158,7 @@ module ActiveSupport
end
# Returns the current time back to its original state, by removing the stubs added by
- # +travel+ and +travel_to+.
+ # +travel+, +travel_to+, and +freeze_time+.
#
# Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
# travel_to Time.zone.local(2004, 11, 24, 01, 04, 44)
@@ -168,6 +168,7 @@ module ActiveSupport
def travel_back
simple_stubs.unstub_all!
end
+ alias_method :unfreeze_time, :travel_back
# Calls +travel_to+ with +Time.now+.
#
diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb
index 7e71318404..fb6956f64f 100644
--- a/activesupport/lib/active_support/time_with_zone.rb
+++ b/activesupport/lib/active_support/time_with_zone.rb
@@ -286,8 +286,10 @@ module ActiveSupport
alias_method :since, :+
alias_method :in, :+
- # Returns a new TimeWithZone object that represents the difference between
- # the current object's time and the +other+ time.
+ # Subtracts an interval of time and returns a new TimeWithZone object unless
+ # the other value `acts_like?` time. Then it will return a Float of the difference
+ # between the two times that represents the difference between the current
+ # object's time and the +other+ time.
#
# Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
# now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28 EST -05:00
@@ -302,6 +304,12 @@ module ActiveSupport
#
# now - 24.hours # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
# now - 1.day # => Sun, 02 Nov 2014 00:26:28 EDT -04:00
+ #
+ # If both the TimeWithZone object and the other value act like Time, a Float
+ # will be returned.
+ #
+ # Time.zone.now - 1.day.ago # => 86399.999967
+ #
def -(other)
if other.acts_like?(:time)
to_time - other.to_time