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.
@@ -36,13 +36,18 @@ class Redis
36
36
  mon_synchronize { yield(@client) }
37
37
  end
38
38
 
39
- # Run code without the client reconnecting
40
- def without_reconnect(&block)
39
+ # Run code with the client reconnecting
40
+ def with_reconnect(val=true, &blk)
41
41
  synchronize do |client|
42
- client.without_reconnect(&block)
42
+ client.with_reconnect(val, &blk)
43
43
  end
44
44
  end
45
45
 
46
+ # Run code without the client reconnecting
47
+ def without_reconnect(&blk)
48
+ with_reconnect(false, &blk)
49
+ end
50
+
46
51
  # Authenticate to the server.
47
52
  #
48
53
  # @param [String] password must match the password specified in the
@@ -65,31 +70,57 @@ class Redis
65
70
  end
66
71
  end
67
72
 
68
- # Get information and statistics about the server.
73
+ # Ping the server.
69
74
  #
70
- # @param [String, Symbol] cmd e.g. "commandstats"
71
- # @return [Hash<String, String>]
72
- def info(cmd = nil)
75
+ # @return [String] `PONG`
76
+ def ping
73
77
  synchronize do |client|
74
- client.call [:info, cmd].compact do |reply|
75
- if reply.kind_of?(String)
76
- reply = Hash[reply.split("\r\n").map do |line|
77
- line.split(":", 2) unless line =~ /^(#|$)/
78
- end]
78
+ client.call [:ping]
79
+ end
80
+ end
79
81
 
80
- if cmd && cmd.to_s == "commandstats"
81
- # Extract nested hashes for INFO COMMANDSTATS
82
- reply = Hash[reply.map do |k, v|
83
- [k[/^cmdstat_(.*)$/, 1], Hash[*v.split(/,|=/)]]
84
- end]
85
- end
86
- end
82
+ # Echo the given string.
83
+ #
84
+ # @param [String] value
85
+ # @return [String]
86
+ def echo(value)
87
+ synchronize do |client|
88
+ client.call [:echo, value]
89
+ end
90
+ end
87
91
 
88
- reply
92
+ # Close the connection.
93
+ #
94
+ # @return [String] `OK`
95
+ def quit
96
+ synchronize do |client|
97
+ begin
98
+ client.call [:quit]
99
+ rescue ConnectionError
100
+ ensure
101
+ client.disconnect
89
102
  end
90
103
  end
91
104
  end
92
105
 
106
+ # Asynchronously rewrite the append-only file.
107
+ #
108
+ # @return [String] `OK`
109
+ def bgrewriteaof
110
+ synchronize do |client|
111
+ client.call [:bgrewriteaof]
112
+ end
113
+ end
114
+
115
+ # Asynchronously save the dataset to disk.
116
+ #
117
+ # @return [String] `OK`
118
+ def bgsave
119
+ synchronize do |client|
120
+ client.call [:bgsave]
121
+ end
122
+ end
123
+
93
124
  # Get or set server configuration parameters.
94
125
  #
95
126
  # @param [String] action e.g. `get`, `set`, `resetstat`
@@ -107,12 +138,18 @@ class Redis
107
138
  end
108
139
  end
109
140
 
110
- # Remove all keys from the current database.
141
+ # Return the number of keys in the selected database.
111
142
  #
112
- # @return [String] `OK`
113
- def flushdb
143
+ # @return [Fixnum]
144
+ def dbsize
114
145
  synchronize do |client|
115
- client.call [:flushdb]
146
+ client.call [:dbsize]
147
+ end
148
+ end
149
+
150
+ def debug(*args)
151
+ synchronize do |client|
152
+ client.call [:debug, *args]
116
153
  end
117
154
  end
118
155
 
@@ -125,158 +162,219 @@ class Redis
125
162
  end
126
163
  end
127
164
 
128
- # Synchronously save the dataset to disk.
165
+ # Remove all keys from the current database.
129
166
  #
130
- # @return [String]
131
- def save
167
+ # @return [String] `OK`
168
+ def flushdb
132
169
  synchronize do |client|
133
- client.call [:save]
170
+ client.call [:flushdb]
134
171
  end
135
172
  end
136
173
 
137
- # Asynchronously save the dataset to disk.
174
+ # Get information and statistics about the server.
138
175
  #
139
- # @return [String] `OK`
140
- def bgsave
176
+ # @param [String, Symbol] cmd e.g. "commandstats"
177
+ # @return [Hash<String, String>]
178
+ def info(cmd = nil)
141
179
  synchronize do |client|
142
- client.call [:bgsave]
180
+ client.call [:info, cmd].compact do |reply|
181
+ if reply.kind_of?(String)
182
+ reply = Hash[reply.split("\r\n").map do |line|
183
+ line.split(":", 2) unless line =~ /^(#|$)/
184
+ end]
185
+
186
+ if cmd && cmd.to_s == "commandstats"
187
+ # Extract nested hashes for INFO COMMANDSTATS
188
+ reply = Hash[reply.map do |k, v|
189
+ [k[/^cmdstat_(.*)$/, 1], Hash[*v.split(/,|=/)]]
190
+ end]
191
+ end
192
+ end
193
+
194
+ reply
195
+ end
143
196
  end
144
197
  end
145
198
 
146
- # Asynchronously rewrite the append-only file.
199
+ # Get the UNIX time stamp of the last successful save to disk.
147
200
  #
148
- # @return [String] `OK`
149
- def bgrewriteaof
201
+ # @return [Fixnum]
202
+ def lastsave
150
203
  synchronize do |client|
151
- client.call [:bgrewriteaof]
204
+ client.call [:lastsave]
152
205
  end
153
206
  end
154
207
 
155
- # Get the value of a key.
208
+ # Listen for all requests received by the server in real time.
209
+ #
210
+ # There is no way to interrupt this command.
211
+ #
212
+ # @yield a block to be called for every line of output
213
+ # @yieldparam [String] line timestamp and command that was executed
214
+ def monitor(&block)
215
+ synchronize do |client|
216
+ client.call_loop([:monitor], &block)
217
+ end
218
+ end
219
+
220
+ # Synchronously save the dataset to disk.
156
221
  #
157
- # @param [String] key
158
222
  # @return [String]
159
- def get(key)
223
+ def save
160
224
  synchronize do |client|
161
- client.call [:get, key]
225
+ client.call [:save]
162
226
  end
163
227
  end
164
228
 
165
- alias :[] :get
229
+ # Synchronously save the dataset to disk and then shut down the server.
230
+ def shutdown
231
+ synchronize do |client|
232
+ client.with_reconnect(false) do
233
+ begin
234
+ client.call [:shutdown]
235
+ rescue ConnectionError
236
+ # This means Redis has probably exited.
237
+ nil
238
+ end
239
+ end
240
+ end
241
+ end
166
242
 
167
- # Returns the bit value at offset in the string value stored at key.
168
- #
169
- # @param [String] key
170
- # @param [Fixnum] offset bit offset
171
- # @return [Fixnum] `0` or `1`
172
- def getbit(key, offset)
243
+ # Make the server a slave of another instance, or promote it as master.
244
+ def slaveof(host, port)
173
245
  synchronize do |client|
174
- client.call [:getbit, key, offset]
246
+ client.call [:slaveof, host, port]
175
247
  end
176
248
  end
177
249
 
178
- # Get a substring of the string stored at a key.
250
+ # Interact with the slowlog (get, len, reset)
179
251
  #
180
- # @param [String] key
181
- # @param [Fixnum] start zero-based start offset
182
- # @param [Fixnum] stop zero-based end offset. Use -1 for representing
183
- # the end of the string
184
- # @return [Fixnum] `0` or `1`
185
- def getrange(key, start, stop)
252
+ # @param [String] subcommand e.g. `get`, `len`, `reset`
253
+ # @param [Fixnum] length maximum number of entries to return
254
+ # @return [Array<String>, Fixnum, String] depends on subcommand
255
+ def slowlog(subcommand, length=nil)
186
256
  synchronize do |client|
187
- client.call [:getrange, key, start, stop]
257
+ args = [:slowlog, subcommand]
258
+ args << length if length
259
+ client.call args
188
260
  end
189
261
  end
190
262
 
191
- # Set the string value of a key and return its old value.
192
- #
193
- # @param [String] key
194
- # @param [String] value value to replace the current value with
195
- # @return [String] the old value stored in the key, or `nil` if the key
196
- # did not exist
197
- def getset(key, value)
263
+ # Internal command used for replication.
264
+ def sync
198
265
  synchronize do |client|
199
- client.call [:getset, key, value]
266
+ client.call [:sync]
200
267
  end
201
268
  end
202
269
 
203
- # Get the values of all the given keys.
270
+ # Return the server time.
204
271
  #
205
272
  # @example
206
- # redis.mget("key1", "key1")
207
- # # => ["v1", "v2"]
208
- #
209
- # @param [Array<String>] keys
210
- # @return [Array<String>] an array of values for the specified keys
273
+ # r.time # => [ 1333093196, 606806 ]
211
274
  #
212
- # @see #mapped_mget
213
- def mget(*keys, &blk)
275
+ # @return [Array<Fixnum>] tuple of seconds since UNIX epoch and
276
+ # microseconds in the current second
277
+ def time
214
278
  synchronize do |client|
215
- client.call [:mget, *keys], &blk
279
+ client.call [:time] do |reply|
280
+ reply.map(&:to_i) if reply
281
+ end
216
282
  end
217
283
  end
218
284
 
219
- # Append a value to a key.
285
+ # Remove the expiration from a key.
220
286
  #
221
287
  # @param [String] key
222
- # @param [String] value value to append
223
- # @return [Fixnum] length of the string after appending
224
- def append(key, value)
288
+ # @return [Boolean] whether the timeout was removed or not
289
+ def persist(key)
225
290
  synchronize do |client|
226
- client.call [:append, key, value]
291
+ client.call [:persist, key], &_boolify
227
292
  end
228
293
  end
229
294
 
230
- # Get the length of the value stored in a key.
295
+ # Set a key's time to live in seconds.
231
296
  #
232
297
  # @param [String] key
233
- # @return [Fixnum] the length of the value stored in the key, or 0
234
- # if the key does not exist
235
- def strlen(key)
298
+ # @param [Fixnum] seconds time to live
299
+ # @return [Boolean] whether the timeout was set or not
300
+ def expire(key, seconds)
236
301
  synchronize do |client|
237
- client.call [:strlen, key]
302
+ client.call [:expire, key, seconds], &_boolify
238
303
  end
239
304
  end
240
305
 
241
- # Get all the fields and values in a hash.
306
+ # Set the expiration for a key as a UNIX timestamp.
242
307
  #
243
308
  # @param [String] key
244
- # @return [Hash<String, String>]
245
- def hgetall(key)
309
+ # @param [Fixnum] unix_time expiry time specified as a UNIX timestamp
310
+ # @return [Boolean] whether the timeout was set or not
311
+ def expireat(key, unix_time)
246
312
  synchronize do |client|
247
- client.call [:hgetall, key], &_hashify
313
+ client.call [:expireat, key, unix_time], &_boolify
248
314
  end
249
315
  end
250
316
 
251
- # Get the value of a hash field.
317
+ # Get the time to live (in seconds) for a key.
252
318
  #
253
319
  # @param [String] key
254
- # @param [String] field
255
- # @return [String]
256
- def hget(key, field)
320
+ # @return [Fixnum] remaining time to live in seconds, or -1 if the
321
+ # key does not exist or does not have a timeout
322
+ def ttl(key)
257
323
  synchronize do |client|
258
- client.call [:hget, key, field]
324
+ client.call [:ttl, key]
259
325
  end
260
326
  end
261
327
 
262
- # Delete one or more hash fields.
328
+ # Set a key's time to live in milliseconds.
263
329
  #
264
330
  # @param [String] key
265
- # @param [String, Array<String>] field
266
- # @return [Fixnum] the number of fields that were removed from the hash
267
- def hdel(key, field)
331
+ # @param [Fixnum] milliseconds time to live
332
+ # @return [Boolean] whether the timeout was set or not
333
+ def pexpire(key, milliseconds)
268
334
  synchronize do |client|
269
- client.call [:hdel, key, field]
335
+ client.call [:pexpire, key, milliseconds], &_boolify
270
336
  end
271
337
  end
272
338
 
273
- # Get all the fields in a hash.
339
+ # Set the expiration for a key as number of milliseconds from UNIX Epoch.
274
340
  #
275
341
  # @param [String] key
276
- # @return [Array<String>]
277
- def hkeys(key)
342
+ # @param [Fixnum] ms_unix_time expiry time specified as number of milliseconds from UNIX Epoch.
343
+ # @return [Boolean] whether the timeout was set or not
344
+ def pexpireat(key, ms_unix_time)
278
345
  synchronize do |client|
279
- client.call [:hkeys, key]
346
+ client.call [:pexpireat, key, ms_unix_time], &_boolify
347
+ end
348
+ end
349
+
350
+ # Get the time to live (in milliseconds) for a key.
351
+ #
352
+ # @param [String] key
353
+ # @return [Fixnum] remaining time to live in milliseconds, or -1 if the
354
+ # key does not exist or does not have a timeout
355
+ def pttl(key)
356
+ synchronize do |client|
357
+ client.call [:pttl, key]
358
+ end
359
+ end
360
+
361
+ # Delete one or more keys.
362
+ #
363
+ # @param [String, Array<String>] keys
364
+ # @return [Fixnum] number of keys that were deleted
365
+ def del(*keys)
366
+ synchronize do |client|
367
+ client.call [:del, *keys]
368
+ end
369
+ end
370
+
371
+ # Determine if a key exists.
372
+ #
373
+ # @param [String] key
374
+ # @return [Boolean]
375
+ def exists(key)
376
+ synchronize do |client|
377
+ client.call [:exists, key], &_boolify
280
378
  end
281
379
  end
282
380
 
@@ -296,1390 +394,1396 @@ class Redis
296
394
  end
297
395
  end
298
396
 
299
- # Return a random key from the keyspace.
397
+ # Move a key to another database.
300
398
  #
301
- # @return [String]
302
- def randomkey
399
+ # @example Move a key to another database
400
+ # redis.set "foo", "bar"
401
+ # # => "OK"
402
+ # redis.move "foo", 2
403
+ # # => true
404
+ # redis.exists "foo"
405
+ # # => false
406
+ # redis.select 2
407
+ # # => "OK"
408
+ # redis.exists "foo"
409
+ # # => true
410
+ # resis.get "foo"
411
+ # # => "bar"
412
+ #
413
+ # @param [String] key
414
+ # @param [Fixnum] db
415
+ # @return [Boolean] whether the key was moved or not
416
+ def move(key, db)
303
417
  synchronize do |client|
304
- client.call [:randomkey]
418
+ client.call [:move, key, db], &_boolify
305
419
  end
306
420
  end
307
421
 
308
- # Echo the given string.
422
+ def object(*args)
423
+ synchronize do |client|
424
+ client.call [:object, *args]
425
+ end
426
+ end
427
+
428
+ # Return a random key from the keyspace.
309
429
  #
310
- # @param [String] value
311
430
  # @return [String]
312
- def echo(value)
431
+ def randomkey
313
432
  synchronize do |client|
314
- client.call [:echo, value]
433
+ client.call [:randomkey]
315
434
  end
316
435
  end
317
436
 
318
- # Return the server time.
319
- #
320
- # @example
321
- # r.time # => [ 1333093196, 606806 ]
437
+ # Rename a key. If the new key already exists it is overwritten.
322
438
  #
323
- # @return [Array<Fixnum>] tuple of seconds since UNIX epoch and
324
- # microseconds in the current second
325
- def time
439
+ # @param [String] old_name
440
+ # @param [String] new_name
441
+ # @return [String] `OK`
442
+ def rename(old_name, new_name)
326
443
  synchronize do |client|
327
- client.call [:time] do |reply|
328
- reply.map(&:to_i) if reply
329
- end
444
+ client.call [:rename, old_name, new_name]
330
445
  end
331
446
  end
332
447
 
333
- # Ping the server.
448
+ # Rename a key, only if the new key does not exist.
334
449
  #
335
- # @return [String] `PONG`
336
- def ping
450
+ # @param [String] old_name
451
+ # @param [String] new_name
452
+ # @return [Boolean] whether the key was renamed or not
453
+ def renamenx(old_name, new_name)
337
454
  synchronize do |client|
338
- client.call [:ping]
455
+ client.call [:renamenx, old_name, new_name], &_boolify
339
456
  end
340
457
  end
341
458
 
342
- # Get the UNIX time stamp of the last successful save to disk.
459
+ # Sort the elements in a list, set or sorted set.
343
460
  #
344
- # @return [Fixnum]
345
- def lastsave
461
+ # @example Retrieve the first 2 elements from an alphabetically sorted "list"
462
+ # redis.sort("list", :order => "alpha", :limit => [0, 2])
463
+ # # => ["a", "b"]
464
+ # @example Store an alphabetically descending list in "target"
465
+ # redis.sort("list", :order => "desc alpha", :store => "target")
466
+ # # => 26
467
+ #
468
+ # @param [String] key
469
+ # @param [Hash] options
470
+ # - `:by => String`: use external key to sort elements by
471
+ # - `:limit => [offset, count]`: skip `offset` elements, return a maximum
472
+ # of `count` elements
473
+ # - `:get => [String, Array<String>]`: single key or array of keys to
474
+ # retrieve per element in the result
475
+ # - `:order => String`: combination of `ASC`, `DESC` and optionally `ALPHA`
476
+ # - `:store => String`: key to store the result at
477
+ #
478
+ # @return [Array<String>, Array<Array<String>>, Fixnum]
479
+ # - when `:get` is not specified, or holds a single element, an array of elements
480
+ # - when `:get` is specified, and holds more than one element, an array of
481
+ # elements where every element is an array with the result for every
482
+ # element specified in `:get`
483
+ # - when `:store` is specified, the number of elements in the stored result
484
+ def sort(key, options = {})
485
+ args = []
486
+
487
+ by = options[:by]
488
+ args.concat ["BY", by] if by
489
+
490
+ limit = options[:limit]
491
+ args.concat ["LIMIT", *limit] if limit
492
+
493
+ get = Array(options[:get])
494
+ args.concat ["GET"].product(get).flatten unless get.empty?
495
+
496
+ order = options[:order]
497
+ args.concat order.split(" ") if order
498
+
499
+ store = options[:store]
500
+ args.concat ["STORE", store] if store
501
+
346
502
  synchronize do |client|
347
- client.call [:lastsave]
503
+ client.call [:sort, key, *args] do |reply|
504
+ if get.size > 1
505
+ if reply
506
+ reply.each_slice(get.size).to_a
507
+ end
508
+ else
509
+ reply
510
+ end
511
+ end
348
512
  end
349
513
  end
350
514
 
351
- # Return the number of keys in the selected database.
515
+ # Determine the type stored at key.
352
516
  #
353
- # @return [Fixnum]
354
- def dbsize
517
+ # @param [String] key
518
+ # @return [String] `string`, `list`, `set`, `zset`, `hash` or `none`
519
+ def type(key)
355
520
  synchronize do |client|
356
- client.call [:dbsize]
521
+ client.call [:type, key]
357
522
  end
358
523
  end
359
524
 
360
- # Determine if a key exists.
525
+ # Decrement the integer value of a key by one.
526
+ #
527
+ # @example
528
+ # redis.decr("value")
529
+ # # => 4
361
530
  #
362
531
  # @param [String] key
363
- # @return [Boolean]
364
- def exists(key)
532
+ # @return [Fixnum] value after decrementing it
533
+ def decr(key)
365
534
  synchronize do |client|
366
- client.call [:exists, key], &_boolify
535
+ client.call [:decr, key]
367
536
  end
368
537
  end
369
538
 
370
- # Get the length of a list.
539
+ # Decrement the integer value of a key by the given number.
540
+ #
541
+ # @example
542
+ # redis.decrby("value", 5)
543
+ # # => 0
371
544
  #
372
545
  # @param [String] key
373
- # @return [Fixnum]
374
- def llen(key)
546
+ # @param [Fixnum] decrement
547
+ # @return [Fixnum] value after decrementing it
548
+ def decrby(key, decrement)
375
549
  synchronize do |client|
376
- client.call [:llen, key]
550
+ client.call [:decrby, key, decrement]
377
551
  end
378
552
  end
379
553
 
380
- # Get a range of elements from a list.
554
+ # Increment the integer value of a key by one.
555
+ #
556
+ # @example
557
+ # redis.incr("value")
558
+ # # => 6
381
559
  #
382
560
  # @param [String] key
383
- # @param [Fixnum] start start index
384
- # @param [Fixnum] stop stop index
385
- # @return [Array<String>]
386
- def lrange(key, start, stop)
561
+ # @return [Fixnum] value after incrementing it
562
+ def incr(key)
387
563
  synchronize do |client|
388
- client.call [:lrange, key, start, stop]
564
+ client.call [:incr, key]
389
565
  end
390
566
  end
391
567
 
392
- # Trim a list to the specified range.
568
+ # Increment the integer value of a key by the given integer number.
569
+ #
570
+ # @example
571
+ # redis.incrby("value", 5)
572
+ # # => 10
393
573
  #
394
574
  # @param [String] key
395
- # @param [Fixnum] start start index
396
- # @param [Fixnum] stop stop index
397
- # @return [String] `OK`
398
- def ltrim(key, start, stop)
575
+ # @param [Fixnum] increment
576
+ # @return [Fixnum] value after incrementing it
577
+ def incrby(key, increment)
399
578
  synchronize do |client|
400
- client.call [:ltrim, key, start, stop]
579
+ client.call [:incrby, key, increment]
401
580
  end
402
581
  end
403
582
 
404
- # Get an element from a list by its index.
583
+ # Increment the numeric value of a key by the given float number.
584
+ #
585
+ # @example
586
+ # redis.incrbyfloat("value", 1.23)
587
+ # # => 1.23
405
588
  #
406
589
  # @param [String] key
407
- # @param [Fixnum] index
408
- # @return [String]
409
- def lindex(key, index)
590
+ # @param [Float] increment
591
+ # @return [Float] value after incrementing it
592
+ def incrbyfloat(key, increment)
410
593
  synchronize do |client|
411
- client.call [:lindex, key, index]
594
+ client.call [:incrbyfloat, key, increment] do |reply|
595
+ Float(reply) if reply
596
+ end
412
597
  end
413
598
  end
414
599
 
415
- # Insert an element before or after another element in a list.
600
+ # Set the string value of a key.
416
601
  #
417
602
  # @param [String] key
418
- # @param [String, Symbol] where `BEFORE` or `AFTER`
419
- # @param [String] pivot reference element
420
603
  # @param [String] value
421
- # @return [Fixnum] length of the list after the insert operation, or `-1`
422
- # when the element `pivot` was not found
423
- def linsert(key, where, pivot, value)
604
+ # @return `"OK"`
605
+ def set(key, value)
424
606
  synchronize do |client|
425
- client.call [:linsert, key, where, pivot, value]
607
+ client.call [:set, key, value]
426
608
  end
427
609
  end
428
610
 
429
- # Set the value of an element in a list by its index.
611
+ alias :[]= :set
612
+
613
+ # Set the time to live in seconds of a key.
430
614
  #
431
615
  # @param [String] key
432
- # @param [Fixnum] index
616
+ # @param [Fixnum] ttl
433
617
  # @param [String] value
434
- # @return [String] `OK`
435
- def lset(key, index, value)
618
+ # @return `"OK"`
619
+ def setex(key, ttl, value)
436
620
  synchronize do |client|
437
- client.call [:lset, key, index, value]
621
+ client.call [:setex, key, ttl, value]
438
622
  end
439
623
  end
440
624
 
441
- # Remove elements from a list.
625
+ # Set the time to live in milliseconds of a key.
442
626
  #
443
627
  # @param [String] key
444
- # @param [Fixnum] count number of elements to remove. Use a positive
445
- # value to remove the first `count` occurrences of `value`. A negative
446
- # value to remove the last `count` occurrences of `value`. Or zero, to
447
- # remove all occurrences of `value` from the list.
628
+ # @param [Fixnum] ttl
448
629
  # @param [String] value
449
- # @return [Fixnum] the number of removed elements
450
- def lrem(key, count, value)
630
+ # @return `"OK"`
631
+ def psetex(key, ttl, value)
451
632
  synchronize do |client|
452
- client.call [:lrem, key, count, value]
633
+ client.call [:psetex, key, ttl, value]
453
634
  end
454
635
  end
455
636
 
456
- # Append one or more values to a list, creating the list if it doesn't exist
637
+ # Set the value of a key, only if the key does not exist.
457
638
  #
458
639
  # @param [String] key
459
640
  # @param [String] value
460
- # @return [Fixnum] the length of the list after the push operation
461
- def rpush(key, value)
641
+ # @return [Boolean] whether the key was set or not
642
+ def setnx(key, value)
462
643
  synchronize do |client|
463
- client.call [:rpush, key, value]
644
+ client.call [:setnx, key, value], &_boolify
464
645
  end
465
646
  end
466
647
 
467
- # Append a value to a list, only if the list exists.
648
+ # Set one or more values.
468
649
  #
469
- # @param [String] key
470
- # @param [String] value
471
- # @return [Fixnum] the length of the list after the push operation
472
- def rpushx(key, value)
650
+ # @example
651
+ # redis.mset("key1", "v1", "key2", "v2")
652
+ # # => "OK"
653
+ #
654
+ # @param [Array<String>] args array of keys and values
655
+ # @return `"OK"`
656
+ #
657
+ # @see #mapped_mset
658
+ def mset(*args)
473
659
  synchronize do |client|
474
- client.call [:rpushx, key, value]
660
+ client.call [:mset, *args]
475
661
  end
476
662
  end
477
663
 
478
- # Prepend one or more values to a list, creating the list if it doesn't exist
664
+ # Set one or more values.
479
665
  #
480
- # @param [String] key
481
- # @param [String] value
482
- # @return [Fixnum] the length of the list after the push operation
483
- def lpush(key, value)
484
- synchronize do |client|
485
- client.call [:lpush, key, value]
486
- end
666
+ # @example
667
+ # redis.mapped_mset({ "f1" => "v1", "f2" => "v2" })
668
+ # # => "OK"
669
+ #
670
+ # @param [Hash] hash keys mapping to values
671
+ # @return `"OK"`
672
+ #
673
+ # @see #mset
674
+ def mapped_mset(hash)
675
+ mset(*hash.to_a.flatten)
487
676
  end
488
677
 
489
- # Prepend a value to a list, only if the list exists.
678
+ # Set one or more values, only if none of the keys exist.
490
679
  #
491
- # @param [String] key
492
- # @param [String] value
493
- # @return [Fixnum] the length of the list after the push operation
494
- def lpushx(key, value)
680
+ # @example
681
+ # redis.msetnx("key1", "v1", "key2", "v2")
682
+ # # => true
683
+ #
684
+ # @param [Array<String>] args array of keys and values
685
+ # @return [Boolean] whether or not all values were set
686
+ #
687
+ # @see #mapped_msetnx
688
+ def msetnx(*args)
495
689
  synchronize do |client|
496
- client.call [:lpushx, key, value]
690
+ client.call [:msetnx, *args], &_boolify
497
691
  end
498
692
  end
499
693
 
500
- # Remove and get the last element in a list.
694
+ # Set one or more values, only if none of the keys exist.
695
+ #
696
+ # @example
697
+ # redis.msetnx({ "key1" => "v1", "key2" => "v2" })
698
+ # # => true
699
+ #
700
+ # @param [Hash] hash keys mapping to values
701
+ # @return [Boolean] whether or not all values were set
702
+ #
703
+ # @see #msetnx
704
+ def mapped_msetnx(hash)
705
+ msetnx(*hash.to_a.flatten)
706
+ end
707
+
708
+ # Get the value of a key.
501
709
  #
502
710
  # @param [String] key
503
711
  # @return [String]
504
- def rpop(key)
712
+ def get(key)
505
713
  synchronize do |client|
506
- client.call [:rpop, key]
714
+ client.call [:get, key]
507
715
  end
508
716
  end
509
717
 
510
- def _bpop(cmd, args)
511
- options = {}
512
-
513
- case args.last
514
- when Hash
515
- options = args.pop
516
- when Integer
517
- # Issue deprecation notice in obnoxious mode...
518
- options[:timeout] = args.pop
519
- end
520
-
521
- if args.size > 1
522
- # Issue deprecation notice in obnoxious mode...
523
- end
524
-
525
- keys = args.flatten
526
- timeout = options[:timeout] || 0
527
-
528
- synchronize do |client|
529
- client.call_without_timeout [cmd, keys, timeout]
530
- end
531
- end
718
+ alias :[] :get
532
719
 
533
- # Remove and get the first element in a list, or block until one is available.
720
+ # Get the values of all the given keys.
534
721
  #
535
- # @example With timeout
536
- # list, element = redis.blpop("list", :timeout => 5)
537
- # # => nil on timeout
538
- # # => ["list", "element"] on success
539
- # @example Without timeout
540
- # list, element = redis.blpop("list")
541
- # # => ["list", "element"]
542
- # @example Blocking pop on multiple lists
543
- # list, element = redis.blpop(["list", "another_list"])
544
- # # => ["list", "element"]
722
+ # @example
723
+ # redis.mget("key1", "key1")
724
+ # # => ["v1", "v2"]
545
725
  #
546
- # @param [String, Array<String>] keys one or more keys to perform the
547
- # blocking pop on
548
- # @param [Hash] options
549
- # - `:timeout => Fixnum`: timeout in seconds, defaults to no timeout
726
+ # @param [Array<String>] keys
727
+ # @return [Array<String>] an array of values for the specified keys
550
728
  #
551
- # @return [nil, [String, String]]
552
- # - `nil` when the operation timed out
553
- # - tuple of the list that was popped from and element was popped otherwise
554
- def blpop(*args)
555
- _bpop(:blpop, args)
729
+ # @see #mapped_mget
730
+ def mget(*keys, &blk)
731
+ synchronize do |client|
732
+ client.call [:mget, *keys], &blk
733
+ end
556
734
  end
557
735
 
558
- # Remove and get the last element in a list, or block until one is available.
736
+ # Get the values of all the given keys.
559
737
  #
560
- # @param [String, Array<String>] keys one or more keys to perform the
561
- # blocking pop on
562
- # @param [Hash] options
563
- # - `:timeout => Fixnum`: timeout in seconds, defaults to no timeout
738
+ # @example
739
+ # redis.mapped_mget("key1", "key1")
740
+ # # => { "key1" => "v1", "key2" => "v2" }
564
741
  #
565
- # @return [nil, [String, String]]
566
- # - `nil` when the operation timed out
567
- # - tuple of the list that was popped from and element was popped otherwise
742
+ # @param [Array<String>] keys array of keys
743
+ # @return [Hash] a hash mapping the specified keys to their values
568
744
  #
569
- # @see #blpop
570
- def brpop(*args)
571
- _bpop(:brpop, args)
745
+ # @see #mget
746
+ def mapped_mget(*keys)
747
+ mget(*keys) do |reply|
748
+ if reply.kind_of?(Array)
749
+ hash = Hash.new
750
+ keys.zip(reply).each do |field, value|
751
+ hash[field] = value
752
+ end
753
+ hash
754
+ else
755
+ reply
756
+ end
757
+ end
572
758
  end
573
759
 
574
- # Pop a value from a list, push it to another list and return it; or block
575
- # until one is available.
576
- #
577
- # @param [String] source source key
578
- # @param [String] destination destination key
579
- # @param [Hash] options
580
- # - `:timeout => Fixnum`: timeout in seconds, defaults to no timeout
760
+ # Overwrite part of a string at key starting at the specified offset.
581
761
  #
582
- # @return [nil, String]
583
- # - `nil` when the operation timed out
584
- # - the element was popped and pushed otherwise
585
- def brpoplpush(source, destination, options = {})
586
- case options
587
- when Integer
588
- # Issue deprecation notice in obnoxious mode...
589
- options = { :timeout => options }
590
- end
591
-
592
- timeout = options[:timeout] || 0
593
-
762
+ # @param [String] key
763
+ # @param [Fixnum] offset byte offset
764
+ # @param [String] value
765
+ # @return [Fixnum] length of the string after it was modified
766
+ def setrange(key, offset, value)
594
767
  synchronize do |client|
595
- client.call_without_timeout [:brpoplpush, source, destination, timeout]
768
+ client.call [:setrange, key, offset, value]
596
769
  end
597
770
  end
598
771
 
599
- # Remove the last element in a list, append it to another list and return it.
772
+ # Get a substring of the string stored at a key.
600
773
  #
601
- # @param [String] source source key
602
- # @param [String] destination destination key
603
- # @return [nil, String] the element, or nil when the source key does not exist
604
- def rpoplpush(source, destination)
774
+ # @param [String] key
775
+ # @param [Fixnum] start zero-based start offset
776
+ # @param [Fixnum] stop zero-based end offset. Use -1 for representing
777
+ # the end of the string
778
+ # @return [Fixnum] `0` or `1`
779
+ def getrange(key, start, stop)
605
780
  synchronize do |client|
606
- client.call [:rpoplpush, source, destination]
781
+ client.call [:getrange, key, start, stop]
607
782
  end
608
783
  end
609
784
 
610
- # Remove and get the first element in a list.
785
+ # Sets or clears the bit at offset in the string value stored at key.
611
786
  #
612
787
  # @param [String] key
613
- # @return [String]
614
- def lpop(key)
788
+ # @param [Fixnum] offset bit offset
789
+ # @param [Fixnum] value bit value `0` or `1`
790
+ # @return [Fixnum] the original bit value stored at `offset`
791
+ def setbit(key, offset, value)
615
792
  synchronize do |client|
616
- client.call [:lpop, key]
793
+ client.call [:setbit, key, offset, value]
617
794
  end
618
795
  end
619
796
 
620
- # Interact with the slowlog (get, len, reset)
797
+ # Returns the bit value at offset in the string value stored at key.
621
798
  #
622
- # @param [String] subcommand e.g. `get`, `len`, `reset`
623
- # @param [Fixnum] length maximum number of entries to return
624
- # @return [Array<String>, Fixnum, String] depends on subcommand
625
- def slowlog(subcommand, length=nil)
799
+ # @param [String] key
800
+ # @param [Fixnum] offset bit offset
801
+ # @return [Fixnum] `0` or `1`
802
+ def getbit(key, offset)
626
803
  synchronize do |client|
627
- args = [:slowlog, subcommand]
628
- args << length if length
629
- client.call args
804
+ client.call [:getbit, key, offset]
630
805
  end
631
806
  end
632
807
 
633
- # Get all the members in a set.
808
+ # Append a value to a key.
634
809
  #
635
810
  # @param [String] key
636
- # @return [Array<String>]
637
- def smembers(key)
811
+ # @param [String] value value to append
812
+ # @return [Fixnum] length of the string after appending
813
+ def append(key, value)
638
814
  synchronize do |client|
639
- client.call [:smembers, key]
815
+ client.call [:append, key, value]
640
816
  end
641
817
  end
642
818
 
643
- # Determine if a given value is a member of a set.
819
+ # Set the string value of a key and return its old value.
644
820
  #
645
821
  # @param [String] key
646
- # @param [String] member
647
- # @return [Boolean]
648
- def sismember(key, member)
822
+ # @param [String] value value to replace the current value with
823
+ # @return [String] the old value stored in the key, or `nil` if the key
824
+ # did not exist
825
+ def getset(key, value)
649
826
  synchronize do |client|
650
- client.call [:sismember, key, member], &_boolify
827
+ client.call [:getset, key, value]
651
828
  end
652
829
  end
653
830
 
654
- # Add one or more members to a set.
831
+ # Get the length of the value stored in a key.
655
832
  #
656
833
  # @param [String] key
657
- # @param [String, Array<String>] member one member, or array of members
658
- # @return [Boolean, Fixnum] `Boolean` when a single member is specified,
659
- # holding whether or not adding the member succeeded, or `Fixnum` when an
660
- # array of members is specified, holding the number of members that were
661
- # successfully added
662
- def sadd(key, member)
834
+ # @return [Fixnum] the length of the value stored in the key, or 0
835
+ # if the key does not exist
836
+ def strlen(key)
663
837
  synchronize do |client|
664
- client.call [:sadd, key, member] do |reply|
665
- if member.is_a? Array
666
- # Variadic: return integer
667
- reply
668
- else
669
- # Single argument: return boolean
670
- _boolify.call(reply)
671
- end
672
- end
838
+ client.call [:strlen, key]
673
839
  end
674
840
  end
675
841
 
676
- # Remove one or more members from a set.
842
+ # Get the length of a list.
677
843
  #
678
844
  # @param [String] key
679
- # @param [String, Array<String>] member one member, or array of members
680
- # @return [Boolean, Fixnum] `Boolean` when a single member is specified,
681
- # holding whether or not removing the member succeeded, or `Fixnum` when an
682
- # array of members is specified, holding the number of members that were
683
- # successfully removed
684
- def srem(key, member)
845
+ # @return [Fixnum]
846
+ def llen(key)
685
847
  synchronize do |client|
686
- client.call [:srem, key, member] do |reply|
687
- if member.is_a? Array
688
- # Variadic: return integer
689
- reply
690
- else
691
- # Single argument: return boolean
692
- _boolify.call(reply)
693
- end
694
- end
848
+ client.call [:llen, key]
695
849
  end
696
850
  end
697
851
 
698
- # Move a member from one set to another.
852
+ # Prepend one or more values to a list, creating the list if it doesn't exist
699
853
  #
700
- # @param [String] source source key
701
- # @param [String] destination destination key
702
- # @param [String] member member to move from `source` to `destination`
703
- # @return [Boolean]
704
- def smove(source, destination, member)
854
+ # @param [String] key
855
+ # @param [String] value
856
+ # @return [Fixnum] the length of the list after the push operation
857
+ def lpush(key, value)
705
858
  synchronize do |client|
706
- client.call [:smove, source, destination, member], &_boolify
859
+ client.call [:lpush, key, value]
707
860
  end
708
861
  end
709
862
 
710
- # Remove and return a random member from a set.
863
+ # Prepend a value to a list, only if the list exists.
711
864
  #
712
865
  # @param [String] key
713
- # @return [String]
714
- def spop(key)
866
+ # @param [String] value
867
+ # @return [Fixnum] the length of the list after the push operation
868
+ def lpushx(key, value)
715
869
  synchronize do |client|
716
- client.call [:spop, key]
870
+ client.call [:lpushx, key, value]
717
871
  end
718
872
  end
719
873
 
720
- # Get the number of members in a set.
874
+ # Append one or more values to a list, creating the list if it doesn't exist
721
875
  #
722
876
  # @param [String] key
723
- # @return [Fixnum]
724
- def scard(key)
877
+ # @param [String] value
878
+ # @return [Fixnum] the length of the list after the push operation
879
+ def rpush(key, value)
725
880
  synchronize do |client|
726
- client.call [:scard, key]
881
+ client.call [:rpush, key, value]
727
882
  end
728
883
  end
729
884
 
730
- # Intersect multiple sets.
885
+ # Append a value to a list, only if the list exists.
731
886
  #
732
- # @param [String, Array<String>] keys keys pointing to sets to intersect
733
- # @return [Array<String>] members in the intersection
734
- def sinter(*keys)
887
+ # @param [String] key
888
+ # @param [String] value
889
+ # @return [Fixnum] the length of the list after the push operation
890
+ def rpushx(key, value)
735
891
  synchronize do |client|
736
- client.call [:sinter, *keys]
892
+ client.call [:rpushx, key, value]
737
893
  end
738
894
  end
739
895
 
740
- # Intersect multiple sets and store the resulting set in a key.
896
+ # Remove and get the first element in a list.
741
897
  #
742
- # @param [String] destination destination key
743
- # @param [String, Array<String>] keys keys pointing to sets to intersect
744
- # @return [Fixnum] number of elements in the resulting set
745
- def sinterstore(destination, *keys)
898
+ # @param [String] key
899
+ # @return [String]
900
+ def lpop(key)
746
901
  synchronize do |client|
747
- client.call [:sinterstore, destination, *keys]
902
+ client.call [:lpop, key]
748
903
  end
749
904
  end
750
905
 
751
- # Add multiple sets.
906
+ # Remove and get the last element in a list.
752
907
  #
753
- # @param [String, Array<String>] keys keys pointing to sets to unify
754
- # @return [Array<String>] members in the union
755
- def sunion(*keys)
908
+ # @param [String] key
909
+ # @return [String]
910
+ def rpop(key)
756
911
  synchronize do |client|
757
- client.call [:sunion, *keys]
912
+ client.call [:rpop, key]
758
913
  end
759
914
  end
760
915
 
761
- # Add multiple sets and store the resulting set in a key.
916
+ # Remove the last element in a list, append it to another list and return it.
762
917
  #
918
+ # @param [String] source source key
763
919
  # @param [String] destination destination key
764
- # @param [String, Array<String>] keys keys pointing to sets to unify
765
- # @return [Fixnum] number of elements in the resulting set
766
- def sunionstore(destination, *keys)
920
+ # @return [nil, String] the element, or nil when the source key does not exist
921
+ def rpoplpush(source, destination)
767
922
  synchronize do |client|
768
- client.call [:sunionstore, destination, *keys]
923
+ client.call [:rpoplpush, source, destination]
769
924
  end
770
925
  end
771
926
 
772
- # Subtract multiple sets.
773
- #
774
- # @param [String, Array<String>] keys keys pointing to sets to subtract
775
- # @return [Array<String>] members in the difference
776
- def sdiff(*keys)
927
+ def _bpop(cmd, args)
928
+ options = {}
929
+
930
+ case args.last
931
+ when Hash
932
+ options = args.pop
933
+ when Integer
934
+ # Issue deprecation notice in obnoxious mode...
935
+ options[:timeout] = args.pop
936
+ end
937
+
938
+ if args.size > 1
939
+ # Issue deprecation notice in obnoxious mode...
940
+ end
941
+
942
+ keys = args.flatten
943
+ timeout = options[:timeout] || 0
944
+
777
945
  synchronize do |client|
778
- client.call [:sdiff, *keys]
946
+ client.call_without_timeout [cmd, keys, timeout]
779
947
  end
780
948
  end
781
949
 
782
- # Subtract multiple sets and store the resulting set in a key.
950
+ # Remove and get the first element in a list, or block until one is available.
951
+ #
952
+ # @example With timeout
953
+ # list, element = redis.blpop("list", :timeout => 5)
954
+ # # => nil on timeout
955
+ # # => ["list", "element"] on success
956
+ # @example Without timeout
957
+ # list, element = redis.blpop("list")
958
+ # # => ["list", "element"]
959
+ # @example Blocking pop on multiple lists
960
+ # list, element = redis.blpop(["list", "another_list"])
961
+ # # => ["list", "element"]
962
+ #
963
+ # @param [String, Array<String>] keys one or more keys to perform the
964
+ # blocking pop on
965
+ # @param [Hash] options
966
+ # - `:timeout => Fixnum`: timeout in seconds, defaults to no timeout
967
+ #
968
+ # @return [nil, [String, String]]
969
+ # - `nil` when the operation timed out
970
+ # - tuple of the list that was popped from and element was popped otherwise
971
+ def blpop(*args)
972
+ _bpop(:blpop, args)
973
+ end
974
+
975
+ # Remove and get the last element in a list, or block until one is available.
976
+ #
977
+ # @param [String, Array<String>] keys one or more keys to perform the
978
+ # blocking pop on
979
+ # @param [Hash] options
980
+ # - `:timeout => Fixnum`: timeout in seconds, defaults to no timeout
981
+ #
982
+ # @return [nil, [String, String]]
983
+ # - `nil` when the operation timed out
984
+ # - tuple of the list that was popped from and element was popped otherwise
985
+ #
986
+ # @see #blpop
987
+ def brpop(*args)
988
+ _bpop(:brpop, args)
989
+ end
990
+
991
+ # Pop a value from a list, push it to another list and return it; or block
992
+ # until one is available.
783
993
  #
994
+ # @param [String] source source key
784
995
  # @param [String] destination destination key
785
- # @param [String, Array<String>] keys keys pointing to sets to subtract
786
- # @return [Fixnum] number of elements in the resulting set
787
- def sdiffstore(destination, *keys)
996
+ # @param [Hash] options
997
+ # - `:timeout => Fixnum`: timeout in seconds, defaults to no timeout
998
+ #
999
+ # @return [nil, String]
1000
+ # - `nil` when the operation timed out
1001
+ # - the element was popped and pushed otherwise
1002
+ def brpoplpush(source, destination, options = {})
1003
+ case options
1004
+ when Integer
1005
+ # Issue deprecation notice in obnoxious mode...
1006
+ options = { :timeout => options }
1007
+ end
1008
+
1009
+ timeout = options[:timeout] || 0
1010
+
788
1011
  synchronize do |client|
789
- client.call [:sdiffstore, destination, *keys]
1012
+ client.call_without_timeout [:brpoplpush, source, destination, timeout]
790
1013
  end
791
1014
  end
792
1015
 
793
- # Get a random member from a set.
1016
+ # Get an element from a list by its index.
794
1017
  #
795
1018
  # @param [String] key
1019
+ # @param [Fixnum] index
796
1020
  # @return [String]
797
- def srandmember(key)
1021
+ def lindex(key, index)
798
1022
  synchronize do |client|
799
- client.call [:srandmember, key]
1023
+ client.call [:lindex, key, index]
800
1024
  end
801
1025
  end
802
1026
 
803
- # Add one or more members to a sorted set, or update the score for members
804
- # that already exist.
805
- #
806
- # @example Add a single `[score, member]` pair to a sorted set
807
- # redis.zadd("zset", 32.0, "member")
808
- # @example Add an array of `[score, member]` pairs to a sorted set
809
- # redis.zadd("zset", [[32.0, "a"], [64.0, "b"]])
1027
+ # Insert an element before or after another element in a list.
810
1028
  #
811
1029
  # @param [String] key
812
- # @param [[Float, String], Array<[Float, String]>] args
813
- # - a single `[score, member]` pair
814
- # - an array of `[score, member]` pairs
815
- #
816
- # @return [Boolean, Fixnum]
817
- # - `Boolean` when a single pair is specified, holding whether or not it was
818
- # **added** to the sorted set
819
- # - `Fixnum` when an array of pairs is specified, holding the number of
820
- # pairs that were **added** to the sorted set
821
- def zadd(key, *args)
1030
+ # @param [String, Symbol] where `BEFORE` or `AFTER`
1031
+ # @param [String] pivot reference element
1032
+ # @param [String] value
1033
+ # @return [Fixnum] length of the list after the insert operation, or `-1`
1034
+ # when the element `pivot` was not found
1035
+ def linsert(key, where, pivot, value)
822
1036
  synchronize do |client|
823
- if args.size == 1 && args[0].is_a?(Array)
824
- # Variadic: return integer
825
- client.call [:zadd, key] + args[0]
826
- elsif args.size == 2
827
- # Single pair: return boolean
828
- client.call [:zadd, key, args[0], args[1]], &_boolify
829
- else
830
- raise ArgumentError, "wrong number of arguments"
831
- end
1037
+ client.call [:linsert, key, where, pivot, value]
832
1038
  end
833
1039
  end
834
1040
 
835
- # Remove one or more members from a sorted set.
836
- #
837
- # @example Remove a single member from a sorted set
838
- # redis.zrem("zset", "a")
839
- # @example Remove an array of members from a sorted set
840
- # redis.zrem("zset", ["a", "b"])
1041
+ # Get a range of elements from a list.
841
1042
  #
842
1043
  # @param [String] key
843
- # @param [String, Array<String>] member
844
- # - a single member
845
- # - an array of members
846
- #
847
- # @return [Boolean, Fixnum]
848
- # - `Boolean` when a single member is specified, holding whether or not it
849
- # was removed from the sorted set
850
- # - `Fixnum` when an array of pairs is specified, holding the number of
851
- # members that were removed to the sorted set
852
- def zrem(key, member)
1044
+ # @param [Fixnum] start start index
1045
+ # @param [Fixnum] stop stop index
1046
+ # @return [Array<String>]
1047
+ def lrange(key, start, stop)
853
1048
  synchronize do |client|
854
- client.call [:zrem, key, member] do |reply|
855
- if member.is_a? Array
856
- # Variadic: return integer
857
- reply
858
- else
859
- # Single argument: return boolean
860
- _boolify.call(reply)
861
- end
862
- end
1049
+ client.call [:lrange, key, start, stop]
863
1050
  end
864
1051
  end
865
1052
 
866
- # Determine the index of a member in a sorted set.
1053
+ # Remove elements from a list.
867
1054
  #
868
1055
  # @param [String] key
869
- # @param [String] member
870
- # @return [Fixnum]
871
- def zrank(key, member)
1056
+ # @param [Fixnum] count number of elements to remove. Use a positive
1057
+ # value to remove the first `count` occurrences of `value`. A negative
1058
+ # value to remove the last `count` occurrences of `value`. Or zero, to
1059
+ # remove all occurrences of `value` from the list.
1060
+ # @param [String] value
1061
+ # @return [Fixnum] the number of removed elements
1062
+ def lrem(key, count, value)
872
1063
  synchronize do |client|
873
- client.call [:zrank, key, member]
1064
+ client.call [:lrem, key, count, value]
874
1065
  end
875
1066
  end
876
1067
 
877
- # Determine the index of a member in a sorted set, with scores ordered from
878
- # high to low.
1068
+ # Set the value of an element in a list by its index.
879
1069
  #
880
1070
  # @param [String] key
881
- # @param [String] member
882
- # @return [Fixnum]
883
- def zrevrank(key, member)
1071
+ # @param [Fixnum] index
1072
+ # @param [String] value
1073
+ # @return [String] `OK`
1074
+ def lset(key, index, value)
884
1075
  synchronize do |client|
885
- client.call [:zrevrank, key, member]
1076
+ client.call [:lset, key, index, value]
886
1077
  end
887
1078
  end
888
1079
 
889
- # Increment the score of a member in a sorted set.
890
- #
891
- # @example
892
- # redis.zincrby("zset", 32.0, "a")
893
- # # => 64.0
1080
+ # Trim a list to the specified range.
894
1081
  #
895
1082
  # @param [String] key
896
- # @param [Float] increment
897
- # @param [String] member
898
- # @return [Float] score of the member after incrementing it
899
- def zincrby(key, increment, member)
1083
+ # @param [Fixnum] start start index
1084
+ # @param [Fixnum] stop stop index
1085
+ # @return [String] `OK`
1086
+ def ltrim(key, start, stop)
900
1087
  synchronize do |client|
901
- client.call [:zincrby, key, increment, member] do |reply|
902
- Float(reply) if reply
903
- end
1088
+ client.call [:ltrim, key, start, stop]
904
1089
  end
905
1090
  end
906
1091
 
907
- # Get the number of members in a sorted set.
908
- #
909
- # @example
910
- # redis.zcard("zset")
911
- # # => 4
1092
+ # Get the number of members in a set.
912
1093
  #
913
1094
  # @param [String] key
914
1095
  # @return [Fixnum]
915
- def zcard(key)
1096
+ def scard(key)
916
1097
  synchronize do |client|
917
- client.call [:zcard, key]
1098
+ client.call [:scard, key]
918
1099
  end
919
1100
  end
920
1101
 
921
- # Return a range of members in a sorted set, by index.
922
- #
923
- # @example Retrieve all members from a sorted set
924
- # redis.zrange("zset", 0, -1)
925
- # # => ["a", "b"]
926
- # @example Retrieve all members and their scores from a sorted set
927
- # redis.zrange("zset", 0, -1, :with_scores => true)
928
- # # => [["a", 32.0], ["b", 64.0]]
1102
+ # Add one or more members to a set.
929
1103
  #
930
1104
  # @param [String] key
931
- # @param [Fixnum] start start index
932
- # @param [Fixnum] stop stop index
933
- # @param [Hash] options
934
- # - `:with_scores => true`: include scores in output
935
- #
936
- # @return [Array<String>, Array<[String, Float]>]
937
- # - when `:with_scores` is not specified, an array of members
938
- # - when `:with_scores` is specified, an array with `[member, score]` pairs
939
- def zrange(key, start, stop, options = {})
940
- args = []
941
-
942
- with_scores = options[:with_scores] || options[:withscores]
943
- args << "WITHSCORES" if with_scores
944
-
1105
+ # @param [String, Array<String>] member one member, or array of members
1106
+ # @return [Boolean, Fixnum] `Boolean` when a single member is specified,
1107
+ # holding whether or not adding the member succeeded, or `Fixnum` when an
1108
+ # array of members is specified, holding the number of members that were
1109
+ # successfully added
1110
+ def sadd(key, member)
945
1111
  synchronize do |client|
946
- client.call [:zrange, key, start, stop, *args] do |reply|
947
- if with_scores
948
- if reply
949
- reply.each_slice(2).map do |member, score|
950
- [member, Float(score)]
951
- end
952
- end
953
- else
1112
+ client.call [:sadd, key, member] do |reply|
1113
+ if member.is_a? Array
1114
+ # Variadic: return integer
954
1115
  reply
1116
+ else
1117
+ # Single argument: return boolean
1118
+ _boolify.call(reply)
955
1119
  end
956
1120
  end
957
1121
  end
958
1122
  end
959
1123
 
960
- # Return a range of members in a sorted set, by index, with scores ordered
961
- # from high to low.
962
- #
963
- # @example Retrieve all members from a sorted set
964
- # redis.zrevrange("zset", 0, -1)
965
- # # => ["b", "a"]
966
- # @example Retrieve all members and their scores from a sorted set
967
- # redis.zrevrange("zset", 0, -1, :with_scores => true)
968
- # # => [["b", 64.0], ["a", 32.0]]
1124
+ # Remove one or more members from a set.
969
1125
  #
970
- # @see #zrange
971
- def zrevrange(key, start, stop, options = {})
972
- args = []
973
-
974
- with_scores = options[:with_scores] || options[:withscores]
975
- args << "WITHSCORES" if with_scores
976
-
1126
+ # @param [String] key
1127
+ # @param [String, Array<String>] member one member, or array of members
1128
+ # @return [Boolean, Fixnum] `Boolean` when a single member is specified,
1129
+ # holding whether or not removing the member succeeded, or `Fixnum` when an
1130
+ # array of members is specified, holding the number of members that were
1131
+ # successfully removed
1132
+ def srem(key, member)
977
1133
  synchronize do |client|
978
- client.call [:zrevrange, key, start, stop, *args] do |reply|
979
- if with_scores
980
- if reply
981
- reply.each_slice(2).map do |member, score|
982
- [member, Float(score)]
983
- end
984
- end
985
- else
1134
+ client.call [:srem, key, member] do |reply|
1135
+ if member.is_a? Array
1136
+ # Variadic: return integer
986
1137
  reply
1138
+ else
1139
+ # Single argument: return boolean
1140
+ _boolify.call(reply)
987
1141
  end
988
1142
  end
989
1143
  end
990
1144
  end
991
1145
 
992
- # Return a range of members in a sorted set, by score.
993
- #
994
- # @example Retrieve members with score `>= 5` and `< 100`
995
- # redis.zrangebyscore("zset", "5", "(100")
996
- # # => ["a", "b"]
997
- # @example Retrieve the first 2 members with score `>= 0`
998
- # redis.zrangebyscore("zset", "0", "+inf", :limit => [0, 2])
999
- # # => ["a", "b"]
1000
- # @example Retrieve members and their scores with scores `> 5`
1001
- # redis.zrangebyscore("zset", "(5", "+inf", :with_scores => true)
1002
- # # => [["a", 32.0], ["b", 64.0]]
1146
+ # Remove and return a random member from a set.
1003
1147
  #
1004
1148
  # @param [String] key
1005
- # @param [String] min
1006
- # - inclusive minimum score is specified verbatim
1007
- # - exclusive minimum score is specified by prefixing `(`
1008
- # @param [String] max
1009
- # - inclusive maximum score is specified verbatim
1010
- # - exclusive maximum score is specified by prefixing `(`
1011
- # @param [Hash] options
1012
- # - `:with_scores => true`: include scores in output
1013
- # - `:limit => [offset, count]`: skip `offset` members, return a maximum of
1014
- # `count` members
1015
- #
1016
- # @return [Array<String>, Array<[String, Float]>]
1017
- # - when `:with_scores` is not specified, an array of members
1018
- # - when `:with_scores` is specified, an array with `[member, score]` pairs
1019
- def zrangebyscore(key, min, max, options = {})
1020
- args = []
1021
-
1022
- with_scores = options[:with_scores] || options[:withscores]
1023
- args.concat ["WITHSCORES"] if with_scores
1024
-
1025
- limit = options[:limit]
1026
- args.concat ["LIMIT", *limit] if limit
1027
-
1149
+ # @return [String]
1150
+ def spop(key)
1028
1151
  synchronize do |client|
1029
- client.call [:zrangebyscore, key, min, max, *args] do |reply|
1030
- if with_scores
1031
- if reply
1032
- reply.each_slice(2).map do |member, score|
1033
- [member, Float(score)]
1034
- end
1035
- end
1036
- else
1037
- reply
1038
- end
1039
- end
1152
+ client.call [:spop, key]
1040
1153
  end
1041
1154
  end
1042
1155
 
1043
- # Return a range of members in a sorted set, by score, with scores ordered
1044
- # from high to low.
1045
- #
1046
- # @example Retrieve members with score `< 100` and `>= 5`
1047
- # redis.zrevrangebyscore("zset", "(100", "5")
1048
- # # => ["b", "a"]
1049
- # @example Retrieve the first 2 members with score `<= 0`
1050
- # redis.zrevrangebyscore("zset", "0", "-inf", :limit => [0, 2])
1051
- # # => ["b", "a"]
1052
- # @example Retrieve members and their scores with scores `> 5`
1053
- # redis.zrevrangebyscore("zset", "+inf", "(5", :with_scores => true)
1054
- # # => [["b", 64.0], ["a", 32.0]]
1156
+ # Get a random member from a set.
1055
1157
  #
1056
- # @see #zrangebyscore
1057
- def zrevrangebyscore(key, max, min, options = {})
1058
- args = []
1059
-
1060
- with_scores = options[:with_scores] || options[:withscores]
1061
- args.concat ["WITHSCORES"] if with_scores
1062
-
1063
- limit = options[:limit]
1064
- args.concat ["LIMIT", *limit] if limit
1065
-
1158
+ # @param [String] key
1159
+ # @return [String]
1160
+ def srandmember(key)
1066
1161
  synchronize do |client|
1067
- client.call [:zrevrangebyscore, key, max, min, *args] do |reply|
1068
- if with_scores
1069
- if reply
1070
- reply.each_slice(2).map do |member, score|
1071
- [member, Float(score)]
1072
- end
1073
- end
1074
- else
1075
- reply
1076
- end
1077
- end
1162
+ client.call [:srandmember, key]
1078
1163
  end
1079
1164
  end
1080
1165
 
1081
- # Count the members in a sorted set with scores within the given values.
1166
+ # Move a member from one set to another.
1082
1167
  #
1083
- # @example Count members with score `>= 5` and `< 100`
1084
- # redis.zcount("zset", "5", "(100")
1085
- # # => 2
1086
- # @example Count members with scores `> 5`
1087
- # redis.zcount("zset", "(5", "+inf")
1088
- # # => 2
1089
- #
1090
- # @param [String] key
1091
- # @param [String] min
1092
- # - inclusive minimum score is specified verbatim
1093
- # - exclusive minimum score is specified by prefixing `(`
1094
- # @param [String] max
1095
- # - inclusive maximum score is specified verbatim
1096
- # - exclusive maximum score is specified by prefixing `(`
1097
- # @return [Fixnum] number of members in within the specified range
1098
- def zcount(key, min, max)
1168
+ # @param [String] source source key
1169
+ # @param [String] destination destination key
1170
+ # @param [String] member member to move from `source` to `destination`
1171
+ # @return [Boolean]
1172
+ def smove(source, destination, member)
1099
1173
  synchronize do |client|
1100
- client.call [:zcount, key, min, max]
1174
+ client.call [:smove, source, destination, member], &_boolify
1101
1175
  end
1102
1176
  end
1103
1177
 
1104
- # Remove all members in a sorted set within the given scores.
1105
- #
1106
- # @example Remove members with score `>= 5` and `< 100`
1107
- # redis.zremrangebyscore("zset", "5", "(100")
1108
- # # => 2
1109
- # @example Remove members with scores `> 5`
1110
- # redis.zremrangebyscore("zset", "(5", "+inf")
1111
- # # => 2
1178
+ # Determine if a given value is a member of a set.
1112
1179
  #
1113
1180
  # @param [String] key
1114
- # @param [String] min
1115
- # - inclusive minimum score is specified verbatim
1116
- # - exclusive minimum score is specified by prefixing `(`
1117
- # @param [String] max
1118
- # - inclusive maximum score is specified verbatim
1119
- # - exclusive maximum score is specified by prefixing `(`
1120
- # @return [Fixnum] number of members that were removed
1121
- def zremrangebyscore(key, min, max)
1181
+ # @param [String] member
1182
+ # @return [Boolean]
1183
+ def sismember(key, member)
1122
1184
  synchronize do |client|
1123
- client.call [:zremrangebyscore, key, min, max]
1185
+ client.call [:sismember, key, member], &_boolify
1124
1186
  end
1125
1187
  end
1126
1188
 
1127
- # Remove all members in a sorted set within the given indexes.
1128
- #
1129
- # @example Remove first 5 members
1130
- # redis.zremrangebyrank("zset", 0, 4)
1131
- # # => 5
1132
- # @example Remove last 5 members
1133
- # redis.zremrangebyrank("zset", -5, -1)
1134
- # # => 5
1189
+ # Get all the members in a set.
1135
1190
  #
1136
1191
  # @param [String] key
1137
- # @param [Fixnum] start start index
1138
- # @param [Fixnum] stop stop index
1139
- # @return [Fixnum] number of members that were removed
1140
- def zremrangebyrank(key, start, stop)
1192
+ # @return [Array<String>]
1193
+ def smembers(key)
1141
1194
  synchronize do |client|
1142
- client.call [:zremrangebyrank, key, start, stop]
1195
+ client.call [:smembers, key]
1143
1196
  end
1144
1197
  end
1145
1198
 
1146
- # Get the score associated with the given member in a sorted set.
1147
- #
1148
- # @example Get the score for member "a"
1149
- # redis.zscore("zset", "a")
1150
- # # => 32.0
1199
+ # Subtract multiple sets.
1151
1200
  #
1152
- # @param [String] key
1153
- # @param [String] member
1154
- # @return [Float] score of the member
1155
- def zscore(key, member)
1201
+ # @param [String, Array<String>] keys keys pointing to sets to subtract
1202
+ # @return [Array<String>] members in the difference
1203
+ def sdiff(*keys)
1156
1204
  synchronize do |client|
1157
- client.call [:zscore, key, member] do |reply|
1158
- Float(reply) if reply
1159
- end
1205
+ client.call [:sdiff, *keys]
1160
1206
  end
1161
1207
  end
1162
1208
 
1163
- # Intersect multiple sorted sets and store the resulting sorted set in a new
1164
- # key.
1165
- #
1166
- # @example Compute the intersection of `2*zsetA` with `1*zsetB`, summing their scores
1167
- # redis.zinterstore("zsetC", ["zsetA", "zsetB"], :weights => [2.0, 1.0], :aggregate => "sum")
1168
- # # => 4
1209
+ # Subtract multiple sets and store the resulting set in a key.
1169
1210
  #
1170
1211
  # @param [String] destination destination key
1171
- # @param [Array<String>] keys source keys
1172
- # @param [Hash] options
1173
- # - `:weights => [Float, Float, ...]`: weights to associate with source
1174
- # sorted sets
1175
- # - `:aggregate => String`: aggregate function to use (sum, min, max, ...)
1176
- # @return [Fixnum] number of elements in the resulting sorted set
1177
- def zinterstore(destination, keys, options = {})
1178
- args = []
1179
-
1180
- weights = options[:weights]
1181
- args.concat ["WEIGHTS", *weights] if weights
1182
-
1183
- aggregate = options[:aggregate]
1184
- args.concat ["AGGREGATE", aggregate] if aggregate
1185
-
1212
+ # @param [String, Array<String>] keys keys pointing to sets to subtract
1213
+ # @return [Fixnum] number of elements in the resulting set
1214
+ def sdiffstore(destination, *keys)
1186
1215
  synchronize do |client|
1187
- client.call [:zinterstore, destination, keys.size, *(keys + args)]
1216
+ client.call [:sdiffstore, destination, *keys]
1188
1217
  end
1189
1218
  end
1190
1219
 
1191
- # Add multiple sorted sets and store the resulting sorted set in a new key.
1192
- #
1193
- # @example Compute the union of `2*zsetA` with `1*zsetB`, summing their scores
1194
- # redis.zunionstore("zsetC", ["zsetA", "zsetB"], :weights => [2.0, 1.0], :aggregate => "sum")
1195
- # # => 8
1220
+ # Intersect multiple sets.
1196
1221
  #
1197
- # @param [String] destination destination key
1198
- # @param [Array<String>] keys source keys
1199
- # @param [Hash] options
1200
- # - `:weights => [Float, Float, ...]`: weights to associate with source
1201
- # sorted sets
1202
- # - `:aggregate => String`: aggregate function to use (sum, min, max, ...)
1203
- # @return [Fixnum] number of elements in the resulting sorted set
1204
- def zunionstore(destination, keys, options = {})
1205
- args = []
1206
-
1207
- weights = options[:weights]
1208
- args.concat ["WEIGHTS", *weights] if weights
1209
-
1210
- aggregate = options[:aggregate]
1211
- args.concat ["AGGREGATE", aggregate] if aggregate
1212
-
1222
+ # @param [String, Array<String>] keys keys pointing to sets to intersect
1223
+ # @return [Array<String>] members in the intersection
1224
+ def sinter(*keys)
1213
1225
  synchronize do |client|
1214
- client.call [:zunionstore, destination, keys.size, *(keys + args)]
1226
+ client.call [:sinter, *keys]
1215
1227
  end
1216
1228
  end
1217
1229
 
1218
- # Move a key to another database.
1219
- #
1220
- # @example Move a key to another database
1221
- # redis.set "foo", "bar"
1222
- # # => "OK"
1223
- # redis.move "foo", 2
1224
- # # => true
1225
- # redis.exists "foo"
1226
- # # => false
1227
- # redis.select 2
1228
- # # => "OK"
1229
- # redis.exists "foo"
1230
- # # => true
1231
- # resis.get "foo"
1232
- # # => "bar"
1230
+ # Intersect multiple sets and store the resulting set in a key.
1233
1231
  #
1234
- # @param [String] key
1235
- # @param [Fixnum] db
1236
- # @return [Boolean] whether the key was moved or not
1237
- def move(key, db)
1232
+ # @param [String] destination destination key
1233
+ # @param [String, Array<String>] keys keys pointing to sets to intersect
1234
+ # @return [Fixnum] number of elements in the resulting set
1235
+ def sinterstore(destination, *keys)
1238
1236
  synchronize do |client|
1239
- client.call [:move, key, db], &_boolify
1237
+ client.call [:sinterstore, destination, *keys]
1240
1238
  end
1241
1239
  end
1242
1240
 
1243
- # Set the value of a key, only if the key does not exist.
1241
+ # Add multiple sets.
1244
1242
  #
1245
- # @param [String] key
1246
- # @param [String] value
1247
- # @return [Boolean] whether the key was set or not
1248
- def setnx(key, value)
1243
+ # @param [String, Array<String>] keys keys pointing to sets to unify
1244
+ # @return [Array<String>] members in the union
1245
+ def sunion(*keys)
1249
1246
  synchronize do |client|
1250
- client.call [:setnx, key, value], &_boolify
1247
+ client.call [:sunion, *keys]
1251
1248
  end
1252
1249
  end
1253
1250
 
1254
- # Delete one or more keys.
1251
+ # Add multiple sets and store the resulting set in a key.
1255
1252
  #
1256
- # @param [String, Array<String>] keys
1257
- # @return [Fixnum] number of keys that were deleted
1258
- def del(*keys)
1253
+ # @param [String] destination destination key
1254
+ # @param [String, Array<String>] keys keys pointing to sets to unify
1255
+ # @return [Fixnum] number of elements in the resulting set
1256
+ def sunionstore(destination, *keys)
1259
1257
  synchronize do |client|
1260
- client.call [:del, *keys]
1258
+ client.call [:sunionstore, destination, *keys]
1261
1259
  end
1262
1260
  end
1263
1261
 
1264
- # Rename a key. If the new key already exists it is overwritten.
1262
+ # Get the number of members in a sorted set.
1265
1263
  #
1266
- # @param [String] old_name
1267
- # @param [String] new_name
1268
- # @return [String] `OK`
1269
- def rename(old_name, new_name)
1270
- synchronize do |client|
1271
- client.call [:rename, old_name, new_name]
1272
- end
1273
- end
1274
-
1275
- # Rename a key, only if the new key does not exist.
1264
+ # @example
1265
+ # redis.zcard("zset")
1266
+ # # => 4
1276
1267
  #
1277
- # @param [String] old_name
1278
- # @param [String] new_name
1279
- # @return [Boolean] whether the key was renamed or not
1280
- def renamenx(old_name, new_name)
1268
+ # @param [String] key
1269
+ # @return [Fixnum]
1270
+ def zcard(key)
1281
1271
  synchronize do |client|
1282
- client.call [:renamenx, old_name, new_name], &_boolify
1272
+ client.call [:zcard, key]
1283
1273
  end
1284
1274
  end
1285
1275
 
1286
- # Set a key's time to live in seconds.
1276
+ # Add one or more members to a sorted set, or update the score for members
1277
+ # that already exist.
1278
+ #
1279
+ # @example Add a single `[score, member]` pair to a sorted set
1280
+ # redis.zadd("zset", 32.0, "member")
1281
+ # @example Add an array of `[score, member]` pairs to a sorted set
1282
+ # redis.zadd("zset", [[32.0, "a"], [64.0, "b"]])
1287
1283
  #
1288
1284
  # @param [String] key
1289
- # @param [Fixnum] seconds time to live
1290
- # @return [Boolean] whether the timeout was set or not
1291
- def expire(key, seconds)
1285
+ # @param [[Float, String], Array<[Float, String]>] args
1286
+ # - a single `[score, member]` pair
1287
+ # - an array of `[score, member]` pairs
1288
+ #
1289
+ # @return [Boolean, Fixnum]
1290
+ # - `Boolean` when a single pair is specified, holding whether or not it was
1291
+ # **added** to the sorted set
1292
+ # - `Fixnum` when an array of pairs is specified, holding the number of
1293
+ # pairs that were **added** to the sorted set
1294
+ def zadd(key, *args)
1292
1295
  synchronize do |client|
1293
- client.call [:expire, key, seconds], &_boolify
1296
+ if args.size == 1 && args[0].is_a?(Array)
1297
+ # Variadic: return integer
1298
+ client.call [:zadd, key] + args[0]
1299
+ elsif args.size == 2
1300
+ # Single pair: return boolean
1301
+ client.call [:zadd, key, args[0], args[1]], &_boolify
1302
+ else
1303
+ raise ArgumentError, "wrong number of arguments"
1304
+ end
1294
1305
  end
1295
1306
  end
1296
1307
 
1297
- # Set a key's time to live in milliseconds.
1308
+ # Increment the score of a member in a sorted set.
1309
+ #
1310
+ # @example
1311
+ # redis.zincrby("zset", 32.0, "a")
1312
+ # # => 64.0
1298
1313
  #
1299
1314
  # @param [String] key
1300
- # @param [Fixnum] milliseconds time to live
1301
- # @return [Boolean] whether the timeout was set or not
1302
- def pexpire(key, milliseconds)
1315
+ # @param [Float] increment
1316
+ # @param [String] member
1317
+ # @return [Float] score of the member after incrementing it
1318
+ def zincrby(key, increment, member)
1303
1319
  synchronize do |client|
1304
- client.call [:pexpire, key, milliseconds], &_boolify
1320
+ client.call [:zincrby, key, increment, member] do |reply|
1321
+ Float(reply) if reply
1322
+ end
1305
1323
  end
1306
1324
  end
1307
1325
 
1308
- # Remove the expiration from a key.
1326
+ # Remove one or more members from a sorted set.
1327
+ #
1328
+ # @example Remove a single member from a sorted set
1329
+ # redis.zrem("zset", "a")
1330
+ # @example Remove an array of members from a sorted set
1331
+ # redis.zrem("zset", ["a", "b"])
1309
1332
  #
1310
1333
  # @param [String] key
1311
- # @return [Boolean] whether the timeout was removed or not
1312
- def persist(key)
1313
- synchronize do |client|
1314
- client.call [:persist, key], &_boolify
1315
- end
1316
- end
1317
-
1318
- # Get the time to live (in seconds) for a key.
1334
+ # @param [String, Array<String>] member
1335
+ # - a single member
1336
+ # - an array of members
1319
1337
  #
1320
- # @param [String] key
1321
- # @return [Fixnum] remaining time to live in seconds, or -1 if the
1322
- # key does not exist or does not have a timeout
1323
- def ttl(key)
1338
+ # @return [Boolean, Fixnum]
1339
+ # - `Boolean` when a single member is specified, holding whether or not it
1340
+ # was removed from the sorted set
1341
+ # - `Fixnum` when an array of pairs is specified, holding the number of
1342
+ # members that were removed to the sorted set
1343
+ def zrem(key, member)
1324
1344
  synchronize do |client|
1325
- client.call [:ttl, key]
1345
+ client.call [:zrem, key, member] do |reply|
1346
+ if member.is_a? Array
1347
+ # Variadic: return integer
1348
+ reply
1349
+ else
1350
+ # Single argument: return boolean
1351
+ _boolify.call(reply)
1352
+ end
1353
+ end
1326
1354
  end
1327
1355
  end
1328
1356
 
1329
- # Get the time to live (in milliseconds) for a key.
1357
+ # Get the score associated with the given member in a sorted set.
1358
+ #
1359
+ # @example Get the score for member "a"
1360
+ # redis.zscore("zset", "a")
1361
+ # # => 32.0
1330
1362
  #
1331
1363
  # @param [String] key
1332
- # @return [Fixnum] remaining time to live in milliseconds, or -1 if the
1333
- # key does not exist or does not have a timeout
1334
- def pttl(key)
1364
+ # @param [String] member
1365
+ # @return [Float] score of the member
1366
+ def zscore(key, member)
1335
1367
  synchronize do |client|
1336
- client.call [:pttl, key]
1368
+ client.call [:zscore, key, member] do |reply|
1369
+ Float(reply) if reply
1370
+ end
1337
1371
  end
1338
1372
  end
1339
1373
 
1340
- # Set the expiration for a key as a UNIX timestamp.
1374
+ # Return a range of members in a sorted set, by index.
1375
+ #
1376
+ # @example Retrieve all members from a sorted set
1377
+ # redis.zrange("zset", 0, -1)
1378
+ # # => ["a", "b"]
1379
+ # @example Retrieve all members and their scores from a sorted set
1380
+ # redis.zrange("zset", 0, -1, :with_scores => true)
1381
+ # # => [["a", 32.0], ["b", 64.0]]
1341
1382
  #
1342
1383
  # @param [String] key
1343
- # @param [Fixnum] unix_time expiry time specified as a UNIX timestamp
1344
- # @return [Boolean] whether the timeout was set or not
1345
- def expireat(key, unix_time)
1384
+ # @param [Fixnum] start start index
1385
+ # @param [Fixnum] stop stop index
1386
+ # @param [Hash] options
1387
+ # - `:with_scores => true`: include scores in output
1388
+ #
1389
+ # @return [Array<String>, Array<[String, Float]>]
1390
+ # - when `:with_scores` is not specified, an array of members
1391
+ # - when `:with_scores` is specified, an array with `[member, score]` pairs
1392
+ def zrange(key, start, stop, options = {})
1393
+ args = []
1394
+
1395
+ with_scores = options[:with_scores] || options[:withscores]
1396
+ args << "WITHSCORES" if with_scores
1397
+
1346
1398
  synchronize do |client|
1347
- client.call [:expireat, key, unix_time], &_boolify
1399
+ client.call [:zrange, key, start, stop, *args] do |reply|
1400
+ if with_scores
1401
+ if reply
1402
+ reply.each_slice(2).map do |member, score|
1403
+ [member, Float(score)]
1404
+ end
1405
+ end
1406
+ else
1407
+ reply
1408
+ end
1409
+ end
1348
1410
  end
1349
1411
  end
1350
1412
 
1351
- # Set the expiration for a key as number of milliseconds from UNIX Epoch.
1413
+ # Return a range of members in a sorted set, by index, with scores ordered
1414
+ # from high to low.
1352
1415
  #
1353
- # @param [String] key
1354
- # @param [Fixnum] ms_unix_time expiry time specified as number of milliseconds from UNIX Epoch.
1355
- # @return [Boolean] whether the timeout was set or not
1356
- def pexpireat(key, ms_unix_time)
1416
+ # @example Retrieve all members from a sorted set
1417
+ # redis.zrevrange("zset", 0, -1)
1418
+ # # => ["b", "a"]
1419
+ # @example Retrieve all members and their scores from a sorted set
1420
+ # redis.zrevrange("zset", 0, -1, :with_scores => true)
1421
+ # # => [["b", 64.0], ["a", 32.0]]
1422
+ #
1423
+ # @see #zrange
1424
+ def zrevrange(key, start, stop, options = {})
1425
+ args = []
1426
+
1427
+ with_scores = options[:with_scores] || options[:withscores]
1428
+ args << "WITHSCORES" if with_scores
1429
+
1357
1430
  synchronize do |client|
1358
- client.call [:pexpireat, key, ms_unix_time], &_boolify
1431
+ client.call [:zrevrange, key, start, stop, *args] do |reply|
1432
+ if with_scores
1433
+ if reply
1434
+ reply.each_slice(2).map do |member, score|
1435
+ [member, Float(score)]
1436
+ end
1437
+ end
1438
+ else
1439
+ reply
1440
+ end
1441
+ end
1359
1442
  end
1360
1443
  end
1361
- # Set the string value of a hash field.
1444
+
1445
+ # Determine the index of a member in a sorted set.
1362
1446
  #
1363
1447
  # @param [String] key
1364
- # @param [String] field
1365
- # @param [String] value
1366
- # @return [Boolean] whether or not the field was **added** to the hash
1367
- def hset(key, field, value)
1448
+ # @param [String] member
1449
+ # @return [Fixnum]
1450
+ def zrank(key, member)
1368
1451
  synchronize do |client|
1369
- client.call [:hset, key, field, value], &_boolify
1452
+ client.call [:zrank, key, member]
1370
1453
  end
1371
1454
  end
1372
1455
 
1373
- # Set the value of a hash field, only if the field does not exist.
1456
+ # Determine the index of a member in a sorted set, with scores ordered from
1457
+ # high to low.
1374
1458
  #
1375
1459
  # @param [String] key
1376
- # @param [String] field
1377
- # @param [String] value
1378
- # @return [Boolean] whether or not the field was **added** to the hash
1379
- def hsetnx(key, field, value)
1460
+ # @param [String] member
1461
+ # @return [Fixnum]
1462
+ def zrevrank(key, member)
1380
1463
  synchronize do |client|
1381
- client.call [:hsetnx, key, field, value], &_boolify
1464
+ client.call [:zrevrank, key, member]
1382
1465
  end
1383
1466
  end
1384
1467
 
1385
- # Set one or more hash values.
1468
+ # Remove all members in a sorted set within the given indexes.
1386
1469
  #
1387
- # @example
1388
- # redis.hmset("hash", "f1", "v1", "f2", "v2")
1389
- # # => "OK"
1470
+ # @example Remove first 5 members
1471
+ # redis.zremrangebyrank("zset", 0, 4)
1472
+ # # => 5
1473
+ # @example Remove last 5 members
1474
+ # redis.zremrangebyrank("zset", -5, -1)
1475
+ # # => 5
1390
1476
  #
1391
1477
  # @param [String] key
1392
- # @param [Array<String>] attrs array of fields and values
1393
- # @return `"OK"`
1394
- #
1395
- # @see #mapped_hmset
1396
- def hmset(key, *attrs)
1478
+ # @param [Fixnum] start start index
1479
+ # @param [Fixnum] stop stop index
1480
+ # @return [Fixnum] number of members that were removed
1481
+ def zremrangebyrank(key, start, stop)
1397
1482
  synchronize do |client|
1398
- client.call [:hmset, key, *attrs]
1483
+ client.call [:zremrangebyrank, key, start, stop]
1399
1484
  end
1400
1485
  end
1401
1486
 
1402
- # Set one or more hash values.
1487
+ # Return a range of members in a sorted set, by score.
1403
1488
  #
1404
- # @example
1405
- # redis.hmset("hash", { "f1" => "v1", "f2" => "v2" })
1406
- # # => "OK"
1489
+ # @example Retrieve members with score `>= 5` and `< 100`
1490
+ # redis.zrangebyscore("zset", "5", "(100")
1491
+ # # => ["a", "b"]
1492
+ # @example Retrieve the first 2 members with score `>= 0`
1493
+ # redis.zrangebyscore("zset", "0", "+inf", :limit => [0, 2])
1494
+ # # => ["a", "b"]
1495
+ # @example Retrieve members and their scores with scores `> 5`
1496
+ # redis.zrangebyscore("zset", "(5", "+inf", :with_scores => true)
1497
+ # # => [["a", 32.0], ["b", 64.0]]
1407
1498
  #
1408
1499
  # @param [String] key
1409
- # @param [Hash] hash fields mapping to values
1410
- # @return `"OK"`
1500
+ # @param [String] min
1501
+ # - inclusive minimum score is specified verbatim
1502
+ # - exclusive minimum score is specified by prefixing `(`
1503
+ # @param [String] max
1504
+ # - inclusive maximum score is specified verbatim
1505
+ # - exclusive maximum score is specified by prefixing `(`
1506
+ # @param [Hash] options
1507
+ # - `:with_scores => true`: include scores in output
1508
+ # - `:limit => [offset, count]`: skip `offset` members, return a maximum of
1509
+ # `count` members
1411
1510
  #
1412
- # @see #hmset
1413
- def mapped_hmset(key, hash)
1414
- hmset(key, *hash.to_a.flatten)
1415
- end
1511
+ # @return [Array<String>, Array<[String, Float]>]
1512
+ # - when `:with_scores` is not specified, an array of members
1513
+ # - when `:with_scores` is specified, an array with `[member, score]` pairs
1514
+ def zrangebyscore(key, min, max, options = {})
1515
+ args = []
1516
+
1517
+ with_scores = options[:with_scores] || options[:withscores]
1518
+ args.concat ["WITHSCORES"] if with_scores
1519
+
1520
+ limit = options[:limit]
1521
+ args.concat ["LIMIT", *limit] if limit
1416
1522
 
1417
- # Get the values of all the given hash fields.
1418
- #
1419
- # @example
1420
- # redis.hmget("hash", "f1", "f2")
1421
- # # => ["v1", "v2"]
1422
- #
1423
- # @param [String] key
1424
- # @param [Array<String>] fields array of fields
1425
- # @return [Array<String>] an array of values for the specified fields
1426
- #
1427
- # @see #mapped_hmget
1428
- def hmget(key, *fields, &blk)
1429
1523
  synchronize do |client|
1430
- client.call [:hmget, key, *fields], &blk
1524
+ client.call [:zrangebyscore, key, min, max, *args] do |reply|
1525
+ if with_scores
1526
+ if reply
1527
+ reply.each_slice(2).map do |member, score|
1528
+ [member, Float(score)]
1529
+ end
1530
+ end
1531
+ else
1532
+ reply
1533
+ end
1534
+ end
1431
1535
  end
1432
1536
  end
1433
1537
 
1434
- # Get the values of all the given hash fields.
1435
- #
1436
- # @example
1437
- # redis.hmget("hash", "f1", "f2")
1438
- # # => { "f1" => "v1", "f2" => "v2" }
1538
+ # Return a range of members in a sorted set, by score, with scores ordered
1539
+ # from high to low.
1439
1540
  #
1440
- # @param [String] key
1441
- # @param [Array<String>] fields array of fields
1442
- # @return [Hash] a hash mapping the specified fields to their values
1541
+ # @example Retrieve members with score `< 100` and `>= 5`
1542
+ # redis.zrevrangebyscore("zset", "(100", "5")
1543
+ # # => ["b", "a"]
1544
+ # @example Retrieve the first 2 members with score `<= 0`
1545
+ # redis.zrevrangebyscore("zset", "0", "-inf", :limit => [0, 2])
1546
+ # # => ["b", "a"]
1547
+ # @example Retrieve members and their scores with scores `> 5`
1548
+ # redis.zrevrangebyscore("zset", "+inf", "(5", :with_scores => true)
1549
+ # # => [["b", 64.0], ["a", 32.0]]
1443
1550
  #
1444
- # @see #hmget
1445
- def mapped_hmget(key, *fields)
1446
- hmget(key, *fields) do |reply|
1447
- if reply.kind_of?(Array)
1448
- hash = Hash.new
1449
- fields.zip(reply).each do |field, value|
1450
- hash[field] = value
1551
+ # @see #zrangebyscore
1552
+ def zrevrangebyscore(key, max, min, options = {})
1553
+ args = []
1554
+
1555
+ with_scores = options[:with_scores] || options[:withscores]
1556
+ args.concat ["WITHSCORES"] if with_scores
1557
+
1558
+ limit = options[:limit]
1559
+ args.concat ["LIMIT", *limit] if limit
1560
+
1561
+ synchronize do |client|
1562
+ client.call [:zrevrangebyscore, key, max, min, *args] do |reply|
1563
+ if with_scores
1564
+ if reply
1565
+ reply.each_slice(2).map do |member, score|
1566
+ [member, Float(score)]
1567
+ end
1568
+ end
1569
+ else
1570
+ reply
1451
1571
  end
1452
- hash
1453
- else
1454
- reply
1455
1572
  end
1456
1573
  end
1457
1574
  end
1458
1575
 
1459
- # Get the number of fields in a hash.
1460
- #
1461
- # @param [String] key
1462
- # @return [Fixnum] number of fields in the hash
1463
- def hlen(key)
1464
- synchronize do |client|
1465
- client.call [:hlen, key]
1466
- end
1467
- end
1468
-
1469
- # Get all the values in a hash.
1576
+ # Remove all members in a sorted set within the given scores.
1470
1577
  #
1471
- # @param [String] key
1472
- # @return [Array<String>]
1473
- def hvals(key)
1474
- synchronize do |client|
1475
- client.call [:hvals, key]
1476
- end
1477
- end
1478
-
1479
- # Increment the integer value of a hash field by the given integer number.
1578
+ # @example Remove members with score `>= 5` and `< 100`
1579
+ # redis.zremrangebyscore("zset", "5", "(100")
1580
+ # # => 2
1581
+ # @example Remove members with scores `> 5`
1582
+ # redis.zremrangebyscore("zset", "(5", "+inf")
1583
+ # # => 2
1480
1584
  #
1481
1585
  # @param [String] key
1482
- # @param [String] field
1483
- # @param [Fixnum] increment
1484
- # @return [Fixnum] value of the field after incrementing it
1485
- def hincrby(key, field, increment)
1586
+ # @param [String] min
1587
+ # - inclusive minimum score is specified verbatim
1588
+ # - exclusive minimum score is specified by prefixing `(`
1589
+ # @param [String] max
1590
+ # - inclusive maximum score is specified verbatim
1591
+ # - exclusive maximum score is specified by prefixing `(`
1592
+ # @return [Fixnum] number of members that were removed
1593
+ def zremrangebyscore(key, min, max)
1486
1594
  synchronize do |client|
1487
- client.call [:hincrby, key, field, increment]
1595
+ client.call [:zremrangebyscore, key, min, max]
1488
1596
  end
1489
1597
  end
1490
1598
 
1491
- # Increment the numeric value of a hash field by the given float number.
1599
+ # Count the members in a sorted set with scores within the given values.
1492
1600
  #
1493
- # @param [String] key
1494
- # @param [String] field
1495
- # @param [Float] increment
1496
- # @return [Float] value of the field after incrementing it
1497
- def hincrbyfloat(key, field, increment)
1498
- synchronize do |client|
1499
- client.call [:hincrbyfloat, key, field, increment] do |reply|
1500
- Float(reply) if reply
1501
- end
1502
- end
1503
- end
1504
-
1505
- # Determine if a hash field exists.
1601
+ # @example Count members with score `>= 5` and `< 100`
1602
+ # redis.zcount("zset", "5", "(100")
1603
+ # # => 2
1604
+ # @example Count members with scores `> 5`
1605
+ # redis.zcount("zset", "(5", "+inf")
1606
+ # # => 2
1506
1607
  #
1507
1608
  # @param [String] key
1508
- # @param [String] field
1509
- # @return [Boolean] whether or not the field exists in the hash
1510
- def hexists(key, field)
1609
+ # @param [String] min
1610
+ # - inclusive minimum score is specified verbatim
1611
+ # - exclusive minimum score is specified by prefixing `(`
1612
+ # @param [String] max
1613
+ # - inclusive maximum score is specified verbatim
1614
+ # - exclusive maximum score is specified by prefixing `(`
1615
+ # @return [Fixnum] number of members in within the specified range
1616
+ def zcount(key, min, max)
1511
1617
  synchronize do |client|
1512
- client.call [:hexists, key, field], &_boolify
1618
+ client.call [:zcount, key, min, max]
1513
1619
  end
1514
1620
  end
1515
1621
 
1516
- # Listen for all requests received by the server in real time.
1622
+ # Intersect multiple sorted sets and store the resulting sorted set in a new
1623
+ # key.
1517
1624
  #
1518
- # There is no way to interrupt this command.
1625
+ # @example Compute the intersection of `2*zsetA` with `1*zsetB`, summing their scores
1626
+ # redis.zinterstore("zsetC", ["zsetA", "zsetB"], :weights => [2.0, 1.0], :aggregate => "sum")
1627
+ # # => 4
1519
1628
  #
1520
- # @yield a block to be called for every line of output
1521
- # @yieldparam [String] line timestamp and command that was executed
1522
- def monitor(&block)
1523
- synchronize do |client|
1524
- client.call_loop([:monitor], &block)
1525
- end
1526
- end
1629
+ # @param [String] destination destination key
1630
+ # @param [Array<String>] keys source keys
1631
+ # @param [Hash] options
1632
+ # - `:weights => [Float, Float, ...]`: weights to associate with source
1633
+ # sorted sets
1634
+ # - `:aggregate => String`: aggregate function to use (sum, min, max, ...)
1635
+ # @return [Fixnum] number of elements in the resulting sorted set
1636
+ def zinterstore(destination, keys, options = {})
1637
+ args = []
1527
1638
 
1528
- def debug(*args)
1529
- synchronize do |client|
1530
- client.call [:debug, *args]
1531
- end
1532
- end
1639
+ weights = options[:weights]
1640
+ args.concat ["WEIGHTS", *weights] if weights
1533
1641
 
1534
- def object(*args)
1535
- synchronize do |client|
1536
- client.call [:object, *args]
1537
- end
1538
- end
1642
+ aggregate = options[:aggregate]
1643
+ args.concat ["AGGREGATE", aggregate] if aggregate
1539
1644
 
1540
- # Internal command used for replication.
1541
- def sync
1542
1645
  synchronize do |client|
1543
- client.call [:sync]
1646
+ client.call [:zinterstore, destination, keys.size, *(keys + args)]
1544
1647
  end
1545
1648
  end
1546
1649
 
1547
- # Set the string value of a key.
1650
+ # Add multiple sorted sets and store the resulting sorted set in a new key.
1548
1651
  #
1549
- # @param [String] key
1550
- # @param [String] value
1551
- # @return `"OK"`
1552
- def set(key, value)
1553
- synchronize do |client|
1554
- client.call [:set, key, value]
1555
- end
1556
- end
1652
+ # @example Compute the union of `2*zsetA` with `1*zsetB`, summing their scores
1653
+ # redis.zunionstore("zsetC", ["zsetA", "zsetB"], :weights => [2.0, 1.0], :aggregate => "sum")
1654
+ # # => 8
1655
+ #
1656
+ # @param [String] destination destination key
1657
+ # @param [Array<String>] keys source keys
1658
+ # @param [Hash] options
1659
+ # - `:weights => [Float, Float, ...]`: weights to associate with source
1660
+ # sorted sets
1661
+ # - `:aggregate => String`: aggregate function to use (sum, min, max, ...)
1662
+ # @return [Fixnum] number of elements in the resulting sorted set
1663
+ def zunionstore(destination, keys, options = {})
1664
+ args = []
1557
1665
 
1558
- alias :[]= :set
1666
+ weights = options[:weights]
1667
+ args.concat ["WEIGHTS", *weights] if weights
1668
+
1669
+ aggregate = options[:aggregate]
1670
+ args.concat ["AGGREGATE", aggregate] if aggregate
1559
1671
 
1560
- # Sets or clears the bit at offset in the string value stored at key.
1561
- #
1562
- # @param [String] key
1563
- # @param [Fixnum] offset bit offset
1564
- # @param [Fixnum] value bit value `0` or `1`
1565
- # @return [Fixnum] the original bit value stored at `offset`
1566
- def setbit(key, offset, value)
1567
1672
  synchronize do |client|
1568
- client.call [:setbit, key, offset, value]
1673
+ client.call [:zunionstore, destination, keys.size, *(keys + args)]
1569
1674
  end
1570
1675
  end
1571
1676
 
1572
- # Set the time to live in seconds of a key.
1677
+ # Get the number of fields in a hash.
1573
1678
  #
1574
1679
  # @param [String] key
1575
- # @param [Fixnum] ttl
1576
- # @param [String] value
1577
- # @return `"OK"`
1578
- def setex(key, ttl, value)
1680
+ # @return [Fixnum] number of fields in the hash
1681
+ def hlen(key)
1579
1682
  synchronize do |client|
1580
- client.call [:setex, key, ttl, value]
1683
+ client.call [:hlen, key]
1581
1684
  end
1582
1685
  end
1583
1686
 
1584
- # Set the time to live in milliseconds of a key.
1687
+ # Set the string value of a hash field.
1585
1688
  #
1586
1689
  # @param [String] key
1587
- # @param [Fixnum] ttl
1690
+ # @param [String] field
1588
1691
  # @param [String] value
1589
- # @return `"OK"`
1590
- def psetex(key, ttl, value)
1692
+ # @return [Boolean] whether or not the field was **added** to the hash
1693
+ def hset(key, field, value)
1591
1694
  synchronize do |client|
1592
- client.call [:psetex, key, ttl, value]
1695
+ client.call [:hset, key, field, value], &_boolify
1593
1696
  end
1594
1697
  end
1595
1698
 
1596
- # Overwrite part of a string at key starting at the specified offset.
1699
+ # Set the value of a hash field, only if the field does not exist.
1597
1700
  #
1598
1701
  # @param [String] key
1599
- # @param [Fixnum] offset byte offset
1702
+ # @param [String] field
1600
1703
  # @param [String] value
1601
- # @return [Fixnum] length of the string after it was modified
1602
- def setrange(key, offset, value)
1704
+ # @return [Boolean] whether or not the field was **added** to the hash
1705
+ def hsetnx(key, field, value)
1603
1706
  synchronize do |client|
1604
- client.call [:setrange, key, offset, value]
1707
+ client.call [:hsetnx, key, field, value], &_boolify
1605
1708
  end
1606
1709
  end
1607
1710
 
1608
- # Set one or more values.
1711
+ # Set one or more hash values.
1609
1712
  #
1610
1713
  # @example
1611
- # redis.mset("key1", "v1", "key2", "v2")
1714
+ # redis.hmset("hash", "f1", "v1", "f2", "v2")
1612
1715
  # # => "OK"
1613
1716
  #
1614
- # @param [Array<String>] args array of keys and values
1717
+ # @param [String] key
1718
+ # @param [Array<String>] attrs array of fields and values
1615
1719
  # @return `"OK"`
1616
1720
  #
1617
- # @see #mapped_mset
1618
- def mset(*args)
1721
+ # @see #mapped_hmset
1722
+ def hmset(key, *attrs)
1619
1723
  synchronize do |client|
1620
- client.call [:mset, *args]
1724
+ client.call [:hmset, key, *attrs]
1621
1725
  end
1622
1726
  end
1623
1727
 
1624
- # Set one or more values.
1728
+ # Set one or more hash values.
1625
1729
  #
1626
1730
  # @example
1627
- # redis.mapped_mset({ "f1" => "v1", "f2" => "v2" })
1731
+ # redis.hmset("hash", { "f1" => "v1", "f2" => "v2" })
1628
1732
  # # => "OK"
1629
1733
  #
1630
- # @param [Hash] hash keys mapping to values
1734
+ # @param [String] key
1735
+ # @param [Hash] hash fields mapping to values
1631
1736
  # @return `"OK"`
1632
1737
  #
1633
- # @see #mset
1634
- def mapped_mset(hash)
1635
- mset(*hash.to_a.flatten)
1738
+ # @see #hmset
1739
+ def mapped_hmset(key, hash)
1740
+ hmset(key, *hash.to_a.flatten)
1636
1741
  end
1637
1742
 
1638
- # Set one or more values, only if none of the keys exist.
1639
- #
1640
- # @example
1641
- # redis.msetnx("key1", "v1", "key2", "v2")
1642
- # # => true
1643
- #
1644
- # @param [Array<String>] args array of keys and values
1645
- # @return [Boolean] whether or not all values were set
1743
+ # Get the value of a hash field.
1646
1744
  #
1647
- # @see #mapped_msetnx
1648
- def msetnx(*args)
1745
+ # @param [String] key
1746
+ # @param [String] field
1747
+ # @return [String]
1748
+ def hget(key, field)
1649
1749
  synchronize do |client|
1650
- client.call [:msetnx, *args], &_boolify
1750
+ client.call [:hget, key, field]
1651
1751
  end
1652
1752
  end
1653
1753
 
1654
- # Set one or more values, only if none of the keys exist.
1754
+ # Get the values of all the given hash fields.
1655
1755
  #
1656
1756
  # @example
1657
- # redis.msetnx({ "key1" => "v1", "key2" => "v2" })
1658
- # # => true
1757
+ # redis.hmget("hash", "f1", "f2")
1758
+ # # => ["v1", "v2"]
1659
1759
  #
1660
- # @param [Hash] hash keys mapping to values
1661
- # @return [Boolean] whether or not all values were set
1760
+ # @param [String] key
1761
+ # @param [Array<String>] fields array of fields
1762
+ # @return [Array<String>] an array of values for the specified fields
1662
1763
  #
1663
- # @see #msetnx
1664
- def mapped_msetnx(hash)
1665
- msetnx(*hash.to_a.flatten)
1764
+ # @see #mapped_hmget
1765
+ def hmget(key, *fields, &blk)
1766
+ synchronize do |client|
1767
+ client.call [:hmget, key, *fields], &blk
1768
+ end
1666
1769
  end
1667
1770
 
1668
- # Get the values of all the given keys.
1771
+ # Get the values of all the given hash fields.
1669
1772
  #
1670
1773
  # @example
1671
- # redis.mapped_mget("key1", "key1")
1672
- # # => { "key1" => "v1", "key2" => "v2" }
1774
+ # redis.hmget("hash", "f1", "f2")
1775
+ # # => { "f1" => "v1", "f2" => "v2" }
1673
1776
  #
1674
- # @param [Array<String>] keys array of keys
1675
- # @return [Hash] a hash mapping the specified keys to their values
1777
+ # @param [String] key
1778
+ # @param [Array<String>] fields array of fields
1779
+ # @return [Hash] a hash mapping the specified fields to their values
1676
1780
  #
1677
- # @see #mget
1678
- def mapped_mget(*keys)
1679
- mget(*keys) do |reply|
1781
+ # @see #hmget
1782
+ def mapped_hmget(key, *fields)
1783
+ hmget(key, *fields) do |reply|
1680
1784
  if reply.kind_of?(Array)
1681
1785
  hash = Hash.new
1682
- keys.zip(reply).each do |field, value|
1786
+ fields.zip(reply).each do |field, value|
1683
1787
  hash[field] = value
1684
1788
  end
1685
1789
  hash
@@ -1689,191 +1793,124 @@ class Redis
1689
1793
  end
1690
1794
  end
1691
1795
 
1692
- # Sort the elements in a list, set or sorted set.
1693
- #
1694
- # @example Retrieve the first 2 elements from an alphabetically sorted "list"
1695
- # redis.sort("list", :order => "alpha", :limit => [0, 2])
1696
- # # => ["a", "b"]
1697
- # @example Store an alphabetically descending list in "target"
1698
- # redis.sort("list", :order => "desc alpha", :store => "target")
1699
- # # => 26
1796
+ # Delete one or more hash fields.
1700
1797
  #
1701
1798
  # @param [String] key
1702
- # @param [Hash] options
1703
- # - `:by => String`: use external key to sort elements by
1704
- # - `:limit => [offset, count]`: skip `offset` elements, return a maximum
1705
- # of `count` elements
1706
- # - `:get => [String, Array<String>]`: single key or array of keys to
1707
- # retrieve per element in the result
1708
- # - `:order => String`: combination of `ASC`, `DESC` and optionally `ALPHA`
1709
- # - `:store => String`: key to store the result at
1710
- #
1711
- # @return [Array<String>, Array<Array<String>>, Fixnum]
1712
- # - when `:get` is not specified, or holds a single element, an array of elements
1713
- # - when `:get` is specified, and holds more than one element, an array of
1714
- # elements where every element is an array with the result for every
1715
- # element specified in `:get`
1716
- # - when `:store` is specified, the number of elements in the stored result
1717
- def sort(key, options = {})
1718
- args = []
1719
-
1720
- by = options[:by]
1721
- args.concat ["BY", by] if by
1722
-
1723
- limit = options[:limit]
1724
- args.concat ["LIMIT", *limit] if limit
1725
-
1726
- get = Array(options[:get])
1727
- args.concat ["GET"].product(get).flatten unless get.empty?
1728
-
1729
- order = options[:order]
1730
- args.concat order.split(" ") if order
1731
-
1732
- store = options[:store]
1733
- args.concat ["STORE", store] if store
1734
-
1799
+ # @param [String, Array<String>] field
1800
+ # @return [Fixnum] the number of fields that were removed from the hash
1801
+ def hdel(key, field)
1735
1802
  synchronize do |client|
1736
- client.call [:sort, key, *args] do |reply|
1737
- if get.size > 1
1738
- if reply
1739
- reply.each_slice(get.size).to_a
1740
- end
1741
- else
1742
- reply
1743
- end
1744
- end
1803
+ client.call [:hdel, key, field]
1745
1804
  end
1746
1805
  end
1747
1806
 
1748
- # Increment the integer value of a key by one.
1749
- #
1750
- # @example
1751
- # redis.incr("value")
1752
- # # => 6
1807
+ # Determine if a hash field exists.
1753
1808
  #
1754
1809
  # @param [String] key
1755
- # @return [Fixnum] value after incrementing it
1756
- def incr(key)
1810
+ # @param [String] field
1811
+ # @return [Boolean] whether or not the field exists in the hash
1812
+ def hexists(key, field)
1757
1813
  synchronize do |client|
1758
- client.call [:incr, key]
1814
+ client.call [:hexists, key, field], &_boolify
1759
1815
  end
1760
1816
  end
1761
1817
 
1762
- # Increment the integer value of a key by the given integer number.
1763
- #
1764
- # @example
1765
- # redis.incrby("value", 5)
1766
- # # => 10
1818
+ # Increment the integer value of a hash field by the given integer number.
1767
1819
  #
1768
1820
  # @param [String] key
1821
+ # @param [String] field
1769
1822
  # @param [Fixnum] increment
1770
- # @return [Fixnum] value after incrementing it
1771
- def incrby(key, increment)
1823
+ # @return [Fixnum] value of the field after incrementing it
1824
+ def hincrby(key, field, increment)
1772
1825
  synchronize do |client|
1773
- client.call [:incrby, key, increment]
1826
+ client.call [:hincrby, key, field, increment]
1774
1827
  end
1775
1828
  end
1776
1829
 
1777
- # Increment the numeric value of a key by the given float number.
1778
- #
1779
- # @example
1780
- # redis.incrbyfloat("value", 1.23)
1781
- # # => 1.23
1830
+ # Increment the numeric value of a hash field by the given float number.
1782
1831
  #
1783
1832
  # @param [String] key
1833
+ # @param [String] field
1784
1834
  # @param [Float] increment
1785
- # @return [Float] value after incrementing it
1786
- def incrbyfloat(key, increment)
1835
+ # @return [Float] value of the field after incrementing it
1836
+ def hincrbyfloat(key, field, increment)
1787
1837
  synchronize do |client|
1788
- client.call [:incrbyfloat, key, increment] do |reply|
1838
+ client.call [:hincrbyfloat, key, field, increment] do |reply|
1789
1839
  Float(reply) if reply
1790
1840
  end
1791
1841
  end
1792
1842
  end
1793
1843
 
1794
- # Decrement the integer value of a key by one.
1795
- #
1796
- # @example
1797
- # redis.decr("value")
1798
- # # => 4
1844
+ # Get all the fields in a hash.
1799
1845
  #
1800
1846
  # @param [String] key
1801
- # @return [Fixnum] value after decrementing it
1802
- def decr(key)
1847
+ # @return [Array<String>]
1848
+ def hkeys(key)
1803
1849
  synchronize do |client|
1804
- client.call [:decr, key]
1850
+ client.call [:hkeys, key]
1805
1851
  end
1806
1852
  end
1807
1853
 
1808
- # Decrement the integer value of a key by the given number.
1809
- #
1810
- # @example
1811
- # redis.decrby("value", 5)
1812
- # # => 0
1854
+ # Get all the values in a hash.
1813
1855
  #
1814
1856
  # @param [String] key
1815
- # @param [Fixnum] decrement
1816
- # @return [Fixnum] value after decrementing it
1817
- def decrby(key, decrement)
1857
+ # @return [Array<String>]
1858
+ def hvals(key)
1818
1859
  synchronize do |client|
1819
- client.call [:decrby, key, decrement]
1860
+ client.call [:hvals, key]
1820
1861
  end
1821
1862
  end
1822
1863
 
1823
- # Determine the type stored at key.
1864
+ # Get all the fields and values in a hash.
1824
1865
  #
1825
1866
  # @param [String] key
1826
- # @return [String] `string`, `list`, `set`, `zset`, `hash` or `none`
1827
- def type(key)
1867
+ # @return [Hash<String, String>]
1868
+ def hgetall(key)
1828
1869
  synchronize do |client|
1829
- client.call [:type, key]
1870
+ client.call [:hgetall, key], &_hashify
1830
1871
  end
1831
1872
  end
1832
1873
 
1833
- # Close the connection.
1834
- #
1835
- # @return [String] `OK`
1836
- def quit
1874
+ # Post a message to a channel.
1875
+ def publish(channel, message)
1837
1876
  synchronize do |client|
1838
- begin
1839
- client.call [:quit]
1840
- rescue ConnectionError
1841
- ensure
1842
- client.disconnect
1843
- end
1877
+ client.call [:publish, channel, message]
1844
1878
  end
1845
1879
  end
1846
1880
 
1847
- # Synchronously save the dataset to disk and then shut down the server.
1848
- def shutdown
1881
+ def subscribed?
1849
1882
  synchronize do |client|
1850
- client.without_reconnect do
1851
- begin
1852
- client.call [:shutdown]
1853
- rescue ConnectionError
1854
- # This means Redis has probably exited.
1855
- nil
1856
- end
1857
- end
1883
+ client.kind_of? SubscribedClient
1858
1884
  end
1859
1885
  end
1860
1886
 
1861
- # Make the server a slave of another instance, or promote it as master.
1862
- def slaveof(host, port)
1887
+ # Listen for messages published to the given channels.
1888
+ def subscribe(*channels, &block)
1863
1889
  synchronize do |client|
1864
- client.call [:slaveof, host, port]
1890
+ _subscription(:subscribe, channels, block)
1865
1891
  end
1866
1892
  end
1867
1893
 
1868
- def pipelined
1894
+ # Stop listening for messages posted to the given channels.
1895
+ def unsubscribe(*channels)
1869
1896
  synchronize do |client|
1870
- begin
1871
- original, @client = @client, Pipeline.new
1872
- yield(self)
1873
- original.call_pipeline(@client)
1874
- ensure
1875
- @client = original
1876
- end
1897
+ raise RuntimeError, "Can't unsubscribe if not subscribed." unless subscribed?
1898
+ client.unsubscribe(*channels)
1899
+ end
1900
+ end
1901
+
1902
+ # Listen for messages published to channels matching the given patterns.
1903
+ def psubscribe(*channels, &block)
1904
+ synchronize do |client|
1905
+ _subscription(:psubscribe, channels, block)
1906
+ end
1907
+ end
1908
+
1909
+ # Stop listening for messages posted to channels matching the given patterns.
1910
+ def punsubscribe(*channels)
1911
+ synchronize do |client|
1912
+ raise RuntimeError, "Can't unsubscribe if not subscribed." unless subscribed?
1913
+ client.punsubscribe(*channels)
1877
1914
  end
1878
1915
  end
1879
1916
 
@@ -1936,6 +1973,18 @@ class Redis
1936
1973
  end
1937
1974
  end
1938
1975
 
1976
+ def pipelined
1977
+ synchronize do |client|
1978
+ begin
1979
+ original, @client = @client, Pipeline.new
1980
+ yield(self)
1981
+ original.call_pipeline(@client)
1982
+ ensure
1983
+ @client = original
1984
+ end
1985
+ end
1986
+ end
1987
+
1939
1988
  # Mark the start of a transaction block.
1940
1989
  #
1941
1990
  # Passing a block is optional.
@@ -2013,47 +2062,115 @@ class Redis
2013
2062
  end
2014
2063
  end
2015
2064
 
2016
- # Post a message to a channel.
2017
- def publish(channel, message)
2018
- synchronize do |client|
2019
- client.call [:publish, channel, message]
2020
- end
2021
- end
2065
+ # Control remote script registry.
2066
+ #
2067
+ # @example Load a script
2068
+ # sha = redis.script(:load, "return 1")
2069
+ # # => <sha of this script>
2070
+ # @example Check if a script exists
2071
+ # redis.script(:exists, sha)
2072
+ # # => true
2073
+ # @example Check if multiple scripts exist
2074
+ # redis.script(:exists, [sha, other_sha])
2075
+ # # => [true, false]
2076
+ # @example Flush the script registry
2077
+ # redis.script(:flush)
2078
+ # # => "OK"
2079
+ # @example Kill a running script
2080
+ # redis.script(:kill)
2081
+ # # => "OK"
2082
+ #
2083
+ # @param [String] subcommand e.g. `exists`, `flush`, `load`, `kill`
2084
+ # @param [Array<String>] args depends on subcommand
2085
+ # @return [String, Boolean, Array<Boolean>, ...] depends on subcommand
2086
+ #
2087
+ # @see #eval
2088
+ # @see #evalsha
2089
+ def script(subcommand, *args)
2090
+ subcommand = subcommand.to_s.downcase
2022
2091
 
2023
- def subscribed?
2024
- synchronize do |client|
2025
- client.kind_of? SubscribedClient
2026
- end
2027
- end
2092
+ if subcommand == "exists"
2093
+ synchronize do |client|
2094
+ arg = args.first
2028
2095
 
2029
- # Stop listening for messages posted to the given channels.
2030
- def unsubscribe(*channels)
2031
- synchronize do |client|
2032
- raise RuntimeError, "Can't unsubscribe if not subscribed." unless subscribed?
2033
- client.unsubscribe(*channels)
2034
- end
2035
- end
2096
+ client.call [:script, :exists, arg] do |reply|
2097
+ reply = reply.map { |r| _boolify.call(r) }
2036
2098
 
2037
- # Stop listening for messages posted to channels matching the given patterns.
2038
- def punsubscribe(*channels)
2039
- synchronize do |client|
2040
- raise RuntimeError, "Can't unsubscribe if not subscribed." unless subscribed?
2041
- client.punsubscribe(*channels)
2099
+ if arg.is_a?(Array)
2100
+ reply
2101
+ else
2102
+ reply.first
2103
+ end
2104
+ end
2105
+ end
2106
+ else
2107
+ synchronize do |client|
2108
+ client.call [:script, subcommand] + args
2109
+ end
2042
2110
  end
2043
2111
  end
2044
2112
 
2045
- # Listen for messages published to the given channels.
2046
- def subscribe(*channels, &block)
2113
+ def _eval(cmd, args)
2114
+ script = args.shift
2115
+ options = args.pop if args.last.is_a?(Hash)
2116
+ options ||= {}
2117
+
2118
+ keys = args.shift || options[:keys] || []
2119
+ argv = args.shift || options[:argv] || []
2120
+
2047
2121
  synchronize do |client|
2048
- _subscription(:subscribe, channels, block)
2122
+ client.call [cmd, script, keys.length] + keys + argv
2049
2123
  end
2050
2124
  end
2051
2125
 
2052
- # Listen for messages published to channels matching the given patterns.
2053
- def psubscribe(*channels, &block)
2054
- synchronize do |client|
2055
- _subscription(:psubscribe, channels, block)
2056
- end
2126
+ # Evaluate Lua script.
2127
+ #
2128
+ # @example EVAL without KEYS nor ARGV
2129
+ # redis.eval("return 1")
2130
+ # # => 1
2131
+ # @example EVAL with KEYS and ARGV as array arguments
2132
+ # redis.eval("return { KEYS, ARGV }", ["k1", "k2"], ["a1", "a2"])
2133
+ # # => [["k1", "k2"], ["a1", "a2"]]
2134
+ # @example EVAL with KEYS and ARGV in a hash argument
2135
+ # redis.eval("return { KEYS, ARGV }", :keys => ["k1", "k2"], :argv => ["a1", "a2"])
2136
+ # # => [["k1", "k2"], ["a1", "a2"]]
2137
+ #
2138
+ # @param [Array<String>] keys optional array with keys to pass to the script
2139
+ # @param [Array<String>] argv optional array with arguments to pass to the script
2140
+ # @param [Hash] options
2141
+ # - `:keys => Array<String>`: optional array with keys to pass to the script
2142
+ # - `:argv => Array<String>`: optional array with arguments to pass to the script
2143
+ # @return depends on the script
2144
+ #
2145
+ # @see #script
2146
+ # @see #evalsha
2147
+ def eval(*args)
2148
+ _eval(:eval, args)
2149
+ end
2150
+
2151
+ # Evaluate Lua script by its SHA.
2152
+ #
2153
+ # @example EVALSHA without KEYS nor ARGV
2154
+ # redis.evalsha(sha)
2155
+ # # => <depends on script>
2156
+ # @example EVALSHA with KEYS and ARGV as array arguments
2157
+ # redis.evalsha(sha, ["k1", "k2"], ["a1", "a2"])
2158
+ # # => <depends on script>
2159
+ # @example EVALSHA with KEYS and ARGV in a hash argument
2160
+ # redis.evalsha(sha, :keys => ["k1", "k2"], :argv => ["a1", "a2"])
2161
+ # # => <depends on script>
2162
+ #
2163
+ # @param [Array<String>] keys optional array with keys to pass to the script
2164
+ # @param [Array<String>] argv optional array with arguments to pass to the script
2165
+ # @param [Hash] options
2166
+ # - `:keys => Array<String>`: optional array with keys to pass to the script
2167
+ # - `:argv => Array<String>`: optional array with arguments to pass to the script
2168
+ # @return depends on the script
2169
+ #
2170
+ # @see #script
2171
+ # @see #eval
2172
+ def evalsha(*args)
2173
+ _eval(:evalsha, args)
2057
2174
  end
2058
2175
 
2059
2176
  def id