├── spec ├── test_app │ ├── log │ │ └── .keep │ ├── app │ │ ├── views │ │ │ ├── inky │ │ │ │ ├── layout.html.erb │ │ │ │ ├── slim.html.inky │ │ │ │ ├── simple.html.inky │ │ │ │ ├── _inky_partial.html.inky │ │ │ │ ├── explicit_builder.html.inky-builder │ │ │ │ ├── explicit_slim.html.inky-slim │ │ │ │ └── non_inky.html.erb │ │ │ └── layouts │ │ │ │ ├── application.html.erb │ │ │ │ └── inky_layout.html.inky │ │ ├── helpers │ │ │ └── application_helper.rb │ │ ├── controllers │ │ │ ├── application_controller.rb │ │ │ └── inky_controller.rb │ │ └── mailers │ │ │ └── application_mailer.rb │ ├── config │ │ ├── routes.rb │ │ ├── initializers │ │ │ ├── secret_token.rb │ │ │ ├── session_store.rb │ │ │ ├── mime_types.rb │ │ │ ├── application_controller_renderer.rb │ │ │ ├── filter_parameter_logging.rb │ │ │ ├── cookies_serializer.rb │ │ │ ├── backtrace_silencers.rb │ │ │ ├── assets.rb │ │ │ ├── wrap_parameters.rb │ │ │ ├── inflections.rb │ │ │ └── new_framework_defaults.rb │ │ ├── spring.rb │ │ ├── environment.rb │ │ ├── cable.yml │ │ ├── boot.rb │ │ ├── database.yml │ │ ├── locales │ │ │ └── en.yml │ │ ├── application.rb │ │ ├── secrets.yml │ │ ├── environments │ │ │ ├── test.rb │ │ │ ├── development.rb │ │ │ └── production.rb │ │ └── puma.rb │ ├── config.ru │ ├── Rakefile │ └── spec │ │ ├── helper.rb │ │ └── features │ │ └── inky_spec.rb ├── cases │ ├── general │ │ ├── no_tag.inky │ │ ├── multiple_root.inky │ │ ├── root_within_text.inky │ │ └── void_html_elements.inky │ ├── menu │ │ ├── menu_with_align.inky │ │ ├── menu.inky │ │ ├── item.inky │ │ └── menu_with_items.inky │ ├── callout │ │ ├── basic.inky │ │ └── with_attributes.inky │ ├── wrapper │ │ ├── basic.inky │ │ ├── with_align.inky │ │ └── with_attributes.inky │ ├── button │ │ ├── no_link.inky │ │ ├── with_expand_class.inky │ │ ├── with_link.inky │ │ ├── with_image.inky │ │ └── with_tricky_class.inky │ ├── grid │ │ ├── row.inky │ │ ├── columns.inky │ │ ├── container.inky │ │ ├── container_with_align.inky │ │ └── row_with_columns.inky │ └── spacer │ │ ├── basic.inky │ │ ├── with_size.inky │ │ ├── with_size_lg.inky │ │ ├── with_size_sm.inky │ │ └── with_size_sm_and_lg.inky ├── inky_spec.rb ├── configuration_spec.rb ├── spec_helper.rb ├── cases_spec.rb ├── grid_spec.rb └── components_spec.rb ├── lib ├── generators │ └── inky │ │ ├── templates │ │ ├── foundation_emails.scss │ │ ├── mailer_layout.html.slim │ │ ├── mailer_layout.html.haml │ │ └── mailer_layout.html.erb │ │ └── install_generator.rb ├── inky │ ├── rails │ │ ├── version.rb │ │ ├── engine.rb │ │ └── template_handler.rb │ ├── configuration.rb │ └── component_factory.rb └── inky.rb ├── .gitignore ├── gemfiles ├── rails_3.gemfile ├── rails_4.gemfile └── rails_5.gemfile ├── Gemfile ├── Rakefile ├── .travis.yml ├── LICENSE ├── inky.gemspec ├── .rubocop.yml ├── README.md └── Gemfile.lock /spec/test_app/log/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/cases/general/no_tag.inky: -------------------------------------------------------------------------------- 1 | Very simple test... 2 | -------------------------------------------------------------------------------- /spec/cases/menu/menu_with_align.inky: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /spec/cases/callout/basic.inky: -------------------------------------------------------------------------------- 1 | Simple callout 2 | -------------------------------------------------------------------------------- /spec/cases/menu/menu.inky: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /spec/cases/wrapper/basic.inky: -------------------------------------------------------------------------------- 1 | In the wrap 2 | -------------------------------------------------------------------------------- /spec/test_app/app/views/inky/layout.html.erb: -------------------------------------------------------------------------------- 1 | Using inky layout 2 | -------------------------------------------------------------------------------- /spec/cases/button/no_link.inky: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /spec/test_app/app/views/inky/slim.html.inky: -------------------------------------------------------------------------------- 1 | container 2 | | Slim example 3 | -------------------------------------------------------------------------------- /spec/cases/grid/row.inky: -------------------------------------------------------------------------------- 1 | columns here 2 | -------------------------------------------------------------------------------- /spec/cases/wrapper/with_align.inky: -------------------------------------------------------------------------------- 1 | In the wrap 2 | -------------------------------------------------------------------------------- /lib/generators/inky/templates/foundation_emails.scss: -------------------------------------------------------------------------------- 1 | @import "foundation-emails"; 2 | -------------------------------------------------------------------------------- /spec/test_app/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /spec/cases/general/multiple_root.inky: -------------------------------------------------------------------------------- 1 | Hey 2 | You 3 | -------------------------------------------------------------------------------- /spec/test_app/app/views/inky/simple.html.inky: -------------------------------------------------------------------------------- 1 | Simplistic example 2 | -------------------------------------------------------------------------------- /spec/cases/general/root_within_text.inky: -------------------------------------------------------------------------------- 1 | Text before 2 | Ho 3 | Text after 4 | -------------------------------------------------------------------------------- /spec/cases/grid/columns.inky: -------------------------------------------------------------------------------- 1 | First column 2 | -------------------------------------------------------------------------------- /spec/cases/grid/container.inky: -------------------------------------------------------------------------------- 1 | some content 2 | -------------------------------------------------------------------------------- /spec/cases/grid/container_with_align.inky: -------------------------------------------------------------------------------- 1 | some content 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | pkg 3 | spec/_cases_output 4 | spec/test_app/log/*.log 5 | spec/test_app/tmp/ 6 | -------------------------------------------------------------------------------- /spec/test_app/app/views/inky/_inky_partial.html.inky: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /spec/test_app/app/views/inky/explicit_builder.html.inky-builder: -------------------------------------------------------------------------------- 1 | xml.container("Built with builder") 2 | -------------------------------------------------------------------------------- /spec/test_app/app/views/inky/explicit_slim.html.inky-slim: -------------------------------------------------------------------------------- 1 | container 2 | | Explicit slim example 3 | -------------------------------------------------------------------------------- /spec/cases/menu/item.inky: -------------------------------------------------------------------------------- 1 | An item 2 | -------------------------------------------------------------------------------- /spec/cases/spacer/basic.inky: -------------------------------------------------------------------------------- 1 |
2 | Stuff on top 3 | 4 | Stuff on bottom 5 |
6 | -------------------------------------------------------------------------------- /spec/cases/wrapper/with_attributes.inky: -------------------------------------------------------------------------------- 1 | In the wrap 2 | -------------------------------------------------------------------------------- /gemfiles/rails_3.gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "rails", "~>3.0" 4 | 5 | gemspec :path => "../" 6 | -------------------------------------------------------------------------------- /gemfiles/rails_4.gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "rails", "~>4.0" 4 | 5 | gemspec :path => "../" 6 | -------------------------------------------------------------------------------- /gemfiles/rails_5.gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "rails", "~>5.0" 4 | 5 | gemspec :path => "../" 6 | -------------------------------------------------------------------------------- /spec/cases/button/with_expand_class.inky: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /spec/test_app/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%= yield -%> 4 | 5 | -------------------------------------------------------------------------------- /spec/test_app/config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | get ':controller(/:action(/:id(.:format)))' 3 | end 4 | -------------------------------------------------------------------------------- /spec/cases/button/with_link.inky: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /spec/cases/callout/with_attributes.inky: -------------------------------------------------------------------------------- 1 | 2 |

I'm in a callout!

3 |
4 | -------------------------------------------------------------------------------- /spec/cases/button/with_image.inky: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /spec/test_app/app/views/inky/non_inky.html.erb: -------------------------------------------------------------------------------- 1 | 2 | <%= render @partial_name, foo: 'bar' if @partial_name %> 3 | 4 | -------------------------------------------------------------------------------- /spec/cases/spacer/with_size.inky: -------------------------------------------------------------------------------- 1 |
2 | Stuff on top 3 | 4 | Stuff on bottom 5 |
6 | -------------------------------------------------------------------------------- /spec/cases/spacer/with_size_lg.inky: -------------------------------------------------------------------------------- 1 |
2 | Stuff on top 3 | 4 |

Stuff on bottom

5 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in inky.gemspec 4 | gemspec 5 | 6 | gem 'rspec-core' 7 | gem 'rspec-expectations' 8 | -------------------------------------------------------------------------------- /spec/cases/spacer/with_size_sm.inky: -------------------------------------------------------------------------------- 1 |
2 | Stuff on top 3 | 4 | Stuff on bottom 5 |
6 | -------------------------------------------------------------------------------- /spec/test_app/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | protect_from_forgery with: :exception 3 | end 4 | -------------------------------------------------------------------------------- /spec/test_app/app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | class ApplicationMailer < ActionMailer::Base 2 | default from: 'from@example.com' 3 | layout 'mailer' 4 | end 5 | -------------------------------------------------------------------------------- /spec/test_app/config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 1 | TestApp::Application.config.secret_token = 'whatevericouldntcarelessaboutthisthingwerejusttestingafterallarentwe' 2 | -------------------------------------------------------------------------------- /spec/test_app/config/spring.rb: -------------------------------------------------------------------------------- 1 | %w( 2 | .ruby-version 3 | .rbenv-vars 4 | tmp/restart.txt 5 | tmp/caching-dev.txt 6 | ).each { |path| Spring.watch(path) } 7 | -------------------------------------------------------------------------------- /spec/test_app/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require_relative 'config/environment' 4 | 5 | run Rails.application 6 | -------------------------------------------------------------------------------- /spec/cases/general/void_html_elements.inky: -------------------------------------------------------------------------------- 1 | 2 | Hello 3 |
4 | Here's an image: 5 | 6 |
7 | -------------------------------------------------------------------------------- /spec/cases/spacer/with_size_sm_and_lg.inky: -------------------------------------------------------------------------------- 1 |
2 | Stuff on top 3 | 4 | Stuff on bottom 5 |
6 | -------------------------------------------------------------------------------- /spec/test_app/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative 'application' 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /lib/inky/rails/version.rb: -------------------------------------------------------------------------------- 1 | module Inky 2 | module Rails 3 | VERSION = "1.3.7.2".freeze 4 | end 5 | NODE_VERSION, GEM_VERSION = Rails::VERSION.rpartition('.').map(&:freeze) 6 | end 7 | -------------------------------------------------------------------------------- /spec/cases/grid/row_with_columns.inky: -------------------------------------------------------------------------------- 1 | 2 | First column 3 | Second column 4 | Last column 5 | 6 | -------------------------------------------------------------------------------- /spec/test_app/config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: async 3 | 4 | test: 5 | adapter: async 6 | 7 | production: 8 | adapter: redis 9 | url: redis://localhost:6379/1 10 | -------------------------------------------------------------------------------- /spec/test_app/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.session_store :cookie_store, key: '_test_app_session' 4 | -------------------------------------------------------------------------------- /spec/test_app/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /spec/cases/menu/menu_with_items.inky: -------------------------------------------------------------------------------- 1 | 2 | An item 3 | Another Item 4 | Last Item 5 | 6 | -------------------------------------------------------------------------------- /spec/test_app/config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # ApplicationController.renderer.defaults.merge!( 4 | # http_host: 'example.org', 5 | # https: false 6 | # ) 7 | -------------------------------------------------------------------------------- /spec/test_app/Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require_relative 'config/application' 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /spec/test_app/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /spec/test_app/config/boot.rb: -------------------------------------------------------------------------------- 1 | # Set up gems listed in the Gemfile. 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__) 3 | 4 | require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) 5 | $LOAD_PATH.unshift File.expand_path('../../../lib', __dir__) 6 | -------------------------------------------------------------------------------- /spec/test_app/app/views/layouts/inky_layout.html.inky: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <%= controller.controller_name %> : <%= controller.action_name %> 5 | 6 | 7 | 8 | <%= yield %> 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require 'rubocop/rake_task' 3 | 4 | RuboCop::RakeTask.new 5 | 6 | begin 7 | require 'rspec/core/rake_task' 8 | RSpec::Core::RakeTask.new(:spec) 9 | rescue LoadError 10 | end 11 | 12 | task test_all: [:spec, :rubocop] 13 | 14 | task default: :test_all 15 | -------------------------------------------------------------------------------- /spec/test_app/config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Specify a serializer for the signed and encrypted cookie jars. 4 | # Valid options are :json, :marshal, and :hybrid. 5 | Rails.application.config.action_dispatch.cookies_serializer = :json 6 | -------------------------------------------------------------------------------- /spec/test_app/app/controllers/inky_controller.rb: -------------------------------------------------------------------------------- 1 | class InkyController < ApplicationController 2 | layout 'inky_layout', only: [:layout] 3 | 4 | def non_inky 5 | @partial_name = params[:partial].presence 6 | end 7 | 8 | %w[simple layout slim explicit_slim explicit_builder].each{ |m| define_method(m){} } 9 | end 10 | -------------------------------------------------------------------------------- /lib/inky/rails/engine.rb: -------------------------------------------------------------------------------- 1 | require 'rails/engine' 2 | 3 | module Inky 4 | module Rails 5 | class Engine < ::Rails::Engine 6 | if config.respond_to?(:annotations) 7 | config.annotations.register_extensions("inky") { |annotation| // } 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: ruby 3 | rvm: 4 | - 2.0.0 5 | - 2.2.5 6 | gemfile: 7 | - gemfiles/rails_3.gemfile 8 | - gemfiles/rails_4.gemfile 9 | - gemfiles/rails_5.gemfile 10 | matrix: 11 | exclude: 12 | - rvm: 2.0.0 13 | gemfile: gemfiles/rails_5.gemfile 14 | before_install: 15 | - gem install bundler 16 | - 'npm install -g inky-cli' 17 | -------------------------------------------------------------------------------- /spec/test_app/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /spec/test_app/spec/helper.rb: -------------------------------------------------------------------------------- 1 | # Configure Rails Envinronment 2 | ENV["RAILS_ENV"] = "test" 3 | 4 | require_relative "../config/environment.rb" 5 | require 'capybara/rspec' 6 | require 'capybara/rails' 7 | require_relative '../../spec_helper.rb' 8 | require 'slim' 9 | 10 | Rails.backtrace_cleaner.remove_silencers! 11 | RSpec.configure do |config| 12 | config.expect_with(:rspec) { |c| c.syntax = [:should, :expect] } 13 | # config.infer_spec_type_from_file_location! 14 | end 15 | -------------------------------------------------------------------------------- /spec/cases/button/with_tricky_class.inky: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | 12 | 13 | 16 | 17 | 20 | -------------------------------------------------------------------------------- /spec/inky_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe "Inky#release_the_kraken" do 4 | it "works on binary text" do 5 | input = ''.b 6 | expected = <<-HTML 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | HTML 15 | 16 | output = Inky::Core.new.release_the_kraken(input) 17 | expect_same_html(output, expected) 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/generators/inky/templates/mailer_layout.html.slim: -------------------------------------------------------------------------------- 1 | doctype strict 2 | html[xmlns='http://www.w3.org/1999/xhtml'] 3 | head 4 | meta http-equiv="Content-Type" content="text/html; charset=utf-8" 5 | meta name="viewport" content="width=device-width" 6 | 7 | = stylesheet_link_tag "foundation_emails" 8 | 9 | body 10 | table.body data-made-with-foundation="" 11 | tr 12 | td.center align="center" valign="top" 13 | center 14 | container 15 | = yield 16 | -------------------------------------------------------------------------------- /lib/generators/inky/templates/mailer_layout.html.haml: -------------------------------------------------------------------------------- 1 | !!! Strict 2 | %html{:xmlns => "http://www.w3.org/1999/xhtml"} 3 | %head 4 | %meta{:content => "text/html; charset=utf-8", "http-equiv" => "Content-Type"}/ 5 | %meta{:content => "width=device-width", :name => "viewport"}/ 6 | = stylesheet_link_tag "foundation_emails" 7 | %body 8 | %table.body{"data-made-with-foundation" => ""} 9 | %tr 10 | %td.center{:align => "center", :valign => "top"} 11 | %center 12 | %container 13 | = yield 14 | -------------------------------------------------------------------------------- /spec/test_app/config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | # Rails.application.config.assets.version = '1.0' 5 | 6 | # Add additional assets to the asset load path 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | 9 | # Precompile additional assets. 10 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. 11 | # Rails.application.config.assets.precompile += %w( search.js ) 12 | -------------------------------------------------------------------------------- /spec/test_app/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /spec/test_app/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | # 7 | default: &default 8 | adapter: sqlite3 9 | pool: 5 10 | timeout: 5000 11 | 12 | development: 13 | <<: *default 14 | database: db/development.sqlite3 15 | 16 | # Warning: The database defined as "test" will be erased and 17 | # re-generated from your development database when you run "rake". 18 | # Do not set this db to the same as development or production. 19 | test: 20 | <<: *default 21 | database: db/test.sqlite3 22 | 23 | production: 24 | <<: *default 25 | database: db/production.sqlite3 26 | -------------------------------------------------------------------------------- /lib/generators/inky/templates/mailer_layout.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <%%= stylesheet_link_tag "foundation_emails" %> 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 |
14 |
15 | <%%= yield %> 16 |
17 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /spec/test_app/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /spec/test_app/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # To learn more, please read the Rails Internationalization guide 20 | # available at http://guides.rubyonrails.org/i18n.html. 21 | 22 | en: 23 | hello: "Hello world" 24 | -------------------------------------------------------------------------------- /spec/test_app/config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative 'boot' 2 | 3 | # Pick the frameworks you want: 4 | # require "active_record/railtie" 5 | require "action_controller/railtie" 6 | require "action_view/railtie" 7 | require "action_mailer/railtie" 8 | # require "active_job/railtie" 9 | # require "action_cable/engine" 10 | # require "rails/test_unit/railtie" 11 | # require "sprockets/railtie" 12 | 13 | Bundler.require(*Rails.groups) 14 | require "inky" 15 | 16 | module TestApp 17 | class Application < Rails::Application 18 | # Settings in config/environments/* take precedence over those specified here. 19 | # Application configuration should go into files in config/initializers 20 | # -- all .rb files in that directory are automatically loaded. 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/inky/configuration.rb: -------------------------------------------------------------------------------- 1 | module Inky 2 | # @return [Inky::Configuration] Inky's current configuration 3 | def self.configuration 4 | @configuration ||= Configuration.new 5 | end 6 | 7 | # Set Inky's configuration 8 | # @param config [Inky::Configuration] 9 | def self.configuration=(config) 10 | @configuration = config 11 | end 12 | 13 | # Modify Inky's current configuration 14 | # @yieldparam [Inky::Configuration] config current Inky config 15 | # ``` 16 | # Inky.configure do |config| 17 | # config.template_engine = :slim 18 | # config.column_count = 24 19 | # end 20 | # ``` 21 | def self.configure 22 | yield configuration 23 | end 24 | 25 | class Configuration 26 | attr_accessor :template_engine, :column_count 27 | 28 | def initialize 29 | @template_engine = :erb 30 | @column_count = 12 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /spec/test_app/config/secrets.yml: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key is used for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | 6 | # Make sure the secret is at least 30 characters and all random, 7 | # no regular words or you'll be exposed to dictionary attacks. 8 | # You can use `rails secret` to generate a secure secret key. 9 | 10 | # Make sure the secrets in this file are kept private 11 | # if you're sharing your code publicly. 12 | 13 | development: 14 | secret_key_base: aa0149c3e0f7d05116280fbd1c6bb6bac422024b1c46e859041316bf3cc0ae6db5e8807f3f30ed952ac0078fd824e085279f2cadd80ccfbc51feb54f902eab2e 15 | 16 | test: 17 | secret_key_base: ced0b68b3cfc4a63eae88c5be56f17e30b1ebd3b08ba61938764ad92f5a209c26c1abbb1fad59421b8c4de74f332c684ded1b3d968dea9e89696a7f483e3f3fe 18 | 19 | # Do not keep production secrets in the repository, 20 | # instead read values from the environment. 21 | production: 22 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2017 ZURB, inc. 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /spec/configuration_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe "Configuration" do 4 | around do |spec| 5 | Inky.configure do |config| 6 | old = config.template_engine 7 | spec.run 8 | config.template_engine = old 9 | end 10 | end 11 | 12 | it "default value is :erb" do 13 | Inky::Configuration.new.template_engine = :erb 14 | end 15 | 16 | describe "#configuration=" do 17 | it "can set template_engine" do 18 | config = Inky::Configuration.new 19 | config.template_engine = :haml 20 | expect(config.template_engine).to eq(:haml) 21 | end 22 | 23 | it "can set column_count" do 24 | config = Inky::Configuration.new 25 | config.column_count = 4 26 | expect(config.column_count).to eq(4) 27 | end 28 | end 29 | 30 | describe "#configuration=" do 31 | before do 32 | Inky.configure do |config| 33 | config.template_engine = :haml 34 | end 35 | end 36 | 37 | it "returns :haml as configured template_engine" do 38 | template_engine = Inky.configuration.template_engine 39 | 40 | expect(template_engine).to be_a(Symbol) 41 | expect(template_engine).to eq(:haml) 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /spec/test_app/config/initializers/new_framework_defaults.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | # 3 | # This file contains migration options to ease your Rails 5.0 upgrade. 4 | # 5 | # Read the Rails 5.0 release notes for more info on each option. 6 | 7 | # Enable per-form CSRF tokens. Previous versions had false. 8 | # Rails.application.config.action_controller.per_form_csrf_tokens = true 9 | 10 | # # Enable origin-checking CSRF mitigation. Previous versions had false. 11 | # Rails.application.config.action_controller.forgery_protection_origin_check = true 12 | 13 | # # Make Ruby 2.4 preserve the timezone of the receiver when calling `to_time`. 14 | # # Previous versions had false. 15 | # ActiveSupport.to_time_preserves_timezone = true 16 | 17 | # # Require `belongs_to` associations by default. Previous versions had false. 18 | # Rails.application.config.active_record.belongs_to_required_by_default = true 19 | 20 | # # Do not halt callback chains when a callback returns false. Previous versions had true. 21 | # ActiveSupport.halt_callback_chains_on_return_false = false 22 | 23 | # # Configure SSL options to enable HSTS with subdomains. Previous versions had false. 24 | # Rails.application.config.ssl_options = { hsts: { subdomains: true } } 25 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'inky' 2 | 3 | def reformat_html(html) 4 | html 5 | .gsub(/\s+/, ' ') # Compact all whitespace to a single space 6 | .gsub(/> *\n<") # Use returns between tags 7 | .gsub(%r{<(\w+)([^>]*)>\n}, '<\1\2/>') # Auto close empty tags, e.g.
\n =>
8 | .gsub(/ "/, '"').gsub(/\=" /, '="') # Remove leading/trailing spaces inside attributes 9 | .gsub(/ /, '>') # Remove leading/trailing spaces inside tags 10 | .gsub(' data-parsed=""', '') # Don't consider this known inky-node artefact 11 | .gsub(' ', ' ') # These are the same entity... 12 | .gsub(/(align="[^"]+") (class="[^"]+")/, '\2 \1') # Tweak order to match inky-node on container 13 | .gsub(/class\="([^"]+)"/) do # Sort class names 14 | classes = $1.split(' ').sort.join(' ') 15 | %{class="#{classes}"} 16 | end 17 | end 18 | 19 | def expect_same_html(input, expected) 20 | expect(reformat_html(input)).to eql(reformat_html(expected)) 21 | end 22 | 23 | def compare(input, expected) 24 | inky = Inky::Core.new 25 | output = inky.release_the_kraken(input) 26 | expect_same_html(output, expected) 27 | end 28 | -------------------------------------------------------------------------------- /lib/inky/rails/template_handler.rb: -------------------------------------------------------------------------------- 1 | module Inky 2 | module Rails 3 | class TemplateHandler 4 | def initialize(compose_with = nil) 5 | @engine_handler = ActionView::Template.registered_template_handler(compose_with) if compose_with 6 | end 7 | 8 | def engine_handler 9 | return @engine_handler if @engine_handler 10 | type = ::Inky.configuration.template_engine 11 | ActionView::Template.registered_template_handler(type) || 12 | raise("No template handler found for #{type}") 13 | end 14 | 15 | def call(template) 16 | compiled_source = engine_handler.call(template) 17 | 18 | "Inky::Core.new.release_the_kraken(begin; #{compiled_source};end)" 19 | end 20 | 21 | module Composer 22 | def register_template_handler(ext, *) 23 | super 24 | super :"inky-#{ext}", Inky::Rails::TemplateHandler.new(ext) 25 | end 26 | end 27 | end 28 | end 29 | end 30 | 31 | ActiveSupport.on_load(:action_view) do 32 | ActionView::Template.template_handler_extensions.each do |ext| 33 | ActionView::Template.register_template_handler :"inky-#{ext}", Inky::Rails::TemplateHandler.new(ext) 34 | end 35 | ActionView::Template.register_template_handler :inky, Inky::Rails::TemplateHandler.new 36 | ActionView::Template.singleton_class.send :prepend, Inky::Rails::TemplateHandler::Composer 37 | end 38 | -------------------------------------------------------------------------------- /inky.gemspec: -------------------------------------------------------------------------------- 1 | lib = File.expand_path('../lib', __FILE__) 2 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 3 | require 'inky/rails/version' 4 | 5 | Gem::Specification.new do |s| 6 | s.name = 'inky-rb' 7 | s.version = Inky::Rails::VERSION 8 | s.summary = 'Inky is an HTML-based templating language that converts simple HTML into complex, responsive email-ready HTML. Designed for Foundation for Emails, a responsive email framework from ZURB. ' 9 | s.description = 'Inky is an HTML-based templating language that converts simple HTML into complex, responsive email-ready HTML. Designed for Foundation for Emails, a responsive email framework from ZURB. ' 10 | s.authors = ["ZURB"] 11 | s.email = ['foundation@zurb.com'] 12 | s.homepage = 'https://github.com/zurb/inky-rb' 13 | 14 | s.files = `git ls-files -z`.split("\x0") 15 | s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) } 16 | s.test_files = Dir['spec/**/*'] 17 | 18 | s.add_dependency "foundation_emails", "~> 2" 19 | s.add_dependency "nokogiri" 20 | s.add_development_dependency "bundler", "~> 1.6" 21 | s.add_development_dependency "rake" 22 | s.add_development_dependency "rubocop" 23 | s.add_development_dependency "rspec-rails" 24 | s.add_development_dependency "capybara" 25 | s.add_development_dependency "rails" 26 | s.add_development_dependency "slim" 27 | # s.add_development_dependency "pry-byebug" 28 | end 29 | -------------------------------------------------------------------------------- /lib/generators/inky/install_generator.rb: -------------------------------------------------------------------------------- 1 | require 'rails/generators' 2 | 3 | module Inky 4 | module Generators 5 | class InstallGenerator < ::Rails::Generators::Base 6 | desc 'Install Foundation for Emails' 7 | source_root File.join(File.dirname(__FILE__), 'templates') 8 | argument :layout_name, type: :string, default: 'mailer', banner: 'layout_name' 9 | 10 | class_option :haml, desc: "Generate layout in Haml", type: :boolean 11 | class_option :slim, desc: "Generate layout in Slim", type: :boolean 12 | 13 | def preserve_original_mailer_layout 14 | return unless layout_name == 'mailer' && extension == 'erb' 15 | original_mailer = File.join(layouts_base_dir, "mailer.html.erb") 16 | rename_filename = File.join(layouts_base_dir, "old_mailer_#{Time.now.to_i}.html.erb") 17 | File.rename(original_mailer, rename_filename) if File.exist? original_mailer 18 | end 19 | 20 | def create_mailer_stylesheet 21 | template 'foundation_emails.scss', File.join(stylesheets_base_dir, 'foundation_emails.scss') 22 | end 23 | 24 | def create_mailer_layout 25 | template "mailer_layout.html.#{extension}", File.join(layouts_base_dir, "#{layout_name.underscore}.html.#{extension}") 26 | end 27 | 28 | private 29 | 30 | def stylesheets_base_dir 31 | File.join('app', 'assets', 'stylesheets') 32 | end 33 | 34 | def layouts_base_dir 35 | File.join('app', 'views', 'layouts') 36 | end 37 | 38 | def extension 39 | %w(haml slim).each do |ext| 40 | return ext if options.send(ext) 41 | end 42 | 'erb' 43 | end 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /spec/cases_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'json' 3 | 4 | INKY_VERSION_REQUIRED = Inky::NODE_VERSION 5 | 6 | def npm_packages 7 | JSON.parse(`npm list -g --depth=1 --json=true`) 8 | rescue 9 | puts <<-Err 10 | npm not detected, skipping comparison tests. 11 | Err 12 | nil 13 | end 14 | 15 | def inky_cli_ok? 16 | return unless packages = npm_packages 17 | version = packages['dependencies']['inky-cli']['dependencies']['inky']['version'] 18 | return true if version >= INKY_VERSION_REQUIRED 19 | puts "Requires inky version #{INKY_VERSION_REQUIRED}+, currently installed #{version}" 20 | false 21 | rescue 22 | puts <<-Err 23 | inky-cli not globally installed, skipping comparison tests. 24 | Install with: 25 | npm install inky-cli -g 26 | Err 27 | false 28 | end 29 | 30 | RSpec.describe "Inky-rb" do 31 | if inky_cli_ok? 32 | context "compared to inky-cli" do 33 | Dir['./spec/cases/*'].each do |path| 34 | folder = File.basename(path) 35 | output_path = "./spec/_cases_output/#{File.basename(folder)}" 36 | sources = "#{path}/*.inky" 37 | source_paths = Dir[sources] 38 | 39 | context "for #{folder} components" do 40 | before(:all) do 41 | shell = source_paths.map { |p| "inky #{p} #{output_path}" } 42 | `#{shell.join(' && ')}` 43 | end 44 | 45 | source_paths.each do |filepath| 46 | file = File.basename(filepath, '.inky') 47 | content = File.read(filepath) 48 | exec = content =~ /^