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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 556f39bab241ad23362562a49530aa44547347cdadb66a72f80acdff43533814
4
- data.tar.gz: f1fd9bde9c1bfde3d041ef67c4b61837e82612fc51a39feaa4fc4c88e75f7464
3
+ metadata.gz: c7864f17e62acc702b5da45e9ca4322bc5207d486190de2ae7bab1a19e5109be
4
+ data.tar.gz: 9a5587f0f059d2d422407d65ad149e0d1ba04b731409a42290d3b4aa2aa34fc3
5
5
  SHA512:
6
- metadata.gz: 1061b94568afb17dd9734b397871d383890e624fcc44dd430708ce0194d370bad171a08fdba62c4e0ebb14250024b7e6003c071c8ac72d5401e9ec8b4229c28b
7
- data.tar.gz: 1c7529382d699d2893ed2a99236d03cb58f9fa0792574cd45d13d64a4e7e911ca5c01fbd332ead728de4a54721cc8002293030badd99b1256b07e8da154a6124
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
@@ -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
- mjml_compiler_options = (::MjmlRb.rails_compiler_options || {}).dup
7
- mjml_result = ::MjmlRb::Compiler.new(mjml_compiler_options).compile(#{template.source.inspect})
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 #{template.identifier}: \#{mjml_result.errors.map { |error| error[:formatted_message] || error[:message] }.join(', ')}"
32
+ raise "MJML compilation failed for #{identifier}: #{mjml_result.errors.map { |error| error[:formatted_message] || error[:message] }.join(', ')}"
10
33
  end
11
- mjml_html = mjml_result.html.to_s
12
- mjml_html.respond_to?(:html_safe) ? mjml_html.html_safe : mjml_html
13
- RUBY
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
@@ -1,3 +1,3 @@
1
1
  module MjmlRb
2
- VERSION = "0.2.38".freeze
2
+ VERSION = "0.2.39".freeze
3
3
  end
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
 
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.38
4
+ version: 0.2.39
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrei Andriichuk