event_aggregator 1.0.0.pre → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
- # EventAggregator
1
+ # EventAggregator gem
2
2
 
3
- The gem 'event_aggregator' is designed for usie with the event aggregator pattern in Ruby.
4
-
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.
3
+ The gem 'event_aggregator' is designed for use with the event aggregator pattern in Ruby.
6
4
 
7
5
  ## Installation
8
6
 
@@ -36,6 +34,10 @@ Or install it yourself as:
36
34
  def handle_message(data)
37
35
  puts data
38
36
  end
37
+
38
+ def foo_unregister(*args)
39
+ message_type_unregister(*args)
40
+ end
39
41
  end
40
42
 
41
43
  f = Foo.new
@@ -45,56 +47,67 @@ Or install it yourself as:
45
47
  EventAggregator::Message.new("foo2", "data").publish
46
48
  #=> data
47
49
  EventAggregator::Message.new("foo3", "data").publish
48
- #=>
49
- f.message_type_unregister("foo2")
50
+ #=> []
51
+ f.foo_unregister("foo2")
50
52
  EventAggregator::Message.new("foo2", "data").publish
51
- #=>
53
+ #=> []
52
54
 
53
- EventAggregator::Message.new("foo2", "data").publish
54
- EventAggregator::Message.new("foo2", "data2").publish
55
+ #Possible outcome:
56
+ EventAggregator::Message.new("foo", "data").publish
57
+ EventAggregator::Message.new("foo", "data2").publish
55
58
  #=> data2
56
59
  #=> data
57
60
 
58
- Message.publish is async by default. To make it synchroneus (not recommended) use the following:
61
+ Message.publish is asynchronous by default. To make it synchronous (not recommended) use the following:
59
62
 
60
- EventAggregator::Message.new("foo2", "data", false).publish
63
+ EventAggregator::Message.new("foo", "data", false).publish
61
64
  #=> data
62
65
 
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.
66
+ 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 to true.
64
67
 
65
- EventAggregator::Message.new("foo2", "data", true, true).publish
68
+ EventAggregator::Message.new("foo", "data", true, true).publish
66
69
 
67
- This enables you to do the following:
70
+ This enables the following:
68
71
 
69
72
  class Foo
70
73
  include EventAggregator::Listener
71
74
  def initialize()
72
- message_type_register( "foo", lambda{|data| data = data + " bar" } )
75
+ message_type_register( "foo", lambda{|data| data << " bar" } )
73
76
  end
74
77
  end
75
78
 
76
79
  f1 = Foo.new
77
80
  f2 = Foo.new
78
81
  data = "foo"
82
+
83
+ EventAggregator::Message.new("foo", data, true, false).publish
84
+
85
+ puts data
86
+ #=> "foo"
79
87
 
80
- EventAggregator::Message.new("foo", data).publish
88
+ EventAggregator::Message.new("foo", data, true, true).publish
81
89
 
82
90
  puts data
83
91
  #=> "foo bar bar"
84
92
 
93
+ EventAggregator::Message.new("foo", data, true, true).publish
94
+
95
+ puts data
96
+ #=> "foo bar bar bar bar"
97
+
98
+
85
99
 
86
100
  ## Usage Considerations
87
- All messages are processed async by default. This means that there might be raise conditions in your code.
101
+ All messages are processed asynchronous by default. This means that there might be raise conditions in your code.
88
102
 
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.
103
+ If you force synchronous 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 advised not to produce messages within the callback for the listener, even when using asynchronous 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.
90
104
 
91
- ## Contributing
105
+ ## About Event Aggregators
106
+ An event aggregator is essentially a message passing service that aims at decoupling 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. When such conditions occurs a message can be produced with all relevant data in it. This message can then be published. The message will then be distributed to all other objects that want to receive this message type. This way the object or class that produced the message do not need to be aware of every other object that might be interested in the condition that just occurred. It also removes the need for this class to implement any consumer producer pattern or other similar methods to solving this problem. With an event aggregator the listener, the receiver of the message, does not need to know that the sender even exists. This will remove a lot of bug-producing couplings between objects and help your code become cleaner.
92
107
 
