lapine 0.0.1

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: a016ee7c70d98cb4610ce8e1b5e3dd53c44c2af6
4
+ data.tar.gz: 6ded62d3a8a567c46e2d6b0279cf9b6aa859176d
5
+ SHA512:
6
+ metadata.gz: ef82948b35e732df7e47632e83c6104b4a7a50502992109b6f1e5d2c906753f98f065f010f7b7eaafdafed1377dd24205d470e3c72ed84884b2c821253257ac0
7
+ data.tar.gz: be30ddb171156832f84b11e9561f13db7d60de38b11b956e72beafb20a9c87a714bfd1d630cf767f6794ae20e6b1f62450d2f47f10458bec12c1bcc6c9b91276
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in lapine.gemspec
4
+ gemspec
@@ -0,0 +1,7 @@
1
+
2
+ guard :rspec, cmd: 'bundle exec rspec' do
3
+ watch(%r{^spec/.+_spec\.rb$})
4
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
5
+ watch('spec/spec_helper.rb') { "spec" }
6
+ end
7
+
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Eric Saxby & Matt Camuto
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,87 @@
1
+ Lapine
2
+ ======
3
+
4
+ Speak to RabbitMQ. This gem serves as a wrapper for publishing messages
5
+ to RabbitMQ via the Bunny gem.
6
+
7
+
8
+ ## Configuration
9
+
10
+ Initialization can be done inline in a daemon, or if used in Rails
11
+ an initializer should be made at `config/initializers/lapine.rb`
12
+
13
+ Register a connection. This connection should be given a name, and
14
+ a hash of connection options that will be passed through to Bunny.
15
+
16
+ ```ruby
17
+ Lapine.add_connection 'my-connection', {
18
+ host: 'my-rabbitmq.mine.com',
19
+ port: 5672,
20
+ user: 'rabbit',
21
+ password: 'meow'
22
+ }
23
+ ```
24
+
25
+ Then register an exchange.
26
+
27
+ ```ruby
28
+ Lapine.add_exchange 'efrafa',
29
+ durable: true,
30
+ connection: 'my-connection', # required
31
+ type: 'topic' # required
32
+ ```
33
+
34
+ ## Usage
35
+
36
+ Define a class that configures which `exchange` is uses. This class
37
+ must define `#to_hash`
38
+
39
+ ```ruby
40
+ require 'lapine'
41
+
42
+ class Worker
43
+ include Lapine::Publisher
44
+
45
+ exchange 'efrafa'
46
+
47
+ def initialize(action)
48
+ @action = action
49
+ end
50
+
51
+ def to_hash
52
+ {
53
+ 'action' => @action
54
+ }
55
+ end
56
+ end
57
+ ```
58
+
59
+ This class can be used to publish messages onto its exchange:
60
+
61
+ ```ruby
62
+ Worker.new('dig').publish
63
+ ```
64
+
65
+ Publishing can take a routing key for topic exchanges:
66
+
67
+ ```ruby
68
+ Worker.new('dig').publish('rabbits.drones')
69
+ ```
70
+
71
+ Note that the `#initialize` method and the contents of `#to_hash`
72
+ are arbitrary.
73
+
74
+
75
+ ## But... WHY
76
+
77
+ * This should be dead simple, but everything else was either too
78
+ complex or assumed very specific configurations different from what
79
+ we want.
80
+
81
+ ## Contributing
82
+
83
+ 1. Fork it ( https://github.com/[my-github-username]/lapine/fork )
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 a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'lapine/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'lapine'
8
+ spec.version = Lapine::VERSION
9
+ spec.authors = ['Eric Saxby','Matt Camuto']
10
+ spec.email = ['dev@wanelo.com']
11
+ spec.summary = %q{Talk to rabbits}
12
+ spec.description = %q{Talk to rabbits}
13
+ spec.homepage = 'https://github.com/wanelo/lapine'
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_dependency 'bunny'
22
+ spec.add_dependency 'oj'
23
+
24
+ spec.add_development_dependency 'bundler', '~> 1.7'
25
+ spec.add_development_dependency 'guard-rspec', '~> 4.3.1'
26
+ spec.add_development_dependency 'rake', '~> 10.0'
27
+ spec.add_development_dependency 'rspec', '~> 3.1.0'
28
+
29
+ end
@@ -0,0 +1,31 @@
1
+ require 'lapine/version'
2
+ require 'lapine/configuration'
3
+ require 'lapine/connection'
4
+
5
+ module Lapine
6
+ class UndefinedConnection < StandardError; end
7
+ class UndefinedExchange < StandardError; end
8
+
9
+ def self.config
10
+ @config ||= Configuration.new
11
+ end
12
+
13
+ def self.add_connection(name, properties)
14
+ config.connection_properties[name] = properties
15
+ end
16
+
17
+ def self.add_exchange(name, properties)
18
+ connection = properties[:connection]
19
+ raise UndefinedConnection unless connection
20
+ raise UndefinedConnection unless config.connection_properties[connection]
21
+ config.exchange_properties[name] = properties
22
+ end
23
+
24
+ def self.find_exchange(name)
25
+ exchange = config.exchange_properties[name]
26
+ raise UndefinedExchange unless exchange
27
+ return config.exchanges[name].exchange if config.exchanges[name]
28
+ config.exchanges[name] = Lapine::Connection.new(name, exchange)
29
+ config.exchanges[name].exchange
30
+ end
31
+ end
@@ -0,0 +1,19 @@
1
+ module Lapine
2
+ class Configuration
3
+ def connections
4
+ @connections ||= {}
5
+ end
6
+
7
+ def connection_properties
8
+ @connection_properties ||= {}
9
+ end
10
+
11
+ def exchanges
12
+ @exchanges ||= {}
13
+ end
14
+
15
+ def exchange_properties
16
+ @exchange_properties ||= {}
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,26 @@
1
+ require 'bunny'
2
+
3
+ module Lapine
4
+ class Connection
5
+ attr_reader :conn, :name, :props
6
+
7
+ def initialize(name, properties)
8
+ @name = name
9
+ @props = properties.dup
10
+ end
11
+
12
+ def exchange
13
+ reconnect unless conn && conn.connected?
14
+ @exchange
15
+ end
16
+
17
+ def reconnect
18
+ connection_props = Lapine.config.connection_properties[props.delete(:connection)]
19
+ @conn = Bunny.new(connection_props)
20
+ conn.start
21
+ channel = conn.create_channel
22
+ exchange_type = props.delete(:type)
23
+ @exchange = Bunny::Exchange.new(channel, exchange_type, name, props)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,24 @@
1
+ require 'oj'
2
+
3
+ module Lapine
4
+ module Publisher
5
+
6
+ def self.included(klass)
7
+ klass.send :extend, ClassMethods
8
+ end
9
+
10
+ def publish(routing_key = nil)
11
+ Lapine.find_exchange(self.class.instance_variable_get(:@exchange)).publish(to_json, routing_key: routing_key)
12
+ end
13
+
14
+ def to_json
15
+ ::Oj.dump(to_hash, mode: :compat)
16
+ end
17
+
18
+ module ClassMethods
19
+ def exchange(name)
20
+ @exchange = name
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,3 @@
1
+ module Lapine
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+ require 'lapine/publisher'
3
+
4
+ RSpec.describe Lapine::Publisher do
5
+ subject(:publisher) { publisher_class.new }
6
+
7
+ let(:publisher_class) {
8
+ Class.new.tap do |klass|
9
+ klass.send :include, Lapine::Publisher
10
+ klass.send :exchange, exchange
11
+ klass.send :define_method, :to_hash do
12
+ {}
13
+ end
14
+ end
15
+ }
16
+ let(:exchange) { 'test_exchange' }
17
+ let(:fake_exchange) { double }
18
+
19
+ before do
20
+ allow(Lapine).to receive(:find_exchange).with(exchange).and_return(fake_exchange)
21
+ end
22
+
23
+ describe '#to_json' do
24
+ before do
25
+ allow(publisher).to receive(:to_hash).and_return({foo: 'bar'})
26
+ end
27
+
28
+ it 'turns the output of #to_hash into JSON' do
29
+ expect(publisher.to_json).to eq('{"foo":"bar"}')
30
+ end
31
+ end
32
+
33
+ describe '#publish' do
34
+ let(:json) { '{"foo": "bar"}' }
35
+
36
+ it 'publishes data with routing key' do
37
+ expect(publisher).to receive(:to_json).and_return(json)
38
+ expect(fake_exchange).to receive(:publish).with(json, routing_key: 'thing.stuff')
39
+ publisher.publish('thing.stuff')
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,114 @@
1
+ require 'spec_helper'
2
+ require 'lapine'
3
+
4
+ RSpec.describe Lapine do
5
+ let(:connection) { double('connection') }
6
+ let(:connection_properties) do
7
+ {
8
+ host: 'someplace.com'
9
+ }
10
+ end
11
+
12
+ let(:config) { Lapine::Configuration.new }
13
+
14
+ before do
15
+ Lapine.instance_variable_set(:@config, config)
16
+ end
17
+
18
+ describe '.add_connection' do
19
+ it 'saves the connection information' do
20
+ Lapine.add_connection 'my-connection', connection_properties
21
+ expect(config.connection_properties['my-connection']).to eq(connection_properties)
22
+ end
23
+ end
24
+
25
+ describe '.add_exchange' do
26
+ context 'when connection has been defined' do
27
+ before do
28
+ config.connection_properties['my-connection'] = {}
29
+ end
30
+
31
+ it 'saves the exchange information' do
32
+ Lapine.add_exchange 'my-exchange', durable: false, connection: 'my-connection'
33
+ expect(config.exchange_properties['my-exchange']).to eq({
34
+ durable: false,
35
+ connection: 'my-connection'
36
+ })
37
+ end
38
+ end
39
+
40
+ context 'when connection has not been defined' do
41
+ it 'raises' do
42
+ expect {
43
+ Lapine.add_exchange 'my-exchange', durable: false, connection: 'my-connection'
44
+ }.to raise_error(Lapine::UndefinedConnection)
45
+ end
46
+ end
47
+ end
48
+
49
+ describe '.find_exchange' do
50
+ before do
51
+ allow(Bunny).to receive(:new).and_return(connection)
52
+ end
53
+
54
+ context 'when exchange has not been registered' do
55
+ it 'raises' do
56
+ expect {
57
+ Lapine.find_exchange 'non-existent-exchange'
58
+ }.to raise_error(Lapine::UndefinedExchange)
59
+ end
60
+ end
61
+
62
+ context 'when exchange has been registered' do
63
+ let(:channel) { double('channel') }
64
+ let(:exchange) { double('exchange') }
65
+
66
+ before do
67
+ allow(connection).to receive(:start)
68
+ allow(connection).to receive(:create_channel).and_return(channel)
69
+ allow(Bunny::Exchange).to receive(:new).and_return(exchange)
70
+ config.exchange_properties['my-exchange'] = {connection: 'my-connection', type: :thing, some: 'exchange-property'}
71
+ end
72
+
73
+ context 'when exchanges has not been created' do
74
+ before do
75
+ allow(connection).to receive(:connected?).and_return(true)
76
+ end
77
+
78
+ it 'returns an exchange' do
79
+ expect(Lapine.find_exchange('my-exchange')).to eq(exchange)
80
+ end
81
+
82
+ it 'creates the exchange with its configured properties' do
83
+ Lapine.find_exchange('my-exchange')
84
+ expect(Bunny::Exchange).to have_received(:new).with(channel, :thing, 'my-exchange', some: 'exchange-property')
85
+ end
86
+
87
+ it 'starts a connection and creates a channel' do
88
+ Lapine.find_exchange('my-exchange')
89
+ expect(connection).to have_received(:start)
90
+ expect(connection).to have_received(:create_channel)
91
+ end
92
+
93
+ it 'only creates exchange once' do
94
+ Lapine.find_exchange('my-exchange')
95
+ Lapine.find_exchange('my-exchange')
96
+ expect(connection).to have_received(:start).once
97
+ expect(connection).to have_received(:create_channel).once
98
+ end
99
+ end
100
+
101
+ context 'with a created exchange' do
102
+ context 'that is closed' do
103
+ it 'establishes a new connection and exchange' do
104
+ Lapine.find_exchange('my-exchange')
105
+ allow(connection).to receive(:connected?).and_return(false)
106
+ Lapine.find_exchange('my-exchange')
107
+ expect(connection).to have_received(:start).twice
108
+ expect(connection).to have_received(:create_channel).twice
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,19 @@
1
+ require 'lapine'
2
+
3
+ RSpec.configure do |config|
4
+ config.expect_with :rspec do |expectations|
5
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
6
+ end
7
+
8
+ config.mock_with :rspec do |mocks|
9
+ mocks.verify_partial_doubles = true
10
+ end
11
+
12
+ config.disable_monkey_patching!
13
+ config.order = :random # use --seed NNNN
14
+ Kernel.srand config.seed
15
+
16
+ config.before :each do
17
+ Lapine.instance_variable_set(:@config, nil)
18
+ end
19
+ end
metadata ADDED
@@ -0,0 +1,149 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lapine
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Eric Saxby
8
+ - Matt Camuto
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-11-06 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bunny
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: oj
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: bundler
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '1.7'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '1.7'
56
+ - !ruby/object:Gem::Dependency
57
+ name: guard-rspec
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: 4.3.1
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: 4.3.1
70
+ - !ruby/object:Gem::Dependency
71
+ name: rake
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '10.0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '10.0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: rspec
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: 3.1.0
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: 3.1.0
98
+ description: Talk to rabbits
99
+ email:
100
+ - dev@wanelo.com
101
+ executables: []
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - ".rspec"
107
+ - Gemfile
108
+ - Guardfile
109
+ - LICENSE.txt
110
+ - README.md
111
+ - Rakefile
112
+ - lapine.gemspec
113
+ - lib/lapine.rb
114
+ - lib/lapine/configuration.rb
115
+ - lib/lapine/connection.rb
116
+ - lib/lapine/publisher.rb
117
+ - lib/lapine/version.rb
118
+ - spec/lib/lapine/publisher_spec.rb
119
+ - spec/lib/lapine_spec.rb
120
+ - spec/spec_helper.rb
121
+ homepage: https://github.com/wanelo/lapine
122
+ licenses:
123
+ - MIT
124
+ metadata: {}
125
+ post_install_message:
126
+ rdoc_options: []
127
+ require_paths:
128
+ - lib
129
+ required_ruby_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ requirements: []
140
+ rubyforge_project:
141
+ rubygems_version: 2.2.2
142
+ signing_key:
143
+ specification_version: 4
144
+ summary: Talk to rabbits
145
+ test_files:
146
+ - spec/lib/lapine/publisher_spec.rb
147
+ - spec/lib/lapine_spec.rb
148
+ - spec/spec_helper.rb
149
+ has_rdoc: