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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4c90f3338948cf8db02bdb1a882e3191adfd52f106fc2b4c1acf873447abd82a
4
- data.tar.gz: 2db659fbaee101e1af2838bdb89dc85838f0e9686d14fe14fd9782fc568ee1f6
3
+ metadata.gz: 55ea9f6a206dba9526be1d7777969b26311f725652b3020344db33563a5835c8
4
+ data.tar.gz: d8a6e1bf2e73d15fadbd71e82aa17e0c511fb11d97a7839ba165c50589324b66
5
5
  SHA512:
6
- metadata.gz: 674b8dabdc6cfca0a982c1f72582bf1fcaab34ead0f0de29d4975cc62e164c13bbded5e6118152951584fb5855b6c539510ca393b36f9cf56622bf663d7b22e2
7
- data.tar.gz: ff1e33f5029a40745172c7196d7e21552e8f4d534c71f057bf5643e3262fe8fa243fb55219eed352195a09abc51c337476f9f8bfcd5bce5f61cee416c2ec8de7
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 been compromised.
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
- - [Passing a context for your observers](#passing-a-context-for-your-observers)
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
- | 1.0.0 | main | >= 2.2.0 | >= 3.2, < 6.1 |
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
+ [⬆️ &nbsp; 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) # attaching multiple observers. e.g. observers.attach(A, B, C)
106
- # <#Micro::Observers::Manager @subject=#<Order:0x00007fb5dd8fce70> @subject_changed=false @subscribers=[OrderEvents]
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, do you need to mark the subject as changed before notify your observers about some event.
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
+ [⬆️ &nbsp; Back to Top](#table-of-contents-)
135
159
 
136
- ### Passing a context for your observers
160
+ ### Sharing a context with your observers
137
161
 
138
- To pass a context (any kind of Ruby object) for one or more observers, you will need to use the `context:` keyword as the last argument of the `#attach` method.
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, context)
153
- puts "The order #(#{order.code}) has been canceled. (from: #{context[:from]})"
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
+ [⬆️ &nbsp; 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
+ [⬆️ &nbsp; 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
+ [⬆️ &nbsp; 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
+ [⬆️ &nbsp; 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
- OrderCancellation = -> (order) { puts "The order #(#{order.object_id}) has been canceled." }
297
+ NotifyAfterCancel = -> (order) { puts "The order #(#{order.object_id}) has been canceled." }
183
298
 
184
299
  order = Order.new
185
- order.observers.attach(OrderCancellation)
300
+ order.observers.attach(NotifyAfterCancel)
186
301
  order.cancel!
187
- # The message below will be printed by the observer (OrderEvents):
302
+ # The message below will be printed by the observer (NotifyAfterCancel):
188
303
  # The order #(70196221441820) has been canceled.
189
304
  ```
190
305
 
191
- PS: The `observers.call` can receive one or more events, but in this case, the default event (`call`) won't be transmitted.a
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
+ [⬆️ &nbsp; 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
+ [⬆️ &nbsp; 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
+ [⬆️ &nbsp; 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
+ [⬆️ &nbsp; 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
+ [⬆️ &nbsp; 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 (`require 'u-observers/for/active_record'`).
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 pass one or more `ActiveModel`/`ActiveRecord` callbacks, that will be used to notify your object observers.
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) # passing multiple callbacks. e.g. notify_observers_on(:before_save, :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, context)
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 4' })
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 observer (OrderEvents):
541
+ # The message below will be printed by the observers (TitlePrinter, TitlePrinterWithContext):
244
542
  # Title: Hello world
245
- # Title: Hello world (from: example 4)
543
+ # Title: Hello world (from: example #6)
246
544
  ```
247
545
 
248
- [⬆️ Back to Top](#table-of-contents-)
546
+ [⬆️ &nbsp; Back to Top](#table-of-contents-)
249
547
 
250
548
  #### notify_observers()
251
549
 
252
- The `notify_observers` allows you to pass one or more *events*, that will be used to notify after the execution of some `ActiveModel`/`ActiveRecord` callback.
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(&notify_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, context)
269
- puts("Title: #{post.title} (from: #{context[: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 5' })
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 observer (OrderEvents):
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
- PS: You can use `include ::Micro::Observers::For::ActiveModel` if your class only makes use of the `ActiveModel` and all the previous examples will work.
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
+ [⬆️ &nbsp; Back to Top](#table-of-contents-)
286
591
 
287
592
  ## Development
288
593