mock_redis 0.22.0 → 0.27.0

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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +26 -5
  3. data/.rubocop_todo.yml +1 -1
  4. data/.travis.yml +1 -0
  5. data/CHANGELOG.md +31 -0
  6. data/Gemfile +4 -2
  7. data/lib/mock_redis.rb +1 -8
  8. data/lib/mock_redis/connection_method.rb +13 -0
  9. data/lib/mock_redis/database.rb +44 -14
  10. data/lib/mock_redis/expire_wrapper.rb +1 -1
  11. data/lib/mock_redis/future.rb +1 -1
  12. data/lib/mock_redis/geospatial_methods.rb +5 -5
  13. data/lib/mock_redis/hash_methods.rb +9 -4
  14. data/lib/mock_redis/info_method.rb +2 -2
  15. data/lib/mock_redis/multi_db_wrapper.rb +3 -3
  16. data/lib/mock_redis/pipelined_wrapper.rb +1 -1
  17. data/lib/mock_redis/stream.rb +22 -2
  18. data/lib/mock_redis/stream/id.rb +1 -1
  19. data/lib/mock_redis/stream_methods.rb +16 -1
  20. data/lib/mock_redis/string_methods.rb +27 -20
  21. data/lib/mock_redis/transaction_wrapper.rb +3 -3
  22. data/lib/mock_redis/utility_methods.rb +1 -1
  23. data/lib/mock_redis/version.rb +1 -1
  24. data/lib/mock_redis/zset_methods.rb +34 -9
  25. data/mock_redis.gemspec +1 -1
  26. data/spec/commands/blpop_spec.rb +0 -6
  27. data/spec/commands/brpop_spec.rb +6 -5
  28. data/spec/commands/connection_spec.rb +15 -0
  29. data/spec/commands/del_spec.rb +17 -0
  30. data/spec/commands/dump_spec.rb +19 -0
  31. data/spec/commands/exists_spec.rb +34 -5
  32. data/spec/commands/future_spec.rb +11 -1
  33. data/spec/commands/geoadd_spec.rb +1 -1
  34. data/spec/commands/hset_spec.rb +6 -6
  35. data/spec/commands/keys_spec.rb +17 -0
  36. data/spec/commands/mget_spec.rb +6 -0
  37. data/spec/commands/move_spec.rb +5 -5
  38. data/spec/commands/pipelined_spec.rb +20 -0
  39. data/spec/commands/restore_spec.rb +47 -0
  40. data/spec/commands/set_spec.rb +59 -9
  41. data/spec/commands/setbit_spec.rb +1 -0
  42. data/spec/commands/setex_spec.rb +16 -0
  43. data/spec/commands/srandmember_spec.rb +1 -1
  44. data/spec/commands/xadd_spec.rb +23 -3
  45. data/spec/commands/xlen_spec.rb +3 -1
  46. data/spec/commands/xrange_spec.rb +13 -0
  47. data/spec/commands/xread_spec.rb +66 -0
  48. data/spec/commands/xtrim_spec.rb +6 -0
  49. data/spec/commands/zinterstore_spec.rb +34 -0
  50. data/spec/commands/zrange_spec.rb +1 -1
  51. data/spec/commands/zrangebyscore_spec.rb +1 -1
  52. data/spec/commands/zrevrange_spec.rb +1 -1
  53. data/spec/commands/zrevrangebyscore_spec.rb +1 -1
  54. data/spec/commands/zunionstore_spec.rb +33 -0
  55. data/spec/spec_helper.rb +2 -1
  56. data/spec/support/redis_multiplexer.rb +2 -1
  57. data/spec/transactions_spec.rb +16 -0
  58. metadata +14 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d9dd8cc0a4f19edccfb6c7b3f1a82724f0da757ad7139f4a576eed1d0b815b8d
4
- data.tar.gz: 980f4326447c75afb034b6292baab71bb723ca05689b04aa7ed4933bd8bbf356
3
+ metadata.gz: b491b0b8e260ee631a3633b35154946ef5822a3310d6bc51ce977febe8559b8a
4
+ data.tar.gz: 795a9ec1aa340ee6b0733b3a539a0ff355dc5e71287f59ca03f2ae64ef9e770e
5
5
  SHA512:
