activesupport 6.1.5 → 7.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (129) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +151 -584
  3. data/MIT-LICENSE +1 -1
  4. data/lib/active_support/actionable_error.rb +1 -1
  5. data/lib/active_support/array_inquirer.rb +0 -2
  6. data/lib/active_support/benchmarkable.rb +2 -2
  7. data/lib/active_support/cache/file_store.rb +15 -9
  8. data/lib/active_support/cache/mem_cache_store.rb +119 -28
  9. data/lib/active_support/cache/memory_store.rb +21 -13
  10. data/lib/active_support/cache/null_store.rb +10 -2
  11. data/lib/active_support/cache/redis_cache_store.rb +39 -59
  12. data/lib/active_support/cache/strategy/local_cache.rb +29 -49
  13. data/lib/active_support/cache.rb +189 -45
  14. data/lib/active_support/callbacks.rb +35 -31
  15. data/lib/active_support/concern.rb +5 -5
  16. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
  17. data/lib/active_support/concurrency/share_lock.rb +2 -2
  18. data/lib/active_support/configurable.rb +6 -3
  19. data/lib/active_support/configuration_file.rb +1 -1
  20. data/lib/active_support/core_ext/array/access.rb +1 -5
  21. data/lib/active_support/core_ext/array/conversions.rb +6 -6
  22. data/lib/active_support/core_ext/array/grouping.rb +6 -6
  23. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  24. data/lib/active_support/core_ext/date/blank.rb +1 -1
  25. data/lib/active_support/core_ext/date/calculations.rb +2 -2
  26. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  27. data/lib/active_support/core_ext/digest/uuid.rb +13 -13
  28. data/lib/active_support/core_ext/enumerable.rb +64 -12
  29. data/lib/active_support/core_ext/file/atomic.rb +1 -1
  30. data/lib/active_support/core_ext/hash/keys.rb +1 -1
  31. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  32. data/lib/active_support/core_ext/module/delegation.rb +2 -8
  33. data/lib/active_support/core_ext/name_error.rb +2 -8
  34. data/lib/active_support/core_ext/numeric/conversions.rb +2 -2
  35. data/lib/active_support/core_ext/object/blank.rb +2 -2
  36. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  37. data/lib/active_support/core_ext/object/duplicable.rb +11 -0
  38. data/lib/active_support/core_ext/object/json.rb +29 -24
  39. data/lib/active_support/core_ext/object/to_query.rb +2 -2
  40. data/lib/active_support/core_ext/object/try.rb +20 -20
  41. data/lib/active_support/core_ext/range/compare_range.rb +0 -25
  42. data/lib/active_support/core_ext/range/each.rb +1 -1
  43. data/lib/active_support/core_ext/range/include_time_with_zone.rb +1 -1
  44. data/lib/active_support/core_ext/string/filters.rb +1 -1
  45. data/lib/active_support/core_ext/string/inflections.rb +1 -1
  46. data/lib/active_support/core_ext/string/output_safety.rb +60 -36
  47. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
  48. data/lib/active_support/core_ext/time/calculations.rb +4 -5
  49. data/lib/active_support/core_ext/time/zones.rb +2 -17
  50. data/lib/active_support/core_ext/uri.rb +0 -14
  51. data/lib/active_support/current_attributes.rb +17 -1
  52. data/lib/active_support/dependencies/interlock.rb +10 -18
  53. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  54. data/lib/active_support/dependencies.rb +58 -788
  55. data/lib/active_support/deprecation/behaviors.rb +4 -1
  56. data/lib/active_support/deprecation/method_wrappers.rb +3 -3
  57. data/lib/active_support/deprecation/proxy_wrappers.rb +1 -1
  58. data/lib/active_support/deprecation.rb +1 -1
  59. data/lib/active_support/descendants_tracker.rb +12 -9
  60. data/lib/active_support/digest.rb +4 -4
  61. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  62. data/lib/active_support/duration/iso8601_serializer.rb +9 -1
  63. data/lib/active_support/duration.rb +80 -52
  64. data/lib/active_support/encrypted_configuration.rb +11 -1
  65. data/lib/active_support/encrypted_file.rb +1 -1
  66. data/lib/active_support/environment_inquirer.rb +1 -1
  67. data/lib/active_support/evented_file_update_checker.rb +1 -1
  68. data/lib/active_support/execution_wrapper.rb +13 -16
  69. data/lib/active_support/fork_tracker.rb +2 -4
  70. data/lib/active_support/gem_version.rb +4 -4
  71. data/lib/active_support/hash_with_indifferent_access.rb +3 -1
  72. data/lib/active_support/i18n.rb +1 -0
  73. data/lib/active_support/inflector/inflections.rb +11 -4
  74. data/lib/active_support/inflector/methods.rb +23 -47
  75. data/lib/active_support/json/encoding.rb +3 -3
  76. data/lib/active_support/key_generator.rb +18 -1
  77. data/lib/active_support/locale/en.yml +1 -1
  78. data/lib/active_support/log_subscriber.rb +13 -3
  79. data/lib/active_support/logger_thread_safe_level.rb +5 -13
  80. data/lib/active_support/message_encryptor.rb +3 -3
  81. data/lib/active_support/message_verifier.rb +4 -4
  82. data/lib/active_support/messages/metadata.rb +2 -2
  83. data/lib/active_support/multibyte/chars.rb +10 -11
  84. data/lib/active_support/multibyte.rb +1 -1
  85. data/lib/active_support/notifications/fanout.rb +31 -11
  86. data/lib/active_support/notifications/instrumenter.rb +17 -0
  87. data/lib/active_support/notifications.rb +10 -0
  88. data/lib/active_support/number_helper/number_converter.rb +1 -3
  89. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  90. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  91. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  92. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
  93. data/lib/active_support/number_helper/rounding_helper.rb +1 -5
  94. data/lib/active_support/number_helper.rb +0 -2
  95. data/lib/active_support/option_merger.rb +4 -16
  96. data/lib/active_support/ordered_hash.rb +1 -1
  97. data/lib/active_support/parameter_filter.rb +5 -0
  98. data/lib/active_support/per_thread_registry.rb +1 -1
  99. data/lib/active_support/railtie.rb +33 -10
  100. data/lib/active_support/reloader.rb +1 -1
  101. data/lib/active_support/rescuable.rb +2 -2
  102. data/lib/active_support/secure_compare_rotator.rb +1 -1
  103. data/lib/active_support/string_inquirer.rb +0 -2
  104. data/lib/active_support/subscriber.rb +5 -0
  105. data/lib/active_support/test_case.rb +9 -21
  106. data/lib/active_support/testing/assertions.rb +34 -4
  107. data/lib/active_support/testing/deprecation.rb +1 -1
  108. data/lib/active_support/testing/isolation.rb +1 -1
  109. data/lib/active_support/testing/method_call_assertions.rb +5 -5
  110. data/lib/active_support/testing/parallelization/server.rb +4 -0
  111. data/lib/active_support/testing/parallelization/worker.rb +3 -0
  112. data/lib/active_support/testing/parallelization.rb +4 -0
  113. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  114. data/lib/active_support/testing/stream.rb +3 -5
  115. data/lib/active_support/testing/tagged_logging.rb +1 -1
  116. data/lib/active_support/testing/time_helpers.rb +13 -2
  117. data/lib/active_support/time_with_zone.rb +19 -6
  118. data/lib/active_support/values/time_zone.rb +25 -11
  119. data/lib/active_support/xml_mini/jdom.rb +1 -1
  120. data/lib/active_support/xml_mini/libxml.rb +5 -5
  121. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  122. data/lib/active_support/xml_mini/nokogiri.rb +4 -4
  123. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  124. data/lib/active_support/xml_mini/rexml.rb +1 -1
  125. data/lib/active_support/xml_mini.rb +2 -1
  126. data/lib/active_support.rb +14 -1
  127. metadata +11 -26
  128. data/lib/active_support/core_ext/marshal.rb +0 -26
  129. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -120
