redis 3.0.0.rc1 → 3.0.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. data/.travis.yml +50 -0
  2. data/.travis/Gemfile +11 -0
  3. data/CHANGELOG.md +47 -19
  4. data/README.md +160 -149
  5. data/Rakefile +15 -50
  6. data/examples/pubsub.rb +1 -1
  7. data/examples/unicorn/config.ru +1 -1
  8. data/examples/unicorn/unicorn.rb +1 -1
  9. data/lib/redis.rb +790 -390
  10. data/lib/redis/client.rb +137 -49
  11. data/lib/redis/connection/hiredis.rb +26 -15
  12. data/lib/redis/connection/ruby.rb +170 -53
  13. data/lib/redis/connection/synchrony.rb +23 -35
  14. data/lib/redis/distributed.rb +92 -32
  15. data/lib/redis/errors.rb +4 -2
  16. data/lib/redis/pipeline.rb +17 -6
  17. data/lib/redis/version.rb +1 -1
  18. data/redis.gemspec +4 -6
  19. data/test/blocking_commands_test.rb +42 -0
  20. data/test/command_map_test.rb +18 -17
  21. data/test/commands_on_hashes_test.rb +13 -12
  22. data/test/commands_on_lists_test.rb +35 -45
  23. data/test/commands_on_sets_test.rb +55 -54
  24. data/test/commands_on_sorted_sets_test.rb +106 -105
  25. data/test/commands_on_strings_test.rb +64 -55
  26. data/test/commands_on_value_types_test.rb +66 -54
  27. data/test/connection_handling_test.rb +136 -151
  28. data/test/distributed_blocking_commands_test.rb +33 -40
  29. data/test/distributed_commands_on_hashes_test.rb +6 -7
  30. data/test/distributed_commands_on_lists_test.rb +13 -14
  31. data/test/distributed_commands_on_sets_test.rb +57 -58
  32. data/test/distributed_commands_on_sorted_sets_test.rb +11 -12
  33. data/test/distributed_commands_on_strings_test.rb +31 -32
  34. data/test/distributed_commands_on_value_types_test.rb +61 -46
  35. data/test/distributed_commands_requiring_clustering_test.rb +108 -108
  36. data/test/distributed_connection_handling_test.rb +14 -15
  37. data/test/distributed_internals_test.rb +7 -19
  38. data/test/distributed_key_tags_test.rb +36 -36
  39. data/test/distributed_persistence_control_commands_test.rb +17 -14
  40. data/test/distributed_publish_subscribe_test.rb +61 -69
  41. data/test/distributed_remote_server_control_commands_test.rb +39 -28
  42. data/test/distributed_sorting_test.rb +12 -13
  43. data/test/distributed_test.rb +40 -41
  44. data/test/distributed_transactions_test.rb +20 -21
  45. data/test/encoding_test.rb +12 -9
  46. data/test/error_replies_test.rb +42 -36
  47. data/test/helper.rb +118 -85
  48. data/test/helper_test.rb +20 -6
  49. data/test/internals_test.rb +167 -103
  50. data/test/lint/blocking_commands.rb +124 -0
  51. data/test/lint/hashes.rb +115 -93
  52. data/test/lint/lists.rb +86 -80
  53. data/test/lint/sets.rb +68 -62
  54. data/test/lint/sorted_sets.rb +200 -195
  55. data/test/lint/strings.rb +112 -94
  56. data/test/lint/value_types.rb +76 -55
  57. data/test/persistence_control_commands_test.rb +17 -12
  58. data/test/pipelining_commands_test.rb +135 -126
  59. data/test/publish_subscribe_test.rb +105 -110
  60. data/test/remote_server_control_commands_test.rb +74 -58
  61. data/test/sorting_test.rb +31 -29
  62. data/test/support/connection/hiredis.rb +1 -0
  63. data/test/support/connection/ruby.rb +1 -0
  64. data/test/support/connection/synchrony.rb +17 -0
  65. data/test/{redis_mock.rb → support/redis_mock.rb} +24 -21
  66. data/test/support/wire/synchrony.rb +24 -0
  67. data/test/support/wire/thread.rb +5 -0
  68. data/test/synchrony_driver.rb +9 -9
  69. data/test/test.conf +1 -1
  70. data/test/thread_safety_test.rb +21 -19
  71. data/test/transactions_test.rb +189 -118
  72. data/test/unknown_commands_test.rb +9 -8
  73. data/test/url_param_test.rb +46 -41
  74. metadata +28 -43
  75. data/TODO.md +0 -4
  76. data/benchmarking/thread_safety.rb +0 -38
  77. data/test/lint/internals.rb +0 -36
