turnpike 0.1.3 → 0.2.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/.travis.yml CHANGED
@@ -1,4 +1,8 @@
1
1
  rvm:
2
2
  - 1.8.7
3
3
  - 1.9.2
4
+ - 1.9.3
5
+ - jruby
4
6
  - rbx
7
+ - rbx-2.0
8
+ - ree
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
1
  # CHANGELOG
2
2
 
3
- See [here](http://code.papercavalier.com/turnpike).
3
+ ## 0.2.0/2011-08-14
4
+
5
+ * implement observer
6
+
7
+ ## 0.1.0/2011-07-18
8
+
9
+ * first release
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Turnpike
2
2
 
3
- [![travis](https://secure.travis-ci.org/papercavalier/turnpike.png)](http://travis-ci.org/papercavalier/turnpike)
3
+ [![travis](https://secure.travis-ci.org/hakanensari/turnpike.png)](http://travis-ci.org/hakanensari/turnpike)
4
4
 
5
- Turnpike is a Redis-backed message processing queue.
5
+ Turnpike is a Redis-backed messaging queue.
6
6
 
7
7
  [Read here](http://code.papercavalier.com/turnpike) for more detail.
@@ -0,0 +1,43 @@
1
+ module Turnpike
2
+ class Observer
3
+ def initialize(name, *items)
4
+ @timeout = items.last.is_a?(Hash) ? items.pop[:timeout] : 10
5
+ @name, @items = name, items
6
+ end
7
+
8
+ def observe
9
+ if reactor_running?
10
+ timer = EM.add_timer(@timeout) { unsubscribe }
11
+ subscribe && EM.cancel_timer(timer)
12
+ else
13
+ thr = Thread.new { subscribe }
14
+ !!thr.join(@timeout)
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def reactor_running?
21
+ defined?(EM) && EM.reactor_running?
22
+ end
23
+
24
+ def subscribe
25
+ redis.subscribe(@name) do |on|
26
+ on.message do |channel, message|
27
+ message.split('|').each { |item| @items.delete(item) }
28
+ unsubscribe if @items.empty?
29
+ end
30
+ end
31
+
32
+ @items.empty?
33
+ end
34
+
35
+ def redis
36
+ @redis ||= Redis.connect(Turnpike.options)
37
+ end
38
+
39
+ def unsubscribe
40
+ redis.unsubscribe
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,137 @@
1
+ module Turnpike
2
+ class Queue
3
+ # The name of the queue.
4
+ attr :name
5
+
6
+ # Specifies for how many seconds a blocking pop or shift should
7
+ # block the connection.
8
+ attr_accessor :timeout
9
+
10
+ # Default timeout to 0.
11
+ @timeout = 0
12
+
13
+ # Creates a new queue.
14
+ #
15
+ # Takes an optional name.
16
+ def initialize(name = 'default')
17
+ @name = "turnpike:#{name}"
18
+ end
19
+
20
+ # Removes all queued items.
21
+ def clear
22
+ redis.del(name)
23
+ end
24
+
25
+ # Calls block once for each queued item.
26
+ #
27
+ # Takes an optional boolean argument to specify if the command
28
+ # should block the connection when the queue is empty. This
29
+ # argument defaults to false.
30
+ def each(blocking = false, &block)
31
+ while item = shift(blocking)
32
+ block.call(item)
33
+ end
34
+ end
35
+
36
+ # Iterates the given block for each slice of _n_ queued items.
37
+ #
38
+ # Takes an optional boolean argument to specify if the command
39
+ # should block the connection when the queue is empty. This
40
+ # argument defaults to false.
41
+ def each_slice(n, blocking = false, &block)
42
+ slice = []
43
+
44
+ each(blocking) do |item|
45
+ slice << item
46
+ if slice.size == n
47
+ block.call(slice)
48
+ slice = []
49
+ end
50
+ end
51
+
52
+ yield slice unless slice.empty?
53
+ end
54
+
55
+ # Returns `true` if the queue is empty.
56
+ def empty?
57
+ length == 0
58
+ end
59
+
60
+ # Returns the length of the queue.
61
+ def length
62
+ redis.llen(name)
63
+ end
64
+
65
+ # Notifies observers that the state of specified items has changed.
66
+ def notify(*items)
67
+ redis.publish(name, items.join('|'))
68
+ end
69
+
70
+ # Observes items.
71
+ #
72
+ # Takes an optional timeout argument, wich defaults to 10 seconds.
73
+ #
74
+ # Returns true if notified of a state change in all items.
75
+ def observe(*items)
76
+ Observer.new(name, *items).observe
77
+ end
78
+
79
+ alias size length
80
+
81
+ # Returns an array of items currently queued.
82
+ #
83
+ # `start` is an integer and indicates the start offset, 0 being the
84
+ # first queued item. If negative, it indicates the offset from the
85
+ # end, -1 being the last queued item.
86
+ #
87
+ # `count` is also an integer and indicates the number of items to
88
+ # return.
89
+ def peek(start, count)
90
+ redis.lrange(name, start, count)
91
+ end
92
+
93
+ # Retrieves the last queued item.
94
+ #
95
+ # Takes an optional boolean argument to specify if the command
96
+ # should block the connection when the queue is empty. This
97
+ # argument defaults to false.
98
+ def pop(blocking = false)
99
+ if blocking
100
+ redis.brpop(name, timeout)[1] rescue nil
101
+ else
102
+ redis.rpop(name)
103
+ end
104
+ end
105
+
106
+ # Pushes items to the end of the queue.
107
+ def push(*items)
108
+ items.each { |item| redis.rpush(name, item) }
109
+ end
110
+
111
+ alias << push
112
+
113
+ # Retrieves the first queued item.
114
+ #
115
+ # Takes an optional boolean argument to specify if the command
116
+ # should block the connection when the queue is empty. This
117
+ # argument defaults to false.
118
+ def shift(blocking = false)
119
+ if blocking
120
+ redis.blpop(name, timeout)[1] rescue nil
121
+ else
122
+ redis.lpop(name)
123
+ end
124
+ end
125
+
126
+ # Pushes items to the front of the queue.
127
+ def unshift(*items)
128
+ items.each { |item| redis.lpush(name, item) }
129
+ end
130
+
131
+ private
132
+
133
+ def redis
134
+ Redis.current ||= Redis.connect(Turnpike.options)
135
+ end
136
+ end
137
+ end
@@ -1,3 +1,3 @@
1
- class Turnpike
2
- VERSION = '0.1.3'
1
+ module Turnpike
2
+ VERSION = '0.2.0'
3
3
  end
data/lib/turnpike.rb CHANGED
@@ -1,140 +1,25 @@
1
1
  require 'redis'
2
+ require 'turnpike/queue'
3
+ require 'turnpike/observer'
2
4
 
3
- # A Redis-backed queue.
4
- class Turnpike
5
+ # = Turnpike
6
+ #
7
+ # A Redis-backed messaging queue.
8
+ module Turnpike
5
9
  class << self
6
- def options
7
- @options ||= {}
10
+ # Returns a cached or new queue.
11
+ def [](queue)
12
+ @queues[queue] ||= Queue.new(queue)
8
13
  end
9
14
 
10
- # Timeout, in seconds, for blocking `pop` or `shift`.
11
- attr_accessor :timeout
12
-
13
- @timeout = 0
14
-
15
+ # Sets Redis connection options.
15
16
  def connect(options)
16
17
  @options = options
17
18
  end
18
19
 
19
- # Returns a queue. Syntactic sugar.
20
- def [](queue)
21
- queues[queue] ||= new(queue)
22
- end
23
-
24
- def configure(&block)
25
- yield self
26
- end
27
-
28
- private
29
-
30
- def queues
31
- @queues ||= Hash.new
32
- end
20
+ # Redis connection options.
21
+ attr :options
33
22
  end
34
23
 
35
- # The name of the queue.
36
- attr :name
37
-
38
- # Creates a new queue.
39
- #
40
- # Takes an optional name.
41
- def initialize(name = 'default')
42
- @name = "turnpike:#{name}"
43
- end
44
-
45
- # Removes all queued items.
46
- def clear
47
- redis.del(name)
48
- end
49
-
50
- # Calls block once for each queued item.
51
- #
52
- # Takes an optional boolean argument to specify if the command should block
53
- # the connection when the queue is empty. This argument defaults to false.
54
- def each(blocking = false, &block)
55
- while item = shift(blocking)
56
- block.call(item)
57
- end
58
- end
59
-
60
- # Iterates the given block for each slice of `n` queued items.
61
- #
62
- # Takes an optional boolean argument to specify if the command should block
63
- # the connection when the queue is empty. This argument defaults to false.
64
- def each_slice(n, blocking = false, &block)
65
- slice = []
66
-
67
- each(blocking) do |item|
68
- slice << item
69
- if slice.size == n
70
- yield slice
71
- slice = []
72
- end
73
- end
74
-
75
- yield slice unless slice.empty?
76
- end
77
-
78
- # Returns `true` if the queue is empty.
79
- def empty?
80
- length == 0
81
- end
82
-
83
- # Returns the length of the queue.
84
- def length
85
- redis.llen(name)
86
- end
87
- alias size length
88
-
89
- # Returns an array of items currently queued.
90
- #
91
- # `start` is an integer and indicates the start offset, 0 being the first
92
- # queued item. If negative, it indicates the offset from the end, -1 being
93
- # the last queued item.
94
- #
95
- # `count` is also an integer and indicates the number of items to return.
96
- def peek(start, count)
97
- redis.lrange(name, start, count)
98
- end
99
-
100
- # Retrieves the last queued item.
101
- #
102
- # Takes an optional boolean argument to specify if the command should block
103
- # the connection when the queue is empty. This argument defaults to false.
104
- def pop(blocking = false)
105
- if blocking
106
- redis.brpop(name, Turnpike.timeout)[1] rescue nil
107
- else
108
- redis.rpop(name)
109
- end
110
- end
111
-
112
- # Pushes items to the end of the queue.
113
- def push(*items)
114
- items.each { |item| redis.rpush(name, item) }
115
- end
116
- alias << push
117
-
118
- # Retrieves the first queued item.
119
- #
120
- # Takes an optional boolean argument to specify if the command should block
121
- # the connection when the queue is empty. This argument defaults to false.
122
- def shift(blocking = false)
123
- if blocking
124
- redis.blpop(name, Turnpike.timeout)[1] rescue nil
125
- else
126
- redis.lpop(name)
127
- end
128
- end
129
-
130
- # Pushes items to the front of the queue.
131
- def unshift(*items)
132
- items.each { |item| redis.lpush(name, item) }
133
- end
134
-
135
- private
136
-
137
- def redis
138
- Redis.current ||= Redis.connect(Turnpike.options)
139
- end
24
+ @options, @queues = {}, {}
140
25
  end
@@ -10,20 +10,20 @@ class TestTurnpike < Test::Unit::TestCase
10
10
  Redis.current.flushall
11
11
  end
12
12
 
13
- def time_out_in(seconds, &block)
14
- original_timeout = Turnpike.timeout
15
- Turnpike.configure { |c| c.timeout = seconds }
13
+ def time_out_in(queue, seconds, &block)
14
+ original_timeout = queue.timeout
15
+ queue.timeout = seconds
16
16
  block.call
17
- Turnpike.configure { |c| c.timeout = original_timeout }
17
+ queue.timeout = original_timeout
18
18
  end
19
19
 
20
20
  def test_bracket_method
21
- assert_equal("turnpike:foo", Turnpike["foo"].name)
22
- assert(Turnpike["foo"] == Turnpike["foo"])
21
+ assert_equal('turnpike:foo', Turnpike["foo"].name)
22
+ assert(Turnpike['foo'] == Turnpike["foo"])
23
23
  end
24
24
 
25
25
  def test_emptiness
26
- queue = Turnpike.new
26
+ queue = Turnpike::Queue.new
27
27
  assert(queue.empty?)
28
28
 
29
29
  queue << 1
@@ -34,7 +34,7 @@ class TestTurnpike < Test::Unit::TestCase
34
34
  end
35
35
 
36
36
  def test_pushing_items
37
- queue = Turnpike.new
37
+ queue = Turnpike::Queue.new
38
38
  queue.push(1)
39
39
  assert_equal(1, queue.length)
40
40
 
@@ -44,7 +44,7 @@ class TestTurnpike < Test::Unit::TestCase
44
44
  end
45
45
 
46
46
  def test_unshifting_items
47
- queue = Turnpike.new
47
+ queue = Turnpike::Queue.new
48
48
  queue.unshift(1)
49
49
  assert_equal(1, queue.length)
50
50
 
@@ -54,7 +54,7 @@ class TestTurnpike < Test::Unit::TestCase
54
54
  end
55
55
 
56
56
  def test_popping_items
57
- queue = Turnpike.new
57
+ queue = Turnpike::Queue.new
58
58
  queue.push(1, 2)
59
59
  assert_equal('2', queue.pop)
60
60
  assert_equal('1', queue.pop)
@@ -62,7 +62,7 @@ class TestTurnpike < Test::Unit::TestCase
62
62
  end
63
63
 
64
64
  def test_shifting_items
65
- queue = Turnpike.new
65
+ queue = Turnpike::Queue.new
66
66
  queue.push(1, 2)
67
67
  assert_equal('1', queue.shift)
68
68
  assert_equal('2', queue.shift)
@@ -70,7 +70,7 @@ class TestTurnpike < Test::Unit::TestCase
70
70
  end
71
71
 
72
72
  def test_enumeration
73
- queue = Turnpike.new
73
+ queue = Turnpike::Queue.new
74
74
  queue.push(1, 2)
75
75
  items = []
76
76
  queue.each { |item| items << item }
@@ -88,14 +88,14 @@ class TestTurnpike < Test::Unit::TestCase
88
88
  end
89
89
 
90
90
  def test_aliases
91
- queue = Turnpike.new
91
+ queue = Turnpike::Queue.new
92
92
  queue << 1
93
93
  assert_equal(1, queue.size)
94
94
  end
95
95
 
96
96
  def test_multiple_queues
97
- queue1 = Turnpike.new("foo")
98
- queue2 = Turnpike.new("bar")
97
+ queue1 = Turnpike::Queue.new("foo")
98
+ queue2 = Turnpike::Queue.new("bar")
99
99
 
100
100
  queue1.push(1)
101
101
  queue2.push(2, 3)
@@ -105,7 +105,7 @@ class TestTurnpike < Test::Unit::TestCase
105
105
  end
106
106
 
107
107
  def test_blocking_pop
108
- queue = Turnpike.new
108
+ queue = Turnpike::Queue.new
109
109
  started_at = Time.now.to_i
110
110
  Thread.new do
111
111
  sleep(1)
@@ -117,7 +117,7 @@ class TestTurnpike < Test::Unit::TestCase
117
117
  end
118
118
 
119
119
  def test_blocking_shift
120
- queue = Turnpike.new
120
+ queue = Turnpike::Queue.new
121
121
  started_at = Time.now.to_i
122
122
  Thread.new do
123
123
  sleep(1)
@@ -129,8 +129,8 @@ class TestTurnpike < Test::Unit::TestCase
129
129
  end
130
130
 
131
131
  def test_timeout
132
- time_out_in 1 do
133
- queue = Turnpike.new
132
+ queue = Turnpike::Queue.new
133
+ time_out_in queue, 1 do
134
134
  thread = Thread.new do
135
135
  sleep(2)
136
136
  queue.push(1)
@@ -142,4 +142,18 @@ class TestTurnpike < Test::Unit::TestCase
142
142
  assert_equal(1, queue.length)
143
143
  end
144
144
  end
145
+
146
+ def test_observer
147
+ items = ['foo', 'bar']
148
+ queue = Turnpike::Queue.new
149
+ Thread.new do
150
+ sleep 1
151
+ queue.notify(*items)
152
+ end
153
+
154
+ assert queue.observe(*items)
155
+
156
+ items << { :timeout => 1 }
157
+ assert !queue.observe(*items)
158
+ end
145
159
  end
data/turnpike.gemspec CHANGED
@@ -7,8 +7,8 @@ Gem::Specification.new do |s|
7
7
  s.authors = ["Paper Cavalier"]
8
8
  s.email = ["code@papercavalier.com"]
9
9
  s.homepage = "http://code.papercavalier.com/turnpike"
10
- s.summary = %q{Turnpike is a Redis-backed message processing queue.}
11
- s.description = %q{Turnpike is a Redis-backed message processing queue.}
10
+ s.summary = %q{A Redis-backed messaging queue}
11
+ s.description = %q{Turnpike is a Redis-backed messaging queue.}
12
12
 
13
13
  s.rubyforge_project = "turnpike"
14
14
 
metadata CHANGED
@@ -1,104 +1,86 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: turnpike
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 1
8
- - 3
9
- version: 0.1.3
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ prerelease:
10
6
  platform: ruby
11
- authors:
7
+ authors:
12
8
  - Paper Cavalier
13
9
  autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
-
17
- date: 2011-07-22 00:00:00 +01:00
18
- default_executable:
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
12
+ date: 2011-08-14 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
21
15
  name: redis
22
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: &70335673360420 !ruby/object:Gem::Requirement
23
17
  none: false
24
- requirements:
18
+ requirements:
25
19
  - - ~>
26
- - !ruby/object:Gem::Version
27
- segments:
28
- - 2
29
- - 2
30
- version: "2.2"
20
+ - !ruby/object:Gem::Version
21
+ version: '2.2'
31
22
  type: :runtime
32
23
  prerelease: false
33
- version_requirements: *id001
34
- - !ruby/object:Gem::Dependency
24
+ version_requirements: *70335673360420
25
+ - !ruby/object:Gem::Dependency
35
26
  name: rake
36
- requirement: &id002 !ruby/object:Gem::Requirement
27
+ requirement: &70335673359520 !ruby/object:Gem::Requirement
37
28
  none: false
38
- requirements:
29
+ requirements:
39
30
  - - ~>
40
- - !ruby/object:Gem::Version
41
- segments:
42
- - 0
43
- - 9
44
- version: "0.9"
31
+ - !ruby/object:Gem::Version
32
+ version: '0.9'
45
33
  type: :development
46
34
  prerelease: false
47
- version_requirements: *id002
48
- description: Turnpike is a Redis-backed message processing queue.
49
- email:
35
+ version_requirements: *70335673359520
36
+ description: Turnpike is a Redis-backed messaging queue.
37
+ email:
50
38
  - code@papercavalier.com
51
39
  executables: []
52
-
53
40
  extensions: []
54
-
55
41
  extra_rdoc_files: []
56
-
57
- files:
42
+ files:
58
43
  - .gitignore
59
- - .rvmrc
60
44
  - .travis.yml
61
45
  - CHANGELOG.md
62
46
  - Gemfile
63
47
  - README.md
64
48
  - Rakefile
65
49
  - lib/turnpike.rb
50
+ - lib/turnpike/observer.rb
51
+ - lib/turnpike/queue.rb
66
52
  - lib/turnpike/version.rb
67
53
  - test/turnpike_test.rb
68
54
  - turnpike.gemspec
69
- has_rdoc: true
70
55
  homepage: http://code.papercavalier.com/turnpike
71
56
  licenses: []
72
-
73
57
  post_install_message:
74
58
  rdoc_options: []
75
-
76
- require_paths:
59
+ require_paths:
77
60
  - lib
78
- required_ruby_version: !ruby/object:Gem::Requirement
61
+ required_ruby_version: !ruby/object:Gem::Requirement
79
62
  none: false
80
- requirements:
81
- - - ">="
82
- - !ruby/object:Gem::Version
83
- hash: 3844900520271104281
84
- segments:
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ segments:
85
68
  - 0
86
- version: "0"
87
- required_rubygems_version: !ruby/object:Gem::Requirement
69
+ hash: 318226748875005980
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
71
  none: false
89
- requirements:
90
- - - ">="
91
- - !ruby/object:Gem::Version
92
- hash: 3844900520271104281
93
- segments:
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ segments:
94
77
  - 0
95
- version: "0"
78
+ hash: 318226748875005980
96
79
  requirements: []
97
-
98
80
  rubyforge_project: turnpike
99
- rubygems_version: 1.3.7
81
+ rubygems_version: 1.8.6
100
82
  signing_key:
101
83
  specification_version: 3
102
- summary: Turnpike is a Redis-backed message processing queue.
103
- test_files:
84
+ summary: A Redis-backed messaging queue
85
+ test_files:
104
86
  - test/turnpike_test.rb
data/.rvmrc DELETED
@@ -1 +0,0 @@
1
- rvm --create use 1.9.2@turnpike