redis 3.0.0.rc2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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