aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Andrew Dona-Couch <hi@andrewcou.ch>2020-07-08 17:03:02 +0000
committerLibravatar Dirkjan Ochtman <dirkjan@ochtman.nl>2020-07-14 20:48:15 +0200
commit42c4cb1d877d696bb97aa2e9402429dad42d7d66 (patch)
tree81db4dfc1925a2a8cc4e99c42ae4cc003e60f9e5
parent21fb60466c9bae2fac325f057da20d7143618412 (diff)
downloadaskama-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 }}`
Diffstat (limited to '')
-rw-r--r--askama_shared/src/filters/mod.rs24
-rw-r--r--askama_shared/src/generator.rs18
-rw-r--r--testing/tests/filters.rs12
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,