untied-publisher 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/untied-publisher/doorkeeper.rb +32 -14
- data/lib/untied-publisher/event.rb +11 -5
- data/lib/untied-publisher/observer.rb +9 -4
- data/lib/untied-publisher/version.rb +1 -1
- data/spec/doorkeeper_spec.rb +46 -1
- data/spec/event_spec.rb +3 -2
- data/spec/producer_spec.rb +2 -1
- data/spec/publisher_observer_spec.rb +17 -17
- data/spec/spec_helper.rb +7 -0
- data/untied-publisher.gemspec +1 -0
- metadata +19 -5
@@ -12,7 +12,7 @@ module Untied
|
|
12
12
|
# The following publisher watches the User after_create event:
|
13
13
|
#
|
14
14
|
# class MyDoorkeeper
|
15
|
-
# include Untied::Doorkeeper
|
15
|
+
# include Untied::Publisher::Doorkeeper
|
16
16
|
#
|
17
17
|
# def initialize
|
18
18
|
# watch User, :after_create
|
@@ -27,14 +27,15 @@ module Untied
|
|
27
27
|
# Watches ActiveRecord lifecycle callbacks for some Class
|
28
28
|
#
|
29
29
|
# class Doorkeeper
|
30
|
-
# include Untied::Doorkeeper
|
30
|
+
# include Untied::Publisher::Doorkeeper
|
31
31
|
# end
|
32
32
|
#
|
33
33
|
# pub.new.watch(User, :after_create)
|
34
34
|
# User.create # sends the user into the wire
|
35
35
|
def watch(*args)
|
36
36
|
entity = args.shift
|
37
|
-
|
37
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
38
|
+
observed << [entity, args, options]
|
38
39
|
end
|
39
40
|
|
40
41
|
# Returns the list of classes watched
|
@@ -46,7 +47,7 @@ module Untied
|
|
46
47
|
# For example, if the publisher is defined as follows:
|
47
48
|
#
|
48
49
|
# class MyDoorkeeper
|
49
|
-
# include Untided::Doorkeeper
|
50
|
+
# include Untided::Publisher::Doorkeeper
|
50
51
|
#
|
51
52
|
# def initialize
|
52
53
|
# watch User, :after_create
|
@@ -57,20 +58,37 @@ module Untied
|
|
57
58
|
# _notify_untied__publisher_observer_for_after_create is created on User's
|
58
59
|
# model. This method is called when the after_create callback is fired.
|
59
60
|
def define_callbacks
|
61
|
+
observed.each do |(klass, callbacks, options)|
|
62
|
+
ActiveRecord::Callbacks::CALLBACKS.each do |callback|
|
63
|
+
next unless callbacks.include?(callback)
|
64
|
+
setup_observer(klass, callback, options)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
protected
|
70
|
+
|
71
|
+
def setup_observer(klass, callback, options={})
|
60
72
|
observer = Untied::Publisher::Observer
|
61
73
|
observer_name = observer.name.underscore.gsub('/', '__')
|
74
|
+
notifier_meth = :"_notify_#{observer_name}_for_#{callback}"
|
62
75
|
|
63
|
-
|
64
|
-
|
65
|
-
next unless callbacks.include?(callback)
|
66
|
-
callback_meth = :"_notify_#{observer_name}_for_#{callback}"
|
67
|
-
unless klass.respond_to?(callback_meth)
|
68
|
-
klass.send(:define_method, callback_meth) do
|
69
|
-
observer.instance.send(callback, self)
|
70
|
-
end
|
71
|
-
klass.send(callback, callback_meth)
|
72
|
-
end
|
76
|
+
if define_notifier_method(klass, observer, callback, notifier_meth, options)
|
77
|
+
klass.send(callback, notifier_meth)
|
73
78
|
end
|
79
|
+
|
80
|
+
klass
|
81
|
+
end
|
82
|
+
|
83
|
+
def define_method_on(klass, method_name, &block)
|
84
|
+
unless klass.respond_to?(method_name)
|
85
|
+
klass.send(:define_method, method_name, &block)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def define_notifier_method(klass, observer, callback, method_name, options={})
|
90
|
+
define_method_on(klass, method_name) do
|
91
|
+
observer.instance.send(callback, self, options)
|
74
92
|
end
|
75
93
|
end
|
76
94
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
-
|
2
|
+
|
3
|
+
require 'representable/json'
|
3
4
|
|
4
5
|
module Untied
|
5
6
|
class Event
|
6
|
-
include ActiveModel::Serializers::JSON
|
7
7
|
attr_accessor :name, :payload, :origin
|
8
8
|
|
9
9
|
def initialize(attrs)
|
@@ -19,9 +19,15 @@ module Untied
|
|
19
19
|
@payload = @config.delete(:payload)
|
20
20
|
@origin = @config.delete(:origin)
|
21
21
|
end
|
22
|
+
end
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
24
|
+
module EventRepresenter
|
25
|
+
include Representable::JSON
|
26
|
+
|
27
|
+
self.representation_wrap = true
|
28
|
+
|
29
|
+
property :name
|
30
|
+
property :payload
|
31
|
+
property :origin
|
26
32
|
end
|
27
33
|
end
|
@@ -18,7 +18,8 @@ module Untied
|
|
18
18
|
|
19
19
|
def method_missing(name, model, *args, &block)
|
20
20
|
if ActiveRecord::Callbacks::CALLBACKS.include?(name)
|
21
|
-
|
21
|
+
options = args.first.is_a?(Hash) ? args.first : {}
|
22
|
+
produce_event(name, model, options)
|
22
23
|
else
|
23
24
|
super
|
24
25
|
end
|
@@ -26,9 +27,13 @@ module Untied
|
|
26
27
|
|
27
28
|
protected
|
28
29
|
|
29
|
-
def produce_event(callback, model)
|
30
|
-
|
31
|
-
|
30
|
+
def produce_event(callback, model, options={})
|
31
|
+
if representer = options[:with_representer]
|
32
|
+
model = model.extend(representer)
|
33
|
+
end
|
34
|
+
e = Event.new(:name => callback,
|
35
|
+
:payload => model, :origin => Publisher.config.service_name)
|
36
|
+
e.extend(EventRepresenter)
|
32
37
|
producer.publish(e)
|
33
38
|
end
|
34
39
|
|
data/spec/doorkeeper_spec.rb
CHANGED
@@ -8,13 +8,21 @@ module Untied
|
|
8
8
|
class ::Doorkeeper
|
9
9
|
include Untied::Publisher::Doorkeeper
|
10
10
|
end
|
11
|
+
|
12
|
+
module SomeRepresenter; end
|
11
13
|
end
|
12
14
|
let(:doorkeeper) { ::Doorkeeper.new }
|
13
15
|
|
14
16
|
context "#watch" do
|
15
17
|
it "should add observed classes to observed list" do
|
16
18
|
doorkeeper.watch(User, :after_create)
|
17
|
-
doorkeeper.observed.should == [[User, [:after_create]]]
|
19
|
+
doorkeeper.observed.should == [[User, [:after_create], {}]]
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should accept a constant" do
|
23
|
+
opts = { :represent_with => SomeRepresenter }
|
24
|
+
doorkeeper.watch(User, :after_create, opts)
|
25
|
+
doorkeeper.observed.should == [[User, [:after_create], opts]]
|
18
26
|
end
|
19
27
|
end
|
20
28
|
|
@@ -48,6 +56,43 @@ module Untied
|
|
48
56
|
Post.new.should \
|
49
57
|
respond_to(:_notify_untied__publisher__observer_for_after_create)
|
50
58
|
end
|
59
|
+
|
60
|
+
context "with :represent_with option" do
|
61
|
+
let(:observer) do
|
62
|
+
observer = double('Untied::Publisher::Observer')
|
63
|
+
observer.stub(:name).and_return("Untied::Publisher::Observer")
|
64
|
+
observer.stub(:after_create)
|
65
|
+
observer
|
66
|
+
end
|
67
|
+
before do
|
68
|
+
Observer.stub(:instance).and_return(observer)
|
69
|
+
doorkeeper.watch(Post, :after_create, :represent_with => SomeRepresenter)
|
70
|
+
doorkeeper.define_callbacks
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should extend the entity with the constant" do
|
74
|
+
observer.should_receive(:after_create).
|
75
|
+
with(an_instance_of(Post), { :represent_with => SomeRepresenter })
|
76
|
+
Post.create
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "Observed#_notify_untied__publisher__observer_for_[callback]" do
|
82
|
+
let(:observer) do
|
83
|
+
observer = double('Untied::Publisher::Observer')
|
84
|
+
observer.stub(:name).and_return("Untied::Publisher::Observer")
|
85
|
+
end
|
86
|
+
before do
|
87
|
+
doorkeeper.watch(User, :after_create)
|
88
|
+
Observer.stub(:instance).and_return(observer)
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should invoke observer method" do
|
92
|
+
observer.should_receive(:after_create)
|
93
|
+
doorkeeper.define_callbacks
|
94
|
+
User.new.send(:_notify_untied__publisher__observer_for_after_create)
|
95
|
+
end
|
51
96
|
end
|
52
97
|
|
53
98
|
context "#observed_classes" do
|
data/spec/event_spec.rb
CHANGED
@@ -28,8 +28,9 @@ module Untied
|
|
28
28
|
end
|
29
29
|
|
30
30
|
it "should include the origin service name" do
|
31
|
-
|
32
|
-
|
31
|
+
e = Event.new(:name => :after_create,
|
32
|
+
:payload => person, :origin => "core")
|
33
|
+
e.origin.should == "core"
|
33
34
|
end
|
34
35
|
end
|
35
36
|
|
data/spec/producer_spec.rb
CHANGED
@@ -33,7 +33,8 @@ module Untied
|
|
33
33
|
context "#publish" do
|
34
34
|
it "should call Channel#publish" do
|
35
35
|
mock_reactor_and_amqp do |channel|
|
36
|
-
e = Event.new(:name => "create",
|
36
|
+
e = Event.new(:name => "create",
|
37
|
+
:payload => { :foo => 'bar' }, :origin => :core)
|
37
38
|
channel.topic.should_receive(:publish)
|
38
39
|
producer = Producer.new(:channel => channel, :deliver_messages => true)
|
39
40
|
producer.publish(e)
|
@@ -3,18 +3,16 @@ require 'spec_helper'
|
|
3
3
|
|
4
4
|
module Untied
|
5
5
|
module Publisher
|
6
|
-
describe
|
6
|
+
describe Observer do
|
7
7
|
before do
|
8
|
-
class
|
8
|
+
class ::FooDoorkeeper
|
9
9
|
include Untied::Publisher::Doorkeeper
|
10
|
-
def initialize
|
11
|
-
watch(User, :after_create)
|
12
|
-
watch(User, :after_update)
|
13
|
-
end
|
14
10
|
end
|
15
|
-
Untied::Publisher.config.doorkeeper =
|
11
|
+
Untied::Publisher.config.doorkeeper = ::FooDoorkeeper
|
12
|
+
module UserRepresenter
|
13
|
+
end
|
16
14
|
end
|
17
|
-
|
15
|
+
let(:doorkeeper) { ::FooDoorkeeper.new }
|
18
16
|
|
19
17
|
context ".instance" do
|
20
18
|
it "should raise a friendly error when no doorkeeper is defined" do
|
@@ -27,17 +25,19 @@ module Untied
|
|
27
25
|
end
|
28
26
|
|
29
27
|
context "ActiveRecord::Callbacks" do
|
30
|
-
|
31
|
-
Observer.instance.should_receive(:after_create)
|
32
|
-
User.create
|
33
|
-
end
|
28
|
+
let(:user) { User.create(:name => "Guila") }
|
34
29
|
|
35
|
-
it "should
|
36
|
-
Observer.instance.should_receive(:
|
37
|
-
Observer.instance.
|
30
|
+
it "should proxy #produce_event" do
|
31
|
+
Observer.instance.should_receive(:produce_event)
|
32
|
+
Observer.instance.send(:after_create, user)
|
33
|
+
end
|
38
34
|
|
39
|
-
|
40
|
-
user.
|
35
|
+
context "passing :with_representer" do
|
36
|
+
it "should call user.extend(UserRepresenter)" do
|
37
|
+
user.should_receive(:extend).with(UserRepresenter)
|
38
|
+
Observer.instance.
|
39
|
+
send(:after_create, user, :with_representer => UserRepresenter)
|
40
|
+
end
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
data/spec/spec_helper.rb
CHANGED
@@ -19,6 +19,13 @@ RSpec.configure do |config|
|
|
19
19
|
config.treat_symbols_as_metadata_keys_with_true_values = true
|
20
20
|
config.run_all_when_everything_filtered = true
|
21
21
|
config.filter_run :focus
|
22
|
+
config.before do
|
23
|
+
# Redefining models for each it
|
24
|
+
%w(User Post).each do |klass|
|
25
|
+
Object.send(:remove_const, :"#{klass}")
|
26
|
+
Object.const_set(klass, Class.new(ActiveRecord::Base))
|
27
|
+
end
|
28
|
+
end
|
22
29
|
|
23
30
|
# Run specs in random order to surface order dependencies. If you find an
|
24
31
|
# order dependency and want to debug it, you can fix the order by providing
|
data/untied-publisher.gemspec
CHANGED
@@ -25,6 +25,7 @@ Gem::Specification.new do |gem|
|
|
25
25
|
gem.add_runtime_dependency "amqp"
|
26
26
|
gem.add_runtime_dependency "configurable"
|
27
27
|
gem.add_runtime_dependency "json"
|
28
|
+
gem.add_runtime_dependency "representable"
|
28
29
|
|
29
30
|
if RUBY_VERSION < "1.9"
|
30
31
|
gem.add_development_dependency "ruby-debug"
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: untied-publisher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 4
|
10
|
+
version: 0.0.4
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Guilherme Cavalcanti
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-
|
18
|
+
date: 2012-11-06 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
version_requirements: &id001 !ruby/object:Gem::Requirement
|
@@ -126,9 +126,23 @@ dependencies:
|
|
126
126
|
- 0
|
127
127
|
version: "0"
|
128
128
|
prerelease: false
|
129
|
+
type: :runtime
|
130
|
+
name: representable
|
131
|
+
requirement: *id008
|
132
|
+
- !ruby/object:Gem::Dependency
|
133
|
+
version_requirements: &id009 !ruby/object:Gem::Requirement
|
134
|
+
none: false
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
hash: 3
|
139
|
+
segments:
|
140
|
+
- 0
|
141
|
+
version: "0"
|
142
|
+
prerelease: false
|
129
143
|
type: :development
|
130
144
|
name: ruby-debug
|
131
|
-
requirement: *
|
145
|
+
requirement: *id009
|
132
146
|
description: Provides the Publisher part of the Untied gem.
|
133
147
|
email:
|
134
148
|
- guiocavalcanti@gmail.com
|