aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport/lib')
-rw-r--r--activesupport/lib/active_support.rb1
-rw-r--r--activesupport/lib/active_support/actionable_error.rb48
-rw-r--r--activesupport/lib/active_support/backtrace_cleaner.rb6
-rw-r--r--activesupport/lib/active_support/cache/redis_cache_store.rb13
-rw-r--r--activesupport/lib/active_support/concern.rb25
-rw-r--r--activesupport/lib/active_support/core_ext/string/output_safety.rb6
-rw-r--r--activesupport/lib/active_support/dependencies/zeitwerk_integration.rb17
-rw-r--r--activesupport/lib/active_support/deprecation/method_wrappers.rb25
-rw-r--r--activesupport/lib/active_support/descendants_tracker.rb4
-rw-r--r--activesupport/lib/active_support/duration.rb1
-rw-r--r--activesupport/lib/active_support/i18n_railtie.rb3
-rw-r--r--activesupport/lib/active_support/notifications/fanout.rb4
-rw-r--r--activesupport/lib/active_support/notifications/instrumenter.rb7
-rw-r--r--activesupport/lib/active_support/testing/parallelization.rb15
14 files changed, 129 insertions, 46 deletions
diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb
index 5589c71281..9e242ddeaa 100644
--- a/activesupport/lib/active_support.rb
+++ b/activesupport/lib/active_support.rb
@@ -34,6 +34,7 @@ module ActiveSupport
extend ActiveSupport::Autoload
autoload :Concern
+ autoload :ActionableError
autoload :CurrentAttributes
autoload :Dependencies
autoload :DescendantsTracker
diff --git a/activesupport/lib/active_support/actionable_error.rb b/activesupport/lib/active_support/actionable_error.rb
new file mode 100644
index 0000000000..7db14cd178
--- /dev/null
+++ b/activesupport/lib/active_support/actionable_error.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+module ActiveSupport
+ # Actionable errors let's you define actions to resolve an error.
+ #
+ # To make an error actionable, include the <tt>ActiveSupport::ActionableError</tt>
+ # module and invoke the +action+ class macro to define the action. An action
+ # needs a name and a block to execute.
+ module ActionableError
+ extend Concern
+
+ class NonActionable < StandardError; end
+
+ included do
+ class_attribute :_actions, default: {}
+ end
+
+ def self.actions(error) # :nodoc:
+ case error
+ when ActionableError, -> it { Class === it && it < ActionableError }
+ error._actions
+ else
+ {}
+ end
+ end
+
+ def self.dispatch(error, name) # :nodoc:
+ actions(error).fetch(name).call
+ rescue KeyError
+ raise NonActionable, "Cannot find action \"#{name}\""
+ end
+
+ module ClassMethods
+ # Defines an action that can resolve the error.
+ #
+ # class PendingMigrationError < MigrationError
+ # include ActiveSupport::ActionableError
+ #
+ # action "Run pending migrations" do
+ # ActiveRecord::Tasks::DatabaseTasks.migrate
+ # end
+ # end
+ def action(name, &block)
+ _actions[name] = block
+ end
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/backtrace_cleaner.rb b/activesupport/lib/active_support/backtrace_cleaner.rb
index 62973eca58..02cbfbaee6 100644
--- a/activesupport/lib/active_support/backtrace_cleaner.rb
+++ b/activesupport/lib/active_support/backtrace_cleaner.rb
@@ -122,7 +122,11 @@ module ActiveSupport
end
def noise(backtrace)
- backtrace - silence(backtrace)
+ backtrace.select do |line|
+ @silencers.any? do |s|
+ s.call(line)
+ end
+ end
end
end
end
diff --git a/activesupport/lib/active_support/cache/redis_cache_store.rb b/activesupport/lib/active_support/cache/redis_cache_store.rb
index 9a55e49e27..bb092fcde9 100644
--- a/activesupport/lib/active_support/cache/redis_cache_store.rb
+++ b/activesupport/lib/active_support/cache/redis_cache_store.rb
@@ -152,12 +152,14 @@ module ActiveSupport
# Creates a new Redis cache store.
#
- # Handles three options: block provided to instantiate, single URL
- # provided, and multiple URLs provided.
+ # Handles four options: :redis block, :redis instance, single :url
+ # string, and multiple :url strings.
#
- # :redis Proc -> options[:redis].call
- # :url String -> Redis.new(url: …)
- # :url Array -> Redis::Distributed.new([{ url: … }, { url: … }, …])
+ # Option Class Result
+ # :redis Proc -> options[:redis].call
+ # :redis Object -> options[:redis]
+ # :url String -> Redis.new(url: …)
+ # :url Array -> Redis::Distributed.new([{ url: … }, { url: … }, …])
#
# No namespace is set by default. Provide one if the Redis cache
# server is shared with other apps: <tt>namespace: 'myapp-cache'</tt>.
@@ -361,6 +363,7 @@ module ActiveSupport
def read_multi_mget(*names)
options = names.extract_options!
options = merged_options(options)
+ return {} if names == []
keys = names.map { |name| normalize_key(name, options) }
diff --git a/activesupport/lib/active_support/concern.rb b/activesupport/lib/active_support/concern.rb
index 5d356a0ab6..708c445031 100644
--- a/activesupport/lib/active_support/concern.rb
+++ b/activesupport/lib/active_support/concern.rb
@@ -110,7 +110,7 @@ module ActiveSupport
base.instance_variable_set(:@_dependencies, [])
end
- def append_features(base)
+ def append_features(base) #:nodoc:
if base.instance_variable_defined?(:@_dependencies)
base.instance_variable_get(:@_dependencies) << self
false
@@ -123,6 +123,9 @@ module ActiveSupport
end
end
+ # Evaluate given block in context of base class,
+ # so that you can write class macros here.
+ # When you define more than one +included+ block, it raises an exception.
def included(base = nil, &block)
if base.nil?
if instance_variable_defined?(:@_included_block)
@@ -137,6 +140,26 @@ module ActiveSupport
end
end
+ # Define class methods from given block.
+ # You can define private class methods as well.
+ #
+ # module Example
+ # extend ActiveSupport::Concern
+ #
+ # class_methods do
+ # def foo; puts 'foo'; end
+ #
+ # private
+ # def bar; puts 'bar'; end
+ # end
+ # end
+ #
+ # class Buzz
+ # include Example
+ # end
+ #
+ # Buzz.foo # => "foo"
+ # Buzz.bar # => private method 'bar' called for Buzz:Class(NoMethodError)
def class_methods(&class_methods_module_definition)
mod = const_defined?(:ClassMethods, false) ?
const_get(:ClassMethods) :
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 638152626b..645b1fea17 100644
--- a/activesupport/lib/active_support/core_ext/string/output_safety.rb
+++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb
@@ -213,6 +213,12 @@ module ActiveSupport #:nodoc:
dup.concat(other)
end
+ def *(*)
+ new_safe_buffer = super
+ new_safe_buffer.instance_variable_set(:@html_safe, @html_safe)
+ new_safe_buffer
+ end
+
def %(args)
case args
when Hash
diff --git a/activesupport/lib/active_support/dependencies/zeitwerk_integration.rb b/activesupport/lib/active_support/dependencies/zeitwerk_integration.rb
index a43d03cf09..fd39ad6e55 100644
--- a/activesupport/lib/active_support/dependencies/zeitwerk_integration.rb
+++ b/activesupport/lib/active_support/dependencies/zeitwerk_integration.rb
@@ -10,6 +10,8 @@ module ActiveSupport
def clear
Dependencies.unload_interlock do
Rails.autoloaders.main.reload
+ rescue Zeitwerk::ReloadingDisabledError
+ raise "reloading is disabled because config.cache_classes is true"
end
end
@@ -22,16 +24,12 @@ module ActiveSupport
end
def autoloaded_constants
- cpaths = []
- Rails.autoloaders.each do |autoloader|
- cpaths.concat(autoloader.loaded_cpaths.to_a)
- end
- cpaths
+ Rails.autoloaders.main.unloadable_cpaths
end
def autoloaded?(object)
cpath = object.is_a?(Module) ? object.name : object.to_s
- Rails.autoloaders.any? { |autoloader| autoloader.loaded?(cpath) }
+ Rails.autoloaders.main.unloadable_cpath?(cpath)
end
def verbose=(verbose)
@@ -51,15 +49,15 @@ module ActiveSupport
end
class << self
- def take_over
- setup_autoloaders
+ def take_over(enable_reloading:)
+ setup_autoloaders(enable_reloading)
freeze_paths
decorate_dependencies
end
private
- def setup_autoloaders
+ def setup_autoloaders(enable_reloading)
Dependencies.autoload_paths.each do |autoload_path|
# Zeitwerk only accepts existing directories in `push_dir` to
# prevent misconfigurations.
@@ -72,6 +70,7 @@ module ActiveSupport
autoloader.do_not_eager_load(autoload_path) unless eager_load?(autoload_path)
end
+ Rails.autoloaders.main.enable_reloading if enable_reloading
Rails.autoloaders.each(&:setup)
end
diff --git a/activesupport/lib/active_support/deprecation/method_wrappers.rb b/activesupport/lib/active_support/deprecation/method_wrappers.rb
index d99571790f..7c0a54a1d0 100644
--- a/activesupport/lib/active_support/deprecation/method_wrappers.rb
+++ b/activesupport/lib/active_support/deprecation/method_wrappers.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require "active_support/core_ext/array/extract_options"
+require "active_support/core_ext/module/redefine_method"
module ActiveSupport
class Deprecation
@@ -52,29 +53,17 @@ module ActiveSupport
options = method_names.extract_options!
deprecator = options.delete(:deprecator) || self
method_names += options.keys
- mod = Module.new
+ mod = nil
method_names.each do |method_name|
if target_module.method_defined?(method_name) || target_module.private_method_defined?(method_name)
- aliased_method, punctuation = method_name.to_s.sub(/([?!=])$/, ""), $1
- with_method = "#{aliased_method}_with_deprecation#{punctuation}"
- without_method = "#{aliased_method}_without_deprecation#{punctuation}"
-
- target_module.define_method(with_method) do |*args, &block|
+ method = target_module.instance_method(method_name)
+ target_module.redefine_method(method_name) do |*args, &block|
deprecator.deprecation_warning(method_name, options[method_name])
- send(without_method, *args, &block)
- end
-
- target_module.alias_method(without_method, method_name)
- target_module.alias_method(method_name, with_method)
-
- case
- when target_module.protected_method_defined?(without_method)
- target_module.send(:protected, method_name)
- when target_module.private_method_defined?(without_method)
- target_module.send(:private, method_name)
+ method.bind(self).call(*args, &block)
end
else
+ mod ||= Module.new
mod.define_method(method_name) do |*args, &block|
deprecator.deprecation_warning(method_name, options[method_name])
super(*args, &block)
@@ -82,7 +71,7 @@ module ActiveSupport
end
end
- target_module.prepend(mod) unless mod.instance_methods(false).empty?
+ target_module.prepend(mod) if mod
end
end
end
diff --git a/activesupport/lib/active_support/descendants_tracker.rb b/activesupport/lib/active_support/descendants_tracker.rb
index 2dca990712..21565138a7 100644
--- a/activesupport/lib/active_support/descendants_tracker.rb
+++ b/activesupport/lib/active_support/descendants_tracker.rb
@@ -23,10 +23,10 @@ module ActiveSupport
def clear
if defined? ActiveSupport::Dependencies
@@direct_descendants.each do |klass, descendants|
- if ActiveSupport::Dependencies.autoloaded?(klass)
+ if Dependencies.autoloaded?(klass)
@@direct_descendants.delete(klass)
else
- descendants.reject! { |v| ActiveSupport::Dependencies.autoloaded?(v) }
+ descendants.reject! { |v| Dependencies.autoloaded?(v) }
end
end
else
diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb
index 97b4634d7b..a30bd11a87 100644
--- a/activesupport/lib/active_support/duration.rb
+++ b/activesupport/lib/active_support/duration.rb
@@ -4,7 +4,6 @@ require "active_support/core_ext/array/conversions"
require "active_support/core_ext/module/delegation"
require "active_support/core_ext/object/acts_like"
require "active_support/core_ext/string/filters"
-require "active_support/deprecation"
module ActiveSupport
# Provides accurate date and time measurements using Date#advance and
diff --git a/activesupport/lib/active_support/i18n_railtie.rb b/activesupport/lib/active_support/i18n_railtie.rb
index 584930e413..8faa93a3e4 100644
--- a/activesupport/lib/active_support/i18n_railtie.rb
+++ b/activesupport/lib/active_support/i18n_railtie.rb
@@ -97,7 +97,8 @@ module I18n
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,
- {...}]`
+ {...}]`. If you want to opt-in to the new behavior, use
+ `config.i18n.fallbacks.defaults = [nil, {...}]`.
MSG
args.unshift I18n.default_locale
end
diff --git a/activesupport/lib/active_support/notifications/fanout.rb b/activesupport/lib/active_support/notifications/fanout.rb
index c506b35b1e..8812b67f63 100644
--- a/activesupport/lib/active_support/notifications/fanout.rb
+++ b/activesupport/lib/active_support/notifications/fanout.rb
@@ -180,13 +180,13 @@ module ActiveSupport
def start(name, id, payload)
timestack = Thread.current[:_timestack] ||= []
- timestack.push Time.now
+ timestack.push Concurrent.monotonic_time
end
def finish(name, id, payload)
timestack = Thread.current[:_timestack]
started = timestack.pop
- @delegate.call(name, started, Time.now, id, payload)
+ @delegate.call(name, started, Concurrent.monotonic_time, id, payload)
end
end
diff --git a/activesupport/lib/active_support/notifications/instrumenter.rb b/activesupport/lib/active_support/notifications/instrumenter.rb
index a03e7e483e..12546511a8 100644
--- a/activesupport/lib/active_support/notifications/instrumenter.rb
+++ b/activesupport/lib/active_support/notifications/instrumenter.rb
@@ -68,9 +68,8 @@ module ActiveSupport
@transaction_id = transaction_id
@end = ending
@children = []
- @duration = nil
- @cpu_time_start = nil
- @cpu_time_finish = nil
+ @cpu_time_start = 0
+ @cpu_time_finish = 0
@allocation_count_start = 0
@allocation_count_finish = 0
end
@@ -125,7 +124,7 @@ module ActiveSupport
#
# @event.duration # => 1000.138
def duration
- @duration ||= 1000.0 * (self.end - time)
+ 1000.0 * (self.end - time)
end
def <<(event)
diff --git a/activesupport/lib/active_support/testing/parallelization.rb b/activesupport/lib/active_support/testing/parallelization.rb
index 63440069b1..e760bf5ce3 100644
--- a/activesupport/lib/active_support/testing/parallelization.rb
+++ b/activesupport/lib/active_support/testing/parallelization.rb
@@ -71,7 +71,9 @@ module ActiveSupport
fork do
DRb.stop_service
- after_fork(worker)
+ begin
+ after_fork(worker)
+ rescue => setup_exception; end
queue = DRbObject.new_with_uri(@url)
@@ -79,7 +81,11 @@ module ActiveSupport
klass = job[0]
method = job[1]
reporter = job[2]
- result = Minitest.run_one_method(klass, method)
+ result = klass.with_info_handler reporter do
+ Minitest.run_one_method(klass, method)
+ end
+
+ add_setup_exception(result, setup_exception) if setup_exception
begin
queue.record(reporter, result)
@@ -104,6 +110,11 @@ module ActiveSupport
@queue_size.times { @queue << nil }
@pool.each { |pid| Process.waitpid pid }
end
+
+ private
+ def add_setup_exception(result, setup_exception)
+ result.failures.prepend Minitest::UnexpectedError.new(setup_exception)
+ end
end
end
end