activesupport 6.0.0.beta1 → 6.0.1.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of activesupport might be problematic. Click here for more details.

Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +302 -1
  3. data/README.rdoc +2 -1
  4. data/lib/active_support.rb +1 -0
  5. data/lib/active_support/actionable_error.rb +48 -0
  6. data/lib/active_support/backtrace_cleaner.rb +5 -1
  7. data/lib/active_support/cache.rb +5 -5
  8. data/lib/active_support/cache/file_store.rb +3 -10
  9. data/lib/active_support/cache/memory_store.rb +4 -2
  10. data/lib/active_support/cache/redis_cache_store.rb +9 -6
  11. data/lib/active_support/concern.rb +24 -1
  12. data/lib/active_support/configurable.rb +3 -3
  13. data/lib/active_support/core_ext/array/access.rb +18 -6
  14. data/lib/active_support/core_ext/class/attribute.rb +10 -15
  15. data/lib/active_support/core_ext/date_and_time/calculations.rb +0 -30
  16. data/lib/active_support/core_ext/digest.rb +3 -0
  17. data/lib/active_support/core_ext/enumerable.rb +24 -4
  18. data/lib/active_support/core_ext/hash.rb +1 -0
  19. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  20. data/lib/active_support/core_ext/hash/except.rb +1 -1
  21. data/lib/active_support/core_ext/kernel.rb +0 -1
  22. data/lib/active_support/core_ext/module/attribute_accessors.rb +5 -5
  23. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +5 -5
  24. data/lib/active_support/core_ext/module/delegation.rb +6 -0
  25. data/lib/active_support/core_ext/object/duplicable.rb +7 -117
  26. data/lib/active_support/core_ext/range/compare_range.rb +27 -12
  27. data/lib/active_support/core_ext/range/include_time_with_zone.rb +2 -2
  28. data/lib/active_support/core_ext/string/filters.rb +1 -1
  29. data/lib/active_support/core_ext/string/inflections.rb +7 -2
  30. data/lib/active_support/core_ext/string/output_safety.rb +51 -4
  31. data/lib/active_support/core_ext/time/calculations.rb +31 -2
  32. data/lib/active_support/current_attributes.rb +6 -0
  33. data/lib/active_support/dependencies.rb +41 -5
  34. data/lib/active_support/dependencies/zeitwerk_integration.rb +118 -0
  35. data/lib/active_support/deprecation/method_wrappers.rb +7 -18
  36. data/lib/active_support/deprecation/proxy_wrappers.rb +24 -3
  37. data/lib/active_support/descendants_tracker.rb +52 -6
  38. data/lib/active_support/duration.rb +2 -3
  39. data/lib/active_support/encrypted_file.rb +2 -1
  40. data/lib/active_support/evented_file_update_checker.rb +14 -2
  41. data/lib/active_support/gem_version.rb +2 -2
  42. data/lib/active_support/hash_with_indifferent_access.rb +19 -3
  43. data/lib/active_support/i18n_railtie.rb +2 -1
  44. data/lib/active_support/inflector/transliterate.rb +43 -14
  45. data/lib/active_support/logger_thread_safe_level.rb +2 -1
  46. data/lib/active_support/message_encryptor.rb +1 -1
  47. data/lib/active_support/message_verifier.rb +1 -1
  48. data/lib/active_support/notifications.rb +9 -0
  49. data/lib/active_support/notifications/fanout.rb +60 -13
  50. data/lib/active_support/notifications/instrumenter.rb +11 -10
  51. data/lib/active_support/ordered_hash.rb +1 -1
  52. data/lib/active_support/ordered_options.rb +1 -1
  53. data/lib/active_support/parameter_filter.rb +6 -1
  54. data/lib/active_support/security_utils.rb +1 -1
  55. data/lib/active_support/subscriber.rb +55 -6
  56. data/lib/active_support/testing/parallelization.rb +21 -2
  57. metadata +27 -7
  58. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
@@ -119,10 +119,16 @@ module ActiveSupport
119
119
  end
120
120
  end
121
121
 
122
+ # Calls this block before #reset is called on the instance. Used for resetting external collaborators that depend on current values.
123
+ def before_reset(&block)
124
+ set_callback :reset, :before, &block
125
+ end
126
+
122
127
  # Calls this block after #reset is called on the instance. Used for resetting external collaborators, like Time.zone.
