use crate::boundary;
use crate::boundary::Boundary;
use crate::pattern::Pattern;
use crate::Case;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
pub struct Converter {
pub boundaries: Vec<Boundary>,
pub pattern: Pattern,
pub delim: String,
}
impl Default for Converter {
fn default() -> Self {
Converter {
boundaries: Boundary::defaults().to_vec(),
pattern: Pattern::Noop,
delim: String::new(),
}
}
}
impl Converter {
pub fn new() -> Self {
Self::default()
}
pub fn convert<T>(&self, s: T) -> String
where
T: AsRef<str>,
{
let words = boundary::split(&s, &self.boundaries);
let words = words.to_vec();
self.pattern.mutate(&words).join(&self.delim)
}
pub fn to_case(mut self, case: Case) -> Self {
self.pattern = case.pattern();
self.delim = case.delim().to_string();
self
}
pub fn from_case(mut self, case: Case) -> Self {
self.boundaries = case.boundaries().to_vec();
self
}
pub fn set_boundaries(mut self, bs: &[Boundary]) -> Self {
self.boundaries = bs.to_vec();
self
}
pub fn add_boundary(mut self, b: Boundary) -> Self {
self.boundaries.push(b);
self
}
pub fn add_boundaries(mut self, bs: &[Boundary]) -> Self {
self.boundaries.extend(bs);
self
}
pub fn remove_boundary(mut self, b: Boundary) -> Self {
self.boundaries.retain(|&x| x != b);
self
}
pub fn remove_boundaries(mut self, bs: &[Boundary]) -> Self {
for b in bs {
self.boundaries.retain(|&x| x != *b);
}
self
}
pub fn set_delim<T>(mut self, d: T) -> Self
where
T: ToString,
{
self.delim = d.to_string();
self
}
pub fn set_pattern(mut self, p: Pattern) -> Self {
self.pattern = p;
self
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::Casing;
#[test]
fn snake_converter_from_case() {
let conv = Converter::new().to_case(Case::Snake);
let s = String::from("my var name");
assert_eq!(s.to_case(Case::Snake), conv.convert(s));
}
#[test]
fn snake_converter_from_scratch() {
let conv = Converter::new()
.set_delim("_")
.set_pattern(Pattern::Lowercase);
let s = String::from("my var name");
assert_eq!(s.to_case(Case::Snake), conv.convert(s));
}
#[test]
fn custom_pattern() {
let conv = Converter::new()
.to_case(Case::Snake)
.set_pattern(Pattern::Sentence);
assert_eq!("Bjarne_case", conv.convert("bjarne case"));
}
#[test]
fn custom_delim() {
let conv = Converter::new().set_delim("..");
assert_eq!("oh..My", conv.convert("ohMy"));
}
#[test]
fn no_delim() {
let conv = Converter::new()
.from_case(Case::Title)
.to_case(Case::Kebab)
.set_delim("");
assert_eq!("justflat", conv.convert("Just Flat"));
}
#[test]
fn no_digit_boundaries() {
let conv = Converter::new()
.remove_boundaries(&Boundary::digits())
.to_case(Case::Snake);
assert_eq!("test_08bound", conv.convert("Test 08Bound"));
assert_eq!("a8a_a8a", conv.convert("a8aA8A"));
}
#[test]
fn remove_boundary() {
let conv = Converter::new()
.remove_boundary(Boundary::DigitUpper)
.to_case(Case::Snake);
assert_eq!("test_08bound", conv.convert("Test 08Bound"));
assert_eq!("a_8_a_a_8a", conv.convert("a8aA8A"));
}
#[test]
fn add_boundary() {
let conv = Converter::new()
.from_case(Case::Snake)
.to_case(Case::Kebab)
.add_boundary(Boundary::LowerUpper);
assert_eq!("word-word-word", conv.convert("word_wordWord"));
}
#[test]
fn add_boundaries() {
let conv = Converter::new()
.from_case(Case::Snake)
.to_case(Case::Kebab)
.add_boundaries(&[Boundary::LowerUpper, Boundary::UpperLower]);
assert_eq!("word-word-w-ord", conv.convert("word_wordWord"));
}
#[test]
fn twice() {
let s = "myVarName".to_string();
let conv = Converter::new().to_case(Case::Snake);
let snake = conv.convert(&s);
let kebab = s.to_case(Case::Kebab);
assert_eq!(snake.to_case(Case::Camel), kebab.to_case(Case::Camel));
}
#[test]
fn reuse_after_change() {
let conv = Converter::new().from_case(Case::Snake).to_case(Case::Kebab);
assert_eq!("word-wordword", conv.convert("word_wordWord"));
let conv = conv.add_boundary(Boundary::LowerUpper);
assert_eq!("word-word-word", conv.convert("word_wordWord"));
}
#[test]
fn explicit_boundaries() {
let conv = Converter::new()
.set_boundaries(&[
Boundary::DigitLower,
Boundary::DigitUpper,
Boundary::Acronym,
])
.to_case(Case::Snake);
assert_eq!(
"section8_lesson2_http_requests",
conv.convert("section8lesson2HTTPRequests")
);
}
}