commit a72dc06a541ecb087811abe251c975704d9504bd Author: kirbylife Date: Wed Aug 30 00:34:26 2023 -0600 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..869df07 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..4a97761 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "tera_thousands" +version = "0.1.0" +authors = ["kirbylife "] +license = "MIT" +readme = "README.md" +homepage = "https://git.kirbylife.dev/kirbylife/tera_thousands" +repository = "https://git.kirbylife.dev/kirbylife/tera_thousands" +documentation = "https://docs.rs/tera_thousands" +description = "Simple filter for tera to split the numbers by thousands" +keywords = ["tera", "template", "formatting", "separators", "numbers"] +categories = ["template-engine"] +edition = "2021" + +[dependencies] +thousands = "0.2.0" +tera = { version = "1.19.0", default-features = false } \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..3c63e44 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,19 @@ +Copyright (c) 2023 Kirbylife + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..caa66ea --- /dev/null +++ b/README.md @@ -0,0 +1,59 @@ +# tera_thousands + +## Simple filter for tera to split the numbers by thousands + +### dependencies: +- [tera](https://crates.io/crates/tera) +- [thousands](https://crates.io/crates/thousands) + +### Usage +The usage is simple: + +First add this crate to the `Cargo.toml` file: +```Toml +tera_thousands = "0.1.0" +``` + +Now add the filter to your Tera instance: +```Rust +let mut tera = Tera::default(); +tera.register_filter("separate_with_commas", tera_thousands::separate_with_commas); +``` + +You can now divide the numbers in your tera template with commas: +```Rust +let mut context = Context::new(); +context.insert("number", &123456); + +let output = tera + .render_str("{{ number | separate_with_commas }}", &context) + .expect("Expected a number"); +assert_eq!(output, "123,456"); +``` + +Also, you can use it with Rocket or any framework compatible with Tera. +For example, this is how it would be used with Rocket: +``` +use rocket_dyn_templates::Template; +use tera_thousands::separate_with_commas; + +#[launch] +fn rocket() -> _ { + rocket::build() + .attach(Template::custom(|engines| { + engines.tera.register_filter("separate_with_commas", separate_with_commas) + })) + .mount(...) +} +``` + +The possible options are: +- `separate_with_commas` +- `separate_with_dots` +- `separate_with_spaces` +- `separate_with_underscores` + +### TO-DO +- [ ] An addition customizable filter from the template + +Contributors are welcome :). diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..41afc98 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,174 @@ +use std::{collections::HashMap, hash::BuildHasher}; +use tera::{to_value, Error, Value}; +use thousands::Separable; + +pub fn separate_with_commas( + value: &Value, + _: &HashMap, +) -> tera::Result { + if value.is_f64() { + Ok(to_value(value.as_f64().unwrap().separate_with_commas()).unwrap()) + } else if value.is_i64() { + Ok(to_value(value.as_i64().unwrap().separate_with_commas()).unwrap()) + } else if value.is_u64() { + Ok(to_value(value.as_u64().unwrap().separate_with_commas()).unwrap()) + } else { + Err(Error::msg("Expected a number")) + } +} + +pub fn separate_with_spaces( + value: &Value, + _: &HashMap, +) -> tera::Result { + if value.is_f64() { + Ok(to_value(value.as_f64().unwrap().separate_with_spaces()).unwrap()) + } else if value.is_i64() { + Ok(to_value(value.as_i64().unwrap().separate_with_spaces()).unwrap()) + } else if value.is_u64() { + Ok(to_value(value.as_u64().unwrap().separate_with_spaces()).unwrap()) + } else { + Err(Error::msg("Expected a number")) + } +} + +pub fn separate_with_dots( + value: &Value, + _: &HashMap, +) -> tera::Result { + if value.is_f64() { + Ok(to_value(value.as_f64().unwrap().separate_with_dots()).unwrap()) + } else if value.is_i64() { + Ok(to_value(value.as_i64().unwrap().separate_with_dots()).unwrap()) + } else if value.is_u64() { + Ok(to_value(value.as_u64().unwrap().separate_with_dots()).unwrap()) + } else { + Err(Error::msg("Expected a number")) + } +} + +pub fn separate_with_underscores( + value: &Value, + _: &HashMap, +) -> tera::Result { + if value.is_f64() { + Ok(to_value(value.as_f64().unwrap().separate_with_underscores()).unwrap()) + } else if value.is_i64() { + Ok(to_value(value.as_i64().unwrap().separate_with_underscores()).unwrap()) + } else if value.is_u64() { + Ok(to_value(value.as_u64().unwrap().separate_with_underscores()).unwrap()) + } else { + Err(Error::msg("Expected a number")) + } +} + +#[cfg(test)] +mod tests { + use super::{ + separate_with_commas, separate_with_dots, separate_with_spaces, separate_with_underscores, + }; + use tera::{Context, Tera}; + + #[test] + fn separate_with_commas_test() { + let mut context = Context::new(); + context.insert("integer_number", &10000); + context.insert("negative_number", &-69420); + context.insert("float_number", &1234.567); + + let mut tera = Tera::default(); + tera.register_filter("separate_with_commas", separate_with_commas); + + let s_int = tera + .render_str("{{ integer_number | separate_with_commas }}", &context) + .expect("Expected a number"); + let s_neg = tera + .render_str("{{ negative_number | separate_with_commas }}", &context) + .expect("Expected a number"); + let s_flt = tera + .render_str("{{ float_number | separate_with_commas }}", &context) + .expect("Expected a number"); + + assert_eq!(s_int, "10,000"); + assert_eq!(s_neg, "-69,420"); + assert_eq!(s_flt, "1,234.567"); + } + + #[test] + fn separate_with_dots_test() { + let mut context = Context::new(); + context.insert("integer_number", &10000); + context.insert("negative_number", &-69420); + context.insert("float_number", &1234.567); + + let mut tera = Tera::default(); + tera.register_filter("separate_with_dots", separate_with_dots); + + let s_int = tera + .render_str("{{ integer_number | separate_with_dots }}", &context) + .expect("Expected a number"); + let s_neg = tera + .render_str("{{ negative_number | separate_with_dots }}", &context) + .expect("Expected a number"); + let s_flt = tera + .render_str("{{ float_number | separate_with_dots }}", &context) + .expect("Expected a number"); + + assert_eq!(s_int, "10.000"); + assert_eq!(s_neg, "-69.420"); + assert_eq!(s_flt, "1.234.567"); + } + + #[test] + fn separate_with_spaces_test() { + let mut context = Context::new(); + context.insert("integer_number", &10000); + context.insert("negative_number", &-69420); + context.insert("float_number", &1234.567); + + let mut tera = Tera::default(); + tera.register_filter("separate_with_spaces", separate_with_spaces); + + let s_int = tera + .render_str("{{ integer_number | separate_with_spaces }}", &context) + .expect("Expected a number"); + let s_neg = tera + .render_str("{{ negative_number | separate_with_spaces }}", &context) + .expect("Expected a number"); + let s_flt = tera + .render_str("{{ float_number | separate_with_spaces }}", &context) + .expect("Expected a number"); + + assert_eq!(s_int, "10 000"); + assert_eq!(s_neg, "-69 420"); + assert_eq!(s_flt, "1 234.567"); + } + + #[test] + fn separate_with_underscores_test() { + let mut context = Context::new(); + context.insert("integer_number", &10000); + context.insert("negative_number", &-69420); + context.insert("float_number", &1234.567); + + let mut tera = Tera::default(); + tera.register_filter("separate_with_underscores", separate_with_underscores); + + let s_int = tera + .render_str("{{ integer_number | separate_with_underscores }}", &context) + .expect("Expected a number"); + let s_neg = tera + .render_str( + "{{ negative_number | separate_with_underscores }}", + &context, + ) + .expect("Expected a number"); + let s_flt = tera + .render_str("{{ float_number | separate_with_underscores }}", &context) + .expect("Expected a number"); + + assert_eq!(s_int, "10_000"); + assert_eq!(s_neg, "-69_420"); + assert_eq!(s_flt, "1_234.567"); + } +}