redis-cache 0.0.0 → 1.0.0.rc1
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.
- data/History.txt +3 -0
- data/README.rdoc +26 -0
- data/Rakefile +5 -0
- data/lib/active_support/cache/redis_store.rb +95 -0
- data/spec/redis_store_spec.rb +151 -0
- data/spec/spec_helper.rb +4 -0
- metadata +38 -15
- data/.gitignore +0 -5
- data/Gemfile +0 -4
- data/redis-cache.gemspec +0 -20
data/History.txt
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
= redis-cache
|
2
|
+
|
3
|
+
* https://github.com/antage/redis-cache
|
4
|
+
|
5
|
+
== DESCRIPTION
|
6
|
+
|
7
|
+
ActiveSupport cache adapter for Redis.
|
8
|
+
|
9
|
+
== SYNOPSIS
|
10
|
+
|
11
|
+
=== RUBY EXAMPLE
|
12
|
+
|
13
|
+
require "active_support"
|
14
|
+
|
15
|
+
cache = ActiveSupport::Cache.lookup_store :redis_store, { :host => "localhost", :port => "6379", :db => 1, :namespace => "test-ns" }
|
16
|
+
cache.write("abc", "test") # you can use options :expires_in and :raw
|
17
|
+
cache.read("abc") # should be "test"
|
18
|
+
|
19
|
+
=== RAILS EXAMPLE
|
20
|
+
|
21
|
+
# config/environments/production.rb:
|
22
|
+
Rails3::Application.configure do
|
23
|
+
...
|
24
|
+
config.cache_store = :redis_store, { :host => "localhost", :port => 6379, :db => 1, :namespace => "rails_app" }
|
25
|
+
...
|
26
|
+
end
|
data/Rakefile
CHANGED
@@ -0,0 +1,95 @@
|
|
1
|
+
begin
|
2
|
+
require "redis"
|
3
|
+
rescue LoadError => e
|
4
|
+
$stderr.puts "You don't have redis installed in your application. Please add it to your Gemfile and run bundle install"
|
5
|
+
raise e
|
6
|
+
end
|
7
|
+
|
8
|
+
require "active_support/time"
|
9
|
+
|
10
|
+
module ActiveSupport
|
11
|
+
module Cache
|
12
|
+
class RedisStore < Store
|
13
|
+
def initialize(options = nil)
|
14
|
+
super(options)
|
15
|
+
|
16
|
+
options = { :logger => self.class.logger }.merge(options || {})
|
17
|
+
@redis = ::Redis.new(options)
|
18
|
+
|
19
|
+
extend Strategy::LocalCache
|
20
|
+
end
|
21
|
+
|
22
|
+
def reconnect
|
23
|
+
@redis and @redis.reconnect
|
24
|
+
end
|
25
|
+
|
26
|
+
def clear(options = nil)
|
27
|
+
@redis.flushdb
|
28
|
+
end
|
29
|
+
|
30
|
+
def increment(name, amount = 1, options = nil)
|
31
|
+
options = merged_options(options)
|
32
|
+
response = instrument(:increment, name, :amount => amount) do
|
33
|
+
@redis.incrby(namespaced_key(name, options), amount)
|
34
|
+
end
|
35
|
+
response
|
36
|
+
end
|
37
|
+
|
38
|
+
def decrement(name, amount = 1, options = nil)
|
39
|
+
options = merged_options(options)
|
40
|
+
response = instrument(:decrement, name, :amount => amount) do
|
41
|
+
@redis.decrby(namespaced_key(name, options), amount)
|
42
|
+
end
|
43
|
+
response
|
44
|
+
end
|
45
|
+
|
46
|
+
def read_multi(*names)
|
47
|
+
options = names.extract_options!
|
48
|
+
options = merged_options(options)
|
49
|
+
keys_to_names = Hash[names.map{|name| [namespaced_key(name, options), name]}]
|
50
|
+
raw_values = @redis.mget(*keys_to_names.keys)
|
51
|
+
values = {}
|
52
|
+
keys_to_names.keys.zip(raw_values).each do |key, value|
|
53
|
+
entry = deserialize_entry(value)
|
54
|
+
values[keys_to_names[key]] = entry.value unless entry.expired?
|
55
|
+
end
|
56
|
+
values
|
57
|
+
end
|
58
|
+
|
59
|
+
protected
|
60
|
+
def read_entry(key, options)
|
61
|
+
deserialize_entry @redis.get(key)
|
62
|
+
end
|
63
|
+
|
64
|
+
def write_entry(key, entry, options)
|
65
|
+
method = options && options[:unless_exist] ? :setnx : :set
|
66
|
+
value = options[:raw] ? entry.value : Marshal.dump(entry)
|
67
|
+
|
68
|
+
@redis.send(method, key, value)
|
69
|
+
|
70
|
+
expires_in = options[:expires_in].to_i
|
71
|
+
if expires_in > 0
|
72
|
+
if !options[:raw]
|
73
|
+
# Set the redis expire a few minutes in the future to support race condition ttls on read
|
74
|
+
expires_in += 5.minutes
|
75
|
+
end
|
76
|
+
@redis.expire(key, expires_in)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def delete_entry(key, options)
|
81
|
+
@redis.del(key)
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
def deserialize_entry(raw_value)
|
86
|
+
if raw_value
|
87
|
+
entry = Marshal.load(raw_value) rescue raw_value
|
88
|
+
entry.is_a?(Entry) ? entry : Entry.new(entry)
|
89
|
+
else
|
90
|
+
nil
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
require "active_support"
|
2
|
+
|
3
|
+
describe "ActiveSupport::Cache::RedisStore" do
|
4
|
+
let!(:redis_options) do
|
5
|
+
{
|
6
|
+
:host => "localhost",
|
7
|
+
:port => 6379,
|
8
|
+
:db => 0
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
context "ActiveSupport::Cache.lookup_store :redis_store with options" do
|
13
|
+
subject { lambda { ActiveSupport::Cache.lookup_store :redis_store, redis_options } }
|
14
|
+
|
15
|
+
it "should not raise any exceptions" do
|
16
|
+
should_not raise_error
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should return instance of ActiveSupport::Cache::RedisStore" do
|
20
|
+
subject.call.should be_instance_of(ActiveSupport::Cache::RedisStore)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "instance" do
|
25
|
+
let!(:store) { ActiveSupport::Cache.lookup_store :redis_store, redis_options }
|
26
|
+
|
27
|
+
before(:each) do
|
28
|
+
store.clear
|
29
|
+
end
|
30
|
+
|
31
|
+
context "#clear" do
|
32
|
+
before(:each) do
|
33
|
+
store.write("abc_entity", "test")
|
34
|
+
store.clear
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should clear store" do
|
38
|
+
store.read("abc_entity").should be_nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "with key 'abc' consisting 'test'" do
|
43
|
+
before(:each) do
|
44
|
+
store.write("abc", "test")
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should be #exist?" do
|
48
|
+
store.exist?("abc").should be_true
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should return 'test' when #read('abc')" do
|
52
|
+
store.read("abc").should == "test"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "with keys 'a1', 'a2', 'a3', #read_multi('a1', 'a2', 'a3')" do
|
57
|
+
before(:each) do
|
58
|
+
store.write("a1", "test1")
|
59
|
+
store.write("a2", "test2")
|
60
|
+
store.write("a3", "test3")
|
61
|
+
end
|
62
|
+
|
63
|
+
subject { store.read_multi("a1", "a2", "a3") }
|
64
|
+
|
65
|
+
(1..3).each do |i|
|
66
|
+
it "should have key 'a#{i}'" do
|
67
|
+
should be_has_key("a#{i}")
|
68
|
+
end
|
69
|
+
|
70
|
+
it "#['a#{i}'] should == 'test#{i}'" do
|
71
|
+
subject["a#{i}"].should == "test#{i}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "with raw value 5 in key 'abc'" do
|
77
|
+
before(:each) do
|
78
|
+
store.write("abc", 5, :raw => true)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "#read('abc') should return 5 as String" do
|
82
|
+
store.read("abc").should be_instance_of(String)
|
83
|
+
store.read("abc").should == "5"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context "with crazy key characters" do
|
88
|
+
let(:crazy_key) { "#/:*(<+=> )&$%@?;'\"\'`~- \t" }
|
89
|
+
|
90
|
+
it "should write the key and should not raise any exceptions" do
|
91
|
+
lambda { store.write(crazy_key, "test") }.should_not raise_error
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should read the key and should not raise any exceptions" do
|
95
|
+
lambda { store.read(crazy_key) }.should_not raise_error
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context "with raw key 'abc' == 5" do
|
100
|
+
before(:each) do
|
101
|
+
store.write("abc", 5, :raw => true)
|
102
|
+
end
|
103
|
+
|
104
|
+
it "#increment('abc', 2) should return 7 and change key 'abc' to 7" do
|
105
|
+
store.increment("abc", 2).should == 7
|
106
|
+
store.read("abc").to_i.should == 7
|
107
|
+
end
|
108
|
+
|
109
|
+
it "#decrement('abc', 2) should return 3 and change key 'abc' to 3" do
|
110
|
+
store.decrement("abc", 2).should == 3
|
111
|
+
store.read("abc").to_i.should == 3
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context "#delete('abc')" do
|
116
|
+
before(:each) do
|
117
|
+
store.write("abc", "test")
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should delete key" do
|
121
|
+
store.delete("abc")
|
122
|
+
store.exist?("abc").should be_false
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context "#fetch('abc', ...)" do
|
127
|
+
before(:each) do
|
128
|
+
store.write("abc", true)
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should fetch value from cache" do
|
132
|
+
store.fetch("abc") { false }.should be_true
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context "instances with different namespaces" do
|
138
|
+
let(:store_ns1) { ActiveSupport::Cache.lookup_store :redis_store, redis_options.merge(:namespace => "ns1") }
|
139
|
+
let(:store_ns2) { ActiveSupport::Cache.lookup_store :redis_store, redis_options.merge(:namespace => "ns2") }
|
140
|
+
|
141
|
+
before(:each) do
|
142
|
+
store_ns1.write("abc", "test1")
|
143
|
+
store_ns2.write("abc", "test2")
|
144
|
+
end
|
145
|
+
|
146
|
+
it "shouldn't inteferent each to other" do
|
147
|
+
store_ns1.read("abc").should == "test1"
|
148
|
+
store_ns2.read("abc").should == "test2"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis-cache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
version: 0.0.
|
4
|
+
prerelease: 6
|
5
|
+
version: 1.0.0.rc1
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Anton Ageev
|
@@ -10,8 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-
|
14
|
-
default_executable:
|
13
|
+
date: 2011-06-08 00:00:00 Z
|
15
14
|
dependencies:
|
16
15
|
- !ruby/object:Gem::Dependency
|
17
16
|
name: activesupport
|
@@ -30,11 +29,33 @@ dependencies:
|
|
30
29
|
requirement: &id002 !ruby/object:Gem::Requirement
|
31
30
|
none: false
|
32
31
|
requirements:
|
33
|
-
- -
|
32
|
+
- - ">="
|
34
33
|
- !ruby/object:Gem::Version
|
35
34
|
version: 2.2.0
|
36
35
|
type: :runtime
|
37
36
|
version_requirements: *id002
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: rspec
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 2.6.0
|
46
|
+
type: :development
|
47
|
+
version_requirements: *id003
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: i18n
|
50
|
+
prerelease: false
|
51
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ~>
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: 0.6.0
|
57
|
+
type: :development
|
58
|
+
version_requirements: *id004
|
38
59
|
description:
|
39
60
|
email:
|
40
61
|
- antage@gmail.com
|
@@ -45,13 +66,14 @@ extensions: []
|
|
45
66
|
extra_rdoc_files: []
|
46
67
|
|
47
68
|
files:
|
48
|
-
- .
|
49
|
-
-
|
69
|
+
- README.rdoc
|
70
|
+
- History.txt
|
50
71
|
- Rakefile
|
51
72
|
- lib/redis-cache.rb
|
52
|
-
-
|
53
|
-
|
54
|
-
|
73
|
+
- lib/active_support/cache/redis_store.rb
|
74
|
+
- spec/spec_helper.rb
|
75
|
+
- spec/redis_store_spec.rb
|
76
|
+
homepage: https://github.com/antage/redis-cache
|
55
77
|
licenses: []
|
56
78
|
|
57
79
|
post_install_message:
|
@@ -68,15 +90,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
68
90
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
91
|
none: false
|
70
92
|
requirements:
|
71
|
-
- - "
|
93
|
+
- - ">"
|
72
94
|
- !ruby/object:Gem::Version
|
73
|
-
version:
|
95
|
+
version: 1.3.1
|
74
96
|
requirements: []
|
75
97
|
|
76
98
|
rubyforge_project:
|
77
|
-
rubygems_version: 1.
|
99
|
+
rubygems_version: 1.8.5
|
78
100
|
signing_key:
|
79
101
|
specification_version: 3
|
80
102
|
summary: ActiveSupport cache adapter for Redis
|
81
|
-
test_files:
|
82
|
-
|
103
|
+
test_files:
|
104
|
+
- spec/spec_helper.rb
|
105
|
+
- spec/redis_store_spec.rb
|
data/Gemfile
DELETED
data/redis-cache.gemspec
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
|
-
$:.push File.expand_path("../lib", __FILE__)
|
3
|
-
|
4
|
-
Gem::Specification.new do |s|
|
5
|
-
s.name = "redis-cache"
|
6
|
-
s.version = "0.0.0"
|
7
|
-
s.platform = Gem::Platform::RUBY
|
8
|
-
s.authors = ["Anton Ageev"]
|
9
|
-
s.email = ["antage@gmail.com"]
|
10
|
-
s.homepage = ""
|
11
|
-
s.summary = %q{ActiveSupport cache adapter for Redis}
|
12
|
-
|
13
|
-
s.files = `git ls-files`.split("\n")
|
14
|
-
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
15
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
16
|
-
s.require_paths = ["lib"]
|
17
|
-
|
18
|
-
s.add_dependency "activesupport", ">= 3.0.0"
|
19
|
-
s.add_dependency "redis", "~> 2.2.0"
|
20
|
-
end
|