honkster-redis-store 0.3.10

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ *.rdb
2
+ *.swp
3
+ *.gem
4
+ *-redis-store.gemspec
5
+ bin/
6
+ coverage/
7
+ pkg/
8
+ vendor/
9
+ tmp/
10
+ .idea
11
+ .bundle
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ gem "redis", "1.0.5"
2
+
3
+ # testing gems
4
+ group :testing do
5
+ gem "ruby-debug"
6
+ gem "rspec"
7
+ gem "rack", "1.1.0"
8
+ gem "rack-cache"
9
+ gem "activesupport"
10
+ gem "actionpack"
11
+ gem "merb"
12
+ gem "jeweler"
13
+ gem "git"
14
+ end
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Luca Guidi
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,105 @@
1
+ # Rack::Session, Rack::Cache and cache Redis stores for Ruby web frameworks
2
+
3
+ ## Installation
4
+
5
+ Download and install Redis from [http://code.google.com/p/redis/](http://code.google.com/p/redis/)
6
+
7
+ curl -OL http://redis.googlecode.com/files/redis-1.02.tar.gz
8
+ tar -zxvf redis-1.02.tar.gz
9
+ mv redis-1.02 redis
10
+ cd redis
11
+ make
12
+
13
+ Install the gems
14
+
15
+ sudo gem install redis-rb redis-store
16
+
17
+ ## Cache store
18
+
19
+ Provides a cache store for your Ruby web framework of choice.
20
+
21
+ ### Rails
22
+
23
+ config.gem "redis-store", :source => "http://gemcutter.org", :lib => "redis-store"
24
+ require "redis-store"
25
+ config.cache_store = :redis_store
26
+
27
+ ### Merb
28
+
29
+ dependency "redis-store", "0.3.7"
30
+ dependency("merb-cache", merb_gems_version) do
31
+ Merb::Cache.setup do
32
+ register(:redis, Merb::Cache::RedisStore, :servers => ["127.0.0.1:6379"])
33
+ end
34
+ end
35
+
36
+ ### Sinatra
37
+
38
+ require "sinatra"
39
+ require "redis-store"
40
+ class MyApp < Sinatra::Base
41
+ register Sinatra::Cache
42
+ get "/hi" do
43
+ cache.fetch("greet") { "Hello, World!" }
44
+ end
45
+ end
46
+
47
+ ## Rack::Session
48
+
49
+ Provides a Redis store for Rack::Session. See [http://rack.rubyforge.org/doc/Rack/Session.html](http://rack.rubyforge.org/doc/Rack/Session.html)
50
+
51
+ ### Rack application
52
+
53
+ require "rack"
54
+ require "redis-store"
55
+ require "application"
56
+ use Rack::Session::Redis
57
+ run Application.new
58
+
59
+ ### Rails
60
+
61
+ config.gem "redis-store", :source => "http://gemcutter.org", :lib => "redis-store"
62
+ ActionController::Base.session_store = Rack::Session::Redis
63
+
64
+ ### Merb
65
+
66
+ dependency "redis-store", "0.3.7"
67
+ Merb::Config.use do |c|
68
+ c[:session_store] = "redis"
69
+ end
70
+ Merb::BootLoader.before_app_loads do
71
+ Merb::SessionContainer.subclasses << "Merb::RedisSession"
72
+ end
73
+
74
+ ### Sinatra
75
+
76
+ Sorry, but Sinatra application boot system [hardcode](http://github.com/sinatra/sinatra/blob/0f02bafe86f8dd9bba9ab425468cb1067caa83ff/lib/sinatra/base.rb#L785) `Rack::Session::Cookie`
77
+
78
+ ## Rack::Cache
79
+
80
+ Provides a Redis store for HTTP caching. See [http://github.com/rtomayko/rack-cache](http://github.com/rtomayko/rack-cache)
81
+
82
+ require "rack"
83
+ require "rack/cache"
84
+ require "redis-store"
85
+ require "application"
86
+ use Rack::Cache,
87
+ :metastore => 'redis://localhost:6379/0',
88
+ :entitystore => 'redis://localhost:6380/1'
89
+ run Application.new
90
+
91
+ ## Running specs
92
+
93
+ gem install jeweler bundler
94
+ git clone git://github.com/jodosha/redis-store.git
95
+ cd redis-store
96
+ gem bundle
97
+ rake dtach:install
98
+ rake redis:install
99
+ rake
100
+
101
+ If you are on **Snow Leopard** you have to run `env ARCHFLAGS="-arch x86_64" gem bundle`
102
+
103
+ ## Copyright
104
+
105
+ (c) 2009 Luca Guidi - [http://lucaguidi.com](http://lucaguidi.com), released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,70 @@
1
+ $:.unshift 'lib'
2
+ require 'rubygems'
3
+ require 'rake'
4
+ require 'rake/testtask'
5
+ require 'rake/rdoctask'
6
+ require 'spec/rake/spectask'
7
+
8
+ task :default => "spec:suite"
9
+
10
+ begin
11
+ require "jeweler"
12
+ Jeweler::Tasks.new do |gemspec|
13
+ gemspec.name = "#{ENV["GEM_PREFIX"]}redis-store"
14
+ gemspec.summary = "Rack::Session, Rack::Cache and cache Redis stores for Ruby web frameworks."
15
+ gemspec.description = "Rack::Session, Rack::Cache and cache Redis stores for Ruby web frameworks."
16
+ gemspec.email = "guidi.luca@gmail.com"
17
+ gemspec.homepage = "http://github.com/jodosha/redis-store"
18
+ gemspec.authors = [ "Luca Guidi" ]
19
+ end
20
+
21
+ Jeweler::GemcutterTasks.new
22
+ rescue LoadError
23
+ puts "Jeweler not available. Install it with: sudo gem install jeweler"
24
+ end
25
+
26
+ namespace :spec do
27
+ desc "Run all the examples by starting a detached Redis instance"
28
+ task :suite do
29
+ invoke_with_redis_cluster "spec:run"
30
+ end
31
+
32
+ Spec::Rake::SpecTask.new(:run) do |t|
33
+ t.spec_files = FileList['spec/**/*_spec.rb']
34
+ t.spec_opts = %w(-fs --color)
35
+ end
36
+ end
37
+
38
+ desc "Run all examples with RCov"
39
+ task :rcov do
40
+ invoke_with_redis_cluster "rcov_run"
41
+ end
42
+
43
+ Spec::Rake::SpecTask.new(:rcov_run) do |t|
44
+ t.spec_files = FileList['spec/**/*_spec.rb']
45
+ t.rcov = true
46
+ end
47
+
48
+ namespace :redis_cluster do
49
+ desc "Starts the redis_cluster"
50
+ task :start do
51
+ result = RedisClusterRunner.start_detached
52
+ raise("Could not start redis-server, aborting.") unless result
53
+ end
54
+
55
+ desc "Stops the redis_cluster"
56
+ task :stop do
57
+ RedisClusterRunner.stop
58
+ end
59
+ end
60
+
61
+ # courtesy of http://github.com/ezmobius/redis-rb team
62
+ load "tasks/redis.tasks.rb"
63
+ def invoke_with_redis_cluster(task_name)
64
+ begin
65
+ Rake::Task["redis_cluster:start"].invoke
66
+ Rake::Task[task_name].invoke
67
+ ensure
68
+ Rake::Task["redis_cluster:stop"].invoke
69
+ end
70
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.3.10
@@ -0,0 +1,63 @@
1
+ module Merb
2
+ module Cache
3
+ class RedisStore < AbstractStore
4
+ # Instantiate the store.
5
+ #
6
+ # Example:
7
+ # RedisStore.new # => host: localhost, port: 6379, db: 0
8
+ # RedisStore.new :servers => ["example.com"] # => host: example.com, port: 6379, db: 0
9
+ # RedisStore.new :servers => ["example.com:23682"] # => host: example.com, port: 23682, db: 0
10
+ # RedisStore.new :servers => ["example.com:23682/1"] # => host: example.com, port: 23682, db: 1
11
+ # RedisStore.new :servers => ["localhost:6379/0", "localhost:6380/0"] # => instantiate a cluster
12
+ def initialize(config = {})
13
+ @data = RedisFactory.create config[:servers]
14
+ end
15
+
16
+ def writable?(key, parameters = {}, conditions = {})
17
+ true
18
+ end
19
+
20
+ def read(key, parameters = {}, conditions = {})
21
+ @data.marshalled_get normalize(key, parameters), conditions
22
+ end
23
+
24
+ def write(key, data = nil, parameters = {}, conditions = {})
25
+ if writable?(key, parameters, conditions)
26
+ method = conditions && conditions[:unless_exist] ? :marshalled_setnx : :marshalled_set
27
+ @data.send method, normalize(key, parameters), data, conditions
28
+ end
29
+ end
30
+
31
+ def write_all(key, data = nil, parameters = {}, conditions = {})
32
+ write key, data, parameters, conditions
33
+ end
34
+
35
+ def fetch(key, parameters = {}, conditions = {}, &blk)
36
+ read(key, parameters) || (write key, yield, parameters, conditions if block_given?)
37
+ end
38
+
39
+ def exists?(key, parameters = {})
40
+ @data.exists normalize(key, parameters)
41
+ end
42
+
43
+ def delete(key, parameters = {})
44
+ @data.del normalize(key, parameters)
45
+ end
46
+
47
+ def delete_all
48
+ @data.flushdb
49
+ end
50
+
51
+ def delete_all!
52
+ delete_all
53
+ end
54
+
55
+ private
56
+ # Returns cache key calculated from base key
57
+ # and SHA2 hex from parameters.
58
+ def normalize(key, parameters = {})
59
+ parameters.empty? ? "#{key}" : "#{key}--#{parameters.to_sha2}"
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,61 @@
1
+ module ActionController
2
+ module Session
3
+ # Redis session storage for Rails, and for Rails only. Derived from
4
+ # the MemCacheStore code, simply dropping in Redis instead.
5
+ #
6
+ # Options:
7
+ # :key => Same as with the other cookie stores, key name
8
+ # :secret => Encryption secret for the key
9
+ # :host => Redis host name, default is localhost
10
+ # :port => Redis port, default is 6379
11
+ # :db => Database number, defaults to 0. Useful to separate your session storage from other data
12
+ # :key_prefix => Prefix for keys used in Redis, e.g. myapp-. Useful to separate session storage keys visibly from others
13
+ # :expire_after => A number in seconds to set the timeout interval for the session. Will map directly to expiry in Redis
14
+
15
+ class RedisSessionStore < ActionController::Session::AbstractStore
16
+
17
+ def initialize(app, options = {})
18
+ # Support old :expires option
19
+ options[:expire_after] ||= options[:expires]
20
+
21
+ super
22
+
23
+ @options = { :key_prefix => "" }.update(options)
24
+ servers = [options[:servers]].flatten.compact.map do |server_options|
25
+ {
26
+ :namespace => 'rack:session',
27
+ :host => 'localhost',
28
+ :port => '6379',
29
+ :db => 0
30
+ }.update(RedisFactory.convert_to_redis_client_options(server_options))
31
+ end
32
+
33
+ @pool = RedisFactory.create(*servers)
34
+ end
35
+
36
+ private
37
+ def prefixed(sid)
38
+ "#{@options[:key_prefix]}#{sid}"
39
+ end
40
+
41
+ def get_session(env, sid)
42
+ sid ||= generate_sid
43
+ begin
44
+ session = @pool.marshalled_get(prefixed(sid)) || {}
45
+ rescue Errno::ECONNREFUSED
46
+ session = {}
47
+ end
48
+ [sid, session]
49
+ end
50
+
51
+ def set_session(env, sid, session_data)
52
+ options = env['rack.session.options']
53
+ @pool.marshalled_set(prefixed(sid), session_data, options)
54
+ return true
55
+ rescue Errno::ECONNREFUSED
56
+ return false
57
+ end
58
+
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,109 @@
1
+ module ActiveSupport
2
+ module Cache
3
+ class RedisStore < Store
4
+ # Instantiate the store.
5
+ #
6
+ # Example:
7
+ # RedisStore.new # => host: localhost, port: 6379, db: 0
8
+ # RedisStore.new "example.com" # => host: example.com, port: 6379, db: 0
9
+ # RedisStore.new "example.com:23682" # => host: example.com, port: 23682, db: 0
10
+ # RedisStore.new "example.com:23682/1" # => host: example.com, port: 23682, db: 1
11
+ # RedisStore.new "localhost:6379/0", "localhost:6380/0" # => instantiate a cluster
12
+ def initialize(*addresses)
13
+ @data = RedisFactory.create(addresses)
14
+ end
15
+
16
+ def write(key, value, options = nil)
17
+ super
18
+ method = options && options[:unless_exist] ? :marshalled_setnx : :marshalled_set
19
+ @data.send method, key, value, options
20
+ end
21
+
22
+ def read(key, options = nil)
23
+ super
24
+ @data.marshalled_get key, options
25
+ end
26
+
27
+ def delete(key, options = nil)
28
+ super
29
+ @data.del key
30
+ end
31
+
32
+ def exist?(key, options = nil)
33
+ super
34
+ @data.exists key
35
+ end
36
+
37
+ # Increment a key in the store.
38
+ #
39
+ # If the key doesn't exist it will be initialized on 0.
40
+ # If the key exist but it isn't a Fixnum it will be initialized on 0.
41
+ #
42
+ # Example:
43
+ # We have two objects in cache:
44
+ # counter # => 23
45
+ # rabbit # => #<Rabbit:0x5eee6c>
46
+ #
47
+ # cache.increment "counter"
48
+ # cache.read "counter", :raw => true # => "24"
49
+ #
50
+ # cache.increment "counter", 6
51
+ # cache.read "counter", :raw => true # => "30"
52
+ #
53
+ # cache.increment "a counter"
54
+ # cache.read "a counter", :raw => true # => "1"
55
+ #
56
+ # cache.increment "rabbit"
57
+ # cache.read "rabbit", :raw => true # => "1"
58
+ def increment(key, amount = 1)
59
+ log "increment", key, amount
60
+ @data.incrby key, amount
61
+ end
62
+
63
+ # Decrement a key in the store
64
+ #
65
+ # If the key doesn't exist it will be initialized on 0.
66
+ # If the key exist but it isn't a Fixnum it will be initialized on 0.
67
+ #
68
+ # Example:
69
+ # We have two objects in cache:
70
+ # counter # => 23
71
+ # rabbit # => #<Rabbit:0x5eee6c>
72
+ #
73
+ # cache.decrement "counter"
74
+ # cache.read "counter", :raw => true # => "22"
75
+ #
76
+ # cache.decrement "counter", 2
77
+ # cache.read "counter", :raw => true # => "20"
78
+ #
79
+ # cache.decrement "a counter"
80
+ # cache.read "a counter", :raw => true # => "-1"
81
+ #
82
+ # cache.decrement "rabbit"
83
+ # cache.read "rabbit", :raw => true # => "-1"
84
+ def decrement(key, amount = 1)
85
+ log "decrement", key, amount
86
+ @data.decrby key, amount
87
+ end
88
+
89
+ # Delete objects for matched keys.
90
+ #
91
+ # Example:
92
+ # cache.del_matched "rab*"
93
+ def delete_matched(matcher, options = nil)
94
+ super
95
+ @data.keys(matcher).each { |key| @data.del key }
96
+ end
97
+
98
+ # Clear all the data from the store.
99
+ def clear
100
+ log "clear", nil, nil
101
+ @data.flushdb
102
+ end
103
+
104
+ def stats
105
+ @data.info
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,118 @@
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
+ @data = RedisFactory.create addresses
20
+ end
21
+
22
+ def write(key, value, options = nil)
23
+ if options
24
+ if options[:unless_exist]
25
+ @data.marshalled_setnx key, value, options
26
+ else
27
+ @data.marshalled_set key, value, options
28
+ end
29
+ else
30
+ @data.marshalled_set key, value
31
+ end
32
+ end
33
+
34
+ def read(key, options = nil)
35
+ @data.marshalled_get(key, options)
36
+ end
37
+
38
+ def delete(key, options = nil)
39
+ @data.del key
40
+ end
41
+
42
+ def exist?(key, options = nil)
43
+ @data.exists key
44
+ end
45
+
46
+ # Increment a key in the store.
47
+ #
48
+ # If the key doesn't exist it will be initialized on 0.
49
+ # If the key exist but it isn't a Fixnum it will be initialized on 0.
50
+ #
51
+ # Example:
52
+ # We have two objects in cache:
53
+ # counter # => 23
54
+ # rabbit # => #<Rabbit:0x5eee6c>
55
+ #
56
+ # cache.increment "counter"
57
+ # cache.read "counter", :raw => true # => "24"
58
+ #
59
+ # cache.increment "counter", 6
60
+ # cache.read "counter", :raw => true # => "30"
61
+ #
62
+ # cache.increment "a counter"
63
+ # cache.read "a counter", :raw => true # => "1"
64
+ #
65
+ # cache.increment "rabbit"
66
+ # cache.read "rabbit", :raw => true # => "1"
67
+ def increment(key, amount = 1)
68
+ @data.incrby key, amount
69
+ end
70
+
71
+ # Decrement a key in the store
72
+ #
73
+ # If the key doesn't exist it will be initialized on 0.
74
+ # If the key exist but it isn't a Fixnum it will be initialized on 0.
75
+ #
76
+ # Example:
77
+ # We have two objects in cache:
78
+ # counter # => 23
79
+ # rabbit # => #<Rabbit:0x5eee6c>
80
+ #
81
+ # cache.decrement "counter"
82
+ # cache.read "counter", :raw => true # => "22"
83
+ #
84
+ # cache.decrement "counter", 2
85
+ # cache.read "counter", :raw => true # => "20"
86
+ #
87
+ # cache.decrement "a counter"
88
+ # cache.read "a counter", :raw => true # => "-1"
89
+ #
90
+ # cache.decrement "rabbit"
91
+ # cache.read "rabbit", :raw => true # => "-1"
92
+ def decrement(key, amount = 1)
93
+ @data.decrby key, amount
94
+ end
95
+
96
+ # Delete objects for matched keys.
97
+ #
98
+ # Example:
99
+ # cache.del_matched "rab*"
100
+ def delete_matched(matcher, options = nil)
101
+ @data.keys(matcher).each { |key| @data.del key }
102
+ end
103
+
104
+ def fetch(key, options = {})
105
+ (!options[:force] && data = read(key, options)) || (write key, yield, options if block_given?)
106
+ end
107
+
108
+ # Clear all the data from the store.
109
+ def clear
110
+ @data.flushdb
111
+ end
112
+
113
+ def stats
114
+ @data.info
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,51 @@
1
+ module Rack
2
+ module Cache
3
+ class EntityStore
4
+ class RedisBase < EntityStore
5
+ # The underlying ::Redis instance used to communicate with the Redis daemon.
6
+ attr_reader :cache
7
+
8
+ extend Rack::Utils
9
+
10
+ def open(key)
11
+ data = read(key)
12
+ data && [data]
13
+ end
14
+
15
+ def self.resolve(uri)
16
+ db = uri.path.sub(/^\//, '')
17
+ db = "0" if db.empty?
18
+ server = { :host => uri.host, :port => uri.port || "6379", :db => db }
19
+ new server
20
+ end
21
+ end
22
+
23
+ class Redis < RedisBase
24
+ def initialize(server, options = {})
25
+ @cache = ::Redis.new server
26
+ end
27
+
28
+ def exist?(key)
29
+ cache.exists key
30
+ end
31
+
32
+ def read(key)
33
+ cache.get key
34
+ end
35
+
36
+ def write(body)
37
+ buf = StringIO.new
38
+ key, size = slurp(body){|part| buf.write(part) }
39
+ [key, size] if cache.set(key, buf.string)
40
+ end
41
+
42
+ def purge(key)
43
+ cache.del key
44
+ nil
45
+ end
46
+ end
47
+
48
+ REDIS = Redis
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,42 @@
1
+ module Rack
2
+ module Cache
3
+ class MetaStore
4
+ class RedisBase < MetaStore
5
+ extend Rack::Utils
6
+
7
+ # The ::MarshaledRedis object used to communicate with the Redis daemon.
8
+ attr_reader :cache
9
+
10
+ def self.resolve(uri)
11
+ db = uri.path.sub(/^\//, '')
12
+ db = "0" if db.empty?
13
+ server = { :host => uri.host, :port => uri.port || "6379", :db => db }
14
+ new server
15
+ end
16
+ end
17
+
18
+ class Redis < RedisBase
19
+ def initialize(server, options = {})
20
+ @cache = ::MarshaledRedis.new server
21
+ end
22
+
23
+ def read(key)
24
+ key = hexdigest(key)
25
+ cache.marshalled_get(key) || []
26
+ end
27
+
28
+ def write(key, entries)
29
+ key = hexdigest(key)
30
+ cache.marshalled_set(key, entries)
31
+ end
32
+
33
+ def purge(key)
34
+ cache.del(hexdigest(key))
35
+ nil
36
+ end
37
+ end
38
+
39
+ REDIS = Redis
40
+ end
41
+ end
42
+ end