redis 2.1.1 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -0
- data/CHANGELOG.md +34 -0
- data/README.md +190 -0
- data/Rakefile +194 -79
- data/benchmarking/logging.rb +62 -0
- data/benchmarking/pipeline.rb +51 -0
- data/benchmarking/speed.rb +21 -0
- data/benchmarking/suite.rb +24 -0
- data/benchmarking/thread_safety.rb +38 -0
- data/benchmarking/worker.rb +71 -0
- data/examples/basic.rb +15 -0
- data/examples/dist_redis.rb +43 -0
- data/examples/incr-decr.rb +17 -0
- data/examples/list.rb +26 -0
- data/examples/pubsub.rb +31 -0
- data/examples/sets.rb +36 -0
- data/examples/unicorn/config.ru +3 -0
- data/examples/unicorn/unicorn.rb +20 -0
- data/lib/redis.rb +612 -156
- data/lib/redis/client.rb +98 -57
- data/lib/redis/connection.rb +9 -134
- data/lib/redis/connection/command_helper.rb +45 -0
- data/lib/redis/connection/hiredis.rb +49 -0
- data/lib/redis/connection/registry.rb +12 -0
- data/lib/redis/connection/ruby.rb +131 -0
- data/lib/redis/connection/synchrony.rb +125 -0
- data/lib/redis/distributed.rb +161 -5
- data/lib/redis/pipeline.rb +6 -0
- data/lib/redis/version.rb +3 -0
- data/redis.gemspec +24 -0
- data/test/commands_on_hashes_test.rb +32 -0
- data/test/commands_on_lists_test.rb +60 -0
- data/test/commands_on_sets_test.rb +78 -0
- data/test/commands_on_sorted_sets_test.rb +109 -0
- data/test/commands_on_strings_test.rb +80 -0
- data/test/commands_on_value_types_test.rb +88 -0
- data/test/connection_handling_test.rb +87 -0
- data/test/db/.gitignore +1 -0
- data/test/distributed_blocking_commands_test.rb +53 -0
- data/test/distributed_commands_on_hashes_test.rb +12 -0
- data/test/distributed_commands_on_lists_test.rb +24 -0
- data/test/distributed_commands_on_sets_test.rb +85 -0
- data/test/distributed_commands_on_strings_test.rb +50 -0
- data/test/distributed_commands_on_value_types_test.rb +73 -0
- data/test/distributed_commands_requiring_clustering_test.rb +148 -0
- data/test/distributed_connection_handling_test.rb +25 -0
- data/test/distributed_internals_test.rb +18 -0
- data/test/distributed_key_tags_test.rb +53 -0
- data/test/distributed_persistence_control_commands_test.rb +24 -0
- data/test/distributed_publish_subscribe_test.rb +101 -0
- data/test/distributed_remote_server_control_commands_test.rb +31 -0
- data/test/distributed_sorting_test.rb +21 -0
- data/test/distributed_test.rb +60 -0
- data/test/distributed_transactions_test.rb +34 -0
- data/test/encoding_test.rb +16 -0
- data/test/error_replies_test.rb +53 -0
- data/test/helper.rb +145 -0
- data/test/internals_test.rb +157 -0
- data/test/lint/hashes.rb +114 -0
- data/test/lint/internals.rb +41 -0
- data/test/lint/lists.rb +93 -0
- data/test/lint/sets.rb +66 -0
- data/test/lint/sorted_sets.rb +167 -0
- data/test/lint/strings.rb +137 -0
- data/test/lint/value_types.rb +84 -0
- data/test/persistence_control_commands_test.rb +22 -0
- data/test/pipelining_commands_test.rb +123 -0
- data/test/publish_subscribe_test.rb +158 -0
- data/test/redis_mock.rb +80 -0
- data/test/remote_server_control_commands_test.rb +63 -0
- data/test/sorting_test.rb +44 -0
- data/test/synchrony_driver.rb +57 -0
- data/test/test.conf +8 -0
- data/test/thread_safety_test.rb +30 -0
- data/test/transactions_test.rb +100 -0
- data/test/unknown_commands_test.rb +14 -0
- data/test/url_param_test.rb +60 -0
- metadata +128 -19
- data/README.markdown +0 -129
data/.gitignore
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# 2.2.0 (unreleased)
|
2
|
+
|
3
|
+
* Added method `Redis#without_reconnect` that ensures the client will not try
|
4
|
+
to reconnect when running the code inside the specified block.
|
5
|
+
|
6
|
+
* Thread-safe by default. Thread safety can be explicitly disabled by passing
|
7
|
+
`:thread_safe => false` as argument.
|
8
|
+
|
9
|
+
* Commands called inside a MULTI/EXEC no longer raise error replies, since a
|
10
|
+
successful EXEC means the commands inside the block were executed.
|
11
|
+
|
12
|
+
* MULTI/EXEC blocks are pipelined.
|
13
|
+
|
14
|
+
* Don't disconnect on error replies.
|
15
|
+
|
16
|
+
* Use `IO#syswrite` instead of `IO#write` because write buffering is not
|
17
|
+
necessary.
|
18
|
+
|
19
|
+
* Connect to a unix socket by passing the `:path` option as argument.
|
20
|
+
|
21
|
+
* The timeout value is coerced into a float, allowing sub-second timeouts.
|
22
|
+
|
23
|
+
* Accept both `:with_scores` _and_ `:withscores` as argument to sorted set
|
24
|
+
commands.
|
25
|
+
|
26
|
+
* Use [hiredis](https://github.com/pietern/hiredis-rb) (v0.3 or higher) by
|
27
|
+
requiring "redis/connection/hiredis".
|
28
|
+
|
29
|
+
* Use [em-synchrony](https://github.com/igrigorik/em-synchrony) by requiring
|
30
|
+
"redis/connection/synchrony".
|
31
|
+
|
32
|
+
# 2.1.1
|
33
|
+
|
34
|
+
See commit log.
|
data/README.md
ADDED
@@ -0,0 +1,190 @@
|
|
1
|
+
# redis-rb
|
2
|
+
|
3
|
+
A Ruby client library for the [Redis](http://redis.io) key-value store.
|
4
|
+
|
5
|
+
## A note about versions
|
6
|
+
|
7
|
+
Versions *1.0.x* target all versions of Redis. You have to use this one if you are using Redis < 1.2.
|
8
|
+
|
9
|
+
Version *2.0* is a big refactoring of the previous version and makes little effort to be
|
10
|
+
backwards-compatible when it shouldn't. It does not support Redis' original protocol, favoring the
|
11
|
+
new, binary-safe one. You should be using this version if you're running Redis 1.2+.
|
12
|
+
|
13
|
+
## Information about Redis
|
14
|
+
|
15
|
+
Redis is a key-value store with some interesting features:
|
16
|
+
|
17
|
+
1. It's fast.
|
18
|
+
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.
|
19
|
+
|
20
|
+
See [the Redis homepage](http://redis.io) for more information.
|
21
|
+
|
22
|
+
## Getting started
|
23
|
+
|
24
|
+
You can connect to Redis by instantiating the `Redis` class:
|
25
|
+
|
26
|
+
require "redis"
|
27
|
+
|
28
|
+
redis = Redis.new
|
29
|
+
|
30
|
+
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:
|
31
|
+
|
32
|
+
redis = Redis.new(:host => "10.0.1.1", :port => 6380)
|
33
|
+
|
34
|
+
To connect to Redis listening on a unix socket, try:
|
35
|
+
|
36
|
+
redis = Redis.new(:path => "/tmp/redis.sock")
|
37
|
+
|
38
|
+
Once connected, you can start running commands against Redis:
|
39
|
+
|
40
|
+
>> redis.set "foo", "bar"
|
41
|
+
=> "OK"
|
42
|
+
|
43
|
+
>> redis.get "foo"
|
44
|
+
=> "bar"
|
45
|
+
|
46
|
+
>> redis.sadd "users", "albert"
|
47
|
+
=> true
|
48
|
+
|
49
|
+
>> redis.sadd "users", "bernard"
|
50
|
+
=> true
|
51
|
+
|
52
|
+
>> redis.sadd "users", "charles"
|
53
|
+
=> true
|
54
|
+
|
55
|
+
How many users?
|
56
|
+
|
57
|
+
>> redis.scard "users"
|
58
|
+
=> 3
|
59
|
+
|
60
|
+
Is `albert` a user?
|
61
|
+
|
62
|
+
>> redis.sismember "users", "albert"
|
63
|
+
=> true
|
64
|
+
|
65
|
+
Is `isabel` a user?
|
66
|
+
|
67
|
+
>> redis.sismember "users", "isabel"
|
68
|
+
=> false
|
69
|
+
|
70
|
+
Handle groups:
|
71
|
+
|
72
|
+
>> redis.sadd "admins", "albert"
|
73
|
+
=> true
|
74
|
+
|
75
|
+
>> redis.sadd "admins", "isabel"
|
76
|
+
=> true
|
77
|
+
|
78
|
+
Users who are also admins:
|
79
|
+
|
80
|
+
>> redis.sinter "users", "admins"
|
81
|
+
=> ["albert"]
|
82
|
+
|
83
|
+
Users who are not admins:
|
84
|
+
|
85
|
+
>> redis.sdiff "users", "admins"
|
86
|
+
=> ["bernard", "charles"]
|
87
|
+
|
88
|
+
Admins who are not users:
|
89
|
+
|
90
|
+
>> redis.sdiff "admins", "users"
|
91
|
+
=> ["isabel"]
|
92
|
+
|
93
|
+
All users and admins:
|
94
|
+
|
95
|
+
>> redis.sunion "admins", "users"
|
96
|
+
=> ["albert", "bernard", "charles", "isabel"]
|
97
|
+
|
98
|
+
|
99
|
+
## Storing objects
|
100
|
+
|
101
|
+
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:
|
102
|
+
|
103
|
+
>> redis.set "foo", [1, 2, 3].to_json
|
104
|
+
=> OK
|
105
|
+
|
106
|
+
>> JSON.parse(redis.get("foo"))
|
107
|
+
=> [1, 2, 3]
|
108
|
+
|
109
|
+
## Executing multiple commands atomically
|
110
|
+
|
111
|
+
You can use `MULTI/EXEC` to run arbitrary commands in an atomic fashion:
|
112
|
+
|
113
|
+
redis.multi do
|
114
|
+
redis.set "foo", "bar"
|
115
|
+
redis.incr "baz"
|
116
|
+
end
|
117
|
+
|
118
|
+
## Multithreaded Operation
|
119
|
+
|
120
|
+
Starting with redis-rb 2.2.0, the client is thread-safe by default. To use
|
121
|
+
earlier versions safely in a multithreaded environment, be sure to initialize
|
122
|
+
the client with `:thread_safe => true`. Thread-safety can be explicitly
|
123
|
+
disabled for versions 2.2 and up by initializing the client with `:thread_safe
|
124
|
+
=> false`.
|
125
|
+
|
126
|
+
See the tests and benchmarks for examples.
|
127
|
+
|
128
|
+
## Alternate drivers
|
129
|
+
|
130
|
+
Non-default connection drivers are only used when they are explicitly required.
|
131
|
+
By default, redis-rb uses Ruby's socket library to talk with Redis.
|
132
|
+
|
133
|
+
### hiredis
|
134
|
+
|
135
|
+
Using redis-rb with hiredis-rb (v0.3 or higher) as backend is done by requiring
|
136
|
+
`redis/connection/hiredis` before requiring `redis`. This will make redis-rb
|
137
|
+
pick up hiredis as default driver automatically. This driver optimizes for
|
138
|
+
speed, at the cost of portability. Since hiredis is a C extension, JRuby is not
|
139
|
+
supported (by default). Use hiredis when you have large array replies (think
|
140
|
+
`LRANGE`, `SMEMBERS`, `ZRANGE`, etc.) and/or large pipelines of commands.
|
141
|
+
|
142
|
+
Using redis-rb with hiredis from a Gemfile:
|
143
|
+
|
144
|
+
gem "hiredis", "~> 0.3.1"
|
145
|
+
gem "redis", "~> 2.2.0", :require => ["redis/connection/hiredis", "redis"]
|
146
|
+
|
147
|
+
### synchrony
|
148
|
+
|
149
|
+
This driver adds support for
|
150
|
+
[em-synchrony](https://github.com/igrigorik/em-synchrony). Using the synchrony
|
151
|
+
backend from redis-rb is done by requiring `redis/connection/synchrony` before
|
152
|
+
requiring `redis`. This driver makes redis-rb work with EventMachine's
|
153
|
+
asynchronous I/O, while not changing the exposed API. The hiredis gem needs to
|
154
|
+
be available as well, because the synchrony driver uses hiredis for parsing the
|
155
|
+
Redis protocol.
|
156
|
+
|
157
|
+
Using redis-rb with synchrony from a Gemfile:
|
158
|
+
|
159
|
+
gem "hiredis", "~> 0.3.1"
|
160
|
+
gem "em-synchrony"
|
161
|
+
gem "redis", "~> 2.2.0", :require => ["redis/connection/synchrony", "redis"]
|
162
|
+
|
163
|
+
## Testing
|
164
|
+
|
165
|
+
This library (v2.2) is tested against the following interpreters:
|
166
|
+
|
167
|
+
* MRI 1.8.7 (drivers: Ruby, hiredis)
|
168
|
+
* MRI 1.9.2 (drivers: Ruby, hiredis, em-synchrony)
|
169
|
+
* JRuby 1.6 (drivers: Ruby)
|
170
|
+
* Rubinius 1.2 (drivers: Ruby, hiredis)
|
171
|
+
|
172
|
+
## Known issues
|
173
|
+
|
174
|
+
* Ruby 1.9 doesn't raise on socket timeouts in `IO#read` but rather retries the
|
175
|
+
read operation. This means socket timeouts don't work on 1.9 when using the
|
176
|
+
pure Ruby I/O code. Use hiredis when you want use socket timeouts on 1.9.
|
177
|
+
|
178
|
+
* Ruby 1.8 *does* raise on socket timeouts in `IO#read`, but prints a warning
|
179
|
+
that using `IO#read` for non blocking reads is obsolete. This is wrong, since
|
180
|
+
the read is in fact blocking, but `EAGAIN` (which is returned on socket
|
181
|
+
timeouts) is interpreted as if the read was non blocking. Use hiredis to
|
182
|
+
prevent seeing this warning.
|
183
|
+
|
184
|
+
## More info
|
185
|
+
|
186
|
+
Check the [Redis Command Reference](http://redis.io/commands) or check the tests to find out how to use this client.
|
187
|
+
|
188
|
+
## Contributing
|
189
|
+
|
190
|
+
[Fork the project](http://github.com/ezmobius/redis-rb) and send pull requests. You can also ask for help at `#redis-rb` on Freenode.
|
data/Rakefile
CHANGED
@@ -3,31 +3,7 @@ require 'rake/gempackagetask'
|
|
3
3
|
require 'rake/testtask'
|
4
4
|
|
5
5
|
$:.unshift File.join(File.dirname(__FILE__), 'lib')
|
6
|
-
require 'redis'
|
7
|
-
|
8
|
-
GEM = 'redis'
|
9
|
-
GEM_NAME = 'redis'
|
10
|
-
GEM_VERSION = Redis::VERSION
|
11
|
-
AUTHORS = ['Ezra Zygmuntowicz', 'Taylor Weibley', 'Matthew Clark', 'Brian McKinney', 'Salvatore Sanfilippo', 'Luca Guidi', 'Michel Martens', 'Damian Janowski']
|
12
|
-
EMAIL = "ez@engineyard.com"
|
13
|
-
HOMEPAGE = "http://github.com/ezmobius/redis-rb"
|
14
|
-
SUMMARY = "Ruby client library for Redis, the key value storage server"
|
15
|
-
|
16
|
-
spec = Gem::Specification.new do |s|
|
17
|
-
s.name = GEM
|
18
|
-
s.version = GEM_VERSION
|
19
|
-
s.platform = Gem::Platform::RUBY
|
20
|
-
s.has_rdoc = true
|
21
|
-
s.extra_rdoc_files = ["LICENSE"]
|
22
|
-
s.summary = SUMMARY
|
23
|
-
s.description = s.summary
|
24
|
-
s.authors = AUTHORS
|
25
|
-
s.email = EMAIL
|
26
|
-
s.homepage = HOMEPAGE
|
27
|
-
s.require_path = 'lib'
|
28
|
-
s.autorequire = GEM
|
29
|
-
s.files = %w(LICENSE README.markdown Rakefile) + Dir.glob("{lib,tasks,spec}/**/*")
|
30
|
-
end
|
6
|
+
require 'redis/version'
|
31
7
|
|
32
8
|
REDIS_DIR = File.expand_path(File.join("..", "test"), __FILE__)
|
33
9
|
REDIS_CNF = File.join(REDIS_DIR, "test.conf")
|
@@ -41,12 +17,12 @@ task :run => [:start, :test, :stop]
|
|
41
17
|
desc "Start the Redis server"
|
42
18
|
task :start do
|
43
19
|
redis_running = \
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
20
|
+
begin
|
21
|
+
File.exists?(REDIS_PID) && Process.kill(0, File.read(REDIS_PID).to_i)
|
22
|
+
rescue Errno::ESRCH
|
23
|
+
FileUtils.rm REDIS_PID
|
24
|
+
false
|
25
|
+
end
|
50
26
|
|
51
27
|
system "redis-server #{REDIS_CNF}" unless redis_running
|
52
28
|
end
|
@@ -59,53 +35,187 @@ task :stop do
|
|
59
35
|
end
|
60
36
|
end
|
61
37
|
|
38
|
+
def isolated(&block)
|
39
|
+
pid = fork { yield }
|
40
|
+
Process.wait(pid)
|
41
|
+
end
|
42
|
+
|
62
43
|
desc "Run the test suite"
|
63
|
-
task :test
|
64
|
-
require 'cutest'
|
44
|
+
task :test => ["test:ruby", "test:hiredis", "test:synchrony"]
|
65
45
|
|
66
|
-
|
67
|
-
|
46
|
+
namespace :test do
|
47
|
+
desc "Run tests against the Ruby driver"
|
48
|
+
task :ruby do
|
49
|
+
require "cutest"
|
68
50
|
|
69
|
-
|
70
|
-
|
71
|
-
end
|
51
|
+
isolated do
|
52
|
+
Cutest.run(Dir["./test/**/*_test.rb"])
|
53
|
+
end
|
54
|
+
end
|
72
55
|
|
73
|
-
desc "
|
74
|
-
task :
|
75
|
-
|
76
|
-
|
56
|
+
desc "Run tests against the hiredis driver"
|
57
|
+
task :hiredis do
|
58
|
+
require "cutest"
|
59
|
+
|
60
|
+
isolated do
|
61
|
+
begin
|
62
|
+
require "redis/connection/hiredis"
|
63
|
+
|
64
|
+
puts
|
65
|
+
puts "Running tests against hiredis v#{Hiredis::VERSION}"
|
66
|
+
|
67
|
+
Cutest.run(Dir["./test/**/*_test.rb"])
|
68
|
+
rescue
|
69
|
+
puts "Skipping tests against hiredis"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
77
73
|
|
78
|
-
desc "
|
79
|
-
task :
|
80
|
-
|
81
|
-
|
74
|
+
desc "Run tests against the em-synchrony driver"
|
75
|
+
task :synchrony do
|
76
|
+
require "cutest"
|
77
|
+
|
78
|
+
# Synchrony needs 1.9
|
79
|
+
next if RUBY_VERSION < "1.9"
|
80
|
+
|
81
|
+
isolated do
|
82
|
+
begin
|
83
|
+
require "redis/connection/synchrony"
|
84
|
+
|
85
|
+
puts
|
86
|
+
puts "Running tests against em-synchrony"
|
87
|
+
|
88
|
+
threaded_tests = ['./test/thread_safety_test.rb']
|
89
|
+
Cutest.run(Dir['./test/**/*_test.rb'] - threaded_tests)
|
90
|
+
rescue Exception => e
|
91
|
+
puts e
|
92
|
+
puts e.backtrace.join("\n")
|
93
|
+
puts "Skipping tests against em-synchrony"
|
94
|
+
end
|
95
|
+
end
|
82
96
|
end
|
83
97
|
end
|
84
98
|
|
85
|
-
|
86
|
-
|
87
|
-
|
99
|
+
task :doc => ["doc:generate", "doc:prepare"]
|
100
|
+
|
101
|
+
namespace :doc do
|
102
|
+
task :generate do
|
103
|
+
require "shellwords"
|
104
|
+
|
105
|
+
`rm -rf doc`
|
106
|
+
|
107
|
+
current_branch = `git branch`[/^\* (.*)$/, 1]
|
108
|
+
|
109
|
+
begin
|
110
|
+
tags = `git tag -l`.split("\n").sort.reverse
|
111
|
+
|
112
|
+
tags.each do |tag|
|
113
|
+
`git checkout -q #{tag} 2>/dev/null`
|
114
|
+
|
115
|
+
unless $?.success?
|
116
|
+
$stderr.puts "Need a clean working copy. Please git-stash away."
|
117
|
+
exit 1
|
118
|
+
end
|
119
|
+
|
120
|
+
puts tag
|
121
|
+
|
122
|
+
`mkdir -p doc/#{tag}`
|
123
|
+
|
124
|
+
files = `git ls-tree -r HEAD lib`.split("\n").map do |line|
|
125
|
+
line[/\t(.*)$/, 1]
|
126
|
+
end
|
127
|
+
|
128
|
+
opts = [
|
129
|
+
"--title", "A Ruby client for Redis",
|
130
|
+
"--output", "doc/#{tag}",
|
131
|
+
"--no-cache",
|
132
|
+
"--no-save",
|
133
|
+
"-q",
|
134
|
+
*files
|
135
|
+
]
|
136
|
+
|
137
|
+
`yardoc #{Shellwords.shelljoin opts}`
|
138
|
+
end
|
139
|
+
ensure
|
140
|
+
`git checkout -q #{current_branch}`
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
task :prepare do
|
145
|
+
versions = `git tag -l`.split("\n").grep(/^v/).sort
|
146
|
+
latest_version = versions.last
|
147
|
+
|
148
|
+
File.open("doc/.htaccess", "w") do |file|
|
149
|
+
file.puts "RedirectMatch 302 ^/?$ /#{latest_version}"
|
150
|
+
end
|
151
|
+
|
152
|
+
File.open("doc/robots.txt", "w") do |file|
|
153
|
+
file.puts "User-Agent: *"
|
154
|
+
|
155
|
+
(versions - [latest_version]).each do |version|
|
156
|
+
file.puts "Disallow: /#{version}"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
google_analytics = <<-EOS
|
161
|
+
<script type="text/javascript">
|
162
|
+
|
163
|
+
var _gaq = _gaq || [];
|
164
|
+
_gaq.push(['_setAccount', 'UA-11356145-2']);
|
165
|
+
_gaq.push(['_trackPageview']);
|
166
|
+
|
167
|
+
(function() {
|
168
|
+
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
169
|
+
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
170
|
+
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
171
|
+
})();
|
172
|
+
|
173
|
+
</script>
|
174
|
+
EOS
|
175
|
+
|
176
|
+
Dir["doc/**/*.html"].each do |path|
|
177
|
+
lines = IO.readlines(path)
|
178
|
+
|
179
|
+
File.open(path, "w") do |file|
|
180
|
+
lines.each do |line|
|
181
|
+
if line.include?("</head>")
|
182
|
+
file.write(google_analytics)
|
183
|
+
end
|
88
184
|
|
89
|
-
|
185
|
+
file.write(line)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
90
190
|
|
91
|
-
|
191
|
+
task :deploy do
|
192
|
+
system "rsync --del -avz doc/* redis-rb.keyvalue.org:deploys/redis-rb.keyvalue.org/"
|
193
|
+
end
|
92
194
|
end
|
93
195
|
|
94
196
|
namespace :commands do
|
95
197
|
def redis_commands
|
96
|
-
$redis_commands ||=
|
198
|
+
$redis_commands ||= doc.keys.map do |key|
|
199
|
+
key.split(" ").first.downcase
|
200
|
+
end.uniq
|
201
|
+
end
|
202
|
+
|
203
|
+
def doc
|
204
|
+
$doc ||= begin
|
97
205
|
require "open-uri"
|
98
|
-
|
206
|
+
require "json"
|
207
|
+
|
208
|
+
JSON.parse(open("https://github.com/antirez/redis-doc/raw/master/commands.json").read)
|
99
209
|
end
|
100
210
|
end
|
101
211
|
|
102
|
-
|
103
|
-
source = File.read(
|
212
|
+
def document(file)
|
213
|
+
source = File.read(file)
|
104
214
|
|
105
|
-
|
106
|
-
source.sub!(/(?:^
|
107
|
-
indent, extra_args = $1, $
|
108
|
-
comment = "#{indent}# #{
|
215
|
+
doc.each do |name, command|
|
216
|
+
source.sub!(/(?:^ *# .*\n)*(^ *#\n(^ *# .+?\n)*)*^( *)def #{name.downcase}(\(|$)/) do
|
217
|
+
extra_comments, indent, extra_args = $1, $3, $4
|
218
|
+
comment = "#{indent}# #{command["summary"].strip}."
|
109
219
|
|
110
220
|
IO.popen("par p#{2 + indent.size} 80", "r+") do |io|
|
111
221
|
io.puts comment
|
@@ -113,43 +223,48 @@ namespace :commands do
|
|
113
223
|
comment = io.read
|
114
224
|
end
|
115
225
|
|
116
|
-
"#{comment}#{indent}def #{name}#{extra_args}"
|
226
|
+
"#{comment}#{extra_comments}#{indent}def #{name.downcase}#{extra_args}"
|
117
227
|
end
|
118
228
|
end
|
119
229
|
|
120
|
-
File.open(
|
230
|
+
File.open(file, "w") { |f| f.write(source) }
|
231
|
+
end
|
232
|
+
|
233
|
+
task :doc do
|
234
|
+
document "lib/redis.rb"
|
235
|
+
document "lib/redis/distributed.rb"
|
121
236
|
end
|
122
237
|
|
123
238
|
task :verify do
|
124
239
|
require "redis"
|
125
240
|
require "stringio"
|
126
241
|
|
127
|
-
|
242
|
+
require "./test/helper"
|
128
243
|
|
129
|
-
|
130
|
-
redis = Redis.new
|
244
|
+
OPTIONS[:logger] = Logger.new("./tmp/log")
|
131
245
|
|
132
|
-
|
246
|
+
Rake::Task["test:ruby"].invoke
|
133
247
|
|
134
|
-
|
248
|
+
redis = Redis.new
|
135
249
|
|
136
|
-
|
137
|
-
defined, tested = redis.respond_to?(name), log.string[">> #{name.upcase}"]
|
250
|
+
report = ["Command", "\033[0mDefined?\033[0m", "\033[0mTested?\033[0m"]
|
138
251
|
|
139
|
-
|
252
|
+
yes, no = "\033[1;32mYes\033[0m", "\033[1;31mNo\033[0m"
|
140
253
|
|
141
|
-
|
142
|
-
report << (defined ? yes : no)
|
143
|
-
report << (tested ? yes : no)
|
144
|
-
end
|
254
|
+
log = File.read("./tmp/log")
|
145
255
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
256
|
+
redis_commands.sort.each do |name, _|
|
257
|
+
defined, tested = redis.respond_to?(name), log[">> #{name.upcase}"]
|
258
|
+
|
259
|
+
next if defined && tested
|
150
260
|
|
151
|
-
|
261
|
+
report << name
|
262
|
+
report << (defined ? yes : no)
|
263
|
+
report << (tested ? yes : no)
|
264
|
+
end
|
152
265
|
|
153
|
-
|
266
|
+
IO.popen("rs 0 3", "w") do |io|
|
267
|
+
io.puts report.join("\n")
|
268
|
+
end
|
154
269
|
end
|
155
270
|
end
|