redis_buddy 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,27 @@
1
+ # a namespaced Redis Cache Store for Rails 3
2
+
3
+ ## Installation
4
+
5
+ gem install redis_buddy
6
+
7
+
8
+ ## Configuration
9
+
10
+ ### Gemfile
11
+
12
+ gem "redis_buddy"
13
+
14
+ ### config/application.rb
15
+
16
+ config.cache_store = :redis_buddy_store
17
+
18
+ or
19
+
20
+ config.cache_store = :redis_buddy_store, ['127.0.0.1', '1.2.3.4']
21
+
22
+
23
+ ## Copyright
24
+
25
+ (c) 2010 Ole Riesenberg, released under the MIT license
26
+
27
+ redis-store (c) 2009 Luca Guidi - [http://lucaguidi.com](http://lucaguidi.com), released under the MIT license
@@ -0,0 +1,13 @@
1
+ # (c) 2009 Luca Guidi
2
+
3
+ class DistributedMarshaledRedis < DistRedis
4
+ def initialize(addresses)
5
+ nodes = addresses.map do |address|
6
+ MarshaledRedis.new address
7
+ end
8
+ @ring = RedisRb::HashRing.new nodes
9
+ end
10
+
11
+ alias_method :flush_db, :delete_cloud!
12
+ end
13
+
@@ -0,0 +1,36 @@
1
+ # (c) 2009 Luca Guidi
2
+
3
+ class MarshaledRedis < Redis
4
+ def set(key, val, options = nil)
5
+ val = Marshal.dump val unless raw?(options)
6
+ super key, val, expires_in(options)
7
+ end
8
+
9
+ def set_unless_exists(key, val, options = nil)
10
+ val = Marshal.dump val unless raw?(options)
11
+ super key, val
12
+ end
13
+
14
+ def get(key, options = nil)
15
+ result = call_command([:get, key])
16
+ result = Marshal.load result if unmarshal?(result, options)
17
+ result
18
+ end
19
+
20
+ private
21
+ def unmarshal?(result, options)
22
+ result && result.size > 0 && !raw?(options)
23
+ end
24
+
25
+ def raw?(options)
26
+ options && options[:raw]
27
+ end
28
+
29
+ def expires_in(options)
30
+ if options
31
+ # Rack::Session Merb Rails/Sinatra
32
+ options[:expire_after] || options[:expires_in] || options[:expire_in]
33
+ end
34
+ end
35
+ end
36
+
@@ -0,0 +1,29 @@
1
+ # (c) 2009 Luca Guidi
2
+
3
+ class RedisFactory
4
+ class << self
5
+ def create(*addresses)
6
+ addresses = extract_addresses(addresses)
7
+ if addresses.size > 1
8
+ DistributedMarshaledRedis.new addresses
9
+ else
10
+ MarshaledRedis.new addresses.first || {}
11
+ end
12
+ end
13
+
14
+ private
15
+ def extract_addresses(addresses)
16
+ addresses = addresses.flatten.compact
17
+ addresses.inject([]) do |result, address|
18
+ host, port = address.split /\:/
19
+ port, db = port.split /\// if port
20
+ address = {}
21
+ address[:host] = host if host
22
+ address[:port] = port if port
23
+ address[:db] = db.to_i if db
24
+ result << address
25
+ result
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,64 @@
1
+ module ActiveSupport
2
+ module Cache
3
+ class RedisBuddyStore < Store
4
+ def initialize(*adresses)
5
+ ns = Rails.application.class.to_s.split('::').first.downcase
6
+ @r = RedisFactory.create(adresses)
7
+ @data = Redis::Namespace.new(ns, :redis => @r)
8
+ end
9
+
10
+ def write(key, value, options = nil)
11
+ super do
12
+ method = options && options[:unless_exist] ? :set_unless_exists : :set
13
+ @data.send method, key, value, options
14
+ @data.expire key, options[:expire] if options && options[:expire]
15
+ end
16
+ end
17
+
18
+ def read(key, options = nil)
19
+ super do
20
+ @data.get key, options
21
+ end
22
+ end
23
+
24
+ def ttl(key, options = nil)
25
+ @data.ttl key, options
26
+ end
27
+
28
+ def delete(key, options = nil)
29
+ super do
30
+ @data.delete key
31
+ end
32
+ end
33
+
34
+ def exist?(key, options = nil)
35
+ super do
36
+ @data.key? key
37
+ end
38
+ end
39
+
40
+ def increment(key, amount = 1)
41
+ @data.incr key, amount
42
+ end
43
+
44
+ def decrement(key, amount = 1)
45
+ @data.decr key, amount
46
+ end
47
+
48
+ def delete_matched(matcher, options = nil)
49
+ super do
50
+ @data.keys(matcher).each { |key| @data.delete key }
51
+ end
52
+ end
53
+
54
+ def clear
55
+ @data.flush_db
56
+ end
57
+
58
+ def info
59
+ @data.info
60
+ end
61
+ end
62
+ end
63
+ end
64
+
@@ -0,0 +1,9 @@
1
+ require 'redis'
2
+ require 'redis/dist_redis'
3
+ require 'redis/namespace'
4
+
5
+ require 'redis/redis_factory'
6
+ require 'redis/marshaled_redis'
7
+ require 'redis/distributed_marshaled_redis'
8
+
9
+ require 'redis_buddy/cache_store'
@@ -0,0 +1,173 @@
1
+ require File.join(File.dirname(__FILE__), "/../spec_helper")
2
+
3
+ module ActiveSupport
4
+ module Cache
5
+ describe "ActiveSupport::Cache::RedisBuddyStore" do
6
+ before(:each) do
7
+ @store = ActiveSupport::Cache::RedisBuddyStore.new
8
+ @dstore = ActiveSupport::Cache::RedisBuddyStore.new "localhost:6380/1", "localhost:6381/1"
9
+ @rabbit = OpenStruct.new :name => "bunny"
10
+ @white_rabbit = OpenStruct.new :color => "white"
11
+ with_store_management do |store|
12
+ store.write "rabbit", @rabbit
13
+ store.delete "counter"
14
+ store.delete "rub-a-dub"
15
+ end
16
+ end
17
+
18
+ it "should accept connection params" do
19
+ redis = instantiate_store
20
+ redis.host.should == "127.0.0.1"
21
+ redis.port.should == 6379
22
+ redis.db.should == 0
23
+
24
+ redis = instantiate_store "localhost"
25
+ redis.host.should == "localhost"
26
+
27
+ redis = instantiate_store "localhost:6380"
28
+ redis.host.should == "localhost"
29
+ redis.port.should == 6380
30
+
31
+ redis = instantiate_store "localhost:6380/13"
32
+ redis.host.should == "localhost"
33
+ redis.port.should == 6380
34
+ redis.db.should == 13
35
+ end
36
+
37
+ it "should instantiate a ring" do
38
+ store = instantiate_store
39
+ store.should be_kind_of(MarshaledRedis)
40
+ store = instantiate_store ["localhost:6379/0", "localhost:6379/1"]
41
+ store.should be_kind_of(DistributedMarshaledRedis)
42
+ end
43
+
44
+ it "should read the data" do
45
+ with_store_management do |store|
46
+ store.read("rabbit").should === @rabbit
47
+ end
48
+ end
49
+
50
+ it "should write the data" do
51
+ with_store_management do |store|
52
+ store.write "rabbit", @white_rabbit
53
+ store.read("rabbit").should === @white_rabbit
54
+ end
55
+ end
56
+
57
+ it "should write the data with expiration time" do
58
+ with_store_management do |store|
59
+ store.write "rabbit", @white_rabbit, :expires_in => 1.second
60
+ store.read("rabbit").should === @white_rabbit ; sleep 2
61
+ store.read("rabbit").should be_nil
62
+ end
63
+ end
64
+
65
+ it "should not write data if :unless_exist option is true" do
66
+ with_store_management do |store|
67
+ store.write "rabbit", @white_rabbit, :unless_exist => true
68
+ store.read("rabbit").should === @rabbit
69
+ end
70
+ end
71
+
72
+ it "should read raw data" do
73
+ with_store_management do |store|
74
+ store.read("rabbit", :raw => true).should == "\004\bU:\017OpenStruct{\006:\tname\"\nbunny"
75
+ end
76
+ end
77
+
78
+ it "should write raw data" do
79
+ with_store_management do |store|
80
+ store.write "rabbit", @white_rabbit, :raw => true
81
+ store.read("rabbit", :raw => true).should == %(#<OpenStruct color="white">)
82
+ end
83
+ end
84
+
85
+ it "should delete data" do
86
+ with_store_management do |store|
87
+ store.delete "rabbit"
88
+ store.read("rabbit").should be_nil
89
+ end
90
+ end
91
+
92
+ it "should delete matched data" do
93
+ with_store_management do |store|
94
+ store.delete_matched "rabb*"
95
+ store.read("rabbit").should be_nil
96
+ end
97
+ end
98
+
99
+ it "should verify existence of an object in the store" do
100
+ with_store_management do |store|
101
+ store.exist?("rabbit").should be_true
102
+ store.exist?("rab-a-dub").should be_false
103
+ end
104
+ end
105
+
106
+ it "should increment a key" do
107
+ with_store_management do |store|
108
+ 3.times { store.increment "counter" }
109
+ store.read("counter", :raw => true).to_i.should == 3
110
+ end
111
+ end
112
+
113
+ it "should decrement a key" do
114
+ with_store_management do |store|
115
+ 3.times { store.increment "counter" }
116
+ 2.times { store.decrement "counter" }
117
+ store.read("counter", :raw => true).to_i.should == 1
118
+ end
119
+ end
120
+
121
+ it "should increment a key by given value" do
122
+ with_store_management do |store|
123
+ store.increment "counter", 3
124
+ store.read("counter", :raw => true).to_i.should == 3
125
+ end
126
+ end
127
+
128
+ it "should decrement a key by given value" do
129
+ with_store_management do |store|
130
+ 3.times { store.increment "counter" }
131
+ store.decrement "counter", 2
132
+ store.read("counter", :raw => true).to_i.should == 1
133
+ end
134
+ end
135
+
136
+ it "should clear the store" do
137
+ with_store_management do |store|
138
+ store.clear
139
+ store.instance_variable_get(:@data).keys("*").flatten.should be_empty
140
+ end
141
+ end
142
+
143
+ it "should return store stats" do
144
+ with_store_management do |store|
145
+ store.stats.should_not be_empty
146
+ end
147
+ end
148
+
149
+ it "should fetch data" do
150
+ with_store_management do |store|
151
+ store.fetch("rabbit").should == @rabbit
152
+ store.fetch("rub-a-dub").should be_nil
153
+ store.fetch("rub-a-dub") { "Flora de Cana" }
154
+ store.fetch("rub-a-dub").should === "Flora de Cana"
155
+ store.fetch("rabbit", :force => true).should be_nil # force cache miss
156
+ store.fetch("rabbit", :force => true, :expires_in => 1.second) { @white_rabbit }
157
+ store.fetch("rabbit").should === @white_rabbit ; sleep 2
158
+ store.fetch("rabbit").should be_nil
159
+ end
160
+ end
161
+
162
+ private
163
+ def instantiate_store(addresses = nil)
164
+ ActiveSupport::Cache::RedisBuddyStore.new(addresses).instance_variable_get(:@data)
165
+ end
166
+
167
+ def with_store_management
168
+ yield @store
169
+ yield @dstore
170
+ end
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,35 @@
1
+ require File.join(File.dirname(__FILE__), "/../spec_helper")
2
+
3
+ describe "DistributedMarshaledRedis" do
4
+ before(:each) do
5
+ @dmr = DistributedMarshaledRedis.new [
6
+ {:host => "localhost", :port => "6380", :db => 0},
7
+ {:host => "localhost", :port => "6381", :db => 0}
8
+ ]
9
+ @rabbit = OpenStruct.new :name => "bunny"
10
+ @white_rabbit = OpenStruct.new :color => "white"
11
+ @dmr.set "rabbit", @rabbit
12
+ end
13
+
14
+ after(:all) do
15
+ @dmr.ring.nodes.each { |server| server.flush_db }
16
+ end
17
+
18
+ it "should accept connection params" do
19
+ dmr = DistributedMarshaledRedis.new [ :host => "localhost", :port => "6380", :db => "1" ]
20
+ dmr.ring.should have(1).node
21
+ mr = dmr.ring.nodes.first
22
+ mr.host.should == "localhost"
23
+ mr.port.should == 6380
24
+ mr.db.should == 1
25
+ end
26
+
27
+ it "should set an object" do
28
+ @dmr.set "rabbit", @white_rabbit
29
+ @dmr.get("rabbit").should == @white_rabbit
30
+ end
31
+
32
+ it "should get an object" do
33
+ @dmr.get("rabbit").should == @rabbit
34
+ end
35
+ end
@@ -0,0 +1,54 @@
1
+ require File.join(File.dirname(__FILE__), "/../spec_helper")
2
+
3
+ describe "MarshaledRedis" do
4
+ before(:each) do
5
+ @store = MarshaledRedis.new
6
+ @rabbit = OpenStruct.new :name => "bunny"
7
+ @white_rabbit = OpenStruct.new :color => "white"
8
+ @store.set "rabbit", @rabbit
9
+ @store.delete "rabbit2"
10
+ end
11
+
12
+ after :each do
13
+ @store.quit
14
+ end
15
+
16
+ it "should unmarshal an object on get" do
17
+ @store.get("rabbit").should === @rabbit
18
+ end
19
+
20
+ it "should marshal object on set" do
21
+ @store.set "rabbit", @white_rabbit
22
+ @store.get("rabbit").should === @white_rabbit
23
+ end
24
+
25
+ it "should not unmarshal object on get if raw option is true" do
26
+ @store.get("rabbit", :raw => true).should == "\004\bU:\017OpenStruct{\006:\tname\"\nbunny"
27
+ end
28
+
29
+ it "should not marshal object on set if raw option is true" do
30
+ @store.set "rabbit", @white_rabbit, :raw => true
31
+ @store.get("rabbit", :raw => true).should == %(#<OpenStruct color="white">)
32
+ end
33
+
34
+ it "should not unmarshal object if getting an empty string" do
35
+ @store.set "empty_string", ""
36
+ lambda { @store.get("empty_string").should == "" }.should_not raise_error
37
+ end
38
+
39
+ it "should not set an object if already exist" do
40
+ @store.set_unless_exists "rabbit", @white_rabbit
41
+ @store.get("rabbit").should === @rabbit
42
+ end
43
+
44
+ it "should marshal object on set_unless_exists" do
45
+ @store.set_unless_exists "rabbit2", @white_rabbit
46
+ @store.get("rabbit2").should === @white_rabbit
47
+ end
48
+
49
+ it "should not marshal object on set_unless_exists if raw option is true" do
50
+ @store.set_unless_exists "rabbit2", @white_rabbit, :raw => true
51
+ @store.get("rabbit2", :raw => true).should == %(#<OpenStruct color="white">)
52
+ end
53
+ end
54
+
@@ -0,0 +1,34 @@
1
+ require File.join(File.dirname(__FILE__), "/../spec_helper")
2
+
3
+ describe "RedisFactory" do
4
+ it "should instantiate a MarshaledRedis store" do
5
+ store = RedisFactory.create
6
+ store.should be_kind_of(MarshaledRedis)
7
+ store.host.should == "127.0.0.1"
8
+ store.port.should == 6379
9
+ store.db.should == 0
10
+ end
11
+
12
+ it "should allow to specify host" do
13
+ store = RedisFactory.create "localhost"
14
+ store.host.should == "localhost"
15
+ end
16
+
17
+ it "should allow to specify port" do
18
+ store = RedisFactory.create "localhost:6380"
19
+ store.host.should == "localhost"
20
+ store.port.should == 6380
21
+ end
22
+
23
+ it "should allow to specify db" do
24
+ store = RedisFactory.create "localhost:6380/13"
25
+ store.host.should == "localhost"
26
+ store.port.should == 6380
27
+ store.db.should == 13
28
+ end
29
+
30
+ it "should instantiate a DistributedMarshaledRedis store" do
31
+ store = RedisFactory.create "localhost:6379", "localhost:6380"
32
+ store.should be_kind_of(DistributedMarshaledRedis)
33
+ end
34
+ end
@@ -0,0 +1,14 @@
1
+ $: << File.join(File.dirname(__FILE__), "/../lib")
2
+ require 'bundler'
3
+ Bundler.setup :testing
4
+ require "ostruct"
5
+ require "spec"
6
+ require "redis"
7
+ require "rails"
8
+ require "redis_buddy"
9
+
10
+ require "cache/redis_buddy_store"
11
+
12
+ class Redis; attr_reader :host, :port, :db end
13
+ $DEBUG = ENV["DEBUG"] === "true"
14
+
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: redis_buddy
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 1
9
+ version: 0.1.1
10
+ platform: ruby
11
+ authors:
12
+ - Ole Riesenberg
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-03-26 00:00:00 +01:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: redis
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ - 2
30
+ - 0
31
+ version: 0.2.0
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: redis-namespace
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ - 3
44
+ - 0
45
+ version: 0.3.0
46
+ type: :runtime
47
+ version_requirements: *id002
48
+ description: A namespaced Redis Cache Store for Rails 3, based on redis-store
49
+ email: labs@buddybrand.de
50
+ executables: []
51
+
52
+ extensions: []
53
+
54
+ extra_rdoc_files:
55
+ - README.md
56
+ files:
57
+ - lib/redis/distributed_marshaled_redis.rb
58
+ - lib/redis/marshaled_redis.rb
59
+ - lib/redis/redis_factory.rb
60
+ - lib/redis_buddy.rb
61
+ - lib/redis_buddy/cache_store.rb
62
+ - README.md
63
+ has_rdoc: true
64
+ homepage: http://buddybrand.de
65
+ licenses: []
66
+
67
+ post_install_message:
68
+ rdoc_options:
69
+ - --charset=UTF-8
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ segments:
84
+ - 0
85
+ version: "0"
86
+ requirements: []
87
+
88
+ rubyforge_project:
89
+ rubygems_version: 1.3.6
90
+ signing_key:
91
+ specification_version: 3
92
+ summary: A namespaced Redis Cache Store for Rails 3
93
+ test_files:
94
+ - spec/spec_helper.rb
95
+ - spec/redis/distributed_marshaled_redis_spec.rb
96
+ - spec/redis/marshaled_redis_spec.rb
97
+ - spec/redis/redis_factory_spec.rb
98
+ - spec/cache/redis_buddy_store.rb