activesupport 5.2.0 → 6.0.3.2

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 (160) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +479 -330
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -3
  5. data/lib/active_support.rb +2 -1
  6. data/lib/active_support/actionable_error.rb +48 -0
  7. data/lib/active_support/backtrace_cleaner.rb +27 -1
  8. data/lib/active_support/cache.rb +104 -84
  9. data/lib/active_support/cache/file_store.rb +29 -30
  10. data/lib/active_support/cache/mem_cache_store.rb +14 -19
  11. data/lib/active_support/cache/memory_store.rb +15 -9
  12. data/lib/active_support/cache/null_store.rb +8 -3
  13. data/lib/active_support/cache/redis_cache_store.rb +73 -34
  14. data/lib/active_support/cache/strategy/local_cache.rb +23 -23
  15. data/lib/active_support/callbacks.rb +16 -8
  16. data/lib/active_support/concern.rb +31 -4
  17. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
  18. data/lib/active_support/concurrency/share_lock.rb +0 -1
  19. data/lib/active_support/configurable.rb +7 -11
  20. data/lib/active_support/core_ext/array.rb +1 -1
  21. data/lib/active_support/core_ext/array/access.rb +18 -6
  22. data/lib/active_support/core_ext/array/conversions.rb +5 -5
  23. data/lib/active_support/core_ext/array/extract.rb +21 -0
  24. data/lib/active_support/core_ext/array/prepend_and_append.rb +2 -6
  25. data/lib/active_support/core_ext/class/attribute.rb +11 -16
  26. data/lib/active_support/core_ext/class/subclasses.rb +1 -1
  27. data/lib/active_support/core_ext/date/calculations.rb +6 -5
  28. data/lib/active_support/core_ext/date_and_time/calculations.rb +24 -47
  29. data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
  30. data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
  31. data/lib/active_support/core_ext/date_time/conversions.rb +0 -1
  32. data/lib/active_support/core_ext/digest.rb +3 -0
  33. data/lib/active_support/core_ext/enumerable.rb +97 -68
  34. data/lib/active_support/core_ext/file/atomic.rb +1 -1
  35. data/lib/active_support/core_ext/hash.rb +1 -2
  36. data/lib/active_support/core_ext/hash/compact.rb +2 -26
  37. data/lib/active_support/core_ext/hash/conversions.rb +1 -1
  38. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  39. data/lib/active_support/core_ext/hash/except.rb +1 -1
  40. data/lib/active_support/core_ext/hash/keys.rb +0 -29
  41. data/lib/active_support/core_ext/hash/slice.rb +3 -25
  42. data/lib/active_support/core_ext/hash/transform_values.rb +2 -29
  43. data/lib/active_support/core_ext/integer/multiple.rb +1 -1
  44. data/lib/active_support/core_ext/kernel.rb +0 -1
  45. data/lib/active_support/core_ext/load_error.rb +1 -1
  46. data/lib/active_support/core_ext/module.rb +0 -1
  47. data/lib/active_support/core_ext/module/attribute_accessors.rb +7 -10
  48. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +13 -19
  49. data/lib/active_support/core_ext/module/delegation.rb +41 -8
  50. data/lib/active_support/core_ext/module/introspection.rb +38 -13
  51. data/lib/active_support/core_ext/module/reachable.rb +1 -6
  52. data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
  53. data/lib/active_support/core_ext/numeric.rb +0 -1
  54. data/lib/active_support/core_ext/numeric/conversions.rb +124 -128
  55. data/lib/active_support/core_ext/numeric/inquiry.rb +2 -25
  56. data/lib/active_support/core_ext/object/blank.rb +1 -2
  57. data/lib/active_support/core_ext/object/duplicable.rb +7 -114
  58. data/lib/active_support/core_ext/object/json.rb +1 -0
  59. data/lib/active_support/core_ext/object/to_query.rb +5 -2
  60. data/lib/active_support/core_ext/object/try.rb +17 -7
  61. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  62. data/lib/active_support/core_ext/range.rb +1 -1
  63. data/lib/active_support/core_ext/range/compare_range.rb +76 -0
  64. data/lib/active_support/core_ext/range/conversions.rb +31 -29
  65. data/lib/active_support/core_ext/range/each.rb +0 -1
  66. data/lib/active_support/core_ext/range/include_range.rb +6 -22
  67. data/lib/active_support/core_ext/range/include_time_with_zone.rb +2 -2
  68. data/lib/active_support/core_ext/regexp.rb +0 -4
  69. data/lib/active_support/core_ext/securerandom.rb +23 -3
  70. data/lib/active_support/core_ext/string/access.rb +8 -0
  71. data/lib/active_support/core_ext/string/filters.rb +42 -1
  72. data/lib/active_support/core_ext/string/inflections.rb +7 -2
  73. data/lib/active_support/core_ext/string/multibyte.rb +4 -3
  74. data/lib/active_support/core_ext/string/output_safety.rb +63 -6
  75. data/lib/active_support/core_ext/string/strip.rb +3 -1
  76. data/lib/active_support/core_ext/time/calculations.rb +31 -2
  77. data/lib/active_support/core_ext/uri.rb +2 -4
  78. data/lib/active_support/current_attributes.rb +8 -0
  79. data/lib/active_support/dependencies.rb +77 -18
  80. data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
  81. data/lib/active_support/deprecation.rb +1 -1
  82. data/lib/active_support/deprecation/behaviors.rb +5 -1
  83. data/lib/active_support/deprecation/method_wrappers.rb +20 -13
  84. data/lib/active_support/deprecation/proxy_wrappers.rb +28 -5
  85. data/lib/active_support/deprecation/reporting.rb +1 -1
  86. data/lib/active_support/descendants_tracker.rb +55 -9
  87. data/lib/active_support/duration.rb +19 -16
  88. data/lib/active_support/duration/iso8601_parser.rb +2 -4
  89. data/lib/active_support/duration/iso8601_serializer.rb +3 -5
  90. data/lib/active_support/encrypted_configuration.rb +1 -5
  91. data/lib/active_support/encrypted_file.rb +4 -3
  92. data/lib/active_support/evented_file_update_checker.rb +39 -10
  93. data/lib/active_support/execution_wrapper.rb +1 -0
  94. data/lib/active_support/file_update_checker.rb +0 -1
  95. data/lib/active_support/gem_version.rb +4 -4
  96. data/lib/active_support/hash_with_indifferent_access.rb +36 -18
  97. data/lib/active_support/i18n.rb +1 -0
  98. data/lib/active_support/i18n_railtie.rb +18 -2
  99. data/lib/active_support/inflector/inflections.rb +1 -5
  100. data/lib/active_support/inflector/methods.rb +18 -29
  101. data/lib/active_support/inflector/transliterate.rb +47 -18
  102. data/lib/active_support/json/decoding.rb +23 -24
  103. data/lib/active_support/json/encoding.rb +6 -2
  104. data/lib/active_support/key_generator.rb +0 -32
  105. data/lib/active_support/lazy_load_hooks.rb +5 -2
  106. data/lib/active_support/locale/en.rb +33 -0
  107. data/lib/active_support/log_subscriber.rb +31 -9
  108. data/lib/active_support/logger.rb +1 -16
  109. data/lib/active_support/logger_silence.rb +28 -12
  110. data/lib/active_support/logger_thread_safe_level.rb +28 -5
  111. data/lib/active_support/message_encryptor.rb +4 -6
  112. data/lib/active_support/message_verifier.rb +5 -5
  113. data/lib/active_support/messages/metadata.rb +3 -2
  114. data/lib/active_support/messages/rotator.rb +4 -4
  115. data/lib/active_support/multibyte/chars.rb +29 -49
  116. data/lib/active_support/multibyte/unicode.rb +44 -282
  117. data/lib/active_support/notifications.rb +41 -4
  118. data/lib/active_support/notifications/fanout.rb +100 -15
  119. data/lib/active_support/notifications/instrumenter.rb +80 -9
  120. data/lib/active_support/number_helper.rb +11 -0
  121. data/lib/active_support/number_helper/number_converter.rb +4 -5
  122. data/lib/active_support/number_helper/number_to_currency_converter.rb +9 -10
  123. data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -2
  124. data/lib/active_support/number_helper/number_to_human_converter.rb +3 -2
  125. data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -2
  126. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  127. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
  128. data/lib/active_support/number_helper/number_to_rounded_converter.rb +5 -4
  129. data/lib/active_support/option_merger.rb +21 -3
  130. data/lib/active_support/ordered_hash.rb +1 -1
  131. data/lib/active_support/ordered_options.rb +5 -1
  132. data/lib/active_support/parameter_filter.rb +128 -0
  133. data/lib/active_support/rails.rb +0 -6
  134. data/lib/active_support/reloader.rb +4 -5
  135. data/lib/active_support/security_utils.rb +1 -1
  136. data/lib/active_support/string_inquirer.rb +0 -1
  137. data/lib/active_support/subscriber.rb +65 -22
  138. data/lib/active_support/tagged_logging.rb +13 -4
  139. data/lib/active_support/test_case.rb +92 -1
  140. data/lib/active_support/testing/assertions.rb +15 -1
  141. data/lib/active_support/testing/deprecation.rb +0 -1
  142. data/lib/active_support/testing/file_fixtures.rb +2 -0
  143. data/lib/active_support/testing/isolation.rb +2 -2
  144. data/lib/active_support/testing/method_call_assertions.rb +28 -1
  145. data/lib/active_support/testing/parallelization.rb +134 -0
  146. data/lib/active_support/testing/setup_and_teardown.rb +5 -9
  147. data/lib/active_support/testing/stream.rb +1 -2
  148. data/lib/active_support/testing/time_helpers.rb +7 -9
  149. data/lib/active_support/time_with_zone.rb +15 -5
  150. data/lib/active_support/values/time_zone.rb +14 -8
  151. data/lib/active_support/xml_mini.rb +2 -10
  152. data/lib/active_support/xml_mini/jdom.rb +2 -3
  153. data/lib/active_support/xml_mini/libxml.rb +2 -2
  154. data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
  155. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  156. data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
  157. data/lib/active_support/xml_mini/rexml.rb +2 -2
  158. metadata +42 -13
  159. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
  160. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -0,0 +1,117 @@
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
+ def setup_autoloaders(enable_reloading)
79
+ Dependencies.autoload_paths.each do |autoload_path|
80
+ # Zeitwerk only accepts existing directories in `push_dir` to
81
+ # prevent misconfigurations.
82
+ next unless File.directory?(autoload_path)
83
+
84
+ autoloader = \
85
+ autoload_once?(autoload_path) ? Rails.autoloaders.once : Rails.autoloaders.main
86
+
87
+ autoloader.push_dir(autoload_path)
88
+ autoloader.do_not_eager_load(autoload_path) unless eager_load?(autoload_path)
89
+ end
90
+
91
+ Rails.autoloaders.main.enable_reloading if enable_reloading
92
+ Rails.autoloaders.each(&:setup)
93
+ end
94
+
95
+ def autoload_once?(autoload_path)
96
+ Dependencies.autoload_once_paths.include?(autoload_path)
97
+ end
98
+
99
+ def eager_load?(autoload_path)
100
+ Dependencies._eager_load_paths.member?(autoload_path)
101
+ end
102
+
103
+ def freeze_paths
104
+ Dependencies.autoload_paths.freeze
105
+ Dependencies.autoload_once_paths.freeze
106
+ Dependencies._eager_load_paths.freeze
107
+ end
108
+
109
+ def decorate_dependencies
110
+ Dependencies.unhook!
111
+ Dependencies.singleton_class.prepend(Decorations)
112
+ Object.prepend(RequireDependency)
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -35,7 +35,7 @@ module ActiveSupport
35
35
  # and the second is a library name.
