redis 3.0.0.rc2 → 3.0.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.
data/.order ADDED
@@ -0,0 +1,169 @@
1
+ {
2
+ "connection": [
3
+ "auth",
4
+ "select",
5
+ "ping",
6
+ "echo",
7
+ "quit"
8
+ ],
9
+ "server": [
10
+ "bgrewriteaof",
11
+ "bgsave",
12
+ "config",
13
+ "dbsize",
14
+ "debug",
15
+ "flushall",
16
+ "flushdb",
17
+ "info",
18
+ "lastsave",
19
+ "monitor",
20
+ "save",
21
+ "shutdown",
22
+ "slaveof",
23
+ "slowlog",
24
+ "sync",
25
+ "time"
26
+ ],
27
+ "generic": [
28
+ "persist",
29
+ "expire",
30
+ "expireat",
31
+ "ttl",
32
+ "pexpire",
33
+ "pexpireat",
34
+ "pttl",
35
+ "dump",
36
+ "restore",
37
+ "del",
38
+ "exists",
39
+ "keys",
40
+ "migrate",
41
+ "move",
42
+ "object",
43
+ "randomkey",
44
+ "rename",
45
+ "renamenx",
46
+ "sort",
47
+ "type"
48
+ ],
49
+ "string": [
50
+ "decr",
51
+ "decrby",
52
+ "incr",
53
+ "incrby",
54
+ "incrbyfloat",
55
+ "set",
56
+ "setex",
57
+ "psetex",
58
+ "setnx",
59
+ "mset",
60
+ "mapped_mset",
61
+ "msetnx",
62
+ "mapped_msetnx",
63
+ "get",
64
+ "mget",
65
+ "mapped_mget",
66
+ "setrange",
67
+ "getrange",
68
+ "setbit",
69
+ "getbit",
70
+ "append",
71
+ "bitcount",
72
+ "getset",
73
+ "strlen"
74
+ ],
75
+ "list": [
76
+ "llen",
77
+ "lpush",
78
+ "lpushx",
79
+ "rpush",
80
+ "rpushx",
81
+ "lpop",
82
+ "rpop",
83
+ "rpoplpush",
84
+ "_bpop",
85
+ "blpop",
86
+ "brpop",
87
+ "brpoplpush",
88
+ "lindex",
89
+ "linsert",
90
+ "lrange",
91
+ "lrem",
92
+ "lset",
93
+ "ltrim",
94
+ "bitop"
95
+ ],
96
+ "set": [
97
+ "scard",
98
+ "sadd",
99
+ "srem",
100
+ "spop",
101
+ "srandmember",
102
+ "smove",
103
+ "sismember",
104
+ "smembers",
105
+ "sdiff",
106
+ "sdiffstore",
107
+ "sinter",
108
+ "sinterstore",
109
+ "sunion",
110
+ "sunionstore"
111
+ ],
112
+ "sorted_set": [
113
+ "zcard",
114
+ "zadd",
115
+ "zincrby",
116
+ "zrem",
117
+ "zscore",
118
+ "zrange",
119
+ "zrevrange",
120
+ "zrank",
121
+ "zrevrank",
122
+ "zremrangebyrank",
123
+ "zrangebyscore",
124
+ "zrevrangebyscore",
125
+ "zremrangebyscore",
126
+ "zcount",
127
+ "zinterstore",
128
+ "zunionstore"
129
+ ],
130
+ "hash": [
131
+ "hlen",
132
+ "hset",
133
+ "hsetnx",
134
+ "hmset",
135
+ "mapped_hmset",
136
+ "hget",
137
+ "hmget",
138
+ "mapped_hmget",
139
+ "hdel",
140
+ "hexists",
141
+ "hincrby",
142
+ "hincrbyfloat",
143
+ "hkeys",
144
+ "hvals",
145
+ "hgetall"
146
+ ],
147
+ "pubsub": [
148
+ "publish",
149
+ "subscribed?",
150
+ "subscribe",
151
+ "unsubscribe",
152
+ "psubscribe",
153
+ "punsubscribe"
154
+ ],
155
+ "transactions": [
156
+ "watch",
157
+ "unwatch",
158
+ "pipelined",
159
+ "multi",
160
+ "exec",
161
+ "discard"
162
+ ],
163
+ "scripting": [
164
+ "script",
165
+ "_eval",
166
+ "eval",
167
+ "evalsha"
168
+ ]
169
+ }
@@ -1,26 +1,89 @@
1
- # 3.0 (unreleased)
1
+ # 3.0.0
2
+
3
+ ### Upgrading from 2.x to 3.0
4
+
5
+ The following items are the most important changes to review when
6
+ upgrading from redis-rb 2.x. A full list of changes can be found below.
7
+
8
+ * The methods for the following commands have changed the arguments they
9
+ take, their return value, or both.
10
+
11
+ * `BLPOP`, `BRPOP`, `BRPOPLPUSH`
12
+ * `SORT`
13
+ * `MSETNX`
14
+ * `ZRANGE`, `ZREVRANGE`, `ZRANGEBYSCORE`, `ZREVRANGEBYSCORE`
15
+ * `ZINCRBY`, `ZSCORE`
16
+
17
+ * The return value from `#pipelined` and `#multi` no longer contains
18
+ unprocessed replies, but the same replies that would be returned if
19
+ the command had not been executed in these blocks.
20
+
21
+ * The client raises custom errors on connection errors, instead of
22
+ `RuntimeError` and errors in the `Errno` family.
23
+
24
+ ### Changes
25
+
26
+ * Added support for scripting commands (Redis 2.6).
27
+
28
+ Scripts can be executed using `#eval` and `#evalsha`. Both can
29
+ commands can either take two arrays to specify `KEYS` and `ARGV`, or
30
+ take a hash containing `:keys` and `:argv` to specify `KEYS` and
31
+ `ARGV`.
32
+
33
+ ```ruby
34
+ redis.eval("return ARGV[1] * ARGV[2]", :argv => [2, 3])
35
+ # => 6
36
+ ```
37
+
38
+ Subcommands of the `SCRIPT` command can be executed via the
39
+ `#script` method.
40
+
41
+ For example:
42
+
43
+ ```ruby
44
+ redis.script(:load, "return ARGV[1] * ARGV[2]")
45
+ # => "58db5d365a1922f32e7aa717722141ea9c2b0cf3"
46
+ redis.script(:exists, "58db5d365a1922f32e7aa717722141ea9c2b0cf3")
47
+ # => true
48
+ redis.script(:flush)
49
+ # => "OK"
50
+ ```
2
51
 
