use heck::*;
use phonenumber::{Mode, parse};
use std::cmp::PartialEq;
use std::convert::From;
use std::ops::Deref;
#[derive(Clone, Eq, PartialEq)]
pub struct StringSanitizer(String);
impl StringSanitizer {
pub fn new(content: String) -> Self {
Self(content)
}
pub fn get(self) -> String {
self.0
}
pub fn trim(&mut self) -> &mut Self {
self.0 = self.0.trim().to_string();
self
}
pub fn numeric(&mut self) -> &mut Self {
self.0 = self.0.chars().filter(|b| b.is_numeric()).collect();
self
}
pub fn alphanumeric(&mut self) -> &mut Self {
self.0 = self.0.chars().filter(|b| b.is_alphanumeric()).collect();
self
}
pub fn to_lowercase(&mut self) -> &mut Self {
self.0 = self.0.to_lowercase();
self
}
pub fn to_uppercase(&mut self) -> &mut Self {
self.0 = self.0.to_uppercase();
self
}
pub fn to_camel_case(&mut self) -> &mut Self {
self.0 = self.0.to_lower_camel_case();
self
}
pub fn to_snake_case(&mut self) -> &mut Self {
self.0 = self.0.to_snake_case();
self
}
pub fn to_kebab_case(&mut self) -> &mut Self {
self.0 = self.0.to_kebab_case();
self
}
pub fn to_screaming_kebab_case(&mut self) -> &mut Self {
self.0 = self.0.to_shouty_kebab_case();
self
}
pub fn to_screaming_snakecase(&mut self) -> &mut Self {
self.0 = self.0.to_shouty_snake_case();
self
}
pub fn clamp_max(&mut self, limit: usize) -> &mut Self {
self.0.truncate(limit);
self
}
pub fn e164(&mut self) -> &mut Self {
let phone_number = parse(None, &self.0);
if let Ok(number) = phone_number {
self.0 = number.format().mode(Mode::E164).to_string();
}
self
}
pub fn cut(&mut self, amount: usize) -> &mut Self {
self.0.truncate(amount);
self
}
pub fn call<F>(&mut self, func: F) -> &mut Self
where
F: FnOnce(&str) -> String,
{
self.0 = func(&self.0);
self
}
}
impl From<String> for StringSanitizer {
fn from(content: String) -> Self {
Self::new(content)
}
}
impl From<&str> for StringSanitizer {
fn from(content: &str) -> Self {
Self::new(content.to_owned())
}
}
impl Deref for StringSanitizer {
type Target = String;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl PartialEq<str> for StringSanitizer {
fn eq(&self, rhs: &str) -> bool {
self.0 == rhs
}
}
impl PartialEq<&str> for StringSanitizer {
fn eq(&self, rhs: &&str) -> bool {
self.0 == *rhs
}
}
impl PartialEq<String> for StringSanitizer {
fn eq(&self, rhs: &String) -> bool {
self.0 == rhs.as_str()
}
}
#[cfg(test)]
mod test {
use super::*;
macro_rules! string_test {
( $sanitizer : ident, $from : expr => $to : expr ) => {
paste::paste! {
#[test]
fn [<$sanitizer>]() {
let mut sanitizer = StringSanitizer::from($from);
sanitizer.$sanitizer();
assert_eq!($to, sanitizer.get());
}
}
};
}
string_test!(trim, " Test " => "Test");
string_test!(numeric, "Test123445Test" => "123445");
string_test!(alphanumeric, "Hello,藏World&&" => "Hello藏World");
string_test!(to_lowercase, "HELLO" => "hello");
string_test!(to_uppercase, "hello" => "HELLO");
string_test!(to_camel_case, "some_string" => "someString");
string_test!(to_snake_case, "someString" => "some_string");
string_test!(to_kebab_case, "someString" => "some-string");
string_test!(to_screaming_kebab_case, "someString" => "SOME-STRING");
string_test!(to_screaming_snakecase, "someString" => "SOME_STRING");
#[test]
fn e164() {
let mut number = StringSanitizer::from("+1 (555) 555-1234");
number.e164();
assert_eq!("+15555551234", number.get());
}
#[test]
fn clamp_max() {
let mut sanitizer = StringSanitizer::from("someString");
sanitizer.clamp_max(9);
assert_eq!("someStrin", sanitizer.get());
}
#[test]
fn wrong_phone_number() {
let mut sanitizer = StringSanitizer::from("Not a Phone Number");
sanitizer.e164();
assert_eq!("Not a Phone Number", sanitizer.get());
}
#[test]
fn multiple_lints() {
let mut sanitizer = StringSanitizer::from(" some_string12 ");
sanitizer.trim().numeric();
assert_eq!("12", sanitizer.get());
}
}