6
- metadata.gz: 53a8419ef9f62a4d276993714241f22f9da4087df9ce69158821ea42c735e4fc022f4ab9431bbef268eb562130cc139308fd46ad9eeef8941ef95d9b56afc083
7
- data.tar.gz: 266de40ac11c22fa449d709380cec9461a93cd18c6950d31aee538b295c613ab2a0ee2fb828420ff02ea2e2351e92e2d565a9bad630abfd21abf8b8eab7c144d
6
+ metadata.gz: ea3fd9aabe7c3afac9c358dbe97a2ffb78277a1d0dab830d6b9983404a1a9f3b2b47f97022441b62884ce01fb6557b1b5a8ca334378bc18ba6c0863b577a947a
7
+ data.tar.gz: 4a487e49858bed2684e8695affe470801de0a6247c1a7281c1f1f3a6913f59ebe38fffee8fa0a41142d20d65cb8339cbb4dd4c2d03ddc2ed5d538760f59fc959
@@ -3,10 +3,10 @@ inherit_from: .rubocop_todo.yml
3
3
  AllCops:
4
4
  TargetRubyVersion: 2.4
5
5
 
6
- Layout/AlignArguments:
6
+ Layout/ArgumentAlignment:
7
7
  Enabled: false
8
8
 
9
- Layout/AlignParameters:
9
+ Layout/ParameterAlignment:
10
10
  Enabled: false
11
11
 
12
12
  Layout/DotPosition:
@@ -15,9 +15,21 @@ Layout/DotPosition:
15
15
  Layout/EmptyLineAfterGuardClause:
16
16
  Enabled: false
17
17
 
18
+ Layout/LineLength:
19
+ Max: 100
20
+
21
+ Layout/SpaceAroundMethodCallOperator:
22
+ Enabled: true
23
+
18
24
  Lint/AssignmentInCondition:
19
25
  Enabled: false
20
26
 
27
+ Lint/RaiseException:
28
+ Enabled: true
29
+
30
+ Lint/StructNewOverride:
31
+ Enabled: true
32
+
21
33
  # We use this a lot in specs where it's perfectly valid
22
34
  Lint/Void:
23
35
  Exclude:
@@ -35,9 +47,6 @@ Metrics/CyclomaticComplexity:
35
47
  Metrics/ClassLength:
36
48
  Enabled: false
37
49
 
38
- Metrics/LineLength:
39
- Max: 100
40
-
41
50
  Metrics/MethodLength:
42
51
  Enabled: false
43
52
 
@@ -57,6 +66,18 @@ Style/Documentation:
57
66
  Style/DoubleNegation:
58
67
  Enabled: false
59
68
 
69
+ Style/ExponentialNotation:
70
+ Enabled: true
71
+
72
+ Style/HashEachMethods:
73
+ Enabled: true
74
+
75
+ Style/HashTransformKeys:
76
+ Enabled: true
77
+
78
+ Style/HashTransformValues:
79
+ Enabled: true
80
+
60
81
  # We have too much code that relies on modifying strings
61
82
  Style/FrozenStringLiteralComment:
62
83
  Enabled: false
@@ -9,7 +9,7 @@
9
9
  # Offense count: 17
10
10
  # Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
11
11
  # AllowedNames: io, id, to, by, on, in, at, ip
12
- Naming/UncommunicativeMethodParamName:
12
+ Naming/MethodParameterName:
13
13
  Exclude:
14
14
  - 'lib/mock_redis/database.rb'
15
15
  - 'lib/mock_redis/expire_wrapper.rb'
@@ -20,6 +20,7 @@ rvm:
20
20
  - 2.4
21
21
  - 2.5
22
22
  - 2.6
23
+ - 2.7
23
24
 
24
25
  before_script:
25
26
  - git config --local user.email "travis@travis.ci"
@@ -1,5 +1,36 @@
1
1
  # MockRedis Changelog
2
2
 
