u-observers 0.9.0 → 2.2.1

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: bfa6d5600e86dd6086b2d6ebd4cd1b015ebe3331bd4cd61be90f2d96a1abf601
4
- data.tar.gz: b483b0721def3d41085260343edf1041905b376264354b6ffbd07cbb5386725f
3
+ metadata.gz: d7ebc064f3e8384d9322c640d3d52b1bf70bf6d5159ae67bf3cd34bdf67482eb
4
+ data.tar.gz: 398d1ab0fc5852a42416c5bc16c377c4a55d760e1e327e2149b58b7db23cae73
5
5
  SHA512:
6
- metadata.gz: '06318ee21d6b9e842fa7ad752f9ccb137286667211fc43bed267d5593506d239fe946f03159236e00e0549c45e71d5de1f36cb1213ce698c3ad3b8edaf4c5abf'
7
- data.tar.gz: 91aac7ae90a990f5575838bf13ddfd174066257a2b82620e82fc8af963519d9c85526aa742005b3d7c1cc78c1dba67d557f62ab233d34b30b70b8c69a945a929
6
+ metadata.gz: 0d805d69fb5cb7d08d1ef5aec34742d08845d2d544cec1262ec63d99788adb5053ed87558957849f1b9843b772929e9490f1ae243ee3c568d87b94e1b432a8c5
7
+ data.tar.gz: 932bfa8189f162fea8160779d521168fdebe253d36414c0b05fbccf2a8c661dc94e127fb5a942523e0ae415142d6090cd8a361124f60f550b7d2166c87106c0e
data/.travis.sh CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  ruby_v=$(ruby -v)
4
4
 
5
+ bundle update
6
+ bundle exec rake test
7
+
5
8
  ACTIVERECORD_VERSION='3.2' bundle update
6
9
  ACTIVERECORD_VERSION='3.2' bundle exec rake test
7
10
 
data/Gemfile CHANGED
@@ -23,16 +23,18 @@ simplecov_version =
23
23
  else '~> 0.19'
24
24
  end
25
25
 
26
- sqlite3 =
27
- case activerecord
28
- when /\A6\.0/, nil then '~> 1.4.0'
29
- else '~> 1.3.0'
30
- end
31
-
32
26
  group :test do
33
27
  gem 'minitest', activerecord_version < '4.1' ? '~> 4.2' : '~> 5.0'
34
28
  gem 'simplecov', simplecov_version, require: false
35
29
 
36
- gem 'sqlite3', sqlite3
37
- gem 'activerecord', activerecord, require: 'active_record'
30
+ if activerecord
31
+ sqlite3 =
32
+ case activerecord
33
+ when /\A6\.0/, nil then '~> 1.4.0'
34
+ else '~> 1.3.0'
35
+ end
36
+
37
+ gem 'sqlite3', sqlite3
38
+ gem 'activerecord', activerecord, require: 'active_record'
39
+ end
38
40
  end
data/README.md CHANGED
@@ -1,28 +1,512 @@
1
- # Micro::Observers
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
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/micro/observers`. To experiment with that code, run `bin/console` for an interactive prompt.
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
- TODO: Delete this and the text above, and describe your gem
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
- ## Installation
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
- Add this line to your application's Gemfile:
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? 🇧🇷&nbsp;🇵🇹 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
+ - [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
+ - [Detaching observers](#detaching-observers)
49
+ - [ActiveRecord and ActiveModel integrations](#activerecord-and-activemodel-integrations)
50
+ - [notify_observers_on()](#notify_observers_on)
51
+ - [notify_observers()](#notify_observers)
52
+ - [Development](#development)
53
+ - [Contributing](#contributing)
54
+ - [License](#license)
55
+ - [Code of Conduct](#code-of-conduct)
56
+
57
+ # Installation
58
+
59
+ Add this line to your application's Gemfile and `bundle install`:
10
60
 
11
61
  ```ruby
