redis-store-1.10.0/0000755000004100000410000000000014537411545014072 5ustar www-datawww-dataredis-store-1.10.0/test/0000755000004100000410000000000014537411545015051 5ustar www-datawww-dataredis-store-1.10.0/test/redis/0000755000004100000410000000000014537411545016157 5ustar www-datawww-dataredis-store-1.10.0/test/redis/store/0000755000004100000410000000000014537411545017313 5ustar www-datawww-dataredis-store-1.10.0/test/redis/store/interface_test.rb0000644000004100000410000000123514537411545022640 0ustar www-datawww-datarequire 'test_helper' class InterfacedRedis < Redis include Redis::Store::Interface end describe Redis::Store::Interface do before do @r = InterfacedRedis.new end it "should get an element" do lambda { @r.get("key", :option => true) } # .wont_raise ArgumentError end it "should set an element" do lambda { @r.set("key", "value", :option => true) } # .wont_raise ArgumentError end it "should setnx an element" do lambda { @r.setnx("key", "value", :option => true) } # .wont_raise ArgumentError end it "should setex an element" do lambda { @r.setex("key", 1, "value", :option => true) } # .wont_raise ArgumentError end end redis-store-1.10.0/test/redis/store/factory_test.rb0000644000004100000410000002706014537411545022353 0ustar www-datawww-datarequire 'test_helper' require 'json' describe "Redis::Store::Factory" do describe ".create" do describe "when not given any arguments" do it "instantiates Redis::Store" do store = Redis::Store::Factory.create _(store).must_be_kind_of(Redis::Store) # `redis.rb` use different default host values in v4 & v5 _(store.to_s).must_match(%r{^Redis Client connected to (127.0.0.1|localhost):6379 against DB 0$}) end end describe "when given a Hash" do it "uses specified host" do store = Redis::Store::Factory.create :host => "localhost" _(store.to_s).must_equal("Redis Client connected to localhost:6379 against DB 0") end it "uses specified port" do store = Redis::Store::Factory.create :host => "localhost", :port => 6380 _(store.to_s).must_equal("Redis Client connected to localhost:6380 against DB 0") end it "uses specified scheme" do store = Redis::Store::Factory.create :scheme => "rediss" client = store.instance_variable_get(:@client) # `redis-client` does NOT have `scheme` client.respond_to?(:scheme) && _(client.scheme).must_equal('rediss') end it "uses specified path" do store = Redis::Store::Factory.create :path => "/var/run/redis.sock" _(store.to_s).must_equal("Redis Client connected to /var/run/redis.sock against DB 0") end it "uses specified db" do store = Redis::Store::Factory.create :host => "localhost", :port => 6380, :db => 13 _(store.to_s).must_equal("Redis Client connected to localhost:6380 against DB 13") end it "uses specified namespace" do store = Redis::Store::Factory.create :namespace => "theplaylist" # `redis.rb` use different default host values in v4 & v5 _(store.to_s).must_match(%r{^Redis Client connected to (127.0.0.1|localhost):6379 against DB 0 with namespace theplaylist$}) end it "uses specified key_prefix as namespace" do store = Redis::Store::Factory.create :key_prefix => "theplaylist" # `redis.rb` use different default host values in v4 & v5 _(store.to_s).must_match(%r{^Redis Client connected to (127.0.0.1|localhost):6379 against DB 0 with namespace theplaylist$}) end it "uses specified password" do store = Redis::Store::Factory.create :password => "secret" _(store.instance_variable_get(:@client).password).must_equal("secret") end it 'uses empty password' do store = Redis::Store::Factory.create :password => '' _(store.instance_variable_get(:@client).password).must_equal('') end it 'uses nil password' do store = Redis::Store::Factory.create :password => nil assert_nil(store.instance_variable_get(:@client).password) end it "disables serialization" do store = Redis::Store::Factory.create :serializer => nil _(store.instance_variable_get(:@serializer)).must_be_nil # `raw` would be removed when `redis-client` is used defined?(::RedisClient) || _(store.instance_variable_get(:@options)[:raw]).must_equal(true) end it "configures pluggable serialization backend" do store = Redis::Store::Factory.create :serializer => JSON _(store.instance_variable_get(:@serializer)).must_equal(JSON) # `raw` would be removed when `redis-client` is used defined?(::RedisClient) || _(store.instance_variable_get(:@options)[:raw]).must_equal(false) end describe "defaults" do it "defaults to localhost if no host specified" do store = Redis::Store::Factory.create # `redis.rb` use different default host values in v4 & v5 _(store.instance_variable_get(:@client).host).must_match(%r{^127.0.0.1|localhost$}) end it "defaults to 6379 if no port specified" do store = Redis::Store::Factory.create _(store.instance_variable_get(:@client).port).must_equal(6379) end it "defaults to redis:// if no scheme specified" do store = Redis::Store::Factory.create client = store.instance_variable_get(:@client) # `redis-client` does NOT have `scheme` client.respond_to?(:scheme) && _(client.scheme).must_equal('redis') end end describe 'with stdout disabled' do before do @original_stderr = $stderr @original_stdout = $stdout $stderr = Tempfile.new('stderr') $stdout = Tempfile.new('stdout') end it "disables marshalling and provides deprecation warning" do store = Redis::Store::Factory.create :marshalling => false _(store.instance_variable_get(:@serializer)).must_be_nil # `raw` would be removed when `redis-client` is used defined?(::RedisClient) || _(store.instance_variable_get(:@options)[:raw]).must_equal(true) end it "enables marshalling but provides warning to use :serializer instead" do store = Redis::Store::Factory.create :marshalling => true _(store.instance_variable_get(:@serializer)).must_equal(Marshal) # `raw` would be removed when `redis-client` is used defined?(::RedisClient) || _(store.instance_variable_get(:@options)[:raw]).must_equal(false) end after do $stderr = @original_stderr $stdout = @original_stdout end end it "should instantiate a Redis::DistributedStore store" do store = Redis::Store::Factory.create( { :host => "localhost", :port => 6379 }, { :host => "localhost", :port => 6380 } ) _(store).must_be_kind_of(Redis::DistributedStore) _(store.nodes.map { |node| node.to_s }).must_equal([ "Redis Client connected to localhost:6379 against DB 0", "Redis Client connected to localhost:6380 against DB 0", ]) end end describe "when given a String" do it "uses specified host" do store = Redis::Store::Factory.create "redis://127.0.0.1" _(store.to_s).must_equal("Redis Client connected to 127.0.0.1:6379 against DB 0") end it "uses specified port" do store = Redis::Store::Factory.create "redis://127.0.0.1:6380" _(store.to_s).must_equal("Redis Client connected to 127.0.0.1:6380 against DB 0") end it "uses specified scheme" do store = Redis::Store::Factory.create "rediss://127.0.0.1:6380" client = store.instance_variable_get(:@client) # `redis-client` does NOT have `scheme` client.respond_to?(:scheme) && _(client.scheme).must_equal('rediss') end it "correctly defaults to redis:// when relative scheme specified" do store = Redis::Store::Factory.create "//127.0.0.1:6379" client = store.instance_variable_get(:@client) # `redis-client` does NOT have `scheme` client.respond_to?(:scheme) && _(client.scheme).must_equal('redis') end it "uses specified path" do store = Redis::Store::Factory.create "unix:///var/run/redis.sock" _(store.to_s).must_equal("Redis Client connected to /var/run/redis.sock against DB 0") end it "uses specified db" do store = Redis::Store::Factory.create "redis://127.0.0.1:6380/13" _(store.to_s).must_equal("Redis Client connected to 127.0.0.1:6380 against DB 13") end it "uses specified namespace" do store = Redis::Store::Factory.create "redis://127.0.0.1:6379/0/theplaylist" _(store.to_s).must_equal("Redis Client connected to 127.0.0.1:6379 against DB 0 with namespace theplaylist") end it "uses specified via query namespace" do store = Redis::Store::Factory.create "redis://127.0.0.1:6379/0?namespace=theplaylist" _(store.to_s).must_equal("Redis Client connected to 127.0.0.1:6379 against DB 0 with namespace theplaylist") end it "uses specified namespace with path" do store = Redis::Store::Factory.create "unix:///var/run/redis.sock?db=2&namespace=theplaylist" _(store.to_s).must_equal("Redis Client connected to /var/run/redis.sock against DB 2 with namespace theplaylist") end it "uses specified password" do store = Redis::Store::Factory.create "redis://:secret@127.0.0.1:6379/0/theplaylist" _(store.instance_variable_get(:@client).password).must_equal("secret") end it 'uses specified password with special characters' do store = Redis::Store::Factory.create 'redis://:pwd%40123@127.0.0.1:6379/0/theplaylist' _(store.instance_variable_get(:@client).password).must_equal('pwd@123') end it 'uses empty password' do store = Redis::Store::Factory.create 'redis://:@127.0.0.1:6379/0/theplaylist' _(store.instance_variable_get(:@client).password).must_equal('') end it 'uses nil password' do store = Redis::Store::Factory.create 'redis://127.0.0.1:6379/0/theplaylist' assert_nil(store.instance_variable_get(:@client).password) end it "correctly uses specified ipv6 host" do store = Redis::Store::Factory.create "redis://[::1]:6380" _(store.to_s).must_equal("Redis Client connected to [::1]:6380 against DB 0") _(store.instance_variable_get('@options')[:host]).must_equal("::1") end it "instantiates Redis::DistributedStore" do store = Redis::Store::Factory.create "redis://127.0.0.1:6379", "redis://127.0.0.1:6380" _(store).must_be_kind_of(Redis::DistributedStore) _(store.nodes.map { |node| node.to_s }).must_equal([ "Redis Client connected to 127.0.0.1:6379 against DB 0", "Redis Client connected to 127.0.0.1:6380 against DB 0", ]) end end describe 'when given host Hash and options Hash' do it 'instantiates Redis::Store and merges options' do Redis::Store::Factory.create( { :host => '127.0.0.1', :port => '6379' }, { :namespace => 'theplaylist' } ) end it 'instantiates Redis::DistributedStore and merges options' do store = Redis::Store::Factory.create( { :host => '127.0.0.1', :port => '6379' }, { :host => '127.0.0.1', :port => '6380' }, { :namespace => 'theplaylist' } ) _(store.nodes.map { |node| node.to_s }).must_equal([ "Redis Client connected to 127.0.0.1:6379 against DB 0 with namespace theplaylist", "Redis Client connected to 127.0.0.1:6380 against DB 0 with namespace theplaylist" ]) end end describe 'when given host String and options Hash' do it 'instantiates Redis::Store and merges options' do store = Redis::Store::Factory.create "redis://127.0.0.1", :namespace => 'theplaylist' _(store.to_s).must_equal("Redis Client connected to 127.0.0.1:6379 against DB 0 with namespace theplaylist") end it 'instantiates Redis::DistributedStore and merges options' do store = Redis::Store::Factory.create "redis://127.0.0.1:6379", "redis://127.0.0.1:6380", :namespace => 'theplaylist' _(store.nodes.map { |node| node.to_s }).must_equal([ "Redis Client connected to 127.0.0.1:6379 against DB 0 with namespace theplaylist", "Redis Client connected to 127.0.0.1:6380 against DB 0 with namespace theplaylist", ]) end it 'instantiates Redis::Store and sets namespace from String' do store = Redis::Store::Factory.create "redis://127.0.0.1:6379/0/theplaylist" _(store.to_s).must_equal("Redis Client connected to 127.0.0.1:6379 against DB 0 with namespace theplaylist") end end end end redis-store-1.10.0/test/redis/store/namespace_test.rb0000644000004100000410000002507114537411545022640 0ustar www-datawww-datarequire 'test_helper' describe "Redis::Store::Namespace" do def setup @namespace = "theplaylist" @store = Redis::Store.new :namespace => @namespace, :serializer => nil @client = @store.instance_variable_get(:@client) @rabbit = "bunny" @default_store = Redis::Store.new @other_namespace = 'other' @other_store = Redis::Store.new :namespace => @other_namespace end def teardown @store.flushdb @store.quit @default_store.flushdb @default_store.quit @other_store.flushdb @other_store.quit end it "only decorates instances that need to be namespaced" do store = Redis::Store.new client = store.instance_variable_get(:@client) # `call_v` used since redis-rb 5.0 client_call_method_name = client.respond_to?(:call_v) ? :call_v : :call client.expects(client_call_method_name).with([:get, "rabbit"]) store.get("rabbit") end it "doesn't namespace a key which is already namespaced" do _(@store.send(:interpolate, "#{@namespace}:rabbit")).must_equal("#{@namespace}:rabbit") end it "should only delete namespaced keys" do @default_store.set 'abc', 'cba' @store.set 'def', 'fed' @store.flushdb _(@store.get('def')).must_be_nil _(@default_store.get('abc')).must_equal('cba') end it 'should allow to change namespace on the fly' do @default_store.set 'abc', 'cba' @other_store.set 'foo', 'bar' _(@default_store.keys).must_include('abc') _(@default_store.keys).must_include('other:foo') @default_store.with_namespace(@other_namespace) do _(@default_store.keys).must_equal ['foo'] _(@default_store.get('foo')).must_equal('bar') end end it "should not try to delete missing namespaced keys" do empty_store = Redis::Store.new :namespace => 'empty' empty_store.flushdb _(empty_store.keys).must_be_empty end it "should work with dynamic namespace" do $ns = "ns1" dyn_store = Redis::Store.new :namespace => -> { $ns } dyn_store.set 'key', 'x' $ns = "ns2" dyn_store.set 'key', 'y' $ns = "ns3" dyn_store.set 'key', 'z' dyn_store.flushdb r3 = dyn_store.get 'key' $ns = "ns2" r2 = dyn_store.get 'key' $ns = "ns1" r1 = dyn_store.get 'key' _(r1).must_equal('x') && _(r2).must_equal('y') && _(r3).must_be_nil end it "namespaces setex and ttl" do @store.flushdb @other_store.flushdb @store.setex('foo', 30, 'bar') _(@store.ttl('foo')).must_be_close_to(30) _(@store.get('foo')).must_equal('bar') _(@other_store.ttl('foo')).must_equal(-2) _(@other_store.get('foo')).must_be_nil end describe 'method calls' do let(:store) { Redis::Store.new :namespace => @namespace, :serializer => nil } let(:client) { store.instance_variable_get(:@client) } let(:client_call_method_name) do # `call_v` used since redis-rb 5.0 client.respond_to?(:call_v) ? :call_v : :call end it "should namespace get" do client.expects(client_call_method_name).with([:get, "#{@namespace}:rabbit"]).once store.get("rabbit") end it "should namespace set" do client.expects(client_call_method_name).with([:set, "#{@namespace}:rabbit", @rabbit]) store.set "rabbit", @rabbit end it "should namespace setnx" do client.expects(client_call_method_name).with([:setnx, "#{@namespace}:rabbit", @rabbit]) store.setnx "rabbit", @rabbit end it "should namespace del with single key" do client.expects(client_call_method_name).with([:del, "#{@namespace}:rabbit"]) store.del "rabbit" end it "should namespace del with multiple keys" do client.expects(client_call_method_name).with([:del, "#{@namespace}:rabbit", "#{@namespace}:white_rabbit"]) store.del "rabbit", "white_rabbit" end it "should namespace keys" do store.set "rabbit", @rabbit _(store.keys("rabb*")).must_equal [ "rabbit" ] end it "should namespace scan when a pattern is given" do store.set "rabbit", @rabbit cursor = "0" keys = [] begin cursor, matched_keys = store.scan(cursor, match: "rabb*") keys = keys.concat(matched_keys) unless matched_keys.empty? end until cursor == "0" _(keys).must_equal [ "rabbit" ] end it "should namespace exists" do client.expects(client_call_method_name).with([:exists, "#{@namespace}:rabbit"]) store.exists "rabbit" end it "should namespace incrby" do client.expects(client_call_method_name).with([:incrby, "#{@namespace}:counter", 1]) store.incrby "counter", 1 end it "should namespace decrby" do client.expects(client_call_method_name).with([:decrby, "#{@namespace}:counter", 1]) store.decrby "counter", 1 end it "should namespace mget" do client.expects(client_call_method_name).with([:mget, "#{@namespace}:rabbit", "#{@namespace}:white_rabbit"]).returns(%w[ foo bar ]) store.mget "rabbit", "white_rabbit" do |result| _(result).must_equal(%w[ foo bar ]) end end it "should namespace mapped_mget" do if client.respond_to?(:process, true) # Redis < 5.0 uses `#process` client.expects(:process).with([[:mget, "#{@namespace}:rabbit", "#{@namespace}:white_rabbit"]]).returns(%w[ foo bar ]) else # Redis 5.x calls `#ensure_connected` (private) client.send(:ensure_connected).expects(:call).returns(%w[ foo bar ]) end result = store.mapped_mget "rabbit", "white_rabbit" _(result.keys).must_equal %w[ rabbit white_rabbit ] _(result["rabbit"]).must_equal "foo" _(result["white_rabbit"]).must_equal "bar" end it "should namespace expire" do client.expects(client_call_method_name).with([:expire, "#{@namespace}:rabbit", 60]).once store.expire("rabbit", 60) end it "should namespace ttl" do client.expects(client_call_method_name).with([:ttl, "#{@namespace}:rabbit"]).once store.ttl("rabbit") end it "should namespace watch" do client.expects(client_call_method_name).with([:watch, "#{@namespace}:rabbit"]).once store.watch("rabbit") end it "wraps flushdb with appropriate KEYS * calls" do client.expects(client_call_method_name).with([:flushdb]).never client.expects(client_call_method_name).with([:keys, "#{@namespace}:*"]).once.returns(["rabbit"]) client.expects(client_call_method_name).with([:del, "#{@namespace}:rabbit"]).once store.flushdb end it "skips flushdb wrapping if the namespace is nil" do client.expects(client_call_method_name).with([:flushdb]) client.expects(client_call_method_name).with([:keys]).never store.with_namespace(nil) do store.flushdb end end it "should namespace hdel" do client.expects(client_call_method_name).with([:hdel, "#{@namespace}:rabbit", "key1", "key2"]).once store.hdel("rabbit", "key1", "key2") end it "should namespace hget" do client.expects(client_call_method_name).with([:hget, "#{@namespace}:rabbit", "key"]).once store.hget("rabbit", "key") end it "should namespace hgetall" do client.expects(client_call_method_name).with([:hgetall, "#{@namespace}:rabbit"]).once store.hgetall("rabbit") end it "should namespace hexists" do client.expects(client_call_method_name).with([:hexists, "#{@namespace}:rabbit", "key"]).once store.hexists("rabbit", "key") end it "should namespace hincrby" do client.expects(client_call_method_name).with([:hincrby, "#{@namespace}:rabbit", "key", 1]).once store.hincrby("rabbit", "key", 1) end it "should namespace hincrbyfloat" do client.expects(client_call_method_name).with([:hincrbyfloat, "#{@namespace}:rabbit", "key", 1.5]).once store.hincrbyfloat("rabbit", "key", 1.5) end it "should namespace hkeys" do client.expects(client_call_method_name).with([:hkeys, "#{@namespace}:rabbit"]) store.hkeys("rabbit") end it "should namespace hlen" do client.expects(client_call_method_name).with([:hlen, "#{@namespace}:rabbit"]) store.hlen("rabbit") end it "should namespace hmget" do client.expects(client_call_method_name).with([:hmget, "#{@namespace}:rabbit", "key1", "key2"]) store.hmget("rabbit", "key1", "key2") end it "should namespace hmset" do client.expects(client_call_method_name).with([:hmset, "#{@namespace}:rabbit", "key", @rabbit]) store.hmset("rabbit", "key", @rabbit) end it "should namespace hset" do client.expects(client_call_method_name).with([:hset, "#{@namespace}:rabbit", "key", @rabbit]) store.hset("rabbit", "key", @rabbit) end it "should namespace hsetnx" do client.expects(client_call_method_name).with([:hsetnx, "#{@namespace}:rabbit", "key", @rabbit]) store.hsetnx("rabbit", "key", @rabbit) end it "should namespace hvals" do client.expects(client_call_method_name).with([:hvals, "#{@namespace}:rabbit"]) store.hvals("rabbit") end it "should namespace hscan" do client.expects(client_call_method_name).with([:hscan, "#{@namespace}:rabbit", 0]) store.hscan("rabbit", 0) end it "should namespace hscan_each with block" do client.public_send(client_call_method_name, [:hset, "#{@namespace}:rabbit", "key1", @rabbit]) client.expects(client_call_method_name).with([:hscan, "#{@namespace}:rabbit", 0]).returns(["0", ["key1"]]) results = [] store.hscan_each("rabbit") do |key| results << key end _(results).must_equal(["key1"]) end it "should namespace hscan_each without block" do client.public_send(client_call_method_name, [:hset, "#{@namespace}:rabbit", "key1", @rabbit]) client.expects(client_call_method_name).with([:hscan, "#{@namespace}:rabbit", 0]).returns(["0", ["key1"]]) results = store.hscan_each("rabbit").to_a _(results).must_equal(["key1"]) end it "should namespace zincrby" do client.expects(client_call_method_name).with([:zincrby, "#{@namespace}:rabbit", 1.0, "member"]) store.zincrby("rabbit", 1.0, "member") end it "should namespace zscore" do client.expects(client_call_method_name).with([:zscore, "#{@namespace}:rabbit", "member"]) store.zscore("rabbit", "member") end it "should namespace zadd" do client.expects(client_call_method_name).with([:zadd, "#{@namespace}:rabbit", 1.0, "member"]) store.zadd("rabbit", 1.0, "member") end it "should namespace zrem" do client.expects(client_call_method_name).with([:zrem, "#{@namespace}:rabbit", "member"]) store.zrem("rabbit", "member") end end end redis-store-1.10.0/test/redis/store/redis_version_test.rb0000644000004100000410000000147214537411545023556 0ustar www-datawww-datarequire 'test_helper' describe "Redis::RedisVersion" do def setup @store = Redis::Store.new end def teardown @store.quit end describe '#redis_version' do it 'returns redis version' do _(@store.redis_version.to_s).must_match(/^\d{1}\.\d{1,}\.\d{1,}$/) end end describe '#supports_redis_version?' do it 'returns true if redis version is greater or equal to required version' do @store.stubs(:redis_version).returns('2.8.19') _(@store.supports_redis_version?('2.6.0')).must_equal(true) _(@store.supports_redis_version?('2.8.19')).must_equal(true) _(@store.supports_redis_version?('2.8.20')).must_equal(false) _(@store.supports_redis_version?('2.9.0')).must_equal(false) _(@store.supports_redis_version?('3.0.0')).must_equal(false) end end end redis-store-1.10.0/test/redis/store/version_test.rb0000644000004100000410000000022114537411545022357 0ustar www-datawww-datarequire 'test_helper' describe Redis::Store::VERSION do it 'returns current version' do _(Redis::Store::VERSION).wont_equal nil end end redis-store-1.10.0/test/redis/store/ttl_test.rb0000644000004100000410000000634214537411545021507 0ustar www-datawww-datarequire 'test_helper' class MockRedis def initialize @sets = [] @setexes = [] @setnxes = [] @expires = [] end def set(*a) @sets << a end def has_set?(*a) @sets.include?(a) end def setex(*a) @setexes << a end def has_setex?(*a) @setexes.include?(a) end def setnx(*a) @setnxes << a end def has_setnx?(*a) @setnxes.include?(a) end def multi(&block) instance_eval do def setnx(*a) @setnxes << a end block.call(self) end end alias_method :pipelined, :multi def expire(*a) @expires << a end def has_expire?(*a) @expires.include?(a) end end class MockTtlStore < MockRedis include Redis::Store::Ttl end describe MockTtlStore do let(:key) { 'hello' } let(:mock_value) { 'value' } let(:options) { { :expire_after => 3600 } } let(:redis) { MockTtlStore.new } describe '#set' do describe 'without options' do it 'must call super with key and value' do redis.set(key, mock_value) _(redis.has_set?(key, mock_value, nil)).must_equal true end end describe 'with options' do it 'must call setex with proper expiry and set raw to true' do redis.set(key, mock_value, options) _(redis.has_setex?(key, options[:expire_after], mock_value, :raw => true)).must_equal true end end describe 'with nx and ex option' do it 'must call super with key and value and options' do set_options = { nx: true, ex: 3600 } redis.set(key, mock_value, set_options) _(redis.has_set?(key, mock_value, set_options)).must_equal true end end end describe '#setnx' do describe 'without expiry' do it 'must call super with key and value' do redis.setnx(key, mock_value) redis.has_setnx?(key, mock_value) end it 'must not call expire' do redis.expects(:expire).never redis.setnx(key, mock_value) end end describe 'with expiry' do it 'uses the mutli command to chain commands' do redis.expects(:multi) redis.setnx(key, mock_value, options) end it 'must call expire' do redis.setnx(key, mock_value, options) _(redis.has_expire?(key, options[:expire_after])).must_equal true end describe 'avoiding multi commands' do let(:options) { { :expire_after => 3600, :avoid_multi_commands => true } } it 'uses the redis pipelined feature to chain commands' do redis.expects(:pipelined) redis.setnx(key, mock_value, options) end it 'must call expire' do redis.setnx(key, mock_value, options) _(redis.has_expire?(key, options[:expire_after])).must_equal true end end describe 'using a redis cluster' do let(:options) { { :expire_after => 3600, :cluster => %w[redis://127.0.0.1:6379/0] } } it 'uses the redis pipelined feature to chain commands' do redis.expects(:pipelined) redis.setnx(key, mock_value, options) end it 'must call expire' do redis.setnx(key, mock_value, options) _(redis.has_expire?(key, options[:expire_after])).must_equal true end end end end end redis-store-1.10.0/test/redis/store/serialization_test.rb0000644000004100000410000001334514537411545023562 0ustar www-datawww-datarequire 'test_helper' describe "Redis::Serialization" do def setup @store = Redis::Store.new serializer: Marshal @rabbit = OpenStruct.new :name => "bunny" @white_rabbit = OpenStruct.new :color => "white" @store.set "rabbit", @rabbit @store.del "rabbit2" end def teardown @store.flushdb @store.quit end it "unmarshals on get" do _(@store.get("rabbit")).must_equal(@rabbit) end it "marshals on set" do @store.set "rabbit", @white_rabbit _(@store.get("rabbit")).must_equal(@white_rabbit) end it "marshals on multi set" do @store.mset("rabbit", @white_rabbit, "rabbit2", @rabbit) _(@store.get("rabbit")).must_equal(@white_rabbit) _(@store.get("rabbit2")).must_equal(@rabbit) end if RUBY_VERSION.match(/1\.9/) it "doesn't unmarshal on get if raw option is true" do _(@store.get("rabbit", :raw => true)).must_equal("\x04\bU:\x0FOpenStruct{\x06:\tnameI\"\nbunny\x06:\x06EF") end else it "doesn't unmarshal on get if raw option is true" do _(@store.get("rabbit", :raw => true)).must_include("\x04\bU:\x0FOpenStruct{\x06:\tname") end end it "doesn't marshal set if raw option is true" do @store.set "rabbit", @white_rabbit, :raw => true _(@store.get("rabbit", :raw => true)).must_equal(%(#)) end it "doesn't marshal multi set if raw option is true" do @store.mset("rabbit", @white_rabbit, "rabbit2", @rabbit, :raw => true) _(@store.get("rabbit", :raw => true)).must_equal(%(#)) _(@store.get("rabbit2", :raw => true)).must_equal(%(#)) end it "doesn't unmarshal if get returns an empty string" do @store.set "empty_string", "" _(@store.get("empty_string")).must_equal("") # TODO use a meaningful Exception # lambda { @store.get("empty_string").must_equal("") }.wont_raise Exception end it "doesn't set an object if already exist" do @store.setnx "rabbit", @white_rabbit _(@store.get("rabbit")).must_equal(@rabbit) end it "marshals on set unless exists" do @store.setnx "rabbit2", @white_rabbit _(@store.get("rabbit2")).must_equal(@white_rabbit) end it "doesn't marshal on set unless exists if raw option is true" do @store.setnx "rabbit2", @white_rabbit, :raw => true _(@store.get("rabbit2", :raw => true)).must_equal(%(#)) end it "marshals on set expire" do @store.setex "rabbit2", 1, @white_rabbit _(@store.get("rabbit2")).must_equal(@white_rabbit) sleep 2 _(@store.get("rabbit2")).must_be_nil end unless ENV['CI'] it "marshals setex (over a distributed store)" do @store = Redis::DistributedStore.new [ { :host => "localhost", :port => "6380", :db => 0 }, { :host => "localhost", :port => "6381", :db => 0 } ] @store.setex "rabbit", 50, @white_rabbit _(@store.get("rabbit")).must_equal(@white_rabbit) end it "doesn't marshal setex if raw option is true (over a distributed store)" do @store = Redis::DistributedStore.new [ { :host => "localhost", :port => "6380", :db => 0 }, { :host => "localhost", :port => "6381", :db => 0 } ] @store.setex "rabbit", 50, @white_rabbit, :raw => true _(@store.get("rabbit", :raw => true)).must_equal(%(#)) end end it "unmarshals on multi get" do @store.set "rabbit2", @white_rabbit @store.mget "rabbit", "rabbit2" do |rabbits| rabbit, rabbit2 = rabbits _(rabbits.length).must_equal(2) _(rabbit).must_equal(@rabbit) _(rabbit2).must_equal(@white_rabbit) end end it "unmarshals on mapped_mget" do @store.set "rabbit2", @white_rabbit result = @store.mapped_mget("rabbit", "rabbit2") _(result.keys).must_equal %w[ rabbit rabbit2 ] _(result["rabbit"]).must_equal @rabbit _(result["rabbit2"]).must_equal @white_rabbit end if RUBY_VERSION.match(/1\.9/) it "doesn't unmarshal on multi get if raw option is true" do @store.set "rabbit2", @white_rabbit @store.mget "rabbit", "rabbit2", :raw => true do |rabbit, rabbit2| _(rabbit).must_equal("\x04\bU:\x0FOpenStruct{\x06:\tnameI\"\nbunny\x06:\x06EF") _(rabbit2).must_equal("\x04\bU:\x0FOpenStruct{\x06:\ncolorI\"\nwhite\x06:\x06EF") end end else it "doesn't unmarshal on multi get if raw option is true" do @store.set "rabbit2", @white_rabbit @store.mget "rabbit", "rabbit2", :raw => true do |rabbit, rabbit2| _(rabbit).must_include("\x04\bU:\x0FOpenStruct{\x06:\tname") _(rabbit2).must_include("\x04\bU:\x0FOpenStruct{\x06:\ncolor") end end end describe "binary safety" do it "marshals objects" do utf8_key = [51339].pack("U*") ascii_rabbit = OpenStruct.new(:name => [128].pack("C*")) @store.set(utf8_key, ascii_rabbit) _(@store.get(utf8_key)).must_equal(ascii_rabbit) end it "gets and sets raw values" do utf8_key = [51339].pack("U*") ascii_string = [128].pack("C*") @store.set(utf8_key, ascii_string, :raw => true) _(@store.get(utf8_key, :raw => true).bytes.to_a).must_equal(ascii_string.bytes.to_a) end it "marshals objects on setnx" do utf8_key = [51339].pack("U*") ascii_rabbit = OpenStruct.new(:name => [128].pack("C*")) @store.del(utf8_key) @store.setnx(utf8_key, ascii_rabbit) _(@store.get(utf8_key)).must_equal(ascii_rabbit) end it "gets and sets raw values on setnx" do utf8_key = [51339].pack("U*") ascii_string = [128].pack("C*") @store.del(utf8_key) @store.setnx(utf8_key, ascii_string, :raw => true) _(@store.get(utf8_key, :raw => true).bytes.to_a).must_equal(ascii_string.bytes.to_a) end end if defined?(Encoding) end redis-store-1.10.0/test/redis/distributed_store_test.rb0000644000004100000410000000653514537411545023312 0ustar www-datawww-datarequire 'test_helper' describe "Redis::DistributedStore" do def setup @dmr = Redis::DistributedStore.new [ { :host => "localhost", :port => "6380", :db => 0 }, { :host => "localhost", :port => "6381", :db => 0 } ] @rabbit = OpenStruct.new :name => "bunny" @white_rabbit = OpenStruct.new :color => "white" @dmr.set "rabbit", @rabbit end def teardown @dmr.ring.nodes.each { |server| server.flushdb } end it "accepts connection params" do dmr = Redis::DistributedStore.new [ :host => "localhost", :port => "6380", :db => "1" ] _(dmr.ring.nodes.size).must_equal(1) mr = dmr.ring.nodes.first _(mr.to_s).must_equal("Redis Client connected to localhost:6380 against DB 1") end it "forces reconnection" do @dmr.nodes.each do |node| node.expects(:reconnect) end @dmr.reconnect end it "sets an object" do @dmr.set "rabbit", @white_rabbit _(@dmr.get("rabbit")).must_equal(@white_rabbit) end it "gets an object" do _(@dmr.get("rabbit")).must_equal(@rabbit) end it "mget" do @dmr.set "rabbit2", @white_rabbit begin @dmr.mget "rabbit", "rabbit2" do |rabbits| rabbit, rabbit2 = rabbits _(rabbits.length).must_equal(2) _(rabbit).must_equal(@rabbit) _(rabbit2).must_equal(@white_rabbit) end rescue Redis::Distributed::CannotDistribute # Not supported on redis-rb < 4, and hence Ruby < 2.2. end end it "mapped_mget" do @dmr.set "rabbit2", @white_rabbit begin result = @dmr.mapped_mget("rabbit", "rabbit2") _(result.keys).must_equal %w[ rabbit rabbit2 ] _(result["rabbit"]).must_equal @rabbit _(result["rabbit2"]).must_equal @white_rabbit rescue Redis::Distributed::CannotDistribute # Not supported on redis-rb < 4, and hence Ruby < 2.2. end end it "passes through ring replica options" do dmr = Redis::DistributedStore.new [ { :host => "localhost", :port => "6380", :db => 0 }, { :host => "localhost", :port => "6381", :db => 0 } ], replicas: 1024 _(dmr.ring.replicas).must_equal 1024 end it "uses a custom ring object" do my_ring = Redis::HashRing.new dmr = Redis::DistributedStore.new [ { :host => "localhost", :port => "6380", :db => 0 }, { :host => "localhost", :port => "6381", :db => 0 } ], ring: my_ring _(dmr.ring).must_equal my_ring _(dmr.ring.nodes.length).must_equal 2 end describe '#redis_version' do it 'returns redis version' do @dmr.nodes.first.expects(:redis_version) @dmr.redis_version end end describe '#supports_redis_version?' do it 'returns redis version' do @dmr.nodes.first.expects(:supports_redis_version?).with('2.8.0') @dmr.supports_redis_version?('2.8.0') end end describe "namespace" do it "uses namespaced key" do @dmr = Redis::DistributedStore.new [ { :host => "localhost", :port => "6380", :db => 0 }, { :host => "localhost", :port => "6381", :db => 0 } ], :namespace => "theplaylist" @dmr.expects(:node_for).with("theplaylist:rabbit").returns(@dmr.nodes.first) @dmr.get "rabbit" end end end unless ENV['CI'] redis-store-1.10.0/test/redis/store_test.rb0000644000004100000410000000330614537411545020701 0ustar www-datawww-datarequire 'test_helper' describe Redis::Store do def setup @store = Redis::Store.new @client = @store.instance_variable_get(:@client) end def teardown @store.flushdb @store.quit end it "returns useful informations about the server" do _(@store.to_s).must_equal("Redis Client connected to #{@client.host}:#{@client.port} against DB #{@client.db}") end it "must force reconnection" do @client.expects(:reconnect) @store.reconnect end describe '#set' do describe 'with expiry' do let(:options) { { :expire_after => 3600 } } it 'must not double marshall' do Marshal.expects(:dump).once @store.set('key', 'value', options) end end describe 'with ex and nx' do let(:key) { 'key' } let(:mock_value) { 'value' } let(:options) { { nx: true, ex: 3600 } } it 'must pass on options' do Marshal.expects(:dump).times(4) # without options no ex or nx will be set @store.del(key) _(@store.set(key, mock_value, {})).must_equal 'OK' _(@store.set(key, mock_value, {})).must_equal 'OK' _(@store.ttl(key)).must_equal(-1) # with ex and nx options, the key can only be set once and a ttl will be set @store.del(key) _(@store.set(key, mock_value, options)).must_equal true _(@store.set(key, mock_value, options)).must_equal false _(@store.ttl(key)).must_equal 3600 end end end describe '#setnx' do describe 'with expiry' do let(:options) { { :expire_after => 3600 } } it 'must not double marshall' do Marshal.expects(:dump).once @store.setnx('key', 'value', options) end end end end redis-store-1.10.0/test/test_helper.rb0000644000004100000410000000070514537411545017716 0ustar www-datawww-datarequire 'bundler/setup' require 'minitest/autorun' require 'mocha/minitest' require 'redis' require 'redis-store' $DEBUG = ENV["DEBUG"] === "true" Redis::DistributedStore.send(:class_variable_set, :@@timeout, 30) # http://mentalized.net/journal/2010/04/02/suppress_warnings_from_ruby/ module Kernel def suppress_warnings original_verbosity = $VERBOSE $VERBOSE = nil result = yield $VERBOSE = original_verbosity result end end redis-store-1.10.0/CODEOWNERS0000644000004100000410000000001114537411545015455 0ustar www-datawww-data* @tubbo redis-store-1.10.0/README.md0000644000004100000410000000353314537411545015355 0ustar www-datawww-data# Redis stores for Ruby frameworks __Redis Store__ provides a full set of stores (*Cache*, *I18n*, *Session*, *HTTP Cache*) for modern Ruby frameworks like: __Ruby on Rails__, __Sinatra__, __Rack__, __Rack::Cache__ and __I18n__. It supports object marshalling, timeouts, single or multiple nodes, and namespaces. Please check the *README* file of each gem for usage and installation guidelines. ## Redis Installation ### Option 1: Homebrew MacOS X users should use [Homebrew](https://github.com/mxcl/homebrew) to install Redis: ```shell brew install redis ``` ### Option 2: From Source Download and install Redis from [the download page](http://redis.io//download) and follow the instructions. ## Running tests ```ruby git clone git://github.com/redis-store/redis-store.git cd redis-store bundle install bundle exec rake ``` If you are on **Snow Leopard** you have to run `env ARCHFLAGS="-arch x86_64" ruby ci/run.rb` ## Contributors https://github.com/redis-store/redis-store/graphs/contributors ## Versioning The **redis-store** family of gems uses [Semantic Versioning](http://semver.org), meaning gems depending on **redis-store** can be reliably inclusive of any version between the current and the next major. We recommend the following dependency in your library's gemspec: ```ruby s.add_dependency 'redis-store', '>= 1.4', '< 2' ``` ## Status [![Gem Version](https://badge.fury.io/rb/redis-store.svg)](http://badge.fury.io/rb/redis-store) [![Build Status](https://github.com/redis-store/redis-store/actions/workflows/ci.yml/badge.svg)](https://github.com/redis-store/redis-store/actions/workflows/ci.yml) [![Code Climate](https://codeclimate.com/github/redis-store/redis-store.svg)](https://codeclimate.com/github/redis-store/redis-store) ## Copyright 2009 - 2013 Luca Guidi - [http://lucaguidi.com](http://lucaguidi.com), released under the MIT license. redis-store-1.10.0/gemfiles/0000755000004100000410000000000014537411545015665 5ustar www-datawww-dataredis-store-1.10.0/gemfiles/redis_4_0_x.gemfile0000644000004100000410000000016414537411545021317 0ustar www-datawww-data# This file was generated by Appraisal source "https://rubygems.org" gem "redis", "~> 4.0.0" gemspec path: "../" redis-store-1.10.0/gemfiles/redis_5_x.gemfile0000644000004100000410000000016214537411545021077 0ustar www-datawww-data# This file was generated by Appraisal source "https://rubygems.org" gem "redis", "~> 5.0" gemspec path: "../" redis-store-1.10.0/gemfiles/redis_4_x.gemfile0000644000004100000410000000016214537411545021076 0ustar www-datawww-data# This file was generated by Appraisal source "https://rubygems.org" gem "redis", "~> 4.0" gemspec path: "../" redis-store-1.10.0/gemfiles/redis_4_1_x.gemfile0000644000004100000410000000016414537411545021320 0ustar www-datawww-data# This file was generated by Appraisal source "https://rubygems.org" gem "redis", "~> 4.1.0" gemspec path: "../" redis-store-1.10.0/gemfiles/redis_4_6_x.gemfile0000644000004100000410000000016414537411545021325 0ustar www-datawww-data# This file was generated by Appraisal source "https://rubygems.org" gem "redis", "~> 4.6.0" gemspec path: "../" redis-store-1.10.0/CHANGELOG.md0000644000004100000410000005623714537411545015720 0ustar www-datawww-data# Changelog ## 1.10.0 and future As at 1.10 and above, changelog information will be on this project's releases page: https://github.com/redis-store/redis-store/releases ## 1.9.0 Breaking Changes * As a factor of updates for Redis v4.2.x, support for Ruby 2.1 and 2.2 has been dropped. These Ruby versions are end-of-life anyway. Fixed * [Compatibility with Redis client v4.2.x](https://github.com/redis-store/redis-store/pull/333) Added * [Support for edge Ruby's keyword arguments](https://github.com/redis-store/redis-store/pull/334) ## 1.8.2 Breaking Changes * None Added * [Add namespace to zincrby and zscore](https://github.com/redis-store/redis-store/pull/323) * [Add namespace to zadd and zrem](https://github.com/redis-store/redis-store/pull/326) Fixed * None ## 1.8.1 Breaking Changes * None Added * None Fixed * [Add namespace to remaining hash methods](https://github.com/redis-store/redis-store/pull/321) ## 1.8.0 Breaking Changes * None Added * [Redis Cluster Support](https://github.com/redis-store/redis-store/pull/318) Fixed * None ## 1.6.0 Breaking Changes * None Added * [SSL/TLS Support with the rediss:// URI scheme](https://github.com/redis-store/redis-store/pull/306) * [Use Code Style Guide For New Contributions](https://github.com/redis-store/redis-store/pull/309) Fixed * None ## 1.5.0 Breaking Changes * None Added * [Support for Redis v4 and above](https://github.com/redis-store/redis-store/pull/292) * [Support for distributed mget/read_multi in Redis v4](https://github.com/redis-store/redis-store/pull/282) * [Tests for Namespace#flushdb](https://github.com/redis-store/redis-store/pull/299) * [Support for UNIX Socket path connections](https://github.com/redis-store/redis-store/pull/298) * [HashRing configuration for DistributedStore](https://github.com/redis-store/redis-store/pull/304) Fixed * [Inefficient use of KEYS when calling FLUSHDB without a namespace](https://github.com/redis-store/redis-store/pull/297) ## 1.4.1 Breaking Changes * None Added * [Support for Redis client library v4](https://github.com/redis-store/redis-store/issues/277) Fixed * None ## 1.4.0 Breaking Changes * None Added * Pluggable backend for serializing data in/out of Redis, eventually replacing `:marshalling` in v2. Fixed * Conventional `Marshal.dump` usage allowing potential security vulnerability (CVE-2017-1000248) ## 1.3.0 Breaking Changes * None Added * Add support for marshalling mset Fixed * Set :raw => true if marshalling * Forward new Hash, not nil, when options are unset ## 1.2.0 Breaking Changes * None Added * Allow changing namespaces on the fly * Begin testing against ruby 2.3.0 Fixed * Use batched deletes for flushdb with a namespace * pass set command options to redis * bump rbx 2 * fix setex marshalling for distributed store * changes to new url * :warning: shadowing outer local variable - key, pattern, value * :warning: `*' interpreted as argument prefix * Removed duplicated method ttl ## 1.1.7 Breaking Changes * None Added * Added redis_version and supports_redis_version? methods to Store and DistributedStore Fixed * Handle minor and patch version correctly as they may be multiple digits *1.1.6 (July 16, 2015)* https://github.com/redis-store/redis-store/compare/v1.1.5...v1.1.6 *1.1.5 (June 8, 2015)* https://github.com/redis-store/redis-store/compare/v1.1.4...v1.1.5 *1.1.4 (August 20, 2013)* * Bump version v1.1.4 * Release redis-rails 4.0.0 * Release redis-actionpack 4.0.0 * Release redis-activesupport 4.0.0 * Release redis-sinatra 1.4.0 * Release redis-rack-cache 1.2.2 * Release redis-i18n 0.6.5 * Release redis-rack 1.5.0 * New versions of the AS, AP and Rails gems [Alexey Vasiliev] * fix gems for Rails 4 [Alexey Vasiliev] * JRuby testing, remove 1.8.7 from tests (unsupported), fix some tests [Alexey Vasiliev] * Change configurations for the Rails dummy app. * use @default_options when calling @pool.set to avoid infinite-ttl session leak, fixes #179 [Sean Walbran] * Test against Rails 4 not master [Rafael Mendonça França] * Make possible to work with rack 1.5 [Rafael Mendonça França] * Add support pluralization support to Redis i18n [Joachim Filip Ignacy Bartosik] * Fixes #189 [Fabrizio Regini] * fix CI script [Fabrizio Regini] * Redis::Factory => Redis::Store::Factory * Added performance warning, per #186. [Brian P O'Rourke] * Fix: read_multi was returning ActiveSupport::Cache::Entry instead of deserialized value [Miles D Goodings] * Fix: can't modify frozen String errors in Redis::Store::Marshalling [Miles D Goodings] * Add expire method and tests [Han Chang] * Run against Rails 4 and Ruby 2.0 [Steve Klabnik] * Clean up README files to be more clear and helpful [Matthew Beale] * Bundler 1.2.0 is now out, don't require the RC on the CI server * Relaxed the requirement for the Redis gem (>= 2.2). Updated development dependencies. * Ensure Redis 2.6 compat *1.1.3 (October 6, 2012)* * Bump version v1.1.3 * Invoke namespaced commands only when keys are present. *1.1.2 (September 4, 2012)* * Bump version v1.1.2 [Matt Horan] * Override flushdb for namespaced datastore [Gregory Marcilhacy] *1.1.1 (June 26, 2012)* * Bump version v1.1.1 * README, CHANGELOG * Bumped redis-sinatra 1.3.3 * Bumped redis-rack 1.4.2 * Bumped redis-i18n 0.6.1 * Relaxing dependencies * Relax requirement on redis (use >= 2.2.0) Because resque still depends on redis 2.x and sidekiq on redis 3.x, using >= 2.2.0 instead of ~> 3.0.0 allows compatibility with both. [Lukas Westermann] * Use default value for port, otherwise factory_test.rb:65 fails (port = 0) [Lukas Westermann] * Use redis 3.x [Lukas Westermann] * Adding examples for rails cache store config with URLs [aliix] * Bumped redis-rack-cache 1.2 * Bump: [Matt Horan] - redis-rails 3.2.3 - redis-actionpack 3.2.3 - redis-activesupport 3.2.3 * Loosen actionpack version requirement for possible Rails 3.2.3 compatibility [Filip Tepper] * Add Rails 3.2.2 support for redis-actionpack, redis-activesupport, redis-rails [Jack Chu] * Bumped redis-rack 1.4.1 * Bumped: - redis-rack 1.4.0 - redis-activesupport 3.2.1 - redis-actionpack 3.2.1 - redis-rails 3.2.1 * Bump redis-sinatra 1.3.2 *1.1.0 (February 14, 2012)* * Bump version v1.1.0 * Prepare stable releases - redis-store 1.1.0 - redis-actionpack 3.1.3 - redis-activesupport 3.1.3 - redis-i18n 0.6.0 - redis-rack-cache 1.1 - redis-rack 1.3.5 - redis-rails 3.1.3 - redis-sinatra 1.3.1 * Replace minitest-rails with mini_specunit [Matt Horan] * Bumped: [Matt Horan] - redis-actionpack 3.1.3.rc4 - redis-activesupport 3.1.3.rc2 - redis-i18n 0.6.0.rc2 - redis-rack-cache 1.1.rc3 - redis-rails 3.1.3.rc4 - redis-sinatra 1.3.1.rc2 * Remove redis-actionpack dependency on redis-rack-cache [Matt Horan] *1.1.0 [rc2] (February 3, 2012)* * Bump version v1.1.0.rc2 * Bumped: [Matt Horan] - redis-store 1.1.0.rc2 - redis-actionpack 3.1.3.rc3 - redis-rails 3.1.3.rc3 * README, CHANGELOG * Don't clobber :redis_server if provided to ActionDispatch::Session::RedisStore [Matt Horan] * Support :servers option to ActionDispatch::Session::RedisStore [Matt Horan] * Add missing assertions [Matt Horan] * Integrate against a distributed Redis store [Matt Horan] * Remove duplicated logic for merging default Redis server with options [Matt Horan] * Rename ActionDispatch::Session::RedisSessionStore to RedisStore in keeping with documentation and MemCacheStore [Matt Horan] * Test auto-load of unloaded class [Matt Horan] * Replace assert_response with must_be [Matt Horan] * Pending upstream fix [Matt Horan] * Additional tests for rack-actionpack, borrowed from MemCacheStoreTest [Matt Horan] * Test redis-actionpack with dummy Rails application [Matt Horan] * Use Rack::Session::Redis API in RedisSessionStore [Matt Horan] * Quiet warnings [Matt Horan] * Remove superfluous tests [Matt Horan] * Cleanup Redis::Store::Ttl setnx and set tests with help from @mike-burns [Matt Horan] * Verify Ttl#setnx sets raw => true if expiry is provided [Matt Horan] * Fix redis-rack spec [Matt Horan] * Previous fix for double marshal just disabled expiry. Instead, call setnx from Ttl module with :raw => true so that Marshal.dump [Matt Horan] * Test and fix for double marshal [Matt Horan] * Cleanup Redis::Store::Ttl spec [Matt Horan] * Fix Redis::Rack version require [Matt Horan] * Redis::Store::Ttl extends Redis#set with TTL support [Matt Horan] * Specs for Redis::Store::Ttl [Matt Horan] * Bumped: - redis-rack-cache 1.1.rc2 - redis-actionpack 3.1.3.rc2 - redis-rails 3.1.3.rc2 * Ensure TTL is an integer - Rails cache returns a float when used with race_condition_ttl [Matt Williams] *1.1.0 [rc] (December 30, 2011)* * Bump version v1.1.0.rc * Prepare RCs * redis-store 1.1.0.rc * CHANGELOG * Use strict dependencies. * READMEs and Licenses * redis-actionpack now depends on redis-rack-cache * Redis::Factory.convert_to_redis_client_options => Redis::Factory.resolve. * Don't use autoload * Make redis-rack-cache tests to pass again * Target Rack::Cache 1.1 for redis-rack-cache * Target Rack 1.4.0 for redis-rack * Gemspecs, dependencies and versions * Make redis-rails tests to pass again * redis-actionpack dependencies * redis-activesupport dependencies * Fix for redis-rack tests * Fix for redis-activesupport tests * Make redis-sinatra tests to pass again * Make redis-actionpack tests to pass again * Install bundler 1.1 RC on travis-ci.org [Michael Klishin] * Make redis-rack tests to pass again * Added SETEX support to Interface and Marshalling * Make redis-i18n tests to pass again * Make redis-activesupport tests to pass again * More tests for redis-store core * Redis::Factory is created with general options and not the redis_server [Julien Kirch] * Moved README.md * Split gems in subdirectories * Moved everything under redis-store * Use bundler 1.1.rc * Better Ruby idiom on File.expand_path * Moved Rake test tasks into lib/tasks/redis.tasks.rb, in order to DRY Rake * Testing: Use relative paths when referring to pid files * Autoload modules * Moved Rake test tasks under lib/ in order to make them accessible to all * Let the Redis::DistributedStore test to pass * Let Redis Rake tasks to work again * Run tests without dtach * Switch from RSpec to MiniTest::Unit * Removed all the references to Rails, Merb, Sinatra, Rack, i18n, Rack::Session and Rack::Cache * Gemfile is now depending on the gemspec. Removed Jewler. *1.0.0 (September 1, 2011)* * Bump version v1.0.0 * Avoid encoding issues when sending strings to Redis. [Damian Janowski] * Fixed a bug that caused all the users to share the same session (with a session_id of 0 or 1) [Mathieu Ravaux] * ActiveSupport cache stores reply to read_multi with a hash, not an array. [Matt Griffin] * Rack::Session && Rack::Cache store can be created with options [aligo] * add destroy_session [aligo] * compatible with rails 3.1. rely on Rack::Session::Redis stores API. [aligo] * Fixed Marshalling semantic *1.0.0 [rc1] (June 5, 2011)* * Bump version v1.0.0.rc1 * Re-implement the delete_entry because it s needed by the ActiveSupport::Cache [Cyril Mougel] * Change readme documentation for rack-cache to use single redis database with namespace support per Redis maintainers recommendation [Travis D. Warlick, Jr.] * Rack-Cache entity and meta store base classes should use the Redis::Factory.convert_to_redis_client_options method for DRYness and for namespace support [Travis D. Warlick, Jr.] * Modify #fetch for cache stores to return the yielded value instead of OK [Rune Botten] * Minor revisions to Readme language and organization [Jeff Casimir] * Re-implement the delete_entry because it s needed by the ActiveSupport::Cache implementation in Rails 3 [Cyril Mougel] * Refactor delete_matched [Andrei Kulakov] *1.0.0 [beta5] (April 2, 2011)* * Bump version v1.0.0.beta5 * Introducing Rails.cache.reconnect, useful for Unicorn environments. Closes #21 * Namespaced i18n backend should strip namespace when lists available locales. Closes #62 * how to configure Redis session store in Sinatra [Christian von Kleist] * gracefully handle Connection Refused errors, allows database fall-back on fetch [Michael Kintzer] * Sinatra's API must have changed, its registered not register. [Michael D'Auria] *1.0.0 [beta4] (December 15, 2010)* * Bump version v1.0.0.beta4 * Force Rails cache store when ActiveSupport is detected * Make sure to accept options when :servers isn't passed * Always force session store loading when using Rails * Make it compatible with Rails 3 sessions store [Andre Medeiros] * Better Rails 3 detection [Andre Medeiros] * Added support for password in Redis URI resolution [Jacob Gyllenstierna] * fix deleting values from session hash [Calvin Yu] * Use defensive design when build options for a store * ActiveSupport cache store doesn't accept any argument in Rails 2 * Updated dependencies *1.0.0 [beta3] (September 10, 2010)* * Bump version v1.0.0.beta3 * Updated gemspec * Made compatible with Ruby 1.9.2 * Made compatible with Rails 3 * Making the redis-store rails session store compatible with Rails 2.3.9. [Aaron Gibralter] * Updated to v2.3.9 the development dependencies for Rails 2.x * Added password support * Set default URI string for Rack session store according to redis gem * Require redis:// scheme as mandatory part of URI string * Updated locked dependencies * Added namespace support for Redis::DistrubutedStore * Specs for Interface module * Moved a spec to reflect lib/ structure * Made specs run again with bundler-1.0.0.rc.2 * Prepare for bundler-1.0.0.rc.1 * Use tmp/ for Redis database dumps * README, gemspec * Lookup for scoped keys * Introducing I18n::Backend::Redis * Don't pollute Redis namespace. closes #16 * Don't look twice for Rails module * Fixed loading ActionDispatch::Session issue with Rails 3 * ActiveSupport cache now uses new Rails 3 namespace API * Let Rack::Cache entity store to use plain Redis client * CHANGELOG * Gemspec * Redis::DistributedMarshaled => Redis::DistributedStore * Extracted expiration logic in Redis::Ttl * Introducing Redis::Store and extracted marshalling logic into Redis::Marshalling * CHANGELOG * Gemspec * Removed superfluous specs. Documentation. * Made the specs pass with Ruby 1.9.2 and Rails 3 * Made the specs pass with Ruby 1.9.2 * Prepare specs for Ruby 1.9.2 * Made the specs pass for Rails 3 * Namespaced keys for ActiveSupport::Cache::RedisStore * Got RedisSessionStore working again with namespace * Delegate MarshaledClient#to_s decoration to Redis::Namespace * Redis::Namespace * Accept :namespace option when instantiate a store * Test against merb-1.1.0 for now * Updated Rake tasks for Redis installation * Advanced configurations for Rails in README. closes #8 * Locked gems * Changed the gemspec according to the new directories structure * Changed directories structure, according to the ActiveSupport loading policies * Typo in CHANGELOG *1.0.0 [beta2] (June 12, 2010)* * Bump version v1.0.0.beta2 * Added committers names to CHANGELOG * Added CHANGELOG * Rake namespace: redis_cluster => redis:cluster * Fixed Rails 3 failing spec * Added ActiveSupport::Cache::RedisStore#read_multi * Enabled notifications for ActiveSupport::Cache::RedisStore * Moved spec * Use consistent Rails 3 check in session store * Make sure of use top-level module * Updated Rails 2.x development dependencies *1.0.0 [beta1] (June 9, 2010)* * Bump version v1.0.0.beta1 * Made specs pass for Ruby 1.9.1 * Updated instructions to test against Rails 3.x * Updated copyright year * Prepare for v1.0.0.beta1 * Use Rails v3.0.0.beta4 * Require redis >= 2.0.0 gem in Gemfile * Updated instructions for Rails 2 session store * Added instructions for Rails 3 configuration * Check against Rails#version instead of Rails::VERSION::STRING * Added redis gem as dependency * Changed spec_helper.rb according to the new Rails 3 check * Fix the rails3 check [Bruno Michel] * Added bundler cleanup Rake task * Fixed ActiveSupport::Cache::RedisStore#fetch * Re-enabled redis:console Rake task * Don't use Rspec#have with ActiveSupport 3 * Fixed Rails 2 regression for ActiveSupport::Cache::RedisStore#delete_matched * Fixed issues for ActiveSupport::Cache::RedisStore #delete_matched, #read, #rwrite * Rails 3 namespace * Use Rails edge instead of 3.0.0.beta3 * Made the specs run again * Updated Gemfile development/test dependencies for rails3. * Updated README instructions * Updated test configuration files, according to redis-2.0.0-rc1 defaults * Made specs pass with redis-2.0.0 gem * Don't support the old redis-rb namespace * Import the whole redis-rb old Rake tasks * Updated redis-rb dependency *0.3.8 [Final] (May 21, 2010)* * Fixed gemspec executable issue * Updated .gemspec * Version bump to 0.3.8 * Started namespace migration for redis-2.0.0 * Merge branch 'master' of http://github.com/akahn/redis-store * Fixed dependency issues. [Brian Takita] * Removed methopara because it require ruby 1.9.1. [Brian Takita] * Merge branch 'master' of http://github.com/dsander/redis-store [Brian Takita] * Moved RedisSessionStore to rack session directory. [Brian Takita] * Got RedisSessionStore working with passing specs. [Brian Takita] * Using modified version of RedisSessionStore (http://github.com/mattmatt/redis-session-store). Still needs testing. [Brian Takita] * Using redis 1.0.5. [Brian Takita] * Ignoring gem files and gemspecs with a prefix. [Brian Takita] * Added git and jeweler to dependencies. [Brian Takita] * Ignoring .bundle and rubymine files. [Brian Takita] * Added ability to add a prefix to the gem name via the GEM_PREFIX environment variable. [Brian Takita] * Fixed marshalling issues with the new Redis api. Fixed redis-server configurations for the latest version of redis-server. Added redis_cluster:start and redis_cluster:stop rake tasks. Spec suite passes. [Brian Takita] * Fixed redis deprecation warnings. [Brian Takita] * Using redis 1.0.4. Loading redis.tasks.rb from redis gem using Bundler. Fixed redis test configurations. [Brian Takita] * Supports redis 1.0.5 [Dominik Sander] * Add Rack::Session::Redis usage for Sinatra to README [Alexander Kahn] * Updated development and testing dependencies * Made compatible with rack-cache-0.5.2 *0.3.7 [Final] (November 15, 2009)* * Version bump to 0.3.7 * Version bump to 0.3.7 * Updated spec instructions in README * Jeweler generated redis-store.gemspec * Removed no longer used Rake tasks. Added Gemcutter support via Jeweler. * Typo * Let Rcov task run with the Redis cluster started * Make spec suite pass again * README.textile -> README.md * Re-enabled Merb specs * Added *.rdb in .gitignore * Run detached Redis instances for spec suite * Start detached Redis server for specs * Added Gemfile, removed rubygems dependecy for testing. * Added *.swp to .gitignore * Added jeweler rake tasks * Make it work in classic Sinatra apps. [Dmitriy Timokhin] * Updated README with new instructions about redis-rb *0.3.6 [Final] (June 18, 2009)* * Prepare for v0.3.6 * Updated README with new version * Changed Redis config files for specs * Updated README instructions * New filelist in gemspec * Fixed typo in spec * Don't try to unmarshal empty strings * Running specs according to the DEBUG env var * Added specs for uncovered Merb Cache API * Added rcov Rake task * Fix README * Fix typo in README * Updated README instructions * Removed RedisError catching * Declaring for now RedisError in spec_helper.rb * Removed unnecessary classes * Fix specs for DistributedMarshaledRedis * Fix some specs * Made Server#notify_observers private * Ensure to select the correct database after the socket connection * Reverted socket pooling. Ensure to always return an active socket. * Lowering default timeout from 10 to 0.1 *0.3.5 [Final] (May 7, 2009)* * Prepare for v0.3.5 * Totally replace ezmobius-redis-rb Server implementation * Fixed default Server timeout to 1 second * Little refactoring * Ensure Server#active? always returns a boolean and never raise an exception * Made configurable connection pool timeout and size * Socket connection pooling * Updated README *0.3.0 [Final] (May 3, 2009)* * Prepare for v0.3.0 * README formatting issues * README formatting (again) * README formatting * Updated Rack::Session instructions for Sinatra * Make Rack::Session implementation working with Merb * Added instructions for Rack::Session * Expiration support for Rack::Session * Ensure to test Rails and Sinatra expiration implementations with both MarshaledRedis and DistrbutedMarshaledRedis * Expiration support for Merb::Cache * Use full qualified class names in specs. Minor spec fix. * Ported for foreword compatibility the expiration implementation from ezmobius/redis-rb * Little spec cleanup * Full support for Rack::Session * Extracted some logic into RedisFactory * Initial support for Rack::Session *0.2.0 [Final] (April 30, 2009)* * Prepare for v0.2.0 * Links in README * Maybe someday I will use the right formatting rules at first attempt * Still formatting README * Formatting for README * Updated instructions for Rack::Cache * Don't require any cache store if no Ruby framework is detected * Implemented EntityStore for Rack::Cache * Added REDIS constant for Rack::Cache::Metastore * MetaStore implementation for Rack::Cache *0.1.0 [Final] (April 30, 2009)* * Prepare for v0.1.0 * Sinatra cache support *0.0.3 [Final] (April 30, 2009)* * Prepare for v0.0.3 * Updated instructions for Merb * Hack for Merb cyclic dependency * Renaming main lib * Merb store #writable always returns true. Added pending test. * Merb store #fetch refactoring * Updated Redis installation instructions * Implemented #fetch for Merb store * Implemented #exists?, #delete and #delete_all for Merb cache store * Renamed project name in Rakefile * Updated project name in README * Updated README with Merb instructions * Changed name in gemspec * New gemspec * Initial cache store support for Merb * Moving files around * Don't complain about missing db in tmp/ *0.0.2 [Final] (April 16, 2009)* * Prepare for v0.0.2 * Updated file list in gemspec * Updated README instructions * Re-enabled spec for RedisStore#fetch * Update rdoc * Fix RedisStore#clear when use a cluster * Test RedisStore both with single server and with a cluster * Fix port in DistributedMarshaledRedis spec * Don't slave Redis cluster node * Changed Redis cluster configuration * Added configuration for Redis cluster * Use a distributed system if the store uses more than one server * Accept params for client connection *0.0.1 [Final] (April 11, 2009)* * Added :unless_exist option to #write * Added failing specs for :expires_in option * Made optional args compatible with the Cache interface * Implemented #delete_matched, #clear, #stats * Implemented #delete, #exist?, #increment, #decrement * Introduced RedisStore * Initial import redis-store-1.10.0/.rubocop.yml0000644000004100000410000000544414537411545016353 0ustar www-datawww-data--- AllCops: TargetRubyVersion: 2.4 # RuboCop has a bunch of cops enabled by default. This setting tells RuboCop # to ignore them, so only the ones explicitly set in this file are enabled. DisabledByDefault: true Exclude: - "**/vendor/**/*" # Prefer &&/|| over and/or. Style/AndOr: Enabled: true # Align comments with method definitions. Layout/CommentIndentation: Enabled: true Layout/ElseAlignment: Enabled: true Layout/EmptyLineAfterMagicComment: Enabled: true # In a regular class definition, no empty lines around the body. Layout/EmptyLinesAroundClassBody: Enabled: true # In a regular method definition, no empty lines around the body. Layout/EmptyLinesAroundMethodBody: Enabled: true # In a regular module definition, no empty lines around the body. Layout/EmptyLinesAroundModuleBody: Enabled: true Layout/FirstParameterIndentation: Enabled: true # Method definitions after `private` or `protected` isolated calls need one # extra level of indentation. Layout/IndentationConsistency: Enabled: true EnforcedStyle: indented_internal_methods # Two spaces, no tabs (for indentation). Layout/IndentationWidth: Enabled: true Layout/LeadingCommentSpace: Enabled: true Layout/SpaceAfterColon: Enabled: true Layout/SpaceAfterComma: Enabled: true Layout/SpaceAroundEqualsInParameterDefault: Enabled: true Layout/SpaceAroundKeyword: Enabled: true Layout/SpaceAroundOperators: Enabled: true Layout/SpaceBeforeComma: Enabled: true Layout/SpaceBeforeFirstArg: Enabled: true Style/DefWithParentheses: Enabled: true # Defining a method with parameters needs parentheses. Style/MethodDefParentheses: Enabled: true # Use `foo {}` not `foo{}`. Layout/SpaceBeforeBlockBraces: Enabled: true # Use `foo { bar }` not `foo {bar}`. Layout/SpaceInsideBlockBraces: Enabled: true # Use `{ a: 1 }` not `{a:1}`. Layout/SpaceInsideHashLiteralBraces: Enabled: true Layout/SpaceInsideParens: Enabled: true # Detect hard tabs, no hard tabs. Layout/IndentationStyle: Enabled: true # Blank lines should not have any spaces. Layout/TrailingEmptyLines: Enabled: true # No trailing whitespace. Layout/TrailingWhitespace: Enabled: true # Use quotes for string literals when they are enough. Style/RedundantPercentQ: Enabled: true # Align `end` with the matching keyword or starting expression except for # assignments, where it should be aligned with the LHS. Layout/EndAlignment: Enabled: true EnforcedStyleAlignWith: variable AutoCorrect: true # Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg. Lint/RequireParentheses: Enabled: true Style/RedundantReturn: Enabled: true AllowMultipleReturnValues: true Style/Semicolon: Enabled: true AllowAsExpressionSeparator: true # Prefer Foo.method over Foo::method Style/ColonMethodCall: Enabled: true redis-store-1.10.0/Appraisals0000644000004100000410000000042414537411545016114 0ustar www-datawww-dataappraise "redis_4_0_x" do gem "redis", "~> 4.0.0" end appraise "redis_4_1_x" do gem "redis", "~> 4.1.0" end appraise "redis_4_6_x" do gem "redis", "~> 4.6.0" end appraise "redis_4_x" do gem "redis", "~> 4.0" end appraise "redis_5_x" do gem "redis", "~> 5.0" end redis-store-1.10.0/.gitignore0000644000004100000410000000020714537411545016061 0ustar www-datawww-dataGemfile.lock *.gem tmp/ stdout # Gemfile locks generated by Appraisals gemfiles/*.gemfile.lock gemfiles/.bundle/ # ASDF .tool-versions redis-store-1.10.0/.codeclimate.yml0000644000004100000410000000010514537411545017140 0ustar www-datawww-data--- plugins: rubocop: enabled: true fixme: enabled: true redis-store-1.10.0/Rakefile0000644000004100000410000000047514537411545015545 0ustar www-datawww-datarequire 'bundler/setup' require 'rake' require 'bundler/gem_tasks' require 'appraisal' require 'rubocop/rake_task' RuboCop::RakeTask.new :lint if !ENV["APPRAISAL_INITIALIZED"] && !ENV["CI"] task :default do sh "appraisal install && rake appraisal default" end else require 'redis-store/testing/tasks' end redis-store-1.10.0/lib/0000755000004100000410000000000014537411545014640 5ustar www-datawww-dataredis-store-1.10.0/lib/redis-store.rb0000644000004100000410000000002614537411545017423 0ustar www-datawww-datarequire 'redis/store' redis-store-1.10.0/lib/redis/0000755000004100000410000000000014537411545015746 5ustar www-datawww-dataredis-store-1.10.0/lib/redis/store/0000755000004100000410000000000014537411545017102 5ustar www-datawww-dataredis-store-1.10.0/lib/redis/store/interface.rb0000644000004100000410000000134114537411545021366 0ustar www-datawww-dataclass Redis class Store < self module Interface def get(key, options = nil) super(key) end REDIS_SET_OPTIONS = %i(ex px nx xx keepttl).freeze private_constant :REDIS_SET_OPTIONS def set(key, value, options = nil) if options && REDIS_SET_OPTIONS.any? { |k| options.key?(k) } kwargs = REDIS_SET_OPTIONS.each_with_object({}) { |key, h| h[key] = options[key] if options.key?(key) } super(key, value, **kwargs) else super(key, value) end end def setnx(key, value, options = nil) super(key, value) end def setex(key, expiry, value, options = nil) super(key, expiry, value) end end end end redis-store-1.10.0/lib/redis/store/version.rb0000644000004100000410000000044214537411545021114 0ustar www-datawww-dataclass Redis class Store < self VERSION = '1.10.0' def self.redis_client_defined? # Doesn't work if declared as constant # due to unpredictable gem loading order # https://github.com/redis-rb/redis-client defined?(::RedisClient::VERSION) end end end redis-store-1.10.0/lib/redis/store/serialization.rb0000644000004100000410000000334114537411545022305 0ustar www-datawww-dataclass Redis class Store < self module Serialization def set(key, value, options = nil) _marshal(value, options) { |v| super encode(key), encode(v), options } end def setnx(key, value, options = nil) _marshal(value, options) { |v| super encode(key), encode(v), options } end def setex(key, expiry, value, options = nil) _marshal(value, options) { |v| super encode(key), expiry, encode(v), options } end def get(key, options = nil) _unmarshal super(key), options end def mget(*keys, &blk) options = keys.pop if keys.last.is_a?(Hash) super(*keys) do |reply| reply.map! { |value| _unmarshal value, options } blk ? blk.call(reply) : reply end end def mset(*args) options = args.pop if args.length.odd? updates = [] args.each_slice(2) do |(key, value)| updates << encode(key) _marshal(value, options) { |v| updates << encode(v) } end super(*updates) end private def _marshal(val, options) yield marshal?(options) ? @serializer.dump(val) : val end def _unmarshal(val, options) unmarshal?(val, options) ? @serializer.load(val) : val end def marshal?(options) !(options && options[:raw]) end def unmarshal?(result, options) result && result.size > 0 && marshal?(options) end if defined?(Encoding) def encode(string) key = string.to_s.dup key.force_encoding(Encoding::BINARY) end else def encode(string) string end end end end end redis-store-1.10.0/lib/redis/store/namespace.rb0000644000004100000410000001167114537411545021371 0ustar www-datawww-dataclass Redis class Store < self module Namespace FLUSHDB_BATCH_SIZE = 1000 def set(key, *args) namespace(key) { |k| super(k, *args) } end def setex(key, *args) namespace(key) { |k| super(k, *args) } end def setnx(key, *args) namespace(key) { |k| super(k, *args) } end def ttl(key, options = nil) namespace(key) { |k| super(k) } end def get(key, *args) namespace(key) { |k| super(k, *args) } end def exists(*keys) super(*keys.map { |key| interpolate(key) }) end def exists?(*keys) super(*keys.map { |key| interpolate(key) }) end def incrby(key, increment) namespace(key) { |k| super(k, increment) } end def decrby(key, increment) namespace(key) { |k| super(k, increment) } end def keys(pattern = "*") namespace(pattern) { |p| super(p).map { |key| strip_namespace(key) } } end def scan(cursor, match: nil, **kwargs) if match namespace(match) do |pattern| cursor, keys = super(cursor, match: pattern, **kwargs) [ cursor, keys.map { |key| strip_namespace(key) } ] end else super(cursor, **kwargs) end end def del(*keys) super(*keys.map { |key| interpolate(key) }) if keys.any? end def unlink(*keys) super(*keys.map { |key| interpolate(key) }) if keys.any? end def watch(*keys) super(*keys.map { |key| interpolate(key) }) if keys.any? end def mget(*keys, &blk) options = (keys.pop if keys.last.is_a? Hash) || {} if keys.any? # Serialization gets extended before Namespace does, so we need to pass options further if singleton_class.ancestors.include? Serialization super(*keys.map { |key| interpolate(key) }, options, &blk) else super(*keys.map { |key| interpolate(key) }, &blk) end end end def expire(key, ttl) namespace(key) { |k| super(k, ttl) } end def hdel(key, *fields) namespace(key) { |k| super(k, *fields) } end def hget(key, field) namespace(key) { |k| super(k, field) } end def hgetall(key) namespace(key) { |k| super(k) } end def hexists(key, field) namespace(key) { |k| super(k, field) } end def hincrby(key, field, increment) namespace(key) { |k| super(k, field, increment) } end def hincrbyfloat(key, field, increment) namespace(key) { |k| super(k, field, increment) } end def hkeys(key) namespace(key) { |k| super(k) } end def hlen(key) namespace(key) { |k| super(k) } end def hmget(key, *fields, &blk) namespace(key) { |k| super(k, *fields, &blk) } end def hmset(key, *attrs) namespace(key) { |k| super(k, *attrs) } end def hset(key, *args) namespace(key) { |k| super(k, *args) } end def hsetnx(key, field, val) namespace(key) { |k| super(k, field, val) } end def hvals(key) namespace(key) { |k| super(k) } end def hscan(key, *args) namespace(key) { |k| super(k, *args) } end def hscan_each(key, *args) namespace(key) { |k| super(k, *args) } end def zincrby(key, increment, member) namespace(key) { |k| super(k, increment, member) } end def zscore(key, member) namespace(key) { |k| super(k, member) } end def zadd(key, *args) namespace(key) { |k| super(k, *args) } end def zrem(key, member) namespace(key) { |k| super(k, member) } end if respond_to?(:ruby2_keywords, true) ruby2_keywords :set, :setex, :setnx, :hscan, :hscan_each end def to_s if namespace_str "#{super} with namespace #{namespace_str}" else super end end def flushdb return super unless namespace_str keys.each_slice(FLUSHDB_BATCH_SIZE) { |key_slice| del(*key_slice) } end def with_namespace(ns) old_ns = @namespace @namespace = ns yield self ensure @namespace = old_ns end private def namespace(key) yield interpolate(key) end def namespace_str @namespace.is_a?(Proc) ? @namespace.call : @namespace end def interpolate(key) return key unless namespace_str key.match(namespace_regexp) ? key : "#{namespace_str}:#{key}" end def strip_namespace(key) return key unless namespace_str key.gsub namespace_regexp, "" end def namespace_regexp @namespace_regexps ||= {} @namespace_regexps[namespace_str] ||= %r{^#{namespace_str}\:} end end end end redis-store-1.10.0/lib/redis/store/factory.rb0000644000004100000410000000550414537411545021102 0ustar www-datawww-datarequire 'cgi' require 'uri' class Redis class Store < self class Factory DEFAULT_PORT = 6379 def self.create(*options) new(options).create end def initialize(*options) @addresses = [] @options = {} extract_addresses_and_options(options) end def create if @addresses.empty? @addresses << {} end if @addresses.size > 1 ::Redis::DistributedStore.new @addresses, @options else ::Redis::Store.new @addresses.first.merge(@options) end end def self.resolve(uri) #:api: private if uri.is_a?(Hash) extract_host_options_from_hash(uri) else extract_host_options_from_uri(uri) end end def self.extract_host_options_from_hash(options) options = normalize_key_names(options) if host_options?(options) options else nil end end def self.normalize_key_names(options) options = options.dup if options.key?(:key_prefix) && !options.key?(:namespace) options[:namespace] = options.delete(:key_prefix) # RailsSessionStore end options[:raw] = case when options.key?(:serializer) options[:serializer].nil? when options.key?(:marshalling) !options[:marshalling] else false end options end def self.host_options?(options) options.keys.any? { |n| [:host, :db, :port, :path].include?(n) } end def self.extract_host_options_from_uri(uri) uri = URI.parse(uri) if uri.scheme == "unix" options = { :path => uri.path } else _, db, namespace = if uri.path uri.path.split(/\//) end options = { :scheme => uri.scheme, :host => uri.hostname, :port => uri.port || DEFAULT_PORT, :password => uri.password.nil? ? nil : CGI.unescape(uri.password.to_s) } options[:db] = db.to_i if db options[:namespace] = namespace if namespace end if uri.query query = Hash[URI.decode_www_form(uri.query)] query.each do |(key, value)| options[key.to_sym] = value end end options end private def extract_addresses_and_options(*options) options.flatten.compact.each do |token| resolved = self.class.resolve(token) if resolved @addresses << resolved else @options.merge!(self.class.normalize_key_names(token)) end end end end end end redis-store-1.10.0/lib/redis/store/ttl.rb0000644000004100000410000000246614537411545020242 0ustar www-datawww-dataclass Redis class Store < self module Ttl def set(key, value, options = nil) if ttl = expires_in(options) setex(key, ttl.to_i, value, :raw => true) else super(key, value, options) end end def setnx(key, value, options = nil) if ttl = expires_in(options) setnx_with_expire(key, value, ttl.to_i, options) else super(key, value) end end protected def setnx_with_expire(key, value, ttl, options = {}) with_multi_or_pipelined(options) do |transaction| if transaction.is_a?(Redis::Store) # for redis < 4.6 setnx(key, value, :raw => true) expire(key, ttl) else transaction.setnx(key, value) transaction.expire(key, ttl) end end end private def expires_in(options) if options # Rack::Session Merb Rails/Sinatra options[:expire_after] || options[:expires_in] || options[:expire_in] end end def with_multi_or_pipelined(options, &block) return pipelined(&block) if options.key?(:cluster) || options[:avoid_multi_commands] multi(&block) end end end end redis-store-1.10.0/lib/redis/store/redis_version.rb0000644000004100000410000000044214537411545022302 0ustar www-datawww-dataclass Redis class Store < self module RedisVersion def redis_version info('server')['redis_version'] end def supports_redis_version?(version) (redis_version.split(".").map(&:to_i) <=> version.split(".").map(&:to_i)) >= 0 end end end end redis-store-1.10.0/lib/redis/distributed_store.rb0000644000004100000410000000311514537411545022031 0ustar www-datawww-datarequire 'redis/distributed' class Redis class DistributedStore < Distributed @@timeout = 5 attr_reader :ring def initialize(addresses, options = {}) _extend_namespace options # `@tag` introduced in `redis-rb` 5.0 @tag = options[:tag] || /^\{(.+?)\}/ @ring = options[:ring] || Redis::HashRing.new([], options[:replicas] || Redis::HashRing::POINTS_PER_SERVER) addresses.each do |address| @ring.add_node(::Redis::Store.new _merge_options(address, options)) end end def nodes ring.nodes end def reconnect nodes.each { |node| node.reconnect } end def set(key, value, options = nil) node_for(key).set(key, value, options) end def get(key, options = nil) node_for(key).get(key, options) end def setnx(key, value, options = nil) node_for(key).setnx(key, value, options) end def redis_version nodes.first.redis_version unless nodes.empty? end def supports_redis_version?(version) if nodes.empty? false else nodes.first.supports_redis_version?(version) end end def setex(key, expiry, value, options = nil) node_for(key).setex(key, expiry, value, options) end private def _extend_namespace(options) @namespace = options[:namespace] extend ::Redis::Store::Namespace if @namespace end def _merge_options(address, options) address.merge( :timeout => options[:timeout] || @@timeout, :namespace => options[:namespace] ) end end end redis-store-1.10.0/lib/redis/store.rb0000644000004100000410000000450614537411545017434 0ustar www-datawww-datarequire 'redis' require 'redis/store/factory' require 'redis/distributed_store' require 'redis/store/namespace' require 'redis/store/serialization' require 'redis/store/version' require 'redis/store/redis_version' require 'redis/store/ttl' require 'redis/store/interface' require 'redis/store/redis_version' class Redis class Store < self include Ttl, Interface, RedisVersion def initialize(options = {}) orig_options = options.dup _remove_unsupported_options(options) # The options here is updated super(options) unless orig_options[:marshalling].nil? puts %( DEPRECATED: You are passing the :marshalling option, which has been replaced with `serializer: Marshal` to support pluggable serialization backends. To disable serialization (much like disabling marshalling), pass `serializer: nil` in your configuration. The :marshalling option will be removed for redis-store 2.0. ) end @serializer = orig_options.key?(:serializer) ? orig_options.delete(:serializer) : Marshal unless orig_options[:marshalling].nil? # `marshalling` only used here, might not be supported in `super` @serializer = orig_options.delete(:marshalling) ? Marshal : nil end _extend_marshalling _extend_namespace orig_options end def reconnect @client.reconnect end def to_s "Redis Client connected to #{location} against DB #{@client.db}" end def location if @client.path @client.path else h = @client.host h = "[#{h}]" if h.include?(":") "#{h}:#{@client.port}" end end private def _remove_unsupported_options(options) return unless self.class.redis_client_defined? # Unsupported keywords should be removed to avoid errors # https://github.com/redis-rb/redis-client/blob/v0.13.0/lib/redis_client/config.rb#L21 options.delete(:raw) options.delete(:serializer) options.delete(:marshalling) options.delete(:namespace) options.delete(:scheme) end def _extend_marshalling extend Serialization unless @serializer.nil? end def _extend_namespace(options) @namespace = options[:namespace] extend Namespace end end end redis-store-1.10.0/Gemfile0000644000004100000410000000012714537411545015365 0ustar www-datawww-datasource 'https://rubygems.org' if RUBY_VERSION < '2' gem 'redis', '< 4' end gemspec redis-store-1.10.0/.github/0000755000004100000410000000000014537411545015432 5ustar www-datawww-dataredis-store-1.10.0/.github/release.yml0000644000004100000410000000044214537411545017575 0ustar www-datawww-datachangelog: exclude: labels: [dependencies] authors: [renovate-bot] categories: - title: Breaking Changes labels: [breaking] - title: New Features labels: [enhancement] - title: Bug Fixes labels: [bug] - title: Other Changes labels: ["*"] redis-store-1.10.0/.github/workflows/0000755000004100000410000000000014537411545017467 5ustar www-datawww-dataredis-store-1.10.0/.github/workflows/ci.yml0000644000004100000410000000270514537411545020611 0ustar www-datawww-dataname: CI on: pull_request: push: branches-ignore: [master] tags-ignore: [v*] concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: test: name: "test (ruby: ${{ matrix.ruby }}, redis.rb: ${{ matrix.redis }})" runs-on: ubuntu-latest continue-on-error: ${{ contains(matrix.ruby, 'head') }} strategy: fail-fast: false matrix: ruby: - "2.7" - "3.0" - "3.1" # - 'head' - "jruby" # - 'jruby-head' - "truffleruby" # - 'truffleruby-head' redis: - 4_0_x - 4_1_x - 4_x - 5_x env: BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/redis_${{ matrix.redis }}.gemfile services: redis: image: redis ports: - 6379:6379 distributed1: image: redis ports: - 6380:6380 distributed2: image: redis ports: - 6381:6381 steps: - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} bundler-cache: true - run: bundle exec rake lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 with: fetch-depth: 0 - uses: ruby/setup-ruby@v1 with: ruby-version: 3.1 bundler-cache: true - run: bundle exec rake lint redis-store-1.10.0/.github/workflows/publish.yml0000644000004100000410000000142514537411545021662 0ustar www-datawww-dataname: Publish on: push: tags: [v*] permissions: contents: write concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: release: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: ruby-version: "3.1" bundle-cache: true - run: | mkdir -p ~/.gem cat << EOF > ~/.gem/credentials --- :rubygems_api_key: ${{ secrets.RUBYGEMS_API_KEY }} EOF chmod 0600 ~/.gem/credentials - run: bundle exec rake release - uses: softprops/action-gh-release@v1 with: files: "*.gem" generate_release_notes: true prerelease: ${{ contains(github.ref, '.pre') }} redis-store-1.10.0/.github/auto-assign-issues.yml0000644000004100000410000000002514537411545021715 0ustar www-datawww-dataassignees: - tubbo redis-store-1.10.0/MIT-LICENSE0000644000004100000410000000204514537411545015527 0ustar www-datawww-dataCopyright (c) 2009 - 2011 Luca Guidi Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. redis-store-1.10.0/redis-store.gemspec0000644000004100000410000000221614537411545017700 0ustar www-datawww-data# -*- encoding: utf-8 -*- $:.push File.expand_path('../lib', __FILE__) require 'redis/store/version' Gem::Specification.new do |s| s.name = 'redis-store' s.version = Redis::Store::VERSION s.authors = ['Luca Guidi'] s.email = ['me@lucaguidi.com'] s.homepage = 'http://redis-store.org/redis-store' s.summary = 'Redis stores for Ruby frameworks' s.description = 'Namespaced Rack::Session, Rack::Cache, I18n and cache Redis stores for Ruby web frameworks.' s.files = `git ls-files`.split("\n") s.require_paths = ["lib"] s.license = 'MIT' s.add_dependency 'redis', '>= 4', '< 6' s.add_development_dependency 'rake', '>= 12.3.3' s.add_development_dependency 'bundler' s.add_development_dependency 'mocha', '~> 2.1.0' s.add_development_dependency 'minitest', '~> 5' s.add_development_dependency 'git', '~> 1.2' s.add_development_dependency 'pry-nav', '~> 0.2.4' s.add_development_dependency 'pry', '~> 0.10.4' s.add_development_dependency 'redis-store-testing' s.add_development_dependency 'appraisal', '~> 2.0' s.add_development_dependency 'rubocop', '~> 0.54' end