36
36
  #
37
37
  # ActiveSupport::Deprecation.new('2.0', 'MyLibrary')
38
- def initialize(deprecation_horizon = "6.0", gem_name = "Rails")
38
+ def initialize(deprecation_horizon = "6.1", gem_name = "Rails")
39
39
  self.gem_name = gem_name
40
40
  self.deprecation_horizon = deprecation_horizon
41
41
  # By default, warnings are not silenced and debugging is off.
@@ -43,7 +43,7 @@ module ActiveSupport
43
43
  deprecation_horizon: deprecation_horizon)
44
44
  },
45
45
 
46
- silence: ->(message, callstack, deprecation_horizon, gem_name) {},
46
+ silence: ->(message, callstack, deprecation_horizon, gem_name) { },
47
47
  }
48
48
 
49
49
  # Behavior module allows to determine how to display deprecation messages.
@@ -94,6 +94,10 @@ module ActiveSupport
94
94
 
95
95
  private
96
96
  def arity_coerce(behavior)
97
+ unless behavior.respond_to?(:call)
98
+ raise ArgumentError, "#{behavior.inspect} is not a valid deprecation behavior."
99
+ end
100
+
97
101
  if behavior.arity == 4 || behavior.arity == -1
98
102
  behavior
99
103
  else
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/module/aliasing"
4
3
  require "active_support/core_ext/array/extract_options"
