redis-namespace 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of redis-namespace might be problematic. Click here for more details.
- data/Rakefile +4 -4
- data/lib/redis/namespace.rb +158 -110
- data/spec/redis_spec.rb +66 -1
- metadata +2 -2
data/Rakefile
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
task :default => :spec
|
2
|
-
task :test
|
2
|
+
task :test => :spec
|
3
3
|
|
4
4
|
desc "Run specs"
|
5
5
|
task :spec do
|
@@ -15,10 +15,10 @@ begin
|
|
15
15
|
gemspec.email = "chris@ozmm.org"
|
16
16
|
gemspec.homepage = "http://github.com/defunkt/redis-namespace"
|
17
17
|
gemspec.authors = ["Chris Wanstrath"]
|
18
|
-
gemspec.version = '0.
|
18
|
+
gemspec.version = '0.3.0'
|
19
19
|
gemspec.add_dependency 'redis'
|
20
20
|
end
|
21
21
|
rescue LoadError
|
22
|
-
|
23
|
-
|
22
|
+
warn "Jeweler not available. Install it with:"
|
23
|
+
warn "gem install jeweler"
|
24
24
|
end
|
data/lib/redis/namespace.rb
CHANGED
@@ -2,86 +2,120 @@ require 'redis'
|
|
2
2
|
|
3
3
|
class Redis
|
4
4
|
class Namespace
|
5
|
-
#
|
6
|
-
#
|
5
|
+
# The following table defines how input parameters and result
|
6
|
+
# values should be modified for the namespace.
|
7
7
|
#
|
8
|
-
#
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
"
|
43
|
-
"
|
44
|
-
"
|
45
|
-
"
|
46
|
-
"
|
47
|
-
"
|
48
|
-
"
|
49
|
-
"
|
50
|
-
"
|
51
|
-
"
|
52
|
-
"
|
53
|
-
"
|
54
|
-
"
|
55
|
-
"
|
56
|
-
"
|
57
|
-
"
|
58
|
-
"
|
59
|
-
"
|
60
|
-
"
|
61
|
-
"
|
62
|
-
"
|
63
|
-
"
|
64
|
-
"
|
65
|
-
"
|
66
|
-
"
|
67
|
-
"
|
68
|
-
"
|
69
|
-
"
|
70
|
-
"
|
71
|
-
"
|
72
|
-
"
|
73
|
-
"
|
74
|
-
"
|
75
|
-
"
|
76
|
-
"
|
77
|
-
"
|
78
|
-
"
|
79
|
-
"
|
80
|
-
"
|
81
|
-
"
|
82
|
-
"[]
|
83
|
-
"[]
|
84
|
-
|
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
|
+
# :alternate
|
29
|
+
# Add the namespace to every other argument, e.g.
|
30
|
+
# MSET key1 value1 key2 value2 =>
|
31
|
+
# MSET namespace:key1 value1 namespace:key2 value2
|
32
|
+
#
|
33
|
+
# The second element in the value array describes how to modify
|
34
|
+
# the return value of the Redis call. It can be one of:
|
35
|
+
#
|
36
|
+
# nil
|
37
|
+
# Do nothing.
|
38
|
+
# :all
|
39
|
+
# Add the namespace to all elements returned, e.g.
|
40
|
+
# key1 key2 => namespace:key1 namespace:key2
|
41
|
+
COMMANDS = {
|
42
|
+
"auth" => [],
|
43
|
+
"bgrewriteaof" => [],
|
44
|
+
"bgsave" => [],
|
45
|
+
"blpop" => [ :exclude_last ],
|
46
|
+
"brpop" => [ :exclude_last ],
|
47
|
+
"dbsize" => [],
|
48
|
+
"decr" => [ :first ],
|
49
|
+
"decrby" => [ :first ],
|
50
|
+
"del" => [ :all ],
|
51
|
+
"exists" => [ :first ],
|
52
|
+
"expire" => [ :first ],
|
53
|
+
"flushall" => [],
|
54
|
+
"flushdb" => [],
|
55
|
+
"get" => [ :first ],
|
56
|
+
"getset" => [ :first ],
|
57
|
+
"incr" => [ :first ],
|
58
|
+
"incrby" => [ :first ],
|
59
|
+
"info" => [],
|
60
|
+
"keys" => [ :first, :all ],
|
61
|
+
"lastsave" => [],
|
62
|
+
"lindex" => [ :first ],
|
63
|
+
"llen" => [ :first ],
|
64
|
+
"lpop" => [ :first ],
|
65
|
+
"lpush" => [ :first ],
|
66
|
+
"lrange" => [ :first ],
|
67
|
+
"lrem" => [ :first ],
|
68
|
+
"lset" => [ :first ],
|
69
|
+
"ltrim" => [ :first ],
|
70
|
+
"mapped_mget" => [ :all, :all ],
|
71
|
+
"mget" => [ :all ],
|
72
|
+
"monitor" => [ :monitor ],
|
73
|
+
"move" => [ :first ],
|
74
|
+
"mset" => [ :alternate ],
|
75
|
+
"msetnx" => [ :alternate ],
|
76
|
+
"quit" => [],
|
77
|
+
"randomkey" => [],
|
78
|
+
"rename" => [ :all ],
|
79
|
+
"renamenx" => [ :all ],
|
80
|
+
"rpop" => [ :first ],
|
81
|
+
"rpoplpush" => [ :all ],
|
82
|
+
"rpush" => [ :first ],
|
83
|
+
"sadd" => [ :first ],
|
84
|
+
"save" => [],
|
85
|
+
"scard" => [ :first ],
|
86
|
+
"sdiff" => [ :all ],
|
87
|
+
"sdiffstore" => [ :all ],
|
88
|
+
"select" => [],
|
89
|
+
"set" => [ :first ],
|
90
|
+
"setnx" => [ :first ],
|
91
|
+
"shutdown" => [],
|
92
|
+
"sinter" => [ :all ],
|
93
|
+
"sinterstore" => [ :all ],
|
94
|
+
"sismember" => [ :first ],
|
95
|
+
"slaveof" => [],
|
96
|
+
"smembers" => [ :first ],
|
97
|
+
"smove" => [ :exclude_last ],
|
98
|
+
"sort" => [ :sort ],
|
99
|
+
"spop" => [ :first ],
|
100
|
+
"srandmember" => [ :first ],
|
101
|
+
"srem" => [ :first ],
|
102
|
+
"sunion" => [ :all ],
|
103
|
+
"sunionstore" => [ :all ],
|
104
|
+
"ttl" => [ :first ],
|
105
|
+
"type" => [ :first ],
|
106
|
+
"zadd" => [ :first ],
|
107
|
+
"zcard" => [ :first ],
|
108
|
+
"zincrby" => [ :first ],
|
109
|
+
"zrange" => [ :first ],
|
110
|
+
"zrangebyscore" => [ :first ],
|
111
|
+
"zrem" => [ :first ],
|
112
|
+
"zremrangebyscore" => [ :first ],
|
113
|
+
"zrevrange" => [ :first ],
|
114
|
+
"zscore" => [ :first ],
|
115
|
+
"[]" => [ :first ],
|
116
|
+
"[]=" => [ :first ]
|
117
|
+
}
|
118
|
+
|
85
119
|
|
86
120
|
attr_accessor :namespace
|
87
121
|
|
@@ -96,48 +130,62 @@ class Redis
|
|
96
130
|
method_missing(:type, key)
|
97
131
|
end
|
98
132
|
|
99
|
-
def
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
133
|
+
def method_missing(command, *args, &block)
|
134
|
+
(before, after) = COMMANDS[command.to_s] ||
|
135
|
+
COMMANDS[Redis::ALIASES[command.to_s]]
|
136
|
+
|
137
|
+
# Add the namespace to any parameters that are keys.
|
138
|
+
case before
|
139
|
+
when :first
|
140
|
+
args[0] = add_namespace(args[0]) if args[0]
|
141
|
+
when :all
|
142
|
+
args = add_namespace(args)
|
143
|
+
when :exclude_first
|
144
|
+
first = args.shift
|
145
|
+
args = add_namespace(args)
|
146
|
+
args.unshift(first) if first
|
147
|
+
when :exclude_last
|
148
|
+
last = args.pop
|
149
|
+
args = add_namespace(args)
|
150
|
+
args.push(last) if last
|
151
|
+
when :alternate
|
152
|
+
args = [ add_namespace(Hash[*args]) ]
|
104
153
|
end
|
105
|
-
result
|
106
|
-
end
|
107
154
|
|
108
|
-
|
109
|
-
|
110
|
-
call_command([:mget] + keys)
|
111
|
-
end
|
155
|
+
# Dispatch the command to Redis and store the result.
|
156
|
+
result = @redis.send(command, *args, &block)
|
112
157
|
|
113
|
-
|
114
|
-
|
115
|
-
end
|
158
|
+
# Remove the namespace from results that are keys.
|
159
|
+
result = rem_namespace(result) if after == :all
|
116
160
|
|
117
|
-
|
118
|
-
call_mset(:msetnx, keys)
|
161
|
+
result
|
119
162
|
end
|
120
163
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
end
|
164
|
+
private
|
165
|
+
def add_namespace(key)
|
166
|
+
return key unless key && @namespace
|
125
167
|
|
126
|
-
|
168
|
+
case key
|
169
|
+
when Array
|
170
|
+
key.map {|k| add_namespace k}
|
171
|
+
when Hash
|
172
|
+
Hash[*key.map {|k, v| [ add_namespace(k), v ]}.flatten]
|
173
|
+
else
|
174
|
+
"#{@namespace}:#{key}"
|
175
|
+
end
|
127
176
|
end
|
128
177
|
|
178
|
+
def rem_namespace(key)
|
179
|
+
return key unless key && @namespace
|
129
180
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
keys = namespaced_keys
|
181
|
+
case key
|
182
|
+
when Array
|
183
|
+
key.map {|k| rem_namespace k}
|
184
|
+
when Hash
|
185
|
+
Hash[*key.map {|k, v| [ rem_namespace(k), v ]}.flatten]
|
186
|
+
else
|
187
|
+
key.to_s.gsub /^#{@namespace}:/, ""
|
138
188
|
end
|
139
|
-
|
140
|
-
call_command([command] + [keys])
|
141
189
|
end
|
142
190
|
end
|
143
191
|
end
|
data/spec/redis_spec.rb
CHANGED
@@ -6,10 +6,10 @@ describe "redis" do
|
|
6
6
|
before(:all) do
|
7
7
|
# use database 15 for testing so we dont accidentally step on you real data
|
8
8
|
@redis = Redis.new :db => 15
|
9
|
-
@namespaced = Redis::Namespace.new(:ns, :redis => @redis)
|
10
9
|
end
|
11
10
|
|
12
11
|
before(:each) do
|
12
|
+
@namespaced = Redis::Namespace.new(:ns, :redis => @redis)
|
13
13
|
@namespaced.flushdb
|
14
14
|
@redis['foo'] = 'bar'
|
15
15
|
end
|
@@ -35,6 +35,17 @@ describe "redis" do
|
|
35
35
|
@namespaced.type('counter').should == 'string'
|
36
36
|
end
|
37
37
|
|
38
|
+
it "should be able to use a namespace with del" do
|
39
|
+
@namespaced['foo'] = 1000
|
40
|
+
@namespaced['bar'] = 2000
|
41
|
+
@namespaced['baz'] = 3000
|
42
|
+
@namespaced.del 'foo'
|
43
|
+
@namespaced['foo'].should == nil
|
44
|
+
@namespaced.del 'bar', 'baz'
|
45
|
+
@namespaced['bar'].should == nil
|
46
|
+
@namespaced['baz'].should == nil
|
47
|
+
end
|
48
|
+
|
38
49
|
it "should be able to use a namespace with mget" do
|
39
50
|
@namespaced['foo'] = 1000
|
40
51
|
@namespaced['bar'] = 2000
|
@@ -54,6 +65,33 @@ describe "redis" do
|
|
54
65
|
@namespaced.mapped_mget('foo', 'baz', 'bar').should == { 'foo' => '1000', 'bar' => '2000'}
|
55
66
|
end
|
56
67
|
|
68
|
+
it "should properly intersect three sets" do
|
69
|
+
@namespaced.sadd('foo', 1)
|
70
|
+
@namespaced.sadd('foo', 2)
|
71
|
+
@namespaced.sadd('foo', 3)
|
72
|
+
@namespaced.sadd('bar', 2)
|
73
|
+
@namespaced.sadd('bar', 3)
|
74
|
+
@namespaced.sadd('bar', 4)
|
75
|
+
@namespaced.sadd('baz', 3)
|
76
|
+
@namespaced.sinter('foo', 'bar', 'baz').should == %w( 3 )
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should properly union two sets" do
|
80
|
+
@namespaced.sadd('foo', 1)
|
81
|
+
@namespaced.sadd('foo', 2)
|
82
|
+
@namespaced.sadd('bar', 2)
|
83
|
+
@namespaced.sadd('bar', 3)
|
84
|
+
@namespaced.sadd('bar', 4)
|
85
|
+
@namespaced.sunion('foo', 'bar').sort.should == %w( 1 2 3 4 )
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should yield the correct list of keys" do
|
89
|
+
@namespaced["foo"] = 1
|
90
|
+
@namespaced["bar"] = 2
|
91
|
+
@namespaced["baz"] = 3
|
92
|
+
@namespaced.keys("*").sort.should == %w( bar baz foo )
|
93
|
+
end
|
94
|
+
|
57
95
|
it "can change its namespace" do
|
58
96
|
@namespaced['foo'].should == nil
|
59
97
|
@namespaced['foo'] = 'chris'
|
@@ -67,4 +105,31 @@ describe "redis" do
|
|
67
105
|
@namespaced['foo'] = 'chris'
|
68
106
|
@namespaced['foo'].should == 'chris'
|
69
107
|
end
|
108
|
+
|
109
|
+
it "should support command aliases (delete)" do
|
110
|
+
@namespaced.delete('foo')
|
111
|
+
@redis.should_not have_key('ns:foo')
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should support command aliases (set_add)" do
|
115
|
+
@namespaced.set_add('bar', 'quux')
|
116
|
+
@namespaced.smembers('bar').should include('quux')
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should support command aliases (push_head)" do
|
120
|
+
@namespaced.push_head('bar', 'quux')
|
121
|
+
@redis.llen('ns:bar').should == 1
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should support command aliases (zset_add)" do
|
125
|
+
@namespaced.zset_add('bar', 1, 'quux')
|
126
|
+
@redis.zcard('ns:bar').should == 1
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
Spec::Matchers.define :have_key do |expected|
|
131
|
+
match do |redis|
|
132
|
+
redis.exists(expected)
|
133
|
+
end
|
134
|
+
end
|
70
135
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis-namespace
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Wanstrath
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-
|
12
|
+
date: 2010-03-12 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|