mock_redis 0.19.0 → 0.24.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 (81) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +32 -5
  3. data/.rubocop_todo.yml +1 -1
  4. data/.travis.yml +9 -10
  5. data/CHANGELOG.md +46 -0
  6. data/Gemfile +2 -2
  7. data/LICENSE.md +21 -0
  8. data/README.md +39 -15
  9. data/lib/mock_redis.rb +0 -5
  10. data/lib/mock_redis/database.rb +59 -22
  11. data/lib/mock_redis/future.rb +1 -1
  12. data/lib/mock_redis/geospatial_methods.rb +14 -22
  13. data/lib/mock_redis/hash_methods.rb +23 -15
  14. data/lib/mock_redis/indifferent_hash.rb +0 -8
  15. data/lib/mock_redis/info_method.rb +2 -2
  16. data/lib/mock_redis/list_methods.rb +2 -2
  17. data/lib/mock_redis/multi_db_wrapper.rb +2 -2
  18. data/lib/mock_redis/pipelined_wrapper.rb +25 -6
  19. data/lib/mock_redis/set_methods.rb +16 -4
  20. data/lib/mock_redis/stream.rb +62 -0
  21. data/lib/mock_redis/stream/id.rb +60 -0
  22. data/lib/mock_redis/stream_methods.rb +87 -0
  23. data/lib/mock_redis/string_methods.rb +31 -20
  24. data/lib/mock_redis/transaction_wrapper.rb +27 -14
  25. data/lib/mock_redis/utility_methods.rb +6 -3
  26. data/lib/mock_redis/version.rb +1 -1
  27. data/lib/mock_redis/zset_methods.rb +54 -11
  28. data/mock_redis.gemspec +6 -6
  29. data/spec/client_spec.rb +12 -0
  30. data/spec/commands/blpop_spec.rb +0 -6
  31. data/spec/commands/brpop_spec.rb +6 -5
  32. data/spec/commands/dump_spec.rb +19 -0
  33. data/spec/commands/exists_spec.rb +34 -5
  34. data/spec/commands/future_spec.rb +11 -1
  35. data/spec/commands/geoadd_spec.rb +1 -1
  36. data/spec/commands/geodist_spec.rb +8 -4
  37. data/spec/commands/geohash_spec.rb +4 -4
  38. data/spec/commands/geopos_spec.rb +4 -4
  39. data/spec/commands/get_spec.rb +1 -0
  40. data/spec/commands/hdel_spec.rb +18 -2
  41. data/spec/commands/hmset_spec.rb +26 -0
  42. data/spec/commands/hset_spec.rb +6 -6
  43. data/spec/commands/keys_spec.rb +17 -0
  44. data/spec/commands/mget_spec.rb +34 -15
  45. data/spec/commands/move_spec.rb +5 -5
  46. data/spec/commands/mset_spec.rb +14 -0
  47. data/spec/commands/pipelined_spec.rb +72 -0
  48. data/spec/commands/restore_spec.rb +47 -0
  49. data/spec/commands/scan_spec.rb +9 -0
  50. data/spec/commands/set_spec.rb +12 -2
  51. data/spec/commands/setbit_spec.rb +1 -0
  52. data/spec/commands/setex_spec.rb +16 -0
  53. data/spec/commands/spop_spec.rb +15 -0
  54. data/spec/commands/srandmember_spec.rb +1 -1
  55. data/spec/commands/srem_spec.rb +5 -0
  56. data/spec/commands/watch_spec.rb +8 -3
  57. data/spec/commands/xadd_spec.rb +104 -0
  58. data/spec/commands/xlen_spec.rb +20 -0
  59. data/spec/commands/xrange_spec.rb +141 -0
  60. data/spec/commands/xrevrange_spec.rb +130 -0
  61. data/spec/commands/xtrim_spec.rb +30 -0
  62. data/spec/commands/zinterstore_spec.rb +34 -0
  63. data/spec/commands/zpopmax_spec.rb +60 -0
  64. data/spec/commands/zpopmin_spec.rb +60 -0
  65. data/spec/commands/zrange_spec.rb +1 -1
  66. data/spec/commands/zrangebyscore_spec.rb +1 -1
  67. data/spec/commands/zrevrange_spec.rb +1 -1
  68. data/spec/commands/zrevrangebyscore_spec.rb +1 -1
  69. data/spec/commands/zunionstore_spec.rb +33 -0
  70. data/spec/mock_redis_spec.rb +4 -6
  71. data/spec/spec_helper.rb +6 -2
  72. data/spec/support/redis_multiplexer.rb +18 -1
  73. data/spec/support/shared_examples/does_not_cleanup_empty_strings.rb +14 -0
  74. data/spec/support/shared_examples/only_operates_on_hashes.rb +2 -0
  75. data/spec/support/shared_examples/only_operates_on_lists.rb +2 -0
  76. data/spec/support/shared_examples/only_operates_on_sets.rb +2 -0
  77. data/spec/support/shared_examples/only_operates_on_zsets.rb +2 -0
  78. data/spec/transactions_spec.rb +30 -26
  79. metadata +45 -31
  80. data/LICENSE +0 -19
  81. data/spec/commands/hash_operator_spec.rb +0 -21
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: da2c2693b445e51b487e52f7c9b3986960417686792f9a5e554ca4d215c323e2
4
- data.tar.gz: 8da2170fcc49e768133a61deb716d72cc18d66291567008d96287b8d2104b15c
3
+ metadata.gz: 0d399a835c1f41a8eb0e5fc42a366e64fc399b5d76ebc23f0d40f73c9db4888e
4
+ data.tar.gz: 1442920d2b12e46d2d45ff9d8854e4ccf3665b5a5f9a4aef6d29669c9110d023
5
5
  SHA512:
