naming_conventions/conventions/
train_case.rs

1use crate::{conventions::to_no_case, tool, Convention};
2
3use regex::{Captures, Error, Regex};
4
5pub struct TrainCase;
6
7impl Convention for TrainCase {
8    fn to(&self, string: &str) -> Result<String, Error> {
9        to_train_case(string)
10    }
11
12    fn is(&self, string: &str) -> Result<bool, Error> {
13        is_train_case(string)
14    }
15}
16
17pub fn to_train_case(string: &str) -> Result<String, Error> {
18    let replacement =
19        |haystack: &str, caps: &Captures, _options: &Option<bool>| -> Result<String, Error> {
20            let m = caps.get(0).unwrap();
21            Ok(haystack[m.start()..m.end()].to_uppercase())
22        };
23
24    let no_case = to_no_case(&string)?.to_lowercase();
25
26    let mut haystack = String::from(" ");
27    haystack.push_str(&no_case);
28
29    let re = Regex::new(r"[^\w][a-z]").unwrap();
30    let result = tool::replace_all(&re, &haystack, replacement, &None)?;
31
32    let re = Regex::new(r"\s+").unwrap();
33    let result = re.replace_all(result.trim(), "-").to_string();
34
35    log::debug!(target: "convention::train_case::to_train_case", "'{}' changed to '{}' (train_case).", string, result);
36    Ok(result)
37}
38
39pub fn is_train_case(string: &str) -> Result<bool, Error> {
40    let train_case = to_train_case(string)?;
41    Ok(train_case == string)
42}
43
44#[cfg(test)]
45mod tests {
46    use super::*;
47
48    fn init() {
49        dotenv::dotenv().ok();
50        let _ = env_logger::try_init();
51    }
52
53    #[test]
54    fn test_to_train_case() {
55        tests::init();
56
57        let result = to_train_case("VahidVakili ").unwrap();
58        assert_eq!(&result, "Vahid-Vakili")
59    }
60
61    #[test]
62    fn test_is_train_case() {
63        tests::init();
64
65        let result = is_train_case("Vahid-Vakili").unwrap();
66        assert_eq!(result, true);
67
68        let result = is_train_case("vahid_Vakili").unwrap();
69        assert_eq!(result, false);
70    }
71}