active_delivery 0.4.3 → 1.0.0.rc2
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 +58 -1
- data/LICENSE.txt +19 -17
- data/README.md +503 -32
- data/lib/.rbnext/3.0/active_delivery/base.rb +124 -0
- data/lib/.rbnext/3.0/active_delivery/callbacks.rb +97 -0
- data/lib/.rbnext/3.0/active_delivery/lines/base.rb +63 -0
- data/lib/.rbnext/3.0/active_delivery/lines/mailer.rb +25 -0
- data/lib/.rbnext/3.1/active_delivery/base.rb +124 -0
- data/lib/.rbnext/3.1/active_delivery/lines/base.rb +63 -0
- data/lib/abstract_notifier/async_adapters/active_job.rb +27 -0
- data/lib/abstract_notifier/async_adapters.rb +16 -0
- data/lib/abstract_notifier/base.rb +178 -0
- data/lib/abstract_notifier/testing/minitest.rb +51 -0
- data/lib/abstract_notifier/testing/rspec.rb +164 -0
- data/lib/abstract_notifier/testing.rb +49 -0
- data/lib/abstract_notifier/version.rb +5 -0
- data/lib/abstract_notifier.rb +74 -0
- data/lib/active_delivery/base.rb +156 -27
- data/lib/active_delivery/callbacks.rb +25 -25
- data/lib/active_delivery/ext/string_constantize.rb +24 -0
- data/lib/active_delivery/lines/base.rb +24 -17
- data/lib/active_delivery/lines/mailer.rb +7 -18
- data/lib/active_delivery/lines/notifier.rb +53 -0
- data/lib/active_delivery/raitie.rb +9 -0
- data/lib/active_delivery/testing/rspec.rb +59 -12
- data/lib/active_delivery/testing.rb +19 -5
- data/lib/active_delivery/version.rb +1 -1
- data/lib/active_delivery.rb +8 -0
- metadata +61 -56
- data/.gem_release.yml +0 -3
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -24
- data/.github/ISSUE_TEMPLATE/feature_request.md +0 -24
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -23
- data/.github/workflows/docs-lint.yml +0 -72
- data/.github/workflows/rspec-jruby.yml +0 -35
- data/.github/workflows/rspec.yml +0 -51
- data/.github/workflows/rubocop.yml +0 -21
- data/.gitignore +0 -43
- data/.mdlrc +0 -1
- data/.rspec +0 -2
- data/.rubocop-md.yml +0 -16
- data/.rubocop.yml +0 -28
- data/Gemfile +0 -17
- data/RELEASING.md +0 -43
- data/Rakefile +0 -20
- data/active_delivery.gemspec +0 -35
- data/forspell.dict +0 -8
- data/gemfiles/jruby.gemfile +0 -5
- data/gemfiles/rails42.gemfile +0 -8
- data/gemfiles/rails5.gemfile +0 -5
- data/gemfiles/rails50.gemfile +0 -8
- data/gemfiles/rails6.gemfile +0 -5
- data/gemfiles/railsmaster.gemfile +0 -6
- data/gemfiles/rubocop.gemfile +0 -4
- data/lefthook.yml +0 -18
- data/lib/active_delivery/action_mailer/parameterized.rb +0 -92
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveDelivery
|
4
|
+
# Base class for deliveries.
|
5
|
+
#
|
6
|
+
# Delivery object describes how to notify a user about
|
7
|
+
# an event (e.g. via email or via push notification or both).
|
8
|
+
#
|
9
|
+
# Delivery class acts like a proxy in front of the different delivery channels
|
10
|
+
# (i.e. mailers, notifiers). That means that calling a method on delivery class invokes the
|
11
|
+
# same method on the corresponding class, e.g.:
|
12
|
+
#
|
13
|
+
# EventsDelivery.notify(:one_hour_before, profile, event)
|
14
|
+
#
|
15
|
+
# # under the hood it calls
|
16
|
+
# EventsMailer.one_hour_before(profile, event).deliver_later
|
17
|
+
#
|
18
|
+
# # and
|
19
|
+
# EventsNotifier.one_hour_before(profile, event).notify_later
|
20
|
+
#
|
21
|
+
# Delivery also supports _parameterized_ calling:
|
22
|
+
#
|
23
|
+
# EventsDelivery.with(profile: profile).notify(:canceled, event)
|
24
|
+
#
|
25
|
+
# The parameters could be accessed through `params` instance method (e.g.
|
26
|
+
# to implement guard-like logic).
|
27
|
+
#
|
28
|
+
# When params are presents the parametrized mailer is used, i.e.:
|
29
|
+
#
|
30
|
+
# EventsMailer.with(profile: profile).canceled(event)
|
31
|
+
#
|
32
|
+
# See https://api.rubyonrails.org/classes/ActionMailer/Parameterized.html
|
33
|
+
class Base
|
34
|
+
class << self
|
35
|
+
attr_accessor :abstract_class
|
36
|
+
|
37
|
+
alias_method :with, :new
|
38
|
+
|
39
|
+
# Enqueues delivery (i.e. uses #deliver_later for mailers)
|
40
|
+
def notify(...)
|
41
|
+
new.notify(...)
|
42
|
+
end; respond_to?(:ruby2_keywords, true) && (ruby2_keywords :notify)
|
43
|
+
|
44
|
+
# The same as .notify but delivers synchronously
|
45
|
+
# (i.e. #deliver_now for mailers)
|
46
|
+
def notify!(mid, *args, **hargs)
|
47
|
+
notify(mid, *args, **hargs, sync: true)
|
48
|
+
end
|
49
|
+
|
50
|
+
def delivery_lines
|
51
|
+
@lines ||= if superclass.respond_to?(:delivery_lines)
|
52
|
+
superclass.delivery_lines.each_with_object({}) do |(key, val), acc|
|
53
|
+
acc[key] = val.dup_for(self)
|
54
|
+
end
|
55
|
+
else
|
56
|
+
{}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def register_line(line_id, line_class, **options)
|
61
|
+
delivery_lines[line_id] = line_class.new(id: line_id, owner: self, **options)
|
62
|
+
|
63
|
+
instance_eval <<~CODE, __FILE__, __LINE__ + 1
|
64
|
+
def #{line_id}(val)
|
65
|
+
delivery_lines[:#{line_id}].handler_class = val
|
66
|
+
end
|
67
|
+
|
68
|
+
def #{line_id}_class
|
69
|
+
delivery_lines[:#{line_id}].handler_class
|
70
|
+
end
|
71
|
+
CODE
|
72
|
+
end
|
73
|
+
|
74
|
+
def unregister_line(line_id)
|
75
|
+
removed_line = delivery_lines.delete(line_id)
|
76
|
+
|
77
|
+
return if removed_line.nil?
|
78
|
+
|
79
|
+
singleton_class.undef_method line_id
|
80
|
+
singleton_class.undef_method "#{line_id}_class"
|
81
|
+
end
|
82
|
+
|
83
|
+
def abstract_class? ; abstract_class == true; end
|
84
|
+
end
|
85
|
+
|
86
|
+
attr_reader :params, :notification_name
|
87
|
+
|
88
|
+
def initialize(**params)
|
89
|
+
@params = params
|
90
|
+
@params.freeze
|
91
|
+
end
|
92
|
+
|
93
|
+
# Enqueues delivery (i.e. uses #deliver_later for mailers)
|
94
|
+
def notify(mid, *__rest__, &__block__)
|
95
|
+
@notification_name = mid
|
96
|
+
do_notify(*__rest__, &__block__)
|
97
|
+
end; respond_to?(:ruby2_keywords, true) && (ruby2_keywords :notify)
|
98
|
+
|
99
|
+
# The same as .notify but delivers synchronously
|
100
|
+
# (i.e. #deliver_now for mailers)
|
101
|
+
def notify!(mid, *args, **hargs)
|
102
|
+
notify(mid, *args, **hargs, sync: true)
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def do_notify(*args, sync: false, **kwargs)
|
108
|
+
delivery_lines.each do |type, line|
|
109
|
+
next if line.handler_class.nil?
|
110
|
+
next unless line.notify?(notification_name)
|
111
|
+
|
112
|
+
notify_line(type, *args, params: params, sync: sync, **kwargs)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def notify_line(type, *__rest__, &__block__)
|
117
|
+
delivery_lines[type].notify(notification_name, *__rest__, &__block__)
|
118
|
+
end; respond_to?(:ruby2_keywords, true) && (ruby2_keywords :notify_line)
|
119
|
+
|
120
|
+
def delivery_lines
|
121
|
+
self.class.delivery_lines
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/version"
|
4
|
+
require "active_support/callbacks"
|
5
|
+
require "active_support/concern"
|
6
|
+
|
7
|
+
module ActiveDelivery
|
8
|
+
# Add callbacks support to Active Delivery (requires ActiveSupport::Callbacks)
|
9
|
+
#
|
10
|
+
# # Run method before delivering notification
|
11
|
+
# # NOTE: when `false` is returned the execution is halted
|
12
|
+
# before_notify :do_something
|
13
|
+
#
|
14
|
+
# # You can specify a notification method (to run callback only for that method)
|
15
|
+
# before_notify :do_mail_something, on: :mail
|
16
|
+
#
|
17
|
+
# # or for push notifications
|
18
|
+
# before_notify :do_mail_something, on: :push
|
19
|
+
#
|
20
|
+
# # after_ and around_ callbacks are also supported
|
21
|
+
# after_notify :cleanup
|
22
|
+
#
|
23
|
+
# around_notify :set_context
|
24
|
+
module Callbacks
|
25
|
+
extend ActiveSupport::Concern
|
26
|
+
|
27
|
+
include ActiveSupport::Callbacks
|
28
|
+
|
29
|
+
CALLBACK_TERMINATOR = ->(_target, result) { result.call == false }
|
30
|
+
|
31
|
+
included do
|
32
|
+
# Define "global" callbacks
|
33
|
+
define_line_callbacks :notify
|
34
|
+
|
35
|
+
prepend InstanceExt
|
36
|
+
singleton_class.prepend SingltonExt
|
37
|
+
end
|
38
|
+
|
39
|
+
module InstanceExt
|
40
|
+
def do_notify(...)
|
41
|
+
run_callbacks(:notify) { super(...) }
|
42
|
+
end; respond_to?(:ruby2_keywords, true) && (ruby2_keywords :do_notify)
|
43
|
+
|
44
|
+
def notify_line(kind, *__rest__, &__block__)
|
45
|
+
run_callbacks(kind) { super(kind, *__rest__, &__block__) }
|
46
|
+
end; respond_to?(:ruby2_keywords, true) && (ruby2_keywords :notify_line)
|
47
|
+
end
|
48
|
+
|
49
|
+
module SingltonExt
|
50
|
+
def register_line(line_id, *__rest__, &__block__)
|
51
|
+
super
|
52
|
+
define_line_callbacks line_id
|
53
|
+
end; respond_to?(:ruby2_keywords, true) && (ruby2_keywords :register_line)
|
54
|
+
end
|
55
|
+
|
56
|
+
class_methods do
|
57
|
+
def _normalize_callback_options(options)
|
58
|
+
_normalize_callback_option(options, :only, :if)
|
59
|
+
_normalize_callback_option(options, :except, :unless)
|
60
|
+
end
|
61
|
+
|
62
|
+
def _normalize_callback_option(options, from, to)
|
63
|
+
if (from = options[from])
|
64
|
+
from_set = Array(from).map(&:to_s).to_set
|
65
|
+
from = proc { |c| from_set.include? c.notification_name.to_s }
|
66
|
+
options[to] = Array(options[to]).unshift(from)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def define_line_callbacks(name)
|
71
|
+
define_callbacks name,
|
72
|
+
terminator: CALLBACK_TERMINATOR,
|
73
|
+
skip_after_callbacks_if_terminated: true
|
74
|
+
end
|
75
|
+
|
76
|
+
def before_notify(method_or_block = nil, on: :notify, **options, &block)
|
77
|
+
method_or_block ||= block
|
78
|
+
_normalize_callback_options(options)
|
79
|
+
set_callback on, :before, method_or_block, options
|
80
|
+
end
|
81
|
+
|
82
|
+
def after_notify(method_or_block = nil, on: :notify, **options, &block)
|
83
|
+
method_or_block ||= block
|
84
|
+
_normalize_callback_options(options)
|
85
|
+
set_callback on, :after, method_or_block, options
|
86
|
+
end
|
87
|
+
|
88
|
+
def around_notify(method_or_block = nil, on: :notify, **options, &block)
|
89
|
+
method_or_block ||= block
|
90
|
+
_normalize_callback_options(options)
|
91
|
+
set_callback on, :around, method_or_block, options
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
ActiveDelivery::Base.include ActiveDelivery::Callbacks
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveDelivery
|
4
|
+
module Lines
|
5
|
+
class Base
|
6
|
+
attr_reader :id, :options
|
7
|
+
attr_accessor :owner
|
8
|
+
attr_writer :handler_class
|
9
|
+
|
10
|
+
def initialize(id:, owner:, **options)
|
11
|
+
@id = id
|
12
|
+
@owner = owner
|
13
|
+
@options = options.tap(&:freeze)
|
14
|
+
@resolver = options[:resolver]
|
15
|
+
end
|
16
|
+
|
17
|
+
def dup_for(new_owner)
|
18
|
+
self.class.new(id: id, **options, owner: new_owner)
|
19
|
+
end
|
20
|
+
|
21
|
+
def resolve_class(name)
|
22
|
+
resolver&.call(name)
|
23
|
+
end
|
24
|
+
|
25
|
+
def notify?(method_name)
|
26
|
+
handler_class.respond_to?(method_name)
|
27
|
+
end
|
28
|
+
|
29
|
+
def notify_now(handler, mid, *__rest__, &__block__)
|
30
|
+
end; respond_to?(:ruby2_keywords, true) && (ruby2_keywords :notify_now)
|
31
|
+
|
32
|
+
def notify_later(handler, mid, *__rest__, &__block__)
|
33
|
+
end; respond_to?(:ruby2_keywords, true) && (ruby2_keywords :notify_later)
|
34
|
+
|
35
|
+
def notify(mid, *args, params:, sync:, **kwargs)
|
36
|
+
clazz = params.empty? ? handler_class : handler_class.with(**params)
|
37
|
+
sync ? notify_now(clazz, mid, *args, **kwargs) : notify_later(clazz, mid, *args, **kwargs)
|
38
|
+
end
|
39
|
+
|
40
|
+
def handler_class
|
41
|
+
return @handler_class if instance_variable_defined?(:@handler_class)
|
42
|
+
|
43
|
+
return @handler_class = nil if owner.abstract_class?
|
44
|
+
|
45
|
+
@handler_class = resolve_class(owner.name) ||
|
46
|
+
superclass_handler
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def superclass_handler
|
52
|
+
handler_method = "#{id}_class"
|
53
|
+
|
54
|
+
return if owner.superclass == ActiveDelivery::Base
|
55
|
+
return unless owner.superclass.respond_to?(handler_method)
|
56
|
+
|
57
|
+
owner.superclass.public_send(handler_method)
|
58
|
+
end
|
59
|
+
|
60
|
+
attr_reader :resolver
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveDelivery
|
4
|
+
module Lines
|
5
|
+
class Mailer < Base
|
6
|
+
alias_method :mailer_class, :handler_class
|
7
|
+
|
8
|
+
DEFAULT_RESOLVER = ->(name) { name.gsub(/Delivery$/, "Mailer").safe_constantize }
|
9
|
+
|
10
|
+
def notify?(method_name)
|
11
|
+
mailer_class.action_methods.include?(method_name.to_s)
|
12
|
+
end
|
13
|
+
|
14
|
+
def notify_now(mailer, mid, *__rest__, &__block__)
|
15
|
+
mailer.public_send(mid, *__rest__, &__block__).deliver_now
|
16
|
+
end; respond_to?(:ruby2_keywords, true) && (ruby2_keywords :notify_now)
|
17
|
+
|
18
|
+
def notify_later(mailer, mid, *__rest__, &__block__)
|
19
|
+
mailer.public_send(mid, *__rest__, &__block__).deliver_later
|
20
|
+
end; respond_to?(:ruby2_keywords, true) && (ruby2_keywords :notify_later)
|
21
|
+
end
|
22
|
+
|
23
|
+
ActiveDelivery::Base.register_line :mailer, Mailer, resolver: Mailer::DEFAULT_RESOLVER
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveDelivery
|
4
|
+
# Base class for deliveries.
|
5
|
+
#
|
6
|
+
# Delivery object describes how to notify a user about
|
7
|
+
# an event (e.g. via email or via push notification or both).
|
8
|
+
#
|
9
|
+
# Delivery class acts like a proxy in front of the different delivery channels
|
10
|
+
# (i.e. mailers, notifiers). That means that calling a method on delivery class invokes the
|
11
|
+
# same method on the corresponding class, e.g.:
|
12
|
+
#
|
13
|
+
# EventsDelivery.notify(:one_hour_before, profile, event)
|
14
|
+
#
|
15
|
+
# # under the hood it calls
|
16
|
+
# EventsMailer.one_hour_before(profile, event).deliver_later
|
17
|
+
#
|
18
|
+
# # and
|
19
|
+
# EventsNotifier.one_hour_before(profile, event).notify_later
|
20
|
+
#
|
21
|
+
# Delivery also supports _parameterized_ calling:
|
22
|
+
#
|
23
|
+
# EventsDelivery.with(profile: profile).notify(:canceled, event)
|
24
|
+
#
|
25
|
+
# The parameters could be accessed through `params` instance method (e.g.
|
26
|
+
# to implement guard-like logic).
|
27
|
+
#
|
28
|
+
# When params are presents the parametrized mailer is used, i.e.:
|
29
|
+
#
|
30
|
+
# EventsMailer.with(profile: profile).canceled(event)
|
31
|
+
#
|
32
|
+
# See https://api.rubyonrails.org/classes/ActionMailer/Parameterized.html
|
33
|
+
class Base
|
34
|
+
class << self
|
35
|
+
attr_accessor :abstract_class
|
36
|
+
|
37
|
+
alias_method :with, :new
|
38
|
+
|
39
|
+
# Enqueues delivery (i.e. uses #deliver_later for mailers)
|
40
|
+
def notify(...)
|
41
|
+
new.notify(...)
|
42
|
+
end
|
43
|
+
|
44
|
+
# The same as .notify but delivers synchronously
|
45
|
+
# (i.e. #deliver_now for mailers)
|
46
|
+
def notify!(mid, *args, **hargs)
|
47
|
+
notify(mid, *args, **hargs, sync: true)
|
48
|
+
end
|
49
|
+
|
50
|
+
def delivery_lines
|
51
|
+
@lines ||= if superclass.respond_to?(:delivery_lines)
|
52
|
+
superclass.delivery_lines.each_with_object({}) do |(key, val), acc|
|
53
|
+
acc[key] = val.dup_for(self)
|
54
|
+
end
|
55
|
+
else
|
56
|
+
{}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def register_line(line_id, line_class, **options)
|
61
|
+
delivery_lines[line_id] = line_class.new(id: line_id, owner: self, **options)
|
62
|
+
|
63
|
+
instance_eval <<~CODE, __FILE__, __LINE__ + 1
|
64
|
+
def #{line_id}(val)
|
65
|
+
delivery_lines[:#{line_id}].handler_class = val
|
66
|
+
end
|
67
|
+
|
68
|
+
def #{line_id}_class
|
69
|
+
delivery_lines[:#{line_id}].handler_class
|
70
|
+
end
|
71
|
+
CODE
|
72
|
+
end
|
73
|
+
|
74
|
+
def unregister_line(line_id)
|
75
|
+
removed_line = delivery_lines.delete(line_id)
|
76
|
+
|
77
|
+
return if removed_line.nil?
|
78
|
+
|
79
|
+
singleton_class.undef_method line_id
|
80
|
+
singleton_class.undef_method "#{line_id}_class"
|
81
|
+
end
|
82
|
+
|
83
|
+
def abstract_class? = abstract_class == true
|
84
|
+
end
|
85
|
+
|
86
|
+
attr_reader :params, :notification_name
|
87
|
+
|
88
|
+
def initialize(**params)
|
89
|
+
@params = params
|
90
|
+
@params.freeze
|
91
|
+
end
|
92
|
+
|
93
|
+
# Enqueues delivery (i.e. uses #deliver_later for mailers)
|
94
|
+
def notify(mid, ...)
|
95
|
+
@notification_name = mid
|
96
|
+
do_notify(...)
|
97
|
+
end
|
98
|
+
|
99
|
+
# The same as .notify but delivers synchronously
|
100
|
+
# (i.e. #deliver_now for mailers)
|
101
|
+
def notify!(mid, *args, **hargs)
|
102
|
+
notify(mid, *args, **hargs, sync: true)
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def do_notify(*args, sync: false, **kwargs)
|
108
|
+
delivery_lines.each do |type, line|
|
109
|
+
next if line.handler_class.nil?
|
110
|
+
next unless line.notify?(notification_name)
|
111
|
+
|
112
|
+
notify_line(type, *args, params: params, sync: sync, **kwargs)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def notify_line(type, ...)
|
117
|
+
delivery_lines[type].notify(notification_name, ...)
|
118
|
+
end
|
119
|
+
|
120
|
+
def delivery_lines
|
121
|
+
self.class.delivery_lines
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveDelivery
|
4
|
+
module Lines
|
5
|
+
class Base
|
6
|
+
attr_reader :id, :options
|
7
|
+
attr_accessor :owner
|
8
|
+
attr_writer :handler_class
|
9
|
+
|
10
|
+
def initialize(id:, owner:, **options)
|
11
|
+
@id = id
|
12
|
+
@owner = owner
|
13
|
+
@options = options.tap(&:freeze)
|
14
|
+
@resolver = options[:resolver]
|
15
|
+
end
|
16
|
+
|
17
|
+
def dup_for(new_owner)
|
18
|
+
self.class.new(id: id, **options, owner: new_owner)
|
19
|
+
end
|
20
|
+
|
21
|
+
def resolve_class(name)
|
22
|
+
resolver&.call(name)
|
23
|
+
end
|
24
|
+
|
25
|
+
def notify?(method_name)
|
26
|
+
handler_class.respond_to?(method_name)
|
27
|
+
end
|
28
|
+
|
29
|
+
def notify_now(handler, mid, ...)
|
30
|
+
end
|
31
|
+
|
32
|
+
def notify_later(handler, mid, ...)
|
33
|
+
end
|
34
|
+
|
35
|
+
def notify(mid, *args, params:, sync:, **kwargs)
|
36
|
+
clazz = params.empty? ? handler_class : handler_class.with(**params)
|
37
|
+
sync ? notify_now(clazz, mid, *args, **kwargs) : notify_later(clazz, mid, *args, **kwargs)
|
38
|
+
end
|
39
|
+
|
40
|
+
def handler_class
|
41
|
+
return @handler_class if instance_variable_defined?(:@handler_class)
|
42
|
+
|
43
|
+
return @handler_class = nil if owner.abstract_class?
|
44
|
+
|
45
|
+
@handler_class = resolve_class(owner.name) ||
|
46
|
+
superclass_handler
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def superclass_handler
|
52
|
+
handler_method = "#{id}_class"
|
53
|
+
|
54
|
+
return if owner.superclass == ActiveDelivery::Base
|
55
|
+
return unless owner.superclass.respond_to?(handler_method)
|
56
|
+
|
57
|
+
owner.superclass.public_send(handler_method)
|
58
|
+
end
|
59
|
+
|
60
|
+
attr_reader :resolver
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,27 @@
|
|
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, payload)
|
8
|
+
AbstractNotifier::Notification.new(notifier_class.constantize, payload).notify_now
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
DEFAULT_QUEUE = "notifiers"
|
13
|
+
|
14
|
+
attr_reader :job
|
15
|
+
|
16
|
+
def initialize(queue: DEFAULT_QUEUE, job: DeliveryJob)
|
17
|
+
@job = job.set(queue: queue)
|
18
|
+
end
|
19
|
+
|
20
|
+
def enqueue(notifier_class, payload)
|
21
|
+
job.perform_later(notifier_class.name, payload)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
AbstractNotifier.async_adapter ||= :active_job
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AbstractNotifier
|
4
|
+
module AsyncAdapters
|
5
|
+
class << self
|
6
|
+
def lookup(adapter, options = nil)
|
7
|
+
return adapter unless adapter.is_a?(Symbol)
|
8
|
+
|
9
|
+
adapter_class_name = adapter.to_s.split("_").map(&:capitalize).join
|
10
|
+
AsyncAdapters.const_get(adapter_class_name).new(**(options || {}))
|
11
|
+
rescue NameError => e
|
12
|
+
raise e.class, "Notifier async adapter :#{adapter} haven't been found", e.backtrace
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|