u-observers 0.7.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.tool-versions +1 -0
- data/.travis.sh +34 -0
- data/.travis.yml +27 -3
- data/Gemfile +31 -5
- data/README.md +392 -11
- data/README.pt-BR.md +426 -0
- data/lib/micro/observers.rb +3 -23
- data/lib/micro/observers/event.rb +21 -0
- data/lib/micro/observers/event/names.rb +29 -0
- data/lib/micro/observers/for/active_model.rb +36 -0
- data/lib/micro/observers/for/active_record.rb +16 -0
- data/lib/micro/observers/set.rb +178 -0
- data/lib/micro/observers/utils.rb +4 -4
- data/lib/micro/observers/version.rb +1 -1
- data/lib/u-observers/for/active_model.rb +2 -0
- data/lib/u-observers/for/active_record.rb +2 -0
- data/test.sh +11 -0
- data/u-observers.gemspec +5 -1
- metadata +42 -5
- data/lib/micro/observers/events_or_actions.rb +0 -25
- data/lib/micro/observers/manager.rb +0 -93
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 52f8cf4c9f76af4b9438412dc60fa7b4156fa84afec92f89a12bb40b90d1ed32
|
4
|
+
data.tar.gz: 1c1ad202a47f467e468186b58671bed796656180660302f057005a7387bdcc7f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c2f779070c6e11ef08c71b85f9d90342907cef3e910e7f6a7b61bbebeeec283baf56d197df1edf3bb4bb7437424e43d74208d97fed1e745b76367b2c14fb2206
|
7
|
+
data.tar.gz: 7995b96fe8868e126fd053e05e831b92adc421325b133324222591c74a288ba4de9677dc59b2b5f57a8d8a437c04a342f04a9548ed460546e9f56b571e4ac3c5
|
data/.tool-versions
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby 2.6.5
|
data/.travis.sh
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
ruby_v=$(ruby -v)
|
4
|
+
|
5
|
+
bundle update
|
6
|
+
bundle exec rake test
|
7
|
+
|
8
|
+
ACTIVERECORD_VERSION='3.2' bundle update
|
9
|
+
ACTIVERECORD_VERSION='3.2' bundle exec rake test
|
10
|
+
|
11
|
+
ACTIVERECORD_VERSION='4.0' bundle update
|
12
|
+
ACTIVERECORD_VERSION='4.0' bundle exec rake test
|
13
|
+
|
14
|
+
ACTIVERECORD_VERSION='4.1' bundle update
|
15
|
+
ACTIVERECORD_VERSION='4.1' bundle exec rake test
|
16
|
+
|
17
|
+
ACTIVERECORD_VERSION='4.2' bundle update
|
18
|
+
ACTIVERECORD_VERSION='4.2' bundle exec rake test
|
19
|
+
|
20
|
+
ACTIVERECORD_VERSION='5.0' bundle update
|
21
|
+
ACTIVERECORD_VERSION='5.0' bundle exec rake test
|
22
|
+
|
23
|
+
ACTIVERECORD_VERSION='5.1' bundle update
|
24
|
+
ACTIVERECORD_VERSION='5.1' bundle exec rake test
|
25
|
+
|
26
|
+
if [[ ! $ruby_v =~ '2.2.0' ]]; then
|
27
|
+
ACTIVERECORD_VERSION='5.2' bundle update
|
28
|
+
ACTIVERECORD_VERSION='5.2' bundle exec rake test
|
29
|
+
fi
|
30
|
+
|
31
|
+
if [[ $ruby_v =~ '2.5.' ]] || [[ $ruby_v =~ '2.6.' ]] || [[ $ruby_v =~ '2.7.' ]]; then
|
32
|
+
ACTIVERECORD_VERSION='6.0' bundle update
|
33
|
+
ACTIVERECORD_VERSION='6.0' bundle exec rake test
|
34
|
+
fi
|
data/.travis.yml
CHANGED
@@ -1,6 +1,30 @@
|
|
1
1
|
---
|
2
2
|
language: ruby
|
3
|
-
|
3
|
+
|
4
|
+
sudo: false
|
5
|
+
|
4
6
|
rvm:
|
5
|
-
|
6
|
-
|
7
|
+
- 2.2.0
|
8
|
+
- 2.3.0
|
9
|
+
- 2.4.0
|
10
|
+
- 2.5.0
|
11
|
+
- 2.6.0
|
12
|
+
- 2.7.0
|
13
|
+
|
14
|
+
cache: bundler
|
15
|
+
|
16
|
+
before_install:
|
17
|
+
- gem uninstall -v '>= 2' -i $(rvm gemdir)@global -ax bundler || true
|
18
|
+
- gem install bundler -v '< 2'
|
19
|
+
|
20
|
+
install: bundle install --jobs=3 --retry=3
|
21
|
+
|
22
|
+
before_script:
|
23
|
+
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
24
|
+
- chmod +x ./cc-test-reporter
|
25
|
+
- "./cc-test-reporter before-build"
|
26
|
+
|
27
|
+
script: "./.travis.sh"
|
28
|
+
|
29
|
+
after_success:
|
30
|
+
- "./cc-test-reporter after-build -t simplecov"
|
data/Gemfile
CHANGED
@@ -3,12 +3,38 @@ source 'https://rubygems.org'
|
|
3
3
|
# Specify your gem's dependencies in u-observers.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
activerecord_version = ENV.fetch('ACTIVERECORD_VERSION', '6.1')
|
7
|
+
|
8
|
+
activerecord = case activerecord_version
|
9
|
+
when '3.2' then '3.2.22'
|
10
|
+
when '4.0' then '4.0.13'
|
11
|
+
when '4.1' then '4.1.16'
|
12
|
+
when '4.2' then '4.2.11'
|
13
|
+
when '5.0' then '5.0.7'
|
14
|
+
when '5.1' then '5.1.7'
|
15
|
+
when '5.2' then '5.2.3'
|
16
|
+
when '6.0' then '6.0.3'
|
17
|
+
end
|
18
|
+
|
19
|
+
simplecov_version =
|
20
|
+
case RUBY_VERSION
|
21
|
+
when /\A2.[23]/ then '~> 0.17.1'
|
22
|
+
when /\A2.4/ then '~> 0.18.5'
|
23
|
+
else '~> 0.19'
|
24
|
+
end
|
8
25
|
|
9
26
|
group :test do
|
10
|
-
gem '
|
11
|
-
gem '
|
27
|
+
gem 'minitest', activerecord_version < '4.1' ? '~> 4.2' : '~> 5.0'
|
28
|
+
gem 'simplecov', simplecov_version, require: false
|
29
|
+
|
30
|
+
if activerecord
|
31
|
+
sqlite3 =
|
32
|
+
case activerecord
|
33
|
+
when /\A6\.0/, nil then '~> 1.4.0'
|
34
|
+
else '~> 1.3.0'
|
35
|
+
end
|
12
36
|
|
13
|
-
|
37
|
+
gem 'sqlite3', sqlite3
|
38
|
+
gem 'activerecord', activerecord, require: 'active_record'
|
39
|
+
end
|
14
40
|
end
|
data/README.md
CHANGED
@@ -1,28 +1,409 @@
|
|
1
|
-
|
1
|
+
<p align="center">
|
2
|
+
<h1 align="center">👀 μ-observers</h1>
|
3
|
+
<p align="center"><i>Simple and powerful implementation of the observer pattern.</i></p>
|
4
|
+
<br>
|
5
|
+
</p>
|
2
6
|
|
3
|
-
|
7
|
+
<p align="center">
|
8
|
+
<img src="https://img.shields.io/badge/ruby->%3D%202.2.0-ruby.svg?colorA=99004d&colorB=cc0066" alt="Ruby">
|
4
9
|
|
5
|
-
|
10
|
+
<a href="https://rubygems.org/gems/u-observers">
|
11
|
+
<img alt="Gem" src="https://img.shields.io/gem/v/u-observers.svg?style=flat-square">
|
12
|
+
</a>
|
6
13
|
|
7
|
-
|
14
|
+
<a href="https://travis-ci.com/serradura/u-observers">
|
15
|
+
<img alt="Build Status" src="https://travis-ci.com/serradura/u-observers.svg?branch=main">
|
16
|
+
</a>
|
8
17
|
|
9
|
-
|
18
|
+
<a href="https://codeclimate.com/github/serradura/u-observers/maintainability">
|
19
|
+
<img alt="Maintainability" src="https://api.codeclimate.com/v1/badges/e72ffa84bc95c59823f2/maintainability">
|
20
|
+
</a>
|
21
|
+
|
22
|
+
<a href="https://codeclimate.com/github/serradura/u-observers/test_coverage">
|
23
|
+
<img alt="Test Coverage" src="https://api.codeclimate.com/v1/badges/e72ffa84bc95c59823f2/test_coverage">
|
24
|
+
</a>
|
25
|
+
</p>
|
26
|
+
|
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
|
+
|
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
|
+
|
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).
|
34
|
+
|
35
|
+
# Table of contents <!-- omit in toc -->
|
36
|
+
- [Installation](#installation)
|
37
|
+
- [Compatibility](#compatibility)
|
38
|
+
- [Usage](#usage)
|
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)
|
43
|
+
- [Calling the observers](#calling-the-observers)
|
44
|
+
- [Notifying observers without marking them as changed](#notifying-observers-without-marking-them-as-changed)
|
45
|
+
- [ActiveRecord and ActiveModel integrations](#activerecord-and-activemodel-integrations)
|
46
|
+
- [notify_observers_on()](#notify_observers_on)
|
47
|
+
- [notify_observers()](#notify_observers)
|
48
|
+
- [Development](#development)
|
49
|
+
- [Contributing](#contributing)
|
50
|
+
- [License](#license)
|
51
|
+
- [Code of Conduct](#code-of-conduct)
|
52
|
+
|
53
|
+
# Installation
|
54
|
+
|
55
|
+
Add this line to your application's Gemfile and `bundle install`:
|
10
56
|
|
11
57
|
```ruby
|
12
|
-
gem '
|
58
|
+
gem 'u-observers'
|
13
59
|
```
|
14
60
|
|
15
|
-
|
61
|
+
# Compatibility
|
16
62
|
|
17
|
-
|
63
|
+
| u-observers | branch | ruby | activerecord |
|
64
|
+
| ----------- | ------- | -------- | ------------- |
|
65
|
+
| unreleased | main | >= 2.2.0 | >= 3.2, < 6.1 |
|
66
|
+
| 2.1.0 | v2.x | >= 2.2.0 | >= 3.2, < 6.1 |
|
67
|
+
| 1.0.0 | v1.x | >= 2.2.0 | >= 3.2, < 6.1 |
|
18
68
|
|
19
|
-
|
69
|
+
> **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).
|
20
70
|
|
21
|
-
|
71
|
+
[⬆️ Back to Top](#table-of-contents-)
|
22
72
|
|
23
73
|
## Usage
|
24
74
|
|
25
|
-
|
75
|
+
Any class with `Micro::Observers` module included can notify events to attached observers.
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
require 'securerandom'
|
79
|
+
|
80
|
+
class Order
|
81
|
+
include Micro::Observers
|
82
|
+
|
83
|
+
attr_reader :code
|
84
|
+
|
85
|
+
def initialize
|
86
|
+
@code, @status = SecureRandom.alphanumeric, :draft
|
87
|
+
end
|
88
|
+
|
89
|
+
def canceled?
|
90
|
+
@status == :canceled
|
91
|
+
end
|
92
|
+
|
93
|
+
def cancel!
|
94
|
+
return self if canceled?
|
95
|
+
|
96
|
+
@status = :canceled
|
97
|
+
|
98
|
+
observers.subject_changed!
|
99
|
+
observers.notify(:canceled) and return self
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
module OrderEvents
|
104
|
+
def self.canceled(order)
|
105
|
+
puts "The order #(#{order.code}) has been canceled."
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
order = Order.new
|
110
|
+
#<Order:0x00007fb5dd8fce70 @code="X0o9yf1GsdQFvLR4", @status=:draft>
|
111
|
+
|
112
|
+
order.observers.attach(OrderEvents) # attaching multiple observers. e.g. observers.attach(A, B, C)
|
113
|
+
# <#Micro::Observers::Set @subject=#<Order:0x00007fb5dd8fce70> @subject_changed=false @subscribers=[OrderEvents]>
|
114
|
+
|
115
|
+
order.canceled?
|
116
|
+
# false
|
117
|
+
|
118
|
+
order.cancel!
|
119
|
+
# The message below will be printed by the observer (OrderEvents):
|
120
|
+
# The order #(X0o9yf1GsdQFvLR4) has been canceled
|
121
|
+
|
122
|
+
order.canceled?
|
123
|
+
# true
|
124
|
+
|
125
|
+
order.observers.detach(OrderEvents) # detaching multiple observers. e.g. observers.detach(A, B, C)
|
126
|
+
# <#Micro::Observers::Set @subject=#<Order:0x00007fb5dd8fce70> @subject_changed=false @subscribers=[]>
|
127
|
+
|
128
|
+
order.canceled?
|
129
|
+
# true
|
130
|
+
|
131
|
+
order.observers.subject_changed!
|
132
|
+
order.observers.notify(:canceled) # nothing will happen, because there are no observers attached.
|
133
|
+
```
|
134
|
+
|
135
|
+
**Highlights of the previous example:**
|
136
|
+
|
137
|
+
To avoid an undesired behavior, you need to mark the subject as changed before notifying your observers about some event.
|
138
|
+
|
139
|
+
You can do this when using the `#subject_changed!` method. It will automatically mark the subject as changed.
|
140
|
+
|
141
|
+
But if you need to apply some conditional to mark a change, you can use the `#subject_changed` method. e.g. `observers.subject_changed(name != new_name)`
|
142
|
+
|
143
|
+
The `#notify` method always requires an event to make a broadcast. So, if you try to use it without one or more events (symbol values) you will get an exception.
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
order.observers.notify
|
147
|
+
# ArgumentError (no events (expected at least 1))
|
148
|
+
```
|
149
|
+
|
150
|
+
[⬆️ Back to Top](#table-of-contents-)
|
151
|
+
|
152
|
+
### Sharing a context with your observers
|
153
|
+
|
154
|
+
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.
|
155
|
+
|
156
|
+
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.
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
class Order
|
160
|
+
include Micro::Observers
|
161
|
+
|
162
|
+
def cancel!
|
163
|
+
observers.subject_changed!
|
164
|
+
observers.notify(:canceled)
|
165
|
+
self
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
module OrderEvents
|
170
|
+
def self.canceled(order, event)
|
171
|
+
puts "The order #(#{order.object_id}) has been canceled. (from: #{event.context[:from]})" # event.ctx is an alias for event.context
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
order = Order.new
|
176
|
+
order.observers.attach(OrderEvents, context: { from: 'example #2' }) # attaching multiple observers. e.g. observers.attach(A, B, context: {hello: :world})
|
177
|
+
order.cancel!
|
178
|
+
# The message below will be printed by the observer (OrderEvents):
|
179
|
+
# The order #(70196221441820) has been canceled. (from: example #2)
|
180
|
+
```
|
181
|
+
|
182
|
+
[⬆️ Back to Top](#table-of-contents-)
|
183
|
+
|
184
|
+
### Sharing data when notifying the observers
|
185
|
+
|
186
|
+
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.
|
187
|
+
|
188
|
+
```ruby
|
189
|
+
class Order
|
190
|
+
include Micro::Observers
|
191
|
+
end
|
192
|
+
|
193
|
+
module OrderHandler
|
194
|
+
def self.changed(order, event)
|
195
|
+
puts "The order #(#{order.object_id}) received the number #{event.data} from #{event.ctx[:from]}."
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
order = Order.new
|
200
|
+
order.observers.attach(OrderHandler, context: { from: 'example #3' })
|
201
|
+
order.observers.subject_changed!
|
202
|
+
order.observers.notify(:changed, data: 1)
|
203
|
+
# The message below will be printed by the observer (OrderHandler):
|
204
|
+
# The order #(70196221441820) received the number 1 from example #3.
|
205
|
+
```
|
206
|
+
|
207
|
+
[⬆️ Back to Top](#table-of-contents-)
|
208
|
+
|
209
|
+
### What is a `Micro::Observers::Event`?
|
210
|
+
|
211
|
+
The `Micro::Observers::Event` is the event payload. Follow below all of its properties:
|
212
|
+
|
213
|
+
- `#name` will be the broadcasted event.
|
214
|
+
- `#subject` will be the observed subject.
|
215
|
+
- `#context` will be [the context data](#sharing-a-context-with-your-observers) that was defined in the moment that you attach the observer.
|
216
|
+
- `#data` will be [the value that was shared in the observers' notification](#sharing-data-when-notifying-the-observers).
|
217
|
+
- `#ctx` is an alias for the `#context` method.
|
218
|
+
- `#subj` is an alias for the `#subject` method.
|
219
|
+
|
220
|
+
[⬆️ Back to Top](#table-of-contents-)
|
221
|
+
|
222
|
+
### Using a callable as an observer
|
223
|
+
|
224
|
+
The `observers.on()` method enables you to attach a callable as an observer.
|
225
|
+
|
226
|
+
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).
|
227
|
+
|
228
|
+
This method receives the below options:
|
229
|
+
1. `:event` the expected event name.
|
230
|
+
2. `:call` the callable object itself.
|
231
|
+
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.
|
232
|
+
4. `:context` will be the context data that was defined in the moment that you attach the observer.
|
233
|
+
|
234
|
+
```ruby
|
235
|
+
class Person
|
236
|
+
include Micro::Observers
|
237
|
+
|
238
|
+
attr_reader :name
|
239
|
+
|
240
|
+
def initialize(name)
|
241
|
+
@name = name
|
242
|
+
end
|
243
|
+
|
244
|
+
def name=(new_name)
|
245
|
+
return unless observers.subject_changed(new_name != @name)
|
246
|
+
|
247
|
+
@name = new_name
|
248
|
+
|
249
|
+
observers.notify(:name_has_been_changed)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
PrintPersonName = -> (data) do
|
254
|
+
puts("Person name: #{data.fetch(:person).name}, number: #{data.fetch(:number)}")
|
255
|
+
end
|
256
|
+
|
257
|
+
person = Person.new('Rodrigo')
|
258
|
+
|
259
|
+
person.observers.on(
|
260
|
+
event: :name_has_been_changed,
|
261
|
+
call: PrintPersonName,
|
262
|
+
with: -> event { {person: event.subject, number: event.context} },
|
263
|
+
context: rand
|
264
|
+
)
|
265
|
+
|
266
|
+
person.name = 'Serradura'
|
267
|
+
# The message below will be printed by the observer (PrintPersonName):
|
268
|
+
# Person name: Serradura, number: 0.5018509191706862
|
269
|
+
```
|
270
|
+
|
271
|
+
[⬆️ Back to Top](#table-of-contents-)
|
272
|
+
|
273
|
+
### Calling the observers
|
274
|
+
|
275
|
+
You can use a callable (a class, module, or object that responds to the call method) to be your observers.
|
276
|
+
To do this, you only need to make use of the method `#call` instead of `#notify`.
|
277
|
+
|
278
|
+
```ruby
|
279
|
+
class Order
|
280
|
+
include Micro::Observers
|
281
|
+
|
282
|
+
def cancel!
|
283
|
+
observers.subject_changed!
|
284
|
+
observers.call # in practice, this is a shortcut to observers.notify(:call)
|
285
|
+
self
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
OrderCancellation = -> (order) { puts "The order #(#{order.object_id}) has been canceled." }
|
290
|
+
|
291
|
+
order = Order.new
|
292
|
+
order.observers.attach(OrderCancellation)
|
293
|
+
order.cancel!
|
294
|
+
# The message below will be printed by the observer (OrderCancellation):
|
295
|
+
# The order #(70196221441820) has been canceled.
|
296
|
+
```
|
297
|
+
|
298
|
+
> **Note**: The `observers.call` can receive one or more events, but in this case, the default event (`call`) won't be transmitted.
|
299
|
+
|
300
|
+
[⬆️ Back to Top](#table-of-contents-)
|
301
|
+
|
302
|
+
### Notifying observers without marking them as changed
|
303
|
+
|
304
|
+
This feature needs to be used with caution!
|
305
|
+
|
306
|
+
If you use the methods `#notify!` or `#call!` you won't need to mark observers with `#subject_changed`.
|
307
|
+
|
308
|
+
[⬆️ Back to Top](#table-of-contents-)
|
309
|
+
|
310
|
+
### ActiveRecord and ActiveModel integrations
|
311
|
+
|
312
|
+
To make use of this feature you need to require an additional module.
|
313
|
+
|
314
|
+
Gemfile example:
|
315
|
+
```ruby
|
316
|
+
gem 'u-observers', require: 'u-observers/for/active_record'
|
317
|
+
```
|
318
|
+
|
319
|
+
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:
|
320
|
+
|
321
|
+
|
322
|
+
#### notify_observers_on()
|
323
|
+
|
324
|
+
The `notify_observers_on` allows you to define one or more `ActiveModel`/`ActiveRecord` callbacks, that will be used to notify your object observers.
|
325
|
+
|
326
|
+
```ruby
|
327
|
+
class Post < ActiveRecord::Base
|
328
|
+
include ::Micro::Observers::For::ActiveRecord
|
329
|
+
|
330
|
+
notify_observers_on(:after_commit) # using multiple callbacks. e.g. notify_observers_on(:before_save, :after_commit)
|
331
|
+
|
332
|
+
# The method above does the same as the commented example below.
|
333
|
+
#
|
334
|
+
# after_commit do |record|
|
335
|
+
# record.subject_changed!
|
336
|
+
# record.notify(:after_commit)
|
337
|
+
# end
|
338
|
+
end
|
339
|
+
|
340
|
+
module TitlePrinter
|
341
|
+
def self.after_commit(post)
|
342
|
+
puts "Title: #{post.title}"
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
module TitlePrinterWithContext
|
347
|
+
def self.after_commit(post, event)
|
348
|
+
puts "Title: #{post.title} (from: #{event.context[:from]})"
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
Post.transaction do
|
353
|
+
post = Post.new(title: 'Hello world')
|
354
|
+
post.observers.attach(TitlePrinter, TitlePrinterWithContext, context: { from: 'example #6' })
|
355
|
+
post.save
|
356
|
+
end
|
357
|
+
# The message below will be printed by the observers (TitlePrinter, TitlePrinterWithContext):
|
358
|
+
# Title: Hello world
|
359
|
+
# Title: Hello world (from: example #6)
|
360
|
+
```
|
361
|
+
|
362
|
+
[⬆️ Back to Top](#table-of-contents-)
|
363
|
+
|
364
|
+
#### notify_observers()
|
365
|
+
|
366
|
+
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.
|
367
|
+
|
368
|
+
```ruby
|
369
|
+
class Post < ActiveRecord::Base
|
370
|
+
include ::Micro::Observers::For::ActiveRecord
|
371
|
+
|
372
|
+
after_commit(¬ify_observers(:transaction_completed))
|
373
|
+
|
374
|
+
# The method above does the same as the commented example below.
|
375
|
+
#
|
376
|
+
# after_commit do |record|
|
377
|
+
# record.subject_changed!
|
378
|
+
# record.notify(:transaction_completed)
|
379
|
+
# end
|
380
|
+
end
|
381
|
+
|
382
|
+
module TitlePrinter
|
383
|
+
def self.transaction_completed(post)
|
384
|
+
puts("Title: #{post.title}")
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
module TitlePrinterWithContext
|
389
|
+
def self.transaction_completed(post, event)
|
390
|
+
puts("Title: #{post.title} (from: #{event.ctx[:from]})")
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
Post.transaction do
|
395
|
+
post = Post.new(title: 'Olá mundo')
|
396
|
+
post.observers.attach(TitlePrinter, TitlePrinterWithContext, context: { from: 'example #7' })
|
397
|
+
post.save
|
398
|
+
end
|
399
|
+
# The message below will be printed by the observers (TitlePrinter, TitlePrinterWithContext):
|
400
|
+
# Title: Olá mundo
|
401
|
+
# Title: Olá mundo (from: example #5)
|
402
|
+
```
|
403
|
+
|
404
|
+
> **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.
|
405
|
+
|
406
|
+
[⬆️ Back to Top](#table-of-contents-)
|
26
407
|
|
27
408
|
## Development
|
28
409
|
|