123
128
  def resets(&block)
124
129
  set_callback :reset, :after, &block
125
130
  end
131
+ alias_method :after_reset, :resets
126
132
 
127
133
  delegate :set, :reset, to: :instance
128
134
 
@@ -20,6 +20,9 @@ module ActiveSupport #:nodoc:
20
20
  module Dependencies #:nodoc:
21
21
  extend self
22
22
 
23
+ UNBOUND_METHOD_MODULE_NAME = Module.instance_method(:name)
24
+ private_constant :UNBOUND_METHOD_MODULE_NAME
25
+
23
26
  mattr_accessor :interlock, default: Interlock.new
24
27
 
25
28
  # :doc:
@@ -70,6 +73,11 @@ module ActiveSupport #:nodoc:
70
73
  # only once. All directories in this set must also be present in +autoload_paths+.
71
74
  mattr_accessor :autoload_once_paths, default: []
72
75
 
76
+ # This is a private set that collects all eager load paths during bootstrap.
77
+ # Useful for Zeitwerk integration. Its public interface is the config.* path
78
+ # accessors of each engine.
79
+ mattr_accessor :_eager_load_paths, default: Set.new
80
+
73
81
  # An array of qualified constant names that have been loaded. Adding a name
74
82
  # to this array will cause it to be unloaded the next time Dependencies are
75
83
  # cleared.
@@ -196,6 +204,11 @@ module ActiveSupport #:nodoc:
196
204
  end
197
205
  end
198
206
 
207
+ def self.include_into(base)
208
+ base.include(self)
209
+ append_features(base)
210
+ end
211
+
199
212
  def const_missing(const_name)
200
213
  from_mod = anonymous? ? guess_for_anonymous(const_name) : self
201
214
  Dependencies.load_missing_constant(from_mod, const_name)
@@ -225,6 +238,21 @@ module ActiveSupport #:nodoc:
225
238
  base.class_eval do
226
239
  define_method(:load, Kernel.instance_method(:load))
227
240
  private :load
241
+
242
+ define_method(:require, Kernel.instance_method(:require))
243
+ private :require
244
+ end
245
+ end
246
+
247
+ def self.include_into(base)
248
+ base.include(self)
249
+
250
+ if base.instance_method(:load).owner == base
251
+ base.remove_method(:load)
252
+ end
253
+
254
+ if base.instance_method(:require).owner == base
255
+ base.remove_method(:require)
228
256
  end
229
257
  end
230
258
 
@@ -321,9 +349,9 @@ module ActiveSupport #:nodoc:
321
349
  end
322
350
 
323
351
  def hook!
324
- Object.class_eval { include Loadable }
325
- Module.class_eval { include ModuleConstMissing }
326
- Exception.class_eval { include Blamable }
352
+ Loadable.include_into(Object)
353
+ ModuleConstMissing.include_into(Module)
354
+ Exception.include(Blamable)
327
355
  end
328
356
 
329
357
  def unhook!
@@ -634,7 +662,7 @@ module ActiveSupport #:nodoc:
634
662
 
635
663
  # Determine if the given constant has been automatically loaded.
636
664
  def autoloaded?(desc)
637
- return false if desc.is_a?(Module) && desc.anonymous?
665
+ return false if desc.is_a?(Module) && real_mod_name(desc).nil?
638
666
  name = to_constant_name desc
639
667
  return false unless qualified_const_defined?(name)
640
668
  autoloaded_constants.include?(name)
@@ -690,7 +718,7 @@ module ActiveSupport #:nodoc:
690
718
  when String then desc.sub(/^::/, "")
691
719
  when Symbol then desc.to_s
692
720
  when Module
693
- desc.name ||
721
+ real_mod_name(desc) ||
694
722
  raise(ArgumentError, "Anonymous modules have no name to be referenced by")
695
723
  else raise TypeError, "Not a valid constant descriptor: #{desc.inspect}"
696
724
  end
@@ -764,6 +792,14 @@ module ActiveSupport #:nodoc:
764
792
  def log(message)
765
793
  logger.debug("autoloading: #{message}") if logger && verbose
