mjml-rb 0.4.2 → 0.4.3
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 +55 -155
- data/lib/mjml-rb/components/section.rb +1 -1
- data/lib/mjml-rb/renderer.rb +6 -0
- data/lib/mjml-rb/version.rb +1 -1
- 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: a143101aa0a18f9aa1e77160d0810561f9b5e58fe6dbf8c68d9f809b91421d8d
|
|
4
|
+
data.tar.gz: b3fb93b17518384e6ce03e96162a30ef870ab4534bfc3c0fe62775b5db21c594
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a811a85d468e8332b29c533efe918038c68fccb9f7383d82bfceff42954cbe7c9faeccbe72dde57380b422881b620a358db2d6032bef62928053a6b25c001d71
|
|
7
|
+
data.tar.gz: c04f1e1df5835cbf5d0c2f81835ba942aa6f9d3149e592662cffeec22ece7c2841d89f44d4834e5ba29ef8b2891070c402a9da277b04363a7f59541740f2c785
|
data/README.md
CHANGED
|
@@ -11,198 +11,98 @@
|
|
|
11
11
|
> This is a **fully open source project** — feedback, bug reports, test cases,
|
|
12
12
|
> and pull requests are welcome!
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
A pure-Ruby MJML v4 compiler — no Node.js required.
|
|
15
15
|
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
16
|
+
- Library API compatible with `mjml2html`
|
|
17
|
+
- Command-line interface (`mjml`)
|
|
18
|
+
- Rails integration (ActionView template handler for `.mjml` views)
|
|
19
|
+
- Validation (soft, strict, skip)
|
|
20
|
+
- Custom component support
|
|
21
|
+
- Pure Ruby parser, AST, validator, and renderer
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
## Compatibility
|
|
25
|
-
|
|
26
|
-
This project targets **MJML v4 only**.
|
|
23
|
+
**[Full Usage Guide](docs/USAGE.md)** — API reference, all compiler options, component attribute tables, CLI flags, Rails setup, custom components, and more.
|
|
27
24
|
|
|
28
|
-
|
|
29
|
-
- component rules and attribute validation follow the MJML v4 model
|
|
25
|
+
## Installation
|
|
30
26
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
bundle install
|
|
35
|
-
bundle exec ruby -Ilib -e 'require "mjml-rb"; puts MjmlRb.mjml2html("<mjml><mj-body><mj-section><mj-column><mj-text>Hello</mj-text></mj-column></mj-section></mj-body></mjml>")[:html]'
|
|
27
|
+
```ruby
|
|
28
|
+
# Gemfile
|
|
29
|
+
gem "mjml-rb"
|
|
36
30
|
```
|
|
37
31
|
|
|
38
|
-
##
|
|
32
|
+
## Quick Start
|
|
39
33
|
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
|
|
34
|
+
```ruby
|
|
35
|
+
require "mjml-rb"
|
|
36
|
+
|
|
37
|
+
result = MjmlRb.mjml2html(<<~MJML)
|
|
38
|
+
<mjml>
|
|
39
|
+
<mj-body>
|
|
40
|
+
<mj-section>
|
|
41
|
+
<mj-column>
|
|
42
|
+
<mj-text>Hello World!</mj-text>
|
|
43
|
+
</mj-column>
|
|
44
|
+
</mj-section>
|
|
45
|
+
</mj-body>
|
|
46
|
+
</mjml>
|
|
47
|
+
MJML
|
|
48
|
+
|
|
49
|
+
puts result[:html] # compiled HTML
|
|
50
|
+
puts result[:errors] # validation errors (if any)
|
|
43
51
|
```
|
|
44
52
|
|
|
45
|
-
##
|
|
46
|
-
|
|
47
|
-
In a Rails app, requiring the gem registers an `ActionView` template handler for
|
|
48
|
-
`.mjml` templates through a `Railtie`.
|
|
49
|
-
|
|
50
|
-
By default, `.mjml` files are treated as raw MJML/XML source.
|
|
53
|
+
## CLI
|
|
51
54
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
```bash
|
|
56
|
+
mjml email.mjml -o email.html # compile to file
|
|
57
|
+
mjml -r "templates/*.mjml" -o output/ # batch compile
|
|
58
|
+
mjml -v email.mjml # validate only
|
|
59
|
+
mjml -i -s < email.mjml # stdin → stdout
|
|
56
60
|
```
|
|
57
61
|
|
|
58
|
-
|
|
62
|
+
See the [Usage Guide — CLI section](docs/USAGE.md#cli) for all flags and config options.
|
|
59
63
|
|
|
60
|
-
|
|
61
|
-
through that template engine first, so partials and embedded Ruby can assemble
|
|
62
|
-
MJML before the outer template is compiled to HTML. Without that setting,
|
|
63
|
-
non-XML MJML source is rejected instead of being guessed.
|
|
64
|
+
## Rails
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
registered in `ActionView` by the corresponding gem or integration layer.
|
|
66
|
+
Add the gem to your Gemfile — that's it. The `.mjml` template handler is registered automatically.
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
```mjml
|
|
68
|
+
```erb
|
|
69
|
+
<!-- app/views/user_mailer/welcome.html.mjml -->
|
|
71
70
|
<mjml>
|
|
72
71
|
<mj-body>
|
|
73
72
|
<mj-section>
|
|
74
73
|
<mj-column>
|
|
75
|
-
<mj-text>
|
|
74
|
+
<mj-text>Welcome, <%= @user.name %>!</mj-text>
|
|
76
75
|
</mj-column>
|
|
77
76
|
</mj-section>
|
|
78
77
|
</mj-body>
|
|
79
78
|
</mjml>
|
|
80
79
|
```
|
|
81
80
|
|
|
82
|
-
Then render it like any other Rails template:
|
|
83
|
-
|
|
84
81
|
```ruby
|
|
85
82
|
class UserMailer < ApplicationMailer
|
|
86
|
-
def welcome
|
|
87
|
-
|
|
83
|
+
def welcome(user)
|
|
84
|
+
@user = user
|
|
85
|
+
mail(to: user.email, subject: "Welcome")
|
|
88
86
|
end
|
|
89
87
|
end
|
|
90
88
|
```
|
|
91
89
|
|
|
92
|
-
|
|
93
|
-
compiler options in your application config:
|
|
94
|
-
|
|
95
|
-
```ruby
|
|
96
|
-
config.mjml_rb.compiler_options = { validation_level: "soft" }
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
## Custom components
|
|
90
|
+
Supports Slim and Haml via `config.mjml_rb.rails_template_language = :slim`. See the [Usage Guide — Rails section](docs/USAGE.md#rails-integration) for full configuration.
|
|
100
91
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
```ruby
|
|
104
|
-
class MjRating < MjmlRb::Components::Base
|
|
105
|
-
TAGS = ["mj-rating"].freeze
|
|
106
|
-
ALLOWED_ATTRIBUTES = { "stars" => "integer", "color" => "color" }.freeze
|
|
107
|
-
DEFAULT_ATTRIBUTES = { "stars" => "5", "color" => "#f4b400" }.freeze
|
|
108
|
-
|
|
109
|
-
def render(tag_name:, node:, context:, attrs:, parent:)
|
|
110
|
-
stars = (attrs["stars"] || "5").to_i
|
|
111
|
-
color = attrs["color"] || "#f4b400"
|
|
112
|
-
%(<div style="color:#{escape_attr(color)}">#{"\u2605" * stars}</div>)
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
MjmlRb.register_component(MjRating,
|
|
117
|
-
dependencies: { "mj-column" => ["mj-rating"] },
|
|
118
|
-
ending_tags: ["mj-rating"]
|
|
119
|
-
)
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
The `dependencies` hash declares which parent tags accept the new component as a child. The `ending_tags` list tells the parser to treat content as raw HTML (like `mj-text`). Both are optional.
|
|
123
|
-
|
|
124
|
-
Once registered, the component works in MJML markup and is validated like any built-in component.
|
|
125
|
-
|
|
126
|
-
## `.mjmlrc` config file
|
|
127
|
-
|
|
128
|
-
Place a `.mjmlrc` file (JSON) in your project root to auto-register custom components and set default compiler options:
|
|
92
|
+
## Architecture
|
|
129
93
|
|
|
130
|
-
```json
|
|
131
|
-
{
|
|
132
|
-
"packages": [
|
|
133
|
-
"./lib/mjml_components/mj_rating.rb"
|
|
134
|
-
],
|
|
135
|
-
"options": {
|
|
136
|
-
"beautify": true,
|
|
137
|
-
"validation-level": "soft"
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
94
|
```
|
|
141
|
-
|
|
142
|
-
- **`packages`** — Ruby files to `require`. Each file should call `MjmlRb.register_component` to register its components.
|
|
143
|
-
- **`options`** — Default compiler options. CLI flags and programmatic options override these.
|
|
144
|
-
|
|
145
|
-
The CLI loads `.mjmlrc` automatically from the working directory. For the library API, load it explicitly:
|
|
146
|
-
|
|
147
|
-
```ruby
|
|
148
|
-
MjmlRb::ConfigFile.load("/path/to/project")
|
|
149
|
-
result = MjmlRb.mjml2html(mjml_string)
|
|
95
|
+
MJML string → Parser → AST → Validator → Renderer → HTML
|
|
150
96
|
```
|
|
151
97
|
|
|
152
|
-
|
|
98
|
+
1. **Parser** — normalizes source, expands `mj-include`, builds `AstNode` tree
|
|
99
|
+
2. **Validator** — checks structure, hierarchy, and attribute types
|
|
100
|
+
3. **Renderer** — resolves head metadata, applies defaults, emits responsive HTML
|
|
153
101
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
1. `MjmlRb.mjml2html` calls `MjmlRb::Compiler`.
|
|
157
|
-
2. `MjmlRb::Parser` normalizes the source, expands `mj-include`, and builds an `AstNode` tree.
|
|
158
|
-
3. `MjmlRb::Validator` checks structural rules and supported attributes.
|
|
159
|
-
4. `MjmlRb::Renderer` resolves head metadata, applies component defaults, and renders HTML.
|
|
160
|
-
5. `MjmlRb::Compiler` post-processes the output and returns a `Result`.
|
|
161
|
-
|
|
162
|
-
The key architectural idea is that the project uses a small shared AST plus a component registry:
|
|
163
|
-
|
|
164
|
-
- the parser produces generic `AstNode` objects instead of component-specific node types
|
|
165
|
-
- structure rules live in `lib/mjml-rb/dependencies.rb`
|
|
166
|
-
- rendering logic lives in `lib/mjml-rb/components/*`
|
|
167
|
-
- head components populate a shared rendering context
|
|
168
|
-
- body components consume that context and emit the final HTML
|
|
169
|
-
|
|
170
|
-
That split keeps the compiler pipeline predictable:
|
|
171
|
-
|
|
172
|
-
- parsing is responsible for source normalization and include expansion
|
|
173
|
-
- validation is responsible for MJML structure and attribute checks
|
|
174
|
-
- rendering is responsible for HTML generation and responsive email output
|
|
175
|
-
|
|
176
|
-
## Project structure
|
|
177
|
-
|
|
178
|
-
The main files are organized like this:
|
|
179
|
-
|
|
180
|
-
```text
|
|
181
|
-
lib/mjml-rb.rb # public gem entry point
|
|
182
|
-
lib/mjml-rb/compiler.rb # orchestration: parse -> validate -> render
|
|
183
|
-
lib/mjml-rb/parser.rb # MJML/XML normalization, includes, AST building
|
|
184
|
-
lib/mjml-rb/ast_node.rb # shared tree representation
|
|
185
|
-
lib/mjml-rb/validator.rb # structural and attribute validation
|
|
186
|
-
lib/mjml-rb/dependencies.rb # allowed parent/child relationships
|
|
187
|
-
lib/mjml-rb/renderer.rb # HTML document assembly and render context
|
|
188
|
-
lib/mjml-rb/components/* # per-component rendering and head handling
|
|
189
|
-
lib/mjml-rb/result.rb # result object returned by the compiler
|
|
190
|
-
lib/mjml-rb/cli.rb # CLI implementation used by bin/mjml
|
|
191
|
-
docs/ARCHITECTURE.md # deeper architecture notes
|
|
192
|
-
docs/PARITY_AUDIT.md # npm vs Ruby parity tracking
|
|
193
|
-
```
|
|
102
|
+
For the full internal walkthrough, see [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
|
|
194
103
|
|
|
195
|
-
|
|
104
|
+
Remaining parity work is tracked in [npm ↔ Ruby Parity Audit](docs/PARITY_AUDIT.md).
|
|
196
105
|
|
|
197
|
-
##
|
|
106
|
+
## License
|
|
198
107
|
|
|
199
|
-
|
|
200
|
-
>
|
|
201
|
-
> The npm `mjml` package requires Node.js at build time (or runtime via a child
|
|
202
|
-
> process / FFI bridge). This project replaces that entire pipeline with a single
|
|
203
|
-
> Ruby library: XML parsing, AST construction, attribute resolution, validation,
|
|
204
|
-
> and HTML rendering — all in Ruby, with no Node.js runtime and no need to
|
|
205
|
-
> shell out to the official MJML renderer. Drop it into a Rails, Sinatra, or
|
|
206
|
-
> plain Ruby project and render MJML templates the same way you render ERB — no
|
|
207
|
-
> extra runtime, no
|
|
208
|
-
> `package.json`, no `node_modules`.
|
|
108
|
+
MIT
|
|
@@ -603,7 +603,7 @@ module MjmlRb
|
|
|
603
603
|
"overflow" => (has_border_radius ? "hidden" : nil),
|
|
604
604
|
"margin" => "0px auto",
|
|
605
605
|
"margin-top" => wrapper_gap,
|
|
606
|
-
"max-width" =>
|
|
606
|
+
"max-width" => "#{container_px}px"
|
|
607
607
|
}.merge(full_width ? {} : background_styles)
|
|
608
608
|
)
|
|
609
609
|
|
data/lib/mjml-rb/renderer.rb
CHANGED
|
@@ -545,6 +545,12 @@ module MjmlRb
|
|
|
545
545
|
end
|
|
546
546
|
|
|
547
547
|
def normalize_background_fallbacks!(node, declarations)
|
|
548
|
+
background_image = declaration_value(declarations["background-image"])
|
|
549
|
+
if background_image && !background_image.empty?
|
|
550
|
+
declarations.delete("background") if syncable_background?(declaration_value(declarations["background"]))
|
|
551
|
+
return
|
|
552
|
+
end
|
|
553
|
+
|
|
548
554
|
background_color = declaration_value(declarations["background-color"])
|
|
549
555
|
return if background_color.nil? || background_color.empty?
|
|
550
556
|
|
data/lib/mjml-rb/version.rb
CHANGED