activesupport 8.0.5.2 → 8.1.0.beta1
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 +220 -278
- data/lib/active_support/backtrace_cleaner.rb +71 -0
- data/lib/active_support/cache/mem_cache_store.rb +14 -17
- data/lib/active_support/cache/redis_cache_store.rb +37 -31
- data/lib/active_support/cache/strategy/local_cache.rb +16 -7
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +7 -7
- data/lib/active_support/cache.rb +69 -6
- data/lib/active_support/configurable.rb +28 -0
- data/lib/active_support/continuous_integration.rb +145 -0
- data/lib/active_support/core_ext/benchmark.rb +0 -1
- data/lib/active_support/core_ext/class/attribute.rb +6 -8
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
- data/lib/active_support/core_ext/enumerable.rb +2 -2
- data/lib/active_support/core_ext/erb/util.rb +3 -3
- data/lib/active_support/core_ext/object/json.rb +9 -2
- data/lib/active_support/core_ext/object/to_query.rb +5 -0
- data/lib/active_support/core_ext/range.rb +0 -1
- data/lib/active_support/core_ext/string/inflections.rb +1 -1
- data/lib/active_support/core_ext/string/multibyte.rb +10 -1
- data/lib/active_support/core_ext/string/output_safety.rb +20 -15
- data/lib/active_support/current_attributes/test_helper.rb +2 -2
- data/lib/active_support/current_attributes.rb +13 -10
- data/lib/active_support/delegation.rb +42 -25
- 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 +50 -6
- data/lib/active_support/event_reporter/test_helper.rb +32 -0
- data/lib/active_support/event_reporter.rb +570 -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/file_update_checker.rb +8 -6
- data/lib/active_support/gem_version.rb +3 -3
- data/lib/active_support/gzip.rb +1 -0
- data/lib/active_support/hash_with_indifferent_access.rb +27 -7
- data/lib/active_support/i18n_railtie.rb +1 -2
- data/lib/active_support/inflector/inflections.rb +32 -17
- data/lib/active_support/inflector/methods.rb +21 -5
- data/lib/active_support/inflector/transliterate.rb +6 -8
- data/lib/active_support/isolated_execution_state.rb +9 -17
- data/lib/active_support/json/decoding.rb +2 -2
- data/lib/active_support/json/encoding.rb +103 -14
- data/lib/active_support/log_subscriber.rb +2 -0
- data/lib/active_support/message_encryptors.rb +52 -0
- data/lib/active_support/message_pack/extensions.rb +6 -1
- data/lib/active_support/message_verifiers.rb +52 -0
- data/lib/active_support/messages/rotation_coordinator.rb +9 -0
- data/lib/active_support/messages/rotator.rb +5 -0
- data/lib/active_support/multibyte/chars.rb +8 -1
- data/lib/active_support/multibyte.rb +4 -0
- data/lib/active_support/notifications/instrumenter.rb +1 -1
- data/lib/active_support/number_helper/number_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +2 -17
- data/lib/active_support/railtie.rb +26 -12
- data/lib/active_support/syntax_error_proxy.rb +3 -0
- data/lib/active_support/test_case.rb +61 -12
- data/lib/active_support/testing/assertions.rb +37 -14
- data/lib/active_support/testing/autorun.rb +0 -5
- data/lib/active_support/testing/error_reporter_assertions.rb +18 -1
- data/lib/active_support/testing/event_reporter_assertions.rb +217 -0
- data/lib/active_support/testing/notification_assertions.rb +92 -0
- data/lib/active_support/testing/parallelization/server.rb +2 -15
- data/lib/active_support/testing/parallelization/worker.rb +5 -7
- data/lib/active_support/testing/parallelization.rb +14 -12
- 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 +19 -5
- data/lib/active_support/values/time_zone.rb +8 -1
- data/lib/active_support/xml_mini.rb +1 -4
- data/lib/active_support.rb +11 -0
- metadata +11 -6
- data/lib/active_support/core_ext/range/each.rb +0 -24
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveSupport
|
|
4
|
+
# Provides a DSL for declaring a continuous integration workflow that can be run either locally or in the cloud.
|
|
5
|
+
# Each step is timed, reports success/error, and is aggregated into a collective report that reports total runtime,
|
|
6
|
+
# as well as whether the entire run was successful or not.
|
|
7
|
+
#
|
|
8
|
+
# Example:
|
|
9
|
+
#
|
|
10
|
+
# ActiveSupport::ContinuousIntegration.run do
|
|
11
|
+
# step "Setup", "bin/setup --skip-server"
|
|
12
|
+
# step "Style: Ruby", "bin/rubocop"
|
|
13
|
+
# step "Security: Gem audit", "bin/bundler-audit"
|
|
14
|
+
# step "Tests: Rails", "bin/rails test test:system"
|
|
15
|
+
#
|
|
16
|
+
# if success?
|
|
17
|
+
# step "Signoff: Ready for merge and deploy", "gh signoff"
|
|
18
|
+
# else
|
|
19
|
+
# failure "Skipping signoff; CI failed.", "Fix the issues and try again."
|
|
20
|
+
# end
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# Starting with Rails 8.1, a default `bin/ci` and `config/ci.rb` file are created to provide out-of-the-box CI.
|
|
24
|
+
class ContinuousIntegration
|
|
25
|
+
COLORS = {
|
|
26
|
+
banner: "\033[1;32m", # Green
|
|
27
|
+
title: "\033[1;35m", # Purple
|
|
28
|
+
subtitle: "\033[1;90m", # Medium Gray
|
|
29
|
+
error: "\033[1;31m", # Red
|
|
30
|
+
success: "\033[1;32m" # Green
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
attr_reader :results
|
|
34
|
+
|
|
35
|
+
# Perform a CI run. Execute each step, show their results and runtime, and exit with a non-zero status if there are any failures.
|
|
36
|
+
#
|
|
37
|
+
# Pass an optional title, subtitle, and a block that declares the steps to be executed.
|
|
38
|
+
#
|
|
39
|
+
# Sets the CI environment variable to "true" to allow for conditional behavior in the app, like enabling eager loading and disabling logging.
|
|
40
|
+
#
|
|
41
|
+
# Example:
|
|
42
|
+
#
|
|
43
|
+
# ActiveSupport::ContinuousIntegration.run do
|
|
44
|
+
# step "Setup", "bin/setup --skip-server"
|
|
45
|
+
# step "Style: Ruby", "bin/rubocop"
|
|
46
|
+
# step "Security: Gem audit", "bin/bundler-audit"
|
|
47
|
+
# step "Tests: Rails", "bin/rails test test:system"
|
|
48
|
+
#
|
|
49
|
+
# if success?
|
|
50
|
+
# step "Signoff: Ready for merge and deploy", "gh signoff"
|
|
51
|
+
# else
|
|
52
|
+
# failure "Skipping signoff; CI failed.", "Fix the issues and try again."
|
|
53
|
+
# end
|
|
54
|
+
# end
|
|
55
|
+
def self.run(title = "Continuous Integration", subtitle = "Running tests, style checks, and security audits", &block)
|
|
56
|
+
new.tap do |ci|
|
|
57
|
+
ENV["CI"] = "true"
|
|
58
|
+
ci.heading title, subtitle, padding: false
|
|
59
|
+
ci.report(title, &block)
|
|
60
|
+
abort unless ci.success?
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def initialize
|
|
65
|
+
@results = []
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Declare a step with a title and a command. The command can either be given as a single string or as multiple
|
|
69
|
+
# strings that will be passed to `system` as individual arguments (and therefore correctly escaped for paths etc).
|
|
70
|
+
#
|
|
71
|
+
# Examples:
|
|
72
|
+
#
|
|
73
|
+
# step "Setup", "bin/setup"
|
|
74
|
+
# step "Single test", "bin/rails", "test", "--name", "test_that_is_one"
|
|
75
|
+
def step(title, *command)
|
|
76
|
+
heading title, command.join(" "), type: :title
|
|
77
|
+
report(title) { results << system(*command) }
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Returns true if all steps were successful.
|
|
81
|
+
def success?
|
|
82
|
+
results.all?
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Display an error heading with the title and optional subtitle to reflect that the run failed.
|
|
86
|
+
def failure(title, subtitle = nil)
|
|
87
|
+
heading title, subtitle, type: :error
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Display a colorized heading followed by an optional subtitle.
|
|
91
|
+
#
|
|
92
|
+
# Examples:
|
|
93
|
+
#
|
|
94
|
+
# heading "Smoke Testing", "End-to-end tests verifying key functionality", padding: false
|
|
95
|
+
# heading "Skipping video encoding tests", "Install FFmpeg to run these tests", type: :error
|
|
96
|
+
#
|
|
97
|
+
# See ActiveSupport::ContinuousIntegration::COLORS for a complete list of options.
|
|
98
|
+
def heading(heading, subtitle = nil, type: :banner, padding: true)
|
|
99
|
+
echo "#{padding ? "\n\n" : ""}#{heading}", type: type
|
|
100
|
+
echo "#{subtitle}#{padding ? "\n" : ""}", type: :subtitle if subtitle
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Echo text to the terminal in the color corresponding to the type of the text.
|
|
104
|
+
#
|
|
105
|
+
# Examples:
|
|
106
|
+
#
|
|
107
|
+
# echo "This is going to be green!", type: :success
|
|
108
|
+
# echo "This is going to be red!", type: :error
|
|
109
|
+
#
|
|
110
|
+
# See ActiveSupport::ContinuousIntegration::COLORS for a complete list of options.
|
|
111
|
+
def echo(text, type:)
|
|
112
|
+
puts colorize(text, type)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# :nodoc:
|
|
116
|
+
def report(title, &block)
|
|
117
|
+
Signal.trap("INT") { abort colorize(:error, "\n❌ #{title} interrupted") }
|
|
118
|
+
|
|
119
|
+
ci = self.class.new
|
|
120
|
+
elapsed = timing { ci.instance_eval(&block) }
|
|
121
|
+
|
|
122
|
+
if ci.success?
|
|
123
|
+
echo "\n✅ #{title} passed in #{elapsed}", type: :success
|
|
124
|
+
else
|
|
125
|
+
echo "\n❌ #{title} failed in #{elapsed}", type: :error
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
results.concat ci.results
|
|
129
|
+
ensure
|
|
130
|
+
Signal.trap("INT", "-")
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
private
|
|
134
|
+
def timing
|
|
135
|
+
started_at = Time.now.to_f
|
|
136
|
+
yield
|
|
137
|
+
min, sec = (Time.now.to_f - started_at).divmod(60)
|
|
138
|
+
"#{"#{min}m" if min > 0}%.2fs" % sec
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def colorize(text, type)
|
|
142
|
+
"#{COLORS.fetch(type)}#{text}\033[0m"
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
@@ -96,16 +96,14 @@ class Class
|
|
|
96
96
|
namespaced_name = :"__class_attr_#{name}"
|
|
97
97
|
::ActiveSupport::ClassAttribute.redefine(self, name, namespaced_name, default)
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
delegators = [
|
|
100
|
+
"def #{name}; #{namespaced_name}; end",
|
|
101
|
+
"def #{name}=(value); self.#{namespaced_name} = value; end",
|
|
102
|
+
]
|
|
101
103
|
|
|
104
|
+
class_methods.concat(delegators)
|
|
102
105
|
if singleton_class?
|
|
103
|
-
methods
|
|
104
|
-
silence_redefinition_of_method(:#{name})
|
|
105
|
-
def #{name}
|
|
106
|
-
self.singleton_class.#{name}
|
|
107
|
-
end
|
|
108
|
-
RUBY
|
|
106
|
+
methods.concat(delegators)
|
|
109
107
|
else
|
|
110
108
|
methods << <<~RUBY if instance_reader
|
|
111
109
|
silence_redefinition_of_method def #{name}
|
|
@@ -17,7 +17,7 @@ module DateAndTime
|
|
|
17
17
|
singleton_class.silence_redefinition_of_method :preserve_timezone
|
|
18
18
|
|
|
19
19
|
#--
|
|
20
|
-
# This re-implements the
|
|
20
|
+
# This re-implements the behavior of the mattr_reader, instead
|
|
21
21
|
# of prepending on to it, to avoid overcomplicating a module that
|
|
22
22
|
# is in turn included in several places. This will all go away in
|
|
23
23
|
# Rails 8.0 anyway.
|
|
@@ -212,12 +212,12 @@ module Enumerable
|
|
|
212
212
|
result = nil
|
|
213
213
|
found = false
|
|
214
214
|
|
|
215
|
-
each do
|
|
215
|
+
each do |element|
|
|
216
216
|
if found
|
|
217
217
|
raise SoleItemExpectedError, "multiple items found"
|
|
218
218
|
end
|
|
219
219
|
|
|
220
|
-
result = element
|
|
220
|
+
result = element
|
|
221
221
|
found = true
|
|
222
222
|
end
|
|
223
223
|
|
|
@@ -12,7 +12,7 @@ module ActiveSupport
|
|
|
12
12
|
if s.html_safe?
|
|
13
13
|
s
|
|
14
14
|
else
|
|
15
|
-
super(
|
|
15
|
+
super(s)
|
|
16
16
|
end
|
|
17
17
|
end
|
|
18
18
|
alias :unwrapped_html_escape :html_escape # :nodoc:
|
|
@@ -61,7 +61,7 @@ class ERB
|
|
|
61
61
|
# html_escape_once('<< Accept & Checkout')
|
|
62
62
|
# # => "<< Accept & Checkout"
|
|
63
63
|
def html_escape_once(s)
|
|
64
|
-
|
|
64
|
+
s.to_s.gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE).html_safe
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
module_function :html_escape_once
|
|
@@ -169,7 +169,7 @@ class ERB
|
|
|
169
169
|
while !source.eos?
|
|
170
170
|
pos = source.pos
|
|
171
171
|
source.scan_until(/(?:#{start_re}|#{finish_re})/)
|
|
172
|
-
|
|
172
|
+
return [[:PLAIN, source.string]] unless source.matched?
|
|
173
173
|
len = source.pos - source.matched.bytesize - pos
|
|
174
174
|
|
|
175
175
|
case source.matched
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
require "json"
|
|
5
5
|
require "bigdecimal"
|
|
6
6
|
require "ipaddr"
|
|
7
|
-
require "uri"
|
|
7
|
+
require "uri/generic"
|
|
8
8
|
require "pathname"
|
|
9
9
|
require "active_support/core_ext/big_decimal/conversions" # for #to_s
|
|
10
10
|
require "active_support/core_ext/hash/except"
|
|
@@ -240,9 +240,16 @@ class Pathname # :nodoc:
|
|
|
240
240
|
end
|
|
241
241
|
|
|
242
242
|
unless IPAddr.method_defined?(:as_json, false)
|
|
243
|
+
# Use `IPAddr#as_json` from the IPAddr gem if the version is 1.2.7 or higher.
|
|
243
244
|
class IPAddr # :nodoc:
|
|
244
245
|
def as_json(options = nil)
|
|
245
|
-
|
|
246
|
+
if ipv4? && prefix == 32
|
|
247
|
+
to_s
|
|
248
|
+
elsif ipv6? && prefix == 128
|
|
249
|
+
to_s
|
|
250
|
+
else
|
|
251
|
+
"#{self}/#{prefix}"
|
|
252
|
+
end
|
|
246
253
|
end
|
|
247
254
|
end
|
|
248
255
|
end
|
|
@@ -248,7 +248,7 @@ class String
|
|
|
248
248
|
# optional parameter +capitalize+ to false.
|
|
249
249
|
# By default, this parameter is true.
|
|
250
250
|
#
|
|
251
|
-
# The trailing '_id' can be kept by setting the
|
|
251
|
+
# The trailing '_id' can be kept and capitalized by setting the
|
|
252
252
|
# optional parameter +keep_id_suffix+ to true.
|
|
253
253
|
# By default, this parameter is false.
|
|
254
254
|
#
|
|
@@ -35,7 +35,16 @@ class String
|
|
|
35
35
|
# For more information about the methods defined on the Chars proxy see ActiveSupport::Multibyte::Chars. For
|
|
36
36
|
# information about how to change the default Multibyte behavior see ActiveSupport::Multibyte.
|
|
37
37
|
def mb_chars
|
|
38
|
-
ActiveSupport
|
|
38
|
+
ActiveSupport.deprecator.warn(
|
|
39
|
+
"String#mb_chars is deprecated and will be removed in Rails 8.2. " \
|
|
40
|
+
"Use normal string methods instead."
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
if ActiveSupport::Multibyte.proxy_class == ActiveSupport::Multibyte::Chars
|
|
44
|
+
ActiveSupport::Multibyte::Chars.new(self, deprecation: false)
|
|
45
|
+
else
|
|
46
|
+
ActiveSupport::Multibyte.proxy_class.new(self)
|
|
47
|
+
end
|
|
39
48
|
end
|
|
40
49
|
|
|
41
50
|
# Returns +true+ if string has utf_8 encoding.
|
|
@@ -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
|
|
|
@@ -128,19 +129,21 @@ module ActiveSupport # :nodoc:
|
|
|
128
129
|
escaped_args = Array(args).map { |arg| explicit_html_escape_interpolated_argument(arg) }
|
|
129
130
|
end
|
|
130
131
|
|
|
131
|
-
|
|
132
|
-
new_safe_buffer.instance_variable_set(:@html_safe, @html_safe)
|
|
133
|
-
new_safe_buffer
|
|
132
|
+
self.class.new(super(escaped_args))
|
|
134
133
|
end
|
|
135
134
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
135
|
+
def html_safe?
|
|
136
|
+
@html_unsafe.nil?
|
|
137
|
+
end
|
|
139
138
|
|
|
140
139
|
def to_s
|
|
141
140
|
self
|
|
142
141
|
end
|
|
143
142
|
|
|
143
|
+
def as_json(*)
|
|
144
|
+
to_str
|
|
145
|
+
end
|
|
146
|
+
|
|
144
147
|
def to_param
|
|
145
148
|
to_str
|
|
146
149
|
end
|
|
@@ -157,7 +160,7 @@ module ActiveSupport # :nodoc:
|
|
|
157
160
|
end # end
|
|
158
161
|
|
|
159
162
|
def #{unsafe_method}!(*args) # def capitalize!(*args)
|
|
160
|
-
@
|
|
163
|
+
@html_unsafe = true # @html_unsafe = true
|
|
161
164
|
super # super
|
|
162
165
|
end # end
|
|
163
166
|
EOT
|
|
@@ -178,7 +181,7 @@ module ActiveSupport # :nodoc:
|
|
|
178
181
|
end # end
|
|
179
182
|
|
|
180
183
|
def #{unsafe_method}!(*args, &block) # def gsub!(*args, &block)
|
|
181
|
-
@
|
|
184
|
+
@html_unsafe = true # @html_unsafe = true
|
|
182
185
|
if block # if block
|
|
183
186
|
super(*args) { |*params| # super(*args) { |*params|
|
|
184
187
|
set_block_back_references(block, $~) # set_block_back_references(block, $~)
|
|
@@ -193,14 +196,14 @@ module ActiveSupport # :nodoc:
|
|
|
193
196
|
|
|
194
197
|
private
|
|
195
198
|
def explicit_html_escape_interpolated_argument(arg)
|
|
196
|
-
(!html_safe? || arg.html_safe?) ? arg :
|
|
199
|
+
(!html_safe? || arg.html_safe?) ? arg : ERB::Util.unwrapped_html_escape(arg)
|
|
197
200
|
end
|
|
198
201
|
|
|
199
202
|
def implicit_html_escape_interpolated_argument(arg)
|
|
200
203
|
if !html_safe? || arg.html_safe?
|
|
201
204
|
arg
|
|
202
205
|
else
|
|
203
|
-
|
|
206
|
+
ERB::Util.unwrapped_html_escape(arg.to_str)
|
|
204
207
|
end
|
|
205
208
|
end
|
|
206
209
|
|
|
@@ -212,7 +215,9 @@ module ActiveSupport # :nodoc:
|
|
|
212
215
|
|
|
213
216
|
def string_into_safe_buffer(new_string, is_html_safe)
|
|
214
217
|
new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
|
|
215
|
-
|
|
218
|
+
unless is_html_safe
|
|
219
|
+
new_safe_buffer.instance_variable_set :@html_unsafe, true
|
|
220
|
+
end
|
|
216
221
|
new_safe_buffer
|
|
217
222
|
end
|
|
218
223
|
end
|
|
@@ -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"
|
|
@@ -125,13 +126,13 @@ module ActiveSupport
|
|
|
125
126
|
owner.define_cached_method(name, namespace: :current_attributes) do |batch|
|
|
126
127
|
batch <<
|
|
127
128
|
"def #{name}" <<
|
|
128
|
-
"attributes[:#{name}]" <<
|
|
129
|
+
"@attributes[:#{name}]" <<
|
|
129
130
|
"end"
|
|
130
131
|
end
|
|
131
132
|
owner.define_cached_method("#{name}=", namespace: :current_attributes) do |batch|
|
|
132
133
|
batch <<
|
|
133
134
|
"def #{name}=(value)" <<
|
|
134
|
-
"attributes[:#{name}] = value" <<
|
|
135
|
+
"@attributes[:#{name}] = value" <<
|
|
135
136
|
"end"
|
|
136
137
|
end
|
|
137
138
|
end
|
|
@@ -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
|
|
@@ -201,12 +200,16 @@ module ActiveSupport
|
|
|
201
200
|
|
|
202
201
|
class_attribute :defaults, instance_writer: false, default: {}.freeze
|
|
203
202
|
|
|
204
|
-
|
|
203
|
+
attr_writer :attributes
|
|
205
204
|
|
|
206
205
|
def initialize
|
|
207
206
|
@attributes = resolve_defaults
|
|
208
207
|
end
|
|
209
208
|
|
|
209
|
+
def attributes
|
|
210
|
+
@attributes.dup
|
|
211
|
+
end
|
|
212
|
+
|
|
210
213
|
# Expose one or more attributes within a block. Old values are returned after the block concludes.
|
|
211
214
|
# Example demonstrating the common use of needing to set Current attributes outside the request-cycle:
|
|
212
215
|
#
|
|
@@ -134,11 +134,11 @@ module ActiveSupport
|
|
|
134
134
|
"def #{method_name}(#{definition})" <<
|
|
135
135
|
" _ = #{receiver}" <<
|
|
136
136
|
" _.#{method}(#{definition})" <<
|
|
137
|
-
"rescue
|
|
137
|
+
"rescue NoMethodError => e" <<
|
|
138
138
|
" if _.nil? && e.name == :#{method}" <<
|
|
139
|
-
"
|
|
139
|
+
" raise ::ActiveSupport::DelegationError.nil_target(:#{method_name}, :'#{receiver}')" <<
|
|
140
140
|
" else" <<
|
|
141
|
-
"
|
|
141
|
+
" raise" <<
|
|
142
142
|
" end" <<
|
|
143
143
|
"end"
|
|
144
144
|
end
|
|
@@ -151,32 +151,49 @@ module ActiveSupport
|
|
|
151
151
|
target = target.to_s
|
|
152
152
|
target = "self.#{target}" if RESERVED_METHOD_NAMES.include?(target) || target == "__target"
|
|
153
153
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
154
|
+
if allow_nil
|
|
155
|
+
owner.module_eval <<~RUBY, __FILE__, __LINE__ + 1
|
|
156
|
+
def respond_to_missing?(name, include_private = false)
|
|
157
|
+
# It may look like an oversight, but we deliberately do not pass
|
|
158
|
+
# +include_private+, because they do not get delegated.
|
|
159
159
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
# +include_private+, because they do not get delegated.
|
|
160
|
+
return false if name == :marshal_dump || name == :_dump
|
|
161
|
+
#{target}.respond_to?(name) || super
|
|
162
|
+
end
|
|
164
163
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
164
|
+
def method_missing(method, ...)
|
|
165
|
+
__target = #{target}
|
|
166
|
+
if __target.nil? && !nil.respond_to?(method)
|
|
167
|
+
nil
|
|
168
|
+
elsif __target.respond_to?(method)
|
|
169
|
+
__target.public_send(method, ...)
|
|
170
|
+
else
|
|
171
|
+
super
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
RUBY
|
|
175
|
+
else
|
|
176
|
+
owner.module_eval <<~RUBY, __FILE__, __LINE__ + 1
|
|
177
|
+
def respond_to_missing?(name, include_private = false)
|
|
178
|
+
# It may look like an oversight, but we deliberately do not pass
|
|
179
|
+
# +include_private+, because they do not get delegated.
|
|
168
180
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
if __target.nil? && !nil.respond_to?(method)
|
|
172
|
-
#{nil_behavior}
|
|
173
|
-
elsif __target.respond_to?(method)
|
|
174
|
-
__target.public_send(method, ...)
|
|
175
|
-
else
|
|
176
|
-
super
|
|
181
|
+
return false if name == :marshal_dump || name == :_dump
|
|
182
|
+
#{target}.respond_to?(name) || super
|
|
177
183
|
end
|
|
178
|
-
|
|
179
|
-
|
|
184
|
+
|
|
185
|
+
def method_missing(method, ...)
|
|
186
|
+
__target = #{target}
|
|
187
|
+
if __target.nil? && !nil.respond_to?(method)
|
|
188
|
+
raise ::ActiveSupport::DelegationError.nil_target(method, :'#{target}')
|
|
189
|
+
elsif __target.respond_to?(method)
|
|
190
|
+
__target.public_send(method, ...)
|
|
191
|
+
else
|
|
192
|
+
super
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
RUBY
|
|
196
|
+
end
|
|
180
197
|
end
|
|
181
198
|
end
|
|
182
199
|
end
|
|
@@ -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
|