jackrabbit 0.0.2

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.
@@ -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