idlemailer 1.0.0 → 2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 347bc7e19b8427031ed9246730a710ca7ad8893f
4
- data.tar.gz: 4e44c6a7525787ab0576655f863fa31b5d1359ff
2
+ SHA256:
3
+ metadata.gz: 288e28b5d6f7ac40873806faa8bf56b8e66143a96819be6025238bcbc5fbc239
4
+ data.tar.gz: 76389af5d9027c264ae2cd2ae0f014a184a3bff41204a001d0a9061ef83e223f
5
5
  SHA512:
6
- metadata.gz: 707144b2594688f8b838dc2eb3aa35f553c2f9bc188a0be8f6f812ccc7e801005a1068691ca8cf54d699564037e4a5fe0bb0f8e4c491425915dedc3e2ae8ef28
7
- data.tar.gz: a349486802b1245cf60dd885b85dfbbb74ea266ee077a0ff0f1b366d864fb2004fd7718ecac63d674ce2bf667d8c2f64dced20935c78aae4f9371fd8a1f931e2
6
+ metadata.gz: 294f547d16812a33f260ac1dfd10602de80e62cda27c8bf6d4401745c2b8e75c74fd840103f2bb04552df1bc4da4da6878de8a4bd40ad213301171ba6649c8aa
7
+ data.tar.gz: f86dfb20178f2dbc43826b6ffb1e879009eed952be403be29f41873c2d19d7aa431e2e00b90ae6d1a8ebc58bd2d92a1637c054be7d4fe6f323fdb0443c47a480
data/README.md CHANGED
@@ -1,15 +1,18 @@
1
1
  # IdleMailer
2
2
 
3
- A lightweight (~100 line) alternative to ActionMailer for hipsters who use Ruby but not Rails. Powered by [mail](http://www.rubydoc.info/gems/mail). Great for API-only backends that need to send email.
3
+ A lightweight (~200 line) alternative to ActionMailer for Rubyists who are too cool for Rails. Powered by the [mail](http://www.rubydoc.info/gems/mail) gem. Great for API-only backends that need to send email.
4
4
 
5
5
  ## Installation
6
6
 
7
- $ [sudo] gem install idlemailer
8
- # Or add "idlemailer" to your Gemfile
7
+ Add to your Gemfile.
8
+
9
+ ```ruby
10
+ gem 'idlemailer'
11
+ ```
9
12
 
10
13
  ## Use
11
14
 
12
- IdleMailer is all about providing mailer classes and templates. But [the mail gem](http://www.rubydoc.info/gems/mail) has a great API, so you have unfettered access to it in your mailers through the "mail" object.
15
+ IdleMailer provides mailer classes and templates on top of the [mail](http://www.rubydoc.info/gems/mail) gem. `mail` has a great API, so you have unfettered access to it in your mailers.
13
16
 
14
17
  ```ruby
15
18
  # Define your mailer class
@@ -17,18 +20,58 @@ class WidgetMailer
17
20
  include IdleMailer::Mailer
18
21
 
19
22
  def initialize(user, widget)
23
+ @widget = widget
20
24
  mail.to = user.email
21
25
  mail.subject = "Widget #{widget.sku}"
22
- @widget = widget
26
+ # 'mail' is just a Mail object from the mail gem, so you can use the
27
+ # full Mail api here, e.g. to, subject, attachments, etc.
23
28
  end
24
29
  end
25
30
 
26
- # Create widget.html.erb and/or widget.text.erb templates.
27
- # They'll have access to instance variables like @widget above.
31
+ # Create widget.html.erb and/or widget.text.erb in your templates directory.
32
+ # They'll have access to instance variables like @widget above, as well as any methods you define.
28
33
 
29
34
  # Send your mail
30
- mailer = WidgetMailer.new(current_user, widget)
31
- mailer.deliver
35
+ WidgetMailer.new(current_user, widget).deliver
36
+ ```
37
+
38
+ ### HTML escaping
39
+
40
+ All values will be automatically HTML-escaped. If you need to bypass escapeing, use the `raw` helper:
41
+
42
+ ```ruby
43
+ <%= raw @something_with_safe_html %>
44
+ ```
45
+
46
+ ### Inline templates
47
+
48
+ If you prefer, you can embed your ERB templates right inside your Ruby class, instead of making separate template files. Slick amiright?
49
+
50
+ ```ruby
51
+ class WidgetMailer
52
+ include IdleMailer::Mailer
53
+
54
+ # optionally override the default layout
55
+ self.layout = "widget_layout"
56
+
57
+ def initialize(user, widget)
58
+ @widget = widget
59
+ mail.to = user.email
60
+ mail.subject = "Widget #{widget.sku}"
61
+ end
62
+
63
+ text %(
64
+ A new widget called <%= @widget %> was just created!
65
+
66
+ Thanks!
67
+ )
68
+
69
+ html %(
70
+ <p>A new widget called <%= @widget %> was just created!</p>
71
+
72
+ <p>Thanks!</p>
73
+ )
74
+ end
32
75
  ```
33
76
 
34
77
  ## Configure
@@ -40,7 +83,10 @@ IdleMailer.config do |config|
40
83
  # Directory containing the mailer templates
41
84
  config.templates = Pathname.new(Dir.getwd).join('templates')
42
85
 
43
- # Name of the layout template. Here, the file(s) would be named
86
+ # Pre-cache all templates and layouts (instead of re-loading them on each delivery)
87
+ config.cache_templates = true
88
+
89
+ # Name of the default layout template. Here, the file(s) would be named
44
90
  # mailer_layout.html.erb and/or mailer_layout.text.erb.
45
91
  config.layout = 'mailer_layout'
46
92
 
@@ -73,7 +119,7 @@ end
73
119
 
74
120
  ## Testing
75
121
 
76
- Put the mailer in testing mode:
122
+ Put the mailer into testing mode:
77
123
 
78
124
  ```ruby
79
125
  IdleMailer.config do |config|
@@ -81,10 +127,44 @@ IdleMailer.config do |config|
81
127
  end
82
128
  ```
83
129
 
84
- Then use mail gem's built in testing helpers in your specs:
130
+ Then configure your test runner. Here's an example with RSpec:
131
+
132
+ ```ruby
133
+ RSpec.configure do |config|
134
+ # Clear sent mail after every test
135
+ config.after :each do
136
+ IdleMailer::Testing.clear_mail!
137
+ end
138
+
139
+ # Include the test helpers in your specs
140
+ config.include IdleMailer::Testing::Helpers
141
+ end
142
+ ```
143
+
144
+ Your tests will have access to these helper methods. (Note you can also call them directly on `IdleMailer::Testing` as well)
85
145
 
86
146
  ```ruby
87
- sent = Mail::TestMailer.deliveries.any? { |mail| mail.to.include? @user.email }
147
+ # quick boolean checks
148
+ sent_mail_to? 'user@example.com'
149
+ sent_mail_to? 'user@example.com', /subject/
150
+ sent_mail_to? 'user@example.com', /subject/, /body/
151
+ sent_mail_with_subject? /Foo/
152
+ sent_mail_with_body? /Bar/
153
+ sent_mail_from? 'user@example.com'
154
+
155
+ # get arrays of matching sent mail (Mail::Message objects)
156
+ mail_to 'user@example.com'
157
+ mail_to 'user@example.com', /subject/
158
+ mail_to 'user@example.com', /subject/, /body/
159
+ mail_with_subject /Foo/
160
+ mail_with_body /Bar/
161
+ mail_from 'user@example.com'
162
+
163
+ # get an array of all sent mail
164
+ sent_mail
165
+
166
+ # clear all sent mail
167
+ clear_mail!
88
168
  ```
89
169
 
90
170
  ## License
@@ -1,13 +1,13 @@
1
1
  module IdleMailer
2
2
  # Struct for holding IdleMailer config
3
3
  # templates A Pathname object pointing to the mail templates directory (defaults to ./templates)
4
- # layout Name of layout file, minus extention (defaults to mailer_layout)
4
+ # layout Name of default layout file, minus extention (defaults to mailer_layout)
5
5
  # delivery_method Symbol like :smtp or :test (see the mail gem for all options)
6
6
  # delivery_options Hash of delivery options (see the mail gem for all options)
7
7
  # default_from Default "from" address if it's left blank
8
8
  # logger a Logger object for logging email
9
9
  # log_body if true, the entire message body will be logged (instead of just the headers) (default false)
10
- Config = Struct.new(:templates, :layout, :delivery_method, :delivery_options, :default_from, :logger, :log_body)
10
+ Config = Struct.new(:templates, :layout, :cache_templates, :delivery_method, :delivery_options, :default_from, :logger, :log_body)
11
11
  @config = Config.new
12
12
 
13
13
  # Takes a block and hands it an IdleMailer::Config object
@@ -1,6 +1,7 @@
1
1
  IdleMailer.config do |config|
2
2
  config.templates = Pathname.new(Dir.getwd).join('templates')
3
3
  config.layout = 'mailer_layout'
4
+ config.cache_templates = true
4
5
  config.delivery_method = :smtp
5
6
  config.delivery_options = {
6
7
  user_name: ENV['MAIL_USER'],
@@ -0,0 +1,16 @@
1
+ module IdleMailer
2
+ class HtmlSafeString < String
3
+ def <<(str)
4
+ safe_str = str.is_a?(HtmlSafeString) ? str : ERB::Util.html_escape(str.to_s)
5
+ super safe_str
6
+ end
7
+
8
+ def safe_concat(val)
9
+ self << HtmlSafeString.new(val)
10
+ end
11
+
12
+ def to_s
13
+ self
14
+ end
15
+ end
16
+ end
@@ -4,6 +4,9 @@ module IdleMailer
4
4
  # class WidgetMailer
5
5
  # include IdleMailer::Mailer
6
6
  #
7
+ # # optionally override the default layout
8
+ # self.layout = "widget_layout"
9
+ #
7
10
  # def initialize(address, widget)
8
11
  # mail.to = address
9
12
  # mail.subject = "Widget #{widget.sku}"
@@ -18,6 +21,10 @@ module IdleMailer
18
21
  # mailer.deliver
19
22
  #
20
23
  module Mailer
24
+ def self.included(klass)
25
+ klass.extend TemplateManager
26
+ end
27
+
21
28
  # Deliver mail
22
29
  def deliver
23
30
  mailer = IdleMailer::Message.new(mail, self)
@@ -13,17 +13,19 @@ module IdleMailer
13
13
 
14
14
  # Deliver mail
15
15
  def deliver!
16
- if has_template? 'html'
16
+ if mailer.class.has_template? 'html'
17
17
  html_body = layout('html') { body('html') }
18
18
  mail.html_part do
19
19
  content_type 'text/html; charset=UTF-8'
20
20
  body html_body
21
21
  end
22
22
  end
23
- if has_template? 'text'
23
+
24
+ if mailer.class.has_template? 'text'
24
25
  text_body = layout('text') { body('text') }
25
26
  mail.text_part { body text_body }
26
27
  end
28
+
27
29
  config = IdleMailer.config
28
30
  mail.from config.default_from if mail.from.nil?
29
31
  mail.delivery_method config.delivery_method, config.delivery_options
@@ -35,35 +37,15 @@ module IdleMailer
35
37
  private
36
38
 
37
39
  def body(type)
38
- render template_path(template_name, type)
40
+ render mailer.class.template(type)
39
41
  end
40
42
 
41
43
  def layout(type)
42
- has_layout?(type) ? render(template_path(IdleMailer.config.layout, type)) { yield } : yield
43
- end
44
-
45
- def render(path)
46
- mailer.render(ERB.new(File.read(path))) { yield }
47
- end
48
-
49
- def has_template?(type)
50
- File.exists? template_path(template_name, type)
51
- end
52
-
53
- def has_layout?(type)
54
- File.exists? template_path(IdleMailer.config.layout, type)
55
- end
56
-
57
- def template_name
58
- @name ||= mailer.class.name.
59
- gsub(/::/, File::SEPARATOR).
60
- sub(/Mailer$/, '').
61
- gsub(/([a-z])([A-Z])/, "\\1_\\2").
62
- downcase
44
+ mailer.class.has_layout?(type) ? render(mailer.class.layout(type)) { yield } : yield
63
45
  end
64
46
 
65
- def template_path(name, type)
66
- IdleMailer.config.templates.join("#{name}.#{type}.erb")
47
+ def render(template)
48
+ mailer.render(template) { yield }
67
49
  end
68
50
  end
69
51
  end
@@ -0,0 +1,68 @@
1
+ module IdleMailer
2
+ # Loads a mailer's templates and layouts
3
+ module TemplateManager
4
+ def self.extended(klass)
5
+ klass.class_eval do
6
+ include Templates::Helpers
7
+ class << self
8
+ attr_reader :layouts, :templates
9
+ end
10
+ @custom_layout, @layouts, @templates = nil, {}, {}
11
+ end
12
+ klass.cache_templates! if IdleMailer.config.cache_templates
13
+ end
14
+
15
+ def text(str)
16
+ templates['text'] = Templates.compile str.chomp
17
+ end
18
+
19
+ def html(str)
20
+ templates['html'] = Templates.compile str.chomp
21
+ end
22
+
23
+ def template(type)
24
+ templates[type] || Templates.compile(template_path(template_name, type).read.chomp)
25
+ end
26
+
27
+ def layout(type)
28
+ layouts[type] || Templates.compile(template_path(layout_name, type).read.chomp)
29
+ end
30
+
31
+ def layout=(new_name)
32
+ @custom_layout = new_name
33
+ layouts.clear
34
+ cache_templates! if IdleMailer.config.cache_templates
35
+ end
36
+
37
+ def has_template?(type)
38
+ templates.has_key?(type) || template_path(template_name, type).exist?
39
+ end
40
+
41
+ def has_layout?(type)
42
+ layouts.has_key?(type) || template_path(layout_name, type).exist?
43
+ end
44
+
45
+ def template_name
46
+ @name ||= self.name.
47
+ gsub(/::/, File::SEPARATOR).
48
+ sub(/Mailer$/, '').
49
+ gsub(/([a-z])([A-Z])/, "\\1_\\2").
50
+ downcase
51
+ end
52
+
53
+ def layout_name
54
+ @custom_layout || IdleMailer.config.layout
55
+ end
56
+
57
+ def template_path(name, type)
58
+ IdleMailer.config.templates.join("#{name}.#{type}.erb")
59
+ end
60
+
61
+ def cache_templates!
62
+ layouts['text'] ||= layout 'text' if has_layout? 'text'
63
+ layouts['html'] ||= layout 'html' if has_layout? 'html'
64
+ templates['text'] ||= template 'text' if has_template? 'text'
65
+ templates['html'] ||= template 'html' if has_template? 'html'
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,27 @@
1
+ module IdleMailer
2
+ module Templates
3
+ def self.compile(src)
4
+ compiler = ERB::Compiler.new("<>")
5
+ compiler.pre_cmd = ["_erbout=+HtmlSafeString.new"]
6
+ compiler.put_cmd = "_erbout.safe_concat"
7
+ compiler.insert_cmd = "_erbout.<<"
8
+ compiler.post_cmd = ["_erbout"]
9
+ code, _enc = compiler.compile(src)
10
+ Template.new code.freeze
11
+ end
12
+
13
+ Template = Struct.new(:code) do
14
+ def result(bind)
15
+ _erbout = HtmlSafeString.new
16
+ eval code, bind
17
+ end
18
+ end
19
+
20
+ module Helpers
21
+ # Don't HTML-escape the given value
22
+ def raw(str)
23
+ HtmlSafeString.new(str)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,60 @@
1
+ module IdleMailer
2
+ # Module for testing. You can call all IdleMailer::Testing::Helpers methods directly on this module if you want.
3
+ module Testing
4
+ # Helpers for your tests
5
+ module Helpers
6
+ # Returns true if any mail was sent from the given email address.
7
+ def sent_mail_from?(addr)
8
+ mail_from(addr).any?
9
+ end
10
+
11
+ # Returns true if any mail was sent to the given email address. You may pass subject and body patterns to get more specific (String or Regexp).
12
+ def sent_mail_to?(addr, subject = nil, body = nil)
13
+ mail_to(addr, subject, body).any?
14
+ end
15
+
16
+ # Returns true if any mail was sent matching the given subject (String or Regexp).
17
+ def sent_mail_with_subject?(pattern)
18
+ mail_with_subject(pattern).any?
19
+ end
20
+
21
+ # Returns true if any mail was sent matching the given body (Regexp).
22
+ def sent_mail_with_body?(pattern)
23
+ mail_with_body(pattern).any?
24
+ end
25
+
26
+ # Returns all mail sent from the given email address.
27
+ def mail_from(addr)
28
+ sent_mail.select { |m| m.from.include? addr }
29
+ end
30
+
31
+ # Returns all mail sent to the given email address. You may pass subject and body patterns to get more specific (String or Regexp).
32
+ def mail_to(addr, subject = nil, body = nil)
33
+ sent_mail.select { |m|
34
+ m.to.include?(addr) && (subject.nil? || subject === m.subject) && (body.nil? || body === m.to_s)
35
+ }
36
+ end
37
+
38
+ # Returns all mail sent matching the given subject (String or Regexp).
39
+ def mail_with_subject(pattern)
40
+ sent_mail.select { |m| pattern === m.subject }
41
+ end
42
+
43
+ # Returns all mail sent matching the given body (Regexp).
44
+ def mail_with_body(pattern)
45
+ sent_mail.select { |m| pattern === m.to_s }
46
+ end
47
+
48
+ # Returns all sent mail.
49
+ def sent_mail
50
+ Mail::TestMailer.deliveries
51
+ end
52
+
53
+ # Clears sent mail.
54
+ def clear_mail!
55
+ Mail::TestMailer.deliveries.clear
56
+ end
57
+ end
58
+ extend Helpers
59
+ end
60
+ end
@@ -1,5 +1,5 @@
1
1
  # IdleMailer module
2
2
  module IdleMailer
3
3
  # Version number
4
- VERSION = '1.0.0'
4
+ VERSION = '2.2.0'
5
5
  end
data/lib/idlemailer.rb CHANGED
@@ -1,8 +1,16 @@
1
1
  require 'erb'
2
2
  require 'pathname'
3
3
  require 'mail'
4
+
4
5
  require 'idlemailer/config'
5
6
  require 'idlemailer/defaults'
6
7
  require 'idlemailer/message'
7
8
  require 'idlemailer/mailer'
9
+ require 'idlemailer/template_manager'
10
+ require 'idlemailer/templates'
11
+ require 'idlemailer/html_safe_string'
8
12
  require 'idlemailer/version'
13
+
14
+ module IdleMailer
15
+ autoload :Testing, 'idlemailer/testing'
16
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: idlemailer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jordan Hollinger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-03 00:00:00.000000000 Z
11
+ date: 2021-09-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mail
@@ -36,8 +36,12 @@ files:
36
36
  - lib/idlemailer.rb
37
37
  - lib/idlemailer/config.rb
38
38
  - lib/idlemailer/defaults.rb
39
+ - lib/idlemailer/html_safe_string.rb
39
40
  - lib/idlemailer/mailer.rb
40
41
  - lib/idlemailer/message.rb
42
+ - lib/idlemailer/template_manager.rb
43
+ - lib/idlemailer/templates.rb
44
+ - lib/idlemailer/testing.rb
41
45
  - lib/idlemailer/version.rb
42
46
  homepage: https://github.com/jhollinger/idlemailer
43
47
  licenses: []
@@ -50,17 +54,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
50
54
  requirements:
51
55
  - - ">="
52
56
  - !ruby/object:Gem::Version
53
- version: '0'
57
+ version: 2.0.0
54
58
  required_rubygems_version: !ruby/object:Gem::Requirement
55
59
  requirements:
56
60
  - - ">="
57
61
  - !ruby/object:Gem::Version
58
62
  version: '0'
59
63
  requirements: []
60
- rubyforge_project:
61
- rubygems_version: 2.4.5.1
64
+ rubygems_version: 3.0.3
62
65
  signing_key:
63
66
  specification_version: 4
64
67
  summary: A lightweight alternative to ActionMailer
65
68
  test_files: []
66
- has_rdoc: