antwort 0.0.12
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.
- 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
 
    
        data/antwort.gemspec
    ADDED
    
    | 
         @@ -0,0 +1,45 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # coding: utf-8
         
     | 
| 
      
 2 
     | 
    
         
            +
            lib = File.expand_path('../lib', __FILE__)
         
     | 
| 
      
 3 
     | 
    
         
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'antwort/version'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            Gem::Specification.new do |s|
         
     | 
| 
      
 7 
     | 
    
         
            +
              s.name        = 'antwort'
         
     | 
| 
      
 8 
     | 
    
         
            +
              s.version     = Antwort::VERSION
         
     | 
| 
      
 9 
     | 
    
         
            +
              s.summary     = 'Antwort Generator'
         
     | 
| 
      
 10 
     | 
    
         
            +
              s.description = 'E-Mail development, build and test system.'
         
     | 
| 
      
 11 
     | 
    
         
            +
              s.authors     = ['Julie Ng']
         
     | 
| 
      
 12 
     | 
    
         
            +
              s.email       = 'hello@antwort.co'
         
     | 
| 
      
 13 
     | 
    
         
            +
              s.homepage    = 'https://antwort.co'
         
     | 
| 
      
 14 
     | 
    
         
            +
              s.license     = 'MIT'
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              s.files         = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
         
     | 
| 
      
 17 
     | 
    
         
            +
              s.executables   = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
         
     | 
| 
      
 18 
     | 
    
         
            +
              s.test_files    = s.files.grep(%r{^(test|spec|features)/})
         
     | 
| 
      
 19 
     | 
    
         
            +
              s.require_paths = ['lib']
         
     | 
| 
      
 20 
     | 
    
         
            +
              s.required_ruby_version = '~> 2.0'
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
              s.add_runtime_dependency 'rake'
         
     | 
| 
      
 23 
     | 
    
         
            +
              s.add_runtime_dependency 'thor'
         
     | 
| 
      
 24 
     | 
    
         
            +
              s.add_runtime_dependency 'sinatra'
         
     | 
| 
      
 25 
     | 
    
         
            +
              s.add_runtime_dependency 'sinatra-contrib'
         
     | 
| 
      
 26 
     | 
    
         
            +
              s.add_runtime_dependency 'sinatra-partial'
         
     | 
| 
      
 27 
     | 
    
         
            +
              s.add_runtime_dependency 'dotenv'
         
     | 
| 
      
 28 
     | 
    
         
            +
              s.add_runtime_dependency 'htmlentities'
         
     | 
| 
      
 29 
     | 
    
         
            +
              s.add_runtime_dependency 'mail'
         
     | 
| 
      
 30 
     | 
    
         
            +
              s.add_runtime_dependency 'nokogiri'
         
     | 
| 
      
 31 
     | 
    
         
            +
              s.add_runtime_dependency 'roadie', '>= 3.0.0'
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
              s.add_runtime_dependency 'sass'
         
     | 
| 
      
 34 
     | 
    
         
            +
              s.add_runtime_dependency 'sprockets', '~> 3.0'
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              s.add_runtime_dependency 'thin'
         
     | 
| 
      
 37 
     | 
    
         
            +
              s.add_runtime_dependency 'rack-livereload'
         
     | 
| 
      
 38 
     | 
    
         
            +
              s.add_runtime_dependency 'guard-livereload'
         
     | 
| 
      
 39 
     | 
    
         
            +
              s.add_runtime_dependency 'fog'
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
              s.add_development_dependency 'pry'
         
     | 
| 
      
 42 
     | 
    
         
            +
              s.add_development_dependency 'rspec', '~> 3.0'
         
     | 
| 
      
 43 
     | 
    
         
            +
              s.add_development_dependency 'rspec-its'
         
     | 
| 
      
 44 
     | 
    
         
            +
              s.add_development_dependency 'guard-rspec'
         
     | 
| 
      
 45 
     | 
    
         
            +
            end
         
     | 
    
        data/bin/antwort
    ADDED
    
    
    
        data/lib/antwort.rb
    ADDED
    
    
| 
         @@ -0,0 +1,8 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'antwort/builder/helpers/logic'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'antwort/builder/helpers/sanitizers'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'antwort/builder/builder'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'antwort/builder/email'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'antwort/builder/partial'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'antwort/builder/flattener'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'antwort/builder/style'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'antwort/cli/helpers'
         
     | 
| 
         @@ -0,0 +1,104 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'fileutils'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'tilt'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'roadie'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'thor/shell'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            module Antwort
         
     | 
| 
      
 7 
     | 
    
         
            +
              class Builder
         
     | 
| 
      
 8 
     | 
    
         
            +
                include Thor::Shell
         
     | 
| 
      
 9 
     | 
    
         
            +
                include Antwort::Helpers
         
     | 
| 
      
 10 
     | 
    
         
            +
                include Antwort::CLIHelpers
         
     | 
| 
      
 11 
     | 
    
         
            +
                include Antwort::LogicHelpers
         
     | 
| 
      
 12 
     | 
    
         
            +
                include Antwort::MarkupSanitizers
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                attr_reader :template_name, :build_id, :build_dir, :markup_dir, :source_dir, :scss_dir, :asset_server, :css, :css_style
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                def initialize(attrs = {})
         
     | 
| 
      
 17 
     | 
    
         
            +
                  attrs = symbolize_keys!(attrs)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @template_name = attrs[:email]
         
     | 
| 
      
 19 
     | 
    
         
            +
                  @build_id      = attrs[:id]
         
     | 
| 
      
 20 
     | 
    
         
            +
                  @build_dir     = "./build/#{template_name}-#{build_id}"
         
     | 
| 
      
 21 
     | 
    
         
            +
                  @markup_dir    = "#{build_dir}/source"
         
     | 
| 
      
 22 
     | 
    
         
            +
                  @source_dir    = "./emails/#{template_name}"
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @scss_dir      = "./assets/css/#{template_name}"
         
     | 
| 
      
 24 
     | 
    
         
            +
                  @css_style     = attrs[:'css-style'].to_sym
         
     | 
| 
      
 25 
     | 
    
         
            +
                  @asset_server  = ENV['ASSET_SERVER'] || '/assets'
         
     | 
| 
      
 26 
     | 
    
         
            +
                  post_initialize(attrs)
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                def post_initialize(*)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  nil
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                def create_build_directories
         
     | 
| 
      
 34 
     | 
    
         
            +
                  return if Dir.exist? build_dir
         
     | 
| 
      
 35 
     | 
    
         
            +
                  Dir.mkdir "build" unless Dir.exist? "./build"
         
     | 
| 
      
 36 
     | 
    
         
            +
                  Dir.mkdir(build_dir)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  Dir.mkdir("#{build_dir}/source")
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                def build
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                def load_css
         
     | 
| 
      
 44 
     | 
    
         
            +
                  css_file = "#{markup_dir}/inline.css"
         
     | 
| 
      
 45 
     | 
    
         
            +
                  build_css unless File.file? css_file
         
     | 
| 
      
 46 
     | 
    
         
            +
                  css = File.read(css_file)
         
     | 
| 
      
 47 
     | 
    
         
            +
                  css
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                def build_css
         
     | 
| 
      
 51 
     | 
    
         
            +
                  compile_scss(source: "#{scss_dir}/inline.scss", destination: "#{markup_dir}/inline.css")
         
     | 
| 
      
 52 
     | 
    
         
            +
                  compile_scss(source: "#{scss_dir}/include.scss", destination: "#{markup_dir}/include.css")
         
     | 
| 
      
 53 
     | 
    
         
            +
                  @css = load_css
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                def compile_scss(attrs = {})
         
     | 
| 
      
 57 
     | 
    
         
            +
                  source_file      = attrs[:source]
         
     | 
| 
      
 58 
     | 
    
         
            +
                  destination_file = attrs[:destination]
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                  if File.file? source_file
         
     | 
| 
      
 61 
     | 
    
         
            +
                    content = Tilt::ScssTemplate.new(source_file, style: @css_style).render
         
     | 
| 
      
 62 
     | 
    
         
            +
                    create_file(content: content, path: destination_file)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  else
         
     | 
| 
      
 64 
     | 
    
         
            +
                    say 'Build failed. ', :red
         
     | 
