activesupport 5.1.1 → 6.1.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +360 -442
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -4
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/all.rb +2 -0
- data/lib/active_support/array_inquirer.rb +6 -2
- data/lib/active_support/backtrace_cleaner.rb +31 -3
- data/lib/active_support/benchmarkable.rb +3 -1
- data/lib/active_support/builder.rb +2 -0
- data/lib/active_support/cache/file_store.rb +37 -36
- data/lib/active_support/cache/mem_cache_store.rb +65 -53
- data/lib/active_support/cache/memory_store.rb +61 -33
- data/lib/active_support/cache/null_store.rb +10 -3
- data/lib/active_support/cache/redis_cache_store.rb +493 -0
- data/lib/active_support/cache/strategy/local_cache.rb +68 -22
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +2 -0
- data/lib/active_support/cache.rb +305 -127
- data/lib/active_support/callbacks.rb +106 -98
- data/lib/active_support/concern.rb +79 -6
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +35 -0
- data/lib/active_support/concurrency/share_lock.rb +2 -1
- data/lib/active_support/configurable.rb +12 -14
- data/lib/active_support/configuration_file.rb +46 -0
- data/lib/active_support/core_ext/array/access.rb +21 -7
- data/lib/active_support/core_ext/array/conversions.rb +7 -5
- 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 +2 -0
- data/lib/active_support/core_ext/array/inquiry.rb +2 -0
- data/lib/active_support/core_ext/array/wrap.rb +2 -0
- data/lib/active_support/core_ext/array.rb +3 -1
- data/lib/active_support/core_ext/benchmark.rb +4 -2
- data/lib/active_support/core_ext/big_decimal/conversions.rb +2 -0
- data/lib/active_support/core_ext/big_decimal.rb +2 -0
- data/lib/active_support/core_ext/class/attribute.rb +50 -47
- data/lib/active_support/core_ext/class/attribute_accessors.rb +2 -0
- data/lib/active_support/core_ext/class/subclasses.rb +18 -40
- data/lib/active_support/core_ext/class.rb +2 -0
- data/lib/active_support/core_ext/date/acts_like.rb +2 -0
- data/lib/active_support/core_ext/date/blank.rb +2 -0
- data/lib/active_support/core_ext/date/calculations.rb +8 -5
- data/lib/active_support/core_ext/date/conversions.rb +12 -10
- data/lib/active_support/core_ext/date/zones.rb +2 -0
- data/lib/active_support/core_ext/date.rb +2 -0
- data/lib/active_support/core_ext/date_and_time/calculations.rb +61 -37
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -1
- data/lib/active_support/core_ext/date_and_time/zones.rb +2 -1
- data/lib/active_support/core_ext/date_time/acts_like.rb +2 -0
- data/lib/active_support/core_ext/date_time/blank.rb +2 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +3 -1
- data/lib/active_support/core_ext/date_time/compatibility.rb +7 -5
- data/lib/active_support/core_ext/date_time/conversions.rb +2 -1
- data/lib/active_support/core_ext/date_time.rb +2 -0
- data/lib/active_support/core_ext/digest/uuid.rb +3 -1
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/enumerable.rb +174 -71
- data/lib/active_support/core_ext/file/atomic.rb +3 -1
- data/lib/active_support/core_ext/file.rb +2 -0
- data/lib/active_support/core_ext/hash/conversions.rb +7 -5
- data/lib/active_support/core_ext/hash/deep_merge.rb +8 -12
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +4 -2
- data/lib/active_support/core_ext/hash/indifferent_access.rb +2 -0
- data/lib/active_support/core_ext/hash/keys.rb +3 -30
- data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
- data/lib/active_support/core_ext/hash/slice.rb +8 -29
- data/lib/active_support/core_ext/hash.rb +3 -2
- data/lib/active_support/core_ext/integer/inflections.rb +2 -0
- data/lib/active_support/core_ext/integer/multiple.rb +3 -1
- data/lib/active_support/core_ext/integer/time.rb +7 -14
- data/lib/active_support/core_ext/integer.rb +2 -0
- data/lib/active_support/core_ext/kernel/concern.rb +2 -0
- data/lib/active_support/core_ext/kernel/reporting.rb +2 -0
- data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
- data/lib/active_support/core_ext/kernel.rb +2 -1
- data/lib/active_support/core_ext/load_error.rb +3 -8
- data/lib/active_support/core_ext/marshal.rb +4 -0
- data/lib/active_support/core_ext/module/aliasing.rb +2 -0
- data/lib/active_support/core_ext/module/anonymous.rb +2 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +4 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +44 -56
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +18 -18
- data/lib/active_support/core_ext/module/concerning.rb +15 -10
- data/lib/active_support/core_ext/module/delegation.rb +103 -58
- data/lib/active_support/core_ext/module/deprecation.rb +2 -0
- data/lib/active_support/core_ext/module/introspection.rb +18 -15
- data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
- data/lib/active_support/core_ext/module/remove_method.rb +5 -23
- data/lib/active_support/core_ext/module.rb +3 -1
- data/lib/active_support/core_ext/name_error.rb +36 -2
- data/lib/active_support/core_ext/numeric/bytes.rb +2 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +131 -129
- data/lib/active_support/core_ext/numeric/time.rb +7 -15
- data/lib/active_support/core_ext/numeric.rb +2 -1
- data/lib/active_support/core_ext/object/acts_like.rb +12 -1
- data/lib/active_support/core_ext/object/blank.rb +13 -3
- data/lib/active_support/core_ext/object/conversions.rb +2 -0
- data/lib/active_support/core_ext/object/deep_dup.rb +3 -1
- data/lib/active_support/core_ext/object/duplicable.rb +6 -101
- data/lib/active_support/core_ext/object/inclusion.rb +2 -0
- data/lib/active_support/core_ext/object/instance_variables.rb +2 -0
- data/lib/active_support/core_ext/object/json.rb +22 -2
- data/lib/active_support/core_ext/object/to_param.rb +2 -0
- data/lib/active_support/core_ext/object/to_query.rb +7 -2
- data/lib/active_support/core_ext/object/try.rb +19 -7
- data/lib/active_support/core_ext/object/with_options.rb +4 -2
- data/lib/active_support/core_ext/object.rb +2 -0
- data/lib/active_support/core_ext/range/compare_range.rb +82 -0
- data/lib/active_support/core_ext/range/conversions.rb +35 -25
- data/lib/active_support/core_ext/range/each.rb +5 -2
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +28 -0
- data/lib/active_support/core_ext/range/overlaps.rb +2 -0
- data/lib/active_support/core_ext/range.rb +4 -1
- data/lib/active_support/core_ext/regexp.rb +10 -5
- data/lib/active_support/core_ext/securerandom.rb +25 -3
- data/lib/active_support/core_ext/string/access.rb +7 -16
- data/lib/active_support/core_ext/string/behavior.rb +2 -0
- data/lib/active_support/core_ext/string/conversions.rb +3 -0
- data/lib/active_support/core_ext/string/exclude.rb +2 -0
- data/lib/active_support/core_ext/string/filters.rb +44 -1
- data/lib/active_support/core_ext/string/indent.rb +2 -0
- data/lib/active_support/core_ext/string/inflections.rb +69 -16
- data/lib/active_support/core_ext/string/inquiry.rb +3 -0
- data/lib/active_support/core_ext/string/multibyte.rb +9 -4
- data/lib/active_support/core_ext/string/output_safety.rb +76 -20
- data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
- data/lib/active_support/core_ext/string/strip.rb +5 -1
- data/lib/active_support/core_ext/string/zones.rb +2 -0
- data/lib/active_support/core_ext/string.rb +2 -0
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/time/acts_like.rb +2 -0
- data/lib/active_support/core_ext/time/calculations.rb +73 -18
- data/lib/active_support/core_ext/time/compatibility.rb +4 -2
- data/lib/active_support/core_ext/time/conversions.rb +4 -0
- data/lib/active_support/core_ext/time/zones.rb +6 -4
- data/lib/active_support/core_ext/time.rb +2 -0
- data/lib/active_support/core_ext/uri.rb +11 -6
- data/lib/active_support/core_ext.rb +3 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +208 -0
- data/lib/active_support/dependencies/autoload.rb +2 -0
- data/lib/active_support/dependencies/interlock.rb +2 -0
- data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
- data/lib/active_support/dependencies.rb +135 -60
- data/lib/active_support/deprecation/behaviors.rb +43 -11
- data/lib/active_support/deprecation/constant_accessor.rb +4 -2
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +2 -1
- data/lib/active_support/deprecation/method_wrappers.rb +30 -15
- data/lib/active_support/deprecation/proxy_wrappers.rb +32 -6
- data/lib/active_support/deprecation/reporting.rb +54 -9
- data/lib/active_support/deprecation.rb +9 -2
- data/lib/active_support/descendants_tracker.rb +61 -9
- data/lib/active_support/digest.rb +20 -0
- data/lib/active_support/duration/iso8601_parser.rb +6 -6
- data/lib/active_support/duration/iso8601_serializer.rb +20 -14
- data/lib/active_support/duration.rb +179 -41
- data/lib/active_support/encrypted_configuration.rb +45 -0
- data/lib/active_support/encrypted_file.rb +117 -0
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/evented_file_update_checker.rb +84 -117
- data/lib/active_support/execution_wrapper.rb +3 -0
- data/lib/active_support/executor.rb +2 -0
- data/lib/active_support/file_update_checker.rb +2 -1
- data/lib/active_support/fork_tracker.rb +62 -0
- data/lib/active_support/gem_version.rb +3 -1
- data/lib/active_support/gzip.rb +2 -0
- data/lib/active_support/hash_with_indifferent_access.rb +134 -37
- data/lib/active_support/i18n.rb +4 -1
- data/lib/active_support/i18n_railtie.rb +20 -11
- data/lib/active_support/inflections.rb +2 -0
- data/lib/active_support/inflector/inflections.rb +19 -8
- data/lib/active_support/inflector/methods.rb +87 -77
- data/lib/active_support/inflector/transliterate.rb +56 -18
- data/lib/active_support/inflector.rb +2 -0
- data/lib/active_support/json/decoding.rb +27 -26
- data/lib/active_support/json/encoding.rb +13 -3
- data/lib/active_support/json.rb +2 -0
- data/lib/active_support/key_generator.rb +3 -33
- data/lib/active_support/lazy_load_hooks.rb +33 -10
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/locale/en.yml +7 -3
- data/lib/active_support/log_subscriber/test_helper.rb +2 -0
- data/lib/active_support/log_subscriber.rb +46 -13
- data/lib/active_support/logger.rb +4 -17
- data/lib/active_support/logger_silence.rb +13 -20
- data/lib/active_support/logger_thread_safe_level.rb +54 -7
- data/lib/active_support/message_encryptor.rb +101 -33
- data/lib/active_support/message_verifier.rb +85 -14
- 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 +12 -68
- data/lib/active_support/multibyte/unicode.rb +17 -327
- data/lib/active_support/multibyte.rb +2 -0
- data/lib/active_support/notifications/fanout.rb +118 -16
- data/lib/active_support/notifications/instrumenter.rb +73 -9
- data/lib/active_support/notifications.rb +74 -8
- data/lib/active_support/number_helper/number_converter.rb +7 -6
- data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -9
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +5 -2
- data/lib/active_support/number_helper/number_to_human_converter.rb +8 -7
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +6 -3
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +5 -2
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +16 -53
- data/lib/active_support/number_helper/rounding_helper.rb +50 -0
- data/lib/active_support/number_helper.rb +41 -12
- data/lib/active_support/option_merger.rb +24 -3
- data/lib/active_support/ordered_hash.rb +3 -1
- data/lib/active_support/ordered_options.rb +17 -5
- data/lib/active_support/parameter_filter.rb +133 -0
- data/lib/active_support/per_thread_registry.rb +3 -1
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/rails.rb +3 -10
- data/lib/active_support/railtie.rb +60 -9
- data/lib/active_support/reloader.rb +11 -10
- data/lib/active_support/rescuable.rb +7 -6
- data/lib/active_support/secure_compare_rotator.rb +51 -0
- data/lib/active_support/security_utils.rb +26 -15
- data/lib/active_support/string_inquirer.rb +6 -3
- data/lib/active_support/subscriber.rb +74 -24
- data/lib/active_support/tagged_logging.rb +44 -8
- data/lib/active_support/test_case.rb +94 -2
- data/lib/active_support/testing/assertions.rb +58 -20
- data/lib/active_support/testing/autorun.rb +2 -4
- data/lib/active_support/testing/constant_lookup.rb +2 -0
- data/lib/active_support/testing/declarative.rb +2 -0
- data/lib/active_support/testing/deprecation.rb +2 -1
- data/lib/active_support/testing/file_fixtures.rb +4 -0
- data/lib/active_support/testing/isolation.rb +8 -4
- data/lib/active_support/testing/method_call_assertions.rb +30 -1
- data/lib/active_support/testing/parallelization/server.rb +78 -0
- data/lib/active_support/testing/parallelization/worker.rb +100 -0
- data/lib/active_support/testing/parallelization.rb +51 -0
- data/lib/active_support/testing/setup_and_teardown.rb +12 -7
- data/lib/active_support/testing/stream.rb +3 -2
- data/lib/active_support/testing/tagged_logging.rb +2 -0
- data/lib/active_support/testing/time_helpers.rb +78 -13
- data/lib/active_support/time.rb +2 -0
- data/lib/active_support/time_with_zone.rb +113 -41
- data/lib/active_support/values/time_zone.rb +55 -25
- data/lib/active_support/version.rb +2 -0
- data/lib/active_support/xml_mini/jdom.rb +5 -4
- data/lib/active_support/xml_mini/libxml.rb +4 -2
- data/lib/active_support/xml_mini/libxmlsax.rb +6 -4
- data/lib/active_support/xml_mini/nokogiri.rb +4 -2
- data/lib/active_support/xml_mini/nokogirisax.rb +5 -3
- data/lib/active_support/xml_mini/rexml.rb +12 -3
- data/lib/active_support/xml_mini.rb +5 -11
- data/lib/active_support.rb +18 -13
- metadata +81 -35
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
- data/lib/active_support/core_ext/hash/compact.rb +0 -27
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -30
- data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
- data/lib/active_support/core_ext/module/reachable.rb +0 -8
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -26
- data/lib/active_support/core_ext/range/include_range.rb +0 -23
- data/lib/active_support/values/unicode_tables.dat +0 -0
data/MIT-LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -5,6 +5,7 @@ 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
6
|
outside of Rails.
|
7
7
|
|
8
|
+
You can read more about the extensions in the {Active Support Core Extensions}[https://edgeguides.rubyonrails.org/active_support_core_extensions.html] guide.
|
8
9
|
|
9
10
|
== Download and installation
|
10
11
|
|
@@ -21,19 +22,19 @@ Source code can be downloaded as part of the Rails project on GitHub:
|
|
21
22
|
|
22
23
|
Active Support is released under the MIT license:
|
23
24
|
|
24
|
-
*
|
25
|
+
* https://opensource.org/licenses/MIT
|
25
26
|
|
26
27
|
|
27
28
|
== Support
|
28
29
|
|
29
30
|
API documentation is at:
|
30
31
|
|
31
|
-
*
|
32
|
+
* https://api.rubyonrails.org
|
32
33
|
|
33
|
-
Bug reports
|
34
|
+
Bug reports for the Ruby on Rails project can be filed here:
|
34
35
|
|
35
36
|
* https://github.com/rails/rails/issues
|
36
37
|
|
37
38
|
Feature requests should be discussed on the rails-core mailing list here:
|
38
39
|
|
39
|
-
* https://
|
40
|
+
* https://discuss.rubyonrails.org/c/rubyonrails-core
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
# Actionable errors let's you define actions to resolve an error.
|
5
|
+
#
|
6
|
+
# To make an error actionable, include the <tt>ActiveSupport::ActionableError</tt>
|
7
|
+
# module and invoke the +action+ class macro to define the action. An action
|
8
|
+
# needs a name and a block to execute.
|
9
|
+
module ActionableError
|
10
|
+
extend Concern
|
11
|
+
|
12
|
+
class NonActionable < StandardError; end
|
13
|
+
|
14
|
+
included do
|
15
|
+
class_attribute :_actions, default: {}
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.actions(error) # :nodoc:
|
19
|
+
case error
|
20
|
+
when ActionableError, -> it { Class === it && it < ActionableError }
|
21
|
+
error._actions
|
22
|
+
else
|
23
|
+
{}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.dispatch(error, name) # :nodoc:
|
28
|
+
actions(error).fetch(name).call
|
29
|
+
rescue KeyError
|
30
|
+
raise NonActionable, "Cannot find action \"#{name}\""
|
31
|
+
end
|
32
|
+
|
33
|
+
module ClassMethods
|
34
|
+
# Defines an action that can resolve the error.
|
35
|
+
#
|
36
|
+
# class PendingMigrationError < MigrationError
|
37
|
+
# include ActiveSupport::ActionableError
|
38
|
+
#
|
39
|
+
# action "Run pending migrations" do
|
40
|
+
# ActiveRecord::Tasks::DatabaseTasks.migrate
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
def action(name, &block)
|
44
|
+
_actions[name] = block
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/active_support/all.rb
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/symbol/starts_ends_with"
|
4
|
+
|
1
5
|
module ActiveSupport
|
2
6
|
# Wrapping an array in an +ArrayInquirer+ gives a friendlier way to check
|
3
7
|
# its string-like contents:
|
@@ -32,11 +36,11 @@ module ActiveSupport
|
|
32
36
|
|
33
37
|
private
|
34
38
|
def respond_to_missing?(name, include_private = false)
|
35
|
-
(
|
39
|
+
name.end_with?("?") || super
|
36
40
|
end
|
37
41
|
|
38
42
|
def method_missing(name, *args)
|
39
|
-
if name
|
43
|
+
if name.end_with?("?")
|
40
44
|
any?(name[0..-2])
|
41
45
|
else
|
42
46
|
super
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveSupport
|
2
4
|
# Backtraces often include many lines that are not relevant for the context
|
3
5
|
# under review. This makes it hard to find the signal amongst the backtrace
|
@@ -14,7 +16,7 @@ module ActiveSupport
|
|
14
16
|
#
|
15
17
|
# bc = ActiveSupport::BacktraceCleaner.new
|
16
18
|
# bc.add_filter { |line| line.gsub(Rails.root.to_s, '') } # strip the Rails.root prefix
|
17
|
-
# bc.add_silencer { |line|
|
19
|
+
# bc.add_silencer { |line| /puma|rubygems/.match?(line) } # skip any lines from puma or rubygems
|
18
20
|
# bc.clean(exception.backtrace) # perform the cleanup
|
19
21
|
#
|
20
22
|
# To reconfigure an existing BacktraceCleaner (like the default one in Rails)
|
@@ -29,6 +31,9 @@ module ActiveSupport
|
|
29
31
|
class BacktraceCleaner
|
30
32
|
def initialize
|
31
33
|
@filters, @silencers = [], []
|
34
|
+
add_gem_filter
|
35
|
+
add_gem_silencer
|
36
|
+
add_stdlib_silencer
|
32
37
|
end
|
33
38
|
|
34
39
|
# Returns the backtrace after all filters and silencers have been run
|
@@ -60,7 +65,7 @@ module ActiveSupport
|
|
60
65
|
# for a given line, it will be excluded from the clean backtrace.
|
61
66
|
#
|
62
67
|
# # Will reject all lines that include the word "puma", like "/gems/puma/server.rb" or "/app/my_puma_server/rb"
|
63
|
-
# backtrace_cleaner.add_silencer { |line|
|
68
|
+
# backtrace_cleaner.add_silencer { |line| /puma/.match?(line) }
|
64
69
|
def add_silencer(&block)
|
65
70
|
@silencers << block
|
66
71
|
end
|
@@ -80,6 +85,25 @@ module ActiveSupport
|
|
80
85
|
end
|
81
86
|
|
82
87
|
private
|
88
|
+
FORMATTED_GEMS_PATTERN = /\A[^\/]+ \([\w.]+\) /
|
89
|
+
|
90
|
+
def add_gem_filter
|
91
|
+
gems_paths = (Gem.path | [Gem.default_dir]).map { |p| Regexp.escape(p) }
|
92
|
+
return if gems_paths.empty?
|
93
|
+
|
94
|
+
gems_regexp = %r{\A(#{gems_paths.join('|')})/(bundler/)?gems/([^/]+)-([\w.]+)/(.*)}
|
95
|
+
gems_result = '\3 (\4) \5'
|
96
|
+
add_filter { |line| line.sub(gems_regexp, gems_result) }
|
97
|
+
end
|
98
|
+
|
99
|
+
def add_gem_silencer
|
100
|
+
add_silencer { |line| FORMATTED_GEMS_PATTERN.match?(line) }
|
101
|
+
end
|
102
|
+
|
103
|
+
def add_stdlib_silencer
|
104
|
+
add_silencer { |line| line.start_with?(RbConfig::CONFIG["rubylibdir"]) }
|
105
|
+
end
|
106
|
+
|
83
107
|
def filter_backtrace(backtrace)
|
84
108
|
@filters.each do |f|
|
85
109
|
backtrace = backtrace.map { |line| f.call(line) }
|
@@ -97,7 +121,11 @@ module ActiveSupport
|
|
97
121
|
end
|
98
122
|
|
99
123
|
def noise(backtrace)
|
100
|
-
backtrace
|
124
|
+
backtrace.select do |line|
|
125
|
+
@silencers.any? do |s|
|
126
|
+
s.call(line)
|
127
|
+
end
|
128
|
+
end
|
101
129
|
end
|
102
130
|
end
|
103
131
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/core_ext/benchmark"
|
2
4
|
require "active_support/core_ext/hash/keys"
|
3
5
|
|
@@ -39,7 +41,7 @@ module ActiveSupport
|
|
39
41
|
|
40
42
|
result = nil
|
41
43
|
ms = Benchmark.ms { result = options[:silence] ? logger.silence { yield } : yield }
|
42
|
-
logger.
|
44
|
+
logger.public_send(options[:level], "%s (%.1fms)" % [ message, ms ])
|
43
45
|
result
|
44
46
|
else
|
45
47
|
yield
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/core_ext/marshal"
|
2
4
|
require "active_support/core_ext/file/atomic"
|
3
5
|
require "active_support/core_ext/string/conversions"
|
@@ -14,9 +16,8 @@ module ActiveSupport
|
|
14
16
|
attr_reader :cache_path
|
15
17
|
|
16
18
|
DIR_FORMATTER = "%03X"
|
17
|
-
FILENAME_MAX_SIZE =
|
19
|
+
FILENAME_MAX_SIZE = 226 # max filename size on file system is 255, minus room for timestamp, pid, and random characters appended by Tempfile (used by atomic write)
|
18
20
|
FILEPATH_MAX_SIZE = 900 # max is 1024, plus some room
|
19
|
-
EXCLUDED_DIRS = [".", ".."].freeze
|
20
21
|
GITKEEP_FILES = [".gitkeep", ".keep"].freeze
|
21
22
|
|
22
23
|
def initialize(cache_path, options = nil)
|
@@ -24,22 +25,26 @@ module ActiveSupport
|
|
24
25
|
@cache_path = cache_path.to_s
|
25
26
|
end
|
26
27
|
|
28
|
+
# Advertise cache versioning support.
|
29
|
+
def self.supports_cache_versioning?
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
27
33
|
# Deletes all items from the cache. In this case it deletes all the entries in the specified
|
28
34
|
# file store directory except for .keep or .gitkeep. Be careful which directory is specified in your
|
29
35
|
# config file when using +FileStore+ because everything in that directory will be deleted.
|
30
|
-
def clear
|
31
|
-
root_dirs =
|
36
|
+
def clear(options = nil)
|
37
|
+
root_dirs = (Dir.children(cache_path) - GITKEEP_FILES)
|
32
38
|
FileUtils.rm_r(root_dirs.collect { |f| File.join(cache_path, f) })
|
33
|
-
rescue Errno::ENOENT
|
39
|
+
rescue Errno::ENOENT, Errno::ENOTEMPTY
|
34
40
|
end
|
35
41
|
|
36
42
|
# Preemptively iterates through all stored keys and removes the ones which have expired.
|
37
43
|
def cleanup(options = nil)
|
38
44
|
options = merged_options(options)
|
39
45
|
search_dir(cache_path) do |fname|
|
40
|
-
|
41
|
-
|
42
|
-
delete_entry(key, options) if entry && entry.expired?
|
46
|
+
entry = read_entry(fname, **options)
|
47
|
+
delete_entry(fname, **options) if entry && entry.expired?
|
43
48
|
end
|
44
49
|
end
|
45
50
|
|
@@ -61,30 +66,30 @@ module ActiveSupport
|
|
61
66
|
matcher = key_matcher(matcher, options)
|
62
67
|
search_dir(cache_path) do |path|
|
63
68
|
key = file_path_key(path)
|
64
|
-
delete_entry(path, options) if key.match(matcher)
|
69
|
+
delete_entry(path, **options) if key.match(matcher)
|
65
70
|
end
|
66
71
|
end
|
67
72
|
end
|
68
73
|
|
69
74
|
private
|
70
|
-
|
71
|
-
def read_entry(key, options)
|
75
|
+
def read_entry(key, **options)
|
72
76
|
if File.exist?(key)
|
73
|
-
File.open(key) { |f|
|
77
|
+
entry = File.open(key) { |f| deserialize_entry(f.read) }
|
78
|
+
entry if entry.is_a?(Cache::Entry)
|
74
79
|
end
|
75
80
|
rescue => e
|
76
81
|
logger.error("FileStoreError (#{e}): #{e.message}") if logger
|
77
82
|
nil
|
78
83
|
end
|
79
84
|
|
80
|
-
def write_entry(key, entry, options)
|
85
|
+
def write_entry(key, entry, **options)
|
81
86
|
return false if options[:unless_exist] && File.exist?(key)
|
82
87
|
ensure_cache_path(File.dirname(key))
|
83
|
-
File.atomic_write(key, cache_path) { |f|
|
88
|
+
File.atomic_write(key, cache_path) { |f| f.write(serialize_entry(entry)) }
|
84
89
|
true
|
85
90
|
end
|
86
91
|
|
87
|
-
def delete_entry(key, options)
|
92
|
+
def delete_entry(key, **options)
|
88
93
|
if File.exist?(key)
|
89
94
|
begin
|
90
95
|
File.delete(key)
|
@@ -102,12 +107,10 @@ module ActiveSupport
|
|
102
107
|
def lock_file(file_name, &block)
|
103
108
|
if File.exist?(file_name)
|
104
109
|
File.open(file_name, "r+") do |f|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
f.flock File::LOCK_UN
|
110
|
-
end
|
110
|
+
f.flock File::LOCK_EX
|
111
|
+
yield
|
112
|
+
ensure
|
113
|
+
f.flock File::LOCK_UN
|
111
114
|
end
|
112
115
|
else
|
113
116
|
yield
|
@@ -120,21 +123,25 @@ module ActiveSupport
|
|
120
123
|
fname = URI.encode_www_form_component(key)
|
121
124
|
|
122
125
|
if fname.size > FILEPATH_MAX_SIZE
|
123
|
-
fname = Digest
|
126
|
+
fname = ActiveSupport::Digest.hexdigest(key)
|
124
127
|
end
|
125
128
|
|
126
129
|
hash = Zlib.adler32(fname)
|
127
130
|
hash, dir_1 = hash.divmod(0x1000)
|
128
131
|
dir_2 = hash.modulo(0x1000)
|
129
|
-
fname_paths = []
|
130
132
|
|
131
133
|
# Make sure file name doesn't exceed file system limits.
|
132
|
-
|
133
|
-
fname_paths
|
134
|
-
|
135
|
-
|
134
|
+
if fname.length < FILENAME_MAX_SIZE
|
135
|
+
fname_paths = fname
|
136
|
+
else
|
137
|
+
fname_paths = []
|
138
|
+
begin
|
139
|
+
fname_paths << fname[0, FILENAME_MAX_SIZE]
|
140
|
+
fname = fname[FILENAME_MAX_SIZE..-1]
|
141
|
+
end until fname.blank?
|
142
|
+
end
|
136
143
|
|
137
|
-
File.join(cache_path, DIR_FORMATTER % dir_1, DIR_FORMATTER % dir_2,
|
144
|
+
File.join(cache_path, DIR_FORMATTER % dir_1, DIR_FORMATTER % dir_2, fname_paths)
|
138
145
|
end
|
139
146
|
|
140
147
|
# Translate a file path into a key.
|
@@ -146,7 +153,7 @@ module ActiveSupport
|
|
146
153
|
# Delete empty directories in the cache.
|
147
154
|
def delete_empty_directories(dir)
|
148
155
|
return if File.realpath(dir) == File.realpath(cache_path)
|
149
|
-
if
|
156
|
+
if Dir.children(dir).empty?
|
150
157
|
Dir.delete(dir) rescue nil
|
151
158
|
delete_empty_directories(File.dirname(dir))
|
152
159
|
end
|
@@ -159,8 +166,7 @@ module ActiveSupport
|
|
159
166
|
|
160
167
|
def search_dir(dir, &callback)
|
161
168
|
return if !File.exist?(dir)
|
162
|
-
Dir.
|
163
|
-
next if EXCLUDED_DIRS.include?(d)
|
169
|
+
Dir.each_child(dir) do |d|
|
164
170
|
name = File.join(dir, d)
|
165
171
|
if File.directory?(name)
|
166
172
|
search_dir(name, &callback)
|
@@ -185,11 +191,6 @@ module ActiveSupport
|
|
185
191
|
end
|
186
192
|
end
|
187
193
|
end
|
188
|
-
|
189
|
-
# Exclude entries from source directory
|
190
|
-
def exclude_from(source, excludes)
|
191
|
-
Dir.entries(source).reject { |f| excludes.include?(f) }
|
192
|
-
end
|
193
194
|
end
|
194
195
|
end
|
195
196
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
begin
|
2
4
|
require "dalli"
|
3
5
|
rescue LoadError => e
|
@@ -5,14 +7,14 @@ rescue LoadError => e
|
|
5
7
|
raise e
|
6
8
|
end
|
7
9
|
|
8
|
-
require "
|
10
|
+
require "active_support/core_ext/enumerable"
|
9
11
|
require "active_support/core_ext/marshal"
|
10
12
|
require "active_support/core_ext/array/extract_options"
|
11
13
|
|
12
14
|
module ActiveSupport
|
13
15
|
module Cache
|
14
16
|
# A cache store implementation which stores data in Memcached:
|
15
|
-
#
|
17
|
+
# https://memcached.org
|
16
18
|
#
|
17
19
|
# This is currently the most popular cache store for production websites.
|
18
20
|
#
|
@@ -24,45 +26,53 @@ module ActiveSupport
|
|
24
26
|
# MemCacheStore implements the Strategy::LocalCache strategy which implements
|
25
27
|
# an in-memory cache inside of a block.
|
26
28
|
class MemCacheStore < Store
|
29
|
+
DEFAULT_CODER = NullCoder # Dalli automatically Marshal values
|
30
|
+
|
27
31
|
# Provide support for raw values in the local cache strategy.
|
28
32
|
module LocalCacheWithRaw # :nodoc:
|
29
33
|
private
|
30
|
-
def
|
31
|
-
entry = super
|
32
|
-
if options[:raw] && local_cache && entry
|
33
|
-
entry = deserialize_entry(entry.value)
|
34
|
-
end
|
35
|
-
entry
|
36
|
-
end
|
37
|
-
|
38
|
-
def write_entry(key, entry, options)
|
34
|
+
def write_entry(key, entry, **options)
|
39
35
|
if options[:raw] && local_cache
|
40
36
|
raw_entry = Entry.new(entry.value.to_s)
|
41
37
|
raw_entry.expires_at = entry.expires_at
|
42
|
-
super(key, raw_entry, options)
|
38
|
+
super(key, raw_entry, **options)
|
43
39
|
else
|
44
40
|
super
|
45
41
|
end
|
46
42
|
end
|
47
43
|
end
|
48
44
|
|
45
|
+
# Advertise cache versioning support.
|
46
|
+
def self.supports_cache_versioning?
|
47
|
+
true
|
48
|
+
end
|
49
|
+
|
49
50
|
prepend Strategy::LocalCache
|
50
51
|
prepend LocalCacheWithRaw
|
51
52
|
|
52
53
|
ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
|
53
54
|
|
54
55
|
# Creates a new Dalli::Client instance with specified addresses and options.
|
55
|
-
#
|
56
|
+
# If no addresses are provided, we give nil to Dalli::Client, so it uses its fallbacks:
|
57
|
+
# - ENV["MEMCACHE_SERVERS"] (if defined)
|
58
|
+
# - "127.0.0.1:11211" (otherwise)
|
56
59
|
#
|
57
60
|
# ActiveSupport::Cache::MemCacheStore.build_mem_cache
|
58
|
-
# # => #<Dalli::Client:0x007f98a47d2028 @servers=["
|
61
|
+
# # => #<Dalli::Client:0x007f98a47d2028 @servers=["127.0.0.1:11211"], @options={}, @ring=nil>
|
59
62
|
# ActiveSupport::Cache::MemCacheStore.build_mem_cache('localhost:10290')
|
60
63
|
# # => #<Dalli::Client:0x007f98a47b3a60 @servers=["localhost:10290"], @options={}, @ring=nil>
|
61
64
|
def self.build_mem_cache(*addresses) # :nodoc:
|
62
65
|
addresses = addresses.flatten
|
63
66
|
options = addresses.extract_options!
|
64
|
-
addresses =
|
65
|
-
|
67
|
+
addresses = nil if addresses.empty?
|
68
|
+
pool_options = retrieve_pool_options(options)
|
69
|
+
|
70
|
+
if pool_options.empty?
|
71
|
+
Dalli::Client.new(addresses, options)
|
72
|
+
else
|
73
|
+
ensure_connection_pool_added!
|
74
|
+
ConnectionPool.new(pool_options) { Dalli::Client.new(addresses, options.merge(threadsafe: false)) }
|
75
|
+
end
|
66
76
|
end
|
67
77
|
|
68
78
|
# Creates a new MemCacheStore object, with the given memcached server
|
@@ -71,8 +81,8 @@ module ActiveSupport
|
|
71
81
|
#
|
72
82
|
# ActiveSupport::Cache::MemCacheStore.new("localhost", "server-downstairs.localnetwork:8229")
|
73
83
|
#
|
74
|
-
# If no addresses are
|
75
|
-
#
|
84
|
+
# If no addresses are provided, but ENV['MEMCACHE_SERVERS'] is defined, it will be used instead. Otherwise,
|
85
|
+
# MemCacheStore will connect to localhost:11211 (the default memcached port).
|
76
86
|
def initialize(*addresses)
|
77
87
|
addresses = addresses.flatten
|
78
88
|
options = addresses.extract_options!
|
@@ -90,22 +100,6 @@ module ActiveSupport
|
|
90
100
|
end
|
91
101
|
end
|
92
102
|
|
93
|
-
# Reads multiple values from the cache using a single call to the
|
94
|
-
# servers for all keys. Options can be passed in the last argument.
|
95
|
-
def read_multi(*names)
|
96
|
-
options = names.extract_options!
|
97
|
-
options = merged_options(options)
|
98
|
-
|
99
|
-
keys_to_names = Hash[names.map { |name| [normalize_key(name, options), name] }]
|
100
|
-
raw_values = @data.get_multi(keys_to_names.keys)
|
101
|
-
values = {}
|
102
|
-
raw_values.each do |key, value|
|
103
|
-
entry = deserialize_entry(value)
|
104
|
-
values[keys_to_names[key]] = entry.value unless entry.expired?
|
105
|
-
end
|
106
|
-
values
|
107
|
-
end
|
108
|
-
|
109
103
|
# Increment a cached value. This method uses the memcached incr atomic
|
110
104
|
# operator and can only be used on values written with the :raw option.
|
111
105
|
# Calling it on a value not stored with :raw will initialize that value
|
@@ -114,7 +108,7 @@ module ActiveSupport
|
|
114
108
|
options = merged_options(options)
|
115
109
|
instrument(:increment, name, amount: amount) do
|
116
110
|
rescue_error_with nil do
|
117
|
-
@data.incr(normalize_key(name, options), amount)
|
111
|
+
@data.with { |c| c.incr(normalize_key(name, options), amount, options[:expires_in]) }
|
118
112
|
end
|
119
113
|
end
|
120
114
|
end
|
@@ -127,7 +121,7 @@ module ActiveSupport
|
|
127
121
|
options = merged_options(options)
|
128
122
|
instrument(:decrement, name, amount: amount) do
|
129
123
|
rescue_error_with nil do
|
130
|
-
@data.decr(normalize_key(name, options), amount)
|
124
|
+
@data.with { |c| c.decr(normalize_key(name, options), amount, options[:expires_in]) }
|
131
125
|
end
|
132
126
|
end
|
133
127
|
end
|
@@ -135,37 +129,56 @@ module ActiveSupport
|
|
135
129
|
# Clear the entire cache on all memcached servers. This method should
|
136
130
|
# be used with care when shared cache is being used.
|
137
131
|
def clear(options = nil)
|
138
|
-
rescue_error_with(nil) { @data.flush_all }
|
132
|
+
rescue_error_with(nil) { @data.with { |c| c.flush_all } }
|
139
133
|
end
|
140
134
|
|
141
135
|
# Get the statistics from the memcached servers.
|
142
136
|
def stats
|
143
|
-
@data.stats
|
137
|
+
@data.with { |c| c.stats }
|
144
138
|
end
|
145
139
|
|
146
140
|
private
|
147
141
|
# Read an entry from the cache.
|
148
|
-
def read_entry(key, options)
|
149
|
-
rescue_error_with(nil) { deserialize_entry(@data.get(key, options)) }
|
142
|
+
def read_entry(key, **options)
|
143
|
+
rescue_error_with(nil) { deserialize_entry(@data.with { |c| c.get(key, options) }) }
|
150
144
|
end
|
151
145
|
|
152
146
|
# Write an entry to the cache.
|
153
|
-
def write_entry(key, entry, options)
|
154
|
-
method = options
|
155
|
-
value = options[:raw] ? entry.value.to_s : entry
|
147
|
+
def write_entry(key, entry, **options)
|
148
|
+
method = options[:unless_exist] ? :add : :set
|
149
|
+
value = options[:raw] ? entry.value.to_s : serialize_entry(entry)
|
156
150
|
expires_in = options[:expires_in].to_i
|
157
|
-
if expires_in > 0 && !options[:raw]
|
151
|
+
if options[:race_condition_ttl] && expires_in > 0 && !options[:raw]
|
158
152
|
# Set the memcache expire a few minutes in the future to support race condition ttls on read
|
159
153
|
expires_in += 5.minutes
|
160
154
|
end
|
161
155
|
rescue_error_with false do
|
162
|
-
|
156
|
+
# The value "compress: false" prevents duplicate compression within Dalli.
|
157
|
+
@data.with { |c| c.send(method, key, value, expires_in, **options, compress: false) }
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Reads multiple entries from the cache implementation.
|
162
|
+
def read_multi_entries(names, **options)
|
163
|
+
keys_to_names = names.index_by { |name| normalize_key(name, options) }
|
164
|
+
|
165
|
+
raw_values = @data.with { |c| c.get_multi(keys_to_names.keys) }
|
166
|
+
values = {}
|
167
|
+
|
168
|
+
raw_values.each do |key, value|
|
169
|
+
entry = deserialize_entry(value)
|
170
|
+
|
171
|
+
unless entry.expired? || entry.mismatched?(normalize_version(keys_to_names[key], options))
|
172
|
+
values[keys_to_names[key]] = entry.value
|
173
|
+
end
|
163
174
|
end
|
175
|
+
|
176
|
+
values
|
164
177
|
end
|
165
178
|
|
166
179
|
# Delete an entry from the cache.
|
167
|
-
def delete_entry(key, options)
|
168
|
-
rescue_error_with(false) { @data.delete(key) }
|
180
|
+
def delete_entry(key, **options)
|
181
|
+
rescue_error_with(false) { @data.with { |c| c.delete(key) } }
|
169
182
|
end
|
170
183
|
|
171
184
|
# Memcache keys are binaries. So we need to force their encoding to binary
|
@@ -175,15 +188,14 @@ module ActiveSupport
|
|
175
188
|
key = super.dup
|
176
189
|
key = key.force_encoding(Encoding::ASCII_8BIT)
|
177
190
|
key = key.gsub(ESCAPE_KEY_CHARS) { |match| "%#{match.getbyte(0).to_s(16).upcase}" }
|
178
|
-
key = "#{key[0, 213]}:md5:#{Digest
|
191
|
+
key = "#{key[0, 213]}:md5:#{ActiveSupport::Digest.hexdigest(key)}" if key.size > 250
|
179
192
|
key
|
180
193
|
end
|
181
194
|
|
182
|
-
def deserialize_entry(
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
end
|
195
|
+
def deserialize_entry(payload)
|
196
|
+
entry = super
|
197
|
+
entry = Entry.new(entry, compress: false) if entry && !entry.is_a?(Entry)
|
198
|
+
entry
|
187
199
|
end
|
188
200
|
|
189
201
|
def rescue_error_with(fallback)
|