@@ -54,7 +54,7 @@ module ActiveSupport
54
54
  # [+stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
55
55
  # [+log+] Log all deprecation warnings to +Rails.logger+.
56
56
  # [+notify+] Use +ActiveSupport::Notifications+ to notify +deprecation.rails+.
57
- # [+silence+] Do nothing.
57
+ # [+silence+] Do nothing. On Rails, set <tt>config.active_support.report_deprecations = false</tt> to disable all behaviors.
58
58
  #
59
59
  # Setting behaviors only affects deprecations that happen after boot time.
60
60
  # For more information you can read the documentation of the +behavior=+ method.
@@ -93,6 +93,9 @@ module ActiveSupport
93
93
  # ActiveSupport::Deprecation.behavior = ->(message, callstack, deprecation_horizon, gem_name) {
94
94
  # # custom stuff
95
95
  # }
96
+ #
97
+ # If you are using Rails, you can set <tt>config.active_support.report_deprecations = false</tt> to disable
98
+ # all deprecation behaviors. This is similar to the +silence+ option but more performant.
96
99
  def behavior=(behavior)
97
100
  @behavior = Array(behavior).map { |b| DEFAULT_BEHAVIORS[b] || arity_coerce(b) }
98
101
  end
@@ -62,9 +62,9 @@ module ActiveSupport
62
62
  target_module.module_eval do
