ryansch-mock_redis 0.2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/.rspec +1 -0
- data/CHANGELOG.md +20 -0
- data/Gemfile +9 -0
- data/LICENSE +19 -0
- data/README.md +94 -0
- data/Rakefile +10 -0
- data/lib/mock_redis.rb +32 -0
- data/lib/mock_redis/assertions.rb +13 -0
- data/lib/mock_redis/database.rb +432 -0
- data/lib/mock_redis/exceptions.rb +3 -0
- data/lib/mock_redis/expire_wrapper.rb +25 -0
- data/lib/mock_redis/hash_methods.rb +102 -0
- data/lib/mock_redis/list_methods.rb +187 -0
- data/lib/mock_redis/multi_db_wrapper.rb +86 -0
- data/lib/mock_redis/set_methods.rb +125 -0
- data/lib/mock_redis/string_methods.rb +195 -0
- data/lib/mock_redis/transaction_wrapper.rb +80 -0
- data/lib/mock_redis/undef_redis_methods.rb +11 -0
- data/lib/mock_redis/utility_methods.rb +22 -0
- data/lib/mock_redis/version.rb +3 -0
- data/lib/mock_redis/zset.rb +110 -0
- data/lib/mock_redis/zset_methods.rb +209 -0
- data/mock_redis.gemspec +24 -0
- data/spec/cloning_spec.rb +96 -0
- data/spec/commands/append_spec.rb +24 -0
- data/spec/commands/auth_spec.rb +7 -0
- data/spec/commands/bgrewriteaof_spec.rb +7 -0
- data/spec/commands/bgsave_spec.rb +7 -0
- data/spec/commands/blpop_spec.rb +55 -0
- data/spec/commands/brpop_spec.rb +54 -0
- data/spec/commands/brpoplpush_spec.rb +53 -0
- data/spec/commands/dbsize_spec.rb +18 -0
- data/spec/commands/decr_spec.rb +34 -0
- data/spec/commands/decrby_spec.rb +34 -0
- data/spec/commands/del_spec.rb +20 -0
- data/spec/commands/echo_spec.rb +11 -0
- data/spec/commands/exists_spec.rb +14 -0
- data/spec/commands/expire_spec.rb +83 -0
- data/spec/commands/expireat_spec.rb +48 -0
- data/spec/commands/flushall_spec.rb +38 -0
- data/spec/commands/flushdb_spec.rb +38 -0
- data/spec/commands/get_spec.rb +23 -0
- data/spec/commands/getbit_spec.rb +34 -0
- data/spec/commands/getrange_spec.rb +22 -0
- data/spec/commands/getset_spec.rb +23 -0
- data/spec/commands/hdel_spec.rb +35 -0
- data/spec/commands/hexists_spec.rb +22 -0
- data/spec/commands/hget_spec.rb +23 -0
- data/spec/commands/hgetall_spec.rb +22 -0
- data/spec/commands/hincrby_spec.rb +52 -0
- data/spec/commands/hkeys_spec.rb +19 -0
- data/spec/commands/hlen_spec.rb +19 -0
- data/spec/commands/hmget_spec.rb +30 -0
- data/spec/commands/hmset_spec.rb +43 -0
- data/spec/commands/hset_spec.rb +23 -0
- data/spec/commands/hsetnx_spec.rb +39 -0
- data/spec/commands/hvals_spec.rb +19 -0
- data/spec/commands/incr_spec.rb +34 -0
- data/spec/commands/incrby_spec.rb +44 -0
- data/spec/commands/info_spec.rb +13 -0
- data/spec/commands/keys_spec.rb +87 -0
- data/spec/commands/lastsave_spec.rb +8 -0
- data/spec/commands/lindex_spec.rb +39 -0
- data/spec/commands/linsert_spec.rb +68 -0
- data/spec/commands/llen_spec.rb +16 -0
- data/spec/commands/lpop_spec.rb +34 -0
- data/spec/commands/lpush_spec.rb +30 -0
- data/spec/commands/lpushx_spec.rb +33 -0
- data/spec/commands/lrange_spec.rb +35 -0
- data/spec/commands/lrem_spec.rb +79 -0
- data/spec/commands/lset_spec.rb +38 -0
- data/spec/commands/ltrim_spec.rb +35 -0
- data/spec/commands/mget_spec.rb +34 -0
- data/spec/commands/move_spec.rb +147 -0
- data/spec/commands/mset_spec.rb +29 -0
- data/spec/commands/msetnx_spec.rb +40 -0
- data/spec/commands/persist_spec.rb +49 -0
- data/spec/commands/ping_spec.rb +7 -0
- data/spec/commands/quit_spec.rb +7 -0
- data/spec/commands/randomkey_spec.rb +20 -0
- data/spec/commands/rename_spec.rb +31 -0
- data/spec/commands/renamenx_spec.rb +36 -0
- data/spec/commands/rpop_spec.rb +34 -0
- data/spec/commands/rpoplpush_spec.rb +45 -0
- data/spec/commands/rpush_spec.rb +30 -0
- data/spec/commands/rpushx_spec.rb +33 -0
- data/spec/commands/sadd_spec.rb +22 -0
- data/spec/commands/save_spec.rb +7 -0
- data/spec/commands/scard_spec.rb +18 -0
- data/spec/commands/sdiff_spec.rb +47 -0
- data/spec/commands/sdiffstore_spec.rb +58 -0
- data/spec/commands/select_spec.rb +53 -0
- data/spec/commands/set_spec.rb +7 -0
- data/spec/commands/setbit_spec.rb +46 -0
- data/spec/commands/setex_spec.rb +22 -0
- data/spec/commands/setnx_spec.rb +25 -0
- data/spec/commands/setrange_spec.rb +30 -0
- data/spec/commands/sinter_spec.rb +41 -0
- data/spec/commands/sinterstore_spec.rb +53 -0
- data/spec/commands/sismember_spec.rb +29 -0
- data/spec/commands/smembers_spec.rb +18 -0
- data/spec/commands/smove_spec.rb +41 -0
- data/spec/commands/spop_spec.rb +25 -0
- data/spec/commands/srandmember_spec.rb +25 -0
- data/spec/commands/srem_spec.rb +35 -0
- data/spec/commands/strlen_spec.rb +19 -0
- data/spec/commands/sunion_spec.rb +40 -0
- data/spec/commands/sunionstore_spec.rb +53 -0
- data/spec/commands/ttl_spec.rb +36 -0
- data/spec/commands/type_spec.rb +36 -0
- data/spec/commands/unwatch_spec.rb +7 -0
- data/spec/commands/watch_spec.rb +7 -0
- data/spec/commands/zadd_spec.rb +29 -0
- data/spec/commands/zcard_spec.rb +19 -0
- data/spec/commands/zcount_spec.rb +23 -0
- data/spec/commands/zincrby_spec.rb +24 -0
- data/spec/commands/zinterstore_spec.rb +96 -0
- data/spec/commands/zrange_spec.rb +31 -0
- data/spec/commands/zrangebyscore_spec.rb +68 -0
- data/spec/commands/zrank_spec.rb +23 -0
- data/spec/commands/zrem_spec.rb +25 -0
- data/spec/commands/zremrangebyrank_spec.rb +22 -0
- data/spec/commands/zremrangebyscore_spec.rb +28 -0
- data/spec/commands/zrevrange_spec.rb +31 -0
- data/spec/commands/zrevrangebyscore_spec.rb +47 -0
- data/spec/commands/zrevrank_spec.rb +23 -0
- data/spec/commands/zscore_spec.rb +16 -0
- data/spec/commands/zunionstore_spec.rb +104 -0
- data/spec/spec_helper.rb +44 -0
- data/spec/support/redis_multiplexer.rb +91 -0
- data/spec/support/shared_examples/only_operates_on_hashes.rb +13 -0
- data/spec/support/shared_examples/only_operates_on_lists.rb +13 -0
- data/spec/support/shared_examples/only_operates_on_sets.rb +13 -0
- data/spec/support/shared_examples/only_operates_on_strings.rb +13 -0
- data/spec/support/shared_examples/only_operates_on_zsets.rb +57 -0
- data/spec/transactions_spec.rb +96 -0
- metadata +361 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
-c -d
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
### 0.2.0
|
2
|
+
* Support passing a block to `#multi`.
|
3
|
+
|
4
|
+
### 0.1.2
|
5
|
+
* Fixes for 1.9.2; no functionality changes.
|
6
|
+
|
7
|
+
### 0.1.1
|
8
|
+
* Fix handling of -inf, +inf, and exclusive endpoints (e.g. "(3") in
|
9
|
+
zrangebyscore, zrevrangebyscore, and zremrangebyscore. ("Fix" here
|
10
|
+
means "write", as it's something that was completely forgotten the
|
11
|
+
first time around.)
|
12
|
+
|
13
|
+
### 0.1.0
|
14
|
+
* Support `move(key, db)` to move keys between databases.
|
15
|
+
|
16
|
+
### 0.0.2
|
17
|
+
* Fix gem homepage.
|
18
|
+
|
19
|
+
### 0.0.1
|
20
|
+
Initial release.
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2011 Philotic, Inc.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
# MockRedis
|
2
|
+
|
3
|
+
A mock redis gem.
|
4
|
+
|
5
|
+
MockRedis provides the same interface as redis-rb, but it stores its
|
6
|
+
data in memory instead of talking to a Redis server. It is intended
|
7
|
+
for use in tests.
|
8
|
+
|
9
|
+
## Getting Started
|
10
|
+
|
11
|
+
It's as easy as `require 'mock_redis'; mr = MockRedis.new`. Then you can
|
12
|
+
call the same methods on it as you can call on a real `Redis` object.
|
13
|
+
|
14
|
+
For example:
|
15
|
+
|
16
|
+
>> require 'mock_redis'
|
17
|
+
>> mr = MockRedis.new
|
18
|
+
>> mr.set('some key', 'some value')
|
19
|
+
=> "OK"
|
20
|
+
>> mr.get('some key')
|
21
|
+
=> "some value"
|
22
|
+
|
23
|
+
## Supported Features
|
24
|
+
|
25
|
+
mock_redis supports most of the methods that redis-rb does. Examples
|
26
|
+
of supported methods:
|
27
|
+
|
28
|
+
* String methods: `get`, `set`, `append`, `incr`, etc.
|
29
|
+
* List methods: `lpush`, `lpop`, `lrange`, `rpoplpush`, etc.
|
30
|
+
* Set methods: `sadd`, `sinter`, `sismember`, etc.
|
31
|
+
* Hash methods: `hset`, `hget`, `hgetall`, `hmget`, etc.
|
32
|
+
* Sorted set methods: `zadd`, `zrank`, `zunionstore`, etc.
|
33
|
+
* Expirations: `expire`, `ttl`, etc.
|
34
|
+
* Transactions: `multi`, `exec`, `discard`
|
35
|
+
|
36
|
+
## Mostly-Supported Commands
|
37
|
+
|
38
|
+
A MockRedis object can't do everything that a real Redis client can
|
39
|
+
since it's an in-memory object confined to a single process. MockRedis
|
40
|
+
makes every attempt to be Redis-compatible, but there are some
|
41
|
+
necessary exceptions.
|
42
|
+
|
43
|
+
* Blocking list commands (`#blpop`, `#brpop`, and `#brpoplpush`) work
|
44
|
+
as expected if there is data for them to retrieve. If you use one of
|
45
|
+
these commands with a nonzero timeout and there is no data for it to
|
46
|
+
retrieve, then the command returns immediately. However, if you ask
|
47
|
+
one of these commands for data with a 0 timeout (means "wait
|
48
|
+
forever") and there is no data available, then a
|
49
|
+
`MockRedis::WouldBlock` exception is raised. It's not what a real
|
50
|
+
Redis client would do, but it beats hanging your test run forever.
|
51
|
+
|
52
|
+
* `#info` just returns canned values; they don't update over time.
|
53
|
+
|
54
|
+
## Unsupported Commands
|
55
|
+
|
56
|
+
Some stuff, we just can't do with a single Ruby object in a single
|
57
|
+
Ruby process.
|
58
|
+
|
59
|
+
* Debugging commands (`#debug('object', key)` and
|
60
|
+
`#debug('segfault')`) aren't available.
|
61
|
+
|
62
|
+
* `#object` isn't available since we don't have any Redis internals to
|
63
|
+
poke at.
|
64
|
+
|
65
|
+
* `#monitor` isn't available; there's no place for requests to come
|
66
|
+
from, so there's nothing to receive.
|
67
|
+
|
68
|
+
* Pubsub commands (`#psubscribe`, `#publish`, `#punsubscribe`) aren't
|
69
|
+
available.
|
70
|
+
|
71
|
+
* `#slowlog` isn't available.
|
72
|
+
|
73
|
+
## Remaining Work
|
74
|
+
|
75
|
+
There are some things we want to have in here, but that we just
|
76
|
+
haven't gotten to doing yet. If you're interested in helping out,
|
77
|
+
please submit a pull request with your (tested!) implementation.
|
78
|
+
|
79
|
+
* `#config(:get|:set|:resetstat)` isn't done. They can just return
|
80
|
+
canned values.
|
81
|
+
|
82
|
+
* `#sort` isn't done. We just haven't gotten to it yet. The input
|
83
|
+
validation will be a pain in the butt, but other than that, it
|
84
|
+
shouldn't be too bad.
|
85
|
+
|
86
|
+
## Running the Tests
|
87
|
+
|
88
|
+
If you want to work on this, you'll probably want to run the
|
89
|
+
tests. (Just kidding! There's no probably about it.) These tests were
|
90
|
+
written with Redis 2.2.11 running on localhost without any passwords
|
91
|
+
required. If you're using a different version of Redis, you may see
|
92
|
+
failures due to error message text being different. If you're running
|
93
|
+
a really old version of Redis, you'll definitely see failures due to
|
94
|
+
stuff that doesn't work!
|
data/Rakefile
ADDED
data/lib/mock_redis.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
require 'mock_redis/assertions'
|
4
|
+
require 'mock_redis/database'
|
5
|
+
require 'mock_redis/expire_wrapper'
|
6
|
+
require 'mock_redis/multi_db_wrapper'
|
7
|
+
require 'mock_redis/transaction_wrapper'
|
8
|
+
require 'mock_redis/undef_redis_methods'
|
9
|
+
|
10
|
+
class MockRedis
|
11
|
+
include UndefRedisMethods
|
12
|
+
|
13
|
+
def initialize(*args)
|
14
|
+
@db = TransactionWrapper.new(
|
15
|
+
ExpireWrapper.new(
|
16
|
+
MultiDbWrapper.new(
|
17
|
+
Database.new(*args))))
|
18
|
+
end
|
19
|
+
|
20
|
+
def respond_to?(method, include_private=false)
|
21
|
+
super || @db.respond_to?(method, include_private)
|
22
|
+
end
|
23
|
+
|
24
|
+
def method_missing(method, *args, &block)
|
25
|
+
@db.send(method, *args, &block)
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize_copy(source)
|
29
|
+
super
|
30
|
+
@db = @db.clone
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,432 @@
|
|
1
|
+
require 'mock_redis/assertions'
|
2
|
+
require 'mock_redis/exceptions'
|
3
|
+
require 'mock_redis/hash_methods'
|
4
|
+
require 'mock_redis/list_methods'
|
5
|
+
require 'mock_redis/set_methods'
|
6
|
+
require 'mock_redis/string_methods'
|
7
|
+
require 'mock_redis/zset_methods'
|
8
|
+
|
9
|
+
class MockRedis
|
10
|
+
class Database
|
11
|
+
include HashMethods
|
12
|
+
include ListMethods
|
13
|
+
include SetMethods
|
14
|
+
include StringMethods
|
15
|
+
include ZsetMethods
|
16
|
+
|
17
|
+
attr_reader :data, :expire_times
|
18
|
+
|
19
|
+
def initialize(*args)
|
20
|
+
@data = {}
|
21
|
+
@expire_times = []
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize_copy(source)
|
25
|
+
@data = @data.clone
|
26
|
+
@data.keys.each {|k| @data[k] = @data[k].clone}
|
27
|
+
@expire_times = @expire_times.map{|x| x.clone}
|
28
|
+
end
|
29
|
+
|
30
|
+
# Redis commands go below this line and above 'private'
|
31
|
+
|
32
|
+
def auth(_) 'OK' end
|
33
|
+
|
34
|
+
def bgrewriteaof() "Background append only file rewriting started" end
|
35
|
+
|
36
|
+
def bgsave() "Background saving started" end
|
37
|
+
|
38
|
+
def dbsize
|
39
|
+
data.keys.length
|
40
|
+
end
|
41
|
+
|
42
|
+
def del(*keys)
|
43
|
+
keys.
|
44
|
+
find_all{|key| data[key]}.
|
45
|
+
each {|k| persist(k)}.
|
46
|
+
each {|k| data.delete(k)}.
|
47
|
+
length
|
48
|
+
end
|
49
|
+
|
50
|
+
def echo(msg)
|
51
|
+
msg.to_s
|
52
|
+
end
|
53
|
+
|
54
|
+
def expire(key, seconds)
|
55
|
+
expireat(key, Time.now.to_i + seconds.to_i)
|
56
|
+
end
|
57
|
+
|
58
|
+
def expireat(key, timestamp)
|
59
|
+
unless looks_like_integer?(timestamp.to_s)
|
60
|
+
raise RuntimeError, "ERR value is not an integer or out of range"
|
61
|
+
end
|
62
|
+
|
63
|
+
if exists(key)
|
64
|
+
set_expiration(key, Time.at(timestamp.to_i))
|
65
|
+
true
|
66
|
+
else
|
67
|
+
false
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def exists(key)
|
72
|
+
data.has_key?(key)
|
73
|
+
end
|
74
|
+
|
75
|
+
def flushdb
|
76
|
+
data.keys.each {|k| del(k)}
|
77
|
+
'OK'
|
78
|
+
end
|
79
|
+
|
80
|
+
def info
|
81
|
+
astats = [
|
82
|
+
["2", "2699"],
|
83
|
+
["6", "1"],
|
84
|
+
["7", "1"],
|
85
|
+
["8", "17197"],
|
86
|
+
["9", "109875"],
|
87
|
+
["10", "94348"],
|
88
|
+
["11", "32580"],
|
89
|
+
["12", "52347"],
|
90
|
+
["13", "86475"],
|
91
|
+
["14", "58175"],
|
92
|
+
["15", "53408"],
|
93
|
+
["16", "876949"],
|
94
|
+
["17", "71157"],
|
95
|
+
["18", "5104"],
|
96
|
+
["19", "2705"],
|
97
|
+
["20", "2903"],
|
98
|
+
["21", "1024"],
|
99
|
+
["22", "2546"],
|
100
|
+
["23", "952"],
|
101
|
+
["24", "186080"],
|
102
|
+
["25", "611"],
|
103
|
+
["26", "40936"],
|
104
|
+
["27", "960"],
|
105
|
+
["28", "1323"],
|
106
|
+
["29", "14216"],
|
107
|
+
["30", "52412"],
|
108
|
+
["31", "21130"],
|
109
|
+
["32", "47959"],
|
110
|
+
["33", "6891"],
|
111
|
+
["34", "9712"],
|
112
|
+
["35", "3366"],
|
113
|
+
["36", "5737"],
|
114
|
+
["37", "11274"],
|
115
|
+
["38", "8057"],
|
116
|
+
["39", "2957"],
|
117
|
+
["40", "51200"],
|
118
|
+
["42", "8220"],
|
119
|
+
["43", "8278"],
|
120
|
+
["44", "6539"],
|
121
|
+
["45", "764"],
|
122
|
+
["47", "1018"],
|
123
|
+
["48", "19250"],
|
124
|
+
["49", "713"],
|
125
|
+
["51", "51"],
|
126
|
+
["53", "2"],
|
127
|
+
["55", "3922"],
|
128
|
+
["56", "153"],
|
129
|
+
["57", "614"],
|
130
|
+
["58", "1"],
|
131
|
+
["59", "1775"],
|
132
|
+
["61", "32865"],
|
133
|
+
["63", "2530"],
|
134
|
+
["64", "565"],
|
135
|
+
["65", "1322"],
|
136
|
+
["67", "1572"],
|
137
|
+
["69", "1421"],
|
138
|
+
["71", "1220"],
|
139
|
+
["72", "241"],
|
140
|
+
["73", "5432"],
|
141
|
+
["74", "1122"],
|
142
|
+
["75", "2555"],
|
143
|
+
["77", "1539"],
|
144
|
+
["78", "612"],
|
145
|
+
["79", "902"],
|
146
|
+
["81", "1678"],
|
147
|
+
["83", "51"],
|
148
|
+
["84", "612"],
|
149
|
+
["85", "706"],
|
150
|
+
["87", "410"],
|
151
|
+
["88", "5435"],
|
152
|
+
["89", "813"],
|
153
|
+
["90", "612"],
|
154
|
+
["93", "153"],
|
155
|
+
["94", "612"],
|
156
|
+
["96", "159"],
|
157
|
+
["97", "306"],
|
158
|
+
["99", "153"],
|
159
|
+
["101", "456"],
|
160
|
+
["103", "741"],
|
161
|
+
["105", "447"],
|
162
|
+
["107", "754"],
|
163
|
+
["109", "414"],
|
164
|
+
["111", "475"],
|
165
|
+
["113", "757"],
|
166
|
+
["115", "287"],
|
167
|
+
["117", "420"],
|
168
|
+
["118", "765"],
|
169
|
+
["119", "642"],
|
170
|
+
["120", "159"],
|
171
|
+
["121", "926"],
|
172
|
+
["122", "612"],
|
173
|
+
["123", "251"],
|
174
|
+
["125", "390"],
|
175
|
+
["127", "354"],
|
176
|
+
["128", "617"],
|
177
|
+
["129", "528"],
|
178
|
+
["131", "298"],
|
179
|
+
["132", "612"],
|
180
|
+
["133", "809"],
|
181
|
+
["135", "244"],
|
182
|
+
["136", "306"],
|
183
|
+
["137", "504"],
|
184
|
+
["139", "201"],
|
185
|
+
["141", "1124"],
|
186
|
+
["143", "139"],
|
187
|
+
["144", "159"],
|
188
|
+
["145", "1322"],
|
189
|
+
["147", "410"],
|
190
|
+
["149", "253"],
|
191
|
+
["151", "304"],
|
192
|
+
["153", "312"],
|
193
|
+
["155", "249"],
|
194
|
+
["157", "306"],
|
195
|
+
["159", "348"],
|
196
|
+
["161", "255"],
|
197
|
+
["163", "458"],
|
198
|
+
["165", "5"],
|
199
|
+
["167", "306"],
|
200
|
+
["168", "47"],
|
201
|
+
["169", "214"],
|
202
|
+
["171", "250"],
|
203
|
+
["173", "5"],
|
204
|
+
["177", "10"],
|
205
|
+
["179", "158"],
|
206
|
+
["181", "5"],
|
207
|
+
["183", "10"],
|
208
|
+
["185", "51"],
|
209
|
+
["187", "49"],
|
210
|
+
["191", "5"],
|
211
|
+
["192", "47"],
|
212
|
+
["193", "51"],
|
213
|
+
["197", "112"],
|
214
|
+
["199", "5"],
|
215
|
+
["201", "5"],
|
216
|
+
["203", "5"],
|
217
|
+
["209", "5"],
|
218
|
+
["213", "51"],
|
219
|
+
["217", "102"],
|
220
|
+
["225", "357"],
|
221
|
+
["229", "51"],
|
222
|
+
["233", "204"],
|
223
|
+
["237", "51"],
|
224
|
+
["239", "1"],
|
225
|
+
["247", "46"],
|
226
|
+
["255", "102"],
|
227
|
+
[">=256", "6201"],
|
228
|
+
]
|
229
|
+
|
230
|
+
{
|
231
|
+
"allocation_stats" => astats.map {|(a,b)| "#{a}=#{b}"}.join(','),
|
232
|
+
"aof_enabled" => "0",
|
233
|
+
"arch_bits" => "64",
|
234
|
+
"bgrewriteaof_in_progress" => "0",
|
235
|
+
"bgsave_in_progress" => "0",
|
236
|
+
"blocked_clients" => "0",
|
237
|
+
"changes_since_last_save" => "0",
|
238
|
+
"client_biggest_input_buf" => "0",
|
239
|
+
"client_longest_output_list" => "0",
|
240
|
+
"connected_clients" => "1",
|
241
|
+
"connected_slaves" => "0",
|
242
|
+
"db0" => "keys=8,expires=0",
|
243
|
+
"evicted_keys" => "0",
|
244
|
+
"expired_keys" => "0",
|
245
|
+
"hash_max_zipmap_entries" => "512",
|
246
|
+
"hash_max_zipmap_value" => "64",
|
247
|
+
"keyspace_hits" => "62645",
|
248
|
+
"keyspace_misses" => "29757",
|
249
|
+
"last_save_time" => "1310596333",
|
250
|
+
"loading" => "0",
|
251
|
+
"lru_clock" => "1036434",
|
252
|
+
"mem_fragmentation_ratio" => "2.04",
|
253
|
+
"multiplexing_api" => "kqueue",
|
254
|
+
"process_id" => "14508",
|
255
|
+
"pubsub_channels" => "0",
|
256
|
+
"pubsub_patterns" => "0",
|
257
|
+
"redis_git_dirty" => "0",
|
258
|
+
"redis_git_sha1" => "00000000",
|
259
|
+
"redis_version" => "2.2.11",
|
260
|
+
"role" => "master",
|
261
|
+
"total_commands_processed" => "196800",
|
262
|
+
"total_connections_received" => "4359",
|
263
|
+
"uptime_in_days" => "0",
|
264
|
+
"uptime_in_seconds" => "84215",
|
265
|
+
"use_tcmalloc" => "0",
|
266
|
+
"used_cpu_sys" => "5.54",
|
267
|
+
"used_cpu_sys_childrens" => "0.00",
|
268
|
+
"used_cpu_user" => "7.65",
|
269
|
+
"used_cpu_user_childrens" => "0.02",
|
270
|
+
"used_memory" => "931456",
|
271
|
+
"used_memory_human" => "909.62K",
|
272
|
+
"used_memory_rss" => "1904640",
|
273
|
+
"vm_enabled" => "0",
|
274
|
+
}
|
275
|
+
end
|
276
|
+
|
277
|
+
def keys(format)
|
278
|
+
data.keys.grep(redis_pattern_to_ruby_regex(format))
|
279
|
+
end
|
280
|
+
|
281
|
+
def lastsave
|
282
|
+
Time.now.to_i
|
283
|
+
end
|
284
|
+
|
285
|
+
def persist(key)
|
286
|
+
if exists(key) && has_expiration?(key)
|
287
|
+
remove_expiration(key)
|
288
|
+
true
|
289
|
+
else
|
290
|
+
false
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
def ping
|
295
|
+
'PONG'
|
296
|
+
end
|
297
|
+
|
298
|
+
def quit
|
299
|
+
'OK'
|
300
|
+
end
|
301
|
+
|
302
|
+
def randomkey
|
303
|
+
data.keys[rand(data.length)]
|
304
|
+
end
|
305
|
+
|
306
|
+
def rename(key, newkey)
|
307
|
+
if key == newkey
|
308
|
+
raise RuntimeError, "ERR source and destination objects are the same"
|
309
|
+
end
|
310
|
+
data[newkey] = data.delete(key)
|
311
|
+
'OK'
|
312
|
+
end
|
313
|
+
|
314
|
+
def renamenx(key, newkey)
|
315
|
+
if key == newkey
|
316
|
+
raise RuntimeError, "ERR source and destination objects are the same"
|
317
|
+
end
|
318
|
+
if exists(newkey)
|
319
|
+
false
|
320
|
+
else
|
321
|
+
rename(key, newkey)
|
322
|
+
true
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
def save
|
327
|
+
'OK'
|
328
|
+
end
|
329
|
+
|
330
|
+
def ttl(key)
|
331
|
+
if has_expiration?(key)
|
332
|
+
(expiration(key) - Time.now).to_i
|
333
|
+
else
|
334
|
+
-1
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
def type(key)
|
339
|
+
if !exists(key)
|
340
|
+
'none'
|
341
|
+
elsif hashy?(key)
|
342
|
+
'hash'
|
343
|
+
elsif stringy?(key)
|
344
|
+
'string'
|
345
|
+
elsif listy?(key)
|
346
|
+
'list'
|
347
|
+
elsif sety?(key)
|
348
|
+
'set'
|
349
|
+
elsif zsety?(key)
|
350
|
+
'zset'
|
351
|
+
else
|
352
|
+
raise ArgumentError, "Not sure how #{data[key].inspect} got in here"
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
private
|
357
|
+
|
358
|
+
def assert_valid_timeout(timeout)
|
359
|
+
if !looks_like_integer?(timeout.to_s)
|
360
|
+
raise RuntimeError, "ERR timeout is not an integer or out of range"
|
361
|
+
elsif timeout < 0
|
362
|
+
raise RuntimeError, "ERR timeout is negative"
|
363
|
+
end
|
364
|
+
timeout
|
365
|
+
end
|
366
|
+
|
367
|
+
def can_incr?(value)
|
368
|
+
value.nil? || looks_like_integer?(value)
|
369
|
+
end
|
370
|
+
|
371
|
+
def extract_timeout(arglist)
|
372
|
+
timeout = assert_valid_timeout(arglist.last)
|
373
|
+
[arglist[0..-2], arglist.last]
|
374
|
+
end
|
375
|
+
|
376
|
+
def expiration(key)
|
377
|
+
expire_times.find {|(_,k)| k == key}.first
|
378
|
+
end
|
379
|
+
|
380
|
+
def has_expiration?(key)
|
381
|
+
expire_times.any? {|(_,k)| k == key}
|
382
|
+
end
|
383
|
+
|
384
|
+
def looks_like_integer?(str)
|
385
|
+
str =~ /^-?\d+$/
|
386
|
+
end
|
387
|
+
|
388
|
+
def redis_pattern_to_ruby_regex(pattern)
|
389
|
+
Regexp.new(
|
390
|
+
"^#{pattern}$".
|
391
|
+
gsub(/([^\\])\?/, "\\1.").
|
392
|
+
gsub(/([^\\])\*/, "\\1.+"))
|
393
|
+
end
|
394
|
+
|
395
|
+
def remove_expiration(key)
|
396
|
+
expire_times.delete_if do |(t, k)|
|
397
|
+
key == k
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
def set_expiration(key, time)
|
402
|
+
remove_expiration(key)
|
403
|
+
|
404
|
+
expire_times << [time, key]
|
405
|
+
expire_times.sort! do |a, b|
|
406
|
+
a.first <=> b.first
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
def zero_pad(string, desired_length)
|
411
|
+
padding = "\000" * [(desired_length - string.length), 0].max
|
412
|
+
string + padding
|
413
|
+
end
|
414
|
+
|
415
|
+
public
|
416
|
+
# This method isn't private, but it also isn't a Redis command, so
|
417
|
+
# it doesn't belong up above with all the Redis commands.
|
418
|
+
def expire_keys
|
419
|
+
now = Time.now
|
420
|
+
|
421
|
+
to_delete = expire_times.take_while do |(time, key)|
|
422
|
+
time <= now
|
423
|
+
end
|
424
|
+
|
425
|
+
to_delete.each do |(time, key)|
|
426
|
+
del(key)
|
427
|
+
end
|
428
|
+
|
429
|
+
expire_times.slice!(0, to_delete.length)
|
430
|
+
end
|
431
|
+
end
|
432
|
+
end
|