766
794
  end
795
+
796
+ private
797
+
798
+ # Returns the original name of a class or module even if `name` has been
799
+ # overridden.
800
+ def real_mod_name(mod)
801
+ UNBOUND_METHOD_MODULE_NAME.bind(mod).call
802
+ end
767
803
  end
768
804
  end
769
805
 
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
4
+ require "active_support/core_ext/string/inflections"
5
+
6
+ module ActiveSupport
7
+ module Dependencies
8
+ module ZeitwerkIntegration # :nodoc: all
9
+ module Decorations
10
+ def clear
11
+ Dependencies.unload_interlock do
12
+ Rails.autoloaders.main.reload
13
+ rescue Zeitwerk::ReloadingDisabledError
14
+ raise "reloading is disabled because config.cache_classes is true"
15
+ end
16
+ end
17
+
18
+ def constantize(cpath)
19
+ ActiveSupport::Inflector.constantize(cpath)
20
+ end
21
+
22
+ def safe_constantize(cpath)
23
+ ActiveSupport::Inflector.safe_constantize(cpath)
24
+ end
25
+
26
+ def autoloaded_constants
27
+ Rails.autoloaders.main.unloadable_cpaths
28
+ end
29
+
30
+ def autoloaded?(object)
31
+ cpath = object.is_a?(Module) ? real_mod_name(object) : object.to_s
32
+ Rails.autoloaders.main.unloadable_cpath?(cpath)
33
+ end
34
+
35
+ def verbose=(verbose)
36
+ l = verbose ? logger || Rails.logger : nil
37
+ Rails.autoloaders.each { |autoloader| autoloader.logger = l }
38
+ end
39
+
40
+ def unhook!
41
+ :no_op
42
+ end
43
+ end
44
+
45
+ module RequireDependency
46
+ def require_dependency(filename)
47
+ filename = filename.to_path if filename.respond_to?(:to_path)
48
+ if abspath = ActiveSupport::Dependencies.search_for_file(filename)
49
+ require abspath
50
+ else
51
+ require filename
52
+ end
53
+ end
54
+ end
55
+
56
+ module Inflector
57
+ # Concurrent::Map is not needed. This is a private class, and overrides
58
+ # must be defined while the application boots.
59
+ @overrides = {}
60
+
61
+ def self.camelize(basename, _abspath)
62
+ @overrides[basename] || basename.camelize
63
+ end
64
+
65
+ def self.inflect(overrides)
66
+ @overrides.merge!(overrides)
67
+ end
68
+ end
69
+
70
+ class << self
71
+ def take_over(enable_reloading:)
72
+ setup_autoloaders(enable_reloading)
73
+ freeze_paths
74
+ decorate_dependencies
75
+ end
76
+
77
+ private
78
+
79
+ def setup_autoloaders(enable_reloading)
80
+ Dependencies.autoload_paths.each do |autoload_path|
81
+ # Zeitwerk only accepts existing directories in `push_dir` to
82
+ # prevent misconfigurations.
83
+ next unless File.directory?(autoload_path)
84
+
85
+ autoloader = \
86
+ autoload_once?(autoload_path) ? Rails.autoloaders.once : Rails.autoloaders.main
87
+
88
+ autoloader.push_dir(autoload_path)
89
+ autoloader.do_not_eager_load(autoload_path) unless eager_load?(autoload_path)
90
+ end
91
+
92
+ Rails.autoloaders.main.enable_reloading if enable_reloading
93
+ Rails.autoloaders.each(&:setup)
94
+ end
95
+
96
+ def autoload_once?(autoload_path)
97
+ Dependencies.autoload_once_paths.include?(autoload_path)
98
+ end
99
+
100
+ def eager_load?(autoload_path)
101
+ Dependencies._eager_load_paths.member?(autoload_path)
102
+ end
103
+
104
+ def freeze_paths
105
+ Dependencies.autoload_paths.freeze
106
+ Dependencies.autoload_once_paths.freeze
107
+ Dependencies._eager_load_paths.freeze
108
+ end
109
+
110
+ def decorate_dependencies
111
+ Dependencies.unhook!
112
+ Dependencies.singleton_class.prepend(Decorations)
113
+ Object.prepend(RequireDependency)
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/array/extract_options"
4
+ require "active_support/core_ext/module/redefine_method"
4
5
 
