fakeredis 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
-b -fn --color
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2011 Guillermo Iguaran
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
data/README.md
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
FakeRedis [![Build Status](http://travis-ci.org/guilleiguaran/fakeredis.png)](http://travis-ci.org/guilleiguaran/fakeredis)
|
2
|
+
--------
|
3
|
+
This a fake implementation of redis-rb for machines without Redis or test environments
|
4
|
+
|
5
|
+
Usage
|
6
|
+
=====
|
7
|
+
You can use FakeRedis::Redis similary as you use redis gem:
|
8
|
+
|
9
|
+
require "fakeredis"
|
10
|
+
|
11
|
+
redis = FakeRedis::Redis.new
|
12
|
+
|
13
|
+
|
14
|
+
>> redis.set "foo", "bar"
|
15
|
+
=> "OK"
|
16
|
+
|
17
|
+
>> redis.get "foo"
|
18
|
+
=> "bar"
|
19
|
+
|
20
|
+
Read [redis-rb](https://github.com/ezmobius/redis-rb) documentation and
|
21
|
+
[Redis](http://redis.io) homepage for more info about commands
|
22
|
+
|
23
|
+
|
24
|
+
Contributing to FakeRedis
|
25
|
+
=======================
|
26
|
+
|
27
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
28
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
29
|
+
* Fork the project
|
30
|
+
* Start a feature/bugfix branch
|
31
|
+
* Commit and push until you are happy with your contribution
|
32
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
33
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
34
|
+
|
35
|
+
Copyright
|
36
|
+
=========
|
37
|
+
|
38
|
+
Copyright (c) 2011 Guillermo Iguaran. See LICENSE for
|
39
|
+
further details.
|
40
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
$:.push File.expand_path("../lib", __FILE__)
|
5
|
+
require "fakeredis/version"
|
6
|
+
|
7
|
+
Bundler::GemHelper.install_tasks
|
8
|
+
|
9
|
+
require 'rspec/core'
|
10
|
+
require 'rspec/core/rake_task'
|
11
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
12
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
13
|
+
end
|
14
|
+
|
15
|
+
task :default => :spec
|
16
|
+
|
17
|
+
require 'rake/rdoctask'
|
18
|
+
Rake::RDocTask.new do |rdoc|
|
19
|
+
version = FakeRedis::VERSION
|
20
|
+
|
21
|
+
rdoc.rdoc_dir = 'rdoc'
|
22
|
+
rdoc.title = "fakeredis #{version}"
|
23
|
+
rdoc.rdoc_files.include('README*')
|
24
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
25
|
+
end
|
26
|
+
|
data/fakeredis.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "fakeredis/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "fakeredis"
|
7
|
+
s.version = FakeRedis::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["fakeredis"]
|
10
|
+
s.email = ["guilleiguaran@gmail.com"]
|
11
|
+
s.homepage = "http://github.com/guilleiguaran/fakeredis"
|
12
|
+
s.summary = %q{Fake redis-rb for your tests}
|
13
|
+
s.description = %q{Fake implementation of redis-rb for machines without Redis or test environments}
|
14
|
+
|
15
|
+
s.rubyforge_project = "fakeredis"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_development_dependency(%q<rspec>, [">= 2.0.0"])
|
23
|
+
end
|
data/lib/fakeredis.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
module FakeRedis
|
3
|
+
class Redis
|
4
|
+
|
5
|
+
def self.connect(options = {})
|
6
|
+
new(options)
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(options = {})
|
10
|
+
@data = {}
|
11
|
+
@expires = {}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
require 'set'
|
17
|
+
|
18
|
+
require "fakeredis/connection"
|
19
|
+
require "fakeredis/keys"
|
20
|
+
require "fakeredis/strings"
|
21
|
+
require "fakeredis/hashes"
|
22
|
+
require "fakeredis/lists"
|
23
|
+
require "fakeredis/sets"
|
24
|
+
#require "fakeredis/sorted_sets"
|
25
|
+
require "fakeredis/transactions"
|
26
|
+
require "fakeredis/server"
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module FakeRedis
|
2
|
+
class Redis
|
3
|
+
module ConnectionMethods
|
4
|
+
|
5
|
+
def auth(password)
|
6
|
+
true
|
7
|
+
end
|
8
|
+
|
9
|
+
def echo(string)
|
10
|
+
string
|
11
|
+
end
|
12
|
+
|
13
|
+
def ping
|
14
|
+
"PONG"
|
15
|
+
end
|
16
|
+
|
17
|
+
def quit ; end
|
18
|
+
|
19
|
+
def select(index) ; end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
include ConnectionMethods
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module FakeRedis
|
2
|
+
class Redis
|
3
|
+
module HashesMethods
|
4
|
+
def hdel(key, field)
|
5
|
+
return unless @data[key]
|
6
|
+
fail "Not a hash" unless @data[key].is_a?(Hash)
|
7
|
+
@data[key].delete(field)
|
8
|
+
end
|
9
|
+
|
10
|
+
def hexists(key, field)
|
11
|
+
return unless @data[key]
|
12
|
+
fail "Not a hash" unless @data[key].is_a?(Hash)
|
13
|
+
@data[key].key?(field)
|
14
|
+
end
|
15
|
+
|
16
|
+
def hget(key, field)
|
17
|
+
return unless @data[key]
|
18
|
+
fail "Not a hash" unless @data[key].is_a?(Hash)
|
19
|
+
@data[key][field]
|
20
|
+
end
|
21
|
+
|
22
|
+
def hgetall(key)
|
23
|
+
case hash = @data[key]
|
24
|
+
when nil then {}
|
25
|
+
when Hash then hash
|
26
|
+
else fail "Not a hash"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def hincrby(key, field, increment)
|
31
|
+
case hash = @data[key]
|
32
|
+
when nil then @data[key] = { field => value.to_s }
|
33
|
+
when Hash then hash[field] = (hash[field].to_i + increment.to_i).to_s
|
34
|
+
else fail "Not a hash"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def hkeys(key)
|
39
|
+
case hash = @data[key]
|
40
|
+
when nil then []
|
41
|
+
when Hash then hash.keys
|
42
|
+
else fail "Not a hash"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def hlen(key)
|
47
|
+
case hash = @data[key]
|
48
|
+
when nil then 0
|
49
|
+
when Hash then hash.size
|
50
|
+
else fail "Not a hash"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def hmget(key, *fields)
|
55
|
+
values = []
|
56
|
+
fields.each do |field|
|
57
|
+
case hash = @data[key]
|
58
|
+
when nil then values << nil
|
59
|
+
when Hash then values << hash[field]
|
60
|
+
else fail "Not a hash"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
values
|
64
|
+
end
|
65
|
+
|
66
|
+
def hmset(key, *fields)
|
67
|
+
@data[key] ||= {}
|
68
|
+
fail "Not a hash" unless @data[key].is_a?(Hash)
|
69
|
+
fields.each_slice(2) do |field|
|
70
|
+
@data[key][field[0].to_s] = field[1].to_s
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def hset(key, field, value)
|
75
|
+
case hash = @data[key]
|
76
|
+
when nil then @data[key] = { field => value.to_s }
|
77
|
+
when Hash then hash[field] = value.to_s
|
78
|
+
else fail "Not a hash"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def hsetnx(key, field, value)
|
83
|
+
return if (@data[key][field] rescue false)
|
84
|
+
hset(key, field, value)
|
85
|
+
end
|
86
|
+
|
87
|
+
def hvals(key)
|
88
|
+
case hash = @data[key]
|
89
|
+
when nil then []
|
90
|
+
when Hash then hash.values
|
91
|
+
else fail "Not a hash"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
include HashesMethods
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module FakeRedis
|
2
|
+
class Redis
|
3
|
+
module KeysMethods
|
4
|
+
|
5
|
+
def del(*keys)
|
6
|
+
old_count = @data.keys.size
|
7
|
+
keys.flatten.each do |key|
|
8
|
+
@data.delete(key)
|
9
|
+
@expires.delete(key)
|
10
|
+
end
|
11
|
+
deleted_count = old_count - @data.keys.size
|
12
|
+
end
|
13
|
+
|
14
|
+
def exists(key)
|
15
|
+
@data.key?(key)
|
16
|
+
end
|
17
|
+
|
18
|
+
def expire(key, ttl)
|
19
|
+
return unless @data[key]
|
20
|
+
@expires[key] = ttl
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
def expireat(key, timestamp)
|
25
|
+
@expires[key] = (Time.at(timestamp) - Time.now).to_i
|
26
|
+
true
|
27
|
+
end
|
28
|
+
|
29
|
+
def keys(pattern)
|
30
|
+
regexp = Regexp.new(pattern.split("*").map { |r| Regexp.escape(r) }.join(".*"))
|
31
|
+
@data.keys.select { |key| key =~ regexp }
|
32
|
+
end
|
33
|
+
|
34
|
+
def persist(key)
|
35
|
+
@expires[key] = -1
|
36
|
+
end
|
37
|
+
|
38
|
+
def randomkey
|
39
|
+
@data.keys[rand(dbsize)]
|
40
|
+
end
|
41
|
+
|
42
|
+
def rename(key, new_key)
|
43
|
+
return unless @data[key]
|
44
|
+
@data[new_key] = @data[key]
|
45
|
+
@expires[new_key] = @expires[key]
|
46
|
+
@data.delete(key)
|
47
|
+
@expires.delete(key)
|
48
|
+
end
|
49
|
+
|
50
|
+
def renamenx(key, new_key)
|
51
|
+
rename(key, new_key) unless exists(new_key)
|
52
|
+
end
|
53
|
+
|
54
|
+
def sort(key)
|
55
|
+
# TODO: Impleent
|
56
|
+
end
|
57
|
+
|
58
|
+
def ttl(key)
|
59
|
+
@expires[key]
|
60
|
+
end
|
61
|
+
|
62
|
+
def type(key)
|
63
|
+
case value = @data[key]
|
64
|
+
when nil then "none"
|
65
|
+
when String then "string"
|
66
|
+
when Hash then "hash"
|
67
|
+
when Array then "list"
|
68
|
+
when Set then "set"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
protected
|
73
|
+
def expired?(key)
|
74
|
+
return false if @expires[key] == -1
|
75
|
+
return true if @expires[key] && @expires[key] < Time.now
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
include KeysMethods
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module FakeRedis
|
2
|
+
class Redis
|
3
|
+
module ListsMethods
|
4
|
+
|
5
|
+
def lindex(key, index)
|
6
|
+
fail "Not a list" unless @data[key].is_a?(Array)
|
7
|
+
return unless @data[key]
|
8
|
+
@data[key][index]
|
9
|
+
end
|
10
|
+
|
11
|
+
def linsert(key, where, pivot, value)
|
12
|
+
fail "Not a list" unless @data[key].is_a?(Array)
|
13
|
+
return unless @data[key]
|
14
|
+
index = @data[key].index(pivot)
|
15
|
+
case where
|
16
|
+
when :before then @data[key].insert(index, value)
|
17
|
+
when :after then @data[key].insert(index + 1, value)
|
18
|
+
else raise ArgumentError.new
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def llen(key)
|
23
|
+
@data[key] ||= []
|
24
|
+
fail "Not a list" unless @data[key].is_a?(Array)
|
25
|
+
@data[key].size
|
26
|
+
end
|
27
|
+
|
28
|
+
def lpop(key)
|
29
|
+
return unless @data[key]
|
30
|
+
fail "Not a list" unless @data[key].is_a?(Array)
|
31
|
+
@data[key].delete_at(0)
|
32
|
+
end
|
33
|
+
|
34
|
+
def lpush(key, value)
|
35
|
+
@data[key] ||= []
|
36
|
+
fail "Not a list" unless @data[key].is_a?(Array)
|
37
|
+
@data[key] = [value] + @data[key]
|
38
|
+
@data[key].size
|
39
|
+
end
|
40
|
+
|
41
|
+
def lpushx(key, value)
|
42
|
+
return unless @data[key]
|
43
|
+
fail "Not a list" unless @data[key].is_a?(Array)
|
44
|
+
lpush(key, value)
|
45
|
+
end
|
46
|
+
|
47
|
+
def lrange(key, startidx, endidx)
|
48
|
+
return unless @data[key]
|
49
|
+
fail "Not a list" unless @data[key].is_a?(Array)
|
50
|
+
@data[key][startidx..endidx]
|
51
|
+
end
|
52
|
+
|
53
|
+
def lrem(key, count, value)
|
54
|
+
fail "Not a list" unless @data[key].is_a?(Array)
|
55
|
+
return unless @data[key]
|
56
|
+
old_size = @data[key].size
|
57
|
+
if count == 0
|
58
|
+
@data[key].delete(value)
|
59
|
+
old_size - @data[key].size
|
60
|
+
else
|
61
|
+
array = count > 0 ? @data[key].dup : @data[key].reverse
|
62
|
+
count.abs.times{ array.delete_at(array.index(value) || array.length) }
|
63
|
+
@data[key] = count > 0 ? array.dup : array.reverse
|
64
|
+
old_size - @data[key].size
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def lset(key, index, value)
|
69
|
+
fail "Not a list" unless @data[key].is_a?(Array)
|
70
|
+
return unless @data[key]
|
71
|
+
raise RuntimeError unless index < @data[key].size
|
72
|
+
@data[key][index] = value
|
73
|
+
end
|
74
|
+
|
75
|
+
def ltrim(key, start, stop)
|
76
|
+
fail "Not a list" unless @data[key].is_a?(Array)
|
77
|
+
return unless @data[key]
|
78
|
+
@data[key] = @data[key][start..stop]
|
79
|
+
end
|
80
|
+
|
81
|
+
def rpop(key)
|
82
|
+
fail "Not a list" unless @data[key].is_a?(Array)
|
83
|
+
@data[key].pop
|
84
|
+
end
|
85
|
+
|
86
|
+
def rpoplpush(key1, key2)
|
87
|
+
fail "Not a list" unless @data[key1].is_a?(Array)
|
88
|
+
elem = @data[key1].pop
|
89
|
+
lpush(key2, elem)
|
90
|
+
end
|
91
|
+
|
92
|
+
def rpush(key, value)
|
93
|
+
@data[key] ||= []
|
94
|
+
fail "Not a list" unless @data[key].is_a?(Array)
|
95
|
+
@data[key].push(value)
|
96
|
+
end
|
97
|
+
|
98
|
+
def rpushx(key, value)
|
99
|
+
return unless @data[key]
|
100
|
+
fail "Not a list" unless @data[key].is_a?(Array)
|
101
|
+
rpush(key, value)
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
include ListsMethods
|
107
|
+
end
|
108
|
+
end
|