-
Notifications
You must be signed in to change notification settings - Fork 15
/
base.rb
119 lines (101 loc) · 3.19 KB
/
base.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# frozen_string_literal: true
module ActiveDelivery
# Base class for deliveries.
#
# Delivery object describes how to notify a user about
# an event (e.g. via email or via push notification or both).
#
# Delivery class acts like a proxy in front of the different delivery channels
# (i.e. mailers, notifiers). That means that calling a method on delivery class invokes the
# same method on the corresponding class, e.g.:
#
# EventsDelivery.notify(:one_hour_before, profile, event)
#
# # under the hood it calls
# EventsMailer.one_hour_before(profile, event).deliver_later
#
# # and
# EventsNotifier.one_hour_before(profile, event).notify_later
#
# Delivery also supports _parameterized_ calling:
#
# EventsDelivery.with(profile: profile).notify(:canceled, event)
#
# The parameters could be accessed through `params` instance method (e.g.
# to implement guard-like logic).
#
# When params are presents the parametrized mailer is used, i.e.:
#
# EventsMailer.with(profile: profile).canceled(event)
#
# See https://api.rubyonrails.org/classes/ActionMailer/Parameterized.html
class Base
class << self
attr_accessor :abstract_class
alias with new
# Enqueues delivery (i.e. uses #deliver_later for mailers)
def notify(*args)
new.notify(*args)
end
# The same as .notify but delivers synchronously
# (i.e. #deliver_now for mailers)
def notify!(mid, *args, **hargs)
notify(mid, *args, **hargs, sync: true)
end
def delivery_lines
@lines ||= begin
if superclass.respond_to?(:delivery_lines)
superclass.delivery_lines.each_with_object({}) do |(key, val), acc|
acc[key] = val.dup_for(self)
end
else
{}
end
end
end
def register_line(line_id, line_class, **options)
delivery_lines[line_id] = line_class.new(id: line_id, owner: self, **options)
instance_eval <<~CODE, __FILE__, __LINE__ + 1
def #{line_id}(val)
delivery_lines[:#{line_id}].handler_class = val
end
def #{line_id}_class
delivery_lines[:#{line_id}].handler_class
end
CODE
end
def abstract_class?
abstract_class == true
end
end
attr_reader :params, :notification_name
def initialize(**params)
@params = params
@params.freeze
end
# Enqueues delivery (i.e. uses #deliver_later for mailers)
def notify(mid, *args)
@notification_name = mid
do_notify(*args)
end
# The same as .notify but delivers synchronously
# (i.e. #deliver_now for mailers)
def notify!(mid, *args, **hargs)
notify(mid, *args, **hargs, sync: true)
end
private
def do_notify(*args, sync: false)
delivery_lines.each do |type, line|
next if line.handler_class.nil?
next unless line.notify?(notification_name)
notify_line(type, *args, params: params, sync: sync)
end
end
def notify_line(type, *args)
delivery_lines[type].notify(notification_name, *args)
end
def delivery_lines
self.class.delivery_lines
end
end
end