aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar defyrlt <defyrlt@users.noreply.github.com>2017-08-29 23:02:13 +0300
committerLibravatar Dirkjan Ochtman <dirkjan@ochtman.nl>2017-09-02 13:34:52 +0200
commit7d2d7718aa8467ddd5ca9753bde2c7a87ff55c9f (patch)
tree98618ab42faa8e64d9ad96f19379e3ec82041a3e
parentb0ea82d87aa61576d1565f20276d411295b9a19d (diff)
downloadaskama-7d2d7718aa8467ddd5ca9753bde2c7a87ff55c9f.tar.gz
askama-7d2d7718aa8467ddd5ca9753bde2c7a87ff55c9f.tar.bz2
askama-7d2d7718aa8467ddd5ca9753bde2c7a87ff55c9f.zip
Add `join` filter & tests for it
-rw-r--r--askama_shared/src/filters/mod.rs46
-rw-r--r--askama_shared/src/generator.rs25
-rw-r--r--testing/templates/filters_join.html1
-rw-r--r--testing/tests/filters.rs25
4 files changed, 97 insertions, 0 deletions
diff --git a/askama_shared/src/filters/mod.rs b/askama_shared/src/filters/mod.rs
index 73b311d..75014fa 100644
--- a/askama_shared/src/filters/mod.rs
+++ b/askama_shared/src/filters/mod.rs
@@ -12,6 +12,7 @@ mod json;
pub use self::json::json;
use std::fmt;
+
use super::Result;
@@ -96,6 +97,27 @@ pub fn trim(s: &fmt::Display) -> Result<String> {
Ok(s.trim().to_owned())
}
+/// Joins iterable into a string separated by provided argument
+pub fn join<T, I, S>(input: I, separator: S) -> Result<String>
+ where T: fmt::Display,
+ I: Iterator<Item = T>,
+ S: AsRef<str>
+{
+ let separator: &str = separator.as_ref();
+
+ let mut rv = String::new();
+
+ for (num, item) in input.enumerate() {
+ if num > 0 {
+ rv.push_str(separator);
+ }
+
+ rv.push_str(&format!("{}", item));
+ }
+
+ Ok(rv)
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -127,4 +149,28 @@ mod tests {
fn test_trim() {
assert_eq!(trim(&" Hello\tworld\t").unwrap(), "Hello\tworld");
}
+
+ #[test]
+ fn test_join() {
+ assert_eq!(join((&["hello", "world"]).into_iter(), ", ").unwrap(), "hello, world");
+ assert_eq!(join((&["hello"]).into_iter(), ", ").unwrap(), "hello");
+
+ let empty: &[&str] = &[];
+ assert_eq!(join(empty.into_iter(), ", ").unwrap(), "");
+
+ let input: Vec<String> = vec!["foo".into(), "bar".into(), "bazz".into()];
+ assert_eq!(join((&input).into_iter(), ":".to_string()).unwrap(), "foo:bar:bazz");
+ assert_eq!(join(input.clone().into_iter(), ":").unwrap(), "foo:bar:bazz");
+ assert_eq!(join(input.clone().into_iter(), ":".to_string()).unwrap(), "foo:bar:bazz");
+
+ let input: &[String] = &["foo".into(), "bar".into()];
+ assert_eq!(join(input.into_iter(), ":").unwrap(), "foo:bar");
+ assert_eq!(join(input.into_iter(), ":".to_string()).unwrap(), "foo:bar");
+
+ let real: String = "blah".into();
+ let input: Vec<&str> = vec![&real];
+ assert_eq!(join(input.into_iter(), ";").unwrap(), "blah");
+
+ assert_eq!(join((&&&&&["foo", "bar"]).into_iter(), ", ").unwrap(), "foo, bar");
+ }
}
diff --git a/askama_shared/src/generator.rs b/askama_shared/src/generator.rs
index e5ffd08..836da34 100644
--- a/askama_shared/src/generator.rs
+++ b/askama_shared/src/generator.rs
@@ -238,10 +238,35 @@ impl<'a> Generator<'a> {
self.write(")");
}
+ fn _visit_join_filter(&mut self, args: &[Expr]) {
+ // this is a separate handler because we need to generate code like
+ // this to force auto-deref for first argument:
+ // `join((&&&&&&self.s).into_iter(), ", ")`
+ // otherwise, we were getting errors described in PR #39
+ self.write("::askama::filters::join((&");
+
+ for (i, arg) in args.iter().enumerate() {
+ if i > 0 {
+ self.write(", &");
+ }
+
+ self.visit_expr(arg);
+
+ if i == 0 {
+ self.write(").into_iter()");
+ }
+ }
+
+ self.write(")?");
+ }
+
fn visit_filter(&mut self, name: &str, args: &[Expr]) {
if name == "format" {
self._visit_format_filter(args);
return;
+ } else if name == "join" {
+ self._visit_join_filter(args);
+ return;
}
if BUILT_IN_FILTERS.contains(&name) {
diff --git a/testing/templates/filters_join.html b/testing/templates/filters_join.html
new file mode 100644
index 0000000..61cc249
--- /dev/null
+++ b/testing/templates/filters_join.html
@@ -0,0 +1 @@
+{{ s|join(", ") }}
diff --git a/testing/tests/filters.rs b/testing/tests/filters.rs
index 524014e..b24ff61 100644
--- a/testing/tests/filters.rs
+++ b/testing/tests/filters.rs
@@ -49,3 +49,28 @@ fn test_my_filter() {
let t = MyFilterTemplate { s: "foo" };
assert_eq!(t.render().unwrap(), "faa");
}
+
+
+#[derive(Template)]
+#[template(path= "filters_join.html")]
+struct JoinTemplate<'a> {
+ s: &'a [&'a str],
+}
+
+#[test]
+fn test_join() {
+ let t = JoinTemplate { s: &["foo", "bar", "bazz"] };
+ assert_eq!(t.render().unwrap(), "foo, bar, bazz");
+}
+
+#[derive(Template)]
+#[template(path= "filters_join.html")]
+struct VecJoinTemplate {
+ s: Vec<String>
+}
+
+#[test]
+fn test_vec_join() {
+ let t = VecJoinTemplate { s: vec!["foo".into(), "bar".into(), "bazz".into()] };
+ assert_eq!(t.render().unwrap(), "foo, bar, bazz");
+}