redislike 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.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +82 -0
- data/Rakefile +64 -0
- data/lib/redislike/helpers/lists.rb +40 -0
- data/lib/redislike/keys.rb +15 -0
- data/lib/redislike/lists.rb +91 -0
- data/lib/redislike.rb +2 -0
- data/redislike.gemspec +21 -0
- data/tests/redislike/lists.rb +255 -0
- data/tests/redislike.rb +11 -0
- metadata +113 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b32d60e77c8f6e9fc89a7df48aa4f8229564c66e
|
4
|
+
data.tar.gz: ce5b4dcdafb32682ac78350970cbbedd6ccca032
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ae5c0c559385cf9e46394631629f942b2bd4c5da4b9b9208d3d5ab13ad030b55fc65325b847cadb24cdf74d3bbc48bfbda23555dcb933e9addfbd468174b3b9a
|
7
|
+
data.tar.gz: 9e0bade973bb81c47130e8ba41975b4798d9ece654d338dda1c627ef23c071aa5e946842e59776797fabc5242c51ca3b266b8ee385f54609f3ba2b18902d385e
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Chris Olstrom
|
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 all
|
13
|
+
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
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
redislike
|
2
|
+
=========
|
3
|
+
|
4
|
+
For when we want Redis, but can't have nice things.
|
5
|
+
|
6
|
+
redislike adds backend-independent support for redis-like list operations to any Moneta datastore.
|
7
|
+
|
8
|
+
Supported Operations
|
9
|
+
--------------------
|
10
|
+
* LINDEX
|
11
|
+
* LINSERT
|
12
|
+
* LLEN
|
13
|
+
* LPOP
|
14
|
+
* LPUSH
|
15
|
+
* LPUSHX
|
16
|
+
* LRANGE
|
17
|
+
* LREM
|
18
|
+
* LSET
|
19
|
+
* LTRIM
|
20
|
+
* RPOP
|
21
|
+
* RPOPLPUSH
|
22
|
+
* RPUSH
|
23
|
+
* RPUSHX
|
24
|
+
|
25
|
+
Missing
|
26
|
+
-------
|
27
|
+
* BLPOP
|
28
|
+
* BRPOP
|
29
|
+
* BRPOPLPUSH
|
30
|
+
|
31
|
+
Other Supported Operations
|
32
|
+
--------------------------
|
33
|
+
* EXISTS
|
34
|
+
|
35
|
+
Installation
|
36
|
+
------------
|
37
|
+
|
38
|
+
```gem install redislike```
|
39
|
+
|
40
|
+
or in your Gemfile
|
41
|
+
|
42
|
+
```gem 'redislike'```
|
43
|
+
|
44
|
+
Example
|
45
|
+
-----
|
46
|
+
|
47
|
+
```
|
48
|
+
require 'redislike'
|
49
|
+
datastore = Moneta.new :Memory, expires: true
|
50
|
+
|
51
|
+
datastore.lpush 'pending', 'foo'
|
52
|
+
datastore.rpoplpush 'pending', 'active'
|
53
|
+
puts datastore.lrange 'active', 0, -1
|
54
|
+
```
|
55
|
+
|
56
|
+
Should return ```['foo']```
|
57
|
+
|
58
|
+
Motivation
|
59
|
+
----------
|
60
|
+
|
61
|
+
Redis may be my favourite data store, for a number of reasons that have nothing to do with this gem. It's also not a silver bullet. Like many tools, used in the right context, it excels. Out of its element, it adds complexity and overhead (when compared to using a tool better suited to that problem domain).
|
62
|
+
|
63
|
+
Then there's Moneta, a lovely gem that provides a unified API to an impressive range of backends for key/value storage. This allows low-effort integration with whatever data store you already have. The consistency also enables trivial swapping of backends as the evolution of an application guides requirements, without rewriting much of anything.
|
64
|
+
|
65
|
+
To achive this consistency, Moneta omits support for backend-specfic features. One of those that I often want is the (B)RPOPLPUSH list operation from Redis. This takes an item from the tail of one list, and puts it at the head of another list.
|
66
|
+
|
67
|
+
Rather than depending on a Redis backend for Moneta, and passing these operations through to it, I built redis-like queue operations on top of Moneta. Once those were in place, it seemed reasonable to continue and build the rest.
|
68
|
+
|
69
|
+
At this point, some sort of scope began to take shape. The methods were restructured to align with those provided by Redis, and tests were written to guide this process.
|
70
|
+
|
71
|
+
**TL;DR: I wanted RPOPLPUSH in Moneta, didn't define scope boundaries and accidentally reimplemented (some of) Redis.**
|
72
|
+
|
73
|
+
Dependencies
|
74
|
+
------------
|
75
|
+
* Moneta
|
76
|
+
|
77
|
+
What's up with the tests?
|
78
|
+
-------------------------
|
79
|
+
|
80
|
+
Alright, so the tests are a bit unconventional, in the sense that you need a working redis server to actually run the tests for a gem with the stated intent of not requiring a redis server.
|
81
|
+
|
82
|
+
These tests that redislike is in fact, redis-like. These work by executing the same instructions against redis, and an in-memory instance of redislike, and asserting that the results should be the same.
|
data/Rakefile
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
# require 'simplecov'
|
2
|
+
|
3
|
+
require 'rubocop/rake_task'
|
4
|
+
require 'reek/rake/task'
|
5
|
+
require 'roodi_task'
|
6
|
+
|
7
|
+
task default: [:test]
|
8
|
+
|
9
|
+
task test: [:kintama]
|
10
|
+
|
11
|
+
desc 'Run Test Suite'
|
12
|
+
task :kintama do
|
13
|
+
sh 'ruby tests/redislike.rb'
|
14
|
+
end
|
15
|
+
|
16
|
+
task audit: [:style, :complexity, :duplication, :design, :documentation]
|
17
|
+
|
18
|
+
task style: [:rubocop]
|
19
|
+
|
20
|
+
desc 'Enforce Style Conformance with RuboCop'
|
21
|
+
RuboCop::RakeTask.new(:rubocop) do |task|
|
22
|
+
task.patterns = ['lib/**/*.rb']
|
23
|
+
task.fail_on_error = false
|
24
|
+
end
|
25
|
+
|
26
|
+
task complexity: [:flog]
|
27
|
+
|
28
|
+
desc 'Assess Complexity with Flog'
|
29
|
+
# FlogTask.new :flog, 9000, ['lib']
|
30
|
+
task :flog do
|
31
|
+
sh 'flog lib/**/*.rb'
|
32
|
+
end
|
33
|
+
|
34
|
+
task duplication: [:flay]
|
35
|
+
|
36
|
+
task :flay do
|
37
|
+
sh 'flay'
|
38
|
+
end
|
39
|
+
|
40
|
+
task design: [:roodi, :reek]
|
41
|
+
|
42
|
+
desc 'Find Code Smells with Reek'
|
43
|
+
Reek::Rake::Task.new(:reek) do |task|
|
44
|
+
task.fail_on_error = false
|
45
|
+
end
|
46
|
+
|
47
|
+
task :rework do
|
48
|
+
sh 'churn'
|
49
|
+
end
|
50
|
+
|
51
|
+
task :documentation do
|
52
|
+
sh 'inch'
|
53
|
+
end
|
54
|
+
|
55
|
+
task generate: [:documents, :graphs]
|
56
|
+
|
57
|
+
task :documents do
|
58
|
+
sh 'yard'
|
59
|
+
end
|
60
|
+
|
61
|
+
task :graphs do
|
62
|
+
sh 'bundle viz'
|
63
|
+
sh 'yard graph | dot -Tpng > lib_graph.png'
|
64
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module RedisLike
|
2
|
+
module Helpers
|
3
|
+
module Lists
|
4
|
+
def enqueue(list, item, to:, allow_create: true)
|
5
|
+
operation = to == :head ? :unshift : :push
|
6
|
+
items = fetch list, []
|
7
|
+
items.method(operation).call(item)
|
8
|
+
store list, items if allow_create || exists(list)
|
9
|
+
llen list
|
10
|
+
end
|
11
|
+
|
12
|
+
def dequeue(list, from:)
|
13
|
+
operation = from == :head ? :shift : :pop
|
14
|
+
current = fetch list, []
|
15
|
+
item = current.method(operation).call
|
16
|
+
store list, current
|
17
|
+
item
|
18
|
+
end
|
19
|
+
|
20
|
+
def remove_count(list, count, item, from:)
|
21
|
+
operation = from == :tail ? :rindex : :index
|
22
|
+
items = fetch list, []
|
23
|
+
removed = count.times.map do
|
24
|
+
found = items.method(operation).call(item)
|
25
|
+
items.delete_at found if found
|
26
|
+
end
|
27
|
+
store list, items
|
28
|
+
removed.compact.length
|
29
|
+
end
|
30
|
+
|
31
|
+
def remove_all(list, item)
|
32
|
+
items = fetch list, []
|
33
|
+
remove_count list, items.count(item), item, from: :head
|
34
|
+
# remaining = items.reject { |i| i == item }
|
35
|
+
# store list, remaining
|
36
|
+
# items.length - remaining.length
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'moneta'
|
2
|
+
require_relative 'helpers/lists'
|
3
|
+
|
4
|
+
# Module containing mixins for redis-like operations.
|
5
|
+
module RedisLike
|
6
|
+
# Mixin containing redis-like list operations for Moneta stores.
|
7
|
+
module Lists
|
8
|
+
include RedisLike::Keys
|
9
|
+
include RedisLike::Helpers::Lists
|
10
|
+
|
11
|
+
def lpush(list, item)
|
12
|
+
enqueue list, item, to: :head
|
13
|
+
end
|
14
|
+
|
15
|
+
def lpushx(list, item)
|
16
|
+
enqueue list, item, to: :head, allow_create: false
|
17
|
+
end
|
18
|
+
|
19
|
+
def rpush(list, item)
|
20
|
+
enqueue list, item, to: :tail
|
21
|
+
end
|
22
|
+
|
23
|
+
def rpushx(list, item)
|
24
|
+
enqueue list, item, to: :tail, allow_create: false
|
25
|
+
end
|
26
|
+
|
27
|
+
def lpop(list)
|
28
|
+
dequeue list, from: :head
|
29
|
+
end
|
30
|
+
|
31
|
+
def rpop(list)
|
32
|
+
dequeue list, from: :tail
|
33
|
+
end
|
34
|
+
|
35
|
+
def rpoplpush(source, destination)
|
36
|
+
item = rpop source
|
37
|
+
lpush destination, item
|
38
|
+
item
|
39
|
+
end
|
40
|
+
|
41
|
+
def lindex(list, item)
|
42
|
+
fetch(list, []).at item
|
43
|
+
end
|
44
|
+
|
45
|
+
def linsert(list, location, pivot, item)
|
46
|
+
return 0 unless exists list
|
47
|
+
return -1 unless lrange(list, 0, -1).include? pivot
|
48
|
+
items = fetch list, []
|
49
|
+
index = items.index pivot
|
50
|
+
index += 1 if location == :before
|
51
|
+
items.insert(index, item)
|
52
|
+
store list, items
|
53
|
+
llen list
|
54
|
+
end
|
55
|
+
|
56
|
+
def llen(list)
|
57
|
+
fetch(list, []).length
|
58
|
+
end
|
59
|
+
|
60
|
+
def lrange(list, start, stop)
|
61
|
+
fetch(list, [])[(start..stop)] || []
|
62
|
+
end
|
63
|
+
|
64
|
+
def lrem(list, count, item)
|
65
|
+
case
|
66
|
+
when count > 0
|
67
|
+
remove_count list, count, item, from: :head
|
68
|
+
when count < 0
|
69
|
+
remove_count list, count.abs, item, from: :tail
|
70
|
+
when count == 0
|
71
|
+
remove_all list, item
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def lset(list, index, item)
|
76
|
+
items = fetch list, []
|
77
|
+
items[index] = item
|
78
|
+
'OK' if store list, items
|
79
|
+
end
|
80
|
+
|
81
|
+
def ltrim(list, start, stop)
|
82
|
+
'OK' if store list, lrange(list, start, stop)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
module Moneta
|
88
|
+
module Defaults
|
89
|
+
include RedisLike::Lists
|
90
|
+
end
|
91
|
+
end
|
data/lib/redislike.rb
ADDED
data/redislike.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Gem::Specification.new do |gem|
|
2
|
+
gem.name = 'redislike'
|
3
|
+
gem.version = '0.1.0'
|
4
|
+
gem.licenses = 'MIT'
|
5
|
+
gem.authors = ['Chris Olstrom']
|
6
|
+
gem.email = 'chris@olstrom.com'
|
7
|
+
gem.homepage = 'http://colstrom.github.io/redislike/'
|
8
|
+
gem.summary = %Q{For when we want Redis, but can't have nice things.}
|
9
|
+
gem.description = %Q{redislike adds backend-independent support for redis-like list operations to any Moneta datastore.}
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split("\n")
|
12
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
13
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
14
|
+
gem.require_paths = ['lib']
|
15
|
+
|
16
|
+
gem.add_runtime_dependency 'moneta', '~> 0.8'
|
17
|
+
|
18
|
+
gem.add_development_dependency 'kintama', '~> 0.1'
|
19
|
+
gem.add_development_dependency 'simplecov', '~> 0.8'
|
20
|
+
gem.add_development_dependency 'redis', '~> 3.2'
|
21
|
+
end
|
@@ -0,0 +1,255 @@
|
|
1
|
+
context 'List Operations' do
|
2
|
+
def mirror(method, *arguments)
|
3
|
+
original = @original.method(method).call(*arguments)
|
4
|
+
compatible = @compatible.method(method).call(*arguments)
|
5
|
+
[original, compatible]
|
6
|
+
end
|
7
|
+
|
8
|
+
def assert_compatible(method, *arguments)
|
9
|
+
assert_equal(*mirror(method, *arguments))
|
10
|
+
end
|
11
|
+
|
12
|
+
setup do
|
13
|
+
@original = Redis.new
|
14
|
+
# @compatible = Moneta.new :Daybreak, file: '.test.db', expires: true
|
15
|
+
@compatible = Moneta.new :Memory
|
16
|
+
|
17
|
+
@original.del 'test', 'test:a', 'test:b', 'test:nx'
|
18
|
+
end
|
19
|
+
|
20
|
+
teardown do
|
21
|
+
@original.disconnect!
|
22
|
+
@compatible.close
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'lindex' do
|
26
|
+
setup do
|
27
|
+
mirror :lpush, 'test', 'foo'
|
28
|
+
mirror :lpush, 'test', 'bar'
|
29
|
+
end
|
30
|
+
|
31
|
+
test 'when list does not exist' do
|
32
|
+
assert_compatible :lindex, 'test:nx', 1
|
33
|
+
end
|
34
|
+
|
35
|
+
test 'in range' do
|
36
|
+
assert_compatible :lindex, 'test', 1
|
37
|
+
end
|
38
|
+
|
39
|
+
test 'out of range' do
|
40
|
+
assert_compatible :lindex, 'test', 999
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'linsert' do
|
45
|
+
setup do
|
46
|
+
mirror :lpush, 'test', 'foo'
|
47
|
+
end
|
48
|
+
|
49
|
+
test 'when list does not exist' do
|
50
|
+
assert_compatible :linsert, 'test:nx', :before, 'foo', 'bar'
|
51
|
+
assert_compatible :linsert, 'test:nx', :after, 'foo', 'bar'
|
52
|
+
end
|
53
|
+
|
54
|
+
test 'when list contains pivot value' do
|
55
|
+
assert_compatible :linsert, 'test', :before, 'foo', 'bar'
|
56
|
+
assert_compatible :linsert, 'test', :after, 'foo', 'bar'
|
57
|
+
end
|
58
|
+
|
59
|
+
test 'when list does not contain pivot value' do
|
60
|
+
assert_compatible :linsert, 'test', :before, 'baz', 'bar'
|
61
|
+
assert_compatible :linsert, 'test', :after, 'baz', 'bar'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'llen' do
|
66
|
+
test 'when list does not exist' do
|
67
|
+
assert_compatible :llen, 'test:nx'
|
68
|
+
end
|
69
|
+
|
70
|
+
test 'when list exists' do
|
71
|
+
mirror :lpush, 'test', 'foo'
|
72
|
+
assert_compatible :llen, 'test'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'lpop' do
|
77
|
+
test 'when list does not exist' do
|
78
|
+
assert_compatible :lpop, 'test:nx'
|
79
|
+
end
|
80
|
+
|
81
|
+
test 'when list exists' do
|
82
|
+
mirror :lpush, 'test', 'foo'
|
83
|
+
assert_compatible :lpop, 'test:nx'
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'lpush' do
|
88
|
+
test 'when list does not exist' do
|
89
|
+
assert_compatible :lpush, 'test:nx', 'foo'
|
90
|
+
end
|
91
|
+
|
92
|
+
test 'when list has items already' do
|
93
|
+
mirror :lpush, 'test', 'foo'
|
94
|
+
assert_compatible :lpush, 'test', 'foo'
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'lpushx' do
|
99
|
+
test 'when list does not exist' do
|
100
|
+
assert_compatible :lpushx, 'test:nx', 'foo'
|
101
|
+
end
|
102
|
+
|
103
|
+
test 'when list has items already' do
|
104
|
+
mirror :lpush, 'test', 'foo'
|
105
|
+
assert_compatible :lpushx, 'test', 'foo'
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'lrange' do
|
110
|
+
test 'when list does not exist' do
|
111
|
+
assert_compatible :lrange, 'test:nx', 0, -1
|
112
|
+
end
|
113
|
+
|
114
|
+
test 'when list exists' do
|
115
|
+
mirror :lpush, 'test', 'foo'
|
116
|
+
assert_compatible :lrange, 'test', 0, -1
|
117
|
+
end
|
118
|
+
|
119
|
+
test 'stop beyond range' do
|
120
|
+
mirror :lpush, 'test', 'foo'
|
121
|
+
assert_compatible :lrange, 'test', 0, 9
|
122
|
+
end
|
123
|
+
|
124
|
+
test 'stop before start' do
|
125
|
+
mirror :lpush, 'test', 'foo'
|
126
|
+
assert_compatible :lrange, 'test', -1, 1
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context 'lrem' do
|
131
|
+
setup do
|
132
|
+
mirror :lpush, 'test', 'foo'
|
133
|
+
mirror :lpush, 'test', 'foo'
|
134
|
+
mirror :lpush, 'test', 'foo'
|
135
|
+
end
|
136
|
+
|
137
|
+
test 'when list does not exist' do
|
138
|
+
assert_compatible :lrem, 'test:nx', 0, 'foo'
|
139
|
+
end
|
140
|
+
|
141
|
+
test 'all items (present)' do
|
142
|
+
assert_compatible :lrem, 'test', 0, 'foo'
|
143
|
+
end
|
144
|
+
|
145
|
+
test 'all items (when not present)' do
|
146
|
+
assert_compatible :lrem, 'test', 0, 'bar'
|
147
|
+
end
|
148
|
+
|
149
|
+
test 'one from head (present)' do
|
150
|
+
assert_compatible :lrem, 'test', 1, 'foo'
|
151
|
+
end
|
152
|
+
|
153
|
+
test 'one from head (when not present)' do
|
154
|
+
assert_compatible :lrem, 'test', 1, 'bar'
|
155
|
+
end
|
156
|
+
|
157
|
+
test 'more than exists from head (present)' do
|
158
|
+
assert_compatible :lrem, 'test', 9, 'foo'
|
159
|
+
end
|
160
|
+
|
161
|
+
test 'more than exists from head (when not present)' do
|
162
|
+
assert_compatible :lrem, 'test', 9, 'bar'
|
163
|
+
end
|
164
|
+
|
165
|
+
test 'one from tail (present)' do
|
166
|
+
assert_compatible :lrem, 'test', -1, 'foo'
|
167
|
+
end
|
168
|
+
|
169
|
+
test 'one from tail (when not present)' do
|
170
|
+
assert_compatible :lrem, 'test', -1, 'bar'
|
171
|
+
end
|
172
|
+
|
173
|
+
test 'more than exists from tail (present)' do
|
174
|
+
assert_compatible :lrem, 'test', -9, 'foo'
|
175
|
+
end
|
176
|
+
|
177
|
+
test 'more than exists from tail (when not present)' do
|
178
|
+
assert_compatible :lrem, 'test', -9, 'bar'
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
context 'lset' do
|
183
|
+
setup do
|
184
|
+
mirror :lpush, 'test', 'foo'
|
185
|
+
mirror :lpush, 'test', 'foo'
|
186
|
+
mirror :lpush, 'test', 'foo'
|
187
|
+
end
|
188
|
+
|
189
|
+
test 'in range' do
|
190
|
+
assert_compatible :lset, 'test', 1, 'bar'
|
191
|
+
assert_equal mirror(:lindex, 'test', 1).uniq, ['bar']
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
context 'ltrim' do
|
196
|
+
setup do
|
197
|
+
100.times do
|
198
|
+
mirror :lpush, 'test', 'foo'
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
test 'when list does not exist' do
|
203
|
+
assert_compatible :ltrim, 'test:nx', 0, 10
|
204
|
+
end
|
205
|
+
|
206
|
+
test 'when range is larger than list length' do
|
207
|
+
assert_compatible :ltrim, 'test', 0, 200
|
208
|
+
assert_equal mirror(:lrange, 'test', 0, -1).uniq.flatten.size, 100
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
context 'rpop' do
|
213
|
+
test 'when list does not exist' do
|
214
|
+
assert_compatible :rpop, 'test:nx'
|
215
|
+
end
|
216
|
+
|
217
|
+
test 'when list exists' do
|
218
|
+
mirror :rpush, 'test', 'foo'
|
219
|
+
assert_compatible :rpop, 'test:nx'
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
context 'rpoplpush' do
|
224
|
+
test 'when source list does not exist' do
|
225
|
+
assert_compatible :rpoplpush, 'test:nx', 'test:b'
|
226
|
+
end
|
227
|
+
|
228
|
+
test 'when list exists' do
|
229
|
+
3.times { mirror :lpush, 'test:a', 'foo' }
|
230
|
+
assert_compatible :rpoplpush, 'test:a', 'test:b'
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
context 'rpush' do
|
235
|
+
test 'when list does not exist' do
|
236
|
+
assert_compatible :rpush, 'test:nx', 'foo'
|
237
|
+
end
|
238
|
+
|
239
|
+
test 'when list has items already' do
|
240
|
+
mirror :rpush, 'test', 'foo'
|
241
|
+
assert_compatible :rpush, 'test', 'foo'
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
context 'rpushx' do
|
246
|
+
test 'when list does not exist' do
|
247
|
+
assert_compatible :rpushx, 'test:nx', 'foo'
|
248
|
+
end
|
249
|
+
|
250
|
+
test 'when list has items already' do
|
251
|
+
mirror :rpush, 'test', 'foo'
|
252
|
+
assert_compatible :rpushx, 'test', 'foo'
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
data/tests/redislike.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'simplecov'
|
4
|
+
SimpleCov.command_name 'Kintama'
|
5
|
+
SimpleCov.start { add_filter '/vendor/' }
|
6
|
+
require 'redis'
|
7
|
+
require 'kintama'
|
8
|
+
require 'moneta'
|
9
|
+
|
10
|
+
require_relative '../lib/redislike'
|
11
|
+
require_relative 'redislike/lists'
|
metadata
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: redislike
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Olstrom
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-04-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: moneta
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.8'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.8'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: kintama
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.1'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.1'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: simplecov
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.8'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.8'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: redis
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.2'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.2'
|
69
|
+
description: redislike adds backend-independent support for redis-like list operations
|
70
|
+
to any Moneta datastore.
|
71
|
+
email: chris@olstrom.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".gitignore"
|
77
|
+
- Gemfile
|
78
|
+
- LICENSE
|
79
|
+
- README.md
|
80
|
+
- Rakefile
|
81
|
+
- lib/redislike.rb
|
82
|
+
- lib/redislike/helpers/lists.rb
|
83
|
+
- lib/redislike/keys.rb
|
84
|
+
- lib/redislike/lists.rb
|
85
|
+
- redislike.gemspec
|
86
|
+
- tests/redislike.rb
|
87
|
+
- tests/redislike/lists.rb
|
88
|
+
homepage: http://colstrom.github.io/redislike/
|
89
|
+
licenses:
|
90
|
+
- MIT
|
91
|
+
metadata: {}
|
92
|
+
post_install_message:
|
93
|
+
rdoc_options: []
|
94
|
+
require_paths:
|
95
|
+
- lib
|
96
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
requirements: []
|
107
|
+
rubyforge_project:
|
108
|
+
rubygems_version: 2.4.5
|
109
|
+
signing_key:
|
110
|
+
specification_version: 4
|
111
|
+
summary: For when we want Redis, but can't have nice things.
|
112
|
+
test_files: []
|
113
|
+
has_rdoc:
|