Skip to content

Commit

Permalink
Merge pull request #6 from kolybasov/mjml3-compatability
Browse files Browse the repository at this point in the history
Add compatability with MJML v3.x.x
  • Loading branch information
Mykola Basov authored Oct 30, 2016
2 parents f74db95 + 2390720 commit e4333a1
Showing 15 changed files with 146 additions and 26 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -28,3 +28,4 @@ doc/

# Node
/node_modules
package.json
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -17,5 +17,5 @@ before_install:
before_script:
- nvm install node
- nvm use node
- npm install -g mjml@^2.3.3
- npm install -g mjml@^3.0.0
- rake prepare
30 changes: 26 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ Allows to create email templates without mess.
Add to Gemfile:

```ruby
gem 'mjml-ruby', '~> 0.2.3', require: 'mjml'
gem 'mjml-ruby', '~> 0.3.0', require: 'mjml'
```

or
@@ -28,12 +28,27 @@ Install [NodeJS](https://nodejs.org/en/) and [MJML](https://mjml.io)
(both installations will works local and global).

```bash
$ npm install -g mjml@^2.3.3
$ npm install -g mjml@^3.0.0
$ bundle install
```

## Usage

### MJML v3

[MJML v3](https://github.com/mjmlio/mjml/releases/tag/3.0.0) had added validation
for templates and it breaks mjml-ruby `v0.2.x` if your template was invalid.
mjml-ruby `> v0.3.x` has `validation_level` option(`:soft` by default) and
allows to use old templates with v3. All validation errors will be logged.

Example:

```ruby
MJML.configure do |config|
config.validation_level = :soft # :skip/:soft/:strict
end
```

### With Rails

```erb
@@ -122,19 +137,26 @@ end
MJML.configure do |config|
config.bin_path = '/usr/bin/env mjml'
config.logger = YourLogger.new(STDOUT)
config.debug = true
config.minify_output = true
config.validation_level = :soft
end

# Rails
Rails.application.configure do
config.mjml.bin_path = '/usr/bin/env mjml'
config.mjml.logger = MJML::Logger.setup!(STDOUT)
config.mjml.debug = true
config.minify_output = true
config.validation_level = :soft
end
```

## Deprecations

### v0.3

- `config.debug = true` is deprecated. If you are using default MJML Logger
use `config.logger.level = ::Logger::DEBUG` instead.

## TODO

- [x] Create parser
10 changes: 8 additions & 2 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -13,10 +13,16 @@ task default: :test
TEMPLATE_PATH = "#{Dir.pwd}/spec/fixtures"
OUTPUT_FILES = ['hello.html', 'hello.min.html']

def mjml_path
local_path = File.expand_path('node_modules/.bin/mjml', Dir.pwd)
return local_path if File.file?(local_path)
@executable ||= `/usr/bin/env bash -c "which mjml"`.strip
end

# Prepare env for tests
task :prepare => [:clear] do
`mjml #{TEMPLATE_PATH}/hello.mjml -o #{TEMPLATE_PATH}/hello.html`
`mjml #{TEMPLATE_PATH}/hello.mjml -o #{TEMPLATE_PATH}/hello.min.html --min`
`#{mjml_path} #{TEMPLATE_PATH}/hello.mjml -o #{TEMPLATE_PATH}/hello.html`
`#{mjml_path} #{TEMPLATE_PATH}/hello.mjml -o #{TEMPLATE_PATH}/hello.min.html --min`
end

task :clear do
5 changes: 4 additions & 1 deletion lib/mjml.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require 'dry-configurable'
require 'mjml/logger'
require 'mjml/feature'
require 'mjml/parser'

# MJML library for ruby
@@ -15,14 +16,16 @@ module MJML
setting :debug
setting :logger
setting :minify_output
setting :validation_level

def self.setup!
# Init config
configure do |config|
config.bin_path = find_executable
config.debug = false
config.debug = nil
config.logger = Logger.setup!(STDOUT)
config.minify_output = false
config.validation_level = :skip
end
end

26 changes: 26 additions & 0 deletions lib/mjml/feature.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module MJML
# Allows to check if feature is availalbe in current mjml version
class Feature
def self.version
semver = MJML.executable_version.split('.')
@version ||= Hash[
major: semver[0].to_i,
minor: semver[1].to_i,
patch: semver[2].to_i
]
end

def self.available?(feature_name)
case feature_name
when :validation_level
version[:major] >= 3
else
false
end
end

def self.missing?(feature_name)
!available?(feature_name)
end
end
end
4 changes: 2 additions & 2 deletions lib/mjml/logger.rb
Original file line number Diff line number Diff line change
@@ -5,10 +5,10 @@ module MJML
class Logger < ::Logger
def self.setup!(destination)
logger = new(destination)
logger.level = ::Logger::DEBUG
logger.level = ::Logger::ERROR

logger.formatter = proc do |severity, datetime, _progname, msg|
"[#{datetime}] #{severity} -- MJML: #{msg}" if MJML.config.debug
"[#{datetime}] #{severity} -- MJML: #{msg}\n\n"
end

logger
29 changes: 26 additions & 3 deletions lib/mjml/parser.rb
Original file line number Diff line number Diff line change
@@ -34,10 +34,14 @@ def exec!(template)
return template if partial?(template)

out, err, _sts = Open3.capture3(cmd, stdin_data: template)
MJML.logger.debug("Output:\n #{out};\n\n Errors:\n #{err}")
parsed = parse_output(out)

MJML.logger.debug("Output:\n #{parsed[:output]}")
MJML.logger.error(err) unless err.empty?
MJML.logger.warn(parsed[:warnings]) unless parsed[:warnings].empty?

raise InvalidTemplate unless err.empty?
out
parsed[:output]
end

def partial?(template)
@@ -49,11 +53,30 @@ def mjml_bin
end

def cmd
"#{mjml_bin} #{minify_output} -is"
"#{mjml_bin} #{minify_output} #{validation_level} -is"
end

def minify_output
'--min' if MJML.config.minify_output
end

def validation_level
"--level=#{MJML.config.validation_level}" if MJML::Feature.available?(:validation_level)
end

def parse_output(out)
warnings = []
output = []

out.lines.each do |l|
if l.strip.start_with?('Line')
warnings << l
else
output << l
end
end

{ warnings: warnings.join, output: output.join }
end
end
end
2 changes: 1 addition & 1 deletion lib/mjml/rails/template_handler.rb
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ def initialize(base_handler = :erb)

def call(template)
compiled = get_handler(@base_handler).call(template)
"::MJML::Parser.new.call(begin;#{compiled};end).html_safe"
"::MJML::Parser.new.call!(begin;#{compiled};end).html_safe"
end

private
2 changes: 1 addition & 1 deletion lib/mjml/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module MJML
VERSION = '0.2.3'.freeze
VERSION = '0.3.0'.freeze
end
2 changes: 1 addition & 1 deletion mjml-ruby.gemspec
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ Gem::Specification.new do |s|
s.homepage = 'https://github.com/kolybasov/mjml-ruby'
s.summary = 'MJML parser and template engine for Ruby'
s.license = 'MIT'
s.post_install_message = 'Don\'t forget to run $ npm install -g mjml@^2.0'
s.post_install_message = 'Don\'t forget to run $ npm install -g mjml@^3.0'

s.files = `git ls-files app lib`.split("\n")
s.test_files = s.files.grep(%r{^(test|spec|features)/})
27 changes: 27 additions & 0 deletions spec/mjml/feature_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
require_relative '../spec_helper'
require 'mjml/feature'

describe MJML::Feature do
let(:mjml_version) { MJML.executable_version }
let(:level_availability) { MJML.executable_version.start_with?('3') }

describe '#availalbe?' do
it 'should return true for :validation_level if mjml is >v3' do
MJML::Feature.available?(:validation_level).must_equal level_availability
end

it 'should return false for unknown feature' do
MJML::Feature.available?(:spaceship).must_equal false
end
end

describe '#missing?' do
it 'should return false for availalbe feature' do
MJML::Feature.missing?(:validation_level).must_equal !level_availability
end

it 'should return true for unknown feature' do
MJML::Feature.missing?(:spaceship).must_equal true
end
end
end
10 changes: 0 additions & 10 deletions spec/mjml/logger.rb

This file was deleted.

19 changes: 19 additions & 0 deletions spec/mjml/logger_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
require_relative '../spec_helper'
require 'mjml/logger'
require 'logger'

describe MJML::Logger do
let(:logger) { MJML.logger }
let(:msg) { 'logger msg' }
let(:matcher) { /msg/ }

it 'should show errors' do
capture_subprocess_io { logger.error(msg) }.to_s.must_match matcher
end

it 'should show debug messages' do
logger.level = ::Logger::DEBUG
capture_subprocess_io { logger.debug(msg) }.to_s.must_match matcher
logger.level = ::Logger::ERROR
end
end
3 changes: 3 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -7,3 +7,6 @@
def read_fixture(name)
File.open("#{FIXTURES_PATH}/#{name}", 'rb', &:read)
end

puts "MJML executable path: #{MJML.find_executable}"
puts "MJML executable version: #{MJML.executable_version}"

0 comments on commit e4333a1

Please sign in to comment.