redis-namespace 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of redis-namespace might be problematic. Click here for more details.

Files changed (4) hide show
  1. data/Rakefile +4 -4
  2. data/lib/redis/namespace.rb +158 -110
  3. data/spec/redis_spec.rb +66 -1
  4. metadata +2 -2
data/Rakefile CHANGED
@@ -1,5 +1,5 @@
1
1
  task :default => :spec
2
- task :test => :spec
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.2.1'
18
+ gemspec.version = '0.3.0'
19
19
  gemspec.add_dependency 'redis'
20
20
  end
21
21
  rescue LoadError
22
- puts "Jeweler not available. Install it with:"
23
- puts "gem install jeweler"
22
+ warn "Jeweler not available. Install it with:"
23
+ warn "gem install jeweler"
24
24
  end
@@ -2,86 +2,120 @@ require 'redis'
2
2
 
3
3
  class Redis
4
4
  class Namespace
5
- # Generated from http://code.google.com/p/redis/wiki/CommandReference
6
- # using the following jQuery:
5
+ # The following table defines how input parameters and result
6
+ # values should be modified for the namespace.
7
7
  #
8
- # $('.vt li a').map(function(i,e){return $(e).text().toLowerCase()}).sort().toArray()
9
- COMMANDS = [
10
- "auth",
11
- "bgrewriteaof",
12
- "bgsave",
13
- "blpop",
14
- "brpop",
15
- "dbsize",
16
- "decr",
17
- "decrby",
18
- "del",
19
- "exists",
20
- "expire",
21
- "flushall",
22
- "flushdb",
23
- "get",
24
- "getset",
25
- "incr",
26
- "incrby",
27
- "info",
28
- "keys",
29
- "lastsave",
30
- "lindex",
31
- "llen",
32
- "lpop",
33
- "lpush",
34
- "lrange",
35
- "lrem",
36
- "lset",
37
- "ltrim",
38
- "mget",
39
- "monitor",
40
- "move",
41
- "mset",
42
- "msetnx",
43
- "quit",
44
- "randomkey",
45
- "rename",
46
- "renamenx",
47
- "rpop",
48
- "rpoplpush",
49
- "rpush",
50
- "sadd",
51
- "save",
52
- "scard",
53
- "sdiff",
54
- "sdiffstore",
55
- "select",
56
- "set",
57
- "setnx",
58
- "shutdown",
59
- "sinter",
60
- "sinterstore",
61
- "sismember",
62
- "slaveof",
63
- "smembers",
64
- "smove",
65
- "sort",
66
- "spop",
67
- "srandmember",
68
- "srem",
69
- "sunion",
70
- "sunionstore",
71
- "ttl",
72
- "type",
73
- "zadd",
74
- "zcard",
75
- "zincrby",
76
- "zrange",
77
- "zrangebyscore",
78
- "zrem",
79
- "zremrangebyscore",
80
- "zrevrange",
81
- "zscore",
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 mapped_mget(*keys)
100
- result = {}
101
- mget(*keys).each do |value|
102
- key = keys.shift
103
- result.merge!(key => value) unless value.nil?
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
- def mget(*keys)
109
- keys = keys.map { |key| "#{@namespace}:#{key}"} if @namespace
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
- def mset(keys)
114
- call_mset(:mset, keys)
115
- end
158
+ # Remove the namespace from results that are keys.
159
+ result = rem_namespace(result) if after == :all
116
160
 
117
- def msetnx(keys)
118
- call_mset(:msetnx, keys)
161
+ result
119
162
  end
120
163
 
121
- def method_missing(command, *args, &block)
122
- if COMMANDS.include?(command.to_s) && args[0]
123
- args[0] = "#{@namespace}:#{args[0]}"
124
- end
164
+ private
165
+ def add_namespace(key)
166
+ return key unless key && @namespace
125
167
 
126
- @redis.send(command, *args, &block)
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
- private
131
-
132
-
133
- def call_mset(command, keys)
134
- if @namespace
135
- namespaced_keys = {}
136
- keys.each { |key, value| namespaced_keys["#{@namespace}:#{key}"] = value }
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.2.1
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-02-16 00:00:00 -08:00
12
+ date: 2010-03-12 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency