activesupport 3.0.0.beta3 → 3.0.0.beta4
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.
- data/CHANGELOG +57 -0
- data/lib/active_support/builder.rb +6 -0
- data/lib/active_support/cache.rb +428 -70
- data/lib/active_support/cache/compressed_mem_cache_store.rb +6 -15
- data/lib/active_support/cache/file_store.rb +139 -41
- data/lib/active_support/cache/mem_cache_store.rb +115 -76
- data/lib/active_support/cache/memory_store.rb +127 -27
- data/lib/active_support/cache/strategy/local_cache.rb +109 -57
- data/lib/active_support/cache/synchronized_memory_store.rb +2 -38
- data/lib/active_support/callbacks.rb +27 -27
- data/lib/active_support/configurable.rb +19 -18
- data/lib/active_support/core_ext/array/conversions.rb +30 -26
- data/lib/active_support/core_ext/array/random_access.rb +19 -5
- data/lib/active_support/core_ext/benchmark.rb +0 -12
- data/lib/active_support/core_ext/class/attribute.rb +1 -4
- data/lib/active_support/core_ext/class/inheritable_attributes.rb +3 -0
- data/lib/active_support/core_ext/date/calculations.rb +27 -8
- data/lib/active_support/core_ext/date/conversions.rb +1 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +9 -3
- data/lib/active_support/core_ext/file.rb +1 -0
- data/lib/active_support/core_ext/hash/conversions.rb +14 -137
- data/lib/active_support/core_ext/kernel/debugger.rb +1 -1
- data/lib/active_support/core_ext/kernel/reporting.rb +2 -1
- data/lib/active_support/core_ext/load_error.rb +1 -0
- data/lib/active_support/core_ext/logger.rb +1 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
- data/lib/active_support/core_ext/object/to_param.rb +2 -2
- data/lib/active_support/core_ext/object/with_options.rb +2 -0
- data/lib/active_support/core_ext/string.rb +1 -0
- data/lib/active_support/core_ext/string/conversions.rb +35 -1
- data/lib/active_support/core_ext/string/encoding.rb +11 -0
- data/lib/active_support/core_ext/string/filters.rb +29 -0
- data/lib/active_support/core_ext/string/inflections.rb +0 -11
- data/lib/active_support/core_ext/string/interpolation.rb +1 -0
- data/lib/active_support/core_ext/string/multibyte.rb +16 -19
- data/lib/active_support/core_ext/time/calculations.rb +7 -6
- data/lib/active_support/core_ext/uri.rb +8 -3
- data/lib/active_support/dependencies.rb +33 -1
- data/lib/active_support/duration.rb +1 -0
- data/lib/active_support/hash_with_indifferent_access.rb +5 -1
- data/lib/active_support/i18n.rb +7 -2
- data/lib/active_support/inflector/transliterate.rb +58 -38
- data/lib/active_support/json/encoding.rb +28 -5
- data/lib/active_support/lazy_load_hooks.rb +14 -4
- data/lib/active_support/locale/en.yml +4 -1
- data/lib/active_support/message_verifier.rb +4 -4
- data/lib/active_support/multibyte.rb +1 -19
- data/lib/active_support/multibyte/chars.rb +143 -427
- data/lib/active_support/multibyte/unicode.rb +393 -0
- data/lib/active_support/notifications/fanout.rb +15 -5
- data/lib/active_support/notifications/instrumenter.rb +10 -4
- data/lib/active_support/railtie.rb +36 -0
- data/lib/active_support/rescuable.rb +1 -0
- data/lib/active_support/ruby/shim.rb +1 -0
- data/lib/active_support/testing/declarative.rb +1 -1
- data/lib/active_support/testing/isolation.rb +2 -1
- data/lib/active_support/testing/setup_and_teardown.rb +3 -0
- data/lib/active_support/values/time_zone.rb +20 -30
- data/lib/active_support/values/unicode_tables.dat +0 -0
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini.rb +126 -1
- metadata +8 -61
- data/lib/active_support/multibyte/unicode_database.rb +0 -71
@@ -1,21 +1,12 @@
|
|
1
|
-
require 'active_support/gzip'
|
2
|
-
|
3
1
|
module ActiveSupport
|
4
2
|
module Cache
|
5
3
|
class CompressedMemCacheStore < MemCacheStore
|
6
|
-
def
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def write(name, value, options = nil)
|
17
|
-
value = ActiveSupport::Gzip.compress(Marshal.dump(value)) unless raw?(options)
|
18
|
-
super(name, value, (options || {}).merge(:raw => true))
|
4
|
+
def initialize(*args)
|
5
|
+
ActiveSupport::Deprecation.warn('ActiveSupport::Cache::CompressedMemCacheStore has been deprecated in favor of ActiveSupport::Cache::MemCacheStore(:compress => true).', caller)
|
6
|
+
addresses = args.dup
|
7
|
+
options = addresses.extract_options!
|
8
|
+
args = addresses + [options.merge(:compress => true)]
|
9
|
+
super(*args)
|
19
10
|
end
|
20
11
|
end
|
21
12
|
end
|
@@ -3,73 +3,171 @@ require 'active_support/core_ext/file/atomic'
|
|
3
3
|
module ActiveSupport
|
4
4
|
module Cache
|
5
5
|
# A cache store implementation which stores everything on the filesystem.
|
6
|
+
#
|
7
|
+
# FileStore implements the Strategy::LocalCache strategy which implements
|
8
|
+
# an in memory cache inside of a block.
|
6
9
|
class FileStore < Store
|
7
10
|
attr_reader :cache_path
|
8
11
|
|
9
|
-
|
12
|
+
DIR_FORMATTER = "%03X"
|
13
|
+
ESCAPE_FILENAME_CHARS = /[^a-z0-9_.-]/i
|
14
|
+
UNESCAPE_FILENAME_CHARS = /%[0-9A-F]{2}/
|
15
|
+
|
16
|
+
def initialize(cache_path, options = nil)
|
17
|
+
super(options)
|
10
18
|
@cache_path = cache_path
|
19
|
+
extend Strategy::LocalCache
|
11
20
|
end
|
12
21
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
def
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
if File.exist?(file_name) && (expires <= 0 || Time.now - File.mtime(file_name) < expires)
|
24
|
-
File.open(file_name, 'rb') { |f| Marshal.load(f) }
|
25
|
-
end
|
22
|
+
def clear(options = nil)
|
23
|
+
root_dirs = Dir.entries(cache_path).reject{|f| ['.', '..'].include?(f)}
|
24
|
+
FileUtils.rm_r(root_dirs.collect{|f| File.join(cache_path, f)})
|
25
|
+
end
|
26
|
+
|
27
|
+
def cleanup(options = nil)
|
28
|
+
options = merged_options(options)
|
29
|
+
each_key(options) do |key|
|
30
|
+
entry = read_entry(key, options)
|
31
|
+
delete_entry(key, options) if entry && entry.expired?
|
26
32
|
end
|
27
33
|
end
|
28
34
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
+
def increment(name, amount = 1, options = nil)
|
36
|
+
file_name = key_file_path(namespaced_key(name, options))
|
37
|
+
lock_file(file_name) do
|
38
|
+
options = merged_options(options)
|
39
|
+
if num = read(name, options)
|
40
|
+
num = num.to_i + amount
|
41
|
+
write(name, num, options)
|
42
|
+
num
|
43
|
+
else
|
44
|
+
nil
|
45
|
+
end
|
35
46
|
end
|
36
|
-
rescue => e
|
37
|
-
logger.error "Couldn't create cache directory: #{name} (#{e.message})" if logger
|
38
47
|
end
|
39
48
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
49
|
+
def decrement(name, amount = 1, options = nil)
|
50
|
+
file_name = key_file_path(namespaced_key(name, options))
|
51
|
+
lock_file(file_name) do
|
52
|
+
options = merged_options(options)
|
53
|
+
if num = read(name, options)
|
54
|
+
num = num.to_i - amount
|
55
|
+
write(name, num, options)
|
56
|
+
num
|
57
|
+
else
|
58
|
+
nil
|
59
|
+
end
|
43
60
|
end
|
44
|
-
rescue SystemCallError => e
|
45
|
-
# If there's no cache, then there's nothing to complain about
|
46
61
|
end
|
47
62
|
|
48
63
|
def delete_matched(matcher, options = nil)
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
64
|
+
options = merged_options(options)
|
65
|
+
instrument(:delete_matched, matcher.inspect) do
|
66
|
+
matcher = key_matcher(matcher, options)
|
67
|
+
search_dir(cache_path) do |path|
|
68
|
+
key = file_path_key(path)
|
69
|
+
delete_entry(key, options) if key.match(matcher)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
protected
|
75
|
+
|
76
|
+
def read_entry(key, options)
|
77
|
+
file_name = key_file_path(key)
|
78
|
+
if File.exist?(file_name)
|
79
|
+
entry = File.open(file_name) { |f| Marshal.load(f) }
|
80
|
+
if entry && !entry.expired? && !entry.expires_in && !self.options[:expires_in]
|
81
|
+
# Check for deprecated use of +:expires_in+ option from versions < 3.0
|
82
|
+
deprecated_expires_in = options[:expires_in]
|
83
|
+
if deprecated_expires_in
|
84
|
+
ActiveSupport::Deprecation.warn('Setting :expires_in on read has been deprecated in favor of setting it on write.', caller)
|
85
|
+
if entry.created_at + deprecated_expires_in.to_f <= Time.now.to_f
|
86
|
+
delete_entry(key, options)
|
87
|
+
entry = nil
|
88
|
+
end
|
56
89
|
end
|
57
90
|
end
|
91
|
+
entry
|
58
92
|
end
|
93
|
+
rescue
|
94
|
+
nil
|
59
95
|
end
|
60
|
-
end
|
61
96
|
|
62
|
-
|
63
|
-
|
64
|
-
File.
|
97
|
+
def write_entry(key, entry, options)
|
98
|
+
file_name = key_file_path(key)
|
99
|
+
ensure_cache_path(File.dirname(file_name))
|
100
|
+
File.atomic_write(file_name, cache_path) {|f| Marshal.dump(entry, f)}
|
101
|
+
true
|
102
|
+
end
|
103
|
+
|
104
|
+
def delete_entry(key, options)
|
105
|
+
file_name = key_file_path(key)
|
106
|
+
if File.exist?(file_name)
|
107
|
+
begin
|
108
|
+
File.delete(file_name)
|
109
|
+
delete_empty_directories(File.dirname(file_name))
|
110
|
+
true
|
111
|
+
rescue => e
|
112
|
+
# Just in case the error was caused by another process deleting the file first.
|
113
|
+
raise e if File.exist?(file_name)
|
114
|
+
false
|
115
|
+
end
|
116
|
+
end
|
65
117
|
end
|
66
|
-
end
|
67
118
|
|
68
119
|
private
|
69
|
-
|
70
|
-
|
120
|
+
# Lock a file for a block so only one process can modify it at a time.
|
121
|
+
def lock_file(file_name, &block) # :nodoc:
|
122
|
+
if File.exist?(file_name)
|
123
|
+
File.open(file_name, 'r') do |f|
|
124
|
+
begin
|
125
|
+
f.flock File::LOCK_EX
|
126
|
+
yield
|
127
|
+
ensure
|
128
|
+
f.flock File::LOCK_UN
|
129
|
+
end
|
130
|
+
end
|
131
|
+
else
|
132
|
+
yield
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Translate a key into a file path.
|
137
|
+
def key_file_path(key)
|
138
|
+
fname = key.to_s.gsub(ESCAPE_FILENAME_CHARS){|match| "%#{match.ord.to_s(16).upcase}"}
|
139
|
+
hash = Zlib.adler32(fname)
|
140
|
+
hash, dir_1 = hash.divmod(0x1000)
|
141
|
+
dir_2 = hash.modulo(0x1000)
|
142
|
+
fname_paths = []
|
143
|
+
# Make sure file name is < 255 characters so it doesn't exceed file system limits.
|
144
|
+
if fname.size <= 255
|
145
|
+
fname_paths << fname
|
146
|
+
else
|
147
|
+
while fname.size <= 255
|
148
|
+
fname_path << fname[0, 255]
|
149
|
+
fname = fname[255, -1]
|
150
|
+
end
|
151
|
+
end
|
152
|
+
File.join(cache_path, DIR_FORMATTER % dir_1, DIR_FORMATTER % dir_2, *fname_paths)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Translate a file path into a key.
|
156
|
+
def file_path_key(path)
|
157
|
+
fname = path[cache_path.size, path.size].split(File::SEPARATOR, 4).last
|
158
|
+
fname.gsub(UNESCAPE_FILENAME_CHARS){|match| $1.ord.to_s(16)}
|
159
|
+
end
|
160
|
+
|
161
|
+
# Delete empty directories in the cache.
|
162
|
+
def delete_empty_directories(dir)
|
163
|
+
return if dir == cache_path
|
164
|
+
if Dir.entries(dir).reject{|f| ['.', '..'].include?(f)}.empty?
|
165
|
+
File.delete(dir) rescue nil
|
166
|
+
delete_empty_directories(File.dirname(dir))
|
167
|
+
end
|
71
168
|
end
|
72
169
|
|
170
|
+
# Make sure a file path's directories exist.
|
73
171
|
def ensure_cache_path(path)
|
74
172
|
FileUtils.makedirs(path) unless File.exist?(path)
|
75
173
|
end
|
@@ -1,5 +1,10 @@
|
|
1
|
-
|
2
|
-
require '
|
1
|
+
begin
|
2
|
+
require 'memcache'
|
3
|
+
rescue LoadError => e
|
4
|
+
$stderr.puts "You don't have memcache installed in your application. Please add it to your Gemfile and run bundle install"
|
5
|
+
raise e
|
6
|
+
end
|
7
|
+
require 'digest/md5'
|
3
8
|
|
4
9
|
module ActiveSupport
|
5
10
|
module Cache
|
@@ -13,8 +18,9 @@ module ActiveSupport
|
|
13
18
|
# and MemCacheStore will load balance between all available servers. If a
|
14
19
|
# server goes down, then MemCacheStore will ignore it until it goes back
|
15
20
|
# online.
|
16
|
-
#
|
17
|
-
#
|
21
|
+
#
|
22
|
+
# MemCacheStore implements the Strategy::LocalCache strategy which implements
|
23
|
+
# an in memory cache inside of a block.
|
18
24
|
class MemCacheStore < Store
|
19
25
|
module Response # :nodoc:
|
20
26
|
STORED = "STORED\r\n"
|
@@ -24,6 +30,8 @@ module ActiveSupport
|
|
24
30
|
DELETED = "DELETED\r\n"
|
25
31
|
end
|
26
32
|
|
33
|
+
ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/
|
34
|
+
|
27
35
|
def self.build_mem_cache(*addresses)
|
28
36
|
addresses = addresses.flatten
|
29
37
|
options = addresses.extract_options!
|
@@ -45,108 +53,139 @@ module ActiveSupport
|
|
45
53
|
# require 'memcached' # gem install memcached; uses C bindings to libmemcached
|
46
54
|
# ActiveSupport::Cache::MemCacheStore.new(Memcached::Rails.new("localhost:11211"))
|
47
55
|
def initialize(*addresses)
|
56
|
+
addresses = addresses.flatten
|
57
|
+
options = addresses.extract_options!
|
58
|
+
super(options)
|
59
|
+
|
48
60
|
if addresses.first.respond_to?(:get)
|
49
61
|
@data = addresses.first
|
50
62
|
else
|
51
|
-
|
63
|
+
mem_cache_options = options.dup
|
64
|
+
UNIVERSAL_OPTIONS.each{|name| mem_cache_options.delete(name)}
|
65
|
+
@data = self.class.build_mem_cache(*(addresses + [mem_cache_options]))
|
52
66
|
end
|
53
67
|
|
54
68
|
extend Strategy::LocalCache
|
69
|
+
extend LocalCacheWithRaw
|
55
70
|
end
|
56
71
|
|
57
|
-
# Reads multiple keys from the cache
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
nil
|
69
|
-
end
|
70
|
-
|
71
|
-
# Writes a value to the cache.
|
72
|
-
#
|
73
|
-
# Possible options:
|
74
|
-
# - <tt>:unless_exist</tt> - set to true if you don't want to update the cache
|
75
|
-
# if the key is already set.
|
76
|
-
# - <tt>:expires_in</tt> - the number of seconds that this value may stay in
|
77
|
-
# the cache. See ActiveSupport::Cache::Store#write for an example.
|
78
|
-
def write(key, value, options = nil)
|
79
|
-
super do
|
80
|
-
method = options && options[:unless_exist] ? :add : :set
|
81
|
-
# memcache-client will break the connection if you send it an integer
|
82
|
-
# in raw mode, so we convert it to a string to be sure it continues working.
|
83
|
-
value = value.to_s if raw?(options)
|
84
|
-
response = @data.send(method, key, value, expires_in(options), raw?(options))
|
85
|
-
response == Response::STORED
|
86
|
-
end
|
87
|
-
rescue MemCache::MemCacheError => e
|
88
|
-
logger.error("MemCacheError (#{e}): #{e.message}") if logger
|
89
|
-
false
|
90
|
-
end
|
91
|
-
|
92
|
-
def delete(key, options = nil) # :nodoc:
|
93
|
-
super do
|
94
|
-
response = @data.delete(key)
|
95
|
-
response == Response::DELETED
|
72
|
+
# Reads multiple keys from the cache using a single call to the
|
73
|
+
# servers for all keys. Options can be passed in the last argument.
|
74
|
+
def read_multi(*names)
|
75
|
+
options = names.extract_options!
|
76
|
+
options = merged_options(options)
|
77
|
+
keys_to_names = names.inject({}){|map, name| map[escape_key(namespaced_key(name, options))] = name; map}
|
78
|
+
raw_values = @data.get_multi(keys_to_names.keys, :raw => true)
|
79
|
+
values = {}
|
80
|
+
raw_values.each do |key, value|
|
81
|
+
entry = deserialize_entry(value)
|
82
|
+
values[keys_to_names[key]] = entry.value unless entry.expired?
|
96
83
|
end
|
97
|
-
|
98
|
-
logger.error("MemCacheError (#{e}): #{e.message}") if logger
|
99
|
-
false
|
84
|
+
values
|
100
85
|
end
|
101
86
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
87
|
+
# Increment a cached value. This method uses the memcached incr atomic
|
88
|
+
# operator and can only be used on values written with the :raw option.
|
89
|
+
# Calling it on a value not stored with :raw will initialize that value
|
90
|
+
# to zero.
|
91
|
+
def increment(name, amount = 1, options = nil) # :nodoc:
|
92
|
+
options = merged_options(options)
|
93
|
+
response = instrument(:increment, name, :amount => amount) do
|
94
|
+
@data.incr(escape_key(namespaced_key(name, options)), amount)
|
108
95
|
end
|
109
|
-
|
110
|
-
|
111
|
-
def increment(key, amount = 1) # :nodoc:
|
112
|
-
response = instrument(:increment, key, :amount => amount) do
|
113
|
-
@data.incr(key, amount)
|
114
|
-
end
|
115
|
-
|
116
|
-
response == Response::NOT_FOUND ? nil : response
|
96
|
+
response == Response::NOT_FOUND ? nil : response.to_i
|
117
97
|
rescue MemCache::MemCacheError
|
118
98
|
nil
|
119
99
|
end
|
120
100
|
|
121
|
-
|
122
|
-
|
123
|
-
|
101
|
+
# Decrement a cached value. This method uses the memcached decr atomic
|
102
|
+
# operator and can only be used on values written with the :raw option.
|
103
|
+
# Calling it on a value not stored with :raw will initialize that value
|
104
|
+
# to zero.
|
105
|
+
def decrement(name, amount = 1, options = nil) # :nodoc:
|
106
|
+
options = merged_options(options)
|
107
|
+
response = instrument(:decrement, name, :amount => amount) do
|
108
|
+
@data.decr(escape_key(namespaced_key(name, options)), amount)
|
124
109
|
end
|
125
|
-
|
126
|
-
response == Response::NOT_FOUND ? nil : response
|
110
|
+
response == Response::NOT_FOUND ? nil : response.to_i
|
127
111
|
rescue MemCache::MemCacheError
|
128
112
|
nil
|
129
113
|
end
|
130
114
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
super
|
135
|
-
raise "Not supported by Memcache"
|
136
|
-
end
|
137
|
-
|
138
|
-
def clear
|
115
|
+
# Clear the entire cache on all memcached servers. This method should
|
116
|
+
# be used with care when using a shared cache.
|
117
|
+
def clear(options = nil)
|
139
118
|
@data.flush_all
|
140
119
|
end
|
141
120
|
|
121
|
+
# Get the statistics from the memcached servers.
|
142
122
|
def stats
|
143
123
|
@data.stats
|
144
124
|
end
|
145
125
|
|
126
|
+
protected
|
127
|
+
# Read an entry from the cache.
|
128
|
+
def read_entry(key, options) # :nodoc:
|
129
|
+
deserialize_entry(@data.get(escape_key(key), true))
|
130
|
+
rescue MemCache::MemCacheError => e
|
131
|
+
logger.error("MemCacheError (#{e}): #{e.message}") if logger
|
132
|
+
nil
|
133
|
+
end
|
134
|
+
|
135
|
+
# Write an entry to the cache.
|
136
|
+
def write_entry(key, entry, options) # :nodoc:
|
137
|
+
method = options && options[:unless_exist] ? :add : :set
|
138
|
+
value = options[:raw] ? entry.value.to_s : entry
|
139
|
+
expires_in = options[:expires_in].to_i
|
140
|
+
if expires_in > 0 && !options[:raw]
|
141
|
+
# Set the memcache expire a few minutes in the future to support race condition ttls on read
|
142
|
+
expires_in += 5.minutes
|
143
|
+
end
|
144
|
+
response = @data.send(method, escape_key(key), value, expires_in, options[:raw])
|
145
|
+
response == Response::STORED
|
146
|
+
rescue MemCache::MemCacheError => e
|
147
|
+
logger.error("MemCacheError (#{e}): #{e.message}") if logger
|
148
|
+
false
|
149
|
+
end
|
150
|
+
|
151
|
+
# Delete an entry from the cache.
|
152
|
+
def delete_entry(key, options) # :nodoc:
|
153
|
+
response = @data.delete(escape_key(key))
|
154
|
+
response == Response::DELETED
|
155
|
+
rescue MemCache::MemCacheError => e
|
156
|
+
logger.error("MemCacheError (#{e}): #{e.message}") if logger
|
157
|
+
false
|
158
|
+
end
|
159
|
+
|
146
160
|
private
|
147
|
-
def
|
148
|
-
|
161
|
+
def escape_key(key)
|
162
|
+
key = key.to_s.gsub(ESCAPE_KEY_CHARS){|match| "%#{match[0].to_s(16).upcase}"}
|
163
|
+
key = "#{key[0, 213]}:md5:#{Digest::MD5.hexdigest(key)}" if key.size > 250
|
164
|
+
key
|
149
165
|
end
|
166
|
+
|
167
|
+
def deserialize_entry(raw_value)
|
168
|
+
if raw_value
|
169
|
+
entry = Marshal.load(raw_value) rescue raw_value
|
170
|
+
entry.is_a?(Entry) ? entry : Entry.new(entry)
|
171
|
+
else
|
172
|
+
nil
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# Provide support for raw values in the local cache strategy.
|
177
|
+
module LocalCacheWithRaw # :nodoc:
|
178
|
+
protected
|
179
|
+
def write_entry(key, entry, options) # :nodoc:
|
180
|
+
retval = super
|
181
|
+
if options[:raw] && local_cache && retval
|
182
|
+
raw_entry = Entry.new(entry.value.to_s)
|
183
|
+
raw_entry.expires_at = entry.expires_at
|
184
|
+
local_cache.write_entry(key, raw_entry, options)
|
185
|
+
end
|
186
|
+
retval
|
187
|
+
end
|
188
|
+
end
|
150
189
|
end
|
151
190
|
end
|
152
191
|
end
|