u-observers 1.0.0 → 2.3.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.
- checksums.yaml +4 -4
- data/README.md +345 -40
- data/README.pt-BR.md +610 -0
- data/lib/micro/observers.rb +5 -3
- data/lib/micro/observers/broadcast.rb +77 -0
- data/lib/micro/observers/event.rb +21 -0
- data/lib/micro/observers/{events.rb → event/names.rb} +5 -3
- data/lib/micro/observers/for/active_model.rb +2 -2
- data/lib/micro/observers/set.rb +107 -0
- data/lib/micro/observers/subscribers.rb +110 -0
- data/lib/micro/observers/utils.rb +12 -3
- data/lib/micro/observers/version.rb +1 -1
- metadata +8 -4
- data/lib/micro/observers/manager.rb +0 -172
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 55ea9f6a206dba9526be1d7777969b26311f725652b3020344db33563a5835c8
|
4
|
+
data.tar.gz: d8a6e1bf2e73d15fadbd71e82aa17e0c511fb11d97a7839ba165c50589324b66
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c9b907879c02a2071b6c194af9f5c1a6e50a3bd17655beaed0f9dfb7858c892f657c9a57666d320d23d0055a48625d168d625fbae19ca7a560722b8c1b475d31
|
7
|
+
data.tar.gz: 4a551b0a43d15b5968d843d2a3b737ae245e177da3ac0c595f9265be887ff3b2b1205a3544c368973cae993869a9083fbffdc2cf64dab9b18c5d6d17eae5282b
|
data/README.md
CHANGED
@@ -26,17 +26,30 @@
|
|
26
26
|
|
27
27
|
This gem implements the observer pattern [[1]](https://en.wikipedia.org/wiki/Observer_pattern)[[2]](https://refactoring.guru/design-patterns/observer) (also known as publish/subscribe). It provides a simple mechanism for one object to inform a set of interested third-party objects when its state changes.
|
28
28
|
|
29
|
-
Ruby's standard library [has an abstraction](https://ruby-doc.org/stdlib-2.7.1/libdoc/observer/rdoc/Observable.html) that enables you to use this pattern. But its design can conflict with other mainstream libraries, like the [`ActiveModel`/`ActiveRecord`](https://api.rubyonrails.org/classes/ActiveModel/Dirty.html#method-i-changed), which also has the [`changed`](https://ruby-doc.org/stdlib-2.7.1/libdoc/observer/rdoc/Observable.html#method-i-changed) method. In this case, the behavior of the Stdlib will be
|
29
|
+
Ruby's standard library [has an abstraction](https://ruby-doc.org/stdlib-2.7.1/libdoc/observer/rdoc/Observable.html) that enables you to use this pattern. But its design can conflict with other mainstream libraries, like the [`ActiveModel`/`ActiveRecord`](https://api.rubyonrails.org/classes/ActiveModel/Dirty.html#method-i-changed), which also has the [`changed`](https://ruby-doc.org/stdlib-2.7.1/libdoc/observer/rdoc/Observable.html#method-i-changed) method. In this case, the behavior of the Stdlib will be compromised.
|
30
30
|
|
31
|
-
Because of this issue, I decided to create a gem that encapsulates the pattern without changing the object's implementation so much. The `Micro::Observers` includes just one instance method in the target class (its instance will be the observed subject).
|
31
|
+
Because of this issue, I decided to create a gem that encapsulates the pattern without changing the object's implementation so much. The `Micro::Observers` includes just one instance method in the target class (its instance will be the observed subject/object).
|
32
|
+
|
33
|
+
> **Note:** Você entende português? 🇧🇷 🇵🇹 Verifique o [README traduzido em pt-BR](https://github.com/serradura/u-observers/blob/main/README.pt-BR.md).
|
32
34
|
|
33
35
|
# Table of contents <!-- omit in toc -->
|
34
36
|
- [Installation](#installation)
|
35
37
|
- [Compatibility](#compatibility)
|
36
38
|
- [Usage](#usage)
|
37
|
-
- [
|
39
|
+
- [Sharing a context with your observers](#sharing-a-context-with-your-observers)
|
40
|
+
- [Sharing data when notifying the observers](#sharing-data-when-notifying-the-observers)
|
41
|
+
- [What is a `Micro::Observers::Event`?](#what-is-a-microobserversevent)
|
42
|
+
- [Using a callable as an observer](#using-a-callable-as-an-observer)
|
38
43
|
- [Calling the observers](#calling-the-observers)
|
39
44
|
- [Notifying observers without marking them as changed](#notifying-observers-without-marking-them-as-changed)
|
45
|
+
- [Defining observers that execute only once](#defining-observers-that-execute-only-once)
|
46
|
+
- [`observers.attach(*args, perform_once: true)`](#observersattachargs-perform_once-true)
|
47
|
+
- [`observers.once(event:, call:, ...)`](#observersonceevent-call-)
|
48
|
+
- [Defining observers using blocks](#defining-observers-using-blocks)
|
49
|
+
- [order.observers.on()](#orderobserverson)
|
50
|
+
- [order.observers.on()](#orderobserverson-1)
|
51
|
+
- [Replacing a block by a `lambda`/`proc`](#replacing-a-block-by-a-lambdaproc)
|
52
|
+
- [Detaching observers](#detaching-observers)
|
40
53
|
- [ActiveRecord and ActiveModel integrations](#activerecord-and-activemodel-integrations)
|
41
54
|
- [notify_observers_on()](#notify_observers_on)
|
42
55
|
- [notify_observers()](#notify_observers)
|
@@ -57,11 +70,13 @@ gem 'u-observers'
|
|
57
70
|
|
58
71
|
| u-observers | branch | ruby | activerecord |
|
59
72
|
| ----------- | ------- | -------- | ------------- |
|
60
|
-
|
|
73
|
+
| unreleased | main | >= 2.2.0 | >= 3.2, < 6.1 |
|
74
|
+
| 2.3.0 | v2.x | >= 2.2.0 | >= 3.2, < 6.1 |
|
75
|
+
| 1.0.0 | v1.x | >= 2.2.0 | >= 3.2, < 6.1 |
|
61
76
|
|
62
77
|
> **Note**: The ActiveRecord isn't a dependency, but you could add a module to enable some static methods that were designed to be used with its [callbacks](https://guides.rubyonrails.org/active_record_callbacks.html).
|
63
78
|
|
64
|
-
[⬆️ Back to Top](#table-of-contents-)
|
79
|
+
[⬆️ Back to Top](#table-of-contents-)
|
65
80
|
|
66
81
|
## Usage
|
67
82
|
|
@@ -102,8 +117,8 @@ end
|
|
102
117
|
order = Order.new
|
103
118
|
#<Order:0x00007fb5dd8fce70 @code="X0o9yf1GsdQFvLR4", @status=:draft>
|
104
119
|
|
105
|
-
order.observers.attach(OrderEvents)
|
106
|
-
# <#Micro::Observers::
|
120
|
+
order.observers.attach(OrderEvents) # attaching multiple observers. e.g. observers.attach(A, B, C)
|
121
|
+
# <#Micro::Observers::Set @subject=#<Order:0x00007fb5dd8fce70> @subject_changed=false @subscribers=[OrderEvents]>
|
107
122
|
|
108
123
|
order.canceled?
|
109
124
|
# false
|
@@ -114,11 +129,20 @@ order.cancel!
|
|
114
129
|
|
115
130
|
order.canceled?
|
116
131
|
# true
|
132
|
+
|
133
|
+
order.observers.detach(OrderEvents) # detaching multiple observers. e.g. observers.detach(A, B, C)
|
134
|
+
# <#Micro::Observers::Set @subject=#<Order:0x00007fb5dd8fce70> @subject_changed=false @subscribers=[]>
|
135
|
+
|
136
|
+
order.canceled?
|
137
|
+
# true
|
138
|
+
|
139
|
+
order.observers.subject_changed!
|
140
|
+
order.observers.notify(:canceled) # nothing will happen, because there are no observers attached.
|
117
141
|
```
|
118
142
|
|
119
143
|
**Highlights of the previous example:**
|
120
144
|
|
121
|
-
To avoid an undesired behavior,
|
145
|
+
To avoid an undesired behavior, you need to mark the subject as changed before notifying your observers about some event.
|
122
146
|
|
123
147
|
You can do this when using the `#subject_changed!` method. It will automatically mark the subject as changed.
|
124
148
|
|
@@ -131,11 +155,13 @@ order.observers.notify
|
|
131
155
|
# ArgumentError (no events (expected at least 1))
|
132
156
|
```
|
133
157
|
|
134
|
-
[⬆️ Back to Top](#table-of-contents-)
|
158
|
+
[⬆️ Back to Top](#table-of-contents-)
|
135
159
|
|
136
|
-
###
|
160
|
+
### Sharing a context with your observers
|
137
161
|
|
138
|
-
To
|
162
|
+
To share a context value (any kind of Ruby object) with one or more observers, you will need to use the `:context` keyword as the last argument of the `#attach` method. This feature gives you a unique opportunity to share a value in the attaching moment.
|
163
|
+
|
164
|
+
When the observer method receives two arguments, the first one will be the subject, and the second one an instance of `Micro::Observers::Event` that will have the given context value.
|
139
165
|
|
140
166
|
```ruby
|
141
167
|
class Order
|
@@ -149,24 +175,113 @@ class Order
|
|
149
175
|
end
|
150
176
|
|
151
177
|
module OrderEvents
|
152
|
-
def self.canceled(order,
|
153
|
-
puts "The order #(#{order.
|
178
|
+
def self.canceled(order, event)
|
179
|
+
puts "The order #(#{order.object_id}) has been canceled. (from: #{event.context[:from]})" # event.ctx is an alias for event.context
|
154
180
|
end
|
155
181
|
end
|
156
182
|
|
157
183
|
order = Order.new
|
158
|
-
order.observers.attach(OrderEvents, context: { from: 'example #2' ) # attaching multiple observers. e.g. observers.attach(A, B, context: {hello: :world})
|
184
|
+
order.observers.attach(OrderEvents, context: { from: 'example #2' }) # attaching multiple observers. e.g. observers.attach(A, B, context: {hello: :world})
|
159
185
|
order.cancel!
|
160
186
|
# The message below will be printed by the observer (OrderEvents):
|
161
187
|
# The order #(70196221441820) has been canceled. (from: example #2)
|
162
188
|
```
|
163
189
|
|
164
|
-
[⬆️ Back to Top](#table-of-contents-)
|
190
|
+
[⬆️ Back to Top](#table-of-contents-)
|
191
|
+
|
192
|
+
### Sharing data when notifying the observers
|
193
|
+
|
194
|
+
As previously mentioned, the [`event context`](#sharing-a-context-with-your-observers) is a value that is stored when you attach your observer. But sometimes, it will be useful to send some additional data when broadcasting an event to the observers. The `event data` gives you this unique opportunity to share some value at the the notification moment.
|
195
|
+
|
196
|
+
```ruby
|
197
|
+
class Order
|
198
|
+
include Micro::Observers
|
199
|
+
end
|
200
|
+
|
201
|
+
module OrderHandler
|
202
|
+
def self.changed(order, event)
|
203
|
+
puts "The order #(#{order.object_id}) received the number #{event.data} from #{event.ctx[:from]}."
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
order = Order.new
|
208
|
+
order.observers.attach(OrderHandler, context: { from: 'example #3' })
|
209
|
+
order.observers.subject_changed!
|
210
|
+
order.observers.notify(:changed, data: 1)
|
211
|
+
# The message below will be printed by the observer (OrderHandler):
|
212
|
+
# The order #(70196221441820) received the number 1 from example #3.
|
213
|
+
```
|
214
|
+
|
215
|
+
[⬆️ Back to Top](#table-of-contents-)
|
216
|
+
|
217
|
+
### What is a `Micro::Observers::Event`?
|
218
|
+
|
219
|
+
The `Micro::Observers::Event` is the event payload. Follow below all of its properties:
|
220
|
+
|
221
|
+
- `#name` will be the broadcasted event.
|
222
|
+
- `#subject` will be the observed subject.
|
223
|
+
- `#context` will be [the context data](#sharing-a-context-with-your-observers) that was defined in the moment that you attach the observer.
|
224
|
+
- `#data` will be [the value that was shared in the observers' notification](#sharing-data-when-notifying-the-observers).
|
225
|
+
- `#ctx` is an alias for the `#context` method.
|
226
|
+
- `#subj` is an alias for the `#subject` method.
|
227
|
+
|
228
|
+
[⬆️ Back to Top](#table-of-contents-)
|
229
|
+
|
230
|
+
### Using a callable as an observer
|
231
|
+
|
232
|
+
The `observers.on()` method enables you to attach a callable as an observer.
|
233
|
+
|
234
|
+
Usually, a callable has a well-defined responsibility (do only one thing), because of this, it tends to be more [SRP (Single-responsibility principle)](https://en.wikipedia.org/wiki/Single-responsibility_principle). friendly than a conventional observer (that could have N methods to respond to different kinds of notification).
|
235
|
+
|
236
|
+
This method receives the below options:
|
237
|
+
1. `:event` the expected event name.
|
238
|
+
2. `:call` the callable object itself.
|
239
|
+
3. `:with` (optional) it can define the value which will be used as the callable object's argument. So, if it is a `Proc`, a `Micro::Observers::Event` instance will be received as the `Proc` argument, and its output will be the callable argument. But if this option wasn't defined, the `Micro::Observers::Event` instance will be the callable argument.
|
240
|
+
4. `:context` will be the context data that was defined in the moment that you attach the observer.
|
241
|
+
|
242
|
+
```ruby
|
243
|
+
class Person
|
244
|
+
include Micro::Observers
|
245
|
+
|
246
|
+
attr_reader :name
|
247
|
+
|
248
|
+
def initialize(name)
|
249
|
+
@name = name
|
250
|
+
end
|
251
|
+
|
252
|
+
def name=(new_name)
|
253
|
+
return unless observers.subject_changed(new_name != @name)
|
254
|
+
|
255
|
+
@name = new_name
|
256
|
+
|
257
|
+
observers.notify(:name_has_been_changed)
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
PrintPersonName = -> (data) do
|
262
|
+
puts("Person name: #{data.fetch(:person).name}, number: #{data.fetch(:number)}")
|
263
|
+
end
|
264
|
+
|
265
|
+
person = Person.new('Rodrigo')
|
266
|
+
|
267
|
+
person.observers.on(
|
268
|
+
event: :name_has_been_changed,
|
269
|
+
call: PrintPersonName,
|
270
|
+
with: -> event { {person: event.subject, number: event.context} },
|
271
|
+
context: rand
|
272
|
+
)
|
273
|
+
|
274
|
+
person.name = 'Serradura'
|
275
|
+
# The message below will be printed by the observer (PrintPersonName):
|
276
|
+
# Person name: Serradura, number: 0.5018509191706862
|
277
|
+
```
|
278
|
+
|
279
|
+
[⬆️ Back to Top](#table-of-contents-)
|
165
280
|
|
166
281
|
### Calling the observers
|
167
282
|
|
168
283
|
You can use a callable (a class, module, or object that responds to the call method) to be your observers.
|
169
|
-
To do this, you only need make use of the method `#call` instead of `#notify`.
|
284
|
+
To do this, you only need to make use of the method `#call` instead of `#notify`.
|
170
285
|
|
171
286
|
```ruby
|
172
287
|
class Order
|
@@ -179,18 +294,18 @@ class Order
|
|
179
294
|
end
|
180
295
|
end
|
181
296
|
|
182
|
-
|
297
|
+
NotifyAfterCancel = -> (order) { puts "The order #(#{order.object_id}) has been canceled." }
|
183
298
|
|
184
299
|
order = Order.new
|
185
|
-
order.observers.attach(
|
300
|
+
order.observers.attach(NotifyAfterCancel)
|
186
301
|
order.cancel!
|
187
|
-
# The message below will be printed by the observer (
|
302
|
+
# The message below will be printed by the observer (NotifyAfterCancel):
|
188
303
|
# The order #(70196221441820) has been canceled.
|
189
304
|
```
|
190
305
|
|
191
|
-
|
306
|
+
> **Note**: The `observers.call` can receive one or more events, but in this case, the default event (`call`) won't be transmitted.
|
192
307
|
|
193
|
-
[⬆️ Back to Top](#table-of-contents-)
|
308
|
+
[⬆️ Back to Top](#table-of-contents-)
|
194
309
|
|
195
310
|
### Notifying observers without marking them as changed
|
196
311
|
|
@@ -198,11 +313,188 @@ This feature needs to be used with caution!
|
|
198
313
|
|
199
314
|
If you use the methods `#notify!` or `#call!` you won't need to mark observers with `#subject_changed`.
|
200
315
|
|
201
|
-
[⬆️ Back to Top](#table-of-contents-)
|
316
|
+
[⬆️ Back to Top](#table-of-contents-)
|
317
|
+
|
318
|
+
### Defining observers that execute only once
|
319
|
+
|
320
|
+
There are two ways to attach an observer and define it to be performed only once.
|
321
|
+
|
322
|
+
The first way to do this is passing the `perform_once: true` option to the `observers.attach()` method. e.g.
|
323
|
+
|
324
|
+
#### `observers.attach(*args, perform_once: true)`
|
325
|
+
|
326
|
+
```ruby
|
327
|
+
class Order
|
328
|
+
include Micro::Observers
|
329
|
+
|
330
|
+
def cancel!
|
331
|
+
observers.notify!(:canceled)
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
module OrderNotifications
|
336
|
+
def self.canceled(order)
|
337
|
+
puts "The order #(#{order.object_id}) has been canceled."
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
order = Order.new
|
342
|
+
order.observers.attach(OrderNotifications, perform_once: true) # you can also pass an array of observers with this option
|
343
|
+
|
344
|
+
order.observers.some? # true
|
345
|
+
order.cancel! # The order #(70291642071660) has been canceled.
|
346
|
+
|
347
|
+
order.observers.some? # false
|
348
|
+
order.cancel! # Nothing will happen because there aren't observers.
|
349
|
+
```
|
350
|
+
|
351
|
+
#### `observers.once(event:, call:, ...)`
|
352
|
+
|
353
|
+
The second way to achieve this is using `observers.once()` that has the same API of [`observers.on()`](#using-a-callable-as-an-observer). But the difference of the `#once()` method is that it will remove the observer after its execution.
|
354
|
+
|
355
|
+
```ruby
|
356
|
+
class Order
|
357
|
+
include Micro::Observers
|
358
|
+
|
359
|
+
def cancel!
|
360
|
+
observers.notify!(:canceled)
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
module NotifyAfterCancel
|
365
|
+
def self.call(event)
|
366
|
+
puts "The order #(#{event.subject.object_id}) has been canceled."
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
order = Order.new
|
371
|
+
order.observers.once(event: :canceled, call: NotifyAfterCancel)
|
372
|
+
|
373
|
+
order.observers.some? # true
|
374
|
+
order.cancel! # The order #(70301497466060) has been canceled.
|
375
|
+
|
376
|
+
order.observers.some? # false
|
377
|
+
order.cancel! # Nothing will happen because there aren't observers.
|
378
|
+
```
|
379
|
+
|
380
|
+
[⬆️ Back to Top](#table-of-contents-)
|
381
|
+
|
382
|
+
### Defining observers using blocks
|
383
|
+
|
384
|
+
The methods `#on()` and `#once()` can receive the event name (a `symbol`) and a block to define observers.
|
385
|
+
|
386
|
+
#### order.observers.on()
|
387
|
+
|
388
|
+
```ruby
|
389
|
+
class Order
|
390
|
+
include Micro::Observers
|
391
|
+
|
392
|
+
def cancel!
|
393
|
+
observers.notify!(:canceled)
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
order = Order.new
|
398
|
+
order.observers.on(:canceled) do |event|
|
399
|
+
puts "The order #(#{event.subject.object_id}) has been canceled."
|
400
|
+
end
|
401
|
+
|
402
|
+
order.observers.some? # true
|
403
|
+
|
404
|
+
order.cancel! # The order #(70301497466060) has been canceled.
|
405
|
+
|
406
|
+
order.observers.some? # true
|
407
|
+
```
|
408
|
+
|
409
|
+
#### order.observers.on()
|
410
|
+
|
411
|
+
```ruby
|
412
|
+
class Order
|
413
|
+
include Micro::Observers
|
414
|
+
|
415
|
+
def cancel!
|
416
|
+
observers.notify!(:canceled)
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
order = Order.new
|
421
|
+
order.observers.once(:canceled) do |event|
|
422
|
+
puts "The order #(#{event.subject.object_id}) has been canceled."
|
423
|
+
end
|
424
|
+
|
425
|
+
order.observers.some? # true
|
426
|
+
|
427
|
+
order.cancel! # The order #(70301497466060) has been canceled.
|
428
|
+
|
429
|
+
order.observers.some? # false
|
430
|
+
```
|
431
|
+
|
432
|
+
#### Replacing a block by a `lambda`/`proc`
|
433
|
+
|
434
|
+
Ruby allows you to replace any block with a `lambda`/`proc`. e.g.
|
435
|
+
|
436
|
+
```ruby
|
437
|
+
class Order
|
438
|
+
include Micro::Observers
|
439
|
+
|
440
|
+
def cancel!
|
441
|
+
observers.notify!(:canceled)
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
NotifyAfterCancel = -> event { puts "The order #(#{event.subject.object_id}) has been canceled." }
|
446
|
+
|
447
|
+
order = Order.new
|
448
|
+
order.observers.once(:canceled, &NotifyAfterCancel)
|
449
|
+
|
450
|
+
order.observers.some? # true
|
451
|
+
order.cancel! # The order #(70301497466060) has been canceled.
|
452
|
+
|
453
|
+
order.observers.some? # false
|
454
|
+
order.cancel! # Nothing will happen because there aren't observers.
|
455
|
+
```
|
456
|
+
|
457
|
+
[⬆️ Back to Top](#table-of-contents-)
|
458
|
+
|
459
|
+
### Detaching observers
|
460
|
+
|
461
|
+
As shown in the first example, you can use the `observers.detach()` to remove observers.
|
462
|
+
|
463
|
+
But, there is an alternative method to remove observer objects or remove callables by their event names. The method to do this is: `observers.off()`.
|
464
|
+
|
465
|
+
```ruby
|
466
|
+
class Order
|
467
|
+
include Micro::Observers
|
468
|
+
end
|
469
|
+
|
470
|
+
NotifyAfterCancel = -> {}
|
471
|
+
|
472
|
+
module OrderNotifications
|
473
|
+
def self.canceled(_order)
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
order = Order.new
|
478
|
+
order.observers.on(event: :canceled, call: NotifyAfterCancel)
|
479
|
+
order.observers.attach(OrderNotifications)
|
480
|
+
|
481
|
+
order.observers.some? # true
|
482
|
+
order.observers.count # 2
|
483
|
+
|
484
|
+
order.observers.off(:canceled) # removing the callable (NotifyAfterCancel).
|
485
|
+
order.observers.some? # true
|
486
|
+
order.observers.count # 1
|
487
|
+
|
488
|
+
order.observers.off(OrderNotifications)
|
489
|
+
order.observers.some? # false
|
490
|
+
order.observers.count # 0
|
491
|
+
```
|
492
|
+
|
493
|
+
[⬆️ Back to Top](#table-of-contents-)
|
202
494
|
|
203
495
|
### ActiveRecord and ActiveModel integrations
|
204
496
|
|
205
|
-
To make use of this feature you need to require an additional module
|
497
|
+
To make use of this feature you need to require an additional module.
|
206
498
|
|
207
499
|
Gemfile example:
|
208
500
|
```ruby
|
@@ -211,16 +503,22 @@ gem 'u-observers', require: 'u-observers/for/active_record'
|
|
211
503
|
|
212
504
|
This feature will expose modules that could be used to add macros (static methods) that were designed to work with `ActiveModel`/`ActiveRecord` callbacks. e.g:
|
213
505
|
|
214
|
-
|
215
506
|
#### notify_observers_on()
|
216
507
|
|
217
|
-
The `notify_observers_on` allows you to
|
508
|
+
The `notify_observers_on` allows you to define one or more `ActiveModel`/`ActiveRecord` callbacks, that will be used to notify your object observers.
|
218
509
|
|
219
510
|
```ruby
|
220
511
|
class Post < ActiveRecord::Base
|
221
512
|
include ::Micro::Observers::For::ActiveRecord
|
222
513
|
|
223
|
-
notify_observers_on(:after_commit) #
|
514
|
+
notify_observers_on(:after_commit) # using multiple callbacks. e.g. notify_observers_on(:before_save, :after_commit)
|
515
|
+
|
516
|
+
# The method above does the same as the commented example below.
|
517
|
+
#
|
518
|
+
# after_commit do |record|
|
519
|
+
# record.subject_changed!
|
520
|
+
# record.notify(:after_commit)
|
521
|
+
# end
|
224
522
|
end
|
225
523
|
|
226
524
|
module TitlePrinter
|
@@ -230,32 +528,39 @@ module TitlePrinter
|
|
230
528
|
end
|
231
529
|
|
232
530
|
module TitlePrinterWithContext
|
233
|
-
def self.after_commit(post,
|
234
|
-
puts "Title: #{post.title} (from: #{context[:from]})"
|
531
|
+
def self.after_commit(post, event)
|
532
|
+
puts "Title: #{post.title} (from: #{event.context[:from]})"
|
235
533
|
end
|
236
534
|
end
|
237
535
|
|
238
536
|
Post.transaction do
|
239
537
|
post = Post.new(title: 'Hello world')
|
240
|
-
post.observers.attach(TitlePrinter, TitlePrinterWithContext, context: { from: 'example
|
538
|
+
post.observers.attach(TitlePrinter, TitlePrinterWithContext, context: { from: 'example #6' })
|
241
539
|
post.save
|
242
540
|
end
|
243
|
-
# The message below will be printed by the
|
541
|
+
# The message below will be printed by the observers (TitlePrinter, TitlePrinterWithContext):
|
244
542
|
# Title: Hello world
|
245
|
-
# Title: Hello world (from: example
|
543
|
+
# Title: Hello world (from: example #6)
|
246
544
|
```
|
247
545
|
|
248
|
-
[⬆️ Back to Top](#table-of-contents-)
|
546
|
+
[⬆️ Back to Top](#table-of-contents-)
|
249
547
|
|
250
548
|
#### notify_observers()
|
251
549
|
|
252
|
-
The `notify_observers` allows you to
|
550
|
+
The `notify_observers` allows you to define one or more *events*, that will be used to notify after the execution of some `ActiveModel`/`ActiveRecord` callback.
|
253
551
|
|
254
552
|
```ruby
|
255
553
|
class Post < ActiveRecord::Base
|
256
554
|
include ::Micro::Observers::For::ActiveRecord
|
257
555
|
|
258
556
|
after_commit(¬ify_observers(:transaction_completed))
|
557
|
+
|
558
|
+
# The method above does the same as the commented example below.
|
559
|
+
#
|
560
|
+
# after_commit do |record|
|
561
|
+
# record.subject_changed!
|
562
|
+
# record.notify(:transaction_completed)
|
563
|
+
# end
|
259
564
|
end
|
260
565
|
|
261
566
|
module TitlePrinter
|
@@ -265,24 +570,24 @@ module TitlePrinter
|
|
265
570
|
end
|
266
571
|
|
267
572
|
module TitlePrinterWithContext
|
268
|
-
def self.transaction_completed(post,
|
269
|
-
puts("Title: #{post.title} (from: #{
|
573
|
+
def self.transaction_completed(post, event)
|
574
|
+
puts("Title: #{post.title} (from: #{event.ctx[:from]})")
|
270
575
|
end
|
271
576
|
end
|
272
577
|
|
273
578
|
Post.transaction do
|
274
579
|
post = Post.new(title: 'Olá mundo')
|
275
|
-
post.observers.attach(TitlePrinter, TitlePrinterWithContext, context: { from: 'example
|
580
|
+
post.observers.attach(TitlePrinter, TitlePrinterWithContext, context: { from: 'example #7' })
|
276
581
|
post.save
|
277
582
|
end
|
278
|
-
# The message below will be printed by the
|
583
|
+
# The message below will be printed by the observers (TitlePrinter, TitlePrinterWithContext):
|
279
584
|
# Title: Olá mundo
|
280
|
-
# Title: Olá mundo (from: example 5)
|
585
|
+
# Title: Olá mundo (from: example #5)
|
281
586
|
```
|
282
587
|
|
283
|
-
|
588
|
+
> **Note**: You can use `include ::Micro::Observers::For::ActiveModel` if your class only makes use of the `ActiveModel` and all the previous examples will work.
|
284
589
|
|
285
|
-
[⬆️ Back to Top](#table-of-contents-)
|
590
|
+
[⬆️ Back to Top](#table-of-contents-)
|
286
591
|
|
287
592
|
## Development
|
288
593
|
|