4
+ require "active_support/core_ext/module/redefine_method"
5
5
 
6
6
  module ActiveSupport
7
7
  class Deprecation
@@ -53,24 +53,31 @@ module ActiveSupport
53
53
  options = method_names.extract_options!
54
54
  deprecator = options.delete(:deprecator) || self
55
55
  method_names += options.keys
56
+ mod = nil
56
57
 
57
- mod = Module.new do
58
- method_names.each do |method_name|
59
- define_method(method_name) do |*args, &block|
60
- deprecator.deprecation_warning(method_name, options[method_name])
61
- super(*args, &block)
58
+ method_names.each do |method_name|
59
+ if target_module.method_defined?(method_name) || target_module.private_method_defined?(method_name)
60
+ method = target_module.instance_method(method_name)
61
+ target_module.module_eval do
62
+ redefine_method(method_name) do |*args, &block|
63
+ deprecator.deprecation_warning(method_name, options[method_name])
64
+ method.bind(self).call(*args, &block)
65
+ end
66
+ ruby2_keywords(method_name) if respond_to?(:ruby2_keywords, true)
62
67
  end
63
-
64
- case
65
- when target_module.protected_method_defined?(method_name)
66
- protected method_name
67
- when target_module.private_method_defined?(method_name)
68
- private method_name
68
+ else
69
+ mod ||= Module.new
70
+ mod.module_eval do
71
+ define_method(method_name) do |*args, &block|
72
+ deprecator.deprecation_warning(method_name, options[method_name])
73
+ super(*args, &block)
74
+ end
75
+ ruby2_keywords(method_name) if respond_to?(:ruby2_keywords, true)
69
76
  end
