redis 3.0.4 → 3.0.5

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.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ OWE3ZTkzYTU5MjZkMWY5YmQ0YTM0NmQ1NWY2ZTVmZTljNmZmYzE1Yg==
5
+ data.tar.gz: !binary |-
6
+ OTY0NWU0ZTA3YzdiNTdhOTdiMmQzMzk2NWQ1ZjBkN2M2N2MxMGEzYg==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ ZDA2NjI0ZWE0YjM2NDc4MmE0MTZmODIyN2Q5MDgxMDc1NGFiODhiM2M1NGEy
10
+ MGI1ODA2NzhmMDQ3OGY5ZGJhNzM3MzI0MjMyZGFkM2FjNDM3YzdlNTlkMjFh
11
+ OTM0ZjQyNTc5OGMwOTkwNGQxZWYyY2E3ODk5Mzc0YmY1ODEzOWE=
12
+ data.tar.gz: !binary |-
13
+ MGYyMzA5MDg1YTU1ZTcyYjVkMDljZjU4OGFhMDc1MTg3NzhhMjkzZDQyZjk5
14
+ MTVmZjJhNmRiZDc0NjE3ODgzMTE5NTMyZGM3YjM0ZjMzMzkyYjA3MjNmYWYx
15
+ MzZjNTk2NzRiOGMzYmYyODZkYzZjZjE5YWU0OTc2MWUwMTAyODk=
@@ -1,4 +1,14 @@
1
- # 3.0.4 (unreleased)
1
+ # 3.0.5
2
+
3
+ * Fix calling #select from a pipeline (#309).
4
+
5
+ * Added method `Redis#connected?`.
6
+
7
+ * Added support for `MIGRATE` (Redis 2.6).
8
+
9
+ * Support extended SET command (#343, thanks to @benubois).
10
+
11
+ # 3.0.4
2
12
 
3
13
  * Ensure #watch without a block returns "OK" (#332).
4
14
 
data/README.md CHANGED
@@ -33,7 +33,7 @@ require "redis"
33
33
  redis = Redis.new
34
34
  ```
35
35
 
36
- This assumes Redis was started with a default configuration, and it
36
+ This assumes Redis was started with a default configuration, and is
37
37
  listening on `localhost`, port 6379. If you need to connect to a remote
38
38
  server or a different port, try:
39
39
 
@@ -205,8 +205,9 @@ against the following interpreters and drivers:
205
205
  * MRI 1.8.7 (drivers: ruby, hiredis)
206
206
  * MRI 1.9.2 (drivers: ruby, hiredis, synchrony)
207
207
  * MRI 1.9.3 (drivers: ruby, hiredis, synchrony)
208
- * JRuby 1.6 (1.8 mode) (drivers: ruby)
209
- * JRuby 1.6 (1.9 mode) (drivers: ruby)
208
+ * MRI 2.0.0 (drivers: ruby, hiredis, synchrony)
209
+ * JRuby 1.7 (1.8 mode) (drivers: ruby)
210
+ * JRuby 1.7 (1.9 mode) (drivers: ruby)
210
211
 
211
212
  ## Contributors
212
213
 
@@ -27,7 +27,7 @@ class Redis
27
27
  include MonitorMixin
28
28
 
29
29
  def initialize(options = {})
30
- @client = Client.new(options)
30
+ @original_client = @client = Client.new(options)
31
31
 
32
32
  super() # Monitor#initialize
33
33
  end
@@ -48,6 +48,11 @@ class Redis
48
48
  with_reconnect(false, &blk)
49
49
  end
50
50
 
51
+ # Test whether or not the client is connected
52
+ def connected?
53
+ @original_client.connected?
54
+ end
55
+
51
56
  # Authenticate to the server.
52
57
  #
53
58
  # @param [String] password must match the password specified in the
@@ -381,6 +386,26 @@ class Redis
381
386
  end
382
387
  end
383
388
 
389
+ # Transfer a key from the connected instance to another instance.
390
+ #
391
+ # @param [String] key
392
+ # @param [Hash] options
393
+ # - `:host => String`: host of instance to migrate to
394
+ # - `:port => Integer`: port of instance to migrate to
395
+ # - `:db => Integer`: database to migrate to (default: same as source)
396
+ # - `:timeout => Integer`: timeout (default: same as connection timeout)
397
+ # @return [String] `"OK"`
398
+ def migrate(key, options)
399
+ host = options[:host] || raise(RuntimeError, ":host not specified")
400
+ port = options[:port] || raise(RuntimeError, ":port not specified")
401
+ db = (options[:db] || client.db).to_i
402
+ timeout = (options[:timeout] || client.timeout).to_i
403
+
404
+ synchronize do |client|
405
+ client.call([:migrate, host, port, key, db, timeout])
406
+ end
407
+ end
408
+
384
409
  # Delete one or more keys.
385
410
  #
386
411
  # @param [String, Array<String>] keys
@@ -430,7 +455,7 @@ class Redis
430
455
  # # => "OK"
431
456
  # redis.exists "foo"
432
457
  # # => true
433
- # resis.get "foo"
458
+ # redis.get "foo"
434
459
  # # => "bar"
435
460
  #
436
461
  # @param [String] key
@@ -624,10 +649,33 @@ class Redis
624
649
  #
625
650
  # @param [String] key
626
651
  # @param [String] value
627
- # @return `"OK"`
628
- def set(key, value)
652
+ # @param [Hash] options
653
+ # - `:ex => Fixnum`: Set the specified expire time, in seconds.
654
+ # - `:px => Fixnum`: Set the specified expire time, in milliseconds.
655
+ # - `:nx => true`: Only set the key if it does not already exist.
656
+ # - `:xx => true`: Only set the key if it already exist.
657
+ # @return [String, Boolean] `"OK"` or true, false if `:nx => true` or `:xx => true`
658
+ def set(key, value, options = {})
659
+ args = []
660
+
661
+ ex = options[:ex]
662
+ args.concat(["EX", ex]) if ex
663
+
664
+ px = options[:px]
665
+ args.concat(["PX", px]) if px
666
+
667
+ nx = options[:nx]
668
+ args.concat(["NX"]) if nx
669
+
670
+ xx = options[:xx]
671
+ args.concat(["XX"]) if xx
672
+
629
673
  synchronize do |client|
630
- client.call([:set, key, value.to_s])
674
+ if nx || xx
675
+ client.call([:set, key, value.to_s] + args, &_boolify_set)
676
+ else
677
+ client.call([:set, key, value.to_s] + args)
678
+ end
631
679
  end
632
680
  end
633
681
 
@@ -2231,7 +2279,7 @@ class Redis
2231
2279
 
2232
2280
  def inspect
2233
2281
  synchronize do |client|
2234
- "#<Redis client v#{Redis::VERSION} for #{client.id}>"
2282
+ "#<Redis client v#{Redis::VERSION} for #{@original_client.id}>"
2235
2283
  end
2236
2284
  end
2237
2285
 
@@ -2252,6 +2300,16 @@ private
2252
2300
  }
2253
2301
  end
2254
2302
 
2303
+ def _boolify_set
2304
+ lambda { |value|
2305
+ if value && "OK" == value
2306
+ true
2307
+ else
2308
+ false
2309
+ end
2310
+ }
2311
+ end
2312
+
2255
2313
  def _hashify
2256
2314
  lambda { |array|
2257
2315
  hash = Hash.new
@@ -118,7 +118,9 @@ class Redis
118
118
  def call_pipeline(pipeline)
119
119
  with_reconnect pipeline.with_reconnect? do
120
120
  begin
121
- pipeline.finish(call_pipelined(pipeline.commands))
121
+ pipeline.finish(call_pipelined(pipeline.commands)).tap do
122
+ self.db = pipeline.db if pipeline.db
123
+ end
122
124
  rescue ConnectionError => e
123
125
  return nil if pipeline.shutdown?
124
126
  # Assume the pipeline was sent in one piece, but execution of
@@ -190,7 +192,7 @@ class Redis
190
192
  end
191
193
 
192
194
  def connected?
193
- connection && connection.connected?
195
+ !! (connection && connection.connected?)
194
196
  end
195
197
 
196
198
  def disconnect
@@ -388,18 +390,11 @@ class Redis
388
390
  driver = driver.to_s if driver.is_a?(Symbol)
389
391
 
390
392
  if driver.kind_of?(String)
391
- case driver
392
- when "ruby"
393
- require "redis/connection/ruby"
394
- driver = Connection::Ruby
395
- when "hiredis"
396
- require "redis/connection/hiredis"
397
- driver = Connection::Hiredis
398
- when "synchrony"
399
- require "redis/connection/synchrony"
400
- driver = Connection::Synchrony
401
- else
402
- raise "Unknown driver: #{driver}"
393
+ begin
394
+ require "redis/connection/#{driver}"
395
+ driver = Connection.const_get(driver.capitalize)
396
+ rescue LoadError, NameError
397
+ raise RuntimeError, "Cannot load driver #{driver.inspect}"
403
398
  end
404
399
  end
405
400
 
@@ -17,8 +17,8 @@ class Redis
17
17
 
18
18
  def initialize(node_configs, options = {})
19
19
  @tag = options.delete(:tag) || /^\{(.+?)\}/
20
+ @ring = options.delete(:ring) || HashRing.new
20
21
  @default_options = options
21
- @ring = HashRing.new
22
22
  node_configs.each { |node_config| add_node(node_config) }
23
23
  @subscribed_node = nil
24
24
  end
@@ -147,6 +147,11 @@ class Redis
147
147
  node_for(key).restore(key, ttl, serialized_value)
148
148
  end
149
149
 
150
+ # Transfer a key from the connected instance to another instance.
151
+ def migrate(key, options)
152
+ raise CannotDistribute, :migrate
153
+ end
154
+
150
155
  # Delete a key.
151
156
  def del(*args)
152
157
  keys_per_node = args.group_by { |key| node_for(key) }
@@ -229,8 +234,8 @@ class Redis
229
234
  end
230
235
 
231
236
  # Set the string value of a key.
232
- def set(key, value)
233
- node_for(key).set(key, value)
237
+ def set(key, value, options = {})
238
+ node_for(key).set(key, value, options)
234
239
  end
235
240
 
236
241
  # Set the time to live in seconds of a key.
@@ -6,6 +6,8 @@ class Redis
6
6
  end
7
7
 
8
8
  class Pipeline
9
+ attr_accessor :db
10
+
9
11
  attr :futures
10
12
 
11
13
  def initialize
@@ -38,6 +40,7 @@ class Redis
38
40
  def call_pipeline(pipeline)
39
41
  @shutdown = true if pipeline.shutdown?
40
42
  @futures.concat(pipeline.futures)
43
+ @db = pipeline.db
41
44
  nil
42
45
  end
43
46
 
@@ -1,3 +1,3 @@
1
1
  class Redis
2
- VERSION = "3.0.4"
2
+ VERSION = "3.0.5"
3
3
  end
@@ -96,4 +96,36 @@ class TestCommandsOnValueTypes < Test::Unit::TestCase
96
96
  assert_equal "FLUSHALL", redis.flushall
97
97
  end
98
98
  end
99
+
100
+ def test_migrate
101
+ redis_mock(:migrate => lambda { |*args| args }) do |redis|
102
+ options = { :host => "localhost", :port => 1234 }
103
+
104
+ assert_raise(RuntimeError, /host not specified/) do
105
+ redis.migrate("foo", options.reject { |key, _| key == :host })
106
+ end
107
+
108
+ assert_raise(RuntimeError, /port not specified/) do
109
+ redis.migrate("foo", options.reject { |key, _| key == :port })
110
+ end
111
+
112
+ default_db = redis.client.db.to_i
113
+ default_timeout = redis.client.timeout.to_i
114
+
115
+ # Test defaults
116
+ actual = redis.migrate("foo", options)
117
+ expected = ["localhost", "1234", "foo", default_db.to_s, default_timeout.to_s]
118
+ assert_equal expected, actual
119
+
120
+ # Test db override
121
+ actual = redis.migrate("foo", options.merge(:db => default_db + 1))
122
+ expected = ["localhost", "1234", "foo", (default_db + 1).to_s, default_timeout.to_s]
123
+ assert_equal expected, actual
124
+
125
+ # Test timeout override
126
+ actual = redis.migrate("foo", options.merge(:timeout => default_timeout + 1))
127
+ expected = ["localhost", "1234", "foo", default_db.to_s, (default_timeout + 1).to_s]
128
+ assert_equal expected, actual
129
+ end
130
+ end
99
131
  end
@@ -84,4 +84,12 @@ class TestDistributedCommandsOnValueTypes < Test::Unit::TestCase
84
84
 
85
85
  assert_equal [0], r.dbsize
86
86
  end
87
+
88
+ def test_migrate
89
+ r.set("foo", "s1")
90
+
91
+ assert_raise Redis::Distributed::CannotDistribute do
92
+ r.migrate("foo", {})
93
+ end
94
+ end
87
95
  end
@@ -149,6 +149,10 @@ module Helper
149
149
  yield _new_client(options.merge(:port => port))
150
150
  end
151
151
  end
152
+
153
+ def assert_in_range(range, value)
154
+ assert range.include?(value), "expected #{value} to be in #{range.inspect}"
155
+ end
152
156
  end
153
157
 
154
158
  module Client
@@ -166,7 +170,7 @@ module Helper
166
170
  end
167
171
 
168
172
  def _new_client(options = {})
169
- Redis.new(_format_options(options))
173
+ Redis.new(_format_options(options).merge(:driver => ENV["conn"]))
170
174
  end
171
175
  end
172
176
 
@@ -188,7 +192,7 @@ module Helper
188
192
  end
189
193
 
190
194
  def _new_client(options = {})
191
- Redis::Distributed.new(NODES, _format_options(options))
195
+ Redis::Distributed.new(NODES, _format_options(options).merge(:driver => ENV["conn"]))
192
196
  end
193
197
  end
194
198
  end
@@ -67,6 +67,17 @@ class TestInternals < Test::Unit::TestCase
67
67
  assert_equal 1, Redis.current.client.db
68
68
  end
69
69
 
70
+ def test_redis_connected?
71
+ fresh_client = _new_client
72
+ assert !fresh_client.connected?
73
+
74
+ fresh_client.ping
75
+ assert fresh_client.connected?
76
+
77
+ fresh_client.quit
78
+ assert !fresh_client.connected?
79
+ end
80
+
70
81
  def test_default_id_with_host_and_port
71
82
  redis = Redis.new(OPTIONS.merge(:host => "host", :port => "1234", :db => 0))
72
83
  assert_equal "redis://host:1234/0", redis.client.id
@@ -47,6 +47,43 @@ module Lint
47
47
  end
48
48
  end
49
49
 
50
+ def test_set_with_ex
51
+ return if version < "2.6.12"
52
+
53
+ r.set("foo", "bar", :ex => 2)
54
+ assert_in_range 0..2, r.ttl("foo")
55
+ end
56
+
57
+ def test_set_with_px
58
+ return if version < "2.6.12"
59
+
60
+ r.set("foo", "bar", :px => 2000)
61
+ assert_in_range 0..2, r.ttl("foo")
62
+ end
63
+
64
+ def test_set_with_nx
65
+ return if version < "2.6.12"
66
+
67
+ r.set("foo", "qux", :nx => true)
68
+ assert !r.set("foo", "bar", :nx => true)
69
+ assert_equal "qux", r.get("foo")
70
+
71
+ r.del("foo")
72
+ assert r.set("foo", "bar", :nx => true)
73
+ assert_equal "bar", r.get("foo")
74
+ end
75
+
76
+ def test_set_with_xx
77
+ return if version < "2.6.12"
78
+
79
+ r.set("foo", "qux")
80
+ assert r.set("foo", "bar", :xx => true)
81
+ assert_equal "bar", r.get("foo")
82
+
83
+ r.del("foo")
84
+ assert !r.set("foo", "bar", :xx => true)
85
+ end
86
+
50
87
  def test_setex
51
88
  assert r.setex("foo", 1, "bar")
52
89
  assert_equal "bar", r.get("foo")
@@ -2,10 +2,6 @@ module Lint
2
2
 
3
3
  module ValueTypes
4
4
 
5
- def assert_in_range(range, value)
6
- assert range.include?(value), "expected #{value} to be in #{range.inspect}"
7
- end
8
-
9
5
  def test_exists
10
6
  assert_equal false, r.exists("foo")
11
7
 
@@ -204,4 +204,41 @@ class TestPipeliningCommands < Test::Unit::TestCase
204
204
 
205
205
  assert_equal "bar", r.get("foo")
206
206
  end
207
+
208
+ def test_pipeline_select
209
+ r.select 1
210
+ r.set("db", "1")
211
+
212
+ r.pipelined do |p|
213
+ p.select 2
214
+ p.set("db", "2")
215
+ end
216
+
217
+ r.select 1
218
+ assert_equal "1", r.get("db")
219
+
220
+ r.select 2
221
+ assert_equal "2", r.get("db")
222
+ end
223
+
224
+ def test_pipeline_select_client_db
225
+ r.select 1
226
+ r.pipelined do |p2|
227
+ p2.select 2
228
+ end
229
+
230
+ assert_equal 2, r.client.db
231
+ end
232
+
233
+ def test_nested_pipeline_select_client_db
234
+ r.select 1
235
+ r.pipelined do |p2|
236
+ p2.select 2
237
+ p2.pipelined do |p3|
238
+ p3.select 3
239
+ end
240
+ end
241
+
242
+ assert_equal 3, r.client.db
243
+ end
207
244
  end
@@ -98,6 +98,11 @@ module RedisMock
98
98
  break :exit
99
99
  elsif response == :close
100
100
  break :close
101
+ elsif response.is_a?(Array)
102
+ session.write("*%d\r\n" % response.size)
103
+ response.each do |e|
104
+ session.write("$%d\r\n%s\r\n" % [e.length, e])
105
+ end
101
106
  else
102
107
  session.write(response)
103
108
  session.write("\r\n") unless response.end_with?("\r\n")
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.4
5
- prerelease:
4
+ version: 3.0.5
6
5
  platform: ruby
7
6
  authors:
8
7
  - Ezra Zygmuntowicz
@@ -17,12 +16,11 @@ authors:
17
16
  autorequire:
18
17
  bindir: bin
19
18
  cert_chain: []
20
- date: 2013-04-23 00:00:00.000000000 Z
19
+ date: 2013-10-02 00:00:00.000000000 Z
21
20
  dependencies:
22
21
  - !ruby/object:Gem::Dependency
23
22
  name: rake
24
23
  requirement: !ruby/object:Gem::Requirement
25
- none: false
26
24
  requirements:
27
25
  - - ! '>='
28
26
  - !ruby/object:Gem::Version
@@ -30,7 +28,6 @@ dependencies:
30
28
  type: :development
31
29
  prerelease: false
32
30
  version_requirements: !ruby/object:Gem::Requirement
33
- none: false
34
31
  requirements:
35
32
  - - ! '>='
36
33
  - !ruby/object:Gem::Version
@@ -141,27 +138,26 @@ files:
141
138
  - test/url_param_test.rb
142
139
  homepage: https://github.com/redis/redis-rb
143
140
  licenses: []
141
+ metadata: {}
144
142
  post_install_message:
145
143
  rdoc_options: []
146
144
  require_paths:
147
145
  - lib
148
146
  required_ruby_version: !ruby/object:Gem::Requirement
149
- none: false
150
147
  requirements:
151
148
  - - ! '>='
152
149
  - !ruby/object:Gem::Version
153
150
  version: '0'
154
151
  required_rubygems_version: !ruby/object:Gem::Requirement
155
- none: false
156
152
  requirements:
157
153
  - - ! '>='
158
154
  - !ruby/object:Gem::Version
159
155
  version: '0'
160
156
  requirements: []
161
157
  rubyforge_project:
162
- rubygems_version: 1.8.23
158
+ rubygems_version: 2.0.0
163
159
  signing_key:
164
- specification_version: 3
160
+ specification_version: 4
165
161
  summary: A Ruby client library for Redis
166
162
  test_files:
167
163
  - test/blocking_commands_test.rb