-
Notifications
You must be signed in to change notification settings - Fork 79
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(filters): array manipulation filters
Implemented some jekyll filters related to arrays: - push - pop - unshift - shift - array_to_sentence_string
- Loading branch information
1 parent
7bc6315
commit 94e6660
Showing
3 changed files
with
230 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,219 @@ | ||
use liquid_value::Value; | ||
|
||
use super::{check_args_len, invalid_input}; | ||
use interpreter::FilterResult; | ||
use std::fmt::Write; | ||
|
||
/// Receives a `Value::Array` as an input. | ||
/// Returns a copy of the input with the given value appended at the end. | ||
pub fn push(input: &Value, args: &[Value]) -> FilterResult { | ||
check_args_len(args, 1, 0)?; | ||
|
||
let value = args[0].clone(); | ||
let mut array = input | ||
.as_array() | ||
.ok_or_else(|| invalid_input("Array expected"))? | ||
.clone(); | ||
array.push(value); | ||
|
||
Ok(Value::array(array)) | ||
} | ||
|
||
/// Receives a `Value::Array` as an input. | ||
/// Returns a copy of the input with the last element removed. | ||
pub fn pop(input: &Value, args: &[Value]) -> FilterResult { | ||
check_args_len(args, 0, 0)?; | ||
|
||
let mut array = input | ||
.as_array() | ||
.ok_or_else(|| invalid_input("Array expected"))? | ||
.clone(); | ||
array.pop(); | ||
|
||
Ok(Value::array(array)) | ||
} | ||
|
||
/// Receives a `Value::Array` as an input. | ||
/// Returns a copy of the input with the given value appended at the beginning. | ||
pub fn unshift(input: &Value, args: &[Value]) -> FilterResult { | ||
check_args_len(args, 1, 0)?; | ||
|
||
let value = args[0].clone(); | ||
let mut array = input | ||
.as_array() | ||
.ok_or_else(|| invalid_input("Array expected"))? | ||
.clone(); | ||
array.insert(0, value); | ||
|
||
Ok(Value::array(array)) | ||
} | ||
|
||
/// Receives a `Value::Array` as an input. | ||
/// Returns a copy of the input with the first element removed. | ||
pub fn shift(input: &Value, args: &[Value]) -> FilterResult { | ||
check_args_len(args, 0, 0)?; | ||
|
||
let mut array = input | ||
.as_array() | ||
.ok_or_else(|| invalid_input("Array expected"))? | ||
.clone(); | ||
|
||
if !array.is_empty() { | ||
array.remove(0); | ||
} | ||
|
||
Ok(Value::array(array)) | ||
} | ||
|
||
/// Convert an array into a sentence. | ||
pub fn array_to_sentence_string(input: &Value, args: &[Value]) -> FilterResult { | ||
check_args_len(args, 0, 1)?; | ||
|
||
let connector = args.get(0).map(|arg| arg.to_str()); | ||
let connector = connector | ||
.as_ref() | ||
.map(|s| s.as_ref()) | ||
.unwrap_or_else(|| "and"); | ||
|
||
let mut array = input | ||
.as_array() | ||
.ok_or_else(|| invalid_input("Array expected"))? | ||
.iter(); | ||
|
||
let mut sentence = array | ||
.next() | ||
.map(|v| v.to_string()) | ||
.unwrap_or_else(|| "".to_string()); | ||
|
||
let last = array.next_back(); | ||
|
||
for value in array { | ||
write!(sentence, ", {}", value).expect("It should be safe to write to a string."); | ||
} | ||
|
||
if let Some(last) = last { | ||
write!(sentence, ", {} {}", connector, last) | ||
.expect("It should be safe to write to a string."); | ||
} | ||
|
||
Ok(Value::scalar(sentence)) | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
|
||
use super::*; | ||
|
||
macro_rules! unit { | ||
($a:ident, $b:expr) => {{ | ||
unit!($a, $b, &[]) | ||
}}; | ||
($a:ident, $b:expr, $c:expr) => {{ | ||
$a(&$b, $c).unwrap() | ||
}}; | ||
} | ||
|
||
#[test] | ||
fn unit_push() { | ||
let input = Value::Array(vec![Value::scalar("Seattle"), Value::scalar("Tacoma")]); | ||
let args = &[Value::scalar("Spokane")]; | ||
let desired_result = Value::Array(vec![ | ||
Value::scalar("Seattle"), | ||
Value::scalar("Tacoma"), | ||
Value::scalar("Spokane"), | ||
]); | ||
assert_eq!(unit!(push, input, args), desired_result); | ||
} | ||
|
||
#[test] | ||
fn unit_pop() { | ||
let input = Value::Array(vec![Value::scalar("Seattle"), Value::scalar("Tacoma")]); | ||
let args = &[]; | ||
let desired_result = Value::Array(vec![Value::scalar("Seattle")]); | ||
assert_eq!(unit!(pop, input, args), desired_result); | ||
} | ||
|
||
#[test] | ||
fn unit_pop_empty() { | ||
let input = Value::Array(vec![]); | ||
let args = &[]; | ||
let desired_result = Value::Array(vec![]); | ||
assert_eq!(unit!(pop, input, args), desired_result); | ||
} | ||
|
||
#[test] | ||
fn unit_unshift() { | ||
let input = Value::Array(vec![Value::scalar("Seattle"), Value::scalar("Tacoma")]); | ||
let args = &[Value::scalar("Olympia")]; | ||
let desired_result = Value::Array(vec![ | ||
Value::scalar("Olympia"), | ||
Value::scalar("Seattle"), | ||
Value::scalar("Tacoma"), | ||
]); | ||
assert_eq!(unit!(unshift, input, args), desired_result); | ||
} | ||
|
||
#[test] | ||
fn unit_shift() { | ||
let input = Value::Array(vec![Value::scalar("Seattle"), Value::scalar("Tacoma")]); | ||
let args = &[]; | ||
let desired_result = Value::Array(vec![Value::scalar("Tacoma")]); | ||
assert_eq!(unit!(shift, input, args), desired_result); | ||
} | ||
|
||
#[test] | ||
fn unit_shift_empty() { | ||
let input = Value::Array(vec![]); | ||
let args = &[]; | ||
let desired_result = Value::Array(vec![]); | ||
assert_eq!(unit!(shift, input, args), desired_result); | ||
} | ||
|
||
#[test] | ||
fn unit_array_to_sentence_string() { | ||
let input = Value::Array(vec![ | ||
Value::scalar("foo"), | ||
Value::scalar("bar"), | ||
Value::scalar("baz"), | ||
]); | ||
let args = &[]; | ||
let desired_result = Value::scalar("foo, bar, and baz"); | ||
assert_eq!(unit!(array_to_sentence_string, input, args), desired_result); | ||
} | ||
|
||
#[test] | ||
fn unit_array_to_sentence_string_two_elements() { | ||
let input = Value::Array(vec![Value::scalar("foo"), Value::scalar("bar")]); | ||
let args = &[]; | ||
let desired_result = Value::scalar("foo, and bar"); | ||
assert_eq!(unit!(array_to_sentence_string, input, args), desired_result); | ||
} | ||
|
||
#[test] | ||
fn unit_array_to_sentence_string_one_element() { | ||
let input = Value::Array(vec![Value::scalar("foo")]); | ||
let args = &[]; | ||
let desired_result = Value::scalar("foo"); | ||
assert_eq!(unit!(array_to_sentence_string, input, args), desired_result); | ||
} | ||
|
||
#[test] | ||
fn unit_array_to_sentence_string_no_elements() { | ||
let input = Value::Array(vec![]); | ||
let args = &[]; | ||
let desired_result = Value::scalar(""); | ||
assert_eq!(unit!(array_to_sentence_string, input, args), desired_result); | ||
} | ||
|
||
#[test] | ||
fn unit_array_to_sentence_string_custom_connector() { | ||
let input = Value::Array(vec![ | ||
Value::scalar("foo"), | ||
Value::scalar("bar"), | ||
Value::scalar("baz"), | ||
]); | ||
let args = &[Value::scalar("or")]; | ||
let desired_result = Value::scalar("foo, bar, or baz"); | ||
assert_eq!(unit!(array_to_sentence_string, input, args), desired_result); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters