activesupport 6.1.6.1 → 7.0.3.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +231 -515
- data/lib/active_support/actionable_error.rb +1 -1
- data/lib/active_support/array_inquirer.rb +0 -2
- data/lib/active_support/backtrace_cleaner.rb +2 -2
- data/lib/active_support/benchmarkable.rb +2 -2
- data/lib/active_support/cache/file_store.rb +15 -9
- data/lib/active_support/cache/mem_cache_store.rb +132 -37
- data/lib/active_support/cache/memory_store.rb +24 -16
- data/lib/active_support/cache/null_store.rb +10 -2
- data/lib/active_support/cache/redis_cache_store.rb +47 -72
- data/lib/active_support/cache/strategy/local_cache.rb +38 -61
- data/lib/active_support/cache.rb +193 -46
- data/lib/active_support/callbacks.rb +184 -85
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +5 -5
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
- data/lib/active_support/concurrency/share_lock.rb +2 -2
- data/lib/active_support/configurable.rb +8 -5
- data/lib/active_support/configuration_file.rb +1 -1
- data/lib/active_support/core_ext/array/access.rb +1 -5
- data/lib/active_support/core_ext/array/conversions.rb +13 -12
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
- data/lib/active_support/core_ext/array/grouping.rb +6 -6
- data/lib/active_support/core_ext/array/inquiry.rb +2 -2
- data/lib/active_support/core_ext/array.rb +1 -0
- data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
- data/lib/active_support/core_ext/class/subclasses.rb +25 -17
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +9 -9
- data/lib/active_support/core_ext/date/conversions.rb +14 -14
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/date.rb +1 -0
- data/lib/active_support/core_ext/date_and_time/calculations.rb +4 -4
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
- data/lib/active_support/core_ext/date_time/blank.rb +1 -1
- data/lib/active_support/core_ext/date_time/conversions.rb +13 -13
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/date_time.rb +1 -0
- data/lib/active_support/core_ext/digest/uuid.rb +39 -14
- data/lib/active_support/core_ext/enumerable.rb +101 -32
- data/lib/active_support/core_ext/file/atomic.rb +3 -1
- data/lib/active_support/core_ext/hash/conversions.rb +0 -1
- data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
- data/lib/active_support/core_ext/hash/keys.rb +1 -1
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
- data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
- data/lib/active_support/core_ext/module/attribute_accessors.rb +2 -0
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +19 -10
- data/lib/active_support/core_ext/module/delegation.rb +2 -8
- data/lib/active_support/core_ext/name_error.rb +2 -8
- data/lib/active_support/core_ext/numeric/conversions.rb +80 -77
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
- data/lib/active_support/core_ext/numeric.rb +1 -0
- data/lib/active_support/core_ext/object/acts_like.rb +29 -5
- data/lib/active_support/core_ext/object/blank.rb +2 -2
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/duplicable.rb +11 -0
- data/lib/active_support/core_ext/object/json.rb +30 -25
- data/lib/active_support/core_ext/object/to_query.rb +2 -2
- data/lib/active_support/core_ext/object/try.rb +20 -20
- data/lib/active_support/core_ext/object/with_options.rb +20 -1
- data/lib/active_support/core_ext/pathname/existence.rb +21 -0
- data/lib/active_support/core_ext/pathname.rb +3 -0
- data/lib/active_support/core_ext/range/compare_range.rb +0 -25
- data/lib/active_support/core_ext/range/conversions.rb +8 -8
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/range/each.rb +1 -1
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -25
- data/lib/active_support/core_ext/range/overlaps.rb +1 -1
- data/lib/active_support/core_ext/range.rb +1 -1
- data/lib/active_support/core_ext/securerandom.rb +1 -1
- data/lib/active_support/core_ext/string/conversions.rb +2 -2
- data/lib/active_support/core_ext/string/filters.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +1 -1
- data/lib/active_support/core_ext/string/inquiry.rb +1 -1
- data/lib/active_support/core_ext/string/output_safety.rb +62 -38
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
- data/lib/active_support/core_ext/time/calculations.rb +7 -8
- data/lib/active_support/core_ext/time/conversions.rb +13 -12
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/time/zones.rb +7 -22
- data/lib/active_support/core_ext/time.rb +1 -0
- data/lib/active_support/core_ext/uri.rb +3 -27
- data/lib/active_support/core_ext.rb +1 -0
- data/lib/active_support/current_attributes.rb +31 -14
- data/lib/active_support/dependencies/interlock.rb +10 -18
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +58 -788
- data/lib/active_support/deprecation/behaviors.rb +5 -2
- data/lib/active_support/deprecation/method_wrappers.rb +3 -3
- data/lib/active_support/deprecation/proxy_wrappers.rb +2 -2
- data/lib/active_support/deprecation.rb +2 -2
- data/lib/active_support/descendants_tracker.rb +174 -68
- data/lib/active_support/digest.rb +4 -4
- data/lib/active_support/duration/iso8601_parser.rb +3 -3
- data/lib/active_support/duration/iso8601_serializer.rb +9 -1
- data/lib/active_support/duration.rb +77 -48
- data/lib/active_support/encrypted_configuration.rb +13 -2
- data/lib/active_support/encrypted_file.rb +1 -1
- data/lib/active_support/environment_inquirer.rb +1 -1
- data/lib/active_support/error_reporter.rb +117 -0
- data/lib/active_support/evented_file_update_checker.rb +3 -5
- data/lib/active_support/execution_context/test_helper.rb +13 -0
- data/lib/active_support/execution_context.rb +53 -0
- data/lib/active_support/execution_wrapper.rb +30 -11
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/fork_tracker.rb +19 -12
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/hash_with_indifferent_access.rb +3 -1
- data/lib/active_support/html_safe_translation.rb +43 -0
- data/lib/active_support/i18n.rb +1 -0
- data/lib/active_support/i18n_railtie.rb +1 -1
- data/lib/active_support/inflector/inflections.rb +23 -7
- data/lib/active_support/inflector/methods.rb +24 -48
- data/lib/active_support/inflector/transliterate.rb +1 -1
- data/lib/active_support/isolated_execution_state.rb +72 -0
- data/lib/active_support/json/encoding.rb +3 -3
- data/lib/active_support/key_generator.rb +22 -5
- data/lib/active_support/lazy_load_hooks.rb +14 -3
- data/lib/active_support/locale/en.yml +1 -1
- data/lib/active_support/log_subscriber/test_helper.rb +2 -2
- data/lib/active_support/log_subscriber.rb +15 -5
- data/lib/active_support/logger.rb +4 -5
- data/lib/active_support/logger_thread_safe_level.rb +4 -13
- data/lib/active_support/message_encryptor.rb +12 -6
- data/lib/active_support/message_verifier.rb +46 -14
- data/lib/active_support/messages/metadata.rb +2 -2
- data/lib/active_support/multibyte/chars.rb +10 -11
- data/lib/active_support/multibyte/unicode.rb +0 -12
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +91 -65
- data/lib/active_support/notifications/instrumenter.rb +32 -15
- data/lib/active_support/notifications.rb +17 -23
- data/lib/active_support/number_helper/number_converter.rb +1 -3
- data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
- data/lib/active_support/number_helper/rounding_helper.rb +1 -5
- data/lib/active_support/number_helper.rb +0 -2
- data/lib/active_support/option_merger.rb +8 -16
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/ordered_options.rb +1 -1
- data/lib/active_support/parameter_filter.rb +5 -0
- data/lib/active_support/per_thread_registry.rb +5 -1
- data/lib/active_support/railtie.rb +69 -19
- data/lib/active_support/rescuable.rb +4 -4
- data/lib/active_support/ruby_features.rb +7 -0
- data/lib/active_support/secure_compare_rotator.rb +2 -2
- data/lib/active_support/string_inquirer.rb +0 -2
- data/lib/active_support/subscriber.rb +7 -18
- data/lib/active_support/tagged_logging.rb +16 -1
- data/lib/active_support/test_case.rb +9 -21
- data/lib/active_support/testing/assertions.rb +35 -5
- data/lib/active_support/testing/deprecation.rb +52 -1
- data/lib/active_support/testing/isolation.rb +2 -2
- data/lib/active_support/testing/method_call_assertions.rb +5 -5
- data/lib/active_support/testing/parallelization/server.rb +4 -0
- data/lib/active_support/testing/parallelization/worker.rb +3 -0
- data/lib/active_support/testing/parallelization.rb +4 -0
- data/lib/active_support/testing/parallelize_executor.rb +76 -0
- data/lib/active_support/testing/stream.rb +3 -5
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +13 -2
- data/lib/active_support/time_with_zone.rb +58 -17
- data/lib/active_support/values/time_zone.rb +33 -14
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini/jdom.rb +1 -1
- data/lib/active_support/xml_mini/libxml.rb +5 -5
- data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
- data/lib/active_support/xml_mini/nokogiri.rb +4 -4
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
- data/lib/active_support/xml_mini/rexml.rb +1 -1
- data/lib/active_support/xml_mini.rb +5 -4
- data/lib/active_support.rb +16 -0
- metadata +23 -21
- data/lib/active_support/core_ext/marshal.rb +0 -26
- data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -120
@@ -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
|
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.
|
43
|
-
new_parts = other.
|
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.
|
55
|
-
new_parts = other.
|
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.
|
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
|
-
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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
|
@@ -188,18 +193,23 @@ module ActiveSupport
|
|
188
193
|
parts = {}
|
189
194
|
remainder_sign = value <=> 0
|
190
195
|
remainder = value.round(9).abs
|
196
|
+
variable = false
|
191
197
|
|
192
198
|
PARTS.each do |part|
|
193
199
|
unless part == :seconds
|
194
200
|
part_in_seconds = PARTS_IN_SECONDS[part]
|
195
201
|
parts[part] = remainder.div(part_in_seconds) * remainder_sign
|
196
202
|
remainder %= part_in_seconds
|
203
|
+
|
204
|
+
unless parts[part].zero?
|
205
|
+
variable ||= VARIABLE_PARTS.include?(part)
|
206
|
+
end
|
197
207
|
end
|
198
208
|
end unless value == 0
|
199
209
|
|
200
210
|
parts[:seconds] = remainder * remainder_sign
|
201
211
|
|
202
|
-
new(value, parts)
|
212
|
+
new(value, parts, variable)
|
203
213
|
end
|
204
214
|
|
205
215
|
private
|
@@ -210,12 +220,23 @@ module ActiveSupport
|
|
210
220
|
end
|
211
221
|
end
|
212
222
|
|
213
|
-
def initialize(value, parts)
|
223
|
+
def initialize(value, parts, variable = nil) # :nodoc:
|
214
224
|
@value, @parts = value, parts
|
215
225
|
@parts.reject! { |k, v| v.zero? } unless value == 0
|
226
|
+
@parts.freeze
|
227
|
+
@variable = variable
|
228
|
+
|
229
|
+
if @variable.nil?
|
230
|
+
@variable = @parts.any? { |part, _| VARIABLE_PARTS.include?(part) }
|
231
|
+
end
|
216
232
|
end
|
217
233
|
|
218
|
-
|
234
|
+
# Returns a copy of the parts hash that defines the duration
|
235
|
+
def parts
|
236
|
+
@parts.dup
|
237
|
+
end
|
238
|
+
|
239
|
+
def coerce(other) # :nodoc:
|
219
240
|
case other
|
220
241
|
when Scalar
|
221
242
|
[other, self]
|
@@ -240,13 +261,13 @@ module ActiveSupport
|
|
240
261
|
# are treated as seconds.
|
241
262
|
def +(other)
|
242
263
|
if Duration === other
|
243
|
-
parts = @parts.merge(other.
|
264
|
+
parts = @parts.merge(other._parts) do |_key, value, other_value|
|
244
265
|
value + other_value
|
245
266
|
end
|
246
|
-
Duration.new(value + other.value, parts)
|
267
|
+
Duration.new(value + other.value, parts, @variable || other.variable?)
|
247
268
|
else
|
248
269
|
seconds = @parts.fetch(:seconds, 0) + other
|
249
|
-
Duration.new(value + other, @parts.merge(seconds: seconds))
|
270
|
+
Duration.new(value + other, @parts.merge(seconds: seconds), @variable)
|
250
271
|
end
|
251
272
|
end
|
252
273
|
|
@@ -259,9 +280,9 @@ module ActiveSupport
|
|
259
280
|
# Multiplies this Duration by a Numeric and returns a new Duration.
|
260
281
|
def *(other)
|
261
282
|
if Scalar === other || Duration === other
|
262
|
-
Duration.new(value * other.value, parts.transform_values { |number| number * other.value })
|
283
|
+
Duration.new(value * other.value, @parts.transform_values { |number| number * other.value }, @variable || other.variable?)
|
263
284
|
elsif Numeric === other
|
264
|
-
Duration.new(value * other, parts.transform_values { |number| number * other })
|
285
|
+
Duration.new(value * other, @parts.transform_values { |number| number * other }, @variable)
|
265
286
|
else
|
266
287
|
raise_type_error(other)
|
267
288
|
end
|
@@ -270,11 +291,11 @@ module ActiveSupport
|
|
270
291
|
# Divides this Duration by a Numeric and returns a new Duration.
|
271
292
|
def /(other)
|
272
293
|
if Scalar === other
|
273
|
-
Duration.new(value / other.value, parts.transform_values { |number| number / other.value })
|
294
|
+
Duration.new(value / other.value, @parts.transform_values { |number| number / other.value }, @variable)
|
274
295
|
elsif Duration === other
|
275
296
|
value / other.value
|
276
297
|
elsif Numeric === other
|
277
|
-
Duration.new(value / other, parts.transform_values { |number| number / other })
|
298
|
+
Duration.new(value / other, @parts.transform_values { |number| number / other }, @variable)
|
278
299
|
else
|
279
300
|
raise_type_error(other)
|
280
301
|
end
|
@@ -292,15 +313,15 @@ module ActiveSupport
|
|
292
313
|
end
|
293
314
|
end
|
294
315
|
|
295
|
-
def -@
|
296
|
-
Duration.new(-value, parts.transform_values(&:-@))
|
316
|
+
def -@ # :nodoc:
|
317
|
+
Duration.new(-value, @parts.transform_values(&:-@), @variable)
|
297
318
|
end
|
298
319
|
|
299
|
-
def +@
|
320
|
+
def +@ # :nodoc:
|
300
321
|
self
|
301
322
|
end
|
302
323
|
|
303
|
-
def is_a?(klass)
|
324
|
+
def is_a?(klass) # :nodoc:
|
304
325
|
Duration == klass || value.is_a?(klass)
|
305
326
|
end
|
306
327
|
alias :kind_of? :is_a?
|
@@ -420,24 +441,24 @@ module ActiveSupport
|
|
420
441
|
alias :until :ago
|
421
442
|
alias :before :ago
|
422
443
|
|
423
|
-
def inspect
|
424
|
-
return "#{value} seconds" if parts.empty?
|
444
|
+
def inspect # :nodoc:
|
445
|
+
return "#{value} seconds" if @parts.empty?
|
425
446
|
|
426
|
-
parts.
|
447
|
+
@parts.
|
427
448
|
sort_by { |unit, _ | PARTS.index(unit) }.
|
428
449
|
map { |unit, val| "#{val} #{val == 1 ? unit.to_s.chop : unit.to_s}" }.
|
429
|
-
to_sentence(locale:
|
450
|
+
to_sentence(locale: false)
|
430
451
|
end
|
431
452
|
|
432
|
-
def as_json(options = nil)
|
453
|
+
def as_json(options = nil) # :nodoc:
|
433
454
|
to_i
|
434
455
|
end
|
435
456
|
|
436
|
-
def init_with(coder)
|
457
|
+
def init_with(coder) # :nodoc:
|
437
458
|
initialize(coder["value"], coder["parts"])
|
438
459
|
end
|
439
460
|
|
440
|
-
def encode_with(coder)
|
461
|
+
def encode_with(coder) # :nodoc:
|
441
462
|
coder.map = { "value" => @value, "parts" => @parts }
|
442
463
|
end
|
443
464
|
|
@@ -447,16 +468,24 @@ module ActiveSupport
|
|
447
468
|
ISO8601Serializer.new(self, precision: precision).serialize
|
448
469
|
end
|
449
470
|
|
471
|
+
def variable? # :nodoc:
|
472
|
+
@variable
|
473
|
+
end
|
474
|
+
|
475
|
+
def _parts # :nodoc:
|
476
|
+
@parts
|
477
|
+
end
|
478
|
+
|
450
479
|
private
|
451
480
|
def sum(sign, time = ::Time.current)
|
452
481
|
unless time.acts_like?(:time) || time.acts_like?(:date)
|
453
482
|
raise ::ArgumentError, "expected a time or date, got #{time.inspect}"
|
454
483
|
end
|
455
484
|
|
456
|
-
if parts.empty?
|
485
|
+
if @parts.empty?
|
457
486
|
time.since(sign * value)
|
458
487
|
else
|
459
|
-
parts.inject(time) do |t, (type, number)|
|
488
|
+
@parts.inject(time) do |t, (type, number)|
|
460
489
|
if type == :seconds
|
461
490
|
t.since(sign * number)
|
462
491
|
elsif type == :minutes
|
@@ -34,12 +34,23 @@ 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)
|
42
|
-
YAML.
|
52
|
+
doc = YAML.respond_to?(:unsafe_load) ? YAML.unsafe_load(config) : YAML.load(config)
|
53
|
+
doc.presence || {}
|
43
54
|
end
|
44
55
|
end
|
45
56
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require "active_support/string_inquirer"
|
4
4
|
|
5
5
|
module ActiveSupport
|
6
|
-
class EnvironmentInquirer < StringInquirer
|
6
|
+
class EnvironmentInquirer < StringInquirer # :nodoc:
|
7
7
|
DEFAULT_ENVIRONMENTS = ["development", "test", "production"]
|
8
8
|
def initialize(env)
|
9
9
|
super(env)
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
# +ActiveSupport::ErrorReporter+ is a common interface for error reporting services.
|
5
|
+
#
|
6
|
+
# To rescue and report any unhandled error, you can use the +handle+ method:
|
7
|
+
#
|
8
|
+
# Rails.error.handle do
|
9
|
+
# do_something!
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# If an error is raised, it will be reported and swallowed.
|
13
|
+
#
|
14
|
+
# Alternatively if you want to report the error but not swallow it, you can use +record+
|
15
|
+
#
|
16
|
+
# Rails.error.record do
|
17
|
+
# do_something!
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# Both methods can be restricted to only handle a specific exception class
|
21
|
+
#
|
22
|
+
# maybe_tags = Rails.error.handle(Redis::BaseError) { redis.get("tags") }
|
23
|
+
#
|
24
|
+
# You can also pass some extra context information that may be used by the error subscribers:
|
25
|
+
#
|
26
|
+
# Rails.error.handle(context: { section: "admin" }) do
|
27
|
+
# # ...
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# Additionally a +severity+ can be passed along to communicate how important the error report is.
|
31
|
+
# +severity+ can be one of +:error+, +:warning+, or +:info+. Handled errors default to the +:warning+
|
32
|
+
# severity, and unhandled ones to +:error+.
|
33
|
+
#
|
34
|
+
# Both +handle+ and +record+ pass through the return value from the block. In the case of +handle+
|
35
|
+
# rescuing an error, a fallback can be provided. The fallback must be a callable whose result will
|
36
|
+
# be returned when the block raises and is handled:
|
37
|
+
#
|
38
|
+
# user = Rails.error.handle(fallback: -> { User.anonymous }) do
|
39
|
+
# User.find_by(params)
|
40
|
+
# end
|
41
|
+
class ErrorReporter
|
42
|
+
SEVERITIES = %i(error warning info)
|
43
|
+
|
44
|
+
attr_accessor :logger
|
45
|
+
|
46
|
+
def initialize(*subscribers, logger: nil)
|
47
|
+
@subscribers = subscribers.flatten
|
48
|
+
@logger = logger
|
49
|
+
end
|
50
|
+
|
51
|
+
# Report any unhandled exception, and swallow it.
|
52
|
+
#
|
53
|
+
# Rails.error.handle do
|
54
|
+
# 1 + '1'
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
def handle(error_class = StandardError, severity: :warning, context: {}, fallback: nil)
|
58
|
+
yield
|
59
|
+
rescue error_class => error
|
60
|
+
report(error, handled: true, severity: severity, context: context)
|
61
|
+
fallback.call if fallback
|
62
|
+
end
|
63
|
+
|
64
|
+
def record(error_class = StandardError, severity: :error, context: {})
|
65
|
+
yield
|
66
|
+
rescue error_class => error
|
67
|
+
report(error, handled: false, severity: severity, context: context)
|
68
|
+
raise
|
69
|
+
end
|
70
|
+
|
71
|
+
# Register a new error subscriber. The subscriber must respond to
|
72
|
+
#
|
73
|
+
# report(Exception, handled: Boolean, context: Hash)
|
74
|
+
#
|
75
|
+
# The +report+ method +should+ never raise an error.
|
76
|
+
def subscribe(subscriber)
|
77
|
+
unless subscriber.respond_to?(:report)
|
78
|
+
raise ArgumentError, "Error subscribers must respond to #report"
|
79
|
+
end
|
80
|
+
@subscribers << subscriber
|
81
|
+
end
|
82
|
+
|
83
|
+
# Update the execution context that is accessible to error subscribers
|
84
|
+
#
|
85
|
+
# Rails.error.set_context(section: "checkout", user_id: @user.id)
|
86
|
+
#
|
87
|
+
# See +ActiveSupport::ExecutionContext.set+
|
88
|
+
def set_context(...)
|
89
|
+
ActiveSupport::ExecutionContext.set(...)
|
90
|
+
end
|
91
|
+
|
92
|
+
# When the block based +handle+ and +record+ methods are not suitable, you can directly use +report+
|
93
|
+
#
|
94
|
+
# Rails.error.report(error, handled: true)
|
95
|
+
def report(error, handled:, severity: handled ? :warning : :error, context: {})
|
96
|
+
unless SEVERITIES.include?(severity)
|
97
|
+
raise ArgumentError, "severity must be one of #{SEVERITIES.map(&:inspect).join(", ")}, got: #{severity.inspect}"
|
98
|
+
end
|
99
|
+
|
100
|
+
full_context = ActiveSupport::ExecutionContext.to_h.merge(context)
|
101
|
+
@subscribers.each do |subscriber|
|
102
|
+
subscriber.report(error, handled: handled, severity: severity, context: full_context)
|
103
|
+
rescue => subscriber_error
|
104
|
+
if logger
|
105
|
+
logger.fatal(
|
106
|
+
"Error subscriber raised an error: #{subscriber_error.message} (#{subscriber_error.class})\n" +
|
107
|
+
subscriber_error.backtrace.join("\n")
|
108
|
+
)
|
109
|
+
else
|
110
|
+
raise
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
nil
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -8,8 +8,8 @@ require "active_support/fork_tracker"
|
|
8
8
|
|
9
9
|
module ActiveSupport
|
10
10
|
# Allows you to "listen" to changes in a file system.
|
11
|
-
# The evented file updater does not hit disk when checking for updates
|
12
|
-
#
|
11
|
+
# The evented file updater does not hit disk when checking for updates.
|
12
|
+
# Instead, it uses platform-specific file system events to trigger a change
|
13
13
|
# in state.
|
14
14
|
#
|
15
15
|
# The file checker takes an array of files to watch or a hash specifying directories
|
@@ -17,8 +17,6 @@ module ActiveSupport
|
|
17
17
|
# EventedFileUpdateChecker#execute is run or when EventedFileUpdateChecker#execute_if_updated
|
18
18
|
# is run and there have been changes to the file system.
|
19
19
|
#
|
20
|
-
# Note: Forking will cause the first call to `updated?` to return `true`.
|
21
|
-
#
|
22
20
|
# Example:
|
23
21
|
#
|
24
22
|
# checker = ActiveSupport::EventedFileUpdateChecker.new(["/tmp/foo"]) { puts "changed" }
|
@@ -34,7 +32,7 @@ module ActiveSupport
|
|
34
32
|
# checker.execute_if_updated
|
35
33
|
# # => "changed"
|
36
34
|
#
|
37
|
-
class EventedFileUpdateChecker
|
35
|
+
class EventedFileUpdateChecker # :nodoc: all
|
38
36
|
def initialize(files, dirs = {}, &block)
|
39
37
|
unless block
|
40
38
|
raise ArgumentError, "A block is required to initialize an EventedFileUpdateChecker"
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
module ExecutionContext # :nodoc:
|
5
|
+
@after_change_callbacks = []
|
6
|
+
class << self
|
7
|
+
def after_change(&block)
|
8
|
+
@after_change_callbacks << block
|
9
|
+
end
|
10
|
+
|
11
|
+
# Updates the execution context. If a block is given, it resets the provided keys to their
|
12
|
+
# previous value once the block exits.
|
13
|
+
def set(**options)
|
14
|
+
options.symbolize_keys!
|
15
|
+
keys = options.keys
|
16
|
+
|
17
|
+
store = self.store
|
18
|
+
|
19
|
+
previous_context = keys.zip(store.values_at(*keys)).to_h
|
20
|
+
|
21
|
+
store.merge!(options)
|
22
|
+
@after_change_callbacks.each(&:call)
|
23
|
+
|
24
|
+
if block_given?
|
25
|
+
begin
|
26
|
+
yield
|
27
|
+
ensure
|
28
|
+
store.merge!(previous_context)
|
29
|
+
@after_change_callbacks.each(&:call)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def []=(key, value)
|
35
|
+
store[key.to_sym] = value
|
36
|
+
@after_change_callbacks.each(&:call)
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_h
|
40
|
+
store.dup
|
41
|
+
end
|
42
|
+
|
43
|
+
def clear
|
44
|
+
store.clear
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
def store
|
49
|
+
IsolatedExecutionState[:active_support_execution_context] ||= {}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/error_reporter"
|
3
4
|
require "active_support/callbacks"
|
4
5
|
require "concurrent/hash"
|
5
6
|
|
@@ -65,7 +66,7 @@ module ActiveSupport
|
|
65
66
|
# Where possible, prefer +wrap+.
|
66
67
|
def self.run!(reset: false)
|
67
68
|
if reset
|
68
|
-
lost_instance =
|
69
|
+
lost_instance = IsolatedExecutionState.delete(active_key)
|
69
70
|
lost_instance&.complete!
|
70
71
|
else
|
71
72
|
return Null if active?
|
@@ -89,28 +90,42 @@ module ActiveSupport
|
|
89
90
|
instance = run!
|
90
91
|
begin
|
91
92
|
yield
|
93
|
+
rescue => error
|
94
|
+
error_reporter.report(error, handled: false)
|
95
|
+
raise
|
92
96
|
ensure
|
93
97
|
instance.complete!
|
94
98
|
end
|
95
99
|
end
|
96
100
|
|
97
|
-
|
98
|
-
|
101
|
+
def self.perform # :nodoc:
|
102
|
+
instance = new
|
103
|
+
instance.run
|
104
|
+
begin
|
105
|
+
yield
|
106
|
+
ensure
|
107
|
+
instance.complete
|
108
|
+
end
|
99
109
|
end
|
100
110
|
|
101
|
-
def self.
|
102
|
-
|
103
|
-
other.active = Concurrent::Hash.new
|
111
|
+
def self.error_reporter
|
112
|
+
@error_reporter ||= ActiveSupport::ErrorReporter.new
|
104
113
|
end
|
105
114
|
|
106
|
-
self.
|
115
|
+
def self.active_key # :nodoc:
|
116
|
+
@active_key ||= :"active_execution_wrapper_#{object_id}"
|
117
|
+
end
|
107
118
|
|
108
119
|
def self.active? # :nodoc:
|
109
|
-
|
120
|
+
IsolatedExecutionState.key?(active_key)
|
110
121
|
end
|
111
122
|
|
112
123
|
def run! # :nodoc:
|
113
|
-
self.class.
|
124
|
+
IsolatedExecutionState[self.class.active_key] = self
|
125
|
+
run
|
126
|
+
end
|
127
|
+
|
128
|
+
def run # :nodoc:
|
114
129
|
run_callbacks(:run)
|
115
130
|
end
|
116
131
|
|
@@ -119,9 +134,13 @@ module ActiveSupport
|
|
119
134
|
#
|
120
135
|
# Where possible, prefer +wrap+.
|
121
136
|
def complete!
|
122
|
-
|
137
|
+
complete
|
123
138
|
ensure
|
124
|
-
self.class.
|
139
|
+
IsolatedExecutionState.delete(self.class.active_key)
|
140
|
+
end
|
141
|
+
|
142
|
+
def complete # :nodoc:
|
143
|
+
run_callbacks(:complete)
|
125
144
|
end
|
126
145
|
|
127
146
|
private
|