activesupport 7.0.8.7 → 7.2.2.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 +143 -459
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -4
- data/lib/active_support/actionable_error.rb +3 -1
- data/lib/active_support/array_inquirer.rb +3 -1
- data/lib/active_support/backtrace_cleaner.rb +39 -7
- data/lib/active_support/benchmarkable.rb +1 -0
- 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 +49 -17
- data/lib/active_support/cache/mem_cache_store.rb +94 -128
- data/lib/active_support/cache/memory_store.rb +80 -25
- data/lib/active_support/cache/null_store.rb +6 -0
- data/lib/active_support/cache/redis_cache_store.rb +165 -152
- data/lib/active_support/cache/serializer_with_fallback.rb +152 -0
- data/lib/active_support/cache/strategy/local_cache.rb +29 -14
- data/lib/active_support/cache.rb +363 -291
- data/lib/active_support/callbacks.rb +118 -134
- data/lib/active_support/code_generator.rb +15 -10
- data/lib/active_support/concern.rb +4 -2
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +42 -3
- data/lib/active_support/concurrency/null_lock.rb +13 -0
- data/lib/active_support/configurable.rb +10 -0
- data/lib/active_support/core_ext/array/conversions.rb +1 -2
- data/lib/active_support/core_ext/array.rb +0 -1
- data/lib/active_support/core_ext/class/subclasses.rb +17 -34
- data/lib/active_support/core_ext/date/blank.rb +4 -0
- data/lib/active_support/core_ext/date/conversions.rb +1 -2
- data/lib/active_support/core_ext/date.rb +0 -1
- data/lib/active_support/core_ext/date_and_time/calculations.rb +10 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +28 -1
- data/lib/active_support/core_ext/date_time/blank.rb +4 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +2 -2
- data/lib/active_support/core_ext/date_time.rb +0 -1
- data/lib/active_support/core_ext/digest/uuid.rb +7 -10
- data/lib/active_support/core_ext/enumerable.rb +3 -75
- data/lib/active_support/core_ext/erb/util.rb +201 -0
- data/lib/active_support/core_ext/hash/conversions.rb +1 -1
- data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
- data/lib/active_support/core_ext/hash/keys.rb +4 -4
- data/lib/active_support/core_ext/module/attr_internal.rb +17 -6
- data/lib/active_support/core_ext/module/attribute_accessors.rb +6 -0
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +34 -16
- data/lib/active_support/core_ext/module/concerning.rb +6 -6
- data/lib/active_support/core_ext/module/delegation.rb +20 -119
- data/lib/active_support/core_ext/module/deprecation.rb +12 -12
- data/lib/active_support/core_ext/module/introspection.rb +0 -1
- data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +5 -3
- data/lib/active_support/core_ext/numeric.rb +0 -1
- data/lib/active_support/core_ext/object/blank.rb +45 -1
- data/lib/active_support/core_ext/object/deep_dup.rb +16 -0
- data/lib/active_support/core_ext/object/inclusion.rb +13 -5
- data/lib/active_support/core_ext/object/instance_variables.rb +4 -2
- data/lib/active_support/core_ext/object/json.rb +17 -7
- data/lib/active_support/core_ext/object/with.rb +46 -0
- data/lib/active_support/core_ext/object/with_options.rb +4 -4
- data/lib/active_support/core_ext/object.rb +1 -0
- data/lib/active_support/core_ext/pathname/blank.rb +20 -0
- data/lib/active_support/core_ext/pathname/existence.rb +2 -0
- data/lib/active_support/core_ext/pathname.rb +1 -0
- data/lib/active_support/core_ext/range/conversions.rb +28 -7
- 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 +1 -5
- data/lib/active_support/core_ext/string/conversions.rb +1 -1
- 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 +16 -5
- data/lib/active_support/core_ext/string/multibyte.rb +1 -1
- data/lib/active_support/core_ext/string/output_safety.rb +34 -177
- data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
- data/lib/active_support/core_ext/time/calculations.rb +36 -30
- data/lib/active_support/core_ext/time/compatibility.rb +16 -0
- data/lib/active_support/core_ext/time/conversions.rb +1 -3
- data/lib/active_support/core_ext/time/zones.rb +4 -4
- data/lib/active_support/core_ext/time.rb +0 -1
- data/lib/active_support/core_ext.rb +0 -1
- data/lib/active_support/current_attributes.rb +53 -46
- data/lib/active_support/deep_mergeable.rb +53 -0
- data/lib/active_support/delegation.rb +202 -0
- data/lib/active_support/dependencies/autoload.rb +9 -16
- data/lib/active_support/deprecation/behaviors.rb +65 -42
- data/lib/active_support/deprecation/constant_accessor.rb +47 -25
- data/lib/active_support/deprecation/deprecators.rb +104 -0
- data/lib/active_support/deprecation/disallowed.rb +3 -5
- data/lib/active_support/deprecation/method_wrappers.rb +6 -23
- data/lib/active_support/deprecation/proxy_wrappers.rb +34 -22
- data/lib/active_support/deprecation/reporting.rb +49 -27
- data/lib/active_support/deprecation.rb +39 -9
- data/lib/active_support/deprecator.rb +7 -0
- data/lib/active_support/descendants_tracker.rb +66 -172
- data/lib/active_support/duration/iso8601_parser.rb +2 -2
- data/lib/active_support/duration/iso8601_serializer.rb +1 -4
- data/lib/active_support/duration.rb +13 -7
- data/lib/active_support/encrypted_configuration.rb +30 -9
- data/lib/active_support/encrypted_file.rb +9 -4
- data/lib/active_support/environment_inquirer.rb +22 -2
- data/lib/active_support/error_reporter/test_helper.rb +15 -0
- data/lib/active_support/error_reporter.rb +160 -36
- data/lib/active_support/evented_file_update_checker.rb +0 -1
- data/lib/active_support/execution_wrapper.rb +4 -5
- data/lib/active_support/file_update_checker.rb +5 -3
- data/lib/active_support/fork_tracker.rb +4 -32
- 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 +41 -25
- data/lib/active_support/html_safe_translation.rb +19 -6
- data/lib/active_support/i18n.rb +1 -1
- data/lib/active_support/i18n_railtie.rb +20 -13
- data/lib/active_support/inflector/inflections.rb +2 -0
- data/lib/active_support/inflector/methods.rb +23 -11
- data/lib/active_support/inflector/transliterate.rb +3 -1
- data/lib/active_support/isolated_execution_state.rb +26 -22
- data/lib/active_support/json/decoding.rb +2 -1
- data/lib/active_support/json/encoding.rb +25 -43
- data/lib/active_support/key_generator.rb +9 -1
- data/lib/active_support/lazy_load_hooks.rb +6 -4
- data/lib/active_support/locale/en.yml +2 -0
- data/lib/active_support/log_subscriber.rb +74 -34
- data/lib/active_support/logger.rb +22 -60
- data/lib/active_support/logger_thread_safe_level.rb +10 -32
- data/lib/active_support/message_encryptor.rb +197 -53
- 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 +305 -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 +220 -89
- 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 +111 -45
- 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 +4 -2
- data/lib/active_support/multibyte/unicode.rb +9 -37
- data/lib/active_support/notifications/fanout.rb +248 -87
- data/lib/active_support/notifications/instrumenter.rb +93 -25
- data/lib/active_support/notifications.rb +29 -28
- data/lib/active_support/number_helper/number_converter.rb +16 -7
- data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -6
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -3
- data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -0
- data/lib/active_support/number_helper.rb +379 -318
- data/lib/active_support/option_merger.rb +2 -2
- data/lib/active_support/ordered_hash.rb +3 -3
- data/lib/active_support/ordered_options.rb +67 -15
- data/lib/active_support/parameter_filter.rb +84 -69
- data/lib/active_support/proxy_object.rb +8 -3
- data/lib/active_support/railtie.rb +25 -20
- data/lib/active_support/reloader.rb +12 -4
- data/lib/active_support/rescuable.rb +2 -0
- data/lib/active_support/secure_compare_rotator.rb +16 -9
- data/lib/active_support/string_inquirer.rb +4 -2
- data/lib/active_support/subscriber.rb +10 -27
- data/lib/active_support/syntax_error_proxy.rb +60 -0
- data/lib/active_support/tagged_logging.rb +64 -25
- data/lib/active_support/test_case.rb +156 -7
- data/lib/active_support/testing/assertions.rb +28 -12
- data/lib/active_support/testing/autorun.rb +0 -2
- data/lib/active_support/testing/constant_stubbing.rb +54 -0
- data/lib/active_support/testing/deprecation.rb +20 -27
- data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
- data/lib/active_support/testing/isolation.rb +21 -9
- data/lib/active_support/testing/method_call_assertions.rb +7 -8
- data/lib/active_support/testing/parallelization/server.rb +3 -0
- data/lib/active_support/testing/parallelize_executor.rb +8 -3
- data/lib/active_support/testing/setup_and_teardown.rb +2 -0
- data/lib/active_support/testing/stream.rb +1 -1
- data/lib/active_support/testing/strict_warnings.rb +43 -0
- data/lib/active_support/testing/tests_without_assertions.rb +19 -0
- data/lib/active_support/testing/time_helpers.rb +38 -16
- data/lib/active_support/time_with_zone.rb +12 -18
- data/lib/active_support/values/time_zone.rb +25 -14
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini/jdom.rb +3 -10
- data/lib/active_support/xml_mini/nokogiri.rb +1 -1
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
- data/lib/active_support/xml_mini/rexml.rb +1 -1
- data/lib/active_support/xml_mini.rb +12 -3
- data/lib/active_support.rb +15 -3
- metadata +140 -19
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +0 -25
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +0 -40
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +0 -36
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +0 -60
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +0 -36
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -5
- data/lib/active_support/core_ext/range/overlaps.rb +0 -10
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +0 -73
- data/lib/active_support/core_ext/uri.rb +0 -5
- data/lib/active_support/deprecation/instance_delegator.rb +0 -38
- data/lib/active_support/per_thread_registry.rb +0 -65
- data/lib/active_support/ruby_features.rb +0 -7
data/MIT-LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
= Active Support -- Utility classes and Ruby extensions from Rails
|
1
|
+
= Active Support -- Utility classes and Ruby extensions from \Rails
|
2
2
|
|
3
3
|
Active Support is a collection of utility classes and standard library
|
4
|
-
extensions that were found useful for the Rails framework. These additions
|
4
|
+
extensions that were found useful for the \Rails framework. These additions
|
5
5
|
reside in this package so they can be loaded as needed in Ruby projects
|
6
|
-
outside of Rails.
|
6
|
+
outside of \Rails.
|
7
7
|
|
8
|
-
You can read more about the extensions in the {Active Support Core Extensions}[https://
|
8
|
+
You can read more about the extensions in the {Active Support Core Extensions}[https://guides.rubyonrails.org/active_support_core_extensions.html] guide.
|
9
9
|
|
10
10
|
== Download and installation
|
11
11
|
|
@@ -1,9 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveSupport
|
4
|
+
# = Actionable Errors
|
5
|
+
#
|
4
6
|
# Actionable errors lets you define actions to resolve an error.
|
5
7
|
#
|
6
|
-
# To make an error actionable, include the
|
8
|
+
# To make an error actionable, include the +ActiveSupport::ActionableError+
|
7
9
|
# module and invoke the +action+ class macro to define the action. An action
|
8
10
|
# needs a name and a block to execute.
|
9
11
|
module ActionableError
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveSupport
|
4
|
+
# = \Array Inquirer
|
5
|
+
#
|
4
6
|
# Wrapping an array in an +ArrayInquirer+ gives a friendlier way to check
|
5
7
|
# its string-like contents:
|
6
8
|
#
|
@@ -37,7 +39,7 @@ module ActiveSupport
|
|
37
39
|
name.end_with?("?") || super
|
38
40
|
end
|
39
41
|
|
40
|
-
def method_missing(name,
|
42
|
+
def method_missing(name, ...)
|
41
43
|
if name.end_with?("?")
|
42
44
|
any?(name[0..-2])
|
43
45
|
else
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveSupport
|
4
|
+
# = Backtrace Cleaner
|
5
|
+
#
|
4
6
|
# Backtraces often include many lines that are not relevant for the context
|
5
7
|
# under review. This makes it hard to find the signal amongst the backtrace
|
6
8
|
# noise, and adds debugging time. With a BacktraceCleaner, filters and
|
@@ -15,11 +17,12 @@ module ActiveSupport
|
|
15
17
|
# can focus on the rest.
|
16
18
|
#
|
17
19
|
# bc = ActiveSupport::BacktraceCleaner.new
|
18
|
-
#
|
20
|
+
# root = "#{Rails.root}/"
|
21
|
+
# bc.add_filter { |line| line.start_with?(root) ? line.from(root.size) : line } # strip the Rails.root prefix
|
19
22
|
# bc.add_silencer { |line| /puma|rubygems/.match?(line) } # skip any lines from puma or rubygems
|
20
23
|
# bc.clean(exception.backtrace) # perform the cleanup
|
21
24
|
#
|
22
|
-
# To reconfigure an existing BacktraceCleaner (like the default one in Rails)
|
25
|
+
# To reconfigure an existing BacktraceCleaner (like the default one in \Rails)
|
23
26
|
# and show as much data as possible, you can always call
|
24
27
|
# BacktraceCleaner#remove_silencers!, which will restore the
|
25
28
|
# backtrace to a pristine state. If you need to reconfigure an existing
|
@@ -31,6 +34,7 @@ module ActiveSupport
|
|
31
34
|
class BacktraceCleaner
|
32
35
|
def initialize
|
33
36
|
@filters, @silencers = [], []
|
37
|
+
add_core_silencer
|
34
38
|
add_gem_filter
|
35
39
|
add_gem_silencer
|
36
40
|
add_stdlib_silencer
|
@@ -52,11 +56,30 @@ module ActiveSupport
|
|
52
56
|
end
|
53
57
|
alias :filter :clean
|
54
58
|
|
59
|
+
# Returns the frame with all filters applied.
|
60
|
+
# returns +nil+ if the frame was silenced.
|
61
|
+
def clean_frame(frame, kind = :silent)
|
62
|
+
frame = frame.to_s
|
63
|
+
@filters.each do |f|
|
64
|
+
frame = f.call(frame.to_s)
|
65
|
+
end
|
66
|
+
|
67
|
+
case kind
|
68
|
+
when :silent
|
69
|
+
frame unless @silencers.any? { |s| s.call(frame) }
|
70
|
+
when :noise
|
71
|
+
frame if @silencers.any? { |s| s.call(frame) }
|
72
|
+
else
|
73
|
+
frame
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
55
77
|
# Adds a filter from the block provided. Each line in the backtrace will be
|
56
78
|
# mapped against this filter.
|
57
79
|
#
|
58
|
-
# # Will turn "/my/rails/root/app/models/person.rb" into "
|
59
|
-
#
|
80
|
+
# # Will turn "/my/rails/root/app/models/person.rb" into "app/models/person.rb"
|
81
|
+
# root = "#{Rails.root}/"
|
82
|
+
# backtrace_cleaner.add_filter { |line| line.start_with?(root) ? line.from(root.size) : line }
|
60
83
|
def add_filter(&block)
|
61
84
|
@filters << block
|
62
85
|
end
|
@@ -87,6 +110,11 @@ module ActiveSupport
|
|
87
110
|
private
|
88
111
|
FORMATTED_GEMS_PATTERN = /\A[^\/]+ \([\w.]+\) /
|
89
112
|
|
113
|
+
def initialize_copy(_other)
|
114
|
+
@filters = @filters.dup
|
115
|
+
@silencers = @silencers.dup
|
116
|
+
end
|
117
|
+
|
90
118
|
def add_gem_filter
|
91
119
|
gems_paths = (Gem.path | [Gem.default_dir]).map { |p| Regexp.escape(p) }
|
92
120
|
return if gems_paths.empty?
|
@@ -96,6 +124,10 @@ module ActiveSupport
|
|
96
124
|
add_filter { |line| line.sub(gems_regexp, gems_result) }
|
97
125
|
end
|
98
126
|
|
127
|
+
def add_core_silencer
|
128
|
+
add_silencer { |line| line.include?("<internal:") }
|
129
|
+
end
|
130
|
+
|
99
131
|
def add_gem_silencer
|
100
132
|
add_silencer { |line| FORMATTED_GEMS_PATTERN.match?(line) }
|
101
133
|
end
|
@@ -106,7 +138,7 @@ module ActiveSupport
|
|
106
138
|
|
107
139
|
def filter_backtrace(backtrace)
|
108
140
|
@filters.each do |f|
|
109
|
-
backtrace = backtrace.map { |line| f.call(line) }
|
141
|
+
backtrace = backtrace.map { |line| f.call(line.to_s) }
|
110
142
|
end
|
111
143
|
|
112
144
|
backtrace
|
@@ -114,7 +146,7 @@ module ActiveSupport
|
|
114
146
|
|
115
147
|
def silence(backtrace)
|
116
148
|
@silencers.each do |s|
|
117
|
-
backtrace = backtrace.reject { |line| s.call(line) }
|
149
|
+
backtrace = backtrace.reject { |line| s.call(line.to_s) }
|
118
150
|
end
|
119
151
|
|
120
152
|
backtrace
|
@@ -123,7 +155,7 @@ module ActiveSupport
|
|
123
155
|
def noise(backtrace)
|
124
156
|
backtrace.select do |line|
|
125
157
|
@silencers.any? do |s|
|
126
|
-
s.call(line)
|
158
|
+
s.call(line.to_s)
|
127
159
|
end
|
128
160
|
end
|
129
161
|
end
|
@@ -4,6 +4,7 @@ require "active_support/core_ext/benchmark"
|
|
4
4
|
require "active_support/core_ext/hash/keys"
|
5
5
|
|
6
6
|
module ActiveSupport
|
7
|
+
# = \Benchmarkable
|
7
8
|
module Benchmarkable
|
8
9
|
# Allows you to measure the execution time of a block in a template and
|
9
10
|
# records the result to the log. Wrap this block around expensive operations
|
@@ -0,0 +1,251 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
# = Active Support Broadcast Logger
|
5
|
+
#
|
6
|
+
# The Broadcast logger is a logger used to write messages to multiple IO. It is commonly used
|
7
|
+
# in development to display messages on STDOUT and also write them to a file (development.log).
|
8
|
+
# With the Broadcast logger, you can broadcast your logs to a unlimited number of sinks.
|
9
|
+
#
|
10
|
+
# The BroadcastLogger acts as a standard logger and all methods you are used to are available.
|
11
|
+
# However, all the methods on this logger will propagate and be delegated to the other loggers
|
12
|
+
# that are part of the broadcast.
|
13
|
+
#
|
14
|
+
# Broadcasting your logs.
|
15
|
+
#
|
16
|
+
# stdout_logger = Logger.new(STDOUT)
|
17
|
+
# file_logger = Logger.new("development.log")
|
18
|
+
# broadcast = BroadcastLogger.new(stdout_logger, file_logger)
|
19
|
+
#
|
20
|
+
# broadcast.info("Hello world!") # Writes the log to STDOUT and the development.log file.
|
21
|
+
#
|
22
|
+
# Add a logger to the broadcast.
|
23
|
+
#
|
24
|
+
# stdout_logger = Logger.new(STDOUT)
|
25
|
+
# broadcast = BroadcastLogger.new(stdout_logger)
|
26
|
+
# file_logger = Logger.new("development.log")
|
27
|
+
# broadcast.broadcast_to(file_logger)
|
28
|
+
#
|
29
|
+
# broadcast.info("Hello world!") # Writes the log to STDOUT and the development.log file.
|
30
|
+
#
|
31
|
+
# Modifying the log level for all broadcasted loggers.
|
32
|
+
#
|
33
|
+
# stdout_logger = Logger.new(STDOUT)
|
34
|
+
# file_logger = Logger.new("development.log")
|
35
|
+
# broadcast = BroadcastLogger.new(stdout_logger, file_logger)
|
36
|
+
#
|
37
|
+
# broadcast.level = Logger::FATAL # Modify the log level for the whole broadcast.
|
38
|
+
#
|
39
|
+
# Stop broadcasting log to a sink.
|
40
|
+
#
|
41
|
+
# stdout_logger = Logger.new(STDOUT)
|
42
|
+
# file_logger = Logger.new("development.log")
|
43
|
+
# broadcast = BroadcastLogger.new(stdout_logger, file_logger)
|
44
|
+
# broadcast.info("Hello world!") # Writes the log to STDOUT and the development.log file.
|
45
|
+
#
|
46
|
+
# broadcast.stop_broadcasting_to(file_logger)
|
47
|
+
# broadcast.info("Hello world!") # Writes the log *only* to STDOUT.
|
48
|
+
#
|
49
|
+
# At least one sink has to be part of the broadcast. Otherwise, your logs will not
|
50
|
+
# be written anywhere. For instance:
|
51
|
+
#
|
52
|
+
# broadcast = BroadcastLogger.new
|
53
|
+
# broadcast.info("Hello world") # The log message will appear nowhere.
|
54
|
+
#
|
55
|
+
# If you are adding a custom logger with custom methods to the broadcast,
|
56
|
+
# the `BroadcastLogger` will proxy them and return the raw value, or an array
|
57
|
+
# of raw values, depending on how many loggers in the broadcasts responded to
|
58
|
+
# the method:
|
59
|
+
#
|
60
|
+
# class MyLogger < ::Logger
|
61
|
+
# def loggable?
|
62
|
+
# true
|
63
|
+
# end
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# logger = BroadcastLogger.new
|
67
|
+
# logger.loggable? # => A NoMethodError exception is raised because no loggers in the broadcasts could respond.
|
68
|
+
#
|
69
|
+
# logger.broadcast_to(MyLogger.new(STDOUT))
|
70
|
+
# logger.loggable? # => true
|
71
|
+
# logger.broadcast_to(MyLogger.new(STDOUT))
|
72
|
+
# puts logger.broadcasts # => [MyLogger, MyLogger]
|
73
|
+
# logger.loggable? # [true, true]
|
74
|
+
class BroadcastLogger
|
75
|
+
include ActiveSupport::LoggerSilence
|
76
|
+
|
77
|
+
# Returns all the logger that are part of this broadcast.
|
78
|
+
attr_reader :broadcasts
|
79
|
+
attr_reader :formatter
|
80
|
+
attr_accessor :progname
|
81
|
+
|
82
|
+
def initialize(*loggers)
|
83
|
+
@broadcasts = []
|
84
|
+
@progname = "Broadcast"
|
85
|
+
|
86
|
+
broadcast_to(*loggers)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Add logger(s) to the broadcast.
|
90
|
+
#
|
91
|
+
# broadcast_logger = ActiveSupport::BroadcastLogger.new
|
92
|
+
# broadcast_logger.broadcast_to(Logger.new(STDOUT), Logger.new(STDERR))
|
93
|
+
def broadcast_to(*loggers)
|
94
|
+
@broadcasts.concat(loggers)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Remove a logger from the broadcast. When a logger is removed, messages sent to
|
98
|
+
# the broadcast will no longer be written to its sink.
|
99
|
+
#
|
100
|
+
# sink = Logger.new(STDOUT)
|
101
|
+
# broadcast_logger = ActiveSupport::BroadcastLogger.new
|
102
|
+
#
|
103
|
+
# broadcast_logger.stop_broadcasting_to(sink)
|
104
|
+
def stop_broadcasting_to(logger)
|
105
|
+
@broadcasts.delete(logger)
|
106
|
+
end
|
107
|
+
|
108
|
+
def level
|
109
|
+
@broadcasts.map(&:level).min
|
110
|
+
end
|
111
|
+
|
112
|
+
def <<(message)
|
113
|
+
dispatch { |logger| logger.<<(message) }
|
114
|
+
end
|
115
|
+
|
116
|
+
def add(...)
|
117
|
+
dispatch { |logger| logger.add(...) }
|
118
|
+
end
|
119
|
+
alias_method :log, :add
|
120
|
+
|
121
|
+
def debug(...)
|
122
|
+
dispatch { |logger| logger.debug(...) }
|
123
|
+
end
|
124
|
+
|
125
|
+
def info(...)
|
126
|
+
dispatch { |logger| logger.info(...) }
|
127
|
+
end
|
128
|
+
|
129
|
+
def warn(...)
|
130
|
+
dispatch { |logger| logger.warn(...) }
|
131
|
+
end
|
132
|
+
|
133
|
+
def error(...)
|
134
|
+
dispatch { |logger| logger.error(...) }
|
135
|
+
end
|
136
|
+
|
137
|
+
def fatal(...)
|
138
|
+
dispatch { |logger| logger.fatal(...) }
|
139
|
+
end
|
140
|
+
|
141
|
+
def unknown(...)
|
142
|
+
dispatch { |logger| logger.unknown(...) }
|
143
|
+
end
|
144
|
+
|
145
|
+
def formatter=(formatter)
|
146
|
+
dispatch { |logger| logger.formatter = formatter }
|
147
|
+
|
148
|
+
@formatter = formatter
|
149
|
+
end
|
150
|
+
|
151
|
+
def level=(level)
|
152
|
+
dispatch { |logger| logger.level = level }
|
153
|
+
end
|
154
|
+
alias_method :sev_threshold=, :level=
|
155
|
+
|
156
|
+
def local_level=(level)
|
157
|
+
dispatch do |logger|
|
158
|
+
logger.local_level = level if logger.respond_to?(:local_level=)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def close
|
163
|
+
dispatch { |logger| logger.close }
|
164
|
+
end
|
165
|
+
|
166
|
+
# +True+ if the log level allows entries with severity Logger::DEBUG to be written
|
167
|
+
# to at least one broadcast. +False+ otherwise.
|
168
|
+
def debug?
|
169
|
+
@broadcasts.any? { |logger| logger.debug? }
|
170
|
+
end
|
171
|
+
|
172
|
+
# Sets the log level to Logger::DEBUG for the whole broadcast.
|
173
|
+
def debug!
|
174
|
+
dispatch { |logger| logger.debug! }
|
175
|
+
end
|
176
|
+
|
177
|
+
# +True+ if the log level allows entries with severity Logger::INFO to be written
|
178
|
+
# to at least one broadcast. +False+ otherwise.
|
179
|
+
def info?
|
180
|
+
@broadcasts.any? { |logger| logger.info? }
|
181
|
+
end
|
182
|
+
|
183
|
+
# Sets the log level to Logger::INFO for the whole broadcast.
|
184
|
+
def info!
|
185
|
+
dispatch { |logger| logger.info! }
|
186
|
+
end
|
187
|
+
|
188
|
+
# +True+ if the log level allows entries with severity Logger::WARN to be written
|
189
|
+
# to at least one broadcast. +False+ otherwise.
|
190
|
+
def warn?
|
191
|
+
@broadcasts.any? { |logger| logger.warn? }
|
192
|
+
end
|
193
|
+
|
194
|
+
# Sets the log level to Logger::WARN for the whole broadcast.
|
195
|
+
def warn!
|
196
|
+
dispatch { |logger| logger.warn! }
|
197
|
+
end
|
198
|
+
|
199
|
+
# +True+ if the log level allows entries with severity Logger::ERROR to be written
|
200
|
+
# to at least one broadcast. +False+ otherwise.
|
201
|
+
def error?
|
202
|
+
@broadcasts.any? { |logger| logger.error? }
|
203
|
+
end
|
204
|
+
|
205
|
+
# Sets the log level to Logger::ERROR for the whole broadcast.
|
206
|
+
def error!
|
207
|
+
dispatch { |logger| logger.error! }
|
208
|
+
end
|
209
|
+
|
210
|
+
# +True+ if the log level allows entries with severity Logger::FATAL to be written
|
211
|
+
# to at least one broadcast. +False+ otherwise.
|
212
|
+
def fatal?
|
213
|
+
@broadcasts.any? { |logger| logger.fatal? }
|
214
|
+
end
|
215
|
+
|
216
|
+
# Sets the log level to Logger::FATAL for the whole broadcast.
|
217
|
+
def fatal!
|
218
|
+
dispatch { |logger| logger.fatal! }
|
219
|
+
end
|
220
|
+
|
221
|
+
def initialize_copy(other)
|
222
|
+
@broadcasts = []
|
223
|
+
@progname = other.progname.dup
|
224
|
+
@formatter = other.formatter.dup
|
225
|
+
|
226
|
+
broadcast_to(*other.broadcasts.map(&:dup))
|
227
|
+
end
|
228
|
+
|
229
|
+
private
|
230
|
+
def dispatch(&block)
|
231
|
+
@broadcasts.each { |logger| block.call(logger) }
|
232
|
+
true
|
233
|
+
end
|
234
|
+
|
235
|
+
def method_missing(name, ...)
|
236
|
+
loggers = @broadcasts.select { |logger| logger.respond_to?(name) }
|
237
|
+
|
238
|
+
if loggers.none?
|
239
|
+
super
|
240
|
+
elsif loggers.one?
|
241
|
+
loggers.first.send(name, ...)
|
242
|
+
else
|
243
|
+
loggers.map { |logger| logger.send(name, ...) }
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
def respond_to_missing?(method, include_all)
|
248
|
+
@broadcasts.any? { |logger| logger.respond_to?(method, include_all) }
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
@@ -3,6 +3,6 @@
|
|
3
3
|
begin
|
4
4
|
require "builder"
|
5
5
|
rescue LoadError => e
|
6
|
-
|
6
|
+
warn "You don't have builder installed in your application. Please add it to your Gemfile and run bundle install"
|
7
7
|
raise e
|
8
8
|
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "entry"
|
4
|
+
|
5
|
+
module ActiveSupport
|
6
|
+
module Cache
|
7
|
+
class Coder # :nodoc:
|
8
|
+
def initialize(serializer, compressor, legacy_serializer: false)
|
9
|
+
@serializer = serializer
|
10
|
+
@compressor = compressor
|
11
|
+
@legacy_serializer = legacy_serializer
|
12
|
+
end
|
13
|
+
|
14
|
+
def dump(entry)
|
15
|
+
return @serializer.dump(entry) if @legacy_serializer
|
16
|
+
|
17
|
+
dump_compressed(entry, Float::INFINITY)
|
18
|
+
end
|
19
|
+
|
20
|
+
def dump_compressed(entry, threshold)
|
21
|
+
return @serializer.dump_compressed(entry, threshold) if @legacy_serializer
|
22
|
+
|
23
|
+
# If value is a string with a supported encoding, use it as the payload
|
24
|
+
# instead of passing it through the serializer.
|
25
|
+
if type = type_for_string(entry.value)
|
26
|
+
payload = entry.value.b
|
27
|
+
else
|
28
|
+
type = OBJECT_DUMP_TYPE
|
29
|
+
payload = @serializer.dump(entry.value)
|
30
|
+
end
|
31
|
+
|
32
|
+
if compressed = try_compress(payload, threshold)
|
33
|
+
payload = compressed
|
34
|
+
type = type | COMPRESSED_FLAG
|
35
|
+
end
|
36
|
+
|
37
|
+
expires_at = entry.expires_at || -1.0
|
38
|
+
|
39
|
+
version = dump_version(entry.version) if entry.version
|
40
|
+
version_length = version&.bytesize || -1
|
41
|
+
|
42
|
+
packed = SIGNATURE.b
|
43
|
+
packed << [type, expires_at, version_length].pack(PACKED_TEMPLATE)
|
44
|
+
packed << version if version
|
45
|
+
packed << payload
|
46
|
+
end
|
47
|
+
|
48
|
+
def load(dumped)
|
49
|
+
return @serializer.load(dumped) if !signature?(dumped)
|
50
|
+
|
51
|
+
type = dumped.unpack1(PACKED_TYPE_TEMPLATE)
|
52
|
+
expires_at = dumped.unpack1(PACKED_EXPIRES_AT_TEMPLATE)
|
53
|
+
version_length = dumped.unpack1(PACKED_VERSION_LENGTH_TEMPLATE)
|
54
|
+
|
55
|
+
expires_at = nil if expires_at < 0
|
56
|
+
version = load_version(dumped.byteslice(PACKED_VERSION_INDEX, version_length)) if version_length >= 0
|
57
|
+
payload = dumped.byteslice((PACKED_VERSION_INDEX + [version_length, 0].max)..)
|
58
|
+
|
59
|
+
compressor = @compressor if type & COMPRESSED_FLAG > 0
|
60
|
+
serializer = STRING_DESERIALIZERS[type & ~COMPRESSED_FLAG] || @serializer
|
61
|
+
|
62
|
+
LazyEntry.new(serializer, compressor, payload, version: version, expires_at: expires_at)
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
SIGNATURE = "\x00\x11".b.freeze
|
67
|
+
|
68
|
+
OBJECT_DUMP_TYPE = 0x01
|
69
|
+
|
70
|
+
STRING_ENCODINGS = {
|
71
|
+
0x02 => Encoding::UTF_8,
|
72
|
+
0x03 => Encoding::BINARY,
|
73
|
+
0x04 => Encoding::US_ASCII,
|
74
|
+
}
|
75
|
+
|
76
|
+
COMPRESSED_FLAG = 0x80
|
77
|
+
|
78
|
+
PACKED_TEMPLATE = "CEl<"
|
79
|
+
PACKED_TYPE_TEMPLATE = "@#{SIGNATURE.bytesize}C"
|
80
|
+
PACKED_EXPIRES_AT_TEMPLATE = "@#{[0].pack(PACKED_TYPE_TEMPLATE).bytesize}E"
|
81
|
+
PACKED_VERSION_LENGTH_TEMPLATE = "@#{[0].pack(PACKED_EXPIRES_AT_TEMPLATE).bytesize}l<"
|
82
|
+
PACKED_VERSION_INDEX = [0].pack(PACKED_VERSION_LENGTH_TEMPLATE).bytesize
|
83
|
+
|
84
|
+
MARSHAL_SIGNATURE = "\x04\x08".b.freeze
|
85
|
+
|
86
|
+
class StringDeserializer
|
87
|
+
def initialize(encoding)
|
88
|
+
@encoding = encoding
|
89
|
+
end
|
90
|
+
|
91
|
+
def load(payload)
|
92
|
+
payload.force_encoding(@encoding)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
STRING_DESERIALIZERS = STRING_ENCODINGS.transform_values { |encoding| StringDeserializer.new(encoding) }
|
97
|
+
|
98
|
+
class LazyEntry < Cache::Entry
|
99
|
+
def initialize(serializer, compressor, payload, **options)
|
100
|
+
super(payload, **options)
|
101
|
+
@serializer = serializer
|
102
|
+
@compressor = compressor
|
103
|
+
@resolved = false
|
104
|
+
end
|
105
|
+
|
106
|
+
def value
|
107
|
+
if !@resolved
|
108
|
+
@value = @serializer.load(@compressor ? @compressor.inflate(@value) : @value)
|
109
|
+
@resolved = true
|
110
|
+
end
|
111
|
+
@value
|
112
|
+
end
|
113
|
+
|
114
|
+
def mismatched?(version)
|
115
|
+
super.tap { |mismatched| value if !mismatched }
|
116
|
+
rescue Cache::DeserializationError
|
117
|
+
true
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def signature?(dumped)
|
122
|
+
dumped.is_a?(String) && dumped.start_with?(SIGNATURE)
|
123
|
+
end
|
124
|
+
|
125
|
+
def type_for_string(value)
|
126
|
+
STRING_ENCODINGS.key(value.encoding) if value.instance_of?(String)
|
127
|
+
end
|
128
|
+
|
129
|
+
def try_compress(string, threshold)
|
130
|
+
if @compressor && string.bytesize >= threshold
|
131
|
+
compressed = @compressor.deflate(string)
|
132
|
+
compressed if compressed.bytesize < string.bytesize
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def dump_version(version)
|
137
|
+
if version.encoding != Encoding::UTF_8 || version.start_with?(MARSHAL_SIGNATURE)
|
138
|
+
Marshal.dump(version)
|
139
|
+
else
|
140
|
+
version.b
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def load_version(dumped_version)
|
145
|
+
if dumped_version.start_with?(MARSHAL_SIGNATURE)
|
146
|
+
Marshal.load(dumped_version)
|
147
|
+
else
|
148
|
+
dumped_version.force_encoding(Encoding::UTF_8)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|