Some time ago, @djc offered @Kijewski and I to take over the maintenance of the askama crate as they don't have time to work on it anymore. We (@Kijewski and I) were originally reviewers and maintainers of the original askama project but had some disagreements over some specifics which we worked out in the meantime. You can find the list of changes between askama 0.12 and rinja in my previous blog post about it.
So in short: rinja
next release will be askama 0.13
.
For users who already migrated to rinja
, there won't be as many changes but this remains a very big release. For askama users, I recommend taking a look at my blog post first and then you can see the rest of the changes in the askama release page. Then when everyone is up-to-date, let's go through this release changes.
We finally added support for deriving Template
on enum types:
Run#[derive(Template)]
#[template(path = "area.txt")]
enum Area {
Square(f32),
Rectangle { a: f32, b: f32 },
Circle { radius: f32 },
}
You can also specialize the implementation for variants if you want:
Run#[derive(Template, Debug)]
#[template(path = "area.txt")]
enum AreaPerVariant {
#[template(source = "{{self.0}}^2")]
Square(f32),
#[template(path = "rectangle.txt")]
Rectangle { a: f32, b: f32 },
Circle { radius: f32 },
}
However if not all variants have a #[template()]
, then the enum needs to have it as it will be used as the default template.
PR: https://github.com/askama-rs/askama/pull/255
You can now concat strings with the new ~
operator:
{{ a ~ b }}
It can be quite useful when you want to call a filter on the concatenated strings as well:
{{ (a ~ b)|upper }}
PR: https://github.com/askama-rs/askama/pull/236
It is now possible to define some variables at runtime. It's especially useful in case you have a common value that you don't want to put into all your types. To do so, we created a new Values
trait which we implemented on a few types provided by the std
like HashMap
:
Runuse std::collections::HashMap;
let mut values: HashMap<&str, Box<dyn Any>> = HashMap::new();
// We add a new value named "name" with the value "Bibop".
values.insert("name", Box::new("Bibop"));
values.insert("age", Box::new(12u32));
The Values
trait is expecting types storing data with the Any trait, allowing to store any type.
Then to render with these values:
Runtemplate_struct.render_with_values(&values).unwrap();
There are two ways to get the values from the template, either by using the (newly added) value
filter or by calling directly the askama::get_value
function:
{% if let Ok(name) = "name"|value::<&str> %}
name is {{ name }}
{% endif %}
{% if let Ok(age) = askama::get_value::<u32>("age") %}
age is {{ age }}
{% endif %}
If you try to retrieve a value with the wrong type or that you didn't set, you will get an Err(ValueError)
.
PR: https://github.com/askama-rs/askama/pull/311
This is an artifact we forgot to remove when we remove the binary operators when we originally forked askama. This restriction is now finally lifted, so you can now have:
{{ a | filter }}
PR: https://github.com/askama-rs/askama/pull/250
Although the if let
chain feature isn't stable yet, we added support for its syntax. Don't forget that until the feature has been stabilized in Rust, the generated code will need nightly to compile. But in any case, this code is now supported by askama:
{% if let Some(bla) = y
&& bla == "x"
&& let Some(blob) = z
&& blob == "z" %}
{{bla}} {{blob}}
{% endif %}
PR: https://github.com/askama-rs/askama/pull/296
By default, askama enables the std
and alloc
features, however you can disable them, allowing you to use this crate in projects that use #![no_std]
.
PR: https://github.com/askama-rs/askama/pull/286
Before, having whitespace control on extends
generated syntax errors. It still doesn't do anything, but at least it doesn't prevent compilation anymore. Example:
{%- extends "some.html" ~%}
You can now write:
Run#[derive(Template)]
#[template(
ext = "txt",
source = "
{%- block first -%} first=<{{first}}> {%- endblock -%}
{%- block fail -%} better luck next time {%- endblock -%}
",
block = "fail",
blocks = ["first"]
)]
struct WithBlocks<'a, S: Display, T>
where
T: Display,
{
first: &'a str,
}
let tmpl = WithBlocks {
first: "number one",
};
assert_eq!(tmpl.as_first().render().unwrap(), "first=<number one>");
assert_eq!(tmpl.render().unwrap(), "better luck next time");
It generates the associated method(s) based on what is listed in blocks
. So in this example, you now have a new as_first
method.
If you use the render
method, it will default to block
if specified, otherwise it'll render the provided template.
PR: https://github.com/askama-rs/askama/pull/337
You can now specify generics when calling a function/method/filter:
{{ a.b::<&str, H<B<C>>>() }}
{{ 12 | a::<&str> }}
PR: https://github.com/askama-rs/askama/pull/317
So now, you finally have variables named _x
or you can match against _
:
{% let _x = 7 %}
{% if let Some(_) = Some(12) %}hey{% endif %}
{% if let [_] = [12] %}hoy{% endif %}
PR: https://github.com/askama-rs/askama/pull/244
The filesizeformat
filter now takes any type which can be casted into f32
as argument:
Run#[derive(Template)]
#[template(
source = r#"{% if let Some(x) = s %}{{x|filesizeformat}}{% endif %}"#,
ext = "html"
)]
struct S {
s: Option<u32>,
}
fn main() {
assert_eq!(S { s: Some(12) }.render().unwrap(), "12 B");
}
PR: https://github.com/askama-rs/askama/pull/216
If you want to implement the Template
trait by hand and not have the weight of proc-macro related crates, it's now possible! There is a new enabled by default derive
feature.
Of course, we still recommend to use it but you now have the option not to.
PR: https://github.com/askama-rs/askama/pull/342
This release took a lot longer to be released with the merge with askama, but we're quite pleased with the result. Thanks to @djc for their trust in our work and we hope you'll enjoy using askama!
No cat was deprived of sleep for this release!