cony 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ cony
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 1.9.3-p484
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,43 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ cony (1.0.0)
5
+ activesupport (>= 3)
6
+ bunny (~> 1.1.7)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ activesupport (4.1.0)
12
+ i18n (~> 0.6, >= 0.6.9)
13
+ json (~> 1.7, >= 1.7.7)
14
+ minitest (~> 5.1)
15
+ thread_safe (~> 0.1)
16
+ tzinfo (~> 1.1)
17
+ amq-protocol (1.9.2)
18
+ bunny (1.1.9)
19
+ amq-protocol (>= 1.9.2)
20
+ diff-lcs (1.2.5)
21
+ i18n (0.6.9)
22
+ json (1.8.1)
23
+ minitest (5.3.3)
24
+ rake (10.3.0)
25
+ rspec (2.14.1)
26
+ rspec-core (~> 2.14.0)
27
+ rspec-expectations (~> 2.14.0)
28
+ rspec-mocks (~> 2.14.0)
29
+ rspec-core (2.14.8)
30
+ rspec-expectations (2.14.5)
31
+ diff-lcs (>= 1.1.3, < 2.0)
32
+ rspec-mocks (2.14.6)
33
+ thread_safe (0.3.3)
34
+ tzinfo (1.1.0)
35
+ thread_safe (~> 0.1)
36
+
37
+ PLATFORMS
38
+ ruby
39
+
40
+ DEPENDENCIES
41
+ cony!
42
+ rake (~> 10.0)
43
+ rspec (~> 2.12)
data/README.md ADDED
@@ -0,0 +1,96 @@
1
+ # :rabbit: Cony [![Build Status](https://travis-ci.org/ninech/cony.svg)](https://travis-ci.org/ninech/cony)
2
+
3
+ Cony sends notifications about the lifecycle of your models via AMQP.
4
+
5
+
6
+ ## Setup
7
+
8
+ ### Rails 3 & 4
9
+
10
+ In Rails 3 and 4, add this to your Gemfile and run the bundle command.
11
+
12
+ ```ruby
13
+ gem 'cony'
14
+ ```
15
+
16
+ To configure the AMQP-Settings, use an initializer (e.g.
17
+ `config/initializers/cony.rb`) with the following content.
18
+
19
+ ```ruby
20
+ Cony.configure do |config|
21
+ config.amqp = {
22
+ host: 'localhost',
23
+ exchange: 'organization.application'
24
+ }
25
+ # config.durable = false
26
+ end
27
+ ```
28
+
29
+
30
+ ## Getting Started
31
+
32
+ To enable the notifications for a model, you just need to include the
33
+ corresponding class. For `ActiveRecord` use the following snippet.
34
+
35
+ ```ruby
36
+ class ExampleModel < ActiveRecord::Base
37
+ include Cony::ActiveRecord
38
+ end
39
+ ```
40
+
41
+ ## Message Format
42
+
43
+ The routing key for the messages have a format of
44
+ `model_name_with_underscore.mutation.action`.
45
+
46
+ It will append the id of the model and the detected changes to the payload of the message.
47
+
48
+ ### Create
49
+
50
+ A create for a `Example::Model` model will have a routing key of
51
+ `example/model.mutation.create`.
52
+
53
+ The sent JSON structure will look like this:
54
+
55
+ ```json
56
+ {
57
+ "id": 1337,
58
+ "changes": [
59
+ { "name": { "old": null, "new": "value" } },
60
+ { "description": { "old": null, "new": "value" } }
61
+ ]
62
+ }
63
+ ```
64
+
65
+
66
+ ### Update
67
+
68
+ An update for a `Example::Model` model will have a routing key of
69
+ `example/model.mutation.update`.
70
+
71
+ The sent JSON structure will look like this:
72
+
73
+ ```json
74
+ {
75
+ "id": 1337,
76
+ "changes": [
77
+ { "name": { "old": "old-value", "new": "new-value" } }
78
+ ]
79
+ }
80
+ ```
81
+
82
+
83
+ ### Destroy
84
+
85
+ A destroy event for a `Example::Model` model will have a routing key of
86
+ `example/model.mutation.destroy`.
87
+
88
+ The sent JSON structure will look like this:
89
+
90
+ ```json
91
+ {
92
+ "id": 1337,
93
+ "changes": []
94
+ }
95
+ ```
96
+
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require 'bundler'
4
+ require 'rake'
5
+ require 'bundler/gem_tasks'
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
data/bin/cony-receive ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'amqp'
4
+
5
+ EventMachine.run do
6
+ AMQP.connect do |connection|
7
+ channel = AMQP::Channel.new(connection)
8
+ # topic exchange name can be any string
9
+ exchange = channel.topic("cony-test", durable: true)
10
+
11
+ # Subscribers.
12
+ channel.queue("", :exclusive => true) do |queue|
13
+ queue.bind(exchange, :routing_key => "#").subscribe do |headers, payload|
14
+ puts payload.inspect
15
+ end
16
+ end
17
+ end
18
+ end
data/cony.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ $:.push File.expand_path('../lib', __FILE__)
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'cony'
7
+ s.version = File.read(File.expand_path('../VERSION', __FILE__)).strip
8
+ s.authors = ['Raffael Schmid']
9
+ s.email = ['info@nine.ch']
10
+ s.homepage = 'http://github.com/ninech/'
11
+ s.license = 'MIT'
12
+ s.summary = 'Automatically sends notifications via AMQP when a model has been changed.'
13
+ s.description = 'Automatically sends notifications via AMQP when a model has been changed.'
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ['lib']
19
+
20
+ s.add_development_dependency 'rake', '~> 10.0'
21
+ s.add_development_dependency 'rspec', '~> 2.12'
22
+
23
+ s.add_runtime_dependency 'activesupport', '>= 3'
24
+ s.add_runtime_dependency 'bunny', '~> 1.1.7'
25
+ end
@@ -0,0 +1,48 @@
1
+ require 'active_support/core_ext/string/inflections'
2
+
3
+ require 'cony'
4
+ require 'cony/amqp_connection_handler'
5
+
6
+ module Cony
7
+ module ActiveRecord
8
+
9
+ extend ActiveSupport::Concern
10
+
11
+ included do
12
+ after_create :cony_send_create_notify
13
+ after_update :cony_send_update_notify
14
+ after_destroy :cony_send_destroy_notify
15
+ end
16
+
17
+ def cony_send_create_notify
18
+ publish(:create)
19
+ end
20
+
21
+ def cony_send_update_notify
22
+ publish(:update)
23
+ end
24
+
25
+ def cony_send_destroy_notify
26
+ publish(:destroy)
27
+ end
28
+
29
+
30
+ private
31
+ def publish(type)
32
+ amqp_connection.publish(
33
+ {id: self.id, changes: cony_changes},
34
+ "#{self.class.name.underscore}.mutation.#{type}")
35
+ end
36
+
37
+ def amqp_connection
38
+ @amqp_connection ||= Cony::AMQPConnectionHandler.new(Cony.config.amqp)
39
+ end
40
+
41
+ def cony_changes
42
+ changes.map do |name, change|
43
+ {name => {old: change.first, new: change.last}}
44
+ end
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,24 @@
1
+ require 'bunny'
2
+ require 'json'
3
+
4
+ module Cony
5
+ class AMQPConnectionHandler
6
+
7
+ def initialize(config)
8
+ @config = config
9
+ end
10
+
11
+ def publish(message, routing_key)
12
+ Bunny.run(@config) do |connection|
13
+ exchange = connection.exchange(@config[:exchange], type: :topic, durable: Cony.config.durable)
14
+ exchange.publish(message.to_json,
15
+ key: routing_key,
16
+ mandatory: false,
17
+ immediate: false,
18
+ persistent: Cony.config.durable,
19
+ content_type: 'application/json')
20
+ end
21
+ end
22
+
23
+ end
24
+ end
data/lib/cony.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'active_support/core_ext/object/deep_dup'
2
+ require 'active_support/configurable'
3
+
4
+ require 'cony/active_record'
5
+
6
+ module Cony
7
+ include ActiveSupport::Configurable
8
+
9
+ defaults = {
10
+ durable: false
11
+ }
12
+
13
+ self.config.merge! defaults.deep_dup
14
+
15
+ end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ require 'cony/active_record'
4
+
5
+ describe Cony::ActiveRecord do
6
+
7
+ let(:amqp_connection) { double('Cony::AMQPConnectionHandler') }
8
+ let(:id) { 1337 }
9
+ let(:active_record_changes) { {name: ['old', 'new']} }
10
+ let(:cony_changes) { [{name: {old: 'old', new: 'new'}}] }
11
+
12
+ let(:model) do
13
+ eval <<-EOF
14
+ Class.new do
15
+ def self.after_create(callback); end
16
+ def self.after_update(callback); end
17
+ def self.after_destroy(callback); end
18
+ def self.name; "Anonymaus::Klass"; end
19
+ def id; #{id}; end
20
+ def changes; #{active_record_changes}; end
21
+
22
+ include Cony::ActiveRecord
23
+ end
24
+ EOF
25
+ end
26
+
27
+ before do
28
+ Cony::AMQPConnectionHandler.stub(:new).and_return(amqp_connection)
29
+ end
30
+
31
+ subject { model.new }
32
+
33
+ describe '#cony_send_create_notify' do
34
+ it 'uses the amqp connection to send the notify' do
35
+ amqp_connection.should_receive(:publish).with({id: id, changes: cony_changes}, 'anonymaus/klass.mutation.create')
36
+ subject.cony_send_create_notify
37
+ end
38
+ end
39
+
40
+ describe '#cony_send_update_notify' do
41
+ it 'uses the amqp connection to send the notify' do
42
+ amqp_connection.should_receive(:publish).with({id: id, changes: cony_changes}, 'anonymaus/klass.mutation.update')
43
+ subject.cony_send_update_notify
44
+ end
45
+ end
46
+
47
+ describe '#cony_send_destroy_notify' do
48
+ it 'uses the amqp connection to send the notify' do
49
+ amqp_connection.should_receive(:publish).with({id: id, changes: cony_changes}, 'anonymaus/klass.mutation.destroy')
50
+ subject.cony_send_destroy_notify
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ require 'cony/amqp_connection_handler'
4
+
5
+ describe Cony::AMQPConnectionHandler do
6
+
7
+ let(:config) { {exchange: 'bunny-tests'} }
8
+ let(:handler) { Cony::AMQPConnectionHandler.new(config) }
9
+ let(:message) { 'Bunnies are connies' }
10
+ let(:routing_key) { 'bunny.info' }
11
+ let(:exchange_double) do
12
+ double('Exchange double').tap do |exc|
13
+ exc.stub(:publish)
14
+ end
15
+ end
16
+ let(:connection_double) do
17
+ double('Connection double').tap do |conn|
18
+ conn.stub(:exchange).and_return(exchange_double)
19
+ end
20
+ end
21
+
22
+ subject { handler }
23
+
24
+ before do
25
+ Bunny.stub(:run).and_yield(connection_double)
26
+ end
27
+
28
+ it 'uses bunny to publish a message' do
29
+ Bunny.should_receive(:run)
30
+ subject.publish(message, routing_key)
31
+ end
32
+
33
+ it 'configures the exchange correctly' do
34
+ connection_double.should_receive(:exchange).with('bunny-tests', type: :topic, durable: false)
35
+ subject.publish(message, routing_key)
36
+ end
37
+
38
+ it 'publishes the message' do
39
+ publish_options = {
40
+ key: routing_key,
41
+ mandatory: false,
42
+ immediate: false,
43
+ persistent: false,
44
+ content_type: 'application/json',
45
+ }
46
+ exchange_double.should_receive(:publish)
47
+ .with('"Bunnies are connies"', publish_options)
48
+ subject.publish(message, routing_key)
49
+ end
50
+
51
+ end
@@ -0,0 +1,17 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ RSpec.configure do |config|
8
+ config.treat_symbols_as_metadata_keys_with_true_values = true
9
+ config.run_all_when_everything_filtered = true
10
+ config.filter_run :focus
11
+
12
+ # Run specs in random order to surface order dependencies. If you find an
13
+ # order dependency and want to debug it, you can fix the order by providing
14
+ # the seed, which is printed after each run.
15
+ # --seed 1234
16
+ config.order = 'random'
17
+ end
metadata ADDED
@@ -0,0 +1,130 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cony
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Raffael Schmid
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-04-16 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '10.0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '10.0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '2.12'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '2.12'
46
+ - !ruby/object:Gem::Dependency
47
+ name: activesupport
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '3'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '3'
62
+ - !ruby/object:Gem::Dependency
63
+ name: bunny
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 1.1.7
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 1.1.7
78
+ description: Automatically sends notifications via AMQP when a model has been changed.
79
+ email:
80
+ - info@nine.ch
81
+ executables:
82
+ - cony-receive
83
+ extensions: []
84
+ extra_rdoc_files: []
85
+ files:
86
+ - .rspec
87
+ - .ruby-gemset
88
+ - .ruby-version
89
+ - Gemfile
90
+ - Gemfile.lock
91
+ - README.md
92
+ - Rakefile
93
+ - VERSION
94
+ - bin/cony-receive
95
+ - cony.gemspec
96
+ - lib/cony.rb
97
+ - lib/cony/active_record.rb
98
+ - lib/cony/amqp_connection_handler.rb
99
+ - spec/cony/active_record_spec.rb
100
+ - spec/cony/amqp_connection_handler_spec.rb
101
+ - spec/spec_helper.rb
102
+ homepage: http://github.com/ninech/
103
+ licenses:
104
+ - MIT
105
+ post_install_message:
106
+ rdoc_options: []
107
+ require_paths:
108
+ - lib
109
+ required_ruby_version: !ruby/object:Gem::Requirement
110
+ none: false
111
+ requirements:
112
+ - - ! '>='
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ! '>='
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ requirements: []
122
+ rubyforge_project:
123
+ rubygems_version: 1.8.23
124
+ signing_key:
125
+ specification_version: 3
126
+ summary: Automatically sends notifications via AMQP when a model has been changed.
127
+ test_files:
128
+ - spec/cony/active_record_spec.rb
129
+ - spec/cony/amqp_connection_handler_spec.rb
130
+ - spec/spec_helper.rb