12
- gem 'micro-observers'
62
+ gem 'u-observers'
13
63
  ```
14
64
 
15
- And then execute:
65
+ # Compatibility
16
66
 
17
- $ bundle install
67
+ | u-observers | branch | ruby | activerecord |
68
+ | ----------- | ------- | -------- | ------------- |
69
+ | unreleased | main | >= 2.2.0 | >= 3.2, < 6.1 |
70
+ | 2.2.0 | v2.x | >= 2.2.0 | >= 3.2, < 6.1 |
71
+ | 1.0.0 | v1.x | >= 2.2.0 | >= 3.2, < 6.1 |
18
72
 
19
- Or install it yourself as:
73
+ > **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
74
 
21
- $ gem install u-observers
75
+ [⬆️ &nbsp; Back to Top](#table-of-contents-)
22
76
 
23
77
  ## Usage
24
78
 
25
- TODO: Write usage instructions here
79
+ Any class with `Micro::Observers` module included can notify events to attached observers.
80
+
81
+ ```ruby
82
+ require 'securerandom'
83
+
84
+ class Order
85
+ include Micro::Observers
86
+
87
+ attr_reader :code
88
+
89
+ def initialize
90
+ @code, @status = SecureRandom.alphanumeric, :draft
91
+ end
92
+
93
+ def canceled?
94
+ @status == :canceled
95
+ end
96
+
97
+ def cancel!
98
+ return self if canceled?
99
+
100
+ @status = :canceled
101
+
102
+ observers.subject_changed!
103
+ observers.notify(:canceled) and return self
104
+ end
105
+ end
106
+
107
+ module OrderEvents
108
+ def self.canceled(order)
109
+ puts "The order #(#{order.code}) has been canceled."
110
+ end
111
+ end
112
+
113
+ order = Order.new
114
+ #<Order:0x00007fb5dd8fce70 @code="X0o9yf1GsdQFvLR4", @status=:draft>
115
+
116
+ order.observers.attach(OrderEvents) # attaching multiple observers. e.g. observers.attach(A, B, C)
117
+ # <#Micro::Observers::Set @subject=#<Order:0x00007fb5dd8fce70> @subject_changed=false @subscribers=[OrderEvents]>
118
+
119
+ order.canceled?
120
+ # false
121
+
122
+ order.cancel!
123
+ # The message below will be printed by the observer (OrderEvents):
124
+ # The order #(X0o9yf1GsdQFvLR4) has been canceled
125
+
126
+ order.canceled?
127
+ # true
128
+
129
+ order.observers.detach(OrderEvents) # detaching multiple observers. e.g. observers.detach(A, B, C)
130
+ # <#Micro::Observers::Set @subject=#<Order:0x00007fb5dd8fce70> @subject_changed=false @subscribers=[]>
131
+
132
+ order.canceled?
133
+ # true
134
+
135
+ order.observers.subject_changed!
136
+ order.observers.notify(:canceled) # nothing will happen, because there are no observers attached.
137
+ ```
138
+
139
+ **Highlights of the previous example:**
140
+
141
+ To avoid an undesired behavior, you need to mark the subject as changed before notifying your observers about some event.
142
+
143
+ You can do this when using the `#subject_changed!` method. It will automatically mark the subject as changed.
144
+
145
+ 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)`
146
+
147
+ 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.
148
+
149
+ ```ruby
150
+ order.observers.notify
151
+ # ArgumentError (no events (expected at least 1))
152
+ ```
153
+
154
+ [⬆️ &nbsp; Back to Top](#table-of-contents-)
155
+
156
+ ### Sharing a context with your observers
157
+
158
+ 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.
159
+
160
+ 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.
161
+
162
+ ```ruby
163
+ class Order
164
+ include Micro::Observers
165
+
166
+ def cancel!
167
+ observers.subject_changed!
168
+ observers.notify(:canceled)
169
+ self
170
+ end
171
+ end
172
+
173
+ module OrderEvents
174
+ def self.canceled(order, event)
175
+ puts "The order #(#{order.object_id}) has been canceled. (from: #{event.context[:from]})" # event.ctx is an alias for event.context
176
+ end
177
+ end
178
+
179
+ order = Order.new
180
+ order.observers.attach(OrderEvents, context: { from: 'example #2' }) # attaching multiple observers. e.g. observers.attach(A, B, context: {hello: :world})
181
+ order.cancel!
182
+ # The message below will be printed by the observer (OrderEvents):
183
+ # The order #(70196221441820) has been canceled. (from: example #2)
184
+ ```
185
+
186
+ [⬆️ &nbsp; Back to Top](#table-of-contents-)
187
+
188
+ ### Sharing data when notifying the observers
189
+
190
+ 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.
191
+
192
+ ```ruby
193
+ class Order
194
+ include Micro::Observers
195
+ end
196
+
197
+ module OrderHandler
198
+ def self.changed(order, event)
199
+ puts "The order #(#{order.object_id}) received the number #{event.data} from #{event.ctx[:from]}."
200
+ end
201
+ end
202
+
203
+ order = Order.new
204
+ order.observers.attach(OrderHandler, context: { from: 'example #3' })
205
+ order.observers.subject_changed!
206
+ order.observers.notify(:changed, data: 1)
207
+ # The message below will be printed by the observer (OrderHandler):
208
+ # The order #(70196221441820) received the number 1 from example #3.
209
+ ```
210
+
211
+ [⬆️ &nbsp; Back to Top](#table-of-contents-)
212
+
213
+ ### What is a `Micro::Observers::Event`?
214
+
215
+ The `Micro::Observers::Event` is the event payload. Follow below all of its properties:
216
+
217
+ - `#name` will be the broadcasted event.
218
+ - `#subject` will be the observed subject.
219
+ - `#context` will be [the context data](#sharing-a-context-with-your-observers) that was defined in the moment that you attach the observer.
220
+ - `#data` will be [the value that was shared in the observers' notification](#sharing-data-when-notifying-the-observers).
221
+ - `#ctx` is an alias for the `#context` method.
222
+ - `#subj` is an alias for the `#subject` method.
223
+
224
+ [⬆️ &nbsp; Back to Top](#table-of-contents-)
225
+
226
+ ### Using a callable as an observer
227
+
228
+ The `observers.on()` method enables you to attach a callable as an observer.
229
+
230
+ 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).
231
+
232
+ This method receives the below options:
233
+ 1. `:event` the expected event name.
234
+ 2. `:call` the callable object itself.
235
+ 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.
236
+ 4. `:context` will be the context data that was defined in the moment that you attach the observer.
237
+
238
+ ```ruby
239
+ class Person
240
+ include Micro::Observers
241
+
242
+ attr_reader :name
243
+
244
+ def initialize(name)
245
+ @name = name
246
+ end
247
+
248
+ def name=(new_name)
249
+ return unless observers.subject_changed(new_name != @name)
250
+
251
+ @name = new_name
252
+
253
+ observers.notify(:name_has_been_changed)
254
+ end
255
+ end
256
+
257
+ PrintPersonName = -> (data) do
258
+ puts("Person name: #{data.fetch(:person).name}, number: #{data.fetch(:number)}")
259
+ end
260
+
261
+ person = Person.new('Rodrigo')
262
+
263
+ person.observers.on(
264
+ event: :name_has_been_changed,
265
+ call: PrintPersonName,
266
+ with: -> event { {person: event.subject, number: event.context} },
267
+ context: rand
268
+ )
269
+
270
+ person.name = 'Serradura'
271
+ # The message below will be printed by the observer (PrintPersonName):
272
+ # Person name: Serradura, number: 0.5018509191706862
273
+ ```
274
+
275
+ [⬆️ &nbsp; Back to Top](#table-of-contents-)
276
+
277
+ ### Calling the observers
278
+
279
+ You can use a callable (a class, module, or object that responds to the call method) to be your observers.
280
+ To do this, you only need to make use of the method `#call` instead of `#notify`.
281
+
282
+ ```ruby
283
+ class Order
284
+ include Micro::Observers
285
+
286
+ def cancel!
287
+ observers.subject_changed!
288
+ observers.call # in practice, this is a shortcut to observers.notify(:call)
289
+ self
290
+ end
291
+ end
292
+
293
+ NotifyAfterCancel = -> (order) { puts "The order #(#{order.object_id}) has been canceled." }
294
+
295
+ order = Order.new
296
+ order.observers.attach(NotifyAfterCancel)
297
+ order.cancel!
298
+ # The message below will be printed by the observer (NotifyAfterCancel):
299
+ # The order #(70196221441820) has been canceled.
300
+ ```
301
+
302
+ > **Note**: The `observers.call` can receive one or more events, but in this case, the default event (`call`) won't be transmitted.
303
+
304
+ [⬆️ &nbsp; Back to Top](#table-of-contents-)
305
+
306
+ ### Notifying observers without marking them as changed
307
+
308
+ This feature needs to be used with caution!
309
+
310
+ If you use the methods `#notify!` or `#call!` you won't need to mark observers with `#subject_changed`.
311
+
312
+ [⬆️ &nbsp; Back to Top](#table-of-contents-)
313
+
314
+ ### Defining observers that execute only once
315
+
316
+ There are two ways to attach an observer and define it to be performed only once.
317
+
318
+ The first way to do this is passing the `perform_once: true` option to the `observers.attach()` method. e.g.
319
+
320
+ #### `observers.attach(*args, perform_once: true)`
321
+
322
+ ```ruby
323
+ class Order
324
+ include Micro::Observers
325
+
326
+ def cancel!
327
+ observers.notify!(:canceled)
328
+ end
329
+ end
330
+
331
+ module OrderNotifications
332
+ def self.canceled(order)
333
+ puts "The order #(#{order.object_id}) has been canceled."
334
+ end
335
+ end
336
+
337
+ order = Order.new
338
+ order.observers.attach(OrderNotifications, perform_once: true) # you can also pass an array of observers with this option
339
+
340
+ order.observers.some? # true
341
+ order.cancel! # The order #(70291642071660) has been canceled.
342
+
343
+ order.observers.some? # false
344
+ order.cancel! # Nothing will happen because there aren't observers.
345
+ ```
346
+
347
+ #### `observers.once(event:, call:, ...)`
348
+
349
+ 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.
350
+
351
+ ```ruby
352
+ class Order
353
+ include Micro::Observers
354
+
355
+ def cancel!
356
+ observers.notify!(:canceled)
357
+ end
358
+ end
359
+
360
+ module NotifyAfterCancel
361
+ def self.call(event)
362
+ puts "The order #(#{event.subject.object_id}) has been canceled."
363
+ end
364
+ end
365
+
366
+ order = Order.new
367
+ order.observers.once(event: :canceled, call: NotifyAfterCancel)
368
+
369
+ order.observers.some? # true
370
+ order.cancel! # The order #(70301497466060) has been canceled.
371
+
372
+ order.observers.some? # false
373
+ order.cancel! # Nothing will happen because there aren't observers.
374
+ ```
375
+
376
+ [⬆️ &nbsp; Back to Top](#table-of-contents-)
377
+
378
+ ### Detaching observers
379
+
380
+ As shown in the first example, you can use the `observers.detach()` to remove observers.
381
+
382
+ 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()`.
383
+
384
+ ```ruby
385
+ class Order
386
+ include Micro::Observers
387
+ end
388
+
389
+ NotifyAfterCancel = -> {}
390
+
391
+ module OrderNotifications
392
+ def self.canceled(_order)
393
+ end
394
+ end
395
+
396
+ order = Order.new
397
+ order.observers.on(event: :canceled, call: NotifyAfterCancel)
398
+ order.observers.attach(OrderNotifications)
399
+
400
+ order.observers.some? # true
401
+ order.observers.count # 2
402
+
403
+ order.observers.off(:canceled) # removing the callable (NotifyAfterCancel).
404
+ order.observers.some? # true
405
+ order.observers.count # 1
406
+
407
+ order.observers.off(OrderNotifications)
408
+ order.observers.some? # false
409
+ order.observers.count # 0
410
+ ```
411
+
412
+ [⬆️ &nbsp; Back to Top](#table-of-contents-)
413
+
414
+ ### ActiveRecord and ActiveModel integrations
415
+
416
+ To make use of this feature you need to require an additional module.
417
+
418
+ Gemfile example:
419
+ ```ruby
420
+ gem 'u-observers', require: 'u-observers/for/active_record'
421
+ ```
422
+
423
+ 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:
424
+
425
+ #### notify_observers_on()
426
+
427
+ The `notify_observers_on` allows you to define one or more `ActiveModel`/`ActiveRecord` callbacks, that will be used to notify your object observers.
428
+
429
+ ```ruby
430
+ class Post < ActiveRecord::Base
431
+ include ::Micro::Observers::For::ActiveRecord
432
+
433
+ notify_observers_on(:after_commit) # using multiple callbacks. e.g. notify_observers_on(:before_save, :after_commit)
434
+
435
+ # The method above does the same as the commented example below.
436
+ #
437
+ # after_commit do |record|
438
+ # record.subject_changed!
439
+ # record.notify(:after_commit)
440
+ # end
441
+ end
442
+
443
+ module TitlePrinter
444
+ def self.after_commit(post)
445
+ puts "Title: #{post.title}"
446
+ end
447
+ end
448
+
449
+ module TitlePrinterWithContext
450
+ def self.after_commit(post, event)
451
+ puts "Title: #{post.title} (from: #{event.context[:from]})"
452
+ end
453
+ end
454
+
455
+ Post.transaction do
456
+ post = Post.new(title: 'Hello world')
457
+ post.observers.attach(TitlePrinter, TitlePrinterWithContext, context: { from: 'example #6' })
458
+ post.save
459
+ end
460
+ # The message below will be printed by the observers (TitlePrinter, TitlePrinterWithContext):
461
+ # Title: Hello world
462
+ # Title: Hello world (from: example #6)
463
+ ```
464
+
465
+ [⬆️ &nbsp; Back to Top](#table-of-contents-)
466
+
467
+ #### notify_observers()
468
+
469
+ 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.
470
+
471
+ ```ruby
472
+ class Post < ActiveRecord::Base
473
+ include ::Micro::Observers::For::ActiveRecord
474
+
475
+ after_commit(&notify_observers(:transaction_completed))
476
+
477
+ # The method above does the same as the commented example below.
478
+ #
479
+ # after_commit do |record|
480
+ # record.subject_changed!
481
+ # record.notify(:transaction_completed)
482
+ # end
483
+ end
484
+
485
+ module TitlePrinter
486
+ def self.transaction_completed(post)
487
+ puts("Title: #{post.title}")
488
+ end
489
+ end
490
+
491
+ module TitlePrinterWithContext
492
+ def self.transaction_completed(post, event)
493
+ puts("Title: #{post.title} (from: #{event.ctx[:from]})")
494
+ end
495
+ end
496
+
497
+ Post.transaction do
498
+ post = Post.new(title: 'Olá mundo')
499
+ post.observers.attach(TitlePrinter, TitlePrinterWithContext, context: { from: 'example #7' })
500
+ post.save
501
+ end
502
+ # The message below will be printed by the observers (TitlePrinter, TitlePrinterWithContext):
503
+ # Title: Olá mundo
504
+ # Title: Olá mundo (from: example #5)
505
+ ```
506
+
507
+ > **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.
508
+
509
+ [⬆️ &nbsp; Back to Top](#table-of-contents-)
26
510
 
27
511
  ## Development
28
512