fakeredis 0.1.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.
- data/.gitignore +5 -0
- data/.rspec +1 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +40 -0
- data/Rakefile +26 -0
- data/fakeredis.gemspec +23 -0
- data/lib/fakeredis.rb +26 -0
- data/lib/fakeredis/connection.rb +25 -0
- data/lib/fakeredis/hashes.rb +98 -0
- data/lib/fakeredis/keys.rb +82 -0
- data/lib/fakeredis/lists.rb +108 -0
- data/lib/fakeredis/server.rb +65 -0
- data/lib/fakeredis/sets.rb +122 -0
- data/lib/fakeredis/sorted_sets.rb +108 -0
- data/lib/fakeredis/strings.rb +112 -0
- data/lib/fakeredis/transactions.rb +13 -0
- data/lib/fakeredis/version.rb +3 -0
- data/spec/connection_spec.rb +22 -0
- data/spec/hashes_spec.rb +98 -0
- data/spec/keys_spec.rb +95 -0
- data/spec/lists_spec.rb +134 -0
- data/spec/server_spec.rb +28 -0
- data/spec/sets_spec.rb +153 -0
- data/spec/sorted_sets_spec.rb +81 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/strings_spec.rb +140 -0
- data/spec/transactions_spec.rb +19 -0
- metadata +102 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
module FakeRedis
|
2
|
+
class Redis
|
3
|
+
module ServerMethods
|
4
|
+
|
5
|
+
def bgreriteaof ; end
|
6
|
+
|
7
|
+
def bgsave ; end
|
8
|
+
|
9
|
+
def config_get(param) ; end
|
10
|
+
|
11
|
+
def config_set(param, value) ; end
|
12
|
+
|
13
|
+
def config_resetstat ; end
|
14
|
+
|
15
|
+
def dbsize
|
16
|
+
@data.keys.count
|
17
|
+
end
|
18
|
+
|
19
|
+
def debug_object(key)
|
20
|
+
return @data[key].inspect
|
21
|
+
end
|
22
|
+
|
23
|
+
def flushdb
|
24
|
+
@data = {}
|
25
|
+
@expires = {}
|
26
|
+
end
|
27
|
+
|
28
|
+
alias flushall flushdb
|
29
|
+
|
30
|
+
def info
|
31
|
+
server_info = {
|
32
|
+
"redis_version" => "0.07",
|
33
|
+
"connected_clients" => "1",
|
34
|
+
"connected_slaves" => "0",
|
35
|
+
"used_memory" => "3187",
|
36
|
+
"changes_since_last_save" => "0",
|
37
|
+
"last_save_time" => "1237655729",
|
38
|
+
"total_connections_received" => "1",
|
39
|
+
"total_commands_processed" => "1",
|
40
|
+
"uptime_in_seconds" => "36000",
|
41
|
+
"uptime_in_days" => 0
|
42
|
+
}
|
43
|
+
return server_info
|
44
|
+
end
|
45
|
+
|
46
|
+
def lastsave
|
47
|
+
Time.now.to_i
|
48
|
+
end
|
49
|
+
|
50
|
+
def monitor ; end
|
51
|
+
|
52
|
+
def save ; end
|
53
|
+
|
54
|
+
def shutdown ; end
|
55
|
+
|
56
|
+
def slaveof(host, port) ; end
|
57
|
+
|
58
|
+
def sync ; end
|
59
|
+
|
60
|
+
alias reset flushdb
|
61
|
+
end
|
62
|
+
|
63
|
+
include ServerMethods
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
module FakeRedis
|
2
|
+
class Redis
|
3
|
+
module SetsMethods
|
4
|
+
def sadd(key, value)
|
5
|
+
fail_unless_set(key)
|
6
|
+
case set = @data[key]
|
7
|
+
when nil then @data[key] = Set.new([value.to_s])
|
8
|
+
when Set then set.add(value.to_s)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def scard(key)
|
13
|
+
fail_unless_set(key)
|
14
|
+
case set = @data[key]
|
15
|
+
when nil then 0
|
16
|
+
when Set then set.size
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def sdiff(key1, *keys)
|
21
|
+
[key1, *keys].each { |k| fail_unless_set(k) }
|
22
|
+
keys = keys.map { |k| @data[k] || Set.new }
|
23
|
+
keys.inject(@data[key1]) do |memo, set|
|
24
|
+
memo - set
|
25
|
+
end.to_a
|
26
|
+
end
|
27
|
+
|
28
|
+
def sdiffstore(destination, key1, *keys)
|
29
|
+
fail_unless_set(destination)
|
30
|
+
result = sdiff(key1, *keys)
|
31
|
+
@data[destination] = Set.new(result)
|
32
|
+
end
|
33
|
+
|
34
|
+
def sinter(*keys)
|
35
|
+
keys.each { |k| fail_unless_set(k) }
|
36
|
+
return Set.new if keys.any? { |k| @data[k].nil? }
|
37
|
+
keys = keys.map { |k| @data[k] || Set.new }
|
38
|
+
keys.inject do |set, key|
|
39
|
+
set & key
|
40
|
+
end.to_a
|
41
|
+
end
|
42
|
+
|
43
|
+
def sinterstore(destination, *keys)
|
44
|
+
fail_unless_set(destination)
|
45
|
+
result = sinter(*keys)
|
46
|
+
@data[destination] = Set.new(result)
|
47
|
+
end
|
48
|
+
|
49
|
+
def sismember(key, value)
|
50
|
+
fail_unless_set(key)
|
51
|
+
case set = @data[key]
|
52
|
+
when nil then false
|
53
|
+
when Set then set.include?(value.to_s)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def smembers(key)
|
58
|
+
fail_unless_set(key)
|
59
|
+
case set = @data[key]
|
60
|
+
when nil then []
|
61
|
+
when Set then set.to_a
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def smove(source, destination, value)
|
66
|
+
fail_unless_set(destination)
|
67
|
+
if elem = self.srem(source, value)
|
68
|
+
self.sadd(destination, value)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def spop(key)
|
73
|
+
fail_unless_set(key)
|
74
|
+
elem = srandmember(key)
|
75
|
+
srem(key, elem)
|
76
|
+
elem
|
77
|
+
end
|
78
|
+
|
79
|
+
def srandmember(key)
|
80
|
+
fail_unless_set(key)
|
81
|
+
case set = @data[key]
|
82
|
+
when nil then nil
|
83
|
+
when Set then set.to_a[rand(set.size)]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def srem(key, value)
|
88
|
+
fail_unless_set(key)
|
89
|
+
case set = @data[key]
|
90
|
+
when nil then return
|
91
|
+
when Set then set.delete(value.to_s)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def sunion(*keys)
|
96
|
+
keys.each { |k| fail_unless_set(k) }
|
97
|
+
keys = keys.map { |k| @data[k] || Set.new }
|
98
|
+
keys.inject(Set.new) do |set, key|
|
99
|
+
set | key
|
100
|
+
end.to_a
|
101
|
+
end
|
102
|
+
|
103
|
+
def sunionstore(destination, *keys)
|
104
|
+
fail_unless_set(destination)
|
105
|
+
result = sunion(*keys)
|
106
|
+
@data[destination] = Set.new(result)
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def is_a_set?(key)
|
112
|
+
@data[key].is_a?(Set) || @data[key].nil?
|
113
|
+
end
|
114
|
+
|
115
|
+
def fail_unless_set(key)
|
116
|
+
fail "Not a set" unless is_a_set?(key)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
include SetsMethods
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module FakeRedis
|
2
|
+
class Redis
|
3
|
+
module SortedSetsMethods
|
4
|
+
class Elem < String
|
5
|
+
attr_accessor :score
|
6
|
+
def initialize(str="", score)
|
7
|
+
super(str)
|
8
|
+
@score = score
|
9
|
+
end
|
10
|
+
def <=>(other)
|
11
|
+
@score <=> other.score
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class CustomSortedSet < SortedSet
|
16
|
+
attr_accessor :indexed_set
|
17
|
+
def add(o)
|
18
|
+
super(o)
|
19
|
+
@indexed_set ||= Set.new
|
20
|
+
@indexed_set.add(o)
|
21
|
+
end
|
22
|
+
|
23
|
+
def delete(o)
|
24
|
+
super(o)
|
25
|
+
@indexed_set ||= Set.new
|
26
|
+
@indexed_set.delete(o)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def zadd(key, score, value)
|
31
|
+
fail_unless_sorted_set(key)
|
32
|
+
case set = @data[key]
|
33
|
+
when nil then @data[key] = CustomSortedSet.new([Elem.new(value.to_s, score)])
|
34
|
+
when CustomSortedSet then set.delete(value.to_s) ; set.add(Elem.new(value.to_s, score))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def zcard(key)
|
39
|
+
fail_unless_sorted_set(key)
|
40
|
+
case set = @data[key]
|
41
|
+
when nil then 0
|
42
|
+
when CustomSortedSet then set.size
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def zcount(key, min, max)
|
47
|
+
fail_unless_sorted_set(key)
|
48
|
+
case set = @data[key]
|
49
|
+
when nil then 0
|
50
|
+
when CustomSortedSet then set.select{|x| x.score >= min && x.score <= max }.size
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def zincrby(key, incr, value)
|
55
|
+
fail_unless_sorted_set(key)
|
56
|
+
case set = @data[key]
|
57
|
+
when nil then @data[key] = CustomSortedSet.new([Elem.new(value.to_s, incr)])
|
58
|
+
when CustomSortedSet then
|
59
|
+
score = set.to_a.select{|x| x == value.to_s}.first.score
|
60
|
+
set.delete(value.to_s)
|
61
|
+
set.add(Elem.new(value.to_s, score+incr))
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def zrange(key, start, stop)
|
66
|
+
fail_unless_sorted_set(key)
|
67
|
+
case set = @data[key]
|
68
|
+
when nil then []
|
69
|
+
when CustomSortedSet then set.indexed_set.to_a[start..stop]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def zrangescore(key, start, stop)
|
74
|
+
fail_unless_sorted_set(key)
|
75
|
+
case set = @data[key]
|
76
|
+
when nil then []
|
77
|
+
when CustomSortedSet then set.to_a.reverse[start..stop]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def zrank(key, value)
|
82
|
+
fail_unless_sorted_set(key)
|
83
|
+
case set = @data[key]
|
84
|
+
when nil then nil
|
85
|
+
when CustomSortedSet then set.to_a.index(value)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def zscore(key, value)
|
90
|
+
case set = @data[key]
|
91
|
+
when nil then 0
|
92
|
+
when CustomSortedSet then set.to_a.select{|x| x == value.to_s}.first.score
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def is_a_sorted_set?(key)
|
99
|
+
@data[key].is_a?(CustomSortedSet) || @data[key].nil?
|
100
|
+
end
|
101
|
+
|
102
|
+
def fail_unless_sorted_set(key)
|
103
|
+
fail "Not a sorted set" unless is_a_sorted_set?(key)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
include SortedSetsMethods
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module FakeRedis
|
2
|
+
class Redis
|
3
|
+
module StringsMethods
|
4
|
+
|
5
|
+
def append(key, value)
|
6
|
+
@data[key] = (@data[key] || "")
|
7
|
+
@data[key] = @data[key] + value.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
def decr(key)
|
11
|
+
@data[key] = (@data[key] || "0")
|
12
|
+
@data[key] = (@data[key].to_i - 1).to_s
|
13
|
+
end
|
14
|
+
|
15
|
+
def decrby(key, by)
|
16
|
+
@data[key] = (@data[key] || "0")
|
17
|
+
@data[key] = (@data[key].to_i - by.to_i).to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
def get(key)
|
21
|
+
#return if expired?(key)
|
22
|
+
@data[key]
|
23
|
+
end
|
24
|
+
|
25
|
+
def getbit(key, offset)
|
26
|
+
#return if expired?(key)
|
27
|
+
return unless @data[key]
|
28
|
+
@data[key].unpack('B8')[0].split("")[offset]
|
29
|
+
end
|
30
|
+
|
31
|
+
def getrange(key, start, ending)
|
32
|
+
return unless @data[key]
|
33
|
+
@data[key][start..ending]
|
34
|
+
end
|
35
|
+
|
36
|
+
def getset(key, value)
|
37
|
+
return unless @data[key]
|
38
|
+
old_value = @data[key]
|
39
|
+
@data[key] = value
|
40
|
+
return old_value
|
41
|
+
end
|
42
|
+
|
43
|
+
def incr(key)
|
44
|
+
@data[key] = (@data[key] || "0")
|
45
|
+
@data[key] = (@data[key].to_i + 1).to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
def incrby(key, by)
|
49
|
+
@data[key] = (@data[key] || "0")
|
50
|
+
@data[key] = (@data[key].to_i + by.to_i).to_s
|
51
|
+
end
|
52
|
+
|
53
|
+
def mget(*keys)
|
54
|
+
@data.values_at(*keys)
|
55
|
+
end
|
56
|
+
|
57
|
+
def mset(*pairs)
|
58
|
+
pairs.each_slice(2) do |pair|
|
59
|
+
@data[pair[0].to_s] = pair[1].to_s
|
60
|
+
end
|
61
|
+
"OK"
|
62
|
+
end
|
63
|
+
|
64
|
+
def msetnx(*pairs)
|
65
|
+
keys = []
|
66
|
+
pairs.each_with_index{|item, index| keys << item.to_s if index % 2 == 0}
|
67
|
+
return if keys.any?{|key| @data.key?(key) }
|
68
|
+
mset(*pairs)
|
69
|
+
true
|
70
|
+
end
|
71
|
+
|
72
|
+
def set(key, value)
|
73
|
+
@data[key] = value.to_s
|
74
|
+
"OK"
|
75
|
+
end
|
76
|
+
|
77
|
+
def setbit(key, offset, bit)
|
78
|
+
return unless @data[key]
|
79
|
+
old_val = @data[key].unpack('B*')[0].split("")
|
80
|
+
old_val[offset] = bit.to_s
|
81
|
+
new_val = ""
|
82
|
+
old_val.each_slice(8){|b| new_val = new_val + b.join("").to_i(2).chr }
|
83
|
+
@data[key] = new_val
|
84
|
+
end
|
85
|
+
|
86
|
+
def setex(key, seconds, value)
|
87
|
+
@data[key] = value
|
88
|
+
expire(key, seconds)
|
89
|
+
end
|
90
|
+
|
91
|
+
def setnx(key, value)
|
92
|
+
set(key, value) unless @data.key?(key)
|
93
|
+
end
|
94
|
+
|
95
|
+
def setrange(key, offset, value)
|
96
|
+
return unless @data[key]
|
97
|
+
s = @data[key][offset,value.size]
|
98
|
+
@data[key][s] = value
|
99
|
+
end
|
100
|
+
|
101
|
+
def strlen(key)
|
102
|
+
return unless @data[key]
|
103
|
+
@data[key].size
|
104
|
+
end
|
105
|
+
|
106
|
+
alias [] get
|
107
|
+
alias []= set
|
108
|
+
end
|
109
|
+
|
110
|
+
include StringsMethods
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module FakeRedis
|
4
|
+
describe "ConnectionMethods" do
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
@client = FakeRedis::Redis.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should authenticate to the server" do
|
11
|
+
@client.auth("pass").should == true
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should echo the given string" do
|
15
|
+
@client.echo("something").should == "something"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should ping the server" do
|
19
|
+
@client.ping.should == "PONG"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|