active_delivery 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +53 -21
- data/lib/.rbnext/3.0/abstract_notifier/async_adapters/active_job.rb +2 -2
- data/lib/.rbnext/3.0/abstract_notifier/base.rb +4 -4
- data/lib/.rbnext/3.0/active_delivery/base.rb +8 -8
- data/lib/.rbnext/3.0/active_delivery/lines/base.rb +4 -4
- data/lib/.rbnext/3.0/active_delivery/testing/minitest.rb +58 -0
- data/lib/.rbnext/3.0/active_delivery/testing.rb +1 -0
- data/lib/.rbnext/3.1/abstract_notifier/async_adapters/active_job.rb +2 -2
- data/lib/.rbnext/3.1/abstract_notifier/base.rb +4 -4
- data/lib/.rbnext/3.1/active_delivery/base.rb +8 -8
- data/lib/.rbnext/3.1/active_delivery/lines/base.rb +4 -4
- data/lib/.rbnext/3.1/active_delivery/testing/minitest.rb +58 -0
- data/lib/.rbnext/3.2/abstract_notifier/async_adapters/active_job.rb +36 -0
- data/lib/.rbnext/3.2/abstract_notifier/base.rb +223 -0
- data/lib/.rbnext/3.2/abstract_notifier/testing/rspec.rb +164 -0
- data/lib/.rbnext/3.2/abstract_notifier/testing.rb +53 -0
- data/lib/.rbnext/3.2/active_delivery/base.rb +249 -0
- data/lib/.rbnext/3.2/active_delivery/lines/base.rb +101 -0
- data/lib/.rbnext/3.2/active_delivery/lines/notifier.rb +57 -0
- data/lib/.rbnext/3.2/active_delivery/testing/rspec.rb +222 -0
- data/lib/abstract_notifier/async_adapters/active_job.rb +2 -2
- data/lib/abstract_notifier/base.rb +4 -4
- data/lib/abstract_notifier/testing/minitest.rb +1 -1
- data/lib/abstract_notifier/testing/rspec.rb +4 -4
- data/lib/abstract_notifier/testing.rb +2 -2
- data/lib/active_delivery/base.rb +8 -8
- data/lib/active_delivery/lines/base.rb +4 -4
- data/lib/active_delivery/lines/notifier.rb +6 -6
- data/lib/active_delivery/testing/minitest.rb +58 -0
- data/lib/active_delivery/testing/rspec.rb +4 -4
- data/lib/active_delivery/testing.rb +1 -0
- data/lib/active_delivery/version.rb +1 -1
- metadata +17 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d05087cb016af8444f7668b81681675248b7b63f41f77a1d9fdb22b65ccb6845
|
4
|
+
data.tar.gz: d60851ccb9d9ea6557d131289942edf57b39c79a499e37d41f8f1d06b480446f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a94a2fd3e2f19d9e99c0df6494752b23649802b064b390ea50d65506b01beb57650f31f5cd140495d6befa847a65423cc141ec8c313a6a116de69a4cd5576df
|
7
|
+
data.tar.gz: 4febe7f49e314d27f370642fa43085c5020dae8bac7fa9a3512514a6b861d17b726d4685ed91f081eab22f4c2af68a4117d37f8f29a576c78fe323f2c73b58e2
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,10 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
## 1.2.0 (2024-02-05)
|
6
|
+
|
7
|
+
- Add Minitest assertions (`assert_deliveries`, `assert_no_deliveries`, `assert_delivery_enqueued`). ([@palkan][])
|
8
|
+
|
5
9
|
## 1.1.0 (2023-12-01) ❄️
|
6
10
|
|
7
11
|
- Support delayed delivery options (e.g, `wait_until`). ([@palkan][])
|
data/README.md
CHANGED
@@ -10,6 +10,8 @@ Since v1.0, Active Delivery is bundled with [Abstract Notifier](https://github.c
|
|
10
10
|
|
11
11
|
📖 Read the introduction post: ["Crafting user notifications in Rails with Active Delivery"](https://evilmartians.com/chronicles/crafting-user-notifications-in-rails-with-active-delivery)
|
12
12
|
|
13
|
+
📖 Read more about designing notifications layer in Ruby on Rails applications in the [Layered design for Ruby on Rails applications](https://www.packtpub.com/product/layered-design-for-ruby-on-rails-applications/9781801813785) book.
|
14
|
+
|
13
15
|
<a href="https://evilmartians.com/?utm_source=action_policy">
|
14
16
|
<img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54"></a>
|
15
17
|
|
@@ -56,7 +58,7 @@ end
|
|
56
58
|
Add this line to your application's Gemfile:
|
57
59
|
|
58
60
|
```ruby
|
59
|
-
gem "active_delivery", "1.0
|
61
|
+
gem "active_delivery", "~> 1.0"
|
60
62
|
```
|
61
63
|
|
62
64
|
And then execute:
|
@@ -291,17 +293,36 @@ MyDeliver.notify(:something_wicked_this_way_comes)
|
|
291
293
|
|
292
294
|
## Testing
|
293
295
|
|
294
|
-
|
296
|
+
### Setup
|
297
|
+
|
298
|
+
Test mode is activated automatically if `RAILS_ENV` or `RACK_ENV` env variable is equal to "test". Otherwise, add `require "active_delivery/testing/rspec"` to your `spec_helper.rb` / `rails_helper.rb` manually or `require "active_delivery/testing/minitest"`. This is also required if you're using Spring in the test environment (e.g. with help of [spring-commands-rspec](https://github.com/jonleighton/spring-commands-rspec)).
|
299
|
+
|
300
|
+
For Minitest, you also MUST include the test helper into your test class. For example:
|
301
|
+
|
302
|
+
```ruby
|
303
|
+
class ActiveSupport::TestCase
|
304
|
+
# ...
|
305
|
+
include ActiveDelivery::TestHelper
|
306
|
+
end
|
307
|
+
```
|
295
308
|
|
296
309
|
### Deliveries
|
297
310
|
|
298
|
-
Active Delivery provides an elegant way to test deliveries in your code (i.e., when you want to check whether a notification has been sent) through a `have_delivered_to` matcher:
|
311
|
+
Active Delivery provides an elegant way to test deliveries in your code (i.e., when you want to check whether a notification has been sent) through a `have_delivered_to` RSpec matcher or `assert_delivery_enqueued` Minitest assertion:
|
299
312
|
|
300
313
|
```ruby
|
314
|
+
# RSpec
|
301
315
|
it "delivers notification" do
|
302
316
|
expect { subject }.to have_delivered_to(Community::EventsDelivery, :modified, event)
|
303
317
|
.with(profile: profile)
|
304
318
|
end
|
319
|
+
|
320
|
+
# Minitest
|
321
|
+
def test_delivers_notification
|
322
|
+
assert_delivery_enqueued(Community::EventsDelivery, :modified, with: [event]) do
|
323
|
+
some_action
|
324
|
+
end
|
325
|
+
end
|
305
326
|
```
|
306
327
|
|
307
328
|
You can also use such RSpec features as compound expectations and composed matchers:
|
@@ -320,14 +341,27 @@ end
|
|
320
341
|
If you want to test that no notification is delivered you can use negation
|
321
342
|
|
322
343
|
```ruby
|
344
|
+
# RSpec
|
323
345
|
specify "when event is not found" do
|
324
346
|
expect do
|
325
347
|
described_class.perform_now(profile.id, "123", "one_hour_before")
|
326
348
|
end.not_to have_delivered_to(Community::EventsDelivery)
|
327
349
|
end
|
350
|
+
|
351
|
+
# Minitest
|
352
|
+
def test_no_notification_if_event_is_not_found
|
353
|
+
assert_no_deliveries do
|
354
|
+
some_action
|
355
|
+
end
|
356
|
+
|
357
|
+
# Alternatively, you can use the positive assertion
|
358
|
+
assert_deliveries(0) do
|
359
|
+
some_action
|
360
|
+
end
|
361
|
+
end
|
328
362
|
```
|
329
363
|
|
330
|
-
|
364
|
+
With RSpec, you can also use the `#have_not_delivered_to` matcher:
|
331
365
|
|
332
366
|
```ruby
|
333
367
|
specify "when event is not found" do
|
@@ -360,7 +394,7 @@ describe PostsDelivery do
|
|
360
394
|
end
|
361
395
|
```
|
362
396
|
|
363
|
-
You can also use the `#deliver_via`
|
397
|
+
You can also use the `#deliver_via` RSpec matcher as follows:
|
364
398
|
|
365
399
|
```ruby
|
366
400
|
describe PostsDelivery, type: :delivery do
|
@@ -387,8 +421,6 @@ describe PostsDelivery, type: :delivery do
|
|
387
421
|
end
|
388
422
|
```
|
389
423
|
|
390
|
-
**NOTE:** test mode activated automatically if `RAILS_ENV` or `RACK_ENV` env variable is equal to "test". Otherwise, add `require "active_delivery/testing/rspec"` to your `spec_helper.rb` / `rails_helper.rb` manually. This is also required if you're using Spring in the test environment (e.g. with help of [spring-commands-rspec](https://github.com/jonleighton/spring-commands-rspec)).
|
391
|
-
|
392
424
|
## Custom "lines"
|
393
425
|
|
394
426
|
The _Line_ class describes the way you want to _transfer_ your deliveries.
|
@@ -410,8 +442,8 @@ class EventPigeon
|
|
410
442
|
alias_method :with, :new
|
411
443
|
|
412
444
|
# delegate delivery action to the instance
|
413
|
-
def message_arrived(*
|
414
|
-
new.message_arrived(*
|
445
|
+
def message_arrived(*)
|
446
|
+
new.message_arrived(*)
|
415
447
|
end
|
416
448
|
end
|
417
449
|
|
@@ -447,17 +479,17 @@ class PigeonLine < ActiveDelivery::Lines::Base
|
|
447
479
|
# Called when we want to send message synchronously
|
448
480
|
# `sender` here either `sender_class` or `sender_class.with(params)`
|
449
481
|
# if params passed.
|
450
|
-
def notify_now(sender, delivery_action,
|
482
|
+
def notify_now(sender, delivery_action, *, **)
|
451
483
|
# For example, our EventPigeon class returns some `Pigeon` object
|
452
|
-
pigeon = sender.public_send(delivery_action,
|
484
|
+
pigeon = sender.public_send(delivery_action, *, **)
|
453
485
|
# PigeonLaunchService do all the sending job
|
454
486
|
PigeonService.launch pigeon
|
455
487
|
end
|
456
488
|
|
457
489
|
# Called when we want to send a message asynchronously.
|
458
490
|
# For example, you can use a background job here.
|
459
|
-
def notify_later(sender, delivery_action,
|
460
|
-
pigeon = sender.public_send(delivery_action,
|
491
|
+
def notify_later(sender, delivery_action, *, **)
|
492
|
+
pigeon = sender.public_send(delivery_action, *, **)
|
461
493
|
# PigeonLaunchService do all the sending job
|
462
494
|
PigeonLaunchJob.perform_later pigeon
|
463
495
|
end
|
@@ -475,8 +507,8 @@ class EventPigeon
|
|
475
507
|
alias_method :with, :new
|
476
508
|
|
477
509
|
# delegate delivery action to the instance
|
478
|
-
def message_arrived(*
|
479
|
-
new.message_arrived(*
|
510
|
+
def message_arrived(*)
|
511
|
+
new.message_arrived(*)
|
480
512
|
end
|
481
513
|
end
|
482
514
|
|
@@ -491,18 +523,18 @@ class EventPigeon
|
|
491
523
|
end
|
492
524
|
|
493
525
|
class PigeonLine < ActiveDelivery::Lines::Base
|
494
|
-
def notify_later(sender, delivery_action,
|
526
|
+
def notify_later(sender, delivery_action, *, **kwargs)
|
495
527
|
# `to_s` is important for serialization. Unless you might have error
|
496
|
-
PigeonLaunchJob.perform_later
|
528
|
+
PigeonLaunchJob.perform_later(sender.class.to_s, delivery_action, *, **kwargs.merge(params: line.params))
|
497
529
|
end
|
498
530
|
end
|
499
531
|
|
500
532
|
class PigeonLaunchJob < ActiveJob::Base
|
501
|
-
def perform(sender, delivery_action,
|
533
|
+
def perform(sender, delivery_action, *, params: nil, **)
|
502
534
|
klass = sender.safe_constantize
|
503
535
|
handler = params ? klass.with(**params) : klass.new
|
504
536
|
|
505
|
-
handler.public_send(delivery_action,
|
537
|
+
handler.public_send(delivery_action, *, **)
|
506
538
|
end
|
507
539
|
end
|
508
540
|
```
|
@@ -591,12 +623,12 @@ class ActionCableDeliveryLine < ActiveDelivery::Line::Base
|
|
591
623
|
# We want to broadcast all notifications
|
592
624
|
def notify?(...) = true
|
593
625
|
|
594
|
-
def notify_now(context, delivery_action,
|
626
|
+
def notify_now(context, delivery_action, *, **)
|
595
627
|
# Skip if no user provided
|
596
628
|
return unless context.user
|
597
629
|
|
598
630
|
payload = {event: [context.scope, delivery_action].join(".")}
|
599
|
-
payload.merge!(serialized_args(
|
631
|
+
payload.merge!(serialized_args(*, **))
|
600
632
|
|
601
633
|
DeliveryChannel.broadcast_to context.user, payload
|
602
634
|
end
|
@@ -22,8 +22,8 @@ module AbstractNotifier
|
|
22
22
|
job.set(queue: queue).perform_later(...)
|
23
23
|
end; respond_to?(:ruby2_keywords, true) && (ruby2_keywords :enqueue)
|
24
24
|
|
25
|
-
def enqueue_delivery(delivery, **
|
26
|
-
job.set(queue: queue, **
|
25
|
+
def enqueue_delivery(delivery, **__kwrest__)
|
26
|
+
job.set(queue: queue, **__kwrest__).perform_later(
|
27
27
|
delivery.notifier_class.name,
|
28
28
|
delivery.action_name,
|
29
29
|
**delivery.delivery_params
|
@@ -23,9 +23,9 @@ module AbstractNotifier
|
|
23
23
|
|
24
24
|
alias_method :notification, :processed
|
25
25
|
|
26
|
-
def notify_later(**
|
26
|
+
def notify_later(**__kwrest__)
|
27
27
|
if notifier_class.async_adapter.respond_to?(:enqueue_delivery)
|
28
|
-
notifier_class.async_adapter.enqueue_delivery(self, **
|
28
|
+
notifier_class.async_adapter.enqueue_delivery(self, **__kwrest__)
|
29
29
|
else
|
30
30
|
notifier_class.async_adapter.enqueue(notifier_class.name, action_name, params: params, args: args, kwargs: kwargs)
|
31
31
|
end
|
@@ -73,8 +73,8 @@ module AbstractNotifier
|
|
73
73
|
end
|
74
74
|
# rubocop:enable Style/MethodMissingSuper
|
75
75
|
|
76
|
-
def respond_to_missing?(*
|
77
|
-
notifier_class.respond_to_missing?(*
|
76
|
+
def respond_to_missing?(*__rest__)
|
77
|
+
notifier_class.respond_to_missing?(*__rest__)
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
@@ -77,8 +77,8 @@ module ActiveDelivery
|
|
77
77
|
|
78
78
|
# The same as .notify but delivers synchronously
|
79
79
|
# (i.e. #deliver_now for mailers)
|
80
|
-
def notify!(mid, *
|
81
|
-
notify(mid, *
|
80
|
+
def notify!(mid, *__rest__, **hargs)
|
81
|
+
notify(mid, *__rest__, **hargs, sync: true)
|
82
82
|
end
|
83
83
|
|
84
84
|
alias_method :notify_now, :notify!
|
@@ -93,7 +93,7 @@ module ActiveDelivery
|
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
|
-
def register_line(line_id, line_class = nil, notifier: nil, **
|
96
|
+
def register_line(line_id, line_class = nil, notifier: nil, **__kwrest__)
|
97
97
|
raise ArgumentError, "A line class or notifier configuration must be provided" if line_class.nil? && notifier.nil?
|
98
98
|
|
99
99
|
# Configure Notifier
|
@@ -101,7 +101,7 @@ module ActiveDelivery
|
|
101
101
|
line_class = ActiveDelivery::Lines::Notifier
|
102
102
|
end
|
103
103
|
|
104
|
-
delivery_lines[line_id] = line_class.new(id: line_id, owner: self, **
|
104
|
+
delivery_lines[line_id] = line_class.new(id: line_id, owner: self, **__kwrest__)
|
105
105
|
|
106
106
|
instance_eval <<~CODE, __FILE__, __LINE__ + 1
|
107
107
|
def #{line_id}(val)
|
@@ -152,13 +152,13 @@ module ActiveDelivery
|
|
152
152
|
super
|
153
153
|
end
|
154
154
|
|
155
|
-
def method_missing(mid, *
|
155
|
+
def method_missing(mid, *__rest__, **__kwrest__)
|
156
156
|
return super unless respond_to_missing?(mid)
|
157
157
|
|
158
158
|
# Lazily define a class method to avoid lookups
|
159
159
|
delivers(mid)
|
160
160
|
|
161
|
-
public_send(mid, *
|
161
|
+
public_send(mid, *__rest__, **__kwrest__)
|
162
162
|
end
|
163
163
|
end
|
164
164
|
|
@@ -197,7 +197,7 @@ module ActiveDelivery
|
|
197
197
|
super
|
198
198
|
end
|
199
199
|
|
200
|
-
def method_missing(mid, *
|
200
|
+
def method_missing(mid, *__rest__, **__kwrest__)
|
201
201
|
return super unless respond_to_missing?(mid)
|
202
202
|
|
203
203
|
# Lazily define a method to avoid future lookups
|
@@ -211,7 +211,7 @@ module ActiveDelivery
|
|
211
211
|
end
|
212
212
|
CODE
|
213
213
|
|
214
|
-
public_send(mid, *
|
214
|
+
public_send(mid, *__rest__, **__kwrest__)
|
215
215
|
end
|
216
216
|
|
217
217
|
protected
|
@@ -41,16 +41,16 @@ module ActiveDelivery
|
|
41
41
|
notify_later(handler, mid, *__rest__, &__block__)
|
42
42
|
end; respond_to?(:ruby2_keywords, true) && (ruby2_keywords :notify_later_with_options)
|
43
43
|
|
44
|
-
def notify(mid, *
|
44
|
+
def notify(mid, *__rest__, params:, sync:, enqueue_options:, **__kwrest__)
|
45
45
|
clazz = params.empty? ? handler_class : handler_class.with(**params)
|
46
46
|
if sync
|
47
|
-
return notify_now(clazz, mid, *
|
47
|
+
return notify_now(clazz, mid, *__rest__, **__kwrest__)
|
48
48
|
end
|
49
49
|
|
50
50
|
if enqueue_options.empty?
|
51
|
-
notify_later(clazz, mid, *
|
51
|
+
notify_later(clazz, mid, *__rest__, **__kwrest__)
|
52
52
|
else
|
53
|
-
notify_later_with_options(clazz, enqueue_options, mid, *
|
53
|
+
notify_later_with_options(clazz, enqueue_options, mid, *__rest__, **__kwrest__)
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveDelivery
|
4
|
+
module TestHelper
|
5
|
+
def assert_deliveries(count)
|
6
|
+
TestDelivery.enable { yield }
|
7
|
+
|
8
|
+
assert_equal TestDelivery.store.count, count, "Expected #{count} deliveries, got #{TestDelivery.store.count}"
|
9
|
+
end
|
10
|
+
|
11
|
+
def assert_no_deliveries(&__block__) ; assert_deliveries(0, &__block__); end
|
12
|
+
|
13
|
+
def assert_delivery_enqueued(delivery_class, event, count: 1, params: nil, with: nil)
|
14
|
+
TestDelivery.enable { yield }
|
15
|
+
|
16
|
+
deliveries = TestDelivery.store
|
17
|
+
|
18
|
+
if with
|
19
|
+
args = with
|
20
|
+
kwargs = args.pop if args.last.is_a?(Hash)
|
21
|
+
end
|
22
|
+
|
23
|
+
matching_deliveries, _unmatching_deliveries =
|
24
|
+
deliveries.partition do |(delivery, options)|
|
25
|
+
next false if delivery_class != delivery.owner.class
|
26
|
+
|
27
|
+
next false if event != delivery.notification
|
28
|
+
|
29
|
+
next false if params && !hash_include?(delivery.owner.params, params)
|
30
|
+
|
31
|
+
next true unless with
|
32
|
+
|
33
|
+
actual_args = delivery.params
|
34
|
+
actual_kwargs = delivery.options
|
35
|
+
|
36
|
+
next false unless args.each.with_index.all? do |arg, i|
|
37
|
+
arg === actual_args[i]
|
38
|
+
end
|
39
|
+
|
40
|
+
next false unless kwargs.all? do |k, v|
|
41
|
+
v === actual_kwargs[k]
|
42
|
+
end
|
43
|
+
|
44
|
+
true
|
45
|
+
end
|
46
|
+
|
47
|
+
assert_equal count, matching_deliveries.count, "Expected #{count} deliveries, got #{deliveries.count}"
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def hash_include?(haystack, needle)
|
53
|
+
needle.all? do |k, v|
|
54
|
+
haystack.key?(k) && haystack[k] == v
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -22,8 +22,8 @@ module AbstractNotifier
|
|
22
22
|
job.set(queue: queue).perform_later(...)
|
23
23
|
end
|
24
24
|
|
25
|
-
def enqueue_delivery(delivery, **
|
26
|
-
job.set(queue: queue, **
|
25
|
+
def enqueue_delivery(delivery, **__kwrest__)
|
26
|
+
job.set(queue: queue, **__kwrest__).perform_later(
|
27
27
|
delivery.notifier_class.name,
|
28
28
|
delivery.action_name,
|
29
29
|
**delivery.delivery_params
|
@@ -23,9 +23,9 @@ module AbstractNotifier
|
|
23
23
|
|
24
24
|
alias_method :notification, :processed
|
25
25
|
|
26
|
-
def notify_later(**
|
26
|
+
def notify_later(**__kwrest__)
|
27
27
|
if notifier_class.async_adapter.respond_to?(:enqueue_delivery)
|
28
|
-
notifier_class.async_adapter.enqueue_delivery(self, **
|
28
|
+
notifier_class.async_adapter.enqueue_delivery(self, **__kwrest__)
|
29
29
|
else
|
30
30
|
notifier_class.async_adapter.enqueue(notifier_class.name, action_name, params: params, args: args, kwargs: kwargs)
|
31
31
|
end
|
@@ -73,8 +73,8 @@ module AbstractNotifier
|
|
73
73
|
end
|
74
74
|
# rubocop:enable Style/MethodMissingSuper
|
75
75
|
|
76
|
-
def respond_to_missing?(*
|
77
|
-
notifier_class.respond_to_missing?(*
|
76
|
+
def respond_to_missing?(*__rest__)
|
77
|
+
notifier_class.respond_to_missing?(*__rest__)
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
@@ -77,8 +77,8 @@ module ActiveDelivery
|
|
77
77
|
|
78
78
|
# The same as .notify but delivers synchronously
|
79
79
|
# (i.e. #deliver_now for mailers)
|
80
|
-
def notify!(mid, *
|
81
|
-
notify(mid, *
|
80
|
+
def notify!(mid, *__rest__, **hargs)
|
81
|
+
notify(mid, *__rest__, **hargs, sync: true)
|
82
82
|
end
|
83
83
|
|
84
84
|
alias_method :notify_now, :notify!
|
@@ -93,7 +93,7 @@ module ActiveDelivery
|
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
|
-
def register_line(line_id, line_class = nil, notifier: nil, **
|
96
|
+
def register_line(line_id, line_class = nil, notifier: nil, **__kwrest__)
|
97
97
|
raise ArgumentError, "A line class or notifier configuration must be provided" if line_class.nil? && notifier.nil?
|
98
98
|
|
99
99
|
# Configure Notifier
|
@@ -101,7 +101,7 @@ module ActiveDelivery
|
|
101
101
|
line_class = ActiveDelivery::Lines::Notifier
|
102
102
|
end
|
103
103
|
|
104
|
-
delivery_lines[line_id] = line_class.new(id: line_id, owner: self, **
|
104
|
+
delivery_lines[line_id] = line_class.new(id: line_id, owner: self, **__kwrest__)
|
105
105
|
|
106
106
|
instance_eval <<~CODE, __FILE__, __LINE__ + 1
|
107
107
|
def #{line_id}(val)
|
@@ -152,13 +152,13 @@ module ActiveDelivery
|
|
152
152
|
super
|
153
153
|
end
|
154
154
|
|
155
|
-
def method_missing(mid, *
|
155
|
+
def method_missing(mid, *__rest__, **__kwrest__)
|
156
156
|
return super unless respond_to_missing?(mid)
|
157
157
|
|
158
158
|
# Lazily define a class method to avoid lookups
|
159
159
|
delivers(mid)
|
160
160
|
|
161
|
-
public_send(mid, *
|
161
|
+
public_send(mid, *__rest__, **__kwrest__)
|
162
162
|
end
|
163
163
|
end
|
164
164
|
|
@@ -197,7 +197,7 @@ module ActiveDelivery
|
|
197
197
|
super
|
198
198
|
end
|
199
199
|
|
200
|
-
def method_missing(mid, *
|
200
|
+
def method_missing(mid, *__rest__, **__kwrest__)
|
201
201
|
return super unless respond_to_missing?(mid)
|
202
202
|
|
203
203
|
# Lazily define a method to avoid future lookups
|
@@ -211,7 +211,7 @@ module ActiveDelivery
|
|
211
211
|
end
|
212
212
|
CODE
|
213
213
|
|
214
|
-
public_send(mid, *
|
214
|
+
public_send(mid, *__rest__, **__kwrest__)
|
215
215
|
end
|
216
216
|
|
217
217
|
protected
|
@@ -41,16 +41,16 @@ module ActiveDelivery
|
|
41
41
|
notify_later(handler, mid, ...)
|
42
42
|
end
|
43
43
|
|
44
|
-
def notify(mid, *
|
44
|
+
def notify(mid, *__rest__, params:, sync:, enqueue_options:, **__kwrest__)
|
45
45
|
clazz = params.empty? ? handler_class : handler_class.with(**params)
|
46
46
|
if sync
|
47
|
-
return notify_now(clazz, mid, *
|
47
|
+
return notify_now(clazz, mid, *__rest__, **__kwrest__)
|
48
48
|
end
|
49
49
|
|
50
50
|
if enqueue_options.empty?
|
51
|
-
notify_later(clazz, mid, *
|
51
|
+
notify_later(clazz, mid, *__rest__, **__kwrest__)
|
52
52
|
else
|
53
|
-
notify_later_with_options(clazz, enqueue_options, mid, *
|
53
|
+
notify_later_with_options(clazz, enqueue_options, mid, *__rest__, **__kwrest__)
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveDelivery
|
4
|
+
module TestHelper
|
5
|
+
def assert_deliveries(count)
|
6
|
+
TestDelivery.enable { yield }
|
7
|
+
|
8
|
+
assert_equal TestDelivery.store.count, count, "Expected #{count} deliveries, got #{TestDelivery.store.count}"
|
9
|
+
end
|
10
|
+
|
11
|
+
def assert_no_deliveries(&__block__) = assert_deliveries(0, &__block__)
|
12
|
+
|
13
|
+
def assert_delivery_enqueued(delivery_class, event, count: 1, params: nil, with: nil)
|
14
|
+
TestDelivery.enable { yield }
|
15
|
+
|
16
|
+
deliveries = TestDelivery.store
|
17
|
+
|
18
|
+
if with
|
19
|
+
args = with
|
20
|
+
kwargs = args.pop if args.last.is_a?(Hash)
|
21
|
+
end
|
22
|
+
|
23
|
+
matching_deliveries, _unmatching_deliveries =
|
24
|
+
deliveries.partition do |(delivery, options)|
|
25
|
+
next false if delivery_class != delivery.owner.class
|
26
|
+
|
27
|
+
next false if event != delivery.notification
|
28
|
+
|
29
|
+
next false if params && !hash_include?(delivery.owner.params, params)
|
30
|
+
|
31
|
+
next true unless with
|
32
|
+
|
33
|
+
actual_args = delivery.params
|
34
|
+
actual_kwargs = delivery.options
|
35
|
+
|
36
|
+
next false unless args.each.with_index.all? do |arg, i|
|
37
|
+
arg === actual_args[i]
|
38
|
+
end
|
39
|
+
|
40
|
+
next false unless kwargs.all? do |k, v|
|
41
|
+
v === actual_kwargs[k]
|
42
|
+
end
|
43
|
+
|
44
|
+
true
|
45
|
+
end
|
46
|
+
|
47
|
+
assert_equal count, matching_deliveries.count, "Expected #{count} deliveries, got #{deliveries.count}"
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def hash_include?(haystack, needle)
|
53
|
+
needle.all? do |k, v|
|
54
|
+
haystack.key?(k) && haystack[k] == v
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AbstractNotifier
|
4
|
+
module AsyncAdapters
|
5
|
+
class ActiveJob
|
6
|
+
class DeliveryJob < ::ActiveJob::Base
|
7
|
+
def perform(notifier_class, ...)
|
8
|
+
AbstractNotifier::NotificationDelivery.new(notifier_class.constantize, ...).notify_now
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
DEFAULT_QUEUE = "notifiers"
|
13
|
+
|
14
|
+
attr_reader :job, :queue
|
15
|
+
|
16
|
+
def initialize(queue: DEFAULT_QUEUE, job: DeliveryJob)
|
17
|
+
@job = job
|
18
|
+
@queue = queue
|
19
|
+
end
|
20
|
+
|
21
|
+
def enqueue(...)
|
22
|
+
job.set(queue:).perform_later(...)
|
23
|
+
end
|
24
|
+
|
25
|
+
def enqueue_delivery(delivery, **__kwrest__)
|
26
|
+
job.set(queue:, **__kwrest__).perform_later(
|
27
|
+
delivery.notifier_class.name,
|
28
|
+
delivery.action_name,
|
29
|
+
**delivery.delivery_params
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
AbstractNotifier.async_adapter ||= :active_job
|