5
6
  module ActiveSupport
6
7
  class Deprecation
@@ -52,29 +53,17 @@ module ActiveSupport
52
53
  options = method_names.extract_options!
53
54
  deprecator = options.delete(:deprecator) || self
54
55
  method_names += options.keys
55
- mod = Module.new
56
+ mod = nil
56
57
 
57
58
  method_names.each do |method_name|
58
59
  if target_module.method_defined?(method_name) || target_module.private_method_defined?(method_name)
59
- aliased_method, punctuation = method_name.to_s.sub(/([?!=])$/, ""), $1
60
- with_method = "#{aliased_method}_with_deprecation#{punctuation}"
61
- without_method = "#{aliased_method}_without_deprecation#{punctuation}"
62
-
63
- target_module.define_method(with_method) do |*args, &block|
60
+ method = target_module.instance_method(method_name)
61
+ target_module.redefine_method(method_name) do |*args, &block|
64
62
  deprecator.deprecation_warning(method_name, options[method_name])
65
- send(without_method, *args, &block)
66
- end
67
-
68
- target_module.alias_method(without_method, method_name)
69
- target_module.alias_method(method_name, with_method)
70
-
71
- case
72
- when target_module.protected_method_defined?(without_method)
73
- target_module.send(:protected, method_name)
74
- when target_module.private_method_defined?(without_method)
75
- target_module.send(:private, method_name)
63
+ method.bind(self).call(*args, &block)
76
64
  end
77
65
  else
66
+ mod ||= Module.new
78
67
  mod.define_method(method_name) do |*args, &block|
79
68
  deprecator.deprecation_warning(method_name, options[method_name])
80
69
  super(*args, &block)
@@ -82,7 +71,7 @@ module ActiveSupport
82
71
  end
83
72
  end
84
73
 
85
- target_module.prepend(mod) unless mod.instance_methods(false).empty?
74
+ target_module.prepend(mod) if mod
86
75
  end
87
76
  end
88
77
  end
@@ -120,7 +120,14 @@ module ActiveSupport
120
120
  # # => DEPRECATION WARNING: PLANETS is deprecated! Use PLANETS_POST_2006 instead.
121
121
  # (Backtrace information…)
122
122
  # ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
123
- class DeprecatedConstantProxy < DeprecationProxy
123
+ class DeprecatedConstantProxy < Module
124
+ def self.new(*args, &block)
125
+ object = args.first
126
+
127
+ return object unless object
128
+ super
129
+ end
130
+
124
131
  def initialize(old_const, new_const, deprecator = ActiveSupport::Deprecation.instance, message: "#{old_const} is deprecated! Use #{new_const} instead.")
125
132
  require "active_support/inflector/methods"
126
133
 
@@ -130,6 +137,14 @@ module ActiveSupport
130
137
  @message = message
131
138
  end
132
139
 
140
+ instance_methods.each { |m| undef_method m unless /^__|^object_id$/.match?(m) }
141
+
142
+ # Don't give a deprecation warning on inspect since test/unit and error
143
+ # logs rely on it for diagnostics.
144
+ def inspect
145
+ target.inspect
146
+ end
147
+
133
148
  # Returns the class of the new constant.
134
149
  #
135
150
  # PLANETS_POST_2006 = %w(mercury venus earth mars jupiter saturn uranus neptune)
@@ -144,8 +159,14 @@ module ActiveSupport
144
159
  ActiveSupport::Inflector.constantize(@new_const.to_s)
145
160
  end
146
161
 
147
- def warn(callstack, called, args)
148
- @deprecator.warn(@message, callstack)
162
+ def const_missing(name)
163
+ @deprecator.warn(@message, caller_locations)
164
+ target.const_get(name)
165
+ end
166
+
167
+ def method_missing(called, *args, &block)
168
+ @deprecator.warn(@message, caller_locations)
169
+ target.__send__(called, *args, &block)
149
170
  end
150
171
  end
151
172
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "weakref"
4
+
3
5
  module ActiveSupport
4
6
  # This module provides an internal implementation to track descendants
