wisper-compat 4.0.0

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.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/test.yml +19 -0
  3. data/.gitignore +20 -0
  4. data/.rspec +4 -0
  5. data/.ruby-version +1 -0
  6. data/CHANGELOG.md +152 -0
  7. data/CONTRIBUTING.md +57 -0
  8. data/Gemfile +10 -0
  9. data/README.md +358 -0
  10. data/Rakefile +6 -0
  11. data/lib/wisper/broadcasters/logger_broadcaster.rb +41 -0
  12. data/lib/wisper/broadcasters/send_broadcaster.rb +9 -0
  13. data/lib/wisper/configuration.rb +44 -0
  14. data/lib/wisper/global_listeners.rb +72 -0
  15. data/lib/wisper/publisher.rb +89 -0
  16. data/lib/wisper/registration/block.rb +11 -0
  17. data/lib/wisper/registration/object.rb +43 -0
  18. data/lib/wisper/registration/registration.rb +18 -0
  19. data/lib/wisper/temporary_listeners.rb +41 -0
  20. data/lib/wisper/value_objects/events.rb +61 -0
  21. data/lib/wisper/value_objects/prefix.rb +29 -0
  22. data/lib/wisper/version.rb +3 -0
  23. data/lib/wisper.rb +65 -0
  24. data/spec/lib/global_listeners_spec.rb +82 -0
  25. data/spec/lib/integration_spec.rb +56 -0
  26. data/spec/lib/simple_example_spec.rb +21 -0
  27. data/spec/lib/temporary_global_listeners_spec.rb +103 -0
  28. data/spec/lib/wisper/broadcasters/logger_broadcaster_spec.rb +129 -0
  29. data/spec/lib/wisper/broadcasters/send_broadcaster_spec.rb +68 -0
  30. data/spec/lib/wisper/configuration/broadcasters_spec.rb +11 -0
  31. data/spec/lib/wisper/configuration_spec.rb +36 -0
  32. data/spec/lib/wisper/publisher_spec.rb +311 -0
  33. data/spec/lib/wisper/registrations/object_spec.rb +14 -0
  34. data/spec/lib/wisper/value_objects/events_spec.rb +107 -0
  35. data/spec/lib/wisper/value_objects/prefix_spec.rb +46 -0
  36. data/spec/lib/wisper_spec.rb +99 -0
  37. data/spec/spec_helper.rb +21 -0
  38. data/wisper-compat.gemspec +29 -0
  39. 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
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ .tool-versions
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
19
+ tags
20
+ vendor
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --format progress
3
+ --require spec_helper
4
+ --warnings
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
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rake'
6
+ gem 'rspec'
7
+
8
+ group :extras do
9
+ gem 'yard'
10
+ end
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,6 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new
5
+
6
+ task :default => :spec
@@ -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
@@ -0,0 +1,9 @@
1
+ module Wisper
2
+ module Broadcasters
3
+ class SendBroadcaster
4
+ def broadcast(listener, publisher, event, *args, **kwargs)
5
+ listener.public_send(event, *args, **kwargs)
6
+ end
7
+ end
8
+ end
9
+ end