redis-session-store 0.4.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +103 -0
- data/README.md +34 -10
- data/lib/redis-session-store.rb +37 -17
- data/spec/redis_session_store_spec.rb +46 -9
- metadata +23 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9148a3bedfc1ab56951717dccdaed7c30e33e356
|
4
|
+
data.tar.gz: ca00490849f6276f4262ddfa100fa8d90c819087
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fdbe30259d8e8eb71a650a73c59f613f830276f913d0e5bd062b5212db29704aa3ff56d7b5d443e95fabdd441085065a5ca8b02aa0c4b998264c3efeb4685cd9
|
7
|
+
data.tar.gz: ad31abd62bb1eb5b093aa03ba1e0f2c11bc197e3e3ff395bb78dabfb1d7659ef2a06f05435cd03a3db060510700a8a1f4ca509cd6561849e017de2014f2e068c
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
redis-session-store history
|
2
|
+
===========================
|
3
|
+
|
4
|
+
## v0.5.0 (2014-03-16)
|
5
|
+
|
6
|
+
* Keep generating session IDs until one is found that doesn't collide
|
7
|
+
with existing session IDs
|
8
|
+
* Add support for `on_sid_collision` handler option
|
9
|
+
* Add support for `on_redis_down` handler option
|
10
|
+
* **BACKWARD INCOMPATIBLE** Drop support for `:raise_errors` option
|
11
|
+
|
12
|
+
## v0.4.2 (2014-03-14)
|
13
|
+
|
14
|
+
* Renaming `load_session` method to not conflict with AbstractStore
|
15
|
+
|
16
|
+
## v0.4.1 (yanked) (2014-03-13)
|
17
|
+
|
18
|
+
* Regenerate session ID when session is missing
|
19
|
+
|
20
|
+
## v0.4.0 (2014-02-19)
|
21
|
+
|
22
|
+
* Add support for `ENV_SESSION_OPTIONS_KEY` rack env option
|
23
|
+
* Add support for `:raise_errors` session option (kinda like Dalli)
|
24
|
+
* Increasing test coverage
|
25
|
+
|
26
|
+
## v0.3.1 (2014-02-19)
|
27
|
+
|
28
|
+
* Add `#destroy_session` method
|
29
|
+
* Clean up remaining RuboCop offenses
|
30
|
+
* Documentation updates
|
31
|
+
|
32
|
+
## v0.3.0 (2014-02-13)
|
33
|
+
|
34
|
+
* Rails 3 compatibility
|
35
|
+
* Switch from minitest to rspec
|
36
|
+
* Add test coverage
|
37
|
+
* RuboCop cleanup
|
38
|
+
|
39
|
+
## v0.2.4 (2014-03-16)
|
40
|
+
|
41
|
+
* Keep generating session IDs until one is found that doesn't collide
|
42
|
+
with existing session IDs
|
43
|
+
|
44
|
+
## v0.2.3 (2014-03-14)
|
45
|
+
|
46
|
+
* Renaming `load_session` method to not conflict with AbstractStore
|
47
|
+
|
48
|
+
## v0.2.2 (yanked) (2014-03-13)
|
49
|
+
|
50
|
+
* Regenerate session ID when session is missing
|
51
|
+
|
52
|
+
## v0.2.1 (2013-09-17)
|
53
|
+
|
54
|
+
* Add explicit MIT license metadata in gemspec
|
55
|
+
|
56
|
+
## v0.2.0 (2013-09-13)
|
57
|
+
|
58
|
+
* Use `@redis.setex` when expiry provided, else `@redis.set`
|
59
|
+
* Gemfile, gemspec, and git updates
|
60
|
+
* Nest redis-specific options inside a `:redis` key of session options
|
61
|
+
* Add `#destroy` method
|
62
|
+
* Rescue only `Errno::ECONNREFUSED` exceptions
|
63
|
+
* Handle `nil` cookies during `#destroy`
|
64
|
+
* Add Travis integration
|
65
|
+
* Add some minimal tests to ensure backward compatibility session options
|
66
|
+
|
67
|
+
## v0.1.9 (2012-03-06)
|
68
|
+
|
69
|
+
## v0.1.8 (2010-12-09)
|
70
|
+
|
71
|
+
* Remove use of `@redis.pipelined`
|
72
|
+
|
73
|
+
## v0.1.7 (2010-12-08)
|
74
|
+
|
75
|
+
* Using latest redis gem API
|
76
|
+
|
77
|
+
## v0.1.6 (2010-04-18)
|
78
|
+
|
79
|
+
* Using pipelined format with `set` and `expire`
|
80
|
+
* Changing default port from 6370 to 6379
|
81
|
+
|
82
|
+
## v0.1.5 (2010-04-07)
|
83
|
+
|
84
|
+
## v0.1.4 (2010-03-26)
|
85
|
+
|
86
|
+
* Changed redis parameter from `:server` to `:host`
|
87
|
+
|
88
|
+
## v0.1.3 (2009-12-30)
|
89
|
+
|
90
|
+
* Documentation updates
|
91
|
+
|
92
|
+
## v0.1.2 (2009-12-30)
|
93
|
+
|
94
|
+
* Documentation updates
|
95
|
+
|
96
|
+
## v0.1.1 (2009-12-30)
|
97
|
+
|
98
|
+
* library file renamed to `redis-session-store.rb` to play nicely with
|
99
|
+
rails require
|
100
|
+
|
101
|
+
## v0.1 (2009-12-30)
|
102
|
+
|
103
|
+
* first working version
|
data/README.md
CHANGED
@@ -19,8 +19,8 @@ only suitable for Rails applications. For other frameworks or
|
|
19
19
|
drop-in support for caching, check out
|
20
20
|
[redis-store](http://github.com/jodosha/redis-store/)
|
21
21
|
|
22
|
-
Compatibility
|
23
|
-
|
22
|
+
Rails 2 Compatibility
|
23
|
+
---------------------
|
24
24
|
|
25
25
|
This gem is currently only compatible with Rails 3+. If you need
|
26
26
|
Rails 2 compatibility, be sure to pin to a lower version like so:
|
@@ -44,17 +44,41 @@ In your Rails app, throw in an initializer with the following contents:
|
|
44
44
|
|
45
45
|
``` ruby
|
46
46
|
My::Application.config.session_store = :redis_session_store, {
|
47
|
-
:
|
48
|
-
:
|
49
|
-
:
|
50
|
-
:
|
51
|
-
:
|
52
|
-
:
|
53
|
-
:
|
47
|
+
key: 'your_session_key',
|
48
|
+
redis: {
|
49
|
+
db: 2,
|
50
|
+
expire_after: 120.minutes,
|
51
|
+
key_prefix: 'myapp:session:',
|
52
|
+
host: 'host', # Redis host name, default is localhost
|
53
|
+
port: 12345 # Redis port, default is 6379
|
54
54
|
}
|
55
55
|
}
|
56
56
|
```
|
57
|
-
|
57
|
+
|
58
|
+
### Session ID collision handling
|
59
|
+
|
60
|
+
If you want to handle cases where the generated session ID (sid)
|
61
|
+
collides with an existing session ID, a custom callable handler may be
|
62
|
+
provided as `on_sid_collision`:
|
63
|
+
|
64
|
+
``` ruby
|
65
|
+
My::Application.config.session_store = :redis_session_store, {
|
66
|
+
# ... other options ...
|
67
|
+
on_sid_collision: ->(sid) { Rails.logger.warn("SID collision! #{sid}") }
|
68
|
+
}
|
69
|
+
```
|
70
|
+
|
71
|
+
### Redis unavailability handling
|
72
|
+
|
73
|
+
If you want to handle cases where Redis is unavailable, a custom
|
74
|
+
callable handler may be provided as `on_redis_down`:
|
75
|
+
|
76
|
+
``` ruby
|
77
|
+
My::Application.config.session_store = :redis_session_store, {
|
78
|
+
# ... other options ...
|
79
|
+
on_redis_down: ->(e, env, sid) { do_something_will_ya!(e) }
|
80
|
+
}
|
81
|
+
```
|
58
82
|
|
59
83
|
Contributing, Authors, & License
|
60
84
|
--------------------------------
|
data/lib/redis-session-store.rb
CHANGED
@@ -4,7 +4,7 @@ require 'redis'
|
|
4
4
|
# Redis session storage for Rails, and for Rails only. Derived from
|
5
5
|
# the MemCacheStore code, simply dropping in Redis instead.
|
6
6
|
class RedisSessionStore < ActionDispatch::Session::AbstractStore
|
7
|
-
VERSION = '0.
|
7
|
+
VERSION = '0.5.0'
|
8
8
|
|
9
9
|
# ==== Options
|
10
10
|
# * +:key+ - Same as with the other cookie stores, key name
|
@@ -14,18 +14,22 @@ class RedisSessionStore < ActionDispatch::Session::AbstractStore
|
|
14
14
|
# * +:db+ - Database number, defaults to 0.
|
15
15
|
# * +:key_prefix+ - Prefix for keys used in Redis, e.g. +myapp:+
|
16
16
|
# * +:expire_after+ - A number in seconds for session timeout
|
17
|
+
# * +:on_sid_collision:+ - Called with SID string when generated SID collides
|
18
|
+
# * +:on_redis_down:+ - Called with err, env, and SID on Errno::ECONNREFUSED
|
17
19
|
#
|
18
20
|
# ==== Examples
|
19
21
|
#
|
20
22
|
# My::Application.config.session_store = :redis_session_store, {
|
21
|
-
# :
|
22
|
-
# :
|
23
|
-
# :
|
24
|
-
# :
|
25
|
-
# :
|
26
|
-
# :
|
27
|
-
# :
|
28
|
-
# }
|
23
|
+
# key: 'your_session_key',
|
24
|
+
# redis: {
|
25
|
+
# db: 2,
|
26
|
+
# expire_after: 120.minutes,
|
27
|
+
# key_prefix: 'myapp:session:',
|
28
|
+
# host: 'host', # Redis host name, default is localhost
|
29
|
+
# port: 12345 # Redis port, default is 6379
|
30
|
+
# },
|
31
|
+
# on_sid_collision: ->(sid) { logger.warn("SID collision! #{sid}") },
|
32
|
+
# on_redis_down: ->(*a) { logger.error("Redis down! #{a.inspect}") }
|
29
33
|
# }
|
30
34
|
#
|
31
35
|
def initialize(app, options = {})
|
@@ -36,17 +40,33 @@ class RedisSessionStore < ActionDispatch::Session::AbstractStore
|
|
36
40
|
@default_options.merge!(namespace: 'rack:session')
|
37
41
|
@default_options.merge!(redis_options)
|
38
42
|
@redis = Redis.new(redis_options)
|
39
|
-
@
|
43
|
+
@on_sid_collision = options[:on_sid_collision]
|
44
|
+
@on_redis_down = options[:on_redis_down]
|
40
45
|
end
|
41
46
|
|
47
|
+
attr_accessor :on_sid_collision, :on_redis_down
|
48
|
+
|
42
49
|
private
|
43
50
|
|
44
|
-
attr_reader :redis, :key, :default_options
|
51
|
+
attr_reader :redis, :key, :default_options
|
45
52
|
|
46
53
|
def prefixed(sid)
|
47
54
|
"#{default_options[:key_prefix]}#{sid}"
|
48
55
|
end
|
49
56
|
|
57
|
+
def generate_sid
|
58
|
+
loop do
|
59
|
+
sid = super
|
60
|
+
break sid unless sid_collision?(sid)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def sid_collision?(sid)
|
65
|
+
!!redis.get(prefixed(sid)).tap do |value| # rubocop: disable DoubleNegation
|
66
|
+
on_sid_collision.call(sid) if value && on_sid_collision
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
50
70
|
def get_session(env, sid)
|
51
71
|
unless sid && (session = load_session_from_redis(sid))
|
52
72
|
sid = generate_sid
|
@@ -55,7 +75,7 @@ class RedisSessionStore < ActionDispatch::Session::AbstractStore
|
|
55
75
|
|
56
76
|
[sid, session]
|
57
77
|
rescue Errno::ECONNREFUSED => e
|
58
|
-
|
78
|
+
on_redis_down.call(e, env, sid) if on_redis_down
|
59
79
|
[generate_sid, {}]
|
60
80
|
end
|
61
81
|
|
@@ -73,7 +93,7 @@ class RedisSessionStore < ActionDispatch::Session::AbstractStore
|
|
73
93
|
end
|
74
94
|
return sid
|
75
95
|
rescue Errno::ECONNREFUSED => e
|
76
|
-
|
96
|
+
on_redis_down.call(e, env, sid) if on_redis_down
|
77
97
|
return false
|
78
98
|
end
|
79
99
|
|
@@ -84,12 +104,12 @@ class RedisSessionStore < ActionDispatch::Session::AbstractStore
|
|
84
104
|
end
|
85
105
|
|
86
106
|
def destroy(env)
|
87
|
-
if env['rack.request.cookie_hash'] &&
|
88
|
-
|
107
|
+
if env['rack.request.cookie_hash'] &&
|
108
|
+
(sid = env['rack.request.cookie_hash'][key])
|
109
|
+
redis.del(prefixed(sid))
|
89
110
|
end
|
90
111
|
rescue Errno::ECONNREFUSED => e
|
91
|
-
|
92
|
-
Rails.logger.warn("RedisSessionStore#destroy: #{e.message}")
|
112
|
+
on_redis_down.call(e, env, sid) if on_redis_down
|
93
113
|
false
|
94
114
|
end
|
95
115
|
end
|
@@ -135,15 +135,23 @@ describe RedisSessionStore do
|
|
135
135
|
end
|
136
136
|
|
137
137
|
context 'when redis is down' do
|
138
|
-
before
|
138
|
+
before do
|
139
|
+
store.stub(:redis).and_raise(Errno::ECONNREFUSED)
|
140
|
+
store.on_redis_down = ->(*a) { @redis_down_handled = true }
|
141
|
+
end
|
139
142
|
|
140
143
|
it 'returns false' do
|
141
144
|
store.send(:set_session, env, session_id, session_data, options)
|
142
145
|
.should eq(false)
|
143
146
|
end
|
144
147
|
|
145
|
-
|
146
|
-
|
148
|
+
it 'calls the on_redis_down handler' do
|
149
|
+
store.send(:set_session, env, session_id, session_data, options)
|
150
|
+
expect(@redis_down_handled).to be_true
|
151
|
+
end
|
152
|
+
|
153
|
+
context 'when :on_redis_down re-raises' do
|
154
|
+
before { store.on_redis_down = ->(e, *) { fail e } }
|
147
155
|
|
148
156
|
it 'explodes' do
|
149
157
|
expect do
|
@@ -160,11 +168,13 @@ describe RedisSessionStore do
|
|
160
168
|
key_prefix: 'customprefix::'
|
161
169
|
}
|
162
170
|
end
|
171
|
+
|
163
172
|
let(:fake_key) { 'thisisarediskey' }
|
164
173
|
|
165
174
|
it 'should retrieve the prefixed key from redis' do
|
166
175
|
redis = double('redis')
|
167
176
|
store.stub(redis: redis)
|
177
|
+
store.stub(generate_sid: fake_key)
|
168
178
|
expect(redis).to receive(:get).with("#{options[:key_prefix]}#{fake_key}")
|
169
179
|
|
170
180
|
store.send(:get_session, double('env'), fake_key)
|
@@ -186,8 +196,8 @@ describe RedisSessionStore do
|
|
186
196
|
.to eq('foop')
|
187
197
|
end
|
188
198
|
|
189
|
-
context 'when :
|
190
|
-
|
199
|
+
context 'when :on_redis_down re-raises' do
|
200
|
+
before { store.on_redis_down = ->(e, *) { fail e } }
|
191
201
|
|
192
202
|
it 'explodes' do
|
193
203
|
expect do
|
@@ -224,8 +234,8 @@ describe RedisSessionStore do
|
|
224
234
|
expect(store.send(:destroy, env)).to be_false
|
225
235
|
end
|
226
236
|
|
227
|
-
context 'when :
|
228
|
-
|
237
|
+
context 'when :on_redis_down re-raises' do
|
238
|
+
before { store.on_redis_down = ->(e, *) { fail e } }
|
229
239
|
|
230
240
|
it 'explodes' do
|
231
241
|
expect do
|
@@ -238,13 +248,40 @@ describe RedisSessionStore do
|
|
238
248
|
|
239
249
|
context 'when destroyed via #destroy_session' do
|
240
250
|
it 'deletes the prefixed key from redis' do
|
241
|
-
redis = double('redis')
|
242
|
-
sid = store.send(:generate_sid)
|
251
|
+
redis = double('redis', get: nil)
|
243
252
|
store.stub(redis: redis)
|
253
|
+
sid = store.send(:generate_sid)
|
244
254
|
expect(redis).to receive(:del).with("#{options[:key_prefix]}#{sid}")
|
245
255
|
|
246
256
|
store.send(:destroy_session, {}, sid, nil)
|
247
257
|
end
|
248
258
|
end
|
249
259
|
end
|
260
|
+
|
261
|
+
describe 'generating a sid' do
|
262
|
+
before { store.on_sid_collision = ->(sid) { @sid = sid } }
|
263
|
+
|
264
|
+
context 'when the generated sid is unique' do
|
265
|
+
before do
|
266
|
+
redis = double('redis', get: nil)
|
267
|
+
store.stub(redis: redis)
|
268
|
+
end
|
269
|
+
|
270
|
+
it 'returns the sid' do
|
271
|
+
expect(store.send(:generate_sid)).to_not be_nil
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
context 'when there is a generated sid collision' do
|
276
|
+
before do
|
277
|
+
redis = double('redis', get: 'herp a derp')
|
278
|
+
store.stub(redis: redis)
|
279
|
+
end
|
280
|
+
|
281
|
+
it 'passes the colliding sid to the collision handler' do
|
282
|
+
store.send(:sid_collision?, 'whatever')
|
283
|
+
expect(@sid).to eql('whatever')
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
250
287
|
end
|
metadata
CHANGED
@@ -1,97 +1,97 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis-session-store
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mathias Meyer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-03-
|
11
|
+
date: 2014-03-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: fakeredis
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rspec
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rubocop
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: simplecov
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- -
|
87
|
+
- - ">="
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: '0'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- -
|
94
|
+
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
97
|
description: A drop-in replacement for e.g. MemCacheStore to store Rails sessions
|
@@ -105,12 +105,13 @@ extra_rdoc_files:
|
|
105
105
|
- AUTHORS.md
|
106
106
|
- CONTRIBUTING.md
|
107
107
|
files:
|
108
|
-
- .gitignore
|
109
|
-
- .rspec
|
110
|
-
- .rubocop.yml
|
111
|
-
- .simplecov
|
112
|
-
- .travis.yml
|
108
|
+
- ".gitignore"
|
109
|
+
- ".rspec"
|
110
|
+
- ".rubocop.yml"
|
111
|
+
- ".simplecov"
|
112
|
+
- ".travis.yml"
|
113
113
|
- AUTHORS.md
|
114
|
+
- CHANGELOG.md
|
114
115
|
- CONTRIBUTING.md
|
115
116
|
- Gemfile
|
116
117
|
- LICENSE
|
@@ -131,17 +132,17 @@ require_paths:
|
|
131
132
|
- lib
|
132
133
|
required_ruby_version: !ruby/object:Gem::Requirement
|
133
134
|
requirements:
|
134
|
-
- -
|
135
|
+
- - ">="
|
135
136
|
- !ruby/object:Gem::Version
|
136
137
|
version: '0'
|
137
138
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
139
|
requirements:
|
139
|
-
- -
|
140
|
+
- - ">="
|
140
141
|
- !ruby/object:Gem::Version
|
141
142
|
version: '0'
|
142
143
|
requirements: []
|
143
144
|
rubyforge_project:
|
144
|
-
rubygems_version: 2.
|
145
|
+
rubygems_version: 2.2.2
|
145
146
|
signing_key:
|
146
147
|
specification_version: 4
|
147
148
|
summary: A drop-in replacement for e.g. MemCacheStore to store Rails sessions (and
|