5
7
  # which is faster than iterating through ObjectSpace.
@@ -8,7 +10,8 @@ module ActiveSupport
8
10
 
9
11
  class << self
10
12
  def direct_descendants(klass)
11
- @@direct_descendants[klass] || []
13
+ descendants = @@direct_descendants[klass]
14
+ descendants ? descendants.to_a : []
12
15
  end
13
16
 
14
17
  def descendants(klass)
@@ -20,10 +23,10 @@ module ActiveSupport
20
23
  def clear
21
24
  if defined? ActiveSupport::Dependencies
22
25
  @@direct_descendants.each do |klass, descendants|
23
- if ActiveSupport::Dependencies.autoloaded?(klass)
26
+ if Dependencies.autoloaded?(klass)
24
27
  @@direct_descendants.delete(klass)
25
28
  else
26
- descendants.reject! { |v| ActiveSupport::Dependencies.autoloaded?(v) }
29
+ descendants.reject! { |v| Dependencies.autoloaded?(v) }
27
30
  end
28
31
  end
29
32
  else
@@ -34,15 +37,17 @@ module ActiveSupport
34
37
  # This is the only method that is not thread safe, but is only ever called
35
38
  # during the eager loading phase.
36
39
  def store_inherited(klass, descendant)
37
- (@@direct_descendants[klass] ||= []) << descendant
40
+ (@@direct_descendants[klass] ||= DescendantsArray.new) << descendant
38
41
  end
39
42
 
40
43
  private
41
44
 
42
45
  def accumulate_descendants(klass, acc)
43
46
  if direct_descendants = @@direct_descendants[klass]
44
- acc.concat(direct_descendants)
45
- direct_descendants.each { |direct_descendant| accumulate_descendants(direct_descendant, acc) }
47
+ direct_descendants.each do |direct_descendant|
48
+ acc << direct_descendant
49
+ accumulate_descendants(direct_descendant, acc)
50
+ end
46
51
  end
47
52
  end
48
53
  end
@@ -59,5 +64,46 @@ module ActiveSupport
59
64
  def descendants
60
65
  DescendantsTracker.descendants(self)
61
66
  end
67
+
68
+ # DescendantsArray is an array that contains weak references to classes.
69
+ class DescendantsArray # :nodoc:
70
+ include Enumerable
71
+
72
+ def initialize
73
+ @refs = []
74
+ end
75
+
76
+ def initialize_copy(orig)
77
+ @refs = @refs.dup
78
+ end
79
+
80
+ def <<(klass)
81
+ cleanup!
82
+ @refs << WeakRef.new(klass)
83
+ end
84
+
85
+ def each
86
+ @refs.each do |ref|
87
+ yield ref.__getobj__
88
+ rescue WeakRef::RefError
89
+ end
90
+ end
91
+
92
+ def refs_size
93
+ @refs.size
94
+ end
95
+
96
+ def cleanup!
97
+ @refs.delete_if { |ref| !ref.weakref_alive? }
98
+ end
99
+
100
+ def reject!
101
+ @refs.reject! do |ref|
102
+ yield ref.__getobj__
103
+ rescue WeakRef::RefError
104
+ true
105
+ end
106
+ end
107
+ end
62
108
  end
63
109
  end
@@ -4,7 +4,6 @@ require "active_support/core_ext/array/conversions"
4
4
  require "active_support/core_ext/module/delegation"
5
5
  require "active_support/core_ext/object/acts_like"
6
6
  require "active_support/core_ext/string/filters"
7
- require "active_support/deprecation"
8
7
 
9
8
  module ActiveSupport
10
9
  # Provides accurate date and time measurements using Date#advance and
@@ -339,8 +338,8 @@ module ActiveSupport
339
338
  # 1.year.to_i # => 31556952
340
339
  #
341
340
  # In such cases, Ruby's core
342
- # Date[http://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html] and
343
- # Time[http://ruby-doc.org/stdlib/libdoc/time/rdoc/Time.html] should be used for precision
341
+ # Date[https://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html] and
342
+ # Time[https://ruby-doc.org/stdlib/libdoc/time/rdoc/Time.html] should be used for precision
344
343
  # date and time arithmetic.
345
344
  def to_i
346
345
  @value.to_i