mjml-rb 0.2.38 → 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 +4 -4
- data/README.md +15 -0
- data/lib/mjml-rb/railtie.rb +2 -0
- data/lib/mjml-rb/template_handler.rb +103 -6
- data/lib/mjml-rb/version.rb +1 -1
- data/lib/mjml-rb.rb +8 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c7864f17e62acc702b5da45e9ca4322bc5207d486190de2ae7bab1a19e5109be
|
|
4
|
+
data.tar.gz: 9a5587f0f059d2d422407d65ad149e0d1ba04b731409a42290d3b4aa2aa34fc3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a910ab3a64a41505e662a31c97ad11b29a72bee403c5e98b70a2abafa7fee0e056a173e55232bde1d8a5b765a524a6acf1a99d0536c0c74a49ef67dcaa17265b
|
|
7
|
+
data.tar.gz: 0d9e9e08cfc38bcde65ba9480ca5a10365b0ecc60a20695a57cbc027dbe4a86df6d92424d46597d2ae8c46c7e25f6e4ccb6575d6d43f0d4dd157c54939afec36
|
data/README.md
CHANGED
|
@@ -46,6 +46,21 @@ bundle exec bin/mjml --validate example.mjml
|
|
|
46
46
|
In a Rails app, requiring the gem registers an `ActionView` template handler for
|
|
47
47
|
`.mjml` templates through a `Railtie`.
|
|
48
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
|
+
|
|
49
64
|
Create a view such as `app/views/user_mailer/welcome.html.mjml`:
|
|
50
65
|
|
|
51
66
|
```mjml
|
data/lib/mjml-rb/railtie.rb
CHANGED
|
@@ -4,9 +4,11 @@ module MjmlRb
|
|
|
4
4
|
class Railtie < Rails::Railtie
|
|
5
5
|
config.mjml_rb = ActiveSupport::OrderedOptions.new
|
|
6
6
|
config.mjml_rb.compiler_options = {validation_level: "strict"}
|
|
7
|
+
config.mjml_rb.template_language = nil
|
|
7
8
|
|
|
8
9
|
initializer "mjml_rb.action_view" do |app|
|
|
9
10
|
MjmlRb.rails_compiler_options = app.config.mjml_rb.compiler_options.to_h
|
|
11
|
+
MjmlRb.rails_template_language = app.config.mjml_rb.template_language
|
|
10
12
|
|
|
11
13
|
ActiveSupport.on_load(:action_view) do
|
|
12
14
|
MjmlRb.register_action_view_template_handler!
|
|
@@ -1,16 +1,113 @@
|
|
|
1
1
|
module MjmlRb
|
|
2
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
|
+
|
|
3
15
|
class << self
|
|
4
16
|
def call(template, source = nil)
|
|
5
17
|
<<~RUBY
|
|
6
|
-
|
|
7
|
-
|
|
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
|
+
|
|
8
31
|
if mjml_result.errors.any?
|
|
9
|
-
raise "MJML compilation failed for #{
|
|
32
|
+
raise "MJML compilation failed for #{identifier}: #{mjml_result.errors.map { |error| error[:formatted_message] || error[:message] }.join(', ')}"
|
|
10
33
|
end
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
|
14
111
|
end
|
|
15
112
|
end
|
|
16
113
|
end
|
data/lib/mjml-rb/version.rb
CHANGED
data/lib/mjml-rb.rb
CHANGED
|
@@ -28,6 +28,14 @@ module MjmlRb
|
|
|
28
28
|
@rails_compiler_options = options || {}
|
|
29
29
|
end
|
|
30
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
|
+
|
|
31
39
|
def register_action_view_template_handler!
|
|
32
40
|
return unless defined?(ActionView::Template)
|
|
33
41
|
|