memcached_store 0.12.7 → 0.12.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -0
- data/Gemfile +7 -1
- data/lib/active_support/cache/memcached_snappy_store.rb +5 -0
- data/lib/active_support/cache/memcached_store.rb +22 -0
- data/lib/memcached_store/memcached_safety.rb +20 -0
- data/lib/memcached_store/version.rb +1 -1
- data/memcached_store.gemspec +0 -4
- data/shipit.rubygems.yml +4 -1
- data/test/test_helper.rb +14 -0
- data/test/test_memcached_safety.rb +5 -0
- data/test/test_memcached_store.rb +214 -16
- metadata +3 -59
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3e458052cfc2aac92c629b37e02fc7ae66077dcd
|
4
|
+
data.tar.gz: af048ce101065d5bc3463a9e118b6c3fb45c7763
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 376570dd86abe4ca47cff7cb74aa934c7b26dac30ad24eeab5ee02b8310a24d9866d8c92ba2c85364c9c7bec426fe842e282b65d84742f2ba371db2cef478254
|
7
|
+
data.tar.gz: 8d958e238be593341eb041916ee4b47648a841ef3c87f45a3ebeeb1a2bca09808c43b1cf16aaf0ae5dba0b842ce49300ea9a3d600621e7f26d3deaeaa223b761
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
@@ -20,6 +20,11 @@ module ActiveSupport
|
|
20
20
|
raise UnsupportedOperation.new("decrement is not supported by: #{self.class.name}")
|
21
21
|
end
|
22
22
|
|
23
|
+
# IdentityCache has its own handling for read only.
|
24
|
+
def read_only
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
23
28
|
private
|
24
29
|
def serialize_entry(entry, options)
|
25
30
|
value = options[:raw] ? entry.value.to_s : Marshal.dump(entry)
|
@@ -30,6 +30,8 @@ module ActiveSupport
|
|
30
30
|
|
31
31
|
ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
|
32
32
|
|
33
|
+
attr_accessor :read_only
|
34
|
+
|
33
35
|
def initialize(*addresses)
|
34
36
|
addresses = addresses.flatten
|
35
37
|
options = addresses.extract_options!
|
@@ -46,6 +48,21 @@ module ActiveSupport
|
|
46
48
|
extend Strategy::LocalCache
|
47
49
|
end
|
48
50
|
|
51
|
+
def logger
|
52
|
+
return @logger if defined?(@logger)
|
53
|
+
@logger = ::Rails.logger if defined?(::Rails)
|
54
|
+
end
|
55
|
+
|
56
|
+
def write(*args)
|
57
|
+
return true if read_only
|
58
|
+
super(*args)
|
59
|
+
end
|
60
|
+
|
61
|
+
def delete(*args)
|
62
|
+
return true if read_only
|
63
|
+
super(*args)
|
64
|
+
end
|
65
|
+
|
49
66
|
def read_multi(*names)
|
50
67
|
options = names.extract_options!
|
51
68
|
options = merged_options(options)
|
@@ -74,6 +91,7 @@ module ActiveSupport
|
|
74
91
|
@data.cas(key, expiration(options), cas_raw?(options)) do |raw_value|
|
75
92
|
entry = deserialize_entry(raw_value)
|
76
93
|
value = yield entry.value
|
94
|
+
break true if read_only
|
77
95
|
serialize_entry(Entry.new(value, options), options).first
|
78
96
|
end
|
79
97
|
end
|
@@ -83,6 +101,7 @@ module ActiveSupport
|
|
83
101
|
end
|
84
102
|
|
85
103
|
def cas_multi(*names)
|
104
|
+
|
86
105
|
options = names.extract_options!
|
87
106
|
options = merged_options(options)
|
88
107
|
keys_to_names = Hash[names.map{|name| [escape_key(namespaced_key(name, options)), name]}]
|
@@ -95,6 +114,7 @@ module ActiveSupport
|
|
95
114
|
values[keys_to_names[key]] = entry.value unless entry.expired?
|
96
115
|
end
|
97
116
|
values = yield values
|
117
|
+
break true if read_only
|
98
118
|
Hash[values.map{|name, value| [escape_key(namespaced_key(name, options)), serialize_entry(Entry.new(value, options), options).first]}]
|
99
119
|
end
|
100
120
|
end
|
@@ -151,6 +171,7 @@ module ActiveSupport
|
|
151
171
|
end
|
152
172
|
|
153
173
|
def write_entry(key, entry, options) # :nodoc:
|
174
|
+
return true if read_only
|
154
175
|
method = options && options[:unless_exist] ? :add : :set
|
155
176
|
expires_in = expiration(options)
|
156
177
|
value, raw = serialize_entry(entry, options)
|
@@ -161,6 +182,7 @@ module ActiveSupport
|
|
161
182
|
end
|
162
183
|
|
163
184
|
def delete_entry(key, options) # :nodoc:
|
185
|
+
return true if read_only
|
164
186
|
@data.delete(escape_key(key))
|
165
187
|
true
|
166
188
|
rescue *NONFATAL_EXCEPTIONS => e
|
@@ -23,6 +23,7 @@ module MemcachedStore
|
|
23
23
|
def exist_with_rescue?(*args)
|
24
24
|
exist_without_rescue?(*args)
|
25
25
|
rescue *NONFATAL_EXCEPTIONS
|
26
|
+
report_exception($!)
|
26
27
|
end
|
27
28
|
alias_method :exist_without_rescue?, :exist?
|
28
29
|
alias_method :exist?, :exist_with_rescue?
|
@@ -30,6 +31,7 @@ module MemcachedStore
|
|
30
31
|
def cas_with_rescue(*args)
|
31
32
|
cas_without_rescue(*args)
|
32
33
|
rescue *NONFATAL_EXCEPTIONS
|
34
|
+
report_exception($!)
|
33
35
|
false
|
34
36
|
end
|
35
37
|
alias_method_chain :cas, :rescue
|
@@ -37,6 +39,7 @@ module MemcachedStore
|
|
37
39
|
def get_multi_with_rescue(*args)
|
38
40
|
get_multi_without_rescue(*args)
|
39
41
|
rescue *NONFATAL_EXCEPTIONS
|
42
|
+
report_exception($!)
|
40
43
|
{}
|
41
44
|
end
|
42
45
|
alias_method_chain :get_multi, :rescue
|
@@ -44,6 +47,7 @@ module MemcachedStore
|
|
44
47
|
def set_with_rescue(*args)
|
45
48
|
set_without_rescue(*args)
|
46
49
|
rescue *NONFATAL_EXCEPTIONS
|
50
|
+
report_exception($!)
|
47
51
|
false
|
48
52
|
end
|
49
53
|
alias_method_chain :set, :rescue
|
@@ -51,6 +55,7 @@ module MemcachedStore
|
|
51
55
|
def add_with_rescue(*args)
|
52
56
|
add_without_rescue(*args)
|
53
57
|
rescue *NONFATAL_EXCEPTIONS
|
58
|
+
report_exception($!)
|
54
59
|
@string_return_types? "NOT STORED\r\n" : true
|
55
60
|
end
|
56
61
|
alias_method_chain :add, :rescue
|
@@ -60,9 +65,24 @@ module MemcachedStore
|
|
60
65
|
def #{meth}_with_rescue(*args)
|
61
66
|
#{meth}_without_rescue(*args)
|
62
67
|
rescue *NONFATAL_EXCEPTIONS
|
68
|
+
report_exception($!)
|
63
69
|
end
|
64
70
|
alias_method_chain :#{meth}, :rescue
|
65
71
|
ENV
|
66
72
|
end
|
73
|
+
|
74
|
+
def logger
|
75
|
+
return @logger if @logger
|
76
|
+
@logger = ::Rails.logger if defined?(::Rails)
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def report_exception(exception)
|
82
|
+
if defined?(::Rails)
|
83
|
+
logger.error "[#{self.class}] exception=#{exception}"
|
84
|
+
end
|
85
|
+
nil # make sure return value is nil
|
86
|
+
end
|
67
87
|
end
|
68
88
|
end
|
data/memcached_store.gemspec
CHANGED
@@ -19,8 +19,4 @@ Gem::Specification.new do |gem|
|
|
19
19
|
gem.add_runtime_dependency "memcached", "~> 1.8.0"
|
20
20
|
|
21
21
|
gem.add_development_dependency "rake"
|
22
|
-
gem.add_development_dependency "minitest"
|
23
|
-
gem.add_development_dependency "mocha"
|
24
|
-
gem.add_development_dependency "timecop"
|
25
|
-
gem.add_development_dependency "snappy"
|
26
22
|
end
|
data/shipit.rubygems.yml
CHANGED
data/test/test_helper.rb
CHANGED
@@ -5,3 +5,17 @@ require 'timecop'
|
|
5
5
|
require 'active_support/test_case'
|
6
6
|
|
7
7
|
require 'memcached_store'
|
8
|
+
|
9
|
+
class Rails
|
10
|
+
def self.logger
|
11
|
+
@logger ||= Logger.new("/dev/null")
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.env
|
15
|
+
Struct.new("Env") do
|
16
|
+
def self.test?
|
17
|
+
true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -125,6 +125,11 @@ class TestMemcachedSafety < ActiveSupport::TestCase
|
|
125
125
|
@cache.prepend("a-key", "other")
|
126
126
|
end
|
127
127
|
end
|
128
|
+
|
129
|
+
test "logger defaults to rails logger" do
|
130
|
+
assert_equal Rails.logger, @cache.logger
|
131
|
+
end
|
132
|
+
|
128
133
|
private
|
129
134
|
|
130
135
|
def expect_nonfatal(sym)
|
@@ -1,9 +1,13 @@
|
|
1
1
|
require 'test_helper'
|
2
|
+
require 'logger'
|
2
3
|
|
3
4
|
class TestMemcachedStore < ActiveSupport::TestCase
|
4
5
|
setup do
|
5
6
|
@cache = ActiveSupport::Cache.lookup_store(:memcached_store, expires_in: 60, support_cas: true)
|
6
7
|
@cache.clear
|
8
|
+
|
9
|
+
# Enable ActiveSupport notifications. Can be disabled in Rails 5.
|
10
|
+
Thread.current[:instrument_cache_store] = true
|
7
11
|
end
|
8
12
|
|
9
13
|
def test_write_not_found
|
@@ -153,26 +157,11 @@ class TestMemcachedStore < ActiveSupport::TestCase
|
|
153
157
|
assert_equal({"fu" => "baz"}, @cache.read_multi('foo', 'fu'))
|
154
158
|
end
|
155
159
|
|
156
|
-
def test_read_multi
|
157
|
-
@cache.write('foo', 'bar')
|
158
|
-
@cache.write('fu', 'baz')
|
159
|
-
@cache.write('fud', 'biz')
|
160
|
-
assert_equal({"foo" => "bar", "fu" => "baz"}, @cache.read_multi('foo', 'fu'))
|
161
|
-
end
|
162
|
-
|
163
160
|
def test_read_multi_not_found
|
164
161
|
expect_not_found
|
165
162
|
assert_equal({}, @cache.read_multi('foe', 'fue'))
|
166
163
|
end
|
167
164
|
|
168
|
-
def test_read_multi_with_expires
|
169
|
-
@cache.write('foo', 'bar', :expires_in => 0.001)
|
170
|
-
@cache.write('fu', 'baz')
|
171
|
-
@cache.write('fud', 'biz')
|
172
|
-
sleep(0.002)
|
173
|
-
assert_equal({"fu" => "baz"}, @cache.read_multi('foo', 'fu'))
|
174
|
-
end
|
175
|
-
|
176
165
|
def test_read_and_write_compressed_small_data
|
177
166
|
@cache.write('foo', 'bar', :compress => true)
|
178
167
|
assert_equal 'bar', @cache.read('foo')
|
@@ -388,15 +377,224 @@ class TestMemcachedStore < ActiveSupport::TestCase
|
|
388
377
|
assert_equal "", client.prefix_key, "should not send the namespace to the client"
|
389
378
|
assert_equal "foo::key", cache.send(:namespaced_key, "key", cache.options)
|
390
379
|
end
|
391
|
-
|
380
|
+
|
392
381
|
def test_reset
|
393
382
|
client = @cache.instance_variable_get(:@data)
|
394
383
|
client.expects(:reset).once
|
395
384
|
@cache.reset
|
396
385
|
end
|
397
386
|
|
387
|
+
def test_write_to_read_only_memcached_store_should_not_write
|
388
|
+
with_read_only(@cache) do
|
389
|
+
assert @cache.write("walrus", "awesome"), "Writing to a disabled memcached
|
390
|
+
store should return truthy to make clients not care"
|
391
|
+
|
392
|
+
assert_nil @cache.read("walrus"), "Key should have nil value in disabled cache"
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
def test_delete_with_read_only_memcached_store_should_not_delete
|
397
|
+
assert @cache.write("walrus", "big")
|
398
|
+
|
399
|
+
with_read_only(@cache) do
|
400
|
+
assert @cache.delete("walrus"), "Should return truthy when deleted to not raise in client"
|
401
|
+
end
|
402
|
+
|
403
|
+
assert_equal "big", @cache.read("walrus"), "Cache entry should not have been deleted from read only client"
|
404
|
+
end
|
405
|
+
|
406
|
+
def test_cas_with_read_only_memcached_store_should_not_s
|
407
|
+
called_block = false
|
408
|
+
@cache.write('walrus', 'slimy')
|
409
|
+
|
410
|
+
with_read_only(@cache) do
|
411
|
+
assert(@cache.cas('walrus') { |value|
|
412
|
+
assert_equal 'slimy', value
|
413
|
+
called_block = true
|
414
|
+
'full'
|
415
|
+
})
|
416
|
+
end
|
417
|
+
|
418
|
+
assert_equal 'slimy', @cache.read('walrus')
|
419
|
+
assert called_block, "CAS with read only should have called the inner block with an assertion"
|
420
|
+
end
|
421
|
+
|
422
|
+
def test_cas_multi_with_read_only_memcached_store_should_not_s
|
423
|
+
called_block = false
|
424
|
+
|
425
|
+
@cache.write('walrus', 'cool')
|
426
|
+
@cache.write('narwhal', 'horn')
|
427
|
+
|
428
|
+
with_read_only(@cache) do
|
429
|
+
assert(@cache.cas_multi('walrus', 'narwhal') {
|
430
|
+
called_block = true
|
431
|
+
{ "walrus" => "not cool", "narwhal" => "not with horns" }
|
432
|
+
})
|
433
|
+
end
|
434
|
+
|
435
|
+
assert_equal 'cool', @cache.read('walrus')
|
436
|
+
assert_equal 'horn', @cache.read('narwhal')
|
437
|
+
assert called_block, "CAS with read only should have called the inner block with an assertion"
|
438
|
+
end
|
439
|
+
|
440
|
+
def test_write_with_read_only_should_not_send_activesupport_notification
|
441
|
+
assert_notifications(/cache/, 0) do
|
442
|
+
with_read_only(@cache) do
|
443
|
+
assert @cache.write("walrus", "bestest")
|
444
|
+
end
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
def test_delete_with_read_only_should_not_send_activesupport_notification
|
449
|
+
assert_notifications(/cache/, 0) do
|
450
|
+
with_read_only(@cache) do
|
451
|
+
assert @cache.delete("walrus")
|
452
|
+
end
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
def test_fetch_with_expires_in_with_read_only_should_not_send_activesupport_notification
|
457
|
+
expires_in = 10
|
458
|
+
@cache.fetch("walrus", expires_in: expires_in) { "yo" }
|
459
|
+
|
460
|
+
Timecop.travel(Time.now + expires_in + 1) do
|
461
|
+
assert_notifications(/cache_write/, 0) do
|
462
|
+
with_read_only(@cache) do
|
463
|
+
@cache.fetch("walrus") { "no" }
|
464
|
+
end
|
465
|
+
end
|
466
|
+
end
|
467
|
+
end
|
468
|
+
|
469
|
+
def test_fetch_with_expired_entry_with_read_only_should_return_nil_and_not_delete_from_cache
|
470
|
+
expires_in = 10
|
471
|
+
@cache.fetch("walrus", expires_in: expires_in) { "yo" }
|
472
|
+
|
473
|
+
Timecop.travel(Time.now + expires_in + 1) do
|
474
|
+
with_read_only(@cache) do
|
475
|
+
value = @cache.fetch("walrus", expires_in: expires_in) { "no" }
|
476
|
+
|
477
|
+
assert_equal "no", value
|
478
|
+
refute @cache.fetch("walrus"), "Client should return nil for expired key"
|
479
|
+
assert_equal "yo", @cache.instance_variable_get(:@data).get("walrus").value
|
480
|
+
end
|
481
|
+
end
|
482
|
+
end
|
483
|
+
|
484
|
+
def test_fetch_with_expired_entry_and_race_condition_ttl_with_read_only_should_return_nil_and_not_delete_from_cache
|
485
|
+
expires_in = 10
|
486
|
+
race_condition_ttl = 10
|
487
|
+
@cache.fetch("walrus", expires_in: expires_in) { "yo" }
|
488
|
+
|
489
|
+
Timecop.travel(Time.now + expires_in + 1) do
|
490
|
+
with_read_only(@cache) do
|
491
|
+
value = @cache.fetch("walrus", expires_in: expires_in, race_condition_ttl: race_condition_ttl) { "no" }
|
492
|
+
|
493
|
+
assert_equal "no", value
|
494
|
+
assert_equal "no", @cache.fetch("walrus") { "no" }
|
495
|
+
refute @cache.fetch("walrus")
|
496
|
+
|
497
|
+
assert_equal "yo", @cache.instance_variable_get(:@data).get("walrus").value
|
498
|
+
end
|
499
|
+
end
|
500
|
+
end
|
501
|
+
|
502
|
+
def test_read_with_expired_with_read_only_entry_should_return_nil_and_not_delete_from_cache
|
503
|
+
expires_in = 10
|
504
|
+
@cache.fetch("walrus", expires_in: expires_in) { "yo" }
|
505
|
+
|
506
|
+
Timecop.travel(Time.now + expires_in + 1) do
|
507
|
+
with_read_only(@cache) do
|
508
|
+
refute @cache.read("walrus")
|
509
|
+
|
510
|
+
assert_equal "yo", @cache.instance_variable_get(:@data).get("walrus").value
|
511
|
+
end
|
512
|
+
end
|
513
|
+
end
|
514
|
+
|
515
|
+
def test_read_multi_with_expired_entry_should_return_nil_and_not_delete_from_cache
|
516
|
+
expires_in = 10
|
517
|
+
@cache.fetch("walrus", expires_in: expires_in) { "yo" }
|
518
|
+
@cache.fetch("narwhal", expires_in: expires_in) { "yiir" }
|
519
|
+
|
520
|
+
Timecop.travel(Time.now + expires_in + 1) do
|
521
|
+
with_read_only(@cache) do
|
522
|
+
assert_predicate @cache.read_multi("walrus", "narwhal"), :empty?
|
523
|
+
|
524
|
+
assert_equal "yo", @cache.instance_variable_get(:@data).get("walrus").value
|
525
|
+
assert_equal "yiir", @cache.instance_variable_get(:@data).get("narwhal").value
|
526
|
+
end
|
527
|
+
end
|
528
|
+
end
|
529
|
+
|
530
|
+
def test_fetch_with_race_condition_ttl_with_read_only_should_not_send_activesupport_notification
|
531
|
+
expires_in = 10
|
532
|
+
race_condition_ttl = 10
|
533
|
+
@cache.fetch("walrus", expires_in: expires_in) { "yo" }
|
534
|
+
|
535
|
+
Timecop.travel(Time.now + expires_in + 1) do
|
536
|
+
assert_notifications(/cache_write/, 0) do
|
537
|
+
with_read_only(@cache) do
|
538
|
+
@cache.fetch("walrus", expires_in: expires_in, race_condition_ttl: race_condition_ttl) { "no" }
|
539
|
+
end
|
540
|
+
end
|
541
|
+
end
|
542
|
+
end
|
543
|
+
|
544
|
+
def test_cas_with_read_only_should_send_activesupport_notification
|
545
|
+
@cache.write("walrus", "yes")
|
546
|
+
|
547
|
+
with_read_only(@cache) do
|
548
|
+
assert_notifications(/cache_cas/, 1) do
|
549
|
+
assert(@cache.cas("walrus") { |value| "no" })
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
assert_equal "yes", @cache.fetch("walrus")
|
554
|
+
end
|
555
|
+
|
556
|
+
def test_cas_multi_with_read_only_should_send_activesupport_notification
|
557
|
+
@cache.write("walrus", "yes")
|
558
|
+
@cache.write("narwhal", "yes")
|
559
|
+
|
560
|
+
with_read_only(@cache) do
|
561
|
+
assert_notifications(/cache_cas/, 1) do
|
562
|
+
assert(@cache.cas_multi("walrus", "narwhal") { |*values|
|
563
|
+
{ "walrus" => "no", "narwhal" => "no" }
|
564
|
+
})
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
568
|
+
assert_equal "yes", @cache.fetch("walrus")
|
569
|
+
assert_equal "yes", @cache.fetch("narwhal")
|
570
|
+
end
|
571
|
+
|
572
|
+
def test_logger_defaults_to_rails_logger
|
573
|
+
assert_equal Rails.logger, @cache.logger
|
574
|
+
end
|
575
|
+
|
398
576
|
private
|
399
577
|
|
578
|
+
def assert_notifications(pattern, num)
|
579
|
+
count = 0
|
580
|
+
subscriber = ActiveSupport::Notifications.subscribe(pattern) do |name, start, finish, id, payload|
|
581
|
+
count += 1
|
582
|
+
end
|
583
|
+
|
584
|
+
yield
|
585
|
+
|
586
|
+
assert_equal num, count, "Expected #{num} notifications for #{pattern}, but got #{count}"
|
587
|
+
ensure
|
588
|
+
ActiveSupport::Notifications.unsubscribe(subscriber)
|
589
|
+
end
|
590
|
+
|
591
|
+
def with_read_only(client)
|
592
|
+
previous, client.read_only = client.read_only, true
|
593
|
+
yield
|
594
|
+
ensure
|
595
|
+
client.read_only = previous
|
596
|
+
end
|
597
|
+
|
400
598
|
def expect_not_found
|
401
599
|
@cache.instance_variable_get(:@data).expects(:check_return_code).raises(Memcached::NotFound)
|
402
600
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: memcached_store
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.12.
|
4
|
+
version: 0.12.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Camilo Lopez
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2016-11-30 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: activesupport
|
@@ -55,62 +55,6 @@ dependencies:
|
|
55
55
|
- - ">="
|
56
56
|
- !ruby/object:Gem::Version
|
57
57
|
version: '0'
|
58
|
-
- !ruby/object:Gem::Dependency
|
59
|
-
name: minitest
|
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: mocha
|
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
|
-
- !ruby/object:Gem::Dependency
|
87
|
-
name: timecop
|
88
|
-
requirement: !ruby/object:Gem::Requirement
|
89
|
-
requirements:
|
90
|
-
- - ">="
|
91
|
-
- !ruby/object:Gem::Version
|
92
|
-
version: '0'
|
93
|
-
type: :development
|
94
|
-
prerelease: false
|
95
|
-
version_requirements: !ruby/object:Gem::Requirement
|
96
|
-
requirements:
|
97
|
-
- - ">="
|
98
|
-
- !ruby/object:Gem::Version
|
99
|
-
version: '0'
|
100
|
-
- !ruby/object:Gem::Dependency
|
101
|
-
name: snappy
|
102
|
-
requirement: !ruby/object:Gem::Requirement
|
103
|
-
requirements:
|
104
|
-
- - ">="
|
105
|
-
- !ruby/object:Gem::Version
|
106
|
-
version: '0'
|
107
|
-
type: :development
|
108
|
-
prerelease: false
|
109
|
-
version_requirements: !ruby/object:Gem::Requirement
|
110
|
-
requirements:
|
111
|
-
- - ">="
|
112
|
-
- !ruby/object:Gem::Version
|
113
|
-
version: '0'
|
114
58
|
description: Plugin-able Memcached adapters to add features (compression, safety)
|
115
59
|
email:
|
116
60
|
- camilo@camilolopez.com
|
@@ -157,7 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
157
101
|
version: '0'
|
158
102
|
requirements: []
|
159
103
|
rubyforge_project:
|
160
|
-
rubygems_version: 2.
|
104
|
+
rubygems_version: 2.5.1
|
161
105
|
signing_key:
|
162
106
|
specification_version: 4
|
163
107
|
summary: Plugin-able Memcached adapters to add features (compression, safety)
|