mjml-rb 0.2.37 → 0.2.39

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 022de3642d6473c98ee598b12dd209cb4f6cfb8f6ce50a230768a9e29a6506e3
4
- data.tar.gz: 786a9cad787fb6f3d3a305f5a7dae786387822a55c67d9d58bf489a63f5e4a34
3
+ metadata.gz: c7864f17e62acc702b5da45e9ca4322bc5207d486190de2ae7bab1a19e5109be
4
+ data.tar.gz: 9a5587f0f059d2d422407d65ad149e0d1ba04b731409a42290d3b4aa2aa34fc3
5
5
  SHA512:
6
- metadata.gz: 30ee8b1a6c75a23db416db7b7f41e0881b8e80c2bca25d097ba622159909e07dd2a0ccb801caff5bb78c3c50b4f3a1bab09c26ff419f51094957e54bddbd5b30
7
- data.tar.gz: 4a1550e5f7d6862abf6c2a3836f3b622b1c21027af1869558e4a8122671d738ba26174ad92ab0bbdf35c651c476240f107b1a27bd4fd61460630bd0e66b7044e
6
+ metadata.gz: a910ab3a64a41505e662a31c97ad11b29a72bee403c5e98b70a2abafa7fee0e056a173e55232bde1d8a5b765a524a6acf1a99d0536c0c74a49ef67dcaa17265b
7
+ data.tar.gz: 0d9e9e08cfc38bcde65ba9480ca5a10365b0ecc60a20695a57cbc027dbe4a86df6d92424d46597d2ae8c46c7e25f6e4ccb6575d6d43f0d4dd157c54939afec36
data/README.md CHANGED
@@ -12,12 +12,20 @@
12
12
  > feedback, bug reports, test cases, optimizations, proposals, and pull requests.
13
13
  > No warranty of any kind is provided.
14
14
 
15
- This directory contains a Ruby-first implementation of the main MJML user-facing tooling:
15
+ This gem provides a Ruby-first implementation of the main MJML tooling:
16
16
 
17
17
  - library API compatible with `mjml2html`
18
18
  - command-line interface (`mjml`)
19
- - migration and validation commands
20
- - pure Ruby parser + AST + renderer (no external native renderer dependency)
19
+ - validation commands
20
+ - pure Ruby parser, AST, validator, and renderer
21
+ - no Node.js runtime and no shelling out to the official npm renderer
22
+
23
+ ## Compatibility
24
+
25
+ This project targets **MJML v4 only**.
26
+
27
+ - parsing, validation, and rendering are implemented against the MJML v4 document structure
28
+ - component rules and attribute validation follow the MJML v4 model
21
29
 
22
30
  ## Quick start
23
31
 
@@ -31,19 +39,115 @@ bundle exec ruby -Ilib -e 'require "mjml-rb"; puts MjmlRb.mjml2html("<mjml><mj-b
31
39
  ```bash
32
40
  bundle exec bin/mjml example.mjml -o output.html
33
41
  bundle exec bin/mjml --validate example.mjml
34
- bundle exec bin/mjml --migrate old.mjml -s
35
42
  ```
36
43
 