70
77
  end
71
78
  end
72
79
 
73
- target_module.prepend(mod)
80
+ target_module.prepend(mod) if mod
74
81
  end
75
82
  end
76
83
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/regexp"
4
-
5
3
  module ActiveSupport
6
4
  class Deprecation
7
5
  class DeprecationProxy #:nodoc:
@@ -122,7 +120,14 @@ module ActiveSupport
122
120
  # # => DEPRECATION WARNING: PLANETS is deprecated! Use PLANETS_POST_2006 instead.
123
121
  # (Backtrace information…)
124
122
  # ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
125
- class DeprecatedConstantProxy < DeprecationProxy
123
+ class DeprecatedConstantProxy < Module
124
+ def self.new(*args, **kwargs, &block)
125
+ object = args.first
126
+
127
+ return object unless object
128
+ super
129
+ end
130
+
126
131
  def initialize(old_const, new_const, deprecator = ActiveSupport::Deprecation.instance, message: "#{old_const} is deprecated! Use #{new_const} instead.")
127
132
  require "active_support/inflector/methods"
128
133
 
@@ -132,6 +137,18 @@ module ActiveSupport
132
137
  @message = message
133
138
  end
134
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
+
148
+ # Don't give a deprecation warning on methods that IRB may invoke
149
+ # during tab-completion.
150
+ delegate :hash, :instance_methods, :name, to: :target
151
+
135
152
  # Returns the class of the new constant.