6
- metadata.gz: 15b8b59cff1120de0befaee6cf08facfb120e239d3fbc1b6b55f40bb60c526f57e5cbb61f1d9f6fd5538067122e49b80e9e782590cd98070a3d49943ec8bb929
7
- data.tar.gz: 52a09f0896a405137be0075db930bec09898dd96e3d5366a95ef6a189268348f91244c051dbe45db5b4b37023a12f87552868fcaf2a5383316bebe9bdaf44997
6
+ metadata.gz: 62b218977c75b5c7ffc80e3762bf0f7791c8f17dfe4f875a8874118583124736ab782e1c985dc92363d62e4366170306d9d0211b19cead2982f16cbff2c13557
7
+ data.tar.gz: 97b5eeb1c20e597d2ce35e9d109f62aaf3a2271f42c86515be1d7e0d627ad628173aee7d74062b119cf954538116f0b199d06eee5d1fe71b552dea543859a69e
@@ -1,17 +1,35 @@
1
1
  inherit_from: .rubocop_todo.yml
2
2
 
3
3
  AllCops:
4
- TargetRubyVersion: 2.2
4
+ TargetRubyVersion: 2.4
5
5
 
6
- Layout/AlignParameters:
6
+ Layout/ArgumentAlignment:
7
+ Enabled: false
8
+
9
+ Layout/ParameterAlignment:
7
10
  Enabled: false
8
11
 
9
12
  Layout/DotPosition:
10
13
  Enabled: false
11
14
 
15
+ Layout/EmptyLineAfterGuardClause:
16
+ Enabled: false
17
+
18
+ Layout/LineLength:
19
+ Max: 100
20
+
21
+ Layout/SpaceAroundMethodCallOperator:
22
+ Enabled: true
23
+
12
24
  Lint/AssignmentInCondition:
13
25
  Enabled: false
14
26
 
27
+ Lint/RaiseException:
28
+ Enabled: true
29
+
30
+ Lint/StructNewOverride:
31
+ Enabled: true
32
+
15
33
  # We use this a lot in specs where it's perfectly valid
16
34
  Lint/Void:
17
35
  Exclude:
@@ -29,9 +47,6 @@ Metrics/CyclomaticComplexity:
29
47
  Metrics/ClassLength:
30
48
  Enabled: false
31
49
 
32
- Metrics/LineLength:
33
- Max: 100
34
-
35
50
  Metrics/MethodLength:
36
51
  Enabled: false
37
52
 
@@ -51,6 +66,18 @@ Style/Documentation:
51
66
  Style/DoubleNegation:
