gorsuch-redis 3.0.0.rc1

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.
Files changed (87) hide show
  1. data/.gitignore +10 -0
  2. data/.yardopts +3 -0
  3. data/CHANGELOG.md +113 -0
  4. data/LICENSE +20 -0
  5. data/README.md +214 -0
  6. data/Rakefile +260 -0
  7. data/TODO.md +4 -0
  8. data/benchmarking/logging.rb +62 -0
  9. data/benchmarking/pipeline.rb +51 -0
  10. data/benchmarking/speed.rb +21 -0
  11. data/benchmarking/suite.rb +24 -0
  12. data/benchmarking/thread_safety.rb +38 -0
  13. data/benchmarking/worker.rb +71 -0
  14. data/examples/basic.rb +15 -0
  15. data/examples/dist_redis.rb +43 -0
  16. data/examples/incr-decr.rb +17 -0
  17. data/examples/list.rb +26 -0
  18. data/examples/pubsub.rb +31 -0
  19. data/examples/sets.rb +36 -0
  20. data/examples/unicorn/config.ru +3 -0
  21. data/examples/unicorn/unicorn.rb +20 -0
  22. data/lib/redis/client.rb +303 -0
  23. data/lib/redis/connection/command_helper.rb +44 -0
  24. data/lib/redis/connection/hiredis.rb +52 -0
  25. data/lib/redis/connection/registry.rb +12 -0
  26. data/lib/redis/connection/ruby.rb +136 -0
  27. data/lib/redis/connection/synchrony.rb +131 -0
  28. data/lib/redis/connection.rb +9 -0
  29. data/lib/redis/distributed.rb +696 -0
  30. data/lib/redis/errors.rb +38 -0
  31. data/lib/redis/hash_ring.rb +131 -0
  32. data/lib/redis/pipeline.rb +106 -0
  33. data/lib/redis/subscribe.rb +79 -0
  34. data/lib/redis/version.rb +3 -0
  35. data/lib/redis.rb +1724 -0
  36. data/redis.gemspec +43 -0
  37. data/test/command_map_test.rb +29 -0
  38. data/test/commands_on_hashes_test.rb +20 -0
  39. data/test/commands_on_lists_test.rb +60 -0
  40. data/test/commands_on_sets_test.rb +76 -0
  41. data/test/commands_on_sorted_sets_test.rb +108 -0
  42. data/test/commands_on_strings_test.rb +80 -0
  43. data/test/commands_on_value_types_test.rb +87 -0
  44. data/test/connection_handling_test.rb +204 -0
  45. data/test/db/.gitignore +1 -0
  46. data/test/distributed_blocking_commands_test.rb +53 -0
  47. data/test/distributed_commands_on_hashes_test.rb +11 -0
  48. data/test/distributed_commands_on_lists_test.rb +23 -0
  49. data/test/distributed_commands_on_sets_test.rb +84 -0
  50. data/test/distributed_commands_on_sorted_sets_test.rb +19 -0
  51. data/test/distributed_commands_on_strings_test.rb +49 -0
  52. data/test/distributed_commands_on_value_types_test.rb +72 -0
  53. data/test/distributed_commands_requiring_clustering_test.rb +148 -0
  54. data/test/distributed_connection_handling_test.rb +24 -0
  55. data/test/distributed_internals_test.rb +27 -0
  56. data/test/distributed_key_tags_test.rb +52 -0
  57. data/test/distributed_persistence_control_commands_test.rb +23 -0
  58. data/test/distributed_publish_subscribe_test.rb +100 -0
  59. data/test/distributed_remote_server_control_commands_test.rb +42 -0
  60. data/test/distributed_sorting_test.rb +21 -0
  61. data/test/distributed_test.rb +59 -0
  62. data/test/distributed_transactions_test.rb +33 -0
  63. data/test/encoding_test.rb +15 -0
  64. data/test/error_replies_test.rb +53 -0
  65. data/test/helper.rb +155 -0
  66. data/test/helper_test.rb +8 -0
  67. data/test/internals_test.rb +152 -0
  68. data/test/lint/hashes.rb +140 -0
  69. data/test/lint/internals.rb +36 -0
  70. data/test/lint/lists.rb +107 -0
  71. data/test/lint/sets.rb +90 -0
  72. data/test/lint/sorted_sets.rb +196 -0
  73. data/test/lint/strings.rb +133 -0
  74. data/test/lint/value_types.rb +81 -0
  75. data/test/persistence_control_commands_test.rb +21 -0
  76. data/test/pipelining_commands_test.rb +186 -0
  77. data/test/publish_subscribe_test.rb +158 -0
  78. data/test/redis_mock.rb +89 -0
  79. data/test/remote_server_control_commands_test.rb +88 -0
  80. data/test/sorting_test.rb +43 -0
  81. data/test/synchrony_driver.rb +57 -0
  82. data/test/test.conf +9 -0
  83. data/test/thread_safety_test.rb +30 -0
  84. data/test/transactions_test.rb +173 -0
  85. data/test/unknown_commands_test.rb +13 -0
  86. data/test/url_param_test.rb +59 -0
  87. metadata +236 -0
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ nohup.out
2
+ redis/*
3
+ rdsrv
4
+ pkg/*
5
+ coverage/*
6
+ .idea
7
+ *.rdb
8
+ *.swp
9
+ .yardoc
10
+ doc/
data/.yardopts ADDED
@@ -0,0 +1,3 @@
1
+ --exclude redis/connection
2
+ --exclude redis/compat
3
+ --markup markdown
data/CHANGELOG.md ADDED
@@ -0,0 +1,113 @@
1
+ # 3.0 (unreleased)
2
+
3
+ * The `ZRANGE`, `ZREVRANGE`, `ZRANGEBYSCORE` and `ZREVRANGEBYSCORE` commands
4
+ now return an array containing `[String, Float]` pairs when
5
+ `:with_scores => true` is passed.
6
+
7
+ * The `ZINCRBY` and `ZSCORE` commands now return a `Float` score instead
8
+ of a string holding a representation of the score.
9
+
10
+ * The client now raises custom exceptions where it makes sense.
11
+
12
+ If by any chance you were rescuing low-level exceptions (`Errno::*`),
13
+ you should now rescue as follows:
14
+
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
22
+
23
+ * Always raise exceptions originating from erroneous command invocation
24
+ inside pipelines and MULTI/EXEC blocks.
25
+
26
+ The old behavior (swallowing exceptions) could cause application bugs
27
+ to go unnoticed.
28
+
29
+ * Implement futures for assigning values inside pipelines and MULTI/EXEC
30
+ blocks. Futures are assigned their value after the pipeline or
31
+ MULTI/EXEC block has executed.
32
+
33
+ ```ruby
34
+ $redis.pipelined do
35
+ @future = $redis.get "key"
36
+ end
37
+
38
+ puts @future.value
39
+ ```
40
+
41
+ * Ruby 1.8.6 is officially not supported.
42
+
43
+ * Support `ZCOUNT` in `Redis::Distributed` (Michael Dungan).
44
+
45
+ * Pipelined commands now return the same replies as when called outside
46
+ a pipeline.
47
+
48
+ In the past, pipelined replies were returned without post-processing.
49
+
50
+ * Support `SLOWLOG` command (Michael Bernstein).
51
+
52
+ * Calling `SHUTDOWN` effectively disconnects the client (Stefan Kaes).
53
+
54
+ * Basic support for mapping commands so that they can be renamed on the
55
+ server.
56
+
57
+ * Connecting using a URL now checks that a host is given.
58
+
59
+ It's just a small sanity check, cf. #126
60
+
61
+ * Support variadic commands introduced in Redis 2.4.
62
+
63
+ # 2.2.2
64
+
65
+ * Added method `Redis::Distributed#hsetnx`.
66
+
67
+ # 2.2.1
68
+
69
+ * Internal API: Client#call and family are now called with a single array
70
+ argument, since splatting a large number of arguments (100K+) results in a
71
+ stack overflow on 1.9.2.
72
+
73
+ * The `INFO` command can optionally take a subcommand. When the subcommand is
74
+ `COMMANDSTATS`, the client will properly format the returned statistics per
75
+ command. Subcommands for `INFO` are available since Redis v2.3.0 (unstable).
76
+
77
+ * Change `IO#syswrite` back to the buffered `IO#write` since some Rubies do
78
+ short writes for large (1MB+) buffers and some don't (see issue #108).
79
+
80
+ # 2.2.0
81
+
82
+ * Added method `Redis#without_reconnect` that ensures the client will not try
83
+ to reconnect when running the code inside the specified block.
84
+
85
+ * Thread-safe by default. Thread safety can be explicitly disabled by passing
86
+ `:thread_safe => false` as argument.
87
+
88
+ * Commands called inside a MULTI/EXEC no longer raise error replies, since a
89
+ successful EXEC means the commands inside the block were executed.
90
+
91
+ * MULTI/EXEC blocks are pipelined.
92
+
93
+ * Don't disconnect on error replies.
94
+
95
+ * Use `IO#syswrite` instead of `IO#write` because write buffering is not
96
+ necessary.
97
+
98
+ * Connect to a unix socket by passing the `:path` option as argument.
99
+
100
+ * The timeout value is coerced into a float, allowing sub-second timeouts.
101
+
102
+ * Accept both `:with_scores` _and_ `:withscores` as argument to sorted set
103
+ commands.
104
+
105
+ * Use [hiredis](https://github.com/pietern/hiredis-rb) (v0.3 or higher) by
106
+ requiring "redis/connection/hiredis".
107
+
108
+ * Use [em-synchrony](https://github.com/igrigorik/em-synchrony) by requiring
109
+ "redis/connection/synchrony".
110
+
111
+ # 2.1.1
112
+
113
+ See commit log.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Ezra Zygmuntowicz
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,214 @@
1
+ # redis-rb
2
+
3
+ A Ruby client library for the [Redis](http://redis.io) key-value store.
4
+
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
+
8
+ ## A note about versions
9
+
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.
24
+
25
+ ## Getting started
26
+
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
62
+
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
72
+
73
+ Handle groups:
74
+
75
+ >> redis.sadd "admins", "albert"
76
+ => true
77
+
78
+ >> redis.sadd "admins", "isabel"
79
+ => true
80
+
81
+ Users who are also admins:
82
+
83
+ >> redis.sinter "users", "admins"
84
+ => ["albert"]
85
+
86
+ Users who are not admins:
87
+
88
+ >> redis.sdiff "users", "admins"
89
+ => ["bernard", "charles"]
90
+
91
+ Admins who are not users:
92
+
93
+ >> redis.sdiff "admins", "users"
94
+ => ["isabel"]
95
+
96
+ All users and admins:
97
+
98
+ >> redis.sunion "admins", "users"
99
+ => ["albert", "bernard", "charles", "isabel"]
100
+
101
+
102
+ ## Storing objects
103
+
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.
133
+
134
+ ## Alternate drivers
135
+
136
+ Non-default connection drivers are only used when they are explicitly required.
137
+ By default, redis-rb uses Ruby's socket library to talk with Redis.
138
+
139
+ ### hiredis
140
+
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.
147
+
148
+ Using redis-rb with hiredis from a Gemfile:
149
+
150
+ gem "hiredis", "~> 0.3.1"
151
+ gem "redis", "~> 2.2.0", :require => ["redis/connection/hiredis", "redis"]
152
+
153
+ ### synchrony
154
+
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.
162
+
163
+ Using redis-rb with synchrony from a Gemfile:
164
+
165
+ gem "hiredis", "~> 0.3.1"
166
+ gem "em-synchrony"
167
+ gem "redis", "~> 2.2.0", :require => ["redis/connection/synchrony", "redis"]
168
+
169
+ ## Testing
170
+
171
+ This library (v2.2) is tested against the following interpreters:
172
+
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)
177
+
178
+ ## Known issues
179
+
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.
183
+
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
+
190
+ ## More info
191
+
192
+ Check the [Redis Command Reference](http://redis.io/commands) or check the tests to find out how to use this client.
193
+
194
+ ## Contributors
195
+
196
+ (ordered chronologically with more than 5 commits, see `git shortlog -sn` for
197
+ all contributors)
198
+
199
+ * Ezra Zygmuntowicz
200
+ * Taylor Weibley
201
+ * Matthew Clark
202
+ * Brian McKinney
203
+ * Luca Guidi
204
+ * Salvatore Sanfillipo
205
+ * Chris Wanstrath
206
+ * Damian Janowski
207
+ * Michel Martens
208
+ * Nick Quaranto
209
+ * Pieter Noordhuis
210
+ * Ilya Grigorik
211
+
212
+ ## Contributing
213
+
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.
data/Rakefile ADDED
@@ -0,0 +1,260 @@
1
+ require 'rubygems'
2
+ require 'rubygems/package_task'
3
+ require 'rake/testtask'
4
+
5
+ $:.unshift File.join(File.dirname(__FILE__), 'lib')
6
+ require 'redis/version'
7
+
8
+ REDIS_DIR = File.expand_path(File.join("..", "test"), __FILE__)
9
+ REDIS_CNF = File.join(REDIS_DIR, "test.conf")
10
+ REDIS_PID = File.join(REDIS_DIR, "db", "redis.pid")
11
+
12
+ task :default => :run
13
+
14
+ desc "Run tests and manage server start/stop"
15
+ task :run => [:start, :test, :stop]
16
+
17
+ desc "Start the Redis server"
18
+ task :start do
19
+ redis_running = \
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
26
+
27
+ system "redis-server #{REDIS_CNF}" unless redis_running
28
+ end
29
+
30
+ desc "Stop the Redis server"
31
+ task :stop do
32
+ if File.exists?(REDIS_PID)
33
+ Process.kill "INT", File.read(REDIS_PID).to_i
34
+ FileUtils.rm REDIS_PID
35
+ end
36
+ end
37
+
38
+ desc "Run the test suite"
39
+ task :test => ["test:ruby", "test:hiredis", "test:synchrony"]
40
+
41
+ namespace :test do
42
+ desc "Run tests against the Ruby driver"
43
+ task :ruby do
44
+ require "cutest"
45
+
46
+ Cutest.run(Dir["./test/**/*_test.rb"])
47
+ end
48
+
49
+ desc "Run tests against the hiredis driver"
50
+ task :hiredis do
51
+ require "cutest"
52
+
53
+ begin
54
+ require "redis/connection/hiredis"
55
+
56
+ puts
57
+ puts "Running tests against hiredis v#{Hiredis::VERSION}"
58
+
59
+ ENV["REDIS_CONNECTION_DRIVER"] = "hiredis"
60
+ Cutest.run(Dir["./test/**/*_test.rb"])
61
+ rescue LoadError
62
+ puts "Skipping tests against hiredis"
63
+ end
64
+ end
65
+
66
+ desc "Run tests against the em-synchrony driver"
67
+ task :synchrony do
68
+ require "cutest"
69
+
70
+ # Synchrony needs 1.9
71
+ next if RUBY_VERSION < "1.9"
72
+
73
+ begin
74
+ require "redis/connection/synchrony"
75
+
76
+ puts
77
+ puts "Running tests against em-synchrony"
78
+
79
+ threaded_tests = ['./test/thread_safety_test.rb']
80
+
81
+ ENV["REDIS_CONNECTION_DRIVER"] = "synchrony"
82
+ Cutest.run(Dir['./test/**/*_test.rb'] - threaded_tests)
83
+ rescue LoadError
84
+ puts "Skipping tests against em-synchrony"
85
+ end
86
+ end
87
+ end
88
+
89
+ task :doc => ["doc:generate", "doc:prepare"]
90
+
91
+ namespace :doc do
92
+ task :generate do
93
+ require "shellwords"
94
+
95
+ `rm -rf doc`
96
+
97
+ current_branch = `git branch`[/^\* (.*)$/, 1]
98
+
99
+ begin
100
+ tags = `git tag -l`.split("\n").sort.reverse
101
+
102
+ tags.each do |tag|
103
+ `git checkout -q #{tag} 2>/dev/null`
104
+
105
+ unless $?.success?
106
+ $stderr.puts "Need a clean working copy. Please git-stash away."
107
+ exit 1
108
+ end
109
+
110
+ puts tag
111
+
112
+ `mkdir -p doc/#{tag}`
113
+
114
+ files = `git ls-tree -r HEAD lib`.split("\n").map do |line|
115
+ line[/\t(.*)$/, 1]
116
+ end
117
+
118
+ opts = [
119
+ "--title", "A Ruby client for Redis",
120
+ "--output", "doc/#{tag}",
121
+ "--no-cache",
122
+ "--no-save",
123
+ "-q",
124
+ *files
125
+ ]
126
+
127
+ `yardoc #{Shellwords.shelljoin opts}`
128
+ end
129
+ ensure
130
+ `git checkout -q #{current_branch}`
131
+ end
132
+ end
133
+
134
+ task :prepare do
135
+ versions = `git tag -l`.split("\n").grep(/^v/).sort
136
+ latest_version = versions.last
137
+
138
+ File.open("doc/.htaccess", "w") do |file|
139
+ file.puts "RedirectMatch 302 ^/?$ /#{latest_version}"
140
+ end
141
+
142
+ File.open("doc/robots.txt", "w") do |file|
143
+ file.puts "User-Agent: *"
144
+
145
+ (versions - [latest_version]).each do |version|
146
+ file.puts "Disallow: /#{version}"
147
+ end
148
+ end
149
+
150
+ google_analytics = <<-EOS
151
+ <script type="text/javascript">
152
+
153
+ var _gaq = _gaq || [];
154
+ _gaq.push(['_setAccount', 'UA-11356145-2']);
155
+ _gaq.push(['_trackPageview']);
156
+
157
+ (function() {
158
+ var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
159
+ ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
160
+ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
161
+ })();
162
+
163
+ </script>
164
+ EOS
165
+
166
+ Dir["doc/**/*.html"].each do |path|
167
+ lines = IO.readlines(path)
168
+
169
+ File.open(path, "w") do |file|
170
+ lines.each do |line|
171
+ if line.include?("</head>")
172
+ file.write(google_analytics)
173
+ end
174
+
175
+ file.write(line)
176
+ end
177
+ end
178
+ end
179
+ end
180
+
181
+ task :deploy do
182
+ system "rsync --del -avz doc/ redis-rb.keyvalue.org:deploys/redis-rb.keyvalue.org/"
183
+ end
184
+ end
185
+
186
+ namespace :commands do
187
+ def redis_commands
188
+ $redis_commands ||= doc.keys.map do |key|
189
+ key.split(" ").first.downcase
190
+ end.uniq
191
+ end
192
+
193
+ def doc
194
+ $doc ||= begin
195
+ require "open-uri"
196
+ require "json"
197
+
198
+ JSON.parse(open("https://github.com/antirez/redis-doc/raw/master/commands.json").read)
199
+ end
200
+ end
201
+
202
+ def document(file)
203
+ source = File.read(file)
204
+
205
+ doc.each do |name, command|
206
+ source.sub!(/(?:^ *# .*\n)*(^ *#\n(^ *# .+?\n)*)*^( *)def #{name.downcase}(\(|$)/) do
207
+ extra_comments, indent, extra_args = $1, $3, $4
208
+ comment = "#{indent}# #{command["summary"].strip}."
209
+
210
+ IO.popen("par p#{2 + indent.size} 80", "r+") do |io|
211
+ io.puts comment
212
+ io.close_write
213
+ comment = io.read
214
+ end
215
+
216
+ "#{comment}#{extra_comments}#{indent}def #{name.downcase}#{extra_args}"
217
+ end
218
+ end
219
+
220
+ File.open(file, "w") { |f| f.write(source) }
221
+ end
222
+
223
+ task :doc do
224
+ document "lib/redis.rb"
225
+ document "lib/redis/distributed.rb"
226
+ end
227
+
228
+ task :verify do
229
+ require "redis"
230
+ require "stringio"
231
+
232
+ require "./test/helper"
233
+
234
+ OPTIONS[:logger] = Logger.new("./tmp/log")
235
+
236
+ Rake::Task["test:ruby"].invoke
237
+
238
+ redis = Redis.new
239
+
240
+ report = ["Command", "\033[0mDefined?\033[0m", "\033[0mTested?\033[0m"]
241
+
242
+ yes, no = "\033[1;32mYes\033[0m", "\033[1;31mNo\033[0m"
243
+
244
+ log = File.read("./tmp/log")
245
+
246
+ redis_commands.sort.each do |name, _|
247
+ defined, tested = redis.respond_to?(name), log[">> #{name.upcase}"]
248
+
249
+ next if defined && tested
250
+
251
+ report << name
252
+ report << (defined ? yes : no)
253
+ report << (tested ? yes : no)
254
+ end
255
+
256
+ IO.popen("rs 0 3", "w") do |io|
257
+ io.puts report.join("\n")
258
+ end
259
+ end
260
+ end