diff options
author | Andrew Dona-Couch <hi@andrewcou.ch> | 2020-07-08 17:03:02 +0000 |
---|---|---|
committer | Dirkjan Ochtman <dirkjan@ochtman.nl> | 2020-07-14 20:48:15 +0200 |
commit | 42c4cb1d877d696bb97aa2e9402429dad42d7d66 (patch) | |
tree | 81db4dfc1925a2a8cc4e99c42ae4cc003e60f9e5 | |
parent | 21fb60466c9bae2fac325f057da20d7143618412 (diff) | |
download | askama-42c4cb1d877d696bb97aa2e9402429dad42d7d66.tar.gz askama-42c4cb1d877d696bb97aa2e9402429dad42d7d66.tar.bz2 askama-42c4cb1d877d696bb97aa2e9402429dad42d7d66.zip |
Add fmt filter that swaps the first two arguments to format!().
This allows a more natural filter usage: `{{ val | fmt("{:?}") }}`
as well as enabling convenient filter composition:
`{{ price | to_f64 | fmt("${:.2}") | center }}`
-rw-r--r-- | askama_shared/src/filters/mod.rs | 24 | ||||
-rw-r--r-- | askama_shared/src/generator.rs | 18 | ||||
-rw-r--r-- | testing/tests/filters.rs | 12 |
3 files changed, 53 insertions, 1 deletions
diff --git a/askama_shared/src/filters/mod.rs b/askama_shared/src/filters/mod.rs index 2604ed9..7253e4b 100644 --- a/askama_shared/src/filters/mod.rs +++ b/askama_shared/src/filters/mod.rs @@ -58,13 +58,14 @@ const ENCODE_SET: &AsciiSet = &NON_ALPHANUMERIC // Askama or should refer to a local `filters` module. It should contain all the // filters shipped with Askama, even the optional ones (since optional inclusion // in the const vector based on features seems impossible right now). -pub const BUILT_IN_FILTERS: [&str; 24] = [ +pub const BUILT_IN_FILTERS: [&str; 25] = [ "abs", "capitalize", "center", "e", "escape", "filesizeformat", + "fmt", "format", "indent", "into_f64", @@ -139,10 +140,31 @@ pub fn urlencode(s: &dyn fmt::Display) -> Result<String> { /// Formats arguments according to the specified format /// +/// The *second* argument to this filter must be a string literal (as in normal +/// Rust). The two arguments are passed through to the `format!()` +/// [macro](https://doc.rust-lang.org/stable/std/macro.format.html) by +/// the Askama code generator, but the order is swapped to support filter +/// composition. +/// +/// ```ignore +/// {{ value | fmt("{:?}") }} +/// ``` +/// +/// Compare with [format](./fn.format.html). +pub fn fmt() {} + +/// Formats arguments according to the specified format +/// /// The first argument to this filter must be a string literal (as in normal /// Rust). All arguments are passed through to the `format!()` /// [macro](https://doc.rust-lang.org/stable/std/macro.format.html) by /// the Askama code generator. +/// +/// ```ignore +/// {{ "{:?}{:?}" | format(value, other_value) }} +/// ``` +/// +/// Compare with [fmt](./fn.fmt.html). pub fn format() {} /// Replaces line breaks in plain text with appropriate HTML diff --git a/askama_shared/src/generator.rs b/askama_shared/src/generator.rs index 82f68ff..e45acb6 100644 --- a/askama_shared/src/generator.rs +++ b/askama_shared/src/generator.rs @@ -999,6 +999,9 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> { if name == "format" { self._visit_format_filter(buf, args); return DisplayWrap::Unwrapped; + } else if name == "fmt" { + self._visit_fmt_filter(buf, args); + return DisplayWrap::Unwrapped; } else if name == "join" { self._visit_join_filter(buf, args); return DisplayWrap::Unwrapped; @@ -1038,6 +1041,21 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> { buf.write(")"); } + fn _visit_fmt_filter(&mut self, buf: &mut Buffer, args: &[Expr]) { + buf.write("format!("); + if let Some(Expr::StrLit(v)) = args.get(1) { + self.visit_str_lit(buf, v); + buf.write(", "); + } else { + panic!("invalid expression type for fmt filter"); + } + self._visit_args(buf, &args[0..1]); + if args.len() > 2 { + panic!("only two arguments allowed to fmt filter"); + } + buf.write(")"); + } + // Force type coercion on first argument to `join` filter (see #39). fn _visit_join_filter(&mut self, buf: &mut Buffer, args: &[Expr]) { buf.write("::askama::filters::join((&"); diff --git a/testing/tests/filters.rs b/testing/tests/filters.rs index b02a64b..035e5da 100644 --- a/testing/tests/filters.rs +++ b/testing/tests/filters.rs @@ -39,6 +39,18 @@ fn filter_format() { } #[derive(Template)] +#[template(source = "{{ var|fmt(\"{:?}\") }}", ext = "html", escape = "none")] +struct FmtTemplate<'a> { + var: &'a str, +} + +#[test] +fn filter_fmt() { + let t = FmtTemplate { var: "formatted" }; + assert_eq!(t.render().unwrap(), "\"formatted\""); +} + +#[derive(Template)] #[template(source = "{{ s|myfilter }}", ext = "txt")] struct MyFilterTemplate<'a> { s: &'a str, |