harper_core/patterns/
implies_quantity.rs

1use crate::{Token, TokenKind};
2
3use super::Pattern;
4
5/// This struct does two things.
6///
7/// First, it acts as a pattern that looks for phrases that describe a quantity of a noun
8/// that may or may not succeed it.
9///
10/// Second, it determines the implied plurality of that quantity.implies
11pub struct ImpliesQuantity;
12
13impl ImpliesQuantity {
14    pub fn implies_plurality(tokens: &[Token], source: &[char]) -> Option<bool> {
15        let token = tokens.first()?;
16
17        match &token.kind {
18            TokenKind::Word(Some(word_metadata)) => {
19                if word_metadata.determiner {
20                    return Some(false);
21                }
22
23                let source = token.span.get_content(source);
24
25                match source {
26                    ['a'] => Some(false),
27                    ['a', 'n'] => Some(false),
28                    ['m', 'a', 'n', 'y'] => Some(true),
29                    _ => None,
30                }
31            }
32            TokenKind::Number(number) => Some((number.value.abs() - 1.).abs() > f64::EPSILON),
33            _ => None,
34        }
35    }
36}
37
38impl Pattern for ImpliesQuantity {
39    fn matches(&self, tokens: &[Token], source: &[char]) -> usize {
40        if Self::implies_plurality(tokens, source).is_some() {
41            1
42        } else {
43            0
44        }
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use crate::{
51        Document, Span,
52        patterns::{DocPattern, ImpliesQuantity},
53    };
54
55    #[test]
56    fn number_implies() {
57        let doc = Document::new_plain_english_curated("There are 60 minutes in an hour.");
58
59        assert_eq!(
60            ImpliesQuantity.find_all_matches_in_doc(&doc),
61            vec![Span::new(4, 5), Span::new(10, 11)]
62        )
63    }
64}