vinted-memcached_store 2.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +22 -0
- data/README.md +60 -0
- data/lib/active_support/cache/memcached_snappy_store.rb +45 -0
- data/lib/active_support/cache/memcached_store.rb +392 -0
- data/lib/memcached_store/railtie.rb +9 -0
- data/lib/memcached_store/version.rb +4 -0
- data/lib/memcached_store.rb +4 -0
- metadata +127 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a6675c19521b317f6a5a3915a39b7d8ff82efed1f12cbffc5d97ec86f2348e0a
|
4
|
+
data.tar.gz: 542e1943df8e5c95a1127b91c2823e490a0a9058a8ae7f9231a04c1209f80588
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d3bb0bf65bf86f5269761b9bcfb0adebc1c20aaf896e093f44c8f25a65b9481196299508c7c2fedead98b8a7a1d434b957062f748f0450a222db1dc099be1447
|
7
|
+
data.tar.gz: 3a4695a77dea72f8b3fa9db8f9353b30c47ee1ed3c7e6ba247ac1842b8810670bd9ef27c1aeecd759ed33998def06cd23b8bdd3d928f859657a46ed40d8c4af1
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013-2016 Shopify Inc.
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# ActiveSupport MemcachedStore
|
2
|
+
|
3
|
+
This gem includes two memcached stores.
|
4
|
+
|
5
|
+
### MemcachedStore
|
6
|
+
|
7
|
+
ActiveSupport memcached store. This wraps the memcached gem into a ActiveSupport::Cache::Store, so it could be used inside Rails.
|
8
|
+
|
9
|
+
### MemcachedSnappyStore
|
10
|
+
|
11
|
+
ActiveSupport cache store that adds snappy compression at the cost of making the `incr, decr` operations unavailable.
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
Add this line to your application's Gemfile:
|
16
|
+
|
17
|
+
```
|
18
|
+
gem 'memcached_store'
|
19
|
+
```
|
20
|
+
|
21
|
+
And then execute:
|
22
|
+
|
23
|
+
```bash
|
24
|
+
$ bundle
|
25
|
+
```
|
26
|
+
|
27
|
+
Or install it yourself as:
|
28
|
+
|
29
|
+
```bash
|
30
|
+
$ gem install memcached_store
|
31
|
+
```
|
32
|
+
|
33
|
+
## Usage
|
34
|
+
|
35
|
+
In your environment file:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
# for memcached store
|
39
|
+
config.cache_store = :memcached_store,
|
40
|
+
|
41
|
+
# for snappy store
|
42
|
+
config.cache_store = :memcached_snappy_store,
|
43
|
+
Memcached.new(['memcached1.foo.com', 'memcached2.foo.com'])
|
44
|
+
```
|
45
|
+
|
46
|
+
## Benchmarks
|
47
|
+
|
48
|
+
For benchmarks please refer to https://github.com/basecamp/memcached_bench.
|
49
|
+
|
50
|
+
## Code status
|
51
|
+
|
52
|
+
[](https://travis-ci.org/Shopify/memcached_store)
|
53
|
+
|
54
|
+
## Contributing
|
55
|
+
|
56
|
+
1. Fork it
|
57
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
58
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
59
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
60
|
+
5. Create new Pull Request
|
@@ -0,0 +1,45 @@
|
|
1
|
+
begin
|
2
|
+
require 'snappy'
|
3
|
+
rescue LoadError => e
|
4
|
+
$stderr.puts "You don't have snappy installed in your application. Please add `gem \"snappy\"` to your Gemfile and run bundle install"
|
5
|
+
raise e
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'active_support/cache/memcached_store'
|
9
|
+
|
10
|
+
module ActiveSupport
|
11
|
+
module Cache
|
12
|
+
class MemcachedSnappyStore < MemcachedStore
|
13
|
+
class UnsupportedOperation < StandardError; end
|
14
|
+
|
15
|
+
module SnappyCompressor
|
16
|
+
def self.compress(source)
|
17
|
+
Snappy.deflate(source)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.decompress(source)
|
21
|
+
Snappy.inflate(source)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def increment(*)
|
26
|
+
raise UnsupportedOperation, "increment is not supported by: #{self.class.name}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def decrement(*)
|
30
|
+
raise UnsupportedOperation, "decrement is not supported by: #{self.class.name}"
|
31
|
+
end
|
32
|
+
|
33
|
+
# IdentityCache has its own handling for read only.
|
34
|
+
def read_only
|
35
|
+
false
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize(*addresses, **options)
|
39
|
+
options[:codec] ||= ActiveSupport::Cache::MemcachedStore::Codec.new(compressor: SnappyCompressor)
|
40
|
+
options[:compress] = false
|
41
|
+
super(*addresses, **options)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,392 @@
|
|
1
|
+
# file havily based out off https://github.com/rails/rails/blob/3-2-stable/activesupport/lib/active_support/cache/mem_cache_store.rb
|
2
|
+
require 'digest/md5'
|
3
|
+
require 'delegate'
|
4
|
+
|
5
|
+
module ActiveSupport
|
6
|
+
module Cache
|
7
|
+
# A cache store implementation which stores data in Memcached:
|
8
|
+
# http://memcached.org/
|
9
|
+
#
|
10
|
+
# MemcachedStore uses memcached gem as backend to connect to Memcached server.
|
11
|
+
#
|
12
|
+
# MemcachedStore implements the Strategy::LocalCache strategy which implements
|
13
|
+
# an in-memory cache inside of a block.
|
14
|
+
class MemcachedStore < Store
|
15
|
+
ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
|
16
|
+
|
17
|
+
class Codec
|
18
|
+
# use dalli compatible flags
|
19
|
+
SERIALIZED_FLAG = 0x1
|
20
|
+
COMPRESSED_FLAG = 0x2
|
21
|
+
|
22
|
+
# Older versions of this gem would use 0 for the flags whether or not
|
23
|
+
# the value was marshal dumped. By setting this flag, we can tell if
|
24
|
+
# it were set with an older version for backwards compatible decoding.
|
25
|
+
RAW_FLAG = 0x10
|
26
|
+
|
27
|
+
def initialize(serializer: Marshal, compressor: nil)
|
28
|
+
@serializer = serializer
|
29
|
+
@compressor = compressor
|
30
|
+
end
|
31
|
+
|
32
|
+
def encode(_key, value, flags)
|
33
|
+
unless value.is_a?(String)
|
34
|
+
flags |= SERIALIZED_FLAG
|
35
|
+
value = @serializer.dump(value)
|
36
|
+
end
|
37
|
+
if @compressor
|
38
|
+
flags |= COMPRESSED_FLAG
|
39
|
+
value = @compressor.compress(value)
|
40
|
+
end
|
41
|
+
flags |= RAW_FLAG if flags == 0
|
42
|
+
[value, flags]
|
43
|
+
end
|
44
|
+
|
45
|
+
def decode(_key, value, flags)
|
46
|
+
if (flags & COMPRESSED_FLAG) != 0
|
47
|
+
value = @compressor.decompress(value)
|
48
|
+
end
|
49
|
+
|
50
|
+
if (flags & SERIALIZED_FLAG) != 0
|
51
|
+
@serializer.load(value)
|
52
|
+
elsif flags == 0 # legacy cache value
|
53
|
+
@serializer.load(value) rescue value
|
54
|
+
else
|
55
|
+
value
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
attr_accessor :read_only, :swallow_exceptions
|
61
|
+
|
62
|
+
prepend(Strategy::LocalCache)
|
63
|
+
|
64
|
+
def initialize(*addresses, **options)
|
65
|
+
addresses = addresses.flatten
|
66
|
+
options[:codec] ||= Codec.new
|
67
|
+
@swallow_exceptions = true
|
68
|
+
@swallow_exceptions = options.delete(:swallow_exceptions) if options.key?(:swallow_exceptions)
|
69
|
+
|
70
|
+
if options.key?(:coder)
|
71
|
+
raise ArgumentError, "ActiveSupport::Cache::MemcachedStore doesn't support custom coders"
|
72
|
+
end
|
73
|
+
|
74
|
+
# We don't use a coder, so we set it to nil so Active Support don't think we're using
|
75
|
+
# a deprecated one.
|
76
|
+
super(options.merge(coder: nil))
|
77
|
+
|
78
|
+
if addresses.first.is_a?(Memcached)
|
79
|
+
@connection = addresses.first
|
80
|
+
raise "Memcached::Rails is no longer supported, "\
|
81
|
+
"use a Memcached instance instead" if @connection.is_a?(Memcached::Rails)
|
82
|
+
else
|
83
|
+
mem_cache_options = options.dup
|
84
|
+
servers = mem_cache_options.delete(:servers)
|
85
|
+
UNIVERSAL_OPTIONS.each { |name| mem_cache_options.delete(name) }
|
86
|
+
@connection = Memcached.new([*addresses, *servers], mem_cache_options)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def append(name, value, options = nil)
|
91
|
+
return true if read_only
|
92
|
+
options = merged_options(options)
|
93
|
+
normalized_key = normalize_key(name, options)
|
94
|
+
|
95
|
+
handle_exceptions(return_value_on_error: nil, on_miss: false, miss_exceptions: [Memcached::NotStored]) do
|
96
|
+
instrument(:append, name) do
|
97
|
+
@connection.append(normalized_key, value)
|
98
|
+
end
|
99
|
+
true
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def write(*)
|
104
|
+
return true if read_only
|
105
|
+
super
|
106
|
+
end
|
107
|
+
|
108
|
+
def delete(*)
|
109
|
+
return true if read_only
|
110
|
+
super
|
111
|
+
end
|
112
|
+
|
113
|
+
def read_multi(*names)
|
114
|
+
options = names.extract_options!
|
115
|
+
return {} if names.empty?
|
116
|
+
|
117
|
+
options = merged_options(options)
|
118
|
+
keys_to_names = Hash[names.map { |name| [normalize_key(name, options), name] }]
|
119
|
+
values = {}
|
120
|
+
|
121
|
+
handle_exceptions(return_value_on_error: {}) do
|
122
|
+
instrument(:read_multi, names, options) do
|
123
|
+
if raw_values = @connection.get(keys_to_names.keys)
|
124
|
+
raw_values.each do |key, value|
|
125
|
+
entry = deserialize_entry(value)
|
126
|
+
values[keys_to_names[key]] = entry.value unless entry.expired?
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
values
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def cas(name, options = nil)
|
135
|
+
options = merged_options(options)
|
136
|
+
key = normalize_key(name, options)
|
137
|
+
payload = nil
|
138
|
+
|
139
|
+
success = handle_exceptions(return_value_on_error: false) do
|
140
|
+
instrument(:cas, name, options) do
|
141
|
+
@connection.cas(key, expiration(options)) do |raw_value|
|
142
|
+
entry = deserialize_entry(raw_value)
|
143
|
+
value = yield entry.value
|
144
|
+
break true if read_only
|
145
|
+
payload = serialize_entry(Entry.new(value, **options), options)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
true
|
149
|
+
end
|
150
|
+
|
151
|
+
if success
|
152
|
+
local_cache.write_entry(key, payload) if local_cache
|
153
|
+
else
|
154
|
+
local_cache.delete_entry(key) if local_cache
|
155
|
+
end
|
156
|
+
|
157
|
+
success
|
158
|
+
end
|
159
|
+
|
160
|
+
def cas_multi(*names, **options)
|
161
|
+
return if names.empty?
|
162
|
+
|
163
|
+
options = merged_options(options)
|
164
|
+
keys_to_names = Hash[names.map { |name| [normalize_key(name, options), name] }]
|
165
|
+
|
166
|
+
sent_payloads = nil
|
167
|
+
|
168
|
+
handle_exceptions(return_value_on_error: false) do
|
169
|
+
instrument(:cas_multi, names, options) do
|
170
|
+
written_payloads = @connection.cas(keys_to_names.keys, expiration(options)) do |raw_values|
|
171
|
+
values = {}
|
172
|
+
|
173
|
+
raw_values.each do |key, raw_value|
|
174
|
+
entry = deserialize_entry(raw_value)
|
175
|
+
values[keys_to_names[key]] = entry.value unless entry.expired?
|
176
|
+
end
|
177
|
+
|
178
|
+
values = yield values
|
179
|
+
|
180
|
+
break true if read_only
|
181
|
+
|
182
|
+
serialized_values = values.map do |name, value|
|
183
|
+
[normalize_key(name, options), serialize_entry(Entry.new(value, **options), options)]
|
184
|
+
end
|
185
|
+
|
186
|
+
sent_payloads = Hash[serialized_values]
|
187
|
+
end
|
188
|
+
|
189
|
+
if local_cache && sent_payloads
|
190
|
+
sent_payloads.each_key do |key|
|
191
|
+
if written_payloads.key?(key)
|
192
|
+
local_cache.write_entry(key, written_payloads[key])
|
193
|
+
else
|
194
|
+
local_cache.delete_entry(key)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
true
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def increment(name, amount = 1, options = nil) # :nodoc:
|
205
|
+
options = merged_options(options)
|
206
|
+
handle_exceptions(return_value_on_error: nil) do
|
207
|
+
instrument(:increment, name, amount: amount) do
|
208
|
+
@connection.incr(normalize_key(name, options), amount)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def decrement(name, amount = 1, options = nil) # :nodoc:
|
214
|
+
options = merged_options(options)
|
215
|
+
handle_exceptions(return_value_on_error: nil) do
|
216
|
+
instrument(:decrement, name, amount: amount) do
|
217
|
+
@connection.decr(normalize_key(name, options), amount)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def clear(options = nil)
|
223
|
+
ActiveSupport::Notifications.instrument("cache_clear.active_support", options || {}) do
|
224
|
+
@connection.flush
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def stats
|
229
|
+
ActiveSupport::Notifications.instrument("cache_stats.active_support") do
|
230
|
+
@connection.stats
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def exist?(*)
|
235
|
+
!!super
|
236
|
+
end
|
237
|
+
|
238
|
+
def reset #:nodoc:
|
239
|
+
handle_exceptions(return_value_on_error: false) do
|
240
|
+
@connection.reset
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
private
|
245
|
+
|
246
|
+
if private_method_defined?(:read_serialized_entry)
|
247
|
+
class DupLocalStore < DelegateClass(Strategy::LocalCache::LocalStore)
|
248
|
+
def write_entry(_key, entry)
|
249
|
+
if entry.is_a?(Entry)
|
250
|
+
entry.dup_value!
|
251
|
+
end
|
252
|
+
super
|
253
|
+
end
|
254
|
+
|
255
|
+
def fetch_entry(key)
|
256
|
+
entry = super do
|
257
|
+
new_entry = yield
|
258
|
+
if entry.is_a?(Entry)
|
259
|
+
new_entry.dup_value!
|
260
|
+
end
|
261
|
+
new_entry
|
262
|
+
end
|
263
|
+
entry = entry.dup
|
264
|
+
|
265
|
+
if entry.is_a?(Entry)
|
266
|
+
entry.dup_value!
|
267
|
+
end
|
268
|
+
|
269
|
+
entry
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
module DupLocalCache
|
274
|
+
private
|
275
|
+
|
276
|
+
def local_cache
|
277
|
+
if local_cache = super
|
278
|
+
DupLocalStore.new(local_cache)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
prepend DupLocalCache
|
284
|
+
|
285
|
+
def read_entry(key, **options) # :nodoc:
|
286
|
+
deserialize_entry(read_serialized_entry(key, **options))
|
287
|
+
end
|
288
|
+
|
289
|
+
def read_serialized_entry(key, **)
|
290
|
+
handle_exceptions(return_value_on_error: nil) do
|
291
|
+
@connection.get(key)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
def write_entry(key, entry, **options) # :nodoc:
|
296
|
+
return true if read_only
|
297
|
+
|
298
|
+
write_serialized_entry(key, serialize_entry(entry, **options), **options)
|
299
|
+
end
|
300
|
+
|
301
|
+
def write_serialized_entry(key, value, **options)
|
302
|
+
method = options && options[:unless_exist] ? :add : :set
|
303
|
+
expires_in = expiration(options)
|
304
|
+
handle_exceptions(return_value_on_error: false) do
|
305
|
+
@connection.send(method, key, value, expires_in)
|
306
|
+
true
|
307
|
+
end
|
308
|
+
end
|
309
|
+
else
|
310
|
+
def read_entry(key, _options) # :nodoc:
|
311
|
+
handle_exceptions(return_value_on_error: nil) do
|
312
|
+
deserialize_entry(@connection.get(key))
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
def write_entry(key, entry, options) # :nodoc:
|
317
|
+
return true if read_only
|
318
|
+
method = options && options[:unless_exist] ? :add : :set
|
319
|
+
expires_in = expiration(options)
|
320
|
+
value = serialize_entry(entry, options)
|
321
|
+
handle_exceptions(return_value_on_error: false) do
|
322
|
+
@connection.send(method, key, value, expires_in)
|
323
|
+
true
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
def delete_entry(key, _options) # :nodoc:
|
329
|
+
return true if read_only
|
330
|
+
handle_exceptions(return_value_on_error: false, on_miss: true) do
|
331
|
+
@connection.delete(key)
|
332
|
+
true
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
private
|
337
|
+
|
338
|
+
def normalize_key(key, options)
|
339
|
+
key = super.dup
|
340
|
+
key = key.force_encoding(Encoding::ASCII_8BIT)
|
341
|
+
key = key.gsub(ESCAPE_KEY_CHARS) { |match| "%#{match.getbyte(0).to_s(16).upcase}" }
|
342
|
+
# When we remove support to Rails 5.1 we can change the code to use ActiveSupport::Digest
|
343
|
+
key = "#{key[0, 213]}:md5:#{::Digest::MD5.hexdigest(key)}" if key.size > 250
|
344
|
+
key
|
345
|
+
end
|
346
|
+
|
347
|
+
def deserialize_entry(value)
|
348
|
+
unless value.nil?
|
349
|
+
value.is_a?(Entry) ? value : Entry.new(value, compress: false)
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
def serialize_entry(entry, options)
|
354
|
+
if options[:raw]
|
355
|
+
entry.value.to_s
|
356
|
+
else
|
357
|
+
entry
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
def expiration(options)
|
362
|
+
expires_in = options[:expires_in].to_i
|
363
|
+
if expires_in > 0 && options[:race_condition_ttl] && !options[:raw]
|
364
|
+
expires_in += options[:race_condition_ttl].to_i
|
365
|
+
end
|
366
|
+
expires_in
|
367
|
+
end
|
368
|
+
|
369
|
+
def handle_exceptions(return_value_on_error:, on_miss: return_value_on_error, miss_exceptions: [])
|
370
|
+
yield
|
371
|
+
rescue Memcached::NotFound, Memcached::ConnectionDataExists, *miss_exceptions
|
372
|
+
on_miss
|
373
|
+
rescue Memcached::Error => e
|
374
|
+
log_warning(e)
|
375
|
+
raise unless @swallow_exceptions
|
376
|
+
return_value_on_error
|
377
|
+
end
|
378
|
+
|
379
|
+
def log_warning(err)
|
380
|
+
return unless logger
|
381
|
+
return if err.is_a?(Memcached::NotStored) && @swallow_exceptions
|
382
|
+
|
383
|
+
logger.warn(
|
384
|
+
"[MEMCACHED_ERROR] swallowed=#{@swallow_exceptions}" \
|
385
|
+
" exception_class=#{err.class} exception_message=#{err.message}"
|
386
|
+
)
|
387
|
+
end
|
388
|
+
|
389
|
+
ActiveSupport.run_load_hooks(:memcached_store)
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
metadata
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vinted-memcached_store
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.3.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Camilo Lopez
|
8
|
+
- Tom Burns
|
9
|
+
- Arthur Neves
|
10
|
+
- Francis Bogsanyi
|
11
|
+
autorequire:
|
12
|
+
bindir: bin
|
13
|
+
cert_chain: []
|
14
|
+
date: 2023-08-31 00:00:00.000000000 Z
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: activesupport
|
18
|
+
requirement: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '6'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '6'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: memcached
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - "~>"
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '1.8'
|
37
|
+
type: :runtime
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - "~>"
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '1.8'
|
44
|
+
- !ruby/object:Gem::Dependency
|
45
|
+
name: rake
|
46
|
+
requirement: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '0'
|
51
|
+
type: :development
|
52
|
+
prerelease: false
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: mocha
|
60
|
+
requirement: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
type: :development
|
66
|
+
prerelease: false
|
67
|
+
version_requirements: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
- !ruby/object:Gem::Dependency
|
73
|
+
name: timecop
|
74
|
+
requirement: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
type: :development
|
80
|
+
prerelease: false
|
81
|
+
version_requirements: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
description: Plugin-able Memcached adapters to add features (compression, safety)
|
87
|
+
email:
|
88
|
+
- camilo@camilolopez.com
|
89
|
+
- tom.burns@shopify.com
|
90
|
+
- arthurnn@gmail.com
|
91
|
+
- francis.bogsanyi@shopify.com
|
92
|
+
executables: []
|
93
|
+
extensions: []
|
94
|
+
extra_rdoc_files: []
|
95
|
+
files:
|
96
|
+
- LICENSE
|
97
|
+
- README.md
|
98
|
+
- lib/active_support/cache/memcached_snappy_store.rb
|
99
|
+
- lib/active_support/cache/memcached_store.rb
|
100
|
+
- lib/memcached_store.rb
|
101
|
+
- lib/memcached_store/railtie.rb
|
102
|
+
- lib/memcached_store/version.rb
|
103
|
+
homepage: https://github.com/Shopify/memcached_store/
|
104
|
+
licenses:
|
105
|
+
- MIT
|
106
|
+
metadata:
|
107
|
+
allowed_push_host: https://rubygems.org
|
108
|
+
post_install_message:
|
109
|
+
rdoc_options: []
|
110
|
+
require_paths:
|
111
|
+
- lib
|
112
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: 2.6.0
|
117
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - ">="
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
requirements: []
|
123
|
+
rubygems_version: 3.4.10
|
124
|
+
signing_key:
|
125
|
+
specification_version: 4
|
126
|
+
summary: Plugin-able Memcached adapters to add features (compression, safety)
|
127
|
+
test_files: []
|