redis 3.0.0.rc2 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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