html_email_creator 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/.gitignore +2 -0
  2. data/Gemfile +4 -0
  3. data/Gemfile.lock +49 -0
  4. data/README.markdown +5 -0
  5. data/Rakefile +7 -0
  6. data/bin/html_email_creator +35 -0
  7. data/html_email_creator.gemspec +41 -0
  8. data/lib/html_email_creator/email.rb +93 -0
  9. data/lib/html_email_creator/email_creator.rb +45 -0
  10. data/lib/html_email_creator/email_version.rb +26 -0
  11. data/lib/html_email_creator/extensions.rb +46 -0
  12. data/lib/html_email_creator/filters.rb +9 -0
  13. data/lib/html_email_creator/formatter.rb +30 -0
  14. data/lib/html_email_creator/formatters/formatter.rb +31 -0
  15. data/lib/html_email_creator/formatters/html_email.rb +24 -0
  16. data/lib/html_email_creator/formatters/markdown.rb +24 -0
  17. data/lib/html_email_creator/formatters/plain_text_email.rb +22 -0
  18. data/lib/html_email_creator/formatters/unknown_formatter.rb +17 -0
  19. data/lib/html_email_creator/helper.rb +25 -0
  20. data/lib/html_email_creator/information.rb +4 -0
  21. data/lib/html_email_creator/layout.rb +15 -0
  22. data/lib/html_email_creator/processor.rb +125 -0
  23. data/lib/html_email_creator/settings.rb +95 -0
  24. data/lib/html_email_creator/tags/include_tag.rb +71 -0
  25. data/lib/html_email_creator/version.rb +3 -0
  26. data/lib/html_email_creator.rb +46 -0
  27. data/spec/fixtures/complex_with_config/.html_config.yaml +11 -0
  28. data/spec/fixtures/complex_with_config/Emails/polite_email.yaml +7 -0
  29. data/spec/fixtures/complex_with_config/Includes/Emails/love.md +1 -0
  30. data/spec/fixtures/complex_with_config/Includes/Footers/polite.md +3 -0
  31. data/spec/fixtures/complex_with_config/Layouts/.keep +0 -0
  32. data/spec/fixtures/complex_with_config/Layouts/basic.liquid +25 -0
  33. data/spec/fixtures/complex_with_config/Output/.keep +0 -0
  34. data/spec/fixtures/default_config/Emails/Newsletter/.keep +0 -0
  35. data/spec/fixtures/default_config/Layouts/.keep +0 -0
  36. data/spec/fixtures/default_config/Output/.keep +0 -0
  37. data/spec/fixtures/with_config/.html_config.yaml +11 -0
  38. data/spec/fixtures/with_config/Emails/first_email.yaml +7 -0
  39. data/spec/fixtures/with_config/Includes/Emails/barfoo.md +1 -0
  40. data/spec/fixtures/with_config/Includes/Emails/foobar.md +1 -0
  41. data/spec/fixtures/with_config/Includes/Quotes/henry_ford.txt +1 -0
  42. data/spec/fixtures/with_config/Layouts/.keep +0 -0
  43. data/spec/fixtures/with_config/Layouts/simple.liquid +7 -0
  44. data/spec/fixtures/with_config/Output/.keep +0 -0
  45. data/spec/html_email_creator/email_creator_spec.rb +119 -0
  46. data/spec/html_email_creator/email_spec.rb +29 -0
  47. data/spec/html_email_creator/formatter_spec.rb +40 -0
  48. data/spec/html_email_creator/layout_spec.rb +55 -0
  49. data/spec/html_email_creator/processor_spec.rb +111 -0
  50. data/spec/html_email_creator/settings_spec.rb +70 -0
  51. data/spec/html_email_creator/tags/include_tag_spec.rb +11 -0
  52. data/spec/spec_helper.rb +32 -0
  53. metadata +244 -0
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ pkg
2
+ .DS_Store
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in html_email_creator.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,49 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ html_email_creator (0.0.1)
5
+ commander (>= 4.0.6)
6
+ inline-style (>= 0.5.0)
7
+ kramdown (>= 0.13.3)
8
+ liquid (>= 2.3.0)
9
+ nokogiri (>= 1.5.0)
10
+
11
+ GEM
12
+ remote: http://rubygems.org/
13
+ specs:
14
+ addressable (2.2.6)
15
+ commander (4.0.6)
16
+ highline (~> 1.5.0)
17
+ css_parser (1.2.5)
18
+ addressable
19
+ diff-lcs (1.1.3)
20
+ facets (2.9.2)
21
+ ffi (1.0.10)
22
+ highline (1.5.2)
23
+ inline-style (0.5.0)
24
+ css_parser
25
+ facets
26
+ maca-fork-csspool
27
+ nokogiri
28
+ kramdown (0.13.3)
29
+ liquid (2.3.0)
30
+ maca-fork-csspool (2.0.2)
31
+ ffi
32
+ nokogiri (1.5.0)
33
+ rake (0.9.2.2)
34
+ rspec (2.7.0)
35
+ rspec-core (~> 2.7.0)
36
+ rspec-expectations (~> 2.7.0)
37
+ rspec-mocks (~> 2.7.0)
38
+ rspec-core (2.7.1)
39
+ rspec-expectations (2.7.0)
40
+ diff-lcs (~> 1.1.2)
41
+ rspec-mocks (2.7.0)
42
+
43
+ PLATFORMS
44
+ ruby
45
+
46
+ DEPENDENCIES
47
+ html_email_creator!
48
+ rake (>= 0.9.2)
49
+ rspec
data/README.markdown ADDED
@@ -0,0 +1,5 @@
1
+ # HTML Email Creator
2
+
3
+ ## Writing Emails
4
+
5
+ http://kramdown.rubyforge.org/syntax.html
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require 'bundler'
2
+ require 'rspec/core/rake_task'
3
+
4
+ Bundler::GemHelper.install_tasks
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'commander/import'
4
+ require 'html_email_creator'
5
+ require 'html_email_creator/version'
6
+ require 'html_email_creator/information'
7
+
8
+ # :name is optional, otherwise uses the basename of this executable
9
+ program :name, 'HTML Email Creator'
10
+ program :version, HtmlEmailCreator::VERSION
11
+ program :description, HtmlEmailCreator::DESCRIPTION
12
+
13
+ command :create do |c|
14
+ c.syntax = 'html_email_creator create <email or directory>'
15
+ c.description = 'Creates a single email or all emails from the directory'
16
+ c.option '--recursive', 'If creating directory, find from sub directories too.'
17
+ c.action do |args, options|
18
+ # TODO implement me
19
+ recursive = options.recursive ? true : false
20
+ full_path = File.expand_path(args.first)
21
+ # run in this directory
22
+ Dir.chdir(File.dirname(full_path))
23
+ results = HtmlEmailCreator::EmailCreator.new.save_emails(full_path, recursive)
24
+ say "Creation completed!\n\n"
25
+ results.each_pair do |file, format|
26
+ say "#{file}:"
27
+ say " Output:"
28
+ format.values.each do |output|
29
+
30
+ say " #{output}"
31
+ end
32
+ end
33
+ say "\nHave a nice day :)"
34
+ end
35
+ end
@@ -0,0 +1,41 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib/', __FILE__)
3
+ $:.unshift lib unless $:.include?(lib)
4
+
5
+ require 'html_email_creator/version'
6
+ require 'html_email_creator/information'
7
+
8
+ Gem::Specification.new do |s|
9
+ s.platform = Gem::Platform::RUBY
10
+ s.name = "html_email_creator"
11
+ s.version = HtmlEmailCreator::VERSION
12
+ s.summary = HtmlEmailCreator::SUMMARY
13
+ s.description = HtmlEmailCreator::DESCRIPTION
14
+ s.default_executable = "html_email_creator"
15
+
16
+ s.required_ruby_version = '>= 1.9.2'
17
+ s.rubygems_version = ">= 1.3.6"
18
+ s.rubyforge_project = "html_email_creator"
19
+
20
+ s.author = 'Pekka Mattila'
21
+ s.email = 'pekka.mattila@gmail.com'
22
+ s.homepage = 'https://github.com/pekkaj/HTML-Email-Creator'
23
+
24
+ s.files = `git ls-files`.split("\n")
25
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
26
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
27
+ s.require_paths = ["lib"]
28
+
29
+ # Runtime Dependencies
30
+
31
+ s.add_runtime_dependency "commander", ">= 4.0.6"
32
+ s.add_runtime_dependency "kramdown", ">= 0.13.3"
33
+ s.add_runtime_dependency "liquid", ">= 2.3.0"
34
+ s.add_runtime_dependency "nokogiri", ">= 1.5.0"
35
+ s.add_runtime_dependency "inline-style", ">= 0.5.0"
36
+
37
+ # Development Dependencies
38
+
39
+ s.add_development_dependency "rspec"
40
+ s.add_development_dependency "rake", ">= 0.9.2"
41
+ end
@@ -0,0 +1,93 @@
1
+ require "liquid"
2
+
3
+ module HtmlEmailCreator
4
+ class Email
5
+ attr_reader :settings
6
+
7
+ def self.find_emails(file_or_directory, recursively = false)
8
+ if File.directory?(file_or_directory)
9
+ if recursively
10
+ Dir.glob(File.join(file_or_directory, "**", "*.yaml"))
11
+ else
12
+ Dir.glob(File.join(file_or_directory, "*.yaml"))
13
+ end
14
+ else
15
+ return [] unless File.extname(file_or_directory) == ".yaml"
16
+ [file_or_directory]
17
+ end
18
+ end
19
+
20
+ def initialize(configuration, settings = HtmlEmailCreator.settings)
21
+ @settings = settings
22
+ @configuration = create_configuration(configuration)
23
+ end
24
+
25
+ # Renders emails using configuration. Returns Hash[format, EmailVersion].
26
+ def render_all
27
+ # render only once
28
+ return @versions if @versions
29
+
30
+ @versions = {}
31
+ output_formats.each do |format|
32
+ @versions[format] = render_only(format)
33
+ end
34
+ @versions
35
+ end
36
+
37
+ # Renders email in a specific format
38
+ def render_only(format)
39
+ formatter = HtmlEmailCreator::Formatter.new(rendered_email, @settings).find(format)
40
+ HtmlEmailCreator::EmailVersion.new(formatter, output_basename, @settings)
41
+ end
42
+
43
+ # Convenience method for rendering HTML email.
44
+ def render_html_email
45
+ render_only(HtmlEmailCreator::Formatters::HtmlEmail.id)
46
+ end
47
+
48
+ # Convenience method for rendering plain text email.
49
+ def render_plain_text_email
50
+ render_only(HtmlEmailCreator::Formatters::PlainTextEmail.id)
51
+ end
52
+
53
+ private
54
+
55
+ def rendered_email
56
+ @email ||= HtmlEmailCreator::Layout.new(fill_blanks(IO.read(layout_path)), settings.extension_data).to_html
57
+ end
58
+
59
+ def output_formats
60
+ @configuration["output_formats"]
61
+ end
62
+
63
+ def create_configuration(configuration)
64
+ config_hash = if configuration.kind_of?(String)
65
+ YAML.load_file(configuration)
66
+ else
67
+ configuration
68
+ end
69
+
70
+ defaults = {
71
+ "output_formats" => ["plain_text_email", "html_email"]
72
+ }
73
+
74
+ config_hash.merge(defaults)
75
+ end
76
+
77
+ def output_basename
78
+ @configuration["config"]["output"]
79
+ end
80
+
81
+ def layout_path
82
+ File.join(@settings.layouts_path, @configuration["config"]["layout"])
83
+ end
84
+
85
+ def fill_blanks(layout)
86
+ filled_layout = layout.dup
87
+ @configuration["config"]["data"].each_pair do |key, value|
88
+ filled_layout.gsub!(/\{\{\s*#{key}\s*\}\}/, value)
89
+ end
90
+ filled_layout
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,45 @@
1
+ module HtmlEmailCreator
2
+ class EmailCreator
3
+ def create_email(file_or_configuration, format)
4
+ email(file_or_configuration).render_only(format)
5
+ end
6
+
7
+ def create_html_email(file_or_configuration)
8
+ email(file_or_configuration).render_html_email
9
+ end
10
+
11
+ def create_plain_text_email(file_or_configuration)
12
+ email(file_or_configuration).render_plain_text_email
13
+ end
14
+
15
+ def create_all_email_versions(file_or_configuration)
16
+ email(file_or_configuration).render_all
17
+ end
18
+
19
+ def save_email(file_or_configuration)
20
+ formats_and_paths = {}
21
+ create_all_email_versions(file_or_configuration).each_value do |version|
22
+ formats_and_paths[version.id] = version.save
23
+ end
24
+ formats_and_paths
25
+ end
26
+
27
+ def save_emails(file_or_directory, recursively = false)
28
+ files = {}
29
+ HtmlEmailCreator::Email.find_emails(file_or_directory, recursively).each do |file|
30
+ files[file] = save_email(file)
31
+ end
32
+ files
33
+ end
34
+
35
+ private
36
+
37
+ def email(file_or_configuration)
38
+ if file_or_configuration.kind_of?(String)
39
+ # Is file so update settings before creating email (makes sure that we have the latest settings file)
40
+ HtmlEmailCreator.update_settings(File.dirname(file_or_configuration))
41
+ end
42
+ Email.new(file_or_configuration, HtmlEmailCreator.settings)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,26 @@
1
+ module HtmlEmailCreator
2
+ class EmailVersion
3
+ def initialize(formatter, output_basename, settings)
4
+ @formatter = formatter
5
+ @output_basename = output_basename
6
+ @settings = settings
7
+ end
8
+
9
+ def get
10
+ @formatter.format
11
+ end
12
+
13
+ def id
14
+ @formatter.id
15
+ end
16
+
17
+ def save
18
+ FileUtils.mkdir_p(@settings.output_path) unless File.exists?(@settings.output_path)
19
+ file = File.join(@settings.output_path, "#{@output_basename}.#{@formatter.extension}")
20
+ File.open(file, "w") do |file|
21
+ file.write(get)
22
+ end
23
+ file
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,46 @@
1
+ require 'kramdown'
2
+
3
+ module HtmlEmailCreator
4
+ class Extensions
5
+ @@EXTENSIONS = {
6
+ 'aweber' => {
7
+ 'email' => '{!email}',
8
+ 'subscription_date' => '{!signdate long}',
9
+ 'unsubscribe_url' => '{!remove_web}',
10
+ 'full_name' => '{!name_fix}',
11
+ 'first_name' => '{!firstname_fix}',
12
+ 'last_name' => '{!lastname_fix}',
13
+ 'company_signature' => '{!signature}',
14
+ 'company_address' => '{!contact_address}',
15
+ 'tomorrow' => '{!date dayname+1}',
16
+ 'after_2_days' => '{!date dayname+2}',
17
+ 'after_3_days' => '{!date dayname+3}',
18
+ 'after_4_days' => '{!date dayname+4}',
19
+ 'after_5_days' => '{!date dayname+5}',
20
+ 'after_6_days' => '{!date dayname+6}',
21
+ 'after_7_days' => '{!date dayname+7}'
22
+ }
23
+ }
24
+
25
+ def initialize(settings = HtmlEmailCreator.settings)
26
+ @settings = settings
27
+ end
28
+
29
+ def built_in(*extensions)
30
+ new_data = {}
31
+ extensions.flatten.each do |extension|
32
+ data = @@EXTENSIONS[extension]
33
+ new_data.merge!(data.dup) if data
34
+ end
35
+ new_data
36
+ end
37
+
38
+ def custom(data = {}, extensions)
39
+ new_data = {}
40
+ extensions.each_pair do |key, value|
41
+ new_data[key] = value
42
+ end
43
+ new_data
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,9 @@
1
+ require "liquid"
2
+
3
+ module HtmlEmailCreator
4
+ module Filters
5
+ def photo(input, alt)
6
+ "<img src=\"#{HtmlEmailCreator.settings.cdn_url}/#{input}\" alt=\"#{alt}\" border=\"0\" />"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,30 @@
1
+ require "liquid"
2
+
3
+ module HtmlEmailCreator
4
+ class Formatter
5
+ @@DEFAULT = HtmlEmailCreator::Formatters::UnknownFormatter
6
+ @@CONFIG = {}
7
+
8
+ [
9
+ HtmlEmailCreator::Formatters::Markdown,
10
+ HtmlEmailCreator::Formatters::PlainTextEmail,
11
+ HtmlEmailCreator::Formatters::HtmlEmail
12
+ ].each do |klass|
13
+ @@CONFIG[klass.id] = klass
14
+ end
15
+
16
+ def initialize(text, settings = HtmlEmailCreator.settings)
17
+ @text = text
18
+ @settings = settings
19
+ end
20
+
21
+ def find(format)
22
+ klass = @@CONFIG[format.to_sym] || @@DEFAULT
23
+ klass.send(:new, @text, @settings)
24
+ end
25
+
26
+ def find_by_filename(filename)
27
+ find(File.extname(filename).split(".").last)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,31 @@
1
+ module HtmlEmailCreator
2
+ module Formatters
3
+ class Formatter
4
+ def self.id
5
+ raise "id needs to be defined"
6
+ end
7
+
8
+ def self.extension
9
+ raise "extension needs to be defined"
10
+ end
11
+
12
+ def initialize(text, settings)
13
+ @text = text
14
+ @settings = settings
15
+ end
16
+
17
+ # override to implement a correct formatter
18
+ def format
19
+ @text
20
+ end
21
+
22
+ def id
23
+ self.class.id
24
+ end
25
+
26
+ def extension
27
+ self.class.extension
28
+ end
29
+ end
30
+ end
31
+ end