bunny_hair 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/Guardfile +9 -0
- data/LICENSE.txt +9 -0
- data/README.md +91 -0
- data/Rakefile +1 -0
- data/bunny_hair.gemspec +26 -0
- data/lib/bunny_hair/channel.rb +29 -0
- data/lib/bunny_hair/connection.rb +25 -0
- data/lib/bunny_hair/consumer.rb +33 -0
- data/lib/bunny_hair/exchange.rb +39 -0
- data/lib/bunny_hair/queue.rb +56 -0
- data/lib/bunny_hair/version.rb +3 -0
- data/lib/bunny_hair.rb +13 -0
- data/spec/lib/bunny_hair/channel_spec.rb +61 -0
- data/spec/lib/bunny_hair/connection_spec.rb +37 -0
- data/spec/lib/bunny_hair/consumer_spec.rb +16 -0
- data/spec/lib/bunny_hair/exchange_spec.rb +59 -0
- data/spec/lib/bunny_hair/queue_spec.rb +105 -0
- data/spec/lib/bunny_hair_spec.rb +10 -0
- data/spec/spec_helper.rb +21 -0
- metadata +143 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c14e6ea05db60ca10bdfe42bfb32c779598a1966
|
4
|
+
data.tar.gz: 80ba433d1b1619d9774aaf5606dfea4a3e731e9a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9963a9760f1506d294eb44774b9fc92b72791b8e229bb48d0a79b45d97e18ed9b3b1fdeb06b877799a7a03d7e11d60ac498fc3c8833d51a4ef9249b938f09e31
|
7
|
+
data.tar.gz: d8d449cb1abb2f319eab3a13d3d722e0eaf6721e11cd656446d0ec591b6f4f971647023c99074aceeac9df61902ec6700cab7fb84dd3f17113dbf319df69b779
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2012 Thunderbolt Labs LLC
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
6
|
+
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
8
|
+
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
# BunnyHair
|
2
|
+
|
3
|
+
This mock of Bunny is **NOT** complete. It includes common interfaces but does not encompass everything.
|
4
|
+
|
5
|
+
Basically it covers:
|
6
|
+
|
7
|
+
* Make a channel
|
8
|
+
* Make an exchange
|
9
|
+
* Make a queue
|
10
|
+
* Bind that queue to the exchange
|
11
|
+
* Subscribe to that queue with a block
|
12
|
+
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Add this line to your application's Gemfile:
|
17
|
+
|
18
|
+
gem 'bunny_hair'
|
19
|
+
|
20
|
+
And then execute:
|
21
|
+
|
22
|
+
$ bundle
|
23
|
+
|
24
|
+
Or install it yourself as:
|
25
|
+
|
26
|
+
$ gem install bunny_hair
|
27
|
+
|
28
|
+
## Usage
|
29
|
+
|
30
|
+
To get a great idea of what is actually possible with this gem, take a gander at the [specs](spec/).
|
31
|
+
|
32
|
+
### Connections
|
33
|
+
|
34
|
+
Typically you'll create a connection in Bunny by simply calling `Bunny.new`, this gem is essentially no different.
|
35
|
+
|
36
|
+
BunnyHair.new # => BunnyHair::Connection.new
|
37
|
+
|
38
|
+
You can assume that this object will respond to the methods you actually care about, such as `#start` and `#create_channel`
|
39
|
+
|
40
|
+
### Queues
|
41
|
+
|
42
|
+
When using queues all publishing will happen immediately. For example...
|
43
|
+
|
44
|
+
connection = BunnyHair.new
|
45
|
+
channel = connection.create_channel
|
46
|
+
|
47
|
+
queue = channel.queue('my.queue')
|
48
|
+
|
49
|
+
queue.subscribe do |info, metadata, payload|
|
50
|
+
puts payload
|
51
|
+
end
|
52
|
+
|
53
|
+
queue.publish('Your payload')
|
54
|
+
|
55
|
+
### Exchanges
|
56
|
+
|
57
|
+
This gem also supports the creation / usage of exchanges. You can use them normally like you would in Bunny itself.
|
58
|
+
|
59
|
+
channel = connection.create_channel
|
60
|
+
topic_exchange = channel.topic('activity.events')
|
61
|
+
|
62
|
+
queue = channel.queue('my.queue', auto_delete: true)
|
63
|
+
|
64
|
+
queue.subscribe do |info, metadata, payload|
|
65
|
+
puts payload
|
66
|
+
end
|
67
|
+
|
68
|
+
queue.bind(topic_exchange, routing_key: 'activity.events')
|
69
|
+
|
70
|
+
topic_exchange.publish('hello', routing_key: 'activity.events')
|
71
|
+
|
72
|
+
$ => hello
|
73
|
+
|
74
|
+
### A note about exchanges
|
75
|
+
|
76
|
+
Exchanges in this gem do NOT follow the logic in a normal rabbitmq exchange. For example, you may have a queue with a routing_key set to `activity.#`
|
77
|
+
If you bind that queue to the exchange, it will not matter what you publish on that exchange, the queue object **WILL** receive it.
|
78
|
+
If you'd like to see this gem encorporate the logic of the separate exchange types, make a PR =)
|
79
|
+
|
80
|
+
|
81
|
+
## Contributing
|
82
|
+
|
83
|
+
1. Fork it
|
84
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
85
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
86
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
87
|
+
5. Create new Pull Request
|
88
|
+
|
89
|
+
# Copyright
|
90
|
+
|
91
|
+
See license.txt for details
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bunny_hair.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'bunny_hair/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "bunny_hair"
|
8
|
+
spec.version = BunnyHair::VERSION
|
9
|
+
spec.authors = ["Robert Ross"]
|
10
|
+
spec.email = ["roberto@thunderboltlabs.com"]
|
11
|
+
spec.description = %q{A simple replacement for Bunny}
|
12
|
+
spec.summary = %q{Use this gem as a replacement for Bunny to do in-memory operations}
|
13
|
+
spec.homepage = "https://github.com/thunderboltlabs/bunny_hair"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "guard-rspec", "~> 3.0.0"
|
23
|
+
spec.add_development_dependency "pry", "~> 0.9.12.2"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
spec.add_development_dependency "rspec", "~> 2.14.1"
|
26
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module BunnyHair
|
2
|
+
class Channel
|
3
|
+
attr_reader :connection
|
4
|
+
|
5
|
+
def initialize(connection=BunnyHair.new)
|
6
|
+
@connection = connection
|
7
|
+
end
|
8
|
+
|
9
|
+
def queue(name, options={})
|
10
|
+
Queue.new(name, options)
|
11
|
+
end
|
12
|
+
|
13
|
+
def topic(name, options={})
|
14
|
+
Exchange.new(connection, :topic, name, options)
|
15
|
+
end
|
16
|
+
|
17
|
+
def fanout(name, options={})
|
18
|
+
Exchange.new(connection, :fanout, name, options)
|
19
|
+
end
|
20
|
+
|
21
|
+
def direct(name, options={})
|
22
|
+
Exchange.new(connection, :direct, name, options)
|
23
|
+
end
|
24
|
+
|
25
|
+
def ack(*args)
|
26
|
+
end
|
27
|
+
alias acknowledge ack
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module BunnyHair
|
2
|
+
class Connection
|
3
|
+
attr_accessor :connected
|
4
|
+
|
5
|
+
def connected?
|
6
|
+
!!connected
|
7
|
+
end
|
8
|
+
|
9
|
+
def start
|
10
|
+
self.connected = true
|
11
|
+
end
|
12
|
+
|
13
|
+
def stop
|
14
|
+
self.connected = false
|
15
|
+
end
|
16
|
+
|
17
|
+
def create_channel
|
18
|
+
Channel.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def default_channel
|
22
|
+
@channel ||= Channel.new
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module BunnyHair
|
2
|
+
class Consumer
|
3
|
+
|
4
|
+
# This interface has been stolen from Bunny itself
|
5
|
+
# https://github.com/ruby-amqp/bunny/blob/master/lib/bunny/consumer.rb
|
6
|
+
# specific commit: https://github.com/ruby-amqp/bunny/blob/f7844397ffcb1ef8b7a377c59335a154a6adfc26/lib/bunny/consumer.rb
|
7
|
+
attr_reader :queue
|
8
|
+
attr_accessor :consumer_tag
|
9
|
+
attr_reader :arguments
|
10
|
+
attr_reader :no_ack
|
11
|
+
attr_reader :exclusive
|
12
|
+
|
13
|
+
def initialize(queue)
|
14
|
+
@queue = queue || raise(ArgumentError, "queue is nil")
|
15
|
+
|
16
|
+
self.queue.consumers << self
|
17
|
+
end
|
18
|
+
|
19
|
+
def on_delivery(&block)
|
20
|
+
@on_delivery = block
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def cancel
|
25
|
+
queue.consumers.delete(self)
|
26
|
+
end
|
27
|
+
|
28
|
+
def call(*args)
|
29
|
+
@on_delivery.call(*args) if @on_delivery
|
30
|
+
end
|
31
|
+
alias handle_delivery call
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module BunnyHair
|
4
|
+
class Exchange
|
5
|
+
attr_reader :name, :options, :connection, :type
|
6
|
+
|
7
|
+
def initialize(connection, type, name, options={})
|
8
|
+
@connection = connection
|
9
|
+
@name = name
|
10
|
+
@type = type
|
11
|
+
@options = options
|
12
|
+
end
|
13
|
+
|
14
|
+
def queues
|
15
|
+
@queues ||= []
|
16
|
+
end
|
17
|
+
|
18
|
+
def channel
|
19
|
+
Channel.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def publish(message, options={})
|
23
|
+
queues.each do |queue|
|
24
|
+
queue.receive(OpenStruct.new, OpenStruct.new, message)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def method_missing(method, *args)
|
29
|
+
method_name = method.to_s
|
30
|
+
is_predicate = false
|
31
|
+
|
32
|
+
if method_name =~ /^(.*)\?$/
|
33
|
+
return !!options[method_name.gsub('?', '').to_sym]
|
34
|
+
end
|
35
|
+
|
36
|
+
super
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module BunnyHair
|
2
|
+
class Queue
|
3
|
+
attr_reader :name, :options, :message_count, :exchange, :messages
|
4
|
+
|
5
|
+
def initialize(name, options={})
|
6
|
+
@name = name
|
7
|
+
@options = options
|
8
|
+
@message_count = 0
|
9
|
+
@messages ||= []
|
10
|
+
end
|
11
|
+
|
12
|
+
def consumers
|
13
|
+
@consumers ||= []
|
14
|
+
end
|
15
|
+
|
16
|
+
def bind(exchange, options={})
|
17
|
+
@exchange = exchange
|
18
|
+
exchange.queues << self
|
19
|
+
end
|
20
|
+
|
21
|
+
def delete
|
22
|
+
@exchange.queues.delete_if { |q| q.name == name }
|
23
|
+
end
|
24
|
+
|
25
|
+
def pop
|
26
|
+
@messages.pop
|
27
|
+
end
|
28
|
+
|
29
|
+
def subscribe(opts = {}, &block)
|
30
|
+
consumer = Consumer.new(self)
|
31
|
+
consumer.on_delivery(&block)
|
32
|
+
|
33
|
+
consumer
|
34
|
+
end
|
35
|
+
|
36
|
+
def receive(metadata, info, payload)
|
37
|
+
metadata ||= OpenStruct.new
|
38
|
+
info ||= OpenStruct.new
|
39
|
+
|
40
|
+
@messages << [metadata, info, payload]
|
41
|
+
@message_count += 1
|
42
|
+
|
43
|
+
consumers.each do |subscription|
|
44
|
+
subscription.call(info, metadata, payload)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def publish(payload)
|
49
|
+
receive(nil, nil, payload)
|
50
|
+
end
|
51
|
+
|
52
|
+
def auto_delete?
|
53
|
+
!!options[:auto_delete]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/bunny_hair.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require "bunny_hair/version"
|
2
|
+
|
3
|
+
module BunnyHair
|
4
|
+
autoload :Connection, 'bunny_hair/connection'
|
5
|
+
autoload :Exchange, 'bunny_hair/exchange'
|
6
|
+
autoload :Channel, 'bunny_hair/channel'
|
7
|
+
autoload :Queue, 'bunny_hair/queue'
|
8
|
+
autoload :Consumer, 'bunny_hair/consumer'
|
9
|
+
|
10
|
+
def self.new(*)
|
11
|
+
Connection.new
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe BunnyHair::Channel do
|
4
|
+
subject(:channel) { BunnyHair::Channel.new }
|
5
|
+
let(:connection) { BunnyHair.new }
|
6
|
+
|
7
|
+
describe '#initialize' do
|
8
|
+
it 'accepts a connection' do
|
9
|
+
instance = described_class.new(connection)
|
10
|
+
expect(instance.connection).to be(connection)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#queue' do
|
15
|
+
it 'returns a queue' do
|
16
|
+
expect(channel.queue('queue')).to be_kind_of(BunnyHair::Queue)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'returns a queue with a name' do
|
20
|
+
queue = channel.queue('my name')
|
21
|
+
expect(queue.name).to eq('my name')
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'returns a queue with the options set' do
|
25
|
+
options = { auto_delete: true }
|
26
|
+
queue = channel.queue('queue', options)
|
27
|
+
expect(queue.options).to eq(options)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#topic' do
|
32
|
+
it 'returns a topic exchange' do
|
33
|
+
exchange = channel.topic('my.topic.exchange', durable: true)
|
34
|
+
expect(exchange.name).to eq('my.topic.exchange')
|
35
|
+
expect(exchange.type).to be(:topic)
|
36
|
+
expect(exchange).to be_durable
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#fanout' do
|
41
|
+
it 'returns a fanout exchange' do
|
42
|
+
exchange = channel.fanout('my.fanout.exchange', durable: true)
|
43
|
+
expect(exchange.name).to eq('my.fanout.exchange')
|
44
|
+
expect(exchange.type).to be(:fanout)
|
45
|
+
expect(exchange).to be_durable
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#direct' do
|
50
|
+
it 'returns a direct exchange' do
|
51
|
+
exchange = channel.direct('my.direct.exchange', durable: true)
|
52
|
+
expect(exchange.name).to eq('my.direct.exchange')
|
53
|
+
expect(exchange.type).to be(:direct)
|
54
|
+
expect(exchange).to be_durable
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '#ack' do
|
59
|
+
it { should respond_to :ack }
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe BunnyHair::Connection do
|
4
|
+
subject(:connection) { BunnyHair::Connection.new }
|
5
|
+
|
6
|
+
describe '#connected?' do
|
7
|
+
it 'returns true when start is called' do
|
8
|
+
connection.start
|
9
|
+
expect(connection).to be_connected
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'returns false when started and stopped' do
|
13
|
+
connection.start
|
14
|
+
connection.stop
|
15
|
+
|
16
|
+
expect(connection).to_not be_connected
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'returns false when never stopped' do
|
20
|
+
expect(connection).to_not be_connected
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#create_channel' do
|
25
|
+
it 'returns a channel' do
|
26
|
+
expect(connection.create_channel).to be_kind_of BunnyHair::Channel
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#default_channel' do
|
31
|
+
it 'returns a single channel' do
|
32
|
+
expect(connection.default_channel).to be_kind_of BunnyHair::Channel
|
33
|
+
object_1, object_2 = connection.default_channel, connection.default_channel
|
34
|
+
expect(object_1).to eq object_2
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe BunnyHair::Consumer do
|
4
|
+
describe '#cancel' do
|
5
|
+
let(:queue) { BunnyHair::Queue.new('queue.name') }
|
6
|
+
subject(:consumer) { BunnyHair::Consumer.new(queue) }
|
7
|
+
|
8
|
+
it 'removes itself from the queues list of consumers' do
|
9
|
+
queue.consumers << consumer
|
10
|
+
|
11
|
+
consumer.cancel
|
12
|
+
|
13
|
+
expect(queue.consumers).to_not include(consumer)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe BunnyHair::Exchange do
|
4
|
+
subject(:exchange) { BunnyHair::Exchange.new(connection, :topic, 'my.exchange', durable: true) }
|
5
|
+
let(:connection) { BunnyHair.new }
|
6
|
+
|
7
|
+
describe '#initialize' do
|
8
|
+
subject(:exchange) { BunnyHair::Exchange.new(connection, :direct, 'chickens', durable: true) }
|
9
|
+
|
10
|
+
it 'accepts a connection' do
|
11
|
+
expect { exchange }.to_not \
|
12
|
+
raise_exception
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'accepts a type' do
|
16
|
+
expect(exchange.type).to be(:direct)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'accepts a name' do
|
20
|
+
expect(exchange.name).to eq('chickens')
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'accepts options' do
|
24
|
+
expect(exchange.options).to eq(durable: true)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#queues' do
|
29
|
+
it 'returns an array' do
|
30
|
+
expect(exchange.queues).to be_kind_of Array
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'returns a memoized array' do
|
34
|
+
original = exchange.queues
|
35
|
+
expect(original).to be(exchange.queues)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#channel' do
|
40
|
+
it 'returns a channel' do
|
41
|
+
expect(exchange.channel).to be_kind_of BunnyHair::Channel
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#publish' do
|
46
|
+
let(:queue) { double('queue', receive: true) }
|
47
|
+
before { exchange.queues << queue }
|
48
|
+
|
49
|
+
it 'calls #receive on all queues stored' do
|
50
|
+
exchange.publish('hello', {})
|
51
|
+
expect(queue).to have_received(:receive).with(instance_of(OpenStruct), instance_of(OpenStruct), 'hello').once
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'predicate methods' do
|
56
|
+
it { should be_durable }
|
57
|
+
it { should_not be_full_of_crap }
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe BunnyHair::Queue do
|
4
|
+
let(:channel) { BunnyHair.new.create_channel }
|
5
|
+
subject(:queue) { BunnyHair::Queue.new('queue.name') }
|
6
|
+
let(:exchange) { BunnyHair::Exchange.new(channel, :direct, 'my.exchange') }
|
7
|
+
|
8
|
+
describe '#consumers' do
|
9
|
+
it 'returns an array' do
|
10
|
+
expect(queue.consumers).to be_kind_of Array
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'returns a memoized array' do
|
14
|
+
original = queue.consumers
|
15
|
+
expect(original).to be(queue.consumers)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#bind' do
|
20
|
+
it 'attaches the queue to the exchange given' do
|
21
|
+
queue.bind(exchange, routing_key: 'hello.world')
|
22
|
+
expect(exchange).to have(1).queues
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#subscribe' do
|
27
|
+
it 'stores the subscription block' do
|
28
|
+
queue.subscribe do |metadata, info, payload|
|
29
|
+
"hello"
|
30
|
+
end
|
31
|
+
|
32
|
+
expect(queue).to have(1).consumers
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'accepts options' do
|
36
|
+
expect do
|
37
|
+
queue.subscribe(ack: false) do |info, message, payload|
|
38
|
+
"hello"
|
39
|
+
end
|
40
|
+
end.to_not raise_error
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'returns a consumer object' do
|
44
|
+
consumer = queue.subscribe do |i, m, p|
|
45
|
+
"hello"
|
46
|
+
end
|
47
|
+
|
48
|
+
expect(consumer).to be_kind_of(BunnyHair::Consumer)
|
49
|
+
expect(queue.consumers).to include(consumer)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#delete' do
|
54
|
+
it 'removes queues' do
|
55
|
+
queue.bind(exchange, routing_key: 'hello.world')
|
56
|
+
queue.delete
|
57
|
+
expect(exchange).to have(0).queues
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#pop' do
|
62
|
+
it 'gets the last message on the queue' do
|
63
|
+
queue.receive({}, {}, 'hello')
|
64
|
+
message = queue.pop
|
65
|
+
expect(message[2]).to eq 'hello'
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe '#receive' do
|
70
|
+
let(:stunt_devil) { double('un diablo', fall: true) }
|
71
|
+
|
72
|
+
it 'runs all subscriptions with the information' do
|
73
|
+
queue.subscribe do |metadata, info, payload|
|
74
|
+
stunt_devil.fall(payload)
|
75
|
+
end
|
76
|
+
|
77
|
+
queue.receive({}, {}, 'hello')
|
78
|
+
expect(stunt_devil).to have_received(:fall).with('hello')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe '#publish' do
|
83
|
+
let(:service) { double('service', payload: true) }
|
84
|
+
|
85
|
+
it 'accepts a payload' do
|
86
|
+
expect { queue.publish('payload') }.to_not raise_error
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'calls the subscription with the payload' do
|
90
|
+
queue.subscribe do |delivery_info, metadata, payload|
|
91
|
+
service.payload(payload)
|
92
|
+
end
|
93
|
+
|
94
|
+
queue.publish('payload')
|
95
|
+
expect(service).to have_received(:payload).with('payload')
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe '#message_count' do
|
100
|
+
it 'stores how many messages it has received' do
|
101
|
+
3.times { queue.receive({}, {}, 'hello') }
|
102
|
+
expect(queue.message_count).to be(3)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
|
8
|
+
require 'bunny_hair'
|
9
|
+
require 'pry'
|
10
|
+
|
11
|
+
RSpec.configure do |config|
|
12
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
13
|
+
config.run_all_when_everything_filtered = true
|
14
|
+
config.filter_run :focus
|
15
|
+
|
16
|
+
# Run specs in random order to surface order dependencies. If you find an
|
17
|
+
# order dependency and want to debug it, you can fix the order by providing
|
18
|
+
# the seed, which is printed after each run.
|
19
|
+
# --seed 1234
|
20
|
+
config.order = 'random'
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bunny_hair
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.9
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Robert Ross
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-04-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: guard-rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.0.0
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 3.0.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pry
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.9.12.2
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.9.12.2
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 2.14.1
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.14.1
|
83
|
+
description: A simple replacement for Bunny
|
84
|
+
email:
|
85
|
+
- roberto@thunderboltlabs.com
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- ".gitignore"
|
91
|
+
- ".rspec"
|
92
|
+
- Gemfile
|
93
|
+
- Guardfile
|
94
|
+
- LICENSE.txt
|
95
|
+
- README.md
|
96
|
+
- Rakefile
|
97
|
+
- bunny_hair.gemspec
|
98
|
+
- lib/bunny_hair.rb
|
99
|
+
- lib/bunny_hair/channel.rb
|
100
|
+
- lib/bunny_hair/connection.rb
|
101
|
+
- lib/bunny_hair/consumer.rb
|
102
|
+
- lib/bunny_hair/exchange.rb
|
103
|
+
- lib/bunny_hair/queue.rb
|
104
|
+
- lib/bunny_hair/version.rb
|
105
|
+
- spec/lib/bunny_hair/channel_spec.rb
|
106
|
+
- spec/lib/bunny_hair/connection_spec.rb
|
107
|
+
- spec/lib/bunny_hair/consumer_spec.rb
|
108
|
+
- spec/lib/bunny_hair/exchange_spec.rb
|
109
|
+
- spec/lib/bunny_hair/queue_spec.rb
|
110
|
+
- spec/lib/bunny_hair_spec.rb
|
111
|
+
- spec/spec_helper.rb
|
112
|
+
homepage: https://github.com/thunderboltlabs/bunny_hair
|
113
|
+
licenses:
|
114
|
+
- MIT
|
115
|
+
metadata: {}
|
116
|
+
post_install_message:
|
117
|
+
rdoc_options: []
|
118
|
+
require_paths:
|
119
|
+
- lib
|
120
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - ">="
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '0'
|
130
|
+
requirements: []
|
131
|
+
rubyforge_project:
|
132
|
+
rubygems_version: 2.2.2
|
133
|
+
signing_key:
|
134
|
+
specification_version: 4
|
135
|
+
summary: Use this gem as a replacement for Bunny to do in-memory operations
|
136
|
+
test_files:
|
137
|
+
- spec/lib/bunny_hair/channel_spec.rb
|
138
|
+
- spec/lib/bunny_hair/connection_spec.rb
|
139
|
+
- spec/lib/bunny_hair/consumer_spec.rb
|
140
|
+
- spec/lib/bunny_hair/exchange_spec.rb
|
141
|
+
- spec/lib/bunny_hair/queue_spec.rb
|
142
|
+
- spec/lib/bunny_hair_spec.rb
|
143
|
+
- spec/spec_helper.rb
|