Crate defy

source ·
Expand description

Replacement for the yew html macro with more Rust-idiomatic, editor-friendly syntax.

The syntax used in this crate is largely inspired by kotlinx.html and horrorshow.

Example

use defy::defy;

struct Datum {
    field:   &'static str,
    display: bool,
    label:   Label,
}
enum Label {
    First(i32),
    Second(u64),
}
let data = vec![
    Datum { field: "foo", display: false, label: Label::First(1) },
    Datum { field: "bar", display: true, label: Label::Second(2) },
];

let vnode = defy! {
    h1 {
        + "Hello world";
    }
    ul {
        for datum in data {
            let field = datum.field;
            if datum.display {
                li(data-length = field.len().to_string()) {
                    + field;
                }
            }
            match datum.label {
                Label::First(i) if i > 3 => {
                    h2 { +i; }
                }
                Label::Second(i) => {
                    h3 { +i; }
                    br;
                }
                _ => { +"unmatched"; }
            }
        }
    }
};

let vnode_html = /* omitted implementation rendering vnode into HTML string */;
assert_eq!(
    canonicalize(vnode_html.as_str()),
    canonicalize(
        r#"
        <h1>Hello world</h1>
        <ul>
            unmatched
            <li data-length="3">bar</li>
            <h3>2</h3>
            <br> <!-- we actually emitted <br/> here, but yew processed it into <br> -->
        </ul>
        "#
    )
);

fn canonicalize(string: &str) -> String {
    // Omitted implementation: strips whitespaces and comments
}

Reference

HTML tag without children

foo(a = b, c = d);

becomes

<foo a={b} c={d} />

HTML tag with children

foo(a = b, c = d) { ... }

becomes

<foo a={b} c={d}> ... </foo>

Text values

+ expr;

becomes

`{ expr }`

Local variables

Local variables can be defined in the form of normal let statements. However they must precede all non-let statements in a {} block in order to preserve evaluation order.

If executing a let statement after other contents is really necessary, place them under a separate if true {} block.

If, If-else, For

Same as the normal Rust syntax, except the contents in braces are automatically defy!-ed.

Match

Same as the normal Rust syntax, except match arm bodies must be surrounded in braces, and the contents inside are automatically defy!-ed.

Macros

  • See crate-level documentation.