activesupport 6.1.0 → 7.1.5.1
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 +1075 -325
- data/MIT-LICENSE +1 -1
- data/README.rdoc +7 -7
- data/lib/active_support/actionable_error.rb +4 -2
- data/lib/active_support/array_inquirer.rb +2 -2
- data/lib/active_support/backtrace_cleaner.rb +32 -7
- data/lib/active_support/benchmarkable.rb +3 -2
- data/lib/active_support/broadcast_logger.rb +251 -0
- data/lib/active_support/builder.rb +1 -1
- data/lib/active_support/cache/coder.rb +153 -0
- data/lib/active_support/cache/entry.rb +134 -0
- data/lib/active_support/cache/file_store.rb +53 -20
- data/lib/active_support/cache/mem_cache_store.rb +201 -62
- data/lib/active_support/cache/memory_store.rb +86 -24
- data/lib/active_support/cache/null_store.rb +16 -2
- data/lib/active_support/cache/redis_cache_store.rb +186 -193
- data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
- data/lib/active_support/cache/strategy/local_cache.rb +63 -71
- data/lib/active_support/cache.rb +487 -249
- data/lib/active_support/callbacks.rb +227 -105
- data/lib/active_support/code_generator.rb +70 -0
- data/lib/active_support/concern.rb +9 -7
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +44 -7
- data/lib/active_support/concurrency/null_lock.rb +13 -0
- data/lib/active_support/concurrency/share_lock.rb +2 -2
- data/lib/active_support/configurable.rb +18 -5
- data/lib/active_support/configuration_file.rb +7 -2
- data/lib/active_support/core_ext/array/access.rb +1 -5
- data/lib/active_support/core_ext/array/conversions.rb +15 -13
- data/lib/active_support/core_ext/array/grouping.rb +6 -6
- data/lib/active_support/core_ext/array/inquiry.rb +2 -2
- data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
- data/lib/active_support/core_ext/class/subclasses.rb +37 -26
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +24 -9
- data/lib/active_support/core_ext/date/conversions.rb +16 -15
- data/lib/active_support/core_ext/date_and_time/calculations.rb +14 -4
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
- data/lib/active_support/core_ext/date_time/blank.rb +1 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +19 -15
- data/lib/active_support/core_ext/digest/uuid.rb +30 -13
- data/lib/active_support/core_ext/enumerable.rb +85 -83
- data/lib/active_support/core_ext/erb/util.rb +196 -0
- data/lib/active_support/core_ext/file/atomic.rb +3 -1
- data/lib/active_support/core_ext/hash/conversions.rb +1 -2
- data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +3 -3
- data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
- data/lib/active_support/core_ext/hash/keys.rb +4 -4
- data/lib/active_support/core_ext/integer/inflections.rb +12 -12
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
- data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
- data/lib/active_support/core_ext/module/attribute_accessors.rb +8 -0
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +49 -22
- data/lib/active_support/core_ext/module/concerning.rb +6 -6
- data/lib/active_support/core_ext/module/delegation.rb +81 -43
- data/lib/active_support/core_ext/module/deprecation.rb +15 -12
- data/lib/active_support/core_ext/module/introspection.rb +0 -1
- data/lib/active_support/core_ext/name_error.rb +2 -8
- data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +82 -77
- 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 +17 -1
- data/lib/active_support/core_ext/object/duplicable.rb +31 -11
- data/lib/active_support/core_ext/object/inclusion.rb +13 -5
- data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
- data/lib/active_support/core_ext/object/json.rb +49 -27
- data/lib/active_support/core_ext/object/to_query.rb +2 -4
- data/lib/active_support/core_ext/object/try.rb +20 -20
- data/lib/active_support/core_ext/object/with.rb +44 -0
- data/lib/active_support/core_ext/object/with_options.rb +25 -6
- data/lib/active_support/core_ext/object.rb +1 -0
- data/lib/active_support/core_ext/pathname/blank.rb +16 -0
- data/lib/active_support/core_ext/pathname/existence.rb +23 -0
- data/lib/active_support/core_ext/pathname.rb +4 -0
- data/lib/active_support/core_ext/range/compare_range.rb +0 -25
- data/lib/active_support/core_ext/range/conversions.rb +34 -13
- data/lib/active_support/core_ext/range/each.rb +1 -1
- data/lib/active_support/core_ext/range/overlap.rb +40 -0
- data/lib/active_support/core_ext/range.rb +1 -2
- data/lib/active_support/core_ext/securerandom.rb +25 -13
- data/lib/active_support/core_ext/string/conversions.rb +2 -2
- data/lib/active_support/core_ext/string/filters.rb +21 -15
- data/lib/active_support/core_ext/string/indent.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +17 -10
- data/lib/active_support/core_ext/string/inquiry.rb +1 -1
- data/lib/active_support/core_ext/string/output_safety.rb +85 -165
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
- data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
- data/lib/active_support/core_ext/time/calculations.rb +30 -8
- data/lib/active_support/core_ext/time/conversions.rb +15 -13
- data/lib/active_support/core_ext/time/zones.rb +12 -28
- data/lib/active_support/core_ext.rb +2 -1
- data/lib/active_support/current_attributes.rb +47 -20
- data/lib/active_support/deep_mergeable.rb +53 -0
- data/lib/active_support/dependencies/autoload.rb +17 -12
- 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 -788
- data/lib/active_support/deprecation/behaviors.rb +66 -40
- data/lib/active_support/deprecation/constant_accessor.rb +5 -4
- data/lib/active_support/deprecation/deprecators.rb +104 -0
- data/lib/active_support/deprecation/disallowed.rb +6 -8
- data/lib/active_support/deprecation/instance_delegator.rb +31 -4
- data/lib/active_support/deprecation/method_wrappers.rb +9 -26
- data/lib/active_support/deprecation/proxy_wrappers.rb +38 -23
- data/lib/active_support/deprecation/reporting.rb +43 -26
- data/lib/active_support/deprecation.rb +32 -5
- data/lib/active_support/deprecator.rb +7 -0
- data/lib/active_support/descendants_tracker.rb +150 -72
- 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 +9 -3
- data/lib/active_support/duration.rb +83 -52
- data/lib/active_support/encrypted_configuration.rb +72 -9
- data/lib/active_support/encrypted_file.rb +29 -13
- data/lib/active_support/environment_inquirer.rb +23 -3
- data/lib/active_support/error_reporter/test_helper.rb +15 -0
- data/lib/active_support/error_reporter.rb +203 -0
- data/lib/active_support/evented_file_update_checker.rb +20 -7
- 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 +44 -22
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/file_update_checker.rb +4 -2
- data/lib/active_support/fork_tracker.rb +28 -11
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/gzip.rb +2 -0
- data/lib/active_support/hash_with_indifferent_access.rb +44 -19
- data/lib/active_support/html_safe_translation.rb +53 -0
- data/lib/active_support/i18n.rb +2 -1
- data/lib/active_support/i18n_railtie.rb +21 -14
- data/lib/active_support/inflector/inflections.rb +25 -7
- data/lib/active_support/inflector/methods.rb +50 -64
- data/lib/active_support/inflector/transliterate.rb +4 -2
- data/lib/active_support/isolated_execution_state.rb +76 -0
- data/lib/active_support/json/decoding.rb +2 -1
- data/lib/active_support/json/encoding.rb +27 -45
- data/lib/active_support/key_generator.rb +31 -6
- data/lib/active_support/lazy_load_hooks.rb +33 -7
- data/lib/active_support/locale/en.yml +4 -2
- data/lib/active_support/log_subscriber/test_helper.rb +2 -2
- data/lib/active_support/log_subscriber.rb +97 -35
- data/lib/active_support/logger.rb +9 -60
- data/lib/active_support/logger_thread_safe_level.rb +11 -34
- data/lib/active_support/message_encryptor.rb +206 -56
- data/lib/active_support/message_encryptors.rb +141 -0
- data/lib/active_support/message_pack/cache_serializer.rb +23 -0
- data/lib/active_support/message_pack/extensions.rb +292 -0
- data/lib/active_support/message_pack/serializer.rb +63 -0
- data/lib/active_support/message_pack.rb +50 -0
- data/lib/active_support/message_verifier.rb +235 -84
- data/lib/active_support/message_verifiers.rb +135 -0
- data/lib/active_support/messages/codec.rb +65 -0
- data/lib/active_support/messages/metadata.rb +112 -46
- data/lib/active_support/messages/rotation_coordinator.rb +93 -0
- data/lib/active_support/messages/rotator.rb +34 -32
- data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
- data/lib/active_support/multibyte/chars.rb +12 -11
- data/lib/active_support/multibyte/unicode.rb +9 -49
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +304 -114
- data/lib/active_support/notifications/instrumenter.rb +117 -35
- data/lib/active_support/notifications.rb +25 -25
- data/lib/active_support/number_helper/number_converter.rb +14 -7
- 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_size_converter.rb +4 -4
- data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +10 -6
- data/lib/active_support/number_helper/rounding_helper.rb +2 -6
- data/lib/active_support/number_helper.rb +379 -319
- data/lib/active_support/option_merger.rb +10 -18
- data/lib/active_support/ordered_hash.rb +4 -4
- data/lib/active_support/ordered_options.rb +15 -1
- data/lib/active_support/parameter_filter.rb +105 -81
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/railtie.rb +83 -21
- data/lib/active_support/reloader.rb +13 -5
- data/lib/active_support/rescuable.rb +18 -16
- data/lib/active_support/ruby_features.rb +7 -0
- data/lib/active_support/secure_compare_rotator.rb +18 -11
- data/lib/active_support/security_utils.rb +1 -1
- data/lib/active_support/string_inquirer.rb +3 -3
- data/lib/active_support/subscriber.rb +11 -40
- data/lib/active_support/syntax_error_proxy.rb +60 -0
- data/lib/active_support/tagged_logging.rb +65 -25
- data/lib/active_support/test_case.rb +166 -27
- data/lib/active_support/testing/assertions.rb +61 -15
- data/lib/active_support/testing/autorun.rb +0 -2
- data/lib/active_support/testing/constant_stubbing.rb +32 -0
- data/lib/active_support/testing/deprecation.rb +53 -2
- data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
- data/lib/active_support/testing/isolation.rb +30 -29
- data/lib/active_support/testing/method_call_assertions.rb +24 -11
- data/lib/active_support/testing/parallelization/server.rb +4 -0
- data/lib/active_support/testing/parallelization/worker.rb +3 -0
- data/lib/active_support/testing/parallelization.rb +4 -0
- data/lib/active_support/testing/parallelize_executor.rb +81 -0
- data/lib/active_support/testing/setup_and_teardown.rb +2 -0
- data/lib/active_support/testing/stream.rb +4 -6
- data/lib/active_support/testing/strict_warnings.rb +39 -0
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +49 -16
- data/lib/active_support/time_with_zone.rb +39 -28
- data/lib/active_support/values/time_zone.rb +50 -18
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini/jdom.rb +4 -11
- 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 +5 -5
- data/lib/active_support/xml_mini/nokogirisax.rb +2 -2
- data/lib/active_support/xml_mini/rexml.rb +2 -2
- data/lib/active_support/xml_mini.rb +7 -6
- data/lib/active_support.rb +28 -1
- metadata +150 -18
- data/lib/active_support/core_ext/marshal.rb +0 -26
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -28
- data/lib/active_support/core_ext/range/overlaps.rb +0 -10
- data/lib/active_support/core_ext/uri.rb +0 -29
- data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
- data/lib/active_support/per_thread_registry.rb +0 -60
@@ -0,0 +1,203 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
# = Active Support \Error Reporter
|
5
|
+
#
|
6
|
+
# +ActiveSupport::ErrorReporter+ is a common interface for error reporting services.
|
7
|
+
#
|
8
|
+
# To rescue and report any unhandled error, you can use the #handle method:
|
9
|
+
#
|
10
|
+
# Rails.error.handle do
|
11
|
+
# do_something!
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# If an error is raised, it will be reported and swallowed.
|
15
|
+
#
|
16
|
+
# Alternatively, if you want to report the error but not swallow it, you can use #record:
|
17
|
+
#
|
18
|
+
# Rails.error.record do
|
19
|
+
# do_something!
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# Both methods can be restricted to handle only a specific error class:
|
23
|
+
#
|
24
|
+
# maybe_tags = Rails.error.handle(Redis::BaseError) { redis.get("tags") }
|
25
|
+
#
|
26
|
+
class ErrorReporter
|
27
|
+
SEVERITIES = %i(error warning info)
|
28
|
+
DEFAULT_SOURCE = "application"
|
29
|
+
|
30
|
+
attr_accessor :logger
|
31
|
+
|
32
|
+
def initialize(*subscribers, logger: nil)
|
33
|
+
@subscribers = subscribers.flatten
|
34
|
+
@logger = logger
|
35
|
+
end
|
36
|
+
|
37
|
+
# Evaluates the given block, reporting and swallowing any unhandled error.
|
38
|
+
# If no error is raised, returns the return value of the block. Otherwise,
|
39
|
+
# returns the result of +fallback.call+, or +nil+ if +fallback+ is not
|
40
|
+
# specified.
|
41
|
+
#
|
42
|
+
# # Will report a TypeError to all subscribers and return nil.
|
43
|
+
# Rails.error.handle do
|
44
|
+
# 1 + '1'
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# Can be restricted to handle only specific error classes:
|
48
|
+
#
|
49
|
+
# maybe_tags = Rails.error.handle(Redis::BaseError) { redis.get("tags") }
|
50
|
+
#
|
51
|
+
# ==== Options
|
52
|
+
#
|
53
|
+
# * +:severity+ - This value is passed along to subscribers to indicate how
|
54
|
+
# important the error report is. Can be +:error+, +:warning+, or +:info+.
|
55
|
+
# Defaults to +:warning+.
|
56
|
+
#
|
57
|
+
# * +:context+ - Extra information that is passed along to subscribers. For
|
58
|
+
# example:
|
59
|
+
#
|
60
|
+
# Rails.error.handle(context: { section: "admin" }) do
|
61
|
+
# # ...
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
# * +:fallback+ - A callable that provides +handle+'s return value when an
|
65
|
+
# unhandled error is raised. For example:
|
66
|
+
#
|
67
|
+
# user = Rails.error.handle(fallback: -> { User.anonymous }) do
|
68
|
+
# User.find_by(params)
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# * +:source+ - This value is passed along to subscribers to indicate the
|
72
|
+
# source of the error. Subscribers can use this value to ignore certain
|
73
|
+
# errors. Defaults to <tt>"application"</tt>.
|
74
|
+
def handle(*error_classes, severity: :warning, context: {}, fallback: nil, source: DEFAULT_SOURCE)
|
75
|
+
error_classes = [StandardError] if error_classes.blank?
|
76
|
+
yield
|
77
|
+
rescue *error_classes => error
|
78
|
+
report(error, handled: true, severity: severity, context: context, source: source)
|
79
|
+
fallback.call if fallback
|
80
|
+
end
|
81
|
+
|
82
|
+
# Evaluates the given block, reporting and re-raising any unhandled error.
|
83
|
+
# If no error is raised, returns the return value of the block.
|
84
|
+
#
|
85
|
+
# # Will report a TypeError to all subscribers and re-raise it.
|
86
|
+
# Rails.error.record do
|
87
|
+
# 1 + '1'
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# Can be restricted to handle only specific error classes:
|
91
|
+
#
|
92
|
+
# tags = Rails.error.record(Redis::BaseError) { redis.get("tags") }
|
93
|
+
#
|
94
|
+
# ==== Options
|
95
|
+
#
|
96
|
+
# * +:severity+ - This value is passed along to subscribers to indicate how
|
97
|
+
# important the error report is. Can be +:error+, +:warning+, or +:info+.
|
98
|
+
# Defaults to +:error+.
|
99
|
+
#
|
100
|
+
# * +:context+ - Extra information that is passed along to subscribers. For
|
101
|
+
# example:
|
102
|
+
#
|
103
|
+
# Rails.error.record(context: { section: "admin" }) do
|
104
|
+
# # ...
|
105
|
+
# end
|
106
|
+
#
|
107
|
+
# * +:source+ - This value is passed along to subscribers to indicate the
|
108
|
+
# source of the error. Subscribers can use this value to ignore certain
|
109
|
+
# errors. Defaults to <tt>"application"</tt>.
|
110
|
+
def record(*error_classes, severity: :error, context: {}, source: DEFAULT_SOURCE)
|
111
|
+
error_classes = [StandardError] if error_classes.blank?
|
112
|
+
yield
|
113
|
+
rescue *error_classes => error
|
114
|
+
report(error, handled: false, severity: severity, context: context, source: source)
|
115
|
+
raise
|
116
|
+
end
|
117
|
+
|
118
|
+
# Register a new error subscriber. The subscriber must respond to
|
119
|
+
#
|
120
|
+
# report(Exception, handled: Boolean, severity: (:error OR :warning OR :info), context: Hash, source: String)
|
121
|
+
#
|
122
|
+
# The +report+ method <b>should never</b> raise an error.
|
123
|
+
def subscribe(subscriber)
|
124
|
+
unless subscriber.respond_to?(:report)
|
125
|
+
raise ArgumentError, "Error subscribers must respond to #report"
|
126
|
+
end
|
127
|
+
@subscribers << subscriber
|
128
|
+
end
|
129
|
+
|
130
|
+
# Unregister an error subscriber. Accepts either a subscriber or a class.
|
131
|
+
#
|
132
|
+
# subscriber = MyErrorSubscriber.new
|
133
|
+
# Rails.error.subscribe(subscriber)
|
134
|
+
#
|
135
|
+
# Rails.error.unsubscribe(subscriber)
|
136
|
+
# # or
|
137
|
+
# Rails.error.unsubscribe(MyErrorSubscriber)
|
138
|
+
def unsubscribe(subscriber)
|
139
|
+
@subscribers.delete_if { |s| subscriber === s }
|
140
|
+
end
|
141
|
+
|
142
|
+
# Prevent a subscriber from being notified of errors for the
|
143
|
+
# duration of the block. You may pass in the subscriber itself, or its class.
|
144
|
+
#
|
145
|
+
# This can be helpful for error reporting service integrations, when they wish
|
146
|
+
# to handle any errors higher in the stack.
|
147
|
+
def disable(subscriber)
|
148
|
+
disabled_subscribers = (ActiveSupport::IsolatedExecutionState[self] ||= [])
|
149
|
+
disabled_subscribers << subscriber
|
150
|
+
begin
|
151
|
+
yield
|
152
|
+
ensure
|
153
|
+
disabled_subscribers.delete(subscriber)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Update the execution context that is accessible to error subscribers. Any
|
158
|
+
# context passed to #handle, #record, or #report will be merged with the
|
159
|
+
# context set here.
|
160
|
+
#
|
161
|
+
# Rails.error.set_context(section: "checkout", user_id: @user.id)
|
162
|
+
#
|
163
|
+
def set_context(...)
|
164
|
+
ActiveSupport::ExecutionContext.set(...)
|
165
|
+
end
|
166
|
+
|
167
|
+
# Report an error directly to subscribers. You can use this method when the
|
168
|
+
# block-based #handle and #record methods are not suitable.
|
169
|
+
#
|
170
|
+
# Rails.error.report(error)
|
171
|
+
#
|
172
|
+
def report(error, handled: true, severity: handled ? :warning : :error, context: {}, source: DEFAULT_SOURCE)
|
173
|
+
return if error.instance_variable_defined?(:@__rails_error_reported)
|
174
|
+
|
175
|
+
unless SEVERITIES.include?(severity)
|
176
|
+
raise ArgumentError, "severity must be one of #{SEVERITIES.map(&:inspect).join(", ")}, got: #{severity.inspect}"
|
177
|
+
end
|
178
|
+
|
179
|
+
full_context = ActiveSupport::ExecutionContext.to_h.merge(context)
|
180
|
+
disabled_subscribers = ActiveSupport::IsolatedExecutionState[self]
|
181
|
+
@subscribers.each do |subscriber|
|
182
|
+
unless disabled_subscribers&.any? { |s| s === subscriber }
|
183
|
+
subscriber.report(error, handled: handled, severity: severity, context: full_context, source: source)
|
184
|
+
end
|
185
|
+
rescue => subscriber_error
|
186
|
+
if logger
|
187
|
+
logger.fatal(
|
188
|
+
"Error subscriber raised an error: #{subscriber_error.message} (#{subscriber_error.class})\n" +
|
189
|
+
subscriber_error.backtrace.join("\n")
|
190
|
+
)
|
191
|
+
else
|
192
|
+
raise
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
unless error.frozen?
|
197
|
+
error.instance_variable_set(:@__rails_error_reported, true)
|
198
|
+
end
|
199
|
+
|
200
|
+
nil
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
@@ -1,15 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
gem "listen", "~> 3.5"
|
4
|
+
require "listen"
|
5
|
+
|
3
6
|
require "set"
|
4
7
|
require "pathname"
|
5
8
|
require "concurrent/atomic/atomic_boolean"
|
6
|
-
require "listen"
|
7
9
|
require "active_support/fork_tracker"
|
8
10
|
|
9
11
|
module ActiveSupport
|
10
12
|
# Allows you to "listen" to changes in a file system.
|
11
|
-
# The evented file updater does not hit disk when checking for updates
|
12
|
-
#
|
13
|
+
# The evented file updater does not hit disk when checking for updates.
|
14
|
+
# Instead, it uses platform-specific file system events to trigger a change
|
13
15
|
# in state.
|
14
16
|
#
|
15
17
|
# The file checker takes an array of files to watch or a hash specifying directories
|
@@ -17,8 +19,6 @@ module ActiveSupport
|
|
17
19
|
# EventedFileUpdateChecker#execute is run or when EventedFileUpdateChecker#execute_if_updated
|
18
20
|
# is run and there have been changes to the file system.
|
19
21
|
#
|
20
|
-
# Note: Forking will cause the first call to `updated?` to return `true`.
|
21
|
-
#
|
22
22
|
# Example:
|
23
23
|
#
|
24
24
|
# checker = ActiveSupport::EventedFileUpdateChecker.new(["/tmp/foo"]) { puts "changed" }
|
@@ -34,7 +34,7 @@ module ActiveSupport
|
|
34
34
|
# checker.execute_if_updated
|
35
35
|
# # => "changed"
|
36
36
|
#
|
37
|
-
class EventedFileUpdateChecker
|
37
|
+
class EventedFileUpdateChecker # :nodoc: all
|
38
38
|
def initialize(files, dirs = {}, &block)
|
39
39
|
unless block
|
40
40
|
raise ArgumentError, "A block is required to initialize an EventedFileUpdateChecker"
|
@@ -45,6 +45,10 @@ module ActiveSupport
|
|
45
45
|
ObjectSpace.define_finalizer(self, @core.finalizer)
|
46
46
|
end
|
47
47
|
|
48
|
+
def inspect
|
49
|
+
"#<ActiveSupport::EventedFileUpdateChecker:#{object_id} @files=#{@core.files.to_a.inspect}"
|
50
|
+
end
|
51
|
+
|
48
52
|
def updated?
|
49
53
|
if @core.restart?
|
50
54
|
@core.thread_safely(&:restart)
|
@@ -68,7 +72,7 @@ module ActiveSupport
|
|
68
72
|
end
|
69
73
|
|
70
74
|
class Core
|
71
|
-
attr_reader :updated
|
75
|
+
attr_reader :updated, :files
|
72
76
|
|
73
77
|
def initialize(files, dirs)
|
74
78
|
@files = files.map { |file| Pathname(file).expand_path }.to_set
|
@@ -86,6 +90,10 @@ module ActiveSupport
|
|
86
90
|
@mutex = Mutex.new
|
87
91
|
|
88
92
|
start
|
93
|
+
# inotify / FSEvents file descriptors are inherited on fork, so
|
94
|
+
# we need to reopen them otherwise only the parent or the child
|
95
|
+
# will be notified.
|
96
|
+
# FIXME: this callback is keeping a reference on the instance
|
89
97
|
@after_fork = ActiveSupport::ForkTracker.after_fork { start }
|
90
98
|
end
|
91
99
|
|
@@ -107,6 +115,11 @@ module ActiveSupport
|
|
107
115
|
@dtw, @missing = [*@dtw, *@missing].partition(&:exist?)
|
108
116
|
@listener = @dtw.any? ? Listen.to(*@dtw, &method(:changed)) : nil
|
109
117
|
@listener&.start
|
118
|
+
|
119
|
+
# Wait for the listener to be ready to avoid race conditions
|
120
|
+
# Unfortunately this isn't quite enough on macOS because the Darwin backend
|
121
|
+
# has an extra private thread we can't wait on.
|
122
|
+
@listener&.wait_for_state(:processing_events)
|
110
123
|
end
|
111
124
|
|
112
125
|
def stop
|
@@ -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,51 +64,68 @@ 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
|
-
|
67
|
+
def self.run!(reset: false)
|
68
|
+
if reset
|
69
|
+
lost_instance = IsolatedExecutionState.delete(active_key)
|
70
|
+
lost_instance&.complete!
|
69
71
|
else
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
72
|
+
return Null if active?
|
73
|
+
end
|
74
|
+
|
75
|
+
new.tap do |instance|
|
76
|
+
success = nil
|
77
|
+
begin
|
78
|
+
instance.run!
|
79
|
+
success = true
|
80
|
+
ensure
|
81
|
+
instance.complete! unless success
|
78
82
|
end
|
79
83
|
end
|
80
84
|
end
|
81
85
|
|
82
86
|
# Perform the work in the supplied block as an execution.
|
83
|
-
def self.wrap
|
87
|
+
def self.wrap(source: "application.active_support")
|
84
88
|
return yield if active?
|
85
89
|
|
86
90
|
instance = run!
|
87
91
|
begin
|
88
92
|
yield
|
93
|
+
rescue => error
|
94
|
+
error_reporter&.report(error, handled: false, source: source)
|
95
|
+
raise
|
89
96
|
ensure
|
90
97
|
instance.complete!
|
91
98
|
end
|
92
99
|
end
|
93
100
|
|
94
|
-
|
95
|
-
|
101
|
+
def self.perform # :nodoc:
|
102
|
+
instance = new
|
103
|
+
instance.run
|
104
|
+
begin
|
105
|
+
yield
|
106
|
+
ensure
|
107
|
+
instance.complete
|
108
|
+
end
|
96
109
|
end
|
97
110
|
|
98
|
-
def self.
|
99
|
-
|
100
|
-
other.active = Concurrent::Hash.new
|
111
|
+
def self.error_reporter # :nodoc:
|
112
|
+
ActiveSupport.error_reporter
|
101
113
|
end
|
102
114
|
|
103
|
-
self.
|
115
|
+
def self.active_key # :nodoc:
|
116
|
+
@active_key ||= :"active_execution_wrapper_#{object_id}"
|
117
|
+
end
|
104
118
|
|
105
119
|
def self.active? # :nodoc:
|
106
|
-
|
120
|
+
IsolatedExecutionState.key?(active_key)
|
107
121
|
end
|
108
122
|
|
109
123
|
def run! # :nodoc:
|
110
|
-
self.class.
|
124
|
+
IsolatedExecutionState[self.class.active_key] = self
|
125
|
+
run
|
126
|
+
end
|
127
|
+
|
128
|
+
def run # :nodoc:
|
111
129
|
run_callbacks(:run)
|
112
130
|
end
|
113
131
|
|
@@ -116,9 +134,13 @@ module ActiveSupport
|
|
116
134
|
#
|
117
135
|
# Where possible, prefer +wrap+.
|
118
136
|
def complete!
|
119
|
-
|
137
|
+
complete
|
120
138
|
ensure
|
121
|
-
self.class.
|
139
|
+
IsolatedExecutionState.delete(self.class.active_key)
|
140
|
+
end
|
141
|
+
|
142
|
+
def complete # :nodoc:
|
143
|
+
run_callbacks(:complete)
|
122
144
|
end
|
123
145
|
|
124
146
|
private
|
@@ -3,7 +3,9 @@
|
|
3
3
|
require "active_support/core_ext/time/calculations"
|
4
4
|
|
5
5
|
module ActiveSupport
|
6
|
-
#
|
6
|
+
# = \File Update Checker
|
7
|
+
#
|
8
|
+
# FileUpdateChecker specifies the API used by \Rails to watch files
|
7
9
|
# and control reloading. The API depends on four methods:
|
8
10
|
#
|
9
11
|
# * +initialize+ which expects two parameters and one block as
|
@@ -20,7 +22,7 @@ module ActiveSupport
|
|
20
22
|
# After initialization, a call to +execute_if_updated+ must execute
|
21
23
|
# the block only if there was really a change in the filesystem.
|
22
24
|
#
|
23
|
-
# This class is used by Rails to reload the I18n framework whenever
|
25
|
+
# This class is used by \Rails to reload the I18n framework whenever
|
24
26
|
# they are changed upon a new request.
|
25
27
|
#
|
26
28
|
# i18n_reloader = ActiveSupport::FileUpdateChecker.new(paths) do
|
@@ -2,8 +2,18 @@
|
|
2
2
|
|
3
3
|
module ActiveSupport
|
4
4
|
module ForkTracker # :nodoc:
|
5
|
+
module ModernCoreExt
|
6
|
+
def _fork
|
7
|
+
pid = super
|
8
|
+
if pid == 0
|
9
|
+
ForkTracker.after_fork_callback
|
10
|
+
end
|
11
|
+
pid
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
5
15
|
module CoreExt
|
6
|
-
def fork(
|
16
|
+
def fork(...)
|
7
17
|
if block_given?
|
8
18
|
super do
|
9
19
|
ForkTracker.check!
|
@@ -20,27 +30,34 @@ module ActiveSupport
|
|
20
30
|
|
21
31
|
module CoreExtPrivate
|
22
32
|
include CoreExt
|
23
|
-
|
24
|
-
private
|
25
|
-
def fork(*)
|
26
|
-
super
|
27
|
-
end
|
33
|
+
private :fork
|
28
34
|
end
|
29
35
|
|
30
36
|
@pid = Process.pid
|
31
37
|
@callbacks = []
|
32
38
|
|
33
39
|
class << self
|
34
|
-
def
|
35
|
-
|
40
|
+
def after_fork_callback
|
41
|
+
new_pid = Process.pid
|
42
|
+
if @pid != new_pid
|
36
43
|
@callbacks.each(&:call)
|
37
|
-
@pid =
|
44
|
+
@pid = new_pid
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
if Process.respond_to?(:_fork) # Ruby 3.1+
|
49
|
+
def check!
|
50
|
+
# We trust the `_fork` callback
|
38
51
|
end
|
52
|
+
else
|
53
|
+
alias_method :check!, :after_fork_callback
|
39
54
|
end
|
40
55
|
|
41
56
|
def hook!
|
42
|
-
if Process.respond_to?(:
|
43
|
-
::
|
57
|
+
if Process.respond_to?(:_fork) # Ruby 3.1+
|
58
|
+
::Process.singleton_class.prepend(ModernCoreExt)
|
59
|
+
elsif Process.respond_to?(:fork)
|
60
|
+
::Object.prepend(CoreExtPrivate) if RUBY_VERSION < "3.0"
|
44
61
|
::Kernel.prepend(CoreExtPrivate)
|
45
62
|
::Kernel.singleton_class.prepend(CoreExt)
|
46
63
|
::Process.singleton_class.prepend(CoreExt)
|
@@ -1,16 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveSupport
|
4
|
-
# Returns the version of
|
4
|
+
# Returns the currently loaded version of Active Support as a +Gem::Version+.
|
5
5
|
def self.gem_version
|
6
6
|
Gem::Version.new VERSION::STRING
|
7
7
|
end
|
8
8
|
|
9
9
|
module VERSION
|
10
|
-
MAJOR =
|
10
|
+
MAJOR = 7
|
11
11
|
MINOR = 1
|
12
|
-
TINY =
|
13
|
-
PRE =
|
12
|
+
TINY = 5
|
13
|
+
PRE = "1"
|
14
14
|
|
15
15
|
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
|
16
16
|
end
|