active_delivery 0.4.3 → 1.0.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|