redis_recipes 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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: