ryansch-mock_redis 0.2.0.1
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.
- 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
|