| 
      
 65 
     | 
    
         
            +
                    say "#{source_file}.scss for #{template_name} not found."
         
     | 
| 
      
 66 
     | 
    
         
            +
                  end
         
     | 
| 
      
 67 
     | 
    
         
            +
                end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                def create_file(attrs)
         
     | 
| 
      
 70 
     | 
    
         
            +
                  content = attrs[:content]
         
     | 
| 
      
 71 
     | 
    
         
            +
                  path    = attrs[:path]
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                  file = File.new(path, 'w')
         
     | 
| 
      
 74 
     | 
    
         
            +
                  file.write(content)
         
     | 
| 
      
 75 
     | 
    
         
            +
                  file.close
         
     | 
| 
      
 76 
     | 
    
         
            +
                  say '    create  ', :green
         
     | 
| 
      
 77 
     | 
    
         
            +
                  say path.gsub(/\A.\//, '')
         
     | 
| 
      
 78 
     | 
    
         
            +
                  file
         
     | 
| 
      
 79 
     | 
    
         
            +
                end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                def use_asset_server(markup = '')
         
     | 
| 
      
 82 
     | 
    
         
            +
                  replaced = "#{asset_server}/"
         
     | 
| 
      
 83 
     | 
    
         
            +
                  output = markup.gsub('/assets/', replaced)
         
     | 
| 
      
 84 
     | 
    
         
            +
                  output
         
     | 
| 
      
 85 
     | 
    
         
            +
                end
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                def flatten_inlined_css(markup)
         
     | 
| 
      
 88 
     | 
    
         
            +
                  copy = ''
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                  # loop through lines so we have the line number
         
     | 
| 
      
 91 
     | 
    
         
            +
                  markup.lines.each_with_index do |line, i|
         
     | 
| 
      
 92 
     | 
    
         
            +
                    f = Flattener.new(line).flatten
         
     | 
| 
      
 93 
     | 
    
         
            +
                    if f.flattened?
         
     | 
| 
      
 94 
     | 
    
         
            +
                      say " flattened  CSS #{f.flattened_keys} ", :yellow
         
     | 
| 
      
 95 
     | 
    
         
            +
                      say "#{i}: #{f.source.strip}"
         
     | 
| 
      
 96 
     | 
    
         
            +
                      copy << f.flattened
         
     | 
| 
      
 97 
     | 
    
         
            +
                    else
         
     | 
| 
      
 98 
     | 
    
         
            +
                      copy << f.source
         
     | 
| 
      
 99 
     | 
    
         
            +
                    end
         
     | 
| 
      
 100 
     | 
    
         
            +
                  end
         
     | 
| 
      
 101 
     | 
    
         
            +
                  copy
         
     | 
| 
      
 102 
     | 
    
         
            +
                end
         
     | 
| 
      
 103 
     | 
    
         
            +
              end
         
     | 
| 
      
 104 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,61 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Antwort
         
     | 
| 
      
 2 
     | 
    
         
            +
              class EmailBuilder < Builder
         
     | 
| 
      
 3 
     | 
    
         
            +
                attr_accessor :html_markup
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                def post_initialize(*)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  app     ||= Antwort::Server.new
         
     | 
| 
      
 7 
     | 
    
         
            +
                  mock    ||= Rack::MockRequest.new(app)
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  request = mock.get("/template/#{template_name}")
         
     | 
| 
      
 10 
     | 
    
         
            +
                  if request.status == 200
         
     | 
| 
      
 11 
     | 
    
         
            +
                    create_build_directories
         
     | 
| 
      
 12 
     | 
    
         
            +
                    @html_markup  = remove_livereload(request.body)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    @inlined_file = "#{build_dir}/#{template_name}.html"
         
     | 
| 
      
 14 
     | 
    
         
            +
                  else
         
     | 
| 
      
 15 
     | 
    
         
            +
                    say 'Error: ', :red
         
     | 
| 
      
 16 
     | 
    
         
            +
                    say "Template '#{template_name}' not found."
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                def build
         
     | 
| 
      
 21 
     | 
    
         
            +
                  unless html_markup.nil?
         
     | 
| 
      
 22 
     | 
    
         
            +
                    build_css
         
     | 
| 
      
 23 
     | 
    
         
            +
                    build_html
         
     | 
| 
      
 24 
     | 
    
         
            +
                    inline_css
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  until File.exist?(@inlined_file)
         
     | 
| 
      
 28 
     | 
    
         
            +
                    sleep 1
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
                  return true
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                def build_html
         
     | 
| 
      
 34 
     | 
    
         
            +
                  markup = html_markup
         
     | 
| 
      
 35 
     | 
    
         
            +
                  markup = markup.gsub("/assets/#{template_name}/inline.css", 'inline.css')
         
     | 
| 
      
 36 
     | 
    
         
            +
                                 .gsub("/assets/#{template_name}/include.css", 'include.css')
         
     | 
| 
      
 37 
     | 
    
         
            +
                  create_file(content: markup, path: "#{markup_dir}/#{template_name}.html")
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                def inline_css
         
     | 
| 
      
 41 
     | 
    
         
            +
                  markup   = preserve_nbsps(html_markup)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  document = Roadie::Document.new(markup)
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                  document.asset_providers << Roadie::NullProvider.new
         
     | 
| 
      
 45 
     | 
    
         
            +
                  document.add_css(css)
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  inlined = restore_nbsps(document.transform)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  inlined = cleanup_markup(inlined)
         
     | 
| 
      
 49 
     | 
    
         
            +
                  lnlined = remove_roadie_flags(inlined)
         
     | 
| 
      
 50 
     | 
    
         
            +
                  inlined = remove_excessive_newlines(inlined)
         
     | 
| 
      
 51 
     | 
    
         
            +
                  inlined = flatten_inlined_css(inlined)
         
     | 
| 
      
 52 
     | 
    
         
            +
                  create_file(content: inlined, path: @inlined_file)
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                def cleanup_markup(markup)
         
     | 
| 
      
 56 
     | 
    
         
            +
                  content = use_asset_server(markup)
         
     | 
| 
      
 57 
     | 
    
         
            +
                  content = add_included_css(content)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  content
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
              end
         
     | 
| 
      
 61 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,37 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Antwort
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Flattener
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
                attr_reader :source, :styles, :flattened, :flattened_keys
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                def initialize(source='')
         
     | 
| 
      
 7 
     | 
    
         
            +
                  @source = source
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @styles = find_styles
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @flattened_keys = []
         
     | 
| 
      
 10 
     | 
    
         
            +
                  self
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def flatten
         
     | 
| 
      
 14 
     | 
    
         
            +
                  copy = String.new(@source)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @styles.each do |m|
         
     | 
| 
      
 16 
     | 
    
         
            +
                    style = Antwort::Style.new(m)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    @flattened_keys.concat(style.duplicate_keys) if style.duplicates?
         
     | 
| 
      
 18 
     | 
    
         
            +
                    copy.sub!(m, style.flattened_str) # flattened_str removes extra spaces and trailing semicolons
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  @flattened = copy
         
     | 
| 
      
 22 
     | 
    
         
            +
                  self
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def flattened?
         
     | 
| 
      
 26 
     | 
    
         
            +
                  @flattened_keys.length > 0
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                private
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  def find_styles
         
     | 
| 
      
 32 
     | 
    
         
            +
                    a = []
         
     | 
| 
      
 33 
     | 
    
         
            +
                    @source.scan(/style="(.+?)"/).each { |match| a.push(match.first) } # first is regex group `(.+?)`
         
     | 
| 
      
 34 
     | 
    
         
            +
                    a
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,82 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Antwort
         
     | 
| 
      
 2 
     | 
    
         
            +
              module LogicHelpers
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
                def preserve_nbsps(html = '')
         
     | 
| 
      
 5 
     | 
    
         
            +
                  html.gsub(/ /, '%nbspace%')
         
     | 
| 
      
 6 
     | 
    
         
            +
                end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                def restore_nbsps(html = '')
         
     | 
| 
      
 9 
     | 
    
         
            +
                  html.gsub(/%nbspace%/, ' ')
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def preserve_logic(html = '')
         
     | 
| 
      
 13 
     | 
    
         
            +
                  html = preserve_comments(html)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  html = preserve_conditionals(html) # conditionals before loops, in case we have them inside loops
         
     | 
| 
      
 15 
     | 
    
         
            +
                  html = preserve_loops(html)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  html = preserve_variables(html)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  html = preserve_assignments(html)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  html = convert_partials_to_includes(html)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  html = convert_helper_wrappers(html)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  html = preserve_leftover_statements(html) # must be last
         
     | 
| 
      
 21 
     | 
    
         
            +
                  html
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                def preserve_conditionals(html = '')
         
     | 
| 
      
 25 
     | 
    
         
            +
                  html.gsub(%r{<%\s*if (.*?)%>}, '{% if \1 %}')         # if
         
     | 
| 
      
 26 
     | 
    
         
            +
                      .gsub(%r{<%\s*unless (.*?)%>}, '{% if !( \1) %}') # unless
         
     | 
| 
      
 27 
     | 
    
         
            +
                      .gsub(%r{<%\s*elsif(.*?)%>}, '{% elseif\1%}')     # elsif
         
     | 
| 
      
 28 
     | 
    
         
            +
                      .gsub(%r{<%\s*else\s*%>}, '{% else %}')           # else
         
     | 
| 
      
 29 
     | 
    
         
            +
                      .gsub(%r{<%\s*end\s*%>}, '{% end %}')             # end
         
     | 
| 
      
 30 
     | 
    
         
            +
                      .gsub(/[ \t]{2,}%}/, ' %}')                       # remove extra white space, e.g. {% else    %}
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                def preserve_loops(html = '')
         
     | 
