use crate::Words;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Spelling {
Snake,
LowerCamel,
UpperCamel,
Kebab,
Screaming,
}
impl Spelling {
pub fn spell(self, words: Words<'_>) -> String {
match self {
Self::Snake => words.join("_"),
Self::Kebab => words.join("-"),
Self::Screaming => words.join("_").to_uppercase(),
Self::LowerCamel => words.iter().enumerate().map(|(i, w)| capitalize(w, i > 0)).collect(),
Self::UpperCamel => words.iter().map(|w| capitalize(w, true)).collect(),
}
}
}
pub fn words_of(identifier: &str) -> Vec<&str> {
identifier.split('_').filter(|word| !word.is_empty()).collect()
}
fn capitalize(word: &str, upper: bool) -> String {
let mut chars = word.chars();
match chars.next() {
Some(first) if upper => first.to_uppercase().collect::<String>() + chars.as_str(),
Some(first) => first.to_lowercase().collect::<String>() + chars.as_str(),
None => String::new(),
}
}
#[cfg(test)]
mod tests {
use super::*;
const DISPLAY_NAME: Words<'static> = &["display", "name"];
const SHA3_SUM: Words<'static> = &["sha3", "sum"];
#[test]
fn one_name_spells_every_way() {
assert_eq!(Spelling::Snake.spell(DISPLAY_NAME), "display_name");
assert_eq!(Spelling::LowerCamel.spell(DISPLAY_NAME), "displayName");
assert_eq!(Spelling::UpperCamel.spell(DISPLAY_NAME), "DisplayName");
assert_eq!(Spelling::Kebab.spell(DISPLAY_NAME), "display-name");
assert_eq!(Spelling::Screaming.spell(DISPLAY_NAME), "DISPLAY_NAME");
}
#[test]
fn an_identifier_states_the_words_it_is_made_of() {
assert_eq!(words_of("display_name"), ["display", "name"]);
assert_eq!(Spelling::LowerCamel.spell(&words_of("display_name")), "displayName");
}
#[test]
fn a_word_with_a_digit_keeps_its_boundary() {
assert_eq!(Spelling::LowerCamel.spell(SHA3_SUM), "sha3Sum");
assert_eq!(Spelling::Snake.spell(SHA3_SUM), "sha3_sum");
}
}