hanami-mailer 0.0.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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