52
67
  Enabled: false
53
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
+
54
81
  # We have too much code that relies on modifying strings
55
82
  Style/FrozenStringLiteralComment:
56
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'
@@ -1,7 +1,5 @@
1
1
  language: ruby
2
2
 
3
- sudo: false
4
-
5
3
  cache: bundler
6
4
 
7
5
  addons:
@@ -12,11 +10,16 @@ addons:
12
10
  services:
13
11
  - redis-server
14
12
 
13
+ before_install:
14
+ - sudo sed -e 's/^bind.*/bind 127.0.0.1/' /etc/redis/redis.conf > redis.conf
15
+ - sudo mv redis.conf /etc/redis
16
+ - sudo service redis-server start
17
+ - echo PING | nc localhost 6379
18
+
15
19
  rvm:
16
- - 2.2
17
- - 2.3.7
18
- - 2.4.4
19
- - 2.5.1
20
+ - 2.4
21
+ - 2.5
22
+ - 2.6
20
23
 
21
24
  before_script:
22
25
  - git config --local user.email "travis@travis.ci"
@@ -27,7 +30,3 @@ script:
27
30
  - bundle exec rspec
28
31
  - bundle exec overcommit --sign
29
32
  - bundle exec overcommit --run
30
-
31
- matrix:
32
- allow_failures:
33
- - rvm: 2.1.0
@@ -1,5 +1,51 @@
1
1
  # MockRedis Changelog
2
2
 
