turnpike 0.2.0 → 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/.travis.yml CHANGED
@@ -4,5 +4,3 @@ rvm:
4
4
  - 1.9.3
5
5
  - jruby
6
6
  - rbx
7
- - rbx-2.0
8
- - ree
data/Gemfile CHANGED
@@ -1,4 +1,2 @@
1
- source "http://rubygems.org"
2
-
3
- # Specify your gem's dependencies in turnpike.gemspec
1
+ source 'http://rubygems.org'
4
2
  gemspec
data/README.md CHANGED
@@ -1,7 +1,38 @@
1
1
  # Turnpike
2
2
 
3
- [![travis](https://secure.travis-ci.org/hakanensari/turnpike.png)](http://travis-ci.org/hakanensari/turnpike)
3
+ [![travis] [1]] [2]
4
4
 
5
- Turnpike is a Redis-backed messaging queue.
5
+ Turnpike is a Redis-backed queue.
6
6
 
7
- [Read here](http://code.papercavalier.com/turnpike) for more detail.
7
+ ![turnpike] [3]
8
+
9
+ Less fancily put: Turnike wraps a [Redis List] [4] and speaks Ruby colloquial.
10
+
11
+ ## Installation
12
+
13
+ ```sh
14
+ gem install turnpike
15
+ ```
16
+
17
+ # Usage
18
+
19
+ An introspective moment of FIFO.
20
+
21
+ ```ruby
22
+ queue = Turnpike['foo']
23
+
24
+ queue << 1, 2, 3
25
+ queue.pop # => 1
26
+
27
+ queue.peek => [1, 2]
28
+ ```
29
+
30
+ [Read the API] [5].
31
+
32
+ It's really short.
33
+
34
+ [1]: https://secure.travis-ci.org/hakanensari/turnpike.png
35
+ [2]: http://travis-ci.org/hakanensari/turnpike
36
+ [3]: http://f.cl.ly/items/33242X323P3M1t1G400H/turnpike.jpg
37
+ [4]: http://redis.io/topics/data-types
38
+ [5]: https://github.com/hakanensari/turnpike/blob/master/lib/turnpike/queue.rb
data/Rakefile CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'bundler/gem_tasks'
2
-
3
2
  require 'rake/testtask'
4
3
 
5
4
  task :default => :test
@@ -1,137 +1,90 @@
1
1
  module Turnpike
2
+ # A queue.
2
3
  class Queue
3
- The name of the queue.
4
+ # Returns a String name.
4
5
  attr :name
5
6
 
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
7
  # Creates a new queue.
14
8
  #
15
- # Takes an optional name.
16
- def initialize(name = 'default')
9
+ # name - A queue name that responds to to_s.
10
+ def initialize(name = 'queue')
17
11
  @name = "turnpike:#{name}"
18
12
  end
19
13
 
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.
14
+ # Removes all items from the queue.
37
15
  #
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?
16
+ # Returns Integer number of items that were removed.
17
+ def clear
18
+ redis.del name
53
19
  end
54
20
 
55
- # Returns `true` if the queue is empty.
21
+ # Returns whether the queue is empty.
56
22
  def empty?
57
- length == 0
23
+ size == 0
58
24
  end
59
25
 
60
- # Returns the length of the queue.
61
- def length
62
- redis.llen(name)
26
+ # Return an Array of all queued items.
27
+ def peek
28
+ redis.lrange(name, 0, -1).map { |i| Marshal.load i }
63
29
  end
64
30
 
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.
31
+ # Pops one or more items from the front of the queue.
71
32
  #
72
- # Takes an optional timeout argument, wich defaults to 10 seconds.
33
+ # n - Integer number of items to pop.
73
34
  #
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
35
+ # Return a String item, an Array of items, or nil if the queue is empty.
36
+ def pop(n = 1)
37
+ items = []
38
+ n.times do
39
+ break unless item = redis.lpop(name)
40
+ items << Marshal.load(item)
41
+ end
80
42
 
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)
43
+ n == 1 ? items.first : items
91
44
  end
92
45
 
93
- # Retrieves the last queued item.
46
+ # Pushes items to the end of the queue.
94
47
  #
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
48
+ # items - A splat Array of items.
49
+ #
50
+ # Returns the Integer size of the queue after the operation.
51
+ def push(*items)
52
+ if redis_version >= '2.4'
53
+ redis.rpush name, items.map { |i| Marshal.dump i }
101
54
  else
102
- redis.rpop(name)
55
+ items.each { |i| redis.rpush name, Marhsal.dump(i) }
103
56
  end
104
57
  end
105
58
 
106
- # Pushes items to the end of the queue.
107
- def push(*items)
108
- items.each { |item| redis.rpush(name, item) }
109
- end
110
-
59
+ # Syntactic sugar.
111
60
  alias << push
112
61
 
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
62
+ # Returns the Integer size of the queue.
63
+ def size
64
+ redis.llen name
124
65
  end
125
66
 
126
67
  # Pushes items to the front of the queue.
68
+ #
69
+ # items - A splat Array of items.
70
+ #
71
+ # Returns the Integer size of the queue after the operation.
127
72
  def unshift(*items)
128
- items.each { |item| redis.lpush(name, item) }
73
+ if redis_version >= '2.4'
74
+ redis.lpush name, items.map { |i| Marshal.dump i }
75
+ else
76
+ items.each { |i| redis.lpush name, Marhsal.dump(i) }
77
+ end
129
78
  end
130
79
 
131
80
  private
132
81
 
133
82
  def redis
134
- Redis.current ||= Redis.connect(Turnpike.options)
83
+ Redis.current ||= Redis.connect Turnpike.options
135
84
  end
85
+
86
+ def redis_version
87
+ @redis_version ||= redis.info['redis_version']
88
+ end
136
89
  end
137
90
  end
@@ -1,3 +1,3 @@
1
1
  module Turnpike
2
- VERSION = '0.2.0'
2
+ VERSION = '0.3.0'
3
3
  end
data/lib/turnpike.rb CHANGED
@@ -1,25 +1,31 @@
1
+ # External dependency.
1
2
  require 'redis'
3
+
4
+ # Internal dependency.
2
5
  require 'turnpike/queue'
3
- require 'turnpike/observer'
4
6
 
5
- # = Turnpike
6
- #
7
- # A Redis-backed messaging queue.
7
+ # A Redis-backed queue.
8
8
  module Turnpike
9
9
  class << self
10
- # Returns a cached or new queue.
11
- def [](queue)
12
- @queues[queue] ||= Queue.new(queue)
10
+ # Returns a Queue.
11
+ #
12
+ # name - A queue name that responds to to_s.
13
+ def [](name)
14
+ Queue.new name
13
15
  end
14
16
 
15
17
  # Sets Redis connection options.
16
- def connect(options)
17
- @options = options
18
+ #
19
+ # hsh - A Hash of options.
20
+ #
21
+ # Returns nothing.
22
+ def connect(hsh)
23
+ @options = hsh
18
24
  end
19
25
 
20
- # Redis connection options.
21
- attr :options
26
+ # Internal: Returns a Hash of Redis connection options.
27
+ def options
28
+ @options ||= {}
29
+ end
22
30
  end
23
-
24
- @options, @queues = {}, {}
25
31
  end
@@ -1,8 +1,5 @@
1
- require 'rubygems'
2
1
  require 'bundler/setup'
3
-
4
2
  require 'test/unit'
5
-
6
3
  require File.expand_path('../lib/turnpike', File.dirname(__FILE__))
7
4
 
8
5
  class TestTurnpike < Test::Unit::TestCase
@@ -10,150 +7,77 @@ class TestTurnpike < Test::Unit::TestCase
10
7
  Redis.current.flushall
11
8
  end
12
9
 
13
- def time_out_in(queue, seconds, &block)
14
- original_timeout = queue.timeout
15
- queue.timeout = seconds
16
- block.call
17
- queue.timeout = original_timeout
18
- end
19
-
20
- def test_bracket_method
21
- assert_equal('turnpike:foo', Turnpike["foo"].name)
22
- assert(Turnpike['foo'] == Turnpike["foo"])
10
+ def test_bracket
11
+ queue = Turnpike['foo']
12
+ assert_kind_of Turnpike::Queue, queue
13
+ assert_equal 'turnpike:foo', queue.name
23
14
  end
24
15
 
25
16
  def test_emptiness
26
17
  queue = Turnpike::Queue.new
27
- assert(queue.empty?)
28
-
18
+ assert queue.empty?
29
19
  queue << 1
30
- assert(!queue.empty?)
31
-
20
+ assert !queue.empty?
32
21
  queue.clear
33
- assert(queue.empty?)
22
+ assert queue.empty?
34
23
  end
35
24
 
36
- def test_pushing_items
25
+ def test_push
37
26
  queue = Turnpike::Queue.new
38
- queue.push(1)
39
- assert_equal(1, queue.length)
40
-
41
- queue.push(2, 3)
42
- assert_equal(3, queue.length)
43
- assert_equal(['1', '2', '3'], queue.peek(0, 3))
27
+ queue.push 1
28
+ assert_equal 1, queue.size
29
+ queue.push 2, 3
30
+ assert_equal 3, queue.size
31
+ assert_equal [1, 2, 3], queue.peek
44
32
  end
45
33
 
46
- def test_unshifting_items
34
+ def test_unshift
47
35
  queue = Turnpike::Queue.new
48
- queue.unshift(1)
49
- assert_equal(1, queue.length)
50
-
51
- queue.unshift(2, 3)
52
- assert_equal(3, queue.length)
53
- assert_equal(['3', '2', '1'], queue.peek(0, 3))
36
+ queue.unshift 1
37
+ assert_equal 1, queue.size
38
+ queue.unshift 2, 3
39
+ assert_equal 3, queue.size
40
+ assert_equal [3, 2, 1], queue.peek
54
41
  end
55
42
 
56
- def test_popping_items
43
+ def test_pop
57
44
  queue = Turnpike::Queue.new
58
- queue.push(1, 2)
59
- assert_equal('2', queue.pop)
60
- assert_equal('1', queue.pop)
61
- assert_equal(nil, queue.pop)
45
+ queue.push 1, 2
46
+ assert_equal 1, queue.pop
47
+ assert_equal 2, queue.pop
48
+ assert_equal nil, queue.pop
62
49
  end
63
50
 
64
- def test_shifting_items
51
+ def test_pop_many
65
52
  queue = Turnpike::Queue.new
66
- queue.push(1, 2)
67
- assert_equal('1', queue.shift)
68
- assert_equal('2', queue.shift)
69
- assert_equal(nil, queue.shift)
53
+ queue.push 1, 2, 3
54
+ assert_equal [1, 2], queue.pop(2)
55
+ assert_equal [3], queue.pop(2)
56
+ assert_equal [], queue.pop(2)
70
57
  end
71
58
 
72
- def test_enumeration
59
+ def test_order
73
60
  queue = Turnpike::Queue.new
74
- queue.push(1, 2)
75
- items = []
76
- queue.each { |item| items << item }
77
- assert_equal(['1', '2'], items)
78
-
79
- queue.push(1, 2, 3, 4)
80
- slices = []
81
- queue.each_slice(3) { |slice| slices << slice }
82
- assert_equal([['1', '2', '3'], ['4']], slices)
83
-
84
- queue.push(1, 2)
85
- slices = []
86
- queue.each_slice(2) { |slice| slices << slice }
87
- assert_equal([['1', '2']], slices)
88
- end
89
-
90
- def test_aliases
91
- queue = Turnpike::Queue.new
92
- queue << 1
93
- assert_equal(1, queue.size)
61
+ queue.push 1, 2
62
+ queue.unshift 3
63
+ assert_equal 3, queue.pop
64
+ assert_equal 1, queue.pop
65
+ assert_equal 2, queue.pop
94
66
  end
95
67
 
96
68
  def test_multiple_queues
97
- queue1 = Turnpike::Queue.new("foo")
98
- queue2 = Turnpike::Queue.new("bar")
99
-
100
- queue1.push(1)
101
- queue2.push(2, 3)
102
-
103
- assert_equal(1, queue1.length)
104
- assert_equal(2, queue2.length)
105
- end
106
-
107
- def test_blocking_pop
108
- queue = Turnpike::Queue.new
109
- started_at = Time.now.to_i
110
- Thread.new do
111
- sleep(1)
112
- queue.push(1)
113
- end
114
- assert_equal(0, queue.length)
115
- assert_equal('1', queue.pop(true))
116
- assert(Time.now.to_i - started_at > 0)
117
- end
118
-
119
- def test_blocking_shift
120
- queue = Turnpike::Queue.new
121
- started_at = Time.now.to_i
122
- Thread.new do
123
- sleep(1)
124
- queue.push(1)
125
- end
126
- assert_equal(0, queue.length)
127
- assert_equal('1', queue.shift(true))
128
- assert(Time.now.to_i - started_at > 0)
69
+ queue1 = Turnpike::Queue.new 'foo'
70
+ queue2 = Turnpike::Queue.new 'bar'
71
+ queue1.push 1
72
+ queue2.push 2, 3
73
+ assert_equal 1, queue1.size
74
+ assert_equal 2, queue2.size
129
75
  end
130
76
 
131
- def test_timeout
77
+ def test_peek
132
78
  queue = Turnpike::Queue.new
133
- time_out_in queue, 1 do
134
- thread = Thread.new do
135
- sleep(2)
136
- queue.push(1)
137
- end
138
- assert_equal(0, queue.length)
139
- assert_equal(nil, queue.shift(true))
140
-
141
- thread.join
142
- assert_equal(1, queue.length)
143
- end
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)
79
+ assert_equal [], queue.peek
80
+ queue << 1
81
+ assert_equal [1], queue.peek
158
82
  end
159
83
  end
data/turnpike.gemspec CHANGED
@@ -1,31 +1,21 @@
1
1
  # -*- encoding: utf-8 -*-
2
- require "./lib/turnpike/version"
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'turnpike/version'
3
4
 
4
5
  Gem::Specification.new do |s|
5
- s.name = "turnpike"
6
+ s.name = 'turnpike'
6
7
  s.version = Turnpike::VERSION
7
- s.authors = ["Paper Cavalier"]
8
- s.email = ["code@papercavalier.com"]
9
- s.homepage = "http://code.papercavalier.com/turnpike"
10
- s.summary = %q{A Redis-backed messaging queue}
11
- s.description = %q{Turnpike is a Redis-backed messaging queue.}
12
-
13
- s.rubyforge_project = "turnpike"
8
+ s.authors = ['Hakan Ensari']
9
+ s.email = ['hakan.ensari@papercavalier.com']
10
+ s.homepage = 'http://github.com/hakanensari/turnpike'
11
+ s.summary = %q{A Redis-backed queue}
12
+ s.description = %q{Turnpike is a Redis-backed queue.}
14
13
 
15
14
  s.files = `git ls-files`.split("\n")
16
15
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
16
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
- s.require_paths = ["lib"]
19
-
20
- {
21
- 'redis' => '~> 2.2'
22
- }.each do |lib, version|
23
- s.add_runtime_dependency lib, version
24
- end
17
+ s.require_paths = ['lib']
25
18
 
26
- {
27
- 'rake' => '~> 0.9'
28
- }.each do |lib, version|
29
- s.add_development_dependency lib, version
30
- end
19
+ s.add_runtime_dependency 'redis', '~> 3.0.0.rc1'
20
+ s.add_development_dependency 'rake', '~> 0.9'
31
21
  end
metadata CHANGED
@@ -1,30 +1,30 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: turnpike
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
8
- - Paper Cavalier
8
+ - Hakan Ensari
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-08-14 00:00:00.000000000Z
12
+ date: 2012-04-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: redis
16
- requirement: &70335673360420 !ruby/object:Gem::Requirement
16
+ requirement: &70125674238280 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
20
20
  - !ruby/object:Gem::Version
21
- version: '2.2'
21
+ version: 3.0.0.rc1
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70335673360420
24
+ version_requirements: *70125674238280
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rake
27
- requirement: &70335673359520 !ruby/object:Gem::Requirement
27
+ requirement: &70125674237780 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,27 +32,25 @@ dependencies:
32
32
  version: '0.9'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70335673359520
36
- description: Turnpike is a Redis-backed messaging queue.
35
+ version_requirements: *70125674237780
36
+ description: Turnpike is a Redis-backed queue.
37
37
  email:
38
- - code@papercavalier.com
38
+ - hakan.ensari@papercavalier.com
39
39
  executables: []
40
40
  extensions: []
41
41
  extra_rdoc_files: []
42
42
  files:
43
43
  - .gitignore
44
44
  - .travis.yml
45
- - CHANGELOG.md
46
45
  - Gemfile
47
46
  - README.md
48
47
  - Rakefile
49
48
  - lib/turnpike.rb
50
- - lib/turnpike/observer.rb
51
49
  - lib/turnpike/queue.rb
52
50
  - lib/turnpike/version.rb
53
51
  - test/turnpike_test.rb
54
52
  - turnpike.gemspec
55
- homepage: http://code.papercavalier.com/turnpike
53
+ homepage: http://github.com/hakanensari/turnpike
56
54
  licenses: []
57
55
  post_install_message:
58
56
  rdoc_options: []
@@ -64,23 +62,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
64
62
  - - ! '>='
65
63
  - !ruby/object:Gem::Version
66
64
  version: '0'
67
- segments:
68
- - 0
69
- hash: 318226748875005980
70
65
  required_rubygems_version: !ruby/object:Gem::Requirement
71
66
  none: false
72
67
  requirements:
73
68
  - - ! '>='
74
69
  - !ruby/object:Gem::Version
75
70
  version: '0'
76
- segments:
77
- - 0
78
- hash: 318226748875005980
79
71
  requirements: []
80
- rubyforge_project: turnpike
81
- rubygems_version: 1.8.6
72
+ rubyforge_project:
73
+ rubygems_version: 1.8.11
82
74
  signing_key:
83
75
  specification_version: 3
84
- summary: A Redis-backed messaging queue
76
+ summary: A Redis-backed queue
85
77
  test_files:
86
78
  - test/turnpike_test.rb
data/CHANGELOG.md DELETED
@@ -1,9 +0,0 @@
1
- # CHANGELOG
2
-
3
- ## 0.2.0/2011-08-14
4
-
5
- * implement observer
6
-
7
- ## 0.1.0/2011-07-18
8
-
9
- * first release
@@ -1,43 +0,0 @@
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