refactor(checks): Make all state dynamic

This commit is contained in:
Ed Page 2021-01-05 21:29:33 -06:00
parent 1c3acd747a
commit ddeee94cf8
3 changed files with 66 additions and 125 deletions

View file

@ -15,11 +15,12 @@ fn bench_checks(c: &mut Criterion) {
let corrections = typos_cli::dict::BuiltIn::new(Default::default()); let corrections = typos_cli::dict::BuiltIn::new(Default::default());
let parser = typos::tokens::Tokenizer::new(); let parser = typos::tokens::Tokenizer::new();
let checks = typos_cli::checks::TyposSettings::new().build_files(); let settings = typos_cli::checks::CheckSettings::new();
b.iter(|| { b.iter(|| {
checks.check_file( typos_cli::checks::FoundFiles.check_file(
sample_path.path(), sample_path.path(),
true, true,
&settings,
&parser, &parser,
&corrections, &corrections,
&typos_cli::report::PrintSilent, &typos_cli::report::PrintSilent,
@ -35,11 +36,12 @@ fn bench_checks(c: &mut Criterion) {
let corrections = typos_cli::dict::BuiltIn::new(Default::default()); let corrections = typos_cli::dict::BuiltIn::new(Default::default());
let parser = typos::tokens::Tokenizer::new(); let parser = typos::tokens::Tokenizer::new();
let checks = typos_cli::checks::TyposSettings::new().build_identifier_parser(); let settings = typos_cli::checks::CheckSettings::new();
b.iter(|| { b.iter(|| {
checks.check_file( typos_cli::checks::Identifiers.check_file(
sample_path.path(), sample_path.path(),
true, true,
&settings,
&parser, &parser,
&corrections, &corrections,
&typos_cli::report::PrintSilent, &typos_cli::report::PrintSilent,
@ -55,11 +57,12 @@ fn bench_checks(c: &mut Criterion) {
let corrections = typos_cli::dict::BuiltIn::new(Default::default()); let corrections = typos_cli::dict::BuiltIn::new(Default::default());
let parser = typos::tokens::Tokenizer::new(); let parser = typos::tokens::Tokenizer::new();
let checks = typos_cli::checks::TyposSettings::new().build_word_parser(); let settings = typos_cli::checks::CheckSettings::new();
b.iter(|| { b.iter(|| {
checks.check_file( typos_cli::checks::Words.check_file(
sample_path.path(), sample_path.path(),
true, true,
&settings,
&parser, &parser,
&corrections, &corrections,
&typos_cli::report::PrintSilent, &typos_cli::report::PrintSilent,
@ -75,11 +78,12 @@ fn bench_checks(c: &mut Criterion) {
let corrections = typos_cli::dict::BuiltIn::new(Default::default()); let corrections = typos_cli::dict::BuiltIn::new(Default::default());
let parser = typos::tokens::Tokenizer::new(); let parser = typos::tokens::Tokenizer::new();
let checks = typos_cli::checks::TyposSettings::new().build_typos(); let settings = typos_cli::checks::CheckSettings::new();
b.iter(|| { b.iter(|| {
checks.check_file( typos_cli::checks::Typos.check_file(
sample_path.path(), sample_path.path(),
true, true,
&settings,
&parser, &parser,
&corrections, &corrections,
&typos_cli::report::PrintSilent, &typos_cli::report::PrintSilent,

View file

@ -12,6 +12,7 @@ pub trait FileChecker: Send + Sync {
&self, &self,
path: &std::path::Path, path: &std::path::Path,
explicit: bool, explicit: bool,
settings: &CheckSettings,
parser: &tokens::Tokenizer, parser: &tokens::Tokenizer,
dictionary: &dyn Dictionary, dictionary: &dyn Dictionary,
reporter: &dyn report::Report, reporter: &dyn report::Report,
@ -19,13 +20,13 @@ pub trait FileChecker: Send + Sync {
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct TyposSettings { pub struct CheckSettings {
check_filenames: bool, check_filenames: bool,
check_files: bool, check_files: bool,
binary: bool, binary: bool,
} }
impl TyposSettings { impl CheckSettings {
pub fn new() -> Self { pub fn new() -> Self {
Default::default() Default::default()
} }
@ -44,55 +45,9 @@ impl TyposSettings {
self.binary = yes; self.binary = yes;
self self
} }
pub fn build_typos(&self) -> Typos {
Typos {
check_filenames: self.check_filenames,
check_files: self.check_files,
binary: self.binary,
}
} }
pub fn build_fix_typos(&self) -> FixTypos { impl Default for CheckSettings {
FixTypos {
check_filenames: self.check_filenames,
check_files: self.check_files,
binary: self.binary,
}
}
pub fn build_diff_typos(&self) -> DiffTypos {
DiffTypos {
check_filenames: self.check_filenames,
check_files: self.check_files,
binary: self.binary,
}
}
pub fn build_identifier_parser(&self) -> Identifiers {
Identifiers {
check_filenames: self.check_filenames,
check_files: self.check_files,
binary: self.binary,
}
}
pub fn build_word_parser(&self) -> Words {
Words {
check_filenames: self.check_filenames,
check_files: self.check_files,
binary: self.binary,
}
}
pub fn build_files(&self) -> FoundFiles {
FoundFiles {
binary: self.binary,
}
}
}
impl Default for TyposSettings {
fn default() -> Self { fn default() -> Self {
Self { Self {
check_filenames: true, check_filenames: true,
@ -102,18 +57,15 @@ impl Default for TyposSettings {
} }
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone, Copy)]
pub struct Typos { pub struct Typos;
check_filenames: bool,
check_files: bool,
binary: bool,
}
impl FileChecker for Typos { impl FileChecker for Typos {
fn check_file( fn check_file(
&self, &self,
path: &std::path::Path, path: &std::path::Path,
explicit: bool, explicit: bool,
settings: &CheckSettings,
tokenizer: &tokens::Tokenizer, tokenizer: &tokens::Tokenizer,
dictionary: &dyn Dictionary, dictionary: &dyn Dictionary,
reporter: &dyn report::Report, reporter: &dyn report::Report,
@ -123,7 +75,7 @@ impl FileChecker for Typos {
.dictionary(dictionary) .dictionary(dictionary)
.build(); .build();
if self.check_filenames { if settings.check_filenames {
if let Some(file_name) = path.file_name().and_then(|s| s.to_str()) { if let Some(file_name) = path.file_name().and_then(|s| s.to_str()) {
for typo in parser.parse_str(file_name) { for typo in parser.parse_str(file_name) {
let msg = report::Typo { let msg = report::Typo {
@ -138,9 +90,9 @@ impl FileChecker for Typos {
} }
} }
if self.check_files { if settings.check_files {
let (buffer, content_type) = read_file(path, reporter)?; let (buffer, content_type) = read_file(path, reporter)?;
if !explicit && !self.binary && content_type.is_binary() { if !explicit && !settings.binary && content_type.is_binary() {
let msg = report::BinaryFile { path }; let msg = report::BinaryFile { path };
reporter.report(msg.into())?; reporter.report(msg.into())?;
} else { } else {
@ -164,18 +116,15 @@ impl FileChecker for Typos {
} }
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone, Copy)]
pub struct FixTypos { pub struct FixTypos;
check_filenames: bool,
check_files: bool,
binary: bool,
}
impl FileChecker for FixTypos { impl FileChecker for FixTypos {
fn check_file( fn check_file(
&self, &self,
path: &std::path::Path, path: &std::path::Path,
explicit: bool, explicit: bool,
settings: &CheckSettings,
tokenizer: &tokens::Tokenizer, tokenizer: &tokens::Tokenizer,
dictionary: &dyn Dictionary, dictionary: &dyn Dictionary,
reporter: &dyn report::Report, reporter: &dyn report::Report,
@ -185,9 +134,9 @@ impl FileChecker for FixTypos {
.dictionary(dictionary) .dictionary(dictionary)
.build(); .build();
if self.check_files { if settings.check_files {
let (buffer, content_type) = read_file(path, reporter)?; let (buffer, content_type) = read_file(path, reporter)?;
if !explicit && !self.binary && content_type.is_binary() { if !explicit && !settings.binary && content_type.is_binary() {
let msg = report::BinaryFile { path }; let msg = report::BinaryFile { path };
reporter.report(msg.into())?; reporter.report(msg.into())?;
} else { } else {
@ -217,7 +166,7 @@ impl FileChecker for FixTypos {
} }
// Ensure the above write can happen before renaming the file. // Ensure the above write can happen before renaming the file.
if self.check_filenames { if settings.check_filenames {
if let Some(file_name) = path.file_name().and_then(|s| s.to_str()) { if let Some(file_name) = path.file_name().and_then(|s| s.to_str()) {
let mut fixes = Vec::new(); let mut fixes = Vec::new();
for typo in parser.parse_str(file_name) { for typo in parser.parse_str(file_name) {
@ -249,18 +198,15 @@ impl FileChecker for FixTypos {
} }
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone, Copy)]
pub struct DiffTypos { pub struct DiffTypos;
check_filenames: bool,
check_files: bool,
binary: bool,
}
impl FileChecker for DiffTypos { impl FileChecker for DiffTypos {
fn check_file( fn check_file(
&self, &self,
path: &std::path::Path, path: &std::path::Path,
explicit: bool, explicit: bool,
settings: &CheckSettings,
tokenizer: &tokens::Tokenizer, tokenizer: &tokens::Tokenizer,
dictionary: &dyn Dictionary, dictionary: &dyn Dictionary,
reporter: &dyn report::Report, reporter: &dyn report::Report,
@ -272,9 +218,9 @@ impl FileChecker for DiffTypos {
let mut content = Vec::new(); let mut content = Vec::new();
let mut new_content = Vec::new(); let mut new_content = Vec::new();
if self.check_files { if settings.check_files {
let (buffer, content_type) = read_file(path, reporter)?; let (buffer, content_type) = read_file(path, reporter)?;
if !explicit && !self.binary && content_type.is_binary() { if !explicit && !settings.binary && content_type.is_binary() {
let msg = report::BinaryFile { path }; let msg = report::BinaryFile { path };
reporter.report(msg.into())?; reporter.report(msg.into())?;
} else { } else {
@ -305,7 +251,7 @@ impl FileChecker for DiffTypos {
// Match FixTypos ordering for easy diffing. // Match FixTypos ordering for easy diffing.
let mut new_path = None; let mut new_path = None;
if self.check_filenames { if settings.check_filenames {
if let Some(file_name) = path.file_name().and_then(|s| s.to_str()) { if let Some(file_name) = path.file_name().and_then(|s| s.to_str()) {
let mut fixes = Vec::new(); let mut fixes = Vec::new();
for typo in parser.parse_str(file_name) { for typo in parser.parse_str(file_name) {
@ -361,23 +307,20 @@ impl FileChecker for DiffTypos {
} }
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone, Copy)]
pub struct Identifiers { pub struct Identifiers;
check_filenames: bool,
check_files: bool,
binary: bool,
}
impl FileChecker for Identifiers { impl FileChecker for Identifiers {
fn check_file( fn check_file(
&self, &self,
path: &std::path::Path, path: &std::path::Path,
explicit: bool, explicit: bool,
settings: &CheckSettings,
tokenizer: &tokens::Tokenizer, tokenizer: &tokens::Tokenizer,
_dictionary: &dyn Dictionary, _dictionary: &dyn Dictionary,
reporter: &dyn report::Report, reporter: &dyn report::Report,
) -> Result<(), std::io::Error> { ) -> Result<(), std::io::Error> {
if self.check_filenames { if settings.check_filenames {
if let Some(file_name) = path.file_name().and_then(|s| s.to_str()) { if let Some(file_name) = path.file_name().and_then(|s| s.to_str()) {
for word in tokenizer.parse_str(file_name) { for word in tokenizer.parse_str(file_name) {
let msg = report::Parse { let msg = report::Parse {
@ -390,9 +333,9 @@ impl FileChecker for Identifiers {
} }
} }
if self.check_files { if settings.check_files {
let (buffer, content_type) = read_file(path, reporter)?; let (buffer, content_type) = read_file(path, reporter)?;
if !explicit && !self.binary && content_type.is_binary() { if !explicit && !settings.binary && content_type.is_binary() {
let msg = report::BinaryFile { path }; let msg = report::BinaryFile { path };
reporter.report(msg.into())?; reporter.report(msg.into())?;
} else { } else {
@ -415,23 +358,20 @@ impl FileChecker for Identifiers {
} }
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone, Copy)]
pub struct Words { pub struct Words;
check_filenames: bool,
check_files: bool,
binary: bool,
}
impl FileChecker for Words { impl FileChecker for Words {
fn check_file( fn check_file(
&self, &self,
path: &std::path::Path, path: &std::path::Path,
explicit: bool, explicit: bool,
settings: &CheckSettings,
tokenizer: &tokens::Tokenizer, tokenizer: &tokens::Tokenizer,
_dictionary: &dyn Dictionary, _dictionary: &dyn Dictionary,
reporter: &dyn report::Report, reporter: &dyn report::Report,
) -> Result<(), std::io::Error> { ) -> Result<(), std::io::Error> {
if self.check_filenames { if settings.check_filenames {
if let Some(file_name) = path.file_name().and_then(|s| s.to_str()) { if let Some(file_name) = path.file_name().and_then(|s| s.to_str()) {
for word in tokenizer.parse_str(file_name).flat_map(|i| i.split()) { for word in tokenizer.parse_str(file_name).flat_map(|i| i.split()) {
let msg = report::Parse { let msg = report::Parse {
@ -444,9 +384,9 @@ impl FileChecker for Words {
} }
} }
if self.check_files { if settings.check_files {
let (buffer, content_type) = read_file(path, reporter)?; let (buffer, content_type) = read_file(path, reporter)?;
if !explicit && !self.binary && content_type.is_binary() { if !explicit && !settings.binary && content_type.is_binary() {
let msg = report::BinaryFile { path }; let msg = report::BinaryFile { path };
reporter.report(msg.into())?; reporter.report(msg.into())?;
} else { } else {
@ -469,22 +409,21 @@ impl FileChecker for Words {
} }
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone, Copy)]
pub struct FoundFiles { pub struct FoundFiles;
binary: bool,
}
impl FileChecker for FoundFiles { impl FileChecker for FoundFiles {
fn check_file( fn check_file(
&self, &self,
path: &std::path::Path, path: &std::path::Path,
explicit: bool, explicit: bool,
settings: &CheckSettings,
_parser: &tokens::Tokenizer, _parser: &tokens::Tokenizer,
_dictionary: &dyn Dictionary, _dictionary: &dyn Dictionary,
reporter: &dyn report::Report, reporter: &dyn report::Report,
) -> Result<(), std::io::Error> { ) -> Result<(), std::io::Error> {
// Check `self.binary` first so we can easily check performance of walking vs reading // Check `settings.binary` first so we can easily check performance of walking vs reading
if self.binary { if settings.binary {
let msg = report::File::new(path); let msg = report::File::new(path);
reporter.report(msg.into())?; reporter.report(msg.into())?;
} else { } else {
@ -674,12 +613,13 @@ fn fix_buffer(mut buffer: Vec<u8>, typos: impl Iterator<Item = typos::Typo<'stat
pub fn walk_path( pub fn walk_path(
walk: ignore::Walk, walk: ignore::Walk,
checks: &dyn FileChecker, checks: &dyn FileChecker,
settings: &CheckSettings,
parser: &typos::tokens::Tokenizer, parser: &typos::tokens::Tokenizer,
dictionary: &dyn typos::Dictionary, dictionary: &dyn typos::Dictionary,
reporter: &dyn report::Report, reporter: &dyn report::Report,
) -> Result<(), ignore::Error> { ) -> Result<(), ignore::Error> {
for entry in walk { for entry in walk {
walk_entry(entry, checks, parser, dictionary, reporter)?; walk_entry(entry, checks, settings, parser, dictionary, reporter)?;
} }
Ok(()) Ok(())
} }
@ -687,6 +627,7 @@ pub fn walk_path(
pub fn walk_path_parallel( pub fn walk_path_parallel(
walk: ignore::WalkParallel, walk: ignore::WalkParallel,
checks: &dyn FileChecker, checks: &dyn FileChecker,
settings: &CheckSettings,
parser: &typos::tokens::Tokenizer, parser: &typos::tokens::Tokenizer,
dictionary: &dyn typos::Dictionary, dictionary: &dyn typos::Dictionary,
reporter: &dyn report::Report, reporter: &dyn report::Report,
@ -694,7 +635,7 @@ pub fn walk_path_parallel(
let error: std::sync::Mutex<Result<(), ignore::Error>> = std::sync::Mutex::new(Ok(())); let error: std::sync::Mutex<Result<(), ignore::Error>> = std::sync::Mutex::new(Ok(()));
walk.run(|| { walk.run(|| {
Box::new(|entry: Result<ignore::DirEntry, ignore::Error>| { Box::new(|entry: Result<ignore::DirEntry, ignore::Error>| {
match walk_entry(entry, checks, parser, dictionary, reporter) { match walk_entry(entry, checks, settings, parser, dictionary, reporter) {
Ok(()) => ignore::WalkState::Continue, Ok(()) => ignore::WalkState::Continue,
Err(err) => { Err(err) => {
*error.lock().unwrap() = Err(err); *error.lock().unwrap() = Err(err);
@ -710,6 +651,7 @@ pub fn walk_path_parallel(
fn walk_entry( fn walk_entry(
entry: Result<ignore::DirEntry, ignore::Error>, entry: Result<ignore::DirEntry, ignore::Error>,
checks: &dyn FileChecker, checks: &dyn FileChecker,
settings: &CheckSettings,
parser: &typos::tokens::Tokenizer, parser: &typos::tokens::Tokenizer,
dictionary: &dyn typos::Dictionary, dictionary: &dyn typos::Dictionary,
reporter: &dyn report::Report, reporter: &dyn report::Report,
@ -728,7 +670,7 @@ fn walk_entry(
} else { } else {
entry.path() entry.path()
}; };
checks.check_file(path, explicit, parser, dictionary, reporter)?; checks.check_file(path, explicit, settings, parser, dictionary, reporter)?;
} }
Ok(()) Ok(())

View file

@ -105,7 +105,7 @@ fn run_checks(args: &args::Args) -> proc_exit::ExitResult {
dictionary.identifiers(config.default.extend_identifiers()); dictionary.identifiers(config.default.extend_identifiers());
dictionary.words(config.default.extend_words()); dictionary.words(config.default.extend_words());
let mut settings = checks::TyposSettings::new(); let mut settings = checks::CheckSettings::new();
settings settings
.check_filenames(config.default.check_filename()) .check_filenames(config.default.check_filename())
.check_files(config.default.check_file()) .check_files(config.default.check_file())
@ -132,31 +132,25 @@ fn run_checks(args: &args::Args) -> proc_exit::ExitResult {
let status_reporter = report::MessageStatus::new(output_reporter); let status_reporter = report::MessageStatus::new(output_reporter);
let reporter: &dyn report::Report = &status_reporter; let reporter: &dyn report::Report = &status_reporter;
let (files, identifier_parser, word_parser, checks, fixer, differ);
let selected_checks: &dyn checks::FileChecker = if args.files { let selected_checks: &dyn checks::FileChecker = if args.files {
files = settings.build_files(); &checks::FoundFiles
&files
} else if args.identifiers { } else if args.identifiers {
identifier_parser = settings.build_identifier_parser(); &checks::Identifiers
&identifier_parser
} else if args.words { } else if args.words {
word_parser = settings.build_word_parser(); &checks::Words
&word_parser
} else if args.write_changes { } else if args.write_changes {
fixer = settings.build_fix_typos(); &checks::FixTypos
&fixer
} else if args.diff { } else if args.diff {
differ = settings.build_diff_typos(); &checks::DiffTypos
&differ
} else { } else {
checks = settings.build_typos(); &checks::Typos
&checks
}; };
if single_threaded { if single_threaded {
checks::walk_path( checks::walk_path(
walk.build(), walk.build(),
selected_checks, selected_checks,
&settings,
&parser, &parser,
&dictionary, &dictionary,
reporter, reporter,
@ -165,6 +159,7 @@ fn run_checks(args: &args::Args) -> proc_exit::ExitResult {
checks::walk_path_parallel( checks::walk_path_parallel(
walk.build_parallel(), walk.build_parallel(),
selected_checks, selected_checks,
&settings,
&parser, &parser,
&dictionary, &dictionary,
reporter, reporter,