| 
      
 34 
     | 
    
         
            +
                  html.gsub(%r{<%\s+(.*)(\.each\s+do\s+\|)\s*(\S+)\s*(\|\s+)%>}, '{% for \3 in \1 %}')
         
     | 
| 
      
 35 
     | 
    
         
            +
                      .gsub(%r{<%\s+(.*)(\.each_with_index\s+do\s+\|)\s*(\S+)\s*,\s*(\S+)\s*(\|\s+)%>}, '{% for \3 in \1 with: {@index: \4} %}')
         
     | 
| 
      
 36 
     | 
    
         
            +
                      .gsub(%r{<%\s*end\s*%>}, '{% end %}')
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                def preserve_comments(html = '')
         
     | 
| 
      
 40 
     | 
    
         
            +
                  html.gsub(%r{<%[ \t]*#(.*)%>},'{#\1#}')
         
     | 
| 
      
 41 
     | 
    
         
            +
                      .gsub(/{#([^=\s])/, '{# \1')      # {#foo #} ->{# foo #}
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                def preserve_variables(html = '')
         
     | 
| 
      
 45 
     | 
    
         
            +
                  html.gsub(/\[:(.*?)\]/, '.\1')        # a[:b][:c] -> a.b.c
         
     | 
| 
      
 46 
     | 
    
         
            +
                      .gsub(/\['(.*?)'\]/, '.\1')       # a['b'] -> a.b
         
     | 
| 
      
 47 
     | 
    
         
            +
                      .gsub(/\["(.*?)"\]/, '.\1')       # a["b"] -> a.b
         
     | 
| 
      
 48 
     | 
    
         
            +
                      .gsub(%r{<%=(.*?)%>}, '{{\1}}')   # assume leftover erb output are variables
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                def preserve_assignments(html = '')
         
     | 
| 
      
 52 
     | 
    
         
            +
                  html.gsub(%r{<%\s+([A-Za-z0-9_]+)\s*(\|\|=)\s*(.*)\s+%>}, '{% set \1 = \1 || \3 %}')
         
     | 
| 
      
 53 
     | 
    
         
            +
                      .gsub(%r{<%\s+([A-Za-z0-9_]+)\s*(=)\s*(.*)\s+%>}, '{% set \1 = \3 %}')
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                def preserve_leftover_statements(html = '')
         
     | 
| 
      
 57 
     | 
    
         
            +
                  html.gsub(%r{<%\s*(.*?)?%>}, '{% \1%}') # no trailing space because group captures it
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                def restore_variables_in_links(html = '')
         
     | 
| 
      
 61 
     | 
    
         
            +
                  html.gsub('%7B%7B%20','{{ ')
         
     | 
| 
      
 62 
     | 
    
         
            +
                      .gsub('%20%7D%7D',' }}')
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                def convert_partials_to_includes(html = '')
         
     | 
| 
      
 66 
     | 
    
         
            +
                  html.gsub(%r{{{ partial :(.+?) }}}, '{% include \1 %}')
         
     | 
| 
      
 67 
     | 
    
         
            +
                      .gsub(%r{{% include (.+),\s+locals:(.+?)%}}, '{% include \1 with:\2%}')
         
     | 
| 
      
 68 
     | 
    
         
            +
                      .gsub(%r{(<%=\s+?partial\s+?:)(.+?),(.+?)(locals:)((.|\n)+?)(%>)}, '{% include \2 with:\5%}') # multiline partials not caught in presumably leftover variable
         
     | 
| 
      
 69 
     | 
    
         
            +
                end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                def convert_helper_wrappers(html = '')
         
     | 
| 
      
 72 
     | 
    
         
            +
                  html.gsub(%r{{{ button(.+?)}}}, '{% button\1%}')
         
     | 
| 
      
 73 
     | 
    
         
            +
                      .gsub(%r{{{ image_tag(.+?)}}}, '{% image_tag\1%}')
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                def cleanup_logic(html = '')
         
     | 
| 
      
 77 
     | 
    
         
            +
                  html.gsub(%r{({%|{{)(.*?)(<)(.*?)(}}|%})}, '\1\2<\4\5') # <
         
     | 
| 
      
 78 
     | 
    
         
            +
                      .gsub(%r{({%|{{)(.*?)(>)(.*?)(}}|%})}, '\1\2>\4\5') # >
         
     | 
| 
      
 79 
     | 
    
         
            +
                      .gsub(/&&/, '&&')
         
     | 
| 
      
 80 
     | 
    
         
            +
                end
         
     | 
| 
      
 81 
     | 
    
         
            +
              end
         
     | 
| 
      
 82 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,29 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Antwort
         
     | 
| 
      
 2 
     | 
    
         
            +
              module MarkupSanitizers
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
                def remove_livereload(markup = '')
         
     | 
| 
      
 5 
     | 
    
         
            +
                  markup.gsub(/<script.*?>(\s|\S)*<\/script>/i, '')
         
     | 
| 
      
 6 
     | 
    
         
            +
                        .gsub(/(<head.*?>\n)(\s*\n)*/i, '\1')
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def add_included_css(markup = '')
         
     | 
| 
      
 10 
     | 
    
         
            +
                  css = File.read("#{markup_dir}/include.css")
         
     | 
| 
      
 11 
     | 
    
         
            +
                  css_markup = "</title>\n<style type=\"text/css\">\n" + css + "</style>\n"
         
     | 
| 
      
 12 
     | 
    
         
            +
                  markup.gsub(%r{</title>}i, css_markup)
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def remove_roadie_flags(markup = '')
         
     | 
| 
      
 16 
     | 
    
         
            +
                  markup.gsub(' data-roadie-ignore', '')
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def remove_excessive_newlines(markup = '')
         
     | 
| 
      
 20 
     | 
    
         
            +
                  markup.gsub(/^([ \t]*\n){3,}/m, "\n\n")
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                def remove_extra_dom(html = '')
         
     | 
| 
      
 24 
     | 
    
         
            +
                  html.gsub(/\<!(.*)\<body.*?\>/im, '')
         
     | 
| 
      
 25 
     | 
    
         
            +
                      .gsub(%r{</body>.*?</html>}im, '')
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,80 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Antwort
         
     | 
| 
      
 2 
     | 
    
         
            +
              class PartialBuilder < Builder
         
     | 
| 
      
 3 
     | 
    
         
            +
                attr_reader :templates
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                def post_initialize(*)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  @templates = list_partials(source_dir).push('index.html.erb')
         
     | 
| 
      
 7 
     | 
    
         
            +
                  if templates.length < 1
         
     | 
| 
      
 8 
     | 
    
         
            +
                    say 'Error: ', :red
         
     | 
| 
      
 9 
     | 
    
         
            +
                    puts "No partials found in #{template_name} folder."
         
     | 
| 
      
 10 
     | 
    
         
            +
                    return
         
     | 
| 
      
 11 
     | 
    
         
            +
                  else
         
     | 
| 
      
 12 
     | 
    
         
            +
                    create_build_directories
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                def build
         
     | 
| 
      
 17 
     | 
    
         
            +
                  @css = load_css
         
     | 
| 
      
 18 
     | 
    
         
            +
                  templates.each { |t| build_html t }
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def build_html(partial_name)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  source_file = "#{source_dir}/#{partial_name}"
         
     | 
| 
      
 23 
     | 
    
         
            +
                  source      = File.read(source_file)
         
     | 
| 
      
 24 
     | 
    
         
            +
                  markup      = preserve_logic(source)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  markup      = preserve_nbsps(markup)
         
     | 
| 
      
 26 
     | 
    
         
            +
                  markup      = preserve_operators_from_nokogiri(markup)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  inlined     = inline(markup)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  inlined     = restore_nbsps(inlined)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  inlined     = flatten_inlined_css(inlined)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  filename    = adjust_filename(partial_name)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  create_file(content: inlined, path: "#{build_dir}/#{filename}")
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                def inline(markup)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  # Force a complete DOM tree before inlining for nokogiri
         
     | 
| 
      
 36 
     | 
    
         
            +
                  # Otherwise we have random <p> at beginning of document
         
     | 
| 
      
 37 
     | 
    
         
            +
                  html = add_nokogiri_wrapper(markup)
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  document = Roadie::Document.new html
         
     | 
| 
      
 40 
     | 
    
         
            +
                  document.add_css(css)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  inlined  = document.transform
         
     | 
| 
      
 42 
     | 
    
         
            +
                  inlined  = cleanup(inlined)
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                  remove_nokogiri_wrapper(inlined)
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                def adjust_filename(filename)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  filename = @template_name if filename == 'index.html.erb'
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                  name = filename.gsub('.erb', '')
         
     | 
| 
      
 51 
     | 
    
         
            +
                  name << '.html' unless name[-5, 5] == '.html'
         
     | 
| 
      
 52 
     | 
    
         
            +
                  name = '_' << name unless name[0] == '_'
         
     | 
| 
      
 53 
     | 
    
         
            +
                  name
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                def cleanup(html = '')
         
     | 
| 
      
 57 
     | 
    
         
            +
                  code = remove_extra_dom(html)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  code = cleanup_logic(code)
         
     | 
| 
      
 59 
     | 
    
         
            +
                  code = restore_variables_in_links(code)
         
     | 
| 
      
 60 
     | 
    
         
            +
                  code
         
     | 
| 
      
 61 
     | 
    
         
            +
                end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                private
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                def add_nokogiri_wrapper(html = '')
         
     | 
| 
      
 66 
     | 
    
         
            +
                  html = '<div id="valid-dom-tree">' + html + '</div><!--/#valid-dom-tree-->'
         
     | 
| 
      
 67 
     | 
    
         
            +
                  html
         
     | 
| 
      
 68 
     | 
    
         
            +
                end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                def remove_nokogiri_wrapper(html = '')
         
     | 
| 
      
 71 
     | 
    
         
            +
                  html.gsub('<div id="valid-dom-tree">', '')
         
     | 
| 
      
 72 
     | 
    
         
            +
                      .gsub(%r{</div>(\s*)<!--/#valid-dom-tree-->}, '')
         
     | 
| 
      
 73 
     | 
    
         
            +
                end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                def preserve_operators_from_nokogiri(html = '')
         
     | 
| 
      
 76 
     | 
    
         
            +
                  html.gsub(%r{{%\s*if(.*?)<(.*?)%}}, '{%\1<\2%}')
         
     | 
| 
      
 77 
     | 
    
         
            +
                      .gsub(%r{{%\s*if(.*?)>(.*?)%}}, '{%\1>\2%}')
         
     | 
| 
      
 78 
     | 
    
         
            +
                end
         
     | 
| 
      
 79 
     | 
    
         
            +
              end
         
     | 
| 
      
 80 
     | 
    
         
            +
            end
         
     |