active_delivery 1.0.0.rc2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +51 -23
- data/README.md +110 -7
- data/lib/.rbnext/3.0/abstract_notifier/async_adapters/active_job.rb +36 -0
- data/lib/.rbnext/3.0/abstract_notifier/base.rb +223 -0
- data/lib/.rbnext/3.0/active_delivery/base.rb +143 -18
- data/lib/.rbnext/3.0/active_delivery/callbacks.rb +21 -17
- data/lib/.rbnext/3.0/active_delivery/lines/base.rb +53 -15
- data/lib/.rbnext/3.0/active_delivery/lines/mailer.rb +6 -1
- data/lib/.rbnext/3.0/active_delivery/testing.rb +62 -0
- data/lib/.rbnext/3.1/abstract_notifier/async_adapters/active_job.rb +36 -0
- data/lib/.rbnext/3.1/abstract_notifier/base.rb +223 -0
- data/lib/.rbnext/3.1/active_delivery/base.rb +141 -16
- data/lib/.rbnext/3.1/active_delivery/lines/base.rb +53 -15
- data/lib/abstract_notifier/async_adapters/active_job.rb +15 -6
- data/lib/abstract_notifier/base.rb +64 -19
- data/lib/abstract_notifier/callbacks.rb +94 -0
- data/lib/abstract_notifier/testing.rb +9 -5
- data/lib/abstract_notifier/version.rb +1 -1
- data/lib/abstract_notifier.rb +1 -0
- data/lib/active_delivery/base.rb +6 -5
- data/lib/active_delivery/lines/base.rb +34 -3
- data/lib/active_delivery/lines/mailer.rb +4 -0
- data/lib/active_delivery/lines/notifier.rb +5 -1
- data/lib/active_delivery/version.rb +1 -1
- metadata +12 -6
@@ -1,25 +1,59 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module AbstractNotifier
|
4
|
-
#
|
4
|
+
# NotificationDelivery payload wrapper which contains
|
5
5
|
# information about the current notifier class
|
6
6
|
# and knows how to trigger the delivery
|
7
|
-
class
|
8
|
-
attr_reader :
|
7
|
+
class NotificationDelivery
|
8
|
+
attr_reader :action_name, :notifier_class
|
9
|
+
|
10
|
+
def initialize(notifier_class, action_name, params: {}, args: [], kwargs: {})
|
11
|
+
@notifier_class = notifier_class
|
12
|
+
@action_name = action_name
|
13
|
+
@params = params
|
14
|
+
@args = args
|
15
|
+
@kwargs = kwargs
|
16
|
+
end
|
9
17
|
|
10
|
-
def
|
11
|
-
@
|
12
|
-
|
18
|
+
def processed
|
19
|
+
return @processed if instance_variable_defined?(:@processed)
|
20
|
+
|
21
|
+
@processed = notifier.process_action(action_name, *args, **kwargs) || Notification.new(nil)
|
13
22
|
end
|
14
23
|
|
15
|
-
|
16
|
-
|
17
|
-
|
24
|
+
alias_method :notification, :processed
|
25
|
+
|
26
|
+
def notify_later(**opts)
|
27
|
+
if notifier_class.async_adapter.respond_to?(:enqueue_delivery)
|
28
|
+
notifier_class.async_adapter.enqueue_delivery(self, **opts)
|
29
|
+
else
|
30
|
+
notifier_class.async_adapter.enqueue(notifier_class.name, action_name, params:, args:, kwargs:)
|
31
|
+
end
|
18
32
|
end
|
19
33
|
|
20
34
|
def notify_now
|
21
|
-
return
|
22
|
-
|
35
|
+
return unless notification.payload
|
36
|
+
|
37
|
+
notifier.deliver!(notification)
|
38
|
+
end
|
39
|
+
|
40
|
+
def delivery_params = {params:, args:, kwargs:}
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
attr_reader :params, :args, :kwargs
|
45
|
+
|
46
|
+
def notifier
|
47
|
+
@notifier ||= notifier_class.new(action_name, **params)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Notification object contains the compiled payload to be delivered
|
52
|
+
class Notification
|
53
|
+
attr_reader :payload
|
54
|
+
|
55
|
+
def initialize(payload)
|
56
|
+
@payload = payload
|
23
57
|
end
|
24
58
|
end
|
25
59
|
|
@@ -35,11 +69,7 @@ module AbstractNotifier
|
|
35
69
|
|
36
70
|
# rubocop:disable Style/MethodMissingSuper
|
37
71
|
def method_missing(method_name, *args, **kwargs)
|
38
|
-
|
39
|
-
notifier_class.new(method_name, **params).public_send(method_name, *args)
|
40
|
-
else
|
41
|
-
notifier_class.new(method_name, **params).public_send(method_name, *args, **kwargs)
|
42
|
-
end
|
72
|
+
NotificationDelivery.new(notifier_class, method_name, params:, args:, kwargs:)
|
43
73
|
end
|
44
74
|
# rubocop:enable Style/MethodMissingSuper
|
45
75
|
|
@@ -112,9 +142,9 @@ module AbstractNotifier
|
|
112
142
|
end
|
113
143
|
end
|
114
144
|
|
115
|
-
def method_missing(method_name, *args)
|
145
|
+
def method_missing(method_name, *args, **kwargs)
|
116
146
|
if action_methods.include?(method_name.to_s)
|
117
|
-
new(method_name
|
147
|
+
NotificationDelivery.new(self, method_name, args:, kwargs:)
|
118
148
|
else
|
119
149
|
super
|
120
150
|
end
|
@@ -152,16 +182,31 @@ module AbstractNotifier
|
|
152
182
|
@params = params.freeze
|
153
183
|
end
|
154
184
|
|
185
|
+
def process_action(...)
|
186
|
+
public_send(...)
|
187
|
+
end
|
188
|
+
|
189
|
+
def deliver!(notification)
|
190
|
+
self.class.driver.call(notification.payload)
|
191
|
+
end
|
192
|
+
|
155
193
|
def notification(**payload)
|
156
194
|
merge_defaults!(payload)
|
157
195
|
|
196
|
+
payload[:body] = implicit_payload_body unless payload.key?(:body)
|
197
|
+
|
158
198
|
raise ArgumentError, "Notification body must be present" if
|
159
199
|
payload[:body].nil? || payload[:body].empty?
|
160
|
-
|
200
|
+
|
201
|
+
@notification = Notification.new(payload)
|
161
202
|
end
|
162
203
|
|
163
204
|
private
|
164
205
|
|
206
|
+
def implicit_payload_body
|
207
|
+
# no-op — override to provide custom logic
|
208
|
+
end
|
209
|
+
|
165
210
|
def merge_defaults!(payload)
|
166
211
|
defaults =
|
167
212
|
if self.class.defaults_generator
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/version"
|
4
|
+
require "active_support/callbacks"
|
5
|
+
require "active_support/concern"
|
6
|
+
|
7
|
+
module AbstractNotifier
|
8
|
+
# Add callbacks support to Abstract Notifier (requires ActiveSupport::Callbacks)
|
9
|
+
#
|
10
|
+
# # Run method before seding notification
|
11
|
+
# # NOTE: when `false` is returned the execution is halted
|
12
|
+
# before_action :do_something
|
13
|
+
#
|
14
|
+
# # after_ and around_ callbacks are also supported
|
15
|
+
# after_action :cleanup
|
16
|
+
#
|
17
|
+
# around_action :set_context
|
18
|
+
#
|
19
|
+
# # Deliver callbacks are also available
|
20
|
+
# before_deliver :do_something
|
21
|
+
#
|
22
|
+
# # after_ and around_ callbacks are also supported
|
23
|
+
# after_deliver :cleanup
|
24
|
+
#
|
25
|
+
# around_deliver :set_context
|
26
|
+
module Callbacks
|
27
|
+
extend ActiveSupport::Concern
|
28
|
+
|
29
|
+
include ActiveSupport::Callbacks
|
30
|
+
|
31
|
+
CALLBACK_TERMINATOR = ->(_target, result) { result.call == false }
|
32
|
+
|
33
|
+
included do
|
34
|
+
define_callbacks :action,
|
35
|
+
terminator: CALLBACK_TERMINATOR,
|
36
|
+
skip_after_callbacks_if_terminated: true
|
37
|
+
|
38
|
+
define_callbacks :deliver,
|
39
|
+
terminator: CALLBACK_TERMINATOR,
|
40
|
+
skip_after_callbacks_if_terminated: true
|
41
|
+
|
42
|
+
prepend InstanceExt
|
43
|
+
end
|
44
|
+
|
45
|
+
module InstanceExt
|
46
|
+
def process_action(...)
|
47
|
+
run_callbacks(:action) { super(...) }
|
48
|
+
end
|
49
|
+
|
50
|
+
def deliver!(...)
|
51
|
+
run_callbacks(:deliver) { super(...) }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class_methods do
|
56
|
+
def _normalize_callback_options(options)
|
57
|
+
_normalize_callback_option(options, :only, :if)
|
58
|
+
_normalize_callback_option(options, :except, :unless)
|
59
|
+
end
|
60
|
+
|
61
|
+
def _normalize_callback_option(options, from, to)
|
62
|
+
if (from = options[from])
|
63
|
+
from_set = Array(from).map(&:to_s).to_set
|
64
|
+
from = proc { |c| from_set.include? c.notification_name.to_s }
|
65
|
+
options[to] = Array(options[to]).unshift(from)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
%i[before after around].each do |kind|
|
70
|
+
%i[action deliver].each do |event|
|
71
|
+
define_method "#{kind}_#{event}" do |*names, on: event, **options, &block|
|
72
|
+
_normalize_callback_options(options)
|
73
|
+
|
74
|
+
names.each do |name|
|
75
|
+
set_callback on, kind, name, options
|
76
|
+
end
|
77
|
+
|
78
|
+
set_callback on, kind, block, options if block
|
79
|
+
end
|
80
|
+
|
81
|
+
define_method "skip_#{kind}_#{event}" do |*names, on: event, **options|
|
82
|
+
_normalize_callback_options(options)
|
83
|
+
|
84
|
+
names.each do |name|
|
85
|
+
skip_callback(on, kind, name, options)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
AbstractNotifier::Base.include AbstractNotifier::Callbacks
|
@@ -27,23 +27,27 @@ module AbstractNotifier
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
-
module
|
30
|
+
module NotificationDelivery
|
31
31
|
def notify_now
|
32
32
|
return super unless AbstractNotifier.test?
|
33
33
|
|
34
|
-
|
34
|
+
payload = notification.payload
|
35
|
+
|
36
|
+
Driver.send_notification payload.merge(via: notifier.class)
|
35
37
|
end
|
36
38
|
|
37
|
-
def notify_later
|
39
|
+
def notify_later(**opts)
|
38
40
|
return super unless AbstractNotifier.test?
|
39
41
|
|
40
|
-
|
42
|
+
payload = notification.payload
|
43
|
+
|
44
|
+
Driver.enqueue_notification payload.merge(via: notifier.class, **opts)
|
41
45
|
end
|
42
46
|
end
|
43
47
|
end
|
44
48
|
end
|
45
49
|
|
46
|
-
AbstractNotifier::
|
50
|
+
AbstractNotifier::NotificationDelivery.prepend AbstractNotifier::Testing::NotificationDelivery
|
47
51
|
|
48
52
|
require "abstract_notifier/testing/rspec" if defined?(RSpec::Core)
|
49
53
|
require "abstract_notifier/testing/minitest" if defined?(Minitest::Assertions)
|
data/lib/abstract_notifier.rb
CHANGED
@@ -69,6 +69,7 @@ end
|
|
69
69
|
require "abstract_notifier/base"
|
70
70
|
require "abstract_notifier/async_adapters"
|
71
71
|
|
72
|
+
require "abstract_notifier/callbacks" if defined?(ActiveSupport)
|
72
73
|
require "abstract_notifier/async_adapters/active_job" if defined?(ActiveJob)
|
73
74
|
|
74
75
|
require "abstract_notifier/testing" if ENV["RACK_ENV"] == "test" || ENV["RAILS_ENV"] == "test"
|
data/lib/active_delivery/base.rb
CHANGED
@@ -12,9 +12,9 @@ module ActiveDelivery
|
|
12
12
|
@metadata = metadata.freeze
|
13
13
|
end
|
14
14
|
|
15
|
-
def deliver_later = owner.perform_notify(self)
|
15
|
+
def deliver_later(**opts) = owner.perform_notify(self, enqueue_options: opts)
|
16
16
|
|
17
|
-
def deliver_now = owner.perform_notify(self, sync: true)
|
17
|
+
def deliver_now(**opts) = owner.perform_notify(self, sync: true)
|
18
18
|
|
19
19
|
def delivery_class = owner.class
|
20
20
|
end
|
@@ -216,22 +216,23 @@ module ActiveDelivery
|
|
216
216
|
|
217
217
|
protected
|
218
218
|
|
219
|
-
def perform_notify(delivery, sync: false)
|
219
|
+
def perform_notify(delivery, sync: false, enqueue_options: {})
|
220
220
|
delivery_lines.each do |type, line|
|
221
221
|
next unless line.notify?(delivery.notification)
|
222
222
|
|
223
|
-
notify_line(type, line, delivery, sync:)
|
223
|
+
notify_line(type, line, delivery, sync:, enqueue_options:)
|
224
224
|
end
|
225
225
|
end
|
226
226
|
|
227
227
|
private
|
228
228
|
|
229
|
-
def notify_line(type, line, delivery, sync:)
|
229
|
+
def notify_line(type, line, delivery, sync:, enqueue_options:)
|
230
230
|
line.notify(
|
231
231
|
delivery.notification,
|
232
232
|
*delivery.params,
|
233
233
|
params:,
|
234
234
|
sync:,
|
235
|
+
enqueue_options:,
|
235
236
|
**delivery.options
|
236
237
|
)
|
237
238
|
true
|
@@ -16,7 +16,7 @@ module ActiveDelivery
|
|
16
16
|
@id = id
|
17
17
|
@owner = owner
|
18
18
|
@options = options.tap(&:freeze)
|
19
|
-
@resolver = options[:resolver]
|
19
|
+
@resolver = options[:resolver] || build_pattern_resolver(options[:resolver_pattern])
|
20
20
|
end
|
21
21
|
|
22
22
|
def dup_for(new_owner)
|
@@ -37,9 +37,21 @@ module ActiveDelivery
|
|
37
37
|
def notify_later(handler, mid, ...)
|
38
38
|
end
|
39
39
|
|
40
|
-
def
|
40
|
+
def notify_later_with_options(handler, enqueue_options, mid, ...)
|
41
|
+
notify_later(handler, mid, ...)
|
42
|
+
end
|
43
|
+
|
44
|
+
def notify(mid, *args, params:, sync:, enqueue_options:, **kwargs)
|
41
45
|
clazz = params.empty? ? handler_class : handler_class.with(**params)
|
42
|
-
sync
|
46
|
+
if sync
|
47
|
+
return notify_now(clazz, mid, *args, **kwargs)
|
48
|
+
end
|
49
|
+
|
50
|
+
if enqueue_options.empty?
|
51
|
+
notify_later(clazz, mid, *args, **kwargs)
|
52
|
+
else
|
53
|
+
notify_later_with_options(clazz, enqueue_options, mid, *args, **kwargs)
|
54
|
+
end
|
43
55
|
end
|
44
56
|
|
45
57
|
def handler_class
|
@@ -65,6 +77,25 @@ module ActiveDelivery
|
|
65
77
|
private
|
66
78
|
|
67
79
|
attr_reader :resolver
|
80
|
+
|
81
|
+
def build_pattern_resolver(pattern)
|
82
|
+
return unless pattern
|
83
|
+
|
84
|
+
proc do |delivery|
|
85
|
+
delivery_class = delivery.name
|
86
|
+
|
87
|
+
next unless delivery_class
|
88
|
+
|
89
|
+
*namespace, delivery_name = delivery_class.split("::")
|
90
|
+
|
91
|
+
delivery_namespace = ""
|
92
|
+
delivery_namespace = "#{namespace.join("::")}::" unless namespace.empty?
|
93
|
+
|
94
|
+
delivery_name = delivery_name.sub(/Delivery$/, "")
|
95
|
+
|
96
|
+
(pattern % {delivery_class:, delivery_name:, delivery_namespace:}).safe_constantize
|
97
|
+
end
|
98
|
+
end
|
68
99
|
end
|
69
100
|
end
|
70
101
|
end
|
@@ -19,6 +19,10 @@ module ActiveDelivery
|
|
19
19
|
def notify_later(mailer, mid, ...)
|
20
20
|
mailer.public_send(mid, ...).deliver_later
|
21
21
|
end
|
22
|
+
|
23
|
+
def notify_later_with_options(mailer, enqueue_options, mid, ...)
|
24
|
+
mailer.public_send(mid, ...).deliver_later(**enqueue_options)
|
25
|
+
end
|
22
26
|
end
|
23
27
|
|
24
28
|
ActiveDelivery::Base.register_line :mailer, Mailer, resolver: Mailer::DEFAULT_RESOLVER
|
@@ -18,7 +18,7 @@ module ActiveDelivery
|
|
18
18
|
|
19
19
|
def initialize(**opts)
|
20
20
|
super
|
21
|
-
@resolver
|
21
|
+
@resolver ||= build_resolver(options.fetch(:suffix, DEFAULT_SUFFIX))
|
22
22
|
end
|
23
23
|
|
24
24
|
def resolve_class(klass)
|
@@ -38,6 +38,10 @@ module ActiveDelivery
|
|
38
38
|
handler.public_send(mid, *args).notify_later
|
39
39
|
end
|
40
40
|
|
41
|
+
def notify_later_with_options(handler, enqueue_options, mid, *args)
|
42
|
+
handler.public_send(mid, *args).notify_later(**enqueue_options)
|
43
|
+
end
|
44
|
+
|
41
45
|
private
|
42
46
|
|
43
47
|
attr_reader :resolver
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_delivery
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vladimir Dementyev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-12-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -67,7 +67,7 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '4.0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name: ruby-next
|
70
|
+
name: ruby-next-core
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - ">="
|
@@ -93,16 +93,22 @@ files:
|
|
93
93
|
- README.md
|
94
94
|
- bin/console
|
95
95
|
- bin/setup
|
96
|
+
- lib/.rbnext/3.0/abstract_notifier/async_adapters/active_job.rb
|
97
|
+
- lib/.rbnext/3.0/abstract_notifier/base.rb
|
96
98
|
- lib/.rbnext/3.0/active_delivery/base.rb
|
97
99
|
- lib/.rbnext/3.0/active_delivery/callbacks.rb
|
98
100
|
- lib/.rbnext/3.0/active_delivery/lines/base.rb
|
99
101
|
- lib/.rbnext/3.0/active_delivery/lines/mailer.rb
|
102
|
+
- lib/.rbnext/3.0/active_delivery/testing.rb
|
103
|
+
- lib/.rbnext/3.1/abstract_notifier/async_adapters/active_job.rb
|
104
|
+
- lib/.rbnext/3.1/abstract_notifier/base.rb
|
100
105
|
- lib/.rbnext/3.1/active_delivery/base.rb
|
101
106
|
- lib/.rbnext/3.1/active_delivery/lines/base.rb
|
102
107
|
- lib/abstract_notifier.rb
|
103
108
|
- lib/abstract_notifier/async_adapters.rb
|
104
109
|
- lib/abstract_notifier/async_adapters/active_job.rb
|
105
110
|
- lib/abstract_notifier/base.rb
|
111
|
+
- lib/abstract_notifier/callbacks.rb
|
106
112
|
- lib/abstract_notifier/testing.rb
|
107
113
|
- lib/abstract_notifier/testing/minitest.rb
|
108
114
|
- lib/abstract_notifier/testing/rspec.rb
|
@@ -138,11 +144,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
138
144
|
version: '2.7'
|
139
145
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
140
146
|
requirements:
|
141
|
-
- - "
|
147
|
+
- - ">="
|
142
148
|
- !ruby/object:Gem::Version
|
143
|
-
version:
|
149
|
+
version: '0'
|
144
150
|
requirements: []
|
145
|
-
rubygems_version: 3.4.
|
151
|
+
rubygems_version: 3.4.20
|
146
152
|
signing_key:
|
147
153
|
specification_version: 4
|
148
154
|
summary: Ruby and Rails framework for managing all types of notifications in one place
|