63
63
  redefine_method(method_name) do |*args, &block|
64
64
  deprecator.deprecation_warning(method_name, message)
65
- method.bind(self).call(*args, &block)
65
+ method.bind_call(self, *args, &block)
66
66
  end
67
- ruby2_keywords(method_name) if respond_to?(:ruby2_keywords, true)
67
+ ruby2_keywords(method_name)
68
68
  end
69
69
  else
70
70
  mod ||= Module.new
@@ -73,7 +73,7 @@ module ActiveSupport
73
73
  deprecator.deprecation_warning(method_name, message)
74
74
  super(*args, &block)
75
75
  end
76
- ruby2_keywords(method_name) if respond_to?(:ruby2_keywords, true)
76
+ ruby2_keywords(method_name)
77
77
  end
78
78
  end
79
79
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module ActiveSupport
4
4
  class Deprecation
5
- class DeprecationProxy #:nodoc:
5
+ class DeprecationProxy # :nodoc:
6
6
  def self.new(*args, &block)
7
7
  object = args.first
8
8
 
@@ -38,7 +38,7 @@ module ActiveSupport
38
38
  # and the second is a library name.
39
39
  #
40
40
  # ActiveSupport::Deprecation.new('2.0', 'MyLibrary')
41
- def initialize(deprecation_horizon = "7.0", gem_name = "Rails")
41
+ def initialize(deprecation_horizon = "7.1", gem_name = "Rails")
42
42
  self.gem_name = gem_name
43
43
  self.deprecation_horizon = deprecation_horizon
44
44
  # By default, warnings are not silenced and debugging is off.
@@ -21,17 +21,20 @@ module ActiveSupport
21
21
  arr
22
22
  end
23
23
 
24
- def clear
25
- if defined? ActiveSupport::Dependencies
26
- @@direct_descendants.each do |klass, descendants|
27
- if Dependencies.autoloaded?(klass)
28
- @@direct_descendants.delete(klass)
29
- else
30
- descendants.reject! { |v| Dependencies.autoloaded?(v) }
24
+ def clear(only: nil)
25
+ if only.nil?
26
+ @@direct_descendants.clear
27
+ return
28
+ end
29
+
30
+ @@direct_descendants.each do |klass, direct_descendants_of_klass|
31
+ if only.member?(klass)
32
+ @@direct_descendants.delete(klass)
33
+ else
34
+ direct_descendants_of_klass.reject! do |direct_descendant_of_class|
35
+ only.member?(direct_descendant_of_class)
31
36
  end
32
37
  end
33
- else
34
- @@direct_descendants.clear
35
38
  end
36
39
  end
37
40
 
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "digest"
3
+ require "openssl"
4
4
 
5
5
  module ActiveSupport
6
- class Digest #:nodoc:
7
- class <<self
6
+ class Digest # :nodoc:
7
+ class << self
8
8
  def hash_digest_class
9
- @hash_digest_class ||= ::Digest::MD5
9
+ @hash_digest_class ||= OpenSSL::Digest::MD5
10
10
  end
11
11
 
12
12
  def hash_digest_class=(klass)
@@ -16,11 +16,11 @@ module ActiveSupport
16
16
  PERIOD = "."
17
17
  COMMA = ","
18
18
 
19
- SIGN_MARKER = /\A\-|\+|/
19
+ SIGN_MARKER = /\A-|\+|/
20
20
  DATE_MARKER = /P/
21
21
  TIME_MARKER = /T/
