Skip to content

Commit

Permalink
Merge pull request #117 from adoptoposs/dependabot/cargo/native/mjml_…
Browse files Browse the repository at this point in the history
…nif/mrml-2.1.1

Bump mrml from 1.2.11 to 2.1.1 in /native/mjml_nif
  • Loading branch information
paulgoetze authored Dec 10, 2023
2 parents e0df1cd + fad656f commit 96839fe
Show file tree
Hide file tree
Showing 8 changed files with 206 additions and 85 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ I.e. `mjml_nif 0.x` versions use mrml versions `>= 0.1, < 1.0.0`, and `mjml_nif
## [Unreleased]

### Changed
- Use rustler_precompiled v0.7.0 + drop support for Elixir < v1.12
- Use rustler_precompiled v0.7.1 + drop support for Elixir < v1.12
- Use Rust edition 2021
- Use rustler v0.30.0
- Drop arm-unknown-linux-gnueabihf as precompiled target
- Use [mrml] v.2.1.1

---

Expand Down
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,21 @@ Available rendering options are:

* `keep_comments` – when `false`, removes comments from the final HTML. Defaults to `true`.
* `social_icon_path` – when given, uses this base path to generate social icon URLs.
* `fonts` – a Map of font names and their URLs to a hosted CSS file.
When given, includes these fonts in the rendered HTML
(Note that only actually used fonts will show up!).
Defaults to `nil`, which will make the default font families available to
be used (Open Sans, Droid Sans, Lato, Roboto, and Ubuntu).

```elixir
mjml = "<mjml>...</mjml>"

opts = [
keep_comments: false,
social_icon_path: "https://example.com/icons/"
social_icon_path: "https://example.com/icons/",
fonts: %{
"Noto Color Emoji": "https://fonts.googleapis.com/css?family=Noto+Color+Emoji:400"
}
]

{:ok, html} = Mjml.to_html(mjml, opts)
Expand Down
14 changes: 13 additions & 1 deletion lib/mjml.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ defmodule Mjml do
E.g. `social_icon_path: "https://example.com/icons/"` will generate a social icon
URL, like "https://example.com/icons/github.png"
* `fonts` – a Map of font names and their URLs to hosted CSS files.
When given, includes these fonts in the rendered HTML
(Note that only actually used fonts will show up!).
Defaults to `nil`, which will make the default font families available to
be used (Open Sans, Droid Sans, Lato, Roboto, and Ubuntu).
## Examples
iex> Mjml.to_html("<mjml><mj-head></mj-head></mjml>")
Expand All @@ -28,7 +34,13 @@ defmodule Mjml do
iex> Mjml.to_html("something not MJML")
{:error, "Couldn't convert MJML template"}
iex> opts = [keep_comments: false, social_icon_path: "https://example.com/icons/"]
iex> opts = [
iex> keep_comments: false,
iex> social_icon_path: "https://example.com/icons/"
iex> fonts: %{
iex> "Noto Color Emoji": "https://fonts.googleapis.com/css?family=Noto+Color+Emoji:400"
iex> }
iex> ]
iex> Mjml.to_html("<mjml><mj-head></mj-head></mjml>", opts)
{:ok, "<!doctype html><html xmlns=..."}
Expand Down
2 changes: 1 addition & 1 deletion lib/mjml/render_options.ex
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
defmodule Mjml.RenderOptions do
defstruct keep_comments: true, social_icon_path: nil
defstruct keep_comments: true, social_icon_path: nil, fonts: nil
end
134 changes: 61 additions & 73 deletions native/mjml_nif/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion native/mjml_nif/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ crate-type = ["cdylib"]

[dependencies]
rustler = "0.30.0"
mrml = { version = "1.2", default-features = false, features = ["parse", "render", "orderedmap"] }
mrml = { version = "2.1", default-features = false, features = ["parse", "render", "orderedmap"] }

[features]
default = ["nif_version_2_15"]
Expand Down
60 changes: 55 additions & 5 deletions native/mjml_nif/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use mrml;
use rustler::{Encoder, Env, NifStruct, NifResult, Term};
use std::borrow::Cow;
use std::borrow::Cow::Owned;
use std::collections::HashMap;

mod atoms {
rustler::atoms! {
Expand All @@ -10,18 +13,20 @@ mod atoms {

#[derive(NifStruct)]
#[module = "Mjml.RenderOptions"]
pub struct Options {
pub struct RenderOptions <'a> {
pub keep_comments: bool,
pub social_icon_path: Option<String>
pub social_icon_path: Option<String>,
pub fonts: Option<HashMap<Term<'a>, Term<'a>>>
}

#[rustler::nif]
pub fn to_html<'a>(env: Env<'a>, mjml: String, render_options: Options) -> NifResult<Term<'a>> {
pub fn to_html<'a>(env: Env<'a>, mjml: String, render_options: RenderOptions) -> NifResult<Term<'a>> {
return match mrml::parse(&mjml) {
Ok(root) => {
let options = mrml::prelude::render::Options{
let options = mrml::prelude::render::RenderOptions{
disable_comments: !render_options.keep_comments,
social_icon_origin: render_options.social_icon_path
social_icon_origin: social_icon_origin_option(render_options.social_icon_path),
fonts: fonts_option(render_options.fonts)
};

return match root.render(&options) {
Expand All @@ -33,4 +38,49 @@ pub fn to_html<'a>(env: Env<'a>, mjml: String, render_options: Options) -> NifRe
};
}

fn social_icon_origin_option(option_value: Option<String>) -> Option<Cow<'static, str>> {
option_value.map_or(
mrml::prelude::render::RenderOptions::default().social_icon_origin,
|origin| Some(Owned(origin))
)
}

fn fonts_option<'a>(option_values: Option<HashMap<Term<'a>, Term<'a>>>) -> HashMap<String, Cow<'static, str>> {
option_values.map_or(
mrml::prelude::render::RenderOptions::default().fonts,
|fonts| -> HashMap<String, Cow<'static, str>> {
let mut options : HashMap<String, Cow<'static, str>> = HashMap::new();

for (key, value) in fonts {
let (k, v) = font_option(key, value);
options.insert(k, v);
}

return options
}
)
}

fn font_option<'a>(key: Term<'a>, value: Term<'a>) -> (String, Cow<'static, str>) {
(
match key.atom_to_string() {
Ok(s) => s,
Err(_) => panic!(
"Keys for the `fonts` render option must be of type Atom, got {:?}.
Please use a Map like this: %{{\"My Font Name\": \"https://myfonts.example.com/css\"}}",
key.get_type()
)

},
match value.decode::<String>() {
Ok(s) => Owned(s),
Err(_) => panic!(
"Values for the `fonts` render option must be of type String, got {:?}.
Please use a Map like this: %{{\"My Font Name\": \"https://myfonts.example.com/css\"}}",
value.get_type()
)
}
)
}

rustler::init!("Elixir.Mjml.Native", [to_html]);
Loading

0 comments on commit 96839fe

Please sign in to comment.