activesupport 6.0.6.1 → 7.1.3.2
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 +865 -438
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -6
- data/lib/active_support/actionable_error.rb +4 -2
- data/lib/active_support/array_inquirer.rb +4 -2
- data/lib/active_support/backtrace_cleaner.rb +30 -10
- data/lib/active_support/benchmarkable.rb +4 -3
- data/lib/active_support/broadcast_logger.rb +250 -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 +208 -63
- data/lib/active_support/cache/memory_store.rb +120 -38
- data/lib/active_support/cache/null_store.rb +16 -2
- data/lib/active_support/cache/redis_cache_store.rb +201 -208
- data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
- data/lib/active_support/cache/strategy/local_cache.rb +73 -66
- data/lib/active_support/cache.rb +539 -261
- data/lib/active_support/callbacks.rb +273 -142
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +53 -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 +19 -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 +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/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 +19 -29
- 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 +18 -16
- data/lib/active_support/core_ext/date_and_time/calculations.rb +27 -4
- 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/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 +146 -72
- 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 +3 -4
- data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +4 -4
- data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
- data/lib/active_support/core_ext/hash/keys.rb +5 -5
- data/lib/active_support/core_ext/hash/slice.rb +3 -2
- 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/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 +31 -29
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +51 -20
- data/lib/active_support/core_ext/module/concerning.rb +14 -8
- data/lib/active_support/core_ext/module/delegation.rb +75 -42
- data/lib/active_support/core_ext/module/deprecation.rb +15 -12
- data/lib/active_support/core_ext/module/introspection.rb +1 -26
- data/lib/active_support/core_ext/name_error.rb +23 -2
- data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +82 -73
- 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 +15 -4
- 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 +52 -28
- 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 +6 -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/regexp.rb +8 -1
- data/lib/active_support/core_ext/securerandom.rb +25 -13
- data/lib/active_support/core_ext/string/access.rb +5 -24
- data/lib/active_support/core_ext/string/conversions.rb +3 -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 +51 -10
- data/lib/active_support/core_ext/string/inquiry.rb +2 -1
- data/lib/active_support/core_ext/string/multibyte.rb +2 -2
- data/lib/active_support/core_ext/string/output_safety.rb +85 -194
- 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/thread/backtrace/location.rb +12 -0
- data/lib/active_support/core_ext/time/calculations.rb +46 -8
- data/lib/active_support/core_ext/time/conversions.rb +16 -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/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +54 -22
- 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 -769
- data/lib/active_support/deprecation/behaviors.rb +77 -38
- 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 +54 -0
- data/lib/active_support/deprecation/instance_delegator.rb +31 -5
- data/lib/active_support/deprecation/method_wrappers.rb +12 -28
- data/lib/active_support/deprecation/proxy_wrappers.rb +40 -25
- data/lib/active_support/deprecation/reporting.rb +76 -16
- data/lib/active_support/deprecation.rb +36 -4
- data/lib/active_support/deprecator.rb +7 -0
- data/lib/active_support/descendants_tracker.rb +150 -68
- 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 -12
- data/lib/active_support/duration.rb +136 -56
- data/lib/active_support/encrypted_configuration.rb +72 -9
- data/lib/active_support/encrypted_file.rb +46 -13
- data/lib/active_support/environment_inquirer.rb +40 -0
- 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 +86 -137
- 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 +31 -12
- 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 +79 -0
- data/lib/active_support/gem_version.rb +5 -5
- data/lib/active_support/gzip.rb +2 -0
- data/lib/active_support/hash_with_indifferent_access.rb +86 -42
- 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 +29 -27
- data/lib/active_support/inflector/inflections.rb +26 -9
- data/lib/active_support/inflector/methods.rb +54 -64
- data/lib/active_support/inflector/transliterate.rb +7 -5
- data/lib/active_support/isolated_execution_state.rb +76 -0
- data/lib/active_support/json/decoding.rb +6 -5
- data/lib/active_support/json/encoding.rb +31 -45
- data/lib/active_support/key_generator.rb +32 -7
- data/lib/active_support/lazy_load_hooks.rb +33 -7
- data/lib/active_support/locale/en.yml +10 -4
- data/lib/active_support/log_subscriber/test_helper.rb +2 -2
- data/lib/active_support/log_subscriber.rb +101 -32
- data/lib/active_support/logger.rb +9 -60
- data/lib/active_support/logger_silence.rb +2 -26
- data/lib/active_support/logger_thread_safe_level.rb +24 -25
- data/lib/active_support/message_encryptor.rb +205 -58
- 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 +237 -86
- 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_configuration.rb +2 -1
- data/lib/active_support/messages/rotation_coordinator.rb +93 -0
- data/lib/active_support/messages/rotator.rb +35 -32
- data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
- data/lib/active_support/multibyte/chars.rb +15 -52
- data/lib/active_support/multibyte/unicode.rb +8 -122
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +310 -105
- data/lib/active_support/notifications/instrumenter.rb +113 -48
- data/lib/active_support/notifications.rb +56 -29
- data/lib/active_support/number_helper/number_converter.rb +15 -8
- data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +5 -5
- data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -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 +379 -304
- data/lib/active_support/option_merger.rb +11 -18
- data/lib/active_support/ordered_hash.rb +4 -4
- data/lib/active_support/ordered_options.rb +23 -3
- data/lib/active_support/parameter_filter.rb +104 -75
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/rails.rb +1 -4
- data/lib/active_support/railtie.rb +90 -6
- data/lib/active_support/reloader.rb +12 -4
- 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 +58 -0
- data/lib/active_support/security_utils.rb +19 -12
- data/lib/active_support/string_inquirer.rb +5 -3
- data/lib/active_support/subscriber.rb +23 -47
- data/lib/active_support/syntax_error_proxy.rb +70 -0
- data/lib/active_support/tagged_logging.rb +84 -23
- data/lib/active_support/test_case.rb +166 -27
- data/lib/active_support/testing/assertions.rb +73 -20
- 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 +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 +81 -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 +89 -19
- data/lib/active_support/time_with_zone.rb +105 -70
- data/lib/active_support/values/time_zone.rb +59 -26
- 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 +9 -2
- data/lib/active_support/xml_mini.rb +7 -6
- data/lib/active_support.rb +40 -1
- metadata +127 -40
- 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/core_ext/range/include_time_with_zone.rb +0 -23
- data/lib/active_support/core_ext/range/overlaps.rb +0 -10
- data/lib/active_support/core_ext/uri.rb +0 -25
- data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
- data/lib/active_support/per_thread_registry.rb +0 -60
@@ -5,55 +5,9 @@ module ActiveSupport
|
|
5
5
|
module Unicode
|
6
6
|
extend self
|
7
7
|
|
8
|
-
# A list of all available normalization forms.
|
9
|
-
# See https://www.unicode.org/reports/tr15/tr15-29.html for more
|
10
|
-
# information about normalization.
|
11
|
-
NORMALIZATION_FORMS = [:c, :kc, :d, :kd]
|
12
|
-
|
13
|
-
NORMALIZATION_FORM_ALIASES = { # :nodoc:
|
14
|
-
c: :nfc,
|
15
|
-
d: :nfd,
|
16
|
-
kc: :nfkc,
|
17
|
-
kd: :nfkd
|
18
|
-
}
|
19
|
-
|
20
8
|
# The Unicode version that is supported by the implementation
|
21
9
|
UNICODE_VERSION = RbConfig::CONFIG["UNICODE_VERSION"]
|
22
10
|
|
23
|
-
# The default normalization used for operations that require
|
24
|
-
# normalization. It can be set to any of the normalizations
|
25
|
-
# in NORMALIZATION_FORMS.
|
26
|
-
#
|
27
|
-
# ActiveSupport::Multibyte::Unicode.default_normalization_form = :c
|
28
|
-
attr_accessor :default_normalization_form
|
29
|
-
@default_normalization_form = :kc
|
30
|
-
|
31
|
-
# Unpack the string at grapheme boundaries. Returns a list of character
|
32
|
-
# lists.
|
33
|
-
#
|
34
|
-
# Unicode.unpack_graphemes('क्षि') # => [[2325, 2381], [2359], [2367]]
|
35
|
-
# Unicode.unpack_graphemes('Café') # => [[67], [97], [102], [233]]
|
36
|
-
def unpack_graphemes(string)
|
37
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
38
|
-
ActiveSupport::Multibyte::Unicode#unpack_graphemes is deprecated and will be
|
39
|
-
removed from Rails 6.1. Use string.scan(/\X/).map(&:codepoints) instead.
|
40
|
-
MSG
|
41
|
-
|
42
|
-
string.scan(/\X/).map(&:codepoints)
|
43
|
-
end
|
44
|
-
|
45
|
-
# Reverse operation of unpack_graphemes.
|
46
|
-
#
|
47
|
-
# Unicode.pack_graphemes(Unicode.unpack_graphemes('क्षि')) # => 'क्षि'
|
48
|
-
def pack_graphemes(unpacked)
|
49
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
50
|
-
ActiveSupport::Multibyte::Unicode#pack_graphemes is deprecated and will be
|
51
|
-
removed from Rails 6.1. Use array.flatten.pack("U*") instead.
|
52
|
-
MSG
|
53
|
-
|
54
|
-
unpacked.flatten.pack("U*")
|
55
|
-
end
|
56
|
-
|
57
11
|
# Decompose composed characters to the decomposed form.
|
58
12
|
def decompose(type, codepoints)
|
59
13
|
if type == :compatibility
|
@@ -68,83 +22,15 @@ module ActiveSupport
|
|
68
22
|
codepoints.pack("U*").unicode_normalize(:nfc).codepoints
|
69
23
|
end
|
70
24
|
|
71
|
-
#
|
72
|
-
|
73
|
-
# Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent
|
74
|
-
# resulting in a valid UTF-8 string.
|
75
|
-
#
|
76
|
-
# Passing +true+ will forcibly tidy all bytes, assuming that the string's
|
77
|
-
# encoding is entirely CP1252 or ISO-8859-1.
|
78
|
-
def tidy_bytes(string, force = false)
|
79
|
-
return string if string.empty?
|
80
|
-
return recode_windows1252_chars(string) if force
|
81
|
-
string.scrub { |bad| recode_windows1252_chars(bad) }
|
82
|
-
end
|
83
|
-
else
|
84
|
-
def tidy_bytes(string, force = false)
|
85
|
-
return string if string.empty?
|
86
|
-
return recode_windows1252_chars(string) if force
|
87
|
-
|
88
|
-
# We can't transcode to the same format, so we choose a nearly-identical encoding.
|
89
|
-
# We're going to 'transcode' bytes from UTF-8 when possible, then fall back to
|
90
|
-
# CP1252 when we get errors. The final string will be 'converted' back to UTF-8
|
91
|
-
# before returning.
|
92
|
-
reader = Encoding::Converter.new(Encoding::UTF_8, Encoding::UTF_16LE)
|
93
|
-
|
94
|
-
source = string.dup
|
95
|
-
out = "".force_encoding(Encoding::UTF_16LE)
|
96
|
-
|
97
|
-
loop do
|
98
|
-
reader.primitive_convert(source, out)
|
99
|
-
_, _, _, error_bytes, _ = reader.primitive_errinfo
|
100
|
-
break if error_bytes.nil?
|
101
|
-
out << error_bytes.encode(Encoding::UTF_16LE, Encoding::Windows_1252, invalid: :replace, undef: :replace)
|
102
|
-
end
|
103
|
-
|
104
|
-
reader.finish
|
105
|
-
|
106
|
-
out.encode!(Encoding::UTF_8)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
# Returns the KC normalization of the string by default. NFKC is
|
111
|
-
# considered the best normalization form for passing strings to databases
|
112
|
-
# and validations.
|
25
|
+
# Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent
|
26
|
+
# resulting in a valid UTF-8 string.
|
113
27
|
#
|
114
|
-
#
|
115
|
-
#
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
# See https://www.unicode.org/reports/tr15, Table 1
|
122
|
-
if alias_form = NORMALIZATION_FORM_ALIASES[form]
|
123
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
124
|
-
ActiveSupport::Multibyte::Unicode#normalize is deprecated and will be
|
125
|
-
removed from Rails 6.1. Use String#unicode_normalize(:#{alias_form}) instead.
|
126
|
-
MSG
|
127
|
-
|
128
|
-
string.unicode_normalize(alias_form)
|
129
|
-
else
|
130
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
131
|
-
ActiveSupport::Multibyte::Unicode#normalize is deprecated and will be
|
132
|
-
removed from Rails 6.1. Use String#unicode_normalize instead.
|
133
|
-
MSG
|
134
|
-
|
135
|
-
raise ArgumentError, "#{form} is not a valid normalization variant", caller
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
%w(downcase upcase swapcase).each do |method|
|
140
|
-
define_method(method) do |string|
|
141
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
142
|
-
ActiveSupport::Multibyte::Unicode##{method} is deprecated and
|
143
|
-
will be removed from Rails 6.1. Use String methods directly.
|
144
|
-
MSG
|
145
|
-
|
146
|
-
string.send(method)
|
147
|
-
end
|
28
|
+
# Passing +true+ will forcibly tidy all bytes, assuming that the string's
|
29
|
+
# encoding is entirely CP1252 or ISO-8859-1.
|
30
|
+
def tidy_bytes(string, force = false)
|
31
|
+
return string if string.empty? || string.ascii_only?
|
32
|
+
return recode_windows1252_chars(string) if force
|
33
|
+
string.scrub { |bad| recode_windows1252_chars(bad) }
|
148
34
|
end
|
149
35
|
|
150
36
|
private
|
@@ -3,9 +3,47 @@
|
|
3
3
|
require "mutex_m"
|
4
4
|
require "concurrent/map"
|
5
5
|
require "set"
|
6
|
+
require "active_support/core_ext/object/try"
|
6
7
|
|
7
8
|
module ActiveSupport
|
8
9
|
module Notifications
|
10
|
+
class InstrumentationSubscriberError < RuntimeError
|
11
|
+
attr_reader :exceptions
|
12
|
+
|
13
|
+
def initialize(exceptions)
|
14
|
+
@exceptions = exceptions
|
15
|
+
exception_class_names = exceptions.map { |e| e.class.name }
|
16
|
+
super "Exception(s) occurred within instrumentation subscribers: #{exception_class_names.join(', ')}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module FanoutIteration # :nodoc:
|
21
|
+
private
|
22
|
+
def iterate_guarding_exceptions(collection)
|
23
|
+
exceptions = nil
|
24
|
+
|
25
|
+
collection.each do |s|
|
26
|
+
yield s
|
27
|
+
rescue Exception => e
|
28
|
+
exceptions ||= []
|
29
|
+
exceptions << e
|
30
|
+
end
|
31
|
+
|
32
|
+
if exceptions
|
33
|
+
exceptions = exceptions.flat_map do |exception|
|
34
|
+
exception.is_a?(InstrumentationSubscriberError) ? exception.exceptions : [exception]
|
35
|
+
end
|
36
|
+
if exceptions.size == 1
|
37
|
+
raise exceptions.first
|
38
|
+
else
|
39
|
+
raise InstrumentationSubscriberError.new(exceptions), cause: exceptions.first
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
collection
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
9
47
|
# This is a default queue implementation that ships with Notifications.
|
10
48
|
# It just pushes events to all registered log subscribers.
|
11
49
|
#
|
@@ -14,21 +52,31 @@ module ActiveSupport
|
|
14
52
|
include Mutex_m
|
15
53
|
|
16
54
|
def initialize
|
17
|
-
@string_subscribers =
|
55
|
+
@string_subscribers = Concurrent::Map.new { |h, k| h.compute_if_absent(k) { [] } }
|
18
56
|
@other_subscribers = []
|
19
|
-
@
|
57
|
+
@all_listeners_for = Concurrent::Map.new
|
58
|
+
@groups_for = Concurrent::Map.new
|
59
|
+
@silenceable_groups_for = Concurrent::Map.new
|
20
60
|
super
|
21
61
|
end
|
22
62
|
|
23
|
-
def
|
24
|
-
|
63
|
+
def inspect # :nodoc:
|
64
|
+
total_patterns = @string_subscribers.size + @other_subscribers.size
|
65
|
+
"#<#{self.class} (#{total_patterns} patterns)>"
|
66
|
+
end
|
67
|
+
|
68
|
+
def subscribe(pattern = nil, callable = nil, monotonic: false, &block)
|
69
|
+
subscriber = Subscribers.new(pattern, callable || block, monotonic)
|
25
70
|
synchronize do
|
26
|
-
|
71
|
+
case pattern
|
72
|
+
when String
|
27
73
|
@string_subscribers[pattern] << subscriber
|
28
|
-
|
29
|
-
|
74
|
+
clear_cache(pattern)
|
75
|
+
when NilClass, Regexp
|
30
76
|
@other_subscribers << subscriber
|
31
|
-
|
77
|
+
clear_cache
|
78
|
+
else
|
79
|
+
raise ArgumentError, "pattern must be specified as a String, Regexp or empty"
|
32
80
|
end
|
33
81
|
end
|
34
82
|
subscriber
|
@@ -39,44 +87,232 @@ module ActiveSupport
|
|
39
87
|
case subscriber_or_name
|
40
88
|
when String
|
41
89
|
@string_subscribers[subscriber_or_name].clear
|
42
|
-
|
90
|
+
clear_cache(subscriber_or_name)
|
43
91
|
@other_subscribers.each { |sub| sub.unsubscribe!(subscriber_or_name) }
|
44
92
|
else
|
45
93
|
pattern = subscriber_or_name.try(:pattern)
|
46
94
|
if String === pattern
|
47
95
|
@string_subscribers[pattern].delete(subscriber_or_name)
|
48
|
-
|
96
|
+
clear_cache(pattern)
|
49
97
|
else
|
50
98
|
@other_subscribers.delete(subscriber_or_name)
|
51
|
-
|
99
|
+
clear_cache
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def clear_cache(key = nil) # :nodoc:
|
106
|
+
if key
|
107
|
+
@all_listeners_for.delete(key)
|
108
|
+
@groups_for.delete(key)
|
109
|
+
@silenceable_groups_for.delete(key)
|
110
|
+
else
|
111
|
+
@all_listeners_for.clear
|
112
|
+
@groups_for.clear
|
113
|
+
@silenceable_groups_for.clear
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
class BaseGroup # :nodoc:
|
118
|
+
include FanoutIteration
|
119
|
+
|
120
|
+
def initialize(listeners, name, id, payload)
|
121
|
+
@listeners = listeners
|
122
|
+
end
|
123
|
+
|
124
|
+
def each(&block)
|
125
|
+
iterate_guarding_exceptions(@listeners, &block)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
class BaseTimeGroup < BaseGroup # :nodoc:
|
130
|
+
def start(name, id, payload)
|
131
|
+
@start_time = now
|
132
|
+
end
|
133
|
+
|
134
|
+
def finish(name, id, payload)
|
135
|
+
stop_time = now
|
136
|
+
each do |listener|
|
137
|
+
listener.call(name, @start_time, stop_time, id, payload)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
class MonotonicTimedGroup < BaseTimeGroup # :nodoc:
|
143
|
+
private
|
144
|
+
def now
|
145
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
class TimedGroup < BaseTimeGroup # :nodoc:
|
150
|
+
private
|
151
|
+
def now
|
152
|
+
Time.now
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
class EventedGroup < BaseGroup # :nodoc:
|
157
|
+
def start(name, id, payload)
|
158
|
+
each do |s|
|
159
|
+
s.start(name, id, payload)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def finish(name, id, payload)
|
164
|
+
each do |s|
|
165
|
+
s.finish(name, id, payload)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
class EventObjectGroup < BaseGroup # :nodoc:
|
171
|
+
def start(name, id, payload)
|
172
|
+
@event = build_event(name, id, payload)
|
173
|
+
@event.start!
|
174
|
+
end
|
175
|
+
|
176
|
+
def finish(name, id, payload)
|
177
|
+
@event.payload = payload
|
178
|
+
@event.finish!
|
179
|
+
|
180
|
+
each do |s|
|
181
|
+
s.call(@event)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
private
|
186
|
+
def build_event(name, id, payload)
|
187
|
+
ActiveSupport::Notifications::Event.new name, nil, nil, id, payload
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def groups_for(name) # :nodoc:
|
192
|
+
groups = @groups_for.compute_if_absent(name) do
|
193
|
+
all_listeners_for(name).reject(&:silenceable).group_by(&:group_class).transform_values do |s|
|
194
|
+
s.map(&:delegate)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
silenceable_groups = @silenceable_groups_for.compute_if_absent(name) do
|
199
|
+
all_listeners_for(name).select(&:silenceable).group_by(&:group_class).transform_values do |s|
|
200
|
+
s.map(&:delegate)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
unless silenceable_groups.empty?
|
205
|
+
groups = groups.dup
|
206
|
+
silenceable_groups.each do |group_class, subscriptions|
|
207
|
+
active_subscriptions = subscriptions.reject { |s| s.silenced?(name) }
|
208
|
+
unless active_subscriptions.empty?
|
209
|
+
groups[group_class] = (groups[group_class] || []) + active_subscriptions
|
52
210
|
end
|
53
211
|
end
|
54
212
|
end
|
213
|
+
|
214
|
+
groups
|
215
|
+
end
|
216
|
+
|
217
|
+
# A +Handle+ is used to record the start and finish time of event.
|
218
|
+
#
|
219
|
+
# Both #start and #finish must each be called exactly once.
|
220
|
+
#
|
221
|
+
# Where possible, it's best to use the block form: ActiveSupport::Notifications.instrument.
|
222
|
+
# +Handle+ is a low-level API intended for cases where the block form can't be used.
|
223
|
+
#
|
224
|
+
# handle = ActiveSupport::Notifications.instrumenter.build_handle("my.event", {})
|
225
|
+
# begin
|
226
|
+
# handle.start
|
227
|
+
# # work to be instrumented
|
228
|
+
# ensure
|
229
|
+
# handle.finish
|
230
|
+
# end
|
231
|
+
class Handle
|
232
|
+
include FanoutIteration
|
233
|
+
|
234
|
+
def initialize(notifier, name, id, payload) # :nodoc:
|
235
|
+
@name = name
|
236
|
+
@id = id
|
237
|
+
@payload = payload
|
238
|
+
@groups = notifier.groups_for(name).map do |group_klass, grouped_listeners|
|
239
|
+
group_klass.new(grouped_listeners, name, id, payload)
|
240
|
+
end
|
241
|
+
@state = :initialized
|
242
|
+
end
|
243
|
+
|
244
|
+
def start
|
245
|
+
ensure_state! :initialized
|
246
|
+
@state = :started
|
247
|
+
|
248
|
+
iterate_guarding_exceptions(@groups) do |group|
|
249
|
+
group.start(@name, @id, @payload)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
def finish
|
254
|
+
finish_with_values(@name, @id, @payload)
|
255
|
+
end
|
256
|
+
|
257
|
+
def finish_with_values(name, id, payload) # :nodoc:
|
258
|
+
ensure_state! :started
|
259
|
+
@state = :finished
|
260
|
+
|
261
|
+
iterate_guarding_exceptions(@groups) do |group|
|
262
|
+
group.finish(name, id, payload)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
private
|
267
|
+
def ensure_state!(expected)
|
268
|
+
if @state != expected
|
269
|
+
raise ArgumentError, "expected state to be #{expected.inspect} but was #{@state.inspect}"
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
include FanoutIteration
|
275
|
+
|
276
|
+
def build_handle(name, id, payload)
|
277
|
+
Handle.new(self, name, id, payload)
|
55
278
|
end
|
56
279
|
|
57
280
|
def start(name, id, payload)
|
58
|
-
|
281
|
+
handle_stack = (IsolatedExecutionState[:_fanout_handle_stack] ||= [])
|
282
|
+
handle = build_handle(name, id, payload)
|
283
|
+
handle_stack << handle
|
284
|
+
handle.start
|
59
285
|
end
|
60
286
|
|
61
|
-
def finish(name, id, payload, listeners =
|
62
|
-
|
287
|
+
def finish(name, id, payload, listeners = nil)
|
288
|
+
handle_stack = IsolatedExecutionState[:_fanout_handle_stack]
|
289
|
+
handle = handle_stack.pop
|
290
|
+
handle.finish_with_values(name, id, payload)
|
63
291
|
end
|
64
292
|
|
65
293
|
def publish(name, *args)
|
66
|
-
listeners_for(name)
|
294
|
+
iterate_guarding_exceptions(listeners_for(name)) { |s| s.publish(name, *args) }
|
67
295
|
end
|
68
296
|
|
69
|
-
def
|
297
|
+
def publish_event(event)
|
298
|
+
iterate_guarding_exceptions(listeners_for(event.name)) { |s| s.publish_event(event) }
|
299
|
+
end
|
300
|
+
|
301
|
+
def all_listeners_for(name)
|
70
302
|
# this is correctly done double-checked locking (Concurrent::Map's lookups have volatile semantics)
|
71
|
-
@
|
303
|
+
@all_listeners_for[name] || synchronize do
|
72
304
|
# use synchronisation when accessing @subscribers
|
73
|
-
@
|
305
|
+
@all_listeners_for[name] ||=
|
74
306
|
@string_subscribers[name] + @other_subscribers.select { |s| s.subscribed_to?(name) }
|
75
307
|
end
|
76
308
|
end
|
77
309
|
|
310
|
+
def listeners_for(name)
|
311
|
+
all_listeners_for(name).reject { |s| s.silenced?(name) }
|
312
|
+
end
|
313
|
+
|
78
314
|
def listening?(name)
|
79
|
-
|
315
|
+
all_listeners_for(name).any? { |s| !s.silenced?(name) }
|
80
316
|
end
|
81
317
|
|
82
318
|
# This is a sync queue, so there is no waiting.
|
@@ -84,43 +320,36 @@ module ActiveSupport
|
|
84
320
|
end
|
85
321
|
|
86
322
|
module Subscribers # :nodoc:
|
87
|
-
def self.new(pattern, listener)
|
88
|
-
subscriber_class = Timed
|
323
|
+
def self.new(pattern, listener, monotonic)
|
324
|
+
subscriber_class = monotonic ? MonotonicTimed : Timed
|
89
325
|
|
90
326
|
if listener.respond_to?(:start) && listener.respond_to?(:finish)
|
91
327
|
subscriber_class = Evented
|
92
328
|
else
|
93
|
-
# Doing
|
94
|
-
# `proc {
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
329
|
+
# Doing this to detect a single argument block or callable
|
330
|
+
# like `proc { |x| }` vs `proc { |*x| }`, `proc { |**x| }`,
|
331
|
+
# or `proc { |x, **y| }`
|
332
|
+
procish = listener.respond_to?(:parameters) ? listener : listener.method(:call)
|
333
|
+
|
334
|
+
if procish.arity == 1 && procish.parameters.length == 1
|
335
|
+
subscriber_class = EventObject
|
100
336
|
end
|
101
337
|
end
|
102
338
|
|
103
|
-
|
339
|
+
subscriber_class.new(pattern, listener)
|
104
340
|
end
|
105
341
|
|
106
|
-
|
107
|
-
wrap_all pattern, EventObject.new(pattern, block)
|
108
|
-
end
|
109
|
-
|
110
|
-
def self.wrap_all(pattern, subscriber)
|
111
|
-
unless pattern
|
112
|
-
AllMessages.new(subscriber)
|
113
|
-
else
|
114
|
-
subscriber
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
class Matcher #:nodoc:
|
342
|
+
class Matcher # :nodoc:
|
119
343
|
attr_reader :pattern, :exclusions
|
120
344
|
|
121
345
|
def self.wrap(pattern)
|
122
|
-
|
123
|
-
|
346
|
+
if String === pattern
|
347
|
+
pattern
|
348
|
+
elsif pattern.nil?
|
349
|
+
AllMessages.new
|
350
|
+
else
|
351
|
+
new(pattern)
|
352
|
+
end
|
124
353
|
end
|
125
354
|
|
126
355
|
def initialize(pattern)
|
@@ -135,15 +364,31 @@ module ActiveSupport
|
|
135
364
|
def ===(name)
|
136
365
|
pattern === name && !exclusions.include?(name)
|
137
366
|
end
|
367
|
+
|
368
|
+
class AllMessages
|
369
|
+
def ===(name)
|
370
|
+
true
|
371
|
+
end
|
372
|
+
|
373
|
+
def unsubscribe!(*)
|
374
|
+
false
|
375
|
+
end
|
376
|
+
end
|
138
377
|
end
|
139
378
|
|
140
|
-
class Evented
|
141
|
-
attr_reader :pattern
|
379
|
+
class Evented # :nodoc:
|
380
|
+
attr_reader :pattern, :delegate, :silenceable
|
142
381
|
|
143
382
|
def initialize(pattern, delegate)
|
144
383
|
@pattern = Matcher.wrap(pattern)
|
145
384
|
@delegate = delegate
|
385
|
+
@silenceable = delegate.respond_to?(:silenced?)
|
146
386
|
@can_publish = delegate.respond_to?(:publish)
|
387
|
+
@can_publish_event = delegate.respond_to?(:publish_event)
|
388
|
+
end
|
389
|
+
|
390
|
+
def group_class
|
391
|
+
EventedGroup
|
147
392
|
end
|
148
393
|
|
149
394
|
def publish(name, *args)
|
@@ -152,91 +397,51 @@ module ActiveSupport
|
|
152
397
|
end
|
153
398
|
end
|
154
399
|
|
155
|
-
def
|
156
|
-
@
|
400
|
+
def publish_event(event)
|
401
|
+
if @can_publish_event
|
402
|
+
@delegate.publish_event event
|
403
|
+
else
|
404
|
+
publish(event.name, event.time, event.end, event.transaction_id, event.payload)
|
405
|
+
end
|
157
406
|
end
|
158
407
|
|
159
|
-
def
|
160
|
-
@delegate.
|
408
|
+
def silenced?(name)
|
409
|
+
@silenceable && @delegate.silenced?(name)
|
161
410
|
end
|
162
411
|
|
163
412
|
def subscribed_to?(name)
|
164
413
|
pattern === name
|
165
414
|
end
|
166
415
|
|
167
|
-
def matches?(name)
|
168
|
-
pattern && pattern === name
|
169
|
-
end
|
170
|
-
|
171
416
|
def unsubscribe!(name)
|
172
417
|
pattern.unsubscribe!(name)
|
173
418
|
end
|
174
419
|
end
|
175
420
|
|
176
421
|
class Timed < Evented # :nodoc:
|
177
|
-
def
|
178
|
-
|
422
|
+
def group_class
|
423
|
+
TimedGroup
|
179
424
|
end
|
180
425
|
|
181
|
-
def
|
182
|
-
|
183
|
-
timestack.push Time.now
|
426
|
+
def publish(name, *args)
|
427
|
+
@delegate.call name, *args
|
184
428
|
end
|
429
|
+
end
|
185
430
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
@delegate.call(name, started, Time.now, id, payload)
|
431
|
+
class MonotonicTimed < Timed # :nodoc:
|
432
|
+
def group_class
|
433
|
+
MonotonicTimedGroup
|
190
434
|
end
|
191
435
|
end
|
192
436
|
|
193
437
|
class EventObject < Evented
|
194
|
-
def
|
195
|
-
|
196
|
-
event = build_event name, id, payload
|
197
|
-
event.start!
|
198
|
-
stack.push event
|
438
|
+
def group_class
|
439
|
+
EventObjectGroup
|
199
440
|
end
|
200
441
|
|
201
|
-
def
|
202
|
-
stack = Thread.current[:_event_stack]
|
203
|
-
event = stack.pop
|
204
|
-
event.finish!
|
442
|
+
def publish_event(event)
|
205
443
|
@delegate.call event
|
206
444
|
end
|
207
|
-
|
208
|
-
private
|
209
|
-
def build_event(name, id, payload)
|
210
|
-
ActiveSupport::Notifications::Event.new name, nil, nil, id, payload
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
class AllMessages # :nodoc:
|
215
|
-
def initialize(delegate)
|
216
|
-
@delegate = delegate
|
217
|
-
end
|
218
|
-
|
219
|
-
def start(name, id, payload)
|
220
|
-
@delegate.start name, id, payload
|
221
|
-
end
|
222
|
-
|
223
|
-
def finish(name, id, payload)
|
224
|
-
@delegate.finish name, id, payload
|
225
|
-
end
|
226
|
-
|
227
|
-
def publish(name, *args)
|
228
|
-
@delegate.publish name, *args
|
229
|
-
end
|
230
|
-
|
231
|
-
def subscribed_to?(name)
|
232
|
-
true
|
233
|
-
end
|
234
|
-
|
235
|
-
def unsubscribe!(*)
|
236
|
-
false
|
237
|
-
end
|
238
|
-
|
239
|
-
alias :matches? :===
|
240
445
|
end
|
241
446
|
end
|
242
447
|
end
|