From 75dc36c26e92c6bdf6d14fe699fad43334b860ec Mon Sep 17 00:00:00 2001 From: Konstantin Stepanov Date: Mon, 13 Jun 2016 12:54:16 +0300 Subject: [PATCH 1/4] add date filter --- Cargo.toml | 1 + src/filters.rs | 25 +++++++++++++++++++++++++ src/lib.rs | 1 + src/template.rs | 3 ++- 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 35d1f88e3..120462dcf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ build = "build.rs" [dependencies] regex = "0.1" lazy_static = "0.1.15" +chrono = "0.2.22" clippy = {version = "0.0", optional = true} [build-dependencies] diff --git a/src/filters.rs b/src/filters.rs index 855edf697..d05e383e6 100644 --- a/src/filters.rs +++ b/src/filters.rs @@ -4,6 +4,8 @@ use std::error::Error; use value::Value; use value::Value::*; +use chrono::DateTime; + use self::FilterError::*; #[derive(Debug)] @@ -297,6 +299,25 @@ pub fn join(input: &Value, args: &[Value]) -> FilterResult { } } +pub fn date(input: &Value, args: &[Value]) -> FilterResult { + if args.len() != 1 { + return Err(FilterError::InvalidArgumentCount(format!("expected 1, {} given", args.len()))); + } + + let date = match input { + &Value::Str(ref s) => try!(DateTime::parse_from_str(&s, "%d %B %Y %H:%M:%S %z") + .map_err(|e| FilterError::InvalidType(format!("Invalid date format: {}", e)))), + _ => return Err(FilterError::InvalidType("String expected".to_owned())), + }; + + let format = match args[0] { + Value::Str(ref s) => s, + _ => return Err(InvalidArgument(0, "Str expected".to_owned())), + }; + + Ok(Value::Str(format!("{}", date.format(format)))) +} + #[cfg(test)] mod tests { @@ -528,4 +549,8 @@ mod tests { assert_eq!(result.unwrap(), tos!("a,1,c")); } + #[test] + fn unit_date() { + assert_eq!(unit!(date, tos!("13 Jun 2016 02:30:00 +0300"), &[tos!("%Y-%m-%d")]), tos!("2016-06-13")); + } } diff --git a/src/lib.rs b/src/lib.rs index a5fc93c00..233c8e08e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,6 +63,7 @@ #[macro_use] extern crate lazy_static; extern crate regex; +extern crate chrono; use std::collections::HashMap; use lexer::Element; diff --git a/src/template.rs b/src/template.rs index 744a5d8aa..e6a7d793c 100644 --- a/src/template.rs +++ b/src/template.rs @@ -1,7 +1,7 @@ use Renderable; use context::Context; use filters::{size, upcase, downcase, capitalize, minus, plus, times, divided_by, ceil, floor, - round, prepend, append, first, last, pluralize, replace}; + round, prepend, append, first, last, pluralize, replace, date}; use filters::split; use filters::join; use error::Result; @@ -32,6 +32,7 @@ impl Renderable for Template { context.add_filter("pluralize", Box::new(pluralize)); context.add_filter("split", Box::new(split)); context.add_filter("join", Box::new(join)); + context.add_filter("date", Box::new(date)); let mut buf = String::new(); for el in &self.elements { From b96454efb1dc5f0d1f1207ae9d0b79cd4ee36523 Mon Sep 17 00:00:00 2001 From: Konstantin Stepanov Date: Thu, 23 Jun 2016 13:17:12 +0300 Subject: [PATCH 2/4] add date tests for error cases --- src/filters.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/filters.rs b/src/filters.rs index d05e383e6..1f8d868bb 100644 --- a/src/filters.rs +++ b/src/filters.rs @@ -8,7 +8,7 @@ use chrono::DateTime; use self::FilterError::*; -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] pub enum FilterError { InvalidType(String), InvalidArgumentCount(String), @@ -333,6 +333,15 @@ mod tests { }}; } + macro_rules! failed { + ( $a:ident, $b:expr ) => {{ + failed!($a, $b, &[]) + }}; + ( $a:ident, $b:expr, $c:expr ) => {{ + $a(&$b, $c).unwrap_err() + }}; + } + macro_rules! tos { ( $a:expr ) => {{ Str($a.to_owned()) @@ -552,5 +561,14 @@ mod tests { #[test] fn unit_date() { assert_eq!(unit!(date, tos!("13 Jun 2016 02:30:00 +0300"), &[tos!("%Y-%m-%d")]), tos!("2016-06-13")); + + assert_eq!(failed!(date, Num(0f32), &[tos!("%Y-%m-%d")]), + FilterError::InvalidType("String expected".to_owned())); + + assert_eq!(failed!(date, tos!("blah blah blah"), &[tos!("%Y-%m-%d")]), + FilterError::InvalidType("Invalid date format: input contains invalid characters".to_owned())); + + assert_eq!(failed!(date, tos!("13 Jun 2016 02:30:00 +0300"), &[Num(0f32)]), + FilterError::InvalidArgument(0, "Str expected".to_owned())); } } From ea22e3e637993d60c1e9ea0720a00b5166c960ae Mon Sep 17 00:00:00 2001 From: Konstantin Stepanov Date: Thu, 23 Jun 2016 13:17:26 +0300 Subject: [PATCH 3/4] better date to string conversion --- src/filters.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/filters.rs b/src/filters.rs index 1f8d868bb..4c879de2a 100644 --- a/src/filters.rs +++ b/src/filters.rs @@ -315,7 +315,7 @@ pub fn date(input: &Value, args: &[Value]) -> FilterResult { _ => return Err(InvalidArgument(0, "Str expected".to_owned())), }; - Ok(Value::Str(format!("{}", date.format(format)))) + Ok(Value::Str(date.format(format).to_string())) } #[cfg(test)] From 63c5321619a6bfabddb41c352465c1671c5a49b0 Mon Sep 17 00:00:00 2001 From: Konstantin Stepanov Date: Thu, 23 Jun 2016 13:33:31 +0300 Subject: [PATCH 4/4] another to error cases for date filter --- src/filters.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/filters.rs b/src/filters.rs index 4c879de2a..154bf3b15 100644 --- a/src/filters.rs +++ b/src/filters.rs @@ -570,5 +570,11 @@ mod tests { assert_eq!(failed!(date, tos!("13 Jun 2016 02:30:00 +0300"), &[Num(0f32)]), FilterError::InvalidArgument(0, "Str expected".to_owned())); + + assert_eq!(failed!(date, tos!("13 Jun 2016 02:30:00 +0300")), + FilterError::InvalidArgumentCount("expected 1, 0 given".to_owned())); + + assert_eq!(failed!(date, tos!("13 Jun 2016 02:30:00 +0300"), &[Num(0f32), Num(1f32)]), + FilterError::InvalidArgumentCount("expected 1, 2 given".to_owned())); } }