awesomemailer 0.0.1

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.
data/CHANGELOG ADDED
@@ -0,0 +1,3 @@
1
+ 0.0.1
2
+ * Hey look, is that ActionMailer::Base? No? Who is that? HOLY CRAP!
3
+ It's AwesomeMailer::Base!
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'css_parser', '>= 1.2.5'#, :git => 'https://github.com/alexdunae/css_parser.git'
4
+ gem 'hpricot', '>= 0.8'
5
+
6
+ group :test do
7
+ gem 'actionmailer', '>= 3.0'
8
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,54 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ abstract (1.0.0)
5
+ actionmailer (3.0.2)
6
+ actionpack (= 3.0.2)
7
+ mail (~> 2.2.9)
8
+ actionpack (3.0.2)
9
+ activemodel (= 3.0.2)
10
+ activesupport (= 3.0.2)
11
+ builder (~> 2.1.2)
12
+ erubis (~> 2.6.6)
13
+ i18n (~> 0.4.1)
14
+ rack (~> 1.2.1)
15
+ rack-mount (~> 0.6.13)
16
+ rack-test (~> 0.5.6)
17
+ tzinfo (~> 0.3.23)
18
+ activemodel (3.0.2)
19
+ activesupport (= 3.0.2)
20
+ builder (~> 2.1.2)
21
+ i18n (~> 0.4.1)
22
+ activesupport (3.0.2)
23
+ addressable (2.2.6)
24
+ builder (2.1.2)
25
+ css_parser (1.2.5)
26
+ addressable
27
+ erubis (2.6.6)
28
+ abstract (>= 1.0.0)
29
+ hpricot (0.8.5)
30
+ i18n (0.4.2)
31
+ mail (2.2.19)
32
+ activesupport (>= 2.3.6)
33
+ i18n (>= 0.4.0)
34
+ mime-types (~> 1.16)
35
+ treetop (~> 1.4.8)
36
+ mime-types (1.17.2)
37
+ polyglot (0.3.3)
38
+ rack (1.2.5)
39
+ rack-mount (0.6.14)
40
+ rack (>= 1.0.0)
41
+ rack-test (0.5.7)
42
+ rack (>= 1.0)
43
+ treetop (1.4.10)
44
+ polyglot
45
+ polyglot (>= 0.3.1)
46
+ tzinfo (0.3.31)
47
+
48
+ PLATFORMS
49
+ ruby
50
+
51
+ DEPENDENCIES
52
+ actionmailer (>= 3.0)
53
+ css_parser (>= 1.2.5)
54
+ hpricot (>= 0.8)
data/README.md ADDED
@@ -0,0 +1,125 @@
1
+ # AwesomeMailer
2
+
3
+ AwesomeMailer is an ActionMailer extension that supports rad stuff like inline CSS embedded through `stylesheet_link_tag` or just, you know, stylesheets.
4
+
5
+ ## Installation
6
+
7
+ Add this to your Gemfile:
8
+
9
+ gem 'awesome_mailer'
10
+
11
+ Or if you're old-fashioned, do this:
12
+
13
+ gem install awesome_mailer
14
+
15
+ Then `require 'awesome_mailer'` and follow the example below.
16
+
17
+ ## Example
18
+
19
+ Suppose you have the following mailer:
20
+
21
+ class UserMailer < ActionMailer::Base
22
+ def signup(user_id)
23
+ @user = User.find(user_id)
24
+ mail(:to => @user.email, :from => "no-reply@example.com")
25
+ end
26
+ end
27
+
28
+ ... and you have a template `app/views/user_mailer/signup.html.erb`. It might look something like this:
29
+
30
+ <html>
31
+ <%= stylesheet_link_tag 'email' %>
32
+ <body>
33
+ <div id="header"><%= link_to raw(image_tag('logo.png')), root_url %></div>
34
+ <div id="content">
35
+ <p>Welcome to AwesomeMailer, <%= @user.name %>! We think you might be neat.</p>
36
+ </div>
37
+ <div id="footer">
38
+ Copyright &copy 2012 <a href="http://www.delightfulwidgets.com">Delightful Widgets</a>
39
+ </div>
40
+ </body>
41
+ </html>
42
+
43
+ ... and your spreadsheet (email.css) might be kinda like this:
44
+
45
+ body {
46
+ background: #f0f0f0;
47
+ font: 12pt Arial normal;
48
+ }
49
+
50
+ a img {
51
+ border-width: 0;
52
+ }
53
+
54
+ #header {
55
+ border-bottom: 1px solid black;
56
+ margin-bottom: 1em;
57
+ }
58
+
59
+ #content {
60
+ font-family: Helvetica;
61
+ padding: 1em 0;
62
+ }
63
+
64
+ #content p {
65
+ line-height: 1.3em;
66
+ }
67
+
68
+ #footer {
69
+ border-top: 1px dotted orange;
70
+ font-size: 10pt;
71
+ }
72
+
73
+ ... you might be unhappy because most mail viewers couldn't care less that you included a stylesheet. But wait!
74
+ There's ActionMailer! Just change your mailer to look like this:
75
+
76
+ class UserMailer < AwesomeMailer::Base
77
+
78
+ ... and voila! Now your templates will render like this:
79
+
80
+ <html>
81
+ <body style="background: #f0f0f0; font: 12pt Arial normal;">
82
+ <div id="header" style="border-bottom: 1px solid black; margin-bottom: 1em;">
83
+ <a href="http://www.delightfulwidgets.com/">
84
+ <img src="http://www.delightfulwidgets.com/assets/logo.png" style="border-width: 0;" />
85
+ </a>
86
+ </div>
87
+ <div id="content" style="font-family: Helvetica; padding: 1em 0;">
88
+ <p style="line-height: 1.3em;">Welcome to AwesomeMailer, <%= @user.name %>! We think you might be neat.</p>
89
+ </div>
90
+ <div id="footer" style="border-top: 1px dotted orange; font-size: 10pt;">
91
+ Copyright &copy 2012 <a href="http://www.delightfulwidgets.com">Delightful Widgets</a>
92
+ </div>
93
+ </body>
94
+ </html>
95
+
96
+ WOW!
97
+
98
+ ## Additional Features
99
+
100
+ ### @import
101
+
102
+ AwesomeMailer (or really, the library it relies on, CSS parser) is smart enough to load up stylesheets through
103
+ @import statements. So go ahead and add `@import url('global.css')` to email.css, and we'll handle the rest.
104
+
105
+ ### Pseudo-classes
106
+
107
+ AwesomeMailer supports more than just inline styles. If you define pseudo-classes like :hover, :after, etc, it'll
108
+ make sure they get included in a &lt;style&gt; tag in the &lt;head&gt; of your e-mail. Don&#x27;t have a &lt;head&gt;? That&#x27;s cool;
109
+ AwesomeMailer will add one.
110
+
111
+ ### @font-face
112
+
113
+ AwesomeMailer will also load up font-face declarations, if'n you have 'em. That means you can add custom fonts to
114
+ your e-mails the same way you do with your websites, and if your user's mail client supports them, UP they'll go!
115
+
116
+ ## Bugs
117
+ File bugs using the issues tab in Github. **Don't** e-mail me. _Please_.
118
+
119
+ ## LEGAL FUNSIES
120
+
121
+ AwesomeMailer is copyright (c) 2011 Delightful Widgets Inc.
122
+
123
+ It was built by Flip Sasser (flip@x451.com) using libraries from Alex Dunae
124
+ ([https://github.com/alexdunae/css_parser](https://github.com/alexdunae/css_parser)) and, as far as I know, Nick Sieger
125
+ ([https://github.com/hpricot/hpricot](https://github.com/hpricot/hpricot)). Those guys are AWESOME. Be their friends.
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gemspec|
4
+ gemspec.name = "awesomemailer"
5
+ gemspec.summary = "An ActionMailer extension that embeds CSS inline in e-mails"
6
+ gemspec.description = %{
7
+ AwesomeMailer embeds your e-mail CSS inline, allowing you to write e-mail templates without worrying too much about stylesheets
8
+ }
9
+ gemspec.email = "flip@x451.com"
10
+ gemspec.homepage = "http://github.com/Plinq/awesome_mailer"
11
+ gemspec.authors = ["Flip Sasser"]
12
+ end
13
+ rescue LoadError
14
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,4 @@
1
+ require 'autotest/fsevent'
2
+ require 'autotest/growl'
3
+
4
+ Autotest.add_discovery { "rspec2" }
@@ -0,0 +1,54 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "awesomemailer"
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Flip Sasser"]
12
+ s.date = "2012-01-05"
13
+ s.description = "\n AwesomeMailer embeds your e-mail CSS inline, allowing you to write e-mail templates without worrying too much about stylesheets\n "
14
+ s.email = "flip@x451.com"
15
+ s.extra_rdoc_files = [
16
+ "README.md"
17
+ ]
18
+ s.files = [
19
+ "CHANGELOG",
20
+ "Gemfile",
21
+ "Gemfile.lock",
22
+ "README.md",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "autotest/discover.rb",
26
+ "lib/awesome_mailer.rb",
27
+ "lib/awesome_mailer/base.rb",
28
+ "spec/lib/awesome_mailer_spec.rb",
29
+ "spec/spec.opts",
30
+ "spec/spec_helper.rb",
31
+ "spec/support/test_mailer/test_email.html.erb",
32
+ "spec/support/test_mailer/test_email.text.erb"
33
+ ]
34
+ s.homepage = "http://github.com/Plinq/awesome_mailer"
35
+ s.require_paths = ["lib"]
36
+ s.rubygems_version = "1.8.10"
37
+ s.summary = "An ActionMailer extension that embeds CSS inline in e-mails"
38
+
39
+ if s.respond_to? :specification_version then
40
+ s.specification_version = 3
41
+
42
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
43
+ s.add_runtime_dependency(%q<css_parser>, [">= 1.2.5"])
44
+ s.add_runtime_dependency(%q<hpricot>, [">= 0.8"])
45
+ else
46
+ s.add_dependency(%q<css_parser>, [">= 1.2.5"])
47
+ s.add_dependency(%q<hpricot>, [">= 0.8"])
48
+ end
49
+ else
50
+ s.add_dependency(%q<css_parser>, [">= 1.2.5"])
51
+ s.add_dependency(%q<hpricot>, [">= 0.8"])
52
+ end
53
+ end
54
+
@@ -0,0 +1,81 @@
1
+ require 'rubygems'
2
+ require 'action_mailer'
3
+ require 'hpricot'
4
+ require 'css_parser'
5
+
6
+ module AwesomeMailer
7
+ class Base < ActionMailer::Base
8
+ abstract!
9
+
10
+ def render(*arguments)
11
+ html_string = super
12
+ document = Hpricot(html_string)
13
+ stylesheets = document.search('link[@rel=stylesheet]')
14
+ stylesheets.each do |stylesheet|
15
+ if stylesheet['media'] =~ /^(all|handheld|screen)$/ # Must be intended for digital screens!
16
+ apply_stylesheet!(document, stylesheet)
17
+ end
18
+ end
19
+ stylesheets.remove
20
+ document.to_html
21
+ end
22
+
23
+ private
24
+ def append_styles!(document, selector, declarations)
25
+ unless head = document.at('head')
26
+ head = Hpricot::Elem.new('head')
27
+ document.children.unshift(head)
28
+ end
29
+ unless style = head.at('style[@type=text/css]')
30
+ style = Hpricot::Elem.new('style')
31
+ style['type'] = 'text/css'
32
+ style.inner_html = "\n"
33
+ head.children.unshift(style)
34
+ end
35
+ style.inner_html += "#{selector} { #{declarations} }\n"
36
+ end
37
+
38
+ def apply_rules!(document, css_parser, url)
39
+ css_parser.each_selector do |selector, declarations, specificity|
40
+ if url
41
+ # Rewrite relative URLs to match their parent CSS's URL path
42
+ path_url = Addressable::URI.parse(url)
43
+ path_url.path = File.dirname(path_url.path)
44
+ declarations.scan(/(url\(?["']+(.[^'"]*)["']\))/i).each do |url_command, item|
45
+ next if item =~ /^http(s){0,1}:\/\//
46
+ item_url = path_url.dup
47
+ item_url.path = File.join(item_url.path, item)
48
+ new_url_command = url_command.gsub(item, item_url.to_s)
49
+ declarations[url_command] = new_url_command
50
+ end
51
+ else
52
+ declarations.reject {|item| item.match(/url\s*\(/) }
53
+ end
54
+ if selector =~ /(^@)/
55
+ append_styles!(document, selector, declarations.to_s) if url
56
+ elsif selector !~ /:/
57
+ document.search(selector).each do |element|
58
+ element['style'] = [element['style'], *declarations].compact.join(';')
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ def apply_stylesheet!(document, stylesheet)
65
+ css_parser = CssParser::Parser.new
66
+ clean_href = stylesheet['href'].split('?').shift
67
+ url = nil
68
+ case stylesheet['href']
69
+ when /^\/assets/
70
+ dirname = File.dirname(clean_href).split('/').reject(&:blank?)[1..-1]
71
+ css_parser.load_file!(File.join(Rails.root, 'app', 'assets', 'stylesheets', dirname, File.basename(clean_href)))
72
+ when /^\//
73
+ css_parser.load_file!(File.join(Rails.root, 'public', clean_href))
74
+ else
75
+ css_parser.load_uri!(stylesheet['href'])
76
+ url = clean_href
77
+ end
78
+ apply_rules!(document, css_parser, url)
79
+ end
80
+ end
81
+ end
@@ -0,0 +1 @@
1
+ require 'awesome_mailer/base'
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+ require 'awesome_mailer'
3
+
4
+ AwesomeMailer::Base.prepend_view_path 'spec/support'
5
+ AwesomeMailer::Base.config.assets_dir = 'spec/support'
6
+
7
+ class TestMailer < AwesomeMailer::Base
8
+ def test_email(subject = "Hello!")
9
+ mail(
10
+ :from => "flip@x451.com",
11
+ :to => "flip@x451.com",
12
+ :subject => subject
13
+ )
14
+ end
15
+
16
+ def test_multipart_email(subject = "Hello")
17
+ mail(
18
+ :from => "flip@x451.com",
19
+ :to => "flip@x451.com",
20
+ :subject => subject
21
+ ) do |format|
22
+ format.html { render :test_email }
23
+ format.text { render :test_email }
24
+ end
25
+ end
26
+ end
27
+
28
+ describe AwesomeMailer::Base do
29
+ it "should render messages like ActionMailer::Base" do
30
+ TestMailer.test_email("Howdy!").should be_instance_of Mail::Message
31
+ end
32
+
33
+ it "should automatically parse the body of HTML e-mails" do
34
+ raise TestMailer.test_email("Howdy!").html_part.body.inspect
35
+ end
36
+
37
+ it "should automatically parse the body of multipart e-mails" do
38
+ raise TestMailer.test_multipart_email("Howdy!").html_part.body.inspect
39
+ end
40
+ end
41
+
data/spec/spec.opts ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --backtrace
@@ -0,0 +1 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
@@ -0,0 +1,2 @@
1
+ <%= stylesheet_link_tag 'test.css' %>
2
+ <div>welcome!</div>
@@ -0,0 +1 @@
1
+ welcome!
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: awesomemailer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Flip Sasser
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-01-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: css_parser
16
+ requirement: &70279699185020 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.2.5
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70279699185020
25
+ - !ruby/object:Gem::Dependency
26
+ name: hpricot
27
+ requirement: &70279699182000 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0.8'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70279699182000
36
+ description: ! "\n AwesomeMailer embeds your e-mail CSS inline, allowing you
37
+ to write e-mail templates without worrying too much about stylesheets\n "
38
+ email: flip@x451.com
39
+ executables: []
40
+ extensions: []
41
+ extra_rdoc_files:
42
+ - README.md
43
+ files:
44
+ - CHANGELOG
45
+ - Gemfile
46
+ - Gemfile.lock
47
+ - README.md
48
+ - Rakefile
49
+ - VERSION
50
+ - autotest/discover.rb
51
+ - awesomemailer.gemspec
52
+ - lib/awesome_mailer.rb
53
+ - lib/awesome_mailer/base.rb
54
+ - spec/lib/awesome_mailer_spec.rb
55
+ - spec/spec.opts
56
+ - spec/spec_helper.rb
57
+ - spec/support/test_mailer/test_email.html.erb
58
+ - spec/support/test_mailer/test_email.text.erb
59
+ homepage: http://github.com/Plinq/awesome_mailer
60
+ licenses: []
61
+ post_install_message:
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements: []
78
+ rubyforge_project:
79
+ rubygems_version: 1.8.10
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: An ActionMailer extension that embeds CSS inline in e-mails
83
+ test_files: []