activesupport 4.0.13 → 4.2.11.3
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 +406 -418
- data/MIT-LICENSE +1 -1
- data/README.rdoc +7 -2
- data/lib/active_support/backtrace_cleaner.rb +8 -8
- data/lib/active_support/benchmarkable.rb +0 -10
- data/lib/active_support/cache/file_store.rb +32 -22
- data/lib/active_support/cache/mem_cache_store.rb +5 -7
- data/lib/active_support/cache/memory_store.rb +1 -0
- data/lib/active_support/cache/strategy/local_cache.rb +11 -30
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +44 -0
- data/lib/active_support/cache.rb +75 -41
- data/lib/active_support/callbacks.rb +482 -261
- data/lib/active_support/concern.rb +23 -7
- data/lib/active_support/configurable.rb +1 -1
- data/lib/active_support/core_ext/array/access.rb +11 -1
- data/lib/active_support/core_ext/array/conversions.rb +2 -17
- data/lib/active_support/core_ext/array/grouping.rb +29 -12
- data/lib/active_support/core_ext/array/prepend_and_append.rb +2 -2
- data/lib/active_support/core_ext/array.rb +0 -1
- data/lib/active_support/core_ext/big_decimal/conversions.rb +0 -15
- data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +16 -0
- data/lib/active_support/core_ext/class/attribute.rb +1 -2
- data/lib/active_support/core_ext/class/attribute_accessors.rb +4 -170
- data/lib/active_support/core_ext/class/delegating_attributes.rb +13 -8
- data/lib/active_support/core_ext/class/subclasses.rb +0 -2
- data/lib/active_support/core_ext/class.rb +0 -1
- data/lib/active_support/core_ext/date/calculations.rb +10 -0
- data/lib/active_support/core_ext/date/conversions.rb +9 -1
- data/lib/active_support/core_ext/date/zones.rb +2 -33
- data/lib/active_support/core_ext/date_and_time/calculations.rb +41 -11
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +41 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +45 -22
- data/lib/active_support/core_ext/date_time/compatibility.rb +16 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +4 -2
- data/lib/active_support/core_ext/date_time/zones.rb +3 -21
- data/lib/active_support/core_ext/date_time.rb +1 -0
- data/lib/active_support/core_ext/digest/uuid.rb +51 -0
- data/lib/active_support/core_ext/enumerable.rb +17 -1
- data/lib/active_support/core_ext/file/atomic.rb +1 -1
- data/lib/active_support/core_ext/hash/compact.rb +24 -0
- data/lib/active_support/core_ext/hash/conversions.rb +9 -8
- data/lib/active_support/core_ext/hash/except.rb +8 -2
- data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -0
- data/lib/active_support/core_ext/hash/keys.rb +25 -19
- data/lib/active_support/core_ext/hash/slice.rb +8 -2
- data/lib/active_support/core_ext/hash/transform_values.rb +23 -0
- data/lib/active_support/core_ext/hash.rb +2 -1
- data/lib/active_support/core_ext/integer/time.rb +0 -15
- data/lib/active_support/core_ext/kernel/concern.rb +10 -0
- data/lib/active_support/core_ext/kernel/debugger.rb +1 -1
- data/lib/active_support/core_ext/kernel/reporting.rb +13 -2
- data/lib/active_support/core_ext/kernel.rb +3 -2
- data/lib/active_support/core_ext/load_error.rb +4 -1
- data/lib/active_support/core_ext/marshal.rb +8 -5
- data/lib/active_support/core_ext/module/aliasing.rb +2 -2
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -1
- data/lib/active_support/core_ext/module/attribute_accessors.rb +160 -14
- data/lib/active_support/core_ext/module/concerning.rb +135 -0
- data/lib/active_support/core_ext/module/delegation.rb +53 -25
- data/lib/active_support/core_ext/module/deprecation.rb +0 -2
- data/lib/active_support/core_ext/module/introspection.rb +0 -16
- data/lib/active_support/core_ext/module/method_transplanting.rb +13 -0
- data/lib/active_support/core_ext/module.rb +1 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +11 -3
- data/lib/active_support/core_ext/numeric/time.rb +4 -29
- data/lib/active_support/core_ext/object/blank.rb +44 -18
- data/lib/active_support/core_ext/object/deep_dup.rb +6 -6
- data/lib/active_support/core_ext/object/duplicable.rb +72 -33
- data/lib/active_support/core_ext/object/inclusion.rb +16 -15
- data/lib/active_support/core_ext/object/itself.rb +15 -0
- data/lib/active_support/core_ext/object/json.rb +197 -0
- data/lib/active_support/core_ext/object/to_query.rb +14 -6
- data/lib/active_support/core_ext/object/try.rb +36 -14
- data/lib/active_support/core_ext/object/with_options.rb +30 -3
- data/lib/active_support/core_ext/object.rb +2 -1
- data/lib/active_support/core_ext/string/access.rb +35 -35
- data/lib/active_support/core_ext/string/conversions.rb +10 -9
- data/lib/active_support/core_ext/string/exclude.rb +3 -3
- data/lib/active_support/core_ext/string/filters.rb +51 -3
- data/lib/active_support/core_ext/string/inflections.rb +15 -10
- data/lib/active_support/core_ext/string/output_safety.rb +97 -33
- data/lib/active_support/core_ext/string/zones.rb +1 -0
- data/lib/active_support/core_ext/thread.rb +12 -5
- data/lib/active_support/core_ext/time/calculations.rb +47 -68
- data/lib/active_support/core_ext/time/compatibility.rb +14 -0
- data/lib/active_support/core_ext/time/conversions.rb +4 -2
- data/lib/active_support/core_ext/time/zones.rb +2 -20
- data/lib/active_support/core_ext/time.rb +1 -0
- data/lib/active_support/core_ext.rb +0 -1
- data/lib/active_support/dependencies/autoload.rb +1 -1
- data/lib/active_support/dependencies.rb +64 -25
- data/lib/active_support/deprecation/behaviors.rb +4 -4
- data/lib/active_support/deprecation.rb +4 -4
- data/lib/active_support/duration.rb +55 -11
- data/lib/active_support/file_update_checker.rb +1 -1
- data/lib/active_support/gem_version.rb +15 -0
- data/lib/active_support/hash_with_indifferent_access.rb +39 -11
- data/lib/active_support/i18n.rb +4 -4
- data/lib/active_support/i18n_railtie.rb +1 -7
- data/lib/active_support/inflections.rb +6 -1
- data/lib/active_support/inflector/inflections.rb +19 -19
- data/lib/active_support/inflector/methods.rb +66 -25
- data/lib/active_support/json/decoding.rb +15 -22
- data/lib/active_support/json/encoding.rb +125 -286
- data/lib/active_support/key_generator.rb +8 -10
- data/lib/active_support/lazy_load_hooks.rb +1 -1
- data/lib/active_support/log_subscriber/test_helper.rb +1 -1
- data/lib/active_support/logger.rb +51 -1
- data/lib/active_support/logger_silence.rb +7 -4
- data/lib/active_support/logger_thread_safe_level.rb +32 -0
- data/lib/active_support/message_encryptor.rb +14 -6
- data/lib/active_support/message_verifier.rb +16 -12
- data/lib/active_support/multibyte/chars.rb +2 -3
- data/lib/active_support/multibyte/unicode.rb +46 -58
- data/lib/active_support/notifications/fanout.rb +12 -7
- data/lib/active_support/notifications/instrumenter.rb +2 -1
- data/lib/active_support/notifications.rb +11 -6
- data/lib/active_support/number_helper/number_converter.rb +182 -0
- data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +23 -0
- data/lib/active_support/number_helper/number_to_human_converter.rb +66 -0
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +58 -0
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +12 -0
- data/lib/active_support/number_helper/number_to_phone_converter.rb +49 -0
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +87 -0
- data/lib/active_support/number_helper.rb +32 -324
- data/lib/active_support/ordered_options.rb +8 -0
- data/lib/active_support/per_thread_registry.rb +13 -10
- data/lib/active_support/security_utils.rb +27 -0
- data/lib/active_support/subscriber.rb +35 -3
- data/lib/active_support/test_case.rb +52 -19
- data/lib/active_support/testing/assertions.rb +1 -31
- data/lib/active_support/testing/autorun.rb +2 -2
- data/lib/active_support/testing/constant_lookup.rb +1 -5
- data/lib/active_support/testing/declarative.rb +7 -21
- data/lib/active_support/testing/isolation.rb +29 -69
- data/lib/active_support/testing/setup_and_teardown.rb +17 -2
- data/lib/active_support/testing/tagged_logging.rb +2 -2
- data/lib/active_support/testing/time_helpers.rb +134 -0
- data/lib/active_support/time.rb +0 -2
- data/lib/active_support/time_with_zone.rb +60 -40
- data/lib/active_support/values/time_zone.rb +101 -101
- data/lib/active_support/values/unicode_tables.dat +0 -0
- data/lib/active_support/version.rb +4 -7
- data/lib/active_support/xml_mini/jdom.rb +6 -5
- data/lib/active_support/xml_mini/libxml.rb +1 -3
- data/lib/active_support/xml_mini/libxmlsax.rb +1 -4
- data/lib/active_support/xml_mini/nokogiri.rb +1 -3
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -3
- data/lib/active_support/xml_mini/rexml.rb +7 -8
- data/lib/active_support/xml_mini.rb +33 -15
- data/lib/active_support.rb +27 -2
- metadata +43 -43
- data/lib/active_support/basic_object.rb +0 -11
- data/lib/active_support/buffered_logger.rb +0 -21
- data/lib/active_support/core_ext/array/uniq_by.rb +0 -19
- data/lib/active_support/core_ext/hash/diff.rb +0 -14
- data/lib/active_support/core_ext/logger.rb +0 -67
- data/lib/active_support/core_ext/object/to_json.rb +0 -27
- data/lib/active_support/core_ext/proc.rb +0 -17
- data/lib/active_support/core_ext/string/encoding.rb +0 -8
- data/lib/active_support/file_watcher.rb +0 -36
- data/lib/active_support/json/variable.rb +0 -18
- data/lib/active_support/testing/pending.rb +0 -14
data/MIT-LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -14,7 +14,7 @@ The latest version of Active Support can be installed with RubyGems:
|
|
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/4-
|
17
|
+
* https://github.com/rails/rails/tree/4-2-stable/activesupport
|
18
18
|
|
19
19
|
|
20
20
|
== License
|
@@ -30,6 +30,11 @@ API documentation is at:
|
|
30
30
|
|
31
31
|
* http://api.rubyonrails.org
|
32
32
|
|
33
|
-
Bug reports
|
33
|
+
Bug reports can be filed for the Ruby on Rails project here:
|
34
34
|
|
35
35
|
* https://github.com/rails/rails/issues
|
36
|
+
|
37
|
+
Feature requests should be discussed on the rails-core mailing list here:
|
38
|
+
|
39
|
+
* https://groups.google.com/forum/?fromgroups#!forum/rubyonrails-core
|
40
|
+
|
@@ -13,17 +13,17 @@ module ActiveSupport
|
|
13
13
|
# can focus on the rest.
|
14
14
|
#
|
15
15
|
# bc = BacktraceCleaner.new
|
16
|
-
# bc.add_filter { |line| line.gsub(Rails.root, '') }
|
17
|
-
# bc.add_silencer { |line| line =~ /mongrel|rubygems/ }
|
18
|
-
# bc.clean(exception.backtrace) #
|
16
|
+
# bc.add_filter { |line| line.gsub(Rails.root.to_s, '') } # strip the Rails.root prefix
|
17
|
+
# bc.add_silencer { |line| line =~ /mongrel|rubygems/ } # skip any lines from mongrel or rubygems
|
18
|
+
# bc.clean(exception.backtrace) # perform the cleanup
|
19
19
|
#
|
20
20
|
# To reconfigure an existing BacktraceCleaner (like the default one in Rails)
|
21
21
|
# and show as much data as possible, you can always call
|
22
22
|
# <tt>BacktraceCleaner#remove_silencers!</tt>, which will restore the
|
23
23
|
# backtrace to a pristine state. If you need to reconfigure an existing
|
24
24
|
# BacktraceCleaner so that it does not filter or modify the paths of any lines
|
25
|
-
# of the backtrace, you can call BacktraceCleaner#remove_filters
|
26
|
-
# methods will give you a completely untouched backtrace.
|
25
|
+
# of the backtrace, you can call <tt>BacktraceCleaner#remove_filters!</tt>
|
26
|
+
# These two methods will give you a completely untouched backtrace.
|
27
27
|
#
|
28
28
|
# Inspired by the Quiet Backtrace gem by Thoughtbot.
|
29
29
|
class BacktraceCleaner
|
@@ -65,14 +65,14 @@ module ActiveSupport
|
|
65
65
|
@silencers << block
|
66
66
|
end
|
67
67
|
|
68
|
-
#
|
69
|
-
#
|
68
|
+
# Removes all silencers, but leaves in the filters. Useful if your
|
69
|
+
# context of debugging suddenly expands as you suspect a bug in one of
|
70
70
|
# the libraries you use.
|
71
71
|
def remove_silencers!
|
72
72
|
@silencers = []
|
73
73
|
end
|
74
74
|
|
75
|
-
# Removes all filters, but leaves in silencers. Useful if you suddenly
|
75
|
+
# Removes all filters, but leaves in the silencers. Useful if you suddenly
|
76
76
|
# need to see entire filepaths in the backtrace that you had already
|
77
77
|
# filtered out.
|
78
78
|
def remove_filters!
|
@@ -45,15 +45,5 @@ module ActiveSupport
|
|
45
45
|
yield
|
46
46
|
end
|
47
47
|
end
|
48
|
-
|
49
|
-
# Silence the logger during the execution of the block.
|
50
|
-
def silence
|
51
|
-
message = "ActiveSupport::Benchmarkable#silence is deprecated. It will be removed from Rails 4.1."
|
52
|
-
ActiveSupport::Deprecation.warn message
|
53
|
-
old_logger_level, logger.level = logger.level, ::Logger::ERROR if logger
|
54
|
-
yield
|
55
|
-
ensure
|
56
|
-
logger.level = old_logger_level if logger
|
57
|
-
end
|
58
48
|
end
|
59
49
|
end
|
@@ -14,6 +14,7 @@ module ActiveSupport
|
|
14
14
|
|
15
15
|
DIR_FORMATTER = "%03X"
|
16
16
|
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
|
+
FILEPATH_MAX_SIZE = 900 # max is 1024, plus some room
|
17
18
|
EXCLUDED_DIRS = ['.', '..'].freeze
|
18
19
|
|
19
20
|
def initialize(cache_path, options = nil)
|
@@ -22,11 +23,15 @@ module ActiveSupport
|
|
22
23
|
extend Strategy::LocalCache
|
23
24
|
end
|
24
25
|
|
26
|
+
# 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
|
+
# config file when using +FileStore+ because everything in that directory will be deleted.
|
25
29
|
def clear(options = nil)
|
26
30
|
root_dirs = Dir.entries(cache_path).reject {|f| (EXCLUDED_DIRS + [".gitkeep"]).include?(f)}
|
27
31
|
FileUtils.rm_r(root_dirs.collect{|f| File.join(cache_path, f)})
|
28
32
|
end
|
29
33
|
|
34
|
+
# Preemptively iterates through all stored keys and removes the ones which have expired.
|
30
35
|
def cleanup(options = nil)
|
31
36
|
options = merged_options(options)
|
32
37
|
search_dir(cache_path) do |fname|
|
@@ -36,32 +41,16 @@ module ActiveSupport
|
|
36
41
|
end
|
37
42
|
end
|
38
43
|
|
44
|
+
# Increments an already existing integer value that is stored in the cache.
|
45
|
+
# If the key is not found nothing is done.
|
39
46
|
def increment(name, amount = 1, options = nil)
|
40
|
-
|
41
|
-
lock_file(file_name) do
|
42
|
-
options = merged_options(options)
|
43
|
-
if num = read(name, options)
|
44
|
-
num = num.to_i + amount
|
45
|
-
write(name, num, options)
|
46
|
-
num
|
47
|
-
else
|
48
|
-
nil
|
49
|
-
end
|
50
|
-
end
|
47
|
+
modify_value(name, amount, options)
|
51
48
|
end
|
52
49
|
|
50
|
+
# Decrements an already existing integer value that is stored in the cache.
|
51
|
+
# If the key is not found nothing is done.
|
53
52
|
def decrement(name, amount = 1, options = nil)
|
54
|
-
|
55
|
-
lock_file(file_name) do
|
56
|
-
options = merged_options(options)
|
57
|
-
if num = read(name, options)
|
58
|
-
num = num.to_i - amount
|
59
|
-
write(name, num, options)
|
60
|
-
num
|
61
|
-
else
|
62
|
-
nil
|
63
|
-
end
|
64
|
-
end
|
53
|
+
modify_value(name, -amount, options)
|
65
54
|
end
|
66
55
|
|
67
56
|
def delete_matched(matcher, options = nil)
|
@@ -89,6 +78,7 @@ module ActiveSupport
|
|
89
78
|
|
90
79
|
def write_entry(key, entry, options)
|
91
80
|
file_name = key_file_path(key)
|
81
|
+
return false if options[:unless_exist] && File.exist?(file_name)
|
92
82
|
ensure_cache_path(File.dirname(file_name))
|
93
83
|
File.atomic_write(file_name, cache_path) {|f| Marshal.dump(entry, f)}
|
94
84
|
true
|
@@ -128,6 +118,10 @@ module ActiveSupport
|
|
128
118
|
|
129
119
|
# Translate a key into a file path.
|
130
120
|
def key_file_path(key)
|
121
|
+
if key.size > FILEPATH_MAX_SIZE
|
122
|
+
key = Digest::MD5.hexdigest(key)
|
123
|
+
end
|
124
|
+
|
131
125
|
fname = URI.encode_www_form_component(key)
|
132
126
|
hash = Zlib.adler32(fname)
|
133
127
|
hash, dir_1 = hash.divmod(0x1000)
|
@@ -175,6 +169,22 @@ module ActiveSupport
|
|
175
169
|
end
|
176
170
|
end
|
177
171
|
end
|
172
|
+
|
173
|
+
# Modifies the amount of an already existing integer value that is stored in the cache.
|
174
|
+
# If the key is not found nothing is done.
|
175
|
+
def modify_value(name, amount, options)
|
176
|
+
file_name = key_file_path(namespaced_key(name, options))
|
177
|
+
|
178
|
+
lock_file(file_name) do
|
179
|
+
options = merged_options(options)
|
180
|
+
|
181
|
+
if num = read(name, options)
|
182
|
+
num = num.to_i + amount
|
183
|
+
write(name, num, options)
|
184
|
+
num
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
178
188
|
end
|
179
189
|
end
|
180
190
|
end
|
@@ -41,17 +41,15 @@ module ActiveSupport
|
|
41
41
|
#
|
42
42
|
# If no addresses are specified, then MemCacheStore will connect to
|
43
43
|
# localhost port 11211 (the default memcached port).
|
44
|
-
#
|
45
|
-
# Instead of addresses one can pass in a MemCache-like object. For example:
|
46
|
-
#
|
47
|
-
# require 'memcached' # gem install memcached; uses C bindings to libmemcached
|
48
|
-
# ActiveSupport::Cache::MemCacheStore.new(Memcached::Rails.new("localhost:11211"))
|
49
44
|
def initialize(*addresses)
|
50
45
|
addresses = addresses.flatten
|
51
46
|
options = addresses.extract_options!
|
52
47
|
super(options)
|
53
48
|
|
54
|
-
|
49
|
+
unless [String, Dalli::Client, NilClass].include?(addresses.first.class)
|
50
|
+
raise ArgumentError, "First argument must be an empty array, an array of hosts or a Dalli::Client instance."
|
51
|
+
end
|
52
|
+
if addresses.first.is_a?(Dalli::Client)
|
55
53
|
@data = addresses.first
|
56
54
|
else
|
57
55
|
mem_cache_options = options.dup
|
@@ -69,7 +67,7 @@ module ActiveSupport
|
|
69
67
|
options = names.extract_options!
|
70
68
|
options = merged_options(options)
|
71
69
|
keys_to_names = Hash[names.map{|name| [escape_key(namespaced_key(name, options)), name]}]
|
72
|
-
raw_values = @data.get_multi(keys_to_names.keys
|
70
|
+
raw_values = @data.get_multi(keys_to_names.keys)
|
73
71
|
values = {}
|
74
72
|
raw_values.each do |key, value|
|
75
73
|
entry = deserialize_entry(value)
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'active_support/core_ext/object/duplicable'
|
2
2
|
require 'active_support/core_ext/string/inflections'
|
3
|
+
require 'active_support/per_thread_registry'
|
3
4
|
|
4
5
|
module ActiveSupport
|
5
6
|
module Cache
|
@@ -8,6 +9,8 @@ module ActiveSupport
|
|
8
9
|
# duration of a block. Repeated calls to the cache for the same key will hit the
|
9
10
|
# in-memory cache for faster access.
|
10
11
|
module LocalCache
|
12
|
+
autoload :Middleware, 'active_support/cache/strategy/local_cache_middleware'
|
13
|
+
|
11
14
|
# Class for storing and registering the local caches.
|
12
15
|
class LocalCacheRegistry # :nodoc:
|
13
16
|
extend ActiveSupport::PerThreadRegistry
|
@@ -23,6 +26,9 @@ module ActiveSupport
|
|
23
26
|
def set_cache_for(local_cache_key, value)
|
24
27
|
@registry[local_cache_key] = value
|
25
28
|
end
|
29
|
+
|
30
|
+
def self.set_cache_for(l, v); instance.set_cache_for l, v; end
|
31
|
+
def self.cache_for(l); instance.cache_for l; end
|
26
32
|
end
|
27
33
|
|
28
34
|
# Simple memory backed cache. This cache is not thread safe and is intended only
|
@@ -60,32 +66,6 @@ module ActiveSupport
|
|
60
66
|
def with_local_cache
|
61
67
|
use_temporary_local_cache(LocalStore.new) { yield }
|
62
68
|
end
|
63
|
-
|
64
|
-
#--
|
65
|
-
# This class wraps up local storage for middlewares. Only the middleware method should
|
66
|
-
# construct them.
|
67
|
-
class Middleware # :nodoc:
|
68
|
-
attr_reader :name, :local_cache_key
|
69
|
-
|
70
|
-
def initialize(name, local_cache_key)
|
71
|
-
@name = name
|
72
|
-
@local_cache_key = local_cache_key
|
73
|
-
@app = nil
|
74
|
-
end
|
75
|
-
|
76
|
-
def new(app)
|
77
|
-
@app = app
|
78
|
-
self
|
79
|
-
end
|
80
|
-
|
81
|
-
def call(env)
|
82
|
-
LocalCacheRegistry.set_cache_for(local_cache_key, LocalStore.new)
|
83
|
-
@app.call(env)
|
84
|
-
ensure
|
85
|
-
LocalCacheRegistry.set_cache_for(local_cache_key, nil)
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
69
|
# Middleware class can be inserted as a Rack handler to be local cache for the
|
90
70
|
# duration of request.
|
91
71
|
def middleware
|
@@ -106,13 +86,13 @@ module ActiveSupport
|
|
106
86
|
|
107
87
|
def increment(name, amount = 1, options = nil) # :nodoc:
|
108
88
|
value = bypass_local_cache{super}
|
109
|
-
|
89
|
+
set_cache_value(value, name, amount, options)
|
110
90
|
value
|
111
91
|
end
|
112
92
|
|
113
93
|
def decrement(name, amount = 1, options = nil) # :nodoc:
|
114
94
|
value = bypass_local_cache{super}
|
115
|
-
|
95
|
+
set_cache_value(value, name, amount, options)
|
116
96
|
value
|
117
97
|
end
|
118
98
|
|
@@ -140,8 +120,7 @@ module ActiveSupport
|
|
140
120
|
super
|
141
121
|
end
|
142
122
|
|
143
|
-
|
144
|
-
def increment_or_decrement(value, name, amount, options)
|
123
|
+
def set_cache_value(value, name, amount, options)
|
145
124
|
if local_cache
|
146
125
|
local_cache.mute do
|
147
126
|
if value
|
@@ -153,6 +132,8 @@ module ActiveSupport
|
|
153
132
|
end
|
154
133
|
end
|
155
134
|
|
135
|
+
private
|
136
|
+
|
156
137
|
def local_cache_key
|
157
138
|
@local_cache_key ||= "#{self.class.name.underscore}_local_cache_#{object_id}".gsub(/[\/-]/, '_').to_sym
|
158
139
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rack/body_proxy'
|
2
|
+
require 'rack/utils'
|
3
|
+
|
4
|
+
module ActiveSupport
|
5
|
+
module Cache
|
6
|
+
module Strategy
|
7
|
+
module LocalCache
|
8
|
+
|
9
|
+
#--
|
10
|
+
# This class wraps up local storage for middlewares. Only the middleware method should
|
11
|
+
# construct them.
|
12
|
+
class Middleware # :nodoc:
|
13
|
+
attr_reader :name, :local_cache_key
|
14
|
+
|
15
|
+
def initialize(name, local_cache_key)
|
16
|
+
@name = name
|
17
|
+
@local_cache_key = local_cache_key
|
18
|
+
@app = nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def new(app)
|
22
|
+
@app = app
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def call(env)
|
27
|
+
LocalCacheRegistry.set_cache_for(local_cache_key, LocalStore.new)
|
28
|
+
response = @app.call(env)
|
29
|
+
response[2] = ::Rack::BodyProxy.new(response[2]) do
|
30
|
+
LocalCacheRegistry.set_cache_for(local_cache_key, nil)
|
31
|
+
end
|
32
|
+
response
|
33
|
+
rescue Rack::Utils::InvalidParameterError
|
34
|
+
LocalCacheRegistry.set_cache_for(local_cache_key, nil)
|
35
|
+
[400, {}, []]
|
36
|
+
rescue Exception
|
37
|
+
LocalCacheRegistry.set_cache_for(local_cache_key, nil)
|
38
|
+
raise
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/active_support/cache.rb
CHANGED
@@ -3,19 +3,20 @@ require 'zlib'
|
|
3
3
|
require 'active_support/core_ext/array/extract_options'
|
4
4
|
require 'active_support/core_ext/array/wrap'
|
5
5
|
require 'active_support/core_ext/benchmark'
|
6
|
-
require 'active_support/core_ext/
|
6
|
+
require 'active_support/core_ext/module/attribute_accessors'
|
7
7
|
require 'active_support/core_ext/numeric/bytes'
|
8
8
|
require 'active_support/core_ext/numeric/time'
|
9
9
|
require 'active_support/core_ext/object/to_param'
|
10
10
|
require 'active_support/core_ext/string/inflections'
|
11
|
+
require 'active_support/deprecation'
|
11
12
|
|
12
13
|
module ActiveSupport
|
13
14
|
# See ActiveSupport::Cache::Store for documentation.
|
14
15
|
module Cache
|
15
|
-
autoload :FileStore,
|
16
|
-
autoload :MemoryStore,
|
16
|
+
autoload :FileStore, 'active_support/cache/file_store'
|
17
|
+
autoload :MemoryStore, 'active_support/cache/memory_store'
|
17
18
|
autoload :MemCacheStore, 'active_support/cache/mem_cache_store'
|
18
|
-
autoload :NullStore,
|
19
|
+
autoload :NullStore, 'active_support/cache/null_store'
|
19
20
|
|
20
21
|
# These options mean something to all cache implementations. Individual cache
|
21
22
|
# implementations may support additional options.
|
@@ -26,7 +27,7 @@ module ActiveSupport
|
|
26
27
|
end
|
27
28
|
|
28
29
|
class << self
|
29
|
-
# Creates a new
|
30
|
+
# Creates a new Store object according to the given options.
|
30
31
|
#
|
31
32
|
# If no arguments are passed to this method, then a new
|
32
33
|
# ActiveSupport::Cache::MemoryStore object will be returned.
|
@@ -88,25 +89,24 @@ module ActiveSupport
|
|
88
89
|
end
|
89
90
|
|
90
91
|
private
|
92
|
+
def retrieve_cache_key(key)
|
93
|
+
case
|
94
|
+
when key.respond_to?(:cache_key) then key.cache_key
|
95
|
+
when key.is_a?(Array) then key.map { |element| retrieve_cache_key(element) }.to_param
|
96
|
+
when key.respond_to?(:to_a) then retrieve_cache_key(key.to_a)
|
97
|
+
else key.to_param
|
98
|
+
end.to_s
|
99
|
+
end
|
91
100
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
# Obtains the specified cache store class, given the name of the +store+.
|
102
|
-
# Raises an error when the store class cannot be found.
|
103
|
-
def retrieve_store_class(store)
|
104
|
-
require "active_support/cache/#{store}"
|
105
|
-
rescue LoadError => e
|
106
|
-
raise "Could not find cache store adapter for #{store} (#{e})"
|
107
|
-
else
|
108
|
-
ActiveSupport::Cache.const_get(store.to_s.camelize)
|
109
|
-
end
|
101
|
+
# Obtains the specified cache store class, given the name of the +store+.
|
102
|
+
# Raises an error when the store class cannot be found.
|
103
|
+
def retrieve_store_class(store)
|
104
|
+
require "active_support/cache/#{store}"
|
105
|
+
rescue LoadError => e
|
106
|
+
raise "Could not find cache store adapter for #{store} (#{e})"
|
107
|
+
else
|
108
|
+
ActiveSupport::Cache.const_get(store.to_s.camelize)
|
109
|
+
end
|
110
110
|
end
|
111
111
|
|
112
112
|
# An abstract cache store class. There are multiple cache store
|
@@ -153,7 +153,6 @@ module ActiveSupport
|
|
153
153
|
# or +write+. To specify the threshold at which to compress values, set the
|
154
154
|
# <tt>:compress_threshold</tt> option. The default threshold is 16K.
|
155
155
|
class Store
|
156
|
-
|
157
156
|
cattr_accessor :logger, :instance_writer => true
|
158
157
|
|
159
158
|
attr_reader :silence, :options
|
@@ -180,14 +179,16 @@ module ActiveSupport
|
|
180
179
|
@silence = previous_silence
|
181
180
|
end
|
182
181
|
|
183
|
-
#
|
184
|
-
# Default is +false+.
|
182
|
+
# :deprecated:
|
185
183
|
def self.instrument=(boolean)
|
186
|
-
|
184
|
+
ActiveSupport::Deprecation.warn "ActiveSupport::Cache.instrument= is deprecated and will be removed in Rails 5. Instrumentation is now always on so you can safely stop using it."
|
185
|
+
true
|
187
186
|
end
|
188
187
|
|
188
|
+
# :deprecated:
|
189
189
|
def self.instrument
|
190
|
-
|
190
|
+
ActiveSupport::Deprecation.warn "ActiveSupport::Cache.instrument is deprecated and will be removed in Rails 5. Instrumentation is now always on so you can safely stop using it."
|
191
|
+
true
|
191
192
|
end
|
192
193
|
|
193
194
|
# Fetches data from the cache, using the given key. If there is data in
|
@@ -228,7 +229,7 @@ module ActiveSupport
|
|
228
229
|
#
|
229
230
|
# Setting <tt>:race_condition_ttl</tt> is very useful in situations where
|
230
231
|
# a cache entry is used very frequently and is under heavy load. If a
|
231
|
-
# cache expires and due to heavy load
|
232
|
+
# cache expires and due to heavy load several different processes will try
|
232
233
|
# to read data natively and then they all will try to write to cache. To
|
233
234
|
# avoid that case the first process to find an expired cache entry will
|
234
235
|
# bump the cache expiration time by the value set in <tt>:race_condition_ttl</tt>.
|
@@ -236,7 +237,7 @@ module ActiveSupport
|
|
236
237
|
# seconds. Because of extended life of the previous cache, other processes
|
237
238
|
# will continue to use slightly stale data for a just a bit longer. In the
|
238
239
|
# meantime that first process will go ahead and will write into cache the
|
239
|
-
# new value. After that all the processes will start getting new value.
|
240
|
+
# new value. After that all the processes will start getting the new value.
|
240
241
|
# The key is to keep <tt>:race_condition_ttl</tt> small.
|
241
242
|
#
|
242
243
|
# If the process regenerating the entry errors out, the entry will be
|
@@ -352,11 +353,39 @@ module ActiveSupport
|
|
352
353
|
results
|
353
354
|
end
|
354
355
|
|
356
|
+
# Fetches data from the cache, using the given keys. If there is data in
|
357
|
+
# the cache with the given keys, then that data is returned. Otherwise,
|
358
|
+
# the supplied block is called for each key for which there was no data,
|
359
|
+
# and the result will be written to the cache and returned.
|
360
|
+
#
|
361
|
+
# Options are passed to the underlying cache implementation.
|
362
|
+
#
|
363
|
+
# Returns a hash with the data for each of the names. For example:
|
364
|
+
#
|
365
|
+
# cache.write("bim", "bam")
|
366
|
+
# cache.fetch_multi("bim", "boom") { |key| key * 2 }
|
367
|
+
# # => { "bam" => "bam", "boom" => "boomboom" }
|
368
|
+
#
|
369
|
+
def fetch_multi(*names)
|
370
|
+
options = names.extract_options!
|
371
|
+
options = merged_options(options)
|
372
|
+
results = read_multi(*names, options)
|
373
|
+
|
374
|
+
names.each_with_object({}) do |name, memo|
|
375
|
+
memo[name] = results.fetch(name) do
|
376
|
+
value = yield name
|
377
|
+
write(name, value, options)
|
378
|
+
value
|
379
|
+
end
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
355
383
|
# Writes the value to the cache, with the key.
|
356
384
|
#
|
357
385
|
# Options are passed to the underlying cache implementation.
|
358
386
|
def write(name, value, options = nil)
|
359
387
|
options = merged_options(options)
|
388
|
+
|
360
389
|
instrument(:write, name, options) do
|
361
390
|
entry = Entry.new(value, options)
|
362
391
|
write_entry(namespaced_key(name, options), entry, options)
|
@@ -368,19 +397,21 @@ module ActiveSupport
|
|
368
397
|
# Options are passed to the underlying cache implementation.
|
369
398
|
def delete(name, options = nil)
|
370
399
|
options = merged_options(options)
|
400
|
+
|
371
401
|
instrument(:delete, name) do
|
372
402
|
delete_entry(namespaced_key(name, options), options)
|
373
403
|
end
|
374
404
|
end
|
375
405
|
|
376
|
-
#
|
406
|
+
# Returns +true+ if the cache contains an entry for the given key.
|
377
407
|
#
|
378
408
|
# Options are passed to the underlying cache implementation.
|
379
409
|
def exist?(name, options = nil)
|
380
410
|
options = merged_options(options)
|
411
|
+
|
381
412
|
instrument(:exist?, name) do
|
382
413
|
entry = read_entry(namespaced_key(name, options), options)
|
383
|
-
entry && !entry.expired?
|
414
|
+
(entry && !entry.expired?) || false
|
384
415
|
end
|
385
416
|
end
|
386
417
|
|
@@ -423,7 +454,7 @@ module ActiveSupport
|
|
423
454
|
# Clear the entire cache. Be careful with this method since it could
|
424
455
|
# affect other processes if shared cache is being used.
|
425
456
|
#
|
426
|
-
#
|
457
|
+
# The options hash is passed to the underlying cache implementation.
|
427
458
|
#
|
428
459
|
# All implementations may not support this method.
|
429
460
|
def clear(options = nil)
|
@@ -511,13 +542,9 @@ module ActiveSupport
|
|
511
542
|
def instrument(operation, key, options = nil)
|
512
543
|
log(operation, key, options)
|
513
544
|
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
ActiveSupport::Notifications.instrument("cache_#{operation}.active_support", payload){ yield(payload) }
|
518
|
-
else
|
519
|
-
yield(nil)
|
520
|
-
end
|
545
|
+
payload = { :key => key }
|
546
|
+
payload.merge!(options) if options.is_a?(Hash)
|
547
|
+
ActiveSupport::Notifications.instrument("cache_#{operation}.active_support", payload){ yield(payload) }
|
521
548
|
end
|
522
549
|
|
523
550
|
def log(operation, key, options = nil)
|
@@ -535,7 +562,7 @@ module ActiveSupport
|
|
535
562
|
def handle_expired_entry(entry, key, options)
|
536
563
|
if entry && entry.expired?
|
537
564
|
race_ttl = options[:race_condition_ttl].to_i
|
538
|
-
if race_ttl && (Time.now.to_f - entry.expires_at <= race_ttl)
|
565
|
+
if (race_ttl > 0) && (Time.now.to_f - entry.expires_at <= race_ttl)
|
539
566
|
# When an entry has :race_condition_ttl defined, put the stale entry back into the cache
|
540
567
|
# for a brief period while the entry is begin recalculated.
|
541
568
|
entry.expires_at = Time.now + race_ttl
|
@@ -557,6 +584,7 @@ module ActiveSupport
|
|
557
584
|
result = instrument(:generate, name, options) do |payload|
|
558
585
|
yield(name)
|
559
586
|
end
|
587
|
+
|
560
588
|
write(name, result, options)
|
561
589
|
result
|
562
590
|
end
|
@@ -580,6 +608,7 @@ module ActiveSupport
|
|
580
608
|
else
|
581
609
|
@value = value
|
582
610
|
end
|
611
|
+
|
583
612
|
@created_at = Time.now.to_f
|
584
613
|
@expires_in = options[:expires_in]
|
585
614
|
@expires_in = @expires_in.to_f if @expires_in
|
@@ -630,6 +659,7 @@ module ActiveSupport
|
|
630
659
|
# serialize entries to protect against accidental cache modifications.
|
631
660
|
def dup_value!
|
632
661
|
convert_version_4beta1_entry! if defined?(@v)
|
662
|
+
|
633
663
|
if @value && !compressed? && !(@value.is_a?(Numeric) || @value == true || @value == false)
|
634
664
|
if @value.is_a?(String)
|
635
665
|
@value = @value.dup
|
@@ -644,8 +674,10 @@ module ActiveSupport
|
|
644
674
|
if value && options[:compress]
|
645
675
|
compress_threshold = options[:compress_threshold] || DEFAULT_COMPRESS_LIMIT
|
646
676
|
serialized_value_size = (value.is_a?(String) ? value : Marshal.dump(value)).bytesize
|
677
|
+
|
647
678
|
return true if serialized_value_size >= compress_threshold
|
648
679
|
end
|
680
|
+
|
649
681
|
false
|
650
682
|
end
|
651
683
|
|
@@ -668,10 +700,12 @@ module ActiveSupport
|
|
668
700
|
@value = @v
|
669
701
|
remove_instance_variable(:@v)
|
670
702
|
end
|
703
|
+
|
671
704
|
if defined?(@c)
|
672
705
|
@compressed = @c
|
673
706
|
remove_instance_variable(:@c)
|
674
707
|
end
|
708
|
+
|
675
709
|
if defined?(@x) && @x
|
676
710
|
@created_at ||= Time.now.to_f
|
677
711
|
@expires_in = @x - @created_at
|