22
- DATE_COMPONENT = /(\-?\d+(?:[.,]\d+)?)(Y|M|D|W)/
23
- TIME_COMPONENT = /(\-?\d+(?:[.,]\d+)?)(H|M|S)/
22
+ DATE_COMPONENT = /(-?\d+(?:[.,]\d+)?)(Y|M|D|W)/
23
+ TIME_COMPONENT = /(-?\d+(?:[.,]\d+)?)(H|M|S)/
24
24
 
25
25
  DATE_TO_PART = { "Y" => :years, "M" => :months, "W" => :weeks, "D" => :days }
26
26
  TIME_TO_PART = { "H" => :hours, "M" => :minutes, "S" => :seconds }
@@ -27,7 +27,7 @@ module ActiveSupport
27
27
  time << "#{parts[:hours]}H" if parts.key?(:hours)
28
28
  time << "#{parts[:minutes]}M" if parts.key?(:minutes)
29
29
  if parts.key?(:seconds)
30
- time << "#{sprintf(@precision ? "%0.0#{@precision}f" : '%g', parts[:seconds])}S"
30
+ time << "#{format_seconds(parts[:seconds])}S"
31
31
  end
32
32
  output << "T#{time}" unless time.empty?
33
33
  output
@@ -54,6 +54,14 @@ module ActiveSupport
54
54
  def week_mixed_with_date?(parts)
55
55
  parts.key?(:weeks) && (parts.keys & DATE_COMPONENTS).any?
56
56
  end
57
+
58
+ def format_seconds(seconds)
59
+ if @precision
60
+ sprintf("%0.0#{@precision}f", seconds)
61
+ else
62
+ seconds.to_s
63
+ end
64
+ end
57
65
  end
58
66
  end
59
67
  end
@@ -11,7 +11,7 @@ module ActiveSupport
11
11
  #
12
12
  # 1.month.ago # equivalent to Time.now.advance(months: -1)
13
13
  class Duration
14
- class Scalar < Numeric #:nodoc:
14
+ class Scalar < Numeric # :nodoc:
15
15
  attr_reader :value
16
16
  delegate :to_i, :to_f, :to_s, to: :value
17
17
 
@@ -39,11 +39,11 @@ module ActiveSupport
39
39
 
40
40
  def +(other)
41
41
  if Duration === other
42
- seconds = value + other.parts.fetch(:seconds, 0)
43
- new_parts = other.parts.merge(seconds: seconds)
42
+ seconds = value + other._parts.fetch(:seconds, 0)
43
+ new_parts = other._parts.merge(seconds: seconds)
44
44
  new_value = value + other.value
45
45
 
46
- Duration.new(new_value, new_parts)
46
+ Duration.new(new_value, new_parts, other.variable?)
47
47
  else
48
48
  calculate(:+, other)
49
49
  end
@@ -51,12 +51,12 @@ module ActiveSupport
51
51
 
52
52
  def -(other)
53
53
  if Duration === other
54
- seconds = value - other.parts.fetch(:seconds, 0)
55
- new_parts = other.parts.transform_values(&:-@)
54
+ seconds = value - other._parts.fetch(:seconds, 0)
55
+ new_parts = other._parts.transform_values(&:-@)
56
56
  new_parts = new_parts.merge(seconds: seconds)
57
57
  new_value = value - other.value
58
58
 
59
- Duration.new(new_value, new_parts)
59
+ Duration.new(new_value, new_parts, other.variable?)
60
60
  else
61
61
  calculate(:-, other)
62
62
  end
@@ -64,10 +64,10 @@ module ActiveSupport
64
64
 
65
65
  def *(other)
66
66
  if Duration === other
67
- new_parts = other.parts.transform_values { |other_value| value * other_value }
67
+ new_parts = other._parts.transform_values { |other_value| value * other_value }
68
68
  new_value = value * other.value
69
69
 
70
- Duration.new(new_value, new_parts)
70
+ Duration.new(new_value, new_parts, other.variable?)
71
71
  else
72
72
  calculate(:*, other)
73
73
  end
@@ -89,6 +89,10 @@ module ActiveSupport
89
89
  end
90
90
  end
91
91
 
92
+ def variable? # :nodoc:
93
+ false
94
+ end
95
+
92
96
  private
93
97
  def calculate(op, other)
94
98
  if Scalar === other
@@ -123,8 +127,9 @@ module ActiveSupport
123
127
  }.freeze
124
128
 
125
129
  PARTS = [:years, :months, :weeks, :days, :hours, :minutes, :seconds].freeze
