activesupport 7.1.5.1 → 7.2.3
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +213 -1082
- data/README.rdoc +1 -1
- data/lib/active_support/array_inquirer.rb +1 -1
- data/lib/active_support/backtrace_cleaner.rb +10 -3
- data/lib/active_support/broadcast_logger.rb +65 -78
- data/lib/active_support/cache/file_store.rb +17 -12
- data/lib/active_support/cache/mem_cache_store.rb +29 -89
- data/lib/active_support/cache/memory_store.rb +7 -6
- data/lib/active_support/cache/null_store.rb +2 -2
- data/lib/active_support/cache/redis_cache_store.rb +17 -14
- data/lib/active_support/cache/serializer_with_fallback.rb +0 -23
- data/lib/active_support/cache/strategy/local_cache.rb +56 -20
- data/lib/active_support/cache.rb +63 -71
- data/lib/active_support/callbacks.rb +77 -115
- data/lib/active_support/core_ext/array/conversions.rb +0 -2
- data/lib/active_support/core_ext/benchmark.rb +1 -0
- data/lib/active_support/core_ext/class/attribute.rb +2 -2
- data/lib/active_support/core_ext/class/subclasses.rb +15 -35
- data/lib/active_support/core_ext/date/blank.rb +4 -0
- data/lib/active_support/core_ext/date/conversions.rb +0 -2
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +28 -1
- data/lib/active_support/core_ext/date_time/blank.rb +4 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +4 -6
- data/lib/active_support/core_ext/digest/uuid.rb +6 -0
- data/lib/active_support/core_ext/enumerable.rb +17 -5
- data/lib/active_support/core_ext/erb/util.rb +7 -2
- data/lib/active_support/core_ext/hash/keys.rb +4 -4
- data/lib/active_support/core_ext/module/attr_internal.rb +17 -6
- data/lib/active_support/core_ext/module/delegation.rb +20 -163
- data/lib/active_support/core_ext/module/deprecation.rb +1 -4
- data/lib/active_support/core_ext/module/introspection.rb +3 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +3 -3
- data/lib/active_support/core_ext/object/blank.rb +45 -1
- data/lib/active_support/core_ext/object/instance_variables.rb +11 -19
- data/lib/active_support/core_ext/object/json.rb +1 -1
- data/lib/active_support/core_ext/object/try.rb +2 -2
- data/lib/active_support/core_ext/object/with.rb +5 -3
- data/lib/active_support/core_ext/pathname/blank.rb +4 -0
- data/lib/active_support/core_ext/range/overlap.rb +1 -1
- data/lib/active_support/core_ext/range/sole.rb +17 -0
- data/lib/active_support/core_ext/range.rb +1 -0
- data/lib/active_support/core_ext/securerandom.rb +4 -4
- data/lib/active_support/core_ext/string/conversions.rb +1 -1
- data/lib/active_support/core_ext/string/filters.rb +4 -4
- data/lib/active_support/core_ext/string/multibyte.rb +3 -3
- data/lib/active_support/core_ext/string/output_safety.rb +0 -7
- data/lib/active_support/core_ext/time/calculations.rb +18 -28
- data/lib/active_support/core_ext/time/compatibility.rb +24 -0
- data/lib/active_support/core_ext/time/conversions.rb +0 -2
- data/lib/active_support/core_ext/time/zones.rb +1 -1
- data/lib/active_support/core_ext.rb +0 -1
- data/lib/active_support/current_attributes.rb +45 -40
- data/lib/active_support/delegation.rb +202 -0
- data/lib/active_support/dependencies/autoload.rb +0 -12
- data/lib/active_support/deprecation/constant_accessor.rb +47 -26
- data/lib/active_support/deprecation/proxy_wrappers.rb +9 -12
- data/lib/active_support/deprecation/reporting.rb +7 -2
- data/lib/active_support/deprecation.rb +8 -5
- data/lib/active_support/descendants_tracker.rb +9 -87
- data/lib/active_support/duration/iso8601_parser.rb +2 -2
- data/lib/active_support/duration/iso8601_serializer.rb +1 -2
- data/lib/active_support/duration.rb +11 -6
- data/lib/active_support/encrypted_file.rb +1 -1
- data/lib/active_support/error_reporter.rb +46 -5
- data/lib/active_support/evented_file_update_checker.rb +0 -1
- data/lib/active_support/execution_wrapper.rb +1 -2
- data/lib/active_support/file_update_checker.rb +2 -2
- data/lib/active_support/fork_tracker.rb +2 -38
- data/lib/active_support/gem_version.rb +3 -3
- data/lib/active_support/hash_with_indifferent_access.rb +26 -24
- data/lib/active_support/html_safe_translation.rb +3 -0
- data/lib/active_support/json/decoding.rb +1 -1
- data/lib/active_support/json/encoding.rb +23 -5
- data/lib/active_support/lazy_load_hooks.rb +1 -1
- data/lib/active_support/log_subscriber.rb +0 -12
- data/lib/active_support/logger.rb +15 -2
- data/lib/active_support/logger_thread_safe_level.rb +0 -8
- data/lib/active_support/message_encryptors.rb +2 -2
- data/lib/active_support/message_pack/extensions.rb +15 -2
- data/lib/active_support/message_verifier.rb +21 -0
- data/lib/active_support/message_verifiers.rb +5 -3
- data/lib/active_support/messages/rotator.rb +5 -0
- data/lib/active_support/multibyte/chars.rb +6 -3
- data/lib/active_support/notifications/fanout.rb +4 -7
- data/lib/active_support/notifications/instrumenter.rb +21 -18
- data/lib/active_support/notifications.rb +28 -27
- data/lib/active_support/number_helper/number_converter.rb +2 -2
- data/lib/active_support/option_merger.rb +2 -2
- data/lib/active_support/ordered_options.rb +53 -15
- data/lib/active_support/proxy_object.rb +8 -5
- data/lib/active_support/railtie.rb +4 -11
- data/lib/active_support/string_inquirer.rb +1 -1
- data/lib/active_support/subscriber.rb +1 -0
- data/lib/active_support/tagged_logging.rb +0 -1
- data/lib/active_support/test_case.rb +3 -1
- data/lib/active_support/testing/assertions.rb +4 -4
- data/lib/active_support/testing/constant_stubbing.rb +30 -8
- data/lib/active_support/testing/deprecation.rb +5 -12
- data/lib/active_support/testing/isolation.rb +20 -8
- data/lib/active_support/testing/method_call_assertions.rb +2 -16
- data/lib/active_support/testing/parallelization/server.rb +18 -2
- data/lib/active_support/testing/parallelization/worker.rb +2 -2
- data/lib/active_support/testing/parallelization.rb +12 -1
- data/lib/active_support/testing/tests_without_assertions.rb +19 -0
- data/lib/active_support/testing/time_helpers.rb +3 -3
- data/lib/active_support/time_with_zone.rb +8 -4
- data/lib/active_support/values/time_zone.rb +7 -7
- data/lib/active_support/xml_mini.rb +13 -2
- data/lib/active_support.rb +2 -1
- metadata +18 -29
- data/lib/active_support/deprecation/instance_delegator.rb +0 -65
- data/lib/active_support/ruby_features.rb +0 -7
- data/lib/active_support/testing/strict_warnings.rb +0 -39
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "weakref"
|
|
4
|
-
require "active_support/ruby_features"
|
|
5
4
|
|
|
6
5
|
module ActiveSupport
|
|
7
6
|
# = Active Support Descendants Tracker
|
|
@@ -95,96 +94,19 @@ module ActiveSupport
|
|
|
95
94
|
end
|
|
96
95
|
end
|
|
97
96
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
klass.subclasses
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def descendants(klass)
|
|
105
|
-
klass.descendants
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
def descendants
|
|
110
|
-
subclasses = DescendantsTracker.reject!(self.subclasses)
|
|
111
|
-
subclasses.concat(subclasses.flat_map(&:descendants))
|
|
112
|
-
end
|
|
113
|
-
else
|
|
114
|
-
# DescendantsArray is an array that contains weak references to classes.
|
|
115
|
-
# Note: DescendantsArray is redundant with WeakSet, however WeakSet when used
|
|
116
|
-
# on Ruby 2.7 or 3.0 can trigger a Ruby crash: https://bugs.ruby-lang.org/issues/18928
|
|
117
|
-
class DescendantsArray # :nodoc:
|
|
118
|
-
include Enumerable
|
|
119
|
-
|
|
120
|
-
def initialize
|
|
121
|
-
@refs = []
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
def <<(klass)
|
|
125
|
-
@refs << WeakRef.new(klass)
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
def each
|
|
129
|
-
@refs.reject! do |ref|
|
|
130
|
-
yield ref.__getobj__
|
|
131
|
-
false
|
|
132
|
-
rescue WeakRef::RefError
|
|
133
|
-
true
|
|
134
|
-
end
|
|
135
|
-
self
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
def refs_size
|
|
139
|
-
@refs.size
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
def cleanup!
|
|
143
|
-
@refs.delete_if { |ref| !ref.weakref_alive? }
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
def reject!
|
|
147
|
-
@refs.reject! do |ref|
|
|
148
|
-
yield ref.__getobj__
|
|
149
|
-
rescue WeakRef::RefError
|
|
150
|
-
true
|
|
151
|
-
end
|
|
152
|
-
end
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
@direct_descendants = {}
|
|
156
|
-
|
|
157
|
-
class << self
|
|
158
|
-
def subclasses(klass)
|
|
159
|
-
descendants = @direct_descendants[klass]
|
|
160
|
-
descendants ? DescendantsTracker.reject!(descendants.to_a) : []
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
def descendants(klass)
|
|
164
|
-
subclasses = self.subclasses(klass)
|
|
165
|
-
subclasses.concat(subclasses.flat_map { |k| descendants(k) })
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
# This is the only method that is not thread safe, but is only ever called
|
|
169
|
-
# during the eager loading phase.
|
|
170
|
-
def store_inherited(klass, descendant) # :nodoc:
|
|
171
|
-
(@direct_descendants[klass] ||= DescendantsArray.new) << descendant
|
|
172
|
-
end
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
def subclasses
|
|
176
|
-
DescendantsTracker.subclasses(self)
|
|
97
|
+
class << self
|
|
98
|
+
def subclasses(klass)
|
|
99
|
+
klass.subclasses
|
|
177
100
|
end
|
|
178
101
|
|
|
179
|
-
def descendants
|
|
180
|
-
|
|
102
|
+
def descendants(klass)
|
|
103
|
+
klass.descendants
|
|
181
104
|
end
|
|
105
|
+
end
|
|
182
106
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
super
|
|
187
|
-
end
|
|
107
|
+
def descendants
|
|
108
|
+
subclasses = DescendantsTracker.reject!(self.subclasses)
|
|
109
|
+
subclasses.concat(subclasses.flat_map(&:descendants))
|
|
188
110
|
end
|
|
189
111
|
end
|
|
190
112
|
end
|
|
@@ -102,12 +102,12 @@ module ActiveSupport
|
|
|
102
102
|
raise_parsing_error("is empty duration") if parts.empty?
|
|
103
103
|
|
|
104
104
|
# Mixing any of Y, M, D with W is invalid.
|
|
105
|
-
if parts.key?(:weeks) &&
|
|
105
|
+
if parts.key?(:weeks) && parts.keys.intersect?(DATE_COMPONENTS)
|
|
106
106
|
raise_parsing_error("mixing weeks with other date parts not allowed")
|
|
107
107
|
end
|
|
108
108
|
|
|
109
109
|
# Specifying an empty T part is invalid.
|
|
110
|
-
if mode == :time &&
|
|
110
|
+
if mode == :time && !parts.keys.intersect?(TIME_COMPONENTS)
|
|
111
111
|
raise_parsing_error("time part marker is present but time part is empty")
|
|
112
112
|
end
|
|
113
113
|
|
|
@@ -35,7 +35,6 @@ module ActiveSupport
|
|
|
35
35
|
# Return pair of duration's parts and whole duration sign.
|
|
36
36
|
# Parts are summarized (as they can become repetitive due to addition, etc).
|
|
37
37
|
# Zero parts are removed as not significant.
|
|
38
|
-
# If all parts are negative it will negate all of them and return minus as a sign.
|
|
39
38
|
def normalize
|
|
40
39
|
parts = @duration.parts.each_with_object(Hash.new(0)) do |(k, v), p|
|
|
41
40
|
p[k] += v unless v.zero?
|
|
@@ -50,7 +49,7 @@ module ActiveSupport
|
|
|
50
49
|
end
|
|
51
50
|
|
|
52
51
|
def week_mixed_with_date?(parts)
|
|
53
|
-
parts.key?(:weeks) &&
|
|
52
|
+
parts.key?(:weeks) && parts.keys.intersect?(DATE_COMPONENTS)
|
|
54
53
|
end
|
|
55
54
|
|
|
56
55
|
def format_seconds(seconds)
|
|
@@ -14,7 +14,7 @@ module ActiveSupport
|
|
|
14
14
|
class Duration
|
|
15
15
|
class Scalar < Numeric # :nodoc:
|
|
16
16
|
attr_reader :value
|
|
17
|
-
delegate :to_i, :to_f, :to_s, to:
|
|
17
|
+
delegate :to_i, :to_f, :to_s, to: :@value
|
|
18
18
|
|
|
19
19
|
def initialize(value)
|
|
20
20
|
@value = value
|
|
@@ -221,6 +221,8 @@ module ActiveSupport
|
|
|
221
221
|
end
|
|
222
222
|
end
|
|
223
223
|
|
|
224
|
+
Delegation.generate(self, [:to_f, :positive?, :negative?, :zero?, :abs], to: :@value, as: Integer, nilable: false)
|
|
225
|
+
|
|
224
226
|
def initialize(value, parts, variable = nil) # :nodoc:
|
|
225
227
|
@value, @parts = value, parts
|
|
226
228
|
@parts.reject! { |k, v| v.zero? } unless value == 0
|
|
@@ -232,7 +234,10 @@ module ActiveSupport
|
|
|
232
234
|
end
|
|
233
235
|
end
|
|
234
236
|
|
|
235
|
-
# Returns a copy of the parts hash that defines the duration
|
|
237
|
+
# Returns a copy of the parts hash that defines the duration.
|
|
238
|
+
#
|
|
239
|
+
# 5.minutes.parts # => {:minutes=>5}
|
|
240
|
+
# 3.years.parts # => {:years=>3}
|
|
236
241
|
def parts
|
|
237
242
|
@parts.dup
|
|
238
243
|
end
|
|
@@ -366,8 +371,8 @@ module ActiveSupport
|
|
|
366
371
|
# 1.year.to_i # => 31556952
|
|
367
372
|
#
|
|
368
373
|
# In such cases, Ruby's core
|
|
369
|
-
# Date[https://ruby-
|
|
370
|
-
# Time[https://ruby-
|
|
374
|
+
# Date[https://docs.ruby-lang.org/en/master/Date.html] and
|
|
375
|
+
# Time[https://docs.ruby-lang.org/en/master/Time.html] should be used for precision
|
|
371
376
|
# date and time arithmetic.
|
|
372
377
|
def to_i
|
|
373
378
|
@value.to_i
|
|
@@ -504,8 +509,8 @@ module ActiveSupport
|
|
|
504
509
|
value.respond_to?(method)
|
|
505
510
|
end
|
|
506
511
|
|
|
507
|
-
def method_missing(
|
|
508
|
-
value.public_send(
|
|
512
|
+
def method_missing(...)
|
|
513
|
+
value.public_send(...)
|
|
509
514
|
end
|
|
510
515
|
|
|
511
516
|
def raise_type_error(other)
|
|
@@ -26,12 +26,16 @@ module ActiveSupport
|
|
|
26
26
|
class ErrorReporter
|
|
27
27
|
SEVERITIES = %i(error warning info)
|
|
28
28
|
DEFAULT_SOURCE = "application"
|
|
29
|
+
DEFAULT_RESCUE = [StandardError].freeze
|
|
29
30
|
|
|
30
|
-
attr_accessor :logger
|
|
31
|
+
attr_accessor :logger, :debug_mode
|
|
32
|
+
|
|
33
|
+
UnexpectedError = Class.new(Exception)
|
|
31
34
|
|
|
32
35
|
def initialize(*subscribers, logger: nil)
|
|
33
36
|
@subscribers = subscribers.flatten
|
|
34
37
|
@logger = logger
|
|
38
|
+
@debug_mode = false
|
|
35
39
|
end
|
|
36
40
|
|
|
37
41
|
# Evaluates the given block, reporting and swallowing any unhandled error.
|
|
@@ -72,7 +76,7 @@ module ActiveSupport
|
|
|
72
76
|
# source of the error. Subscribers can use this value to ignore certain
|
|
73
77
|
# errors. Defaults to <tt>"application"</tt>.
|
|
74
78
|
def handle(*error_classes, severity: :warning, context: {}, fallback: nil, source: DEFAULT_SOURCE)
|
|
75
|
-
error_classes =
|
|
79
|
+
error_classes = DEFAULT_RESCUE if error_classes.empty?
|
|
76
80
|
yield
|
|
77
81
|
rescue *error_classes => error
|
|
78
82
|
report(error, handled: true, severity: severity, context: context, source: source)
|
|
@@ -108,13 +112,47 @@ module ActiveSupport
|
|
|
108
112
|
# source of the error. Subscribers can use this value to ignore certain
|
|
109
113
|
# errors. Defaults to <tt>"application"</tt>.
|
|
110
114
|
def record(*error_classes, severity: :error, context: {}, source: DEFAULT_SOURCE)
|
|
111
|
-
error_classes =
|
|
115
|
+
error_classes = DEFAULT_RESCUE if error_classes.empty?
|
|
112
116
|
yield
|
|
113
117
|
rescue *error_classes => error
|
|
114
118
|
report(error, handled: false, severity: severity, context: context, source: source)
|
|
115
119
|
raise
|
|
116
120
|
end
|
|
117
121
|
|
|
122
|
+
# Either report the given error when in production, or raise it when in development or test.
|
|
123
|
+
#
|
|
124
|
+
# When called in production, after the error is reported, this method will return
|
|
125
|
+
# nil and execution will continue.
|
|
126
|
+
#
|
|
127
|
+
# When called in development, the original error is wrapped in a different error class to ensure
|
|
128
|
+
# it's not being rescued higher in the stack and will be surfaced to the developer.
|
|
129
|
+
#
|
|
130
|
+
# This method is intended for reporting violated assertions about preconditions, or similar
|
|
131
|
+
# cases that can and should be gracefully handled in production, but that aren't supposed to happen.
|
|
132
|
+
#
|
|
133
|
+
# The error can be either an exception instance or a String.
|
|
134
|
+
#
|
|
135
|
+
# example:
|
|
136
|
+
#
|
|
137
|
+
# def edit
|
|
138
|
+
# if published?
|
|
139
|
+
# Rails.error.unexpected("[BUG] Attempting to edit a published article, that shouldn't be possible")
|
|
140
|
+
# return false
|
|
141
|
+
# end
|
|
142
|
+
# # ...
|
|
143
|
+
# end
|
|
144
|
+
#
|
|
145
|
+
def unexpected(error, severity: :warning, context: {}, source: DEFAULT_SOURCE)
|
|
146
|
+
error = RuntimeError.new(error) if error.is_a?(String)
|
|
147
|
+
error.set_backtrace(caller(1)) if error.backtrace.nil?
|
|
148
|
+
|
|
149
|
+
if @debug_mode
|
|
150
|
+
raise UnexpectedError, "#{error.class.name}: #{error.message}", error.backtrace, cause: error
|
|
151
|
+
else
|
|
152
|
+
report(error, handled: true, severity: severity, context: context, source: source)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
118
156
|
# Register a new error subscriber. The subscriber must respond to
|
|
119
157
|
#
|
|
120
158
|
# report(Exception, handled: Boolean, severity: (:error OR :warning OR :info), context: Hash, source: String)
|
|
@@ -193,8 +231,11 @@ module ActiveSupport
|
|
|
193
231
|
end
|
|
194
232
|
end
|
|
195
233
|
|
|
196
|
-
|
|
197
|
-
error.
|
|
234
|
+
while error
|
|
235
|
+
unless error.frozen?
|
|
236
|
+
error.instance_variable_set(:@__rails_error_reported, true)
|
|
237
|
+
end
|
|
238
|
+
error = error.cause
|
|
198
239
|
end
|
|
199
240
|
|
|
200
241
|
nil
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
require "active_support/error_reporter"
|
|
4
4
|
require "active_support/callbacks"
|
|
5
|
-
require "concurrent/hash"
|
|
6
5
|
|
|
7
6
|
module ActiveSupport
|
|
8
7
|
class ExecutionWrapper
|
|
@@ -90,7 +89,7 @@ module ActiveSupport
|
|
|
90
89
|
instance = run!
|
|
91
90
|
begin
|
|
92
91
|
yield
|
|
93
|
-
rescue => error
|
|
92
|
+
rescue Exception => error
|
|
94
93
|
error_reporter&.report(error, handled: false, source: source)
|
|
95
94
|
raise
|
|
96
95
|
ensure
|
|
@@ -104,7 +104,7 @@ module ActiveSupport
|
|
|
104
104
|
@watched || begin
|
|
105
105
|
all = @files.select { |f| File.exist?(f) }
|
|
106
106
|
all.concat(Dir[@glob]) if @glob
|
|
107
|
-
all
|
|
107
|
+
all.tap(&:uniq!)
|
|
108
108
|
end
|
|
109
109
|
end
|
|
110
110
|
|
|
@@ -120,7 +120,7 @@ module ActiveSupport
|
|
|
120
120
|
# healthy to consider this edge case because with mtimes in the future
|
|
121
121
|
# reloading is not triggered.
|
|
122
122
|
def max_mtime(paths)
|
|
123
|
-
time_now = Time.
|
|
123
|
+
time_now = Time.at(0, Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond), :nanosecond)
|
|
124
124
|
max_mtime = nil
|
|
125
125
|
|
|
126
126
|
# Time comparisons are performed with #compare_without_coercion because
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module ActiveSupport
|
|
4
4
|
module ForkTracker # :nodoc:
|
|
5
|
-
module
|
|
5
|
+
module CoreExt
|
|
6
6
|
def _fork
|
|
7
7
|
pid = super
|
|
8
8
|
if pid == 0
|
|
@@ -12,27 +12,6 @@ module ActiveSupport
|
|
|
12
12
|
end
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
module CoreExt
|
|
16
|
-
def fork(...)
|
|
17
|
-
if block_given?
|
|
18
|
-
super do
|
|
19
|
-
ForkTracker.check!
|
|
20
|
-
yield
|
|
21
|
-
end
|
|
22
|
-
else
|
|
23
|
-
unless pid = super
|
|
24
|
-
ForkTracker.check!
|
|
25
|
-
end
|
|
26
|
-
pid
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
module CoreExtPrivate
|
|
32
|
-
include CoreExt
|
|
33
|
-
private :fork
|
|
34
|
-
end
|
|
35
|
-
|
|
36
15
|
@pid = Process.pid
|
|
37
16
|
@callbacks = []
|
|
38
17
|
|
|
@@ -45,23 +24,8 @@ module ActiveSupport
|
|
|
45
24
|
end
|
|
46
25
|
end
|
|
47
26
|
|
|
48
|
-
if Process.respond_to?(:_fork) # Ruby 3.1+
|
|
49
|
-
def check!
|
|
50
|
-
# We trust the `_fork` callback
|
|
51
|
-
end
|
|
52
|
-
else
|
|
53
|
-
alias_method :check!, :after_fork_callback
|
|
54
|
-
end
|
|
55
|
-
|
|
56
27
|
def hook!
|
|
57
|
-
|
|
58
|
-
::Process.singleton_class.prepend(ModernCoreExt)
|
|
59
|
-
elsif Process.respond_to?(:fork)
|
|
60
|
-
::Object.prepend(CoreExtPrivate) if RUBY_VERSION < "3.0"
|
|
61
|
-
::Kernel.prepend(CoreExtPrivate)
|
|
62
|
-
::Kernel.singleton_class.prepend(CoreExt)
|
|
63
|
-
::Process.singleton_class.prepend(CoreExt)
|
|
64
|
-
end
|
|
28
|
+
::Process.singleton_class.prepend(CoreExt)
|
|
65
29
|
end
|
|
66
30
|
|
|
67
31
|
def after_fork(&block)
|
|
@@ -262,9 +262,7 @@ module ActiveSupport
|
|
|
262
262
|
# hash[:a][:c] # => "c"
|
|
263
263
|
# dup[:a][:c] # => "c"
|
|
264
264
|
def dup
|
|
265
|
-
self.class.new(self)
|
|
266
|
-
set_defaults(new_hash)
|
|
267
|
-
end
|
|
265
|
+
copy_defaults(self.class.new(self))
|
|
268
266
|
end
|
|
269
267
|
|
|
270
268
|
# This method has the same semantics of +update+, except it does not
|
|
@@ -342,21 +340,26 @@ module ActiveSupport
|
|
|
342
340
|
NOT_GIVEN = Object.new # :nodoc:
|
|
343
341
|
|
|
344
342
|
def transform_keys(hash = NOT_GIVEN, &block)
|
|
345
|
-
|
|
346
|
-
|
|
343
|
+
if NOT_GIVEN.equal?(hash)
|
|
344
|
+
if block_given?
|
|
345
|
+
self.class.new(super(&block))
|
|
346
|
+
else
|
|
347
|
+
to_enum(:transform_keys)
|
|
348
|
+
end
|
|
349
|
+
else
|
|
350
|
+
self.class.new(super)
|
|
351
|
+
end
|
|
347
352
|
end
|
|
348
353
|
|
|
349
354
|
def transform_keys!(hash = NOT_GIVEN, &block)
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
elsif block_given?
|
|
357
|
-
keys.each { |key| self[hash[key] || yield(key)] = delete(key) }
|
|
355
|
+
if NOT_GIVEN.equal?(hash)
|
|
356
|
+
if block_given?
|
|
357
|
+
replace(copy_defaults(transform_keys(&block)))
|
|
358
|
+
else
|
|
359
|
+
return to_enum(:transform_keys!)
|
|
360
|
+
end
|
|
358
361
|
else
|
|
359
|
-
|
|
362
|
+
replace(copy_defaults(transform_keys(hash, &block)))
|
|
360
363
|
end
|
|
361
364
|
|
|
362
365
|
self
|
|
@@ -379,7 +382,7 @@ module ActiveSupport
|
|
|
379
382
|
# Convert to a regular hash with string keys.
|
|
380
383
|
def to_hash
|
|
381
384
|
_new_hash = Hash.new
|
|
382
|
-
|
|
385
|
+
copy_defaults(_new_hash)
|
|
383
386
|
|
|
384
387
|
each do |key, value|
|
|
385
388
|
_new_hash[key] = convert_value(value, conversion: :to_hash)
|
|
@@ -387,15 +390,13 @@ module ActiveSupport
|
|
|
387
390
|
_new_hash
|
|
388
391
|
end
|
|
389
392
|
|
|
393
|
+
def to_proc
|
|
394
|
+
proc { |key| self[key] }
|
|
395
|
+
end
|
|
396
|
+
|
|
390
397
|
private
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
key.kind_of?(Symbol) ? key.name : key
|
|
394
|
-
end
|
|
395
|
-
else
|
|
396
|
-
def convert_key(key)
|
|
397
|
-
key.kind_of?(Symbol) ? key.to_s : key
|
|
398
|
-
end
|
|
398
|
+
def convert_key(key)
|
|
399
|
+
Symbol === key ? key.name : key
|
|
399
400
|
end
|
|
400
401
|
|
|
401
402
|
def convert_value(value, conversion: nil)
|
|
@@ -415,12 +416,13 @@ module ActiveSupport
|
|
|
415
416
|
end
|
|
416
417
|
end
|
|
417
418
|
|
|
418
|
-
def
|
|
419
|
+
def copy_defaults(target)
|
|
419
420
|
if default_proc
|
|
420
421
|
target.default_proc = default_proc.dup
|
|
421
422
|
else
|
|
422
423
|
target.default = default
|
|
423
424
|
end
|
|
425
|
+
target
|
|
424
426
|
end
|
|
425
427
|
|
|
426
428
|
def update_with_single_argument(other_hash, block)
|
|
@@ -9,11 +9,14 @@ module ActiveSupport
|
|
|
9
9
|
html_safe_options = html_escape_translation_options(options)
|
|
10
10
|
|
|
11
11
|
exception = false
|
|
12
|
+
|
|
12
13
|
exception_handler = ->(*args) do
|
|
13
14
|
exception = true
|
|
14
15
|
I18n.exception_handler.call(*args)
|
|
15
16
|
end
|
|
17
|
+
|
|
16
18
|
translation = I18n.translate(key, **html_safe_options, exception_handler: exception_handler)
|
|
19
|
+
|
|
17
20
|
if exception
|
|
18
21
|
translation
|
|
19
22
|
else
|
|
@@ -18,7 +18,7 @@ module ActiveSupport
|
|
|
18
18
|
# See http://www.json.org for more info.
|
|
19
19
|
#
|
|
20
20
|
# ActiveSupport::JSON.decode("{\"team\":\"rails\",\"players\":\"36\"}")
|
|
21
|
-
# => {"team" => "rails", "players" => "36"}
|
|
21
|
+
# # => {"team" => "rails", "players" => "36"}
|
|
22
22
|
def decode(json)
|
|
23
23
|
data = ::JSON.parse(json, quirks_mode: true)
|
|
24
24
|
|
|
@@ -13,12 +13,30 @@ module ActiveSupport
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
module JSON
|
|
16
|
-
# Dumps objects in JSON (JavaScript Object Notation).
|
|
17
|
-
# See http://www.json.org for more info.
|
|
18
|
-
#
|
|
19
|
-
# ActiveSupport::JSON.encode({ team: 'rails', players: '36' })
|
|
20
|
-
# # => "{\"team\":\"rails\",\"players\":\"36\"}"
|
|
21
16
|
class << self
|
|
17
|
+
# Dumps objects in JSON (JavaScript Object Notation).
|
|
18
|
+
# See http://www.json.org for more info.
|
|
19
|
+
#
|
|
20
|
+
# ActiveSupport::JSON.encode({ team: 'rails', players: '36' })
|
|
21
|
+
# # => "{\"team\":\"rails\",\"players\":\"36\"}"
|
|
22
|
+
#
|
|
23
|
+
# Generates JSON that is safe to include in JavaScript as it escapes
|
|
24
|
+
# U+2028 (Line Separator) and U+2029 (Paragraph Separator):
|
|
25
|
+
#
|
|
26
|
+
# ActiveSupport::JSON.encode({ key: "\u2028" })
|
|
27
|
+
# # => "{\"key\":\"\\u2028\"}"
|
|
28
|
+
#
|
|
29
|
+
# By default, it also generates JSON that is safe to include in HTML, as
|
|
30
|
+
# it escapes <tt><</tt>, <tt>></tt>, and <tt>&</tt>:
|
|
31
|
+
#
|
|
32
|
+
# ActiveSupport::JSON.encode({ key: "<>&" })
|
|
33
|
+
# # => "{\"key\":\"\\u003c\\u003e\\u0026\"}"
|
|
34
|
+
#
|
|
35
|
+
# This can be changed with the +escape_html_entities+ option, or the
|
|
36
|
+
# global escape_html_entities_in_json configuration option.
|
|
37
|
+
#
|
|
38
|
+
# ActiveSupport::JSON.encode({ key: "<>&" }, escape_html_entities: false)
|
|
39
|
+
# # => "{\"key\":\"<>&\"}"
|
|
22
40
|
def encode(value, options = nil)
|
|
23
41
|
Encoding.json_encoder.new(options).encode(value)
|
|
24
42
|
end
|
|
@@ -53,7 +53,7 @@ module ActiveSupport
|
|
|
53
53
|
# loaded. If the component has already loaded, the block is executed
|
|
54
54
|
# immediately.
|
|
55
55
|
#
|
|
56
|
-
# Options
|
|
56
|
+
# ==== Options
|
|
57
57
|
#
|
|
58
58
|
# * <tt>:yield</tt> - Yields the object that run_load_hooks to +block+.
|
|
59
59
|
# * <tt>:run_once</tt> - Given +block+ will run only once.
|
|
@@ -62,10 +62,6 @@ module ActiveSupport
|
|
|
62
62
|
# that all logs are flushed, and it is called in Rails::Rack::Logger after a
|
|
63
63
|
# request finishes.
|
|
64
64
|
class LogSubscriber < Subscriber
|
|
65
|
-
# Embed in a String to clear all previous ANSI sequences.
|
|
66
|
-
CLEAR = ActiveSupport::Deprecation::DeprecatedObjectProxy.new("\e[0m", "CLEAR is deprecated! Use MODES[:clear] instead.", ActiveSupport.deprecator)
|
|
67
|
-
BOLD = ActiveSupport::Deprecation::DeprecatedObjectProxy.new("\e[1m", "BOLD is deprecated! Use MODES[:bold] instead.", ActiveSupport.deprecator)
|
|
68
|
-
|
|
69
65
|
# ANSI sequence modes
|
|
70
66
|
MODES = {
|
|
71
67
|
clear: 0,
|
|
@@ -182,14 +178,6 @@ module ActiveSupport
|
|
|
182
178
|
end
|
|
183
179
|
|
|
184
180
|
def mode_from(options)
|
|
185
|
-
if options.is_a?(TrueClass) || options.is_a?(FalseClass)
|
|
186
|
-
ActiveSupport.deprecator.warn(<<~MSG.squish)
|
|
187
|
-
Bolding log text with a positional boolean is deprecated and will be removed
|
|
188
|
-
in Rails 7.2. Use an option hash instead (eg. `color("my text", :red, bold: true)`).
|
|
189
|
-
MSG
|
|
190
|
-
options = { bold: options }
|
|
191
|
-
end
|
|
192
|
-
|
|
193
181
|
modes = MODES.values_at(*options.compact_blank.keys)
|
|
194
182
|
|
|
195
183
|
"\e[#{modes.join(";")}m" if modes.any?
|
|
@@ -13,6 +13,10 @@ module ActiveSupport
|
|
|
13
13
|
# logger = Logger.new(STDOUT)
|
|
14
14
|
# ActiveSupport::Logger.logger_outputs_to?(logger, STDOUT)
|
|
15
15
|
# # => true
|
|
16
|
+
#
|
|
17
|
+
# logger = Logger.new('/var/log/rails.log')
|
|
18
|
+
# ActiveSupport::Logger.logger_outputs_to?(logger, '/var/log/rails.log')
|
|
19
|
+
# # => true
|
|
16
20
|
def self.logger_outputs_to?(logger, *sources)
|
|
17
21
|
loggers = if logger.is_a?(BroadcastLogger)
|
|
18
22
|
logger.broadcasts
|
|
@@ -21,9 +25,9 @@ module ActiveSupport
|
|
|
21
25
|
end
|
|
22
26
|
|
|
23
27
|
logdevs = loggers.map { |logger| logger.instance_variable_get(:@logdev) }
|
|
24
|
-
logger_sources = logdevs.filter_map { |logdev| logdev.
|
|
28
|
+
logger_sources = logdevs.filter_map { |logdev| logdev.try(:filename) || logdev.try(:dev) }
|
|
25
29
|
|
|
26
|
-
(sources
|
|
30
|
+
normalize_sources(sources).intersect?(normalize_sources(logger_sources))
|
|
27
31
|
end
|
|
28
32
|
|
|
29
33
|
def initialize(*args, **kwargs)
|
|
@@ -38,5 +42,14 @@ module ActiveSupport
|
|
|
38
42
|
"#{String === msg ? msg : msg.inspect}\n"
|
|
39
43
|
end
|
|
40
44
|
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
def self.normalize_sources(sources)
|
|
48
|
+
sources.map do |source|
|
|
49
|
+
source = source.path if source.respond_to?(:path)
|
|
50
|
+
source = File.realpath(source) if source.is_a?(String) && File.exist?(source)
|
|
51
|
+
source
|
|
52
|
+
end
|
|
53
|
+
end
|
|
41
54
|
end
|
|
42
55
|
end
|
|
@@ -7,14 +7,6 @@ module ActiveSupport
|
|
|
7
7
|
module LoggerThreadSafeLevel # :nodoc:
|
|
8
8
|
extend ActiveSupport::Concern
|
|
9
9
|
|
|
10
|
-
Logger::Severity.constants.each do |severity|
|
|
11
|
-
class_eval(<<-EOT, __FILE__, __LINE__ + 1)
|
|
12
|
-
def #{severity.downcase}? # def debug?
|
|
13
|
-
Logger::#{severity} >= level # DEBUG >= level
|
|
14
|
-
end # end
|
|
15
|
-
EOT
|
|
16
|
-
end
|
|
17
|
-
|
|
18
10
|
def local_level
|
|
19
11
|
IsolatedExecutionState[local_level_key]
|
|
20
12
|
end
|
|
@@ -28,8 +28,8 @@ module ActiveSupport
|
|
|
28
28
|
# <tt>transitional = false</tt>.
|
|
29
29
|
|
|
30
30
|
##
|
|
31
|
-
# :method:
|
|
32
|
-
# :call-seq:
|
|
31
|
+
# :singleton-method: new
|
|
32
|
+
# :call-seq: new(&secret_generator)
|
|
33
33
|
#
|
|
34
34
|
# Initializes a new instance. +secret_generator+ must accept a salt and a
|
|
35
35
|
# +secret_length+ kwarg, and return a suitable secret (string) or secrets
|