fakeredis 0.5.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +3 -0
- data/.travis.yml +14 -5
- data/LICENSE +1 -1
- data/README.md +42 -24
- data/fakeredis.gemspec +1 -1
- data/lib/fakeredis.rb +28 -0
- data/lib/fakeredis/bitop_command.rb +56 -0
- data/lib/fakeredis/command_executor.rb +6 -9
- data/lib/fakeredis/expiring_hash.rb +3 -5
- data/lib/fakeredis/geo_commands.rb +142 -0
- data/lib/fakeredis/geo_set.rb +84 -0
- data/lib/fakeredis/minitest.rb +24 -0
- data/lib/fakeredis/rspec.rb +1 -0
- data/lib/fakeredis/sort_method.rb +3 -3
- data/lib/fakeredis/sorted_set_store.rb +1 -1
- data/lib/fakeredis/transaction_commands.rb +2 -2
- data/lib/fakeredis/version.rb +1 -1
- data/lib/fakeredis/zset.rb +8 -2
- data/lib/redis/connection/memory.rb +650 -82
- data/spec/bitop_command_spec.rb +209 -0
- data/spec/command_executor_spec.rb +15 -0
- data/spec/compatibility_spec.rb +1 -1
- data/spec/connection_spec.rb +21 -21
- data/spec/fakeredis_spec.rb +73 -0
- data/spec/geo_set_spec.rb +164 -0
- data/spec/hashes_spec.rb +138 -57
- data/spec/hyper_log_logs_spec.rb +50 -0
- data/spec/keys_spec.rb +232 -90
- data/spec/lists_spec.rb +91 -35
- data/spec/memory_spec.rb +80 -7
- data/spec/server_spec.rb +38 -24
- data/spec/sets_spec.rb +112 -46
- data/spec/sort_method_spec.rb +6 -0
- data/spec/sorted_sets_spec.rb +482 -150
- data/spec/spec_helper.rb +9 -18
- data/spec/spec_helper_live_redis.rb +4 -4
- data/spec/strings_spec.rb +113 -79
- data/spec/subscription_spec.rb +107 -0
- data/spec/support/shared_examples/bitwise_operation.rb +59 -0
- data/spec/support/shared_examples/sortable.rb +20 -16
- data/spec/transactions_spec.rb +34 -13
- data/spec/upcase_method_name_spec.rb +2 -2
- metadata +23 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7c0b77a04c1c761edb3a6544aca213f373d57bb485d17f9e7e0f2c63bfd7e660
|
4
|
+
data.tar.gz: 57975993a6664bc469ee297a6a36d75ac2e4e429972aee6e50a2f518f93ca580
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba35de9b7e297eca69cb7652d7817f257c447d7533d8c259c47215b15355ec49e5c2584907f0726f97327c443de122bd240cbca6fa194222f114bc99ffd0dbb9
|
7
|
+
data.tar.gz: 8c4e340be842d1fe966a3a4c6f63987bc8af346da74ced914cdc77488e08a6d15101ee6625097337287ec55c19f41118da4a79892b7fdd00bbebff1d103a813a
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -1,8 +1,17 @@
|
|
1
1
|
language: ruby
|
2
|
+
cache: bundler
|
3
|
+
# Use the faster container based infrastructure
|
4
|
+
# http://blog.travis-ci.com/2014-12-17-faster-builds-with-container-based-infrastructure/
|
5
|
+
sudo: false
|
6
|
+
|
2
7
|
rvm:
|
3
|
-
-
|
4
|
-
-
|
5
|
-
- 2.
|
6
|
-
-
|
7
|
-
- jruby
|
8
|
+
- 2.4
|
9
|
+
- 2.5
|
10
|
+
- 2.6
|
11
|
+
- ruby-head
|
12
|
+
- jruby
|
8
13
|
- rbx-2
|
14
|
+
|
15
|
+
matrix:
|
16
|
+
allow_failures:
|
17
|
+
- rvm: rbx-2
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -15,8 +15,8 @@ Add it to your Gemfile:
|
|
15
15
|
|
16
16
|
## Versions
|
17
17
|
|
18
|
-
FakeRedis currently supports redis-rb v3
|
19
|
-
redis-rb v2.2
|
18
|
+
FakeRedis currently supports redis-rb v3 or later, if you are using
|
19
|
+
redis-rb v2.2 install the version 0.3.x:
|
20
20
|
|
21
21
|
gem install fakeredis -v "~> 0.3.0"
|
22
22
|
|
@@ -29,45 +29,63 @@ or use the branch 0-3-x on your Gemfile:
|
|
29
29
|
|
30
30
|
You can use FakeRedis without any changes:
|
31
31
|
|
32
|
+
```
|
32
33
|
require "fakeredis"
|
33
|
-
|
34
|
+
|
34
35
|
redis = Redis.new
|
35
|
-
|
36
|
+
|
36
37
|
>> redis.set "foo", "bar"
|
37
38
|
=> "OK"
|
38
|
-
|
39
|
+
|
39
40
|
>> redis.get "foo"
|
40
41
|
=> "bar"
|
42
|
+
```
|
41
43
|
|
42
|
-
Read [redis-rb](https://github.com/
|
44
|
+
Read [redis-rb](https://github.com/redis/redis-rb) documentation and
|
43
45
|
[Redis](http://redis.io) homepage for more info about commands
|
44
46
|
|
45
47
|
## Usage with RSpec
|
46
48
|
|
47
|
-
Require this either in your Gemfile or in RSpec's support scripts. So either:
|
49
|
+
Require this either in your Gemfile or in RSpec's support scripts. So either:
|
48
50
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
51
|
+
```ruby
|
52
|
+
# Gemfile
|
53
|
+
group :test do
|
54
|
+
gem "rspec"
|
55
|
+
gem "fakeredis", :require => "fakeredis/rspec"
|
56
|
+
end
|
57
|
+
```
|
54
58
|
|
55
59
|
Or:
|
56
60
|
|
57
|
-
|
58
|
-
|
61
|
+
```ruby
|
62
|
+
# spec/support/fakeredis.rb
|
63
|
+
require 'fakeredis/rspec'
|
64
|
+
```
|
59
65
|
|
60
|
-
##
|
66
|
+
## Usage with Minitest
|
67
|
+
|
68
|
+
Require this either in your Gemfile or in Minitest's support scripts. So
|
69
|
+
either:
|
61
70
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
71
|
+
```ruby
|
72
|
+
# Gemfile
|
73
|
+
group :test do
|
74
|
+
gem "minitest"
|
75
|
+
gem "fakeredis", :require => "fakeredis/minitest"
|
76
|
+
end
|
77
|
+
```
|
78
|
+
|
79
|
+
Or:
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
# test/test_helper.rb (or test/minitest_config.rb)
|
83
|
+
require 'fakeredis/minitest'
|
84
|
+
```
|
85
|
+
|
86
|
+
## Acknowledgements
|
70
87
|
|
88
|
+
Thanks to [all contributors](https://github.com/guilleiguaran/fakeredis/graphs/contributors), specially to [Caius Durling](https://github.com/caius) the most active one.
|
71
89
|
|
72
90
|
## Contributing to FakeRedis
|
73
91
|
|
@@ -82,5 +100,5 @@ Or:
|
|
82
100
|
|
83
101
|
## Copyright
|
84
102
|
|
85
|
-
Copyright (c) 2011-
|
103
|
+
Copyright (c) 2011-2018 Guillermo Iguaran. See LICENSE for
|
86
104
|
further details.
|
data/fakeredis.gemspec
CHANGED
@@ -18,6 +18,6 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
19
|
s.require_paths = ["lib"]
|
20
20
|
|
21
|
-
s.add_runtime_dependency(%q<redis>, ["~>
|
21
|
+
s.add_runtime_dependency(%q<redis>, ["~> 4.1"])
|
22
22
|
s.add_development_dependency(%q<rspec>, ["~> 3.0"])
|
23
23
|
end
|
data/lib/fakeredis.rb
CHANGED
@@ -3,4 +3,32 @@ require 'redis/connection/memory'
|
|
3
3
|
|
4
4
|
module FakeRedis
|
5
5
|
Redis = ::Redis
|
6
|
+
|
7
|
+
def self.enable
|
8
|
+
Redis::Connection.drivers << Redis::Connection::Memory unless enabled?
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.enabled?
|
12
|
+
Redis::Connection.drivers.last == Redis::Connection::Memory
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.disable
|
16
|
+
Redis::Connection.drivers.delete_if {|driver| Redis::Connection::Memory == driver }
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.disabling
|
20
|
+
return yield unless enabled?
|
21
|
+
|
22
|
+
disable
|
23
|
+
yield
|
24
|
+
enable
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.enabling
|
28
|
+
return yield if enabled?
|
29
|
+
|
30
|
+
enable
|
31
|
+
yield
|
32
|
+
disable
|
33
|
+
end
|
6
34
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module FakeRedis
|
2
|
+
module BitopCommand
|
3
|
+
BIT_OPERATORS = {
|
4
|
+
'or' => :|,
|
5
|
+
'and' => :&,
|
6
|
+
'xor' => :'^',
|
7
|
+
'not' => :~,
|
8
|
+
}
|
9
|
+
|
10
|
+
def bitop(operation, destkey, *keys)
|
11
|
+
if result = apply(operator(operation), keys)
|
12
|
+
set(destkey, result)
|
13
|
+
result.length
|
14
|
+
else
|
15
|
+
0
|
16
|
+
end
|
17
|
+
rescue ArgumentError => _
|
18
|
+
raise_argument_error('bitop')
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def operator(operation)
|
24
|
+
BIT_OPERATORS[operation.to_s.downcase]
|
25
|
+
end
|
26
|
+
|
27
|
+
def apply(operator, keys)
|
28
|
+
case operator
|
29
|
+
when :~
|
30
|
+
raise ArgumentError if keys.count != 1
|
31
|
+
bitwise_not(keys.first)
|
32
|
+
when :&, :|, :'^'
|
33
|
+
raise ArgumentError if keys.empty?
|
34
|
+
bitwise_operation(operator, keys)
|
35
|
+
else
|
36
|
+
raise ArgumentError
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def bitwise_not(key)
|
41
|
+
if value = get(keys.first)
|
42
|
+
value.bytes.map { |byte| ~ byte }.pack('c*')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def bitwise_operation(operation, keys)
|
47
|
+
apply_onto, *values = keys.map { |key| get(key) }.reject(&:nil?)
|
48
|
+
values.reduce(apply_onto) do |memo, value|
|
49
|
+
shorter, longer = [memo, value].sort_by(&:length).map(&:bytes).map(&:to_a)
|
50
|
+
longer.each_with_index.map do |byte, index|
|
51
|
+
byte.send(operation, shorter[index] || 0)
|
52
|
+
end.pack('c*')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -1,23 +1,20 @@
|
|
1
1
|
module FakeRedis
|
2
2
|
module CommandExecutor
|
3
3
|
def write(command)
|
4
|
-
meffod = command.
|
4
|
+
meffod = command[0].to_s.downcase.to_sym
|
5
|
+
args = command[1..-1]
|
5
6
|
|
6
7
|
if in_multi && !(TRANSACTION_COMMANDS.include? meffod) # queue commands
|
7
|
-
queued_commands << [meffod, *
|
8
|
+
queued_commands << [meffod, *args]
|
8
9
|
reply = 'QUEUED'
|
10
|
+
elsif respond_to?(meffod) && method(meffod).arity.zero?
|
11
|
+
reply = send(meffod)
|
9
12
|
elsif respond_to?(meffod)
|
10
|
-
reply = send(meffod, *
|
13
|
+
reply = send(meffod, *args)
|
11
14
|
else
|
12
15
|
raise Redis::CommandError, "ERR unknown command '#{meffod}'"
|
13
16
|
end
|
14
17
|
|
15
|
-
if reply == true
|
16
|
-
reply = 1
|
17
|
-
elsif reply == false
|
18
|
-
reply = 0
|
19
|
-
end
|
20
|
-
|
21
18
|
replies << reply
|
22
19
|
nil
|
23
20
|
end
|
@@ -34,7 +34,7 @@ module FakeRedis
|
|
34
34
|
|
35
35
|
def expired?(key)
|
36
36
|
key = normalize key
|
37
|
-
expires.include?(key) && expires[key]
|
37
|
+
expires.include?(key) && expires[key] <= Time.now
|
38
38
|
end
|
39
39
|
|
40
40
|
def key?(key)
|
@@ -44,10 +44,8 @@ module FakeRedis
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def values_at(*keys)
|
47
|
-
keys.
|
48
|
-
|
49
|
-
delete(key) if expired?(key)
|
50
|
-
end
|
47
|
+
keys = keys.map { |key| normalize(key) }
|
48
|
+
keys.each { |key| delete(key) if expired?(key) }
|
51
49
|
super
|
52
50
|
end
|
53
51
|
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require "fakeredis/geo_set"
|
2
|
+
|
3
|
+
module FakeRedis
|
4
|
+
module GeoCommands
|
5
|
+
DISTANCE_UNITS = {
|
6
|
+
"m" => 1,
|
7
|
+
"km" => 1000,
|
8
|
+
"ft" => 0.3048,
|
9
|
+
"mi" => 1609.34
|
10
|
+
}
|
11
|
+
|
12
|
+
REDIS_DOUBLE_PRECISION = 4
|
13
|
+
REDIS_GEOHASH_SIZE = 10
|
14
|
+
|
15
|
+
def geoadd(key, *members)
|
16
|
+
raise_argument_error("geoadd") if members.empty? || members.size % 3 != 0
|
17
|
+
|
18
|
+
set = (data[key] ||= GeoSet.new)
|
19
|
+
prev_size = set.size
|
20
|
+
members.each_slice(3) do |member|
|
21
|
+
set.add(*member)
|
22
|
+
end
|
23
|
+
set.size - prev_size
|
24
|
+
end
|
25
|
+
|
26
|
+
def geodist(key, member1, member2, unit = "m")
|
27
|
+
unit = unit.to_s
|
28
|
+
raise_command_error("ERR unsupported unit provided. please use #{DISTANCE_UNITS.keys.join(', ')}") unless DISTANCE_UNITS.include?(unit)
|
29
|
+
|
30
|
+
set = (data[key] || GeoSet.new)
|
31
|
+
point1 = set.get(member1)
|
32
|
+
point2 = set.get(member2)
|
33
|
+
if point1 && point2
|
34
|
+
distance = point1.distance_to(point2)
|
35
|
+
distance_in_units = distance / DISTANCE_UNITS[unit]
|
36
|
+
distance_in_units.round(REDIS_DOUBLE_PRECISION).to_s
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def geohash(key, member)
|
41
|
+
members = Array(member)
|
42
|
+
raise_argument_error("geohash") if members.empty?
|
43
|
+
set = (data[key] || GeoSet.new)
|
44
|
+
members.map do |member|
|
45
|
+
point = set.get(member)
|
46
|
+
point.geohash(REDIS_GEOHASH_SIZE) if point
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def geopos(key, member)
|
51
|
+
return nil unless data[key]
|
52
|
+
|
53
|
+
members = Array(member)
|
54
|
+
set = (data[key] || GeoSet.new)
|
55
|
+
members.map do |member|
|
56
|
+
point = set.get(member)
|
57
|
+
[point.lon.to_s, point.lat.to_s] if point
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def georadius(*args)
|
62
|
+
args = args.dup
|
63
|
+
raise_argument_error("georadius") if args.size < 5
|
64
|
+
key, lon, lat, radius, unit, *rest = args
|
65
|
+
raise_argument_error("georadius") unless DISTANCE_UNITS.has_key?(unit)
|
66
|
+
radius *= DISTANCE_UNITS[unit]
|
67
|
+
|
68
|
+
set = (data[key] || GeoSet.new)
|
69
|
+
center = GeoSet::Point.new(lon, lat, nil)
|
70
|
+
|
71
|
+
do_georadius(set, center, radius, unit, rest)
|
72
|
+
end
|
73
|
+
|
74
|
+
def georadiusbymember(*args)
|
75
|
+
args = args.dup
|
76
|
+
raise_argument_error("georadiusbymember") if args.size < 4
|
77
|
+
key, member, radius, unit, *rest = args
|
78
|
+
raise_argument_error("georadiusbymember") unless DISTANCE_UNITS.has_key?(unit)
|
79
|
+
radius *= DISTANCE_UNITS[unit]
|
80
|
+
|
81
|
+
set = (data[key] || GeoSet.new)
|
82
|
+
center = set.get(member)
|
83
|
+
raise_command_error("ERR could not decode requested zset member") unless center
|
84
|
+
|
85
|
+
do_georadius(set, center, radius, unit, args)
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def do_georadius(set, center, radius, unit, args)
|
91
|
+
points = set.points_within_radius(center, radius)
|
92
|
+
|
93
|
+
options = georadius_options(args)
|
94
|
+
|
95
|
+
if options[:asc]
|
96
|
+
points.sort_by! { |p| p.distance_to(center) }
|
97
|
+
elsif options[:desc]
|
98
|
+
points.sort_by! { |p| -p.distance_to(center) }
|
99
|
+
end
|
100
|
+
|
101
|
+
points = points.take(options[:count]) if options[:count]
|
102
|
+
extras = options[:extras]
|
103
|
+
return points.map(&:name) if extras.empty?
|
104
|
+
|
105
|
+
points.map do |point|
|
106
|
+
member = [point.name]
|
107
|
+
|
108
|
+
extras.each do |extra|
|
109
|
+
case extra
|
110
|
+
when "WITHCOORD"
|
111
|
+
member << [point.lon.to_s, point.lat.to_s]
|
112
|
+
when "WITHDIST"
|
113
|
+
distance = point.distance_to(center)
|
114
|
+
distance_in_units = distance / DISTANCE_UNITS[unit]
|
115
|
+
member << distance_in_units.round(REDIS_DOUBLE_PRECISION).to_s
|
116
|
+
when "WITHHASH"
|
117
|
+
member << point.geohash(REDIS_GEOHASH_SIZE)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
member
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def georadius_options(args)
|
126
|
+
options = {}
|
127
|
+
args = args.map { |arg| arg.to_s.upcase }
|
128
|
+
|
129
|
+
if idx = args.index("COUNT")
|
130
|
+
options[:count] = Integer(args[idx + 1])
|
131
|
+
end
|
132
|
+
|
133
|
+
options[:asc] = true if args.include?("ASC")
|
134
|
+
options[:desc] = true if args.include?("DESC")
|
135
|
+
|
136
|
+
extras = args & ["WITHCOORD", "WITHDIST", "WITHHASH"]
|
137
|
+
options[:extras] = extras
|
138
|
+
|
139
|
+
options
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|