wisper-compat 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/test.yml +19 -0
- data/.gitignore +20 -0
- data/.rspec +4 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +152 -0
- data/CONTRIBUTING.md +57 -0
- data/Gemfile +10 -0
- data/README.md +358 -0
- data/Rakefile +6 -0
- data/lib/wisper/broadcasters/logger_broadcaster.rb +41 -0
- data/lib/wisper/broadcasters/send_broadcaster.rb +9 -0
- data/lib/wisper/configuration.rb +44 -0
- data/lib/wisper/global_listeners.rb +72 -0
- data/lib/wisper/publisher.rb +89 -0
- data/lib/wisper/registration/block.rb +11 -0
- data/lib/wisper/registration/object.rb +43 -0
- data/lib/wisper/registration/registration.rb +18 -0
- data/lib/wisper/temporary_listeners.rb +41 -0
- data/lib/wisper/value_objects/events.rb +61 -0
- data/lib/wisper/value_objects/prefix.rb +29 -0
- data/lib/wisper/version.rb +3 -0
- data/lib/wisper.rb +65 -0
- data/spec/lib/global_listeners_spec.rb +82 -0
- data/spec/lib/integration_spec.rb +56 -0
- data/spec/lib/simple_example_spec.rb +21 -0
- data/spec/lib/temporary_global_listeners_spec.rb +103 -0
- data/spec/lib/wisper/broadcasters/logger_broadcaster_spec.rb +129 -0
- data/spec/lib/wisper/broadcasters/send_broadcaster_spec.rb +68 -0
- data/spec/lib/wisper/configuration/broadcasters_spec.rb +11 -0
- data/spec/lib/wisper/configuration_spec.rb +36 -0
- data/spec/lib/wisper/publisher_spec.rb +311 -0
- data/spec/lib/wisper/registrations/object_spec.rb +14 -0
- data/spec/lib/wisper/value_objects/events_spec.rb +107 -0
- data/spec/lib/wisper/value_objects/prefix_spec.rb +46 -0
- data/spec/lib/wisper_spec.rb +99 -0
- data/spec/spec_helper.rb +21 -0
- data/wisper-compat.gemspec +29 -0
- metadata +102 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: aaf3ed2b13cd914cd672a6dbd4807be4b15768625ca23986f5a52816787e6d2e
|
4
|
+
data.tar.gz: 987559f11ef6927aef4481bbb2221d7e5f1f7e881b82e92371440ab3ed4391df
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 30141f0611839a2e847e71b29e58f2e32615ce9786d792b0b735160a8cc3c70c0cc84b75720c6811251cd87ee494ff97d37090ca238ef054ebbe8d609d95819d
|
7
|
+
data.tar.gz: ebad69d7040bdf43ea1e45dc798c32d197c761211a19af37d5c60affd61075ba91bdbc658f59b0743a1675cc6152c3627b3662b4796de7012bea17f369d06cff
|
@@ -0,0 +1,19 @@
|
|
1
|
+
name: Test
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
|
6
|
+
jobs:
|
7
|
+
test:
|
8
|
+
name: Test
|
9
|
+
runs-on: ubuntu-latest
|
10
|
+
strategy:
|
11
|
+
matrix:
|
12
|
+
ruby: [2.7, 3.0, 3.1, 3.2]
|
13
|
+
steps:
|
14
|
+
- uses: actions/checkout@v3
|
15
|
+
- uses: ruby/setup-ruby@v1
|
16
|
+
with:
|
17
|
+
ruby-version: ${{ matrix.ruby }}
|
18
|
+
bundler-cache: true
|
19
|
+
- run: bundle exec rspec spec
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.2.1
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
## HEAD (unreleased)
|
2
|
+
|
3
|
+
## 4.0 (28th Feb 2023)
|
4
|
+
Authors: Jamie Schembri
|
5
|
+
|
6
|
+
* feature: rename gem from `wisper` to `wisper-compat`.
|
7
|
+
|
8
|
+
## 3.0 (20th Jan 2023)
|
9
|
+
Authors: doits, jstoks, merringtion
|
10
|
+
|
11
|
+
* Adds: Support for Ruby 3.0 keyword arguments
|
12
|
+
* Removes: Support for Ruby 2.6 and lower
|
13
|
+
|
14
|
+
## 2.0.1 (29th Aug 2019)
|
15
|
+
|
16
|
+
Authors: David Wilkie, hosseintoussi, Maxim Polunin, Tristan
|
17
|
+
Harmer, Bartosz Żurkowski, Kris Leech
|
18
|
+
|
19
|
+
* fix: support nested temporary global listeners
|
20
|
+
* docs: add threadsafe notes to README for global and temporary listeners
|
21
|
+
* docs: fix spelling mistakes in README
|
22
|
+
* fix: safely get signing key in gemspec when HOME is not set
|
23
|
+
* adds: add console to aid experiments and REPL driven development
|
24
|
+
* adds: Latest Ruby to CI
|
25
|
+
|
26
|
+
## 2.0.0 (7th Mar 2017)
|
27
|
+
|
28
|
+
Authors: Sergey Mostovoy, Andrew Kozin, Kyle Tolle, Martin, Rob Miller, Mike
|
29
|
+
Dalto, orthographic-pedant, Drew Ulmer, Mikey Hogarth, Attila Domokos, Josh
|
30
|
+
Miltz, Pascal Betz, Vasily Kolesnikov, Julien Letessier, Kris Leech
|
31
|
+
|
32
|
+
* Fix: logger raises exception if hash is passed as an argument to a listener #133, #136
|
33
|
+
* Fix: deprecation warnings #120
|
34
|
+
* Doc improvements: #106, #111, #116, #122, #128, #130, #147, #149, #150, #151
|
35
|
+
* Adds: Allow configuration of default prefix when using `prefix: true`. #105
|
36
|
+
* Adds: Allow unsubscribing of global listeners #118
|
37
|
+
* Adds: Helpful error message when passing a block to `#subscribe` of `#on` #125
|
38
|
+
* Adds: raise an error message when `#on` is not passed a block #146
|
39
|
+
* Adds: Support for JRuby 9.x #148
|
40
|
+
* Adds: Support for MRI 2.4.0 #155
|
41
|
+
* Refactor specs #126, #131
|
42
|
+
|
43
|
+
## 2.0.0.rc1 (17 Dec 2014)
|
44
|
+
|
45
|
+
Authors: Kris Leech
|
46
|
+
|
47
|
+
* remove: deprecated methods
|
48
|
+
* remove: rspec matcher and stubbing (moved to [wisper-rspec](https://github.com/krisleech/wisper-rspec))
|
49
|
+
* feature: add regexp support to `on` argument
|
50
|
+
* remove: announce alias for broadcasting
|
51
|
+
* docs: add Code of Conduct
|
52
|
+
* drop support for Ruby 1.9
|
53
|
+
|
54
|
+
## 1.6.0 (25 Oct 2014)
|
55
|
+
|
56
|
+
Authors: Kris Leech
|
57
|
+
|
58
|
+
* deprecate: add_listener, add_block_listener and respond_to
|
59
|
+
* internal: make method naming more consistent
|
60
|
+
|
61
|
+
## 1.5.0 (6th Oct 2014)
|
62
|
+
|
63
|
+
Authors: Kris Leech
|
64
|
+
|
65
|
+
* feature: allow events to be published asynchronously
|
66
|
+
* feature: broadcasting of events is plugable and configurable
|
67
|
+
* feature: broadcasters can be aliased via a symbol
|
68
|
+
* feature: logging broadcaster
|
69
|
+
|
70
|
+
## 1.4.0 (8th Sept 2014)
|
71
|
+
|
72
|
+
Authors: Kris Leech, Marc Ignacio, Ahmed Abdel Razzak, kmehkeri, Jake Hoffner
|
73
|
+
|
74
|
+
* feature: matcher for rspec 3
|
75
|
+
* fix: temporary global listeners are cleared if an exception is raised
|
76
|
+
* refactor: update all specs to rspec 3 expect syntax
|
77
|
+
* docs: update README to rspec 3 expect syntax
|
78
|
+
* feature: combine global and temporary listener methods as `Wisper.subscribe`
|
79
|
+
* deprecate: `Wisper.add_listener` and `Wisper.with_listeners,` use `Wisper.subscribe` instead
|
80
|
+
|
81
|
+
## 1.3.0 (18th Jan 2014)
|
82
|
+
|
83
|
+
Authors: Kris Leech, Yan Pritzker, Charlie Tran
|
84
|
+
|
85
|
+
* feature: global subscriptions can be scoped to a class (and sub-classes)
|
86
|
+
* upgrade: use rspec 3
|
87
|
+
* feature: allow prefixing of events with 'on'
|
88
|
+
* feature: Allow stubbed publisher method to accept arbitrary args
|
89
|
+
|
90
|
+
## 1.2.1 (7th Oct 2013)
|
91
|
+
|
92
|
+
Authors: Kris Leech, Tomasz Szymczyszyn, Alex Heeton
|
93
|
+
|
94
|
+
* feature: global subscriptions can be passed options
|
95
|
+
* docs: improve README examples
|
96
|
+
* docs: add license to gemspec
|
97
|
+
|
98
|
+
## 1.2.0 (21st July 2013)
|
99
|
+
|
100
|
+
Authors: Kris Leech, Darren Coxall
|
101
|
+
|
102
|
+
* feature: support for multiple events at once
|
103
|
+
* fix: clear global listeners after each spec
|
104
|
+
|
105
|
+
## 1.1.0 (7th June 2013)
|
106
|
+
|
107
|
+
Authors: Kris Leech, chatgris
|
108
|
+
|
109
|
+
* feature: add temporary global listeners
|
110
|
+
* docs: improve ActiveRecord example
|
111
|
+
* refactor: improve specs
|
112
|
+
* upgrade: add Ruby 2.0 support
|
113
|
+
* fix: make listener collection immutable
|
114
|
+
* remove: async publishing and Celluloid dependency
|
115
|
+
* fix: Make global listeners getter and setter threadsafe [9]
|
116
|
+
|
117
|
+
## 1.0.1 (2nd May 2013)
|
118
|
+
|
119
|
+
Authors: Kris Leech, Yan Pritzker
|
120
|
+
|
121
|
+
* feature: add async publishing using Celluloid
|
122
|
+
* docs: improve README examples
|
123
|
+
* feature: `stub_wisper_publisher` rspec helper
|
124
|
+
* feature: global listeners
|
125
|
+
* refactor: improve specs
|
126
|
+
|
127
|
+
## 1.0.0 (7th April 2013)
|
128
|
+
|
129
|
+
Authors: Kris Leech
|
130
|
+
|
131
|
+
* refactor: specs
|
132
|
+
* refactor: registrations
|
133
|
+
* feature: Add `with` argument to `subscribe`
|
134
|
+
* docs: improve README examples
|
135
|
+
* feature: Allow subscriptions to be chainable
|
136
|
+
* feature: Add `on` syntax for block subscription
|
137
|
+
* remove: Remove support for Ruby 1.8.7
|
138
|
+
* docs: Add badges to README
|
139
|
+
|
140
|
+
## 0.0.2 (30th March 2013)
|
141
|
+
|
142
|
+
Authors: Kris Leech
|
143
|
+
|
144
|
+
* remove: ActiveSupport dependency
|
145
|
+
* docs: fix syntax highlighting in README
|
146
|
+
|
147
|
+
## 0.0.1 (30th March 2013)
|
148
|
+
|
149
|
+
Authors: Kris Leech
|
150
|
+
|
151
|
+
* docs: add README
|
152
|
+
* feature: registration of objects and blocks
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# How to Contribute
|
2
|
+
|
3
|
+
We very much welcome contributions to Wisper.
|
4
|
+
|
5
|
+
This project is intended to be a safe, welcoming space for collaboration,
|
6
|
+
and contributors are expected to adhere to the
|
7
|
+
[Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
8
|
+
|
9
|
+
## Getting started
|
10
|
+
|
11
|
+
Please first check the existing [Issues](https://github.com/krisleech/wisper/issues)
|
12
|
+
and [Pull Requests](https://github.com/krisleech/wisper/pulls) to ensure your
|
13
|
+
issue has not already been discused.
|
14
|
+
|
15
|
+
## Bugs
|
16
|
+
|
17
|
+
Please submit a bug report to the issue tracker, with the version of Wisper
|
18
|
+
and Ruby you are using and a small code sample (or better yet a failing test).
|
19
|
+
|
20
|
+
## Features
|
21
|
+
|
22
|
+
Please open an issue with your proposed feature. We can discuss the feature and
|
23
|
+
if it is acceptable we can also discuss implimentation details. You will in
|
24
|
+
most cases have to submit a PR which adds the feature.
|
25
|
+
|
26
|
+
Wisper is a micro library and will remain lean. Some features would be most
|
27
|
+
appropriate as an extension to Wisper.
|
28
|
+
|
29
|
+
We also have a [Gitter channel](https://gitter.im/krisleech/wisper) if you wish to discuss your ideas.
|
30
|
+
|
31
|
+
## Questions
|
32
|
+
|
33
|
+
Try the [Wiki](https://github.com/krisleech/wisper/wiki) first, the examples
|
34
|
+
and how to sections have lots of information.
|
35
|
+
|
36
|
+
Please ask questions on StackOverflow, [tagged wisper](https://stackoverflow.com/questions/tagged/wisper).
|
37
|
+
|
38
|
+
Feel free to ping me the URL on [Twitter](https://twitter.com/krisleech).
|
39
|
+
|
40
|
+
## Pull requests
|
41
|
+
|
42
|
+
* Fork the project, create a new branch `master`.
|
43
|
+
* Squash commits which are related.
|
44
|
+
* Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
|
45
|
+
* Documentation only changes should have `[skip ci]` in the commit message
|
46
|
+
* Follow existing code style in terms of syntax, indentation etc.
|
47
|
+
* Add an entry to the CHANGELOG
|
48
|
+
* Do not bump the VERSION, but do indicate in the CHANGELOG if the change is
|
49
|
+
not backwards compatible.
|
50
|
+
* Issue a Pull Request
|
51
|
+
|
52
|
+
## Versions
|
53
|
+
|
54
|
+
The `v1` branch is a long lived branch and you should
|
55
|
+
branch from this if you wish to fix an issue in version `~> 1.0`.
|
56
|
+
|
57
|
+
Otherwise branch from `master` branch.
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,358 @@
|
|
1
|
+
# Wisper
|
2
|
+
|
3
|
+
*A micro library providing Ruby objects with Publish-Subscribe capabilities*
|
4
|
+
|
5
|
+
[![Gem Version](https://badge.fury.io/rb/wisper-compat.svg)](http://badge.fury.io/rb/wisper-compat)
|
6
|
+
|
7
|
+
* Decouple core business logic from external concerns in Hexagonal style architectures
|
8
|
+
* Use as an alternative to ActiveRecord callbacks and Observers in Rails apps
|
9
|
+
* Connect objects based on context without permanence
|
10
|
+
* Publish events synchronously or asynchronously
|
11
|
+
|
12
|
+
Note: Wisper was originally extracted from a Rails codebase but is not dependant on Rails.
|
13
|
+
|
14
|
+
Please also see the [Wiki](https://github.com/krisleech/wisper/wiki) for more additional information and articles.
|
15
|
+
|
16
|
+
**For greenfield applications you might also be interested in
|
17
|
+
[WisperNext](https://gitlab.com/kris.leech/wisper_next) and [Ma](https://gitlab.com/kris.leech/ma).**
|
18
|
+
|
19
|
+
## Installation
|
20
|
+
|
21
|
+
Add this line to your application's Gemfile:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
gem 'wisper-compat', '4.0.0'
|
25
|
+
```
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
Any class with the `Wisper::Publisher` module included can broadcast events
|
30
|
+
to subscribed listeners. Listeners subscribe, at runtime, to the publisher.
|
31
|
+
|
32
|
+
### Publishing
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
class CancelOrder
|
36
|
+
include Wisper::Publisher
|
37
|
+
|
38
|
+
def call(order_id)
|
39
|
+
order = Order.find_by_id(order_id)
|
40
|
+
|
41
|
+
# business logic...
|
42
|
+
|
43
|
+
if order.cancelled?
|
44
|
+
broadcast(:cancel_order_successful, order.id)
|
45
|
+
else
|
46
|
+
broadcast(:cancel_order_failed, order.id)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
52
|
+
When a publisher broadcasts an event it can include any number of arguments.
|
53
|
+
|
54
|
+
The `broadcast` method is also aliased as `publish`.
|
55
|
+
|
56
|
+
You can also include `Wisper.publisher` instead of `Wisper::Publisher`.
|
57
|
+
|
58
|
+
### Subscribing
|
59
|
+
|
60
|
+
#### Objects
|
61
|
+
|
62
|
+
Any object can be subscribed as a listener.
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
cancel_order = CancelOrder.new
|
66
|
+
|
67
|
+
cancel_order.subscribe(OrderNotifier.new)
|
68
|
+
|
69
|
+
cancel_order.call(order_id)
|
70
|
+
```
|
71
|
+
|
72
|
+
The listener would need to implement a method for every event it wishes to receive.
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
class OrderNotifier
|
76
|
+
def cancel_order_successful(order_id)
|
77
|
+
order = Order.find_by_id(order_id)
|
78
|
+
|
79
|
+
# notify someone ...
|
80
|
+
end
|
81
|
+
end
|
82
|
+
```
|
83
|
+
|
84
|
+
#### Blocks
|
85
|
+
|
86
|
+
Blocks can be subscribed to single events and can be chained.
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
cancel_order = CancelOrder.new
|
90
|
+
|
91
|
+
cancel_order.on(:cancel_order_successful) { |order_id| ... }
|
92
|
+
.on(:cancel_order_failed) { |order_id| ... }
|
93
|
+
|
94
|
+
cancel_order.call(order_id)
|
95
|
+
```
|
96
|
+
|
97
|
+
You can also subscribe to multiple events using `on` by passing
|
98
|
+
additional events as arguments.
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
cancel_order = CancelOrder.new
|
102
|
+
|
103
|
+
cancel_order.on(:cancel_order_successful) { |order_id| ... }
|
104
|
+
.on(:cancel_order_failed,
|
105
|
+
:cancel_order_invalid) { |order_id| ... }
|
106
|
+
|
107
|
+
cancel_order.call(order_id)
|
108
|
+
```
|
109
|
+
|
110
|
+
Do not `return` from inside a subscribed block, due to the way
|
111
|
+
[Ruby treats blocks](http://product.reverb.com/2015/02/28/the-strange-case-of-wisper-and-ruby-blocks-behaving-like-procs/)
|
112
|
+
this will prevent any subsequent listeners having their events delivered.
|
113
|
+
|
114
|
+
### Handling Events Asynchronously
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
cancel_order.subscribe(OrderNotifier.new, async: true)
|
118
|
+
```
|
119
|
+
|
120
|
+
Wisper has various adapters for asynchronous event handling, please refer to
|
121
|
+
[wisper-celluloid](https://github.com/krisleech/wisper-celluloid),
|
122
|
+
[wisper-sidekiq](https://github.com/krisleech/wisper-sidekiq),
|
123
|
+
[wisper-activejob](https://github.com/krisleech/wisper-activejob),
|
124
|
+
[wisper-que](https://github.com/joevandyk/wisper-que) or
|
125
|
+
[wisper-resque](https://github.com/bzurkowski/wisper-resque).
|
126
|
+
|
127
|
+
Depending on the adapter used the listener may need to be a class instead of an object. In this situation, every method corresponding to events should be declared as a class method, too. For example:
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
class OrderNotifier
|
131
|
+
# declare a class method if you are subscribing the listener class instead of its instance like:
|
132
|
+
# cancel_order.subscribe(OrderNotifier)
|
133
|
+
#
|
134
|
+
def self.cancel_order_successful(order_id)
|
135
|
+
order = Order.find_by_id(order_id)
|
136
|
+
|
137
|
+
# notify someone ...
|
138
|
+
end
|
139
|
+
end
|
140
|
+
```
|
141
|
+
|
142
|
+
### ActionController
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
class CancelOrderController < ApplicationController
|
146
|
+
|
147
|
+
def create
|
148
|
+
cancel_order = CancelOrder.new
|
149
|
+
|
150
|
+
cancel_order.subscribe(OrderMailer, async: true)
|
151
|
+
cancel_order.subscribe(ActivityRecorder, async: true)
|
152
|
+
cancel_order.subscribe(StatisticsRecorder, async: true)
|
153
|
+
|
154
|
+
cancel_order.on(:cancel_order_successful) { |order_id| redirect_to order_path(order_id) }
|
155
|
+
cancel_order.on(:cancel_order_failed) { |order_id| render action: :new }
|
156
|
+
|
157
|
+
cancel_order.call(order_id)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
```
|
161
|
+
|
162
|
+
### ActiveRecord
|
163
|
+
|
164
|
+
If you wish to publish directly from ActiveRecord models you can broadcast events from callbacks:
|
165
|
+
|
166
|
+
```ruby
|
167
|
+
class Order < ActiveRecord::Base
|
168
|
+
include Wisper::Publisher
|
169
|
+
|
170
|
+
after_commit :publish_creation_successful, on: :create
|
171
|
+
after_validation :publish_creation_failed, on: :create
|
172
|
+
|
173
|
+
private
|
174
|
+
|
175
|
+
def publish_creation_successful
|
176
|
+
broadcast(:order_creation_successful, self)
|
177
|
+
end
|
178
|
+
|
179
|
+
def publish_creation_failed
|
180
|
+
broadcast(:order_creation_failed, self) if errors.any?
|
181
|
+
end
|
182
|
+
end
|
183
|
+
```
|
184
|
+
|
185
|
+
There are more examples in the [Wiki](https://github.com/krisleech/wisper/wiki).
|
186
|
+
|
187
|
+
## Global Listeners
|
188
|
+
|
189
|
+
Global listeners receive all broadcast events which they can respond to.
|
190
|
+
|
191
|
+
This is useful for cross cutting concerns such as recording statistics, indexing, caching and logging.
|
192
|
+
|
193
|
+
```ruby
|
194
|
+
Wisper.subscribe(MyListener.new)
|
195
|
+
```
|
196
|
+
|
197
|
+
In a Rails app you might want to add your global listeners in an initializer.
|
198
|
+
|
199
|
+
Global listeners are threadsafe. Subscribers will receive events published on all threads.
|
200
|
+
|
201
|
+
|
202
|
+
### Scoping by publisher class
|
203
|
+
|
204
|
+
You might want to globally subscribe a listener to publishers with a certain
|
205
|
+
class.
|
206
|
+
|
207
|
+
```ruby
|
208
|
+
Wisper.subscribe(MyListener.new, scope: :MyPublisher)
|
209
|
+
Wisper.subscribe(MyListener.new, scope: MyPublisher)
|
210
|
+
Wisper.subscribe(MyListener.new, scope: "MyPublisher")
|
211
|
+
Wisper.subscribe(MyListener.new, scope: [:MyPublisher, :MyOtherPublisher])
|
212
|
+
```
|
213
|
+
|
214
|
+
This will subscribe the listener to all instances of the specified class(es) and their
|
215
|
+
subclasses.
|
216
|
+
|
217
|
+
Alternatively you can also do exactly the same with a publisher class itself:
|
218
|
+
|
219
|
+
```ruby
|
220
|
+
MyPublisher.subscribe(MyListener.new)
|
221
|
+
```
|
222
|
+
|
223
|
+
## Temporary Global Listeners
|
224
|
+
|
225
|
+
You can also globally subscribe listeners for the duration of a block.
|
226
|
+
|
227
|
+
```ruby
|
228
|
+
Wisper.subscribe(MyListener.new, OtherListener.new) do
|
229
|
+
# do stuff
|
230
|
+
end
|
231
|
+
```
|
232
|
+
|
233
|
+
Any events broadcast within the block by any publisher will be sent to the
|
234
|
+
listeners.
|
235
|
+
|
236
|
+
This is useful for capturing events published by objects to which you do not have access in a given context.
|
237
|
+
|
238
|
+
Temporary Global Listeners are threadsafe. Subscribers will receive events published on the same thread.
|
239
|
+
|
240
|
+
## Subscribing to selected events
|
241
|
+
|
242
|
+
By default a listener will get notified of all events it can respond to. You
|
243
|
+
can limit which events a listener is notified of by passing a string, symbol,
|
244
|
+
array or regular expression to `on`:
|
245
|
+
|
246
|
+
```ruby
|
247
|
+
post_creator.subscribe(PusherListener.new, on: :create_post_successful)
|
248
|
+
```
|
249
|
+
|
250
|
+
## Prefixing broadcast events
|
251
|
+
|
252
|
+
If you would prefer listeners to receive events with a prefix, for example
|
253
|
+
`on`, you can do so by passing a string or symbol to `prefix:`.
|
254
|
+
|
255
|
+
```ruby
|
256
|
+
post_creator.subscribe(PusherListener.new, prefix: :on)
|
257
|
+
```
|
258
|
+
|
259
|
+
If `post_creator` were to broadcast the event `post_created` the subscribed
|
260
|
+
listeners would receive `on_post_created`. You can also pass `true` which will
|
261
|
+
use the default prefix, "on".
|
262
|
+
|
263
|
+
## Mapping an event to a different method
|
264
|
+
|
265
|
+
By default the method called on the listener is the same as the event
|
266
|
+
broadcast. However it can be mapped to a different method using `with:`.
|
267
|
+
|
268
|
+
```ruby
|
269
|
+
report_creator.subscribe(MailResponder.new, with: :successful)
|
270
|
+
```
|
271
|
+
|
272
|
+
This is pretty useless unless used in conjunction with `on:`, since all events
|
273
|
+
will get mapped to `:successful`. Instead you might do something like this:
|
274
|
+
|
275
|
+
```ruby
|
276
|
+
report_creator.subscribe(MailResponder.new, on: :create_report_successful,
|
277
|
+
with: :successful)
|
278
|
+
```
|
279
|
+
|
280
|
+
If you pass an array of events to `on:` each event will be mapped to the same
|
281
|
+
method when `with:` is specified. If you need to listen for select events
|
282
|
+
_and_ map each one to a different method subscribe the listener once for
|
283
|
+
each mapping:
|
284
|
+
|
285
|
+
```ruby
|
286
|
+
report_creator.subscribe(MailResponder.new, on: :create_report_successful,
|
287
|
+
with: :successful)
|
288
|
+
|
289
|
+
report_creator.subscribe(MailResponder.new, on: :create_report_failed,
|
290
|
+
with: :failed)
|
291
|
+
```
|
292
|
+
|
293
|
+
You could also alias the method within your listener, as such
|
294
|
+
`alias successful create_report_successful`.
|
295
|
+
|
296
|
+
## Testing
|
297
|
+
|
298
|
+
Testing matchers and stubs are in separate gems.
|
299
|
+
|
300
|
+
* [wisper-rspec](https://github.com/krisleech/wisper-rspec)
|
301
|
+
* [wisper-minitest](https://github.com/digitalcuisine/wisper-minitest)
|
302
|
+
|
303
|
+
### Clearing Global Listeners
|
304
|
+
|
305
|
+
If you use global listeners in non-feature tests you _might_ want to clear them
|
306
|
+
in a hook to prevent global subscriptions persisting between tests.
|
307
|
+
|
308
|
+
```ruby
|
309
|
+
after { Wisper.clear }
|
310
|
+
```
|
311
|
+
|
312
|
+
## Need help?
|
313
|
+
|
314
|
+
The [Wiki](https://github.com/krisleech/wisper/wiki) has more examples,
|
315
|
+
articles and talks.
|
316
|
+
|
317
|
+
Got a specific question, try the
|
318
|
+
[Wisper tag on StackOverflow](http://stackoverflow.com/questions/tagged/wisper).
|
319
|
+
|
320
|
+
## Running Specs
|
321
|
+
|
322
|
+
```
|
323
|
+
bundle exec rspec
|
324
|
+
```
|
325
|
+
|
326
|
+
To run the specs on code changes try [entr](http://entrproject.org/):
|
327
|
+
|
328
|
+
```
|
329
|
+
ls **/*.rb | entr bundle exec rspec
|
330
|
+
```
|
331
|
+
|
332
|
+
## Contributing
|
333
|
+
|
334
|
+
Please read the [Contributing Guidelines](https://github.com/nedap/wisper-compat/blob/master/CONTRIBUTING.md).
|
335
|
+
|
336
|
+
## License
|
337
|
+
|
338
|
+
(The MIT License)
|
339
|
+
|
340
|
+
Copyright (c) 2013 Kris Leech
|
341
|
+
|
342
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
343
|
+
this software and associated documentation files (the 'Software'), to deal in
|
344
|
+
the Software without restriction, including without limitation the rights to
|
345
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
346
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
347
|
+
so, subject to the following conditions:
|
348
|
+
|
349
|
+
The above copyright notice and this permission notice shall be included in all
|
350
|
+
copies or substantial portions of the Software.
|
351
|
+
|
352
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
353
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
354
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
355
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
356
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
357
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
358
|
+
SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# Provides a way of wrapping another broadcaster with logging
|
2
|
+
|
3
|
+
module Wisper
|
4
|
+
module Broadcasters
|
5
|
+
class LoggerBroadcaster
|
6
|
+
def initialize(logger, broadcaster)
|
7
|
+
@logger = logger
|
8
|
+
@broadcaster = broadcaster
|
9
|
+
end
|
10
|
+
|
11
|
+
def broadcast(listener, publisher, event, *args, **kwargs)
|
12
|
+
@logger.info("[WISPER] #{name(publisher)} published #{event} to #{name(listener)} with #{args_info(args)} and #{kwargs_info(kwargs)}")
|
13
|
+
@broadcaster.broadcast(listener, publisher, event, *args, **kwargs)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def name(object)
|
19
|
+
id_method = %w(id uuid key object_id).find do |method_name|
|
20
|
+
object.respond_to?(method_name) && object.method(method_name).arity <= 0
|
21
|
+
end
|
22
|
+
id = object.send(id_method)
|
23
|
+
class_name = object.class == Class ? object.name : object.class.name
|
24
|
+
"#{class_name}##{id}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def args_info(args)
|
28
|
+
return 'no arguments' if args.empty?
|
29
|
+
args.map do |arg|
|
30
|
+
arg_string = name(arg)
|
31
|
+
arg_string += ": #{arg.inspect}" if [Numeric, Array, Hash, String].any? {|klass| arg.is_a?(klass) }
|
32
|
+
arg_string
|
33
|
+
end.join(', ')
|
34
|
+
end
|
35
|
+
|
36
|
+
def kwargs_info(kwargs)
|
37
|
+
kwargs.empty? ? 'no keyword arguments' : "keyword arguments #{kwargs.inspect}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|