activesupport 5.1.7 → 7.0.4.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 +259 -585
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -5
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/all.rb +2 -0
- data/lib/active_support/array_inquirer.rb +4 -2
- data/lib/active_support/backtrace_cleaner.rb +33 -5
- data/lib/active_support/benchmarkable.rb +5 -3
- data/lib/active_support/builder.rb +2 -0
- data/lib/active_support/cache/file_store.rb +50 -43
- data/lib/active_support/cache/mem_cache_store.rb +194 -67
- data/lib/active_support/cache/memory_store.rb +70 -34
- data/lib/active_support/cache/null_store.rb +18 -3
- data/lib/active_support/cache/redis_cache_store.rb +474 -0
- data/lib/active_support/cache/strategy/local_cache.rb +73 -50
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +2 -0
- data/lib/active_support/cache.rb +556 -220
- data/lib/active_support/callbacks.rb +264 -159
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +81 -8
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +16 -0
- data/lib/active_support/concurrency/share_lock.rb +4 -3
- data/lib/active_support/configurable.rb +17 -16
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/array/access.rb +18 -8
- data/lib/active_support/core_ext/array/conversions.rb +20 -17
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
- data/lib/active_support/core_ext/array/extract.rb +21 -0
- data/lib/active_support/core_ext/array/extract_options.rb +2 -0
- data/lib/active_support/core_ext/array/grouping.rb +8 -6
- data/lib/active_support/core_ext/array/inquiry.rb +4 -2
- data/lib/active_support/core_ext/array/wrap.rb +2 -0
- data/lib/active_support/core_ext/array.rb +4 -1
- data/lib/active_support/core_ext/benchmark.rb +4 -2
- data/lib/active_support/core_ext/big_decimal/conversions.rb +3 -1
- data/lib/active_support/core_ext/big_decimal.rb +2 -0
- data/lib/active_support/core_ext/class/attribute.rb +50 -47
- data/lib/active_support/core_ext/class/attribute_accessors.rb +2 -0
- data/lib/active_support/core_ext/class/subclasses.rb +10 -24
- data/lib/active_support/core_ext/class.rb +2 -0
- data/lib/active_support/core_ext/date/acts_like.rb +2 -0
- data/lib/active_support/core_ext/date/blank.rb +3 -1
- data/lib/active_support/core_ext/date/calculations.rb +17 -14
- data/lib/active_support/core_ext/date/conversions.rb +24 -22
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/date/zones.rb +2 -0
- data/lib/active_support/core_ext/date.rb +3 -0
- data/lib/active_support/core_ext/date_and_time/calculations.rb +65 -41
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -1
- data/lib/active_support/core_ext/date_and_time/zones.rb +2 -1
- data/lib/active_support/core_ext/date_time/acts_like.rb +2 -0
- data/lib/active_support/core_ext/date_time/blank.rb +3 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +3 -1
- data/lib/active_support/core_ext/date_time/compatibility.rb +7 -5
- data/lib/active_support/core_ext/date_time/conversions.rb +15 -14
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/date_time.rb +3 -0
- data/lib/active_support/core_ext/digest/uuid.rb +42 -14
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/enumerable.rb +244 -72
- data/lib/active_support/core_ext/file/atomic.rb +6 -2
- data/lib/active_support/core_ext/file.rb +2 -0
- data/lib/active_support/core_ext/hash/conversions.rb +7 -6
- data/lib/active_support/core_ext/hash/deep_merge.rb +8 -12
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +4 -2
- data/lib/active_support/core_ext/hash/indifferent_access.rb +5 -3
- data/lib/active_support/core_ext/hash/keys.rb +4 -31
- data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
- data/lib/active_support/core_ext/hash/slice.rb +8 -29
- data/lib/active_support/core_ext/hash.rb +3 -2
- data/lib/active_support/core_ext/integer/inflections.rb +2 -0
- data/lib/active_support/core_ext/integer/multiple.rb +3 -1
- data/lib/active_support/core_ext/integer/time.rb +7 -14
- data/lib/active_support/core_ext/integer.rb +2 -0
- data/lib/active_support/core_ext/kernel/concern.rb +2 -0
- data/lib/active_support/core_ext/kernel/reporting.rb +6 -4
- data/lib/active_support/core_ext/kernel/singleton_class.rb +3 -1
- data/lib/active_support/core_ext/kernel.rb +2 -1
- data/lib/active_support/core_ext/load_error.rb +3 -8
- data/lib/active_support/core_ext/module/aliasing.rb +2 -0
- data/lib/active_support/core_ext/module/anonymous.rb +2 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +4 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +46 -56
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +36 -27
- data/lib/active_support/core_ext/module/concerning.rb +15 -10
- data/lib/active_support/core_ext/module/delegation.rb +97 -58
- data/lib/active_support/core_ext/module/deprecation.rb +2 -0
- data/lib/active_support/core_ext/module/introspection.rb +18 -15
- data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
- data/lib/active_support/core_ext/module/remove_method.rb +5 -23
- data/lib/active_support/core_ext/module.rb +3 -1
- data/lib/active_support/core_ext/name_error.rb +30 -2
- data/lib/active_support/core_ext/numeric/bytes.rb +2 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +134 -129
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
- data/lib/active_support/core_ext/numeric/time.rb +7 -15
- data/lib/active_support/core_ext/numeric.rb +3 -1
- data/lib/active_support/core_ext/object/acts_like.rb +41 -6
- data/lib/active_support/core_ext/object/blank.rb +15 -5
- data/lib/active_support/core_ext/object/conversions.rb +2 -0
- data/lib/active_support/core_ext/object/deep_dup.rb +3 -1
- data/lib/active_support/core_ext/object/duplicable.rb +16 -110
- data/lib/active_support/core_ext/object/inclusion.rb +2 -0
- data/lib/active_support/core_ext/object/instance_variables.rb +2 -0
- data/lib/active_support/core_ext/object/json.rb +51 -26
- data/lib/active_support/core_ext/object/to_param.rb +2 -0
- data/lib/active_support/core_ext/object/to_query.rb +4 -2
- data/lib/active_support/core_ext/object/try.rb +26 -14
- data/lib/active_support/core_ext/object/with_options.rb +24 -3
- data/lib/active_support/core_ext/object.rb +2 -0
- 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 +57 -0
- data/lib/active_support/core_ext/range/conversions.rb +35 -25
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/range/each.rb +6 -3
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +7 -0
- data/lib/active_support/core_ext/range/overlaps.rb +3 -1
- data/lib/active_support/core_ext/range.rb +4 -1
- data/lib/active_support/core_ext/regexp.rb +10 -5
- data/lib/active_support/core_ext/securerandom.rb +25 -3
- data/lib/active_support/core_ext/string/access.rb +7 -16
- data/lib/active_support/core_ext/string/behavior.rb +2 -0
- data/lib/active_support/core_ext/string/conversions.rb +5 -2
- data/lib/active_support/core_ext/string/exclude.rb +2 -0
- data/lib/active_support/core_ext/string/filters.rb +44 -1
- data/lib/active_support/core_ext/string/indent.rb +2 -0
- data/lib/active_support/core_ext/string/inflections.rb +69 -16
- data/lib/active_support/core_ext/string/inquiry.rb +4 -1
- data/lib/active_support/core_ext/string/multibyte.rb +9 -4
- data/lib/active_support/core_ext/string/output_safety.rb +135 -27
- data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
- data/lib/active_support/core_ext/string/strip.rb +5 -1
- data/lib/active_support/core_ext/string/zones.rb +2 -0
- data/lib/active_support/core_ext/string.rb +2 -0
- 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/acts_like.rb +2 -0
- data/lib/active_support/core_ext/time/calculations.rb +81 -24
- data/lib/active_support/core_ext/time/compatibility.rb +4 -2
- data/lib/active_support/core_ext/time/conversions.rb +17 -12
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/time/zones.rb +12 -25
- data/lib/active_support/core_ext/time.rb +3 -0
- data/lib/active_support/core_ext/uri.rb +4 -23
- data/lib/active_support/core_ext.rb +4 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +226 -0
- data/lib/active_support/dependencies/autoload.rb +2 -0
- data/lib/active_support/dependencies/interlock.rb +12 -18
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +59 -715
- data/lib/active_support/deprecation/behaviors.rb +48 -13
- data/lib/active_support/deprecation/constant_accessor.rb +4 -2
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +2 -1
- data/lib/active_support/deprecation/method_wrappers.rb +29 -21
- data/lib/active_support/deprecation/proxy_wrappers.rb +34 -8
- data/lib/active_support/deprecation/reporting.rb +54 -9
- data/lib/active_support/deprecation.rb +10 -3
- data/lib/active_support/descendants_tracker.rb +192 -34
- data/lib/active_support/digest.rb +22 -0
- data/lib/active_support/duration/iso8601_parser.rb +9 -9
- data/lib/active_support/duration/iso8601_serializer.rb +29 -15
- data/lib/active_support/duration.rb +158 -72
- data/lib/active_support/encrypted_configuration.rb +56 -0
- data/lib/active_support/encrypted_file.rb +129 -0
- 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 +87 -122
- 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 +46 -21
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/executor.rb +2 -0
- data/lib/active_support/file_update_checker.rb +2 -1
- data/lib/active_support/fork_tracker.rb +71 -0
- data/lib/active_support/gem_version.rb +7 -5
- data/lib/active_support/gzip.rb +2 -0
- data/lib/active_support/hash_with_indifferent_access.rb +126 -42
- data/lib/active_support/html_safe_translation.rb +43 -0
- data/lib/active_support/i18n.rb +5 -1
- data/lib/active_support/i18n_railtie.rb +19 -14
- data/lib/active_support/inflections.rb +2 -0
- data/lib/active_support/inflector/inflections.rb +41 -14
- data/lib/active_support/inflector/methods.rb +73 -87
- data/lib/active_support/inflector/transliterate.rb +56 -18
- data/lib/active_support/inflector.rb +2 -0
- data/lib/active_support/isolated_execution_state.rb +72 -0
- data/lib/active_support/json/decoding.rb +27 -26
- data/lib/active_support/json/encoding.rb +16 -6
- data/lib/active_support/json.rb +2 -0
- data/lib/active_support/key_generator.rb +25 -38
- data/lib/active_support/lazy_load_hooks.rb +35 -6
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/locale/en.yml +8 -4
- data/lib/active_support/log_subscriber/test_helper.rb +4 -2
- data/lib/active_support/log_subscriber.rb +54 -13
- data/lib/active_support/logger.rb +4 -17
- data/lib/active_support/logger_silence.rb +13 -20
- data/lib/active_support/logger_thread_safe_level.rb +48 -10
- data/lib/active_support/message_encryptor.rb +111 -37
- data/lib/active_support/message_verifier.rb +124 -21
- data/lib/active_support/messages/metadata.rb +80 -0
- data/lib/active_support/messages/rotation_configuration.rb +23 -0
- data/lib/active_support/messages/rotator.rb +57 -0
- data/lib/active_support/multibyte/chars.rb +19 -76
- data/lib/active_support/multibyte/unicode.rb +9 -331
- data/lib/active_support/multibyte.rb +3 -1
- data/lib/active_support/notifications/fanout.rb +165 -37
- data/lib/active_support/notifications/instrumenter.rb +92 -11
- data/lib/active_support/notifications.rb +96 -30
- data/lib/active_support/number_helper/number_converter.rb +8 -9
- data/lib/active_support/number_helper/number_to_currency_converter.rb +14 -12
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +6 -3
- data/lib/active_support/number_helper/number_to_human_converter.rb +6 -3
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +7 -4
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +6 -3
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +14 -27
- data/lib/active_support/number_helper/rounding_helper.rb +16 -34
- data/lib/active_support/number_helper.rb +38 -12
- data/lib/active_support/option_merger.rb +19 -6
- data/lib/active_support/ordered_hash.rb +4 -2
- data/lib/active_support/ordered_options.rb +18 -6
- data/lib/active_support/parameter_filter.rb +138 -0
- data/lib/active_support/per_thread_registry.rb +8 -1
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/rails.rb +3 -10
- data/lib/active_support/railtie.rb +112 -11
- data/lib/active_support/reloader.rb +12 -11
- data/lib/active_support/rescuable.rb +19 -18
- 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 +26 -15
- data/lib/active_support/string_inquirer.rb +4 -3
- data/lib/active_support/subscriber.rb +81 -42
- data/lib/active_support/tagged_logging.rb +45 -9
- data/lib/active_support/test_case.rb +86 -2
- data/lib/active_support/testing/assertions.rb +89 -21
- data/lib/active_support/testing/autorun.rb +2 -0
- data/lib/active_support/testing/constant_lookup.rb +2 -0
- data/lib/active_support/testing/declarative.rb +2 -0
- data/lib/active_support/testing/deprecation.rb +54 -2
- data/lib/active_support/testing/file_fixtures.rb +4 -0
- data/lib/active_support/testing/isolation.rb +6 -4
- data/lib/active_support/testing/method_call_assertions.rb +34 -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 +55 -0
- data/lib/active_support/testing/parallelize_executor.rb +76 -0
- data/lib/active_support/testing/setup_and_teardown.rb +12 -7
- data/lib/active_support/testing/stream.rb +6 -7
- data/lib/active_support/testing/tagged_logging.rb +3 -1
- data/lib/active_support/testing/time_helpers.rb +91 -15
- data/lib/active_support/time.rb +2 -0
- data/lib/active_support/time_with_zone.rb +168 -56
- data/lib/active_support/values/time_zone.rb +85 -37
- data/lib/active_support/version.rb +3 -1
- data/lib/active_support/xml_mini/jdom.rb +6 -5
- data/lib/active_support/xml_mini/libxml.rb +9 -7
- data/lib/active_support/xml_mini/libxmlsax.rb +7 -5
- data/lib/active_support/xml_mini/nokogiri.rb +8 -6
- data/lib/active_support/xml_mini/nokogirisax.rb +6 -4
- data/lib/active_support/xml_mini/rexml.rb +13 -4
- data/lib/active_support/xml_mini.rb +10 -15
- data/lib/active_support.rb +30 -9
- metadata +76 -35
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
- data/lib/active_support/core_ext/hash/compact.rb +0 -27
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -30
- data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
- data/lib/active_support/core_ext/marshal.rb +0 -22
- data/lib/active_support/core_ext/module/reachable.rb +0 -8
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -26
- data/lib/active_support/core_ext/range/include_range.rb +0 -23
- data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
# +ActiveSupport::ErrorReporter+ is a common interface for error reporting services.
|
5
|
+
#
|
6
|
+
# To rescue and report any unhandled error, you can use the +handle+ method:
|
7
|
+
#
|
8
|
+
# Rails.error.handle do
|
9
|
+
# do_something!
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# If an error is raised, it will be reported and swallowed.
|
13
|
+
#
|
14
|
+
# Alternatively if you want to report the error but not swallow it, you can use +record+
|
15
|
+
#
|
16
|
+
# Rails.error.record do
|
17
|
+
# do_something!
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# Both methods can be restricted to only handle a specific exception class
|
21
|
+
#
|
22
|
+
# maybe_tags = Rails.error.handle(Redis::BaseError) { redis.get("tags") }
|
23
|
+
#
|
24
|
+
# You can also pass some extra context information that may be used by the error subscribers:
|
25
|
+
#
|
26
|
+
# Rails.error.handle(context: { section: "admin" }) do
|
27
|
+
# # ...
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# Additionally a +severity+ can be passed along to communicate how important the error report is.
|
31
|
+
# +severity+ can be one of +:error+, +:warning+, or +:info+. Handled errors default to the +:warning+
|
32
|
+
# severity, and unhandled ones to +:error+.
|
33
|
+
#
|
34
|
+
# Both +handle+ and +record+ pass through the return value from the block. In the case of +handle+
|
35
|
+
# rescuing an error, a fallback can be provided. The fallback must be a callable whose result will
|
36
|
+
# be returned when the block raises and is handled:
|
37
|
+
#
|
38
|
+
# user = Rails.error.handle(fallback: -> { User.anonymous }) do
|
39
|
+
# User.find_by(params)
|
40
|
+
# end
|
41
|
+
class ErrorReporter
|
42
|
+
SEVERITIES = %i(error warning info)
|
43
|
+
|
44
|
+
attr_accessor :logger
|
45
|
+
|
46
|
+
def initialize(*subscribers, logger: nil)
|
47
|
+
@subscribers = subscribers.flatten
|
48
|
+
@logger = logger
|
49
|
+
end
|
50
|
+
|
51
|
+
# Report any unhandled exception, and swallow it.
|
52
|
+
#
|
53
|
+
# Rails.error.handle do
|
54
|
+
# 1 + '1'
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
def handle(error_class = StandardError, severity: :warning, context: {}, fallback: nil)
|
58
|
+
yield
|
59
|
+
rescue error_class => error
|
60
|
+
report(error, handled: true, severity: severity, context: context)
|
61
|
+
fallback.call if fallback
|
62
|
+
end
|
63
|
+
|
64
|
+
def record(error_class = StandardError, severity: :error, context: {})
|
65
|
+
yield
|
66
|
+
rescue error_class => error
|
67
|
+
report(error, handled: false, severity: severity, context: context)
|
68
|
+
raise
|
69
|
+
end
|
70
|
+
|
71
|
+
# Register a new error subscriber. The subscriber must respond to
|
72
|
+
#
|
73
|
+
# report(Exception, handled: Boolean, context: Hash)
|
74
|
+
#
|
75
|
+
# The +report+ method +should+ never raise an error.
|
76
|
+
def subscribe(subscriber)
|
77
|
+
unless subscriber.respond_to?(:report)
|
78
|
+
raise ArgumentError, "Error subscribers must respond to #report"
|
79
|
+
end
|
80
|
+
@subscribers << subscriber
|
81
|
+
end
|
82
|
+
|
83
|
+
# Update the execution context that is accessible to error subscribers
|
84
|
+
#
|
85
|
+
# Rails.error.set_context(section: "checkout", user_id: @user.id)
|
86
|
+
#
|
87
|
+
# See +ActiveSupport::ExecutionContext.set+
|
88
|
+
def set_context(...)
|
89
|
+
ActiveSupport::ExecutionContext.set(...)
|
90
|
+
end
|
91
|
+
|
92
|
+
# When the block based +handle+ and +record+ methods are not suitable, you can directly use +report+
|
93
|
+
#
|
94
|
+
# Rails.error.report(error, handled: true)
|
95
|
+
def report(error, handled:, severity: handled ? :warning : :error, context: {})
|
96
|
+
unless SEVERITIES.include?(severity)
|
97
|
+
raise ArgumentError, "severity must be one of #{SEVERITIES.map(&:inspect).join(", ")}, got: #{severity.inspect}"
|
98
|
+
end
|
99
|
+
|
100
|
+
full_context = ActiveSupport::ExecutionContext.to_h.merge(context)
|
101
|
+
@subscribers.each do |subscriber|
|
102
|
+
subscriber.report(error, handled: handled, severity: severity, context: full_context)
|
103
|
+
rescue => subscriber_error
|
104
|
+
if logger
|
105
|
+
logger.fatal(
|
106
|
+
"Error subscriber raised an error: #{subscriber_error.message} (#{subscriber_error.class})\n" +
|
107
|
+
subscriber_error.backtrace.join("\n")
|
108
|
+
)
|
109
|
+
else
|
110
|
+
raise
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
nil
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -1,11 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "set"
|
2
4
|
require "pathname"
|
3
5
|
require "concurrent/atomic/atomic_boolean"
|
6
|
+
require "listen"
|
7
|
+
require "active_support/fork_tracker"
|
4
8
|
|
5
9
|
module ActiveSupport
|
6
10
|
# Allows you to "listen" to changes in a file system.
|
7
|
-
# The evented file updater does not hit disk when checking for updates
|
8
|
-
#
|
11
|
+
# The evented file updater does not hit disk when checking for updates.
|
12
|
+
# Instead, it uses platform-specific file system events to trigger a change
|
9
13
|
# in state.
|
10
14
|
#
|
11
15
|
# The file checker takes an array of files to watch or a hash specifying directories
|
@@ -13,8 +17,6 @@ module ActiveSupport
|
|
13
17
|
# EventedFileUpdateChecker#execute is run or when EventedFileUpdateChecker#execute_if_updated
|
14
18
|
# is run and there have been changes to the file system.
|
15
19
|
#
|
16
|
-
# Note: Forking will cause the first call to `updated?` to return `true`.
|
17
|
-
#
|
18
20
|
# Example:
|
19
21
|
#
|
20
22
|
# checker = ActiveSupport::EventedFileUpdateChecker.new(["/tmp/foo"]) { puts "changed" }
|
@@ -30,54 +32,28 @@ module ActiveSupport
|
|
30
32
|
# checker.execute_if_updated
|
31
33
|
# # => "changed"
|
32
34
|
#
|
33
|
-
class EventedFileUpdateChecker
|
35
|
+
class EventedFileUpdateChecker # :nodoc: all
|
34
36
|
def initialize(files, dirs = {}, &block)
|
35
37
|
unless block
|
36
38
|
raise ArgumentError, "A block is required to initialize an EventedFileUpdateChecker"
|
37
39
|
end
|
38
40
|
|
39
|
-
@
|
40
|
-
@
|
41
|
-
|
42
|
-
@dirs = {}
|
43
|
-
dirs.each do |dir, exts|
|
44
|
-
@dirs[@ph.xpath(dir)] = Array(exts).map { |ext| @ph.normalize_extension(ext) }
|
45
|
-
end
|
46
|
-
|
47
|
-
@block = block
|
48
|
-
@updated = Concurrent::AtomicBoolean.new(false)
|
49
|
-
@lcsp = @ph.longest_common_subpath(@dirs.keys)
|
50
|
-
@pid = Process.pid
|
51
|
-
@boot_mutex = Mutex.new
|
52
|
-
|
53
|
-
if (@dtw = directories_to_watch).any?
|
54
|
-
# Loading listen triggers warnings. These are originated by a legit
|
55
|
-
# usage of attr_* macros for private attributes, but adds a lot of noise
|
56
|
-
# to our test suite. Thus, we lazy load it and disable warnings locally.
|
57
|
-
silence_warnings do
|
58
|
-
begin
|
59
|
-
require "listen"
|
60
|
-
rescue LoadError => e
|
61
|
-
raise LoadError, "Could not load the 'listen' gem. Add `gem 'listen'` to the development group of your Gemfile", e.backtrace
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
boot!
|
41
|
+
@block = block
|
42
|
+
@core = Core.new(files, dirs)
|
43
|
+
ObjectSpace.define_finalizer(self, @core.finalizer)
|
66
44
|
end
|
67
45
|
|
68
46
|
def updated?
|
69
|
-
@
|
70
|
-
|
71
|
-
|
72
|
-
@pid = Process.pid
|
73
|
-
@updated.make_true
|
74
|
-
end
|
47
|
+
if @core.restart?
|
48
|
+
@core.thread_safely(&:restart)
|
49
|
+
@core.updated.make_true
|
75
50
|
end
|
76
|
-
|
51
|
+
|
52
|
+
@core.updated.true?
|
77
53
|
end
|
78
54
|
|
79
55
|
def execute
|
80
|
-
@updated.make_false
|
56
|
+
@core.updated.make_false
|
81
57
|
@block.call
|
82
58
|
end
|
83
59
|
|
@@ -89,115 +65,104 @@ module ActiveSupport
|
|
89
65
|
end
|
90
66
|
end
|
91
67
|
|
92
|
-
|
93
|
-
|
94
|
-
Listen.to(*@dtw, &method(:changed)).start
|
95
|
-
end
|
68
|
+
class Core
|
69
|
+
attr_reader :updated
|
96
70
|
|
97
|
-
def
|
98
|
-
|
99
|
-
|
71
|
+
def initialize(files, dirs)
|
72
|
+
@files = files.map { |file| Pathname(file).expand_path }.to_set
|
73
|
+
|
74
|
+
@dirs = dirs.each_with_object({}) do |(dir, exts), hash|
|
75
|
+
hash[Pathname(dir).expand_path] = Array(exts).map { |ext| ext.to_s.sub(/\A\.?/, ".") }.to_set
|
100
76
|
end
|
101
|
-
end
|
102
77
|
|
103
|
-
|
104
|
-
file = @ph.xpath(file)
|
78
|
+
@common_path = common_path(@dirs.keys)
|
105
79
|
|
106
|
-
|
107
|
-
|
108
|
-
elsif file.directory?
|
109
|
-
false
|
110
|
-
else
|
111
|
-
ext = @ph.normalize_extension(file.extname)
|
80
|
+
@dtw = directories_to_watch
|
81
|
+
@missing = []
|
112
82
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
83
|
+
@updated = Concurrent::AtomicBoolean.new(false)
|
84
|
+
@mutex = Mutex.new
|
85
|
+
|
86
|
+
start
|
87
|
+
@after_fork = ActiveSupport::ForkTracker.after_fork { start }
|
121
88
|
end
|
122
89
|
|
123
|
-
def
|
124
|
-
|
125
|
-
|
126
|
-
|
90
|
+
def finalizer
|
91
|
+
proc do
|
92
|
+
stop
|
93
|
+
ActiveSupport::ForkTracker.unregister(@after_fork)
|
94
|
+
end
|
95
|
+
end
|
127
96
|
|
128
|
-
|
129
|
-
|
130
|
-
|
97
|
+
def thread_safely
|
98
|
+
@mutex.synchronize do
|
99
|
+
yield self
|
131
100
|
end
|
101
|
+
end
|
132
102
|
|
133
|
-
|
103
|
+
def start
|
104
|
+
normalize_dirs!
|
105
|
+
@dtw, @missing = [*@dtw, *@missing].partition(&:exist?)
|
106
|
+
@listener = @dtw.any? ? Listen.to(*@dtw, &method(:changed)) : nil
|
107
|
+
@listener&.start
|
134
108
|
end
|
135
109
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
end
|
110
|
+
def stop
|
111
|
+
@listener&.stop
|
112
|
+
end
|
140
113
|
|
141
|
-
|
142
|
-
|
143
|
-
|
114
|
+
def restart
|
115
|
+
stop
|
116
|
+
start
|
117
|
+
end
|
144
118
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
return if paths.empty?
|
149
|
-
|
150
|
-
lcsp = Pathname.new(paths[0])
|
151
|
-
|
152
|
-
paths[1..-1].each do |path|
|
153
|
-
until ascendant_of?(lcsp, path)
|
154
|
-
if lcsp.root?
|
155
|
-
# If we get here a root directory is not an ascendant of path.
|
156
|
-
# This may happen if there are paths in different drives on
|
157
|
-
# Windows.
|
158
|
-
return
|
159
|
-
else
|
160
|
-
lcsp = lcsp.parent
|
161
|
-
end
|
162
|
-
end
|
163
|
-
end
|
119
|
+
def restart?
|
120
|
+
@missing.any?(&:exist?)
|
121
|
+
end
|
164
122
|
|
165
|
-
|
123
|
+
def normalize_dirs!
|
124
|
+
@dirs.transform_keys! do |dir|
|
125
|
+
dir.exist? ? dir.realpath : dir
|
166
126
|
end
|
127
|
+
end
|
167
128
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
break ascendant if ascendant.directory?
|
172
|
-
end
|
129
|
+
def changed(modified, added, removed)
|
130
|
+
unless @updated.true?
|
131
|
+
@updated.make_true if (modified + added + removed).any? { |f| watching?(f) }
|
173
132
|
end
|
133
|
+
end
|
174
134
|
|
175
|
-
|
176
|
-
|
177
|
-
return dirs if dirs.length < 2
|
135
|
+
def watching?(file)
|
136
|
+
file = Pathname(file)
|
178
137
|
|
179
|
-
|
180
|
-
|
138
|
+
if @files.member?(file)
|
139
|
+
true
|
140
|
+
elsif file.directory?
|
141
|
+
false
|
142
|
+
else
|
143
|
+
ext = file.extname
|
181
144
|
|
182
|
-
|
183
|
-
|
145
|
+
file.dirname.ascend do |dir|
|
146
|
+
matching = @dirs[dir]
|
184
147
|
|
185
|
-
|
186
|
-
|
148
|
+
if matching && (matching.empty? || matching.include?(ext))
|
149
|
+
break true
|
150
|
+
elsif dir == @common_path || dir.root?
|
151
|
+
break false
|
187
152
|
end
|
188
153
|
end
|
189
|
-
|
190
|
-
# Array#- preserves order.
|
191
|
-
dirs - descendants
|
192
154
|
end
|
155
|
+
end
|
193
156
|
|
194
|
-
|
157
|
+
def directories_to_watch
|
158
|
+
dtw = @dirs.keys | @files.map(&:dirname)
|
159
|
+
accounted_for = dtw.to_set + Gem.path.map { |path| Pathname(path) }
|
160
|
+
dtw.reject { |dir| dir.ascend.drop(1).any? { |parent| accounted_for.include?(parent) } }
|
161
|
+
end
|
195
162
|
|
196
|
-
|
197
|
-
|
198
|
-
break true if base == ascendant
|
199
|
-
end
|
200
|
-
end
|
163
|
+
def common_path(paths)
|
164
|
+
paths.map { |path| path.ascend.to_a }.reduce(&:&)&.first
|
201
165
|
end
|
166
|
+
end
|
202
167
|
end
|
203
168
|
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,4 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/error_reporter"
|
1
4
|
require "active_support/callbacks"
|
5
|
+
require "concurrent/hash"
|
2
6
|
|
3
7
|
module ActiveSupport
|
4
8
|
class ExecutionWrapper
|
@@ -60,18 +64,21 @@ module ActiveSupport
|
|
60
64
|
# after the work has been performed.
|
61
65
|
#
|
62
66
|
# Where possible, prefer +wrap+.
|
63
|
-
def self.run!
|
64
|
-
if
|
65
|
-
|
67
|
+
def self.run!(reset: false)
|
68
|
+
if reset
|
69
|
+
lost_instance = IsolatedExecutionState.delete(active_key)
|
70
|
+
lost_instance&.complete!
|
66
71
|
else
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
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
|
75
82
|
end
|
76
83
|
end
|
77
84
|
end
|
@@ -83,28 +90,42 @@ module ActiveSupport
|
|
83
90
|
instance = run!
|
84
91
|
begin
|
85
92
|
yield
|
93
|
+
rescue => error
|
94
|
+
error_reporter.report(error, handled: false)
|
95
|
+
raise
|
86
96
|
ensure
|
87
97
|
instance.complete!
|
88
98
|
end
|
89
99
|
end
|
90
100
|
|
91
|
-
|
92
|
-
|
101
|
+
def self.perform # :nodoc:
|
102
|
+
instance = new
|
103
|
+
instance.run
|
104
|
+
begin
|
105
|
+
yield
|
106
|
+
ensure
|
107
|
+
instance.complete
|
108
|
+
end
|
93
109
|
end
|
94
110
|
|
95
|
-
def self.
|
96
|
-
|
97
|
-
other.active = Concurrent::Hash.new
|
111
|
+
def self.error_reporter
|
112
|
+
@error_reporter ||= ActiveSupport::ErrorReporter.new
|
98
113
|
end
|
99
114
|
|
100
|
-
self.
|
115
|
+
def self.active_key # :nodoc:
|
116
|
+
@active_key ||= :"active_execution_wrapper_#{object_id}"
|
117
|
+
end
|
101
118
|
|
102
119
|
def self.active? # :nodoc:
|
103
|
-
|
120
|
+
IsolatedExecutionState.key?(active_key)
|
104
121
|
end
|
105
122
|
|
106
123
|
def run! # :nodoc:
|
107
|
-
self.class.
|
124
|
+
IsolatedExecutionState[self.class.active_key] = self
|
125
|
+
run
|
126
|
+
end
|
127
|
+
|
128
|
+
def run # :nodoc:
|
108
129
|
run_callbacks(:run)
|
109
130
|
end
|
110
131
|
|
@@ -113,9 +134,13 @@ module ActiveSupport
|
|
113
134
|
#
|
114
135
|
# Where possible, prefer +wrap+.
|
115
136
|
def complete!
|
116
|
-
|
137
|
+
complete
|
117
138
|
ensure
|
118
|
-
self.class.
|
139
|
+
IsolatedExecutionState.delete(self.class.active_key)
|
140
|
+
end
|
141
|
+
|
142
|
+
def complete # :nodoc:
|
143
|
+
run_callbacks(:complete)
|
119
144
|
end
|
120
145
|
|
121
146
|
private
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/core_ext/time/calculations"
|
2
4
|
|
3
5
|
module ActiveSupport
|
@@ -96,7 +98,6 @@ module ActiveSupport
|
|
96
98
|
end
|
97
99
|
|
98
100
|
private
|
99
|
-
|
100
101
|
def watched
|
101
102
|
@watched || begin
|
102
103
|
all = @files.select { |f| File.exist?(f) }
|
@@ -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!
|
@@ -1,14 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveSupport
|
2
|
-
# Returns the version of
|
4
|
+
# Returns the currently loaded version of Active Support as a <tt>Gem::Version</tt>.
|
3
5
|
def self.gem_version
|
4
6
|
Gem::Version.new VERSION::STRING
|
5
7
|
end
|
6
8
|
|
7
9
|
module VERSION
|
8
|
-
MAJOR =
|
9
|
-
MINOR =
|
10
|
-
TINY =
|
11
|
-
PRE =
|
10
|
+
MAJOR = 7
|
11
|
+
MINOR = 0
|
12
|
+
TINY = 4
|
13
|
+
PRE = "1"
|
12
14
|
|
13
15
|
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
|
14
16
|
end
|