hanami-mailer 0.0.0 → 0.2.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.
@@ -0,0 +1,288 @@
1
+ require 'hanami/mailer/rendering/template_name'
2
+ require 'hanami/mailer/rendering/templates_finder'
3
+
4
+ module Hanami
5
+ module Mailer
6
+ # Class level DSL
7
+ #
8
+ # @since 0.1.0
9
+ module Dsl
10
+ # Set the template name IF it differs from the convention.
11
+ #
12
+ # For a given mailer named <tt>Signup::Welcome</tt> it will look for
13
+ # <tt>signup/welcome.*.*</tt> templates under the root directory.
14
+ #
15
+ # If for some reason, we need to specify a different template name, we can
16
+ # use this method.
17
+ #
18
+ # This is part of a DSL, for this reason when this method is called with
19
+ # an argument, it will set the corresponding class variable. When
20
+ # called without, it will return the already set value, or the default.
21
+ #
22
+ # @overload template(value)
23
+ # Sets the given value
24
+ # @param value [String, #to_s] relative template path, under root
25
+ # @return [NilClass]
26
+ #
27
+ # @overload template
28
+ # Gets the template name
29
+ # @return [String]
30
+ #
31
+ # @since 0.1.0
32
+ #
33
+ # @see Hanami::Mailers::Configuration.root
34
+ #
35
+ # @example Custom template name
36
+ # require 'hanami/mailer'
37
+ #
38
+ # class MyMailer
39
+ # include Hanami::Mailer
40
+ # template 'mailer'
41
+ # end
42
+ def template(value = nil)
43
+ if value.nil?
44
+ @template ||= ::Hanami::Mailer::Rendering::TemplateName.new(name, configuration.namespace).to_s
45
+ else
46
+ @template = value
47
+ end
48
+ end
49
+
50
+ # Returns a set of associated templates or only one for the given format
51
+ #
52
+ # This is part of a DSL, for this reason when this method is called with
53
+ # an argument, it will set the corresponding class variable. When
54
+ # called without, it will return the already set value, or the default.
55
+ #
56
+ # @overload templates(format)
57
+ # Returns the template associated with the given format
58
+ # @param value [Symbol] the format
59
+ # @return [Hash]
60
+ #
61
+ # @overload templates
62
+ # Returns all the associated templates
63
+ # Gets the template name
64
+ # @return [Hash] a set of templates
65
+ #
66
+ # @since 0.1.0
67
+ # @api private
68
+ def templates(format = nil)
69
+ if format.nil?
70
+ @templates = ::Hanami::Mailer::Rendering::TemplatesFinder.new(self).find
71
+ else
72
+ @templates.fetch(format, nil)
73
+ end
74
+ end
75
+
76
+ # Sets the sender for mail messages
77
+ #
78
+ # It accepts a hardcoded value as a string, or a symbol that represents
79
+ # an instance method for more complex logic.
80
+ #
81
+ # This value MUST be set, otherwise an exception is raised at the delivery
82
+ # time.
83
+ #
84
+ # When a value is given, specify the sender of the email
85
+ # Otherwise, it returns the sender of the email
86
+ #
87
+ # This is part of a DSL, for this reason when this method is called with
88
+ # an argument, it will set the corresponding class variable. When
89
+ # called without, it will return the already set value, or the default.
90
+ #
91
+ # @overload from(value)
92
+ # Sets the sender
93
+ # @param value [String, Symbol] the hardcoded value or method name
94
+ # @return [NilClass]
95
+ #
96
+ # @overload from
97
+ # Returns the sender
98
+ # @return [String, Symbol] the sender
99
+ #
100
+ # @since 0.1.0
101
+ #
102
+ # @example Hardcoded value (String)
103
+ # require 'hanami/mailer'
104
+ #
105
+ # class WelcomeMailer
106
+ # include Hanami::Mailer
107
+ #
108
+ # from "noreply@example.com"
109
+ # end
110
+ #
111
+ # @example Method (Symbol)
112
+ # require 'hanami/mailer'
113
+ #
114
+ # class WelcomeMailer
115
+ # include Hanami::Mailer
116
+ # from :sender
117
+ #
118
+ # private
119
+ #
120
+ # def sender
121
+ # "noreply@example.com"
122
+ # end
123
+ # end
124
+ def from(value = nil)
125
+ if value.nil?
126
+ @from
127
+ else
128
+ @from = value
129
+ end
130
+ end
131
+
132
+ # Sets the recipient for mail messages
133
+ #
134
+ # It accepts a hardcoded value as a string or array of strings.
135
+ # For dynamic values, you can specify a symbol that represents an instance
136
+ # method.
137
+ #
138
+ # This value MUST be set, otherwise an exception is raised at the delivery
139
+ # time.
140
+ #
141
+ # When a value is given, specify the recipient of the email
142
+ # Otherwise, it returns the recipient of the email
143
+ #
144
+ # This is part of a DSL, for this reason when this method is called with
145
+ # an argument, it will set the corresponding class variable. When
146
+ # called without, it will return the already set value, or the default.
147
+ #
148
+ # @overload to(value)
149
+ # Sets the recipient
150
+ # @param value [String, Array, Symbol] the hardcoded value or method name
151
+ # @return [NilClass]
152
+ #
153
+ # @overload to
154
+ # Returns the recipient
155
+ # @return [String, Array, Symbol] the recipient
156
+ #
157
+ # @since 0.1.0
158
+ #
159
+ # @example Hardcoded value (String)
160
+ # require 'hanami/mailer'
161
+ #
162
+ # class WelcomeMailer
163
+ # include Hanami::Mailer
164
+ #
165
+ # to "user@example.com"
166
+ # end
167
+ #
168
+ # @example Hardcoded value (Array)
169
+ # require 'hanami/mailer'
170
+ #
171
+ # class WelcomeMailer
172
+ # include Hanami::Mailer
173
+ #
174
+ # to ["user-1@example.com", "user-2@example.com"]
175
+ # end
176
+ #
177
+ # @example Method (Symbol)
178
+ # require 'hanami/mailer'
179
+ #
180
+ # class WelcomeMailer
181
+ # include Hanami::Mailer
182
+ # to :email_address
183
+ #
184
+ # private
185
+ #
186
+ # def email_address
187
+ # user.email
188
+ # end
189
+ # end
190
+ #
191
+ # user = User.new(name: 'L')
192
+ # WelcomeMailer.deliver(user: user)
193
+ #
194
+ # @example Method that returns a collection of recipients
195
+ # require 'hanami/mailer'
196
+ #
197
+ # class WelcomeMailer
198
+ # include Hanami::Mailer
199
+ # to :recipients
200
+ #
201
+ # private
202
+ #
203
+ # def recipients
204
+ # users.map(&:email)
205
+ # end
206
+ # end
207
+ #
208
+ # users = [User.new(name: 'L'), User.new(name: 'MG')]
209
+ # WelcomeMailer.deliver(users: users)
210
+ def to(value = nil)
211
+ if value.nil?
212
+ @to
213
+ else
214
+ @to = value
215
+ end
216
+ end
217
+
218
+ # Sets the subject for mail messages
219
+ #
220
+ # It accepts a hardcoded value as a string, or a symbol that represents
221
+ # an instance method for more complex logic.
222
+ #
223
+ # This value MUST be set, otherwise an exception is raised at the delivery
224
+ # time.
225
+ #
226
+ # This is part of a DSL, for this reason when this method is called with
227
+ # an argument, it will set the corresponding class variable. When
228
+ # called without, it will return the already set value, or the default.
229
+ #
230
+ # @overload subject(value)
231
+ # Sets the subject
232
+ # @param value [String, Symbol] the hardcoded value or method name
233
+ # @return [NilClass]
234
+ #
235
+ # @overload subject
236
+ # Returns the subject
237
+ # @return [String, Symbol] the subject
238
+ #
239
+ # @since 0.1.0
240
+ #
241
+ # @example Hardcoded value (String)
242
+ # require 'hanami/mailer'
243
+ #
244
+ # class WelcomeMailer
245
+ # include Hanami::Mailer
246
+ #
247
+ # subject "Welcome"
248
+ # end
249
+ #
250
+ # @example Method (Symbol)
251
+ # require 'hanami/mailer'
252
+ #
253
+ # class WelcomeMailer
254
+ # include Hanami::Mailer
255
+ # subject :greeting
256
+ #
257
+ # private
258
+ #
259
+ # def greeting
260
+ # "Hello, #{ user.name }"
261
+ # end
262
+ # end
263
+ #
264
+ # user = User.new(name: 'L')
265
+ # WelcomeMailer.deliver(user: user)
266
+ def subject(value = nil)
267
+ if value.nil?
268
+ @subject
269
+ else
270
+ @subject = value
271
+ end
272
+ end
273
+
274
+ protected
275
+
276
+ # Loading mechanism hook.
277
+ #
278
+ # @api private
279
+ # @since 0.1.0
280
+ #
281
+ # @see Hanami::Mailer.load!
282
+ def load!
283
+ templates.freeze
284
+ configuration.freeze
285
+ end
286
+ end
287
+ end
288
+ end
@@ -0,0 +1,52 @@
1
+ require 'hanami/utils/string'
2
+
3
+ module Hanami
4
+ module Mailer
5
+ module Rendering
6
+ # @since 0.1.0
7
+ # @api private
8
+ #
9
+ # TODO this is identical to Hanami::View, consider to move into Hanami::Utils
10
+ class TemplateName
11
+ # @since 0.1.0
12
+ # @api private
13
+ NAMESPACE_SEPARATOR = '::'.freeze
14
+
15
+ # @since 0.1.0
16
+ # @api private
17
+ def initialize(name, namespace)
18
+ @name = name
19
+ compile!(namespace)
20
+ end
21
+
22
+ # @since 0.1.0
23
+ # @api private
24
+ def to_s
25
+ @name
26
+ end
27
+
28
+ private
29
+ # @since 0.1.0
30
+ # @api private
31
+ def compile!(namespace)
32
+ tokens(namespace) { |token| replace!(token) }
33
+ @name = Utils::String.new(@name).underscore
34
+ end
35
+
36
+ # @since 0.1.0
37
+ # @api private
38
+ def tokens(namespace)
39
+ namespace.to_s.split(NAMESPACE_SEPARATOR).each do |token|
40
+ yield token
41
+ end
42
+ end
43
+
44
+ # @since 0.1.0
45
+ # @api private
46
+ def replace!(token)
47
+ @name.gsub!(%r{\A#{ token }#{ NAMESPACE_SEPARATOR }}, '')
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,133 @@
1
+ require 'hanami/mailer/template'
2
+
3
+ module Hanami
4
+ module Mailer
5
+ module Rendering
6
+ # Find templates for a mailer
7
+ #
8
+ # @api private
9
+ # @since 0.1.0
10
+ #
11
+ # @see Mailer::Template
12
+ class TemplatesFinder
13
+ # Default format
14
+ #
15
+ # @api private
16
+ # @since 0.1.0
17
+ FORMAT = '*'.freeze
18
+
19
+ # Default template engines
20
+ #
21
+ # @api private
22
+ # @since 0.1.0
23
+ ENGINES = '*'.freeze
24
+
25
+ # Recursive pattern
26
+ #
27
+ # @api private
28
+ # @since 0.1.0
29
+ RECURSIVE = '**'.freeze
30
+
31
+ # Initialize a finder
32
+ #
33
+ # @param mailer [Class] the mailer class
34
+ #
35
+ # @api private
36
+ # @since 0.1.0
37
+ def initialize(mailer)
38
+ @mailer = mailer
39
+ end
40
+
41
+ # Find all the associated templates to the mailer.
42
+ # It recursively looks for templates under the root path of the mailer,
43
+ # that are matching the template name
44
+ #
45
+ # @return [Hash] the templates
46
+ #
47
+ # @api private
48
+ # @since 0.1.0
49
+ #
50
+ # @see Hanami::Mailer::Dsl#root
51
+ # @see Hanami::Mailer::Dsl#templates
52
+ #
53
+ # @example
54
+ # require 'hanami/mailer'
55
+ #
56
+ # module Mailers
57
+ # class Welcome
58
+ # include Hanami::Mailer
59
+ # end
60
+ # end
61
+ #
62
+ # Mailers::Welcome.root # => "/path/to/templates"
63
+ # Mailers::Welcome.templates # => {[:html] => "welcome"}
64
+ #
65
+ # # This mailer has a template:
66
+ # #
67
+ # # "/path/to/templates/welcome.html.erb"
68
+ #
69
+ # Hanami::Mailer::Rendering::TemplatesFinder.new(Mailers::Welcome).find
70
+ # # => [#<Hanami::Mailer::Template:0x007f8a0a86a970 ... @file="/path/to/templates/welcome.html.erb">]
71
+ def find
72
+ templates = Hash.new
73
+ _find.map do |template|
74
+ name = File.basename(template)
75
+ format = (( name.split(".") )[-2]).to_sym
76
+ templates[ format ] = Mailer::Template.new(template)
77
+ end
78
+ templates
79
+ end
80
+
81
+ protected
82
+
83
+ # @api private
84
+ # @since 0.1.0
85
+ def _find(lookup = search_path)
86
+ Dir.glob( "#{ [root, lookup, template_name].join(separator) }.#{ format }.#{ engines }" )
87
+ end
88
+
89
+ # @api private
90
+ # @since 0.1.0
91
+ def template_name
92
+ Rendering::TemplateName.new(@mailer.template, @mailer.configuration.namespace).to_s
93
+ end
94
+
95
+ # @api private
96
+ # @since 0.1.0
97
+ def root
98
+ @mailer.configuration.root
99
+ end
100
+
101
+ # @api private
102
+ # @since 0.1.0
103
+ def search_path
104
+ recursive
105
+ end
106
+
107
+ # @api private
108
+ # @since 0.1.0
109
+ def recursive
110
+ RECURSIVE
111
+ end
112
+
113
+ # @api private
114
+ # @since 0.1.0
115
+ def separator
116
+ ::File::SEPARATOR
117
+ end
118
+
119
+ # @api private
120
+ # @since 0.1.0
121
+ def format
122
+ FORMAT
123
+ end
124
+
125
+ # @api private
126
+ # @since 0.1.0
127
+ def engines
128
+ ENGINES
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end