turnpike 0.1.3 → 0.2.0

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