activesupport 6.0.6 → 7.0.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 +224 -608
- data/MIT-LICENSE +1 -1
- data/lib/active_support/actionable_error.rb +1 -1
- data/lib/active_support/array_inquirer.rb +2 -2
- data/lib/active_support/backtrace_cleaner.rb +3 -3
- data/lib/active_support/benchmarkable.rb +3 -3
- data/lib/active_support/cache/file_store.rb +16 -10
- data/lib/active_support/cache/mem_cache_store.rb +143 -38
- data/lib/active_support/cache/memory_store.rb +56 -28
- data/lib/active_support/cache/null_store.rb +10 -2
- data/lib/active_support/cache/redis_cache_store.rb +62 -87
- data/lib/active_support/cache/strategy/local_cache.rb +46 -57
- data/lib/active_support/cache.rb +268 -77
- data/lib/active_support/callbacks.rb +226 -118
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +49 -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 +9 -6
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/array/access.rb +1 -5
- data/lib/active_support/core_ext/array/conversions.rb +9 -7
- 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.rb +1 -0
- data/lib/active_support/core_ext/benchmark.rb +2 -2
- data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
- data/lib/active_support/core_ext/class/attribute.rb +34 -44
- data/lib/active_support/core_ext/class/subclasses.rb +11 -24
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +4 -4
- data/lib/active_support/core_ext/date/conversions.rb +5 -4
- 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 +13 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/date_time/blank.rb +1 -1
- data/lib/active_support/core_ext/date_time/conversions.rb +5 -5
- 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 -13
- data/lib/active_support/core_ext/enumerable.rb +139 -15
- data/lib/active_support/core_ext/file/atomic.rb +1 -1
- data/lib/active_support/core_ext/hash/conversions.rb +2 -2
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
- data/lib/active_support/core_ext/hash/keys.rb +2 -2
- data/lib/active_support/core_ext/hash/slice.rb +3 -2
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
- data/lib/active_support/core_ext/load_error.rb +1 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +25 -29
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +26 -13
- data/lib/active_support/core_ext/module/concerning.rb +8 -2
- data/lib/active_support/core_ext/module/delegation.rb +40 -36
- data/lib/active_support/core_ext/module/introspection.rb +1 -25
- data/lib/active_support/core_ext/name_error.rb +23 -2
- data/lib/active_support/core_ext/numeric/conversions.rb +79 -72
- 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 +41 -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 +6 -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 -20
- data/lib/active_support/core_ext/range.rb +1 -1
- data/lib/active_support/core_ext/regexp.rb +8 -1
- data/lib/active_support/core_ext/string/access.rb +5 -24
- data/lib/active_support/core_ext/string/conversions.rb +1 -0
- data/lib/active_support/core_ext/string/filters.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +39 -5
- data/lib/active_support/core_ext/string/inquiry.rb +1 -0
- data/lib/active_support/core_ext/string/multibyte.rb +2 -2
- data/lib/active_support/core_ext/string/output_safety.rb +62 -67
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/time/calculations.rb +23 -5
- data/lib/active_support/core_ext/time/conversions.rb +6 -3
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/time/zones.rb +4 -19
- data/lib/active_support/core_ext/time.rb +1 -0
- data/lib/active_support/core_ext/uri.rb +3 -23
- data/lib/active_support/core_ext.rb +2 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +39 -16
- 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 -769
- data/lib/active_support/deprecation/behaviors.rb +19 -3
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +0 -1
- data/lib/active_support/deprecation/method_wrappers.rb +6 -5
- data/lib/active_support/deprecation/proxy_wrappers.rb +3 -3
- data/lib/active_support/deprecation/reporting.rb +50 -7
- data/lib/active_support/deprecation.rb +6 -1
- data/lib/active_support/descendants_tracker.rb +174 -64
- data/lib/active_support/digest.rb +5 -3
- data/lib/active_support/duration/iso8601_parser.rb +3 -3
- data/lib/active_support/duration/iso8601_serializer.rb +24 -10
- data/lib/active_support/duration.rb +134 -55
- data/lib/active_support/encrypted_configuration.rb +11 -1
- data/lib/active_support/encrypted_file.rb +20 -3
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/error_reporter.rb +117 -0
- data/lib/active_support/evented_file_update_checker.rb +70 -134
- 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 +41 -18
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/fork_tracker.rb +71 -0
- data/lib/active_support/gem_version.rb +2 -2
- data/lib/active_support/hash_with_indifferent_access.rb +51 -25
- 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 +14 -19
- data/lib/active_support/inflector/inflections.rb +24 -9
- data/lib/active_support/inflector/methods.rb +29 -49
- data/lib/active_support/inflector/transliterate.rb +4 -4
- data/lib/active_support/isolated_execution_state.rb +56 -0
- data/lib/active_support/json/decoding.rb +4 -4
- data/lib/active_support/json/encoding.rb +8 -4
- data/lib/active_support/key_generator.rb +19 -2
- data/lib/active_support/locale/en.yml +8 -4
- data/lib/active_support/log_subscriber.rb +21 -3
- data/lib/active_support/logger.rb +1 -1
- data/lib/active_support/logger_silence.rb +2 -26
- data/lib/active_support/logger_thread_safe_level.rb +34 -21
- data/lib/active_support/message_encryptor.rb +12 -10
- data/lib/active_support/message_verifier.rb +50 -18
- data/lib/active_support/messages/metadata.rb +2 -2
- data/lib/active_support/messages/rotation_configuration.rb +2 -1
- data/lib/active_support/messages/rotator.rb +6 -5
- data/lib/active_support/multibyte/chars.rb +13 -52
- data/lib/active_support/multibyte/unicode.rb +1 -87
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +110 -69
- data/lib/active_support/notifications/instrumenter.rb +37 -29
- data/lib/active_support/notifications.rb +47 -26
- data/lib/active_support/number_helper/number_converter.rb +2 -4
- 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_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +2 -2
- data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
- data/lib/active_support/number_helper/rounding_helper.rb +12 -32
- data/lib/active_support/number_helper.rb +29 -16
- data/lib/active_support/option_merger.rb +9 -16
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/ordered_options.rb +8 -2
- data/lib/active_support/parameter_filter.rb +21 -11
- data/lib/active_support/per_thread_registry.rb +6 -1
- data/lib/active_support/rails.rb +1 -4
- data/lib/active_support/railtie.rb +77 -5
- data/lib/active_support/reloader.rb +1 -1
- data/lib/active_support/rescuable.rb +6 -6
- data/lib/active_support/ruby_features.rb +7 -0
- data/lib/active_support/secure_compare_rotator.rb +51 -0
- data/lib/active_support/security_utils.rb +19 -12
- data/lib/active_support/string_inquirer.rb +2 -2
- data/lib/active_support/subscriber.rb +19 -25
- data/lib/active_support/tagged_logging.rb +31 -6
- data/lib/active_support/test_case.rb +9 -21
- data/lib/active_support/testing/assertions.rb +49 -12
- 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 +82 -0
- data/lib/active_support/testing/parallelization/worker.rb +103 -0
- data/lib/active_support/testing/parallelization.rb +16 -95
- 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 +53 -5
- data/lib/active_support/time_with_zone.rb +120 -55
- data/lib/active_support/values/time_zone.rb +49 -18
- 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 +9 -2
- data/lib/active_support/xml_mini.rb +5 -4
- data/lib/active_support.rb +29 -1
- metadata +45 -45
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
- data/lib/active_support/core_ext/hash/compact.rb +0 -5
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
- data/lib/active_support/core_ext/marshal.rb +0 -24
- data/lib/active_support/core_ext/module/reachable.rb +0 -6
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
- data/lib/active_support/core_ext/range/include_range.rb +0 -9
- data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
@@ -3,6 +3,8 @@
|
|
3
3
|
require "set"
|
4
4
|
require "pathname"
|
5
5
|
require "concurrent/atomic/atomic_boolean"
|
6
|
+
require "listen"
|
7
|
+
require "active_support/fork_tracker"
|
6
8
|
|
7
9
|
module ActiveSupport
|
8
10
|
# Allows you to "listen" to changes in a file system.
|
@@ -32,68 +34,28 @@ module ActiveSupport
|
|
32
34
|
# checker.execute_if_updated
|
33
35
|
# # => "changed"
|
34
36
|
#
|
35
|
-
class EventedFileUpdateChecker
|
37
|
+
class EventedFileUpdateChecker # :nodoc: all
|
36
38
|
def initialize(files, dirs = {}, &block)
|
37
39
|
unless block
|
38
40
|
raise ArgumentError, "A block is required to initialize an EventedFileUpdateChecker"
|
39
41
|
end
|
40
42
|
|
41
|
-
@
|
42
|
-
@
|
43
|
-
|
44
|
-
@dirs = {}
|
45
|
-
dirs.each do |dir, exts|
|
46
|
-
@dirs[@ph.xpath(dir)] = Array(exts).map { |ext| @ph.normalize_extension(ext) }
|
47
|
-
end
|
48
|
-
|
49
|
-
@block = block
|
50
|
-
@updated = Concurrent::AtomicBoolean.new(false)
|
51
|
-
@lcsp = @ph.longest_common_subpath(@dirs.keys)
|
52
|
-
@pid = Process.pid
|
53
|
-
@boot_mutex = Mutex.new
|
54
|
-
|
55
|
-
dtw = directories_to_watch
|
56
|
-
@dtw, @missing = dtw.partition(&:exist?)
|
57
|
-
|
58
|
-
if @dtw.any?
|
59
|
-
# Loading listen triggers warnings. These are originated by a legit
|
60
|
-
# usage of attr_* macros for private attributes, but adds a lot of noise
|
61
|
-
# to our test suite. Thus, we lazy load it and disable warnings locally.
|
62
|
-
silence_warnings do
|
63
|
-
require "listen"
|
64
|
-
rescue LoadError => e
|
65
|
-
raise LoadError, "Could not load the 'listen' gem. Add `gem 'listen'` to the development group of your Gemfile", e.backtrace
|
66
|
-
end
|
67
|
-
end
|
68
|
-
boot!
|
43
|
+
@block = block
|
44
|
+
@core = Core.new(files, dirs)
|
45
|
+
ObjectSpace.define_finalizer(self, @core.finalizer)
|
69
46
|
end
|
70
47
|
|
71
48
|
def updated?
|
72
|
-
@
|
73
|
-
|
74
|
-
|
75
|
-
@pid = Process.pid
|
76
|
-
@updated.make_true
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
if @missing.any?(&:exist?)
|
81
|
-
@boot_mutex.synchronize do
|
82
|
-
appeared, @missing = @missing.partition(&:exist?)
|
83
|
-
shutdown!
|
84
|
-
|
85
|
-
@dtw += appeared
|
86
|
-
boot!
|
87
|
-
|
88
|
-
@updated.make_true
|
89
|
-
end
|
49
|
+
if @core.restart?
|
50
|
+
@core.thread_safely(&:restart)
|
51
|
+
@core.updated.make_true
|
90
52
|
end
|
91
53
|
|
92
|
-
@updated.true?
|
54
|
+
@core.updated.true?
|
93
55
|
end
|
94
56
|
|
95
57
|
def execute
|
96
|
-
@updated.make_false
|
58
|
+
@core.updated.make_false
|
97
59
|
@block.call
|
98
60
|
end
|
99
61
|
|
@@ -105,17 +67,59 @@ module ActiveSupport
|
|
105
67
|
end
|
106
68
|
end
|
107
69
|
|
108
|
-
|
109
|
-
|
110
|
-
|
70
|
+
class Core
|
71
|
+
attr_reader :updated
|
72
|
+
|
73
|
+
def initialize(files, dirs)
|
74
|
+
@files = files.map { |file| Pathname(file).expand_path }.to_set
|
75
|
+
|
76
|
+
@dirs = dirs.each_with_object({}) do |(dir, exts), hash|
|
77
|
+
hash[Pathname(dir).expand_path] = Array(exts).map { |ext| ext.to_s.sub(/\A\.?/, ".") }.to_set
|
78
|
+
end
|
79
|
+
|
80
|
+
@common_path = common_path(@dirs.keys)
|
81
|
+
|
82
|
+
@dtw = directories_to_watch
|
83
|
+
@missing = []
|
84
|
+
|
85
|
+
@updated = Concurrent::AtomicBoolean.new(false)
|
86
|
+
@mutex = Mutex.new
|
87
|
+
|
88
|
+
start
|
89
|
+
@after_fork = ActiveSupport::ForkTracker.after_fork { start }
|
90
|
+
end
|
91
|
+
|
92
|
+
def finalizer
|
93
|
+
proc do
|
94
|
+
stop
|
95
|
+
ActiveSupport::ForkTracker.unregister(@after_fork)
|
96
|
+
end
|
97
|
+
end
|
111
98
|
|
112
|
-
|
113
|
-
|
99
|
+
def thread_safely
|
100
|
+
@mutex.synchronize do
|
101
|
+
yield self
|
114
102
|
end
|
115
103
|
end
|
116
104
|
|
117
|
-
def
|
118
|
-
|
105
|
+
def start
|
106
|
+
normalize_dirs!
|
107
|
+
@dtw, @missing = [*@dtw, *@missing].partition(&:exist?)
|
108
|
+
@listener = @dtw.any? ? Listen.to(*@dtw, &method(:changed)) : nil
|
109
|
+
@listener&.start
|
110
|
+
end
|
111
|
+
|
112
|
+
def stop
|
113
|
+
@listener&.stop
|
114
|
+
end
|
115
|
+
|
116
|
+
def restart
|
117
|
+
stop
|
118
|
+
start
|
119
|
+
end
|
120
|
+
|
121
|
+
def restart?
|
122
|
+
@missing.any?(&:exist?)
|
119
123
|
end
|
120
124
|
|
121
125
|
def normalize_dirs!
|
@@ -125,27 +129,27 @@ module ActiveSupport
|
|
125
129
|
end
|
126
130
|
|
127
131
|
def changed(modified, added, removed)
|
128
|
-
unless updated?
|
132
|
+
unless @updated.true?
|
129
133
|
@updated.make_true if (modified + added + removed).any? { |f| watching?(f) }
|
130
134
|
end
|
131
135
|
end
|
132
136
|
|
133
137
|
def watching?(file)
|
134
|
-
file =
|
138
|
+
file = Pathname(file)
|
135
139
|
|
136
140
|
if @files.member?(file)
|
137
141
|
true
|
138
142
|
elsif file.directory?
|
139
143
|
false
|
140
144
|
else
|
141
|
-
ext =
|
145
|
+
ext = file.extname
|
142
146
|
|
143
147
|
file.dirname.ascend do |dir|
|
144
148
|
matching = @dirs[dir]
|
145
149
|
|
146
150
|
if matching && (matching.empty? || matching.include?(ext))
|
147
151
|
break true
|
148
|
-
elsif dir == @
|
152
|
+
elsif dir == @common_path || dir.root?
|
149
153
|
break false
|
150
154
|
end
|
151
155
|
end
|
@@ -153,82 +157,14 @@ module ActiveSupport
|
|
153
157
|
end
|
154
158
|
|
155
159
|
def directories_to_watch
|
156
|
-
dtw = @files.map(&:dirname)
|
157
|
-
dtw.
|
158
|
-
dtw.
|
159
|
-
|
160
|
-
normalized_gem_paths = Gem.path.map { |path| File.join path, "" }
|
161
|
-
dtw = dtw.reject do |path|
|
162
|
-
normalized_gem_paths.any? { |gem_path| path.to_s.start_with?(gem_path) }
|
163
|
-
end
|
164
|
-
|
165
|
-
@ph.filter_out_descendants(dtw)
|
160
|
+
dtw = @dirs.keys | @files.map(&:dirname)
|
161
|
+
accounted_for = dtw.to_set + Gem.path.map { |path| Pathname(path) }
|
162
|
+
dtw.reject { |dir| dir.ascend.drop(1).any? { |parent| accounted_for.include?(parent) } }
|
166
163
|
end
|
167
164
|
|
168
|
-
|
169
|
-
|
170
|
-
Pathname.new(path).expand_path
|
171
|
-
end
|
172
|
-
|
173
|
-
def normalize_extension(ext)
|
174
|
-
ext.to_s.sub(/\A\./, "")
|
175
|
-
end
|
176
|
-
|
177
|
-
# Given a collection of Pathname objects returns the longest subpath
|
178
|
-
# common to all of them, or +nil+ if there is none.
|
179
|
-
def longest_common_subpath(paths)
|
180
|
-
return if paths.empty?
|
181
|
-
|
182
|
-
lcsp = Pathname.new(paths[0])
|
183
|
-
|
184
|
-
paths[1..-1].each do |path|
|
185
|
-
until ascendant_of?(lcsp, path)
|
186
|
-
if lcsp.root?
|
187
|
-
# If we get here a root directory is not an ascendant of path.
|
188
|
-
# This may happen if there are paths in different drives on
|
189
|
-
# Windows.
|
190
|
-
return
|
191
|
-
else
|
192
|
-
lcsp = lcsp.parent
|
193
|
-
end
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
lcsp
|
198
|
-
end
|
199
|
-
|
200
|
-
# Returns the deepest existing ascendant, which could be the argument itself.
|
201
|
-
def existing_parent(dir)
|
202
|
-
dir.ascend do |ascendant|
|
203
|
-
break ascendant if ascendant.directory?
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
# Filters out directories which are descendants of others in the collection (stable).
|
208
|
-
def filter_out_descendants(dirs)
|
209
|
-
return dirs if dirs.length < 2
|
210
|
-
|
211
|
-
dirs_sorted_by_nparts = dirs.sort_by { |dir| dir.each_filename.to_a.length }
|
212
|
-
descendants = []
|
213
|
-
|
214
|
-
until dirs_sorted_by_nparts.empty?
|
215
|
-
dir = dirs_sorted_by_nparts.shift
|
216
|
-
|
217
|
-
dirs_sorted_by_nparts.reject! do |possible_descendant|
|
218
|
-
ascendant_of?(dir, possible_descendant) && descendants << possible_descendant
|
219
|
-
end
|
220
|
-
end
|
221
|
-
|
222
|
-
# Array#- preserves order.
|
223
|
-
dirs - descendants
|
224
|
-
end
|
225
|
-
|
226
|
-
private
|
227
|
-
def ascendant_of?(base, other)
|
228
|
-
base != other && other.ascend do |ascendant|
|
229
|
-
break true if base == ascendant
|
230
|
-
end
|
231
|
-
end
|
165
|
+
def common_path(paths)
|
166
|
+
paths.map { |path| path.ascend.to_a }.reduce(&:&)&.first
|
232
167
|
end
|
168
|
+
end
|
233
169
|
end
|
234
170
|
end
|
@@ -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
|
|
@@ -63,21 +64,18 @@ module ActiveSupport
|
|
63
64
|
# after the work has been performed.
|
64
65
|
#
|
65
66
|
# Where possible, prefer +wrap+.
|
66
|
-
def self.run!
|
67
|
-
if
|
68
|
-
|
69
|
-
lost_instance&.complete!
|
67
|
+
def self.run!
|
68
|
+
if active?
|
69
|
+
Null
|
70
70
|
else
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
ensure
|
80
|
-
instance.complete! unless success
|
71
|
+
new.tap do |instance|
|
72
|
+
success = nil
|
73
|
+
begin
|
74
|
+
instance.run!
|
75
|
+
success = true
|
76
|
+
ensure
|
77
|
+
instance.complete! unless success
|
78
|
+
end
|
81
79
|
end
|
82
80
|
end
|
83
81
|
end
|
@@ -89,15 +87,32 @@ module ActiveSupport
|
|
89
87
|
instance = run!
|
90
88
|
begin
|
91
89
|
yield
|
90
|
+
rescue => error
|
91
|
+
error_reporter.report(error, handled: false)
|
92
|
+
raise
|
92
93
|
ensure
|
93
94
|
instance.complete!
|
94
95
|
end
|
95
96
|
end
|
96
97
|
|
98
|
+
def self.perform # :nodoc:
|
99
|
+
instance = new
|
100
|
+
instance.run
|
101
|
+
begin
|
102
|
+
yield
|
103
|
+
ensure
|
104
|
+
instance.complete
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
97
108
|
class << self # :nodoc:
|
98
109
|
attr_accessor :active
|
99
110
|
end
|
100
111
|
|
112
|
+
def self.error_reporter
|
113
|
+
@error_reporter ||= ActiveSupport::ErrorReporter.new
|
114
|
+
end
|
115
|
+
|
101
116
|
def self.inherited(other) # :nodoc:
|
102
117
|
super
|
103
118
|
other.active = Concurrent::Hash.new
|
@@ -106,11 +121,15 @@ module ActiveSupport
|
|
106
121
|
self.active = Concurrent::Hash.new
|
107
122
|
|
108
123
|
def self.active? # :nodoc:
|
109
|
-
@active.
|
124
|
+
@active[IsolatedExecutionState.unique_id]
|
110
125
|
end
|
111
126
|
|
112
127
|
def run! # :nodoc:
|
113
|
-
self.class.active[
|
128
|
+
self.class.active[IsolatedExecutionState.unique_id] = true
|
129
|
+
run
|
130
|
+
end
|
131
|
+
|
132
|
+
def run # :nodoc:
|
114
133
|
run_callbacks(:run)
|
115
134
|
end
|
116
135
|
|
@@ -119,9 +138,13 @@ module ActiveSupport
|
|
119
138
|
#
|
120
139
|
# Where possible, prefer +wrap+.
|
121
140
|
def complete!
|
122
|
-
|
141
|
+
complete
|
123
142
|
ensure
|
124
|
-
self.class.active.delete
|
143
|
+
self.class.active.delete(IsolatedExecutionState.unique_id)
|
144
|
+
end
|
145
|
+
|
146
|
+
def complete # :nodoc:
|
147
|
+
run_callbacks(:complete)
|
125
148
|
end
|
126
149
|
|
127
150
|
private
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
module ForkTracker # :nodoc:
|
5
|
+
module ModernCoreExt
|
6
|
+
def _fork
|
7
|
+
pid = super
|
8
|
+
if pid == 0
|
9
|
+
ForkTracker.check!
|
10
|
+
end
|
11
|
+
pid
|
12
|
+
end
|
13
|
+
end
|
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
|
+
@pid = Process.pid
|
37
|
+
@callbacks = []
|
38
|
+
|
39
|
+
class << self
|
40
|
+
def check!
|
41
|
+
new_pid = Process.pid
|
42
|
+
if @pid != new_pid
|
43
|
+
@callbacks.each(&:call)
|
44
|
+
@pid = new_pid
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def hook!
|
49
|
+
if Process.respond_to?(:_fork) # Ruby 3.1+
|
50
|
+
::Process.singleton_class.prepend(ModernCoreExt)
|
51
|
+
elsif Process.respond_to?(:fork)
|
52
|
+
::Object.prepend(CoreExtPrivate) if RUBY_VERSION < "3.0"
|
53
|
+
::Kernel.prepend(CoreExtPrivate)
|
54
|
+
::Kernel.singleton_class.prepend(CoreExt)
|
55
|
+
::Process.singleton_class.prepend(CoreExt)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def after_fork(&block)
|
60
|
+
@callbacks << block
|
61
|
+
block
|
62
|
+
end
|
63
|
+
|
64
|
+
def unregister(callback)
|
65
|
+
@callbacks.delete(callback)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
ActiveSupport::ForkTracker.hook!
|