130
+ VARIABLE_PARTS = [:years, :months, :weeks, :days].freeze
126
131
 
127
- attr_accessor :value, :parts
132
+ attr_reader :value
128
133
 
129
134
  autoload :ISO8601Parser, "active_support/duration/iso8601_parser"
130
135
  autoload :ISO8601Serializer, "active_support/duration/iso8601_serializer"
@@ -140,38 +145,38 @@ module ActiveSupport
140
145
  new(calculate_total_seconds(parts), parts)
141
146
  end
142
147
 
143
- def ===(other) #:nodoc:
148
+ def ===(other) # :nodoc:
144
149
  other.is_a?(Duration)
145
150
  rescue ::NoMethodError
146
151
  false
147
152
  end
148
153
 
149
- def seconds(value) #:nodoc:
150
- new(value, seconds: value)
154
+ def seconds(value) # :nodoc:
155
+ new(value, { seconds: value }, false)
151
156
  end
152
157
 
153
- def minutes(value) #:nodoc:
154
- new(value * SECONDS_PER_MINUTE, minutes: value)
158
+ def minutes(value) # :nodoc:
159
+ new(value * SECONDS_PER_MINUTE, { minutes: value }, false)
155
160
  end
156
161
 
157
- def hours(value) #:nodoc:
158
- new(value * SECONDS_PER_HOUR, hours: value)
162
+ def hours(value) # :nodoc:
163
+ new(value * SECONDS_PER_HOUR, { hours: value }, false)
159
164
  end
160
165
 
161
- def days(value) #:nodoc:
162
- new(value * SECONDS_PER_DAY, days: value)
166
+ def days(value) # :nodoc:
167
+ new(value * SECONDS_PER_DAY, { days: value }, true)
163
168
  end
164
169
 
165
- def weeks(value) #:nodoc:
166
- new(value * SECONDS_PER_WEEK, weeks: value)
170
+ def weeks(value) # :nodoc:
171
+ new(value * SECONDS_PER_WEEK, { weeks: value }, true)
167
172
  end
168
173
 
169
- def months(value) #:nodoc:
170
- new(value * SECONDS_PER_MONTH, months: value)
174
+ def months(value) # :nodoc:
175
+ new(value * SECONDS_PER_MONTH, { months: value }, true)
171
176
  end
172
177
 
173
- def years(value) #:nodoc:
174
- new(value * SECONDS_PER_YEAR, years: value)
178
+ def years(value) # :nodoc:
179
+ new(value * SECONDS_PER_YEAR, { years: value }, true)
175
180
  end
176
181
 
177
182
  # Creates a new Duration from a seconds value that is converted
@@ -186,20 +191,24 @@ module ActiveSupport
186
191
  end
187
192
 
188
193
  parts = {}
189
- remainder_sign = value <=> 0
190
- remainder = value.round(9).abs
194
+ remainder = value.round(9)
195
+ variable = false
191
196
 
192
197
  PARTS.each do |part|
193
198
  unless part == :seconds
194
199
  part_in_seconds = PARTS_IN_SECONDS[part]
195
- parts[part] = remainder.div(part_in_seconds) * remainder_sign
200
+ parts[part] = remainder.div(part_in_seconds)
196
201
  remainder %= part_in_seconds
202
+
203
+ unless parts[part].zero?
204
+ variable ||= VARIABLE_PARTS.include?(part)
205
+ end
197
206
  end
198
207
  end unless value == 0
199
208
 
200
- parts[:seconds] = remainder * remainder_sign
209
+ parts[:seconds] = remainder
201
210
 
202
- new(value, parts)
211
+ new(value, parts, variable)
203
212
  end
204
213
 
205
214
  private
@@ -210,12 +219,23 @@ module ActiveSupport
210
219
  end
211
220
  end
212
221
 
213
- def initialize(value, parts) #:nodoc:
222
+ def initialize(value, parts, variable = nil) # :nodoc:
214
223
  @value, @parts = value, parts
215
224
  @parts.reject! { |k, v| v.zero? } unless value == 0
225
+ @parts.freeze
226
+ @variable = variable
227
+
228
+ if @variable.nil?
229
+ @variable = @parts.any? { |part, _| VARIABLE_PARTS.include?(part) }
230
+ end
216
231
  end
217
232
 