136
153
  #
137
154
  # PLANETS_POST_2006 = %w(mercury venus earth mars jupiter saturn uranus neptune)
@@ -146,8 +163,14 @@ module ActiveSupport
146
163
  ActiveSupport::Inflector.constantize(@new_const.to_s)
147
164
  end
148
165
 
149
- def warn(callstack, called, args)
150
- @deprecator.warn(@message, callstack)
166
+ def const_missing(name)
167
+ @deprecator.warn(@message, caller_locations)
168
+ target.const_get(name)
169
+ end
170
+
171
+ def method_missing(called, *args, &block)
172
+ @deprecator.warn(@message, caller_locations)
173
+ target.__send__(called, *args, &block)
151
174
  end
152
175
  end
153
176
  end
@@ -104,7 +104,7 @@ module ActiveSupport
104
104
  end
105
105
  end
106
106
 
107
- RAILS_GEM_ROOT = File.expand_path("../../../..", __dir__)
107
+ RAILS_GEM_ROOT = File.expand_path("../../../..", __dir__) + "/"
108
108
 
109
109
  def ignored_callstack(path)
110
110
  path.start_with?(RAILS_GEM_ROOT) || path.start_with?(RbConfig::CONFIG["rubylibdir"])
@@ -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,16 +37,18 @@ 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
- def accumulate_descendants(klass, acc)
42
- if direct_descendants = @@direct_descendants[klass]
43
- acc.concat(direct_descendants)
44
- direct_descendants.each { |direct_descendant| accumulate_descendants(direct_descendant, acc) }
44
+ def accumulate_descendants(klass, acc)
45
+ if direct_descendants = @@direct_descendants[klass]
46
+ direct_descendants.each do |direct_descendant|
47
+ acc << direct_descendant
48
+ accumulate_descendants(direct_descendant, acc)
49
+ end
50
+ end
45
51
  end
46
- end
47
52
  end
48
53
 
49
54
  def inherited(base)
@@ -58,5 +63,46 @@ module ActiveSupport
58
63
  def descendants
59
64
  DescendantsTracker.descendants(self)
60
65
  end
66
+
67
+ # DescendantsArray is an array that contains weak references to classes.
68
+ class DescendantsArray # :nodoc:
69
+ include Enumerable
70
+
71
+ def initialize
72
+ @refs = []
73
+ end
74
+
75
+ def initialize_copy(orig)
76
+ @refs = @refs.dup
77
+ end
78
+
79
+ def <<(klass)
80
+ cleanup!
81
+ @refs << WeakRef.new(klass)
82
+ end
83
+
84
+ def each
85
+ @refs.each do |ref|
86
+ yield ref.__getobj__
87
+ rescue WeakRef::RefError
88
+ end
89
+ end
90
+
91
+ def refs_size
92
+ @refs.size
93
+ end
94
+
95
+ def cleanup!
96
+ @refs.delete_if { |ref| !ref.weakref_alive? }
97
+ end
98
+
99
+ def reject!
100
+ @refs.reject! do |ref|
101
+ yield ref.__getobj__
102
+ rescue WeakRef::RefError
103
+ true
104
+ end
105
+ end
106
+ end
61
107
  end
62
108
  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
