idlemailer 1.0.0 → 2.2.0

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