antwort 0.0.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.rspec +2 -0
- data/.rubocop.yml +19 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +249 -0
- data/Gemfile +3 -0
- data/Guardfile +14 -0
- data/README.md +108 -0
- data/Rakefile +14 -0
- data/antwort.gemspec +45 -0
- data/bin/antwort +5 -0
- data/lib/antwort.rb +13 -0
- data/lib/antwort/builder.rb +8 -0
- data/lib/antwort/builder/builder.rb +104 -0
- data/lib/antwort/builder/email.rb +61 -0
- data/lib/antwort/builder/flattener.rb +37 -0
- data/lib/antwort/builder/helpers/logic.rb +82 -0
- data/lib/antwort/builder/helpers/sanitizers.rb +29 -0
- data/lib/antwort/builder/partial.rb +80 -0
- data/lib/antwort/builder/style.rb +59 -0
- data/lib/antwort/cli.rb +7 -0
- data/lib/antwort/cli/cli.rb +275 -0
- data/lib/antwort/cli/helpers.rb +44 -0
- data/lib/antwort/cli/send.rb +79 -0
- data/lib/antwort/cli/upload.rb +89 -0
- data/lib/antwort/helpers.rb +19 -0
- data/lib/antwort/server.rb +70 -0
- data/lib/antwort/server/assets.rb +23 -0
- data/lib/antwort/server/helpers.rb +67 -0
- data/lib/antwort/server/markup.rb +39 -0
- data/lib/antwort/version.rb +3 -0
- data/spec/builder/builder_spec.rb +30 -0
- data/spec/builder/email_spec.rb +21 -0
- data/spec/builder/flattener_spec.rb +64 -0
- data/spec/builder/helpers_logic_spec.rb +244 -0
- data/spec/builder/partial_spec.rb +87 -0
- data/spec/builder/style_spec.rb +66 -0
- data/spec/cli/helpers_spec.rb +60 -0
- data/spec/cli/upload_spec.rb +47 -0
- data/spec/cli_spec.rb +46 -0
- data/spec/fixtures/assets/images/1-demo/placeholder.png +0 -0
- data/spec/fixtures/assets/images/newsletter/placeholder.png +0 -0
- data/spec/fixtures/assets/images/shared/placeholder-grey.png +0 -0
- data/spec/fixtures/assets/images/shared/placeholder-white.png +0 -0
- data/spec/fixtures/build/demo-123456/build.html +7 -0
- data/spec/fixtures/build/demo-123457/build.html +7 -0
- data/spec/fixtures/build/demo-bar-123/build.html +7 -0
- data/spec/fixtures/build/foo-1/build.html +7 -0
- data/spec/fixtures/data/1-demo.yml +3 -0
- data/spec/fixtures/emails/1-demo/index.html.erb +9 -0
- data/spec/fixtures/emails/2-no-layout/index.html.erb +6 -0
- data/spec/fixtures/emails/3-no-title/index.html.erb +1 -0
- data/spec/fixtures/views/404.html.erb +1 -0
- data/spec/fixtures/views/index.html.erb +14 -0
- data/spec/fixtures/views/layout.erb +8 -0
- data/spec/fixtures/views/server.erb +5 -0
- data/spec/server_spec.rb +54 -0
- data/spec/spec_helper.rb +38 -0
- data/spec/support/capture.rb +17 -0
- data/template/email/css/include.scss +5 -0
- data/template/email/css/inline.scss +5 -0
- data/template/email/email.html.erb +11 -0
- data/template/email/images/.empty_directory +0 -0
- data/template/project/.env.sample +21 -0
- data/template/project/.gitignore.tt +17 -0
- data/template/project/.ruby-version +1 -0
- data/template/project/Gemfile.tt +9 -0
- data/template/project/Guardfile +9 -0
- data/template/project/assets/css/demo/include.scss +3 -0
- data/template/project/assets/css/demo/inline.scss +33 -0
- data/template/project/assets/css/server.scss +167 -0
- data/template/project/assets/css/shared/_base.scss +64 -0
- data/template/project/assets/css/shared/_mixins.scss +25 -0
- data/template/project/assets/css/shared/_reset.scss +59 -0
- data/template/project/assets/css/shared/_vars.scss +12 -0
- data/template/project/assets/css/shared/include.scss +23 -0
- data/template/project/assets/css/shared/inline.scss +9 -0
- data/template/project/assets/images/.gitkeep +0 -0
- data/template/project/assets/images/shared/placeholder.png +0 -0
- data/template/project/build/.empty_directory +0 -0
- data/template/project/data/.empty_directory +0 -0
- data/template/project/data/config.yml +3 -0
- data/template/project/data/demo.yml +4 -0
- data/template/project/emails/demo/_partial.html.erb +9 -0
- data/template/project/emails/demo/index.html.erb +54 -0
- data/template/project/views/404.html.erb +8 -0
- data/template/project/views/index.html.erb +18 -0
- data/template/project/views/layout.erb +38 -0
- data/template/project/views/markup/_button.html.erb +5 -0
- data/template/project/views/markup/_image_tag.html.erb +10 -0
- data/template/project/views/server.erb +32 -0
- metadata +443 -0
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'fog'
|
2
|
+
|
3
|
+
module Antwort
|
4
|
+
class CLI
|
5
|
+
class Upload < Thor
|
6
|
+
include Thor::Actions
|
7
|
+
include Antwort::CLIHelpers
|
8
|
+
attr_reader :email_id
|
9
|
+
|
10
|
+
def initialize(email_id, force = false)
|
11
|
+
@force = force
|
12
|
+
@email_id = email_id
|
13
|
+
@images_dir = images_dir(email_id)
|
14
|
+
check_credentials
|
15
|
+
end
|
16
|
+
|
17
|
+
no_commands do
|
18
|
+
|
19
|
+
def check_credentials
|
20
|
+
failed = false
|
21
|
+
vars = ['ASSET_SERVER', 'AWS_BUCKET', 'AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY']
|
22
|
+
vars.each do |var|
|
23
|
+
if ENV[var].nil?
|
24
|
+
say "Error ", :red
|
25
|
+
say "#{var} not set."
|
26
|
+
failed = true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
if failed
|
31
|
+
abort "Please fix your .env config file and try again."
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def upload
|
36
|
+
count = count_files @images_dir
|
37
|
+
abort "No images in #{@images_dir} to upload." if count === 0
|
38
|
+
|
39
|
+
if confirms_upload?(count)
|
40
|
+
do_upload
|
41
|
+
else
|
42
|
+
say 'Upload aborted. ', :red
|
43
|
+
say 'No files deleted or replaced.'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def confirms_upload?(count)
|
48
|
+
yes?("Upload #{count} images and overwrite '#{email_id}' folder on assets server? (y/n)")
|
49
|
+
end
|
50
|
+
|
51
|
+
def do_upload
|
52
|
+
clean_directory!
|
53
|
+
Dir.foreach(@images_dir) do |f|
|
54
|
+
next if f.to_s[0] == '.'
|
55
|
+
directory.files.create(
|
56
|
+
key: "#{email_id}/#{f}",
|
57
|
+
body: File.open(File.join(@images_dir, f)),
|
58
|
+
public: true
|
59
|
+
)
|
60
|
+
say ' create ', :green
|
61
|
+
say "#{ENV['ASSET_SERVER']}/#{email_id}/#{f}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def connection
|
66
|
+
@connection ||=
|
67
|
+
Fog::Storage.new(
|
68
|
+
provider: 'AWS',
|
69
|
+
aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'],
|
70
|
+
aws_secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'],
|
71
|
+
region: ENV['FOG_REGION']
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
def directory
|
76
|
+
return @directory if defined?(@directory)
|
77
|
+
|
78
|
+
@directory ||=
|
79
|
+
connection.directories.get(ENV['AWS_BUCKET'], prefix: email_id)
|
80
|
+
end
|
81
|
+
|
82
|
+
def clean_directory!
|
83
|
+
directory.files.each(&:destroy)
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Antwort
|
2
|
+
module Helpers
|
3
|
+
def symbolize_keys!(hash)
|
4
|
+
hash.reduce({}) do |result, (key, value)|
|
5
|
+
new_key = case key
|
6
|
+
when String then key.to_sym
|
7
|
+
else key
|
8
|
+
end
|
9
|
+
new_value = case value
|
10
|
+
when Hash then symbolize_keys!(value)
|
11
|
+
when Array then value.map { |v| v.is_a?(Hash) ? symbolize_keys!(v) : v }
|
12
|
+
else value
|
13
|
+
end
|
14
|
+
result[new_key] = new_value
|
15
|
+
result
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'antwort/server/assets'
|
2
|
+
require 'antwort/server/helpers'
|
3
|
+
require 'antwort/server/markup'
|
4
|
+
require 'sinatra/base'
|
5
|
+
require 'sinatra/partial'
|
6
|
+
require 'sinatra/content_for'
|
7
|
+
require 'rack-livereload'
|
8
|
+
require 'sinatra/reloader'
|
9
|
+
require 'ostruct'
|
10
|
+
|
11
|
+
module Antwort
|
12
|
+
class Server < Sinatra::Base
|
13
|
+
use Rack::LiveReload
|
14
|
+
Tilt.register Tilt::ERBTemplate, 'html.erb'
|
15
|
+
register Sinatra::Partial
|
16
|
+
register Sinatra::Reloader
|
17
|
+
helpers Sinatra::ContentFor
|
18
|
+
helpers Antwort::Helpers
|
19
|
+
helpers Antwort::ApplicationHelpers
|
20
|
+
helpers Antwort::MarkupHelpers
|
21
|
+
|
22
|
+
configure do
|
23
|
+
enable :logging
|
24
|
+
set :root, Dir.pwd
|
25
|
+
set :root, Dir.pwd + '/spec/fixtures/' if ENV['RACK_ENV'] == 'test'
|
26
|
+
set :views, settings.root
|
27
|
+
set :templates_dir, settings.root + '/emails'
|
28
|
+
set :partial_template_engine, :erb
|
29
|
+
enable :partial_underscores
|
30
|
+
set :port, 9292
|
31
|
+
end
|
32
|
+
|
33
|
+
register Sinatra::Assets # after we set root
|
34
|
+
|
35
|
+
get '/' do
|
36
|
+
pages = Dir.entries(settings.templates_dir)
|
37
|
+
pages.delete_if { |page| page.to_s[0] == '.' }
|
38
|
+
@pages = Array.new
|
39
|
+
pages.each do |p|
|
40
|
+
path = p.split('.').first
|
41
|
+
@pages.push({
|
42
|
+
path: path,
|
43
|
+
title: get_page_title(path)
|
44
|
+
})
|
45
|
+
end
|
46
|
+
erb :'views/index', layout: :'views/server'
|
47
|
+
end
|
48
|
+
|
49
|
+
get '/template/:template' do
|
50
|
+
@config = OpenStruct.new(fetch_data_yaml('config'))
|
51
|
+
@template = sanitize_param params[:template]
|
52
|
+
|
53
|
+
if template_exists? @template
|
54
|
+
content = read_template @template
|
55
|
+
hash_to_instance_vars content[:metadata]
|
56
|
+
hash_to_instance_vars fetch_data_yaml(@template)
|
57
|
+
layout = @layout.nil? ? :'views/layout' : @layout
|
58
|
+
erb content[:body], layout: layout
|
59
|
+
else
|
60
|
+
status 404
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
not_found do
|
65
|
+
content_type 'text/html'
|
66
|
+
erb :'views/404', layout: :'views/server'
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'sinatra/extension'
|
3
|
+
require 'sprockets'
|
4
|
+
require 'sass'
|
5
|
+
|
6
|
+
module Sinatra
|
7
|
+
module Assets
|
8
|
+
extend Sinatra::Extension
|
9
|
+
|
10
|
+
configure do
|
11
|
+
set :assets, assets = Sprockets::Environment.new(root)
|
12
|
+
assets.append_path 'assets/css'
|
13
|
+
assets.append_path 'assets/images'
|
14
|
+
|
15
|
+
assets.cache = Sprockets::Cache::FileStore.new('./tmp')
|
16
|
+
end
|
17
|
+
|
18
|
+
get '/assets/*' do
|
19
|
+
env['PATH_INFO'].sub!(%r{^/assets}, '')
|
20
|
+
settings.assets.call(env)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Antwort
|
2
|
+
module ApplicationHelpers
|
3
|
+
|
4
|
+
def sanitize_param(string)
|
5
|
+
string.nil? ? '' : string.gsub(/([^A-Za-z0-9_\/-]+)|(--)/, '_')
|
6
|
+
end
|
7
|
+
|
8
|
+
def get_template_file(template_name)
|
9
|
+
# Dir.entries("your/folder").select {|f| !File.directory? f}
|
10
|
+
"#{settings.views}/emails/#{template_name}/index.html.erb"
|
11
|
+
end
|
12
|
+
|
13
|
+
def get_page_title(template_name)
|
14
|
+
get_metadata(template_name)[:title] || 'Untitled'
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_metadata(template_name)
|
18
|
+
read_template(template_name)[:metadata]
|
19
|
+
end
|
20
|
+
|
21
|
+
def read_template(template_name)
|
22
|
+
file = get_template_file(template_name)
|
23
|
+
|
24
|
+
data = File.read(file)
|
25
|
+
md = data.match(/^(?<metadata>---\s*\n.*?\n?)^(---\s*$\n?)/m)
|
26
|
+
{
|
27
|
+
body: (md.nil?) ? data : md.post_match,
|
28
|
+
metadata: (md.nil?) ? {} : symbolize_keys!(YAML.load(md[:metadata]))
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def fetch_data_yaml(template_name)
|
33
|
+
data = {}
|
34
|
+
data_file = settings.root + '/data/' + template_name + '.yml'
|
35
|
+
if File.file? data_file
|
36
|
+
data = YAML.load_file(data_file)
|
37
|
+
data = symbolize_keys! data if data
|
38
|
+
end
|
39
|
+
data
|
40
|
+
end
|
41
|
+
|
42
|
+
def template_exists?(template_name)
|
43
|
+
File.file? settings.templates_dir + '/' + template_name + '/index.html.erb'
|
44
|
+
end
|
45
|
+
|
46
|
+
def template_from_path
|
47
|
+
request.path_info.gsub(%r{/template/}i, '')
|
48
|
+
end
|
49
|
+
|
50
|
+
def hash_to_instance_vars(data)
|
51
|
+
data.each { |k, v| instance_variable_set("@#{k}", v) } if data
|
52
|
+
end
|
53
|
+
|
54
|
+
def image_url_from_path(path)
|
55
|
+
p = path.split(':')[0]
|
56
|
+
if (p == 'http' || p == 'https')
|
57
|
+
url = path
|
58
|
+
else
|
59
|
+
a = [path]
|
60
|
+
a.unshift(template_from_path) unless path[0] == '/'
|
61
|
+
a.unshift('/assets')
|
62
|
+
url = File.join(a)
|
63
|
+
end
|
64
|
+
url
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Antwort
|
2
|
+
module MarkupHelpers
|
3
|
+
def image_tag(path, options = {})
|
4
|
+
options[:source] = image_url_from_path(path)
|
5
|
+
options[:alt] ||= ''
|
6
|
+
partial('views/markup/image_tag', locals: options)
|
7
|
+
.gsub(/\n/, '')
|
8
|
+
end
|
9
|
+
|
10
|
+
def button(text, url, args = {})
|
11
|
+
options = {
|
12
|
+
text: text,
|
13
|
+
url: url
|
14
|
+
}.merge(args)
|
15
|
+
partial('views/markup/button', locals: options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def wrapper_table(args = {}, &block)
|
19
|
+
options = {
|
20
|
+
width: '100%',
|
21
|
+
cell_align: 'center',
|
22
|
+
cell_valign: 'top',
|
23
|
+
content: capture_html(&block)
|
24
|
+
}.merge(args)
|
25
|
+
|
26
|
+
concat_content partial('views/markup/table_wrapper', locals: options)
|
27
|
+
end
|
28
|
+
|
29
|
+
def counter_classes(index)
|
30
|
+
# 0 index based
|
31
|
+
klass = ''
|
32
|
+
klass += index.even? ? ' is-2n' : ''
|
33
|
+
klass += (index % 3 == 0) ? ' is-3n' : ''
|
34
|
+
klass += (index % 4 == 0) ? ' is-4n' : ''
|
35
|
+
klass += (index % 6 == 0) ? ' is-6n' : ''
|
36
|
+
klass
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Antwort::Builder do
|
4
|
+
before :each do
|
5
|
+
@builder = Antwort::Builder.new
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "Initialize" do
|
9
|
+
it "has a template_name"
|
10
|
+
it "has a build_id"
|
11
|
+
it "has a markup_dir"
|
12
|
+
it "has a source_dir"
|
13
|
+
it "has a scss_dir"
|
14
|
+
it "has an asset_server"
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "Compiles" do
|
18
|
+
it "SCSS"
|
19
|
+
it "inline.scss"
|
20
|
+
it "include.scss"
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "Helpers" do
|
24
|
+
it "creates files"
|
25
|
+
it "creates IDs from Timestamps"
|
26
|
+
it "changes relative assets URLs to use asset server"
|
27
|
+
it "preserves ` `s"
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Antwort::EmailBuilder do
|
4
|
+
before :each do
|
5
|
+
@builder = Antwort::EmailBuilder.new
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "Builds" do
|
9
|
+
it "builds HTML"
|
10
|
+
it "inlines CSS"
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "Helpers" do
|
14
|
+
it "can inline CSS"
|
15
|
+
it "cleans up markup"
|
16
|
+
it "removes livereload"
|
17
|
+
it "adds in the included CSS"
|
18
|
+
it "removes excessive newlines"
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Antwort::Flattener do
|
4
|
+
|
5
|
+
describe "initialize" do
|
6
|
+
it "saves source to a attr_reader" do
|
7
|
+
s = Antwort::Flattener.new('<td>')
|
8
|
+
expect(s.source).to eq('<td>')
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "saves matches to an array" do
|
12
|
+
it "matches single style per source" do
|
13
|
+
s = Antwort::Flattener.new('<div style="color:black">')
|
14
|
+
expect(s.styles).to eq(['color:black'])
|
15
|
+
end
|
16
|
+
it "matches multiple styles per source" do
|
17
|
+
s = Antwort::Flattener.new('<td style="background-color:#cccccc"><div style="color: red">')
|
18
|
+
expect(s.styles).to eq(['background-color:#cccccc', 'color: red'])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "flattens css styles" do
|
24
|
+
it "a single match" do
|
25
|
+
s = Antwort::Flattener.new('<div style="color:black;color:red;background:white;">').flatten
|
26
|
+
expect(s.flattened).to eq('<div style="color:red;background:white">')
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "multiple styles" do
|
30
|
+
let (:style) { Antwort::Flattener.new('<td style="color:black;color:red;"><div style="background:white;">').flatten }
|
31
|
+
|
32
|
+
it "stores original source as a string" do
|
33
|
+
expect(style.source).to eq('<td style="color:black;color:red;"><div style="background:white;">')
|
34
|
+
end
|
35
|
+
|
36
|
+
it "stores flattened source as a string" do
|
37
|
+
expect(style.flattened).to eq('<td style="color:red"><div style="background:white">')
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "method flattened?" do
|
42
|
+
it "returns true if changes where made" do
|
43
|
+
s = Antwort::Flattener.new('<td style="color: red; color: black;">').flatten
|
44
|
+
expect(s.flattened?).to eq(true)
|
45
|
+
end
|
46
|
+
it "returns false if chnages were not made" do
|
47
|
+
s = Antwort::Flattener.new('<td style"color:red">').flatten
|
48
|
+
expect(s.flattened?).to eq(false)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "code cleanup" do
|
54
|
+
let (:style) { Antwort::Flattener.new('<td style="color: black;">').flatten }
|
55
|
+
|
56
|
+
it "removes trailing semicolon;" do
|
57
|
+
expect(style.flattened).to eq('<td style="color:black">')
|
58
|
+
expect(style.flattened).not_to eq('<td style="color:black;">')
|
59
|
+
end
|
60
|
+
it "remove extra white space" do
|
61
|
+
expect(style.flattened).not_to eq('<td style="color: black">')
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,244 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Dummy
|
4
|
+
end
|
5
|
+
|
6
|
+
describe Antwort::LogicHelpers do
|
7
|
+
|
8
|
+
before :each do
|
9
|
+
@helper = Dummy.new
|
10
|
+
@helper.extend(Antwort::LogicHelpers)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "non breaking spaces" do
|
14
|
+
it "preserves by adjusting markup" do
|
15
|
+
expect(@helper.preserve_nbsps('foo bar')).to eq('foo%nbspace%bar')
|
16
|
+
end
|
17
|
+
|
18
|
+
it "can restore to proper markup" do
|
19
|
+
expect(@helper.restore_nbsps('foo%nbspace%bar')).to eq('foo bar')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "statements" do
|
24
|
+
it "preserves erb markup" do
|
25
|
+
expect(@helper.preserve_logic('<% user.merge!({clear: true}) %>')).to eq('{% user.merge!({clear: true}) %}')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
#-- Comments --
|
30
|
+
|
31
|
+
describe "comments" do
|
32
|
+
it "preserves erb comments" do
|
33
|
+
h = {
|
34
|
+
"<%# foo %>" => "{# foo #}",
|
35
|
+
"<% # foo %>" => "{# foo #}",
|
36
|
+
"<% #foo %>" => "{# foo #}",
|
37
|
+
"<%#= foo %>" => "{#= foo #}",
|
38
|
+
"<%# foo bar == cat %>" => "{# foo bar == cat #}"
|
39
|
+
}
|
40
|
+
h.each do |key, value|
|
41
|
+
expect(@helper.preserve_logic(key)).to eq(value)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it "preserves comments despite leading/trailing spaces" do
|
46
|
+
expect(@helper.preserve_logic('<% # foo %>')).to eq('{# foo #}')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
#-- Variables --
|
51
|
+
|
52
|
+
describe "variable outputs" do
|
53
|
+
it "preserves interpolated strings" do
|
54
|
+
expect(@helper.preserve_logic('<%= "color: #{foo};" %>')).to eq('{{ "color: #{foo};" }}')
|
55
|
+
end
|
56
|
+
|
57
|
+
context "hashes" do
|
58
|
+
it "preserves nested" do
|
59
|
+
expect(@helper.preserve_logic('<%= foo[:bar] %>')).to eq('{{ foo.bar }}')
|
60
|
+
expect(@helper.preserve_logic('<%= foo[:bar][:cat] %>')).to eq('{{ foo.bar.cat }}')
|
61
|
+
end
|
62
|
+
|
63
|
+
it "preseves string keys" do
|
64
|
+
expect(@helper.preserve_logic("<%= foo['bar'] %>")).to eq('{{ foo.bar }}')
|
65
|
+
expect(@helper.preserve_logic("<%= foo['bar']['cat'] %>")).to eq('{{ foo.bar.cat }}')
|
66
|
+
expect(@helper.preserve_logic('<%= foo["bar"] %>')).to eq('{{ foo.bar }}')
|
67
|
+
expect(@helper.preserve_logic('<%= foo["bar"]["cat"] %>')).to eq('{{ foo.bar.cat }}')
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
#-- Assignments --
|
73
|
+
|
74
|
+
describe "preserves assignments" do
|
75
|
+
|
76
|
+
describe "incl. variables" do
|
77
|
+
it "well-formatted code" do
|
78
|
+
expect(@helper.preserve_logic("<% foo = bar %>")).to eq("{% set foo = bar %}")
|
79
|
+
end
|
80
|
+
|
81
|
+
it "not well-formatted code" do
|
82
|
+
expect(@helper.preserve_logic("<% foo=bar %>")).to eq("{% set foo = bar %}")
|
83
|
+
expect(@helper.preserve_logic("<% foo =bar %>")).to eq("{% set foo = bar %}")
|
84
|
+
expect(@helper.preserve_logic("<% foo=bar %>")).to eq("{% set foo = bar %}")
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
it "incl. strings" do
|
89
|
+
expect(@helper.preserve_logic('<% foo = "bar" %>')).to eq('{% set foo = "bar" %}')
|
90
|
+
expect(@helper.preserve_logic("<% foo = 'bar' %>")).to eq("{% set foo = 'bar' %}")
|
91
|
+
end
|
92
|
+
|
93
|
+
it "incl. integers" do
|
94
|
+
expect(@helper.preserve_logic('<% foo = 1 %>')).to eq('{% set foo = 1 %}')
|
95
|
+
expect(@helper.preserve_logic('<% foo=1 %>')).to eq('{% set foo = 1 %}')
|
96
|
+
end
|
97
|
+
|
98
|
+
it "incl. arrays" do
|
99
|
+
h = {
|
100
|
+
"<% foo = [1] %>" => "{% set foo = [1] %}",
|
101
|
+
"<% foo = [ 1 ] %>" => "{% set foo = [ 1 ] %}",
|
102
|
+
"<% foo = [1,2] %>" => "{% set foo = [1,2] %}",
|
103
|
+
"<% foo = [1, 2, 3] %>" => "{% set foo = [1, 2, 3] %}"
|
104
|
+
}
|
105
|
+
h.each do |key, value|
|
106
|
+
expect(@helper.preserve_logic(key)).to eq(value)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
it "incl. objects/hashes" do
|
111
|
+
expect(@helper.preserve_logic('<% foo = { key: val } %>')).to eq('{% set foo = { key: val } %}')
|
112
|
+
end
|
113
|
+
|
114
|
+
it "respects memoized assignemnts" do
|
115
|
+
expect(@helper.preserve_logic('<% foo ||= "bar" %>')).to eq('{% set foo = foo || "bar" %}')
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
#-- Conditionals --
|
120
|
+
|
121
|
+
describe "conditionals" do
|
122
|
+
describe "if" do
|
123
|
+
it "/ end" do
|
124
|
+
h = {
|
125
|
+
'<% if foo %>do something<% end %>' => '{% if foo %}do something{% end %}',
|
126
|
+
'<%if foo%>do something<%end%>' => '{% if foo %}do something{% end %}',
|
127
|
+
'<% if foo=bar %>do something<% end %>' => '{% if foo=bar %}do something{% end %}',
|
128
|
+
'<% if foo = \'bar\' %>do something<% end %>' => '{% if foo = \'bar\' %}do something{% end %}',
|
129
|
+
'<% if foo = "bar" %>do something<% end %>' => '{% if foo = "bar" %}do something{% end %}',
|
130
|
+
'<% if i < @config.products.length - 1 %>' => '{% if i < @config.products.length - 1 %}',
|
131
|
+
'<% if i<@config.products.length-1 %>' => '{% if i<@config.products.length-1 %}'
|
132
|
+
}
|
133
|
+
h.each do |key, value|
|
134
|
+
expect(@helper.preserve_logic(key)).to eq(value)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
it "/ else / end" do
|
139
|
+
expect(@helper.preserve_logic('<% if foo %>bar<% else %>cat<% end %>')).to eq('{% if foo %}bar{% else %}cat{% end %}')
|
140
|
+
end
|
141
|
+
|
142
|
+
it "/ elsif / else / end" do
|
143
|
+
expect(@helper.preserve_logic('<% if foo = bar %>bar<% elsif foo = cat %>cat<% else %>dog<% end %>')).to eq('{% if foo = bar %}bar{% elseif foo = cat %}cat{% else %}dog{% end %}')
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe "unless" do
|
148
|
+
it "/ end" do
|
149
|
+
expect(@helper.preserve_logic('<% unless foo %>')).to eq('{% if !( foo ) %}')
|
150
|
+
expect(@helper.preserve_logic('<% unless foo == bar - 1 %>')).to eq('{% if !( foo == bar - 1 ) %}')
|
151
|
+
end
|
152
|
+
|
153
|
+
it "/ else / end" do
|
154
|
+
expect(@helper.preserve_logic('<% unless foo == bar %>this<% else %>that<% end %>')).to eq('{% if !( foo == bar ) %}this{% else %}that{% end %}')
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
#-- Loops --
|
160
|
+
|
161
|
+
describe "loops" do
|
162
|
+
it "preserves each loops as for loops" do
|
163
|
+
h = {
|
164
|
+
"<% cats.each do |cat| %>" => "{% for cat in cats %}",
|
165
|
+
"<% cats.each do | cat | %>" => "{% for cat in cats %}",
|
166
|
+
"<% end %>" => "{% end %}"
|
167
|
+
}
|
168
|
+
h.each do |key, value|
|
169
|
+
expect(@helper.preserve_logic(key)).to eq(value)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
it "preserves each_with_index" do
|
174
|
+
h = {
|
175
|
+
"<% cats.each_with_index do | cat , i | %>" => "{% for cat in cats with: {@index: i} %}",
|
176
|
+
"<% cats.each_with_index do |cat, i| %>" => "{% for cat in cats with: {@index: i} %}",
|
177
|
+
"<% cats.each_with_index do |cat,i| %>" => "{% for cat in cats with: {@index: i} %}"
|
178
|
+
}
|
179
|
+
h.each do |key, value|
|
180
|
+
expect(@helper.preserve_logic(key)).to eq(value)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
#-- Helpers --
|
186
|
+
|
187
|
+
describe "Helpers use statements syntax, not output" do
|
188
|
+
it "includes button" do
|
189
|
+
expect(@helper.preserve_logic("<%= button 'foo', '#' %>")).to eq("{% button 'foo', '#' %}")
|
190
|
+
expect(@helper.preserve_logic("<%= button 'foo', '#', color: 'blue' %>")).to eq("{% button 'foo', '#', color: 'blue' %}")
|
191
|
+
end
|
192
|
+
|
193
|
+
it "includes image_tag" do
|
194
|
+
expect(@helper.preserve_logic("<%= image_tag 'photo.jpg', width: 100, alt: 'caption' %>")).to eq("{% image_tag 'photo.jpg', width: 100, alt: 'caption' %}")
|
195
|
+
expect(@helper.preserve_logic('<%= image_tag "#{user}-photo.jpg", width: 100, alt: "caption" %>')).to eq('{% image_tag "#{user}-photo.jpg", width: 100, alt: "caption" %}')
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
#-- Partials --
|
200
|
+
|
201
|
+
describe "partials are converted to friendlier include syntax" do
|
202
|
+
it "with locals" do
|
203
|
+
expect(@helper.preserve_logic("{{ partial :'foo', locals: bar }}")).to eq("{% include 'foo' with: bar %}")
|
204
|
+
expect(@helper.preserve_logic("{{ partial :'foo', locals:bar }}")).to eq("{% include 'foo' with:bar %}")
|
205
|
+
expect(@helper.preserve_logic("{{ partial :'foo', locals: {cat: cat} }}")).to eq("{% include 'foo' with: {cat: cat} %}")
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
it "including multiline" do
|
210
|
+
markup = %q(
|
211
|
+
<%= partial :'user', locals: {
|
212
|
+
name: 'foo',
|
213
|
+
size: bar
|
214
|
+
} %>
|
215
|
+
)
|
216
|
+
result = %q(
|
217
|
+
{% include 'user' with: {
|
218
|
+
name: 'foo',
|
219
|
+
size: bar
|
220
|
+
} %}
|
221
|
+
)
|
222
|
+
|
223
|
+
expect(@helper.preserve_logic(markup)).to eq(result)
|
224
|
+
end
|
225
|
+
|
226
|
+
it "without locals" do
|
227
|
+
expect(@helper.preserve_logic("{{ partial :'foo' }}")).to eq("{% include 'foo' %}")
|
228
|
+
expect(@helper.preserve_logic("{{ partial :foo }}")).to eq("{% include foo %}")
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
describe "multiple statements on one line" do
|
233
|
+
it "does not match too early" do
|
234
|
+
h = {
|
235
|
+
"<% if %>this<% else %>that<%end%>" => "{% if %}this{% else %}that{% end %}",
|
236
|
+
"<% if i==0 %><%= partial :foo %><% else %><%= partial :bar %><% end %>" => "{% if i==0 %}{% include foo %}{% else %}{% include bar %}{% end %}"
|
237
|
+
}
|
238
|
+
h.each do |key, value|
|
239
|
+
expect(@helper.preserve_logic(key)).to eq(value)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
end
|