mock_redis 0.46.0 → 0.48.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/README.md +3 -2
- data/lib/mock_redis/assertions.rb +20 -3
- data/lib/mock_redis/database.rb +17 -22
- data/lib/mock_redis/error.rb +27 -0
- data/lib/mock_redis/geospatial_methods.rb +9 -7
- data/lib/mock_redis/hash_methods.rb +49 -15
- data/lib/mock_redis/list_methods.rb +42 -17
- data/lib/mock_redis/set_methods.rb +23 -7
- data/lib/mock_redis/sort_method.rb +1 -1
- data/lib/mock_redis/stream_methods.rb +7 -2
- data/lib/mock_redis/string_methods.rb +25 -25
- data/lib/mock_redis/transaction_wrapper.rb +20 -28
- data/lib/mock_redis/version.rb +1 -1
- data/lib/mock_redis/zset_methods.rb +19 -16
- data/lib/mock_redis.rb +1 -0
- metadata +12 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b443f014758e0bcf36ab97b1b52c8835e445b6d08c3934f00171a9d0c2ab8b8
|
4
|
+
data.tar.gz: 401f2c621a340ae75c59409943718a6fdcfbb76c816d38651f93d9548e086d71
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 52ea483bccaab28544bfa90773463085afea971730b8ccb715127cb1815d6de4e007f6d4fac9b055aa2e659720a24618e392a96992875cc77d36d151e9389c32
|
7
|
+
data.tar.gz: 141763ba4434ed736d5f28f50e9ec5b012d040fdf0aaa00c8a11a736165a02db7912624841fb319109bec1465aaeb05a49b48adb6c74b08dbfb1976d715bb031
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
# MockRedis Changelog
|
2
2
|
|
3
|
+
### 0.48.1
|
4
|
+
|
5
|
+
* Fix load issue with `redis-client` gem
|
6
|
+
|
7
|
+
### 0.48.0
|
8
|
+
|
9
|
+
* Add support for `lmpop` on Redis 7+
|
10
|
+
|
11
|
+
### 0.47.0
|
12
|
+
|
13
|
+
* Add support for `redis-rb` gem versions 5.x
|
14
|
+
* Drop support for `redis-rb` gem versions < 5.x
|
15
|
+
|
3
16
|
### 0.46.0
|
4
17
|
|
5
18
|
* Fix `hset` for array of key-value pairs
|
data/README.md
CHANGED
@@ -10,9 +10,10 @@ for use in tests.
|
|
10
10
|
|
11
11
|
## Requirements
|
12
12
|
|
13
|
-
Ruby 3.
|
13
|
+
Ruby 3.x
|
14
|
+
redis-rb 5.x
|
14
15
|
|
15
|
-
The current implementation is tested against Redis 6.2. Older versions may work, but can also return different results or not support some commands.
|
16
|
+
The current implementation is **tested against Redis 6.2 and 7.0**. Older versions may work, but can also return different results or not support some commands.
|
16
17
|
|
17
18
|
## Getting Started
|
18
19
|
|
@@ -1,11 +1,28 @@
|
|
1
|
+
require 'redis-client'
|
2
|
+
require 'mock_redis/error'
|
3
|
+
|
1
4
|
class MockRedis
|
5
|
+
DUMP_TYPES = RedisClient::RESP3::DUMP_TYPES
|
6
|
+
|
2
7
|
module Assertions
|
3
8
|
private
|
4
9
|
|
5
10
|
def assert_has_args(args, command)
|
6
|
-
|
7
|
-
raise
|
8
|
-
|
11
|
+
if args.empty?
|
12
|
+
raise Error.command_error(
|
13
|
+
"ERR wrong number of arguments for '#{command}' command",
|
14
|
+
self
|
15
|
+
)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def assert_type(*args)
|
20
|
+
args.each do |arg|
|
21
|
+
DUMP_TYPES.fetch(arg.class) do |unexpected_class|
|
22
|
+
unless DUMP_TYPES.keys.find { |t| t > unexpected_class }
|
23
|
+
raise TypeError, "Unsupported command argument type: #{unexpected_class}"
|
24
|
+
end
|
25
|
+
end
|
9
26
|
end
|
10
27
|
end
|
11
28
|
end
|
data/lib/mock_redis/database.rb
CHANGED
@@ -95,13 +95,13 @@ class MockRedis
|
|
95
95
|
end
|
96
96
|
|
97
97
|
def expire(key, seconds, nx: nil, xx: nil, lt: nil, gt: nil) # rubocop:disable Metrics/ParameterLists
|
98
|
-
|
98
|
+
seconds = Integer(seconds)
|
99
99
|
|
100
100
|
pexpire(key, seconds.to_i * 1000, nx: nx, xx: xx, lt: lt, gt: gt)
|
101
101
|
end
|
102
102
|
|
103
103
|
def pexpire(key, ms, nx: nil, xx: nil, lt: nil, gt: nil) # rubocop:disable Metrics/ParameterLists
|
104
|
-
|
104
|
+
ms = Integer(ms)
|
105
105
|
|
106
106
|
now, miliseconds = @base.now
|
107
107
|
now_ms = (now * 1000) + miliseconds
|
@@ -109,18 +109,19 @@ class MockRedis
|
|
109
109
|
end
|
110
110
|
|
111
111
|
def expireat(key, timestamp, nx: nil, xx: nil, lt: nil, gt: nil) # rubocop:disable Metrics/ParameterLists
|
112
|
-
|
112
|
+
timestamp = Integer(timestamp)
|
113
113
|
|
114
114
|
pexpireat(key, timestamp.to_i * 1000, nx: nx, xx: xx, lt: lt, gt: gt)
|
115
115
|
end
|
116
116
|
|
117
117
|
def pexpireat(key, timestamp_ms, nx: nil, xx: nil, lt: nil, gt: nil) # rubocop:disable Metrics/ParameterLists
|
118
|
-
|
118
|
+
timestamp_ms = Integer(timestamp_ms)
|
119
119
|
|
120
120
|
if nx && gt || gt && lt || lt && nx || nx && xx
|
121
|
-
raise
|
122
|
-
ERR NX and XX, GT or LT options at the same time are not compatible
|
123
|
-
|
121
|
+
raise Error.command_error(
|
122
|
+
'ERR NX and XX, GT or LT options at the same time are not compatible',
|
123
|
+
self
|
124
|
+
)
|
124
125
|
end
|
125
126
|
|
126
127
|
return false unless exists?(key)
|
@@ -157,7 +158,7 @@ class MockRedis
|
|
157
158
|
|
158
159
|
def restore(key, ttl, value, replace: false)
|
159
160
|
if !replace && exists?(key)
|
160
|
-
raise
|
161
|
+
raise Error.command_error('BUSYKEY Target key name already exists.', self)
|
161
162
|
end
|
162
163
|
data[key] = Marshal.load(value) # rubocop:disable Security/MarshalLoad
|
163
164
|
if ttl > 0
|
@@ -211,7 +212,7 @@ class MockRedis
|
|
211
212
|
|
212
213
|
def rename(key, newkey)
|
213
214
|
unless data.include?(key)
|
214
|
-
raise
|
215
|
+
raise Error.command_error('ERR no such key', self)
|
215
216
|
end
|
216
217
|
|
217
218
|
if key != newkey
|
@@ -227,7 +228,7 @@ class MockRedis
|
|
227
228
|
|
228
229
|
def renamenx(key, newkey)
|
229
230
|
unless data.include?(key)
|
230
|
-
raise
|
231
|
+
raise Error.command_error('ERR no such key', self)
|
231
232
|
end
|
232
233
|
|
233
234
|
if exists?(newkey)
|
@@ -301,19 +302,13 @@ class MockRedis
|
|
301
302
|
|
302
303
|
private
|
303
304
|
|
304
|
-
def assert_valid_integer(integer)
|
305
|
-
unless looks_like_integer?(integer.to_s)
|
306
|
-
raise Redis::CommandError, 'ERR value is not an integer or out of range'
|
307
|
-
end
|
308
|
-
integer
|
309
|
-
end
|
310
|
-
|
311
305
|
def assert_valid_timeout(timeout)
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
raise
|
306
|
+
timeout = Integer(timeout)
|
307
|
+
|
308
|
+
if timeout < 0
|
309
|
+
raise ArgumentError, 'time interval must not be negative'
|
316
310
|
end
|
311
|
+
|
317
312
|
timeout
|
318
313
|
end
|
319
314
|
|
@@ -347,7 +342,7 @@ class MockRedis
|
|
347
342
|
end
|
348
343
|
|
349
344
|
def looks_like_integer?(str)
|
350
|
-
str
|
345
|
+
!!Integer(str) rescue false
|
351
346
|
end
|
352
347
|
|
353
348
|
def looks_like_float?(str)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class MockRedis
|
2
|
+
module Error
|
3
|
+
module_function
|
4
|
+
|
5
|
+
def build(error_class, message, database)
|
6
|
+
connection = database.connection
|
7
|
+
url = "redis://#{connection[:host]}:#{connection[:port]}"
|
8
|
+
error_class.new("#{message} (#{url})")
|
9
|
+
end
|
10
|
+
|
11
|
+
def wrong_type_error(database)
|
12
|
+
build(
|
13
|
+
Redis::WrongTypeError,
|
14
|
+
'WRONGTYPE Operation against a key holding the wrong kind of value',
|
15
|
+
database
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
def syntax_error(database)
|
20
|
+
command_error('ERR syntax error', database)
|
21
|
+
end
|
22
|
+
|
23
|
+
def command_error(message, database)
|
24
|
+
build(Redis::CommandError, message, database)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'mock_redis/error'
|
2
|
+
|
1
3
|
class MockRedis
|
2
4
|
module GeospatialMethods
|
3
5
|
LNG_RANGE = (-180..180)
|
@@ -81,8 +83,7 @@ class MockRedis
|
|
81
83
|
points = args.each_slice(3).to_a
|
82
84
|
|
83
85
|
if points.last.size != 3
|
84
|
-
raise
|
85
|
-
"ERR wrong number of arguments for 'geoadd' command"
|
86
|
+
raise Error.command_error("ERR wrong number of arguments for 'geoadd' command", self)
|
86
87
|
end
|
87
88
|
|
88
89
|
points.map do |point|
|
@@ -97,13 +98,15 @@ class MockRedis
|
|
97
98
|
unless LNG_RANGE.include?(lng) && LAT_RANGE.include?(lat)
|
98
99
|
lng = format('%<long>.6f', long: lng)
|
99
100
|
lat = format('%<lat>.6f', lat: lat)
|
100
|
-
raise
|
101
|
-
"ERR invalid longitude,latitude pair #{lng},#{lat}"
|
101
|
+
raise Error.command_error(
|
102
|
+
"ERR invalid longitude,latitude pair #{lng},#{lat}",
|
103
|
+
self
|
104
|
+
)
|
102
105
|
end
|
103
106
|
|
104
107
|
{ key: point[2], lng: lng, lat: lat }
|
105
108
|
rescue ArgumentError
|
106
|
-
raise
|
109
|
+
raise Error.command_error('ERR value is not a valid float', self)
|
107
110
|
end
|
108
111
|
|
109
112
|
# Returns ZSET score for passed coordinates
|
@@ -212,8 +215,7 @@ class MockRedis
|
|
212
215
|
unit = unit.to_sym
|
213
216
|
return UNITS[unit] if UNITS[unit]
|
214
217
|
|
215
|
-
raise
|
216
|
-
'ERR unsupported unit provided. please use m, km, ft, mi'
|
218
|
+
raise Error.command_error('ERR unsupported unit provided. please use m, km, ft, mi', self)
|
217
219
|
end
|
218
220
|
|
219
221
|
def geohash_distance(lng1d, lat1d, lng2d, lat2d)
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'mock_redis/assertions'
|
2
2
|
require 'mock_redis/utility_methods'
|
3
|
+
require 'mock_redis/error'
|
3
4
|
|
4
5
|
class MockRedis
|
5
6
|
module HashMethods
|
@@ -7,12 +8,16 @@ class MockRedis
|
|
7
8
|
include UtilityMethods
|
8
9
|
|
9
10
|
def hdel(key, *fields)
|
11
|
+
assert_type(key)
|
12
|
+
|
10
13
|
with_hash_at(key) do |hash|
|
11
14
|
orig_size = hash.size
|
12
15
|
fields = Array(fields).flatten.map(&:to_s)
|
13
16
|
|
17
|
+
assert_type(*fields)
|
18
|
+
|
14
19
|
if fields.empty?
|
15
|
-
raise
|
20
|
+
raise Error.command_error("ERR wrong number of arguments for 'hdel' command", self)
|
16
21
|
end
|
17
22
|
|
18
23
|
hash.delete_if { |k, _v| fields.include?(k) }
|
@@ -21,25 +26,31 @@ class MockRedis
|
|
21
26
|
end
|
22
27
|
|
23
28
|
def hexists(key, field)
|
29
|
+
assert_type(key, field)
|
30
|
+
|
24
31
|
with_hash_at(key) { |h| h.key?(field.to_s) }
|
25
32
|
end
|
26
33
|
|
27
34
|
def hget(key, field)
|
35
|
+
assert_type(key, field)
|
36
|
+
|
28
37
|
with_hash_at(key) { |h| h[field.to_s] }
|
29
38
|
end
|
30
39
|
|
31
40
|
def hgetall(key)
|
41
|
+
assert_type(key)
|
42
|
+
|
32
43
|
with_hash_at(key) { |h| h }
|
33
44
|
end
|
34
45
|
|
35
46
|
def hincrby(key, field, increment)
|
47
|
+
assert_type(key, field)
|
48
|
+
|
36
49
|
with_hash_at(key) do |hash|
|
37
50
|
field = field.to_s
|
51
|
+
increment = Integer(increment)
|
38
52
|
unless can_incr?(data[key][field])
|
39
|
-
raise
|
40
|
-
end
|
41
|
-
unless looks_like_integer?(increment.to_s)
|
42
|
-
raise Redis::CommandError, 'ERR value is not an integer or out of range'
|
53
|
+
raise Error.command_error('ERR hash value is not an integer', self)
|
43
54
|
end
|
44
55
|
|
45
56
|
new_value = (hash[field] || '0').to_i + increment.to_i
|
@@ -49,14 +60,13 @@ class MockRedis
|
|
49
60
|
end
|
50
61
|
|
51
62
|
def hincrbyfloat(key, field, increment)
|
63
|
+
assert_type(key, field)
|
64
|
+
|
52
65
|
with_hash_at(key) do |hash|
|
53
66
|
field = field.to_s
|
67
|
+
increment = Float(increment)
|
54
68
|
unless can_incr_float?(data[key][field])
|
55
|
-
raise
|
56
|
-
end
|
57
|
-
|
58
|
-
unless looks_like_float?(increment.to_s)
|
59
|
-
raise Redis::CommandError, 'ERR value is not a valid float'
|
69
|
+
raise Error.command_error('ERR hash value is not a float', self)
|
60
70
|
end
|
61
71
|
|
62
72
|
new_value = (hash[field] || '0').to_f + increment.to_f
|
@@ -67,21 +77,28 @@ class MockRedis
|
|
67
77
|
end
|
68
78
|
|
69
79
|
def hkeys(key)
|
80
|
+
assert_type(key)
|
81
|
+
|
70
82
|
with_hash_at(key, &:keys)
|
71
83
|
end
|
72
84
|
|
73
85
|
def hlen(key)
|
86
|
+
assert_type(key)
|
87
|
+
|
74
88
|
hkeys(key).length
|
75
89
|
end
|
76
90
|
|
77
91
|
def hmget(key, *fields)
|
78
92
|
fields.flatten!
|
79
93
|
|
94
|
+
assert_type(key, *fields)
|
80
95
|
assert_has_args(fields, 'hmget')
|
81
96
|
fields.map { |f| hget(key, f) }
|
82
97
|
end
|
83
98
|
|
84
99
|
def mapped_hmget(key, *fields)
|
100
|
+
fields.flatten!
|
101
|
+
|
85
102
|
reply = hmget(key, *fields)
|
86
103
|
if reply.is_a?(Array)
|
87
104
|
Hash[fields.zip(reply)]
|
@@ -98,10 +115,15 @@ class MockRedis
|
|
98
115
|
end
|
99
116
|
|
100
117
|
kvpairs.flatten!
|
118
|
+
|
119
|
+
assert_type(key, *kvpairs)
|
101
120
|
assert_has_args(kvpairs, 'hmset')
|
102
121
|
|
103
122
|
if kvpairs.length.odd?
|
104
|
-
raise
|
123
|
+
raise Error.command_error(
|
124
|
+
err_msg || "ERR wrong number of arguments for 'hmset' command",
|
125
|
+
self
|
126
|
+
)
|
105
127
|
end
|
106
128
|
|
107
129
|
kvpairs.each_slice(2) do |(k, v)|
|
@@ -111,21 +133,27 @@ class MockRedis
|
|
111
133
|
end
|
112
134
|
|
113
135
|
def mapped_hmset(key, hash)
|
114
|
-
kvpairs = hash.
|
136
|
+
kvpairs = hash.flatten
|
137
|
+
|
138
|
+
assert_type(key, *kvpairs)
|
115
139
|
assert_has_args(kvpairs, 'hmset')
|
116
140
|
if kvpairs.length.odd?
|
117
|
-
raise
|
141
|
+
raise Error.command_error("ERR wrong number of arguments for 'hmset' command", self)
|
118
142
|
end
|
119
143
|
|
120
144
|
hmset(key, *kvpairs)
|
121
145
|
end
|
122
146
|
|
123
147
|
def hscan(key, cursor, opts = {})
|
148
|
+
assert_type(key, cursor)
|
149
|
+
|
124
150
|
opts = opts.merge(key: lambda { |x| x[0] })
|
125
151
|
common_scan(hgetall(key).to_a, cursor, opts)
|
126
152
|
end
|
127
153
|
|
128
154
|
def hscan_each(key, opts = {}, &block)
|
155
|
+
assert_type(key)
|
156
|
+
|
129
157
|
return to_enum(:hscan_each, key, opts) unless block_given?
|
130
158
|
cursor = 0
|
131
159
|
loop do
|
@@ -138,11 +166,15 @@ class MockRedis
|
|
138
166
|
def hset(key, *args)
|
139
167
|
added = 0
|
140
168
|
args.flatten!(1)
|
169
|
+
assert_type(key)
|
170
|
+
|
141
171
|
with_hash_at(key) do |hash|
|
142
172
|
if args.length == 1 && args[0].is_a?(Hash)
|
143
173
|
args = args[0].to_a.flatten
|
144
174
|
end
|
145
175
|
|
176
|
+
assert_type(*args)
|
177
|
+
|
146
178
|
args.each_slice(2) do |field, value|
|
147
179
|
added += 1 unless hash.key?(field.to_s)
|
148
180
|
hash[field.to_s] = value.to_s
|
@@ -152,6 +184,7 @@ class MockRedis
|
|
152
184
|
end
|
153
185
|
|
154
186
|
def hsetnx(key, field, value)
|
187
|
+
assert_type(key, field, value)
|
155
188
|
if hget(key, field)
|
156
189
|
false
|
157
190
|
else
|
@@ -161,6 +194,8 @@ class MockRedis
|
|
161
194
|
end
|
162
195
|
|
163
196
|
def hvals(key)
|
197
|
+
assert_type(key)
|
198
|
+
|
164
199
|
with_hash_at(key, &:values)
|
165
200
|
end
|
166
201
|
|
@@ -176,8 +211,7 @@ class MockRedis
|
|
176
211
|
|
177
212
|
def assert_hashy(key)
|
178
213
|
unless hashy?(key)
|
179
|
-
raise
|
180
|
-
'WRONGTYPE Operation against a key holding the wrong kind of value'
|
214
|
+
raise Error.wrong_type_error(self)
|
181
215
|
end
|
182
216
|
end
|
183
217
|
end
|
@@ -46,9 +46,7 @@ class MockRedis
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
-
def brpoplpush(source, destination,
|
50
|
-
options = { :timeout => options } if options.is_a?(Integer)
|
51
|
-
timeout = options.is_a?(Hash) && options[:timeout] || 0
|
49
|
+
def brpoplpush(source, destination, timeout: 0)
|
52
50
|
assert_valid_timeout(timeout)
|
53
51
|
|
54
52
|
if llen(source) > 0
|
@@ -66,7 +64,7 @@ class MockRedis
|
|
66
64
|
|
67
65
|
def linsert(key, position, pivot, value)
|
68
66
|
unless %w[before after].include?(position.to_s)
|
69
|
-
raise
|
67
|
+
raise Error.command_error('ERR syntax error', self)
|
70
68
|
end
|
71
69
|
|
72
70
|
assert_listy(key)
|
@@ -92,6 +90,32 @@ class MockRedis
|
|
92
90
|
with_list_at(key, &:length)
|
93
91
|
end
|
94
92
|
|
93
|
+
def lmpop(*keys, **options)
|
94
|
+
keys.each do |key|
|
95
|
+
assert_listy(key)
|
96
|
+
end
|
97
|
+
|
98
|
+
modifier = options.is_a?(Hash) && options[:modifier]&.to_s&.downcase || 'left'
|
99
|
+
count = (options.is_a?(Hash) && options[:count]) || 1
|
100
|
+
|
101
|
+
unless %w[left right].include?(modifier)
|
102
|
+
raise Redis::CommandError, 'ERR syntax error'
|
103
|
+
end
|
104
|
+
|
105
|
+
keys.each do |key|
|
106
|
+
record_count = llen(key)
|
107
|
+
next if record_count.zero?
|
108
|
+
|
109
|
+
values = [count, record_count].min.times.map do
|
110
|
+
modifier == 'left' ? with_list_at(key, &:shift) : with_list_at(key, &:pop)
|
111
|
+
end
|
112
|
+
|
113
|
+
return [key, values]
|
114
|
+
end
|
115
|
+
|
116
|
+
nil
|
117
|
+
end
|
118
|
+
|
95
119
|
def lmove(source, destination, wherefrom, whereto)
|
96
120
|
assert_listy(source)
|
97
121
|
assert_listy(destination)
|
@@ -99,9 +123,8 @@ class MockRedis
|
|
99
123
|
wherefrom = wherefrom.to_s.downcase
|
100
124
|
whereto = whereto.to_s.downcase
|
101
125
|
|
102
|
-
|
103
|
-
|
104
|
-
end
|
126
|
+
assert_where_field(wherefrom, 'where_source')
|
127
|
+
assert_where_field(whereto, 'where_destination')
|
105
128
|
|
106
129
|
value = wherefrom == 'left' ? lpop(source) : rpop(source)
|
107
130
|
(whereto == 'left' ? lpush(destination, value) : rpush(destination, value)) unless value.nil?
|
@@ -127,7 +150,7 @@ class MockRedis
|
|
127
150
|
def lpushx(key, value)
|
128
151
|
value = [value] unless value.is_a?(Array)
|
129
152
|
if value.empty?
|
130
|
-
raise
|
153
|
+
raise Error.command_error("ERR wrong number of arguments for 'lpushx' command", self)
|
131
154
|
end
|
132
155
|
assert_listy(key)
|
133
156
|
return 0 unless list_at?(key)
|
@@ -140,10 +163,7 @@ class MockRedis
|
|
140
163
|
end
|
141
164
|
|
142
165
|
def lrem(key, count, value)
|
143
|
-
|
144
|
-
raise Redis::CommandError, 'ERR value is not an integer or out of range'
|
145
|
-
end
|
146
|
-
count = count.to_i
|
166
|
+
count = Integer(count)
|
147
167
|
value = value.to_s
|
148
168
|
|
149
169
|
with_list_at(key) do |list|
|
@@ -167,12 +187,12 @@ class MockRedis
|
|
167
187
|
assert_listy(key)
|
168
188
|
|
169
189
|
unless list_at?(key)
|
170
|
-
raise
|
190
|
+
raise Error.command_error('ERR no such key', self)
|
171
191
|
end
|
172
192
|
|
173
193
|
index = index.to_i
|
174
194
|
unless (0...llen(key)).cover?(index)
|
175
|
-
raise
|
195
|
+
raise Error.command_error('ERR index out of range', self)
|
176
196
|
end
|
177
197
|
|
178
198
|
data[key][index] = value.to_s
|
@@ -211,7 +231,7 @@ class MockRedis
|
|
211
231
|
def rpushx(key, value)
|
212
232
|
value = [value] unless value.is_a?(Array)
|
213
233
|
if value.empty?
|
214
|
-
raise
|
234
|
+
raise Error.command_error("ERR wrong number of arguments for 'rpushx' command", self)
|
215
235
|
end
|
216
236
|
assert_listy(key)
|
217
237
|
return 0 unless list_at?(key)
|
@@ -235,8 +255,13 @@ class MockRedis
|
|
235
255
|
def assert_listy(key)
|
236
256
|
unless listy?(key)
|
237
257
|
# Not the most helpful error, but it's what redis-rb barfs up
|
238
|
-
raise
|
239
|
-
|
258
|
+
raise Error.wrong_type_error(self)
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
def assert_where_field(where, argument_name)
|
263
|
+
unless %w[left right].include?(where)
|
264
|
+
raise ArgumentError, "#{argument_name} must be 'LEFT' or 'RIGHT'"
|
240
265
|
end
|
241
266
|
end
|
242
267
|
|
@@ -6,9 +6,10 @@ class MockRedis
|
|
6
6
|
include Assertions
|
7
7
|
include UtilityMethods
|
8
8
|
|
9
|
-
def sadd(key, members)
|
9
|
+
def sadd(key, *members)
|
10
10
|
members_class = members.class
|
11
|
-
members = Array(members).map(&:to_s)
|
11
|
+
members = Array(members).flatten.map(&:to_s)
|
12
|
+
assert_type(key, *members)
|
12
13
|
assert_has_args(members, 'sadd')
|
13
14
|
|
14
15
|
with_set_at(key) do |s|
|
@@ -21,7 +22,7 @@ class MockRedis
|
|
21
22
|
if members_class == Array
|
22
23
|
s.size - size_before
|
23
24
|
else
|
24
|
-
added
|
25
|
+
added ? 1 : 0
|
25
26
|
end
|
26
27
|
end
|
27
28
|
end
|
@@ -33,6 +34,7 @@ class MockRedis
|
|
33
34
|
end
|
34
35
|
|
35
36
|
def scard(key)
|
37
|
+
assert_type(key)
|
36
38
|
with_set_at(key, &:length)
|
37
39
|
end
|
38
40
|
|
@@ -42,6 +44,7 @@ class MockRedis
|
|
42
44
|
end
|
43
45
|
|
44
46
|
def sdiffstore(destination, *keys)
|
47
|
+
assert_type(destination, *keys)
|
45
48
|
assert_has_args(keys, 'sdiffstore')
|
46
49
|
with_set_at(destination) do |set|
|
47
50
|
set.replace(sdiff(*keys))
|
@@ -58,6 +61,7 @@ class MockRedis
|
|
58
61
|
end
|
59
62
|
|
60
63
|
def sinterstore(destination, *keys)
|
64
|
+
assert_type(destination, *keys)
|
61
65
|
assert_has_args(keys, 'sinterstore')
|
62
66
|
with_set_at(destination) do |set|
|
63
67
|
set.replace(sinter(*keys))
|
@@ -66,16 +70,21 @@ class MockRedis
|
|
66
70
|
end
|
67
71
|
|
68
72
|
def sismember(key, member)
|
73
|
+
assert_type(key, member)
|
69
74
|
with_set_at(key) { |s| s.include?(member.to_s) }
|
70
75
|
end
|
71
76
|
|
72
77
|
def smismember(key, *members)
|
78
|
+
members.flatten!
|
79
|
+
|
80
|
+
assert_type(key, *members)
|
73
81
|
with_set_at(key) do |set|
|
74
|
-
members.
|
82
|
+
members.map { |m| set.include?(m.to_s) }
|
75
83
|
end
|
76
84
|
end
|
77
85
|
|
78
86
|
def smembers(key)
|
87
|
+
assert_type(key)
|
79
88
|
with_set_at(key, &:to_a).map(&:dup).reverse
|
80
89
|
end
|
81
90
|
|
@@ -93,6 +102,7 @@ class MockRedis
|
|
93
102
|
end
|
94
103
|
|
95
104
|
def spop(key, count = nil)
|
105
|
+
assert_type(key)
|
96
106
|
with_set_at(key) do |set|
|
97
107
|
if count.nil?
|
98
108
|
member = set.first
|
@@ -112,6 +122,7 @@ class MockRedis
|
|
112
122
|
end
|
113
123
|
|
114
124
|
def srandmember(key, count = nil)
|
125
|
+
assert_type(key)
|
115
126
|
members = with_set_at(key, &:to_a)
|
116
127
|
if count
|
117
128
|
if count > 0
|
@@ -124,7 +135,10 @@ class MockRedis
|
|
124
135
|
end
|
125
136
|
end
|
126
137
|
|
127
|
-
def srem(key, members)
|
138
|
+
def srem(key, *members)
|
139
|
+
members = members.flatten.uniq
|
140
|
+
assert_type(key, *members)
|
141
|
+
|
128
142
|
with_set_at(key) do |s|
|
129
143
|
if members.is_a?(Array)
|
130
144
|
orig_size = s.size
|
@@ -177,6 +191,9 @@ class MockRedis
|
|
177
191
|
|
178
192
|
def with_sets_at(*keys, &blk)
|
179
193
|
keys = keys.flatten
|
194
|
+
|
195
|
+
assert_type(*keys)
|
196
|
+
|
180
197
|
if keys.length == 1
|
181
198
|
with_set_at(keys.first, &blk)
|
182
199
|
else
|
@@ -195,8 +212,7 @@ class MockRedis
|
|
195
212
|
def assert_sety(key)
|
196
213
|
unless sety?(key)
|
197
214
|
# Not the most helpful error, but it's what redis-rb barfs up
|
198
|
-
raise
|
199
|
-
'WRONGTYPE Operation against a key holding the wrong kind of value'
|
215
|
+
raise Error.wrong_type_error(self)
|
200
216
|
end
|
201
217
|
end
|
202
218
|
end
|
@@ -35,6 +35,8 @@ class MockRedis
|
|
35
35
|
stream.add id, entry
|
36
36
|
stream.trim opts[:maxlen] if opts[:maxlen]
|
37
37
|
return stream.last_id
|
38
|
+
rescue Redis::CommandError => e
|
39
|
+
raise Error.command_error(e.message, self)
|
38
40
|
end
|
39
41
|
end
|
40
42
|
|
@@ -55,6 +57,8 @@ class MockRedis
|
|
55
57
|
args += ['COUNT', count] if count
|
56
58
|
with_stream_at(key) do |stream|
|
57
59
|
return stream.range(*args)
|
60
|
+
rescue Redis::CommandError => e
|
61
|
+
raise Error.command_error(e.message, self)
|
58
62
|
end
|
59
63
|
end
|
60
64
|
|
@@ -63,6 +67,8 @@ class MockRedis
|
|
63
67
|
args += ['COUNT', count] if count
|
64
68
|
with_stream_at(key) do |stream|
|
65
69
|
return stream.range(*args)
|
70
|
+
rescue Redis::CommandError => e
|
71
|
+
raise Error.command_error(e.message, self)
|
66
72
|
end
|
67
73
|
end
|
68
74
|
|
@@ -94,8 +100,7 @@ class MockRedis
|
|
94
100
|
|
95
101
|
def assert_streamy(key)
|
96
102
|
unless streamy?(key)
|
97
|
-
raise
|
98
|
-
'WRONGTYPE Operation against a key holding the wrong kind of value'
|
103
|
+
raise Error.wrong_type_error(self)
|
99
104
|
end
|
100
105
|
end
|
101
106
|
end
|
@@ -14,7 +14,7 @@ class MockRedis
|
|
14
14
|
|
15
15
|
def bitfield(*args)
|
16
16
|
if args.length < 4
|
17
|
-
raise
|
17
|
+
raise Error.command_error('ERR wrong number of arguments for BITFIELD', self)
|
18
18
|
end
|
19
19
|
|
20
20
|
key = args.shift
|
@@ -28,7 +28,7 @@ class MockRedis
|
|
28
28
|
new_overflow_method = args.shift.to_s.downcase
|
29
29
|
|
30
30
|
unless %w[wrap sat fail].include? new_overflow_method
|
31
|
-
raise
|
31
|
+
raise Error.command_error('ERR Invalid OVERFLOW type specified', self)
|
32
32
|
end
|
33
33
|
|
34
34
|
overflow_method = new_overflow_method
|
@@ -41,9 +41,11 @@ class MockRedis
|
|
41
41
|
type_size = type[1..].to_i
|
42
42
|
|
43
43
|
if (type_size > 64 && is_signed) || (type_size >= 64 && !is_signed)
|
44
|
-
raise
|
44
|
+
raise Error.command_error(
|
45
45
|
'ERR Invalid bitfield type. Use something like i16 u8. ' \
|
46
|
-
'Note that u64 is not supported but i64 is.'
|
46
|
+
'Note that u64 is not supported but i64 is.',
|
47
|
+
self
|
48
|
+
)
|
47
49
|
end
|
48
50
|
|
49
51
|
if offset.to_s[0] == '#'
|
@@ -130,12 +132,10 @@ class MockRedis
|
|
130
132
|
|
131
133
|
def incrby(key, n)
|
132
134
|
assert_stringy(key)
|
133
|
-
|
134
|
-
raise Redis::CommandError, 'ERR value is not an integer or out of range'
|
135
|
-
end
|
135
|
+
n = Integer(n)
|
136
136
|
|
137
|
-
unless
|
138
|
-
raise
|
137
|
+
unless can_incr?(data[key])
|
138
|
+
raise Error.command_error('ERR value is not an integer or out of range', self)
|
139
139
|
end
|
140
140
|
|
141
141
|
new_value = data[key].to_i + n.to_i
|
@@ -146,12 +146,9 @@ class MockRedis
|
|
146
146
|
|
147
147
|
def incrbyfloat(key, n)
|
148
148
|
assert_stringy(key)
|
149
|
+
n = Float(n)
|
149
150
|
unless can_incr_float?(data[key])
|
150
|
-
raise
|
151
|
-
end
|
152
|
-
|
153
|
-
unless looks_like_float?(n.to_s)
|
154
|
-
raise Redis::CommandError, 'ERR value is not a valid float'
|
151
|
+
raise Error.command_error('ERR value is not a valid float', self)
|
155
152
|
end
|
156
153
|
|
157
154
|
new_value = data[key].to_f + n.to_f
|
@@ -181,7 +178,7 @@ class MockRedis
|
|
181
178
|
kvpairs = kvpairs.first if kvpairs.size == 1 && kvpairs.first.is_a?(Enumerable)
|
182
179
|
|
183
180
|
if kvpairs.length.odd?
|
184
|
-
raise
|
181
|
+
raise Error.command_error('ERR wrong number of arguments for MSET', self)
|
185
182
|
end
|
186
183
|
|
187
184
|
kvpairs.each_slice(2) do |(k, v)|
|
@@ -237,28 +234,28 @@ class MockRedis
|
|
237
234
|
remove_expiration(key) unless keepttl
|
238
235
|
if ex
|
239
236
|
if ex == 0
|
240
|
-
raise
|
237
|
+
raise Error.command_error('ERR invalid expire time in set', self)
|
241
238
|
end
|
242
239
|
expire(key, ex)
|
243
240
|
end
|
244
241
|
|
245
242
|
if px
|
246
243
|
if px == 0
|
247
|
-
raise
|
244
|
+
raise Error.command_error('ERR invalid expire time in set', self)
|
248
245
|
end
|
249
246
|
pexpire(key, px)
|
250
247
|
end
|
251
248
|
|
252
249
|
if exat
|
253
250
|
if exat == 0
|
254
|
-
raise
|
251
|
+
raise Error.command_error('ERR invalid expire time in set', self)
|
255
252
|
end
|
256
253
|
expireat(key, exat)
|
257
254
|
end
|
258
255
|
|
259
256
|
if pxat
|
260
257
|
if pxat == 0
|
261
|
-
raise
|
258
|
+
raise Error.command_error('ERR invalid expire time in set', self)
|
262
259
|
end
|
263
260
|
pexpireat(key, pxat)
|
264
261
|
end
|
@@ -347,7 +344,7 @@ class MockRedis
|
|
347
344
|
|
348
345
|
def setex(key, seconds, value)
|
349
346
|
if seconds <= 0
|
350
|
-
raise
|
347
|
+
raise Error.command_error('ERR invalid expire time in setex', self)
|
351
348
|
else
|
352
349
|
set(key, value)
|
353
350
|
expire(key, seconds)
|
@@ -357,7 +354,7 @@ class MockRedis
|
|
357
354
|
|
358
355
|
def psetex(key, milliseconds, value)
|
359
356
|
if milliseconds <= 0
|
360
|
-
raise
|
357
|
+
raise Error.command_error('ERR invalid expire time in psetex', self)
|
361
358
|
else
|
362
359
|
set(key, value)
|
363
360
|
pexpire(key, milliseconds)
|
@@ -377,7 +374,7 @@ class MockRedis
|
|
377
374
|
def setrange(key, offset, value)
|
378
375
|
assert_stringy(key)
|
379
376
|
value = value.to_s
|
380
|
-
old_value =
|
377
|
+
old_value = data[key] || ''
|
381
378
|
|
382
379
|
prefix = zero_pad(old_value[0...offset], offset)
|
383
380
|
data[key] = prefix + value + (old_value[(offset + value.length)..] || '')
|
@@ -395,10 +392,13 @@ class MockRedis
|
|
395
392
|
data[key].nil? || data[key].is_a?(String)
|
396
393
|
end
|
397
394
|
|
398
|
-
def assert_stringy(key,
|
399
|
-
message = 'WRONGTYPE Operation against a key holding the wrong kind of value')
|
395
|
+
def assert_stringy(key, message = nil)
|
400
396
|
unless stringy?(key)
|
401
|
-
|
397
|
+
if message
|
398
|
+
raise Error.command_error(message, self)
|
399
|
+
else
|
400
|
+
raise Error.wrong_type_error(self)
|
401
|
+
end
|
402
402
|
end
|
403
403
|
end
|
404
404
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'mock_redis/undef_redis_methods'
|
2
|
+
require 'mock_redis/error'
|
2
3
|
|
3
4
|
class MockRedis
|
4
5
|
class TransactionWrapper
|
@@ -12,18 +13,12 @@ class MockRedis
|
|
12
13
|
@db = db
|
13
14
|
@transaction_futures = []
|
14
15
|
@multi_stack = []
|
15
|
-
@multi_block_given = false
|
16
16
|
end
|
17
17
|
|
18
18
|
ruby2_keywords def method_missing(method, *args, &block)
|
19
19
|
if in_multi?
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
if @multi_block_given
|
24
|
-
future
|
25
|
-
else
|
26
|
-
'QUEUED'
|
20
|
+
MockRedis::Future.new([method, *args], block).tap do |future|
|
21
|
+
@transaction_futures << future
|
27
22
|
end
|
28
23
|
else
|
29
24
|
@db.expire_keys
|
@@ -40,7 +35,7 @@ class MockRedis
|
|
40
35
|
|
41
36
|
def discard
|
42
37
|
unless in_multi?
|
43
|
-
raise
|
38
|
+
raise Error.command_error('ERR DISCARD without MULTI', self)
|
44
39
|
end
|
45
40
|
pop_multi
|
46
41
|
|
@@ -50,22 +45,23 @@ class MockRedis
|
|
50
45
|
|
51
46
|
def exec
|
52
47
|
unless in_multi?
|
53
|
-
raise
|
48
|
+
raise Error.command_error('ERR EXEC without MULTI', self)
|
54
49
|
end
|
50
|
+
|
55
51
|
pop_multi
|
56
52
|
return if in_multi?
|
57
|
-
@multi_block_given = false
|
58
53
|
|
59
54
|
responses = @transaction_futures.map do |future|
|
60
55
|
result = send(*future.command)
|
61
56
|
future.store_result(result)
|
62
57
|
future.value
|
63
|
-
rescue StandardError => e
|
64
|
-
e
|
65
58
|
end
|
66
59
|
|
67
|
-
@transaction_futures = []
|
68
60
|
responses
|
61
|
+
ensure
|
62
|
+
# At this point, multi is done, so we can't call discard anymore.
|
63
|
+
# Therefore, we need to clear the transaction futures manually.
|
64
|
+
@transaction_futures = []
|
69
65
|
end
|
70
66
|
|
71
67
|
def in_multi?
|
@@ -81,20 +77,16 @@ class MockRedis
|
|
81
77
|
end
|
82
78
|
|
83
79
|
def multi
|
84
|
-
if
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
else
|
95
|
-
raise Redis::CommandError, 'ERR MULTI calls can not be nested' if in_multi?
|
96
|
-
push_multi
|
97
|
-
'OK'
|
80
|
+
raise Redis::BaseError, "Can't nest multi transaction" if in_multi?
|
81
|
+
|
82
|
+
push_multi
|
83
|
+
|
84
|
+
begin
|
85
|
+
yield(self)
|
86
|
+
exec
|
87
|
+
rescue StandardError => e
|
88
|
+
discard if in_multi?
|
89
|
+
raise e
|
98
90
|
end
|
99
91
|
end
|
100
92
|
|
data/lib/mock_redis/version.rb
CHANGED
@@ -12,7 +12,10 @@ class MockRedis
|
|
12
12
|
zadd_options = args.pop if args.last.is_a?(Hash)
|
13
13
|
|
14
14
|
if zadd_options&.include?(:nx) && zadd_options&.include?(:xx)
|
15
|
-
raise
|
15
|
+
raise Error.command_error(
|
16
|
+
'ERR XX and NX options at the same time are not compatible',
|
17
|
+
self
|
18
|
+
)
|
16
19
|
end
|
17
20
|
|
18
21
|
if args.size == 1 && args[0].is_a?(Array)
|
@@ -21,7 +24,7 @@ class MockRedis
|
|
21
24
|
score, member = args
|
22
25
|
zadd_one_member(key, score, member, zadd_options)
|
23
26
|
else
|
24
|
-
raise
|
27
|
+
raise ArgumentError, 'wrong number of arguments'
|
25
28
|
end
|
26
29
|
end
|
27
30
|
|
@@ -57,12 +60,13 @@ class MockRedis
|
|
57
60
|
private :zadd_one_member
|
58
61
|
|
59
62
|
def zadd_multiple_members(key, args, zadd_options = {})
|
60
|
-
assert_has_args(args, 'zadd')
|
61
|
-
|
62
63
|
args = args.each_slice(2).to_a unless args.first.is_a?(Array)
|
63
64
|
with_zset_at(key) do |zset|
|
64
65
|
if zadd_options[:incr]
|
65
|
-
raise
|
66
|
+
raise Error.command_error(
|
67
|
+
'ERR INCR option supports a single increment-element pair',
|
68
|
+
self
|
69
|
+
)
|
66
70
|
elsif zadd_options[:xx]
|
67
71
|
args.each { |score, member| zset.include?(member) && zset.add(score, member.to_s) }
|
68
72
|
0
|
@@ -143,7 +147,7 @@ class MockRedis
|
|
143
147
|
else
|
144
148
|
args = args.first
|
145
149
|
if args.empty?
|
146
|
-
|
150
|
+
retval = 0
|
147
151
|
else
|
148
152
|
retval = args.map { |member| !!zscore(key, member.to_s) }.count(true)
|
149
153
|
with_zset_at(key) do |z|
|
@@ -257,7 +261,7 @@ class MockRedis
|
|
257
261
|
offset, count = limit
|
258
262
|
collection.drop(offset).take(count)
|
259
263
|
else
|
260
|
-
raise
|
264
|
+
raise Error.syntax_error(self)
|
261
265
|
end
|
262
266
|
else
|
263
267
|
collection
|
@@ -277,7 +281,7 @@ class MockRedis
|
|
277
281
|
def combine_weighted_zsets(keys, options, how)
|
278
282
|
weights = options.fetch(:weights, keys.map { 1 })
|
279
283
|
if weights.length != keys.length
|
280
|
-
raise
|
284
|
+
raise Error.syntax_error(self)
|
281
285
|
end
|
282
286
|
|
283
287
|
aggregator = case options.fetch(:aggregate, :sum).to_s.downcase.to_sym
|
@@ -288,7 +292,7 @@ class MockRedis
|
|
288
292
|
when :max
|
289
293
|
proc { |a, b| [a, b].compact.max }
|
290
294
|
else
|
291
|
-
raise
|
295
|
+
raise Error.syntax_error(self)
|
292
296
|
end
|
293
297
|
|
294
298
|
with_zsets_at(*keys, coercible: true) do |*zsets|
|
@@ -342,15 +346,13 @@ class MockRedis
|
|
342
346
|
|
343
347
|
def assert_zsety(key)
|
344
348
|
unless zsety?(key)
|
345
|
-
raise
|
346
|
-
'WRONGTYPE Operation against a key holding the wrong kind of value'
|
349
|
+
raise Error.wrong_type_error(self)
|
347
350
|
end
|
348
351
|
end
|
349
352
|
|
350
353
|
def assert_coercible_zsety(key)
|
351
354
|
unless coercible_zsety?(key)
|
352
|
-
raise
|
353
|
-
'WRONGTYPE Operation against a key holding the wrong kind of value'
|
355
|
+
raise Error.wrong_type_error(self)
|
354
356
|
end
|
355
357
|
end
|
356
358
|
|
@@ -363,9 +365,10 @@ class MockRedis
|
|
363
365
|
return if value.to_s =~ /\(?(-|\+)inf/
|
364
366
|
|
365
367
|
value = $1 if value.to_s =~ /\((.*)/
|
366
|
-
|
367
|
-
|
368
|
-
|
368
|
+
|
369
|
+
assert_type(value)
|
370
|
+
|
371
|
+
raise Error.command_error(message, self) unless looks_like_float?(value)
|
369
372
|
end
|
370
373
|
|
371
374
|
def assert_range_args(min, max)
|
data/lib/mock_redis.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mock_redis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.48.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shane da Silva
|
8
8
|
- Samuel Merritt
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-
|
12
|
+
date: 2024-12-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -31,14 +31,14 @@ dependencies:
|
|
31
31
|
requirements:
|
32
32
|
- - "~>"
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version:
|
34
|
+
version: '5'
|
35
35
|
type: :development
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
39
|
- - "~>"
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version:
|
41
|
+
version: '5'
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: rspec
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -96,6 +96,7 @@ files:
|
|
96
96
|
- lib/mock_redis/assertions.rb
|
97
97
|
- lib/mock_redis/connection_method.rb
|
98
98
|
- lib/mock_redis/database.rb
|
99
|
+
- lib/mock_redis/error.rb
|
99
100
|
- lib/mock_redis/exceptions.rb
|
100
101
|
- lib/mock_redis/expire_wrapper.rb
|
101
102
|
- lib/mock_redis/future.rb
|
@@ -124,11 +125,11 @@ licenses:
|
|
124
125
|
- MIT
|
125
126
|
metadata:
|
126
127
|
bug_tracker_uri: https://github.com/sds/mock_redis/issues
|
127
|
-
changelog_uri: https://github.com/sds/mock_redis/blob/v0.
|
128
|
-
documentation_uri: https://www.rubydoc.info/gems/mock_redis/0.
|
128
|
+
changelog_uri: https://github.com/sds/mock_redis/blob/v0.48.1/CHANGELOG.md
|
129
|
+
documentation_uri: https://www.rubydoc.info/gems/mock_redis/0.48.1
|
129
130
|
homepage_uri: https://github.com/sds/mock_redis
|
130
|
-
source_code_uri: https://github.com/sds/mock_redis/tree/v0.
|
131
|
-
post_install_message:
|
131
|
+
source_code_uri: https://github.com/sds/mock_redis/tree/v0.48.1
|
132
|
+
post_install_message:
|
132
133
|
rdoc_options: []
|
133
134
|
require_paths:
|
134
135
|
- lib
|
@@ -143,8 +144,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
143
144
|
- !ruby/object:Gem::Version
|
144
145
|
version: '0'
|
145
146
|
requirements: []
|
146
|
-
rubygems_version: 3.
|
147
|
-
signing_key:
|
147
|
+
rubygems_version: 3.0.3.1
|
148
|
+
signing_key:
|
148
149
|
specification_version: 4
|
149
150
|
summary: Redis mock that just lives in memory; useful for testing.
|
150
151
|
test_files: []
|