3
+ ### 0.27.0
4
+
5
+ * Fix handling of keyword arguments on Ruby 3 ([#199](https://github.com/sds/mock_redis/pull/199))
6
+ * Allow passing string `offset` to `setbit` ([#200](https://github.com/sds/mock_redis/pull/200))
7
+ * Add `connection` method ([#201](https://github.com/sds/mock_redis/pull/201))
8
+
9
+ ### 0.26.0
10
+
11
+ * Add block and count support to `xread` ([#194](https://github.com/sds/mock_redis/pull/194))
12
+
13
+ ### 0.25.0
14
+
15
+ * Add support for `xread` command ([#190](https://github.com/sds/mock_redis/pull/190))
16
+ * Fix `mget` to raise error when passing empty array ([#191](https://github.com/sds/mock_redis/pull/191))
17
+ * Fix `xadd` when `maxlen` is zero ([#192](https://github.com/sds/mock_redis/pull/192))
18
+
19
+ ### 0.24.0
20
+
21
+ * Fix handling of blocks within `multi` blocks ([#185](https://github.com/sds/mock_redis/pull/185))
22
+ * Fix handling of multiple consecutive `?` characters in key pattern matching ([#186](https://github.com/sds/mock_redis/pull/186))
23
+ * Change `exists` to return an integer and add `exists?` ([#188](https://github.com/sds/mock_redis/pull/188))
24
+
25
+ ### 0.23.0
26
+
27
+ * Raise error when `setex` called with negative timeout ([#174](https://github.com/sds/mock_redis/pull/174))
28
+ * Add support for `dump`/`restore` between MockRedis instances ([#176](https://github.com/sds/mock_redis/pull/176))
29
+ * Fix warnings for ZSET methods on Ruby 2.7 ([#177](https://github.com/sds/mock_redis/pull/177))
30
+ * Add support for returning time in pipelines ([#179](https://github.com/sds/mock_redis/pull/179))
31
+ * Fix SET methods to correct set milliseconds with `px` ([#180](https://github.com/sds/mock_redis/pull/180))
32
+ * Add support for unsorted sets within `zinterstore`/`zunionstore`([#182](https://github.com/sds/mock_redis/pull/182))
33
+
3
34
  ### 0.22.0
4
35
 
5
36
  * Gracefully handle cursors larger than the collection size in scan commands ([#171](https://github.com/sds/mock_redis/pull/171))
data/Gemfile CHANGED
@@ -4,9 +4,11 @@ source 'http://rubygems.org'
4
4
  gemspec
5
5
 
6
6
  # Run all pre-commit hooks via Overcommit during CI runs
7
- gem 'overcommit', '0.48.0'
7
+ gem 'overcommit', '0.53.0'
8
8
 
9
9
  # Pin tool versions (which are executed by Overcommit) for Travis builds
10
- gem 'rubocop', '0.68.1'
10
+ gem 'rubocop', '0.82.0'
11
+
12
+ gem 'ruby2_keywords'
11
13
 
12
14
  gem 'coveralls', require: false
@@ -64,13 +64,6 @@ class MockRedis
64
64
  options[:db]
65
65
  end
66
66
 
67
- def now
68
- current_time = options[:time_class].now
69
- miliseconds = (current_time.to_r - current_time.to_i) * 1_000
70
- [current_time.to_i, miliseconds.to_i]
71
- end
72
- alias time now
73
-
74
67
  def time_at(timestamp)
75
68
  options[:time_class].at(timestamp)
76
69
  end
@@ -91,7 +84,7 @@ class MockRedis
91
84
  super || @db.respond_to?(method, include_private)
92
85
  end
93
86
 
94
- def method_missing(method, *args, &block)
87
+ ruby2_keywords def method_missing(method, *args, &block)
95
88
  @db.send(method, *args, &block)
96
89
  end
97
90
 
@@ -0,0 +1,13 @@
1
+ class MockRedis
2
+ module ConnectionMethod
3
+ def connection
4
+ {
5
+ :host => @base.host,
6
+ :port => @base.port,
7
+ :db => @base.db,
8
+ :id => @base.id,
9
+ :location => "#{@base.host}:#{@base.port}"
10
+ }
11
+ end
12
+ end
13
+ end
@@ -11,6 +11,7 @@ require 'mock_redis/info_method'
11
11
  require 'mock_redis/utility_methods'
12
12
  require 'mock_redis/geospatial_methods'
13
13
  require 'mock_redis/stream_methods'
14
+ require 'mock_redis/connection_method'
14
15
 
15
16
  class MockRedis
16
17
  class Database
@@ -24,6 +25,7 @@ class MockRedis
24
25
  include UtilityMethods
25
26
  include GeospatialMethods
26
27
  include StreamMethods
28
+ include ConnectionMethod
27
29
 
28
30
  attr_reader :data, :expire_times
29
31
 
@@ -35,7 +37,7 @@ class MockRedis
35
37
 
36
38
  def initialize_copy(_source)
37
39
  @data = @data.clone
38
- @data.keys.each { |k| @data[k] = @data[k].clone }
40
+ @data.each_key { |k| @data[k] = @data[k].clone }
39
41
  @expire_times = @expire_times.map(&:clone)
40
42
  end
41
43
 
@@ -106,7 +108,7 @@ class MockRedis
106
108
  raise Redis::CommandError, 'ERR value is not an integer or out of range'
107
109
  end
108
110
 
109
- if exists(key)
111
+ if exists?(key)
110
112
  timestamp = Rational(timestamp_ms.to_i, 1000)
111
113
  set_expiration(key, @base.time_at(timestamp))
112
114
  true
@@ -115,12 +117,33 @@ class MockRedis
115
117
  end
116
118
  end
117
119
 
118
- def exists(key)
119
- data.key?(key)
120
+ def exists(*keys)
121
+ keys.count { |key| data.key?(key) }
122
+ end
123
+
124
+ def exists?(*keys)
125
+ keys.each { |key| return true if data.key?(key) }
126
+ false
120
127
  end
121
128
 
122
129
  def flushdb
123
- data.keys.each { |k| del(k) }
130
+ data.each_key { |k| del(k) }
131
+ 'OK'
132
+ end
133
+
134
+ def dump(key)
135
+ value = data[key]
136
+ value ? Marshal.dump(value) : nil
137
+ end
138
+
139
+ def restore(key, ttl, value, replace: false)
140
+ if !replace && exists?(key)
141
+ raise Redis::CommandError, 'BUSYKEY Target key name already exists.'
142
+ end
143
+ data[key] = Marshal.load(value) # rubocop:disable Security/MarshalLoad
144
+ if ttl > 0
145
+ pexpire(key, ttl)
146
+ end
124
147
  'OK'
125
148
  end
126
149
 
@@ -143,11 +166,11 @@ class MockRedis
143
166
  end
144
167
 
145
168
  def lastsave
146
- @base.now.first
169
+ now.first
147
170
  end
148
171
 
149
172
  def persist(key)
150
- if exists(key) && has_expiration?(key)
173
+ if exists?(key) && has_expiration?(key)
151
174
  remove_expiration(key)
152
175
  true
153
176
  else
@@ -188,7 +211,7 @@ class MockRedis
188
211
  raise Redis::CommandError, 'ERR no such key'
189
212
  end
190
213
 
191
- if exists(newkey)
214
+ if exists?(newkey)
192
215
  false
193
216
  else
194
217
  rename(key, newkey)
@@ -201,7 +224,7 @@ class MockRedis
201
224
  end
202
225
 
203
226
  def ttl(key)
204
- if !exists(key)
227
+ if !exists?(key)
205
228
  -2
206
229
  elsif has_expiration?(key)
207
230
  now, = @base.now
@@ -215,7 +238,7 @@ class MockRedis
215
238
  now, miliseconds = @base.now
216
239
  now_ms = now * 1000 + miliseconds
217
240
 
218
- if !exists(key)
241
+ if !exists?(key)
219
242
  -2
220
243
  elsif has_expiration?(key)
221
244
  (expiration(key).to_r * 1000).to_i - now_ms
@@ -224,8 +247,15 @@ class MockRedis
224
247
  end
225
248
  end
226
249
 
250
+ def now
251
+ current_time = @base.options[:time_class].now
252
+ miliseconds = (current_time.to_r - current_time.to_i) * 1_000
253
+ [current_time.to_i, miliseconds.to_i]
254
+ end
255
+ alias time now
256
+
227
257
  def type(key)
228
- if !exists(key)
258
+ if !exists?(key)
229
259
  'none'
230
260
  elsif hashy?(key)
231
261
  'hash'
@@ -300,7 +330,7 @@ class MockRedis
300
330
  Regexp.new(
301
331
  "^#{pattern}$".
302
332
  gsub(/([+|()])/, '\\\\\1').
303
- gsub(/([^\\])\?/, '\\1.').
333
+ gsub(/(?<!\\)\?/, '\\1.').
304
334
  gsub(/([^\\])\*/, '\\1.*')
305
335
  )
306
336
  end
@@ -328,8 +358,8 @@ class MockRedis
328
358
  # This method isn't private, but it also isn't a Redis command, so
329
359
  # it doesn't belong up above with all the Redis commands.
330
360
  def expire_keys
331
- now, miliseconds = @base.now
332
- now_ms = now * 1_000 + miliseconds
361
+ now_sec, miliseconds = now
362
+ now_ms = now_sec * 1_000 + miliseconds
333
363
 
334
364
  to_delete = expire_times.take_while do |(time, _key)|
335
365
  (time.to_r * 1_000).to_i <= now_ms
@@ -12,7 +12,7 @@ class MockRedis
12
12
  @db = db
13
13
  end
14
14
 
15
- def method_missing(method, *args, &block)
15
+ ruby2_keywords def method_missing(method, *args, &block)
16
16
  @db.expire_keys
17
17
  @db.send(method, *args, &block)
18
18
  end
@@ -17,7 +17,7 @@ class MockRedis
17
17
 
18
18
  def store_result(result)
19
19
  @result_set = true
20
- @result = result
20
+ @result = @block ? @block.call(result) : result
21
21
  end
22
22
  end
23
23
  end
@@ -12,7 +12,7 @@ class MockRedis
12
12
  D_R = Math::PI / 180.0
13
13
  EARTH_RADIUS_IN_METERS = 6_372_797.560856
14
14
 
15
- def geoadd(key, *args)
15
+ ruby2_keywords def geoadd(key, *args)
16
16
  points = parse_points(args)
17
17
 
18
18
  scored_points = points.map do |point|
@@ -38,7 +38,7 @@ class MockRedis
38
38
  lng2, lat2 = geohash_decode(hash2)
39
39
 
40
40
  distance = geohash_distance(lng1, lat1, lng2, lat2) / to_meter
41
- format('%.4f', distance)
41
+ format('%<distance>.4f', distance: distance)
42
42
  end
43
43
 
44
44
  def geohash(key, members)
@@ -95,8 +95,8 @@ class MockRedis
95
95
  lat = Float(point[1])
96
96
 
97
97
  unless LNG_RANGE.include?(lng) && LAT_RANGE.include?(lat)
98
- lng = format('%.6f', lng)
99
- lat = format('%.6f', lat)
98
+ lng = format('%<long>.6f', long: lng)
99
+ lat = format('%<lat>.6f', lat: lat)
100
100
  raise Redis::CommandError,
101
101
  "ERR invalid longitude,latitude pair #{lng},#{lat}"
102
102
  end
@@ -201,7 +201,7 @@ class MockRedis
201
201
  end
202
202
 
203
203
  def format_decoded_coord(coord)
204
- coord = format('%.17f', coord)
204
+ coord = format('%<coord>.17f', coord: coord)
205
205
  l = 1
206
206
  l += 1 while coord[-l] == '0'
207
207
  coord = coord[0..-l]
@@ -128,10 +128,15 @@ class MockRedis
128
128
  end
129
129
  end
130
130
 
131
- def hset(key, field, value)
132
- field_exists = hexists(key, field)
133
- with_hash_at(key) { |h| h[field.to_s] = value.to_s }
134
- !field_exists
131
+ def hset(key, *args)
132
+ added = 0
133
+ with_hash_at(key) do |hash|
134
+ args.each_slice(2) do |field, value|
135
+ added += 1 unless hash.key?(field.to_s)
136
+ hash[field.to_s] = value.to_s
137
+ end
138
+ end
139
+ added
135
140
  end
136
141
 
137
142
  def hsetnx(key, field, value)
@@ -83,7 +83,7 @@ class MockRedis
83
83
 
84
84
  # The Ruby Redis client returns commandstats differently when it's called as
85
85
  # "INFO commandstats".
86
- # rubocop:disable Metrics/LineLength
86
+ # rubocop:disable Layout/LineLength
87
87
  COMMAND_STATS_SOLO_INFO = {
88
88
  'auth' => { 'calls' => '572501', 'usec' => '2353163', 'usec_per_call' => '4.11' },
89
89
  'client' => { 'calls' => '1', 'usec' => '80', 'usec_per_call' => '80.00' },
@@ -123,7 +123,7 @@ class MockRedis
123
123
  'cmdstat_smembers' => 'calls=58,usec=231,usec_per_call=3.98',
124
124
  'cmdstat_sunionstore' => 'calls=4185027,usec=11762454022,usec_per_call=2810.60',
125
125
  }.freeze
126
- # rubocop:enable Metrics/LineLength
126
+ # rubocop:enable Layout/LineLength
127
127
 
128
128
  DEFAULT_INFO = [
129
129
  SERVER_INFO,
@@ -17,14 +17,14 @@ class MockRedis
17
17
  super || current_db.respond_to?(method, include_private)
18
18
  end
19
19
 
20
- def method_missing(method, *args, &block)
20
+ ruby2_keywords def method_missing(method, *args, &block)
21
21
  current_db.send(method, *args, &block)
22
22
  end
23
23
 
24
24
  def initialize_copy(source)
25
25
  super
26
26
  @databases = @databases.clone
27
- @databases.keys.each do |k|
27
+ @databases.each_key do |k|
28
28
  @databases[k] = @databases[k].clone
29
29
  end
30
30
  end
@@ -39,7 +39,7 @@ class MockRedis
39
39
  src = current_db
40
40
  dest = db(db_index)
41
41
 
42
- if !src.exists(key) || dest.exists(key)
42
+ if !src.exists?(key) || dest.exists?(key)
43
43
  false
44
44
  else
45
45
  case current_db.type(key)