218
- def coerce(other) #:nodoc:
233
+ # Returns a copy of the parts hash that defines the duration
234
+ def parts
235
+ @parts.dup
236
+ end
237
+
238
+ def coerce(other) # :nodoc:
219
239
  case other
220
240
  when Scalar
221
241
  [other, self]
@@ -240,13 +260,13 @@ module ActiveSupport
240
260
  # are treated as seconds.
241
261
  def +(other)
242
262
  if Duration === other
243
- parts = @parts.merge(other.parts) do |_key, value, other_value|
263
+ parts = @parts.merge(other._parts) do |_key, value, other_value|
244
264
  value + other_value
245
265
  end
246
- Duration.new(value + other.value, parts)
266
+ Duration.new(value + other.value, parts, @variable || other.variable?)
247
267
  else
248
268
  seconds = @parts.fetch(:seconds, 0) + other
249
- Duration.new(value + other, @parts.merge(seconds: seconds))
269
+ Duration.new(value + other, @parts.merge(seconds: seconds), @variable)
250
270
  end
251
271
  end
252
272
 
@@ -259,9 +279,9 @@ module ActiveSupport
259
279
  # Multiplies this Duration by a Numeric and returns a new Duration.
260
280
  def *(other)
261
281
  if Scalar === other || Duration === other
262
- Duration.new(value * other.value, parts.transform_values { |number| number * other.value })
282
+ Duration.new(value * other.value, @parts.transform_values { |number| number * other.value }, @variable || other.variable?)
263
283
  elsif Numeric === other
264
- Duration.new(value * other, parts.transform_values { |number| number * other })
284
+ Duration.new(value * other, @parts.transform_values { |number| number * other }, @variable)
265
285
  else
266
286
  raise_type_error(other)
267
287
  end
@@ -270,11 +290,11 @@ module ActiveSupport
270
290
  # Divides this Duration by a Numeric and returns a new Duration.
271
291
  def /(other)
272
292
  if Scalar === other
273
- Duration.new(value / other.value, parts.transform_values { |number| number / other.value })
293
+ Duration.new(value / other.value, @parts.transform_values { |number| number / other.value }, @variable)
274
294
  elsif Duration === other
275
295
  value / other.value
276
296
  elsif Numeric === other
277
- Duration.new(value / other, parts.transform_values { |number| number / other })
297
+ Duration.new(value / other, @parts.transform_values { |number| number / other }, @variable)
278
298
  else
279
299
  raise_type_error(other)
280
300
  end
@@ -292,15 +312,15 @@ module ActiveSupport
292
312
  end
293
313
  end
294
314
 
295
- def -@ #:nodoc:
296
- Duration.new(-value, parts.transform_values(&:-@))
315
+ def -@ # :nodoc:
316
+ Duration.new(-value, @parts.transform_values(&:-@), @variable)
297
317
  end
298
318
 
299
- def +@ #:nodoc:
319
+ def +@ # :nodoc:
300
320
  self
301
321
  end
302
322
 
303
- def is_a?(klass) #:nodoc:
323
+ def is_a?(klass) # :nodoc:
304
324
  Duration == klass || value.is_a?(klass)
305
325
  end
306
326
  alias :kind_of? :is_a?
@@ -420,24 +440,24 @@ module ActiveSupport
420
440
  alias :until :ago
421
441
  alias :before :ago
422
442
 
423
- def inspect #:nodoc:
424
- return "#{value} seconds" if parts.empty?
443
+ def inspect # :nodoc:
444
+ return "#{value} seconds" if @parts.empty?
425
445
 
426
- parts.
446
+ @parts.
427
447
  sort_by { |unit, _ | PARTS.index(unit) }.
428
448
  map { |unit, val| "#{val} #{val == 1 ? unit.to_s.chop : unit.to_s}" }.
429
- to_sentence(locale: ::I18n.default_locale)
449
+ to_sentence(locale: false)
430
450
  end
431
451
 
432
- def as_json(options = nil) #:nodoc:
452
+ def as_json(options = nil) # :nodoc:
433
453
  to_i
434
454
  end
435
455
 
436
- def init_with(coder) #:nodoc:
456
+ def init_with(coder) # :nodoc:
437
457
  initialize(coder["value"], coder["parts"])
438
458
  end
439
459
 
