activesupport 4.0.12 → 7.0.2.4
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 +5 -5
- data/CHANGELOG.md +249 -501
- data/MIT-LICENSE +2 -2
- data/README.rdoc +10 -5
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/all.rb +5 -3
- data/lib/active_support/array_inquirer.rb +48 -0
- data/lib/active_support/backtrace_cleaner.rb +41 -13
- data/lib/active_support/benchmarkable.rb +7 -15
- data/lib/active_support/builder.rb +3 -1
- data/lib/active_support/cache/file_store.rb +96 -74
- data/lib/active_support/cache/mem_cache_store.rb +211 -103
- data/lib/active_support/cache/memory_store.rb +90 -58
- data/lib/active_support/cache/null_store.rb +19 -7
- data/lib/active_support/cache/redis_cache_store.rb +468 -0
- data/lib/active_support/cache/strategy/local_cache.rb +86 -83
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
- data/lib/active_support/cache.rb +580 -241
- data/lib/active_support/callbacks.rb +812 -425
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +103 -14
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +33 -0
- data/lib/active_support/concurrency/share_lock.rb +226 -0
- data/lib/active_support/configurable.rb +21 -19
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/array/access.rb +47 -1
- data/lib/active_support/core_ext/array/conversions.rb +35 -44
- 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 +26 -16
- data/lib/active_support/core_ext/array/inquiry.rb +19 -0
- data/lib/active_support/core_ext/array/wrap.rb +7 -4
- data/lib/active_support/core_ext/array.rb +10 -7
- data/lib/active_support/core_ext/benchmark.rb +5 -3
- data/lib/active_support/core_ext/big_decimal/conversions.rb +9 -26
- data/lib/active_support/core_ext/big_decimal.rb +3 -1
- data/lib/active_support/core_ext/class/attribute.rb +52 -49
- data/lib/active_support/core_ext/class/attribute_accessors.rb +5 -169
- data/lib/active_support/core_ext/class/subclasses.rb +25 -26
- data/lib/active_support/core_ext/class.rb +4 -4
- data/lib/active_support/core_ext/date/acts_like.rb +3 -1
- data/lib/active_support/core_ext/date/blank.rb +14 -0
- data/lib/active_support/core_ext/date/calculations.rb +31 -18
- data/lib/active_support/core_ext/date/conversions.rb +43 -32
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/date/zones.rb +5 -34
- data/lib/active_support/core_ext/date.rb +7 -4
- data/lib/active_support/core_ext/date_and_time/calculations.rb +198 -66
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +31 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
- data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
- data/lib/active_support/core_ext/date_time/blank.rb +14 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +79 -38
- data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +31 -26
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/date_time.rb +8 -4
- data/lib/active_support/core_ext/digest/uuid.rb +79 -0
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/enumerable.rb +249 -17
- data/lib/active_support/core_ext/file/atomic.rb +41 -32
- data/lib/active_support/core_ext/file.rb +3 -1
- data/lib/active_support/core_ext/hash/conversions.rb +71 -49
- data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +14 -5
- data/lib/active_support/core_ext/hash/indifferent_access.rb +5 -3
- data/lib/active_support/core_ext/hash/keys.rb +39 -56
- data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
- data/lib/active_support/core_ext/hash/slice.rb +8 -23
- data/lib/active_support/core_ext/hash.rb +10 -8
- data/lib/active_support/core_ext/integer/inflections.rb +3 -1
- data/lib/active_support/core_ext/integer/multiple.rb +3 -1
- data/lib/active_support/core_ext/integer/time.rb +11 -33
- data/lib/active_support/core_ext/integer.rb +5 -3
- data/lib/active_support/core_ext/kernel/concern.rb +14 -0
- data/lib/active_support/core_ext/kernel/reporting.rb +9 -78
- data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
- data/lib/active_support/core_ext/kernel.rb +5 -4
- data/lib/active_support/core_ext/load_error.rb +5 -21
- data/lib/active_support/core_ext/module/aliasing.rb +6 -44
- data/lib/active_support/core_ext/module/anonymous.rb +12 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +8 -8
- data/lib/active_support/core_ext/module/attribute_accessors.rb +186 -44
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +157 -0
- data/lib/active_support/core_ext/module/concerning.rb +140 -0
- data/lib/active_support/core_ext/module/delegation.rb +172 -45
- data/lib/active_support/core_ext/module/deprecation.rb +3 -3
- data/lib/active_support/core_ext/module/introspection.rb +23 -38
- data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
- data/lib/active_support/core_ext/module/remove_method.rb +8 -3
- data/lib/active_support/core_ext/module.rb +13 -10
- data/lib/active_support/core_ext/name_error.rb +45 -4
- data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +135 -127
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
- data/lib/active_support/core_ext/numeric/time.rb +37 -50
- data/lib/active_support/core_ext/numeric.rb +6 -3
- data/lib/active_support/core_ext/object/acts_like.rb +41 -6
- data/lib/active_support/core_ext/object/blank.rb +70 -20
- data/lib/active_support/core_ext/object/conversions.rb +6 -4
- data/lib/active_support/core_ext/object/deep_dup.rb +19 -10
- data/lib/active_support/core_ext/object/duplicable.rb +17 -47
- data/lib/active_support/core_ext/object/inclusion.rb +18 -15
- data/lib/active_support/core_ext/object/instance_variables.rb +3 -1
- data/lib/active_support/core_ext/object/json.rb +244 -0
- data/lib/active_support/core_ext/object/to_param.rb +3 -1
- data/lib/active_support/core_ext/object/to_query.rb +21 -8
- data/lib/active_support/core_ext/object/try.rb +106 -26
- data/lib/active_support/core_ext/object/with_options.rb +64 -5
- data/lib/active_support/core_ext/object.rb +14 -12
- 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 +37 -15
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/range/each.rb +18 -17
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +7 -0
- data/lib/active_support/core_ext/range/overlaps.rb +2 -0
- data/lib/active_support/core_ext/range.rb +7 -4
- data/lib/active_support/core_ext/regexp.rb +10 -1
- data/lib/active_support/core_ext/securerandom.rb +45 -0
- data/lib/active_support/core_ext/string/access.rb +42 -51
- data/lib/active_support/core_ext/string/behavior.rb +3 -1
- data/lib/active_support/core_ext/string/conversions.rb +18 -13
- data/lib/active_support/core_ext/string/exclude.rb +5 -3
- data/lib/active_support/core_ext/string/filters.rb +97 -7
- data/lib/active_support/core_ext/string/indent.rb +6 -4
- data/lib/active_support/core_ext/string/inflections.rb +106 -25
- data/lib/active_support/core_ext/string/inquiry.rb +4 -1
- data/lib/active_support/core_ext/string/multibyte.rb +18 -9
- data/lib/active_support/core_ext/string/output_safety.rb +227 -54
- data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
- data/lib/active_support/core_ext/string/strip.rb +6 -5
- data/lib/active_support/core_ext/string/zones.rb +4 -1
- data/lib/active_support/core_ext/string.rb +15 -13
- 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 +3 -1
- data/lib/active_support/core_ext/time/calculations.rb +178 -116
- data/lib/active_support/core_ext/time/compatibility.rb +16 -0
- data/lib/active_support/core_ext/time/conversions.rb +37 -25
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/time/zones.rb +44 -42
- data/lib/active_support/core_ext/time.rb +8 -5
- data/lib/active_support/core_ext/uri.rb +4 -25
- data/lib/active_support/core_ext.rb +4 -2
- 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 +3 -1
- data/lib/active_support/dependencies/interlock.rb +49 -0
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +71 -696
- data/lib/active_support/deprecation/behaviors.rb +65 -16
- data/lib/active_support/deprecation/constant_accessor.rb +52 -0
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +16 -2
- data/lib/active_support/deprecation/method_wrappers.rb +62 -21
- data/lib/active_support/deprecation/proxy_wrappers.rb +82 -31
- data/lib/active_support/deprecation/reporting.rb +81 -18
- data/lib/active_support/deprecation.rb +19 -11
- 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 +123 -0
- data/lib/active_support/duration/iso8601_serializer.rb +67 -0
- data/lib/active_support/duration.rb +437 -39
- data/lib/active_support/encrypted_configuration.rb +56 -0
- data/lib/active_support/encrypted_file.rb +117 -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 +170 -0
- 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 +151 -0
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/executor.rb +8 -0
- data/lib/active_support/file_update_checker.rb +62 -37
- data/lib/active_support/fork_tracker.rb +71 -0
- data/lib/active_support/gem_version.rb +17 -0
- data/lib/active_support/gzip.rb +7 -5
- data/lib/active_support/hash_with_indifferent_access.rb +207 -54
- data/lib/active_support/html_safe_translation.rb +43 -0
- data/lib/active_support/i18n.rb +10 -6
- data/lib/active_support/i18n_railtie.rb +48 -19
- data/lib/active_support/inflections.rb +19 -12
- data/lib/active_support/inflector/inflections.rb +97 -37
- data/lib/active_support/inflector/methods.rb +192 -157
- data/lib/active_support/inflector/transliterate.rb +83 -33
- data/lib/active_support/inflector.rb +7 -5
- data/lib/active_support/isolated_execution_state.rb +64 -0
- data/lib/active_support/json/decoding.rb +37 -42
- data/lib/active_support/json/encoding.rb +93 -293
- data/lib/active_support/json.rb +4 -2
- data/lib/active_support/key_generator.rb +30 -47
- data/lib/active_support/lazy_load_hooks.rb +54 -21
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/locale/en.yml +10 -4
- data/lib/active_support/log_subscriber/test_helper.rb +14 -12
- data/lib/active_support/log_subscriber.rb +61 -18
- data/lib/active_support/logger.rb +40 -4
- data/lib/active_support/logger_silence.rb +17 -20
- data/lib/active_support/logger_thread_safe_level.rb +69 -0
- data/lib/active_support/message_encryptor.rb +178 -55
- data/lib/active_support/message_verifier.rb +195 -26
- 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 +45 -92
- data/lib/active_support/multibyte/unicode.rb +44 -377
- data/lib/active_support/multibyte.rb +5 -3
- data/lib/active_support/notifications/fanout.rb +177 -44
- data/lib/active_support/notifications/instrumenter.rb +117 -17
- data/lib/active_support/notifications.rb +106 -39
- data/lib/active_support/number_helper/number_converter.rb +181 -0
- data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +30 -0
- data/lib/active_support/number_helper/number_to_human_converter.rb +69 -0
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +60 -0
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
- data/lib/active_support/number_helper/number_to_phone_converter.rb +59 -0
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +59 -0
- data/lib/active_support/number_helper/rounding_helper.rb +46 -0
- data/lib/active_support/number_helper.rb +152 -394
- data/lib/active_support/option_merger.rb +18 -5
- data/lib/active_support/ordered_hash.rb +8 -6
- data/lib/active_support/ordered_options.rb +43 -7
- data/lib/active_support/parameter_filter.rb +138 -0
- data/lib/active_support/per_thread_registry.rb +24 -11
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/rails.rb +10 -11
- data/lib/active_support/railtie.rb +118 -12
- data/lib/active_support/reloader.rb +130 -0
- data/lib/active_support/rescuable.rb +112 -57
- 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 +38 -0
- data/lib/active_support/string_inquirer.rb +11 -4
- data/lib/active_support/subscriber.rb +109 -39
- data/lib/active_support/tagged_logging.rb +54 -17
- data/lib/active_support/test_case.rb +121 -37
- data/lib/active_support/testing/assertions.rb +177 -39
- data/lib/active_support/testing/autorun.rb +5 -3
- data/lib/active_support/testing/constant_lookup.rb +3 -6
- data/lib/active_support/testing/declarative.rb +10 -22
- data/lib/active_support/testing/deprecation.rb +65 -11
- data/lib/active_support/testing/file_fixtures.rb +38 -0
- data/lib/active_support/testing/isolation.rb +56 -87
- data/lib/active_support/testing/method_call_assertions.rb +70 -0
- 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 +30 -10
- data/lib/active_support/testing/stream.rb +41 -0
- data/lib/active_support/testing/tagged_logging.rb +6 -4
- data/lib/active_support/testing/time_helpers.rb +246 -0
- data/lib/active_support/time.rb +13 -13
- data/lib/active_support/time_with_zone.rb +315 -90
- data/lib/active_support/values/time_zone.rb +306 -135
- data/lib/active_support/version.rb +6 -7
- data/lib/active_support/xml_mini/jdom.rb +117 -115
- data/lib/active_support/xml_mini/libxml.rb +22 -21
- data/lib/active_support/xml_mini/libxmlsax.rb +17 -19
- data/lib/active_support/xml_mini/nokogiri.rb +19 -19
- data/lib/active_support/xml_mini/nokogirisax.rb +16 -17
- data/lib/active_support/xml_mini/rexml.rb +25 -17
- data/lib/active_support/xml_mini.rb +67 -56
- data/lib/active_support.rb +58 -3
- metadata +125 -66
- data/lib/active_support/basic_object.rb +0 -11
- data/lib/active_support/buffered_logger.rb +0 -21
- data/lib/active_support/concurrency/latch.rb +0 -27
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
- data/lib/active_support/core_ext/array/uniq_by.rb +0 -19
- data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -40
- data/lib/active_support/core_ext/date_time/zones.rb +0 -24
- data/lib/active_support/core_ext/hash/diff.rb +0 -14
- data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
- data/lib/active_support/core_ext/kernel/debugger.rb +0 -10
- data/lib/active_support/core_ext/logger.rb +0 -67
- data/lib/active_support/core_ext/marshal.rb +0 -21
- data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
- data/lib/active_support/core_ext/module/reachable.rb +0 -8
- data/lib/active_support/core_ext/object/to_json.rb +0 -27
- data/lib/active_support/core_ext/proc.rb +0 -17
- data/lib/active_support/core_ext/range/include_range.rb +0 -23
- data/lib/active_support/core_ext/string/encoding.rb +0 -8
- data/lib/active_support/core_ext/struct.rb +0 -6
- data/lib/active_support/core_ext/thread.rb +0 -79
- data/lib/active_support/core_ext/time/marshal.rb +0 -30
- data/lib/active_support/file_watcher.rb +0 -36
- data/lib/active_support/json/variable.rb +0 -18
- data/lib/active_support/testing/pending.rb +0 -14
- data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/execution_wrapper"
|
4
|
+
require "active_support/executor"
|
5
|
+
|
6
|
+
module ActiveSupport
|
7
|
+
#--
|
8
|
+
# This class defines several callbacks:
|
9
|
+
#
|
10
|
+
# to_prepare -- Run once at application startup, and also from
|
11
|
+
# +to_run+.
|
12
|
+
#
|
13
|
+
# to_run -- Run before a work run that is reloading. If
|
14
|
+
# +reload_classes_only_on_change+ is true (the default), the class
|
15
|
+
# unload will have already occurred.
|
16
|
+
#
|
17
|
+
# to_complete -- Run after a work run that has reloaded. If
|
18
|
+
# +reload_classes_only_on_change+ is false, the class unload will
|
19
|
+
# have occurred after the work run, but before this callback.
|
20
|
+
#
|
21
|
+
# before_class_unload -- Run immediately before the classes are
|
22
|
+
# unloaded.
|
23
|
+
#
|
24
|
+
# after_class_unload -- Run immediately after the classes are
|
25
|
+
# unloaded.
|
26
|
+
#
|
27
|
+
class Reloader < ExecutionWrapper
|
28
|
+
define_callbacks :prepare
|
29
|
+
|
30
|
+
define_callbacks :class_unload
|
31
|
+
|
32
|
+
# Registers a callback that will run once at application startup and every time the code is reloaded.
|
33
|
+
def self.to_prepare(*args, &block)
|
34
|
+
set_callback(:prepare, *args, &block)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Registers a callback that will run immediately before the classes are unloaded.
|
38
|
+
def self.before_class_unload(*args, &block)
|
39
|
+
set_callback(:class_unload, *args, &block)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Registers a callback that will run immediately after the classes are unloaded.
|
43
|
+
def self.after_class_unload(*args, &block)
|
44
|
+
set_callback(:class_unload, :after, *args, &block)
|
45
|
+
end
|
46
|
+
|
47
|
+
to_run(:after) { self.class.prepare! }
|
48
|
+
|
49
|
+
# Initiate a manual reload
|
50
|
+
def self.reload!
|
51
|
+
executor.wrap do
|
52
|
+
new.tap do |instance|
|
53
|
+
instance.run!
|
54
|
+
ensure
|
55
|
+
instance.complete!
|
56
|
+
end
|
57
|
+
end
|
58
|
+
prepare!
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.run!(reset: false) # :nodoc:
|
62
|
+
if check!
|
63
|
+
super
|
64
|
+
else
|
65
|
+
Null
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Run the supplied block as a work unit, reloading code as needed
|
70
|
+
def self.wrap
|
71
|
+
executor.wrap do
|
72
|
+
super
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class_attribute :executor, default: Executor
|
77
|
+
class_attribute :check, default: lambda { false }
|
78
|
+
|
79
|
+
def self.check! # :nodoc:
|
80
|
+
@should_reload ||= check.call
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.reloaded! # :nodoc:
|
84
|
+
@should_reload = false
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.prepare! # :nodoc:
|
88
|
+
new.run_callbacks(:prepare)
|
89
|
+
end
|
90
|
+
|
91
|
+
def initialize
|
92
|
+
super
|
93
|
+
@locked = false
|
94
|
+
end
|
95
|
+
|
96
|
+
# Acquire the ActiveSupport::Dependencies::Interlock unload lock,
|
97
|
+
# ensuring it will be released automatically
|
98
|
+
def require_unload_lock!
|
99
|
+
unless @locked
|
100
|
+
ActiveSupport::Dependencies.interlock.start_unloading
|
101
|
+
@locked = true
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Release the unload lock if it has been previously obtained
|
106
|
+
def release_unload_lock!
|
107
|
+
if @locked
|
108
|
+
@locked = false
|
109
|
+
ActiveSupport::Dependencies.interlock.done_unloading
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def run! # :nodoc:
|
114
|
+
super
|
115
|
+
release_unload_lock!
|
116
|
+
end
|
117
|
+
|
118
|
+
def class_unload!(&block) # :nodoc:
|
119
|
+
require_unload_lock!
|
120
|
+
run_callbacks(:class_unload, &block)
|
121
|
+
end
|
122
|
+
|
123
|
+
def complete! # :nodoc:
|
124
|
+
super
|
125
|
+
self.class.reloaded!
|
126
|
+
ensure
|
127
|
+
release_unload_lock!
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -1,7 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/concern"
|
4
|
+
require "active_support/core_ext/class/attribute"
|
5
|
+
require "active_support/core_ext/string/inflections"
|
5
6
|
|
6
7
|
module ActiveSupport
|
7
8
|
# Rescuable module adds support for easier exception handling.
|
@@ -9,17 +10,16 @@ module ActiveSupport
|
|
9
10
|
extend Concern
|
10
11
|
|
11
12
|
included do
|
12
|
-
class_attribute :rescue_handlers
|
13
|
-
self.rescue_handlers = []
|
13
|
+
class_attribute :rescue_handlers, default: []
|
14
14
|
end
|
15
15
|
|
16
16
|
module ClassMethods
|
17
|
-
#
|
17
|
+
# Registers exception classes with a handler to be called by <tt>rescue_with_handler</tt>.
|
18
18
|
#
|
19
19
|
# <tt>rescue_from</tt> receives a series of exception classes or class
|
20
|
-
# names, and a trailing <tt>:with</tt>
|
21
|
-
#
|
22
|
-
# be given.
|
20
|
+
# names, and an exception handler specified by a trailing <tt>:with</tt>
|
21
|
+
# option containing the name of a method or a Proc object. Alternatively, a block
|
22
|
+
# can be given as the handler.
|
23
23
|
#
|
24
24
|
# Handlers that take one argument will be called with the exception, so
|
25
25
|
# that the exception can be inspected when dealing with it.
|
@@ -37,7 +37,7 @@ module ActiveSupport
|
|
37
37
|
# render xml: exception, status: 500
|
38
38
|
# end
|
39
39
|
#
|
40
|
-
#
|
40
|
+
# private
|
41
41
|
# def deny_access
|
42
42
|
# ...
|
43
43
|
# end
|
@@ -48,72 +48,127 @@ module ActiveSupport
|
|
48
48
|
# end
|
49
49
|
#
|
50
50
|
# Exceptions raised inside exception handlers are not propagated up.
|
51
|
-
def rescue_from(*klasses, &block)
|
52
|
-
|
53
|
-
|
54
|
-
unless options.has_key?(:with)
|
51
|
+
def rescue_from(*klasses, with: nil, &block)
|
52
|
+
unless with
|
55
53
|
if block_given?
|
56
|
-
|
54
|
+
with = block
|
57
55
|
else
|
58
|
-
raise ArgumentError, "Need a handler.
|
56
|
+
raise ArgumentError, "Need a handler. Pass the with: keyword argument or provide a block."
|
59
57
|
end
|
60
58
|
end
|
61
59
|
|
62
60
|
klasses.each do |klass|
|
63
|
-
key = if klass.is_a?(
|
61
|
+
key = if klass.is_a?(Module) && klass.respond_to?(:===)
|
64
62
|
klass.name
|
65
63
|
elsif klass.is_a?(String)
|
66
64
|
klass
|
67
65
|
else
|
68
|
-
raise ArgumentError, "#{klass}
|
66
|
+
raise ArgumentError, "#{klass.inspect} must be an Exception class or a String referencing an Exception class"
|
69
67
|
end
|
70
68
|
|
71
|
-
#
|
72
|
-
self.rescue_handlers += [[key,
|
69
|
+
# Put the new handler at the end because the list is read in reverse.
|
70
|
+
self.rescue_handlers += [[key, with]]
|
73
71
|
end
|
74
72
|
end
|
75
|
-
end
|
76
73
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
74
|
+
# Matches an exception to a handler based on the exception class.
|
75
|
+
#
|
76
|
+
# If no handler matches the exception, check for a handler matching the
|
77
|
+
# (optional) exception.cause. If no handler matches the exception or its
|
78
|
+
# cause, this returns +nil+, so you can deal with unhandled exceptions.
|
79
|
+
# Be sure to re-raise unhandled exceptions if this is what you expect.
|
80
|
+
#
|
81
|
+
# begin
|
82
|
+
# …
|
83
|
+
# rescue => exception
|
84
|
+
# rescue_with_handler(exception) || raise
|
85
|
+
# end
|
86
|
+
#
|
87
|
+
# Returns the exception if it was handled and +nil+ if it was not.
|
88
|
+
def rescue_with_handler(exception, object: self, visited_exceptions: [])
|
89
|
+
visited_exceptions << exception
|
84
90
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
# could trigger some other handler and the array could include
|
96
|
-
# precisely a string whose corresponding constant has not yet been
|
97
|
-
# seen. This is why we are tolerant to unknown constants.
|
98
|
-
#
|
99
|
-
# Note that this tolerance only matters if the exception was given as
|
100
|
-
# a string, otherwise a NameError will be raised by the interpreter
|
101
|
-
# itself when rescue_from CONSTANT is executed.
|
102
|
-
klass = self.class.const_get(klass_name) rescue nil
|
103
|
-
klass ||= klass_name.constantize rescue nil
|
104
|
-
exception.is_a?(klass) if klass
|
91
|
+
if handler = handler_for_rescue(exception, object: object)
|
92
|
+
handler.call exception
|
93
|
+
exception
|
94
|
+
elsif exception
|
95
|
+
if visited_exceptions.include?(exception.cause)
|
96
|
+
nil
|
97
|
+
else
|
98
|
+
rescue_with_handler(exception.cause, object: object, visited_exceptions: visited_exceptions)
|
99
|
+
end
|
100
|
+
end
|
105
101
|
end
|
106
102
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
103
|
+
def handler_for_rescue(exception, object: self) # :nodoc:
|
104
|
+
case rescuer = find_rescue_handler(exception)
|
105
|
+
when Symbol
|
106
|
+
method = object.method(rescuer)
|
107
|
+
if method.arity == 0
|
108
|
+
-> e { method.call }
|
109
|
+
else
|
110
|
+
method
|
111
|
+
end
|
112
|
+
when Proc
|
113
|
+
if rescuer.arity == 0
|
114
|
+
-> e { object.instance_exec(&rescuer) }
|
115
|
+
else
|
116
|
+
-> e { object.instance_exec(e, &rescuer) }
|
117
|
+
end
|
115
118
|
end
|
116
119
|
end
|
120
|
+
|
121
|
+
private
|
122
|
+
def find_rescue_handler(exception)
|
123
|
+
if exception
|
124
|
+
# Handlers are in order of declaration but the most recently declared
|
125
|
+
# is the highest priority match, so we search for matching handlers
|
126
|
+
# in reverse.
|
127
|
+
_, handler = rescue_handlers.reverse_each.detect do |class_or_name, _|
|
128
|
+
if klass = constantize_rescue_handler_class(class_or_name)
|
129
|
+
klass === exception
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
handler
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def constantize_rescue_handler_class(class_or_name)
|
138
|
+
case class_or_name
|
139
|
+
when String, Symbol
|
140
|
+
begin
|
141
|
+
# Try a lexical lookup first since we support
|
142
|
+
#
|
143
|
+
# class Super
|
144
|
+
# rescue_from 'Error', with: …
|
145
|
+
# end
|
146
|
+
#
|
147
|
+
# class Sub
|
148
|
+
# class Error < StandardError; end
|
149
|
+
# end
|
150
|
+
#
|
151
|
+
# so an Error raised in Sub will hit the 'Error' handler.
|
152
|
+
const_get class_or_name
|
153
|
+
rescue NameError
|
154
|
+
class_or_name.safe_constantize
|
155
|
+
end
|
156
|
+
else
|
157
|
+
class_or_name
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# Delegates to the class method, but uses the instance as the subject for
|
163
|
+
# rescue_from handlers (method calls, instance_exec blocks).
|
164
|
+
def rescue_with_handler(exception)
|
165
|
+
self.class.rescue_with_handler exception, object: self
|
166
|
+
end
|
167
|
+
|
168
|
+
# Internal handler lookup. Delegates to class method. Some libraries call
|
169
|
+
# this directly, so keeping it around for compatibility.
|
170
|
+
def handler_for_rescue(exception) # :nodoc:
|
171
|
+
self.class.handler_for_rescue exception, object: self
|
117
172
|
end
|
118
173
|
end
|
119
174
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/security_utils"
|
4
|
+
require "active_support/messages/rotator"
|
5
|
+
|
6
|
+
module ActiveSupport
|
7
|
+
# The ActiveSupport::SecureCompareRotator is a wrapper around +ActiveSupport::SecurityUtils.secure_compare+
|
8
|
+
# and allows you to rotate a previously defined value to a new one.
|
9
|
+
#
|
10
|
+
# It can be used as follow:
|
11
|
+
#
|
12
|
+
# rotator = ActiveSupport::SecureCompareRotator.new('new_production_value')
|
13
|
+
# rotator.rotate('previous_production_value')
|
14
|
+
# rotator.secure_compare!('previous_production_value')
|
15
|
+
#
|
16
|
+
# One real use case example would be to rotate a basic auth credentials:
|
17
|
+
#
|
18
|
+
# class MyController < ApplicationController
|
19
|
+
# def authenticate_request
|
20
|
+
# rotator = ActiveSupport::SecureCompareRotator.new('new_password')
|
21
|
+
# rotator.rotate('old_password')
|
22
|
+
#
|
23
|
+
# authenticate_or_request_with_http_basic do |username, password|
|
24
|
+
# rotator.secure_compare!(password)
|
25
|
+
# rescue ActiveSupport::SecureCompareRotator::InvalidMatch
|
26
|
+
# false
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
class SecureCompareRotator
|
31
|
+
include SecurityUtils
|
32
|
+
prepend Messages::Rotator
|
33
|
+
|
34
|
+
InvalidMatch = Class.new(StandardError)
|
35
|
+
|
36
|
+
def initialize(value, **_options)
|
37
|
+
@value = value
|
38
|
+
end
|
39
|
+
|
40
|
+
def secure_compare!(other_value, on_rotation: @on_rotation)
|
41
|
+
secure_compare(@value, other_value) ||
|
42
|
+
run_rotations(on_rotation) { |wrapper| wrapper.secure_compare!(other_value) } ||
|
43
|
+
raise(InvalidMatch)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
def build_rotation(previous_value, _options)
|
48
|
+
self.class.new(previous_value)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
module SecurityUtils
|
5
|
+
# Constant time string comparison, for fixed length strings.
|
6
|
+
#
|
7
|
+
# The values compared should be of fixed length, such as strings
|
8
|
+
# that have already been processed by HMAC. Raises in case of length mismatch.
|
9
|
+
|
10
|
+
if defined?(OpenSSL.fixed_length_secure_compare)
|
11
|
+
def fixed_length_secure_compare(a, b)
|
12
|
+
OpenSSL.fixed_length_secure_compare(a, b)
|
13
|
+
end
|
14
|
+
else
|
15
|
+
def fixed_length_secure_compare(a, b)
|
16
|
+
raise ArgumentError, "string length mismatch." unless a.bytesize == b.bytesize
|
17
|
+
|
18
|
+
l = a.unpack "C#{a.bytesize}"
|
19
|
+
|
20
|
+
res = 0
|
21
|
+
b.each_byte { |byte| res |= byte ^ l.shift }
|
22
|
+
res == 0
|
23
|
+
end
|
24
|
+
end
|
25
|
+
module_function :fixed_length_secure_compare
|
26
|
+
|
27
|
+
# Secure string comparison for strings of variable length.
|
28
|
+
#
|
29
|
+
# While a timing attack would not be able to discern the content of
|
30
|
+
# a secret compared via secure_compare, it is possible to determine
|
31
|
+
# the secret length. This should be considered when using secure_compare
|
32
|
+
# to compare weak, short secrets to user input.
|
33
|
+
def secure_compare(a, b)
|
34
|
+
a.bytesize == b.bytesize && fixed_length_secure_compare(a, b)
|
35
|
+
end
|
36
|
+
module_function :secure_compare
|
37
|
+
end
|
38
|
+
end
|
@@ -1,22 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveSupport
|
2
4
|
# Wrapping a string in this class gives you a prettier way to test
|
3
5
|
# for equality. The value returned by <tt>Rails.env</tt> is wrapped
|
4
|
-
# in a StringInquirer object so instead of calling this:
|
6
|
+
# in a StringInquirer object, so instead of calling this:
|
5
7
|
#
|
6
8
|
# Rails.env == 'production'
|
7
9
|
#
|
8
10
|
# you can call this:
|
9
11
|
#
|
10
12
|
# Rails.env.production?
|
13
|
+
#
|
14
|
+
# == Instantiating a new StringInquirer
|
15
|
+
#
|
16
|
+
# vehicle = ActiveSupport::StringInquirer.new('car')
|
17
|
+
# vehicle.car? # => true
|
18
|
+
# vehicle.bike? # => false
|
11
19
|
class StringInquirer < String
|
12
20
|
private
|
13
|
-
|
14
21
|
def respond_to_missing?(method_name, include_private = false)
|
15
|
-
method_name
|
22
|
+
method_name.end_with?("?") || super
|
16
23
|
end
|
17
24
|
|
18
25
|
def method_missing(method_name, *arguments)
|
19
|
-
if method_name
|
26
|
+
if method_name.end_with?("?")
|
20
27
|
self == method_name[0..-2]
|
21
28
|
else
|
22
29
|
super
|
@@ -1,93 +1,163 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/notifications"
|
2
4
|
|
3
5
|
module ActiveSupport
|
4
6
|
# ActiveSupport::Subscriber is an object set to consume
|
5
7
|
# ActiveSupport::Notifications. The subscriber dispatches notifications to
|
6
8
|
# a registered object based on its given namespace.
|
7
9
|
#
|
8
|
-
# An example would be Active Record subscriber responsible for collecting
|
10
|
+
# An example would be an Active Record subscriber responsible for collecting
|
9
11
|
# statistics about queries:
|
10
12
|
#
|
11
13
|
# module ActiveRecord
|
12
14
|
# class StatsSubscriber < ActiveSupport::Subscriber
|
15
|
+
# attach_to :active_record
|
16
|
+
#
|
13
17
|
# def sql(event)
|
14
18
|
# Statsd.timing("sql.#{event.payload[:name]}", event.duration)
|
15
19
|
# end
|
16
20
|
# end
|
17
21
|
# end
|
18
22
|
#
|
19
|
-
# And it's finally registered as:
|
20
|
-
#
|
21
|
-
# ActiveRecord::StatsSubscriber.attach_to :active_record
|
22
|
-
#
|
23
|
-
# Since we need to know all instance methods before attaching the log
|
24
|
-
# subscriber, the line above should be called after your subscriber definition.
|
25
|
-
#
|
26
23
|
# After configured, whenever a "sql.active_record" notification is published,
|
27
24
|
# it will properly dispatch the event (ActiveSupport::Notifications::Event) to
|
28
25
|
# the +sql+ method.
|
26
|
+
#
|
27
|
+
# We can detach a subscriber as well:
|
28
|
+
#
|
29
|
+
# ActiveRecord::StatsSubscriber.detach_from(:active_record)
|
29
30
|
class Subscriber
|
30
31
|
class << self
|
31
|
-
|
32
32
|
# Attach the subscriber to a namespace.
|
33
|
-
def attach_to(namespace, subscriber=new, notifier=ActiveSupport::Notifications)
|
33
|
+
def attach_to(namespace, subscriber = new, notifier = ActiveSupport::Notifications, inherit_all: false)
|
34
|
+
@namespace = namespace
|
35
|
+
@subscriber = subscriber
|
36
|
+
@notifier = notifier
|
37
|
+
@inherit_all = inherit_all
|
38
|
+
|
34
39
|
subscribers << subscriber
|
35
40
|
|
36
|
-
|
37
|
-
|
41
|
+
# Add event subscribers for all existing methods on the class.
|
42
|
+
fetch_public_methods(subscriber, inherit_all).each do |event|
|
43
|
+
add_event_subscriber(event)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Detach the subscriber from a namespace.
|
48
|
+
def detach_from(namespace, notifier = ActiveSupport::Notifications)
|
49
|
+
@namespace = namespace
|
50
|
+
@subscriber = find_attached_subscriber
|
51
|
+
@notifier = notifier
|
52
|
+
|
53
|
+
return unless subscriber
|
38
54
|
|
39
|
-
|
55
|
+
subscribers.delete(subscriber)
|
56
|
+
|
57
|
+
# Remove event subscribers of all existing methods on the class.
|
58
|
+
fetch_public_methods(subscriber, true).each do |event|
|
59
|
+
remove_event_subscriber(event)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Reset notifier so that event subscribers will not add for new methods added to the class.
|
63
|
+
@notifier = nil
|
64
|
+
end
|
65
|
+
|
66
|
+
# Adds event subscribers for all new methods added to the class.
|
67
|
+
def method_added(event)
|
68
|
+
# Only public methods are added as subscribers, and only if a notifier
|
69
|
+
# has been set up. This means that subscribers will only be set up for
|
70
|
+
# classes that call #attach_to.
|
71
|
+
if public_method_defined?(event) && notifier
|
72
|
+
add_event_subscriber(event)
|
40
73
|
end
|
41
74
|
end
|
42
75
|
|
43
76
|
def subscribers
|
44
77
|
@@subscribers ||= []
|
45
78
|
end
|
79
|
+
|
80
|
+
private
|
81
|
+
attr_reader :subscriber, :notifier, :namespace
|
82
|
+
|
83
|
+
def add_event_subscriber(event) # :doc:
|
84
|
+
return if invalid_event?(event)
|
85
|
+
|
86
|
+
pattern = prepare_pattern(event)
|
87
|
+
|
88
|
+
# Don't add multiple subscribers (e.g. if methods are redefined).
|
89
|
+
return if pattern_subscribed?(pattern)
|
90
|
+
|
91
|
+
subscriber.patterns[pattern] = notifier.subscribe(pattern, subscriber)
|
92
|
+
end
|
93
|
+
|
94
|
+
def remove_event_subscriber(event) # :doc:
|
95
|
+
return if invalid_event?(event)
|
96
|
+
|
97
|
+
pattern = prepare_pattern(event)
|
98
|
+
|
99
|
+
return unless pattern_subscribed?(pattern)
|
100
|
+
|
101
|
+
notifier.unsubscribe(subscriber.patterns[pattern])
|
102
|
+
subscriber.patterns.delete(pattern)
|
103
|
+
end
|
104
|
+
|
105
|
+
def find_attached_subscriber
|
106
|
+
subscribers.find { |attached_subscriber| attached_subscriber.instance_of?(self) }
|
107
|
+
end
|
108
|
+
|
109
|
+
def invalid_event?(event)
|
110
|
+
%i{ start finish }.include?(event.to_sym)
|
111
|
+
end
|
112
|
+
|
113
|
+
def prepare_pattern(event)
|
114
|
+
"#{event}.#{namespace}"
|
115
|
+
end
|
116
|
+
|
117
|
+
def pattern_subscribed?(pattern)
|
118
|
+
subscriber.patterns.key?(pattern)
|
119
|
+
end
|
120
|
+
|
121
|
+
def fetch_public_methods(subscriber, inherit_all)
|
122
|
+
subscriber.public_methods(inherit_all) - Subscriber.public_instance_methods(true)
|
123
|
+
end
|
46
124
|
end
|
47
125
|
|
126
|
+
attr_reader :patterns # :nodoc:
|
127
|
+
|
48
128
|
def initialize
|
49
129
|
@queue_key = [self.class.name, object_id].join "-"
|
130
|
+
@patterns = {}
|
50
131
|
super
|
51
132
|
end
|
52
133
|
|
53
134
|
def start(name, id, payload)
|
54
|
-
|
135
|
+
event = ActiveSupport::Notifications::Event.new(name, nil, nil, id, payload)
|
136
|
+
event.start!
|
55
137
|
parent = event_stack.last
|
56
|
-
parent <<
|
138
|
+
parent << event if parent
|
57
139
|
|
58
|
-
event_stack.push
|
140
|
+
event_stack.push event
|
59
141
|
end
|
60
142
|
|
61
143
|
def finish(name, id, payload)
|
62
|
-
|
63
|
-
event
|
64
|
-
event.end = finished
|
144
|
+
event = event_stack.pop
|
145
|
+
event.finish!
|
65
146
|
event.payload.merge!(payload)
|
66
147
|
|
67
|
-
method = name.split(
|
148
|
+
method = name.split(".").first
|
68
149
|
send(method, event)
|
69
150
|
end
|
70
151
|
|
71
|
-
|
152
|
+
def publish_event(event) # :nodoc:
|
153
|
+
method = event.name.split(".").first
|
154
|
+
send(method, event)
|
155
|
+
end
|
72
156
|
|
157
|
+
private
|
73
158
|
def event_stack
|
74
|
-
|
159
|
+
registry = ActiveSupport::IsolatedExecutionState[:active_support_subscriber_queue_registry] ||= {}
|
160
|
+
registry[@queue_key] ||= []
|
75
161
|
end
|
76
162
|
end
|
77
|
-
|
78
|
-
# This is a registry for all the event stacks kept for subscribers.
|
79
|
-
#
|
80
|
-
# See the documentation of <tt>ActiveSupport::PerThreadRegistry</tt>
|
81
|
-
# for further details.
|
82
|
-
class SubscriberQueueRegistry # :nodoc:
|
83
|
-
extend PerThreadRegistry
|
84
|
-
|
85
|
-
def initialize
|
86
|
-
@registry = {}
|
87
|
-
end
|
88
|
-
|
89
|
-
def get_queue(queue_key)
|
90
|
-
@registry[queue_key] ||= []
|
91
|
-
end
|
92
|
-
end
|
93
163
|
end
|