event_aggregator 0.0.2 → 1.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +57 -9
- data/event_aggregator.gemspec +2 -0
- data/lib/event_aggregator.rb +1 -0
- data/lib/event_aggregator/aggregator.rb +39 -11
- data/lib/event_aggregator/listener.rb +8 -66
- data/lib/event_aggregator/message.rb +20 -4
- data/lib/event_aggregator/message_job.rb +9 -0
- data/lib/event_aggregator/version.rb +1 -1
- data/spec/factories.rb +2 -2
- data/spec/lib/event_aggregator/aggregator_spec.rb +110 -60
- data/spec/lib/event_aggregator/listener_spec.rb +13 -43
- data/spec/lib/event_aggregator/message_spec.rb +5 -10
- data/spec/spec_helper.rb +2 -0
- metadata +22 -5
data/README.md
CHANGED
@@ -1,10 +1,8 @@
|
|
1
1
|
# EventAggregator
|
2
2
|
|
3
|
-
|
3
|
+
The gem 'event_aggregator' is designed for usie with the event aggregator pattern in Ruby.
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
An event aggregator is essentially a message passing service that aims at decoupeling object communication and that lets
|
5
|
+
An event aggregator is essentially a message passing service that aims at decoupeling objects in your code. This is achieved with messages that has a type and some data. A message might be produced when an event, or other condition, occurs within one object or class that might be of interest to thers. This object or class then put all relevant data into the message and publishes it. This message will then be distributed to all other objects that want to recieve this message type. This way the object or class that first got knowledge of the condition do not need to be aware of every other object that might be interested in knowing about this. It also removes the need for this class to implement any listeners and so forth. This way the listener, the receiver of the message, does not need to know that the sender even exists. This will help your code be a lot cleaner and remove a lot of bug-producing couplings between objects.
|
8
6
|
|
9
7
|
## Installation
|
10
8
|
|
@@ -30,9 +28,9 @@ Or install it yourself as:
|
|
30
28
|
class Foo
|
31
29
|
include EventAggregator::Listener
|
32
30
|
def initialize()
|
33
|
-
|
31
|
+
message_type_register( "foo", lambda{|data| puts "bar" } )
|
34
32
|
|
35
|
-
|
33
|
+
message_type_register( "foo2", method(:handle_message) )
|
36
34
|
end
|
37
35
|
|
38
36
|
def handle_message(data)
|
@@ -48,6 +46,47 @@ Or install it yourself as:
|
|
48
46
|
#=> data
|
49
47
|
EventAggregator::Message.new("foo3", "data").publish
|
50
48
|
#=>
|
49
|
+
f.message_type_unregister("foo2")
|
50
|
+
EventAggregator::Message.new("foo2", "data").publish
|
51
|
+
#=>
|
52
|
+
|
53
|
+
EventAggregator::Message.new("foo2", "data").publish
|
54
|
+
EventAggregator::Message.new("foo2", "data2").publish
|
55
|
+
#=> data2
|
56
|
+
#=> data
|
57
|
+
|
58
|
+
Message.publish is async by default. To make it synchroneus (not recommended) use the following:
|
59
|
+
|
60
|
+
EventAggregator::Message.new("foo2", "data", false).publish
|
61
|
+
#=> data
|
62
|
+
|
63
|
+
The message data is duplicated by default for each of the receiving listeners. To force the same object for all listeners, set the consisten_data property.
|
64
|
+
|
65
|
+
EventAggregator::Message.new("foo2", "data", true, true).publish
|
66
|
+
|
67
|
+
This enables you to do the following:
|
68
|
+
|
69
|
+
class Foo
|
70
|
+
include EventAggregator::Listener
|
71
|
+
def initialize()
|
72
|
+
message_type_register( "foo", lambda{|data| data = data + " bar" } )
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
f1 = Foo.new
|
77
|
+
f2 = Foo.new
|
78
|
+
data = "foo"
|
79
|
+
|
80
|
+
EventAggregator::Message.new("foo", data).publish
|
81
|
+
|
82
|
+
puts data
|
83
|
+
#=> "foo bar bar"
|
84
|
+
|
85
|
+
|
86
|
+
## Usage Considerations
|
87
|
+
All messages are processed async by default. This means that there might be raise conditions in your code.
|
88
|
+
|
89
|
+
If you force synchroneus message publishing you should take extra care of where in your code you produce new messages. You can very easily create infinite loops where messages are published and consumed by the same listener. Because of this it is adivised not to produce messages within the callback for the listener, even when using async message publishing. Another good rule is never to produce messages of the same type as those you listen to. This does not completely guard you, as there can still exist loops between two or more listeners.
|
51
90
|
|
52
91
|
## Contributing
|
53
92
|
|
@@ -58,7 +97,16 @@ Or install it yourself as:
|
|
58
97
|
5. Create new Pull Request
|
59
98
|
|
60
99
|
## Todo:
|
61
|
-
|
62
|
-
- Adding tests
|
63
|
-
- Enable threaded message passing for higher performance.
|
64
100
|
- Improving the readme and documentation in the gem.
|
101
|
+
|
102
|
+
## Versioning Standard:
|
103
|
+
Using Semantic Versioning - http://semver.org/
|
104
|
+
### Versioning Summary
|
105
|
+
Given a version number MAJOR.MINOR.PATCH, increment the:
|
106
|
+
|
107
|
+
### 0.0.X - Patch
|
108
|
+
Small updates and patches that are backwards-compatible. Updating from 0.0.X -> 0.0.Y should not break your code.
|
109
|
+
### 0.X - Minor
|
110
|
+
Adding functionality and changes that are backwards-compatible. Updating from 0.X -> 0.Y should not break your code.
|
111
|
+
### X - Major
|
112
|
+
Architectural changes and other major changes that alter the API. Updating from X -> Y will most likely break your code.
|
data/event_aggregator.gemspec
CHANGED
data/lib/event_aggregator.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
#require 'singleton'
|
2
|
-
|
3
1
|
module EventAggregator
|
4
2
|
|
5
3
|
# Public: TODO: Could potentially turn this into a module.
|
@@ -12,29 +10,59 @@ module EventAggregator
|
|
12
10
|
# end
|
13
11
|
# end
|
14
12
|
class Aggregator
|
15
|
-
#include Singleton
|
16
13
|
class <<self; private :new; end
|
17
|
-
#TODO: Figure out how to do singleton pattern properly
|
18
14
|
|
19
15
|
@@listeners = Hash.new{|h, k| h[k] = []}
|
20
16
|
|
21
|
-
|
22
|
-
|
17
|
+
# Public: Register an EventAggregator::Listener to recieve
|
18
|
+
# a specified message type
|
19
|
+
#
|
20
|
+
# listener - An EventAggregator::Listener which should recieve
|
21
|
+
# the messages.
|
22
|
+
# message_type - The message type to recieve. Can be anything except nil.
|
23
|
+
# Often it is preferable to use a string eg. "Message Type".
|
24
|
+
def self.register( listener, message_type, callback )
|
25
|
+
@@listeners[message_type] << [listener, callback] unless ! (listener.class < EventAggregator::Listener) || @@listeners[message_type].include?(listener)
|
23
26
|
end
|
24
27
|
|
28
|
+
# Public: Unegister an EventAggregator::Listener to a
|
29
|
+
# specified message type. The listener will no
|
30
|
+
# longer get messages of this type.
|
31
|
+
#
|
32
|
+
# listener - The EventAggregator::Listener which should no longer recieve
|
33
|
+
# the messages.
|
34
|
+
# message_type - The message type to unregister for.
|
25
35
|
def self.unregister( listener, message_type )
|
26
|
-
@@listeners[message_type].
|
36
|
+
@@listeners[message_type].delete_if{|value| value[0] == listener}
|
27
37
|
end
|
38
|
+
|
39
|
+
# Public: As Unregister, but will unregister listener from all message types.
|
40
|
+
#
|
41
|
+
# listener - The listener who should no longer get any messages at all,
|
42
|
+
# regardless of type.
|
28
43
|
def self.unregister_all( listener )
|
29
44
|
@@listeners.each do |e|
|
30
|
-
e[1].
|
45
|
+
e[1].delete_if{|value| value[0] == listener}
|
31
46
|
end
|
32
47
|
end
|
33
|
-
def self.message_publish ( message )
|
34
|
-
raise "Invalid message" unless message.is_a? EventAggregator::Message
|
35
48
|
|
49
|
+
# Public: Will publish the specified message to all listeners
|
50
|
+
# who has registered for this message type.
|
51
|
+
#
|
52
|
+
# message - The message to be distributed to the listeners.
|
53
|
+
# async - true => message will be sent async. Default true
|
54
|
+
# consisten_data - true => the same object will be sent to all recievers. Default false
|
55
|
+
def self.message_publish ( message, async = true, consisten_data = false )
|
56
|
+
raise "Invalid message" unless message.respond_to?(:message_type) && message.respond_to?(:data)
|
36
57
|
@@listeners[message.message_type].each do |l|
|
37
|
-
l.
|
58
|
+
if l[1].respond_to? :call
|
59
|
+
case [async, consisten_data]
|
60
|
+
when [true, true] then EventAggregator::MessageJob.new.async.perform(message.data, l[1])
|
61
|
+
when [true, false] then EventAggregator::MessageJob.new.async.perform(message.data.clone, l[1])
|
62
|
+
when [false, true] then EventAggregator::MessageJob.new.perform( message.data, l[1])
|
63
|
+
when [false, false] then EventAggregator::MessageJob.new.perform( message.data.clone, l[1])
|
64
|
+
end
|
65
|
+
end
|
38
66
|
end
|
39
67
|
end
|
40
68
|
end
|
@@ -9,69 +9,13 @@ module EventAggregator
|
|
9
9
|
# ...
|
10
10
|
# def initialize()
|
11
11
|
# ...
|
12
|
-
#
|
12
|
+
# message_type_register( "foo", lambda{ puts "bar" } )
|
13
13
|
# end
|
14
14
|
# ...
|
15
15
|
# end
|
16
16
|
#
|
17
17
|
module Listener
|
18
|
-
|
19
|
-
#event_listener_listens_to = Hash.new() #This actually sets Listener.event_listener_listens_to = Hash.new, not the instance
|
20
|
-
|
21
|
-
|
22
|
-
# Public: This is the callback method when the module is extended.
|
23
|
-
# Using this to setup the last few things before the event listener can start.
|
24
|
-
#
|
25
|
-
# base - The class object for the class extening the Listener module
|
26
|
-
#
|
27
|
-
# Returns nil
|
28
|
-
def self.extended(base)
|
29
|
-
# Initialize module.
|
30
|
-
# add_auto_register_procedure(base) #Depricated now, but it is utterly awesome that you can do this.
|
31
|
-
end
|
32
|
-
|
33
|
-
# Public: This is the callback method when the module is included.
|
34
|
-
# Using this to setup the last few things before the event listener can start.
|
35
|
-
#
|
36
|
-
# base - The class object for the class including the Listener module
|
37
|
-
#
|
38
|
-
# Returns nil
|
39
|
-
def self.included(base)
|
40
|
-
# Initialize module.
|
41
|
-
# add_auto_register_procedure(base) #Depricated now, but it is utterly awesome that you can do this.
|
42
|
-
end
|
43
|
-
|
44
|
-
|
45
|
-
# Public: DEPRICATED: Adding extra initialize to the class so that we make sure new objects are added to the EventAggregators registry.
|
46
|
-
# This whole hack-deal is possibly not nescessary. Can be omited with a simple "register" when you add a new "receive message_type"
|
47
|
-
#
|
48
|
-
# base - The class object for the class including the Listener module
|
49
|
-
#
|
50
|
-
# Returns nil
|
51
|
-
def self.add_auto_register_procedure(base)
|
52
|
-
base.class_eval do
|
53
|
-
# back up method's name
|
54
|
-
alias_method :old_initialize, :initialize
|
55
|
-
|
56
|
-
# replace the old method with a new version which adds the Aggregator registry
|
57
|
-
def initialize(*args)
|
58
|
-
Aggregator.register self
|
59
|
-
old_initialize(*args)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def receive_message( message )
|
65
|
-
m = event_listener_listens_to[message.message_type]
|
66
|
-
|
67
|
-
m.call(message.data) if m.respond_to? :call #Should not need the check here, however who knows what kind of conurrency issues we might have.
|
68
|
-
#This will probably become hotpath, so having the extra check can be problematic.
|
69
|
-
end
|
70
|
-
|
71
18
|
private
|
72
|
-
def event_listener_listens_to
|
73
|
-
@event_listener_listens_to ||= Hash.new
|
74
|
-
end
|
75
19
|
# public: Use to add message types you want to receive. Overwirte existing callback when existing message type is given.
|
76
20
|
#
|
77
21
|
# message_type - A string indicating the message type you want to receive from the event aggregrator. Can actually be anything.
|
@@ -79,13 +23,12 @@ module EventAggregator
|
|
79
23
|
#
|
80
24
|
# Examples
|
81
25
|
#
|
82
|
-
#
|
83
|
-
#
|
84
|
-
#
|
26
|
+
# message_type_register("foo", method(:my_class_method))
|
27
|
+
# message_type_register("foo", lambda { puts "foo" })
|
28
|
+
# message_type_register("foo", Proc.new { puts "foo" })
|
85
29
|
#
|
86
|
-
def
|
87
|
-
|
88
|
-
Aggregator.register( self, message_type )
|
30
|
+
def message_type_register( message_type, callback )
|
31
|
+
Aggregator.register( self, message_type, callback)
|
89
32
|
end
|
90
33
|
|
91
34
|
# Public: Used to remove a certain type of message from your listening types. Messages of this specific type will no longer
|
@@ -95,10 +38,9 @@ module EventAggregator
|
|
95
38
|
#
|
96
39
|
# Examples
|
97
40
|
#
|
98
|
-
#
|
41
|
+
# message_type_unregister("foo")
|
99
42
|
#
|
100
|
-
def
|
101
|
-
event_listener_listens_to[message_type] = nil
|
43
|
+
def message_type_unregister( message_type )
|
102
44
|
Aggregator.unregister(self, message_type)
|
103
45
|
end
|
104
46
|
end
|
@@ -3,15 +3,31 @@ module EventAggregator
|
|
3
3
|
attr_accessor :message_type, :data
|
4
4
|
@message_type = nil
|
5
5
|
@data = nil
|
6
|
-
|
7
|
-
|
6
|
+
@async = nil
|
7
|
+
@consisten_data = nil
|
8
|
+
|
9
|
+
|
10
|
+
# Public: Initialize the Message
|
11
|
+
#
|
12
|
+
# message_type - The type of the message which determine
|
13
|
+
# which listeners will recieve the message
|
14
|
+
# data -
|
15
|
+
# async = true - Indicates if message should be published async or not
|
16
|
+
# consisten_data = false - Indicates if message listeners should recieve
|
17
|
+
# the same object reference
|
18
|
+
def initialize(message_type, data, async = true, consisten_data = false)
|
19
|
+
raise "Illegal Message Type" if message_type == nil
|
8
20
|
|
9
21
|
@message_type = message_type
|
10
22
|
@data = data
|
23
|
+
@async = async
|
24
|
+
@consisten_data = consisten_data
|
11
25
|
end
|
12
|
-
|
26
|
+
|
27
|
+
# Public: Will publish the message to all that
|
28
|
+
# listens of this message_type
|
13
29
|
def publish
|
14
|
-
Aggregator.message_publish( self )
|
30
|
+
Aggregator.message_publish( self, async, consisten_data )
|
15
31
|
end
|
16
32
|
end
|
17
33
|
end
|
data/spec/factories.rb
CHANGED
@@ -2,7 +2,7 @@ require 'factory_girl'
|
|
2
2
|
require 'faker'
|
3
3
|
require 'event_aggregator'
|
4
4
|
|
5
|
-
|
5
|
+
|
6
6
|
# Public: Not really used. Might not be needed at all. The same
|
7
7
|
# goes for FactoryGirl in general. Might not be needed.
|
8
8
|
#
|
@@ -16,7 +16,7 @@ FactoryGirl.define do
|
|
16
16
|
end
|
17
17
|
factory :message do
|
18
18
|
message_type { Faker::Name.name }
|
19
|
-
data { Faker::Commerce.product_name }
|
19
|
+
data { Faker::Commerce.product_name }
|
20
20
|
#initialize_with(Faker::Name.name, Faker::Name.name)
|
21
21
|
end
|
22
22
|
end
|
@@ -4,7 +4,8 @@ describe EventAggregator::Aggregator do
|
|
4
4
|
let(:listener) { (Class.new { include EventAggregator::Listener }).new }
|
5
5
|
let(:listener_class) { Class.new { include EventAggregator::Listener }}
|
6
6
|
let(:message_type) { Faker::Name.name }
|
7
|
-
let(:data)
|
7
|
+
let(:data) { Faker::Name.name }
|
8
|
+
let(:callback) { lambda{ |data| } }
|
8
9
|
|
9
10
|
before(:each) do
|
10
11
|
EventAggregator::Aggregator.class_variable_set :@@listener, Hash.new{|h, k| h[k] = []}
|
@@ -12,58 +13,58 @@ describe EventAggregator::Aggregator do
|
|
12
13
|
describe "self.register" do
|
13
14
|
describe 'legal parameters' do
|
14
15
|
it 'registered at correct place' do
|
15
|
-
EventAggregator::Aggregator.register(listener, message_type)
|
16
|
-
expect(EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type]).to include(listener)
|
16
|
+
EventAggregator::Aggregator.register(listener, message_type, callback)
|
17
|
+
expect(EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type]).to include([listener, callback])
|
17
18
|
end
|
18
19
|
|
19
|
-
it '
|
20
|
-
EventAggregator::Aggregator.register(listener, message_type)
|
20
|
+
it 'not be registered in wrong place' do
|
21
|
+
EventAggregator::Aggregator.register(listener, message_type, callback)
|
21
22
|
EventAggregator::Aggregator.class_variable_get(:@@listeners).each do |e|
|
22
23
|
if e[0] == message_type
|
23
|
-
expect(e[1]).to include(listener)
|
24
|
+
expect(e[1]).to include([listener, callback])
|
24
25
|
else
|
25
|
-
expect(e[1]).to_not include(listener)
|
26
|
+
expect(e[1]).to_not include([listener, callback])
|
26
27
|
end
|
27
28
|
end
|
28
29
|
end
|
29
30
|
end
|
30
31
|
describe 'illegal parameters' do
|
31
|
-
it '
|
32
|
-
expect{EventAggregator::Aggregator.register(nil, message_type)}.to_not change{EventAggregator::Aggregator.class_variable_get(:@@listeners)}
|
32
|
+
it 'not allow nil as message type' do
|
33
|
+
expect{EventAggregator::Aggregator.register(nil, message_type, callback)}.to_not change{EventAggregator::Aggregator.class_variable_get(:@@listeners)}
|
33
34
|
end
|
34
|
-
it '
|
35
|
-
expect{EventAggregator::Aggregator.register(EventAggregator::Message.new("a","b"), message_type)}.to_not change{EventAggregator::Aggregator.class_variable_get(:@@listeners)}
|
36
|
-
expect{EventAggregator::Aggregator.register("string", message_type)}.to_not change{EventAggregator::Aggregator.class_variable_get(:@@listeners)}
|
37
|
-
expect{EventAggregator::Aggregator.register(1, message_type)}.to_not change{EventAggregator::Aggregator.class_variable_get(:@@listeners)}
|
38
|
-
expect{EventAggregator::Aggregator.register(2.0, message_type)}.to_not change{EventAggregator::Aggregator.class_variable_get(:@@listeners)}
|
35
|
+
it 'not allow non-listener to register' do
|
36
|
+
expect{EventAggregator::Aggregator.register(EventAggregator::Message.new("a","b"), message_type, callback)}.to_not change{EventAggregator::Aggregator.class_variable_get(:@@listeners)}
|
37
|
+
expect{EventAggregator::Aggregator.register("string", message_type, callback)}.to_not change{EventAggregator::Aggregator.class_variable_get(:@@listeners)}
|
38
|
+
expect{EventAggregator::Aggregator.register(1, message_type, callback)}.to_not change{EventAggregator::Aggregator.class_variable_get(:@@listeners)}
|
39
|
+
expect{EventAggregator::Aggregator.register(2.0, message_type, callback)}.to_not change{EventAggregator::Aggregator.class_variable_get(:@@listeners)}
|
39
40
|
end
|
40
41
|
end
|
41
42
|
end
|
42
43
|
|
43
44
|
describe "self.unregister" do
|
44
45
|
describe 'legal parameters' do
|
45
|
-
it '
|
46
|
-
EventAggregator::Aggregator.register(listener, message_type)
|
46
|
+
it 'decrease count by 1' do
|
47
|
+
EventAggregator::Aggregator.register(listener, message_type, callback)
|
47
48
|
expect{EventAggregator::Aggregator.unregister(listener, message_type)}.to change{EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type].length}.by(-1)
|
48
49
|
end
|
49
|
-
it '
|
50
|
-
EventAggregator::Aggregator.register(listener, message_type)
|
50
|
+
it 'be remove from list' do
|
51
|
+
EventAggregator::Aggregator.register(listener, message_type, callback)
|
51
52
|
EventAggregator::Aggregator.unregister(listener, message_type)
|
52
|
-
expect(EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type]).to_not include(listener)
|
53
|
+
expect(EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type]).to_not include([listener, callback])
|
53
54
|
end
|
54
|
-
it '
|
55
|
+
it 'keep listener in unrelated lists' do
|
55
56
|
message_type2 = message_type + " different"
|
56
57
|
|
57
|
-
EventAggregator::Aggregator.register(listener, message_type)
|
58
|
-
EventAggregator::Aggregator.register(listener, message_type2)
|
58
|
+
EventAggregator::Aggregator.register(listener, message_type, callback)
|
59
|
+
EventAggregator::Aggregator.register(listener, message_type2, callback)
|
59
60
|
|
60
61
|
EventAggregator::Aggregator.unregister(listener, message_type)
|
61
62
|
|
62
|
-
expect(EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type2]).to include(listener)
|
63
|
+
expect(EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type2]).to include([listener, callback])
|
63
64
|
end
|
64
65
|
end
|
65
66
|
describe 'unregitering nonregisterd listener' do
|
66
|
-
it '
|
67
|
+
it 'not change list' do
|
67
68
|
message_type1 = message_type + " different 1"
|
68
69
|
message_type2 = message_type + " different 2"
|
69
70
|
message_type3 = message_type + " different 3"
|
@@ -71,9 +72,9 @@ describe EventAggregator::Aggregator do
|
|
71
72
|
listener2 = listener_class.new
|
72
73
|
listener3 = listener_class.new
|
73
74
|
|
74
|
-
EventAggregator::Aggregator.register(listener1, message_type1)
|
75
|
-
EventAggregator::Aggregator.register(listener2, message_type2)
|
76
|
-
EventAggregator::Aggregator.register(listener3, message_type3)
|
75
|
+
EventAggregator::Aggregator.register(listener1, message_type1, callback)
|
76
|
+
EventAggregator::Aggregator.register(listener2, message_type2, callback)
|
77
|
+
EventAggregator::Aggregator.register(listener3, message_type3, callback)
|
77
78
|
|
78
79
|
#Touching hash
|
79
80
|
EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type]
|
@@ -82,22 +83,22 @@ describe EventAggregator::Aggregator do
|
|
82
83
|
expect{EventAggregator::Aggregator.unregister(listener2, message_type)}.to_not change{EventAggregator::Aggregator.class_variable_get(:@@listeners)}
|
83
84
|
expect{EventAggregator::Aggregator.unregister(listener3, message_type)}.to_not change{EventAggregator::Aggregator.class_variable_get(:@@listeners)}
|
84
85
|
|
85
|
-
expect(EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type1]).to include(listener1)
|
86
|
-
expect(EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type2]).to include(listener2)
|
87
|
-
expect(EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type3]).to include(listener3)
|
86
|
+
expect(EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type1]).to include([listener1, callback])
|
87
|
+
expect(EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type2]).to include([listener2, callback])
|
88
|
+
expect(EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type3]).to include([listener3, callback])
|
88
89
|
end
|
89
90
|
end
|
90
91
|
describe 'unregitering listener from wrong message type' do
|
91
|
-
it '
|
92
|
+
it 'not change list' do
|
92
93
|
message_type2 = message_type + " different"
|
93
94
|
|
94
|
-
EventAggregator::Aggregator.register(listener, message_type)
|
95
|
+
EventAggregator::Aggregator.register(listener, message_type, callback)
|
95
96
|
|
96
97
|
expect{EventAggregator::Aggregator.unregister(listener, message_type2)}.to_not change{EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type]}
|
97
98
|
end
|
98
99
|
end
|
99
100
|
describe 'unregitering non-listener class' do
|
100
|
-
it '
|
101
|
+
it 'not change register list' do
|
101
102
|
#Touching hash
|
102
103
|
EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type]
|
103
104
|
|
@@ -111,14 +112,14 @@ describe EventAggregator::Aggregator do
|
|
111
112
|
|
112
113
|
describe "self.unregister_all" do
|
113
114
|
describe "unregistering listener registered to one message type" do
|
114
|
-
it "
|
115
|
-
EventAggregator::Aggregator.register(listener, message_type)
|
115
|
+
it "unregister from list" do
|
116
|
+
EventAggregator::Aggregator.register(listener, message_type, callback)
|
116
117
|
|
117
118
|
EventAggregator::Aggregator.unregister_all(listener)
|
118
119
|
|
119
|
-
expect(EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type]).to_not include(listener)
|
120
|
+
expect(EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type]).to_not include([listener, callback])
|
120
121
|
end
|
121
|
-
it "
|
122
|
+
it "not unregister wrong listener" do
|
122
123
|
listener2 = listener_class.new
|
123
124
|
listener3 = listener_class.new
|
124
125
|
listener4 = listener_class.new
|
@@ -126,65 +127,67 @@ describe EventAggregator::Aggregator do
|
|
126
127
|
message_type2 = message_type + " different"
|
127
128
|
message_type3 = message_type + " different 2"
|
128
129
|
|
129
|
-
EventAggregator::Aggregator.register(listener, message_type)
|
130
|
-
EventAggregator::Aggregator.register(listener2, message_type)
|
131
|
-
EventAggregator::Aggregator.register(listener3, message_type2)
|
132
|
-
EventAggregator::Aggregator.register(listener4, message_type3)
|
130
|
+
EventAggregator::Aggregator.register(listener, message_type, callback)
|
131
|
+
EventAggregator::Aggregator.register(listener2, message_type, callback)
|
132
|
+
EventAggregator::Aggregator.register(listener3, message_type2, callback)
|
133
|
+
EventAggregator::Aggregator.register(listener4, message_type3, callback)
|
133
134
|
|
134
135
|
|
135
136
|
EventAggregator::Aggregator.unregister_all(listener)
|
136
137
|
|
137
|
-
expect(EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type]).to include(listener2)
|
138
|
-
expect(EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type2]).to include(listener3)
|
139
|
-
expect(EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type3]).to include(listener4)
|
138
|
+
expect(EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type]).to include([listener2, callback])
|
139
|
+
expect(EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type2]).to include([listener3, callback])
|
140
|
+
expect(EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type3]).to include([listener4, callback])
|
140
141
|
end
|
141
142
|
end
|
142
143
|
describe "unregistering listener registered for several message types" do
|
143
|
-
it "
|
144
|
-
EventAggregator::Aggregator.register(listener, message_type)
|
144
|
+
it "unregister from all lists" do
|
145
|
+
EventAggregator::Aggregator.register(listener, message_type, callback)
|
145
146
|
message_type2 = message_type + " different"
|
146
|
-
EventAggregator::Aggregator.register(listener, message_type2)
|
147
|
+
EventAggregator::Aggregator.register(listener, message_type2, callback)
|
147
148
|
|
148
149
|
EventAggregator::Aggregator.unregister_all(listener)
|
149
150
|
|
150
|
-
expect(EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type]).to_not include(listener)
|
151
|
-
expect(EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type2]).to_not include(listener)
|
151
|
+
expect(EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type]).to_not include([listener, callback])
|
152
|
+
expect(EventAggregator::Aggregator.class_variable_get(:@@listeners)[message_type2]).to_not include([listener, callback])
|
152
153
|
end
|
153
154
|
end
|
154
155
|
end
|
155
156
|
|
156
157
|
describe "self.message_publish" do
|
157
158
|
describe 'legal parameters' do
|
158
|
-
it '
|
159
|
-
EventAggregator::Aggregator.register(listener, message_type)
|
159
|
+
it 'run correct callback' do
|
160
|
+
EventAggregator::Aggregator.register(listener, message_type, callback)
|
160
161
|
message = EventAggregator::Message.new(message_type, data)
|
161
162
|
|
162
|
-
expect(
|
163
|
+
expect(callback).to receive(:call).with(data)
|
163
164
|
|
164
165
|
EventAggregator::Aggregator.message_publish(message)
|
165
166
|
end
|
166
|
-
it '
|
167
|
+
it 'not run incorrect callback' do
|
167
168
|
message_type2 = message_type + " different"
|
168
169
|
|
169
|
-
EventAggregator::Aggregator.register(listener, message_type)
|
170
|
+
EventAggregator::Aggregator.register(listener, message_type, callback)
|
170
171
|
message = EventAggregator::Message.new(message_type2, data)
|
171
172
|
|
172
|
-
expect(
|
173
|
+
expect(callback).to_not receive(:call).with(data)
|
173
174
|
|
174
175
|
EventAggregator::Aggregator.message_publish(message)
|
175
176
|
end
|
176
177
|
|
177
|
-
it '
|
178
|
+
it 'run correct callback in list' do
|
178
179
|
listener2 = listener_class.new
|
179
180
|
message_type2 = message_type + " different"
|
180
181
|
|
181
|
-
|
182
|
-
|
182
|
+
callback2 = lambda{|data|}
|
183
|
+
|
184
|
+
EventAggregator::Aggregator.register(listener, message_type, callback)
|
185
|
+
EventAggregator::Aggregator.register(listener, message_type2, callback2)
|
183
186
|
|
184
187
|
message = EventAggregator::Message.new(message_type, data)
|
185
188
|
|
186
|
-
expect(
|
187
|
-
expect(
|
189
|
+
expect(callback).to receive(:call).with(data)
|
190
|
+
expect(callback2).to_not receive(:call)
|
188
191
|
|
189
192
|
EventAggregator::Aggregator.message_publish(message)
|
190
193
|
end
|
@@ -198,5 +201,52 @@ describe EventAggregator::Aggregator do
|
|
198
201
|
expect{EventAggregator::Aggregator.message_publish(nil)}.to raise_error
|
199
202
|
end
|
200
203
|
end
|
204
|
+
describe 'consisten_data behaviour' do
|
205
|
+
it 'uses same object when true' do
|
206
|
+
listener2 = listener_class.new
|
207
|
+
callback1 = lambda{|data|}
|
208
|
+
callback2 = lambda{|data|}
|
209
|
+
|
210
|
+
EventAggregator::Aggregator.register(listener, message_type, callback1)
|
211
|
+
EventAggregator::Aggregator.register(listener2, message_type, callback2)
|
212
|
+
|
213
|
+
message = EventAggregator::Message.new(message_type, data)
|
214
|
+
|
215
|
+
expect(callback1).to receive(:call) {|arg| expect(arg).to equal(data)}
|
216
|
+
expect(callback2).to receive(:call) {|arg| expect(arg).to equal(data)}
|
217
|
+
|
218
|
+
EventAggregator::Aggregator.message_publish(message, false, true)
|
219
|
+
end
|
220
|
+
it 'uses different objects when false' do
|
221
|
+
listener2 = listener_class.new
|
222
|
+
callback1 = lambda{|data| data ="no"}
|
223
|
+
callback2 = lambda{|data| data ="no"}
|
224
|
+
|
225
|
+
EventAggregator::Aggregator.register(listener, message_type, callback1)
|
226
|
+
EventAggregator::Aggregator.register(listener2, message_type, callback2)
|
227
|
+
|
228
|
+
message = EventAggregator::Message.new(message_type, data)
|
229
|
+
|
230
|
+
expect(callback1).to receive(:call) {|arg| expect(arg).to_not equal(data)}
|
231
|
+
expect(callback2).to receive(:call) {|arg| expect(arg).to_not equal(data)}
|
232
|
+
|
233
|
+
EventAggregator::Aggregator.message_publish(message, false, false)
|
234
|
+
end
|
235
|
+
it 'objects have same values when false' do
|
236
|
+
listener2 = listener_class.new
|
237
|
+
callback1 = lambda{|data| data ="no"}
|
238
|
+
callback2 = lambda{|data| data ="no"}
|
239
|
+
|
240
|
+
EventAggregator::Aggregator.register(listener, message_type, callback1)
|
241
|
+
EventAggregator::Aggregator.register(listener2, message_type, callback2)
|
242
|
+
|
243
|
+
message = EventAggregator::Message.new(message_type, data)
|
244
|
+
|
245
|
+
expect(callback1).to receive(:call) {|arg| expect(arg).to eq(data)}
|
246
|
+
expect(callback2).to receive(:call) {|arg| expect(arg).to eq(data)}
|
247
|
+
|
248
|
+
EventAggregator::Aggregator.message_publish(message, false, false)
|
249
|
+
end
|
250
|
+
end
|
201
251
|
end
|
202
252
|
end
|
@@ -23,68 +23,38 @@ describe EventAggregator::Listener do
|
|
23
23
|
EventAggregator::Aggregator.class_variable_set :@@listener, Hash.new{|h, k| h[k] = []}
|
24
24
|
@message = EventAggregator::Message.new(message_type, data)
|
25
25
|
end
|
26
|
-
describe '.receive_message' do
|
27
|
-
describe 'legal parameters' do
|
28
|
-
it 'execute callback' do
|
29
|
-
#TODO: This is subject to refactor because the method is stroed in the module by a hack.
|
30
|
-
# This stuff should be moved to the aggregator, or somewhere else.
|
31
|
-
listener.class.publicize_methods do
|
32
|
-
listener.message_type_to_receive_add(message_type, lambda_method)
|
33
|
-
|
34
|
-
expect(lambda_method).to receive(:call)
|
35
|
-
|
36
|
-
listener.receive_message(@message)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
describe 'illegal parameters' do
|
41
|
-
#This should not recieve illegal parameters.
|
42
|
-
it 'pending' do
|
43
|
-
pending "not implemented"
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
26
|
|
48
27
|
describe '.message_type_to_receive_add' do
|
49
28
|
describe 'legal parameters' do
|
50
|
-
it '
|
51
|
-
expect(EventAggregator::Aggregator).to receive(:register).with(listener, message_type)
|
29
|
+
it 'invoke aggregator register' do
|
30
|
+
expect(EventAggregator::Aggregator).to receive(:register).with(listener, message_type, lambda_method)
|
52
31
|
|
53
32
|
listener.class.publicize_methods do
|
54
|
-
listener.
|
33
|
+
listener.message_type_register(message_type, lambda_method)
|
55
34
|
end
|
56
35
|
end
|
57
|
-
it 'pending' do
|
58
|
-
pending "not implemented"
|
59
|
-
end
|
60
36
|
end
|
61
37
|
describe 'illegal parameters' do
|
62
|
-
it '
|
63
|
-
expect{listener.
|
64
|
-
expect{listener.
|
65
|
-
expect{listener.
|
66
|
-
expect{listener.
|
38
|
+
it 'raise error' do
|
39
|
+
expect{listener.message_type_register(message_type, nil)}.to raise_error
|
40
|
+
expect{listener.message_type_register(message_type, 1)}.to raise_error
|
41
|
+
expect{listener.message_type_register(message_type, "string")}.to raise_error
|
42
|
+
expect{listener.message_type_register(message_type, listener_class.new)}.to raise_error
|
67
43
|
end
|
68
44
|
end
|
69
45
|
end
|
70
46
|
|
71
47
|
describe '.message_type_to_receive_remove' do
|
72
48
|
describe 'legal parameters' do
|
73
|
-
it '
|
49
|
+
it 'invoke aggregator unregister' do
|
74
50
|
listener.class.publicize_methods do
|
75
|
-
listener.
|
76
|
-
|
51
|
+
listener.message_type_register(message_type, lambda_method)
|
52
|
+
|
53
|
+
expect(EventAggregator::Aggregator).to receive(:unregister).with(listener, message_type)
|
77
54
|
|
78
|
-
|
79
|
-
|
80
|
-
listener.receive_message(@message)
|
55
|
+
listener.message_type_unregister(message_type)
|
81
56
|
end
|
82
57
|
end
|
83
58
|
end
|
84
|
-
describe 'illegal parameters' do
|
85
|
-
it 'not registered reciever' do
|
86
|
-
pending "This will really likely be removed in next refactor"
|
87
|
-
end
|
88
|
-
end
|
89
59
|
end
|
90
60
|
end
|
@@ -5,25 +5,20 @@ describe EventAggregator::Message do
|
|
5
5
|
let(:message_type) {Faker::Name.name}
|
6
6
|
let(:data) {Faker::Name.name}
|
7
7
|
let(:listener_class) { (Class.new { include EventAggregator::Listener }) }
|
8
|
+
let(:callback) { lambda{ |data| } }
|
8
9
|
|
9
10
|
before(:each) do
|
10
11
|
EventAggregator::Aggregator.class_variable_set :@@listener, Hash.new{|h, k| h[k] = []}
|
11
12
|
@listener_one = listener_class.new
|
12
13
|
@listener_two = listener_class.new
|
13
14
|
|
14
|
-
EventAggregator::Aggregator.register(@listener_one, message_type)
|
15
|
-
EventAggregator::Aggregator.register(@listener_two, message_type+" different")
|
15
|
+
EventAggregator::Aggregator.register(@listener_one, message_type, callback)
|
16
|
+
EventAggregator::Aggregator.register(@listener_two, message_type+" different", callback)
|
16
17
|
end
|
17
18
|
|
18
|
-
it 'should
|
19
|
-
message = EventAggregator::Message.new(message_type, data)
|
20
|
-
expect(@listener_one).to receive(:receive_message).with(message)
|
21
|
-
expect(@listener_two).to_not receive(:receive_message)
|
22
|
-
|
23
|
-
message.publish
|
24
|
-
end
|
25
|
-
it 'should be published to the aggregator' do
|
19
|
+
it 'should invoke message_publish on aggregator' do
|
26
20
|
message = EventAggregator::Message.new(message_type, data)
|
21
|
+
|
27
22
|
expect(EventAggregator::Aggregator).to receive(:message_publish).with(message)
|
28
23
|
|
29
24
|
message.publish
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: event_aggregator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
5
|
-
prerelease:
|
4
|
+
version: 1.0.0.pre
|
5
|
+
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Stephan Eriksen
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-12-
|
12
|
+
date: 2013-12-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -91,6 +91,22 @@ dependencies:
|
|
91
91
|
- - ! '>='
|
92
92
|
- !ruby/object:Gem::Version
|
93
93
|
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: sucker_punch
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '1.0'
|
102
|
+
type: :runtime
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '1.0'
|
94
110
|
description: A simple Ruby event aggregator.
|
95
111
|
email:
|
96
112
|
- stephan.n.eriksen@gmail.com
|
@@ -110,6 +126,7 @@ files:
|
|
110
126
|
- lib/event_aggregator/aggregator.rb
|
111
127
|
- lib/event_aggregator/listener.rb
|
112
128
|
- lib/event_aggregator/message.rb
|
129
|
+
- lib/event_aggregator/message_job.rb
|
113
130
|
- lib/event_aggregator/version.rb
|
114
131
|
- spec/factories.rb
|
115
132
|
- spec/lib/event_aggregator/aggregator_spec.rb
|
@@ -132,9 +149,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
132
149
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
133
150
|
none: false
|
134
151
|
requirements:
|
135
|
-
- - ! '
|
152
|
+
- - ! '>'
|
136
153
|
- !ruby/object:Gem::Version
|
137
|
-
version:
|
154
|
+
version: 1.3.1
|
138
155
|
requirements: []
|
139
156
|
rubyforge_project:
|
140
157
|
rubygems_version: 1.8.25
|