activesupport 6.0.3.6 → 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 +4 -4
- data/CHANGELOG.md +355 -475
- data/MIT-LICENSE +1 -1
- data/lib/active_support.rb +13 -1
- data/lib/active_support/array_inquirer.rb +4 -2
- data/lib/active_support/backtrace_cleaner.rb +3 -3
- data/lib/active_support/benchmarkable.rb +1 -1
- data/lib/active_support/cache.rb +85 -44
- data/lib/active_support/cache/file_store.rb +4 -3
- data/lib/active_support/cache/mem_cache_store.rb +21 -14
- data/lib/active_support/cache/memory_store.rb +46 -26
- data/lib/active_support/cache/redis_cache_store.rb +27 -27
- data/lib/active_support/cache/strategy/local_cache.rb +21 -6
- data/lib/active_support/callbacks.rb +65 -56
- data/lib/active_support/concern.rb +46 -2
- data/lib/active_support/configurable.rb +3 -3
- data/lib/active_support/configuration_file.rb +46 -0
- data/lib/active_support/core_ext.rb +1 -1
- data/lib/active_support/core_ext/benchmark.rb +2 -2
- data/lib/active_support/core_ext/class/attribute.rb +34 -44
- data/lib/active_support/core_ext/class/subclasses.rb +17 -38
- data/lib/active_support/core_ext/date/conversions.rb +2 -1
- data/lib/active_support/core_ext/date_and_time/calculations.rb +13 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/enumerable.rb +76 -4
- data/lib/active_support/core_ext/hash/conversions.rb +2 -2
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
- data/lib/active_support/core_ext/hash/except.rb +1 -1
- data/lib/active_support/core_ext/hash/keys.rb +1 -1
- data/lib/active_support/core_ext/hash/slice.rb +3 -2
- data/lib/active_support/core_ext/load_error.rb +1 -1
- data/lib/active_support/core_ext/marshal.rb +2 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +23 -29
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +8 -4
- data/lib/active_support/core_ext/module/concerning.rb +8 -2
- data/lib/active_support/core_ext/module/delegation.rb +38 -28
- data/lib/active_support/core_ext/module/introspection.rb +1 -25
- data/lib/active_support/core_ext/name_error.rb +29 -2
- data/lib/active_support/core_ext/numeric/conversions.rb +22 -18
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/json.rb +13 -2
- data/lib/active_support/core_ext/object/try.rb +2 -2
- data/lib/active_support/core_ext/range/compare_range.rb +9 -3
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
- data/lib/active_support/core_ext/regexp.rb +8 -1
- data/lib/active_support/core_ext/string/access.rb +5 -24
- data/lib/active_support/core_ext/string/conversions.rb +1 -0
- data/lib/active_support/core_ext/string/inflections.rb +38 -4
- data/lib/active_support/core_ext/string/inquiry.rb +1 -0
- data/lib/active_support/core_ext/string/multibyte.rb +2 -2
- data/lib/active_support/core_ext/string/output_safety.rb +10 -10
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
- data/lib/active_support/core_ext/time/calculations.rb +19 -1
- data/lib/active_support/core_ext/time/conversions.rb +2 -0
- data/lib/active_support/core_ext/uri.rb +5 -1
- data/lib/active_support/current_attributes.rb +7 -2
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/dependencies.rb +43 -19
- data/lib/active_support/deprecation.rb +6 -1
- data/lib/active_support/deprecation/behaviors.rb +15 -2
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +0 -1
- data/lib/active_support/deprecation/method_wrappers.rb +3 -2
- data/lib/active_support/deprecation/proxy_wrappers.rb +3 -3
- data/lib/active_support/deprecation/reporting.rb +50 -7
- data/lib/active_support/descendants_tracker.rb +6 -2
- data/lib/active_support/duration.rb +71 -22
- data/lib/active_support/duration/iso8601_serializer.rb +15 -9
- data/lib/active_support/encrypted_file.rb +19 -2
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/evented_file_update_checker.rb +69 -133
- data/lib/active_support/fork_tracker.rb +62 -0
- data/lib/active_support/gem_version.rb +3 -3
- data/lib/active_support/hash_with_indifferent_access.rb +42 -23
- data/lib/active_support/i18n_railtie.rb +14 -19
- data/lib/active_support/inflector/inflections.rb +1 -2
- data/lib/active_support/inflector/methods.rb +35 -31
- data/lib/active_support/inflector/transliterate.rb +4 -4
- data/lib/active_support/json/decoding.rb +4 -4
- data/lib/active_support/json/encoding.rb +5 -1
- data/lib/active_support/key_generator.rb +1 -1
- data/lib/active_support/locale/en.yml +7 -3
- data/lib/active_support/log_subscriber.rb +8 -0
- data/lib/active_support/logger.rb +1 -1
- data/lib/active_support/logger_silence.rb +2 -26
- data/lib/active_support/logger_thread_safe_level.rb +34 -12
- data/lib/active_support/message_encryptor.rb +4 -7
- data/lib/active_support/message_verifier.rb +5 -5
- data/lib/active_support/messages/metadata.rb +9 -1
- data/lib/active_support/messages/rotation_configuration.rb +2 -1
- data/lib/active_support/messages/rotator.rb +6 -5
- data/lib/active_support/multibyte/chars.rb +4 -42
- data/lib/active_support/multibyte/unicode.rb +9 -83
- data/lib/active_support/notifications.rb +31 -4
- data/lib/active_support/notifications/fanout.rb +23 -8
- data/lib/active_support/notifications/instrumenter.rb +6 -15
- data/lib/active_support/number_helper.rb +29 -14
- data/lib/active_support/number_helper/number_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_currency_converter.rb +3 -7
- data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +3 -3
- data/lib/active_support/number_helper/rounding_helper.rb +12 -28
- data/lib/active_support/option_merger.rb +3 -2
- data/lib/active_support/ordered_options.rb +8 -2
- data/lib/active_support/parameter_filter.rb +15 -10
- data/lib/active_support/per_thread_registry.rb +1 -1
- data/lib/active_support/rails.rb +1 -4
- data/lib/active_support/railtie.rb +23 -1
- data/lib/active_support/rescuable.rb +4 -4
- data/lib/active_support/secure_compare_rotator.rb +51 -0
- data/lib/active_support/security_utils.rb +19 -12
- data/lib/active_support/string_inquirer.rb +4 -2
- data/lib/active_support/subscriber.rb +12 -7
- data/lib/active_support/tagged_logging.rb +29 -4
- data/lib/active_support/testing/assertions.rb +18 -11
- data/lib/active_support/testing/parallelization.rb +12 -95
- 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/time_helpers.rb +40 -3
- data/lib/active_support/time_with_zone.rb +66 -42
- data/lib/active_support/values/time_zone.rb +20 -10
- data/lib/active_support/xml_mini/rexml.rb +8 -1
- metadata +37 -39
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
- data/lib/active_support/core_ext/hash/compact.rb +0 -5
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
- data/lib/active_support/core_ext/module/reachable.rb +0 -6
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
- data/lib/active_support/core_ext/range/include_range.rb +0 -9
data/MIT-LICENSE
CHANGED
data/lib/active_support.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#--
|
4
|
-
# Copyright (c) 2005-
|
4
|
+
# Copyright (c) 2005-2020 David Heinemeier Hansson
|
5
5
|
#
|
6
6
|
# Permission is hereby granted, free of charge, to any person obtaining
|
7
7
|
# a copy of this software and associated documentation files (the
|
@@ -35,6 +35,7 @@ module ActiveSupport
|
|
35
35
|
|
36
36
|
autoload :Concern
|
37
37
|
autoload :ActionableError
|
38
|
+
autoload :ConfigurationFile
|
38
39
|
autoload :CurrentAttributes
|
39
40
|
autoload :Dependencies
|
40
41
|
autoload :DescendantsTracker
|
@@ -42,9 +43,11 @@ module ActiveSupport
|
|
42
43
|
autoload :Executor
|
43
44
|
autoload :FileUpdateChecker
|
44
45
|
autoload :EventedFileUpdateChecker
|
46
|
+
autoload :ForkTracker
|
45
47
|
autoload :LogSubscriber
|
46
48
|
autoload :Notifications
|
47
49
|
autoload :Reloader
|
50
|
+
autoload :SecureCompareRotator
|
48
51
|
|
49
52
|
eager_autoload do
|
50
53
|
autoload :BacktraceCleaner
|
@@ -67,6 +70,7 @@ module ActiveSupport
|
|
67
70
|
autoload :OrderedHash
|
68
71
|
autoload :OrderedOptions
|
69
72
|
autoload :StringInquirer
|
73
|
+
autoload :EnvironmentInquirer
|
70
74
|
autoload :TaggedLogging
|
71
75
|
autoload :XmlMini
|
72
76
|
autoload :ArrayInquirer
|
@@ -91,6 +95,14 @@ module ActiveSupport
|
|
91
95
|
def self.to_time_preserves_timezone=(value)
|
92
96
|
DateAndTime::Compatibility.preserve_timezone = value
|
93
97
|
end
|
98
|
+
|
99
|
+
def self.utc_to_local_returns_utc_offset_times
|
100
|
+
DateAndTime::Compatibility.utc_to_local_returns_utc_offset_times
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.utc_to_local_returns_utc_offset_times=(value)
|
104
|
+
DateAndTime::Compatibility.utc_to_local_returns_utc_offset_times = value
|
105
|
+
end
|
94
106
|
end
|
95
107
|
|
96
108
|
autoload :I18n, "active_support/i18n"
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/symbol/starts_ends_with"
|
4
|
+
|
3
5
|
module ActiveSupport
|
4
6
|
# Wrapping an array in an +ArrayInquirer+ gives a friendlier way to check
|
5
7
|
# its string-like contents:
|
@@ -34,11 +36,11 @@ module ActiveSupport
|
|
34
36
|
|
35
37
|
private
|
36
38
|
def respond_to_missing?(name, include_private = false)
|
37
|
-
(
|
39
|
+
name.end_with?("?") || super
|
38
40
|
end
|
39
41
|
|
40
42
|
def method_missing(name, *args)
|
41
|
-
if name
|
43
|
+
if name.end_with?("?")
|
42
44
|
any?(name[0..-2])
|
43
45
|
else
|
44
46
|
super
|
@@ -16,7 +16,7 @@ module ActiveSupport
|
|
16
16
|
#
|
17
17
|
# bc = ActiveSupport::BacktraceCleaner.new
|
18
18
|
# bc.add_filter { |line| line.gsub(Rails.root.to_s, '') } # strip the Rails.root prefix
|
19
|
-
# bc.add_silencer { |line|
|
19
|
+
# bc.add_silencer { |line| /puma|rubygems/.match?(line) } # skip any lines from puma or rubygems
|
20
20
|
# bc.clean(exception.backtrace) # perform the cleanup
|
21
21
|
#
|
22
22
|
# To reconfigure an existing BacktraceCleaner (like the default one in Rails)
|
@@ -65,7 +65,7 @@ module ActiveSupport
|
|
65
65
|
# for a given line, it will be excluded from the clean backtrace.
|
66
66
|
#
|
67
67
|
# # Will reject all lines that include the word "puma", like "/gems/puma/server.rb" or "/app/my_puma_server/rb"
|
68
|
-
# backtrace_cleaner.add_silencer { |line|
|
68
|
+
# backtrace_cleaner.add_silencer { |line| /puma/.match?(line) }
|
69
69
|
def add_silencer(&block)
|
70
70
|
@silencers << block
|
71
71
|
end
|
@@ -91,7 +91,7 @@ module ActiveSupport
|
|
91
91
|
gems_paths = (Gem.path | [Gem.default_dir]).map { |p| Regexp.escape(p) }
|
92
92
|
return if gems_paths.empty?
|
93
93
|
|
94
|
-
gems_regexp = %r{(#{gems_paths.join('|')})/(bundler/)?gems/([^/]+)-([\w.]+)/(.*)}
|
94
|
+
gems_regexp = %r{\A(#{gems_paths.join('|')})/(bundler/)?gems/([^/]+)-([\w.]+)/(.*)}
|
95
95
|
gems_result = '\3 (\4) \5'
|
96
96
|
add_filter { |line| line.sub(gems_regexp, gems_result) }
|
97
97
|
end
|
@@ -41,7 +41,7 @@ module ActiveSupport
|
|
41
41
|
|
42
42
|
result = nil
|
43
43
|
ms = Benchmark.ms { result = options[:silence] ? logger.silence { yield } : yield }
|
44
|
-
logger.
|
44
|
+
logger.public_send(options[:level], "%s (%.1fms)" % [ message, ms ])
|
45
45
|
result
|
46
46
|
else
|
47
47
|
yield
|
data/lib/active_support/cache.rb
CHANGED
@@ -3,10 +3,12 @@
|
|
3
3
|
require "zlib"
|
4
4
|
require "active_support/core_ext/array/extract_options"
|
5
5
|
require "active_support/core_ext/array/wrap"
|
6
|
+
require "active_support/core_ext/enumerable"
|
6
7
|
require "active_support/core_ext/module/attribute_accessors"
|
7
8
|
require "active_support/core_ext/numeric/bytes"
|
8
9
|
require "active_support/core_ext/numeric/time"
|
9
10
|
require "active_support/core_ext/object/to_param"
|
11
|
+
require "active_support/core_ext/object/try"
|
10
12
|
require "active_support/core_ext/string/inflections"
|
11
13
|
|
12
14
|
module ActiveSupport
|
@@ -20,7 +22,7 @@ module ActiveSupport
|
|
20
22
|
|
21
23
|
# These options mean something to all cache implementations. Individual cache
|
22
24
|
# implementations may support additional options.
|
23
|
-
UNIVERSAL_OPTIONS = [:namespace, :compress, :compress_threshold, :expires_in, :race_condition_ttl]
|
25
|
+
UNIVERSAL_OPTIONS = [:namespace, :compress, :compress_threshold, :expires_in, :race_condition_ttl, :coder]
|
24
26
|
|
25
27
|
module Strategy
|
26
28
|
autoload :LocalCache, "active_support/cache/strategy/local_cache"
|
@@ -79,7 +81,7 @@ module ActiveSupport
|
|
79
81
|
#
|
80
82
|
# The +key+ argument can also respond to +cache_key+ or +to_param+.
|
81
83
|
def expand_cache_key(key, namespace = nil)
|
82
|
-
expanded_cache_key =
|
84
|
+
expanded_cache_key = namespace ? +"#{namespace}/" : +""
|
83
85
|
|
84
86
|
if prefix = ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"]
|
85
87
|
expanded_cache_key << "#{prefix}/"
|
@@ -156,6 +158,8 @@ module ActiveSupport
|
|
156
158
|
# threshold is configurable with the <tt>:compress_threshold</tt> option,
|
157
159
|
# specified in bytes.
|
158
160
|
class Store
|
161
|
+
DEFAULT_CODER = Marshal
|
162
|
+
|
159
163
|
cattr_accessor :logger, instance_writer: true
|
160
164
|
|
161
165
|
attr_reader :silence, :options
|
@@ -183,6 +187,7 @@ module ActiveSupport
|
|
183
187
|
# namespace for the cache.
|
184
188
|
def initialize(options = nil)
|
185
189
|
@options = options ? options.dup : {}
|
190
|
+
@coder = @options.delete(:coder) { self.class::DEFAULT_CODER } || NullCoder
|
186
191
|
end
|
187
192
|
|
188
193
|
# Silences the logger.
|
@@ -312,14 +317,14 @@ module ActiveSupport
|
|
312
317
|
# :bar
|
313
318
|
# end
|
314
319
|
# cache.fetch('foo') # => "bar"
|
315
|
-
def fetch(name, options = nil)
|
320
|
+
def fetch(name, options = nil, &block)
|
316
321
|
if block_given?
|
317
322
|
options = merged_options(options)
|
318
323
|
key = normalize_key(name, options)
|
319
324
|
|
320
325
|
entry = nil
|
321
326
|
instrument(:read, name, options) do |payload|
|
322
|
-
cached_entry = read_entry(key, **options) unless options[:force]
|
327
|
+
cached_entry = read_entry(key, **options, event: payload) unless options[:force]
|
323
328
|
entry = handle_expired_entry(cached_entry, key, options)
|
324
329
|
entry = nil if entry && entry.mismatched?(normalize_version(name, options))
|
325
330
|
payload[:super_operation] = :fetch if payload
|
@@ -327,9 +332,9 @@ module ActiveSupport
|
|
327
332
|
end
|
328
333
|
|
329
334
|
if entry
|
330
|
-
get_entry_value(entry, name,
|
335
|
+
get_entry_value(entry, name, options)
|
331
336
|
else
|
332
|
-
save_block_result_to_cache(name,
|
337
|
+
save_block_result_to_cache(name, options, &block)
|
333
338
|
end
|
334
339
|
elsif options && options[:force]
|
335
340
|
raise ArgumentError, "Missing block: Calling `Cache#fetch` with `force: true` requires a block."
|
@@ -353,7 +358,7 @@ module ActiveSupport
|
|
353
358
|
version = normalize_version(name, options)
|
354
359
|
|
355
360
|
instrument(:read, name, options) do |payload|
|
356
|
-
entry = read_entry(key, **options)
|
361
|
+
entry = read_entry(key, **options, event: payload)
|
357
362
|
|
358
363
|
if entry
|
359
364
|
if entry.expired?
|
@@ -385,7 +390,7 @@ module ActiveSupport
|
|
385
390
|
options = merged_options(options)
|
386
391
|
|
387
392
|
instrument :read_multi, names, options do |payload|
|
388
|
-
read_multi_entries(names, **options).tap do |results|
|
393
|
+
read_multi_entries(names, **options, event: payload).tap do |results|
|
389
394
|
payload[:hits] = results.keys
|
390
395
|
end
|
391
396
|
end
|
@@ -441,14 +446,14 @@ module ActiveSupport
|
|
441
446
|
instrument :read_multi, names, options do |payload|
|
442
447
|
reads = read_multi_entries(names, **options)
|
443
448
|
writes = {}
|
444
|
-
ordered = names.
|
445
|
-
|
449
|
+
ordered = names.index_with do |name|
|
450
|
+
reads.fetch(name) { writes[name] = yield(name) }
|
446
451
|
end
|
447
452
|
|
448
453
|
payload[:hits] = reads.keys
|
449
454
|
payload[:super_operation] = :fetch_multi
|
450
455
|
|
451
|
-
write_multi(writes,
|
456
|
+
write_multi(writes, options)
|
452
457
|
|
453
458
|
ordered
|
454
459
|
end
|
@@ -477,14 +482,26 @@ module ActiveSupport
|
|
477
482
|
end
|
478
483
|
end
|
479
484
|
|
485
|
+
# Deletes multiple entries in the cache.
|
486
|
+
#
|
487
|
+
# Options are passed to the underlying cache implementation.
|
488
|
+
def delete_multi(names, options = nil)
|
489
|
+
options = merged_options(options)
|
490
|
+
names.map! { |key| normalize_key(key, options) }
|
491
|
+
|
492
|
+
instrument :delete_multi, names do
|
493
|
+
delete_multi_entries(names, **options)
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
480
497
|
# Returns +true+ if the cache contains an entry for the given key.
|
481
498
|
#
|
482
499
|
# Options are passed to the underlying cache implementation.
|
483
500
|
def exist?(name, options = nil)
|
484
501
|
options = merged_options(options)
|
485
502
|
|
486
|
-
instrument(:exist?, name) do
|
487
|
-
entry = read_entry(normalize_key(name, options), **options)
|
503
|
+
instrument(:exist?, name) do |payload|
|
504
|
+
entry = read_entry(normalize_key(name, options), **options, event: payload)
|
488
505
|
(entry && !entry.expired? && !entry.mismatched?(normalize_version(name, options))) || false
|
489
506
|
end
|
490
507
|
end
|
@@ -567,26 +584,31 @@ module ActiveSupport
|
|
567
584
|
raise NotImplementedError.new
|
568
585
|
end
|
569
586
|
|
587
|
+
def serialize_entry(entry)
|
588
|
+
@coder.dump(entry)
|
589
|
+
end
|
590
|
+
|
591
|
+
def deserialize_entry(payload)
|
592
|
+
payload.nil? ? nil : @coder.load(payload)
|
593
|
+
end
|
594
|
+
|
570
595
|
# Reads multiple entries from the cache implementation. Subclasses MAY
|
571
596
|
# implement this method.
|
572
597
|
def read_multi_entries(names, **options)
|
573
|
-
|
574
|
-
|
575
|
-
|
598
|
+
names.each_with_object({}) do |name, results|
|
599
|
+
key = normalize_key(name, options)
|
600
|
+
entry = read_entry(key, **options)
|
601
|
+
|
602
|
+
next unless entry
|
603
|
+
|
576
604
|
version = normalize_version(name, options)
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
elsif entry.mismatched?(version)
|
583
|
-
# Skip mismatched versions
|
584
|
-
else
|
585
|
-
results[name] = entry.value
|
586
|
-
end
|
605
|
+
|
606
|
+
if entry.expired?
|
607
|
+
delete_entry(key, **options)
|
608
|
+
elsif !entry.mismatched?(version)
|
609
|
+
results[name] = entry.value
|
587
610
|
end
|
588
611
|
end
|
589
|
-
results
|
590
612
|
end
|
591
613
|
|
592
614
|
# Writes multiple entries to the cache implementation. Subclasses MAY
|
@@ -603,6 +625,12 @@ module ActiveSupport
|
|
603
625
|
raise NotImplementedError.new
|
604
626
|
end
|
605
627
|
|
628
|
+
# Deletes multiples entries in the cache implementation. Subclasses MAY
|
629
|
+
# implement this method.
|
630
|
+
def delete_multi_entries(entries, **options)
|
631
|
+
entries.count { |key| delete_entry(key, **options) }
|
632
|
+
end
|
633
|
+
|
606
634
|
# Merges the default options with ones specific to a method call.
|
607
635
|
def merged_options(call_options)
|
608
636
|
if call_options
|
@@ -639,6 +667,10 @@ module ActiveSupport
|
|
639
667
|
namespace = namespace.call
|
640
668
|
end
|
641
669
|
|
670
|
+
if key && key.encoding != Encoding::UTF_8
|
671
|
+
key = key.dup.force_encoding(Encoding::UTF_8)
|
672
|
+
end
|
673
|
+
|
642
674
|
if namespace
|
643
675
|
"#{namespace}:#{key}"
|
644
676
|
else
|
@@ -655,15 +687,15 @@ module ActiveSupport
|
|
655
687
|
case key
|
656
688
|
when Array
|
657
689
|
if key.size > 1
|
658
|
-
key
|
690
|
+
key.collect { |element| expanded_key(element) }
|
659
691
|
else
|
660
|
-
|
692
|
+
expanded_key(key.first)
|
661
693
|
end
|
662
694
|
when Hash
|
663
|
-
key
|
664
|
-
|
665
|
-
|
666
|
-
|
695
|
+
key.collect { |k, v| "#{k}=#{v}" }.sort!
|
696
|
+
else
|
697
|
+
key
|
698
|
+
end.to_param
|
667
699
|
end
|
668
700
|
|
669
701
|
def normalize_version(key, options = nil)
|
@@ -673,24 +705,21 @@ module ActiveSupport
|
|
673
705
|
def expanded_version(key)
|
674
706
|
case
|
675
707
|
when key.respond_to?(:cache_version) then key.cache_version.to_param
|
676
|
-
when key.is_a?(Array) then key.map { |element| expanded_version(element) }.compact.to_param
|
708
|
+
when key.is_a?(Array) then key.map { |element| expanded_version(element) }.tap(&:compact!).to_param
|
677
709
|
when key.respond_to?(:to_a) then expanded_version(key.to_a)
|
678
710
|
end
|
679
711
|
end
|
680
712
|
|
681
713
|
def instrument(operation, key, options = nil)
|
682
|
-
|
714
|
+
if logger && logger.debug? && !silence?
|
715
|
+
logger.debug "Cache #{operation}: #{normalize_key(key, options)}#{options.blank? ? "" : " (#{options.inspect})"}"
|
716
|
+
end
|
683
717
|
|
684
|
-
payload = { key: key }
|
718
|
+
payload = { key: key, store: self.class.name }
|
685
719
|
payload.merge!(options) if options.is_a?(Hash)
|
686
720
|
ActiveSupport::Notifications.instrument("cache_#{operation}.active_support", payload) { yield(payload) }
|
687
721
|
end
|
688
722
|
|
689
|
-
def log
|
690
|
-
return unless logger && logger.debug? && !silence?
|
691
|
-
logger.debug(yield)
|
692
|
-
end
|
693
|
-
|
694
723
|
def handle_expired_entry(entry, key, options)
|
695
724
|
if entry && entry.expired?
|
696
725
|
race_ttl = options[:race_condition_ttl].to_i
|
@@ -712,7 +741,7 @@ module ActiveSupport
|
|
712
741
|
entry.value
|
713
742
|
end
|
714
743
|
|
715
|
-
def save_block_result_to_cache(name,
|
744
|
+
def save_block_result_to_cache(name, options)
|
716
745
|
result = instrument(:generate, name, options) do
|
717
746
|
yield(name)
|
718
747
|
end
|
@@ -722,6 +751,18 @@ module ActiveSupport
|
|
722
751
|
end
|
723
752
|
end
|
724
753
|
|
754
|
+
module NullCoder # :nodoc:
|
755
|
+
class << self
|
756
|
+
def load(payload)
|
757
|
+
payload
|
758
|
+
end
|
759
|
+
|
760
|
+
def dump(entry)
|
761
|
+
entry
|
762
|
+
end
|
763
|
+
end
|
764
|
+
end
|
765
|
+
|
725
766
|
# This class is used to represent cache entries. Cache entries have a value, an optional
|
726
767
|
# expiration time, and an optional version. The expiration time is used to support the :race_condition_ttl option
|
727
768
|
# on the cache. The version is used to support the :version option on the cache for rejecting
|
@@ -772,8 +813,8 @@ module ActiveSupport
|
|
772
813
|
end
|
773
814
|
|
774
815
|
# Returns the size of the cached value. This could be less than
|
775
|
-
# <tt>value.
|
776
|
-
def
|
816
|
+
# <tt>value.bytesize</tt> if the data is compressed.
|
817
|
+
def bytesize
|
777
818
|
case value
|
778
819
|
when NilClass
|
779
820
|
0
|
@@ -16,7 +16,7 @@ module ActiveSupport
|
|
16
16
|
attr_reader :cache_path
|
17
17
|
|
18
18
|
DIR_FORMATTER = "%03X"
|
19
|
-
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)
|
20
20
|
FILEPATH_MAX_SIZE = 900 # max is 1024, plus some room
|
21
21
|
GITKEEP_FILES = [".gitkeep", ".keep"].freeze
|
22
22
|
|
@@ -74,7 +74,8 @@ module ActiveSupport
|
|
74
74
|
private
|
75
75
|
def read_entry(key, **options)
|
76
76
|
if File.exist?(key)
|
77
|
-
File.open(key) { |f|
|
77
|
+
entry = File.open(key) { |f| deserialize_entry(f.read) }
|
78
|
+
entry if entry.is_a?(Cache::Entry)
|
78
79
|
end
|
79
80
|
rescue => e
|
80
81
|
logger.error("FileStoreError (#{e}): #{e.message}") if logger
|
@@ -84,7 +85,7 @@ module ActiveSupport
|
|
84
85
|
def write_entry(key, entry, **options)
|
85
86
|
return false if options[:unless_exist] && File.exist?(key)
|
86
87
|
ensure_cache_path(File.dirname(key))
|
87
|
-
File.atomic_write(key, cache_path) { |f|
|
88
|
+
File.atomic_write(key, cache_path) { |f| f.write(serialize_entry(entry)) }
|
88
89
|
true
|
89
90
|
end
|
90
91
|
|
@@ -7,6 +7,8 @@ rescue LoadError => e
|
|
7
7
|
raise e
|
8
8
|
end
|
9
9
|
|
10
|
+
require "active_support/core_ext/enumerable"
|
11
|
+
require "active_support/core_ext/marshal"
|
10
12
|
require "active_support/core_ext/array/extract_options"
|
11
13
|
|
12
14
|
module ActiveSupport
|
@@ -24,6 +26,8 @@ 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
|
@@ -49,16 +53,18 @@ module ActiveSupport
|
|
49
53
|
ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
|
50
54
|
|
51
55
|
# Creates a new Dalli::Client instance with specified addresses and options.
|
52
|
-
#
|
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)
|
53
59
|
#
|
54
60
|
# ActiveSupport::Cache::MemCacheStore.build_mem_cache
|
55
|
-
# # => #<Dalli::Client:0x007f98a47d2028 @servers=["
|
61
|
+
# # => #<Dalli::Client:0x007f98a47d2028 @servers=["127.0.0.1:11211"], @options={}, @ring=nil>
|
56
62
|
# ActiveSupport::Cache::MemCacheStore.build_mem_cache('localhost:10290')
|
57
63
|
# # => #<Dalli::Client:0x007f98a47b3a60 @servers=["localhost:10290"], @options={}, @ring=nil>
|
58
64
|
def self.build_mem_cache(*addresses) # :nodoc:
|
59
65
|
addresses = addresses.flatten
|
60
66
|
options = addresses.extract_options!
|
61
|
-
addresses =
|
67
|
+
addresses = nil if addresses.empty?
|
62
68
|
pool_options = retrieve_pool_options(options)
|
63
69
|
|
64
70
|
if pool_options.empty?
|
@@ -75,8 +81,8 @@ module ActiveSupport
|
|
75
81
|
#
|
76
82
|
# ActiveSupport::Cache::MemCacheStore.new("localhost", "server-downstairs.localnetwork:8229")
|
77
83
|
#
|
78
|
-
# If no addresses are
|
79
|
-
#
|
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).
|
80
86
|
def initialize(*addresses)
|
81
87
|
addresses = addresses.flatten
|
82
88
|
options = addresses.extract_options!
|
@@ -139,21 +145,22 @@ module ActiveSupport
|
|
139
145
|
|
140
146
|
# Write an entry to the cache.
|
141
147
|
def write_entry(key, entry, **options)
|
142
|
-
method = options
|
143
|
-
value = options[:raw] ? entry.value.to_s : entry
|
148
|
+
method = options[:unless_exist] ? :add : :set
|
149
|
+
value = options[:raw] ? entry.value.to_s : serialize_entry(entry)
|
144
150
|
expires_in = options[:expires_in].to_i
|
145
|
-
if expires_in > 0 && !options[:raw]
|
151
|
+
if options[:race_condition_ttl] && expires_in > 0 && !options[:raw]
|
146
152
|
# Set the memcache expire a few minutes in the future to support race condition ttls on read
|
147
153
|
expires_in += 5.minutes
|
148
154
|
end
|
149
155
|
rescue_error_with false do
|
150
|
-
|
156
|
+
# The value "compress: false" prevents duplicate compression within Dalli.
|
157
|
+
@data.with { |c| c.send(method, key, value, expires_in, **options, compress: false) }
|
151
158
|
end
|
152
159
|
end
|
153
160
|
|
154
161
|
# Reads multiple entries from the cache implementation.
|
155
162
|
def read_multi_entries(names, **options)
|
156
|
-
keys_to_names =
|
163
|
+
keys_to_names = names.index_by { |name| normalize_key(name, options) }
|
157
164
|
|
158
165
|
raw_values = @data.with { |c| c.get_multi(keys_to_names.keys) }
|
159
166
|
values = {}
|
@@ -185,10 +192,10 @@ module ActiveSupport
|
|
185
192
|
key
|
186
193
|
end
|
187
194
|
|
188
|
-
def deserialize_entry(
|
189
|
-
|
190
|
-
|
191
|
-
|
195
|
+
def deserialize_entry(payload)
|
196
|
+
entry = super
|
197
|
+
entry = Entry.new(entry, compress: false) if entry && !entry.is_a?(Entry)
|
198
|
+
entry
|
192
199
|
end
|
193
200
|
|
194
201
|
def rescue_error_with(fallback)
|