redis 3.0.4 → 3.0.5

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