inflekt/
lib.rs

1use inflections::case;
2use inflections::Inflect;
3use inflector::string::pluralize::to_plural;
4use inflector::string::singularize::to_singular;
5
6mod deduped_vec;
7
8pub fn inflect_all(words: &Vec<String>) -> Vec<Vec<String>> {
9    inflect_ord(words).iter().flat_map(|ws| inflect_case(ws)).collect()
10}
11
12fn inflect_ord(words: &Vec<String>) -> Vec<Vec<String>> {
13    inflect_when_some_dont_match(
14        words,
15        vec![
16            (is_plural, to_plural),
17            // note: keep after plural
18            // so that singular replacements do not interfere with plurals ones
19            // e.g., we want:
20            //   FOOS BARS
21            //   FOO BAR
22            // rather than:
23            //  FOO BAR
24            //  FOOS BARS <- FOOS will already have been partially matched by FOO in previous line
25            (is_singular, to_singular),
26        ],
27    )
28}
29
30fn inflect_case(words: &Vec<String>) -> Vec<Vec<String>> {
31    inflect_when_some_dont_match(
32        words,
33        vec![
34            (case::is_camel_case, case::to_camel_case),
35            (case::is_pascal_case, case::to_pascal_case),
36            (case::is_kebab_case, case::to_kebab_case),
37            (case::is_train_case, case::to_train_case),
38            (case::is_snake_case, case::to_snake_case),
39            (case::is_constant_case, case::to_constant_case),
40            (is_all_lower, to_all_lower),
41            (is_all_upper, to_all_upper), // note: keep last to not conflict with CONSTANT_CASE
42        ],
43    )
44}
45
46// if not all words match a pred (i.e. there are some words that do not match), applies the inflecting fn to those words
47fn inflect_when_some_dont_match(
48    words: &Vec<String>,
49    preds_and_fns: Vec<(fn(&str) -> bool, fn(&str) -> String)>,
50) -> Vec<Vec<String>> {
51    let mut out = deduped_vec::DedupedVec::new();
52
53    out.push(words.clone());
54
55    for (pred, f) in preds_and_fns.iter() {
56        let all_match = words.iter().all(|w| pred(w));
57        if !all_match {
58            let mapped: Vec<String> = words.iter().map(|w| f(w)).collect();
59            out.push(mapped);
60        }
61    }
62
63    out.items
64}
65
66fn to_all_lower(word: &str) -> String {
67    word.to_camel_case().to_lowercase()
68}
69
70fn to_all_upper(word: &str) -> String {
71    word.to_camel_case().to_uppercase()
72}
73
74fn is_all_lower(word: &str) -> bool {
75    to_all_lower(word) == word
76}
77
78fn is_all_upper(word: &str) -> bool {
79    to_all_upper(word) == word
80}
81
82fn is_singular(word: &str) -> bool {
83    to_singular(word) == word
84}
85
86fn is_plural(word: &str) -> bool {
87    to_plural(word) == word
88}
89
90pub fn print_matrix(xxs: Vec<Vec<String>>) {
91    for xs in xxs {
92        println!("{}", xs.join(" "));
93    }
94}