3
52
  * The repository now lives at [https://github.com/redis/redis-rb](https://github.com/redis/redis-rb).
4
53
  Thanks, Ezra!
5
54
 
6
- * Added support for `PEXPIRE`, `PTTL`, `PEXPIREAT`, `PSETEX`,
55
+ * Added support for `PEXPIRE`, `PEXPIREAT`, `PTTL`, `PSETEX`,
7
56
  `INCRYBYFLOAT`, `HINCRYBYFLOAT` and `TIME` (Redis 2.6).
8
57
 
9
58
  * `Redis.current` is now thread unsafe, because the client itself is thread safe.
10
59
 
11
60
  In the future you'll be able to do something like:
12
61
 
13
- Redis.current = Redis::Pool.connect
62
+ ```ruby
63
+ Redis.current = Redis::Pool.connect
64
+ ```
14
65
 
15
66
  This makes `Redis.current` actually usable in multi-threaded environments,
16
67
  while not affecting those running a single thread.
17
68
 
18
- * Change API for `BLPOP`, `BRPOP` and `BRPOPLPUSH`. Both `BLPOP` and
19
- `BRPOP` now take a single argument equal to a string key, or an array
20
- with string keys, followed by an optional hash with a `:timeout` key.
21
- `BRPOPLPUSH` also takes an optional hash with a `:timeout` key as last
22
- argument for consistency. By default, these commands use a timeout of
23
- `0` to not time out.
69
+ * Change API for `BLPOP`, `BRPOP` and `BRPOPLPUSH`.
70
+
71
+ Both `BLPOP` and `BRPOP` now take a single argument equal to a
72
+ string key, or an array with string keys, followed by an optional
73
+ hash with a `:timeout` key. When not specified, the timeout defaults
74
+ to `0` to not time out.
75
+
76
+ ```ruby
77
+ redis.blpop(["list1", "list2"], :timeout => 1.0)
78
+ ```
79
+
80
+ `BRPOPLPUSH` also takes an optional hash with a `:timeout` key as
81
+ last argument for consistency. When not specified, the timeout
82
+ defaults to `0` to not time out.
83
+
84
+ ```ruby
85
+ redis.brpoplpush("some_list", "another_list", :timeout => 1.0)
86
+ ```
24
87
 
25
88
  * When `SORT` is passed multiple key patterns to get via the `:get`
26
89
  option, it now returns an array per result element, holding all `GET`
@@ -32,6 +95,13 @@
32
95
  now return an array containing `[String, Float]` pairs when
33
96
  `:with_scores => true` is passed.
34
97
 
98
+ For example:
99
+
100
+ ```ruby
101
+ redis.zrange("zset", 0, -1, :with_scores => true)
102
+ # => [["foo", 1.0], ["bar", 2.0]]
103
+ ```
104
+
35
105
  * The `ZINCRBY` and `ZSCORE` commands now return a `Float` score instead
36
106
  of a string holding a representation of the score.
37
107
 
data/README.md CHANGED
@@ -12,6 +12,13 @@ A Ruby client that tries to match Redis' API one-to-one, while still
12
12
  providing an idiomatic interface. It features thread-safety, client-side
13
13
  sharding, pipelining, and an obsession for performance.
14
14
 
15
+ ## Upgrading from 2.x to 3.0
16
+
17
+ Please refer to the [CHANGELOG][changelog-3.0.0] for a summary of the
18
+ most important changes, as well as a full list of changes.
19
+
20
+ [changelog-3.0.0]: https://github.com/redis/redis-rb/blob/master/CHANGELOG.md#300
21
+
15
22
  ## Getting started
16
23
 
17
24
  As of version 2.0 this client only targets Redis version 2.0 and higher.
data/Rakefile CHANGED
@@ -148,6 +148,71 @@ namespace :doc do
148
148
  end
149
149
  end
150
150
 
151
+ class Source
152
+
153
+ MATCHER = "(?:\\s{%d}#[^\\n]*\\n)*^\\s{%d}def ([a-z_?]+)(?:\(.*?\))?\\n.*?^\\s{%d}end\\n\\n"
154
+
155
+ def initialize(data, options = {})
156
+ @doc = parse(File.read(data), options)
157
+ end
158
+
159
+ def methods
160
+ @doc.select do |d|
161
+ d.is_a?(Method)
162
+ end.map do |d|
163
+ d.name
164
+ end
165
+ end
166
+
167
+ def move(a, b)
168
+ ao = @doc.find { |m| m.is_a?(Method) && m.name == a }
169
+ bo = @doc.find { |m| m.is_a?(Method) && m.name == b }
170
+ ai = @doc.index(ao)
171
+ bi = @doc.index(bo)
172
+
173
+ @doc.delete_at(ai)
174
+ @doc.insert(bi, ao)
175
+
176
+ nil
177
+ end
178
+
179
+ def to_s
180
+ @doc.join
181
+ end
182
+
183
+ protected
184
+
185
+ def parse(data, options = {})
186
+ re = Regexp.new(MATCHER % ([options[:indent]] * 3), Regexp::MULTILINE)
187
+ tail = data.dup
188
+ doc = []
189
+
190
+ while match = re.match(tail)
191
+ doc << match.pre_match
192
+ doc << Method.new(match)
193
+ tail = match.post_match
194
+ end
195
+
196
+ doc << tail if tail
197
+ doc
198
+ end
199
+
200
+ class Method
201
+
202
+ def initialize(match)
203
+ @match = match
204
+ end
205
+
206
+ def name
207
+ @match[1]
208
+ end
209
+
210
+ def to_s
211
+ @match[0]
212
+ end
213
+ end
214
+ end
215
+
151
216
  namespace :commands do
152
217
  def redis_commands
153
218
  $redis_commands ||= doc.keys.map do |key|
@@ -164,6 +229,108 @@ namespace :commands do
164
229
  end
165
230
  end
166
231
 
232
+ task :order do
233
+ require "json"
234
+
235
+ reference = if File.exist?(".order")
236
+ JSON.parse(File.read(".order"))
237
+ else
238
+ {}
239
+ end
240
+
241
+ buckets = {}
242
+ doc.each do |k, v|
243
+ buckets[v["group"]] ||= []
244
+ buckets[v["group"]] << k.split.first.downcase
245
+ buckets[v["group"]].uniq!
246
+ end
247
+
248
+ result = (reference.keys + (buckets.keys - reference.keys)).map do |g|
249
+ [g, reference[g] + (buckets[g] - reference[g])]
250
+ end
251
+
252
+ File.open(".order", "w") do |f|
253
+ f.write(JSON.pretty_generate(Hash[result]))
254
+ end
255
+ end
256
+
257
+ def reorder(file, options = {})
258
+ require "json"
259
+ require "set"
260
+
261
+ STDERR.puts "reordering #{file}..."
262
+
263
+ reference = if File.exist?(".order")
264
+ JSON.parse(File.read(".order"))
265
+ else
266
+ {}
267
+ end
268
+
269
+ dst = Source.new(file, options)
270
+
271
+ src_methods = reference.map { |k, v| v }.flatten
272
+ dst_methods = dst.methods
273
+
274
+ src_set = Set.new(src_methods)
275
+ dst_set = Set.new(dst_methods)
276
+
277
+ intersection = src_set & dst_set
278
+ intersection.delete("initialize")
279
+
280
+ loop do
281
+ src_methods = reference.map { |k, v| v }.flatten
282
+ dst_methods = dst.methods
283
+
284
+ src_methods = src_methods.select do |m|
285
+ intersection.include?(m)
286
+ end
287
+
288
+ dst_methods = dst_methods.select do |m|
289
+ intersection.include?(m)
290
+ end
291
+
292
+ if src_methods == dst_methods
293
+ break
294
+ end
295
+
296
+ rv = yield(src_methods, dst_methods, dst)
297
+ break if rv == false
298
+ end
299
+
300
+ File.open(file, "w") do |f|
301
+ f.write(dst.to_s)
302
+ end
303
+ end
304
+
305
+ task :reorder do
306
+ blk = lambda do |src_methods, dst_methods, dst|
307
+ src_methods.zip(dst_methods).each do |a, b|
308
+ if a != b
309
+ dst.move(a, b)
310
+ break
311
+ end
312
+ end
313
+ end
314
+
315
+ reorder "lib/redis.rb", :indent => 2, &blk
316
+ reorder "lib/redis/distributed.rb", :indent => 4, &blk
317
+ end
318
+
319
+ def missing(file, options = {})
320
+ src = Source.new(file, options)
321
+
322
+ defined_methods = src.methods.map(&:downcase)
323
+ required_methods = redis_commands.map(&:downcase)
324
+
325
+ STDOUT.puts "missing in #{file}:"
326
+ STDOUT.puts (required_methods - defined_methods).inspect
327
+ end
328
+
329
+ task :missing do
330
+ missing "lib/redis.rb", :indent => 2
331
+ missing "lib/redis/distributed.rb", :indent => 4
332
+ end
333
+
167
334
  def document(file)
168
335
  source = File.read(file)
169
336