lotus-mailer 0.0.0 → 0.1.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,307 @@
1
+ require 'set'
2
+ require 'lotus/utils/kernel'
3
+
4
+ module Lotus
5
+ module Mailer
6
+ # Framework configuration
7
+ #
8
+ # @since 0.1.0
9
+ class Configuration
10
+ # Default root
11
+ #
12
+ # @since 0.1.0
13
+ # @api private
14
+ DEFAULT_ROOT = '.'.freeze
15
+
16
+ # Default delivery method
17
+ #
18
+ # @since 0.1.0
19
+ # @api private
20
+ DEFAULT_DELIVERY_METHOD = :smtp
21
+
22
+ # Default charset
23
+ #
24
+ # @since 0.1.0
25
+ # @api private
26
+ DEFAULT_CHARSET = 'UTF-8'.freeze
27
+
28
+ # @since 0.1.0
29
+ # @api private
30
+ attr_reader :mailers
31
+
32
+ # @since 0.1.0
33
+ # @api private
34
+ attr_reader :modules
35
+
36
+ # Initialize a configuration instance
37
+ #
38
+ # @return [Lotus::Mailer::Configuration] a new configuration's instance
39
+ #
40
+ # @since 0.1.0
41
+ def initialize
42
+ @namespace = Object
43
+ reset!
44
+ end
45
+
46
+ # Set the Ruby namespace where to lookup for mailers.
47
+ #
48
+ # When multiple instances of the framework are used, we want to make sure
49
+ # that if a `MyApp` wants a `Mailers::Signup` mailer, we are loading the
50
+ # right one.
51
+ #
52
+ # If not set, this value defaults to `Object`.
53
+ #
54
+ # This is part of a DSL, for this reason when this method is called with
55
+ # an argument, it will set the corresponding instance variable. When
56
+ # called without, it will return the already set value, or the default.
57
+ #
58
+ # @overload namespace(value)
59
+ # Sets the given value
60
+ # @param value [Class, Module, String] a valid Ruby namespace identifier
61
+ #
62
+ # @overload namespace
63
+ # Gets the value
64
+ # @return [Class, Module, String]
65
+ #
66
+ # @api private
67
+ # @since 0.1.0
68
+ #
69
+ # @example Getting the value
70
+ # require 'lotus/mailer'
71
+ #
72
+ # Lotus::Mailer.configuration.namespace # => Object
73
+ #
74
+ # @example Setting the value
75
+ # require 'lotus/mailer'
76
+ #
77
+ # Lotus::Mailer.configure do
78
+ # namespace 'MyApp::Mailers'
79
+ # end
80
+ def namespace(value = nil)
81
+ if value
82
+ @namespace = value
83
+ else
84
+ @namespace
85
+ end
86
+ end
87
+
88
+ # Set the root path where to search for templates
89
+ #
90
+ # If not set, this value defaults to the current directory.
91
+ #
92
+ # When this method is called with an argument, it will set the corresponding instance variable.
93
+ # When called without, it will return the already set value, or the default.
94
+ #
95
+ # @overload root(value)
96
+ # Sets the given value
97
+ # @param value [String, Pathname, #to_pathname] an object that can be
98
+ # coerced to Pathname
99
+ #
100
+ # @overload root
101
+ # Gets the value
102
+ # @return [Pathname]
103
+ #
104
+ # @since 0.1.0
105
+ #
106
+ # @see http://www.ruby-doc.org/stdlib/libdoc/pathname/rdoc/Pathname.html
107
+ # @see http://rdoc.info/gems/lotus-utils/Lotus/Utils/Kernel#Pathname-class_method
108
+ #
109
+ # @example Getting the value
110
+ # require 'lotus/mailer'
111
+ #
112
+ # Lotus::Mailer.configuration.root # => #<Pathname:.>
113
+ #
114
+ # @example Setting the value
115
+ # require 'lotus/mailer'
116
+ #
117
+ # Lotus::Mailer.configure do
118
+ # root '/path/to/templates'
119
+ # end
120
+ #
121
+ # Lotus::Mailer.configuration.root # => #<Pathname:/path/to/templates>
122
+ def root(value = nil)
123
+ if value
124
+ @root = Utils::Kernel.Pathname(value).realpath
125
+ else
126
+ @root
127
+ end
128
+ end
129
+
130
+ # Prepare the mailers.
131
+ #
132
+ # The given block will be yielded when `Lotus::Mailer` will be included by
133
+ # a mailer.
134
+ #
135
+ # This method can be called multiple times.
136
+ #
137
+ # @param blk [Proc] the code block
138
+ #
139
+ # @return [void]
140
+ #
141
+ # @raise [ArgumentError] if called without passing a block
142
+ #
143
+ # @since 0.1.0
144
+ #
145
+ # @see Lotus::Mailer.configure
146
+ def prepare(&blk)
147
+ if block_given?
148
+ @modules.push(blk)
149
+ else
150
+ raise ArgumentError.new('Please provide a block')
151
+ end
152
+ end
153
+
154
+ # Add a mailer to the registry
155
+ #
156
+ # @since 0.1.0
157
+ # @api private
158
+ def add_mailer(mailer)
159
+ @mailers.add(mailer)
160
+ end
161
+
162
+ # Duplicate by copying the settings in a new instance.
163
+ #
164
+ # @return [Lotus::Mailer::Configuration] a copy of the configuration
165
+ #
166
+ # @since 0.1.0
167
+ # @api private
168
+ def duplicate
169
+ Configuration.new.tap do |c|
170
+ c.namespace = namespace
171
+ c.root = root.dup
172
+ c.modules = modules.dup
173
+ c.delivery_method = delivery_method
174
+ c.default_charset = default_charset
175
+ end
176
+ end
177
+
178
+ # Load the configuration
179
+ def load!
180
+ mailers.each { |m| m.__send__(:load!) }
181
+ freeze
182
+ end
183
+
184
+ # Reset the configuration
185
+ def reset!
186
+ root(DEFAULT_ROOT)
187
+ delivery_method(DEFAULT_DELIVERY_METHOD)
188
+ default_charset(DEFAULT_CHARSET)
189
+
190
+ @mailers = Set.new
191
+ @modules = []
192
+ end
193
+
194
+ alias_method :unload!, :reset!
195
+
196
+ # Copy the configuration for the given mailer
197
+ #
198
+ # @param base [Class] the target mailer
199
+ #
200
+ # @return void
201
+ #
202
+ # @since 0.1.0
203
+ # @api private
204
+ def copy!(base)
205
+ modules.each do |mod|
206
+ base.class_eval(&mod)
207
+ end
208
+ end
209
+
210
+ # Specify a global delivery method for the mail gateway.
211
+ #
212
+ # It supports the following delivery methods:
213
+ #
214
+ # * Exim (<tt>:exim</tt>)
215
+ # * Sendmail (<tt>:sendmail</tt>)
216
+ # * SMTP (<tt>:smtp</tt>, for local installations)
217
+ # * SMTP Connection (<tt>:smtp_connection</tt>,
218
+ # via <tt>Net::SMTP</tt> - for remote installations)
219
+ # * Test (<tt>:test</tt>, for testing purposes)
220
+ #
221
+ # The default delivery method is SMTP (<tt>:smtp</tt>).
222
+ #
223
+ # Custom delivery methods can be specified by passing the class policy and
224
+ # a set of optional configurations. This class MUST respond to:
225
+ #
226
+ # * <tt>initialize(options = {})</tt>
227
+ # * <tt>deliver!(mail)<tt>
228
+ #
229
+ # @param method [Symbol, #initialize, deliver!] delivery method
230
+ # @param options [Hash] optional settings
231
+ #
232
+ # @return [Array] an array containing the delivery method and the optional settings as an Hash
233
+ #
234
+ # @since 0.1.0
235
+ #
236
+ # @example Setup delivery method with supported symbol
237
+ # require 'lotus/mailer'
238
+ #
239
+ # Lotus::Mailer.configure do
240
+ # delivery_method :sendmail
241
+ # end
242
+ #
243
+ # @example Setup delivery method with supported symbol and options
244
+ # require 'lotus/mailer'
245
+ #
246
+ # Lotus::Mailer.configure do
247
+ # delivery_method :smtp, address: "localhost", port: 1025
248
+ # end
249
+ #
250
+ # @example Setup custom delivery method with options
251
+ # require 'lotus/mailer'
252
+ #
253
+ # class MandrillDeliveryMethod
254
+ # def initialize(options)
255
+ # @options = options
256
+ # end
257
+ #
258
+ # def deliver!(mail)
259
+ # # ...
260
+ # end
261
+ # end
262
+ #
263
+ # Lotus::Mailer.configure do
264
+ # delivery_method MandrillDeliveryMethod,
265
+ # username: ENV['MANDRILL_USERNAME'],
266
+ # password: ENV['MANDRILL_API_KEY']
267
+ # end
268
+ def delivery_method(method = nil, options = {})
269
+ if method.nil?
270
+ @delivery_method
271
+ else
272
+ @delivery_method = [method, options]
273
+ end
274
+ end
275
+
276
+ # @since 0.1.0
277
+ def default_charset(value = nil)
278
+ if value.nil?
279
+ @default_charset
280
+ else
281
+ @default_charset = value
282
+ end
283
+ end
284
+
285
+ protected
286
+ # @api private
287
+ # @since 0.1.0
288
+ attr_writer :root
289
+
290
+ # @api private
291
+ # @since 0.1.0
292
+ attr_writer :delivery_method
293
+
294
+ # @api private
295
+ # @since 0.1.0
296
+ attr_writer :default_charset
297
+
298
+ # @api private
299
+ # @since 0.1.0
300
+ attr_writer :namespace
301
+
302
+ # @api private
303
+ # @since 0.1.0
304
+ attr_writer :modules
305
+ end
306
+ end
307
+ end
@@ -0,0 +1,288 @@
1
+ require 'lotus/mailer/rendering/template_name'
2
+ require 'lotus/mailer/rendering/templates_finder'
3
+
4
+ module Lotus
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 Lotus::Mailers::Configuration.root
34
+ #
35
+ # @example Custom template name
36
+ # require 'lotus/mailer'
37
+ #
38
+ # class MyMailer
39
+ # include Lotus::Mailer
40
+ # template 'mailer'
41
+ # end
42
+ def template(value = nil)
43
+ if value.nil?
44
+ @template ||= ::Lotus::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 = ::Lotus::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 'lotus/mailer'
104
+ #
105
+ # class WelcomeMailer
106
+ # include Lotus::Mailer
107
+ #
108
+ # from "noreply@example.com"
109
+ # end
110
+ #
111
+ # @example Method (Symbol)
112
+ # require 'lotus/mailer'
113
+ #
114
+ # class WelcomeMailer
115
+ # include Lotus::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 'lotus/mailer'
161
+ #
162
+ # class WelcomeMailer
163
+ # include Lotus::Mailer
164
+ #
165
+ # to "user@example.com"
166
+ # end
167
+ #
168
+ # @example Hardcoded value (Array)
169
+ # require 'lotus/mailer'
170
+ #
171
+ # class WelcomeMailer
172
+ # include Lotus::Mailer
173
+ #
174
+ # to ["user-1@example.com", "user-2@example.com"]
175
+ # end
176
+ #
177
+ # @example Method (Symbol)
178
+ # require 'lotus/mailer'
179
+ #
180
+ # class WelcomeMailer
181
+ # include Lotus::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 'lotus/mailer'
196
+ #
197
+ # class WelcomeMailer
198
+ # include Lotus::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 'lotus/mailer'
243
+ #
244
+ # class WelcomeMailer
245
+ # include Lotus::Mailer
246
+ #
247
+ # subject "Welcome"
248
+ # end
249
+ #
250
+ # @example Method (Symbol)
251
+ # require 'lotus/mailer'
252
+ #
253
+ # class WelcomeMailer
254
+ # include Lotus::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 Lotus::Mailer.load!
282
+ def load!
283
+ templates.freeze
284
+ configuration.freeze
285
+ end
286
+ end
287
+ end
288
+ end