93
- 1. Fork it
94
- 2. Create your feature branch (`git checkout -b my-new-feature`)
95
- 3. Commit your changes (`git commit -am 'Add some feature'`)
96
- 4. Push to the branch (`git push origin my-new-feature`)
97
- 5. Create new Pull Request
108
+ For more information see: http://martinfowler.com/eaaDev/EventAggregator.html
109
+
110
+ Or: https://www.google.com/#q=event+aggregator
98
111
 
99
112
  ## Todo:
100
113
  - Improving the readme and documentation in the gem.
@@ -102,11 +115,17 @@ If you force synchroneus message publishing you should take extra care of where
102
115
  ## Versioning Standard:
103
116
  Using Semantic Versioning - http://semver.org/
104
117
  ### Versioning Summary
105
- Given a version number MAJOR.MINOR.PATCH, increment the:
106
118
 
107
- ### 0.0.X - Patch
119
+ #### 0.0.X - Patch
108
120
  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
121
+ #### 0.X - Minor
110
122
  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.
123
+ #### X - Major
124
+ Architectural changes and other major changes that alter the API. Updating from X -> Y will most likely break your code.
125
+ ## Contributing
126
+
127
+ 1. Fork it
128
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
129
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
130
+ 4. Push to the branch (`git push origin my-new-feature`)
131
+ 5. Create new Pull Request
@@ -24,5 +24,5 @@ Gem::Specification.new do |spec|
24
24
  spec.add_development_dependency 'factory_girl'
25
25
  spec.add_development_dependency 'faker'
26
26
 
27
- spec.add_runtime_dependency 'sucker_punch', "~> 1.0"
27
+ spec.add_dependency 'sucker_punch', "~> 1.0"
28
28
  end
@@ -1,9 +1,11 @@
1
+ require "sucker_punch"
1
2
  require "event_aggregator/version"
2
3
  require "event_aggregator/aggregator"
3
4
  require "event_aggregator/listener"
4
5
  require "event_aggregator/message"
5
6
  require "event_aggregator/message_job"
6
7
 
8
+
7
9
  module EventAggregator
8
10
 
9
11
  end
@@ -22,6 +22,7 @@ module EventAggregator
22
22
  # message_type - The message type to recieve. Can be anything except nil.
23
23
  # Often it is preferable to use a string eg. "Message Type".
24
24
  def self.register( listener, message_type, callback )
25
+ raise "Illegal callback" unless callback.respond_to?(:call)
25
26
  @@listeners[message_type] << [listener, callback] unless ! (listener.class < EventAggregator::Listener) || @@listeners[message_type].include?(listener)
26
27
  end
27
28
 
@@ -52,11 +53,11 @@ module EventAggregator
52
53
  # message - The message to be distributed to the listeners.
53
54
  # async - true => message will be sent async. Default true
54
55
  # 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
+ def self.message_publish ( message )
56
57
  raise "Invalid message" unless message.respond_to?(:message_type) && message.respond_to?(:data)
57
58
  @@listeners[message.message_type].each do |l|
58
59
  if l[1].respond_to? :call
59
- case [async, consisten_data]
60
+ case [message.async, message.consisten_data]
60
61
  when [true, true] then EventAggregator::MessageJob.new.async.perform(message.data, l[1])
61
62
  when [true, false] then EventAggregator::MessageJob.new.async.perform(message.data.clone, l[1])
62
63
  when [false, true] then EventAggregator::MessageJob.new.perform( message.data, l[1])
@@ -1,20 +1,37 @@
1
1
  module EventAggregator
