maciejhirsz / ramhorns

Fast Mustache template engine implementation in pure Rust.
https://crates.io/crates/ramhorns
Mozilla Public License 2.0
297 stars 29 forks source link

Is it possible to name elements of a Vec<String>? #42

Open quat1024 opened 3 years ago

quat1024 commented 3 years ago

So I'm making a personal blog site (surprise), and I wanted to add post tags. No problem, i'll add a field to my struct real quick.

#[derive(Content)]
pub struct Post {
    //...
    pub tags: Vec<String>
}

Now to make a row of links to each tag. Let's see.

{{#tags}}<a href="/post/tag/{{ ? }}">{{ ? }}</a> {{/tags}}

...I'm not sure how to name each item in the Vec. The section repeats 3 times if there are 3 elements in the Vec, but I don't know how to actually refer to the element, to make the sections different.

I was able to solve it using a tuple struct, just because I can name the field 0, like this.

#[derive(Content)]
pub struct Post {
    //...
    pub tags: Vec<Tag>
}

#[derive(Content, Clone, PartialEq, Eq, Hash, Default, Debug)] //idk im not used to tuple structs
pub struct Tag(String);
{{#tags}}<a href="/post/tag/{{0}}">{{0}}</a> {{/tags}}

I'm a little bummed that I needed a useless tuple struct for this though. Is there a nicer way to do this?

maciejhirsz commented 3 years ago

There isn't a way to address "self" in mustache as far as I'm aware, so that was never part of the spec here either. I'd be happy to accept a PR that adds render_field_escaped and render_field_unescaped to String and str impls of Content for a predefined faux field name, such as . (so {{.}} in templates).

maciejhirsz commented 3 years ago

Having slept on this, I think the proper way to do it is to expose sections to the same variable name as the main field in the map, so in your case that should be: {{#tags}}<a href="/post/tag/{{tags}}">{{tags}}</a> {{/tags}}.

This would make loops analogous to how a single string works with existence checks. On the flip side, it will require a bit more messing around in the code.