activesupport 6.1.4.6 → 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 (131) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +151 -551
  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 -12
  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 +6 -5
  49. data/lib/active_support/core_ext/time/zones.rb +2 -17
  50. data/lib/active_support/core_ext/uri.rb +1 -15
  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 +5 -3
  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 +77 -48
  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/unicode.rb +2 -2
  85. data/lib/active_support/multibyte.rb +1 -1
  86. data/lib/active_support/notifications/fanout.rb +31 -11
  87. data/lib/active_support/notifications/instrumenter.rb +17 -0
  88. data/lib/active_support/notifications.rb +10 -0
  89. data/lib/active_support/number_helper/number_converter.rb +1 -3
  90. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  91. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  92. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  93. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
  94. data/lib/active_support/number_helper/rounding_helper.rb +1 -5
  95. data/lib/active_support/number_helper.rb +0 -2
  96. data/lib/active_support/option_merger.rb +4 -16
  97. data/lib/active_support/ordered_hash.rb +1 -1
  98. data/lib/active_support/parameter_filter.rb +5 -0
  99. data/lib/active_support/per_thread_registry.rb +1 -0
  100. data/lib/active_support/railtie.rb +34 -11
  101. data/lib/active_support/reloader.rb +1 -1
  102. data/lib/active_support/rescuable.rb +2 -2
  103. data/lib/active_support/secure_compare_rotator.rb +1 -1
  104. data/lib/active_support/string_inquirer.rb +0 -2
  105. data/lib/active_support/subscriber.rb +5 -0
  106. data/lib/active_support/tagged_logging.rb +1 -1
  107. data/lib/active_support/test_case.rb +9 -21
  108. data/lib/active_support/testing/assertions.rb +35 -5
  109. data/lib/active_support/testing/deprecation.rb +1 -1
  110. data/lib/active_support/testing/isolation.rb +1 -1
  111. data/lib/active_support/testing/method_call_assertions.rb +5 -5
  112. data/lib/active_support/testing/parallelization/server.rb +4 -0
  113. data/lib/active_support/testing/parallelization/worker.rb +3 -0
  114. data/lib/active_support/testing/parallelization.rb +4 -0
  115. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  116. data/lib/active_support/testing/stream.rb +3 -5
  117. data/lib/active_support/testing/tagged_logging.rb +1 -1
  118. data/lib/active_support/testing/time_helpers.rb +13 -2
  119. data/lib/active_support/time_with_zone.rb +19 -6
  120. data/lib/active_support/values/time_zone.rb +25 -9
  121. data/lib/active_support/xml_mini/jdom.rb +1 -1
  122. data/lib/active_support/xml_mini/libxml.rb +5 -5
  123. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  124. data/lib/active_support/xml_mini/nokogiri.rb +4 -4
  125. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  126. data/lib/active_support/xml_mini/rexml.rb +1 -1
  127. data/lib/active_support/xml_mini.rb +2 -1
  128. data/lib/active_support.rb +14 -1
  129. metadata +14 -28
  130. data/lib/active_support/core_ext/marshal.rb +0 -26
  131. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
@@ -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 = "6.2", 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,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "openssl"
4
+
3
5
  module ActiveSupport
4
- class Digest #:nodoc:
5
- class <<self
6
+ class Digest # :nodoc:
7
+ class << self
6
8
  def hash_digest_class
7
- @hash_digest_class ||= ::Digest::MD5
9
+ @hash_digest_class ||= OpenSSL::Digest::MD5
8
10
  end
9
11
 
10
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
@@ -187,18 +192,23 @@ module ActiveSupport
187
192
 
188
193
  parts = {}
189
194
  remainder = value.round(9)
195
+ variable = false
190
196
 
191
197
  PARTS.each do |part|
192
198
  unless part == :seconds
193
199
  part_in_seconds = PARTS_IN_SECONDS[part]
194
200
  parts[part] = remainder.div(part_in_seconds)
195
201
  remainder %= part_in_seconds
202
+
203
+ unless parts[part].zero?
204
+ variable ||= VARIABLE_PARTS.include?(part)
205
+ end
196
206
  end
197
207
  end unless value == 0
198
208
 
199
209
  parts[:seconds] = remainder
200
210
 
201
- new(value, parts)
211
+ new(value, parts, variable)
202
212
  end
203
213
 
204
214
  private
@@ -209,12 +219,23 @@ module ActiveSupport
209
219
  end
210
220
  end
211
221
 
212
- def initialize(value, parts) #:nodoc:
222
+ def initialize(value, parts, variable = nil) # :nodoc:
213
223
  @value, @parts = value, parts
214
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
215
231
  end
216
232
 
217
- 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:
218
239
  case other
219
240
  when Scalar
220
241
  [other, self]
