u-observers 1.0.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,610 @@
1
+ <p align="center">
2
+ <h1 align="center">👀 μ-observers</h1>
3
+ <p align="center"><i>Implementação simples e poderosa do padrão observer.</i></p>
4
+ <br>
5
+ </p>
6
+
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">
9
+
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>
13
+
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>
17
+
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
+ Esta gem implementa o padrão observer[[1]](https://en.wikipedia.org/wiki/Observer_pattern)[[2]](https://refactoring.guru/design-patterns/observer) (também conhecido como publicar/assinar). Ela fornece um mecanismo simples para um objeto informar um conjunto de objetos de terceiros interessados ​​quando seu estado muda.
28
+
29
+ A biblioteca padrão do Ruby [tem uma abstração](https://ruby-doc.org/stdlib-2.7.1/libdoc/observer/rdoc/Observable.html) que permite usar esse padrão, mas seu design pode entrar em conflito com outras bibliotecas convencionais, como [`ActiveModel`/`ActiveRecord`](https://api.rubyonrails.org/classes/ActiveModel/Dirty.html#method-i-changed), que também tem o método [`changed`](https://ruby-doc.org/stdlib-2.7.1/libdoc/observer/rdoc/Observable.html#method-i-changed). Nesse caso, o comportamento ficaria comprometido por conta dessa sobrescrita de métodos.
30
+
31
+ Por causa desse problema, decidi criar uma gem que encapsula o padrão sem alterar tanto a implementação do objeto. O `Micro::Observers` inclui apenas um método de instância na classe de destino (sua instância será o sujeito/objeto observado).
32
+
33
+ # Índice <!-- omit in toc -->
34
+
35
+ - [Instalação](#instalação)
36
+ - [Compatibilidade](#compatibilidade)
37
+ - [Uso](#uso)
38
+ - [Compartilhando um contexto com seus observadores](#compartilhando-um-contexto-com-seus-observadores)
39
+ - [Compartilhando dados ao notificar os observadores](#compartilhando-dados-ao-notificar-os-observadores)
40
+ - [O que é `Micro::Observers::Event`?](#o-que-é-microobserversevent)
41
+ - [Usando um callable como um observador](#usando-um-callable-como-um-observador)
42
+ - [Chamando os observadores](#chamando-os-observadores)
43
+ - [Notificar observadores sem marcá-los como alterados](#notificar-observadores-sem-marcá-los-como-alterados)
44
+ - [Definindo observers que executam apenas uma vez](#definindo-observers-que-executam-apenas-uma-vez)
45
+ - [`observers.attach(*args, perform_once: true)`](#observersattachargs-perform_once-true)
46
+ - [`observers.once(event:, call:, ...)`](#observersonceevent-call-)
47
+ - [Definindo observers com blocos](#definindo-observers-com-blocos)
48
+ - [order.observers.on()](#orderobserverson)
49
+ - [order.observers.on()](#orderobserverson-1)
50
+ - [Substituindo um bloco por um `lambda`/`proc`](#substituindo-um-bloco-por-um-lambdaproc)
51
+ - [Desanexando observers](#desanexando-observers)
52
+ - [Integrações ActiveRecord e ActiveModel](#integrações-activerecord-e-activemodel)
53
+ - [notify_observers_on()](#notify_observers_on)
54
+ - [notify_observers()](#notify_observers)
55
+ - [Desenvolvimento](#desenvolvimento)
56
+ - [Contribuindo](#contribuindo)
57
+ - [License](#license)
58
+ - [Código de conduta](#código-de-conduta)
59
+
60
+ # Instalação
61
+
62
+ Adicione esta linha ao Gemfile da sua aplicação e execute `bundle install`:
63
+
64
+ ```ruby
65
+ gem 'u-observers'
66
+ ```
67
+
68
+ # Compatibilidade
69
+
70
+ | u-observers | branch | ruby | activerecord |
71
+ | ----------- | ------- | -------- | ------------- |
72
+ | unreleased | main | >= 2.2.0 | >= 3.2, < 6.1 |
73
+ | 2.3.0 | v2.x | >= 2.2.0 | >= 3.2, < 6.1 |
74
+ | 1.0.0 | v1.x | >= 2.2.0 | >= 3.2, < 6.1 |
75
+
76
+ > **Nota**: O ActiveRecord não é uma dependência, mas você pode adicionar um módulo para habilitar alguns métodos estáticos que foram projetados para serem usados ​​com seus [callbacks](https://guides.rubyonrails.org/active_record_callbacks.html).
77
+
78
+ [⬆️ Voltar para o índice](#índice-)
79
+
80
+ ## Uso
81
+
82
+ Qualquer classe com o `Micro::Observers` incluído pode notificar eventos para observadores anexados.
83
+
84
+ ```ruby
85
+ require 'securerandom'
86
+
87
+ class Order
88
+ include Micro::Observers
89
+
90
+ attr_reader :code
91
+
92
+ def initialize
93
+ @code, @status = SecureRandom.alphanumeric, :draft
94
+ end
95
+
96
+ def canceled?
97
+ @status == :canceled
98
+ end
99
+
100
+ def cancel!
101
+ return self if canceled?
102
+
103
+ @status = :canceled
104
+
105
+ observers.subject_changed!
106
+ observers.notify(:canceled) and return self
107
+ end
108
+ end
109
+
110
+ module OrderEvents
111
+ def self.canceled(order)
112
+ puts "The order #(#{order.code}) has been canceled."
113
+ end
114
+ end
115
+
116
+ order = Order.new
117
+ #<Order:0x00007fb5dd8fce70 @code="X0o9yf1GsdQFvLR4", @status=:draft>
118
+
119
+ order.observers.attach(OrderEvents) # anexando vários observadores. Exemplo: observers.attach(A, B, C)
120
+ # <#Micro::Observers::Set @subject=#<Order:0x00007fb5dd8fce70> @subject_changed=false @subscribers=[OrderEvents]>
121
+
122
+ order.canceled?
123
+ # false
124
+
125
+ order.cancel!
126
+ # A mensagem abaixo será impressa pelo observador (OrderEvents):
127
+ # The order #(X0o9yf1GsdQFvLR4) has been canceled
128
+
129
+ order.canceled?
130
+ # true
131
+
132
+ order.observers.detach(OrderEvents) # desanexando vários observadores. Exemplo: observers.detach(A, B, C)
133
+ # <#Micro::Observers::Set @subject=#<Order:0x00007fb5dd8fce70> @subject_changed=false @subscribers=[]>
134
+
135
+ order.canceled?
136
+ # true
137
+
138
+ order.observers.subject_changed!
139
+ order.observers.notify(:canceled) # nada acontecerá, pois não há observadores vinculados (observers.attach)
140
+ ```
141
+
142
+ **Destaques do exemplo anterior:**
143
+
144
+ Para evitar um comportamento indesejado, você precisa marcar o "subject" (sujeito) como alterado antes de notificar seus observadores sobre algum evento.
145
+
146
+ Você pode fazer isso ao usar o método `#subject_changed!`. Ele marcará automaticamente o sujeito como alterado.
147
+
148
+ Mas se você precisar aplicar alguma condicional para marcar uma mudança, você pode usar o método `#subject_changed`. Exemplo: `observers.subject_changed(name != new_name)`
149
+
150
+ O método `#notify` sempre requer um evento para fazer uma transmissão. Portanto, se você tentar usá-lo sem nenhum evento, você obterá uma exceção.
151
+
152
+ ```ruby
153
+ order.observers.notify
154
+ # ArgumentError (no events (expected at least 1))
155
+ ```
156
+
157
+ [⬆️ Voltar para o índice](#índice-)
158
+
159
+ ### Compartilhando um contexto com seus observadores
160
+
161
+ Para compartilhar um valor de contexto (qualquer tipo de objeto Ruby) com um ou mais observadores, você precisará usar a palavra-chave `:context` como o último argumento do método `#attach`. Este recurso oferece a você uma oportunidade única de compartilhar um valor no momento de anexar um *observer*.
162
+
163
+ Quando o método do observer receber dois argumentos, o primeiro será o sujeito e o segundo uma instância `Micro::Observers::Event` que terá o valor do contexto.
164
+
165
+ ```ruby
166
+ class Order
167
+ include Micro::Observers
168
+
169
+ def cancel!
170
+ observers.subject_changed!
171
+ observers.notify(:canceled)
172
+ self
173
+ end
174
+ end
175
+
176
+ module OrderEvents
177
+ def self.canceled(order, event)
178
+ puts "The order #(#{order.object_id}) has been canceled. (from: #{event.context[:from]})" # event.ctx é um alias para event.context
179
+ end
180
+ end
181
+
182
+ order = Order.new
183
+ order.observers.attach(OrderEvents, context: { from: 'example #2' }) # anexando vários observadores. Exemplo: observers.attach(A, B, context: {hello:: world})
184
+ order.cancel!
185
+ # A mensagem abaixo será impressa pelo observador (OrderEvents):
186
+ # The order #(70196221441820) has been canceled. (from: example #2)
187
+ ```
188
+
189
+ [⬆️ Voltar para o índice](#índice-)
190
+
191
+ ### Compartilhando dados ao notificar os observadores
192
+
193
+ Como mencionado anteriormente, o [`event context`](#compartilhando-um-contexto-com-seus-observadores) é um valor armazenado quando você anexa seu *observer*. Mas, às vezes, será útil enviar alguns dados adicionais ao transmitir um evento aos seus *observers*. O `event data` dá a você esta oportunidade única de compartilhar algum valor no momento da notificação.
194
+
195
+ ```ruby
196
+ class Order
197
+ include Micro::Observers
198
+ end
199
+
200
+ module OrderHandler
201
+ def self.changed(order, event)
202
+ puts "The order #(#{order.object_id}) received the number #{event.data} from #{event.ctx[:from]}."
203
+ end
204
+ end
205
+
206
+ order = Order.new
207
+ order.observers.attach(OrderHandler, context: { from: 'example #3' })
208
+ order.observers.subject_changed!
209
+ order.observers.notify(:changed, data: 1)
210
+
211
+ # A mensagem abaixo será impressa pelo observador (OrderHandler):
212
+ # The order #(70196221441820) received the number 1 from example #3.
213
+ ```
214
+
215
+ [⬆️ Voltar para o índice](#índice-)
216
+
217
+ ### O que é `Micro::Observers::Event`?
218
+
219
+ O `Micro::Observers::Event` é o payload do evento. Veja abaixo todas as suas propriedades:
220
+ - `#name` será o evento transmitido.
221
+ - `#subject` será o sujeito observado.
222
+ - `#context` serão [os dados de contexto](#compartilhando-um-contexto-com-seus-observadores) que foram definidos no momento em que você anexa o *observer*.
223
+ - `#data` será [o valor compartilhado na notificação dos observadores](#compartilhando-dados-ao-notificar-os-observadores).
224
+ - `#ctx` é um apelido para o método `#context`.
225
+ - `#subj` é um *alias* para o método `#subject`.
226
+
227
+ [⬆️ Voltar para o índice](#índice-)
228
+
229
+ ### Usando um callable como um observador
230
+
231
+ O método `observers.on()` permite que você anexe um callable (objeto que responda ao método `call`) como um observador.
232
+
233
+ Normalmente, um callable tem uma responsabilidade bem definida (faz apenas uma coisa), por isso, tende a ser mais amigável com o [SRP (princípio de responsabilidade única)](https://en.wikipedia.org/wiki/Single-responsibility_principle) do que um observador convencional (que poderia ter N métodos para responder a diferentes tipos de notificação).
234
+
235
+ Este método recebe as opções abaixo:
236
+ 1. `:event` o nome do evento esperado.
237
+ 2. `:call` o próprio callable.
238
+ 3. `:with` (opcional) pode definir o valor que será usado como argumento do objeto callable. Portanto, se for um `Proc`, uma instância de `Micro::Observers::Event` será recebida como o argumento `Proc` e sua saída será o argumento que pode ser chamado. Mas se essa opção não for definida, a instância `Micro::Observers::Event` será o argumento do callable.
239
+ 4. `:context` serão os dados de contexto que foram definidos no momento em que você anexa o *observer*.
240
+
241
+ ```ruby
242
+ class Person
243
+ include Micro::Observers
244
+
245
+ attr_reader :name
246
+
247
+ def initialize(name)
248
+ @name = name
249
+ end
250
+
251
+ def name=(new_name)
252
+ return unless observers.subject_changed(new_name != @name)
253
+
254
+ @name = new_name
255
+
256
+ observers.notify(:name_has_been_changed)
257
+ end
258
+ end
259
+
260
+ PrintPersonName = -> (data) do
261
+ puts("Person name: #{data.fetch(:person).name}, number: #{data.fetch(:number)}")
262
+ end
263
+
264
+ person = Person.new('Aristóteles')
265
+
266
+ person.observers.on(
267
+ event: :name_has_been_changed,
268
+ call: PrintPersonName,
269
+ with: -> event { {person: event.subject, number: event.context} },
270
+ context: rand
271
+ )
272
+
273
+ person.name = 'Coutinho'
274
+
275
+ # A mensagem abaixo será impressa pelo observador (PrintPersonName):
276
+ # Person name: Coutinho, number: 0.5018509191706862
277
+ ```
278
+
279
+ [⬆️ Voltar para o índice](#índice-)
280
+
281
+ ### Chamando os observadores
282
+
283
+ Você pode usar um callable (uma classe, módulo ou objeto que responda ao método `call`) para ser seu *observer*. Para fazer isso, você só precisa usar o método `#call` em vez de `#notify`.
284
+
285
+ ```ruby
286
+ class Order
287
+ include Micro::Observers
288
+
289
+ def cancel!
290
+ observers.subject_changed!
291
+ observers.call # na prática, este é um alias para observers.notify(:call)
292
+ self
293
+ end
294
+ end
295
+
296
+ OrderCancellation = -> (order) { puts "The order #(#{order.object_id}) has been canceled." }
297
+
298
+ order = Order.new
299
+ order.observers.attach(OrderCancellation)
300
+ order.cancel!
301
+
302
+ # A mensagem abaixo será impressa pelo observador (OrderCancellation):
303
+ # The order #(70196221441820) has been canceled.
304
+ ```
305
+
306
+ > **Nota**: O `observers.call` pode receber um ou mais eventos, mas no caso de receber eventos/argumentos, o evento padrão (`call`) não será transmitido.
307
+
308
+ [⬆️ Voltar para o índice](#índice-)
309
+
310
+ ### Notificar observadores sem marcá-los como alterados
311
+
312
+ Este recurso deve ser usado com cuidado!
313
+
314
+ Se você usar os métodos `#notify!` ou `#call!` você não precisará marcar observers com `#subject_changed`.
315
+
316
+ [⬆️ Voltar para o índice](#índice-)
317
+
318
+ ### Definindo observers que executam apenas uma vez
319
+
320
+ Existem duas formas de anexar um observer e definir que ele executará apenas uma vez.
321
+
322
+ A primeira forma de fazer isso é passando a opção `perform_once: true` para o método `observers.attach()`. Exemplo:
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
+ A segunda forma de conseguir isso é usando o método `observers.once()` que tem a mesma API do [`observers.on()`](#usando-um-callable-como-um-observador). Mas a diferença é que o método `#once()` removerá o observer após a sua execução.
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
+ [⬆️ Voltar para o índice](#índice-)
381
+
382
+ ### Definindo observers com blocos
383
+
384
+ Os métodos `#on()` e `#once()` podem receber um evento (a `symbol`) e um bloco para definir 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
+ #### Substituindo um bloco por um `lambda`/`proc`
433
+
434
+ Ruby permite que você substitua qualquer bloco com um `lambda`/`proc`. Exemplo:
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
+ [⬆️ Voltar para o índice](#índice-)
458
+
459
+ ### Desanexando observers
460
+
461
+ Como mostrado no primeiro exemplo, você pode usar o `observers.detach()` para remove observers.
462
+
463
+ Mas, existe uma alternativa a esse método que permite remover objetos observers ou remover callables pelo nome de seus eventos. O método para fazer isso é: `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
+ [⬆️ Voltar para o índice](#índice-)
494
+
495
+ ### Integrações ActiveRecord e ActiveModel
496
+
497
+ Para fazer uso deste recurso, você precisa de um módulo adicional.
498
+
499
+ Exemplo de Gemfile:
500
+ ```ruby
501
+ gem 'u-observers', require: 'u-observers/for/active_record'
502
+ ```
503
+
504
+ Este recurso irá expor módulos que podem ser usados ​​para adicionar macros (métodos estáticos) que foram projetados para funcionar com os callbacks do `ActiveModel`/`ActiveRecord`. Exemplo:
505
+
506
+ #### notify_observers_on()
507
+
508
+ O `notify_observers_on` permite que você defina um ou mais callbacks do `ActiveModel`/`ActiveRecord`, que serão usados ​​para notificar seus *observers*.
509
+
510
+ ```ruby
511
+ class Post < ActiveRecord::Base
512
+ include ::Micro::Observers::For::ActiveRecord
513
+
514
+ notify_observers_on(:after_commit) # usando vários callbacks. Exemplo: notificar_observadores_on(:before_save, :after_commit)
515
+
516
+ # O método acima faz o mesmo que o exemplo comentado abaixo.
517
+ #
518
+ # after_commit do | record |
519
+ # record.subject_changed!
520
+ # record.notify (:after_commit)
521
+ # end
522
+ end
523
+
524
+ module TitlePrinter
525
+ def self.after_commit(post)
526
+ puts "Title: #{post.title}"
527
+ end
528
+ end
529
+
530
+ module TitlePrinterWithContext
531
+ def self.after_commit(post, event)
532
+ puts "Title: #{post.title} (from: #{event.context[:from]})"
533
+ end
534
+ end
535
+
536
+ Post.transaction do
537
+ post = Post.new(title: 'Hello world')
538
+ post.observers.attach(TitlePrinter, TitlePrinterWithContext, context: { from: 'example #6' })
539
+ post.save
540
+ end
541
+
542
+ # A mensagem abaixo será impressa pelos observadores (TitlePrinter, TitlePrinterWithContext):
543
+ # Title: Hello world
544
+ # Title: Hello world (de: exemplo # 6)
545
+ ```
546
+
547
+ [⬆️ Voltar para o índice](#índice-)
548
+
549
+ #### notify_observers()
550
+
551
+ O `notify_observers` permite definir um ou mais eventos, que serão utilizados para notificar após a execução de algum callback do `ActiveModel`/`ActiveRecord`.
552
+
553
+ ```ruby
554
+ class Post < ActiveRecord::Base
555
+ include ::Micro::Observers::For::ActiveRecord
556
+
557
+ after_commit(&notify_observers(:transaction_completed))
558
+
559
+ # O método acima faz o mesmo que o exemplo comentado abaixo.
560
+ #
561
+ # after_commit do | record |
562
+ # record.subject_changed!
563
+ # record.notify (:transaction_completed)
564
+ # end
565
+ end
566
+
567
+ module TitlePrinter
568
+ def self.transaction_completed(post)
569
+ puts("Title: #{post.title}")
570
+ end
571
+ end
572
+
573
+ module TitlePrinterWithContext
574
+ def self.transaction_completed(post, event)
575
+ puts("Title: #{post.title} (from: #{event.ctx[:from]})")
576
+ end
577
+ end
578
+
579
+ Post.transaction do
580
+ post = Post.new(title: 'Olá mundo')
581
+ post.observers.attach(TitlePrinter, TitlePrinterWithContext, context: { from: 'example #7' })
582
+ post.save
583
+ end
584
+
585
+ # A mensagem abaixo será impressa pelos observadores (TitlePrinter, TitlePrinterWithContext):
586
+ # Title: Olá mundo
587
+ # Title: Olá mundo (from: example # 5)
588
+ ```
589
+
590
+ > **Observação**: você pode usar `include ::Micro::Observers::For::ActiveModel` se sua classe apenas fizer uso do `ActiveModel` e todos os exemplos anteriores funcionarão.
591
+
592
+ [⬆️ Voltar para o índice](#índice-)
593
+
594
+ ## Desenvolvimento
595
+
596
+ Depois de verificar o repositório, execute `bin/setup` para instalar as dependências. Em seguida, execute `rake test` para executar os testes. Você também pode executar `bin/console` um prompt interativo que permitirá que você experimente.
597
+
598
+ Para instalar esta gem em sua máquina local, execute `bundle exec rake install`. Para lançar uma nova versão, atualize o número da versão em `version.rb` e execute `bundle exec rake release`, que criará uma tag git para a versão, envie os commits ao git e envie e envie o arquivo `.gem` para [rubygems.org](https://rubygems.org).
599
+
600
+ ## Contribuindo
601
+
602
+ Reportar bugs e solicitações de pull-requests são bem-vindos no GitHub em https://github.com/serradura/u-observers. Este projeto pretende ser um espaço seguro e acolhedor para colaboração, e espera-se que os colaboradores sigam o [código de conduta](https://github.com/serradura/u-observers/blob/master/CODE_OF_CONDUCT.md).
603
+
604
+ ## License
605
+
606
+ A gem está disponível como código aberto sob os termos da [Licença MIT](https://opensource.org/licenses/MIT).
607
+
608
+ ## Código de conduta
609
+
610
+ Espera-se que todos que interagem nas bases de código do projeto `Micro::Observers`, rastreadores de problemas, salas de bate-papo e listas de discussão sigam o [código de conduta](https://github.com/serradura/u-observers/blob/master/CODE_OF_CONDUCT.md).