Keats / tera

A template engine for Rust based on Jinja2/Django
http://keats.github.io/tera/
MIT License
3.36k stars 280 forks source link

Ability to build an object or hashmap? #898

Open absolutejam opened 5 months ago

absolutejam commented 5 months ago

Hey!

I'm trying to build some grouping functionality for my Zola blog and I wondered if it is currently possible (or planned) to build and mutate a JSON object or hashmap data structure?

For example, I'm currently iterating over an array of objects that each have their own tags. I'd like to be able to group these objects into by their tags, ending up with a Hashmap<String, Vec<MyObject>> in rough Rust terms.

It looks like this would probably want to live in https://github.com/Keats/tera/blob/master/src/builtins/filters/object.rs as this is already concerned with handling serde_json::Value::Objects?

I'm happy to take a stab at this if you're okay with it 👍

schungx commented 3 months ago

This will be tremendously interesting to me. It will drastically reduce the number of parameters I have in macros and simplify a lot of code if optional fields can be grouped inside a single config object instead of each being a variable.

A way to create a hash literal is needed as well as the ability to set a field of an object.

schungx commented 3 months ago

@absolutejam your suggestion gives me an idea.

We can very simply write such a function, say make_obj, that returns a hash object from its parameters.

Until the native syntax arrives, this can be a huge boom in productivity as I can then write macros that take objects as parameters.

EDIT: I confirm that the idea works. I have obj function and mixin/polyfill filters and all are looking good!

Keats commented 3 months ago

What's not defined yet is what would be the syntax to update a hashmap

schungx commented 3 months ago

I solved it via a mixin filter:

{{ map | mixin(foo=42, bar=true) }}

will return a new map with the two properties replaced.

Setting properties then become:

set map = map | mixin(foo=42, bar=true)
Keats commented 3 months ago

Yeah the filter is the obvious one, it's just a bit verbose to set new things but maybe it's the simpler one

schungx commented 2 months ago

If you're looking for syntax suggestions, I suggest:

{% set_prop map.foo = 42 %}
{% set_prop map["foo"] = 42 %}

{% remove_prop map.foo %}
{% remove_prop map["foo"] %}
Keats commented 2 months ago

Or maybe just {% set map.foo = 42 %}? I don't know if we will need to remove things from a hashmap. I have never needed that in any template engine (so far)

schungx commented 2 months ago

Or maybe just {% set map.foo = 42 %}? I don't know if we will need to remove things from a hashmap. I have never needed that in any template engine (so far)

That would work too...

In that case we can do delete map.prop or delete_prop map.prop like JavaScript.