440
- def encode_with(coder) #:nodoc:
460
+ def encode_with(coder) # :nodoc:
441
461
  coder.map = { "value" => @value, "parts" => @parts }
442
462
  end
443
463
 
@@ -447,16 +467,24 @@ module ActiveSupport
447
467
  ISO8601Serializer.new(self, precision: precision).serialize
448
468
  end
449
469
 
470
+ def variable? # :nodoc:
471
+ @variable
472
+ end
473
+
474
+ def _parts # :nodoc:
475
+ @parts
476
+ end
477
+
450
478
  private
451
479
  def sum(sign, time = ::Time.current)
452
480
  unless time.acts_like?(:time) || time.acts_like?(:date)
453
481
  raise ::ArgumentError, "expected a time or date, got #{time.inspect}"
454
482
  end
455
483
 
456
- if parts.empty?
484
+ if @parts.empty?
457
485
  time.since(sign * value)
458
486
  else
459
- parts.inject(time) do |t, (type, number)|
487
+ @parts.inject(time) do |t, (type, number)|
460
488
  if type == :seconds
461
489
  t.since(sign * number)
462
490
  elsif type == :minutes
@@ -34,8 +34,18 @@ module ActiveSupport
34
34
  end
35
35
 
36
36
  private
37
+ def deep_transform(hash)
38
+ return hash unless hash.is_a?(Hash)
39
+
40
+ h = ActiveSupport::InheritableOptions.new
41
+ hash.each do |k, v|
42
+ h[k] = deep_transform(v)
43
+ end
44
+ h
45
+ end
46
+
37
47
  def options
38
- @options ||= ActiveSupport::InheritableOptions.new(config)
48
+ @options ||= ActiveSupport::InheritableOptions.new(deep_transform(config))
39
49
  end
40
50
 
41
51
  def deserialize(config)
@@ -98,7 +98,7 @@ module ActiveSupport
98
98
 
99
99
 
100
100
  def read_env_key
101
- ENV[env_key]
101
+ ENV[env_key].presence
102
102
  end
103
103
 
104
104
  def read_key_file
@@ -3,7 +3,7 @@
3
3
  require "active_support/string_inquirer"
4
4
 
5
5
  module ActiveSupport
6
- class EnvironmentInquirer < StringInquirer #:nodoc:
6
+ class EnvironmentInquirer < StringInquirer # :nodoc:
7
7
  DEFAULT_ENVIRONMENTS = ["development", "test", "production"]
8
8
  def initialize(env)
9
9
  super(env)
@@ -34,7 +34,7 @@ module ActiveSupport
34
34
  # checker.execute_if_updated
35
35
  # # => "changed"
36
36
  #
37
- class EventedFileUpdateChecker #:nodoc: all
37
+ class EventedFileUpdateChecker # :nodoc: all
38
38
  def initialize(files, dirs = {}, &block)
39
39
  unless block
40
40
  raise ArgumentError, "A block is required to initialize an EventedFileUpdateChecker"
@@ -63,21 +63,18 @@ module ActiveSupport
63
63
  # after the work has been performed.
64
64
  #
65
65
  # Where possible, prefer +wrap+.
66
- def self.run!(reset: false)
67
- if reset
68
- lost_instance = active.delete(Thread.current)
69
- lost_instance&.complete!
66
+ def self.run!
67
+ if active?
68
+ Null
70
69
  else
71
- return Null if active?
72
- end
73
-
74
- new.tap do |instance|
75
- success = nil
76
- begin
77
- instance.run!
78
- success = true
79
- ensure
80
- instance.complete! unless success
70
+ new.tap do |instance|
71
+ success = nil
72
+ begin
73
+ instance.run!
74
+ success = true
75
+ ensure
76
+ instance.complete! unless success
77
+ end
81
78
  end
82
79
  end
83
80
  end
@@ -106,11 +103,11 @@ module ActiveSupport
106
103
  self.active = Concurrent::Hash.new
107
104
 
108
105
  def self.active? # :nodoc:
109
- @active.key?(Thread.current)
106
+ @active[Thread.current]
110
107
  end
111
108
 
112
109
  def run! # :nodoc:
113
- self.class.active[Thread.current] = self
110
+ self.class.active[Thread.current] = true
114
111
  run_callbacks(:run)
115
112
  end
116
113
 
@@ -3,7 +3,7 @@
3
3
  module ActiveSupport
