jmoses_event_bus 1.0.1
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 +2 -0
- data/.yardopts +1 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +42 -0
- data/README.md +153 -0
- data/Rakefile +6 -0
- data/lib/event_bus/registrations.rb +74 -0
- data/lib/event_bus.rb +124 -0
- data/spec/lib/event_bus_spec.rb +227 -0
- data/spec/spec_helper.rb +11 -0
- metadata +108 -0
data/.rspec
ADDED
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--no-private
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
event_bus (1.0.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
diff-lcs (1.2.4)
|
10
|
+
json (1.8.0)
|
11
|
+
multi_json (1.7.3)
|
12
|
+
rake (10.0.4)
|
13
|
+
rspec (2.13.0)
|
14
|
+
rspec-core (~> 2.13.0)
|
15
|
+
rspec-expectations (~> 2.13.0)
|
16
|
+
rspec-mocks (~> 2.13.0)
|
17
|
+
rspec-core (2.13.1)
|
18
|
+
rspec-expectations (2.13.0)
|
19
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
20
|
+
rspec-given (2.4.1)
|
21
|
+
rspec (>= 2.11)
|
22
|
+
sorcerer (>= 0.3.7)
|
23
|
+
rspec-mocks (2.13.1)
|
24
|
+
rspec-spies (2.1.4)
|
25
|
+
rspec (~> 2.0)
|
26
|
+
simplecov (0.7.1)
|
27
|
+
multi_json (~> 1.0)
|
28
|
+
simplecov-html (~> 0.7.1)
|
29
|
+
simplecov-html (0.7.1)
|
30
|
+
sorcerer (0.3.10)
|
31
|
+
|
32
|
+
PLATFORMS
|
33
|
+
ruby
|
34
|
+
|
35
|
+
DEPENDENCIES
|
36
|
+
event_bus!
|
37
|
+
json
|
38
|
+
rake (~> 10.0.1)
|
39
|
+
rspec (~> 2.12)
|
40
|
+
rspec-given
|
41
|
+
rspec-spies
|
42
|
+
simplecov
|
data/README.md
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
# EventBus
|
2
|
+
|
3
|
+
A simple pubsub event bus for Ruby applications.
|
4
|
+
|
5
|
+
[](https://travis-ci.org/kevinrutherford/event_bus)
|
6
|
+
[](https://gemnasium.com/kevinrutherford/event_bus)
|
8
|
+
[](https://codeclimate.com/github/kevinrutherford/event_bus)
|
10
|
+
|
11
|
+
* Gem: <https://rubygems.org/gems/event_bus>
|
12
|
+
* API docs: <http://rubydoc.info/gems/event_bus/frames>
|
13
|
+
* Source code: <https://github.com/kevinrutherford/event_bus>
|
14
|
+
|
15
|
+
## Features
|
16
|
+
|
17
|
+
* Simple, global support for the Observer pattern, aka Publisher-Subscriber.
|
18
|
+
* Publish and subscribe to events throughout your Ruby application.
|
19
|
+
* Listen for events without coupling to the publishing object or class.
|
20
|
+
* Subscribe to events using names or regex patterns.
|
21
|
+
* Works with Rails.
|
22
|
+
* Works without Rails.
|
23
|
+
|
24
|
+
## Installation
|
25
|
+
|
26
|
+
Install the gem
|
27
|
+
|
28
|
+
```
|
29
|
+
gem install event_bus
|
30
|
+
```
|
31
|
+
|
32
|
+
Or add it to your Gemfile and run `bundle`.
|
33
|
+
|
34
|
+
``` ruby
|
35
|
+
gem 'event_bus'
|
36
|
+
```
|
37
|
+
|
38
|
+
## Usage
|
39
|
+
|
40
|
+
### Publishing events
|
41
|
+
|
42
|
+
Publish events whenever something significant happens in your application:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
class PlaceOrder
|
46
|
+
//...
|
47
|
+
EventBus.announce(:order_placed, order: current_order, customer: current_user)
|
48
|
+
end
|
49
|
+
```
|
50
|
+
|
51
|
+
The event name (first argument) can be a String or a Symbol.
|
52
|
+
The Hash is optional and supplies a payload of information to any subscribers.
|
53
|
+
|
54
|
+
(If you don't like the method name `announce` you can use `publish` or
|
55
|
+
`broadcast` instead.)
|
56
|
+
|
57
|
+
### Subscribing to events
|
58
|
+
|
59
|
+
There are three ways to subscribe to events.
|
60
|
+
|
61
|
+
1. Subscribe a listener object:
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
EventBus.subscribe(StatsRecorder.new)
|
65
|
+
```
|
66
|
+
|
67
|
+
The event will be handled by a method whose name matches the event name:
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
class StatsRecorder
|
71
|
+
def order_placed(payload)
|
72
|
+
order = payload[:order]
|
73
|
+
//...
|
74
|
+
end
|
75
|
+
end
|
76
|
+
```
|
77
|
+
|
78
|
+
If the object has no matching method, it doesn't receive the event.
|
79
|
+
|
80
|
+
2. Specify the method to be called when the event fires:
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
EventBus.subscribe(:order_placed, StatsRecorder.new, :print_order)
|
84
|
+
```
|
85
|
+
|
86
|
+
In this case the event will be handled by the `print_order` method:
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
class StatsRecorder
|
90
|
+
def print_order(payload)
|
91
|
+
order = payload[:order]
|
92
|
+
//...
|
93
|
+
end
|
94
|
+
end
|
95
|
+
```
|
96
|
+
|
97
|
+
The first argument to `subscribe` can be a String,
|
98
|
+
a Symbol or a Regexp:
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
EventBus.subscribe(/order/, StatsRecorder.new, :print_order)
|
102
|
+
```
|
103
|
+
|
104
|
+
3. Subscribe a block:
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
EventBus.subscribe(:order_placed) do |payload|
|
108
|
+
order = payload[:order]
|
109
|
+
//...
|
110
|
+
end
|
111
|
+
```
|
112
|
+
|
113
|
+
The argument to `subscribe` can be a String, a Symbol or a Regexp:
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
EventBus.subscribe(/order/) do |payload|
|
117
|
+
order = payload[:order]
|
118
|
+
//...
|
119
|
+
end
|
120
|
+
```
|
121
|
+
|
122
|
+
See the specs for more detailed usage scenarios.
|
123
|
+
|
124
|
+
## Compatibility
|
125
|
+
|
126
|
+
Tested with Ruby 1.9.x, JRuby, Rubinius.
|
127
|
+
See the [build status](https://travis-ci.org/kevinrutherford/event_bus)
|
128
|
+
for details.
|
129
|
+
|
130
|
+
## License
|
131
|
+
|
132
|
+
(The MIT License)
|
133
|
+
|
134
|
+
Copyright (c) 2013 Kevin Rutherford
|
135
|
+
|
136
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
137
|
+
this software and associated documentation files (the 'Software'), to deal in
|
138
|
+
the Software without restriction, including without limitation the rights to
|
139
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
140
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
141
|
+
so, subject to the following conditions:
|
142
|
+
|
143
|
+
The above copyright notice and this permission notice shall be included in all
|
144
|
+
copies or substantial portions of the Software.
|
145
|
+
|
146
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
147
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
148
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
149
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
150
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
151
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
152
|
+
SOFTWARE.
|
153
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
class EventBus
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
class Registrations
|
8
|
+
include Singleton
|
9
|
+
|
10
|
+
def announce(event_name, payload)
|
11
|
+
full_payload = {event_name: event_name}.merge(payload)
|
12
|
+
listeners.each do |listener|
|
13
|
+
pass_event_to listener, event_name, full_payload
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def clear
|
18
|
+
listeners.clear
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_method(pattern, listener, method_name)
|
22
|
+
listeners << Registration.new(pattern, listener, method_name)
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_block(pattern, &blk)
|
26
|
+
listeners << BlockRegistration.new(pattern, blk)
|
27
|
+
end
|
28
|
+
|
29
|
+
def on_error(&blk)
|
30
|
+
@error_handler = blk
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def listeners
|
36
|
+
@listeners ||= []
|
37
|
+
end
|
38
|
+
|
39
|
+
def error_handler
|
40
|
+
@error_handler
|
41
|
+
end
|
42
|
+
|
43
|
+
def pass_event_to(listener, event_name, payload)
|
44
|
+
begin
|
45
|
+
listener.respond(event_name, payload)
|
46
|
+
rescue => error
|
47
|
+
error_handler.call(listener.receiver, payload.merge(error: error)) if error_handler
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
Registration = Struct.new(:pattern, :listener, :method_name) do
|
52
|
+
def respond(event_name, payload)
|
53
|
+
listener.send(method_name, payload) if pattern === event_name
|
54
|
+
end
|
55
|
+
|
56
|
+
def receiver
|
57
|
+
listener
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
BlockRegistration = Struct.new(:pattern, :block) do
|
62
|
+
def respond(event_name, payload)
|
63
|
+
block.call(payload) if pattern === event_name
|
64
|
+
end
|
65
|
+
|
66
|
+
def receiver
|
67
|
+
block
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
data/lib/event_bus.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
require_relative 'event_bus/registrations'
|
2
|
+
|
3
|
+
class EventBus
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
#
|
8
|
+
# Announce an event to any waiting listeners.
|
9
|
+
#
|
10
|
+
# The +event_name+ is added to the +payload+ hash (with the key +:event_name+)
|
11
|
+
# before being passed on to listeners.
|
12
|
+
#
|
13
|
+
# @param event_name [String, Symbol] the name of your event
|
14
|
+
# @param payload [Hash] the information you want to pass to the listeners
|
15
|
+
# @return [EventBus] the EventBus, ready to be called again.
|
16
|
+
#
|
17
|
+
def publish(event_name, payload = {})
|
18
|
+
case event_name
|
19
|
+
when Symbol, String
|
20
|
+
registrations.announce(event_name, payload)
|
21
|
+
self
|
22
|
+
else
|
23
|
+
raise ArgumentError.new('The event name must be a string or a symbol')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
alias :announce :publish
|
28
|
+
alias :broadcast :publish
|
29
|
+
|
30
|
+
#
|
31
|
+
# Subscribe to a set of events.
|
32
|
+
#
|
33
|
+
# If +blk+ is supplied, it will be called with any event whose name
|
34
|
+
# matches +pattern+.
|
35
|
+
#
|
36
|
+
# If no block is given, and if +pattern+ is a String or a Regexp,
|
37
|
+
# a method will be called on +listener+ whenever an event matching
|
38
|
+
# +pattern+ occurs. In this case, if +method_name+ is supplied the
|
39
|
+
# EventBus will look for, and call, a method of that name on +listener+;
|
40
|
+
# otherwise if +method_name+ is not given, the EventBus will attempt to
|
41
|
+
# call a method whose name matches the event's name.
|
42
|
+
#
|
43
|
+
# Finally, if no block is given and +pattern+ is not a String or a Regexp,
|
44
|
+
# then +pattern+ is taken to be a listener object and the EventBus will
|
45
|
+
# attempt to call a method on it whose name matches the event's name.
|
46
|
+
#
|
47
|
+
# Either +listener+ or +blk+ must be provided, both never both.
|
48
|
+
#
|
49
|
+
# When a matching event occurs, either the block is called or the +method_name+
|
50
|
+
# method on the +listener+ object is called.
|
51
|
+
#
|
52
|
+
# @param pattern [String, Regexp] listen for any events whose name matches this pattern
|
53
|
+
# @param listener the object to be notified when a matching event occurs
|
54
|
+
# @param method_name [Symbol] the method to be called on +listener+ when a matching event occurs
|
55
|
+
# @return [EventBus] the EventBus, ready to be called again.
|
56
|
+
#
|
57
|
+
def subscribe(pattern, listener = nil, method_name = nil, &blk)
|
58
|
+
case pattern
|
59
|
+
when Regexp, String, Symbol
|
60
|
+
subscribe_pattern(pattern, listener, method_name, &blk)
|
61
|
+
else
|
62
|
+
raise ArgumentError.new('You cannot give two listeners') if listener || method_name
|
63
|
+
raise ArgumentError.new('You cannot give both a listener and a block') if block_given?
|
64
|
+
subscribe_obj(pattern)
|
65
|
+
end
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
alias :listen_for :subscribe
|
70
|
+
|
71
|
+
#
|
72
|
+
# Register a global error handler
|
73
|
+
#
|
74
|
+
# The supplied block will be called once for each error that is raised by
|
75
|
+
# any listener, for any event.
|
76
|
+
#
|
77
|
+
# The block will be provided with two parameters, the listener that errored,
|
78
|
+
# and the payload of the event.
|
79
|
+
#
|
80
|
+
# @param blk the block to be called when any unhandled error occurs in a listener
|
81
|
+
# @return [EventBus] the EventBus, ready to be called again
|
82
|
+
def on_error(&blk)
|
83
|
+
registrations.on_error &blk
|
84
|
+
self
|
85
|
+
end
|
86
|
+
|
87
|
+
#
|
88
|
+
# Delete all current listener registrations
|
89
|
+
#
|
90
|
+
# @return the EventBus, ready to be called again.
|
91
|
+
#
|
92
|
+
def clear
|
93
|
+
registrations.clear
|
94
|
+
self
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def subscribe_pattern(pattern, listener, method_name, &blk)
|
100
|
+
if listener
|
101
|
+
raise ArgumentError.new('You cannot give both a listener and a block') if block_given?
|
102
|
+
raise ArgumentError.new('You must supply a method name') unless method_name
|
103
|
+
registrations.add_method(pattern, listener, method_name)
|
104
|
+
else
|
105
|
+
raise ArgumentError.new('You must provide a listener or a block') unless block_given?
|
106
|
+
registrations.add_block(pattern, &blk)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def subscribe_obj(listener)
|
111
|
+
registrations.add_block(/.*/) do |payload|
|
112
|
+
method = payload[:event_name].to_sym
|
113
|
+
listener.send(method, payload) if listener.respond_to?(method)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def registrations
|
118
|
+
Registrations.instance
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
@@ -0,0 +1,227 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EventBus do
|
4
|
+
let(:listener) { double(:listener, handler: true) }
|
5
|
+
|
6
|
+
before do
|
7
|
+
EventBus.clear
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'publishing' do
|
11
|
+
|
12
|
+
context 'accepts a string for the event name' do
|
13
|
+
Given { EventBus.subscribe(/aa123bb/, listener, :handler) }
|
14
|
+
When { EventBus.publish('aa123bb') }
|
15
|
+
Then { listener.should have_received(:handler).with(event_name: 'aa123bb') }
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'accepts a symbol for the event name' do
|
19
|
+
Given { EventBus.subscribe(/aa123bb/, listener, :handler) }
|
20
|
+
When { EventBus.publish(:aa123bb) }
|
21
|
+
Then { listener.should have_received(:handler).with(event_name: :aa123bb) }
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'rejects any other type as the event name' do
|
25
|
+
When(:result) { EventBus.publish(123) }
|
26
|
+
Then { result.should have_failed(ArgumentError) }
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'adds the event name to the payload' do
|
30
|
+
Given { EventBus.subscribe('aa123bb', listener, :handler) }
|
31
|
+
When { EventBus.publish('aa123bb', a: 56) }
|
32
|
+
Then { listener.should have_received(:handler).with(event_name: 'aa123bb', a: 56) }
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'allows the payload to be omitted' do
|
36
|
+
Given { EventBus.subscribe('aa123bb', listener, :handler) }
|
37
|
+
When { EventBus.publish('aa123bb') }
|
38
|
+
Then { listener.should have_received(:handler).with(event_name: 'aa123bb') }
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
describe 'publishing with errors' do
|
44
|
+
Given(:error) { RuntimeError.new }
|
45
|
+
Given(:erroring_listener) { double(:erroring_listener) }
|
46
|
+
Given(:error_handler) { double(:error_handler, handle_error: true) }
|
47
|
+
Given { erroring_listener.stub(:handler) { raise error } }
|
48
|
+
|
49
|
+
context 'sends the event to the second listener when the first errors' do
|
50
|
+
Given { EventBus.subscribe('aa123bb', erroring_listener, :handler) }
|
51
|
+
Given { EventBus.subscribe('aa123bb', listener, :handler) }
|
52
|
+
When { EventBus.publish('aa123bb') }
|
53
|
+
Then { listener.should have_received(:handler).with(event_name: 'aa123bb') }
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'with an error handler' do
|
57
|
+
Given { EventBus.on_error do |listener, payload|
|
58
|
+
error_handler.handle_error(listener, payload)
|
59
|
+
end }
|
60
|
+
|
61
|
+
context 'when the listener is an object' do
|
62
|
+
Given { EventBus.subscribe('aa123bb', erroring_listener, :handler) }
|
63
|
+
When { EventBus.publish('aa123bb') }
|
64
|
+
Then { error_handler.should have_received(:handle_error).with(erroring_listener, event_name: 'aa123bb', error: error ) }
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'when the listener is a block' do
|
68
|
+
Given { EventBus.subscribe('aa123bb') {|info| raise error } }
|
69
|
+
When { EventBus.publish('aa123bb') }
|
70
|
+
Then { error_handler.should have_received(:handle_error).with(instance_of(Proc), event_name: 'aa123bb', error: error) }
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
describe 'subscribing' do
|
78
|
+
|
79
|
+
context 'with a regex pattern' do
|
80
|
+
context 'sends the event to a matching listener' do
|
81
|
+
Given { EventBus.subscribe(/123b/, listener, :handler) }
|
82
|
+
When { EventBus.publish('aa123bb', a: 1, b: 2) }
|
83
|
+
Then { listener.should have_received(:handler).with(a: 1, b: 2, event_name: 'aa123bb') }
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'does not send the event to non-matching listeners' do
|
87
|
+
Given { EventBus.subscribe(/123a/, listener, :handler) }
|
88
|
+
When { EventBus.publish('aa123bb', a: 1, b: 2, event_name: 'aa123bb') }
|
89
|
+
Then { listener.should_not have_received(:handler) }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'with a string pattern' do
|
94
|
+
context 'sends the event to a matching listener' do
|
95
|
+
Given { EventBus.subscribe('aa123bb', listener, :handler) }
|
96
|
+
When { EventBus.publish('aa123bb', a: 1, b: 2) }
|
97
|
+
Then { listener.should have_received(:handler).with(a: 1, b: 2, event_name: 'aa123bb') }
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'does not send the event to non-matching listeners' do
|
101
|
+
Given { EventBus.subscribe('blah', listener, :handler) }
|
102
|
+
When { EventBus.publish('aa123bb', a: 1, b: 2, event_name: 'aa123bb') }
|
103
|
+
Then { listener.should_not have_received(:handler) }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context 'with a symbol pattern' do
|
108
|
+
context 'sends the event to a matching listener' do
|
109
|
+
Given { EventBus.subscribe(:aa123bb, listener, :handler) }
|
110
|
+
When { EventBus.publish(:aa123bb, a: 1, b: 2) }
|
111
|
+
Then { listener.should have_received(:handler).with(a: 1, b: 2, event_name: :aa123bb) }
|
112
|
+
end
|
113
|
+
|
114
|
+
context 'does not send the event to non-matching listeners' do
|
115
|
+
Given { EventBus.subscribe(:blah, listener, :handler) }
|
116
|
+
When { EventBus.publish('aa123bb', a: 1, b: 2, event_name: 'aa123bb') }
|
117
|
+
Then { listener.should_not have_received(:handler) }
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'subscribing a block' do
|
122
|
+
Given(:spy) { double(:spy, block_called: nil) }
|
123
|
+
Given {
|
124
|
+
EventBus.subscribe('aa123bb') {|info| spy.block_called(info) }
|
125
|
+
}
|
126
|
+
|
127
|
+
context 'calls the block when the event matches' do
|
128
|
+
When { EventBus.publish('aa123bb', a: 1, b: 2) }
|
129
|
+
Then { spy.should have_received(:block_called).with(a: 1, b: 2, event_name: 'aa123bb') }
|
130
|
+
end
|
131
|
+
|
132
|
+
context 'does not call the block when the event does not match' do
|
133
|
+
When { EventBus.publish('blah') }
|
134
|
+
Then { spy.should_not have_received(:block_called) }
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
context 'with a listener object' do
|
139
|
+
Given { EventBus.subscribe(listener) }
|
140
|
+
|
141
|
+
context 'calls a listener method whose name matches the event name' do
|
142
|
+
When { EventBus.publish('handler', a: 2, b: 3) }
|
143
|
+
Then { listener.should have_received(:handler).with(a: 2, b: 3, event_name: 'handler') }
|
144
|
+
end
|
145
|
+
|
146
|
+
context 'calls a listener method with symbol whose name matches the event name' do
|
147
|
+
When { EventBus.publish(:handler, a: 2, b: 3) }
|
148
|
+
Then { listener.should have_received(:handler).with(a: 2, b: 3, event_name: :handler) }
|
149
|
+
end
|
150
|
+
|
151
|
+
context 'calls no method when there is no name match' do
|
152
|
+
When { EventBus.publish('b_method') }
|
153
|
+
Then { listener.should_not have_received(:handler) }
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
context 'when called incorrectly' do
|
159
|
+
|
160
|
+
context 'when specifying the event name' do
|
161
|
+
|
162
|
+
context 'must provide a method or a block' do
|
163
|
+
When(:subscribe) { EventBus.subscribe('blah', listener) }
|
164
|
+
Then { subscribe.should have_failed(ArgumentError) }
|
165
|
+
end
|
166
|
+
|
167
|
+
context 'cannot provide a method AND a block' do
|
168
|
+
When(:subscribe) { EventBus.subscribe('blah', listener, :handler) {|info| }}
|
169
|
+
Then { subscribe.should have_failed(ArgumentError) }
|
170
|
+
end
|
171
|
+
|
172
|
+
context 'must provide a block when no method is supplied' do
|
173
|
+
When(:subscribe) { EventBus.subscribe('blah') }
|
174
|
+
Then { subscribe.should have_failed(ArgumentError) }
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
context 'when specifying a listener object' do
|
180
|
+
|
181
|
+
context 'when a method is also provided' do
|
182
|
+
When(:subscribe) { EventBus.subscribe(listener, double) }
|
183
|
+
Then { subscribe.should have_failed(ArgumentError) }
|
184
|
+
end
|
185
|
+
|
186
|
+
context 'when a block is also provided' do
|
187
|
+
When(:subscribe) { EventBus.subscribe(listener) {|info| } }
|
188
|
+
Then { subscribe.should have_failed(ArgumentError) }
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
describe '.clear' do
|
198
|
+
context 'removes all previous registrants' do
|
199
|
+
Given { EventBus.subscribe('aa123bb', listener, :handler) }
|
200
|
+
Given { EventBus.clear }
|
201
|
+
When { EventBus.publish('aa123bb', {}) }
|
202
|
+
Then { listener.should_not have_received(:handler) }
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
context 'EventBus methods cascade' do
|
208
|
+
|
209
|
+
context 'clear' do
|
210
|
+
When(:result) { EventBus.clear }
|
211
|
+
Then { result.should == EventBus }
|
212
|
+
end
|
213
|
+
|
214
|
+
context 'publish' do
|
215
|
+
When(:result) { EventBus.publish('aa123bb', {}) }
|
216
|
+
Then { result.should == EventBus }
|
217
|
+
end
|
218
|
+
|
219
|
+
context 'subscribe' do
|
220
|
+
When(:result) { EventBus.subscribe('aa123bb', listener, :handler) }
|
221
|
+
Then { result.should == EventBus }
|
222
|
+
end
|
223
|
+
|
224
|
+
end
|
225
|
+
|
226
|
+
end
|
227
|
+
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jmoses_event_bus
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jon Moses
|
9
|
+
- Kevin Rutherford
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2013-07-31 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rake
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 10.0.1
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ~>
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: 10.0.1
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: rspec
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ~>
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '2.12'
|
39
|
+
type: :development
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '2.12'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: simplecov
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
description: event_bus provides support for application-wide events, without coupling
|
64
|
+
the publishing and subscribing objects or classes to each other
|
65
|
+
email:
|
66
|
+
- jon@burningbus.us
|
67
|
+
- kevin@rutherford-software.com
|
68
|
+
executables: []
|
69
|
+
extensions: []
|
70
|
+
extra_rdoc_files: []
|
71
|
+
files:
|
72
|
+
- .rspec
|
73
|
+
- .yardopts
|
74
|
+
- Gemfile
|
75
|
+
- Gemfile.lock
|
76
|
+
- README.md
|
77
|
+
- Rakefile
|
78
|
+
- lib/event_bus.rb
|
79
|
+
- lib/event_bus/registrations.rb
|
80
|
+
- spec/lib/event_bus_spec.rb
|
81
|
+
- spec/spec_helper.rb
|
82
|
+
homepage: http://github.com/jmoses/event_bus
|
83
|
+
licenses: []
|
84
|
+
post_install_message:
|
85
|
+
rdoc_options: []
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ! '>='
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
requirements: []
|
101
|
+
rubyforge_project:
|
102
|
+
rubygems_version: 1.8.24
|
103
|
+
signing_key:
|
104
|
+
specification_version: 3
|
105
|
+
summary: A simple pubsub event bus for Ruby applications (fork by jmoses)
|
106
|
+
test_files:
|
107
|
+
- spec/lib/event_bus_spec.rb
|
108
|
+
- spec/spec_helper.rb
|