activesupport 6.0.3.7 → 7.0.0
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 +220 -533
- data/MIT-LICENSE +1 -1
- data/README.rdoc +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 +18 -11
- data/lib/active_support/cache/mem_cache_store.rb +143 -37
- 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 +63 -88
- data/lib/active_support/cache/strategy/local_cache.rb +46 -57
- data/lib/active_support/cache.rb +273 -82
- 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 +21 -40
- 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/except.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/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 +42 -26
- 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 +69 -45
- 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 +26 -6
- 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 -764
- 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 +4 -4
- data/lib/active_support/deprecation/reporting.rb +50 -7
- data/lib/active_support/deprecation.rb +6 -1
- data/lib/active_support/descendants_tracker.rb +177 -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 +30 -4
- 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 +3 -3
- 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 +11 -3
- 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 +10 -9
- 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/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 +46 -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
|
|
@@ -86,15 +87,32 @@ module ActiveSupport
|
|
86
87
|
instance = run!
|
87
88
|
begin
|
88
89
|
yield
|
90
|
+
rescue => error
|
91
|
+
error_reporter.report(error, handled: false)
|
92
|
+
raise
|
89
93
|
ensure
|
90
94
|
instance.complete!
|
91
95
|
end
|
92
96
|
end
|
93
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
|
+
|
94
108
|
class << self # :nodoc:
|
95
109
|
attr_accessor :active
|
96
110
|
end
|
97
111
|
|
112
|
+
def self.error_reporter
|
113
|
+
@error_reporter ||= ActiveSupport::ErrorReporter.new
|
114
|
+
end
|
115
|
+
|
98
116
|
def self.inherited(other) # :nodoc:
|
99
117
|
super
|
100
118
|
other.active = Concurrent::Hash.new
|
@@ -103,11 +121,15 @@ module ActiveSupport
|
|
103
121
|
self.active = Concurrent::Hash.new
|
104
122
|
|
105
123
|
def self.active? # :nodoc:
|
106
|
-
@active[
|
124
|
+
@active[IsolatedExecutionState.unique_id]
|
107
125
|
end
|
108
126
|
|
109
127
|
def run! # :nodoc:
|
110
|
-
self.class.active[
|
128
|
+
self.class.active[IsolatedExecutionState.unique_id] = true
|
129
|
+
run
|
130
|
+
end
|
131
|
+
|
132
|
+
def run # :nodoc:
|
111
133
|
run_callbacks(:run)
|
112
134
|
end
|
113
135
|
|
@@ -116,9 +138,13 @@ module ActiveSupport
|
|
116
138
|
#
|
117
139
|
# Where possible, prefer +wrap+.
|
118
140
|
def complete!
|
119
|
-
|
141
|
+
complete
|
120
142
|
ensure
|
121
|
-
self.class.active.delete
|
143
|
+
self.class.active.delete(IsolatedExecutionState.unique_id)
|
144
|
+
end
|
145
|
+
|
146
|
+
def complete # :nodoc:
|
147
|
+
run_callbacks(:complete)
|
122
148
|
end
|
123
149
|
|
124
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!
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require "active_support/core_ext/hash/keys"
|
4
4
|
require "active_support/core_ext/hash/reverse_merge"
|
5
5
|
require "active_support/core_ext/hash/except"
|
6
|
+
require "active_support/core_ext/hash/slice"
|
6
7
|
|
7
8
|
module ActiveSupport
|
8
9
|
# Implements a hash where keys <tt>:foo</tt> and <tt>"foo"</tt> are considered
|
@@ -64,14 +65,16 @@ module ActiveSupport
|
|
64
65
|
self
|
65
66
|
end
|
66
67
|
|
67
|
-
def initialize(constructor =
|
68
|
+
def initialize(constructor = nil)
|
68
69
|
if constructor.respond_to?(:to_hash)
|
69
70
|
super()
|
70
71
|
update(constructor)
|
71
72
|
|
72
|
-
hash = constructor.to_hash
|
73
|
+
hash = constructor.is_a?(Hash) ? constructor : constructor.to_hash
|
73
74
|
self.default = hash.default if hash.default
|
74
75
|
self.default_proc = hash.default_proc if hash.default_proc
|
76
|
+
elsif constructor.nil?
|
77
|
+
super()
|
75
78
|
else
|
76
79
|
super(constructor)
|
77
80
|
end
|
@@ -91,12 +94,12 @@ module ActiveSupport
|
|
91
94
|
#
|
92
95
|
# This value can be later fetched using either +:key+ or <tt>'key'</tt>.
|
93
96
|
def []=(key, value)
|
94
|
-
regular_writer(convert_key(key), convert_value(value,
|
97
|
+
regular_writer(convert_key(key), convert_value(value, conversion: :assignment))
|
95
98
|
end
|
96
99
|
|
97
100
|
alias_method :store, :[]=
|
98
101
|
|
99
|
-
# Updates the receiver in-place, merging in the
|
102
|
+
# Updates the receiver in-place, merging in the hashes passed as arguments:
|
100
103
|
#
|
101
104
|
# hash_1 = ActiveSupport::HashWithIndifferentAccess.new
|
102
105
|
# hash_1[:key] = 'value'
|
@@ -106,11 +109,14 @@ module ActiveSupport
|
|
106
109
|
#
|
107
110
|
# hash_1.update(hash_2) # => {"key"=>"New Value!"}
|
108
111
|
#
|
109
|
-
#
|
112
|
+
# hash = ActiveSupport::HashWithIndifferentAccess.new
|
113
|
+
# hash.update({ "a" => 1 }, { "b" => 2 }) # => { "a" => 1, "b" => 2 }
|
114
|
+
#
|
115
|
+
# The arguments can be either an
|
110
116
|
# <tt>ActiveSupport::HashWithIndifferentAccess</tt> or a regular +Hash+.
|
111
117
|
# In either case the merge respects the semantics of indifferent access.
|
112
118
|
#
|
113
|
-
# If the argument is a regular hash with keys +:key+ and
|
119
|
+
# If the argument is a regular hash with keys +:key+ and <tt>"key"</tt> only one
|
114
120
|
# of the values end up in the receiver, but which one is unspecified.
|
115
121
|
#
|
116
122
|
# When given a block, the value for duplicated keys will be determined
|
@@ -121,18 +127,15 @@ module ActiveSupport
|
|
121
127
|
# hash_1[:key] = 10
|
122
128
|
# hash_2['key'] = 12
|
123
129
|
# hash_1.update(hash_2) { |key, old, new| old + new } # => {"key"=>22}
|
124
|
-
def update(
|
125
|
-
if
|
126
|
-
|
130
|
+
def update(*other_hashes, &block)
|
131
|
+
if other_hashes.size == 1
|
132
|
+
update_with_single_argument(other_hashes.first, block)
|
127
133
|
else
|
128
|
-
|
129
|
-
|
130
|
-
value = yield(convert_key(key), self[key], value)
|
131
|
-
end
|
132
|
-
regular_writer(convert_key(key), convert_value(value))
|
134
|
+
other_hashes.each do |other_hash|
|
135
|
+
update_with_single_argument(other_hash, block)
|
133
136
|
end
|
134
|
-
self
|
135
137
|
end
|
138
|
+
self
|
136
139
|
end
|
137
140
|
|
138
141
|
alias_method :merge!, :update
|
@@ -259,8 +262,8 @@ module ActiveSupport
|
|
259
262
|
# This method has the same semantics of +update+, except it does not
|
260
263
|
# modify the receiver but rather returns a new hash with indifferent
|
261
264
|
# access with the result of the merge.
|
262
|
-
def merge(
|
263
|
-
dup.update(
|
265
|
+
def merge(*hashes, &block)
|
266
|
+
dup.update(*hashes, &block)
|
264
267
|
end
|
265
268
|
|
266
269
|
# Like +merge+ but the other way around: Merges the receiver into the
|
@@ -293,6 +296,10 @@ module ActiveSupport
|
|
293
296
|
super(convert_key(key))
|
294
297
|
end
|
295
298
|
|
299
|
+
# Returns a hash with indifferent access that includes everything except given keys.
|
300
|
+
# hash = { a: "x", b: "y", c: 10 }.with_indifferent_access
|
301
|
+
# hash.except(:a, "b") # => {c: 10}.with_indifferent_access
|
302
|
+
# hash # => { a: "x", b: "y", c: 10 }.with_indifferent_access
|
296
303
|
def except(*keys)
|
297
304
|
slice(*self.keys - keys.map { |key| convert_key(key) })
|
298
305
|
end
|
@@ -357,40 +364,59 @@ module ActiveSupport
|
|
357
364
|
set_defaults(_new_hash)
|
358
365
|
|
359
366
|
each do |key, value|
|
360
|
-
_new_hash[key] = convert_value(value,
|
367
|
+
_new_hash[key] = convert_value(value, conversion: :to_hash)
|
361
368
|
end
|
362
369
|
_new_hash
|
363
370
|
end
|
364
371
|
|
365
372
|
private
|
366
|
-
|
367
|
-
key
|
373
|
+
if Symbol.method_defined?(:name)
|
374
|
+
def convert_key(key)
|
375
|
+
key.kind_of?(Symbol) ? key.name : key
|
376
|
+
end
|
377
|
+
else
|
378
|
+
def convert_key(key)
|
379
|
+
key.kind_of?(Symbol) ? key.to_s : key
|
380
|
+
end
|
368
381
|
end
|
369
382
|
|
370
|
-
def convert_value(value,
|
383
|
+
def convert_value(value, conversion: nil)
|
371
384
|
if value.is_a? Hash
|
372
|
-
if
|
385
|
+
if conversion == :to_hash
|
373
386
|
value.to_hash
|
374
387
|
else
|
375
388
|
value.nested_under_indifferent_access
|
376
389
|
end
|
377
390
|
elsif value.is_a?(Array)
|
378
|
-
if
|
391
|
+
if conversion != :assignment || value.frozen?
|
379
392
|
value = value.dup
|
380
393
|
end
|
381
|
-
value.map! { |e| convert_value(e,
|
394
|
+
value.map! { |e| convert_value(e, conversion: conversion) }
|
382
395
|
else
|
383
396
|
value
|
384
397
|
end
|
385
398
|
end
|
386
399
|
|
387
|
-
def set_defaults(target)
|
400
|
+
def set_defaults(target)
|
388
401
|
if default_proc
|
389
402
|
target.default_proc = default_proc.dup
|
390
403
|
else
|
391
404
|
target.default = default
|
392
405
|
end
|
393
406
|
end
|
407
|
+
|
408
|
+
def update_with_single_argument(other_hash, block)
|
409
|
+
if other_hash.is_a? HashWithIndifferentAccess
|
410
|
+
regular_update(other_hash, &block)
|
411
|
+
else
|
412
|
+
other_hash.to_hash.each_pair do |key, value|
|
413
|
+
if block && key?(key)
|
414
|
+
value = block.call(convert_key(key), self[key], value)
|
415
|
+
end
|
416
|
+
regular_writer(convert_key(key), convert_value(value))
|
417
|
+
end
|
418
|
+
end
|
419
|
+
end
|
394
420
|
end
|
395
421
|
end
|
396
422
|
|