redis-namespace-with-multi 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Chris Wanstrath
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,38 @@
1
+ redis-namespace
2
+ ---------------
3
+
4
+ Requires the redis gem.
5
+
6
+ Namespaces all Redis calls.
7
+
8
+ ``` ruby
9
+ r = Redis::Namespace.new(:ns, :redis => @r)
10
+ r['foo'] = 1000
11
+ ```
12
+
13
+ This will perform the equivalent of:
14
+
15
+ redis-cli set ns:foo 1000
16
+
17
+ Useful when you have multiple systems using Redis differently in your app.
18
+
19
+
20
+ Installation
21
+ ============
22
+
23
+ $ gem install redis-namespace
24
+
25
+
26
+
27
+ Testing
28
+ =======
29
+
30
+ $ bundle install
31
+ $ rake
32
+
33
+
34
+ Author
35
+ =====
36
+
37
+ Chris Wanstrath :: chris@ozmm.org
38
+ Terence Lee :: hone02@gmail.com
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ task :default => :spec
2
+ task :test => :spec
3
+
4
+ desc "Run specs"
5
+ task :spec do
6
+ exec "rspec spec/redis_spec.rb"
7
+ end
@@ -0,0 +1,316 @@
1
+ require 'redis'
2
+
3
+ class Redis
4
+ class Namespace
5
+ # The following table defines how input parameters and result
6
+ # values should be modified for the namespace.
7
+ #
8
+ # COMMANDS is a hash. Each key is the name of a command and each
9
+ # value is a two element array.
10
+ #
11
+ # The first element in the value array describes how to modify the
12
+ # arguments passed. It can be one of:
13
+ #
14
+ # nil
15
+ # Do nothing.
16
+ # :first
17
+ # Add the namespace to the first argument passed, e.g.
18
+ # GET key => GET namespace:key
19
+ # :all
20
+ # Add the namespace to all arguments passed, e.g.
21
+ # MGET key1 key2 => MGET namespace:key1 namespace:key2
22
+ # :exclude_first
23
+ # Add the namespace to all arguments but the first, e.g.
24
+ # :exclude_last
25
+ # Add the namespace to all arguments but the last, e.g.
26
+ # BLPOP key1 key2 timeout =>
27
+ # BLPOP namespace:key1 namespace:key2 timeout
28
+ # :exclude_options
29
+ # Add the namespace to all arguments, except the last argument,
30
+ # if the last argument is a hash of options.
31
+ # ZUNIONSTORE key1 2 key2 key3 WEIGHTS 2 1 =>
32
+ # ZUNIONSTORE namespace:key1 2 namespace:key2 namespace:key3 WEIGHTS 2 1
33
+ # :alternate
34
+ # Add the namespace to every other argument, e.g.
35
+ # MSET key1 value1 key2 value2 =>
36
+ # MSET namespace:key1 value1 namespace:key2 value2
37
+ #
38
+ # The second element in the value array describes how to modify
39
+ # the return value of the Redis call. It can be one of:
40
+ #
41
+ # nil
42
+ # Do nothing.
43
+ # :all
44
+ # Add the namespace to all elements returned, e.g.
45
+ # key1 key2 => namespace:key1 namespace:key2
46
+ COMMANDS = {
47
+ "append" => [:first],
48
+ "auth" => [],
49
+ "bgrewriteaof" => [],
50
+ "bgsave" => [],
51
+ "bitcount" => [ :first ],
52
+ "bitop" => [ :exclude_first ],
53
+ "blpop" => [ :exclude_last, :first ],
54
+ "brpop" => [ :exclude_last ],
55
+ "brpoplpush" => [ :exclude_last ],
56
+ "config" => [],
57
+ "dbsize" => [],
58
+ "debug" => [ :exclude_first ],
59
+ "decr" => [ :first ],
60
+ "decrby" => [ :first ],
61
+ "del" => [ :all ],
62
+ "discard" => [],
63
+ "dump" => [ :first ],
64
+ "exists" => [ :first ],
65
+ "expire" => [ :first ],
66
+ "expireat" => [ :first ],
67
+ "flushall" => [],
68
+ "flushdb" => [],
69
+ "get" => [ :first ],
70
+ "getbit" => [ :first ],
71
+ "getrange" => [ :first ],
72
+ "getset" => [ :first ],
73
+ "hset" => [ :first ],
74
+ "hsetnx" => [ :first ],
75
+ "hget" => [ :first ],
76
+ "hincrby" => [ :first ],
77
+ "hincrbyfloat" => [ :first ],
78
+ "hmget" => [ :first ],
79
+ "hmset" => [ :first ],
80
+ "hdel" => [ :first ],
81
+ "hexists" => [ :first ],
82
+ "hlen" => [ :first ],
83
+ "hkeys" => [ :first ],
84
+ "hvals" => [ :first ],
85
+ "hgetall" => [ :first ],
86
+ "incr" => [ :first ],
87
+ "incrby" => [ :first ],
88
+ "incrbyfloat" => [ :first ],
89
+ "info" => [],
90
+ "keys" => [ :first, :all ],
91
+ "lastsave" => [],
92
+ "lindex" => [ :first ],
93
+ "linsert" => [ :first ],
94
+ "llen" => [ :first ],
95
+ "lpop" => [ :first ],
96
+ "lpush" => [ :first ],
97
+ "lpushx" => [ :first ],
98
+ "lrange" => [ :first ],
99
+ "lrem" => [ :first ],
100
+ "lset" => [ :first ],
101
+ "ltrim" => [ :first ],
102
+ "mapped_hmset" => [ :first ],
103
+ "mapped_hmget" => [ :first ],
104
+ "mapped_mget" => [ :all, :all ],
105
+ "mget" => [ :all ],
106
+ "monitor" => [ :monitor ],
107
+ "move" => [ :first ],
108
+ "mset" => [ :alternate ],
109
+ "msetnx" => [ :alternate ],
110
+ "object" => [ :exclude_first ],
111
+ "persist" => [ :first ],
112
+ "pexpire" => [ :first ],
113
+ "pexpireat" => [ :first ],
114
+ "ping" => [],
115
+ "psetex" => [ :first ],
116
+ "psubscribe" => [ :all ],
117
+ "pttl" => [ :first ],
118
+ "publish" => [ :first ],
119
+ "punsubscribe" => [ :all ],
120
+ "quit" => [],
121
+ "randomkey" => [],
122
+ "rename" => [ :all ],
123
+ "renamenx" => [ :all ],
124
+ "restore" => [ :first ],
125
+ "rpop" => [ :first ],
126
+ "rpoplpush" => [ :all ],
127
+ "rpush" => [ :first ],
128
+ "rpushx" => [ :first ],
129
+ "sadd" => [ :first ],
130
+ "save" => [],
131
+ "scard" => [ :first ],
132
+ "sdiff" => [ :all ],
133
+ "sdiffstore" => [ :all ],
134
+ "select" => [],
135
+ "set" => [ :first ],
136
+ "setbit" => [ :first ],
137
+ "setex" => [ :first ],
138
+ "setnx" => [ :first ],
139
+ "setrange" => [ :first ],
140
+ "shutdown" => [],
141
+ "sinter" => [ :all ],
142
+ "sinterstore" => [ :all ],
143
+ "sismember" => [ :first ],
144
+ "slaveof" => [],
145
+ "smembers" => [ :first ],
146
+ "smove" => [ :exclude_last ],
147
+ "sort" => [ :sort ],
148
+ "spop" => [ :first ],
149
+ "srandmember" => [ :first ],
150
+ "srem" => [ :first ],
151
+ "subscribe" => [ :all ],
152
+ "sunion" => [ :all ],
153
+ "sunionstore" => [ :all ],
154
+ "ttl" => [ :first ],
155
+ "type" => [ :first ],
156
+ "unsubscribe" => [ :all ],
157
+ "watch" => [ :all ],
158
+ "zadd" => [ :first ],
159
+ "zcard" => [ :first ],
160
+ "zcount" => [ :first ],
161
+ "zincrby" => [ :first ],
162
+ "zinterstore" => [ :exclude_options ],
163
+ "zrange" => [ :first ],
164
+ "zrangebyscore" => [ :first ],
165
+ "zrank" => [ :first ],
166
+ "zrem" => [ :first ],
167
+ "zremrangebyrank" => [ :first ],
168
+ "zremrangebyscore" => [ :first ],
169
+ "zrevrange" => [ :first ],
170
+ "zrevrangebyscore" => [ :first ],
171
+ "zrevrank" => [ :first ],
172
+ "zscore" => [ :first ],
173
+ "zunionstore" => [ :exclude_options ],
174
+ "[]" => [ :first ],
175
+ "[]=" => [ :first ]
176
+ }
177
+
178
+ # support previous versions of redis gem
179
+ ALIASES = case
180
+ when defined? Redis::Client::ALIASES then Redis::Client::ALIASES
181
+ when defined? Redis::ALIASES then Redis::ALIASES
182
+ else {}
183
+ end
184
+
185
+ attr_accessor :namespace
186
+ attr_reader :redis
187
+
188
+ def initialize(namespace, options = {})
189
+ @namespace = namespace
190
+ @redis = options[:redis] || Redis.current
191
+ end
192
+
193
+ # Ruby defines a now deprecated type method so we need to override it here
194
+ # since it will never hit method_missing
195
+ def type(key)
196
+ method_missing(:type, key)
197
+ end
198
+
199
+ alias_method :self_respond_to?, :respond_to?
200
+
201
+ def respond_to?(command, include_private=false)
202
+ if self_respond_to?(command, include_private)
203
+ true
204
+ else
205
+ @redis.respond_to?(command, include_private)
206
+ end
207
+ end
208
+
209
+ def keys(query = nil)
210
+ query.nil? ? super("*") : super
211
+ end
212
+
213
+ def multi(&block)
214
+ namespaced_block(:multi, &block)
215
+ end
216
+
217
+ def pipelined(&block)
218
+ namespaced_block(:pipelined, &block)
219
+ end
220
+
221
+ def method_missing(command, *args, &block)
222
+ handling = COMMANDS[command.to_s] ||
223
+ COMMANDS[ALIASES[command.to_s]]
224
+
225
+ # redis-namespace does not know how to handle this command.
226
+ # Passing it to @redis as is.
227
+ if handling.nil?
228
+ return @redis.send(command, *args, &block)
229
+ end
230
+
231
+ (before, after) = handling
232
+
233
+ # Add the namespace to any parameters that are keys.
234
+ case before
235
+ when :first
236
+ args[0] = add_namespace(args[0]) if args[0]
237
+ when :all
238
+ args = add_namespace(args)
239
+ when :exclude_first
240
+ first = args.shift
241
+ args = add_namespace(args)
242
+ args.unshift(first) if first
243
+ when :exclude_last
244
+ last = args.pop
245
+ args = add_namespace(args)
246
+ args.push(last) if last
247
+ when :exclude_options
248
+ if args.last.is_a?(Hash)
249
+ last = args.pop
250
+ args = add_namespace(args)
251
+ args.push(last)
252
+ else
253
+ args = add_namespace(args)
254
+ end
255
+ when :alternate
256
+ args.each_with_index { |a, i| args[i] = add_namespace(a) if i.even? }
257
+ when :sort
258
+ args[0] = add_namespace(args[0]) if args[0]
259
+ [:by, :get, :store].each do |key|
260
+ args[1][key] = add_namespace(args[1][key]) if args[1][key]
261
+ end if args[1].is_a?(Hash)
262
+ end
263
+
264
+ # Dispatch the command to Redis and store the result.
265
+ result = @redis.send(command, *args, &block)
266
+
267
+ # Remove the namespace from results that are keys.
268
+ case after
269
+ when :all
270
+ result = rem_namespace(result)
271
+ when :first
272
+ result[0] = rem_namespace(result[0]) if result
273
+ end
274
+
275
+ result
276
+ end
277
+
278
+ private
279
+
280
+ def namespaced_block(command, &block)
281
+ original = @redis
282
+ result = redis.send(command) do |r|
283
+ @redis = r
284
+ yield self
285
+ end
286
+ @redis = original
287
+ result
288
+ end
289
+
290
+ def add_namespace(key)
291
+ return key unless key && @namespace
292
+
293
+ case key
294
+ when Array
295
+ key.map {|k| add_namespace k}
296
+ when Hash
297
+ Hash[*key.map {|k, v| [ add_namespace(k), v ]}.flatten]
298
+ else
299
+ "#{@namespace}:#{key}"
300
+ end
301
+ end
302
+
303
+ def rem_namespace(key)
304
+ return key unless key && @namespace
305
+
306
+ case key
307
+ when Array
308
+ key.map {|k| rem_namespace k}
309
+ when Hash
310
+ Hash[*key.map {|k, v| [ rem_namespace(k), v ]}.flatten]
311
+ else
312
+ key.to_s.gsub /^#{@namespace}:/, ""
313
+ end
314
+ end
315
+ end
316
+ end
@@ -0,0 +1 @@
1
+ require 'redis/namespace'
@@ -0,0 +1,361 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe "redis" do
4
+ @redis_version = Gem::Version.new(Redis.current.info["redis_version"])
5
+
6
+ before(:all) do
7
+ # use database 15 for testing so we dont accidentally step on your real data
8
+ @redis = Redis.new :db => 15
9
+ end
10
+
11
+ before(:each) do
12
+ @namespaced = Redis::Namespace.new(:ns, :redis => @redis)
13
+ @namespaced.flushdb
14
+ @redis['foo'] = 'bar'
15
+ end
16
+
17
+ after(:each) do
18
+ @redis.flushdb
19
+ end
20
+
21
+ after(:all) do
22
+ @redis.quit
23
+ end
24
+
25
+ it "proxies `client` to the client" do
26
+ @namespaced.client.should == @redis.client
27
+ end
28
+
29
+ it "should be able to use a namespace" do
30
+ @namespaced['foo'].should == nil
31
+ @namespaced['foo'] = 'chris'
32
+ @namespaced['foo'].should == 'chris'
33
+ @redis['foo'] = 'bob'
34
+ @redis['foo'].should == 'bob'
35
+
36
+ @namespaced.incrby('counter', 2)
37
+ @namespaced['counter'].to_i.should == 2
38
+ @redis['counter'].should == nil
39
+ @namespaced.type('counter').should == 'string'
40
+ end
41
+
42
+ it "should be able to use a namespace with bpop" do
43
+ @namespaced.rpush "foo", "string"
44
+ @namespaced.rpush "foo", "ns:string"
45
+ @namespaced.blpop("foo", 1).should == ["foo", "string"]
46
+ @namespaced.blpop("foo", 1).should == ["foo", "ns:string"]
47
+ @namespaced.blpop("foo", 1).should == nil
48
+ end
49
+
50
+ it "should be able to use a namespace with del" do
51
+ @namespaced['foo'] = 1000
52
+ @namespaced['bar'] = 2000
53
+ @namespaced['baz'] = 3000
54
+ @namespaced.del 'foo'
55
+ @namespaced['foo'].should == nil
56
+ @namespaced.del 'bar', 'baz'
57
+ @namespaced['bar'].should == nil
58
+ @namespaced['baz'].should == nil
59
+ end
60
+
61
+ it 'should be able to use a namespace with append' do
62
+ @namespaced['foo'] = 'bar'
63
+ @namespaced.append('foo','n').should == 4
64
+ @namespaced['foo'].should == 'barn'
65
+ @redis['foo'].should == 'bar'
66
+ end
67
+
68
+ it 'should be able to use a namespace with brpoplpush' do
69
+ @namespaced.lpush('foo','bar')
70
+ @namespaced.brpoplpush('foo','bar',0).should == 'bar'
71
+ @namespaced.lrange('foo',0,-1).should == []
72
+ @namespaced.lrange('bar',0,-1).should == ['bar']
73
+ end
74
+
75
+ it 'should be able to use a namespace with getbit' do
76
+ @namespaced.set('foo','bar')
77
+ @namespaced.getbit('foo',1).should == 1
78
+ end
79
+
80
+ it 'should be able to use a namespace with getrange' do
81
+ @namespaced.set('foo','bar')
82
+ @namespaced.getrange('foo',0,-1).should == 'bar'
83
+ end
84
+
85
+ it 'should be able to use a namespace with linsert' do
86
+ @namespaced.rpush('foo','bar')
87
+ @namespaced.rpush('foo','barn')
88
+ @namespaced.rpush('foo','bart')
89
+ @namespaced.linsert('foo','BEFORE','barn','barf').should == 4
90
+ @namespaced.lrange('foo',0,-1).should == ['bar','barf','barn','bart']
91
+ end
92
+
93
+ it 'should be able to use a namespace with lpushx' do
94
+ @namespaced.lpushx('foo','bar').should == 0
95
+ @namespaced.lpush('foo','boo')
96
+ @namespaced.lpushx('foo','bar').should == 2
97
+ @namespaced.lrange('foo',0,-1).should == ['bar','boo']
98
+ end
99
+
100
+ it 'should be able to use a namespace with rpushx' do
101
+ @namespaced.rpushx('foo','bar').should == 0
102
+ @namespaced.lpush('foo','boo')
103
+ @namespaced.rpushx('foo','bar').should == 2
104
+ @namespaced.lrange('foo',0,-1).should == ['boo','bar']
105
+ end
106
+
107
+ it 'should be able to use a namespace with setbit' do
108
+ @namespaced.setbit('virgin_key', 1, 1)
109
+ @namespaced.exists('virgin_key').should be_true
110
+ @namespaced.get('virgin_key').should == @namespaced.getrange('virgin_key',0,-1)
111
+ end
112
+
113
+ it 'should be able to use a namespace with setrange' do
114
+ @namespaced.setrange('foo', 0, 'bar')
115
+ @namespaced['foo'].should == 'bar'
116
+
117
+ @namespaced.setrange('bar', 2, 'foo')
118
+ @namespaced['bar'].should == "\000\000foo"
119
+ end
120
+
121
+ it "should be able to use a namespace with mget" do
122
+ @namespaced['foo'] = 1000
123
+ @namespaced['bar'] = 2000
124
+ @namespaced.mapped_mget('foo', 'bar').should == { 'foo' => '1000', 'bar' => '2000' }
125
+ @namespaced.mapped_mget('foo', 'baz', 'bar').should == {'foo'=>'1000', 'bar'=>'2000', 'baz' => nil}
126
+ end
127
+
128
+ it "should be able to use a namespace with mset" do
129
+ @namespaced.mset('foo', '1000', 'bar', '2000')
130
+ @namespaced.mapped_mget('foo', 'bar').should == { 'foo' => '1000', 'bar' => '2000' }
131
+ @namespaced.mapped_mget('foo', 'baz', 'bar').should == { 'foo' => '1000', 'bar' => '2000', 'baz' => nil}
132
+ end
133
+
134
+ it "should be able to use a namespace with msetnx" do
135
+ @namespaced.msetnx('foo', '1000', 'bar', '2000')
136
+ @namespaced.mapped_mget('foo', 'bar').should == { 'foo' => '1000', 'bar' => '2000' }
137
+ @namespaced.mapped_mget('foo', 'baz', 'bar').should == { 'foo' => '1000', 'bar' => '2000', 'baz' => nil}
138
+ end
139
+
140
+ it "should be able to use a namespace with hashes" do
141
+ @namespaced.hset('foo', 'key', 'value')
142
+ @namespaced.hset('foo', 'key1', 'value1')
143
+ @namespaced.hget('foo', 'key').should == 'value'
144
+ @namespaced.hgetall('foo').should == {'key' => 'value', 'key1' => 'value1'}
145
+ @namespaced.hlen('foo').should == 2
146
+ @namespaced.hkeys('foo').should == ['key', 'key1']
147
+ @namespaced.hmset('bar', 'key', 'value', 'key1', 'value1')
148
+ @namespaced.hmget('bar', 'key', 'key1')
149
+ @namespaced.hmset('bar', 'a_number', 1)
150
+ @namespaced.hmget('bar', 'a_number').should == ['1']
151
+ @namespaced.hincrby('bar', 'a_number', 3)
152
+ @namespaced.hmget('bar', 'a_number').should == ['4']
153
+ @namespaced.hgetall('bar').should == {'key' => 'value', 'key1' => 'value1', 'a_number' => '4'}
154
+
155
+ @namespaced.hsetnx('foonx','nx',10).should be_true
156
+ @namespaced.hsetnx('foonx','nx',12).should be_false
157
+ @namespaced.hget('foonx','nx').should == "10"
158
+ @namespaced.hkeys('foonx').should == %w{ nx }
159
+ @namespaced.hvals('foonx').should == %w{ 10 }
160
+ @namespaced.mapped_hmset('baz', {'key' => 'value', 'key1' => 'value1', 'a_number' => 4})
161
+ @namespaced.mapped_hmget('baz', 'key', 'key1', 'a_number').should == {'key' => 'value', 'key1' => 'value1', 'a_number' => '4'}
162
+ @namespaced.hgetall('baz').should == {'key' => 'value', 'key1' => 'value1', 'a_number' => '4'}
163
+ end
164
+
165
+ it "should properly intersect three sets" do
166
+ @namespaced.sadd('foo', 1)
167
+ @namespaced.sadd('foo', 2)
168
+ @namespaced.sadd('foo', 3)
169
+ @namespaced.sadd('bar', 2)
170
+ @namespaced.sadd('bar', 3)
171
+ @namespaced.sadd('bar', 4)
172
+ @namespaced.sadd('baz', 3)
173
+ @namespaced.sinter('foo', 'bar', 'baz').should == %w( 3 )
174
+ end
175
+
176
+ it "should properly union two sets" do
177
+ @namespaced.sadd('foo', 1)
178
+ @namespaced.sadd('foo', 2)
179
+ @namespaced.sadd('bar', 2)
180
+ @namespaced.sadd('bar', 3)
181
+ @namespaced.sadd('bar', 4)
182
+ @namespaced.sunion('foo', 'bar').sort.should == %w( 1 2 3 4 )
183
+ end
184
+
185
+ it "should properly union two sorted sets with options" do
186
+ @namespaced.zadd('sort1', 1, 1)
187
+ @namespaced.zadd('sort1', 2, 2)
188
+ @namespaced.zadd('sort2', 2, 2)
189
+ @namespaced.zadd('sort2', 3, 3)
190
+ @namespaced.zadd('sort2', 4, 4)
191
+ @namespaced.zunionstore('union', ['sort1', 'sort2'], :weights => [2, 1])
192
+ @namespaced.zrevrange('union', 0, -1).should == %w( 2 4 3 1 )
193
+ end
194
+
195
+ it "should properly union two sorted sets without options" do
196
+ @namespaced.zadd('sort1', 1, 1)
197
+ @namespaced.zadd('sort1', 2, 2)
198
+ @namespaced.zadd('sort2', 2, 2)
199
+ @namespaced.zadd('sort2', 3, 3)
200
+ @namespaced.zadd('sort2', 4, 4)
201
+ @namespaced.zunionstore('union', ['sort1', 'sort2'])
202
+ @namespaced.zrevrange('union', 0, -1).should == %w( 4 2 3 1 )
203
+ end
204
+
205
+ it "should add namespace to sort" do
206
+ @namespaced.sadd('foo', 1)
207
+ @namespaced.sadd('foo', 2)
208
+ @namespaced.set('weight_1', 2)
209
+ @namespaced.set('weight_2', 1)
210
+ @namespaced.set('value_1', 'a')
211
+ @namespaced.set('value_2', 'b')
212
+
213
+ @namespaced.sort('foo').should == %w( 1 2 )
214
+ @namespaced.sort('foo', :limit => [0, 1]).should == %w( 1 )
215
+ @namespaced.sort('foo', :order => 'desc').should == %w( 2 1 )
216
+ @namespaced.sort('foo', :by => 'weight_*').should == %w( 2 1 )
217
+ @namespaced.sort('foo', :get => 'value_*').should == %w( a b )
218
+
219
+ @namespaced.sort('foo', :store => 'result')
220
+ @namespaced.lrange('result', 0, -1).should == %w( 1 2 )
221
+ end
222
+
223
+ it "should yield the correct list of keys" do
224
+ @namespaced["foo"] = 1
225
+ @namespaced["bar"] = 2
226
+ @namespaced["baz"] = 3
227
+ @namespaced.keys("*").sort.should == %w( bar baz foo )
228
+ @namespaced.keys.sort.should == %w( bar baz foo )
229
+ end
230
+
231
+ it "should add namepsace to multi blocks" do
232
+ @namespaced.mapped_hmset "a_hash", {"foo" => "bar"}
233
+ @namespaced.multi do |r|
234
+ r.del "a_hash"
235
+ r.mapped_hmset "a_hash", {"yin" => "yang"}
236
+ end
237
+ @namespaced.hgetall("a_hash").should == {"yin" => "yang"}
238
+ end
239
+
240
+ it "should add namespace to pipelined blocks" do
241
+ @namespaced.mapped_hmset "a_hash", {"foo" => "bar"}
242
+ @namespaced.pipelined do |r|
243
+ r.del "a_hash"
244
+ r.mapped_hmset "a_hash", {"yin" => "yang"}
245
+ end
246
+ @namespaced.hgetall("a_hash").should == {"yin" => "yang"}
247
+ end
248
+
249
+ it "should returned response array from pipelined block" do
250
+ @namespaced.mset "foo", "bar", "yin", "yang"
251
+ result = @namespaced.pipelined do |r|
252
+ r["foo"]
253
+ r["yin"]
254
+ end
255
+ result.should == ["bar", "yang"]
256
+ end
257
+
258
+ it "can change its namespace" do
259
+ @namespaced['foo'].should == nil
260
+ @namespaced['foo'] = 'chris'
261
+ @namespaced['foo'].should == 'chris'
262
+
263
+ @namespaced.namespace.should == :ns
264
+ @namespaced.namespace = :spec
265
+ @namespaced.namespace.should == :spec
266
+
267
+ @namespaced['foo'].should == nil
268
+ @namespaced['foo'] = 'chris'
269
+ @namespaced['foo'].should == 'chris'
270
+ end
271
+
272
+ it "should respond to :namespace=" do
273
+ @namespaced.respond_to?(:namespace=).should == true
274
+ end
275
+
276
+ if @redis_version >= Gem::Version.new("2.6.0")
277
+ describe "redis 2.6 commands" do
278
+ it "should namespace bitcount" do
279
+ pending "awaiting implementaton of command in redis gem"
280
+ end
281
+
282
+ it "should namespace bitop" do
283
+ pending "awaiting implementaton of command in redis gem"
284
+ end
285
+
286
+ it "should namespace dump" do
287
+ pending "awaiting implementaton of command in redis gem"
288
+ end
289
+
290
+ it "should namespace hincrbyfloat" do
291
+ @namespaced.hset('mykey', 'field', 10.50)
292
+ @namespaced.hincrbyfloat('mykey', 'field', 0.1).should == 10.6
293
+ end
294
+
295
+ it "should namespace incrbyfloat" do
296
+ @namespaced.set('mykey', 10.50)
297
+ @namespaced.incrbyfloat('mykey', 0.1).should == 10.6
298
+ end
299
+
300
+ it "should namespace object" do
301
+ @namespaced.set('foo', 1000)
302
+ @namespaced.object('encoding', 'foo').should == 'int'
303
+ end
304
+
305
+ it "should namespace persist" do
306
+ @namespaced.set('mykey', 'Hello')
307
+ @namespaced.expire('mykey', 60)
308
+ @namespaced.persist('mykey').should == true
309
+ @namespaced.ttl('mykey').should == -1
310
+ end
311
+
312
+ it "should namespace pexpire" do
313
+ @namespaced.set('mykey', 'Hello')
314
+ @namespaced.pexpire('mykey', 60000).should == true
315
+ end
316
+
317
+ it "should namespace pexpireat" do
318
+ @namespaced.set('mykey', 'Hello')
319
+ @namespaced.pexpire('mykey', 1555555555005).should == true
320
+ end
321
+
322
+ it "should namespace psetex" do
323
+ @namespaced.psetex('mykey', 10000, 'Hello').should == 'OK'
324
+ @namespaced.get('mykey').should == 'Hello'
325
+ end
326
+
327
+ it "should namespace pttl" do
328
+ @namespaced.set('mykey', 'Hello')
329
+ @namespaced.expire('mykey', 1)
330
+ @namespaced.pttl('mykey').should == 1000
331
+ end
332
+
333
+ it "should namespace restore" do
334
+ pending "awaiting implementaton of command in redis gem"
335
+ end
336
+ end
337
+ end
338
+
339
+ # Only test aliasing functionality for Redis clients that support aliases.
340
+ unless Redis::Namespace::ALIASES.empty?
341
+ it "should support command aliases (delete)" do
342
+ @namespaced.delete('foo')
343
+ @redis.should_not have_key('ns:foo')
344
+ end
345
+
346
+ it "should support command aliases (set_add)" do
347
+ @namespaced.set_add('bar', 'quux')
348
+ @namespaced.smembers('bar').should include('quux')
349
+ end
350
+
351
+ it "should support command aliases (push_head)" do
352
+ @namespaced.push_head('bar', 'quux')
353
+ @redis.llen('ns:bar').should == 1
354
+ end
355
+
356
+ it "should support command aliases (zset_add)" do
357
+ @namespaced.zset_add('bar', 1, 'quux')
358
+ @redis.zcard('ns:bar').should == 1
359
+ end
360
+ end
361
+ end
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ Bundler.setup(:default, :test)
4
+ Bundler.require(:default, :test)
5
+
6
+ require 'rspec'
7
+ require 'redis'
8
+ require 'logger'
9
+
10
+ $TESTING=true
11
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
12
+ require 'redis/namespace'
13
+
14
+ RSpec::Matchers.define :have_key do |expected|
15
+ match do |redis|
16
+ redis.exists(expected)
17
+ end
18
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: redis-namespace-with-multi
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Chris Wanstrath
9
+ - Terence Lee
10
+ - Carl Zulauf
11
+ autorequire:
12
+ bindir: bin
13
+ cert_chain: []
14
+ date: 2012-08-24 00:00:00.000000000Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: redis
18
+ requirement: &70195823091700 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: 3.0.0
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: *70195823091700
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: &70195823091300 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ! '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: *70195823091300
38
+ - !ruby/object:Gem::Dependency
39
+ name: rspec
40
+ requirement: &70195823090840 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ type: :development
47
+ prerelease: false
48
+ version_requirements: *70195823090840
49
+ description: ! 'Adds a Redis::Namespace class which can be used to namespace calls
50
+
51
+ to Redis. This is useful when using a single instance of Redis with
52
+
53
+ multiple, different applications.
54
+
55
+
56
+ This fork adds support for the much loved multi and pipelined commands.
57
+
58
+ '
59
+ email: carl@linkleaf.com
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - README.md
65
+ - Rakefile
66
+ - LICENSE
67
+ - lib/redis/namespace.rb
68
+ - lib/redis-namespace.rb
69
+ - spec/redis_spec.rb
70
+ - spec/spec_helper.rb
71
+ homepage: http://github.com/carlzulauf/redis-namespace
72
+ licenses: []
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ! '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubyforge_project:
91
+ rubygems_version: 1.8.15
92
+ signing_key:
93
+ specification_version: 3
94
+ summary: Namespaces Redis commands. Fork with working pipelined/multi.
95
+ test_files: []