active_delivery 1.0.0.rc2 → 1.0.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 +33 -23
- data/README.md +106 -6
- data/lib/.rbnext/3.0/abstract_notifier/async_adapters/active_job.rb +27 -0
- data/lib/.rbnext/3.0/active_delivery/base.rb +142 -18
- data/lib/.rbnext/3.0/active_delivery/callbacks.rb +21 -17
- data/lib/.rbnext/3.0/active_delivery/lines/base.rb +39 -13
- data/lib/.rbnext/3.0/active_delivery/lines/mailer.rb +2 -1
- data/lib/.rbnext/3.0/active_delivery/testing.rb +62 -0
- data/lib/.rbnext/3.1/abstract_notifier/base.rb +217 -0
- data/lib/.rbnext/3.1/active_delivery/base.rb +140 -16
- data/lib/.rbnext/3.1/active_delivery/lines/base.rb +39 -13
- data/lib/abstract_notifier/async_adapters/active_job.rb +4 -4
- data/lib/abstract_notifier/base.rb +57 -18
- data/lib/abstract_notifier/callbacks.rb +94 -0
- data/lib/abstract_notifier/testing.rb +8 -4
- data/lib/abstract_notifier/version.rb +1 -1
- data/lib/abstract_notifier.rb +1 -0
- data/lib/active_delivery/lines/base.rb +20 -1
- data/lib/active_delivery/lines/notifier.rb +1 -1
- data/lib/active_delivery/version.rb +1 -1
- metadata +9 -5
@@ -1,25 +1,53 @@
|
|
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
|
9
|
+
|
10
|
+
def initialize(owner_class, action_name, params: {}, args: [], kwargs: {})
|
11
|
+
@owner_class = owner_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
|
|
24
|
+
alias_method :notification, :processed
|
25
|
+
|
15
26
|
def notify_later
|
16
|
-
|
17
|
-
owner.async_adapter.enqueue owner, payload
|
27
|
+
owner_class.async_adapter.enqueue(owner_class.name, action_name, params:, args:, kwargs:)
|
18
28
|
end
|
19
29
|
|
20
30
|
def notify_now
|
21
|
-
return
|
22
|
-
|
31
|
+
return unless notification.payload
|
32
|
+
|
33
|
+
notifier.deliver!(notification)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
attr_reader :owner_class, :params, :args, :kwargs
|
39
|
+
|
40
|
+
def notifier
|
41
|
+
@notifier ||= owner_class.new(action_name, **params)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Notification object contains the compiled payload to be delivered
|
46
|
+
class Notification
|
47
|
+
attr_reader :payload
|
48
|
+
|
49
|
+
def initialize(payload)
|
50
|
+
@payload = payload
|
23
51
|
end
|
24
52
|
end
|
25
53
|
|
@@ -35,11 +63,7 @@ module AbstractNotifier
|
|
35
63
|
|
36
64
|
# rubocop:disable Style/MethodMissingSuper
|
37
65
|
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
|
66
|
+
NotificationDelivery.new(notifier_class, method_name, params:, args:, kwargs:)
|
43
67
|
end
|
44
68
|
# rubocop:enable Style/MethodMissingSuper
|
45
69
|
|
@@ -112,9 +136,9 @@ module AbstractNotifier
|
|
112
136
|
end
|
113
137
|
end
|
114
138
|
|
115
|
-
def method_missing(method_name, *args)
|
139
|
+
def method_missing(method_name, *args, **kwargs)
|
116
140
|
if action_methods.include?(method_name.to_s)
|
117
|
-
new(method_name
|
141
|
+
NotificationDelivery.new(self, method_name, args:, kwargs:)
|
118
142
|
else
|
119
143
|
super
|
120
144
|
end
|
@@ -152,16 +176,31 @@ module AbstractNotifier
|
|
152
176
|
@params = params.freeze
|
153
177
|
end
|
154
178
|
|
179
|
+
def process_action(...)
|
180
|
+
public_send(...)
|
181
|
+
end
|
182
|
+
|
183
|
+
def deliver!(notification)
|
184
|
+
self.class.driver.call(notification.payload)
|
185
|
+
end
|
186
|
+
|
155
187
|
def notification(**payload)
|
156
188
|
merge_defaults!(payload)
|
157
189
|
|
190
|
+
payload[:body] = implicit_payload_body unless payload.key?(:body)
|
191
|
+
|
158
192
|
raise ArgumentError, "Notification body must be present" if
|
159
193
|
payload[:body].nil? || payload[:body].empty?
|
160
|
-
|
194
|
+
|
195
|
+
@notification = Notification.new(payload)
|
161
196
|
end
|
162
197
|
|
163
198
|
private
|
164
199
|
|
200
|
+
def implicit_payload_body
|
201
|
+
# no-op — override to provide custom logic
|
202
|
+
end
|
203
|
+
|
165
204
|
def merge_defaults!(payload)
|
166
205
|
defaults =
|
167
206
|
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
39
|
def notify_later
|
38
40
|
return super unless AbstractNotifier.test?
|
39
41
|
|
40
|
-
|
42
|
+
payload = notification.payload
|
43
|
+
|
44
|
+
Driver.enqueue_notification payload.merge(via: notifier.class)
|
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"
|
@@ -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)
|
@@ -65,6 +65,25 @@ module ActiveDelivery
|
|
65
65
|
private
|
66
66
|
|
67
67
|
attr_reader :resolver
|
68
|
+
|
69
|
+
def build_pattern_resolver(pattern)
|
70
|
+
return unless pattern
|
71
|
+
|
72
|
+
proc do |delivery|
|
73
|
+
delivery_class = delivery.name
|
74
|
+
|
75
|
+
next unless delivery_class
|
76
|
+
|
77
|
+
*namespace, delivery_name = delivery_class.split("::")
|
78
|
+
|
79
|
+
delivery_namespace = ""
|
80
|
+
delivery_namespace = "#{namespace.join("::")}::" unless namespace.empty?
|
81
|
+
|
82
|
+
delivery_name = delivery_name.sub(/Delivery$/, "")
|
83
|
+
|
84
|
+
(pattern % {delivery_class:, delivery_name:, delivery_namespace:}).safe_constantize
|
85
|
+
end
|
86
|
+
end
|
68
87
|
end
|
69
88
|
end
|
70
89
|
end
|
@@ -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)
|
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.0.0
|
4
|
+
version: 1.0.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-08-29 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,20 @@ 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
|
96
97
|
- lib/.rbnext/3.0/active_delivery/base.rb
|
97
98
|
- lib/.rbnext/3.0/active_delivery/callbacks.rb
|
98
99
|
- lib/.rbnext/3.0/active_delivery/lines/base.rb
|
99
100
|
- lib/.rbnext/3.0/active_delivery/lines/mailer.rb
|
101
|
+
- lib/.rbnext/3.0/active_delivery/testing.rb
|
102
|
+
- lib/.rbnext/3.1/abstract_notifier/base.rb
|
100
103
|
- lib/.rbnext/3.1/active_delivery/base.rb
|
101
104
|
- lib/.rbnext/3.1/active_delivery/lines/base.rb
|
102
105
|
- lib/abstract_notifier.rb
|
103
106
|
- lib/abstract_notifier/async_adapters.rb
|
104
107
|
- lib/abstract_notifier/async_adapters/active_job.rb
|
105
108
|
- lib/abstract_notifier/base.rb
|
109
|
+
- lib/abstract_notifier/callbacks.rb
|
106
110
|
- lib/abstract_notifier/testing.rb
|
107
111
|
- lib/abstract_notifier/testing/minitest.rb
|
108
112
|
- lib/abstract_notifier/testing/rspec.rb
|
@@ -138,9 +142,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
138
142
|
version: '2.7'
|
139
143
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
140
144
|
requirements:
|
141
|
-
- - "
|
145
|
+
- - ">="
|
142
146
|
- !ruby/object:Gem::Version
|
143
|
-
version:
|
147
|
+
version: '0'
|
144
148
|
requirements: []
|
145
149
|
rubygems_version: 3.4.8
|
146
150
|
signing_key:
|