@@ -183,15 +182,15 @@ module ActiveSupport
183
182
  #
184
183
  def build(value)
185
184
  parts = {}
186
- remainder = value.to_f
185
+ remainder = value.round(9)
187
186
 
188
187
  PARTS.each do |part|
189
188
  unless part == :seconds
190
189
  part_in_seconds = PARTS_IN_SECONDS[part]
191
190
  parts[part] = remainder.div(part_in_seconds)
192
- remainder = (remainder % part_in_seconds).round(9)
191
+ remainder %= part_in_seconds
193
192
  end
194
- end
193
+ end unless value == 0
195
194
 
196
195
  parts[:seconds] = remainder
197
196
 
@@ -199,7 +198,6 @@ module ActiveSupport
199
198
  end
200
199
 
201
200
  private
202
-
203
201
  def calculate_total_seconds(parts)
204
202
  parts.inject(0) do |total, (part, value)|
205
203
  total + value * PARTS_IN_SECONDS[part]
@@ -210,12 +208,15 @@ module ActiveSupport
210
208
  def initialize(value, parts) #:nodoc:
211
209
  @value, @parts = value, parts.to_h
212
210
  @parts.default = 0
213
- @parts.reject! { |k, v| v.zero? }
211
+ @parts.reject! { |k, v| v.zero? } unless value == 0
214
212
  end
215
213
 
216
214
  def coerce(other) #:nodoc:
217
- if Scalar === other
215
+ case other
216
+ when Scalar
218
217
  [other, self]
218
+ when Duration
219
+ [Scalar.new(other.value), self]
219
220
  else
220
221
  [Scalar.new(other), self]
221
222
  end
@@ -336,8 +337,8 @@ module ActiveSupport
336
337
  # 1.year.to_i # => 31556952
337
338
  #
338
339
  # In such cases, Ruby's core
339
- # Date[http://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html] and
340
- # Time[http://ruby-doc.org/stdlib/libdoc/time/rdoc/Time.html] should be used for precision
340
+ # Date[https://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html] and
341
+ # Time[https://ruby-doc.org/stdlib/libdoc/time/rdoc/Time.html] should be used for precision
341
342
  # date and time arithmetic.
342
343
  def to_i
343
344
  @value.to_i
@@ -370,10 +371,9 @@ module ActiveSupport
370
371
  alias :before :ago
371
372
 
372
373
  def inspect #:nodoc:
373
- return "0 seconds" if parts.empty?
374
+ return "#{value} seconds" if parts.empty?
374
375
 
375
376
  parts.
376
- reduce(::Hash.new(0)) { |h, (l, r)| h[l] += r; h }.
377
377
  sort_by { |unit, _ | PARTS.index(unit) }.
378
378
  map { |unit, val| "#{val} #{val == 1 ? unit.to_s.chop : unit.to_s}" }.
379
379
  to_sentence(locale: ::I18n.default_locale)
@@ -398,10 +398,15 @@ module ActiveSupport
398
398
  end
399
399
 
400
400
  private
401
-
402
401
  def sum(sign, time = ::Time.current)
403
- parts.inject(time) do |t, (type, number)|
404
- if t.acts_like?(:time) || t.acts_like?(:date)
402
+ unless time.acts_like?(:time) || time.acts_like?(:date)
403
+ raise ::ArgumentError, "expected a time or date, got #{time.inspect}"
404
+ end
405
+
406
+ if parts.empty?
407
+ time.since(sign * value)
408
+ else
409
+ parts.inject(time) do |t, (type, number)|
405
410
  if type == :seconds
406
411
  t.since(sign * number)
407
412
  elsif type == :minutes
@@ -411,8 +416,6 @@ module ActiveSupport
411
416
  else
412
417
  t.advance(type => sign * number)
413
418
  end
414
- else
415
- raise ::ArgumentError, "expected a time or date, got #{time.inspect}"
416
419
  end
417
420
  end
418
421
  end