html_email_creator 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +49 -0
- data/README.markdown +5 -0
- data/Rakefile +7 -0
- data/bin/html_email_creator +35 -0
- data/html_email_creator.gemspec +41 -0
- data/lib/html_email_creator/email.rb +93 -0
- data/lib/html_email_creator/email_creator.rb +45 -0
- data/lib/html_email_creator/email_version.rb +26 -0
- data/lib/html_email_creator/extensions.rb +46 -0
- data/lib/html_email_creator/filters.rb +9 -0
- data/lib/html_email_creator/formatter.rb +30 -0
- data/lib/html_email_creator/formatters/formatter.rb +31 -0
- data/lib/html_email_creator/formatters/html_email.rb +24 -0
- data/lib/html_email_creator/formatters/markdown.rb +24 -0
- data/lib/html_email_creator/formatters/plain_text_email.rb +22 -0
- data/lib/html_email_creator/formatters/unknown_formatter.rb +17 -0
- data/lib/html_email_creator/helper.rb +25 -0
- data/lib/html_email_creator/information.rb +4 -0
- data/lib/html_email_creator/layout.rb +15 -0
- data/lib/html_email_creator/processor.rb +125 -0
- data/lib/html_email_creator/settings.rb +95 -0
- data/lib/html_email_creator/tags/include_tag.rb +71 -0
- data/lib/html_email_creator/version.rb +3 -0
- data/lib/html_email_creator.rb +46 -0
- data/spec/fixtures/complex_with_config/.html_config.yaml +11 -0
- data/spec/fixtures/complex_with_config/Emails/polite_email.yaml +7 -0
- data/spec/fixtures/complex_with_config/Includes/Emails/love.md +1 -0
- data/spec/fixtures/complex_with_config/Includes/Footers/polite.md +3 -0
- data/spec/fixtures/complex_with_config/Layouts/.keep +0 -0
- data/spec/fixtures/complex_with_config/Layouts/basic.liquid +25 -0
- data/spec/fixtures/complex_with_config/Output/.keep +0 -0
- data/spec/fixtures/default_config/Emails/Newsletter/.keep +0 -0
- data/spec/fixtures/default_config/Layouts/.keep +0 -0
- data/spec/fixtures/default_config/Output/.keep +0 -0
- data/spec/fixtures/with_config/.html_config.yaml +11 -0
- data/spec/fixtures/with_config/Emails/first_email.yaml +7 -0
- data/spec/fixtures/with_config/Includes/Emails/barfoo.md +1 -0
- data/spec/fixtures/with_config/Includes/Emails/foobar.md +1 -0
- data/spec/fixtures/with_config/Includes/Quotes/henry_ford.txt +1 -0
- data/spec/fixtures/with_config/Layouts/.keep +0 -0
- data/spec/fixtures/with_config/Layouts/simple.liquid +7 -0
- data/spec/fixtures/with_config/Output/.keep +0 -0
- data/spec/html_email_creator/email_creator_spec.rb +119 -0
- data/spec/html_email_creator/email_spec.rb +29 -0
- data/spec/html_email_creator/formatter_spec.rb +40 -0
- data/spec/html_email_creator/layout_spec.rb +55 -0
- data/spec/html_email_creator/processor_spec.rb +111 -0
- data/spec/html_email_creator/settings_spec.rb +70 -0
- data/spec/html_email_creator/tags/include_tag_spec.rb +11 -0
- data/spec/spec_helper.rb +32 -0
- metadata +244 -0
@@ -0,0 +1 @@
|
|
1
|
+
I really love {{ what }}. {{ great }}
|
File without changes
|
@@ -0,0 +1,25 @@
|
|
1
|
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
5
|
+
<title>{{ title_content }}</title>
|
6
|
+
</head>
|
7
|
+
<body>
|
8
|
+
|
9
|
+
<style type="text/css">
|
10
|
+
.h1 div{font-family:Helvetica}
|
11
|
+
ul{margin: 5px 5px 5px 5px}
|
12
|
+
</style>
|
13
|
+
|
14
|
+
<h1>Header 1 starts</h1>
|
15
|
+
|
16
|
+
Hi {{ full_name }},
|
17
|
+
|
18
|
+
{{ header_1_content }}
|
19
|
+
|
20
|
+
<h2>Header 2 starts</h2>
|
21
|
+
|
22
|
+
{{ header_2_content }}
|
23
|
+
|
24
|
+
</body>
|
25
|
+
</html>
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
bar foo
|
@@ -0,0 +1 @@
|
|
1
|
+
foo bar
|
@@ -0,0 +1 @@
|
|
1
|
+
A bore is a person who opens his {{ what }} and puts his feats in it.
|
File without changes
|
File without changes
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
describe HtmlEmailCreator::EmailCreator do
|
4
|
+
let(:creator) { HtmlEmailCreator::EmailCreator.new }
|
5
|
+
let(:email) { fixture_dir("complex_with_config", "Emails", "polite_email.yaml") }
|
6
|
+
let(:expected_basic_text_html) {
|
7
|
+
html = <<eos
|
8
|
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
9
|
+
<html>
|
10
|
+
<head>
|
11
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
12
|
+
<title>A variant</title>
|
13
|
+
</head>
|
14
|
+
<body>
|
15
|
+
|
16
|
+
<div class="h1"><div style="font-family: Helvetica;">Header 1 starts</div></div>
|
17
|
+
|
18
|
+
Hi {!name_fix},
|
19
|
+
|
20
|
+
**Logo**: WOHOO.
|
21
|
+
|
22
|
+
<div class="h2"><div>Header 2 starts</div></div>
|
23
|
+
|
24
|
+
<p>I really love iPhone. GREAT!</p>
|
25
|
+
|
26
|
+
</body>
|
27
|
+
</html>
|
28
|
+
eos
|
29
|
+
}
|
30
|
+
|
31
|
+
let(:expected_basic_text_txt) {
|
32
|
+
text = <<eos
|
33
|
+
=============================================================================
|
34
|
+
Header 1 starts
|
35
|
+
|
36
|
+
Hi {!name_fix},
|
37
|
+
|
38
|
+
**Logo**: WOHOO.
|
39
|
+
|
40
|
+
-----------------------------------------------------------------------------
|
41
|
+
Header 2 starts
|
42
|
+
|
43
|
+
I really love iPhone. GREAT!
|
44
|
+
eos
|
45
|
+
text.strip
|
46
|
+
}
|
47
|
+
|
48
|
+
let(:expected_first_html) {
|
49
|
+
html = <<eos
|
50
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
|
51
|
+
<html><body>
|
52
|
+
<p>This is simple template.
|
53
|
+
|
54
|
+
</p>
|
55
|
+
<p>foo bar</p>
|
56
|
+
|
57
|
+
<p>bar foo</p>
|
58
|
+
|
59
|
+
<img src="http://cdn.example.com/foo/bar" alt="alt text" border="0">
|
60
|
+
</body></html>
|
61
|
+
eos
|
62
|
+
}
|
63
|
+
|
64
|
+
let(:expected_first_txt) {
|
65
|
+
text = <<eos
|
66
|
+
This is simple template.
|
67
|
+
|
68
|
+
foo bar
|
69
|
+
|
70
|
+
bar foo
|
71
|
+
|
72
|
+
alt text (http://cdn.example.com/foo/bar)
|
73
|
+
eos
|
74
|
+
text.strip
|
75
|
+
}
|
76
|
+
|
77
|
+
describe "HTML mail" do
|
78
|
+
it "should create well formed and expected HTML mail" do
|
79
|
+
creator.create_html_email(email).get.should == expected_basic_text_html
|
80
|
+
creator.create_email(email, HtmlEmailCreator::Formatters::HtmlEmail.id).get.should == expected_basic_text_html
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "Plain text mail" do
|
85
|
+
it "should create well formed and expected plain text email" do
|
86
|
+
creator.create_plain_text_email(email).get.should == expected_basic_text_txt
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "Saving email to a filesystem" do
|
91
|
+
after(:each) { clean_fixture_output }
|
92
|
+
|
93
|
+
it "should be possible to store emails recursively" do
|
94
|
+
creator.save_emails(".").should be_empty
|
95
|
+
creator.save_emails(".", true).should_not be_empty
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should store all correct versions of emails recursively" do
|
99
|
+
emails = creator.save_emails(".", true)
|
100
|
+
|
101
|
+
read_fixture("complex_with_config", "Output", "basic_text.html").should == expected_basic_text_html
|
102
|
+
read_fixture("complex_with_config", "Output", "basic_text.txt").should == expected_basic_text_txt
|
103
|
+
read_fixture("with_config", "Output", "first.html").should == expected_first_html
|
104
|
+
read_fixture("with_config", "Output", "first.txt").should == expected_first_txt
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should store only one file if needed using absolute paths" do
|
108
|
+
IO.read(creator.create_html_email(fixture_dir("complex_with_config", "Emails", "polite_email.yaml")).save).should == expected_basic_text_html
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should store only one file if needed using relative paths" do
|
112
|
+
run_in_fixture_dir("complex_with_config") do
|
113
|
+
email_creator = HtmlEmailCreator::EmailCreator.new
|
114
|
+
IO.read(email_creator.create_html_email(File.join("Emails", "polite_email.yaml")).save).should == expected_basic_text_html
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
describe HtmlEmailCreator::Email do
|
4
|
+
let(:email) {
|
5
|
+
HtmlEmailCreator::Email.new(fixture_dir("with_config", "Emails", "first_email.yaml")).render_only(:html_email)
|
6
|
+
}
|
7
|
+
|
8
|
+
let(:expected_html) {
|
9
|
+
html = <<eos
|
10
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
|
11
|
+
<html><body>
|
12
|
+
<p>This is simple template.
|
13
|
+
|
14
|
+
</p>
|
15
|
+
<p>foo bar</p>
|
16
|
+
|
17
|
+
<p>bar foo</p>
|
18
|
+
|
19
|
+
<img src="http://cdn.example.com/foo/bar" alt="alt text" border="0">
|
20
|
+
</body></html>
|
21
|
+
eos
|
22
|
+
}
|
23
|
+
|
24
|
+
it "should render markdown and liquid templates using settings and email configuration" do
|
25
|
+
run_in_fixture_dir("with_config") do
|
26
|
+
email.get.should eql(expected_html)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
describe HtmlEmailCreator::Formatter do
|
4
|
+
describe "Markdown" do
|
5
|
+
let(:md) { HtmlEmailCreator::Formatters::Markdown.id }
|
6
|
+
|
7
|
+
it "should convert correctly" do
|
8
|
+
HtmlEmailCreator::Formatter.new("**I am strong**").find(md).format.should eql("<p><strong>I am strong</strong></p>")
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should support table extension" do
|
12
|
+
markdown = <<-eos
|
13
|
+
| First | Second | Third |
|
14
|
+
|:------|:-------|:------|
|
15
|
+
| 1 | 2 | 3 |
|
16
|
+
eos
|
17
|
+
|
18
|
+
html = <<eos
|
19
|
+
<table>
|
20
|
+
<thead>
|
21
|
+
<tr>
|
22
|
+
<th style="text-align: left">First</th>
|
23
|
+
<th style="text-align: left">Second</th>
|
24
|
+
<th style="text-align: left">Third</th>
|
25
|
+
</tr>
|
26
|
+
</thead>
|
27
|
+
<tbody>
|
28
|
+
<tr>
|
29
|
+
<td style="text-align: left">1</td>
|
30
|
+
<td style="text-align: left">2</td>
|
31
|
+
<td style="text-align: left">3</td>
|
32
|
+
</tr>
|
33
|
+
</tbody>
|
34
|
+
</table>
|
35
|
+
eos
|
36
|
+
|
37
|
+
HtmlEmailCreator::Formatter.new(markdown).find(md).format.should eql(html.strip)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
describe HtmlEmailCreator::Layout do
|
4
|
+
|
5
|
+
describe "with custom variables" do
|
6
|
+
it "should replace variables" do
|
7
|
+
HtmlEmailCreator::Layout.new("foo {{ bar }}").to_html("bar" => "great bar").should eql("foo great bar")
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should just ignore the variable if the variable was not found" do
|
11
|
+
HtmlEmailCreator::Layout.new("foo {{ bar }}").to_html.should eql("foo ")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "with built-in extensions" do
|
16
|
+
|
17
|
+
describe "aweber" do
|
18
|
+
let(:aweber) { HtmlEmailCreator::Extensions.new.built_in("aweber") }
|
19
|
+
let(:none) { {} }
|
20
|
+
|
21
|
+
it "should replace Aweber extension keys correctly if aweber extension is being used" do
|
22
|
+
HtmlEmailCreator::Layout.new("{{ after_7_days }}", aweber).to_html.should eql('{!date dayname+7}')
|
23
|
+
HtmlEmailCreator::Layout.new("{{ after_7_days }}", none).to_html.should eql('')
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should replace Aweber extension keys correctly if aweber extension is being used in settings" do
|
27
|
+
run_in_fixture_dir("with_config") do
|
28
|
+
HtmlEmailCreator::Layout.new("{{ after_7_days }}").to_html.should eql('{!date dayname+7}')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "with custom extensions" do
|
35
|
+
|
36
|
+
it "should replace custom extension keys correctly use custom extensions from configuration to render the layout" do
|
37
|
+
run_in_fixture_dir("with_config") do
|
38
|
+
HtmlEmailCreator::Layout.new("{{ foobar }}").to_html.should eql('Hi, this is foobar.')
|
39
|
+
HtmlEmailCreator::Layout.new("{{ great }}").to_html.should eql('Hi, this is **great**')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "with built-in filters" do
|
46
|
+
|
47
|
+
it "should generate photo url correctly" do
|
48
|
+
run_in_fixture_dir("with_config") do
|
49
|
+
markdown = '{{ "hello/world.jpg" | photo: "Custom alt text" }}'
|
50
|
+
output = '<img src="http://cdn.example.com/hello/world.jpg" alt="Custom alt text" border="0" />'
|
51
|
+
HtmlEmailCreator::Layout.new(markdown).to_html.should eql(output)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
describe HtmlEmailCreator::Processor do
|
4
|
+
|
5
|
+
let(:processor) {
|
6
|
+
html = <<-eos
|
7
|
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
8
|
+
<html>
|
9
|
+
<head>
|
10
|
+
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
11
|
+
<title>Title</title>
|
12
|
+
</head>
|
13
|
+
<body>
|
14
|
+
|
15
|
+
<style type="text/css">
|
16
|
+
.h1 div{font-family:Helvetica}
|
17
|
+
ul{margin: 5px 5px 5px 5px}
|
18
|
+
</style>
|
19
|
+
|
20
|
+
<h1>Header 1</h1>
|
21
|
+
|
22
|
+
<table class="inline">
|
23
|
+
<tr><td>col1</td><td>col2</td>
|
24
|
+
<tr><td>row 1 col 1</td><td>row 1 col 2</td>
|
25
|
+
<tr><td>row 2 col 1</td><td>row 2 col 2</td>
|
26
|
+
</table>
|
27
|
+
|
28
|
+
This is simple email with <a href="http://link1.com">link</a>
|
29
|
+
|
30
|
+
<p><img src="http://cdn.example.com/foo/bar" alt="Great image" border="0" /></p>
|
31
|
+
|
32
|
+
<p><a href="http://signup"><img src="http://cdn.example.com/foo/bar" alt="Signup" border="0" /></a></p>
|
33
|
+
|
34
|
+
<h2>Header 2</h2>
|
35
|
+
|
36
|
+
<ul>
|
37
|
+
<li>list 1</li>
|
38
|
+
<li>list 2</li>
|
39
|
+
</ul>
|
40
|
+
</body>
|
41
|
+
</html>
|
42
|
+
eos
|
43
|
+
|
44
|
+
HtmlEmailCreator::Processor.new(html)
|
45
|
+
}
|
46
|
+
|
47
|
+
describe "#to_html" do
|
48
|
+
let(:html) { processor.to_html }
|
49
|
+
|
50
|
+
it "should wrap headers with divs" do
|
51
|
+
html.should include('<div class="h1"><div style="font-family: Helvetica;">Header 1</div></div>')
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should inline styles" do
|
55
|
+
html.should include('<ul style="margin: 5px 5px 5px 5px;">')
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "#to_plain_text" do
|
61
|
+
let(:text) { processor.to_plain_text }
|
62
|
+
|
63
|
+
it "format plain text message in a nice way" do
|
64
|
+
expected_output = <<-eos
|
65
|
+
=============================================================================
|
66
|
+
Header 1
|
67
|
+
|
68
|
+
col1
|
69
|
+
* row 1 col 1
|
70
|
+
* row 2 col 1
|
71
|
+
|
72
|
+
col2
|
73
|
+
* row 1 col 2
|
74
|
+
* row 2 col 2
|
75
|
+
|
76
|
+
This is simple email with link (http://link1.com)
|
77
|
+
|
78
|
+
Great image (http://cdn.example.com/foo/bar)
|
79
|
+
|
80
|
+
Signup (http://signup)
|
81
|
+
|
82
|
+
-----------------------------------------------------------------------------
|
83
|
+
Header 2
|
84
|
+
|
85
|
+
- list 1
|
86
|
+
- list 2
|
87
|
+
eos
|
88
|
+
|
89
|
+
text.should eq(expected_output.strip)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "aweber escaping" do
|
94
|
+
it "should not escape aweber markup if using aweber extension" do
|
95
|
+
html = <<-eos
|
96
|
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
97
|
+
<html>
|
98
|
+
<body>
|
99
|
+
<p>{!date dayname+7}</p>
|
100
|
+
</body>
|
101
|
+
</html>
|
102
|
+
eos
|
103
|
+
|
104
|
+
run_in_fixture_dir("with_config") do
|
105
|
+
processor = HtmlEmailCreator::Processor.new(html)
|
106
|
+
processor.to_html.should include("<p>{!date dayname+7}</p>")
|
107
|
+
processor.to_plain_text.should include("{!date dayname+7}")
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|