turnpike 0.2.0 → 0.3.0

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