pub(super) fn name_matches(name_segment: &str, term: &str) -> bool {
if name_segment == term {
return true;
}
let singular = singular_key(term);
singular != term && name_segment == singular || name_segment.contains(term)
}
pub(super) fn alias_matches(alias: &str, terms: &[String]) -> bool {
let mut words = alias
.split(|c: char| !c.is_ascii_alphanumeric() && c != '_')
.filter(|w| !w.is_empty())
.peekable();
if words.peek().is_none() {
return false;
}
words.all(|word| {
terms
.iter()
.any(|term| term == word || singular_key(term) == singular_key(word))
})
}
pub(super) fn singular_key(term: &str) -> String {
let bytes = term.as_bytes();
let n = bytes.len();
if n > 3 && term.ends_with("ies") {
return format!("{}y", &term[..n - 3]);
}
if n > 2 && term.ends_with("es") {
let stem = &term[..n - 2];
if stem.ends_with(['s', 'x', 'z']) || stem.ends_with("ch") || stem.ends_with("sh") {
return stem.to_string();
}
}
if n > 3
&& term.ends_with('s')
&& !term.ends_with("ss")
&& !term.ends_with("us")
&& !term.ends_with("is")
&& !term.ends_with("ies")
{
return term[..n - 1].to_string();
}
term.to_string()
}
#[cfg(test)]
mod alias_tests {
use super::alias_matches;
fn terms(words: &[&str]) -> Vec<String> {
words.iter().map(|w| (*w).to_string()).collect()
}
#[test]
fn a_multi_word_alias_matches_the_words_of_the_question() {
assert!(alias_matches(
"account managers",
&terms(["many", "account", "managers"].as_ref())
));
}
#[test]
fn plural_and_singular_forms_reach_each_other() {
assert!(alias_matches(
"account manager",
&terms(["account", "managers"].as_ref())
));
assert!(alias_matches(
"account managers",
&terms(["account", "manager"].as_ref())
));
}
#[test]
fn a_partial_phrase_is_not_the_phrase() {
assert!(!alias_matches(
"account managers",
&terms(["account"].as_ref())
));
assert!(!alias_matches("gross margin", &terms(["margin"].as_ref())));
}
#[test]
fn a_single_word_alias_still_matches_exactly_as_before() {
assert!(alias_matches("reps", &terms(["how", "reps"].as_ref())));
assert!(!alias_matches("reps", &terms(["staff"].as_ref())));
}
#[test]
fn word_order_does_not_matter() {
assert!(alias_matches(
"active customers",
&terms(["customers", "active"].as_ref())
));
}
#[test]
fn an_alias_with_no_words_matches_nothing() {
assert!(!alias_matches("", &terms(["account"].as_ref())));
assert!(!alias_matches(" ", &terms(["account"].as_ref())));
assert!(!alias_matches("--", &terms(["account"].as_ref())));
}
#[test]
fn no_terms_selects_nothing() {
assert!(!alias_matches("account managers", &[]));
}
}