activesupport 8.0.0 → 8.1.0
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 +391 -67
- data/README.rdoc +1 -1
- data/lib/active_support/backtrace_cleaner.rb +72 -1
- data/lib/active_support/broadcast_logger.rb +61 -74
- data/lib/active_support/cache/file_store.rb +2 -2
- data/lib/active_support/cache/mem_cache_store.rb +26 -28
- data/lib/active_support/cache/memory_store.rb +5 -5
- data/lib/active_support/cache/null_store.rb +2 -2
- data/lib/active_support/cache/redis_cache_store.rb +37 -31
- data/lib/active_support/cache/strategy/local_cache.rb +72 -27
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +7 -7
- data/lib/active_support/cache.rb +72 -9
- data/lib/active_support/callbacks.rb +27 -11
- data/lib/active_support/class_attribute.rb +15 -8
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +8 -62
- data/lib/active_support/concurrency/thread_monitor.rb +55 -0
- data/lib/active_support/configurable.rb +34 -0
- data/lib/active_support/continuous_integration.rb +145 -0
- data/lib/active_support/core_ext/array/conversions.rb +3 -3
- data/lib/active_support/core_ext/array.rb +7 -7
- data/lib/active_support/core_ext/benchmark.rb +4 -11
- data/lib/active_support/core_ext/big_decimal.rb +1 -1
- data/lib/active_support/core_ext/class/attribute.rb +20 -5
- data/lib/active_support/core_ext/class.rb +2 -2
- data/lib/active_support/core_ext/date.rb +5 -5
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +0 -35
- data/lib/active_support/core_ext/date_time/compatibility.rb +3 -5
- data/lib/active_support/core_ext/date_time/conversions.rb +4 -2
- data/lib/active_support/core_ext/date_time.rb +5 -5
- data/lib/active_support/core_ext/digest.rb +1 -1
- data/lib/active_support/core_ext/enumerable.rb +17 -5
- data/lib/active_support/core_ext/erb/util.rb +5 -5
- data/lib/active_support/core_ext/file.rb +1 -1
- data/lib/active_support/core_ext/hash/deep_merge.rb +1 -0
- data/lib/active_support/core_ext/hash.rb +8 -8
- data/lib/active_support/core_ext/integer.rb +3 -3
- data/lib/active_support/core_ext/kernel.rb +3 -3
- data/lib/active_support/core_ext/module/introspection.rb +3 -0
- data/lib/active_support/core_ext/module.rb +11 -11
- data/lib/active_support/core_ext/numeric.rb +3 -3
- data/lib/active_support/core_ext/object/json.rb +8 -1
- data/lib/active_support/core_ext/object/to_query.rb +7 -1
- data/lib/active_support/core_ext/object/try.rb +2 -2
- data/lib/active_support/core_ext/object.rb +13 -13
- data/lib/active_support/core_ext/pathname.rb +2 -2
- data/lib/active_support/core_ext/range/overlap.rb +3 -3
- data/lib/active_support/core_ext/range/sole.rb +17 -0
- data/lib/active_support/core_ext/range.rb +4 -4
- data/lib/active_support/core_ext/securerandom.rb +24 -8
- data/lib/active_support/core_ext/string/filters.rb +3 -3
- data/lib/active_support/core_ext/string/multibyte.rb +12 -3
- data/lib/active_support/core_ext/string/output_safety.rb +19 -12
- data/lib/active_support/core_ext/string.rb +13 -13
- data/lib/active_support/core_ext/symbol.rb +1 -1
- data/lib/active_support/core_ext/time/calculations.rb +0 -7
- data/lib/active_support/core_ext/time/compatibility.rb +2 -27
- data/lib/active_support/core_ext/time.rb +5 -5
- data/lib/active_support/core_ext.rb +1 -1
- data/lib/active_support/current_attributes/test_helper.rb +2 -2
- data/lib/active_support/current_attributes.rb +27 -17
- data/lib/active_support/dependencies/interlock.rb +11 -5
- data/lib/active_support/dependencies.rb +6 -1
- data/lib/active_support/deprecation/reporting.rb +4 -2
- data/lib/active_support/deprecation.rb +1 -1
- data/lib/active_support/editor.rb +70 -0
- data/lib/active_support/error_reporter.rb +61 -8
- data/lib/active_support/event_reporter/test_helper.rb +32 -0
- data/lib/active_support/event_reporter.rb +592 -0
- data/lib/active_support/evented_file_update_checker.rb +5 -1
- data/lib/active_support/execution_context.rb +64 -7
- data/lib/active_support/execution_wrapper.rb +1 -1
- data/lib/active_support/file_update_checker.rb +8 -6
- data/lib/active_support/gem_version.rb +1 -1
- data/lib/active_support/gzip.rb +1 -0
- data/lib/active_support/hash_with_indifferent_access.rb +47 -24
- data/lib/active_support/i18n_railtie.rb +1 -2
- data/lib/active_support/inflector/inflections.rb +31 -15
- data/lib/active_support/inflector/transliterate.rb +6 -8
- data/lib/active_support/isolated_execution_state.rb +12 -15
- data/lib/active_support/json/decoding.rb +6 -4
- data/lib/active_support/json/encoding.rb +155 -19
- data/lib/active_support/lazy_load_hooks.rb +1 -1
- data/lib/active_support/log_subscriber.rb +2 -6
- data/lib/active_support/logger_thread_safe_level.rb +6 -3
- data/lib/active_support/message_encryptors.rb +54 -2
- data/lib/active_support/message_pack/extensions.rb +5 -0
- data/lib/active_support/message_verifier.rb +9 -0
- data/lib/active_support/message_verifiers.rb +57 -3
- data/lib/active_support/messages/rotation_coordinator.rb +9 -0
- data/lib/active_support/messages/rotator.rb +10 -0
- data/lib/active_support/multibyte/chars.rb +12 -2
- data/lib/active_support/multibyte.rb +4 -0
- data/lib/active_support/notifications/fanout.rb +64 -42
- data/lib/active_support/notifications/instrumenter.rb +1 -1
- data/lib/active_support/railtie.rb +32 -13
- data/lib/active_support/structured_event_subscriber.rb +99 -0
- data/lib/active_support/subscriber.rb +0 -5
- data/lib/active_support/syntax_error_proxy.rb +3 -0
- data/lib/active_support/test_case.rb +61 -6
- data/lib/active_support/testing/assertions.rb +34 -6
- data/lib/active_support/testing/error_reporter_assertions.rb +18 -1
- data/lib/active_support/testing/event_reporter_assertions.rb +227 -0
- data/lib/active_support/testing/notification_assertions.rb +92 -0
- data/lib/active_support/testing/parallelization/server.rb +15 -2
- data/lib/active_support/testing/parallelization/worker.rb +4 -2
- data/lib/active_support/testing/parallelization.rb +25 -1
- data/lib/active_support/testing/tests_without_assertions.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +7 -3
- data/lib/active_support/time_with_zone.rb +23 -23
- data/lib/active_support/values/time_zone.rb +8 -1
- data/lib/active_support/xml_mini.rb +3 -2
- data/lib/active_support.rb +20 -15
- metadata +27 -23
- data/lib/active_support/core_ext/range/each.rb +0 -24
- data/lib/active_support/testing/strict_warnings.rb +0 -43
|
@@ -67,14 +67,13 @@ module ActiveSupport # :nodoc:
|
|
|
67
67
|
original_concat(value)
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
-
def initialize(
|
|
71
|
-
@html_safe = true
|
|
70
|
+
def initialize(_str = "")
|
|
72
71
|
super
|
|
73
72
|
end
|
|
74
73
|
|
|
75
74
|
def initialize_copy(other)
|
|
76
75
|
super
|
|
77
|
-
@
|
|
76
|
+
@html_unsafe = true unless other.html_safe?
|
|
78
77
|
end
|
|
79
78
|
|
|
80
79
|
def concat(value)
|
|
@@ -116,7 +115,9 @@ module ActiveSupport # :nodoc:
|
|
|
116
115
|
def *(_)
|
|
117
116
|
new_string = super
|
|
118
117
|
new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
|
|
119
|
-
|
|
118
|
+
if @html_unsafe
|
|
119
|
+
new_safe_buffer.instance_variable_set(:@html_unsafe, true)
|
|
120
|
+
end
|
|
120
121
|
new_safe_buffer
|
|
121
122
|
end
|
|
122
123
|
|
|
@@ -131,14 +132,18 @@ module ActiveSupport # :nodoc:
|
|
|
131
132
|
self.class.new(super(escaped_args))
|
|
132
133
|
end
|
|
133
134
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
135
|
+
def html_safe?
|
|
136
|
+
@html_unsafe.nil?
|
|
137
|
+
end
|
|
137
138
|
|
|
138
139
|
def to_s
|
|
139
140
|
self
|
|
140
141
|
end
|
|
141
142
|
|
|
143
|
+
def as_json(*)
|
|
144
|
+
to_str
|
|
145
|
+
end
|
|
146
|
+
|
|
142
147
|
def to_param
|
|
143
148
|
to_str
|
|
144
149
|
end
|
|
@@ -155,7 +160,7 @@ module ActiveSupport # :nodoc:
|
|
|
155
160
|
end # end
|
|
156
161
|
|
|
157
162
|
def #{unsafe_method}!(*args) # def capitalize!(*args)
|
|
158
|
-
@
|
|
163
|
+
@html_unsafe = true # @html_unsafe = true
|
|
159
164
|
super # super
|
|
160
165
|
end # end
|
|
161
166
|
EOT
|
|
@@ -176,7 +181,7 @@ module ActiveSupport # :nodoc:
|
|
|
176
181
|
end # end
|
|
177
182
|
|
|
178
183
|
def #{unsafe_method}!(*args, &block) # def gsub!(*args, &block)
|
|
179
|
-
@
|
|
184
|
+
@html_unsafe = true # @html_unsafe = true
|
|
180
185
|
if block # if block
|
|
181
186
|
super(*args) { |*params| # super(*args) { |*params|
|
|
182
187
|
set_block_back_references(block, $~) # set_block_back_references(block, $~)
|
|
@@ -191,14 +196,14 @@ module ActiveSupport # :nodoc:
|
|
|
191
196
|
|
|
192
197
|
private
|
|
193
198
|
def explicit_html_escape_interpolated_argument(arg)
|
|
194
|
-
(!html_safe? || arg.html_safe?) ? arg :
|
|
199
|
+
(!html_safe? || arg.html_safe?) ? arg : ERB::Util.unwrapped_html_escape(arg)
|
|
195
200
|
end
|
|
196
201
|
|
|
197
202
|
def implicit_html_escape_interpolated_argument(arg)
|
|
198
203
|
if !html_safe? || arg.html_safe?
|
|
199
204
|
arg
|
|
200
205
|
else
|
|
201
|
-
|
|
206
|
+
ERB::Util.unwrapped_html_escape(arg.to_str)
|
|
202
207
|
end
|
|
203
208
|
end
|
|
204
209
|
|
|
@@ -210,7 +215,9 @@ module ActiveSupport # :nodoc:
|
|
|
210
215
|
|
|
211
216
|
def string_into_safe_buffer(new_string, is_html_safe)
|
|
212
217
|
new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
|
|
213
|
-
|
|
218
|
+
unless is_html_safe
|
|
219
|
+
new_safe_buffer.instance_variable_set :@html_unsafe, true
|
|
220
|
+
end
|
|
214
221
|
new_safe_buffer
|
|
215
222
|
end
|
|
216
223
|
end
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
3
|
+
require_relative "string/conversions"
|
|
4
|
+
require_relative "string/filters"
|
|
5
|
+
require_relative "string/multibyte"
|
|
6
|
+
require_relative "string/starts_ends_with"
|
|
7
|
+
require_relative "string/inflections"
|
|
8
|
+
require_relative "string/access"
|
|
9
|
+
require_relative "string/behavior"
|
|
10
|
+
require_relative "string/output_safety"
|
|
11
|
+
require_relative "string/exclude"
|
|
12
|
+
require_relative "string/strip"
|
|
13
|
+
require_relative "string/inquiry"
|
|
14
|
+
require_relative "string/indent"
|
|
15
|
+
require_relative "string/zones"
|
|
@@ -224,13 +224,6 @@ class Time
|
|
|
224
224
|
# Returns a new Time representing the time a number of seconds since the instance time
|
|
225
225
|
def since(seconds)
|
|
226
226
|
self + seconds
|
|
227
|
-
rescue TypeError
|
|
228
|
-
result = to_datetime.since(seconds)
|
|
229
|
-
ActiveSupport.deprecator.warn(
|
|
230
|
-
"Passing an instance of #{seconds.class} to #{self.class}#since is deprecated. This behavior will raise " \
|
|
231
|
-
"a `TypeError` in Rails 8.1."
|
|
232
|
-
)
|
|
233
|
-
result
|
|
234
227
|
end
|
|
235
228
|
alias :in :since
|
|
236
229
|
|
|
@@ -8,33 +8,8 @@ class Time
|
|
|
8
8
|
|
|
9
9
|
silence_redefinition_of_method :to_time
|
|
10
10
|
|
|
11
|
-
#
|
|
12
|
-
# on the setting of +ActiveSupport.to_time_preserves_timezone+.
|
|
11
|
+
# Return +self+.
|
|
13
12
|
def to_time
|
|
14
|
-
|
|
13
|
+
self
|
|
15
14
|
end
|
|
16
|
-
|
|
17
|
-
def preserve_timezone # :nodoc:
|
|
18
|
-
system_local_time? || super
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
private
|
|
22
|
-
def system_local_time?
|
|
23
|
-
if ::Time.equal?(self.class)
|
|
24
|
-
zone = self.zone
|
|
25
|
-
String === zone &&
|
|
26
|
-
(zone != "UTC" || active_support_local_zone == "UTC")
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
@@active_support_local_tz = nil
|
|
31
|
-
|
|
32
|
-
def active_support_local_zone
|
|
33
|
-
@@active_support_local_zone = nil if @@active_support_local_tz != ENV["TZ"]
|
|
34
|
-
@@active_support_local_zone ||=
|
|
35
|
-
begin
|
|
36
|
-
@@active_support_local_tz = ENV["TZ"]
|
|
37
|
-
Time.new.zone
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
15
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
require_relative "time/acts_like"
|
|
4
|
+
require_relative "time/calculations"
|
|
5
|
+
require_relative "time/compatibility"
|
|
6
|
+
require_relative "time/conversions"
|
|
7
|
+
require_relative "time/zones"
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
module ActiveSupport::CurrentAttributes::TestHelper # :nodoc:
|
|
4
4
|
def before_setup
|
|
5
|
-
ActiveSupport::CurrentAttributes.
|
|
5
|
+
ActiveSupport::CurrentAttributes.clear_all
|
|
6
6
|
super
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
def after_teardown
|
|
10
10
|
super
|
|
11
|
-
ActiveSupport::CurrentAttributes.
|
|
11
|
+
ActiveSupport::CurrentAttributes.clear_all
|
|
12
12
|
end
|
|
13
13
|
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "active_support/callbacks"
|
|
4
|
+
require "active_support/execution_context"
|
|
4
5
|
require "active_support/core_ext/object/with"
|
|
5
6
|
require "active_support/core_ext/enumerable"
|
|
6
7
|
require "active_support/core_ext/module/delegation"
|
|
@@ -108,35 +109,35 @@ module ActiveSupport
|
|
|
108
109
|
# ==== Options
|
|
109
110
|
#
|
|
110
111
|
# * <tt>:default</tt> - The default value for the attributes. If the value
|
|
111
|
-
#
|
|
112
|
-
#
|
|
113
|
-
#
|
|
112
|
+
# is a proc or lambda, it will be called whenever an instance is
|
|
113
|
+
# constructed. Otherwise, the value will be duplicated with +#dup+.
|
|
114
|
+
# Default values are re-assigned when the attributes are reset.
|
|
114
115
|
def attribute(*names, default: NOT_SET)
|
|
115
116
|
invalid_attribute_names = names.map(&:to_sym) & INVALID_ATTRIBUTE_NAMES
|
|
116
117
|
if invalid_attribute_names.any?
|
|
117
118
|
raise ArgumentError, "Restricted attribute names: #{invalid_attribute_names.join(", ")}"
|
|
118
119
|
end
|
|
119
120
|
|
|
121
|
+
Delegation.generate(singleton_class, names, to: :instance, nilable: false, signature: "")
|
|
122
|
+
Delegation.generate(singleton_class, names.map { |n| "#{n}=" }, to: :instance, nilable: false, signature: "value")
|
|
123
|
+
|
|
120
124
|
ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |owner|
|
|
121
125
|
names.each do |name|
|
|
122
126
|
owner.define_cached_method(name, namespace: :current_attributes) do |batch|
|
|
123
127
|
batch <<
|
|
124
128
|
"def #{name}" <<
|
|
125
|
-
"attributes[:#{name}]" <<
|
|
129
|
+
"@attributes[:#{name}]" <<
|
|
126
130
|
"end"
|
|
127
131
|
end
|
|
128
132
|
owner.define_cached_method("#{name}=", namespace: :current_attributes) do |batch|
|
|
129
133
|
batch <<
|
|
130
134
|
"def #{name}=(value)" <<
|
|
131
|
-
"attributes[:#{name}] = value" <<
|
|
135
|
+
"@attributes[:#{name}] = value" <<
|
|
132
136
|
"end"
|
|
133
137
|
end
|
|
134
138
|
end
|
|
135
139
|
end
|
|
136
140
|
|
|
137
|
-
Delegation.generate(singleton_class, names, to: :instance, nilable: false, signature: "")
|
|
138
|
-
Delegation.generate(singleton_class, names.map { |n| "#{n}=" }, to: :instance, nilable: false, signature: "value")
|
|
139
|
-
|
|
140
141
|
self.defaults = defaults.merge(names.index_with { default })
|
|
141
142
|
end
|
|
142
143
|
|
|
@@ -153,13 +154,11 @@ module ActiveSupport
|
|
|
153
154
|
|
|
154
155
|
delegate :set, :reset, to: :instance
|
|
155
156
|
|
|
156
|
-
def reset_all # :nodoc:
|
|
157
|
-
current_instances.each_value(&:reset)
|
|
158
|
-
end
|
|
159
|
-
|
|
160
157
|
def clear_all # :nodoc:
|
|
161
|
-
|
|
162
|
-
|
|
158
|
+
if instances = current_instances
|
|
159
|
+
instances.values.each(&:reset)
|
|
160
|
+
instances.clear
|
|
161
|
+
end
|
|
163
162
|
end
|
|
164
163
|
|
|
165
164
|
private
|
|
@@ -168,7 +167,7 @@ module ActiveSupport
|
|
|
168
167
|
end
|
|
169
168
|
|
|
170
169
|
def current_instances
|
|
171
|
-
|
|
170
|
+
ExecutionContext.current_attributes_instances
|
|
172
171
|
end
|
|
173
172
|
|
|
174
173
|
def current_instances_key
|
|
@@ -185,21 +184,32 @@ module ActiveSupport
|
|
|
185
184
|
|
|
186
185
|
def method_added(name)
|
|
187
186
|
super
|
|
187
|
+
|
|
188
|
+
# We try to generate instance delegators early to not rely on method_missing.
|
|
188
189
|
return if name == :initialize
|
|
190
|
+
|
|
191
|
+
# If the added method isn't public, we don't delegate it.
|
|
189
192
|
return unless public_method_defined?(name)
|
|
190
|
-
|
|
193
|
+
|
|
194
|
+
# If we already have a class method by that name, we don't override it.
|
|
195
|
+
return if singleton_class.method_defined?(name) || singleton_class.private_method_defined?(name)
|
|
196
|
+
|
|
191
197
|
Delegation.generate(singleton_class, [name], to: :instance, as: self, nilable: false)
|
|
192
198
|
end
|
|
193
199
|
end
|
|
194
200
|
|
|
195
201
|
class_attribute :defaults, instance_writer: false, default: {}.freeze
|
|
196
202
|
|
|
197
|
-
|
|
203
|
+
attr_writer :attributes
|
|
198
204
|
|
|
199
205
|
def initialize
|
|
200
206
|
@attributes = resolve_defaults
|
|
201
207
|
end
|
|
202
208
|
|
|
209
|
+
def attributes
|
|
210
|
+
@attributes.dup
|
|
211
|
+
end
|
|
212
|
+
|
|
203
213
|
# Expose one or more attributes within a block. Old values are returned after the block concludes.
|
|
204
214
|
# Example demonstrating the common use of needing to set Current attributes outside the request-cycle:
|
|
205
215
|
#
|
|
@@ -10,19 +10,24 @@ module ActiveSupport # :nodoc:
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def loading(&block)
|
|
13
|
-
|
|
13
|
+
ActiveSupport.deprecator.warn(
|
|
14
|
+
"ActiveSupport::Dependencies::Interlock#loading is deprecated and " \
|
|
15
|
+
"will be removed in Rails 9.0. The loading interlock is no longer " \
|
|
16
|
+
"used since Rails switched to Zeitwerk for autoloading."
|
|
17
|
+
)
|
|
18
|
+
yield if block
|
|
14
19
|
end
|
|
15
20
|
|
|
16
21
|
def unloading(&block)
|
|
17
|
-
@lock.exclusive(purpose: :unload, compatible: [:
|
|
22
|
+
@lock.exclusive(purpose: :unload, compatible: [:unload], after_compatible: [:unload], &block)
|
|
18
23
|
end
|
|
19
24
|
|
|
20
25
|
def start_unloading
|
|
21
|
-
@lock.start_exclusive(purpose: :unload, compatible: [:
|
|
26
|
+
@lock.start_exclusive(purpose: :unload, compatible: [:unload])
|
|
22
27
|
end
|
|
23
28
|
|
|
24
29
|
def done_unloading
|
|
25
|
-
@lock.stop_exclusive(compatible: [:
|
|
30
|
+
@lock.stop_exclusive(compatible: [:unload])
|
|
26
31
|
end
|
|
27
32
|
|
|
28
33
|
def start_running
|
|
@@ -38,7 +43,8 @@ module ActiveSupport # :nodoc:
|
|
|
38
43
|
end
|
|
39
44
|
|
|
40
45
|
def permit_concurrent_loads(&block)
|
|
41
|
-
|
|
46
|
+
# Soft deprecated: no deprecation warning for now, but this is a no-op.
|
|
47
|
+
yield if block
|
|
42
48
|
end
|
|
43
49
|
|
|
44
50
|
def raw_state(&block) # :nodoc:
|
|
@@ -21,7 +21,12 @@ module ActiveSupport # :nodoc:
|
|
|
21
21
|
# preventing any other thread from being inside a #run_interlock
|
|
22
22
|
# block at the same time.
|
|
23
23
|
def self.load_interlock(&block)
|
|
24
|
-
|
|
24
|
+
ActiveSupport.deprecator.warn(
|
|
25
|
+
"ActiveSupport::Dependencies.load_interlock is deprecated and " \
|
|
26
|
+
"will be removed in Rails 9.0. The loading interlock is no longer " \
|
|
27
|
+
"used since Rails switched to Zeitwerk for autoloading."
|
|
28
|
+
)
|
|
29
|
+
yield if block
|
|
25
30
|
end
|
|
26
31
|
|
|
27
32
|
# Execute the supplied block while holding an exclusive lock,
|
|
@@ -149,8 +149,10 @@ module ActiveSupport
|
|
|
149
149
|
[offending_line.path, offending_line.lineno, offending_line.label]
|
|
150
150
|
end
|
|
151
151
|
|
|
152
|
-
RAILS_GEM_ROOT = File.expand_path("../../../..", __dir__) + "/"
|
|
153
|
-
|
|
152
|
+
RAILS_GEM_ROOT = File.expand_path("../../../..", __dir__) + "/"
|
|
153
|
+
private_constant :RAILS_GEM_ROOT
|
|
154
|
+
LIB_DIR = RbConfig::CONFIG["libdir"]
|
|
155
|
+
private_constant :LIB_DIR
|
|
154
156
|
|
|
155
157
|
def ignored_callstack?(path)
|
|
156
158
|
path.start_with?(RAILS_GEM_ROOT, LIB_DIR) || path.include?("<internal:")
|
|
@@ -68,7 +68,7 @@ module ActiveSupport
|
|
|
68
68
|
# and the second is a library name.
|
|
69
69
|
#
|
|
70
70
|
# ActiveSupport::Deprecation.new('2.0', 'MyLibrary')
|
|
71
|
-
def initialize(deprecation_horizon = "8.
|
|
71
|
+
def initialize(deprecation_horizon = "8.2", gem_name = "Rails")
|
|
72
72
|
self.gem_name = gem_name
|
|
73
73
|
self.deprecation_horizon = deprecation_horizon
|
|
74
74
|
# By default, warnings are not silenced and debugging is off.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
5
|
+
module ActiveSupport
|
|
6
|
+
class Editor
|
|
7
|
+
@editors = {}
|
|
8
|
+
@current = false
|
|
9
|
+
|
|
10
|
+
class << self
|
|
11
|
+
# Registers a URL pattern for opening file in a given editor.
|
|
12
|
+
# This allows Rails to generate clickable links to control known editors.
|
|
13
|
+
#
|
|
14
|
+
# Example:
|
|
15
|
+
#
|
|
16
|
+
# ActiveSupport::Editor.register("myeditor", "myeditor://%s:%d")
|
|
17
|
+
def register(name, url_pattern, aliases: [])
|
|
18
|
+
editor = new(url_pattern)
|
|
19
|
+
@editors[name] = editor
|
|
20
|
+
aliases.each do |a|
|
|
21
|
+
@editors[a] = editor
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Returns the current editor pattern if it is known.
|
|
26
|
+
# First check for the `RAILS_EDITOR` environment variable, and if it's
|
|
27
|
+
# missing, check for the `EDITOR` environment variable.
|
|
28
|
+
def current
|
|
29
|
+
if @current == false
|
|
30
|
+
@current = if editor_name = ENV["RAILS_EDITOR"] || ENV["EDITOR"]
|
|
31
|
+
@editors[editor_name]
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
@current
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# :nodoc:
|
|
38
|
+
|
|
39
|
+
def find(name)
|
|
40
|
+
@editors[name]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def reset
|
|
44
|
+
@current = false
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def initialize(url_pattern)
|
|
49
|
+
@url_pattern = url_pattern
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def url_for(path, line)
|
|
53
|
+
sprintf(@url_pattern, path, line)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
register "atom", "atom://core/open/file?filename=%s&line=%d"
|
|
57
|
+
register "cursor", "cursor://file/%s:%f"
|
|
58
|
+
register "emacs", "emacs://open?url=file://%s&line=%d", aliases: ["emacsclient"]
|
|
59
|
+
register "idea", "idea://open?file=%s&line=%d"
|
|
60
|
+
register "macvim", "mvim://open?url=file://%s&line=%d", aliases: ["mvim"]
|
|
61
|
+
register "nova", "nova://open?path=%s&line=%d"
|
|
62
|
+
register "rubymine", "x-mine://open?file=%s&line=%d"
|
|
63
|
+
register "sublime", "subl://open?url=file://%s&line=%d", aliases: ["subl"]
|
|
64
|
+
register "textmate", "txmt://open?url=file://%s&line=%d", aliases: ["mate"]
|
|
65
|
+
register "vscode", "vscode://file/%s:%d", aliases: ["code"]
|
|
66
|
+
register "vscodium", "vscodium://file/%s:%d", aliases: ["codium"]
|
|
67
|
+
register "windsurf", "windsurf://file/%s:%d"
|
|
68
|
+
register "zed", "zed://file/%s:%d"
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -36,6 +36,7 @@ module ActiveSupport
|
|
|
36
36
|
@subscribers = subscribers.flatten
|
|
37
37
|
@logger = logger
|
|
38
38
|
@debug_mode = false
|
|
39
|
+
@context_middlewares = ErrorContextMiddlewareStack.new
|
|
39
40
|
end
|
|
40
41
|
|
|
41
42
|
# Evaluates the given block, reporting and swallowing any unhandled error.
|
|
@@ -202,20 +203,51 @@ module ActiveSupport
|
|
|
202
203
|
ActiveSupport::ExecutionContext.set(...)
|
|
203
204
|
end
|
|
204
205
|
|
|
206
|
+
# Add a middleware to modify the error context before it is sent to subscribers.
|
|
207
|
+
#
|
|
208
|
+
# Middleware is added to a stack of callables run on an error's execution context
|
|
209
|
+
# before passing to subscribers. Allows creation of entries in error context that
|
|
210
|
+
# are shared by all subscribers.
|
|
211
|
+
#
|
|
212
|
+
# A context middleware receives the same parameters as #report.
|
|
213
|
+
# It must return a hash - the middleware stack returns the hash after it has
|
|
214
|
+
# run through all middlewares. A middleware can mutate or replace the hash.
|
|
215
|
+
#
|
|
216
|
+
# Rails.error.add_middleware(-> (error, context) { context.merge({ foo: :bar }) })
|
|
217
|
+
#
|
|
218
|
+
def add_middleware(middleware)
|
|
219
|
+
@context_middlewares.use(middleware)
|
|
220
|
+
end
|
|
221
|
+
|
|
205
222
|
# Report an error directly to subscribers. You can use this method when the
|
|
206
223
|
# block-based #handle and #record methods are not suitable.
|
|
207
224
|
#
|
|
208
225
|
# Rails.error.report(error)
|
|
209
226
|
#
|
|
227
|
+
# The +error+ argument must be an instance of Exception.
|
|
228
|
+
#
|
|
229
|
+
# Rails.error.report(Exception.new("Something went wrong"))
|
|
230
|
+
#
|
|
231
|
+
# Otherwise you can use #unexpected to report an error which does accept a
|
|
232
|
+
# string argument.
|
|
210
233
|
def report(error, handled: true, severity: handled ? :warning : :error, context: {}, source: DEFAULT_SOURCE)
|
|
211
234
|
return if error.instance_variable_defined?(:@__rails_error_reported)
|
|
235
|
+
raise ArgumentError, "Reported error must be an Exception, got: #{error.inspect}" unless error.is_a?(Exception)
|
|
236
|
+
|
|
212
237
|
ensure_backtrace(error)
|
|
213
238
|
|
|
214
239
|
unless SEVERITIES.include?(severity)
|
|
215
240
|
raise ArgumentError, "severity must be one of #{SEVERITIES.map(&:inspect).join(", ")}, got: #{severity.inspect}"
|
|
216
241
|
end
|
|
217
242
|
|
|
218
|
-
full_context =
|
|
243
|
+
full_context = @context_middlewares.execute(
|
|
244
|
+
error,
|
|
245
|
+
context: ActiveSupport::ExecutionContext.to_h.merge(context || {}),
|
|
246
|
+
handled:,
|
|
247
|
+
severity:,
|
|
248
|
+
source:
|
|
249
|
+
)
|
|
250
|
+
|
|
219
251
|
disabled_subscribers = ActiveSupport::IsolatedExecutionState[self]
|
|
220
252
|
@subscribers.each do |subscriber|
|
|
221
253
|
unless disabled_subscribers&.any? { |s| s === subscriber }
|
|
@@ -232,8 +264,11 @@ module ActiveSupport
|
|
|
232
264
|
end
|
|
233
265
|
end
|
|
234
266
|
|
|
235
|
-
|
|
236
|
-
error.
|
|
267
|
+
while error
|
|
268
|
+
unless error.frozen?
|
|
269
|
+
error.instance_variable_set(:@__rails_error_reported, true)
|
|
270
|
+
end
|
|
271
|
+
error = error.cause
|
|
237
272
|
end
|
|
238
273
|
|
|
239
274
|
nil
|
|
@@ -241,14 +276,12 @@ module ActiveSupport
|
|
|
241
276
|
|
|
242
277
|
private
|
|
243
278
|
def ensure_backtrace(error)
|
|
244
|
-
return if error.frozen? # re-raising won't add a backtrace
|
|
279
|
+
return if error.frozen? # re-raising won't add a backtrace or set the cause
|
|
245
280
|
return unless error.backtrace.nil?
|
|
246
281
|
|
|
247
282
|
begin
|
|
248
|
-
#
|
|
249
|
-
#
|
|
250
|
-
# `Exception#backtrace_locations`. So raising the exception
|
|
251
|
-
# is a good way to build a real backtrace.
|
|
283
|
+
# As of Ruby 3.4, we could use Exception#set_backtrace to set the backtrace,
|
|
284
|
+
# but there's nothing like Exception#set_cause. Raising+rescuing is the only way to set the cause.
|
|
252
285
|
raise error
|
|
253
286
|
rescue error.class => error
|
|
254
287
|
end
|
|
@@ -261,5 +294,25 @@ module ActiveSupport
|
|
|
261
294
|
|
|
262
295
|
error.backtrace.shift(count)
|
|
263
296
|
end
|
|
297
|
+
|
|
298
|
+
class ErrorContextMiddlewareStack # :nodoc:
|
|
299
|
+
def initialize
|
|
300
|
+
@stack = []
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
# Add a middleware to the error context stack.
|
|
304
|
+
def use(middleware)
|
|
305
|
+
unless middleware.respond_to?(:call)
|
|
306
|
+
raise ArgumentError, "Error context middleware must respond to #call"
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
@stack << middleware
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# Run all middlewares in the stack
|
|
313
|
+
def execute(error, handled:, severity:, context:, source:)
|
|
314
|
+
@stack.inject(context) { |c, middleware| middleware.call(error, context: c, handled:, severity:, source:) }
|
|
315
|
+
end
|
|
316
|
+
end
|
|
264
317
|
end
|
|
265
318
|
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveSupport::EventReporter::TestHelper # :nodoc:
|
|
4
|
+
class EventSubscriber # :nodoc:
|
|
5
|
+
attr_reader :events
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
@events = []
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def emit(event)
|
|
12
|
+
@events << event
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def event_matcher(name:, payload: nil, tags: {}, context: {}, source_location: nil)
|
|
17
|
+
->(event) {
|
|
18
|
+
return false unless event[:name] == name
|
|
19
|
+
return false unless event[:payload] == payload
|
|
20
|
+
return false unless event[:tags] == tags
|
|
21
|
+
return false unless event[:context] == context
|
|
22
|
+
|
|
23
|
+
[:filepath, :lineno, :label].each do |key|
|
|
24
|
+
if source_location && source_location[key]
|
|
25
|
+
return false unless event[:source_location][key] == source_location[key]
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
true
|
|
30
|
+
}
|
|
31
|
+
end
|
|
32
|
+
end
|