jackrabbit 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: eb590a46a8d61eff7c99222aa45c28a8de948b4b
4
+ data.tar.gz: 931c3bfb9cd1226d9e1238a1726c61f542f3acca
5
+ SHA512:
6
+ metadata.gz: 544a4435206ab23db02b379eb9147fe5bae330c07cd5d06887ae35a1ea6d42fc601258c2f3404ae10c215646adfe294280da558d12260b1fb74cef31d97f776b
7
+ data.tar.gz: 735ddd4f5271293742248425cf5aab872e864f2289fe73556e4c578dde07278ea216d602d8622a2dd55839c01056905c3d3a1e2fbad32a8a8a06680186843865
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --warnings
3
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in jackrabbit.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Robert Ross
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,101 @@
1
+ # Jackrabbit
2
+
3
+ Jackrabbit makes interacting with RabbitMQ a little nicer.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'jackrabbit'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install jackrabbit
18
+
19
+ ## Usage
20
+
21
+ ### Configuration
22
+
23
+ Jackrabbit has an assumption that you're working with 1 exchange most of the time. It does allow you to work with multiple. But configuration on the class pertains to 1 exchange.
24
+
25
+ Jackrabbit.config do |c|
26
+ c.exchange_type = 'topic'
27
+ c.exchange_name = 'my.exchange'
28
+ c.exchange_options = {}
29
+
30
+ c.connection = Bunny.new
31
+ c.connection.start
32
+ end
33
+
34
+ Jackrabbit will use the Bunny gem connection you pass in. You must have called #start on it yourself however.
35
+ The reason for this is because in specs you can swap the connection out for something like [BunnyHair](http://github.com/thunderboltlabs/bunny_hair) which tries to mimick Bunny but in memory.
36
+
37
+ ### Clients
38
+
39
+ Calling `Jackrabbit.new` will return a `Jackrabbit::Client` object. This is the object you'll be interfacing the most with.
40
+
41
+ client = Jackrabbit.new
42
+ #=> Jackrabbit::Client
43
+
44
+ ### Bonded Queues
45
+
46
+ With the client object you can create queues that are bonded to your exchange automatically. This is handy since binding queues become tedious when you do it a lot. For example:
47
+
48
+ client.bonded_queue('my.queue.name', binding: { routing_key: 'key.#' }) do |message|
49
+ puts message.payload
50
+ puts message.delivery_info
51
+ puts message.message
52
+ end
53
+
54
+ When you pass a block to the bonded queue this is the block that is called for each message that the queue receives. It is your consumer.
55
+
56
+ ### Messages
57
+
58
+ In the subscription block from bonded queue, you aren't given info, delivery, and payload arguments like the Bunny gem provides. Instead you get a single object that incapsulates all of them and gives some nice behavior.
59
+
60
+ For example, message acknowledgements become very simple.
61
+
62
+ client.bonded_queue('my.queue.name', binding: { routing_key: 'key.#' }, subscription: { ack: true}) do |message|
63
+ puts message.payload
64
+
65
+ # acknowledge the message to RabbitMQ
66
+ message.acknowledge!
67
+ end
68
+
69
+ Passing in the additional key of `subscription: { ack: true }` details that you want to explicitly ack messages.
70
+
71
+ ### Publishing Messages
72
+
73
+ Along with subscriptions, you can also publish messages to your client object.
74
+
75
+ client = Jackrabbit.new
76
+
77
+ client.publish('my message')
78
+ client.publish('my message', routing_key: 'my.routing.key')
79
+
80
+ This will publish the message **to the exchange, not a queue**.
81
+
82
+ ### Multiple Exchanges
83
+
84
+ There might be an instance that you want to maybe use a different connection with a different exchange. To do this you can instantiate clients manually with a separate configuration.
85
+
86
+ config = Jackrabbit::Config.new
87
+ config.exchange_type = 'direct'
88
+ config.exchange_name = 'direct.exchange'
89
+ config.connection = Bunny.new
90
+
91
+ client = Jackrabbit::Client.new(config)
92
+
93
+ Now your client object will interact with the other exchange you've detailed.
94
+
95
+ ## Contributing
96
+
97
+ 1. Fork it ( https://github.com/bobbytables/jackrabbit/fork )
98
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
99
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
100
+ 4. Push to the branch (`git push origin my-new-feature`)
101
+ 5. Create a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'jackrabbit/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "jackrabbit"
8
+ spec.version = Jackrabbit::VERSION
9
+ spec.authors = ["Robert Ross"]
10
+ spec.email = ["robert@creativequeries.com"]
11
+ spec.summary = %q{Work with RabbitMQ in a more sane way}
12
+ spec.description = %q{Jackrabbit simplifies doing very common tasks with RabbitMQ}
13
+ spec.homepage = "http://github.com/bobbytables/jackrabbit'"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
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.6"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency 'rspec', '~> 3.0.0.rc1'
24
+ spec.add_development_dependency 'bunny_hair', '~> 0.0.10'
25
+ end
@@ -0,0 +1,201 @@
1
+ # Stolen from rails
2
+
3
+ unless defined?(Module::DelegationError)
4
+ class Module
5
+ # Error generated by +delegate+ when a method is called on +nil+ and +allow_nil+
6
+ # option is not used.
7
+ class DelegationError < NoMethodError; end
8
+
9
+ # Provides a +delegate+ class method to easily expose contained objects'
10
+ # public methods as your own.
11
+ #
12
+ # ==== Options
13
+ # * <tt>:to</tt> - Specifies the target object
14
+ # * <tt>:prefix</tt> - Prefixes the new method with the target name or a custom prefix
15
+ # * <tt>:allow_nil</tt> - if set to true, prevents a +NoMethodError+ to be raised
16
+ #
17
+ # The macro receives one or more method names (specified as symbols or
18
+ # strings) and the name of the target object via the <tt>:to</tt> option
19
+ # (also a symbol or string).
20
+ #
21
+ # Delegation is particularly useful with Active Record associations:
22
+ #
23
+ # class Greeter < ActiveRecord::Base
24
+ # def hello
25
+ # 'hello'
26
+ # end
27
+ #
28
+ # def goodbye
29
+ # 'goodbye'
30
+ # end
31
+ # end
32
+ #
33
+ # class Foo < ActiveRecord::Base
34
+ # belongs_to :greeter
35
+ # delegate :hello, to: :greeter
36
+ # end
37
+ #
38
+ # Foo.new.hello # => "hello"
39
+ # Foo.new.goodbye # => NoMethodError: undefined method `goodbye' for #<Foo:0x1af30c>
40
+ #
41
+ # Multiple delegates to the same target are allowed:
42
+ #
43
+ # class Foo < ActiveRecord::Base
44
+ # belongs_to :greeter
45
+ # delegate :hello, :goodbye, to: :greeter
46
+ # end
47
+ #
48
+ # Foo.new.goodbye # => "goodbye"
49
+ #
50
+ # Methods can be delegated to instance variables, class variables, or constants
51
+ # by providing them as a symbols:
52
+ #
53
+ # class Foo
54
+ # CONSTANT_ARRAY = [0,1,2,3]
55
+ # @@class_array = [4,5,6,7]
56
+ #
57
+ # def initialize
58
+ # @instance_array = [8,9,10,11]
59
+ # end
60
+ # delegate :sum, to: :CONSTANT_ARRAY
61
+ # delegate :min, to: :@@class_array
62
+ # delegate :max, to: :@instance_array
63
+ # end
64
+ #
65
+ # Foo.new.sum # => 6
66
+ # Foo.new.min # => 4
67
+ # Foo.new.max # => 11
68
+ #
69
+ # It's also possible to delegate a method to the class by using +:class+:
70
+ #
71
+ # class Foo
72
+ # def self.hello
73
+ # "world"
74
+ # end
75
+ #
76
+ # delegate :hello, to: :class
77
+ # end
78
+ #
79
+ # Foo.new.hello # => "world"
80
+ #
81
+ # Delegates can optionally be prefixed using the <tt>:prefix</tt> option. If the value
82
+ # is <tt>true</tt>, the delegate methods are prefixed with the name of the object being
83
+ # delegated to.
84
+ #
85
+ # Person = Struct.new(:name, :address)
86
+ #
87
+ # class Invoice < Struct.new(:client)
88
+ # delegate :name, :address, to: :client, prefix: true
89
+ # end
90
+ #
91
+ # john_doe = Person.new('John Doe', 'Vimmersvej 13')
92
+ # invoice = Invoice.new(john_doe)
93
+ # invoice.client_name # => "John Doe"
94
+ # invoice.client_address # => "Vimmersvej 13"
95
+ #
96
+ # It is also possible to supply a custom prefix.
97
+ #
98
+ # class Invoice < Struct.new(:client)
99
+ # delegate :name, :address, to: :client, prefix: :customer
100
+ # end
101
+ #
102
+ # invoice = Invoice.new(john_doe)
103
+ # invoice.customer_name # => 'John Doe'
104
+ # invoice.customer_address # => 'Vimmersvej 13'
105
+ #
106
+ # If the target is +nil+ and does not respond to the delegated method a
107
+ # +NoMethodError+ is raised, as with any other value. Sometimes, however, it
108
+ # makes sense to be robust to that situation and that is the purpose of the
109
+ # <tt>:allow_nil</tt> option: If the target is not +nil+, or it is and
110
+ # responds to the method, everything works as usual. But if it is +nil+ and
111
+ # does not respond to the delegated method, +nil+ is returned.
112
+ #
113
+ # class User < ActiveRecord::Base
114
+ # has_one :profile
115
+ # delegate :age, to: :profile
116
+ # end
117
+ #
118
+ # User.new.age # raises NoMethodError: undefined method `age'
119
+ #
120
+ # But if not having a profile yet is fine and should not be an error
121
+ # condition:
122
+ #
123
+ # class User < ActiveRecord::Base
124
+ # has_one :profile
125
+ # delegate :age, to: :profile, allow_nil: true
126
+ # end
127
+ #
128
+ # User.new.age # nil
129
+ #
130
+ # Note that if the target is not +nil+ then the call is attempted regardless of the
131
+ # <tt>:allow_nil</tt> option, and thus an exception is still raised if said object
132
+ # does not respond to the method:
133
+ #
134
+ # class Foo
135
+ # def initialize(bar)
136
+ # @bar = bar
137
+ # end
138
+ #
139
+ # delegate :name, to: :@bar, allow_nil: true
140
+ # end
141
+ #
142
+ # Foo.new("Bar").name # raises NoMethodError: undefined method `name'
143
+ #
144
+ # The target method must be public, otherwise it will raise +NoMethodError+.
145
+ #
146
+ def delegate(*methods)
147
+ options = methods.pop
148
+ unless options.is_a?(Hash) && to = options[:to]
149
+ raise ArgumentError, 'Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, to: :greeter).'
150
+ end
151
+
152
+ prefix, allow_nil = options.values_at(:prefix, :allow_nil)
153
+
154
+ if prefix == true && to =~ /^[^a-z_]/
155
+ raise ArgumentError, 'Can only automatically set the delegation prefix when delegating to a method.'
156
+ end
157
+
158
+ method_prefix = \
159
+ if prefix
160
+ "#{prefix == true ? to : prefix}_"
161
+ else
162
+ ''
163
+ end
164
+
165
+ file, line = caller.first.split(':', 2)
166
+ line = line.to_i
167
+
168
+ to = to.to_s
169
+ to = 'self.class' if to == 'class'
170
+
171
+ methods.each do |method|
172
+ # Attribute writer methods only accept one argument. Makes sure []=
173
+ # methods still accept two arguments.
174
+ definition = (method =~ /[^\]]=$/) ? 'arg' : '*args, &block'
175
+
176
+ # The following generated method calls the target exactly once, storing
177
+ # the returned value in a dummy variable.
178
+ #
179
+ # Reason is twofold: On one hand doing less calls is in general better.
180
+ # On the other hand it could be that the target has side-effects,
181
+ # whereas conceptually, from the user point of view, the delegator should
182
+ # be doing one call.
183
+
184
+ exception = %(raise DelegationError, "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
185
+
186
+ method_def = [
187
+ "def #{method_prefix}#{method}(#{definition})",
188
+ " _ = #{to}",
189
+ " if !_.nil? || nil.respond_to?(:#{method})",
190
+ " _.#{method}(#{definition})",
191
+ " else",
192
+ " #{exception unless allow_nil}",
193
+ " end",
194
+ "end"
195
+ ].join ';'
196
+
197
+ module_eval(method_def, file, line)
198
+ end
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,17 @@
1
+ require 'core_ext'
2
+
3
+ module Jackrabbit
4
+ autoload :Exchange, 'jackrabbit/exchange'
5
+ autoload :Config, 'jackrabbit/config'
6
+ autoload :Client, 'jackrabbit/client'
7
+ autoload :MessageReceiver, 'jackrabbit/message_receiver'
8
+ autoload :Message, 'jackrabbit/message'
9
+
10
+ def self.config(&block)
11
+ Config.default(&block)
12
+ end
13
+
14
+ def self.new
15
+ Client.new
16
+ end
17
+ end
@@ -0,0 +1,50 @@
1
+ module Jackrabbit
2
+ class Client
3
+ InvalidExchangeType = Class.new(StandardError)
4
+
5
+ attr_reader :config
6
+ delegate :connection, to: :config
7
+
8
+ def initialize(config = Jackrabbit.config)
9
+ @config = config
10
+ end
11
+
12
+ def channel
13
+ connection.default_channel
14
+ end
15
+
16
+ def exchange
17
+ if %w(fanout direct topic).include?(config.exchange_type)
18
+ @exchange ||= channel.send(config.exchange_type, config.exchange_name, config.exchange_options)
19
+ else
20
+ raise InvalidExchangeType, "The exchange type '#{config.exchange_type}' is invalid"
21
+ end
22
+ end
23
+
24
+ def publish(message, options = {})
25
+ exchange.publish(message, options)
26
+ end
27
+
28
+ def bonded_queue(name, options = {}, &block)
29
+ queue_opts, binding_opts, sub_options = split_options(options)
30
+
31
+ queue = channel.queue(name, queue_opts)
32
+ receiver = MessageReceiver.new(channel, &block)
33
+
34
+ queue.bind(exchange, binding_opts)
35
+
36
+ queue.subscribe(sub_options) do |info, message, payload|
37
+ receiver.handle(info, message, payload)
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def split_options(options)
44
+ binding_options = options.delete(:binding) || {}
45
+ sub_options = options.delete(:subscription) || {}
46
+
47
+ return [options, binding_options, sub_options]
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,16 @@
1
+ module Jackrabbit
2
+ class Config
3
+ def self.default(&block)
4
+ (@default ||= new).tap do |config|
5
+ yield config if block_given?
6
+ end
7
+ end
8
+
9
+ attr_accessor :exchange_name, :exchange_type, :connection
10
+ attr_accessor :exchange_options
11
+
12
+ def initialize
13
+ @exchange_options = {}
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,4 @@
1
+ module Jackrabbit
2
+ class Exchange
3
+ end
4
+ end
@@ -0,0 +1,16 @@
1
+ module Jackrabbit
2
+ class Message
3
+ attr_reader :info, :message, :payload, :channel
4
+
5
+ def initialize(info, message, payload, channel)
6
+ @info = info
7
+ @message = message
8
+ @payload = payload
9
+ @channel = channel
10
+ end
11
+
12
+ def acknowledge!
13
+ channel.acknowledge(info.delivery_tag, false)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ module Jackrabbit
2
+ class MessageReceiver
3
+ attr_reader :channel, :options, :handler
4
+
5
+ def initialize(channel, options = {}, &block)
6
+ @channel = channel
7
+ @options = options
8
+ handle_with(&block) if block_given?
9
+ end
10
+
11
+ def handle(info, message, payload)
12
+ @handler.call Message.new(info, message, payload, channel)
13
+ end
14
+
15
+ private
16
+
17
+ def handle_with(&block)
18
+ @handler = block
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ module Jackrabbit
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,117 @@
1
+ require 'spec_helper'
2
+ require 'jackrabbit'
3
+
4
+ describe Jackrabbit::Client do
5
+ subject(:client) { Jackrabbit::Client.new(config) }
6
+
7
+ let(:config) do
8
+ Jackrabbit::Config.new.tap do |config|
9
+ config.exchange_name = 'bunk'
10
+ config.exchange_type = 'topic'
11
+ config.connection = BunnyHair.new
12
+ end
13
+ end
14
+
15
+ describe '#config' do
16
+ it 'is defaulted to the global config' do
17
+ client = Jackrabbit::Client.new
18
+ expect(client.config).to be(Jackrabbit.config)
19
+ end
20
+
21
+ it 'can be injected in on initialization' do
22
+ config = double
23
+ client = Jackrabbit::Client.new(config)
24
+ expect(client.config).to be(config)
25
+ end
26
+ end
27
+
28
+ describe '#channel' do
29
+ it 'returns the default channel' do
30
+ expect(client.channel).to_not be_nil
31
+ end
32
+ end
33
+
34
+ describe '#exchange' do
35
+ it 'returns an exchange' do
36
+ expect(client.exchange.name).to eq('bunk')
37
+ expect(client.exchange.type).to eq(:topic)
38
+ end
39
+
40
+ it 'raises an error when the config specifies an incorrect type' do
41
+ config.exchange_type = 'nothin'
42
+ expect { client.exchange }.to raise_error(Jackrabbit::Client::InvalidExchangeType)
43
+ end
44
+ end
45
+
46
+ describe '#publish' do
47
+ it 'pushes a message onto the exchange' do
48
+ expect(client.exchange).to receive(:publish).with(
49
+ 'message', anything
50
+ ).and_call_original
51
+
52
+ client.publish('message')
53
+ end
54
+
55
+ it 'publishes with options passed' do
56
+ expect(client.exchange).to receive(:publish).with(
57
+ 'payload', routing_key: 'bunk'
58
+ ).and_call_original
59
+
60
+ client.publish('payload', routing_key: 'bunk')
61
+ end
62
+ end
63
+
64
+ describe '#bonded_queue' do
65
+ def test_queues
66
+ client.channel.test_queues
67
+ end
68
+
69
+ it 'creates a queue' do
70
+ client.bonded_queue('name')
71
+ expect(test_queues[0].name).to eq('name')
72
+ end
73
+
74
+ it 'creates a queue with options set' do
75
+ client.bonded_queue('name', durable: true, exclusive: true, auto_delete: true)
76
+ expect(test_queues[0]).to be_auto_delete
77
+ expect(test_queues[0].options[:durable]).to be_truthy
78
+ expect(test_queues[0].options[:exclusive]).to be_truthy
79
+ end
80
+
81
+ it 'creates a consumer for the queue' do
82
+ client.bonded_queue('name')
83
+ expect(test_queues.first.consumers.size).to be(1)
84
+ end
85
+
86
+ it 'handles the messages in the block when the exchange gets a message' do
87
+ assertion = double('foo', asserted: false)
88
+ client.bonded_queue('bunk') do |message|
89
+ assertion.asserted(message)
90
+ end
91
+
92
+ client.publish('message')
93
+
94
+ expect(assertion).to have_received(:asserted).with(instance_of(Jackrabbit::Message)).once
95
+ end
96
+
97
+ context 'binding' do
98
+ it 'passes binding options to the queue binding' do
99
+ queue = BunnyHair::Queue.new('bunk')
100
+ allow(client.channel).to receive(:queue).and_return(queue)
101
+ expect(queue).to receive(:bind).with(client.exchange, routing_key: 'bunk')
102
+
103
+ client.bonded_queue('foo', binding: { routing_key: 'bunk' })
104
+ end
105
+ end
106
+
107
+ context 'subscriptions' do
108
+ it 'passes subscription options to the queue subscription' do
109
+ queue = BunnyHair::Queue.new('bunk')
110
+ allow(client.channel).to receive(:queue).and_return(queue)
111
+ expect(queue).to receive(:subscribe).with(ack: true)
112
+
113
+ client.bonded_queue('foo', subscription: { ack: true })
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+ require 'jackrabbit'
3
+
4
+ describe Jackrabbit::Config do
5
+ def has_a_setting_for(setting)
6
+ value = 'bunk'
7
+ expect(subject).to respond_to("#{setting}=")
8
+ subject.send("#{setting}=", value)
9
+
10
+ expect(subject.send(setting)).to be(value)
11
+ end
12
+
13
+ describe '.default' do
14
+ it 'returns a default instance of the config' do
15
+ config = Jackrabbit::Config.default
16
+ expect(config).to be_instance_of(Jackrabbit::Config)
17
+ expect(config).to be(Jackrabbit::Config.default)
18
+ end
19
+
20
+ it 'yields the instance to a block when passed in' do
21
+ expect {|b| Jackrabbit::Config.default(&b) }.to yield_with_args(instance_of(Jackrabbit::Config))
22
+ end
23
+ end
24
+
25
+ describe 'Settings' do
26
+ it { has_a_setting_for(:exchange_name) }
27
+ it { has_a_setting_for(:exchange_type) }
28
+ it { has_a_setting_for(:exchange_options) }
29
+ it { has_a_setting_for(:connection) }
30
+ end
31
+
32
+ describe 'Sane Defaults' do
33
+ it 'defaults the exchange options to an empty hash' do
34
+ config = Jackrabbit::Config.new
35
+ expect(config.exchange_options).to eq({})
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,2 @@
1
+ require 'spec_helper'
2
+ require 'jackrabbit'
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+ require 'jackrabbit'
3
+
4
+ describe Jackrabbit::MessageReceiver do
5
+ let(:channel) { double('channel') }
6
+ let(:handler) do
7
+ Proc.new do |message|
8
+ end
9
+ end
10
+
11
+ describe '#initialize' do
12
+ it 'returns a message reciever instance' do
13
+ instance = Jackrabbit::MessageReceiver.new(channel, {}, &Proc.new {})
14
+ expect(instance.channel).to be(channel)
15
+ expect(instance.options).to eq({})
16
+ expect(instance.handler).to respond_to(:call)
17
+ end
18
+ end
19
+
20
+ describe '#handle' do
21
+ let(:assertion) { double('assertion', asserted: false) }
22
+ subject(:receiver) do
23
+ Jackrabbit::MessageReceiver.new(channel) do |message|
24
+ assertion.asserted(message)
25
+ end
26
+ end
27
+
28
+ it 'calls to the handler block' do
29
+ receiver.handle('info', 'message', 'payload')
30
+ expect(assertion).to have_received(:asserted)
31
+ end
32
+
33
+ it 'calls the handler block with a message object with the correct properties set' do
34
+ expect(assertion).to receive(:asserted) do |message|
35
+ expect(message.info).to eq('info')
36
+ expect(message.message).to eq('message')
37
+ expect(message.payload).to eq('payload')
38
+ expect(message.channel).to be(channel)
39
+ end
40
+
41
+ receiver.handle('info', 'message', 'payload')
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe Jackrabbit::Message do
4
+ describe '#acknowledge!' do
5
+ let(:channel) { double('channel', acknowledge: false) }
6
+ let(:info) { double('info', delivery_tag: 1) }
7
+
8
+ subject(:message) { Jackrabbit::Message.new(info, double, double, channel) }
9
+
10
+ it 'acknowledges the message to the channel' do
11
+ expect(channel).to receive(:acknowledge).with(info.delivery_tag, false)
12
+ message.acknowledge!
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+ require 'jackrabbit'
3
+
4
+ describe Jackrabbit do
5
+ describe '.config' do
6
+ it 'returns the default configuration object' do
7
+ config = double
8
+ allow(Jackrabbit::Config).to receive(:default).and_return(config)
9
+
10
+ expect(Jackrabbit.config).to be(config)
11
+ end
12
+
13
+ it 'yields the default configuration' do
14
+ expect {|b| Jackrabbit.config(&b) }.to yield_with_args(Jackrabbit::Config.default)
15
+ end
16
+ end
17
+
18
+ describe '.new' do
19
+ it 'returns a Jackrabbit::Client object' do
20
+ expect(Jackrabbit.new).to be_instance_of(Jackrabbit::Client)
21
+ end
22
+
23
+ it 'returns a client with the config set' do
24
+ client = Jackrabbit.new
25
+ expect(client.config).to be(Jackrabbit.config)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,6 @@
1
+ require 'jackrabbit'
2
+ require 'bunny_hair'
3
+
4
+ RSpec.configure do |config|
5
+
6
+ end
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jackrabbit
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Robert Ross
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-26 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.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 3.0.0.rc1
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 3.0.0.rc1
55
+ - !ruby/object:Gem::Dependency
56
+ name: bunny_hair
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.0.10
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 0.0.10
69
+ description: Jackrabbit simplifies doing very common tasks with RabbitMQ
70
+ email:
71
+ - robert@creativequeries.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gitignore
77
+ - .rspec
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - jackrabbit.gemspec
83
+ - lib/core_ext.rb
84
+ - lib/jackrabbit.rb
85
+ - lib/jackrabbit/client.rb
86
+ - lib/jackrabbit/config.rb
87
+ - lib/jackrabbit/exchange.rb
88
+ - lib/jackrabbit/message.rb
89
+ - lib/jackrabbit/message_receiver.rb
90
+ - lib/jackrabbit/version.rb
91
+ - spec/lib/jackrabbit/client_spec.rb
92
+ - spec/lib/jackrabbit/config_spec.rb
93
+ - spec/lib/jackrabbit/exchange_spec.rb
94
+ - spec/lib/jackrabbit/message_receiver_spec.rb
95
+ - spec/lib/jackrabbit/message_spec.rb
96
+ - spec/lib/jackrabbit_spec.rb
97
+ - spec/spec_helper.rb
98
+ homepage: http://github.com/bobbytables/jackrabbit'
99
+ licenses:
100
+ - MIT
101
+ metadata: {}
102
+ post_install_message:
103
+ rdoc_options: []
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - '>='
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ requirements: []
117
+ rubyforge_project:
118
+ rubygems_version: 2.2.2
119
+ signing_key:
120
+ specification_version: 4
121
+ summary: Work with RabbitMQ in a more sane way
122
+ test_files:
123
+ - spec/lib/jackrabbit/client_spec.rb
124
+ - spec/lib/jackrabbit/config_spec.rb
125
+ - spec/lib/jackrabbit/exchange_spec.rb
126
+ - spec/lib/jackrabbit/message_receiver_spec.rb
127
+ - spec/lib/jackrabbit/message_spec.rb
128
+ - spec/lib/jackrabbit_spec.rb
129
+ - spec/spec_helper.rb