2
+
3
+ # Public: The Message class is used as a distribution object
4
+ # for the EventAggregator::Aggregator to send messages to
5
+ # EventAggregator::Listener objects
6
+ #
7
+ # Examples
8
+ #
9
+ # EventAggregator::Message.new("foo", "data").publish
10
+ # EventAggregator::Message.new("foo", "data", true, false).publish #equivalent to the first example
11
+ # EventAggregator::Message.new("foo2", 7843).publish #Data can be anything
12
+ # #Data can be anything
13
+ # EventAggregator::Message.new("foo2", lambda{p ["", "bA", "bw", "bA", "IA", "bg", "YQ", "aA", "cA", "ZQ", "dA", "w"].map{|e| e[0] && e[0] == "w" ?'U'+e : 'n'+e}.reverse.join('==\\').unpack(('m'+'x'*4)*11).join}).publish
14
+ # #Non-asynchroneus distribution and consistend data object for all listeners.
15
+ # EventAggregator::Message.new("foo3", SomeClass.new(), false, true).publish
16
+ #
2
17
  class Message
3
- attr_accessor :message_type, :data
18
+ attr_accessor :message_type, :data, :async, :consisten_data
4
19
  @message_type = nil
5
20
  @data = nil
6
21
  @async = nil
7
22
  @consisten_data = nil
8
23
 
9
-
24
+
10
25
  # Public: Initialize the Message
11
- #
26
+ #
12
27
  # message_type - The type of the message which determine
13
- # which listeners will recieve the message
14
- # data -
28
+ # which EventAggregator::Listener objects will recieve the message
29
+ # upon publish
30
+ # data - The data that will be passed to the
31
+ # EventAggregator::Listener objects
15
32
  # 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
33
+ # consisten_data = false - Indicates if EventAggregator::Listener objects
34
+ # should recieve a consistent object reference or clones.
18
35
  def initialize(message_type, data, async = true, consisten_data = false)
19
36
  raise "Illegal Message Type" if message_type == nil
20
37
 
@@ -23,11 +40,12 @@ module EventAggregator
23
40
  @async = async
24
41
  @consisten_data = consisten_data
25
42
  end
26
-
27
- # Public: Will publish the message to all that
28
- # listens of this message_type
43
+
44
+ # Public: Will publish the message to all instances of
45
+ # EventAggregator::Listener that is registered for message types
46
+ # equal to this.message_type
29
47
  def publish
30
- Aggregator.message_publish( self, async, consisten_data )
48
+ Aggregator.message_publish( self )
31
49
  end
32
50
  end
33
51
  end
@@ -1,7 +1,17 @@
1
1
  module EventAggregator
2
+
3
+ # Public: MessageJob is a class used by the EventAggregator::Aggregator
4
+ # for processing message distribution.
5
+ #
2
6
  class MessageJob
3
7
  include SuckerPunch::Job
4
-
8
+
9
+ # Public: Duplicate some text an arbitrary number of times.
10
+ #
11
+ # data - The data that will be sent to the callback, originating
12
+ # from a message.
13
+ # callback - The callback that will be processed with the data as
14
+ # a parameter
5
15
  def perform(data, callback)
6
16
  callback.call(data)
7
17
  end
@@ -1,3 +1,3 @@
1
1
  module EventAggregator
2
- VERSION = "1.0.0.pre"
2
+ VERSION = "1.0.1"
3
3
  end
@@ -210,12 +210,12 @@ describe EventAggregator::Aggregator do
210
210
  EventAggregator::Aggregator.register(listener, message_type, callback1)
211
211
  EventAggregator::Aggregator.register(listener2, message_type, callback2)
212
212
 
213
- message = EventAggregator::Message.new(message_type, data)
213
+ message = EventAggregator::Message.new(message_type, data, false, true)
214
214
 
215
215
  expect(callback1).to receive(:call) {|arg| expect(arg).to equal(data)}
216
216
  expect(callback2).to receive(:call) {|arg| expect(arg).to equal(data)}
217
217
 
218
- EventAggregator::Aggregator.message_publish(message, false, true)
218
+ EventAggregator::Aggregator.message_publish(message)
219
219
  end
220
220
  it 'uses different objects when false' do
221
221
  listener2 = listener_class.new
@@ -225,12 +225,12 @@ describe EventAggregator::Aggregator do
225
225
  EventAggregator::Aggregator.register(listener, message_type, callback1)
226
226
  EventAggregator::Aggregator.register(listener2, message_type, callback2)
227
227
 
