harper_core/linting/
back_in_the_day.rs1use crate::{
2 Lrc, Token, TokenStringExt,
3 patterns::{ExactPhrase, OwnedPatternExt, Pattern, SequencePattern, WordSet},
4};
5
6use super::{Lint, LintKind, PatternLinter, Suggestion};
7
8pub struct BackInTheDay {
9 pattern: Box<dyn Pattern>,
10 exceptions: Lrc<WordSet>,
12}
13
14impl Default for BackInTheDay {
15 fn default() -> Self {
16 let exceptions = Lrc::new(WordSet::new(&["before", "of", "when"]));
17 let phrase = Lrc::new(ExactPhrase::from_phrase("back in the days"));
18
19 let pattern = SequencePattern::default()
20 .then(phrase.clone())
21 .then_whitespace()
22 .then(exceptions.clone())
23 .or(Box::new(phrase));
24
25 Self {
26 pattern: Box::new(pattern),
27 exceptions,
28 }
29 }
30}
31
32impl PatternLinter for BackInTheDay {
33 fn pattern(&self) -> &dyn Pattern {
34 self.pattern.as_ref()
35 }
36
37 fn match_to_lint(&self, matched_tokens: &[Token], source: &[char]) -> Option<Lint> {
38 if let Some(tail) = matched_tokens.get(8..) {
39 if self.exceptions.matches(tail, source).is_some() {
40 return None;
41 }
42 }
43
44 let span = matched_tokens.span()?;
45 let chars = span.get_content(source);
46
47 Some(Lint {
48 span,
49 lint_kind: LintKind::WordChoice,
50 suggestions: vec![Suggestion::replace_with_match_case(
51 "back in the day".chars().collect(),
52 chars,
53 )],
54 message: "Use the more idiomatic version of this phrase.".to_owned(),
55 priority: 127,
56 })
57 }
58
59 fn description(&self) -> &'static str {
60 "This linter flags instances of the nonstandard phrase `back in the days`. The correct, more accepted form is `back in the day`"
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::BackInTheDay;
67 use crate::linting::tests::{assert_lint_count, assert_suggestion_result};
68
69 #[test]
70 fn detects_gem_update_case() {
71 assert_suggestion_result(
72 "... has been resolved through a gem update back in the days",
73 BackInTheDay::default(),
74 "... has been resolved through a gem update back in the day",
75 );
76 }
77
78 #[test]
79 fn detects_install_case() {
80 assert_suggestion_result(
81 "Back in the days we're used to install it directly from ...",
82 BackInTheDay::default(),
83 "Back in the day we're used to install it directly from ...",
84 );
85 }
86
87 #[test]
88 fn detects_composer_json_case() {
89 assert_suggestion_result(
90 "Back in the days there was only composer.json and ...",
91 BackInTheDay::default(),
92 "Back in the day there was only composer.json and ...",
93 );
94 }
95
96 #[test]
97 fn detects_version_release_case() {
98 assert_suggestion_result(
99 "... should have been released back in the days in a version 11",
100 BackInTheDay::default(),
101 "... should have been released back in the day in a version 11",
102 );
103 }
104
105 #[test]
106 fn avoids_false_positive_springfox() {
107 assert_lint_count(
108 "Back in the days of SpringFox, there were several requests to ...",
109 BackInTheDay::default(),
110 0,
111 );
112 }
113
114 #[test]
115 fn avoids_false_positive_ie() {
116 assert_lint_count(
117 "Back in the days of IE, Powershell used to ...",
118 BackInTheDay::default(),
119 0,
120 );
121 }
122
123 #[test]
124 fn avoids_false_positive_code_usage() {
125 assert_lint_count(
126 "Back in the days when I had 100% of my code in ...",
127 BackInTheDay::default(),
128 0,
129 );
130 }
131 #[test]
132 fn catches_uppercase() {
133 assert_lint_count(
134 "Back in the days, we went for a walk.",
135 BackInTheDay::default(),
136 1,
137 );
138 }
139
140 #[test]
141 fn catches_lowercase() {
142 assert_lint_count(
143 "We used to go for walks back in the days.",
144 BackInTheDay::default(),
145 1,
146 );
147 }
148
149 #[test]
150 fn doesnt_catch_false_positive_of() {
151 assert_lint_count(
152 "Back in the days of CRTs, computers were expensive.",
153 BackInTheDay::default(),
154 0,
155 );
156 }
157
158 #[test]
159 fn doesnt_catch_false_positive_when() {
160 assert_lint_count(
161 "Back in the days when videogame arcades were popular.",
162 BackInTheDay::default(),
163 0,
164 );
165 }
166
167 #[test]
168 fn catches_comma_when() {
169 assert_lint_count(
170 "Back in the days, when we were children, we played outside.",
171 BackInTheDay::default(),
172 1,
173 );
174 }
175
176 #[test]
177 fn doesnt_catch_false_positive_before() {
178 assert_lint_count(
179 "Back in the days before laptops we had \"luggables\".",
180 BackInTheDay::default(),
181 0,
182 );
183 }
184
185 #[test]
186 fn catches_comma_before() {
187 assert_lint_count(
188 "Back in the days, before laptops.",
189 BackInTheDay::default(),
190 1,
191 );
192 }
193
194 #[test]
195 fn doesnt_catch_qualified_days() {
196 assert_lint_count(
197 "Back in the old days we did this by hand.",
198 BackInTheDay::default(),
199 0,
200 );
201 }
202}