multiple_man 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 57e599dcf8963d8967ae8baff34c30f343b32b3b
4
+ data.tar.gz: d960ac0f5ce2c49b62e435e832ff14b1fe352754
5
+ SHA512:
6
+ metadata.gz: a50d81bd2d7aad87ea74ccdc42e671d88b42005436fde62a6a9353df0237f1138ba8dd9308d7ed93332d2cf4504c79168af0110968693ad64016df49675cf383
7
+ data.tar.gz: d5ace8d5cd8c4376112c45282c1542b85b89a676a5723ccf3fafc241c7a606d33dc79570198551aca28fb4f5d89b27d7a13e9a4b5d9ffac926a1beb6cf9d68f1
data/.gitignore ADDED
@@ -0,0 +1,17 @@
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
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in multiple_man.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Ryan Brunner
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.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # MultipleMan
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'multiple_man'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install multiple_man
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new('spec')
6
+
7
+ # If you want to make this the default task
8
+ task :default => :spec
@@ -0,0 +1,28 @@
1
+ require 'json'
2
+
3
+ module MultipleMan
4
+ class AttributeExtractor
5
+
6
+ def initialize(record, fields)
7
+ raise "Fields must be specified" unless fields
8
+
9
+ self.record = record
10
+ self.fields = fields
11
+ end
12
+
13
+ def data
14
+ Hash[fields.map do |field|
15
+ [field, record.send(field)]
16
+ end]
17
+ end
18
+
19
+ def to_json
20
+ data.to_json
21
+ end
22
+
23
+ private
24
+
25
+ attr_accessor :record, :fields
26
+
27
+ end
28
+ end
@@ -0,0 +1,19 @@
1
+ module MultipleMan
2
+ class Configuration
3
+
4
+ def initialize
5
+ self.topic_name = "multiple_man"
6
+ self.app_name = Rails.application.class.parent.to_s if defined?(Rails)
7
+ end
8
+
9
+ attr_accessor :topic_name, :app_name, :connection
10
+ end
11
+
12
+ def self.configuration
13
+ @configuration ||= Configuration.new
14
+ end
15
+
16
+ def self.configure
17
+ yield(configuration) if block_given?
18
+ end
19
+ end
@@ -0,0 +1,32 @@
1
+ module MultipleMan
2
+ class Connection
3
+ def self.connect
4
+ connection = Bunny.new(MultipleMan.configuration.connection)
5
+ connection.start
6
+ yield new(connection) if block_given?
7
+ ensure
8
+ connection.close
9
+ end
10
+
11
+ def initialize(connection)
12
+ self.connection = connection
13
+ end
14
+
15
+ def channel
16
+ @channel ||= connection.create_channel
17
+ end
18
+
19
+ def topic
20
+ @topic ||= channel.topic(topic_name)
21
+ end
22
+
23
+ def topic_name
24
+ MultipleMan.configuration.topic_name
25
+ end
26
+
27
+ private
28
+
29
+ attr_accessor :connection
30
+
31
+ end
32
+ end
@@ -0,0 +1,53 @@
1
+ require 'json'
2
+
3
+ module MultipleMan
4
+ class Listener
5
+
6
+ class << self
7
+ def start(connection)
8
+ puts "Starting listeners."
9
+ self.connection = connection
10
+ ModelSubscriber.subscriptions.each do |subscription|
11
+ new(subscription).listen
12
+ end
13
+ end
14
+
15
+ attr_accessor :connection
16
+ end
17
+
18
+ def initialize(subscription)
19
+ self.subscription = subscription
20
+ end
21
+
22
+ attr_accessor :subscription
23
+
24
+ def listen
25
+ puts "Listening for #{subscription.klass} with routing key #{subscription.routing_key}."
26
+ queue.bind(connection.topic, routing_key: subscription.routing_key).subscribe do |delivery_info, meta_data, payload|
27
+ process_message(delivery_info, payload)
28
+ end
29
+ end
30
+
31
+ def process_message(delivery_info, payload)
32
+ puts "Processing message for #{delivery_info.routing_key}."
33
+ begin
34
+ operation = delivery_info.routing_key.split(".").last
35
+ subscription.send(operation, JSON.parse(payload))
36
+ rescue Exception => ex
37
+ puts " Error - #{ex.message}"
38
+ end
39
+ puts " Successfully processed!"
40
+ end
41
+
42
+ def queue
43
+ connection.channel.queue(subscription.queue_name, durable: true, auto_delete: false)
44
+ end
45
+
46
+ private
47
+
48
+ def connection
49
+ self.class.connection
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,15 @@
1
+ module MultipleMan
2
+ module Publisher
3
+ def Publisher.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ module ClassMethods
8
+ def publish(options = {})
9
+ after_commit ModelPublisher.new(:create, options), on: :create
10
+ after_commit ModelPublisher.new(:update, options), on: :update
11
+ after_commit ModelPublisher.new(:destroy, options), on: :destroy
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ module MultipleMan
2
+ module Subscriber
3
+ def Subscriber.included(base)
4
+ MultipleMan::ModelSubscriber.register(base)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,33 @@
1
+ module MultipleMan
2
+ class ModelPublisher
3
+
4
+ def initialize(operation, options = {})
5
+ self.operation = operation
6
+ self.options = options
7
+ end
8
+
9
+ def after_commit(record)
10
+ Connection.connect do |connection|
11
+ connection.topic.publish(record_data(record), routing_key: RoutingKey.new(record, operation).to_s)
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ attr_accessor :operation, :options
18
+
19
+ def connection
20
+ @connection ||= Connection.new
21
+ end
22
+
23
+ def record_data(record)
24
+ AttributeExtractor.new(record, fields).to_json
25
+ end
26
+
27
+ def fields
28
+ options[:fields]
29
+ end
30
+
31
+
32
+ end
33
+ end
@@ -0,0 +1,50 @@
1
+ module MultipleMan
2
+ class ModelSubscriber
3
+
4
+ @subscriptions = []
5
+ class << self
6
+ attr_accessor :subscriptions
7
+
8
+ def register(klass)
9
+ self.subscriptions << new(klass)
10
+ end
11
+ end
12
+
13
+ def initialize(klass)
14
+ self.klass = klass
15
+ end
16
+
17
+ attr_reader :klass
18
+
19
+ def create(data)
20
+ model = find_model(data)
21
+ model.remote_id = data.delete(:id)
22
+ model.attributes = data
23
+ model.save!
24
+ end
25
+
26
+ alias_method :update, :create
27
+
28
+ def destroy(data)
29
+ model = find_model(data)
30
+ model.destroy!
31
+ end
32
+
33
+ def routing_key
34
+ RoutingKey.new(klass).to_s
35
+ end
36
+
37
+ def queue_name
38
+ "#{MultipleMan.configuration.app_name}.#{klass.name}"
39
+ end
40
+
41
+ private
42
+
43
+ def find_model(data)
44
+ klass.find_by_remote_id(data[:id]) || klass.new
45
+ end
46
+
47
+ attr_writer :klass
48
+
49
+ end
50
+ end
@@ -0,0 +1,12 @@
1
+ require 'multiple_man'
2
+ require 'rails'
3
+
4
+ module MultipleMan
5
+ class Railtie < Rails::Railtie
6
+ railtie_name :multiple_man
7
+
8
+ rake_tasks do
9
+ load "multiple_man/tasks/worker.rake"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,27 @@
1
+ module MultipleMan
2
+ class RoutingKey
3
+ ALLOWED_OPERATIONS = [:create, :update, :destroy, :"#"]
4
+
5
+ def initialize(klass, operation = :"#")
6
+ self.klass = klass
7
+ self.operation = operation
8
+ end
9
+
10
+ def to_s
11
+ "#{klass.name}.#{operation}"
12
+ end
13
+
14
+ attr_reader :operation
15
+ attr_reader :klass
16
+
17
+ def operation=(value)
18
+ raise "Operation #{value} is not recognized" unless ALLOWED_OPERATIONS.include?(value)
19
+ @operation = value
20
+ end
21
+
22
+ def klass=(value)
23
+ @klass = (value.is_a?(Class) ? value : value.class)
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,14 @@
1
+ namespace :multiple_man do
2
+ desc "Run multiple man listeners"
3
+ task :worker => :environment do
4
+ Rails.application.eager_load!
5
+
6
+ MultipleMan::Connection.connect do |connection|
7
+ MultipleMan::Listener.start(connection)
8
+
9
+ while(true)
10
+ sleep 10
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ module MultipleMan
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,15 @@
1
+ require "multiple_man/version"
2
+
3
+ module MultipleMan
4
+ require 'multiple_man/railtie' if defined?(Rake)
5
+
6
+ require 'multiple_man/mixins/publisher'
7
+ require 'multiple_man/mixins/subscriber'
8
+ require 'multiple_man/configuration'
9
+ require 'multiple_man/model_subscriber'
10
+ require 'multiple_man/model_publisher'
11
+ require 'multiple_man/attribute_extractor'
12
+ require 'multiple_man/connection'
13
+ require 'multiple_man/routing_key'
14
+ require 'multiple_man/listener'
15
+ end
@@ -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 'multiple_man/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "multiple_man"
8
+ spec.version = MultipleMan::VERSION
9
+ spec.authors = ["Ryan Brunner"]
10
+ spec.email = ["ryan@influitive.com"]
11
+ spec.description = %q{MultipleMan syncs changes to ActiveRecord models via AMQP}
12
+ spec.summary = %q{MultipleMan syncs changes to ActiveRecord models via AMQP}
13
+ spec.homepage = ""
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 "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_runtime_dependency "bunny"
25
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe MultipleMan::AttributeExtractor do
4
+
5
+ MockClass = Struct.new(:a, :b, :c)
6
+ let(:object) { MockClass.new(1,2,3) }
7
+ subject { described_class.new(object, fields) }
8
+
9
+ context "without fields" do
10
+ it "should not be allowed" do
11
+ expect { described_class.new(object, nil) }.to raise_error
12
+ end
13
+ end
14
+
15
+ context "with fields" do
16
+ let(:fields) { [:a, :c] }
17
+ its(:data) { should == {a: 1, c: 3}}
18
+ its(:to_json) { should == '{"a":1,"c":3}'}
19
+ end
20
+
21
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe MultipleMan::Connection do
4
+
5
+ let(:mock_bunny) { double(Bunny) }
6
+
7
+ describe "connect" do
8
+ it "should open and close the connection" do
9
+ mock_bunny.should_receive(:start)
10
+ mock_bunny.should_receive(:close)
11
+ Bunny.should_receive(:new).and_return(mock_bunny)
12
+
13
+ described_class.connect
14
+ end
15
+ end
16
+
17
+ subject { described_class.new(mock_bunny) }
18
+
19
+ its(:topic_name) { should == MultipleMan.configuration.topic_name }
20
+
21
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe MultipleMan::Listener do
4
+ class MockClass1; end
5
+ class MockClass2; end
6
+
7
+ describe "start" do
8
+ it "should listen to each subscription" do
9
+ MultipleMan::ModelSubscriber.stub(:subscriptions).and_return([
10
+ mock1 = double(MultipleMan::ModelSubscriber, klass: MockClass1),
11
+ mock2 = double(MultipleMan::ModelSubscriber, klass: MockClass2)
12
+ ])
13
+
14
+ mock_listener = double(MultipleMan::Listener)
15
+ MultipleMan::Listener.should_receive(:new).twice.and_return(mock_listener)
16
+
17
+ # Would actually be two seperate objects in reality, this is for
18
+ # ease of stubbing.
19
+ mock_listener.should_receive(:listen).twice
20
+
21
+ MultipleMan::Listener.start(double(Bunny))
22
+ end
23
+ end
24
+
25
+ describe "listen" do
26
+ let(:connection_stub) { double(Bunny, channel: channel_stub, topic: 'app') }
27
+ let(:channel_stub) { double(Bunny::Channel, queue: queue_stub) }
28
+ let(:queue_stub) { double(Bunny::Queue, bind: bind_stub) }
29
+ let(:bind_stub) { double(:bind, subscribe: nil)}
30
+
31
+ before { MultipleMan::Listener.stub(:connection).and_return(connection_stub) }
32
+
33
+ it "should listen to the right topic, and for all updates to a model" do
34
+ listener = MultipleMan::Listener.new(double(MultipleMan::ModelSubscriber, klass: MockClass1, routing_key: "MockClass1.#", queue_name: "MockClass1"))
35
+ queue_stub.should_receive(:bind).with('app', routing_key: "MockClass1.#")
36
+ listener.listen
37
+ end
38
+ end
39
+
40
+ specify "process_message should send the correct data" do
41
+ subscriber = double(MultipleMan::ModelSubscriber, klass: MockClass1, routing_key: "MockClass1.#")
42
+ listener = MultipleMan::Listener.new(subscriber)
43
+ subscriber.should_receive(:create).with({"a" => 1, "b" => 2})
44
+ listener.process_message(OpenStruct.new(routing_key: "MockClass1.create"), '{"a":1,"b":2}')
45
+ end
46
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe MultipleMan::ModelPublisher do
4
+ let(:channel_stub) { double(Bunny::Channel, topic: topic_stub)}
5
+ let(:topic_stub) { double(Bunny::Exchange, publish: nil) }
6
+
7
+ before {
8
+ MultipleMan.configure do |config|
9
+ config.topic_name = "app"
10
+ end
11
+
12
+ MultipleMan::Connection.any_instance.stub(:channel).and_return(channel_stub)
13
+ }
14
+
15
+ class MockObject
16
+ def foo
17
+ "bar"
18
+ end
19
+
20
+ def model_name
21
+ OpenStruct.new(singular: "mock_object")
22
+ end
23
+ end
24
+
25
+ subject { described_class.new(:create, fields: [:foo]) }
26
+
27
+ describe "after_commit" do
28
+ it "should queue the update in the correct topic" do
29
+ channel_stub.should_receive(:topic).with("app")
30
+ described_class.new(:create, fields: [:foo]).after_commit(MockObject.new)
31
+ end
32
+ it "should send the jsonified version of the model to the correct routing key" do
33
+ MultipleMan::AttributeExtractor.any_instance.should_receive(:to_json).and_return('{"foo": "bar"}')
34
+ topic_stub.should_receive(:publish).with('{"foo": "bar"}', routing_key: "MockObject.create")
35
+ described_class.new(:create, fields: [:foo]).after_commit(MockObject.new)
36
+ end
37
+ end
38
+
39
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ describe MultipleMan::ModelSubscriber do
4
+ class MockClass
5
+ def remote_id=(value)
6
+ end
7
+ end
8
+
9
+ describe "register" do
10
+ it "should add a subscriber" do
11
+ MultipleMan::ModelSubscriber.register(MockClass)
12
+ MultipleMan::ModelSubscriber.subscriptions[0].klass.should == MockClass
13
+ end
14
+ end
15
+
16
+ describe "create" do
17
+ it "should create a new model" do
18
+ mock_object = MockClass.new
19
+ MockClass.stub(:find_by_remote_id).and_return(nil)
20
+ mock_object.should_receive(:attributes=)
21
+ mock_object.should_receive(:remote_id=)
22
+ MockClass.should_receive(:new).and_return(mock_object)
23
+ mock_object.should_receive(:save!)
24
+
25
+ MultipleMan::ModelSubscriber.new(MockClass).create({a: 1, b: 2})
26
+ end
27
+ end
28
+
29
+ describe "update" do
30
+ it "should find an existing model and update it" do
31
+ mock_object = MockClass.new
32
+ MockClass.should_receive(:find_by_remote_id).and_return(mock_object)
33
+ mock_object.should_receive(:attributes=)
34
+ mock_object.should_receive(:save!)
35
+
36
+ MultipleMan::ModelSubscriber.new(MockClass).update({id: 5, a: 1, b: 2})
37
+ end
38
+ end
39
+
40
+ describe "destroy" do
41
+ it "should destroy the model" do
42
+ mock_object = MockClass.new
43
+ MockClass.should_receive(:find_by_remote_id).and_return(mock_object)
44
+ mock_object.should_receive(:destroy!)
45
+
46
+ MultipleMan::ModelSubscriber.new(MockClass).destroy({id: 1})
47
+ end
48
+ end
49
+
50
+ specify "routing_key should be the model name and a wildcard" do
51
+ MultipleMan::ModelSubscriber.new(MockClass).routing_key.should == "MockClass.#"
52
+ end
53
+
54
+ specify "queue name should be the app name + class" do
55
+ MultipleMan.configure do |config|
56
+ config.app_name = "test"
57
+ end
58
+ MultipleMan::ModelSubscriber.new(MockClass).queue_name.should == "test.MockClass"
59
+ end
60
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe MultipleMan::Publisher do
4
+ class MockClass
5
+ class << self
6
+ attr_accessor :subscriber
7
+
8
+ def after_commit(subscriber, operation)
9
+ self.subscriber = subscriber
10
+ end
11
+ end
12
+
13
+ include MultipleMan::Publisher
14
+
15
+ def save
16
+ self.class.subscriber.after_commit(self)
17
+ end
18
+ end
19
+
20
+ describe "including" do
21
+ it "should add an after commit hook" do
22
+ # once for each operation
23
+ MockClass.should_receive(:after_commit).exactly(3).times
24
+ MockClass.publish
25
+ end
26
+ end
27
+
28
+ describe "publish" do
29
+ before { MockClass.publish }
30
+ it "should tell ModelPublisher to publish" do
31
+ my_mock = MockClass.new
32
+ mock_publisher = double(MultipleMan::ModelPublisher)
33
+ MultipleMan::ModelPublisher.any_instance.should_receive(:after_commit).with(my_mock)
34
+ my_mock.save
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe MultipleMan::RoutingKey do
4
+ class MockObject
5
+ end
6
+
7
+ describe "to_s" do
8
+ subject { described_class.new(MockObject.new, operation).to_s }
9
+
10
+ context "creating" do
11
+ let(:operation) { :create }
12
+ it { should == "MockObject.create" }
13
+ end
14
+
15
+ context "updating" do
16
+ let(:operation) { :update }
17
+ it { should == "MockObject.update" }
18
+ end
19
+
20
+ context "destroying" do
21
+ let(:operation) { :destroy }
22
+ it { should == "MockObject.destroy" }
23
+ end
24
+
25
+ context "not specified" do
26
+ subject { described_class.new(MockObject.new).to_s }
27
+ it { should == "MockObject.#" }
28
+ end
29
+ end
30
+
31
+ describe "operation=" do
32
+ [:create, :update, :destroy, :"#"].each do |op|
33
+ it "should allow #{op}" do
34
+ rk = described_class.new(Object)
35
+ rk.operation = op
36
+ rk.operation.should == op
37
+ end
38
+ end
39
+
40
+ ["new", nil, "", "create"].each do |op|
41
+ it "should not allow #{op}" do
42
+ rk = described_class.new(Object)
43
+ expect { rk.operation = op }.to raise_error
44
+ end
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,5 @@
1
+ require 'bundler/setup'
2
+ require 'bunny'
3
+ require 'ostruct'
4
+
5
+ require_relative '../lib/multiple_man.rb'
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe MultipleMan::Subscriber do
4
+ class MockClass
5
+
6
+ end
7
+
8
+ describe "inclusion" do
9
+ it "should register itself" do
10
+ MultipleMan::ModelSubscriber.should_receive(:register).with(MockClass)
11
+ MockClass.send(:include, MultipleMan::Subscriber)
12
+ end
13
+ end
14
+ end
metadata ADDED
@@ -0,0 +1,138 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: multiple_man
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ryan Brunner
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-02 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: 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: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bunny
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: MultipleMan syncs changes to ActiveRecord models via AMQP
70
+ email:
71
+ - ryan@influitive.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
+ - lib/multiple_man.rb
83
+ - lib/multiple_man/attribute_extractor.rb
84
+ - lib/multiple_man/configuration.rb
85
+ - lib/multiple_man/connection.rb
86
+ - lib/multiple_man/listener.rb
87
+ - lib/multiple_man/mixins/publisher.rb
88
+ - lib/multiple_man/mixins/subscriber.rb
89
+ - lib/multiple_man/model_publisher.rb
90
+ - lib/multiple_man/model_subscriber.rb
91
+ - lib/multiple_man/railtie.rb
92
+ - lib/multiple_man/routing_key.rb
93
+ - lib/multiple_man/tasks/worker.rake
94
+ - lib/multiple_man/version.rb
95
+ - multiple_man.gemspec
96
+ - spec/attribute_extractor_spec.rb
97
+ - spec/connection_spec.rb
98
+ - spec/listener_spec.rb
99
+ - spec/model_publisher_spec.rb
100
+ - spec/model_subscriber_spec.rb
101
+ - spec/publisher_spec.rb
102
+ - spec/routing_key_spec.rb
103
+ - spec/spec_helper.rb
104
+ - spec/subscriber_spec.rb
105
+ homepage: ''
106
+ licenses:
107
+ - MIT
108
+ metadata: {}
109
+ post_install_message:
110
+ rdoc_options: []
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - '>='
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ requirements: []
124
+ rubyforge_project:
125
+ rubygems_version: 2.1.11
126
+ signing_key:
127
+ specification_version: 4
128
+ summary: MultipleMan syncs changes to ActiveRecord models via AMQP
129
+ test_files:
130
+ - spec/attribute_extractor_spec.rb
131
+ - spec/connection_spec.rb
132
+ - spec/listener_spec.rb
133
+ - spec/model_publisher_spec.rb
134
+ - spec/model_subscriber_spec.rb
135
+ - spec/publisher_spec.rb
136
+ - spec/routing_key_spec.rb
137
+ - spec/spec_helper.rb
138
+ - spec/subscriber_spec.rb