redis_recipes 0.3.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/.rspec +1 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +28 -0
- data/README.md +26 -0
- data/Rakefile +8 -0
- data/lib/range_lookup/README.md +62 -0
- data/lib/range_lookup/add.lua +66 -0
- data/lib/range_lookup/lookup.lua +27 -0
- data/lib/range_lookup/remove.lua +62 -0
- data/lib/range_lookup_x/README.md +59 -0
- data/lib/range_lookup_x/add.lua +59 -0
- data/lib/range_lookup_x/lookup.lua +19 -0
- data/lib/range_lookup_x/remove.lua +51 -0
- data/redis_recipes.gemspec +23 -0
- data/spec/range_lookup/add_spec.rb +146 -0
- data/spec/range_lookup/lookup_spec.rb +64 -0
- data/spec/range_lookup/remove_spec.rb +189 -0
- data/spec/range_lookup_x/add_spec.rb +149 -0
- data/spec/range_lookup_x/lookup_spec.rb +65 -0
- data/spec/range_lookup_x/remove_spec.rb +186 -0
- data/spec/spec_helper.rb +64 -0
- metadata +121 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Range Lookup X: Lookup" do
|
4
|
+
|
5
|
+
def add(member, min, max)
|
6
|
+
evalsha :add, keys: ["my_store"], argv: [member, min, max]
|
7
|
+
end
|
8
|
+
|
9
|
+
def lookup(value)
|
10
|
+
evalsha :lookup, keys: ["my_store"], argv: [value]
|
11
|
+
end
|
12
|
+
|
13
|
+
before do
|
14
|
+
add("A", 0, 8)
|
15
|
+
add("B", 4, 6)
|
16
|
+
add("C", 2, 9)
|
17
|
+
add("D", 7, 10)
|
18
|
+
end
|
19
|
+
|
20
|
+
def state
|
21
|
+
ranges = {}
|
22
|
+
redis.zrange('my_store:~', 0, -1, with_scores: true).each do |value, score|
|
23
|
+
ranges[score.to_f] = redis.smembers("my_store:#{value}").sort
|
24
|
+
end
|
25
|
+
ranges
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should catch invalid arguments' do
|
29
|
+
lambda { evalsha :lookup }.should raise_error(Redis::CommandError, /wrong number of arguments/)
|
30
|
+
lambda { evalsha :lookup, keys: ["one"] }.should raise_error(Redis::CommandError, /wrong number of arguments/)
|
31
|
+
lambda { evalsha :lookup, keys: ["one"], argv: ["one", 2] }.should raise_error(Redis::CommandError, /wrong number of arguments/)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should catch non-numeric ranges' do
|
35
|
+
lambda { evalsha :lookup, keys: ["one"], argv: ["one"] }.should raise_error(Redis::CommandError, /not numeric or out of range/)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should return the members when found' do
|
39
|
+
lookup(0).should =~ ["A"]
|
40
|
+
lookup(1).should =~ ["A"]
|
41
|
+
lookup(2).should =~ ["A", "C"]
|
42
|
+
lookup(3).should =~ ["A", "C"]
|
43
|
+
lookup(4).should =~ ["A", "B", "C"]
|
44
|
+
lookup(5).should =~ ["A", "B", "C"]
|
45
|
+
lookup(6).should =~ ["A", "C"]
|
46
|
+
lookup(7).should =~ ["A", "C", "D"]
|
47
|
+
lookup(8).should =~ ["C", "D"]
|
48
|
+
lookup(9).should =~ ["D"]
|
49
|
+
lookup(10).should =~ []
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should return an empty set if not found' do
|
53
|
+
lookup(-1).should =~ []
|
54
|
+
lookup(11).should =~ []
|
55
|
+
lookup(111).should =~ []
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should support float lookups' do
|
59
|
+
lookup(-0.1).should =~ []
|
60
|
+
lookup(6.5).should =~ ["A", "C"]
|
61
|
+
lookup(7.5).should =~ ["A", "C", "D"]
|
62
|
+
lookup(9.99).should =~ ["D"]
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Range Lookup X: Removing" do
|
4
|
+
|
5
|
+
def state(c = :to_i)
|
6
|
+
ranges = {}
|
7
|
+
redis.zrange('my_store:~', 0, -1, with_scores: true).each do |value, score|
|
8
|
+
ranges[score.send(c)] = redis.smembers("my_store:#{value}").sort.join
|
9
|
+
end
|
10
|
+
ranges
|
11
|
+
end
|
12
|
+
|
13
|
+
def brackets
|
14
|
+
redis.zrange('my_store:~', 0, -1)
|
15
|
+
end
|
16
|
+
|
17
|
+
def add(member, min, max)
|
18
|
+
evalsha :add, keys: ["my_store"], argv: [member, min, max]
|
19
|
+
end
|
20
|
+
|
21
|
+
def remove(member, min, max)
|
22
|
+
evalsha :remove, keys: ["my_store"], argv: [member, min, max]
|
23
|
+
end
|
24
|
+
|
25
|
+
def scenario(pairs)
|
26
|
+
pairs.each do |member, range|
|
27
|
+
add member.to_s, range.first, range.last
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "general" do
|
32
|
+
|
33
|
+
it 'should catch invalid arguments' do
|
34
|
+
lambda { evalsha :remove }.should raise_error(Redis::CommandError, /wrong number of arguments/)
|
35
|
+
lambda { evalsha :remove, keys: ["one"] }.should raise_error(Redis::CommandError, /wrong number of arguments/)
|
36
|
+
lambda { evalsha :remove, keys: ["one"], argv: ["one", 2] }.should raise_error(Redis::CommandError, /wrong number of arguments/)
|
37
|
+
lambda { evalsha :remove, keys: ["one", "two"], argv: ["one", 2, 3] }.should raise_error(Redis::CommandError, /wrong number of arguments/)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should catch non-numeric ranges' do
|
41
|
+
lambda { evalsha :remove, keys: ["one"], argv: ["one", "two", 3] }.should raise_error(Redis::CommandError, /not numeric or out of range/)
|
42
|
+
lambda { evalsha :remove, keys: ["one"], argv: ["one", 2, "three"] }.should raise_error(Redis::CommandError, /not numeric or out of range/)
|
43
|
+
lambda { evalsha :remove, keys: ["one"], argv: ["one", 3, 2] }.should raise_error(Redis::CommandError, /not numeric or out of range/)
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "removing" do
|
49
|
+
before { add("A", 8, 17) }
|
50
|
+
|
51
|
+
it 'should return OK if successful' do
|
52
|
+
remove("A", 8, 17).should == "OK"
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should support negative ranges & zero bounds' do
|
56
|
+
scenario B: -5..0, C: 0..5
|
57
|
+
|
58
|
+
lambda {
|
59
|
+
remove("B", -5, 0)
|
60
|
+
remove("C", 0, 5)
|
61
|
+
}.should change { state }.
|
62
|
+
from(-5 => "B", 0 => "C", 5 => "", 8 => "A", 17 => "").
|
63
|
+
to(8 => "A", 17 => "")
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should clean up index' do
|
67
|
+
scenario B: 15..22, C: 15..23
|
68
|
+
|
69
|
+
lambda {
|
70
|
+
remove("B", 15, 22)
|
71
|
+
}.should change { brackets }.to ["8", "15", "17", "23"]
|
72
|
+
|
73
|
+
lambda {
|
74
|
+
remove("C", 15, 23)
|
75
|
+
}.should change { brackets }.to ["8", "17"]
|
76
|
+
|
77
|
+
lambda {
|
78
|
+
remove("A", 8, 17)
|
79
|
+
}.should change { brackets }.to []
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "use cases" do
|
85
|
+
|
86
|
+
it "should remove from [A: 1-2, B: 3-4]" do
|
87
|
+
scenario A: 1..2, B: 3..4
|
88
|
+
lambda { remove("A", 1, 2) }.should change { state }.
|
89
|
+
from(1 => "A", 2 => "", 3 => "B", 4 => "").
|
90
|
+
to(3 => "B", 4 => "")
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should remove from [A: 3-4, B: 1-2]" do
|
94
|
+
scenario A: 3..4, B: 1..2
|
95
|
+
lambda { remove("A", 3, 4) }.should change { state }.
|
96
|
+
from(1 => "B", 2 => "", 3 => "A", 4 => "").
|
97
|
+
to(1 => "B", 2 => "")
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should remove from [A: 1-3, B: 2-4]" do
|
101
|
+
scenario A: 1..3, B: 2..4
|
102
|
+
lambda { remove("A", 1, 3) }.should change { state }.
|
103
|
+
from(1 => "A", 2 => "AB", 3 => "B", 4 => "").
|
104
|
+
to(2 => "B", 4 => "")
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should remove from [A: 2-4, B: 1-3]" do
|
108
|
+
scenario A: 2..4, B: 1..3
|
109
|
+
lambda { remove("A", 2, 4) }.should change { state }.
|
110
|
+
from(1 => "B", 2 => "AB", 3 => "A", 4 => "").
|
111
|
+
to(1 => "B", 3 => "")
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should remove from [A: 1-4, B: 2-3]" do
|
115
|
+
scenario A: 1..4, B: 2..3
|
116
|
+
lambda { remove("A", 1, 4) }.should change { state }.
|
117
|
+
from(1 => "A", 2 => "AB", 3 => "A", 4 => "").
|
118
|
+
to(2 => "B", 3 => "")
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should remove from [A: 2-3, B: 1-4]" do
|
122
|
+
scenario A: 2..3, B: 1..4
|
123
|
+
lambda { remove("A", 2, 3) }.should change { state }.
|
124
|
+
from(1 => "B", 2 => "AB", 3 => "B", 4 => "").
|
125
|
+
to(1 => "B", 4 => "")
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should remove from [A: 1-3, B: 3-4]" do
|
129
|
+
scenario A: 1..3, B: 3..4
|
130
|
+
lambda { remove("A", 1, 3) }.should change { state }.
|
131
|
+
from(1 => "A", 3 => "B", 4 => "").
|
132
|
+
to(3 => "B", 4 => "")
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should remove from [A: 1-4, B: 3-4]" do
|
136
|
+
scenario A: 1..4, B: 3..4
|
137
|
+
lambda { remove("A", 1, 4) }.should change { state }.
|
138
|
+
from(1 => "A", 3 => "AB", 4 => "").
|
139
|
+
to(3 => "B", 4 => "")
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should remove from [A: 3-4, B: 1-3]" do
|
143
|
+
scenario A: 3..4, B: 1..3
|
144
|
+
lambda { remove("A", 3, 4) }.should change { state }.
|
145
|
+
from(1 => "B", 3 => "A", 4 => "").
|
146
|
+
to(1 => "B", 3 => "")
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should remove from [A: 3-4, B: 1-4]" do
|
150
|
+
scenario A: 3..4, B: 1..4
|
151
|
+
lambda { remove("A", 3, 4) }.should change { state }.
|
152
|
+
from(1 => "B", 3 => "AB", 4 => "").
|
153
|
+
to(1 => "B", 4 => "")
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should remove from [A: 1-4, B: 1-2]" do
|
157
|
+
scenario A: 1..4, B: 1..2
|
158
|
+
lambda { remove("A", 1, 4) }.should change { state }.
|
159
|
+
from(1 => "AB", 2 => "A", 4 => "").
|
160
|
+
to(1 => "B", 2 => "")
|
161
|
+
end
|
162
|
+
|
163
|
+
it "should remove from [A: 2-4, B: 1-2]" do
|
164
|
+
scenario A: 2..4, B: 1..2
|
165
|
+
lambda { remove("A", 2, 4) }.should change { state }.
|
166
|
+
from(1 => "B", 2 => "A", 4 => "").
|
167
|
+
to(1 => "B", 2 => "")
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should remove from [A: 1-4, B: 1-4]" do
|
171
|
+
scenario A: 1..4, B: 1..4
|
172
|
+
lambda { remove("A", 1, 4) }.should change { state }.
|
173
|
+
from(1 => "AB", 4 => "").
|
174
|
+
to(1 => "B", 4 => "")
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should remove from [A: 1-4]" do
|
178
|
+
scenario A: 1..4
|
179
|
+
lambda { remove("A", 1, 4) }.should change { state }.
|
180
|
+
from(1 => "A", 4 => "").
|
181
|
+
to({})
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
ENV["REDIS_URL"] ||= 'redis://127.0.0.1:6379/9'
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'rspec'
|
5
|
+
require 'redis'
|
6
|
+
|
7
|
+
count = Redis.current.dbsize
|
8
|
+
unless count.zero?
|
9
|
+
STDERR.puts
|
10
|
+
STDERR.puts " !! WARNING!"
|
11
|
+
STDERR.puts " !! ========"
|
12
|
+
STDERR.puts " !!"
|
13
|
+
STDERR.puts " !! Your Redis (test) database at #{Redis.current.id} contains #{count} keys."
|
14
|
+
STDERR.puts " !! Running specs would wipe your database and result in potentail data loss."
|
15
|
+
STDERR.puts " !! Please specify a REDIS_URL environment variable to point to an empty database."
|
16
|
+
STDERR.puts
|
17
|
+
abort
|
18
|
+
end
|
19
|
+
|
20
|
+
version = Redis.current.info["redis_version"]
|
21
|
+
unless version >= "2.5"
|
22
|
+
STDERR.puts
|
23
|
+
STDERR.puts " !! WARNING!"
|
24
|
+
STDERR.puts " !! ========"
|
25
|
+
STDERR.puts " !!"
|
26
|
+
STDERR.puts " !! Your Redis (test) database at #{Redis.current.id} v#{version} is not suitable."
|
27
|
+
STDERR.puts " !! Please upgrade to Redis 2.6, or higher."
|
28
|
+
STDERR.puts
|
29
|
+
abort
|
30
|
+
end
|
31
|
+
|
32
|
+
module RSpec::RedisHelper
|
33
|
+
ROOT = File.expand_path("../../lib", __FILE__)
|
34
|
+
|
35
|
+
def redis
|
36
|
+
Redis.current
|
37
|
+
end
|
38
|
+
|
39
|
+
def evalsha(name, *args)
|
40
|
+
part = File.basename(File.dirname(self.class.file_path)).to_sym
|
41
|
+
redis.evalsha scripts[part][name], *args
|
42
|
+
end
|
43
|
+
|
44
|
+
def scripts
|
45
|
+
@scripts ||= Dir[File.join(ROOT, "**/*.lua")].inject({}) do |result, file|
|
46
|
+
part, name = file.sub(ROOT, "").sub(".lua", "").split("/").reject(&:empty?).map(&:to_sym)
|
47
|
+
result[part] ||= {}
|
48
|
+
result[part][name] = redis.script :load, File.read(file)
|
49
|
+
result
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
RSpec.configure do |config|
|
56
|
+
|
57
|
+
config.after do
|
58
|
+
redis.unwatch
|
59
|
+
redis.flushdb
|
60
|
+
end
|
61
|
+
|
62
|
+
config.include RSpec::RedisHelper
|
63
|
+
|
64
|
+
end
|
metadata
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: redis_recipes
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Black Square Media
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-01 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: redis
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.0.0
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.0.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: Require Redis 2.6.0 or higher
|
63
|
+
email: info@blacksquaremedia.com
|
64
|
+
executables: []
|
65
|
+
extensions: []
|
66
|
+
extra_rdoc_files: []
|
67
|
+
files:
|
68
|
+
- .rspec
|
69
|
+
- Gemfile
|
70
|
+
- Gemfile.lock
|
71
|
+
- README.md
|
72
|
+
- Rakefile
|
73
|
+
- lib/range_lookup/README.md
|
74
|
+
- lib/range_lookup/add.lua
|
75
|
+
- lib/range_lookup/lookup.lua
|
76
|
+
- lib/range_lookup/remove.lua
|
77
|
+
- lib/range_lookup_x/README.md
|
78
|
+
- lib/range_lookup_x/add.lua
|
79
|
+
- lib/range_lookup_x/lookup.lua
|
80
|
+
- lib/range_lookup_x/remove.lua
|
81
|
+
- redis_recipes.gemspec
|
82
|
+
- spec/range_lookup/add_spec.rb
|
83
|
+
- spec/range_lookup/lookup_spec.rb
|
84
|
+
- spec/range_lookup/remove_spec.rb
|
85
|
+
- spec/range_lookup_x/add_spec.rb
|
86
|
+
- spec/range_lookup_x/lookup_spec.rb
|
87
|
+
- spec/range_lookup_x/remove_spec.rb
|
88
|
+
- spec/spec_helper.rb
|
89
|
+
homepage: https://github.com/bsm/redis_recipes
|
90
|
+
licenses: []
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- - lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ! '>='
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: 1.9.0
|
101
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
|
+
none: false
|
103
|
+
requirements:
|
104
|
+
- - ! '>='
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: 1.3.6
|
107
|
+
requirements: []
|
108
|
+
rubyforge_project:
|
109
|
+
rubygems_version: 1.8.24
|
110
|
+
signing_key:
|
111
|
+
specification_version: 3
|
112
|
+
summary: Redis LUA recipes.
|
113
|
+
test_files:
|
114
|
+
- spec/range_lookup/add_spec.rb
|
115
|
+
- spec/range_lookup/lookup_spec.rb
|
116
|
+
- spec/range_lookup/remove_spec.rb
|
117
|
+
- spec/range_lookup_x/add_spec.rb
|
118
|
+
- spec/range_lookup_x/lookup_spec.rb
|
119
|
+
- spec/range_lookup_x/remove_spec.rb
|
120
|
+
- spec/spec_helper.rb
|
121
|
+
has_rdoc:
|