4
4
  module ForkTracker # :nodoc:
5
5
  module CoreExt
6
- def fork(*)
6
+ def fork(...)
7
7
  if block_given?
8
8
  super do
9
9
  ForkTracker.check!
@@ -16,17 +16,15 @@ module ActiveSupport
16
16
  pid
17
17
  end
18
18
  end
19
- ruby2_keywords(:fork) if respond_to?(:ruby2_keywords, true)
20
19
  end
21
20
 
22
21
  module CoreExtPrivate
23
22
  include CoreExt
24
23
 
25
24
  private
26
- def fork(*)
25
+ def fork(...)
27
26
  super
28
27
  end
29
- ruby2_keywords(:fork) if respond_to?(:ruby2_keywords, true)
30
28
  end
31
29
 
32
30
  @pid = Process.pid
@@ -7,10 +7,10 @@ module ActiveSupport
7
7
  end
8
8
 
9
9
  module VERSION
10
- MAJOR = 6
11
- MINOR = 1
12
- TINY = 5
13
- PRE = nil
10
+ MAJOR = 7
11
+ MINOR = 0
12
+ TINY = 0
13
+ PRE = "alpha1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -65,7 +65,7 @@ module ActiveSupport
65
65
  self
66
66
  end
67
67
 
68
- def initialize(constructor = {})
68
+ def initialize(constructor = nil)
69
69
  if constructor.respond_to?(:to_hash)
70
70
  super()
71
71
  update(constructor)
@@ -73,6 +73,8 @@ module ActiveSupport
73
73
  hash = constructor.is_a?(Hash) ? constructor : constructor.to_hash
74
74
  self.default = hash.default if hash.default
75
75
  self.default_proc = hash.default_proc if hash.default_proc
76
+ elsif constructor.nil?
77
+ super()
76
78
  else
77
79
  super(constructor)
78
80
  end
@@ -5,6 +5,7 @@ require "active_support/core_ext/hash/except"
5
5
  require "active_support/core_ext/hash/slice"
6
6
  begin
7
7
  require "i18n"
8
+ require "i18n/backend/fallbacks"
8
9
  rescue LoadError => e
9
10
  $stderr.puts "The i18n gem is not available. Please add it to your Gemfile and run bundle install"
10
11
  raise e
@@ -16,13 +16,13 @@ module ActiveSupport
16
16
  # inflect.plural /^(ox)$/i, '\1\2en'
17
17
  # inflect.singular /^(ox)en/i, '\1'
18
18
  #
19
- # inflect.irregular 'octopus', 'octopi'
19
+ # inflect.irregular 'cactus', 'cacti'
20
20
  #
21
21
  # inflect.uncountable 'equipment'
22
22
  # end
23
23
  #
24
24
  # New rules are added at the top. So in the example above, the irregular
25
- # rule for octopus will now be the first of the pluralization and
25
+ # rule for cactus will now be the first of the pluralization and
26
26
  # singularization rules that is runs. This guarantees that your rules run
27
27
  # before any of the rules that may already have been loaded.
28
28
  class Inflections
@@ -64,6 +64,13 @@ module ActiveSupport
64
64
  @__instance__[locale] ||= new
65
65
  end
66
66
 
67
+ def self.instance_or_fallback(locale)
68
+ I18n.fallbacks[locale].each do |k|
69
+ return @__instance__[k] if @__instance__.key?(k)
70
+ end
71
+ instance(locale)
72
+ end
73
+
67
74
  attr_reader :plurals, :singulars, :uncountables, :humans, :acronyms
68
75
 
69
76
  attr_reader :acronyms_camelize_regex, :acronyms_underscore_regex # :nodoc:
@@ -160,7 +167,7 @@ module ActiveSupport
160
167
  # regular expressions. You simply pass the irregular in singular and
161
168
  # plural form.
162
169
  #
163
- # irregular 'octopus', 'octopi'
170
+ # irregular 'cactus', 'cacti'
164
171
  # irregular 'person', 'people'
165
172
  def irregular(singular, plural)
166
173
  @uncountables.delete(singular)
@@ -248,7 +255,7 @@ module ActiveSupport
248
255
  if block_given?
249
256
  yield Inflections.instance(locale)
250
257
  else
251
- Inflections.instance(locale)
258
+ Inflections.instance_or_fallback(locale)
252
259
  end
253
260
  end
254
261
  end