@@ -239,13 +260,13 @@ module ActiveSupport
239
260
  # are treated as seconds.
240
261
  def +(other)
241
262
  if Duration === other
242
- parts = @parts.merge(other.parts) do |_key, value, other_value|
263
+ parts = @parts.merge(other._parts) do |_key, value, other_value|
243
264
  value + other_value
244
265
  end
245
- Duration.new(value + other.value, parts)
266
+ Duration.new(value + other.value, parts, @variable || other.variable?)
246
267
  else
247
268
  seconds = @parts.fetch(:seconds, 0) + other
248
- Duration.new(value + other, @parts.merge(seconds: seconds))
269
+ Duration.new(value + other, @parts.merge(seconds: seconds), @variable)
249
270
  end
250
271
  end
251
272
 
@@ -258,9 +279,9 @@ module ActiveSupport
258
279
  # Multiplies this Duration by a Numeric and returns a new Duration.
259
280
  def *(other)
260
281
  if Scalar === other || Duration === other
261
- 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?)
262
283
  elsif Numeric === other
263
- Duration.new(value * other, parts.transform_values { |number| number * other })
284
+ Duration.new(value * other, @parts.transform_values { |number| number * other }, @variable)
264
285
  else
265
286
  raise_type_error(other)
266
287
  end
@@ -269,11 +290,11 @@ module ActiveSupport
269
290
  # Divides this Duration by a Numeric and returns a new Duration.
270
291
  def /(other)
271
292
  if Scalar === other
272
- 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)
273
294
  elsif Duration === other
274
295
  value / other.value
275
296
  elsif Numeric === other
276
- Duration.new(value / other, parts.transform_values { |number| number / other })
297
+ Duration.new(value / other, @parts.transform_values { |number| number / other }, @variable)
277
298
  else
278
299
  raise_type_error(other)
279
300
  end
@@ -291,15 +312,15 @@ module ActiveSupport
291
312
  end
292
313
  end
293
314
 
294
- def -@ #:nodoc:
295
- Duration.new(-value, parts.transform_values(&:-@))
315
+ def -@ # :nodoc:
316
+ Duration.new(-value, @parts.transform_values(&:-@), @variable)
296
317
  end
297
318
 
298
- def +@ #:nodoc:
319
+ def +@ # :nodoc:
299
320
  self
300
321
  end
301
322
 
302
- def is_a?(klass) #:nodoc:
323
+ def is_a?(klass) # :nodoc:
303
324
  Duration == klass || value.is_a?(klass)
304
325
  end
305
326
  alias :kind_of? :is_a?
@@ -419,24 +440,24 @@ module ActiveSupport
419
440
  alias :until :ago
420
441
  alias :before :ago
421
442
 
422
- def inspect #:nodoc:
423
- return "#{value} seconds" if parts.empty?
443
+ def inspect # :nodoc:
444
+ return "#{value} seconds" if @parts.empty?
424
445
 
425
- parts.
446
+ @parts.
426
447
  sort_by { |unit, _ | PARTS.index(unit) }.
427
448
  map { |unit, val| "#{val} #{val == 1 ? unit.to_s.chop : unit.to_s}" }.
428
- to_sentence(locale: ::I18n.default_locale)
449
+ to_sentence(locale: false)
429
450
  end
430
451
 
431
- def as_json(options = nil) #:nodoc:
452
+ def as_json(options = nil) # :nodoc:
432
453
  to_i
433
454
  end
434
455
 
435
- def init_with(coder) #:nodoc:
456
+ def init_with(coder) # :nodoc:
436
457
  initialize(coder["value"], coder["parts"])
437
458
  end
438
459
 
439
- def encode_with(coder) #:nodoc:
460
+ def encode_with(coder) # :nodoc:
440
461
  coder.map = { "value" => @value, "parts" => @parts }
441
462
  end
442
463
 
@@ -446,16 +467,24 @@ module ActiveSupport
446
467
  ISO8601Serializer.new(self, precision: precision).serialize
447
468
  end
448
469
 
470
+ def variable? # :nodoc:
471
+ @variable
472
+ end
473
+
474
+ def _parts # :nodoc:
475
+ @parts
476
+ end
477
+
449
478
  private
450
479
  def sum(sign, time = ::Time.current)
451
480
  unless time.acts_like?(:time) || time.acts_like?(:date)
452
481
  raise ::ArgumentError, "expected a time or date, got #{time.inspect}"
453
482
  end
454
483
 
455
- if parts.empty?
484
+ if @parts.empty?
456
485
  time.since(sign * value)
457
486
  else
458
- parts.inject(time) do |t, (type, number)|
487
+ @parts.inject(time) do |t, (type, number)|
459
488
  if type == :seconds
460
489
  t.since(sign * number)
461
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 = 4
13
- PRE = "6"
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