redis-store-with-cas 0.0.1
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/.gitignore +9 -0
- data/Gemfile +2 -0
- data/MIT-LICENSE +21 -0
- data/README.md +30 -0
- data/Rakefile +4 -0
- data/irb.rb +4 -0
- data/lib/redis-store-with-cas.rb +3 -0
- data/lib/redis/store-with-cas.rb +15 -0
- data/lib/redis/store-with-cas/cas.rb +107 -0
- data/lib/redis/store-with-cas/namespace.rb +17 -0
- data/lib/redis/store-with-cas/version.rb +7 -0
- data/redis-store-with-cas.gemspec +34 -0
- data/test/store_test.rb +127 -0
- data/test/test_helper.rb +6 -0
- data/test/version_test.rb +7 -0
- metadata +215 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b078891090e8eb34a95b4ee0bc6a8a4f2f9fc179
|
4
|
+
data.tar.gz: c80c840495cff70bc4e3b46da42f04d9a5fae9bd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0b1d51e1aca950890aa2bf18c97b284269c5fbc9352a174e27c277c5678af10bb7d9349a1775bc60b3135bae09e9de2132e8ecb393a405f318dd655cf6b8eb65
|
7
|
+
data.tar.gz: 033d735df907553eb5e537c3d8076cd2771079b28aff0ee89e676bb5223ad56305d20f32f7e5113b7c95ae0c1202fcf019ccda6eb04e644355d2ef66014b532f
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2017 Rajko Albrecht
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# Enhance redis store with Compare-and-Swap methods
|
2
|
+
|
3
|
+
__Redis Store With CAS__ enhance the existing [redis-store for Ruby Frameworks](https://github.com/redis-store/redis-store)
|
4
|
+
with so called Compare-And-Swap.
|
5
|
+
|
6
|
+
This is required for thread-safe-usage of cache systems like [Identity cache](https://github.com/Shopify/identity_cache).
|
7
|
+
|
8
|
+
The tests and workflow are build like in [Memcached store for ruby](https://github.com/Shopify/memcached_store)
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add the following to your Gemfile
|
13
|
+
|
14
|
+
`gem 'redis-store-with-cas`
|
15
|
+
|
16
|
+
## Usage
|
17
|
+
|
18
|
+
Add a
|
19
|
+
|
20
|
+
`require 'redis-store-with-cas'`
|
21
|
+
|
22
|
+
line to your source before first call to `Redis::Store.new`. Now each instance of `Redis::Store` has
|
23
|
+
two new methods:
|
24
|
+
|
25
|
+
* `cas`
|
26
|
+
* `cas_multi`
|
27
|
+
|
28
|
+
## Copyright
|
29
|
+
|
30
|
+
2017 Rajko Albrecht - [http://alwins-world.de](http://alwins-world.de)
|
data/Rakefile
ADDED
data/irb.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'redis'
|
2
|
+
require 'redis/store'
|
3
|
+
require 'redis/store-with-cas/cas'
|
4
|
+
require 'redis/store-with-cas/version'
|
5
|
+
require 'redis/store/marshalling'
|
6
|
+
require 'redis/store/namespace'
|
7
|
+
require 'redis/store-with-cas/namespace'
|
8
|
+
|
9
|
+
class Redis
|
10
|
+
|
11
|
+
class Store < self
|
12
|
+
include Cas
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
class Redis
|
2
|
+
|
3
|
+
# simple enhancement of Redis::Store
|
4
|
+
class Store < self
|
5
|
+
|
6
|
+
# Implements Compare-And-Swap (or as Redis says Compare-And-Save)
|
7
|
+
# on top of Redis::Store using Redis::Store::watch. It is designated for simple values, not redis-lists/hashes etc
|
8
|
+
module Cas
|
9
|
+
|
10
|
+
# Single CAS
|
11
|
+
#
|
12
|
+
# Trys to save change the value of a redis-key when it may not done in a atomic matter. Eg, you have do some
|
13
|
+
# checks on old value before setting the new one and so on. If key content changes meanwhile it refuses to
|
14
|
+
# set and you will not overwrite changes from other Thread or Process.
|
15
|
+
#
|
16
|
+
# This method works only on existing keys in redis.
|
17
|
+
# It works only with keys holding a value, eg, read/writeable with get/set
|
18
|
+
#
|
19
|
+
# @yield [value] the current value of given key
|
20
|
+
# @yieldparam [String] key the key to get and set the value
|
21
|
+
# @yieldreturn [String] the new value to store in key
|
22
|
+
# @return [Boolean] true if new value was stored, otherwise false
|
23
|
+
# @param key [String] the key to set. Must not be nil and key must exists in Redis
|
24
|
+
# @param ttl [Integer] if not nil and integer > 0 set a TTL to the changed key
|
25
|
+
# @example
|
26
|
+
#
|
27
|
+
# storewithcas.cas('examplekey') do |value|
|
28
|
+
# # value is the CURRENT value!
|
29
|
+
# new_value = do_some_important_stuff_here(value)
|
30
|
+
# new_value # write back to redis unless key has changed meanwhile
|
31
|
+
# end
|
32
|
+
def cas key, ttl=nil
|
33
|
+
return false unless exists(key)
|
34
|
+
watch(key) do
|
35
|
+
value = get(key)
|
36
|
+
value = yield value
|
37
|
+
ires = multi do |multi|
|
38
|
+
multi.set(key,value,ttl.nil? ? {} : {:expire_after => ttl})
|
39
|
+
end
|
40
|
+
ires.is_a?(Array) && ires[0] == 'OK'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Multi CAS
|
45
|
+
#
|
46
|
+
# Safe changing multiple keys at once. It works only with keys holding a value, eg, read/writeable with get/set
|
47
|
+
#
|
48
|
+
# @example
|
49
|
+
#
|
50
|
+
# storewithcas.cas_multi('key1','key1') do |currenthash|
|
51
|
+
# newhashedvalues = make_something_with_current(currenthash)
|
52
|
+
# newhashedvalues
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# @example
|
56
|
+
# storewithcas.cas_multi('k1','k2', :expire_in => 1200) do |currenthash| #=> ttl for all keys swapped
|
57
|
+
# {'k1' => '1', 'k2' => 2}
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
# @yield [values] a key=>value hash with values of given keys. keys not existing are not yielded
|
61
|
+
# @yieldparam [Array] keys the keys to change
|
62
|
+
# @yieldreturn [Hash] key-value-pairs to change. Keys not given in parameter or not existing in redis are ignored.
|
63
|
+
# @return [Boolean] true if tried making changes, nil when keylist empty
|
64
|
+
# @param keys [Array] the keys to set. Must not be nil and keys must exists in Redis. After keys list you may append hash with options for redis.
|
65
|
+
def cas_multi *keys
|
66
|
+
return if keys.empty?
|
67
|
+
options = extract_options keys
|
68
|
+
watch(*keys) do
|
69
|
+
values = read_multi(*keys,options)
|
70
|
+
valuehash = yield values
|
71
|
+
valuehash.map do |name,value|
|
72
|
+
multi do |multi|
|
73
|
+
multi.set(name,value,options)
|
74
|
+
end if values.key?(name)
|
75
|
+
end
|
76
|
+
true
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Read list of keys and return values as Hash
|
81
|
+
#
|
82
|
+
# @param keys Array the keys to read
|
83
|
+
# @return [Hash] key-value-pairs of key found in redis, eg, exists.
|
84
|
+
#
|
85
|
+
# @example
|
86
|
+
# values = read_multi("key1","key2","key3") #=> {"key1" => "1", "key2" => "2", "key3" => "3"}
|
87
|
+
def read_multi *keys
|
88
|
+
options = extract_options keys
|
89
|
+
keys = keys.select {|k| exists(k)}
|
90
|
+
return {} if keys.empty?
|
91
|
+
values = mget(*keys,options)
|
92
|
+
values.nil? ? {} : Hash[keys.zip(values)]
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def extract_options array
|
98
|
+
if array.last.is_a?(Hash) && array.last.instance_of?(Hash)
|
99
|
+
array.pop
|
100
|
+
else
|
101
|
+
{}
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Redis
|
2
|
+
class Store < self
|
3
|
+
# Add namespaced methods missing in #Redis::Store
|
4
|
+
module Namespace
|
5
|
+
# redis.watch for a list of keys respecting the namespace for keys of the
|
6
|
+
# Redis::Store instance
|
7
|
+
# @param keys Array a list of keys to watch
|
8
|
+
# @see Redis::Store::watch in redis-store-gem
|
9
|
+
# @see Redis::watch in redis-gem
|
10
|
+
def watch *keys
|
11
|
+
if keys.any?
|
12
|
+
super(*keys.map {|key| interpolate(key) })
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path('../lib', __FILE__)
|
3
|
+
require 'redis/store-with-cas/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'redis-store-with-cas'
|
7
|
+
s.version = Redis::StoreWithCas::VERSION
|
8
|
+
s.authors = ['Rajko Albrecht']
|
9
|
+
s.email = ['ral@alwins-world.de']
|
10
|
+
s.homepage = 'https://git.alwin-it.de/alwin/redis-store-with-cas'
|
11
|
+
s.summary = %q{Extend redis store for Ruby frameworks with cas}
|
12
|
+
s.description = %q{Extend the redis store with CAS (compare-and-swap) functionality for better cache integrity support}
|
13
|
+
|
14
|
+
s.rubyforge_project = 'redis-store-with-cas'
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
s.license = 'MIT'
|
21
|
+
|
22
|
+
s.add_dependency 'redis', '>= 2.2', '< 4'
|
23
|
+
s.add_dependency 'redis-store', '>= 1.1.0', '< 2'
|
24
|
+
|
25
|
+
s.add_development_dependency 'rake', '~> 10'
|
26
|
+
s.add_development_dependency 'bundler', '~> 1.3'
|
27
|
+
s.add_development_dependency 'mocha', '~> 0.14.0'
|
28
|
+
s.add_development_dependency 'minitest', '~> 5'
|
29
|
+
s.add_development_dependency 'git', '~> 1.2'
|
30
|
+
s.add_development_dependency 'pry-nav', '~> 0.2.4'
|
31
|
+
s.add_development_dependency 'pry', '~> 0.10.4'
|
32
|
+
s.add_development_dependency 'redis-store-testing'
|
33
|
+
|
34
|
+
end
|
data/test/store_test.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe Redis::StoreWithCas do
|
4
|
+
def setup
|
5
|
+
@store = Redis::Store.new :namespace => 'storetest'
|
6
|
+
end
|
7
|
+
|
8
|
+
def teardown
|
9
|
+
@store.flushdb
|
10
|
+
@store.quit
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_cas
|
14
|
+
@store.set('foo', 'baz')
|
15
|
+
assert(@store.cas('foo') do |value|
|
16
|
+
assert_equal 'baz', value
|
17
|
+
'bar'
|
18
|
+
end)
|
19
|
+
assert_equal 'bar', @store.get('foo')
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_cas_with_cache_miss
|
23
|
+
refute @store.cas('not_exist') { |_value| flunk }
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_cas_with_conflict
|
27
|
+
@store.set('foo', 'bar')
|
28
|
+
refute @store.cas('foo') { |_value|
|
29
|
+
@store.set('foo', 'baz')
|
30
|
+
'biz'
|
31
|
+
}
|
32
|
+
assert_equal 'baz', @store.get('foo')
|
33
|
+
end
|
34
|
+
|
35
|
+
# TODO write a Mockup redis with support for watch
|
36
|
+
def test_cas_with_ttl
|
37
|
+
@store.set('ttlfoo','bar')
|
38
|
+
assert(@store.cas('ttlfoo',3600) do |value|
|
39
|
+
assert_equal 'bar',value
|
40
|
+
'ttlbar'
|
41
|
+
end)
|
42
|
+
assert_equal @store.get('ttlfoo'),'ttlbar'
|
43
|
+
assert @store.ttl('ttlfoo') > 0
|
44
|
+
assert(@store.cas('ttlfoo') do |value|
|
45
|
+
'bar'
|
46
|
+
end)
|
47
|
+
assert_equal -1,@store.ttl('ttlfoo')
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_cas_multi_with_empty_set
|
51
|
+
refute @store.cas_multi { |_hash| flunk }
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def test_read_multi
|
56
|
+
@store.set('k1','m1')
|
57
|
+
@store.set('k2','m2')
|
58
|
+
assert_equal({"k1" => "m1","k2" => "m2"},@store.read_multi("k1","k2"))
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_cas_multi
|
62
|
+
@store.set('foo', 'bar')
|
63
|
+
@store.set('fud', 'biz')
|
64
|
+
assert_equal true, (@store.cas_multi('foo', 'fud') do |hash|
|
65
|
+
assert_equal({ "foo" => "bar", "fud" => "biz" }, hash)
|
66
|
+
{ "foo" => "baz", "fud" => "buz" }
|
67
|
+
end)
|
68
|
+
assert_equal({ "foo" => "baz", "fud" => "buz" }, @store.read_multi('foo', 'fud'))
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_cas_multi_with_ttl
|
72
|
+
@store.set('foo', 'bar')
|
73
|
+
@store.set('fud', 'biz')
|
74
|
+
@store.cas_multi('foo','fud',{:expires_in => 3600}) do |hash|
|
75
|
+
{ "foo" => "baz", "fud" => "buz" }
|
76
|
+
end
|
77
|
+
assert @store.ttl('foo') > 0
|
78
|
+
assert @store.ttl('fud') > 0
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_cas_multi_with_cache_miss
|
82
|
+
assert(@store.cas_multi('not_exist') do |hash|
|
83
|
+
assert hash.empty?
|
84
|
+
{}
|
85
|
+
end)
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_cas_multi_with_altered_key
|
89
|
+
@store.set('foo', 'baz')
|
90
|
+
assert @store.cas_multi('foo') { |_hash| { 'fu' => 'baz' } }
|
91
|
+
assert_nil @store.get('fu')
|
92
|
+
assert_equal 'baz', @store.get('foo')
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_cas_multi_with_partial_miss
|
96
|
+
@store.set('foo', 'baz')
|
97
|
+
assert(@store.cas_multi('foo', 'bar') do |hash|
|
98
|
+
assert_equal({ "foo" => "baz" }, hash)
|
99
|
+
{}
|
100
|
+
end)
|
101
|
+
assert_equal 'baz', @store.get('foo')
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_cas_multi_with_partial_update
|
105
|
+
@store.set('foo', 'bar')
|
106
|
+
@store.set('fud', 'biz')
|
107
|
+
assert(@store.cas_multi('foo', 'fud') do |hash|
|
108
|
+
assert_equal({ "foo" => "bar", "fud" => "biz" }, hash)
|
109
|
+
|
110
|
+
{ "foo" => "baz" }
|
111
|
+
end)
|
112
|
+
assert_equal({ "foo" => "baz", "fud" => "biz" }, @store.read_multi('foo', 'fud'))
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_cas_multi_with_partial_conflict
|
116
|
+
@store.set('foo', 'bar')
|
117
|
+
@store.set('fud', 'biz')
|
118
|
+
result = @store.cas_multi('foo', 'fud') do |hash|
|
119
|
+
assert_equal({ "foo" => "bar", "fud" => "biz" }, hash)
|
120
|
+
@store.set('foo', 'bad')
|
121
|
+
{ "foo" => "baz", "fud" => "buz" }
|
122
|
+
end
|
123
|
+
assert result
|
124
|
+
assert_equal({ "foo" => "bad", "fud" => "buz" }, @store.read_multi('foo', 'fud'))
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,215 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: redis-store-with-cas
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Rajko Albrecht
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-07-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: redis
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.2'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '4'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '2.2'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '4'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: redis-store
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 1.1.0
|
40
|
+
- - "<"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '2'
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 1.1.0
|
50
|
+
- - "<"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '2'
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: rake
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '10'
|
60
|
+
type: :development
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - "~>"
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '10'
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: bundler
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - "~>"
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '1.3'
|
74
|
+
type: :development
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - "~>"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '1.3'
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: mocha
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - "~>"
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: 0.14.0
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - "~>"
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: 0.14.0
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: minitest
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - "~>"
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '5'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - "~>"
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '5'
|
109
|
+
- !ruby/object:Gem::Dependency
|
110
|
+
name: git
|
111
|
+
requirement: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - "~>"
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '1.2'
|
116
|
+
type: :development
|
117
|
+
prerelease: false
|
118
|
+
version_requirements: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - "~>"
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '1.2'
|
123
|
+
- !ruby/object:Gem::Dependency
|
124
|
+
name: pry-nav
|
125
|
+
requirement: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - "~>"
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: 0.2.4
|
130
|
+
type: :development
|
131
|
+
prerelease: false
|
132
|
+
version_requirements: !ruby/object:Gem::Requirement
|
133
|
+
requirements:
|
134
|
+
- - "~>"
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: 0.2.4
|
137
|
+
- !ruby/object:Gem::Dependency
|
138
|
+
name: pry
|
139
|
+
requirement: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - "~>"
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: 0.10.4
|
144
|
+
type: :development
|
145
|
+
prerelease: false
|
146
|
+
version_requirements: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - "~>"
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: 0.10.4
|
151
|
+
- !ruby/object:Gem::Dependency
|
152
|
+
name: redis-store-testing
|
153
|
+
requirement: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - ">="
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
158
|
+
type: :development
|
159
|
+
prerelease: false
|
160
|
+
version_requirements: !ruby/object:Gem::Requirement
|
161
|
+
requirements:
|
162
|
+
- - ">="
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
version: '0'
|
165
|
+
description: Extend the redis store with CAS (compare-and-swap) functionality for
|
166
|
+
better cache integrity support
|
167
|
+
email:
|
168
|
+
- ral@alwins-world.de
|
169
|
+
executables: []
|
170
|
+
extensions: []
|
171
|
+
extra_rdoc_files: []
|
172
|
+
files:
|
173
|
+
- ".gitignore"
|
174
|
+
- Gemfile
|
175
|
+
- MIT-LICENSE
|
176
|
+
- README.md
|
177
|
+
- Rakefile
|
178
|
+
- irb.rb
|
179
|
+
- lib/redis-store-with-cas.rb
|
180
|
+
- lib/redis/store-with-cas.rb
|
181
|
+
- lib/redis/store-with-cas/cas.rb
|
182
|
+
- lib/redis/store-with-cas/namespace.rb
|
183
|
+
- lib/redis/store-with-cas/version.rb
|
184
|
+
- redis-store-with-cas.gemspec
|
185
|
+
- test/store_test.rb
|
186
|
+
- test/test_helper.rb
|
187
|
+
- test/version_test.rb
|
188
|
+
homepage: https://git.alwin-it.de/alwin/redis-store-with-cas
|
189
|
+
licenses:
|
190
|
+
- MIT
|
191
|
+
metadata: {}
|
192
|
+
post_install_message:
|
193
|
+
rdoc_options: []
|
194
|
+
require_paths:
|
195
|
+
- lib
|
196
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
197
|
+
requirements:
|
198
|
+
- - ">="
|
199
|
+
- !ruby/object:Gem::Version
|
200
|
+
version: '0'
|
201
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
202
|
+
requirements:
|
203
|
+
- - ">="
|
204
|
+
- !ruby/object:Gem::Version
|
205
|
+
version: '0'
|
206
|
+
requirements: []
|
207
|
+
rubyforge_project: redis-store-with-cas
|
208
|
+
rubygems_version: 2.6.11
|
209
|
+
signing_key:
|
210
|
+
specification_version: 4
|
211
|
+
summary: Extend redis store for Ruby frameworks with cas
|
212
|
+
test_files:
|
213
|
+
- test/store_test.rb
|
214
|
+
- test/test_helper.rb
|
215
|
+
- test/version_test.rb
|