activesupport 4.2.0 → 5.0.0.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 +630 -220
- data/MIT-LICENSE +2 -2
- data/README.rdoc +2 -3
- data/lib/active_support/array_inquirer.rb +44 -0
- data/lib/active_support/backtrace_cleaner.rb +1 -1
- data/lib/active_support/benchmarkable.rb +1 -1
- data/lib/active_support/cache/file_store.rb +36 -22
- data/lib/active_support/cache/mem_cache_store.rb +63 -54
- data/lib/active_support/cache/memory_store.rb +16 -21
- data/lib/active_support/cache/null_store.rb +1 -4
- data/lib/active_support/cache/strategy/local_cache.rb +31 -20
- data/lib/active_support/cache.rb +73 -89
- data/lib/active_support/callbacks.rb +195 -155
- data/lib/active_support/concern.rb +2 -2
- data/lib/active_support/concurrency/latch.rb +7 -15
- data/lib/active_support/concurrency/share_lock.rb +186 -0
- data/lib/active_support/configurable.rb +1 -0
- data/lib/active_support/core_ext/array/access.rb +27 -1
- data/lib/active_support/core_ext/array/conversions.rb +6 -4
- data/lib/active_support/core_ext/array/grouping.rb +9 -18
- data/lib/active_support/core_ext/array/inquiry.rb +17 -0
- data/lib/active_support/core_ext/array/wrap.rb +5 -4
- data/lib/active_support/core_ext/array.rb +1 -0
- data/lib/active_support/core_ext/big_decimal/conversions.rb +8 -10
- data/lib/active_support/core_ext/class/attribute.rb +10 -9
- data/lib/active_support/core_ext/class/subclasses.rb +3 -4
- data/lib/active_support/core_ext/class.rb +0 -1
- data/lib/active_support/core_ext/date/blank.rb +12 -0
- data/lib/active_support/core_ext/date/calculations.rb +1 -1
- data/lib/active_support/core_ext/date/conversions.rb +13 -6
- data/lib/active_support/core_ext/date.rb +1 -1
- data/lib/active_support/core_ext/date_and_time/calculations.rb +109 -25
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +3 -4
- data/lib/active_support/core_ext/date_time/blank.rb +12 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +36 -10
- data/lib/active_support/core_ext/date_time/compatibility.rb +5 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +2 -0
- data/lib/active_support/core_ext/date_time.rb +2 -1
- data/lib/active_support/core_ext/enumerable.rb +49 -5
- data/lib/active_support/core_ext/file/atomic.rb +30 -25
- data/lib/active_support/core_ext/hash/conversions.rb +23 -4
- data/lib/active_support/core_ext/hash/deep_merge.rb +1 -1
- data/lib/active_support/core_ext/hash/except.rb +9 -8
- data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -1
- data/lib/active_support/core_ext/hash/keys.rb +23 -19
- data/lib/active_support/core_ext/hash/slice.rb +1 -1
- data/lib/active_support/core_ext/hash/transform_values.rb +11 -5
- data/lib/active_support/core_ext/integer/time.rb +1 -16
- data/lib/active_support/core_ext/kernel/concern.rb +2 -0
- data/lib/active_support/core_ext/kernel/debugger.rb +3 -10
- data/lib/active_support/core_ext/kernel/reporting.rb +2 -83
- data/lib/active_support/core_ext/kernel.rb +0 -1
- data/lib/active_support/core_ext/load_error.rb +4 -2
- data/lib/active_support/core_ext/marshal.rb +12 -11
- data/lib/active_support/core_ext/module/aliasing.rb +6 -1
- data/lib/active_support/core_ext/module/anonymous.rb +10 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -5
- data/lib/active_support/core_ext/module/attribute_accessors.rb +15 -15
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +141 -0
- data/lib/active_support/core_ext/module/concerning.rb +4 -4
- data/lib/active_support/core_ext/module/delegation.rb +35 -25
- data/lib/active_support/core_ext/module/deprecation.rb +2 -2
- data/lib/active_support/core_ext/module/introspection.rb +4 -0
- data/lib/active_support/core_ext/module/method_transplanting.rb +3 -11
- data/lib/active_support/core_ext/module/qualified_const.rb +30 -12
- data/lib/active_support/core_ext/module/remove_method.rb +23 -0
- data/lib/active_support/core_ext/module.rb +1 -0
- data/lib/active_support/core_ext/name_error.rb +15 -2
- data/lib/active_support/core_ext/numeric/bytes.rb +20 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +74 -64
- data/lib/active_support/core_ext/numeric/inquiry.rb +26 -0
- data/lib/active_support/core_ext/numeric/time.rb +24 -19
- data/lib/active_support/core_ext/numeric.rb +1 -0
- data/lib/active_support/core_ext/object/blank.rb +17 -5
- data/lib/active_support/core_ext/object/deep_dup.rb +10 -3
- data/lib/active_support/core_ext/object/duplicable.rb +8 -13
- data/lib/active_support/core_ext/object/inclusion.rb +2 -2
- data/lib/active_support/core_ext/object/instance_variables.rb +1 -1
- data/lib/active_support/core_ext/object/json.rb +15 -7
- data/lib/active_support/core_ext/object/to_query.rb +1 -1
- data/lib/active_support/core_ext/object/try.rb +68 -22
- data/lib/active_support/core_ext/object/with_options.rb +1 -1
- data/lib/active_support/core_ext/object.rb +0 -1
- data/lib/active_support/core_ext/range/conversions.rb +18 -6
- data/lib/active_support/core_ext/range/each.rb +16 -18
- data/lib/active_support/core_ext/range/include_range.rb +20 -20
- data/lib/active_support/core_ext/securerandom.rb +23 -0
- data/lib/active_support/core_ext/string/access.rb +1 -1
- data/lib/active_support/core_ext/string/behavior.rb +1 -1
- data/lib/active_support/core_ext/string/conversions.rb +4 -3
- data/lib/active_support/core_ext/string/filters.rb +5 -5
- data/lib/active_support/core_ext/string/inflections.rb +32 -5
- data/lib/active_support/core_ext/string/multibyte.rb +11 -7
- data/lib/active_support/core_ext/string/output_safety.rb +18 -16
- data/lib/active_support/core_ext/string/strip.rb +3 -6
- data/lib/active_support/core_ext/struct.rb +3 -6
- data/lib/active_support/core_ext/time/calculations.rb +36 -11
- data/lib/active_support/core_ext/time/compatibility.rb +5 -0
- data/lib/active_support/core_ext/time/conversions.rb +4 -2
- data/lib/active_support/core_ext/time/marshal.rb +2 -29
- data/lib/active_support/core_ext/time/zones.rb +36 -4
- data/lib/active_support/core_ext/time.rb +1 -1
- data/lib/active_support/core_ext/uri.rb +1 -3
- data/lib/active_support/core_ext.rb +2 -1
- data/lib/active_support/dependencies/interlock.rb +51 -0
- data/lib/active_support/dependencies.rb +87 -95
- data/lib/active_support/deprecation/behaviors.rb +16 -2
- data/lib/active_support/deprecation/method_wrappers.rb +42 -16
- data/lib/active_support/deprecation/proxy_wrappers.rb +47 -24
- data/lib/active_support/deprecation/reporting.rb +23 -5
- data/lib/active_support/deprecation.rb +1 -1
- data/lib/active_support/duration/iso8601_parser.rb +122 -0
- data/lib/active_support/duration/iso8601_serializer.rb +51 -0
- data/lib/active_support/duration.rb +55 -10
- data/lib/active_support/evented_file_update_checker.rb +194 -0
- data/lib/active_support/execution_wrapper.rb +117 -0
- data/lib/active_support/executor.rb +6 -0
- data/lib/active_support/file_update_checker.rb +23 -3
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/hash_with_indifferent_access.rb +46 -13
- data/lib/active_support/i18n_railtie.rb +25 -4
- data/lib/active_support/inflector/inflections.rb +36 -5
- data/lib/active_support/inflector/methods.rb +97 -90
- data/lib/active_support/inflector/transliterate.rb +36 -21
- data/lib/active_support/json/decoding.rb +11 -10
- data/lib/active_support/json/encoding.rb +4 -49
- data/lib/active_support/key_generator.rb +7 -9
- data/lib/active_support/locale/en.yml +2 -0
- data/lib/active_support/log_subscriber/test_helper.rb +3 -3
- data/lib/active_support/log_subscriber.rb +1 -1
- data/lib/active_support/logger.rb +50 -1
- data/lib/active_support/logger_silence.rb +8 -4
- data/lib/active_support/logger_thread_safe_level.rb +31 -0
- data/lib/active_support/message_encryptor.rb +4 -4
- data/lib/active_support/message_verifier.rb +70 -8
- data/lib/active_support/multibyte/chars.rb +13 -4
- data/lib/active_support/multibyte/unicode.rb +44 -21
- data/lib/active_support/notifications/fanout.rb +6 -6
- data/lib/active_support/notifications/instrumenter.rb +20 -2
- data/lib/active_support/notifications.rb +2 -2
- data/lib/active_support/number_helper/number_to_currency_converter.rb +7 -9
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +8 -3
- data/lib/active_support/number_helper/number_to_human_converter.rb +6 -4
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +6 -2
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +11 -2
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +30 -25
- data/lib/active_support/number_helper.rb +90 -67
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/ordered_options.rb +15 -1
- data/lib/active_support/per_thread_registry.rb +8 -3
- data/lib/active_support/rails.rb +2 -2
- data/lib/active_support/railtie.rb +6 -1
- data/lib/active_support/reloader.rb +129 -0
- data/lib/active_support/rescuable.rb +93 -47
- data/lib/active_support/security_utils.rb +7 -0
- data/lib/active_support/string_inquirer.rb +1 -1
- data/lib/active_support/subscriber.rb +5 -10
- data/lib/active_support/tagged_logging.rb +3 -1
- data/lib/active_support/test_case.rb +15 -29
- data/lib/active_support/testing/assertions.rb +15 -13
- data/lib/active_support/testing/autorun.rb +8 -1
- data/lib/active_support/testing/deprecation.rb +9 -8
- data/lib/active_support/testing/file_fixtures.rb +34 -0
- data/lib/active_support/testing/isolation.rb +22 -8
- data/lib/active_support/testing/method_call_assertions.rb +41 -0
- data/lib/active_support/testing/stream.rb +42 -0
- data/lib/active_support/testing/time_helpers.rb +13 -10
- data/lib/active_support/time_with_zone.rb +135 -46
- data/lib/active_support/values/time_zone.rb +95 -47
- data/lib/active_support/values/unicode_tables.dat +0 -0
- data/lib/active_support/xml_mini/jdom.rb +7 -6
- data/lib/active_support/xml_mini/libxml.rb +2 -2
- data/lib/active_support/xml_mini/nokogiri.rb +2 -2
- data/lib/active_support/xml_mini/rexml.rb +7 -8
- data/lib/active_support/xml_mini.rb +22 -14
- data/lib/active_support.rb +20 -6
- metadata +33 -35
- data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -14
- data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
- data/lib/active_support/core_ext/date_time/zones.rb +0 -6
- data/lib/active_support/core_ext/object/itself.rb +0 -15
- data/lib/active_support/core_ext/thread.rb +0 -86
data/MIT-LICENSE
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (c) 2005-
|
1
|
+
Copyright (c) 2005-2016 David Heinemeier Hansson
|
2
2
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining
|
4
4
|
a copy of this software and associated documentation files (the
|
@@ -17,4 +17,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
17
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
18
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
19
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
CHANGED
@@ -10,11 +10,11 @@ outside of Rails.
|
|
10
10
|
|
11
11
|
The latest version of Active Support can be installed with RubyGems:
|
12
12
|
|
13
|
-
|
13
|
+
$ gem install activesupport
|
14
14
|
|
15
15
|
Source code can be downloaded as part of the Rails project on GitHub:
|
16
16
|
|
17
|
-
* https://github.com/rails/rails/tree/
|
17
|
+
* https://github.com/rails/rails/tree/master/activesupport
|
18
18
|
|
19
19
|
|
20
20
|
== License
|
@@ -37,4 +37,3 @@ Bug reports can be filed for the Ruby on Rails project here:
|
|
37
37
|
Feature requests should be discussed on the rails-core mailing list here:
|
38
38
|
|
39
39
|
* https://groups.google.com/forum/?fromgroups#!forum/rubyonrails-core
|
40
|
-
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module ActiveSupport
|
2
|
+
# Wrapping an array in an +ArrayInquirer+ gives a friendlier way to check
|
3
|
+
# its string-like contents:
|
4
|
+
#
|
5
|
+
# variants = ActiveSupport::ArrayInquirer.new([:phone, :tablet])
|
6
|
+
#
|
7
|
+
# variants.phone? # => true
|
8
|
+
# variants.tablet? # => true
|
9
|
+
# variants.desktop? # => false
|
10
|
+
class ArrayInquirer < Array
|
11
|
+
# Passes each element of +candidates+ collection to ArrayInquirer collection.
|
12
|
+
# The method returns true if at least one element is the same. If +candidates+
|
13
|
+
# collection is not given, method returns true.
|
14
|
+
#
|
15
|
+
# variants = ActiveSupport::ArrayInquirer.new([:phone, :tablet])
|
16
|
+
#
|
17
|
+
# variants.any? # => true
|
18
|
+
# variants.any?(:phone, :tablet) # => true
|
19
|
+
# variants.any?('phone', 'desktop') # => true
|
20
|
+
# variants.any?(:desktop, :watch) # => false
|
21
|
+
def any?(*candidates, &block)
|
22
|
+
if candidates.none?
|
23
|
+
super
|
24
|
+
else
|
25
|
+
candidates.any? do |candidate|
|
26
|
+
include?(candidate.to_sym) || include?(candidate.to_s)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def respond_to_missing?(name, include_private = false)
|
33
|
+
name[-1] == '?'
|
34
|
+
end
|
35
|
+
|
36
|
+
def method_missing(name, *args)
|
37
|
+
if name[-1] == '?'
|
38
|
+
any?(name[0..-2])
|
39
|
+
else
|
40
|
+
super
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -25,7 +25,7 @@ module ActiveSupport
|
|
25
25
|
# of the backtrace, you can call <tt>BacktraceCleaner#remove_filters!</tt>
|
26
26
|
# These two methods will give you a completely untouched backtrace.
|
27
27
|
#
|
28
|
-
# Inspired by the Quiet Backtrace gem by
|
28
|
+
# Inspired by the Quiet Backtrace gem by thoughtbot.
|
29
29
|
class BacktraceCleaner
|
30
30
|
def initialize
|
31
31
|
@filters, @silencers = [], []
|
@@ -38,7 +38,7 @@ module ActiveSupport
|
|
38
38
|
options[:level] ||= :info
|
39
39
|
|
40
40
|
result = nil
|
41
|
-
ms = Benchmark.ms { result = options[:silence] ? silence { yield } : yield }
|
41
|
+
ms = Benchmark.ms { result = options[:silence] ? logger.silence { yield } : yield }
|
42
42
|
logger.send(options[:level], '%s (%.1fms)' % [ message, ms ])
|
43
43
|
result
|
44
44
|
else
|
@@ -10,25 +10,27 @@ module ActiveSupport
|
|
10
10
|
# FileStore implements the Strategy::LocalCache strategy which implements
|
11
11
|
# an in-memory cache inside of a block.
|
12
12
|
class FileStore < Store
|
13
|
+
prepend Strategy::LocalCache
|
13
14
|
attr_reader :cache_path
|
14
15
|
|
15
16
|
DIR_FORMATTER = "%03X"
|
16
17
|
FILENAME_MAX_SIZE = 228 # max filename size on file system is 255, minus room for timestamp and random characters appended by Tempfile (used by atomic write)
|
17
18
|
FILEPATH_MAX_SIZE = 900 # max is 1024, plus some room
|
18
19
|
EXCLUDED_DIRS = ['.', '..'].freeze
|
20
|
+
GITKEEP_FILES = ['.gitkeep', '.keep'].freeze
|
19
21
|
|
20
22
|
def initialize(cache_path, options = nil)
|
21
23
|
super(options)
|
22
24
|
@cache_path = cache_path.to_s
|
23
|
-
extend Strategy::LocalCache
|
24
25
|
end
|
25
26
|
|
26
27
|
# Deletes all items from the cache. In this case it deletes all the entries in the specified
|
27
|
-
# file store directory except for .gitkeep. Be careful which directory is specified in your
|
28
|
+
# file store directory except for .keep or .gitkeep. Be careful which directory is specified in your
|
28
29
|
# config file when using +FileStore+ because everything in that directory will be deleted.
|
29
30
|
def clear(options = nil)
|
30
|
-
root_dirs =
|
31
|
+
root_dirs = exclude_from(cache_path, EXCLUDED_DIRS + GITKEEP_FILES)
|
31
32
|
FileUtils.rm_r(root_dirs.collect{|f| File.join(cache_path, f)})
|
33
|
+
rescue Errno::ENOENT
|
32
34
|
end
|
33
35
|
|
34
36
|
# Preemptively iterates through all stored keys and removes the ones which have expired.
|
@@ -59,7 +61,7 @@ module ActiveSupport
|
|
59
61
|
matcher = key_matcher(matcher, options)
|
60
62
|
search_dir(cache_path) do |path|
|
61
63
|
key = file_path_key(path)
|
62
|
-
delete_entry(
|
64
|
+
delete_entry(path, options) if key.match(matcher)
|
63
65
|
end
|
64
66
|
end
|
65
67
|
end
|
@@ -67,9 +69,8 @@ module ActiveSupport
|
|
67
69
|
protected
|
68
70
|
|
69
71
|
def read_entry(key, options)
|
70
|
-
|
71
|
-
|
72
|
-
File.open(file_name) { |f| Marshal.load(f) }
|
72
|
+
if File.exist?(key)
|
73
|
+
File.open(key) { |f| Marshal.load(f) }
|
73
74
|
end
|
74
75
|
rescue => e
|
75
76
|
logger.error("FileStoreError (#{e}): #{e.message}") if logger
|
@@ -77,23 +78,21 @@ module ActiveSupport
|
|
77
78
|
end
|
78
79
|
|
79
80
|
def write_entry(key, entry, options)
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
File.atomic_write(file_name, cache_path) {|f| Marshal.dump(entry, f)}
|
81
|
+
return false if options[:unless_exist] && File.exist?(key)
|
82
|
+
ensure_cache_path(File.dirname(key))
|
83
|
+
File.atomic_write(key, cache_path) {|f| Marshal.dump(entry, f)}
|
84
84
|
true
|
85
85
|
end
|
86
86
|
|
87
87
|
def delete_entry(key, options)
|
88
|
-
|
89
|
-
if File.exist?(file_name)
|
88
|
+
if File.exist?(key)
|
90
89
|
begin
|
91
|
-
File.delete(
|
92
|
-
delete_empty_directories(File.dirname(
|
90
|
+
File.delete(key)
|
91
|
+
delete_empty_directories(File.dirname(key))
|
93
92
|
true
|
94
93
|
rescue => e
|
95
94
|
# Just in case the error was caused by another process deleting the file first.
|
96
|
-
raise e if File.exist?(
|
95
|
+
raise e if File.exist?(key)
|
97
96
|
false
|
98
97
|
end
|
99
98
|
end
|
@@ -117,12 +116,14 @@ module ActiveSupport
|
|
117
116
|
end
|
118
117
|
|
119
118
|
# Translate a key into a file path.
|
120
|
-
def
|
121
|
-
|
122
|
-
|
119
|
+
def normalize_key(key, options)
|
120
|
+
key = super
|
121
|
+
fname = URI.encode_www_form_component(key)
|
122
|
+
|
123
|
+
if fname.size > FILEPATH_MAX_SIZE
|
124
|
+
fname = Digest::MD5.hexdigest(key)
|
123
125
|
end
|
124
126
|
|
125
|
-
fname = URI.encode_www_form_component(key)
|
126
127
|
hash = Zlib.adler32(fname)
|
127
128
|
hash, dir_1 = hash.divmod(0x1000)
|
128
129
|
dir_2 = hash.modulo(0x1000)
|
@@ -137,6 +138,14 @@ module ActiveSupport
|
|
137
138
|
File.join(cache_path, DIR_FORMATTER % dir_1, DIR_FORMATTER % dir_2, *fname_paths)
|
138
139
|
end
|
139
140
|
|
141
|
+
def key_file_path(key)
|
142
|
+
ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
|
143
|
+
`key_file_path` is deprecated and will be removed from Rails 5.1.
|
144
|
+
Please use `normalize_key` which will return a fully resolved key or nothing.
|
145
|
+
MESSAGE
|
146
|
+
key
|
147
|
+
end
|
148
|
+
|
140
149
|
# Translate a file path into a key.
|
141
150
|
def file_path_key(path)
|
142
151
|
fname = path[cache_path.to_s.size..-1].split(File::SEPARATOR, 4).last
|
@@ -146,7 +155,7 @@ module ActiveSupport
|
|
146
155
|
# Delete empty directories in the cache.
|
147
156
|
def delete_empty_directories(dir)
|
148
157
|
return if File.realpath(dir) == File.realpath(cache_path)
|
149
|
-
if
|
158
|
+
if exclude_from(dir, EXCLUDED_DIRS).empty?
|
150
159
|
Dir.delete(dir) rescue nil
|
151
160
|
delete_empty_directories(File.dirname(dir))
|
152
161
|
end
|
@@ -173,7 +182,7 @@ module ActiveSupport
|
|
173
182
|
# Modifies the amount of an already existing integer value that is stored in the cache.
|
174
183
|
# If the key is not found nothing is done.
|
175
184
|
def modify_value(name, amount, options)
|
176
|
-
file_name =
|
185
|
+
file_name = normalize_key(name, options)
|
177
186
|
|
178
187
|
lock_file(file_name) do
|
179
188
|
options = merged_options(options)
|
@@ -185,6 +194,11 @@ module ActiveSupport
|
|
185
194
|
end
|
186
195
|
end
|
187
196
|
end
|
197
|
+
|
198
|
+
# Exclude entries from source directory
|
199
|
+
def exclude_from(source, excludes)
|
200
|
+
Dir.entries(source).reject { |f| excludes.include?(f) }
|
201
|
+
end
|
188
202
|
end
|
189
203
|
end
|
190
204
|
end
|
@@ -24,9 +24,41 @@ module ActiveSupport
|
|
24
24
|
# MemCacheStore implements the Strategy::LocalCache strategy which implements
|
25
25
|
# an in-memory cache inside of a block.
|
26
26
|
class MemCacheStore < Store
|
27
|
+
# Provide support for raw values in the local cache strategy.
|
28
|
+
module LocalCacheWithRaw # :nodoc:
|
29
|
+
protected
|
30
|
+
def read_entry(key, options)
|
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) # :nodoc:
|
39
|
+
if options[:raw] && local_cache
|
40
|
+
raw_entry = Entry.new(entry.value.to_s)
|
41
|
+
raw_entry.expires_at = entry.expires_at
|
42
|
+
super(key, raw_entry, options)
|
43
|
+
else
|
44
|
+
super
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
prepend Strategy::LocalCache
|
50
|
+
prepend LocalCacheWithRaw
|
51
|
+
|
27
52
|
ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
|
28
53
|
|
29
|
-
|
54
|
+
# Creates a new Dalli::Client instance with specified addresses and options.
|
55
|
+
# By default address is equal localhost:11211.
|
56
|
+
#
|
57
|
+
# ActiveSupport::Cache::MemCacheStore.build_mem_cache
|
58
|
+
# # => #<Dalli::Client:0x007f98a47d2028 @servers=["localhost:11211"], @options={}, @ring=nil>
|
59
|
+
# ActiveSupport::Cache::MemCacheStore.build_mem_cache('localhost:10290')
|
60
|
+
# # => #<Dalli::Client:0x007f98a47b3a60 @servers=["localhost:10290"], @options={}, @ring=nil>
|
61
|
+
def self.build_mem_cache(*addresses) # :nodoc:
|
30
62
|
addresses = addresses.flatten
|
31
63
|
options = addresses.extract_options!
|
32
64
|
addresses = ["localhost:11211"] if addresses.empty?
|
@@ -56,9 +88,6 @@ module ActiveSupport
|
|
56
88
|
UNIVERSAL_OPTIONS.each{|name| mem_cache_options.delete(name)}
|
57
89
|
@data = self.class.build_mem_cache(*(addresses + [mem_cache_options]))
|
58
90
|
end
|
59
|
-
|
60
|
-
extend Strategy::LocalCache
|
61
|
-
extend LocalCacheWithRaw
|
62
91
|
end
|
63
92
|
|
64
93
|
# Reads multiple values from the cache using a single call to the
|
@@ -66,7 +95,8 @@ module ActiveSupport
|
|
66
95
|
def read_multi(*names)
|
67
96
|
options = names.extract_options!
|
68
97
|
options = merged_options(options)
|
69
|
-
|
98
|
+
|
99
|
+
keys_to_names = Hash[names.map{|name| [normalize_key(name, options), name]}]
|
70
100
|
raw_values = @data.get_multi(keys_to_names.keys, :raw => true)
|
71
101
|
values = {}
|
72
102
|
raw_values.each do |key, value|
|
@@ -83,11 +113,10 @@ module ActiveSupport
|
|
83
113
|
def increment(name, amount = 1, options = nil) # :nodoc:
|
84
114
|
options = merged_options(options)
|
85
115
|
instrument(:increment, name, :amount => amount) do
|
86
|
-
|
116
|
+
rescue_error_with nil do
|
117
|
+
@data.incr(normalize_key(name, options), amount)
|
118
|
+
end
|
87
119
|
end
|
88
|
-
rescue Dalli::DalliError => e
|
89
|
-
logger.error("DalliError (#{e}): #{e.message}") if logger
|
90
|
-
nil
|
91
120
|
end
|
92
121
|
|
93
122
|
# Decrement a cached value. This method uses the memcached decr atomic
|
@@ -97,20 +126,16 @@ module ActiveSupport
|
|
97
126
|
def decrement(name, amount = 1, options = nil) # :nodoc:
|
98
127
|
options = merged_options(options)
|
99
128
|
instrument(:decrement, name, :amount => amount) do
|
100
|
-
|
129
|
+
rescue_error_with nil do
|
130
|
+
@data.decr(normalize_key(name, options), amount)
|
131
|
+
end
|
101
132
|
end
|
102
|
-
rescue Dalli::DalliError => e
|
103
|
-
logger.error("DalliError (#{e}): #{e.message}") if logger
|
104
|
-
nil
|
105
133
|
end
|
106
134
|
|
107
135
|
# Clear the entire cache on all memcached servers. This method should
|
108
136
|
# be used with care when shared cache is being used.
|
109
137
|
def clear(options = nil)
|
110
|
-
@data.flush_all
|
111
|
-
rescue Dalli::DalliError => e
|
112
|
-
logger.error("DalliError (#{e}): #{e.message}") if logger
|
113
|
-
nil
|
138
|
+
rescue_error_with(nil) { @data.flush_all }
|
114
139
|
end
|
115
140
|
|
116
141
|
# Get the statistics from the memcached servers.
|
@@ -121,10 +146,7 @@ module ActiveSupport
|
|
121
146
|
protected
|
122
147
|
# Read an entry from the cache.
|
123
148
|
def read_entry(key, options) # :nodoc:
|
124
|
-
deserialize_entry(@data.get(
|
125
|
-
rescue Dalli::DalliError => e
|
126
|
-
logger.error("DalliError (#{e}): #{e.message}") if logger
|
127
|
-
nil
|
149
|
+
rescue_error_with(nil) { deserialize_entry(@data.get(key, options)) }
|
128
150
|
end
|
129
151
|
|
130
152
|
# Write an entry to the cache.
|
@@ -136,18 +158,14 @@ module ActiveSupport
|
|
136
158
|
# Set the memcache expire a few minutes in the future to support race condition ttls on read
|
137
159
|
expires_in += 5.minutes
|
138
160
|
end
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
false
|
161
|
+
rescue_error_with false do
|
162
|
+
@data.send(method, key, value, expires_in, options)
|
163
|
+
end
|
143
164
|
end
|
144
165
|
|
145
166
|
# Delete an entry from the cache.
|
146
167
|
def delete_entry(key, options) # :nodoc:
|
147
|
-
@data.delete(
|
148
|
-
rescue Dalli::DalliError => e
|
149
|
-
logger.error("DalliError (#{e}): #{e.message}") if logger
|
150
|
-
false
|
168
|
+
rescue_error_with(false) { @data.delete(key) }
|
151
169
|
end
|
152
170
|
|
153
171
|
private
|
@@ -155,44 +173,35 @@ module ActiveSupport
|
|
155
173
|
# Memcache keys are binaries. So we need to force their encoding to binary
|
156
174
|
# before applying the regular expression to ensure we are escaping all
|
157
175
|
# characters properly.
|
158
|
-
def
|
159
|
-
key =
|
176
|
+
def normalize_key(key, options)
|
177
|
+
key = super.dup
|
160
178
|
key = key.force_encoding(Encoding::ASCII_8BIT)
|
161
179
|
key = key.gsub(ESCAPE_KEY_CHARS){ |match| "%#{match.getbyte(0).to_s(16).upcase}" }
|
162
180
|
key = "#{key[0, 213]}:md5:#{Digest::MD5.hexdigest(key)}" if key.size > 250
|
163
181
|
key
|
164
182
|
end
|
165
183
|
|
184
|
+
def escape_key(key)
|
185
|
+
ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
|
186
|
+
`escape_key` is deprecated and will be removed from Rails 5.1.
|
187
|
+
Please use `normalize_key` which will return a fully resolved key or nothing.
|
188
|
+
MESSAGE
|
189
|
+
key
|
190
|
+
end
|
191
|
+
|
166
192
|
def deserialize_entry(raw_value)
|
167
193
|
if raw_value
|
168
194
|
entry = Marshal.load(raw_value) rescue raw_value
|
169
195
|
entry.is_a?(Entry) ? entry : Entry.new(entry)
|
170
|
-
else
|
171
|
-
nil
|
172
196
|
end
|
173
197
|
end
|
174
198
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
entry = deserialize_entry(entry.value)
|
182
|
-
end
|
183
|
-
entry
|
184
|
-
end
|
185
|
-
|
186
|
-
def write_entry(key, entry, options) # :nodoc:
|
187
|
-
retval = super
|
188
|
-
if options[:raw] && local_cache && retval
|
189
|
-
raw_entry = Entry.new(entry.value.to_s)
|
190
|
-
raw_entry.expires_at = entry.expires_at
|
191
|
-
local_cache.write_entry(key, raw_entry, options)
|
192
|
-
end
|
193
|
-
retval
|
194
|
-
end
|
195
|
-
end
|
199
|
+
def rescue_error_with(fallback)
|
200
|
+
yield
|
201
|
+
rescue Dalli::DalliError => e
|
202
|
+
logger.error("DalliError (#{e}): #{e.message}") if logger
|
203
|
+
fallback
|
204
|
+
end
|
196
205
|
end
|
197
206
|
end
|
198
207
|
end
|
@@ -75,30 +75,12 @@ module ActiveSupport
|
|
75
75
|
|
76
76
|
# Increment an integer value in the cache.
|
77
77
|
def increment(name, amount = 1, options = nil)
|
78
|
-
|
79
|
-
options = merged_options(options)
|
80
|
-
if num = read(name, options)
|
81
|
-
num = num.to_i + amount
|
82
|
-
write(name, num, options)
|
83
|
-
num
|
84
|
-
else
|
85
|
-
nil
|
86
|
-
end
|
87
|
-
end
|
78
|
+
modify_value(name, amount, options)
|
88
79
|
end
|
89
80
|
|
90
81
|
# Decrement an integer value in the cache.
|
91
82
|
def decrement(name, amount = 1, options = nil)
|
92
|
-
|
93
|
-
options = merged_options(options)
|
94
|
-
if num = read(name, options)
|
95
|
-
num = num.to_i - amount
|
96
|
-
write(name, num, options)
|
97
|
-
num
|
98
|
-
else
|
99
|
-
nil
|
100
|
-
end
|
101
|
-
end
|
83
|
+
modify_value(name, -amount, options)
|
102
84
|
end
|
103
85
|
|
104
86
|
def delete_matched(matcher, options = nil)
|
@@ -126,7 +108,7 @@ module ActiveSupport
|
|
126
108
|
|
127
109
|
PER_ENTRY_OVERHEAD = 240
|
128
110
|
|
129
|
-
def cached_size(key, entry)
|
111
|
+
def cached_size(key, entry) # :nodoc:
|
130
112
|
key.to_s.bytesize + entry.size + PER_ENTRY_OVERHEAD
|
131
113
|
end
|
132
114
|
|
@@ -167,6 +149,19 @@ module ActiveSupport
|
|
167
149
|
!!entry
|
168
150
|
end
|
169
151
|
end
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
def modify_value(name, amount, options)
|
156
|
+
synchronize do
|
157
|
+
options = merged_options(options)
|
158
|
+
if num = read(name, options)
|
159
|
+
num = num.to_i + amount
|
160
|
+
write(name, num, options)
|
161
|
+
num
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
170
165
|
end
|
171
166
|
end
|
172
167
|
end
|
@@ -8,10 +8,7 @@ module ActiveSupport
|
|
8
8
|
# be cached inside blocks that utilize this strategy. See
|
9
9
|
# ActiveSupport::Cache::Strategy::LocalCache for more details.
|
10
10
|
class NullStore < Store
|
11
|
-
|
12
|
-
super(options)
|
13
|
-
extend Strategy::LocalCache
|
14
|
-
end
|
11
|
+
prepend Strategy::LocalCache
|
15
12
|
|
16
13
|
def clear(options = nil)
|
17
14
|
end
|
@@ -39,7 +39,7 @@ module ActiveSupport
|
|
39
39
|
@data = {}
|
40
40
|
end
|
41
41
|
|
42
|
-
# Don't allow synchronizing since it isn't thread safe
|
42
|
+
# Don't allow synchronizing since it isn't thread safe.
|
43
43
|
def synchronize # :nodoc:
|
44
44
|
yield
|
45
45
|
end
|
@@ -60,6 +60,10 @@ module ActiveSupport
|
|
60
60
|
def delete_entry(key, options)
|
61
61
|
!!@data.delete(key)
|
62
62
|
end
|
63
|
+
|
64
|
+
def fetch_entry(key, options = nil) # :nodoc:
|
65
|
+
@data.fetch(key) { @data[key] = yield }
|
66
|
+
end
|
63
67
|
end
|
64
68
|
|
65
69
|
# Use a local cache for the duration of block.
|
@@ -75,36 +79,35 @@ module ActiveSupport
|
|
75
79
|
end
|
76
80
|
|
77
81
|
def clear(options = nil) # :nodoc:
|
78
|
-
|
82
|
+
return super unless cache = local_cache
|
83
|
+
cache.clear(options)
|
79
84
|
super
|
80
85
|
end
|
81
86
|
|
82
87
|
def cleanup(options = nil) # :nodoc:
|
83
|
-
|
88
|
+
return super unless cache = local_cache
|
89
|
+
cache.clear(options)
|
84
90
|
super
|
85
91
|
end
|
86
92
|
|
87
93
|
def increment(name, amount = 1, options = nil) # :nodoc:
|
94
|
+
return super unless local_cache
|
88
95
|
value = bypass_local_cache{super}
|
89
|
-
|
96
|
+
write_cache_value(name, value, options)
|
90
97
|
value
|
91
98
|
end
|
92
99
|
|
93
100
|
def decrement(name, amount = 1, options = nil) # :nodoc:
|
101
|
+
return super unless local_cache
|
94
102
|
value = bypass_local_cache{super}
|
95
|
-
|
103
|
+
write_cache_value(name, value, options)
|
96
104
|
value
|
97
105
|
end
|
98
106
|
|
99
107
|
protected
|
100
108
|
def read_entry(key, options) # :nodoc:
|
101
|
-
if local_cache
|
102
|
-
|
103
|
-
unless entry
|
104
|
-
entry = super
|
105
|
-
local_cache.write_entry(key, entry, options)
|
106
|
-
end
|
107
|
-
entry
|
109
|
+
if cache = local_cache
|
110
|
+
cache.fetch_entry(key) { super }
|
108
111
|
else
|
109
112
|
super
|
110
113
|
end
|
@@ -120,14 +123,22 @@ module ActiveSupport
|
|
120
123
|
super
|
121
124
|
end
|
122
125
|
|
123
|
-
def set_cache_value(value, name, amount, options)
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
126
|
+
def set_cache_value(value, name, amount, options) # :nodoc:
|
127
|
+
ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
|
128
|
+
`set_cache_value` is deprecated and will be removed from Rails 5.1.
|
129
|
+
Please use `write_cache_value` instead.
|
130
|
+
MESSAGE
|
131
|
+
write_cache_value name, value, options
|
132
|
+
end
|
133
|
+
|
134
|
+
def write_cache_value(name, value, options) # :nodoc:
|
135
|
+
name = normalize_key(name, options)
|
136
|
+
cache = local_cache
|
137
|
+
cache.mute do
|
138
|
+
if value
|
139
|
+
cache.write(name, value, options)
|
140
|
+
else
|
141
|
+
cache.delete(name, options)
|
131
142
|
end
|
132
143
|
end
|
133
144
|
end
|