simple_queues 1.0.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/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ doc/*
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in simple_queues.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008-2009 François Beausoleil (francois@teksol.info)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ 'Software'), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,60 @@
1
+ h1. SimpleQueues
2
+
3
+ In the Gang of Four books, one of the first few lines is "Program to an interface, not an implementation." When you need a queue, the only operations you need are enqueue and dequeue. It doesn't matter that Redis (a nice and simple queue server when you need it) has all kinds of operations available.
4
+
5
+ This library was written and spec'd on Ruby 1.9.2. It's so small it should work anywhere the Redis gem works.
6
+
7
+ h2. Exceptions
8
+
9
+ All underlying exceptions the Redis gem raises are let through: no extra exceptions are raised. This means you'll see <code>Errno::ECONNREFUSED</code>, <code>Errno::EAGAIN</code> and friends.
10
+
11
+ h2. Usage
12
+
13
+ <pre><code>require "simple_queues"
14
+ Queues = SimpleQueues::Redis.new
15
+
16
+ Queues.enqueue :pages_to_crawl, {:url => "http://blog.teksol.info"}.to_json
17
+ Queues.enqueue :pages_to_crawl, {:url => "http://techcrunch.com"}.to_json
18
+
19
+ # In another process
20
+
21
+ loop do
22
+ message = Queues.dequeue_blocking :pages_to_crawl
23
+ process(message)
24
+ end
25
+
26
+ # Alternatively, using a timeout
27
+ loop do
28
+ message = Queues.dequeue_with_timeout :pages_to_crawl, 5 # seconds
29
+ if message then
30
+ process(message)
31
+ else
32
+ # Timed out
33
+ end
34
+ end
35
+ <code></pre>
36
+
37
+ h2. LICENSE
38
+
39
+ (The MIT License)
40
+
41
+ Copyright (c) 2008-2009 François Beausoleil (francois@teksol.info)
42
+
43
+ Permission is hereby granted, free of charge, to any person obtaining
44
+ a copy of this software and associated documentation files (the
45
+ 'Software'), to deal in the Software without restriction, including
46
+ without limitation the rights to use, copy, modify, merge, publish,
47
+ distribute, sublicense, and/or sell copies of the Software, and to
48
+ permit persons to whom the Software is furnished to do so, subject to
49
+ the following conditions:
50
+
51
+ The above copyright notice and this permission notice shall be
52
+ included in all copies or substantial portions of the Software.
53
+
54
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
55
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
56
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
57
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
58
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
59
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
60
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ begin
5
+ require "rspec/core/rake_task"
6
+ RSpec::Core::RakeTask.new
7
+
8
+ task :default => :spec
9
+ rescue LoadError
10
+ warn "RSpec not available - Rake tasks not available"
11
+ warn "Install rspec using: gem install rspec"
12
+ end
13
+
14
+ begin
15
+ require "yard"
16
+ YARD::Rake::YardocTask.new(:doc)
17
+ rescue LoadError
18
+ warn "YARD not available - gem install yard"
19
+ end
@@ -0,0 +1 @@
1
+ Autotest.add_discovery { "rspec2" }
@@ -0,0 +1,44 @@
1
+ module SimpleQueues
2
+ # The Redis version of SimpleQueues.
3
+ #
4
+ # Messages are enqueued to the right, dequeued from the left - thus the most recent messages are at the end of the list.
5
+ class Redis
6
+ def initialize(redis=Redis.new)
7
+ @redis = redis
8
+ end
9
+
10
+ # Enqueues a new message to the Redis backend.
11
+ #
12
+ # @param queue_name [String, Symbol] The queue name, which must not be nil or the empty String.
13
+ # @param message [#to_s] The message to be enqueued. The message will be turned into a String through #to_s before being enqueued. Must not be nil, but the empty string is accepted, although it seems meaningless to do so.
14
+ # @return No useful value.
15
+ # @raise ArgumentError Whenever the queue name or the message are nil, or the queue name is empty.
16
+ def enqueue(queue_name, message)
17
+ raise ArgumentError, "Queue name argument was nil - must not be" if queue_name.nil? || queue_name.to_s.empty?
18
+ raise ArgumentError, "Message argument was nil - must not be" if message.nil?
19
+
20
+ @redis.rpush(queue_name.to_s, message.to_s)
21
+ end
22
+
23
+ # Dequeues a message, and waits forever for one to arrive.
24
+ #
25
+ # @param queue_name [String, Symbol] The queue name to read from.
26
+ # @return [String] The first message in the queue.
27
+ # @raise ArgumentError If +queue_name+ is nil or the empty String.
28
+ def dequeue_blocking(queue_name)
29
+ dequeue_with_timeout(queue_name, 0)
30
+ end
31
+
32
+ # Dequeues a message, or returns +nil+ if the timeout is exceeded.
33
+ #
34
+ # @param queue_name [String, Symbol] The queue name to read from.
35
+ # @param timeout [#to_i] The number of seconds to wait before returning nil.
36
+ # @return [String, nil] The first message in the queue, or nil if the timeout was exceeded.
37
+ # @raise ArgumentError If +queue_name+ is nil or the empty String.
38
+ def dequeue_with_timeout(queue_name, timeout)
39
+ raise ArgumentError, "Queue name argument was nil - must not be" if queue_name.nil? || queue_name.to_s.empty?
40
+
41
+ @redis.blpop(queue_name.to_s, timeout)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,3 @@
1
+ module SimpleQueues
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,14 @@
1
+ # A simple API for queueing and dequeueing messages.
2
+ #
3
+ # In the Gang of Four book, the phrase "Program to an interface, not an implementation" made me think I shouldn't
4
+ # bind my software directly to Redis, but to an API from which I could change the implementation at any time. If
5
+ # I ever need to replace Redis with RabbitMQ, it will be possible to do so, given my software is coded to this
6
+ # interface.
7
+ #
8
+ # All SimpleQueues implementations support three methods:
9
+ # * +enqueue+
10
+ # * +dequeue_with_timeout+
11
+ # * +dequeue_blocking+
12
+ module SimpleQueues
13
+ autoload :Redis, "simple_queues/redis"
14
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "simple_queues/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "simple_queues"
7
+ s.version = SimpleQueues::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["François Beausoleil"]
10
+ s.email = ["francois@teksol.info"]
11
+ s.homepage = "https://github.com/francois/simple_queues"
12
+ s.summary = %q{Simple enqueue/dequeue API for working with queues}
13
+ s.description = %q{Program to an interface, not an implementation - hides Redis (used as a queue) behind a simple interface}
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_dependency 'redis'
21
+ s.add_development_dependency 'rspec'
22
+ s.add_development_dependency 'yard'
23
+ s.add_development_dependency 'RedCloth'
24
+ end
@@ -0,0 +1,51 @@
1
+ require "spec_helper"
2
+
3
+ describe SimpleQueues::Redis, "dequeue_blocking" do
4
+ let :redis do
5
+ double("redis")
6
+ end
7
+
8
+ let :queue do
9
+ SimpleQueues::Redis.new(redis)
10
+ end
11
+
12
+ it "requests an infinite timeout from Redis #blpop" do
13
+ redis.should_receive(:blpop).with("pages_to_crawl", 0)
14
+ queue.dequeue_blocking("pages_to_crawl")
15
+ end
16
+
17
+ it "accepts symbols as queue names and translates them to strings" do
18
+ redis.should_receive(:blpop).with("pages_to_crawl", 0)
19
+ queue.dequeue_blocking(:pages_to_crawl)
20
+ end
21
+
22
+ it "raises an ArgumentError when the queue name is nil or empty" do
23
+ lambda { queue.dequeue_blocking(nil) }.should raise_error(ArgumentError)
24
+ lambda { queue.dequeue_blocking("") }.should raise_error(ArgumentError)
25
+ end
26
+ end
27
+
28
+ describe SimpleQueues::Redis, "dequeue_with_timeout" do
29
+ let :redis do
30
+ double("redis")
31
+ end
32
+
33
+ let :queue do
34
+ SimpleQueues::Redis.new(redis)
35
+ end
36
+
37
+ it "should call Redis' BLPOP with the requested timeout" do
38
+ redis.should_receive(:blpop).with("pages_to_crawl", 42)
39
+ queue.dequeue_with_timeout(:pages_to_crawl, 42)
40
+ end
41
+
42
+ it "accepts symbols as queue names and translates them to strings" do
43
+ redis.should_receive(:blpop).with("pages_to_crawl", 5)
44
+ queue.dequeue_with_timeout(:pages_to_crawl, 5)
45
+ end
46
+
47
+ it "raises an ArgumentError when the queue name is nil or empty" do
48
+ lambda { queue.dequeue_with_timeout(nil) }.should raise_error(ArgumentError)
49
+ lambda { queue.dequeue_with_timeout("") }.should raise_error(ArgumentError)
50
+ end
51
+ end
@@ -0,0 +1,40 @@
1
+ require "spec_helper"
2
+
3
+ describe SimpleQueues::Redis, "enqueue" do
4
+ let :redis do
5
+ double("redis")
6
+ end
7
+
8
+ let :queue do
9
+ SimpleQueues::Redis.new(redis)
10
+ end
11
+
12
+ it "should enqueue to the end of the list" do
13
+ redis.should_receive(:rpush).with("q", "message")
14
+ queue.enqueue("q", "message")
15
+ end
16
+
17
+ it "should reject invalid queue names" do
18
+ lambda { queue.enqueue(nil, "") }.should raise_error(ArgumentError)
19
+ lambda { queue.enqueue("", "") }.should raise_error(ArgumentError)
20
+ end
21
+
22
+ it "should reject nil messages" do
23
+ lambda { queue.enqueue(:a, nil) }.should raise_error(ArgumentError)
24
+ end
25
+
26
+ it "should allow blank messages (although does this make sense?)" do
27
+ redis.should_receive(:rpush)
28
+ lambda { queue.enqueue(:a, "") }.should_not raise_error
29
+ end
30
+
31
+ it "accepts symbols as queue names, translating to a string" do
32
+ redis.should_receive(:rpush).with("pages_to_crawl", "http://blog.teksol.info/")
33
+ queue.enqueue :pages_to_crawl, "http://blog.teksol.info/"
34
+ end
35
+
36
+ it "translates the message to a String before enqueueing" do
37
+ redis.should_receive(:rpush).with("ops", "shutdown_and_destroy")
38
+ queue.enqueue :ops, :shutdown_and_destroy
39
+ end
40
+ end
@@ -0,0 +1 @@
1
+ require "simple_queues"
metadata ADDED
@@ -0,0 +1,131 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple_queues
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 0
9
+ version: 1.0.0
10
+ platform: ruby
11
+ authors:
12
+ - "Fran\xC3\xA7ois Beausoleil"
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-02-26 00:00:00 -05:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: redis
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: rspec
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ version: "0"
44
+ type: :development
45
+ version_requirements: *id002
46
+ - !ruby/object:Gem::Dependency
47
+ name: yard
48
+ prerelease: false
49
+ requirement: &id003 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ segments:
55
+ - 0
56
+ version: "0"
57
+ type: :development
58
+ version_requirements: *id003
59
+ - !ruby/object:Gem::Dependency
60
+ name: RedCloth
61
+ prerelease: false
62
+ requirement: &id004 !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ type: :development
71
+ version_requirements: *id004
72
+ description: Program to an interface, not an implementation - hides Redis (used as a queue) behind a simple interface
73
+ email:
74
+ - francois@teksol.info
75
+ executables: []
76
+
77
+ extensions: []
78
+
79
+ extra_rdoc_files: []
80
+
81
+ files:
82
+ - .gitignore
83
+ - .rvmrc
84
+ - Gemfile
85
+ - LICENSE
86
+ - README.textile
87
+ - Rakefile
88
+ - autotest/discover.rb
89
+ - lib/simple_queues.rb
90
+ - lib/simple_queues/redis.rb
91
+ - lib/simple_queues/version.rb
92
+ - simple_queues.gemspec
93
+ - spec/dequeueing_spec.rb
94
+ - spec/enqueueing_spec.rb
95
+ - spec/spec_helper.rb
96
+ has_rdoc: true
97
+ homepage: https://github.com/francois/simple_queues
98
+ licenses: []
99
+
100
+ post_install_message:
101
+ rdoc_options: []
102
+
103
+ require_paths:
104
+ - lib
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ segments:
111
+ - 0
112
+ version: "0"
113
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ segments:
119
+ - 0
120
+ version: "0"
121
+ requirements: []
122
+
123
+ rubyforge_project:
124
+ rubygems_version: 1.3.7
125
+ signing_key:
126
+ specification_version: 3
127
+ summary: Simple enqueue/dequeue API for working with queues
128
+ test_files:
129
+ - spec/dequeueing_spec.rb
130
+ - spec/enqueueing_spec.rb
131
+ - spec/spec_helper.rb