3
+ ### 0.24.0
4
+
5
+ * Fix handling of blocks within `multi` blocks ([#185](https://github.com/sds/mock_redis/pull/185))
6
+ * Fix handling of multiple consecutive `?` characters in key pattern matching ([#186](https://github.com/sds/mock_redis/pull/186))
7
+ * Change `exists` to return an integer and add `exists?` ([#188](https://github.com/sds/mock_redis/pull/188))
8
+
9
+ ### 0.23.0
10
+
11
+ * Raise error when `setex` called with negative timeout ([#174](https://github.com/sds/mock_redis/pull/174))
12
+ * Add support for `dump`/`restore` between MockRedis instances ([#176](https://github.com/sds/mock_redis/pull/176))
13
+ * Fix warnings for ZSET methods on Ruby 2.7 ([#177](https://github.com/sds/mock_redis/pull/177))
14
+ * Add support for returning time in pipelines ([#179](https://github.com/sds/mock_redis/pull/179))
15
+ * Fix SET methods to correct set milliseconds with `px` ([#180](https://github.com/sds/mock_redis/pull/180))
16
+ * Add support for unsorted sets within `zinterstore`/`zunionstore`([#182](https://github.com/sds/mock_redis/pull/182))
17
+
18
+ ### 0.22.0
19
+
20
+ * Gracefully handle cursors larger than the collection size in scan commands ([#171](https://github.com/sds/mock_redis/pull/171))
21
+ * Add `zpopmin` and `zpopmax` commands ([#172](https://github.com/sds/mock_redis/pull/172))
22
+ * Fix `hmset` to support array arguments ([#173](https://github.com/sds/mock_redis/pull/173))
23
+ * Fix `hmset` to always treat keys as strings ([#173](https://github.com/sds/mock_redis/pull/173))
24
+ * Remove unnecessary dependency on `rake` gem
25
+
26
+ ### 0.21.0
27
+
28
+ * Fix behavior of `time` to return array of two integers ([#161](https://github.com/sds/mock_redis/pull/161))
29
+ * Add support for `close` and `disconnect!` ([#163](https://github.com/sds/mock_redis/pull/163))
30
+ * Fix `set` to properly handle (and ignore) other options ([#164](https://github.com/sds/mock_redis/pull/163))
31
+ * Fix `srem` to allow array of integers as argument ([#166](https://github.com/sds/mock_redis/pull/166))
32
+ * Fix `hdel` to allow array as argument ([#168](https://github.com/sds/mock_redis/pull/168))
33
+
34
+ ### 0.20.0
35
+
36
+ * Add support for `count` parameter of `spop`
37
+ * Fix `mget` and `mset` to accept array as parameters
38
+ * Fix pipelined array replies
39
+ * Fix nested pipelining
40
+ * Allow nested multi
41
+ * Require Redis gem 4.0.1 or newer
42
+ * Add support for stream commands on Redis 5
43
+ * Keep empty strings on type mismatch
44
+ * Improve performance of `set_expiration`
45
+ * Fix `watch` to allow multiple keys
46
+ * Add `unlink` alias for `del`
47
+ * Drop support for Ruby 2.3 or older
48
+
3
49
  ### 0.19.0
4
50
 
5
51
  * Require Ruby 2.2+
data/Gemfile CHANGED
@@ -4,9 +4,9 @@ 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.45.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.58.2'
10
+ gem 'rubocop', '0.82.0'
11
11
 
12
12
  gem 'coveralls', require: false
@@ -0,0 +1,21 @@
1
+ MockRedis released under the MIT license.
2
+
3
+ > Copyright (c) Shane da Silva. http://shane.io
4
+ >
5
+ > Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ > of this software and associated documentation files (the "Software"), to deal
7
+ > in the Software without restriction, including without limitation the rights
8
+ > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ > copies of the Software, and to permit persons to whom the Software is
10
+ > furnished to do so, subject to the following conditions:
11
+ >
12
+ > The above copyright notice and this permission notice shall be included in
13
+ > all copies or substantial portions of the Software.
14
+ >
15
+ > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ > SOFTWARE.
data/README.md CHANGED
@@ -1,18 +1,27 @@
1
1
  # MockRedis
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/mock_redis.svg)](http://badge.fury.io/rb/mock_redis)
4
- [![Build Status](https://travis-ci.org/brigade/mock_redis.svg)](https://travis-ci.org/brigade/mock_redis)
5
- [![Coverage Status](https://coveralls.io/repos/brigade/mock_redis/badge.svg)](https://coveralls.io/r/brigade/mock_redis)
4
+ [![Build Status](https://travis-ci.org/sds/mock_redis.svg)](https://travis-ci.org/sds/mock_redis)
5
+ [![Coverage Status](https://coveralls.io/repos/sds/mock_redis/badge.svg)](https://coveralls.io/r/sds/mock_redis)
6
6
 
7
7
  MockRedis provides the same interface as `redis-rb`, but it stores its
8
8
  data in memory instead of talking to a Redis server. It is intended
9
9
  for use in tests.
10
10
 
11
- The current implementation is tested against *Redis 4*. Older versions
12
- of Redis may return different results or not support some commands.
11
+ ## Requirements
12
+
13
+ * Ruby 2.4+
14
+
15
+ The current implementation is tested against **Redis 5**. Older versions may work, but can also return different results or not support some commands.
13
16
 
14
17
  ## Getting Started
15
18
 
19
+ Install the gem:
20
+
21
+ ```bash
22
+ gem install mock_redis
23
+ ```
24
+
16
25
  It's as easy as `require 'mock_redis'; mr = MockRedis.new`. Then you can
17
26
  call the same methods on it as you can call on a real `Redis` object.
18
27
 
@@ -90,17 +99,32 @@ please submit a pull request with your (tested!) implementation.
90
99
  * `#config(:get|:set|:resetstat)` isn't done. They can just return
91
100
  canned values.
92
101
 
93
- ## Compatibility
102
+ ## Running tests
103
+
104
+ We recommend running Redis within a Docker container to make development as simple as possible, but as long as you have a Redis instance listening on `localhost:6379` you should be good to go.
105
+
106
+ 1. Start Redis.
107
+ ```bash
108
+ docker run --rm -p 6379:6379 redis
109
+ ```
110
+ 2. Install dependencies.
111
+ ```bash
112
+ bundle install
113
+ ```
114
+ 3. Run tests.
115
+ ```bash
116
+ bundle exec rspec
117
+ ```
118
+
119
+ These tests were written with Redis running on `localhost` without any
120
+ passwords required. If you're using a different version of Redis, you
121
+ may see failures due to error message text being different and other
122
+ breaking changes over time.
123
+
124
+ ## Changelog
94
125
 
95
- As of version `0.19.0`, Ruby 2.2 and above are supported. For
96
- older versions of Ruby, use `0.18.0` or older.
126
+ If you're interested in seeing the changes and bug fixes between each version of `mock_redis`, read the [MockRedis Changelog](CHANGELOG.md).
97
127
 
98
- ## Running the Tests
128
+ ## License
99
129
 
100
- If you want to work on this, you'll probably want to run the
101
- tests. (Just kidding! There's no probably about it.) These tests were
102
- written with Redis running on `localhost` without any passwords
103
- required. If you're using a different version of Redis, you may see
104
- failures due to error message text being different. If you're running
105
- a really old version of Redis, you'll definitely see failures due to
106
- stuff that doesn't work!
130
+ This project is released under the [MIT license](LICENSE.md).
@@ -64,11 +64,6 @@ class MockRedis
64
64
  options[:db]
65
65
  end
66
66
 
67
- def now
68
- options[:time_class].now
69
- end
70
- alias time now
71
-
72
67
  def time_at(timestamp)
73
68
  options[:time_class].at(timestamp)
74
69
  end
@@ -10,6 +10,7 @@ require 'mock_redis/indifferent_hash'
10
10
  require 'mock_redis/info_method'
11
11
  require 'mock_redis/utility_methods'
12
12
  require 'mock_redis/geospatial_methods'
13
+ require 'mock_redis/stream_methods'
13
14
 
14
15
  class MockRedis
15
16
  class Database
@@ -22,6 +23,7 @@ class MockRedis
22
23
  include InfoMethod
23
24
  include UtilityMethods
24
25
  include GeospatialMethods
26
+ include StreamMethods
25
27
 
26
28
  attr_reader :data, :expire_times
27
29
 
@@ -33,7 +35,7 @@ class MockRedis
33
35
 
34
36
  def initialize_copy(_source)
35
37
  @data = @data.clone
36
- @data.keys.each { |k| @data[k] = @data[k].clone }
38
+ @data.each_key { |k| @data[k] = @data[k].clone }
37
39
  @expire_times = @expire_times.map(&:clone)
38
40
  end
39
41
 
@@ -54,6 +56,8 @@ class MockRedis
54
56
  def disconnect
55
57
  nil
56
58
  end
59
+ alias close disconnect
60
+ alias disconnect! close
57
61
 
58
62
  def connected?
59
63
  true
@@ -73,6 +77,7 @@ class MockRedis
73
77
  each { |k| data.delete(k) }.
74
78
  length
75
79
  end
80
+ alias unlink del
76
81
 
77
82
  def echo(msg)
78
83
  msg.to_s
@@ -83,7 +88,8 @@ class MockRedis
83
88
  end
84
89
 
85
90
  def pexpire(key, ms)
86
- now_ms = (@base.now.to_r * 1000).to_i
91
+ now, miliseconds = @base.now
92
+ now_ms = (now * 1000) + miliseconds
87
93
  pexpireat(key, now_ms + ms.to_i)
88
94
  end
89
95
 
@@ -100,7 +106,7 @@ class MockRedis
100
106
  raise Redis::CommandError, 'ERR value is not an integer or out of range'
101
107
  end
102
108
 
103
- if exists(key)
109
+ if exists?(key)
104
110
  timestamp = Rational(timestamp_ms.to_i, 1000)
105
111
  set_expiration(key, @base.time_at(timestamp))
106
112
  true
@@ -109,12 +115,33 @@ class MockRedis
109
115
  end
110
116
  end
111
117
 
112
- def exists(key)
113
- data.key?(key)
118
+ def exists(*keys)
119
+ keys.count { |key| data.key?(key) }
120
+ end
121
+
122
+ def exists?(*keys)
123
+ keys.each { |key| return true if data.key?(key) }
124
+ false
114
125
  end
115
126
 
116
127
  def flushdb
117
- data.keys.each { |k| del(k) }
128
+ data.each_key { |k| del(k) }
129
+ 'OK'
130
+ end
131
+
132
+ def dump(key)
133
+ value = data[key]
134
+ value ? Marshal.dump(value) : nil
135
+ end
136
+
137
+ def restore(key, ttl, value, replace: false)
138
+ if !replace && exists?(key)
139
+ raise Redis::CommandError, 'BUSYKEY Target key name already exists.'
140
+ end
141
+ data[key] = Marshal.load(value) # rubocop:disable Security/MarshalLoad
142
+ if ttl > 0
143
+ pexpire(key, ttl)
144
+ end
118
145
  'OK'
119
146
  end
120
147
 
@@ -137,11 +164,11 @@ class MockRedis
137
164
  end
138
165
 
139
166
  def lastsave
140
- @base.now.to_i
167
+ now.first
141
168
  end
142
169
 
143
170
  def persist(key)
144
- if exists(key) && has_expiration?(key)
171
+ if exists?(key) && has_expiration?(key)
145
172
  remove_expiration(key)
146
173
  true
147
174
  else
@@ -182,7 +209,7 @@ class MockRedis
182
209
  raise Redis::CommandError, 'ERR no such key'
183
210
  end
184
211
 
185
- if exists(newkey)
212
+ if exists?(newkey)
186
213
  false
187
214
  else
188
215
  rename(key, newkey)
@@ -195,27 +222,38 @@ class MockRedis
195
222
  end
196
223
 
197
224
  def ttl(key)
198
- if !exists(key)
225
+ if !exists?(key)
199
226
  -2
200
227
  elsif has_expiration?(key)
201
- expiration(key).to_i - @base.now.to_i
228
+ now, = @base.now
229
+ expiration(key).to_i - now
202
230
  else
203
231
  -1
204
232
  end
205
233
  end
206
234
 
207
235
  def pttl(key)
208
- if !exists(key)
236
+ now, miliseconds = @base.now
237
+ now_ms = now * 1000 + miliseconds
238
+
239
+ if !exists?(key)
209
240
  -2
210
241
  elsif has_expiration?(key)
211
- (expiration(key).to_r * 1000).to_i - (@base.now.to_r * 1000).to_i
242
+ (expiration(key).to_r * 1000).to_i - now_ms
212
243
  else
213
244
  -1
214
245
  end
215
246
  end
216
247
 
248
+ def now
249
+ current_time = @base.options[:time_class].now
250
+ miliseconds = (current_time.to_r - current_time.to_i) * 1_000
251
+ [current_time.to_i, miliseconds.to_i]
252
+ end
253
+ alias time now
254
+
217
255
  def type(key)
218
- if !exists(key)
256
+ if !exists?(key)
219
257
  'none'
220
258
  elsif hashy?(key)
221
259
  'hash'
@@ -290,7 +328,7 @@ class MockRedis
290
328
  Regexp.new(
291
329
  "^#{pattern}$".
292
330
  gsub(/([+|()])/, '\\\\\1').
293
- gsub(/([^\\])\?/, '\\1.').
331
+ gsub(/(?<!\\)\?/, '\\1.').
294
332
  gsub(/([^\\])\*/, '\\1.*')
295
333
  )
296
334
  end
@@ -303,11 +341,9 @@ class MockRedis
303
341
 
304
342
  def set_expiration(key, time)
305
343
  remove_expiration(key)
306
-
307
- expire_times << [time, key.to_s]
308
- expire_times.sort! do |a, b|
309
- a.first <=> b.first
310
- end
344
+ found = expire_times.each_with_index.to_a.bsearch { |item, _| item.first >= time }
345
+ index = found ? found.last : -1
346
+ expire_times.insert(index, [time, key.to_s])
311
347
  end
312
348
 
313
349
  def zero_pad(string, desired_length)
@@ -320,10 +356,11 @@ class MockRedis
320
356
  # This method isn't private, but it also isn't a Redis command, so
321
357
  # it doesn't belong up above with all the Redis commands.
322
358
  def expire_keys
323
- now = @base.now
359
+ now_sec, miliseconds = now
360
+ now_ms = now_sec * 1_000 + miliseconds
324
361
 
325
362
  to_delete = expire_times.take_while do |(time, _key)|
326
- (time.to_r * 1_000).to_i <= (now.to_r * 1_000).to_i
363
+ (time.to_r * 1_000).to_i <= now_ms
327
364
  end
328
365
 
329
366
  to_delete.each do |(_time, key)|