use crate::expr::Expr;
use crate::expr::FirstMatchOf;
use crate::expr::FixedPhrase;
use crate::linting::expr_linter::Chunk;
use crate::linting::{ExprLinter, Lint, LintKind};
use crate::{Token, TokenStringExt};
pub struct Oxymorons {
expr: FirstMatchOf,
}
impl Oxymorons {
pub fn new() -> Self {
let phrases = vec![
"advancing backwards",
"alludes explicitly to",
"amateur expert",
"build down",
"completely obsolescent",
"conspicuous absence",
"exact estimate",
"explicitly alludes to",
"found missing",
"generally always",
"increasingly less",
"intense apathy",
"mandatory choice",
"nonworking mother",
"organized mess",
"standard Option",
"totally obsolescent",
"usually always",
];
let exprs: Vec<Box<dyn Expr>> = phrases
.into_iter()
.map(|s| Box::new(FixedPhrase::from_phrase(s)) as Box<dyn Expr>)
.collect();
Self {
expr: FirstMatchOf::new(exprs),
}
}
}
impl Default for Oxymorons {
fn default() -> Self {
Self::new()
}
}
impl ExprLinter for Oxymorons {
type Unit = Chunk;
fn expr(&self) -> &dyn Expr {
&self.expr
}
fn match_to_lint(&self, matched_tokens: &[Token], source: &[char]) -> Option<Lint> {
let span = matched_tokens.span()?;
let matched_text: String = span.get_content(source).iter().collect();
Some(Lint {
span,
lint_kind: LintKind::Miscellaneous,
suggestions: Vec::new(),
message: format!("'{matched_text}' is an oxymoron."),
priority: 31,
})
}
fn description(&self) -> &str {
"Flags oxymoronic phrases (e.g. `amateur expert`, `increasingly less`, etc.)."
}
}
#[cfg(test)]
mod tests {
use super::Oxymorons;
use crate::linting::tests::assert_lint_count;
#[test]
fn detects_amateur_expert() {
assert_lint_count("The amateur expert gave his opinion.", Oxymorons::new(), 1);
}
#[test]
fn detects_increasingly_less() {
assert_lint_count(
"The solution was increasingly less effective.",
Oxymorons::new(),
1,
);
}
#[test]
fn detects_advancing_backwards() {
assert_lint_count("The project is advancing backwards?", Oxymorons::new(), 1);
}
#[test]
fn detects_alludes_explicitly_to() {
assert_lint_count(
"The report alludes explicitly to several issues.",
Oxymorons::new(),
1,
);
}
#[test]
fn detects_explicitly_alludes_to() {
assert_lint_count(
"The report explicitly alludes to several issues.",
Oxymorons::new(),
1,
);
}
#[test]
fn does_not_flag_clean_text() {
assert_lint_count("The expert provided clear advice.", Oxymorons::new(), 0);
}
#[test]
fn lowercase_match() {
assert_lint_count(
"the amateur expert is often unreliable.",
Oxymorons::new(),
1,
);
}
#[test]
fn phrase_with_extra_whitespace() {
assert_lint_count("An organized mess was found.", Oxymorons::new(), 1);
}
#[test]
fn phrase_split_by_line_break() {
assert_lint_count(
"nonworking\nmother is not a term to be used.",
Oxymorons::new(),
1,
);
}
#[test]
fn detects_standard_option() {
assert_lint_count(
"and that probably correlates with CD players becoming a standard option in cars",
Oxymorons::new(),
1,
);
}
}