37
- ## Implementation idea
44
+ ## Rails integration
45
+
46
+ In a Rails app, requiring the gem registers an `ActionView` template handler for
47
+ `.mjml` templates through a `Railtie`.
48
+
49
+ By default, `.mjml` files are treated as raw MJML/XML source.
50
+
51
+ If you want Slim-backed MJML templates, configure it explicitly:
52
+
53
+ ```ruby
54
+ config.mjml_rb.template_language = :slim
55
+ ```
56
+
57
+ Supported values are `:erb`, `:slim`, and `:haml`.
58
+
59
+ With a configured `template_language`, `.mjml` templates are rendered through
60
+ that template engine first, so partials and embedded Ruby can assemble MJML
61
+ before the outer template is compiled to HTML. Without that setting, non-XML
62
+ MJML source is rejected instead of being guessed.
63
+
64
+ Create a view such as `app/views/user_mailer/welcome.html.mjml`:
65
+
66
+ ```mjml
67
+ <mjml>
68
+ <mj-body>
69
+ <mj-section>
70
+ <mj-column>
71
+ <mj-text>Hello from Rails</mj-text>
72
+ </mj-column>
73
+ </mj-section>
74
+ </mj-body>
75
+ </mjml>
76
+ ```
77
+
78
+ Then render it like any other Rails template:
79
+
80
+ ```ruby
81
+ class UserMailer < ApplicationMailer
82
+ def welcome
83
+ mail(to: "user@example.com", subject: "Welcome")
84
+ end
85
+ end
86
+ ```
87
+
88
+ Rails rendering uses strict MJML validation by default. You can override the
89
+ compiler options in your application config:
90
+
91
+ ```ruby
92
+ config.mjml_rb.compiler_options = { validation_level: "soft" }
93
+ ```
94
+
95
+ ## Architecture
96
+
97
+ The compile pipeline is intentionally simple and fully Ruby-based:
98
+
99
+ 1. `MjmlRb.mjml2html` calls `MjmlRb::Compiler`.
100
+ 2. `MjmlRb::Parser` normalizes the source, expands `mj-include`, and builds an `AstNode` tree.
101
+ 3. `MjmlRb::Validator` checks structural rules and supported attributes.
102
+ 4. `MjmlRb::Renderer` resolves head metadata, applies component defaults, and renders HTML.
103
+ 5. `MjmlRb::Compiler` post-processes the output and returns a `Result`.
104
+
105
+ The key architectural idea is that the project uses a small shared AST plus a component registry:
106
+
107
+ - the parser produces generic `AstNode` objects instead of component-specific node types
108
+ - structure rules live in `lib/mjml-rb/dependencies.rb`
109
+ - rendering logic lives in `lib/mjml-rb/components/*`
110
+ - head components populate a shared rendering context
111
+ - body components consume that context and emit the final HTML
112
+
113
+ That split keeps the compiler pipeline predictable:
114
+
115
+ - parsing is responsible for source normalization and include expansion
116
+ - validation is responsible for MJML structure and attribute checks
117
+ - rendering is responsible for HTML generation and responsive email output
118
+
119
+ ## Project structure
120
+
121
+ The main files are organized like this:
122
+
123
+ ```text
124
+ lib/mjml-rb.rb # public gem entry point
125
+ lib/mjml-rb/compiler.rb # orchestration: parse -> validate -> render
126
+ lib/mjml-rb/parser.rb # MJML/XML normalization, includes, AST building
127
+ lib/mjml-rb/ast_node.rb # shared tree representation
128
+ lib/mjml-rb/validator.rb # structural and attribute validation
129
+ lib/mjml-rb/dependencies.rb # allowed parent/child relationships
130
+ lib/mjml-rb/renderer.rb # HTML document assembly and render context
131
+ lib/mjml-rb/components/* # per-component rendering and head handling
132
+ lib/mjml-rb/result.rb # result object returned by the compiler
133
+ lib/mjml-rb/cli.rb # CLI implementation used by bin/mjml
134
+ docs/ARCHITECTURE.md # deeper architecture notes
135
+ docs/PARITY_AUDIT.md # npm vs Ruby parity tracking
136
+ ```
137
+
138
+ If you want the full internal walkthrough, see [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
139
+
140
+ ## Implementation goal
38
141
 
39
- > **Zero-dependency pure-Ruby MJML renderer.**
142
+ > **Ruby MJML pipeline without the Node.js renderer.**
40
143
  >
41
144
  > The npm `mjml` package requires Node.js at build time (or runtime via a child
42
145
  > process / FFI bridge). This project replaces that entire pipeline with a single
43
146
  > Ruby library: XML parsing, AST construction, attribute resolution, validation,
44
- > and HTML rendering — all in Ruby, with no native extensions and no Node.js
45
- > dependency. Drop it into a Rails, Sinatra, or plain Ruby project and render
46
- > MJML templates the same way you render ERB — no extra runtime, no
147
+ > and HTML rendering — all in Ruby, with no Node.js runtime and no need to
148
+ > shell out to the official MJML renderer. Drop it into a Rails, Sinatra, or
149
+ > plain Ruby project and render MJML templates the same way you render ERB — no
150
+ > extra runtime, no
47
151
  > `package.json`, no `node_modules`.
48
152
 
49
- Remaining parity work is tracked in [npm ↔ Ruby Parity Audit](/docs/PARITY_AUDIT.md).
153
+ Remaining parity work is tracked in [npm ↔ Ruby Parity Audit](docs/PARITY_AUDIT.md).
data/lib/mjml-rb/cli.rb CHANGED
@@ -4,7 +4,6 @@ require "pathname"
4
4
  require "time"
5
5
 
6
6
  require_relative "compiler"
7
- require_relative "migrator"
8
7
  require_relative "version"
9
8
 
10
9
  module MjmlRb
@@ -58,7 +57,6 @@ module MjmlRb
58
57
  def default_options
59
58
  {
60
59
  read: [],
61
- migrate: [],
62
60
  validate: [],
63
61
  watch: [],
64
62
  stdin: false,
@@ -77,7 +75,6 @@ module MjmlRb
77
75
  opts.banner = "Usage: mjml [options] [files]"
78
76
 
79
77
  opts.on("-r", "--read FILES", Array, "Compile MJML files") { |v| options[:read].concat(v) }
80
- opts.on("-m", "--migrate FILES", Array, "Migrate MJML3 files") { |v| options[:migrate].concat(v) }
81
78
  opts.on("-v", "--validate FILES", Array, "Validate MJML files") { |v| options[:validate].concat(v) }
82
79
  opts.on("-w", "--watch FILES", Array, "Watch and compile files when modified") { |v| options[:watch].concat(v) }
83
80
  opts.on("-i", "--stdin", "Read MJML from stdin") { options[:stdin] = true }
@@ -148,7 +145,6 @@ module MjmlRb
148
145
  def resolve_input(options)
149
146
  inputs = {}
150
147
  inputs[:read] = options[:read] unless options[:read].empty?
151
- inputs[:migrate] = options[:migrate] unless options[:migrate].empty?
152
148
  inputs[:validate] = options[:validate] unless options[:validate].empty?
153
149
  inputs[:watch] = options[:watch] unless options[:watch].empty?
154
150
  inputs[:stdin] = true if options[:stdin]
@@ -183,9 +179,6 @@ module MjmlRb
183
179
 
184
180
  def process_input(input, mode, config)
185
181
  case mode
186
- when :migrate
187
- html = Migrator.new.migrate(input[:mjml])
188
- { file: input[:file], compiled: Result.new(html: html) }
189
182
  when :validate
190
183
  compiler = Compiler.new(config.merge(validation_level: "strict"))
191
184
  { file: input[:file], compiled: compiler.compile(input[:mjml]) }
@@ -61,7 +61,7 @@ module MjmlRb
61
61
  "font-size" => "unit(px)",
62
62
  "font-family" => "string",
63
63
  "font-weight" => "string",
64
- "letter-spacing" => "unit(px,em)",
64
+ "letter-spacing" => "unitWithNegative(px,em)",
65
65
  "line-height" => "unit(px,%,)",
66
66
  "color" => "color",
67
67
  "padding-bottom" => "unit(px,%)",
@@ -25,7 +25,7 @@ module MjmlRb
25
25
  "name" => "string",
26
26
  "title" => "string",
27
27
  "inner-padding" => "unit(px,%){1,4}",
28
- "letter-spacing" => "unit(px,em)",
28
+ "letter-spacing" => "unitWithNegative(px,em)",
29
29
  "line-height" => "unit(px,%,)",
30
30
  "padding-bottom" => "unit(px,%)",
31
31
  "padding-left" => "unit(px,%)",
@@ -7,7 +7,7 @@ module MjmlRb
7
7
 
8
8
  ALLOWED_ATTRIBUTES = {
9
9
  "mj-style" => {
10
- "inline" => "string"
10
+ "inline" => "enum(inline)"
11
11
  },
12
12
  "mj-font" => {
13
13
  "name" => "string",
@@ -6,7 +6,7 @@ module MjmlRb
6
6
  TAGS = ["mj-hero"].freeze
7
7
 
8
8
  ALLOWED_ATTRIBUTES = {
9
- "mode" => "string",
9
+ "mode" => "enum(fixed-height,fluid-height)",
10
10
  "height" => "unit(px,%)",
11
11
  "background-url" => "string",
12
12
  "background-width" => "unit(px,%)",
@@ -10,7 +10,7 @@ module MjmlRb
10
10
  NAVBAR_ALLOWED_ATTRIBUTES = {
11
11
  "align" => "enum(left,center,right)",
12
12
  "base-url" => "string",
13
- "hamburger" => "string",
13
+ "hamburger" => "enum(hamburger)",
14
14
  "ico-align" => "enum(left,center,right)",
15
15
  "ico-open" => "string",
16
16
  "ico-close" => "string",
@@ -29,7 +29,7 @@ module MjmlRb
29
29
  "padding-right" => "unit(px,%)",
30
30
  "padding-bottom" => "unit(px,%)",
31
31
  "ico-text-decoration" => "string",
32
- "ico-line-height" => "unit(px,%)"
32
+ "ico-line-height" => "unit(px,%,)"
33
33
  }.freeze
34
34
 
35
35
  NAVBAR_LINK_ALLOWED_ATTRIBUTES = {
@@ -42,8 +42,8 @@ module MjmlRb
42
42
  "name" => "string",
43
43
  "target" => "string",
44
44
  "rel" => "string",
45
- "letter-spacing" => "string",
46
- "line-height" => "unit(px,%)",
45
+ "letter-spacing" => "unitWithNegative(px,em)",
46
+ "line-height" => "unit(px,%,)",
47
47
  "padding-bottom" => "unit(px,%)",
48
48
  "padding-left" => "unit(px,%)",
49
49
  "padding-right" => "unit(px,%)",
@@ -8,23 +8,23 @@ module MjmlRb
8
8
  ALLOWED_ATTRIBUTES = {
9
9
  "align" => "enum(left,right,center)",
10
10
  "border" => "string",
11
- "cellpadding" => "string",
12
- "cellspacing" => "string",
11
+ "cellpadding" => "integer",
12
+ "cellspacing" => "integer",
13
13
  "color" => "color",
14
14
  "container-background-color" => "color",
15
15
  "font-family" => "string",
16
- "font-size" => "string",
16
+ "font-size" => "unit(px)",
17
17
  "font-weight" => "string",
18
- "line-height" => "string",
18
+ "line-height" => "unit(px,%,)",
19
19
  "padding" => "unit(px,%){1,4}",
20
20
  "padding-top" => "unit(px,%)",
21
21
  "padding-right" => "unit(px,%)",
22
22
  "padding-bottom" => "unit(px,%)",
23
23
  "padding-left" => "unit(px,%)",
24
- "role" => "string",
25
- "table-layout" => "enum(auto,fixed)",
24
+ "role" => "enum(none,presentation)",
25
+ "table-layout" => "enum(auto,fixed,initial,inherit)",
26
26
  "vertical-align" => "enum(top,bottom,middle)",
27
- "width" => "string"
27
+ "width" => "unit(px,%,auto)"
28
28
  }.freeze
29
29
 
30
30
  DEFAULTS = {
@@ -11,12 +11,12 @@ module MjmlRb
11
11
  "color" => "color",
12
12
  "container-background-color" => "color",
13
13
  "font-family" => "string",
14
- "font-size" => "string",
14
+ "font-size" => "unit(px)",
15
15
  "font-style" => "string",
16
16
  "font-weight" => "string",
17
- "height" => "string",
18
- "letter-spacing" => "string",
19
- "line-height" => "string",
17
+ "height" => "unit(px,%)",
18
+ "letter-spacing" => "unitWithNegative(px,em)",
19
+ "line-height" => "unit(px,%,)",
20
20
  "padding" => "unit(px,%){1,4}",
21
21
  "padding-top" => "unit(px,%)",
22
22
  "padding-right" => "unit(px,%)",
@@ -0,0 +1,18 @@
1
+ require_relative "template_handler"
2
+
3
+ module MjmlRb
4
+ class Railtie < Rails::Railtie
5
+ config.mjml_rb = ActiveSupport::OrderedOptions.new
6
+ config.mjml_rb.compiler_options = {validation_level: "strict"}
7
+ config.mjml_rb.template_language = nil
8
+
9
+ initializer "mjml_rb.action_view" do |app|
10
+ MjmlRb.rails_compiler_options = app.config.mjml_rb.compiler_options.to_h
11
+ MjmlRb.rails_template_language = app.config.mjml_rb.template_language
12
+
13
+ ActiveSupport.on_load(:action_view) do
14
+ MjmlRb.register_action_view_template_handler!
15
+ end
16
+ end
17
+ end
18
+ end
@@ -209,7 +209,7 @@ module MjmlRb
209
209
 
210
210
  def render_node(node, context, parent:)
211
211
  return escape_html(node.content.to_s) if node.text?
212
- return "" if node.comment?
212
+ return "<!--#{node.content}-->" if node.comment?
213
213
 
214
214
  attrs = resolved_attributes(node, context)
215
215
  if (component = component_for(node.tag_name))
@@ -0,0 +1,114 @@
1
+ module MjmlRb
2
+ class TemplateHandler
3
+ MJML_CAPTURE_DEPTH_IVAR = :@_mjml_rb_capture_depth
4
+ TEMPLATE_ENGINES = {
5
+ slim: {
6
+ require: "slim",
7
+ gem_name: "slim"
8
+ },
9
+ haml: {
10
+ require: "haml",
11
+ gem_name: "haml"
12
+ }
13
+ }.freeze
14
+
15
+ class << self
16
+ def call(template, source = nil)
17
+ <<~RUBY
18
+ ::MjmlRb::TemplateHandler.render(self, #{template.source.inspect}, #{template.identifier.inspect}, local_assigns)
19
+ RUBY
20
+ end
21
+
22
+ def render(view_context, source, identifier, local_assigns = {})
23
+ if capture_mode?(view_context)
24
+ return mark_html_safe(render_source(view_context, source, local_assigns))
25
+ end
26
+
27
+ with_capture_mode(view_context) do
28
+ mjml_source = render_source(view_context, source, local_assigns).to_s
29
+ mjml_result = ::MjmlRb::Compiler.new(::MjmlRb.rails_compiler_options || {}).compile(mjml_source)
30
+
31
+ if mjml_result.errors.any?
32
+ raise "MJML compilation failed for #{identifier}: #{mjml_result.errors.map { |error| error[:formatted_message] || error[:message] }.join(', ')}"
33
+ end
34
+
35
+ mark_html_safe(mjml_result.html.to_s)
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def render_source(view_context, source, local_assigns)
42
+ language = ::MjmlRb.rails_template_language
43
+ if language.nil?
44
+ stripped_source = source.to_s.lstrip
45
+ return source.to_s if stripped_source.start_with?("<")
46
+
47
+ raise "MJML Rails template_language is not configured for non-XML templates. Supported values: nil, :erb, :slim, :haml"
48
+ end
49
+
50
+ case language
51
+ when :erb
52
+ render_erb_source(view_context, source.to_s, local_assigns)
53
+ when :slim, :haml
54
+ render_template_language_source(view_context, source.to_s, local_assigns, language)
55
+ else
56
+ raise "Unsupported MJML Rails template_language `#{language}`. Supported values: nil, :erb, :slim, :haml"
57
+ end
58
+ end
59
+
60
+ def render_erb_source(view_context, source, local_assigns)
61
+ require "erb"
62
+
63
+ local_assigns.each do |name, value|
64
+ define_local_reader(view_context, name, value)
65
+ end
66
+
67
+ erb = ::ERB.new(source)
68
+ erb.result(view_context.instance_eval { binding })
69
+ end
70
+
71
+ def render_template_language_source(view_context, source, local_assigns, language)
72
+ engine = TEMPLATE_ENGINES.fetch(language)
73
+ require engine[:require]
74
+
75
+ case language
76
+ when :slim
77
+ ::Slim::Template.new { source }.render(view_context, local_assigns.transform_keys(&:to_sym))
78
+ when :haml
79
+ if defined?(::Haml::Template)
80
+ ::Haml::Template.new { source }.render(view_context, local_assigns.transform_keys(&:to_sym))
81
+ else
82
+ raise "MJML Rails template_language is set to :haml, but this Haml version does not expose Haml::Template"
83
+ end
84
+ end
85
+ rescue LoadError
86
+ raise "MJML Rails template_language is set to :#{language}, but the `#{engine[:gem_name]}` gem is not available"
87
+ end
88
+
89
+ def define_local_reader(view_context, name, value)
90
+ singleton_class = class << view_context; self; end
91
+ singleton_class.send(:define_method, name) do
92
+ value
93
+ end
94
+ end
95
+
96
+ def capture_mode?(view_context)
97
+ view_context.instance_variable_get(MJML_CAPTURE_DEPTH_IVAR).to_i.positive?
98
+ end
99
+
100
+ def with_capture_mode(view_context)
101
+ depth = view_context.instance_variable_get(MJML_CAPTURE_DEPTH_IVAR).to_i
102
+ view_context.instance_variable_set(MJML_CAPTURE_DEPTH_IVAR, depth + 1)
103
+ yield
104
+ ensure
105
+ next_depth = view_context.instance_variable_get(MJML_CAPTURE_DEPTH_IVAR).to_i - 1
106
+ view_context.instance_variable_set(MJML_CAPTURE_DEPTH_IVAR, [next_depth, 0].max)
107
+ end
108
+
109
+ def mark_html_safe(value)
110
+ value.respond_to?(:html_safe) ? value.html_safe : value
111
+ end
112
+ end
113
+ end
114
+ end
@@ -160,8 +160,13 @@ module MjmlRb
160
160
  color?(value)
161
161
  when /\Aenum\((.+)\)\z/
162
162
  Regexp.last_match(1).split(",").map(&:strip).include?(value)
163
+ when /\AunitWithNegative\((.+)\)(?:\{(\d+),(\d+)\})?\z/
164
+ units = Regexp.last_match(1).split(",", -1).map(&:strip)
165
+ min_count = Regexp.last_match(2)&.to_i || 1
166
+ max_count = Regexp.last_match(3)&.to_i || 1
167
+ unit_values?(value, units, min_count: min_count, max_count: max_count)
163
168
  when /\Aunit\((.+)\)(?:\{(\d+),(\d+)\})?\z/
164
- units = Regexp.last_match(1).split(",").map(&:strip)
169
+ units = Regexp.last_match(1).split(",", -1).map(&:strip)
165
170
  min_count = Regexp.last_match(2)&.to_i || 1
166
171
  max_count = Regexp.last_match(3)&.to_i || 1
167
172
  unit_values?(value, units, min_count: min_count, max_count: max_count)
@@ -188,7 +193,11 @@ module MjmlRb
188
193
  return true if value.match?(/\A0(?:\.0+)?\z/)
189
194
 
190
195
  units.any? do |unit|
191
- value == unit || value.match?(/\A-?\d+(?:\.\d+)?#{Regexp.escape(unit)}\z/)
196
+ if unit.empty?
197
+ value.match?(/\A-?\d+(?:\.\d+)?\z/)
198
+ else
199
+ value == unit || value.match?(/\A-?\d+(?:\.\d+)?#{Regexp.escape(unit)}\z/)
200
+ end
192
201
  end
193
202
  end
194
203
 
@@ -1,3 +1,3 @@
1
1
  module MjmlRb
2
- VERSION = "0.2.37".freeze
2
+ VERSION = "0.2.39".freeze
3
3
  end
data/lib/mjml-rb.rb CHANGED
@@ -6,7 +6,6 @@ require_relative "mjml-rb/parser"
6
6
  require_relative "mjml-rb/renderer"
7
7
  require_relative "mjml-rb/compiler"
8
8
  require_relative "mjml-rb/validator"
9
- require_relative "mjml-rb/migrator"
10
9
  require_relative "mjml-rb/cli"
11
10
 
12
11
  module MjmlRb
@@ -21,6 +20,29 @@ module MjmlRb
21
20
  WARNING
22
21
 
23
22
  class << self
23
+ def rails_compiler_options
24
+ @rails_compiler_options ||= {validation_level: "strict"}
25
+ end
26
+
27
+ def rails_compiler_options=(options)
28
+ @rails_compiler_options = options || {}
29
+ end
30
+
31
+ def rails_template_language
32
+ @rails_template_language
33
+ end
34
+
35
+ def rails_template_language=(language)
36
+ @rails_template_language = language&.to_sym
37
+ end
38
+
39
+ def register_action_view_template_handler!
40
+ return unless defined?(ActionView::Template)
41
+
42
+ require_relative "mjml-rb/template_handler"
43
+ ActionView::Template.register_template_handler(:mjml, TemplateHandler)
44
+ end
45
+
24
46
  def mjml2html(mjml, options = {})
25
47
  Compiler.new(options).compile(mjml).to_h
26
48
  end
@@ -28,3 +50,9 @@ module MjmlRb
28
50
  alias to_html mjml2html
29
51
  end
30
52
  end
53
+
54
+ MjmlRb.register_action_view_template_handler! if defined?(ActionView::Template)
55
+
56
+ if defined?(Rails::Railtie)
57
+ require_relative "mjml-rb/railtie"
58
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mjml-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.37
4
+ version: 0.2.39
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrei Andriichuk
@@ -76,10 +76,11 @@ files:
76
76
  - lib/mjml-rb/components/table.rb
77
77
  - lib/mjml-rb/components/text.rb
78
78
  - lib/mjml-rb/dependencies.rb
79
- - lib/mjml-rb/migrator.rb
80
79
  - lib/mjml-rb/parser.rb
80
+ - lib/mjml-rb/railtie.rb
81
81
  - lib/mjml-rb/renderer.rb
82
82
  - lib/mjml-rb/result.rb
83
+ - lib/mjml-rb/template_handler.rb
83
84
  - lib/mjml-rb/validator.rb
84
85
  - lib/mjml-rb/version.rb
85
86
  - mjml-rb.gemspec
@@ -1,18 +0,0 @@
1
- module MjmlRb
2
- class Migrator
3
- TAG_RENAMES = {
4
- "mj-container" => "mj-body"
5
- }.freeze
6
-
7
- def migrate(mjml)
8
- output = mjml.to_s.dup
9
-
10
- TAG_RENAMES.each do |from, to|
11
- output.gsub!("<#{from}", "<#{to}")
12
- output.gsub!("</#{from}>", "</#{to}>")
13
- end
14
-
15
- output
16
- end
17
- end
18
- end