cony 1.0.0

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