228
- message = EventAggregator::Message.new(message_type, data)
228
+ message = EventAggregator::Message.new(message_type, data, false, false)
229
229
 
230
230
  expect(callback1).to receive(:call) {|arg| expect(arg).to_not equal(data)}
231
231
  expect(callback2).to receive(:call) {|arg| expect(arg).to_not equal(data)}
232
232
 
233
- EventAggregator::Aggregator.message_publish(message, false, false)
233
+ EventAggregator::Aggregator.message_publish(message)
234
234
  end
235
235
  it 'objects have same values when false' do
236
236
  listener2 = listener_class.new
@@ -240,12 +240,12 @@ describe EventAggregator::Aggregator do
240
240
  EventAggregator::Aggregator.register(listener, message_type, callback1)
241
241
  EventAggregator::Aggregator.register(listener2, message_type, callback2)
242
242
 
243
- message = EventAggregator::Message.new(message_type, data)
243
+ message = EventAggregator::Message.new(message_type, data, false, false)
244
244
 
245
245
  expect(callback1).to receive(:call) {|arg| expect(arg).to eq(data)}
246
246
  expect(callback2).to receive(:call) {|arg| expect(arg).to eq(data)}
247
247
 
248
- EventAggregator::Aggregator.message_publish(message, false, false)
248
+ EventAggregator::Aggregator.message_publish(message)
249
249
  end
250
250
  end
251
251
  end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe EventAggregator::MessageJob do
4
+ let(:callback) { lambda{ |data| } }
5
+ let(:data) { Faker::Name.name }
6
+ let(:message_job) { EventAggregator::MessageJob.new }
7
+
8
+ describe '.perform' do
9
+ describe 'legal parameters' do
10
+ it 'excute callback with data' do
11
+ expect(callback).to receive(:call).with(data)
12
+
13
+ message_job.perform(data, callback)
14
+ end
15
+ end
16
+ describe 'illegal parameters' do
17
+ it 'should never be passed to MessageJob' do
18
+ expect(true).to eq(true)
19
+ end
20
+ end
21
+ end
22
+ end
data/spec/spec_helper.rb CHANGED
@@ -2,10 +2,10 @@ require "rubygems"
2
2
  require "bundler/setup"
3
3
  require "factory_girl"
4
4
  require "faker"
5
- require "sucker_punch"
5
+ require "event_aggregator"
6
6
  require "sucker_punch/testing/inline"
7
7
 
8
- require "event_aggregator"
8
+
9
9
 
10
10
  RSpec.configure do |config|
11
11
  config.treat_symbols_as_metadata_keys_with_true_values = true
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: 1.0.0.pre
5
- prerelease: 6
4
+ version: 1.0.1
5
+ prerelease:
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-22 00:00:00.000000000 Z
12
+ date: 2013-12-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -131,6 +131,7 @@ files:
131
131
  - spec/factories.rb
132
132
  - spec/lib/event_aggregator/aggregator_spec.rb
133
133
  - spec/lib/event_aggregator/listener_spec.rb
134
+ - spec/lib/event_aggregator/message_job_spec.rb
134
135
  - spec/lib/event_aggregator/message_spec.rb
135
136
  - spec/spec_helper.rb
136
137
  homepage: https://github.com/stephan-nordnes-eriksen/event_aggregator
@@ -149,9 +150,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
149
150
  required_rubygems_version: !ruby/object:Gem::Requirement
150
151
  none: false
151
152
  requirements:
152
- - - ! '>'
153
+ - - ! '>='
153
154
  - !ruby/object:Gem::Version
154
- version: 1.3.1
155
+ version: '0'
155
156
  requirements: []
156
157
  rubyforge_project:
157
158
  rubygems_version: 1.8.25
@@ -162,5 +163,6 @@ test_files:
162
163
  - spec/factories.rb
163
164
  - spec/lib/event_aggregator/aggregator_spec.rb
164
165
  - spec/lib/event_aggregator/listener_spec.rb
166
+ - spec/lib/event_aggregator/message_job_spec.rb
165
167
  - spec/lib/event_aggregator/message_spec.rb
166
168
  - spec/spec_helper.rb