jodosha-redis-store 0.0.3 → 0.1.0
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/README.textile +15 -1
- data/Rakefile +1 -1
- data/lib/cache/sinatra/redis_store.rb +131 -0
- data/lib/redis-store.rb +3 -1
- data/redis-store.gemspec +3 -3
- data/spec/cache/rails/redis_store_spec.rb +1 -0
- data/spec/cache/sinatra/redis_store_spec.rb +192 -0
- data/spec/spec_helper.rb +1 -0
- metadata +4 -1
data/README.textile
CHANGED
@@ -24,13 +24,27 @@ In your configuration files:
|
|
24
24
|
|
25
25
|
h2. How to use with Merb
|
26
26
|
|
27
|
-
dependency "redis-store", "0.0
|
27
|
+
dependency "jodosha-redis-store", "0.1.0"
|
28
28
|
dependency("merb-cache", merb_gems_version) do
|
29
29
|
Merb::Cache.setup do
|
30
30
|
register(:redis, Merb::Cache::RedisStore, :servers => ["127.0.0.1:6379"])
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
+
h2. How to use with Sinatra
|
35
|
+
|
36
|
+
require 'rubygems'
|
37
|
+
require 'sinatra'
|
38
|
+
require 'jodosha-redis-store'
|
39
|
+
|
40
|
+
class MyApp < Sinatra::Base
|
41
|
+
register Sinatra::Cache
|
42
|
+
|
43
|
+
get '/hi' do
|
44
|
+
cache.fetch("greet") { "Hello, World!" }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
34
48
|
h2. Copyright
|
35
49
|
|
36
50
|
(c) 2009 Luca Guidi - http://lucaguidi.com, released under the MIT license
|
data/Rakefile
CHANGED
@@ -0,0 +1,131 @@
|
|
1
|
+
module Sinatra
|
2
|
+
module Cache
|
3
|
+
class << self
|
4
|
+
def register(app)
|
5
|
+
app.set :cache, RedisStore.new
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class RedisStore
|
10
|
+
# Instantiate the store.
|
11
|
+
#
|
12
|
+
# Example:
|
13
|
+
# RedisStore.new # => host: localhost, port: 6379, db: 0
|
14
|
+
# RedisStore.new "example.com" # => host: example.com, port: 6379, db: 0
|
15
|
+
# RedisStore.new "example.com:23682" # => host: example.com, port: 23682, db: 0
|
16
|
+
# RedisStore.new "example.com:23682/1" # => host: example.com, port: 23682, db: 1
|
17
|
+
# RedisStore.new "localhost:6379/0", "localhost:6380/0" # => instantiate a cluster
|
18
|
+
def initialize(*addresses)
|
19
|
+
addresses = extract_addresses(addresses)
|
20
|
+
@data = if addresses.size > 1
|
21
|
+
DistributedMarshaledRedis.new addresses
|
22
|
+
else
|
23
|
+
MarshaledRedis.new addresses.first || {}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def write(key, value, options = nil)
|
28
|
+
method = options && options[:unless_exist] ? :set_unless_exists : :set
|
29
|
+
@data.send method, key, value, options
|
30
|
+
end
|
31
|
+
|
32
|
+
def read(key, options = nil)
|
33
|
+
@data.get key, options
|
34
|
+
end
|
35
|
+
|
36
|
+
def delete(key, options = nil)
|
37
|
+
@data.delete key
|
38
|
+
end
|
39
|
+
|
40
|
+
def exist?(key, options = nil)
|
41
|
+
@data.key? key
|
42
|
+
end
|
43
|
+
|
44
|
+
# Increment a key in the store.
|
45
|
+
#
|
46
|
+
# If the key doesn't exist it will be initialized on 0.
|
47
|
+
# If the key exist but it isn't a Fixnum it will be initialized on 0.
|
48
|
+
#
|
49
|
+
# Example:
|
50
|
+
# We have two objects in cache:
|
51
|
+
# counter # => 23
|
52
|
+
# rabbit # => #<Rabbit:0x5eee6c>
|
53
|
+
#
|
54
|
+
# cache.increment "counter"
|
55
|
+
# cache.read "counter", :raw => true # => "24"
|
56
|
+
#
|
57
|
+
# cache.increment "counter", 6
|
58
|
+
# cache.read "counter", :raw => true # => "30"
|
59
|
+
#
|
60
|
+
# cache.increment "a counter"
|
61
|
+
# cache.read "a counter", :raw => true # => "1"
|
62
|
+
#
|
63
|
+
# cache.increment "rabbit"
|
64
|
+
# cache.read "rabbit", :raw => true # => "1"
|
65
|
+
def increment(key, amount = 1)
|
66
|
+
@data.incr key, amount
|
67
|
+
end
|
68
|
+
|
69
|
+
# Decrement a key in the store
|
70
|
+
#
|
71
|
+
# If the key doesn't exist it will be initialized on 0.
|
72
|
+
# If the key exist but it isn't a Fixnum it will be initialized on 0.
|
73
|
+
#
|
74
|
+
# Example:
|
75
|
+
# We have two objects in cache:
|
76
|
+
# counter # => 23
|
77
|
+
# rabbit # => #<Rabbit:0x5eee6c>
|
78
|
+
#
|
79
|
+
# cache.decrement "counter"
|
80
|
+
# cache.read "counter", :raw => true # => "22"
|
81
|
+
#
|
82
|
+
# cache.decrement "counter", 2
|
83
|
+
# cache.read "counter", :raw => true # => "20"
|
84
|
+
#
|
85
|
+
# cache.decrement "a counter"
|
86
|
+
# cache.read "a counter", :raw => true # => "-1"
|
87
|
+
#
|
88
|
+
# cache.decrement "rabbit"
|
89
|
+
# cache.read "rabbit", :raw => true # => "-1"
|
90
|
+
def decrement(key, amount = 1)
|
91
|
+
@data.decr key, amount
|
92
|
+
end
|
93
|
+
|
94
|
+
# Delete objects for matched keys.
|
95
|
+
#
|
96
|
+
# Example:
|
97
|
+
# cache.delete_matched "rab*"
|
98
|
+
def delete_matched(matcher, options = nil)
|
99
|
+
@data.keys(matcher).each { |key| @data.delete key }
|
100
|
+
end
|
101
|
+
|
102
|
+
def fetch(key, options = {})
|
103
|
+
(!options[:force] && data = read(key, options)) || (write key, yield, options if block_given?)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Clear all the data from the store.
|
107
|
+
def clear
|
108
|
+
@data.flush_db
|
109
|
+
end
|
110
|
+
|
111
|
+
def stats
|
112
|
+
@data.info
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
def extract_addresses(addresses) # TODO extract in a module or a class
|
117
|
+
addresses = addresses.flatten.compact
|
118
|
+
addresses.inject([]) do |result, address|
|
119
|
+
host, port = address.split /\:/
|
120
|
+
port, db = port.split /\// if port
|
121
|
+
address = {}
|
122
|
+
address[:host] = host if host
|
123
|
+
address[:port] = port if port
|
124
|
+
address[:db] = db.to_i if db
|
125
|
+
result << address
|
126
|
+
result
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
data/lib/redis-store.rb
CHANGED
@@ -3,7 +3,9 @@ require "dist_redis"
|
|
3
3
|
require "redis/marshaled_redis"
|
4
4
|
require "redis/distributed_marshaled_redis"
|
5
5
|
|
6
|
-
if defined?(
|
6
|
+
if defined?(Sinatra)
|
7
|
+
require "cache/sinatra/redis_store"
|
8
|
+
elsif defined?(Merb)
|
7
9
|
# HACK for cyclic dependency: redis-store is required before merb-cache
|
8
10
|
module Merb; module Cache; class AbstractStore; end end end
|
9
11
|
require "cache/merb/redis_store"
|
data/redis-store.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "redis-store"
|
3
|
-
s.version = "0.0
|
3
|
+
s.version = "0.1.0"
|
4
4
|
s.date = "2009-04-30"
|
5
5
|
s.summary = "Redis cache and session stores for Ruby web frameworks"
|
6
6
|
s.author = "Luca Guidi"
|
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.homepage = "http://lucaguidi.com"
|
9
9
|
s.description = "Redis cache and session stores for Ruby web frameworks"
|
10
10
|
s.has_rdoc = true
|
11
|
-
s.files = ["MIT-LICENSE", "README.textile", "Rakefile", "lib/cache/merb/redis_store.rb", "lib/cache/rails/redis_store.rb", "lib/redis-store.rb", "lib/redis/distributed_marshaled_redis.rb", "lib/redis/marshaled_redis.rb", "redis-store.gemspec", "spec/cache/merb/redis_store_spec.rb", "spec/cache/rails/redis_store_spec.rb", "spec/config/master.conf", "spec/config/single.conf", "spec/config/slave.conf", "spec/redis/distributed_marshaled_redis_spec.rb", "spec/redis/marshaled_redis_spec.rb", "spec/spec_helper.rb"]
|
12
|
-
s.test_files = ["spec/cache/merb/redis_store_spec.rb", "spec/cache/rails/redis_store_spec.rb", "spec/redis/distributed_marshaled_redis_spec.rb", "spec/redis/marshaled_redis_spec.rb"]
|
11
|
+
s.files = ["MIT-LICENSE", "README.textile", "Rakefile", "lib/cache/merb/redis_store.rb", "lib/cache/rails/redis_store.rb", "lib/cache/sinatra/redis_store.rb", "lib/redis-store.rb", "lib/redis/distributed_marshaled_redis.rb", "lib/redis/marshaled_redis.rb", "redis-store.gemspec", "spec/cache/merb/redis_store_spec.rb", "spec/cache/rails/redis_store_spec.rb", "spec/cache/sinatra/redis_store_spec.rb", "spec/config/master.conf", "spec/config/single.conf", "spec/config/slave.conf", "spec/redis/distributed_marshaled_redis_spec.rb", "spec/redis/marshaled_redis_spec.rb", "spec/spec_helper.rb"]
|
12
|
+
s.test_files = ["spec/cache/merb/redis_store_spec.rb", "spec/cache/rails/redis_store_spec.rb", "spec/cache/sinatra/redis_store_spec.rb", "spec/redis/distributed_marshaled_redis_spec.rb", "spec/redis/marshaled_redis_spec.rb"]
|
13
13
|
s.extra_rdoc_files = ["README.textile"]
|
14
14
|
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "/../../spec_helper")
|
2
|
+
|
3
|
+
class App
|
4
|
+
def initialize
|
5
|
+
@values = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def set(key, value)
|
9
|
+
@values[key] = value
|
10
|
+
end
|
11
|
+
|
12
|
+
def get(key)
|
13
|
+
@values[key]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module Sinatra
|
18
|
+
module Cache
|
19
|
+
describe "RedisStore" do
|
20
|
+
before(:each) do
|
21
|
+
@store = RedisStore.new
|
22
|
+
@dstore = RedisStore.new "localhost:6380/1", "localhost:6381/1"
|
23
|
+
@rabbit = OpenStruct.new :name => "bunny"
|
24
|
+
@white_rabbit = OpenStruct.new :color => "white"
|
25
|
+
with_store_management do |store|
|
26
|
+
store.write "rabbit", @rabbit
|
27
|
+
store.delete "counter"
|
28
|
+
store.delete "rub-a-dub"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should register as extension" do
|
33
|
+
app = App.new
|
34
|
+
Sinatra::Cache.register(app)
|
35
|
+
store = app.get(:cache)
|
36
|
+
store.should be_kind_of(RedisStore)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should accept connection params" do
|
40
|
+
redis = instantiate_store
|
41
|
+
redis.instance_variable_get(:@db).should == 0
|
42
|
+
redis.host.should == "localhost"
|
43
|
+
redis.port.should == "6379"
|
44
|
+
|
45
|
+
redis = instantiate_store "redis.com"
|
46
|
+
redis.host.should == "redis.com"
|
47
|
+
|
48
|
+
redis = instantiate_store "redis.com:6380"
|
49
|
+
redis.host.should == "redis.com"
|
50
|
+
redis.port.should == "6380"
|
51
|
+
|
52
|
+
redis = instantiate_store "redis.com:6380/23"
|
53
|
+
redis.instance_variable_get(:@db).should == 23
|
54
|
+
redis.host.should == "redis.com"
|
55
|
+
redis.port.should == "6380"
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should instantiate a ring" do
|
59
|
+
store = instantiate_store
|
60
|
+
store.should be_kind_of(MarshaledRedis)
|
61
|
+
store = instantiate_store ["localhost:6379/0", "localhost:6379/1"]
|
62
|
+
store.should be_kind_of(DistributedMarshaledRedis)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should read the data" do
|
66
|
+
with_store_management do |store|
|
67
|
+
store.read("rabbit").should === @rabbit
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should write the data" do
|
72
|
+
with_store_management do |store|
|
73
|
+
store.write "rabbit", @white_rabbit
|
74
|
+
store.read("rabbit").should === @white_rabbit
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# it "should write the data with expiration time" do
|
79
|
+
# @store.write "rabbit", @white_rabbit, :expires_in => 1.second
|
80
|
+
# @store.read("rabbit").should === @white_rabbit ; sleep 2
|
81
|
+
# @store.read("rabbit").should be_nil
|
82
|
+
# end
|
83
|
+
|
84
|
+
it "should not write data if :unless_exist option is true" do
|
85
|
+
with_store_management do |store|
|
86
|
+
store.write "rabbit", @white_rabbit, :unless_exist => true
|
87
|
+
store.read("rabbit").should === @rabbit
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should read raw data" do
|
92
|
+
with_store_management do |store|
|
93
|
+
store.read("rabbit", :raw => true).should == "\004\bU:\017OpenStruct{\006:\tname\"\nbunny"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should write raw data" do
|
98
|
+
with_store_management do |store|
|
99
|
+
store.write "rabbit", @white_rabbit, :raw => true
|
100
|
+
store.read("rabbit", :raw => true).should == %(#<OpenStruct color="white">)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should delete data" do
|
105
|
+
with_store_management do |store|
|
106
|
+
store.delete "rabbit"
|
107
|
+
store.read("rabbit").should be_nil
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should delete matched data" do
|
112
|
+
with_store_management do |store|
|
113
|
+
store.delete_matched "rabb*"
|
114
|
+
store.read("rabbit").should be_nil
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should verify existence of an object in the store" do
|
119
|
+
with_store_management do |store|
|
120
|
+
store.exist?("rabbit").should be_true
|
121
|
+
store.exist?("rab-a-dub").should be_false
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should increment a key" do
|
126
|
+
with_store_management do |store|
|
127
|
+
3.times { store.increment "counter" }
|
128
|
+
store.read("counter", :raw => true).to_i.should == 3
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should decrement a key" do
|
133
|
+
with_store_management do |store|
|
134
|
+
3.times { store.increment "counter" }
|
135
|
+
2.times { store.decrement "counter" }
|
136
|
+
store.read("counter", :raw => true).to_i.should == 1
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should increment a key by given value" do
|
141
|
+
with_store_management do |store|
|
142
|
+
store.increment "counter", 3
|
143
|
+
store.read("counter", :raw => true).to_i.should == 3
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should decrement a key by given value" do
|
148
|
+
with_store_management do |store|
|
149
|
+
3.times { store.increment "counter" }
|
150
|
+
store.decrement "counter", 2
|
151
|
+
store.read("counter", :raw => true).to_i.should == 1
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should clear the store" do
|
156
|
+
with_store_management do |store|
|
157
|
+
store.clear
|
158
|
+
store.instance_variable_get(:@data).keys("*").should be_empty
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
it "should return store stats" do
|
163
|
+
with_store_management do |store|
|
164
|
+
store.stats.should_not be_empty
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should fetch data" do
|
169
|
+
with_store_management do |store|
|
170
|
+
store.fetch("rabbit").should == @rabbit
|
171
|
+
store.fetch("rub-a-dub").should be_nil
|
172
|
+
store.fetch("rub-a-dub") { "Flora de Cana" }
|
173
|
+
store.fetch("rub-a-dub").should === "Flora de Cana"
|
174
|
+
store.fetch("rabbit", :force => true).should be_nil # force cache miss
|
175
|
+
# store.fetch("rabbit", :force => true, :expires_in => 1.second) { @white_rabbit }
|
176
|
+
# store.fetch("rabbit").should === @white_rabbit ; sleep 2
|
177
|
+
# store.fetch("rabbit").should be_nil
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
private
|
182
|
+
def instantiate_store(addresses = nil)
|
183
|
+
RedisStore.new(addresses).instance_variable_get(:@data)
|
184
|
+
end
|
185
|
+
|
186
|
+
def with_store_management
|
187
|
+
yield @store
|
188
|
+
yield @dstore
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jodosha-redis-store
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luca Guidi
|
@@ -27,12 +27,14 @@ files:
|
|
27
27
|
- Rakefile
|
28
28
|
- lib/cache/merb/redis_store.rb
|
29
29
|
- lib/cache/rails/redis_store.rb
|
30
|
+
- lib/cache/sinatra/redis_store.rb
|
30
31
|
- lib/redis-store.rb
|
31
32
|
- lib/redis/distributed_marshaled_redis.rb
|
32
33
|
- lib/redis/marshaled_redis.rb
|
33
34
|
- redis-store.gemspec
|
34
35
|
- spec/cache/merb/redis_store_spec.rb
|
35
36
|
- spec/cache/rails/redis_store_spec.rb
|
37
|
+
- spec/cache/sinatra/redis_store_spec.rb
|
36
38
|
- spec/config/master.conf
|
37
39
|
- spec/config/single.conf
|
38
40
|
- spec/config/slave.conf
|
@@ -68,5 +70,6 @@ summary: Redis cache and session stores for Ruby web frameworks
|
|
68
70
|
test_files:
|
69
71
|
- spec/cache/merb/redis_store_spec.rb
|
70
72
|
- spec/cache/rails/redis_store_spec.rb
|
73
|
+
- spec/cache/sinatra/redis_store_spec.rb
|
71
74
|
- spec/redis/distributed_marshaled_redis_spec.rb
|
72
75
|
- spec/redis/marshaled_redis_spec.rb
|