turnpike 0.6.0 → 0.7.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 +4 -4
- data/.travis.yml +0 -2
- data/Gemfile +1 -1
- data/README.md +32 -10
- data/lib/turnpike.rb +3 -8
- data/lib/turnpike/base.rb +31 -0
- data/lib/turnpike/queue.rb +6 -37
- data/lib/turnpike/unique_queue.rb +59 -0
- data/lib/turnpike/version.rb +1 -1
- data/test/turnpike_test.rb +76 -34
- data/turnpike.gemspec +4 -3
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 71c0caf5486b4a3dd29477c55ad64dd46a524413
|
4
|
+
data.tar.gz: 74a7c074fb111de0d96a35b5d8de8ac75d509270
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 80372b97d3b71ec35006cd72c933d2466de7334cf983496ba64c942e19ed8f81e3f577efe6a3bf44e31a665de96f759c53cf2824c946f57ea3d0f1dd05ff55b8
|
7
|
+
data.tar.gz: 641c1458dc324d58e98369c04bf8e403e403be5acbac3747236cadcffe0edba72c176c8e68a8d0d57edf43ede2a30d2b1972c9333c7fa9e1c82d43456826f194
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
source '
|
1
|
+
source 'https://rubygems.org'
|
2
2
|
gemspec
|
data/README.md
CHANGED
@@ -2,19 +2,41 @@
|
|
2
2
|
|
3
3
|
![turnpike][nj]
|
4
4
|
|
5
|
-
Turnpike
|
5
|
+
Turnpike is a minimal [Redis][red]-backed FIFO queue in Ruby.
|
6
|
+
|
7
|
+
## Usage
|
8
|
+
|
9
|
+
Push and pop:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
q = Turnpike.call('queue name')
|
13
|
+
q.push('foo', 'bar', 'baz', 'qux') # => 4
|
14
|
+
q.pop # => 'foo'
|
15
|
+
```
|
16
|
+
|
17
|
+
Pop multiple items:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
q.pop(2) # => ['bar', 'baz']
|
21
|
+
```
|
22
|
+
|
23
|
+
Push payload to the front of the queue:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
q.unshift('foo') # => 2
|
27
|
+
q.pop # => 'foo"'
|
28
|
+
```
|
29
|
+
|
30
|
+
Use a queue with set-like properties to ensure uniqueness of queued items:
|
6
31
|
|
7
32
|
```ruby
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
queue.unshift(1)
|
13
|
-
queue.pop(4) # => [1, 2, 3, 4]
|
33
|
+
q = Turnpike.call('queue name', unique: true)
|
34
|
+
q.push('foo', 'bar') # => 2
|
35
|
+
q.push('bar') # => 2
|
36
|
+
q.pop(3) # => ['foo', 'bar']
|
14
37
|
```
|
15
38
|
|
16
|
-
Turnpike requires Redis 2.
|
39
|
+
Turnpike requires Ruby 2.0 and Redis 2.6 or higher.
|
17
40
|
|
18
41
|
[nj]: http://f.cl.ly/items/33242X323P3M1t1G400H/turnpike.jpg
|
19
|
-
[
|
20
|
-
[msgpack]: http://msgpack.org/
|
42
|
+
[red]: http://redis.io/
|
data/lib/turnpike.rb
CHANGED
@@ -1,13 +1,8 @@
|
|
1
1
|
require 'turnpike/queue'
|
2
|
+
require 'turnpike/unique_queue'
|
2
3
|
|
3
|
-
# A Redis-backed queue.
|
4
4
|
module Turnpike
|
5
|
-
|
6
|
-
|
7
|
-
# name - A queue name that responds to to_s.
|
8
|
-
#
|
9
|
-
# Returns a Turnpike::Queue.
|
10
|
-
def self.[](name)
|
11
|
-
Queue.new(name)
|
5
|
+
def self.call(name = 'default', unique: false)
|
6
|
+
(unique ? UniqueQueue : Queue).new(name)
|
12
7
|
end
|
13
8
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'msgpack'
|
3
|
+
require 'redis'
|
4
|
+
|
5
|
+
module Turnpike
|
6
|
+
class Base
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
def_delegator :Redis, :current, :redis
|
10
|
+
def_delegators :MessagePack, :pack, :unpack
|
11
|
+
|
12
|
+
attr :name
|
13
|
+
|
14
|
+
def initialize(name)
|
15
|
+
@name = "turnpike:#{name}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def clear
|
19
|
+
redis.del(name)
|
20
|
+
end
|
21
|
+
|
22
|
+
def empty?
|
23
|
+
size == 0
|
24
|
+
end
|
25
|
+
|
26
|
+
def pop(*); raise NotImplementedError; end
|
27
|
+
def push(*); raise NotImplementedError; end
|
28
|
+
def size; raise NotImplementedError; end
|
29
|
+
def unshift(*); raise NotImplementedError; end
|
30
|
+
end
|
31
|
+
end
|
data/lib/turnpike/queue.rb
CHANGED
@@ -1,32 +1,8 @@
|
|
1
|
-
require '
|
2
|
-
require 'redis'
|
1
|
+
require 'turnpike/base'
|
3
2
|
|
4
3
|
module Turnpike
|
5
|
-
|
6
|
-
|
7
|
-
# Returns a String name.
|
8
|
-
attr :name
|
9
|
-
|
10
|
-
# Create a new queue.
|
11
|
-
#
|
12
|
-
# name - A queue name that responds to to_s.
|
13
|
-
def initialize(name = 'queue')
|
14
|
-
@name = "turnpike:#{name}"
|
15
|
-
end
|
16
|
-
|
17
|
-
# Remove all items from the queue.
|
18
|
-
#
|
19
|
-
# Returns Integer number of items that were removed.
|
20
|
-
def clear
|
21
|
-
redis.del(name)
|
22
|
-
end
|
23
|
-
|
24
|
-
# Returns whether the queue is empty.
|
25
|
-
def empty?
|
26
|
-
size == 0
|
27
|
-
end
|
28
|
-
|
29
|
-
# Pop one or more items from the front of the queue.
|
4
|
+
class Queue < Base
|
5
|
+
# Pop one or more items from the queue.
|
30
6
|
#
|
31
7
|
# n - Integer number of items to pop.
|
32
8
|
#
|
@@ -35,7 +11,7 @@ module Turnpike
|
|
35
11
|
items = []
|
36
12
|
n.times do
|
37
13
|
break unless item = redis.lpop(name)
|
38
|
-
items <<
|
14
|
+
items << unpack(item)
|
39
15
|
end
|
40
16
|
|
41
17
|
n == 1 ? items.first : items
|
@@ -47,10 +23,9 @@ module Turnpike
|
|
47
23
|
#
|
48
24
|
# Returns the Integer size of the queue after the operation.
|
49
25
|
def push(*items)
|
50
|
-
redis.rpush(name, items.map { |i|
|
26
|
+
redis.rpush(name, items.map { |i| pack(i) })
|
51
27
|
end
|
52
28
|
|
53
|
-
# Syntactic sugar.
|
54
29
|
alias << push
|
55
30
|
|
56
31
|
# Returns the Integer size of the queue.
|
@@ -64,13 +39,7 @@ module Turnpike
|
|
64
39
|
#
|
65
40
|
# Returns the Integer size of the queue after the operation.
|
66
41
|
def unshift(*items)
|
67
|
-
redis.lpush(name, items.map { |i|
|
68
|
-
end
|
69
|
-
|
70
|
-
private
|
71
|
-
|
72
|
-
def redis
|
73
|
-
Redis.current
|
42
|
+
redis.lpush(name, items.map { |i| pack(i) })
|
74
43
|
end
|
75
44
|
end
|
76
45
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
require 'turnpike/base'
|
3
|
+
|
4
|
+
module Turnpike
|
5
|
+
class UniqueQueue < Base
|
6
|
+
ZPOP = <<-EOF
|
7
|
+
local res = redis.call('zrange', KEYS[1], 0, KEYS[2] - 1)
|
8
|
+
redis.pcall('zrem', KEYS[1], unpack(res))
|
9
|
+
return res
|
10
|
+
EOF
|
11
|
+
|
12
|
+
ZPOP_SHA = Digest::SHA1.hexdigest(ZPOP)
|
13
|
+
|
14
|
+
# Pop one or more items from the queue.
|
15
|
+
#
|
16
|
+
# n - Integer number of items to pop.
|
17
|
+
#
|
18
|
+
# Returns a String item, an Array of items, or nil if the queue is empty.
|
19
|
+
def pop(n = 1)
|
20
|
+
items = begin
|
21
|
+
redis.evalsha(ZPOP_SHA, [name, n])
|
22
|
+
rescue Redis::CommandError
|
23
|
+
redis.eval(ZPOP, [name, n])
|
24
|
+
end
|
25
|
+
items.map! { |i| unpack(i) }
|
26
|
+
|
27
|
+
n == 1 ? items.first : items
|
28
|
+
end
|
29
|
+
|
30
|
+
# Push items to the end of the queue.
|
31
|
+
#
|
32
|
+
# items - A splat Array of items.
|
33
|
+
#
|
34
|
+
# Returns the Integer size of the queue after the operation.
|
35
|
+
def push(*items, score: Time.now.to_f)
|
36
|
+
redis.multi do
|
37
|
+
redis.zadd(name, items.reduce([]) { |ary, i| ary.push(score, pack(i)) })
|
38
|
+
size
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
alias << push
|
43
|
+
|
44
|
+
# Returns the Integer size of the queue.
|
45
|
+
def size
|
46
|
+
redis.zcard(name)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Push items to the front of the queue.
|
50
|
+
#
|
51
|
+
# items - A splat Array of items.
|
52
|
+
#
|
53
|
+
# Returns the Integer size of the queue after the operation.
|
54
|
+
def unshift(*items)
|
55
|
+
_, score = redis.zrange(name, 0, 0, with_scores: true).pop
|
56
|
+
score ? push(*items, score: score - 1) : push(*items)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/turnpike/version.rb
CHANGED
data/test/turnpike_test.rb
CHANGED
@@ -1,52 +1,75 @@
|
|
1
|
-
|
1
|
+
$: << File.expand_path('../lib', File.dirname(__FILE__))
|
2
2
|
require 'minitest/autorun'
|
3
|
-
require
|
3
|
+
require 'minitest/benchmark' if ENV['BENCH']
|
4
|
+
require 'turnpike'
|
4
5
|
|
5
6
|
class TestTurnpike < MiniTest::Unit::TestCase
|
6
|
-
def
|
7
|
-
|
7
|
+
def test_call
|
8
|
+
assert_kind_of Turnpike::Queue, Turnpike.call
|
9
|
+
assert_kind_of Turnpike::UniqueQueue, Turnpike.call(unique: true)
|
8
10
|
end
|
9
11
|
|
10
|
-
def
|
11
|
-
|
12
|
-
|
12
|
+
def test_queue_name
|
13
|
+
queue = Turnpike::Base.new('foo')
|
14
|
+
assert_includes queue.name, 'foo'
|
13
15
|
end
|
14
16
|
|
15
|
-
def
|
16
|
-
queue = Turnpike
|
17
|
-
|
18
|
-
|
17
|
+
def test_abstract_class
|
18
|
+
queue = Turnpike::Base.new('foo')
|
19
|
+
%w(push pop unshift size).each do |mth|
|
20
|
+
assert_raises(NotImplementedError) { queue.send(mth) }
|
21
|
+
end
|
19
22
|
end
|
20
23
|
|
21
|
-
def
|
22
|
-
queue = Turnpike
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
def bench_queue
|
25
|
+
queue = Turnpike.call
|
26
|
+
assert_performance_linear do |n|
|
27
|
+
queue.push(*(1..n).to_a)
|
28
|
+
1.upto(n) { queue.pop }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def bench_unique
|
33
|
+
queue = Turnpike.call(unique: true)
|
34
|
+
assert_performance_linear do |n|
|
35
|
+
queue.push(*(1..n).to_a)
|
36
|
+
1.upto(n) { queue.pop }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module QueueTests
|
42
|
+
def queue
|
43
|
+
@queue ||= klass.new('foo')
|
44
|
+
end
|
45
|
+
|
46
|
+
def setup
|
47
|
+
Redis.current.flushall
|
28
48
|
end
|
29
49
|
|
30
50
|
def test_push
|
31
|
-
queue = Turnpike::Queue.new
|
32
51
|
queue.push(1)
|
33
52
|
assert_equal 1, queue.size
|
34
53
|
queue.push(2, 3)
|
35
|
-
assert_equal 3, queue.size
|
36
54
|
assert_equal [1, 2, 3], peek(queue)
|
37
55
|
end
|
38
56
|
|
57
|
+
def test_emptiness
|
58
|
+
assert queue.empty?
|
59
|
+
queue << 1
|
60
|
+
assert !queue.empty?
|
61
|
+
queue.clear
|
62
|
+
assert queue.empty?
|
63
|
+
end
|
64
|
+
|
39
65
|
def test_unshift
|
40
|
-
queue
|
41
|
-
queue.unshift(1)
|
42
|
-
assert_equal 1, queue.size
|
66
|
+
queue.push(1)
|
43
67
|
queue.unshift(2, 3)
|
44
68
|
assert_equal 3, queue.size
|
45
|
-
assert_equal
|
69
|
+
assert_equal 1, peek(queue).last
|
46
70
|
end
|
47
71
|
|
48
72
|
def test_pop
|
49
|
-
queue = Turnpike::Queue.new
|
50
73
|
queue.push(1, 2)
|
51
74
|
assert_equal 1, queue.pop
|
52
75
|
assert_equal 2, queue.pop
|
@@ -54,7 +77,6 @@ class TestTurnpike < MiniTest::Unit::TestCase
|
|
54
77
|
end
|
55
78
|
|
56
79
|
def test_pop_many
|
57
|
-
queue = Turnpike::Queue.new
|
58
80
|
queue.push(1, 2, 3)
|
59
81
|
assert_equal [1, 2], queue.pop(2)
|
60
82
|
assert_equal [3], queue.pop(2)
|
@@ -62,7 +84,6 @@ class TestTurnpike < MiniTest::Unit::TestCase
|
|
62
84
|
end
|
63
85
|
|
64
86
|
def test_order
|
65
|
-
queue = Turnpike::Queue.new
|
66
87
|
queue.push(1, 2)
|
67
88
|
queue.unshift(3)
|
68
89
|
assert_equal 3, queue.pop
|
@@ -70,12 +91,33 @@ class TestTurnpike < MiniTest::Unit::TestCase
|
|
70
91
|
assert_equal 2, queue.pop
|
71
92
|
end
|
72
93
|
|
73
|
-
def
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
assert_equal 1,
|
79
|
-
assert_equal 2,
|
94
|
+
def test_multiplicity
|
95
|
+
q1 = klass.new('foo')
|
96
|
+
q2 = klass.new('bar')
|
97
|
+
q1.push(1)
|
98
|
+
q2.push(2, 3)
|
99
|
+
assert_equal 1, q1.size
|
100
|
+
assert_equal 2, q2.size
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class TestQueue < MiniTest::Unit::TestCase
|
105
|
+
include QueueTests
|
106
|
+
|
107
|
+
def klass; Turnpike::Queue; end
|
108
|
+
|
109
|
+
def peek(queue)
|
110
|
+
queue.redis.lrange(queue.name, 0, -1).map { |i| queue.unpack(i) }
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
class TestUniqueQueue < MiniTest::Unit::TestCase
|
116
|
+
include QueueTests
|
117
|
+
|
118
|
+
def klass; Turnpike::UniqueQueue; end
|
119
|
+
|
120
|
+
def peek(queue)
|
121
|
+
queue.redis.zrange(queue.name, 0, -1).map { |i| queue.unpack(i) }
|
80
122
|
end
|
81
123
|
end
|
data/turnpike.gemspec
CHANGED
@@ -8,15 +8,16 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.authors = ['Hakan Ensari']
|
9
9
|
s.email = ['hakan.ensari@papercavalier.com']
|
10
10
|
s.homepage = 'http://github.com/hakanensari/turnpike'
|
11
|
-
s.
|
12
|
-
s.
|
11
|
+
s.description = %q{A Redis-backed FIFO queue}
|
12
|
+
s.summary = %q{A Redis-backed FIFO queue}
|
13
13
|
|
14
14
|
s.files = `git ls-files`.split("\n")
|
15
15
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
16
|
s.require_paths = ['lib']
|
18
17
|
|
19
18
|
s.add_runtime_dependency 'redis', '~> 3.0'
|
20
19
|
s.add_runtime_dependency 'msgpack', '~> 0.5.4'
|
21
20
|
s.add_development_dependency 'rake'
|
21
|
+
|
22
|
+
s.required_ruby_version = '>= 2.0'
|
22
23
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: turnpike
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hakan Ensari
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-05-
|
11
|
+
date: 2013-05-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
@@ -52,7 +52,7 @@ dependencies:
|
|
52
52
|
- - '>='
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
-
description:
|
55
|
+
description: A Redis-backed FIFO queue
|
56
56
|
email:
|
57
57
|
- hakan.ensari@papercavalier.com
|
58
58
|
executables: []
|
@@ -66,7 +66,9 @@ files:
|
|
66
66
|
- README.md
|
67
67
|
- Rakefile
|
68
68
|
- lib/turnpike.rb
|
69
|
+
- lib/turnpike/base.rb
|
69
70
|
- lib/turnpike/queue.rb
|
71
|
+
- lib/turnpike/unique_queue.rb
|
70
72
|
- lib/turnpike/version.rb
|
71
73
|
- test/turnpike_test.rb
|
72
74
|
- turnpike.gemspec
|
@@ -81,7 +83,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
81
83
|
requirements:
|
82
84
|
- - '>='
|
83
85
|
- !ruby/object:Gem::Version
|
84
|
-
version: '0'
|
86
|
+
version: '2.0'
|
85
87
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
88
|
requirements:
|
87
89
|
- - '>='
|
@@ -92,7 +94,6 @@ rubyforge_project:
|
|
92
94
|
rubygems_version: 2.0.0
|
93
95
|
signing_key:
|
94
96
|
specification_version: 4
|
95
|
-
summary: A Redis-backed queue
|
97
|
+
summary: A Redis-backed FIFO queue
|
96
98
|
test_files:
|
97
99
|
- test/turnpike_test.rb
|
98
|
-
has_rdoc:
|