@@ -0,0 +1,50 @@
1
+ language: ruby
2
+
3
+ branches:
4
+ only:
5
+ - master
6
+ - test-unit
7
+
8
+ rvm:
9
+ - 1.8.7
10
+ - 1.9.2
11
+ - 1.9.3
12
+ - jruby-18mode
13
+ - jruby-19mode
14
+
15
+ gemfile:
16
+ - .travis/Gemfile
17
+
18
+ env:
19
+ - conn=ruby
20
+ - conn=hiredis
21
+ - conn=synchrony
22
+
23
+ matrix:
24
+ exclude:
25
+ # hiredis
26
+ - rvm: jruby-18mode
27
+ gemfile: .travis/Gemfile
28
+ env: conn=hiredis
29
+ - rvm: jruby-19mode
30
+ gemfile: .travis/Gemfile
31
+ env: conn=hiredis
32
+
33
+ # synchrony
34
+ - rvm: 1.8.7
35
+ gemfile: .travis/Gemfile
36
+ env: conn=synchrony
37
+ - rvm: jruby-18mode
38
+ gemfile: .travis/Gemfile
39
+ env: conn=synchrony
40
+ - rvm: jruby-19mode
41
+ gemfile: .travis/Gemfile
42
+ env: conn=synchrony
43
+
44
+ notifications:
45
+ irc:
46
+ - irc.freenode.net#redis-rb
47
+ email:
48
+ - damian.janowski@gmail.com
49
+ - michel@soveran.com
50
+ - pcnoordhuis@gmail.com
@@ -0,0 +1,11 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec :path => "../"
4
+
5
+ case ENV["conn"]
6
+ when "hiredis"
7
+ gem "hiredis"
8
+ when "synchrony"
9
+ gem "hiredis"
10
+ gem "em-synchrony"
11
+ end
@@ -1,5 +1,33 @@
1
1
  # 3.0 (unreleased)
2
2
 
3
+ * The repository now lives at [https://github.com/redis/redis-rb](https://github.com/redis/redis-rb).
4
+ Thanks, Ezra!
5
+
6
+ * Added support for `PEXPIRE`, `PTTL`, `PEXPIREAT`, `PSETEX`,
7
+ `INCRYBYFLOAT`, `HINCRYBYFLOAT` and `TIME` (Redis 2.6).
8
+
9
+ * `Redis.current` is now thread unsafe, because the client itself is thread safe.
10
+
11
+ In the future you'll be able to do something like:
12
+
13
+ Redis.current = Redis::Pool.connect
14
+
15
+ This makes `Redis.current` actually usable in multi-threaded environments,
16
+ while not affecting those running a single thread.
17
+
18
+ * Change API for `BLPOP`, `BRPOP` and `BRPOPLPUSH`. Both `BLPOP` and
19
+ `BRPOP` now take a single argument equal to a string key, or an array
20
+ with string keys, followed by an optional hash with a `:timeout` key.
21
+ `BRPOPLPUSH` also takes an optional hash with a `:timeout` key as last
22
+ argument for consistency. By default, these commands use a timeout of
23
+ `0` to not time out.
24
+
25
+ * When `SORT` is passed multiple key patterns to get via the `:get`
26
+ option, it now returns an array per result element, holding all `GET`
27
+ substitutions.
28
+
29
+ * The `MSETNX` command now returns a boolean.
30
+
3
31
  * The `ZRANGE`, `ZREVRANGE`, `ZRANGEBYSCORE` and `ZREVRANGEBYSCORE` commands
4
32
  now return an array containing `[String, Float]` pairs when
5
33
  `:with_scores => true` is passed.
@@ -9,34 +37,34 @@
9
37
 
10
38
  * The client now raises custom exceptions where it makes sense.
11
39
 
12
- If by any chance you were rescuing low-level exceptions (`Errno::*`),
13
- you should now rescue as follows:
40
+ If by any chance you were rescuing low-level exceptions (`Errno::*`),
41
+ you should now rescue as follows:
14
42
 
15
- Errno::ECONNRESET -> Redis::ConnectionError
16
- Errno::EPIPE -> Redis::ConnectionError
17
- Errno::ECONNABORTED -> Redis::ConnectionError
18
- Errno::EBADF -> Redis::ConnectionError
19
- Errno::EINVAL -> Redis::ConnectionError
20
- Errno::EAGAIN -> Redis::TimeoutError
21
- Errno::ECONNREFUSED -> Redis::CannotConnectError
43
+ Errno::ECONNRESET -> Redis::ConnectionError
44
+ Errno::EPIPE -> Redis::ConnectionError
45
+ Errno::ECONNABORTED -> Redis::ConnectionError
46
+ Errno::EBADF -> Redis::ConnectionError
47
+ Errno::EINVAL -> Redis::ConnectionError
48
+ Errno::EAGAIN -> Redis::TimeoutError
49
+ Errno::ECONNREFUSED -> Redis::CannotConnectError
22
50
 
23
51
  * Always raise exceptions originating from erroneous command invocation
24
52
  inside pipelines and MULTI/EXEC blocks.
25
53
 
26
- The old behavior (swallowing exceptions) could cause application bugs
27
- to go unnoticed.
54
+ The old behavior (swallowing exceptions) could cause application bugs
55
+ to go unnoticed.
28
56
 
29
57
  * Implement futures for assigning values inside pipelines and MULTI/EXEC
30
58
  blocks. Futures are assigned their value after the pipeline or
31
59
  MULTI/EXEC block has executed.
32
60
 
33
- ```ruby
34
- $redis.pipelined do
35
- @future = $redis.get "key"
36
- end
61
+ ```ruby
62
+ $redis.pipelined do
63
+ @future = $redis.get "key"
64
+ end
37
65
 
38
- puts @future.value
39
- ```
66
+ puts @future.value
67
+ ```
40
68
 
41
69
  * Ruby 1.8.6 is officially not supported.
42
70
 
@@ -45,7 +73,7 @@ puts @future.value
45
73
  * Pipelined commands now return the same replies as when called outside
46
74
  a pipeline.
47
75
 
48
- In the past, pipelined replies were returned without post-processing.
76
+ In the past, pipelined replies were returned without post-processing.
49
77
 
50
78
  * Support `SLOWLOG` command (Michael Bernstein).
51
79
 
@@ -56,7 +84,7 @@ puts @future.value
56
84
 
57
85
  * Connecting using a URL now checks that a host is given.
58
86
 
59
- It's just a small sanity check, cf. #126
87
+ It's just a small sanity check, cf. #126
60
88
 
61
89
  * Support variadic commands introduced in Redis 2.4.
62
90
 
data/README.md CHANGED
@@ -1,195 +1,205 @@
1
- # redis-rb
1
+ # redis-rb [![Build Status][travis-image]][travis-link]
2
2
 
3
- A Ruby client library for the [Redis](http://redis.io) key-value store.
3
+ [travis-image]: https://secure.travis-ci.org/redis/redis-rb.png?branch=master
4
+ [travis-link]: http://travis-ci.org/redis/redis-rb
5
+ [travis-home]: http://travis-ci.org/
4
6
 
5
- A simple Ruby client trying to match Redis' API one-to-one while still providing a Rubystic interface.
6
- It features thread safety, client-side sharding, and an obsession for performance.
7
+ A Ruby client library for [Redis][redis-home].
7
8
 
8
- ## A note about versions
9
+ [redis-home]: http://redis.io
9
10
 
10
- Versions *1.0.x* target all versions of Redis. You have to use this one if you are using Redis < 1.2.
11
-
12
- Version *2.0* is a big refactoring of the previous version and makes little effort to be
13
- backwards-compatible when it shouldn't. It does not support Redis' original protocol, favoring the
14
- new, binary-safe one. You should be using this version if you're running Redis 1.2+.
15
-
16
- ## Information about Redis
17
-
18
- Redis is a key-value store with some interesting features:
19
-
20
- 1. It's fast.
21
- 2. Keys are strings but values are typed. Currently Redis supports strings, lists, sets, sorted sets and hashes. [Atomic operations](http://redis.io/commands) can be done on all of these types.
22
-
23
- See [the Redis homepage](http://redis.io) for more information.
11
+ A Ruby client that tries to match Redis' API one-to-one, while still
12
+ providing an idiomatic interface. It features thread-safety, client-side
13
+ sharding, pipelining, and an obsession for performance.
24
14
 
25
15
  ## Getting started
26
16
 
27
- You can connect to Redis by instantiating the `Redis` class:
28
-
29
- require "redis"
30
-
31
- redis = Redis.new
32
-
33
- This assumes Redis was started with default values listening on `localhost`, port 6379. If you need to connect to a remote server or a different port, try:
34
-
35
- redis = Redis.new(:host => "10.0.1.1", :port => 6380)
36
-
37
- To connect to Redis listening on a unix socket, try:
38
-
39
- redis = Redis.new(:path => "/tmp/redis.sock")
40
-
41
- Once connected, you can start running commands against Redis:
42
-
43
- >> redis.set "foo", "bar"
44
- => "OK"
45
-
46
- >> redis.get "foo"
47
- => "bar"
48
-
49
- >> redis.sadd "users", "albert"
50
- => true
51
-
52
- >> redis.sadd "users", "bernard"
53
- => true
54
-
55
- >> redis.sadd "users", "charles"
56
- => true
57
-
58
- How many users?
59
-
60
- >> redis.scard "users"
61
- => 3
17
+ As of version 2.0 this client only targets Redis version 2.0 and higher.
18
+ You can use an older version of this client if you need to interface
19
+ with a Redis instance older than 2.0, but this is no longer supported.
62
20
 
63
- Is `albert` a user?
64
-
65
- >> redis.sismember "users", "albert"
66
- => true
67
-
68
- Is `isabel` a user?
69
-
70
- >> redis.sismember "users", "isabel"
71
- => false
21
+ You can connect to Redis by instantiating the `Redis` class:
72
22
 
73
- Handle groups:
23
+ ```ruby
24
+ require "redis"
74
25
 
75
- >> redis.sadd "admins", "albert"
76
- => true
26
+ redis = Redis.new
27
+ ```
77
28
 
78
- >> redis.sadd "admins", "isabel"
79
- => true
29
+ This assumes Redis was started with a default configuration, and it
30
+ listening on `localhost`, port 6379. If you need to connect to a remote
31
+ server or a different port, try:
80
32
 
81
- Users who are also admins:
33
+ ```ruby
34
+ redis = Redis.new(:host => "10.0.1.1", :port => 6380)
35
+ ```
82
36
 
83
- >> redis.sinter "users", "admins"
84
- => ["albert"]
37
+ To connect to Redis listening on a Unix socket, try:
85
38
 
86
- Users who are not admins:
39
+ ```ruby
40
+ redis = Redis.new(:path => "/tmp/redis.sock")
41
+ ```
87
42
 
88
- >> redis.sdiff "users", "admins"
89
- => ["bernard", "charles"]
43
+ The Redis class exports methods that are named identical to the commands
44
+ they execute. The arguments these methods accept are often identical to
45
+ the arguments specified on the [Redis website][redis-commands]. For
46
+ instance, the `SET` and `GET` commands can be called like this:
90
47
 
91
- Admins who are not users:
48
+ [redis-commands]: http://redis.io/commands
92
49
 
93
- >> redis.sdiff "admins", "users"
94
- => ["isabel"]
50
+ ```ruby
51
+ redis.set("mykey", "hello world")
52
+ # => "OK"
95
53
 
96
- All users and admins:
54
+ redis.get("mykey")
55
+ # => "hello world"
56
+ ```
97
57
 
98
- >> redis.sunion "admins", "users"
99
- => ["albert", "bernard", "charles", "isabel"]
58
+ All commands, their arguments and return values are documented, and
59
+ available on [rdoc.info][rdoc].
100
60
 
61
+ [rdoc]: http://rdoc.info/github/redis/redis-rb/
101
62
 
102
63
  ## Storing objects
103
64
 
104
- Redis only stores strings as values. If you want to store an object inside a key, you can use a serialization/deseralization mechanism like JSON:
105
-
106
- >> require 'json'
107
- => true
108
-
109
- >> redis.set "foo", [1, 2, 3].to_json
110
- => OK
111
-
112
- >> JSON.parse(redis.get("foo"))
113
- => [1, 2, 3]
114
-
115
- ## Executing multiple commands atomically
116
-
117
- You can use `MULTI/EXEC` to run arbitrary commands in an atomic fashion:
118
-
119
- redis.multi do
120
- redis.set "foo", "bar"
121
- redis.incr "baz"
122
- end
123
-
124
- ## Multithreaded Operation
125
-
126
- Starting with redis-rb 2.2.0, the client is thread-safe by default. To use
127
- earlier versions safely in a multithreaded environment, be sure to initialize
128
- the client with `:thread_safe => true`. Thread-safety can be explicitly
129
- disabled for versions 2.2 and up by initializing the client with `:thread_safe
130
- => false`.
131
-
132
- See the tests and benchmarks for examples.
65
+ Redis only stores strings as values. If you want to store an object, you
66
+ can use a serialization mechanism such as JSON:
67
+
68
+ ```ruby
69
+ require "json"
70
+
71
+ redis.set "foo", [1, 2, 3].to_json
72
+ # => OK
73
+
74
+ JSON.parse(redis.get("foo"))
75
+ # => [1, 2, 3]
76
+ ```
77
+
78
+ ## Pipelining
79
+
80
+ When multiple commands are executed sequentially, but are not dependent,
81
+ the calls can be *pipelined*. This means that the client doesn't wait
82
+ for reply of the first command before sending the next command. The
83
+ advantage is that multiple commands are sent at once, resulting in
84
+ faster overall execution.
85
+
86
+ The client can be instructed to pipeline commands by using the
87
+ `#pipelined` method. After the block is executed, the client sends all
88
+ commands to Redis and gathers their replies. These replies are returned
89
+ by the `#pipelined` method.
90
+
91
+ ```ruby
92
+ redis.pipelined do
93
+ redis.set "foo", "bar"
94
+ redis.incr "baz"
95
+ end
96
+ # => ["OK", 1]
97
+ ```
98
+
99
+ ### Executing commands atomically
100
+
101
+ You can use `MULTI/EXEC` to run a number of commands in an atomic
102
+ fashion. This is similar to executing a pipeline, but the commands are
103
+ preceded by a call to `MULTI`, and followed by a call to `EXEC`. Like
104
+ the regular pipeline, the replies to the commands are returned by the
105
+ `#multi` method.
106
+
107
+ ```ruby
108
+ redis.multi do
109
+ redis.set "foo", "bar"
110
+ redis.incr "baz"
111
+ end
112
+ # => ["OK", 1]
113
+ ```
114
+
115
+ ### Futures
116
+
117
+ Replies to commands in a pipeline can be accessed via the *futures* they
118
+ emit (since redis-rb 3.0). All calls inside a pipeline block return a
119
+ `Future` object, which responds to the `#value` method. When the
120
+ pipeline has succesfully executed, all futures are assigned their
121
+ respective replies and can be used.
122
+
123
+ ```ruby
124
+ redis.pipelined do
125
+ @set = redis.set "foo", "bar"
126
+ @incr = redis.incr "baz"
127
+ end
128
+
129
+ @set.value
130
+ # => "OK"
131
+
132
+ @incr.value
133
+ # => 1
134
+ ```
133
135
 
134
136
  ## Alternate drivers
135
137
 
136
- Non-default connection drivers are only used when they are explicitly required.
137
138
  By default, redis-rb uses Ruby's socket library to talk with Redis.
139
+ To use an alternative connection driver it should be specified as option
140
+ when instantiating the client object. These instructions are only valid
141
+ for **redis-rb 3.0**. For instructions on how to use alternate drivers from
142
+ **redis-rb 2.2**, please refer to an [older README][readme-2.2.2].
143
+
144
+ [readme-2.2.2]: https://github.com/redis/redis-rb/blob/v2.2.2/README.md
138
145
 
139
146
  ### hiredis
140
147
 
141
- Using redis-rb with hiredis-rb (v0.3 or higher) as backend is done by requiring
142
- `redis/connection/hiredis` before requiring `redis`. This will make redis-rb
143
- pick up hiredis as default driver automatically. This driver optimizes for
144
- speed, at the cost of portability. Since hiredis is a C extension, JRuby is not
145
- supported (by default). Use hiredis when you have large array replies (think
146
- `LRANGE`, `SMEMBERS`, `ZRANGE`, etc.) and/or large pipelines of commands.
148
+ The hiredis driver uses the connection facility of hiredis-rb. In turn,
149
+ hiredis-rb is a binding to the official hiredis client library. It
150
+ optimizes for speed, at the cost of portability. Because it is a C
151
+ extension, JRuby is not supported (by default).
147
152
 
148
- Using redis-rb with hiredis from a Gemfile:
153
+ It is best to use hiredis when you have large replies (for example:
154
+ `LRANGE`, `SMEMBERS`, `ZRANGE`, etc.) and/or use big pipelines.
149
155
 
150
- gem "hiredis", "~> 0.3.1"
151
- gem "redis", "~> 2.2.0", :require => ["redis/connection/hiredis", "redis"]
156
+ In your Gemfile, include hiredis:
152
157
 
153
- ### synchrony
158
+ ```ruby
159
+ gem "redis", "~> 3.0.0.rc2"
160
+ gem "hiredis", "~> 0.4.5"
161
+ ```
154
162
 
155
- This driver adds support for
156
- [em-synchrony](https://github.com/igrigorik/em-synchrony). Using the synchrony
157
- backend from redis-rb is done by requiring `redis/connection/synchrony` before
158
- requiring `redis`. This driver makes redis-rb work with EventMachine's
159
- asynchronous I/O, while not changing the exposed API. The hiredis gem needs to
160
- be available as well, because the synchrony driver uses hiredis for parsing the
161
- Redis protocol.
163
+ When instantiating the client object, specify hiredis:
162
164
 
163
- Using redis-rb with synchrony from a Gemfile:
165
+ ```ruby
166
+ redis = Redis.new(:driver => :hiredis)
167
+ ```
164
168
 
165
- gem "hiredis", "~> 0.3.1"
166
- gem "em-synchrony"
167
- gem "redis", "~> 2.2.0", :require => ["redis/connection/synchrony", "redis"]
169
+ ### synchrony
168
170
 
169
- ## Testing
171
+ The synchrony driver adds support for [em-synchrony][em-synchrony].
172
+ This makes redis-rb work with EventMachine's asynchronous I/O, while not
173
+ changing the exposed API. The hiredis gem needs to be available as
174
+ well, because the synchrony driver uses hiredis for parsing the Redis
175
+ protocol.
170
176
 
171
- This library (v2.2) is tested against the following interpreters:
177
+ [em-synchrony]: https://github.com/igrigorik/em-synchrony
172
178
 
173
- * MRI 1.8.7 (drivers: Ruby, hiredis)
174
- * MRI 1.9.2 (drivers: Ruby, hiredis, em-synchrony)
175
- * JRuby 1.6 (drivers: Ruby)
176
- * Rubinius 1.2 (drivers: Ruby, hiredis)
179
+ In your Gemfile, include em-synchrony and hiredis:
177
180
 
178
- ## Known issues
181
+ ```ruby
182
+ gem "redis", "~> 3.0.0.rc2"
183
+ gem "hiredis", "~> 0.4.5"
184
+ gem "em-synchrony"
185
+ ```
179
186
 
180
- * Ruby 1.9 doesn't raise on socket timeouts in `IO#read` but rather retries the
181
- read operation. This means socket timeouts don't work on 1.9 when using the
182
- pure Ruby I/O code. Use hiredis when you want use socket timeouts on 1.9.
187
+ When instantiating the client object, specify hiredis:
183
188
 
184
- * Ruby 1.8 *does* raise on socket timeouts in `IO#read`, but prints a warning
185
- that using `IO#read` for non blocking reads is obsolete. This is wrong, since
186
- the read is in fact blocking, but `EAGAIN` (which is returned on socket
187
- timeouts) is interpreted as if the read was non blocking. Use hiredis to
188
- prevent seeing this warning.
189
+ ```ruby
190
+ redis = Redis.new(:driver => :synchrony)
191
+ ```
192
+
193
+ ## Testing
189
194
 
190
- ## More info
195
+ This library is tested using [Travis][travis-home], where it is tested
196
+ against the following interpreters and drivers:
191
197
 
192
- Check the [Redis Command Reference](http://redis.io/commands) or check the tests to find out how to use this client.
198
+ * MRI 1.8.7 (drivers: ruby, hiredis)
199
+ * MRI 1.9.2 (drivers: ruby, hiredis, synchrony)
200
+ * MRI 1.9.3 (drivers: ruby, hiredis, synchrony)
201
+ * JRuby 1.6 (1.8 mode) (drivers: ruby)
202
+ * JRuby 1.6 (1.9 mode) (drivers: ruby)
193
203
 
194
204
  ## Contributors
195
205
 
@@ -211,4 +221,5 @@ all contributors)
211
221
 
212
222
  ## Contributing
213
223
 
214
- [Fork the project](http://github.com/ezmobius/redis-rb) and send pull requests. You can also ask for help at `#redis-rb` on Freenode.
224
+ [Fork the project](https://github.com/redis/redis-rb) and send pull
225
+ requests. You can also ask for help at `#redis-rb` on Freenode.