Use impl Write over a closure
This commit is contained in:
parent
a31d0f769a
commit
20263c9474
2 changed files with 46 additions and 63 deletions
99
src/lib.rs
99
src/lib.rs
|
@ -1,8 +1,11 @@
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::Debug;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::io::Write;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(version)]
|
#[command(version)]
|
||||||
pub struct Cli {
|
pub struct Cli {
|
||||||
|
@ -26,58 +29,44 @@ pub struct Cli {
|
||||||
ignore_extras: bool,
|
ignore_extras: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SkipError(String);
|
pub fn skip(cli: &Cli, writer: &mut impl Write) -> Result<()> {
|
||||||
|
|
||||||
impl Debug for SkipError {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::result::Result<(), std::fmt::Error> {
|
|
||||||
write!(f, "{}", self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Result<T> = core::result::Result<T, SkipError>;
|
|
||||||
|
|
||||||
pub fn skip<F>(cli: &Cli, out: F) -> Result<()>
|
|
||||||
where
|
|
||||||
F: FnMut(String) -> (),
|
|
||||||
{
|
|
||||||
match &cli.file {
|
match &cli.file {
|
||||||
Some(ref file) => {
|
Some(ref file) => {
|
||||||
if let Some(line) = &cli.line {
|
if let Some(line) = &cli.line {
|
||||||
skip_file_lines_matching(&cli, out, file, line)
|
skip_file_lines_matching(&cli, writer, file, line)
|
||||||
} else if let Some(ref token) = cli.token {
|
} else if let Some(ref token) = cli.token {
|
||||||
skip_file_tokens(cli, out, file, token)
|
skip_file_tokens(cli, writer, file, token)
|
||||||
} else {
|
} else {
|
||||||
skip_file_lines(cli, out, file)
|
skip_file_lines(cli, writer, file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => Err(SkipError("Not yet implemented - reading from stdin".into())),
|
None => todo!("reading from stdin"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn skip_file_lines<F>(cli: &Cli, mut out: F, file: &PathBuf) -> Result<()>
|
fn skip_file_lines(cli: &Cli, writer: &mut impl Write, file: &PathBuf) -> Result<()> {
|
||||||
where
|
|
||||||
F: FnMut(String) -> (),
|
|
||||||
{
|
|
||||||
let content = fs::read_to_string(file).expect("Could not read file");
|
let content = fs::read_to_string(file).expect("Could not read file");
|
||||||
let mut counter = 0usize;
|
let mut counter = 0usize;
|
||||||
for current_line in content.lines() {
|
for current_line in content.lines() {
|
||||||
if counter >= cli.lines {
|
if counter >= cli.lines {
|
||||||
out(String::from(current_line));
|
writeln!(writer, "{}", current_line)?;
|
||||||
}
|
}
|
||||||
counter += 1;
|
counter += 1;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn skip_file_lines_matching<F>(cli: &Cli, mut out: F, file: &PathBuf, line: &str) -> Result<()>
|
fn skip_file_lines_matching(
|
||||||
where
|
cli: &Cli,
|
||||||
F: FnMut(String) -> (),
|
writer: &mut impl Write,
|
||||||
{
|
file: &PathBuf,
|
||||||
|
line: &str,
|
||||||
|
) -> Result<()> {
|
||||||
let content = fs::read_to_string(file).expect("Could not read file");
|
let content = fs::read_to_string(file).expect("Could not read file");
|
||||||
let mut counter = 0usize;
|
let mut counter = 0usize;
|
||||||
for current_line in content.lines() {
|
for current_line in content.lines() {
|
||||||
if counter >= cli.lines {
|
if counter >= cli.lines {
|
||||||
out(String::from(current_line));
|
writeln!(writer, "{}", current_line)?;
|
||||||
}
|
}
|
||||||
if line == current_line {
|
if line == current_line {
|
||||||
counter += 1;
|
counter += 1;
|
||||||
|
@ -86,15 +75,12 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn skip_file_tokens<F>(cli: &Cli, mut out: F, file: &PathBuf, token: &str) -> Result<()>
|
fn skip_file_tokens(cli: &Cli, writer: &mut impl Write, file: &PathBuf, token: &str) -> Result<()> {
|
||||||
where
|
|
||||||
F: FnMut(String) -> (),
|
|
||||||
{
|
|
||||||
let content = fs::read_to_string(file).expect("Could not read file");
|
let content = fs::read_to_string(file).expect("Could not read file");
|
||||||
let mut counter = 0usize;
|
let mut counter = 0usize;
|
||||||
for current_line in content.lines() {
|
for current_line in content.lines() {
|
||||||
if counter >= cli.lines {
|
if counter >= cli.lines {
|
||||||
out(String::from(current_line));
|
writeln!(writer, "{}", current_line)?;
|
||||||
}
|
}
|
||||||
if current_line.contains(&token) {
|
if current_line.contains(&token) {
|
||||||
if cli.ignore_extras {
|
if cli.ignore_extras {
|
||||||
|
@ -123,13 +109,13 @@ mod tests {
|
||||||
token: None,
|
token: None,
|
||||||
ignore_extras: false,
|
ignore_extras: false,
|
||||||
};
|
};
|
||||||
let mut lines: Vec<String> = Vec::new();
|
let mut lines = Vec::new();
|
||||||
|
|
||||||
//when
|
//when
|
||||||
skip(&cli, |line| lines.push(line))?;
|
skip(&cli, &mut lines)?;
|
||||||
|
|
||||||
//then
|
//then
|
||||||
assert_eq!(lines, vec!["line 2"]);
|
assert_eq!(String::from_utf8(lines)?, "line 2\n");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,13 +129,13 @@ mod tests {
|
||||||
token: None,
|
token: None,
|
||||||
ignore_extras: false,
|
ignore_extras: false,
|
||||||
};
|
};
|
||||||
let mut lines: Vec<String> = Vec::new();
|
let mut lines = Vec::new();
|
||||||
|
|
||||||
//when
|
//when
|
||||||
skip(&cli, |line| lines.push(line))?;
|
skip(&cli, &mut lines)?;
|
||||||
|
|
||||||
//then
|
//then
|
||||||
assert_eq!(lines, vec!["alpha", "gamma"]);
|
assert_eq!(String::from_utf8(lines)?, vec!["alpha", "gamma\n"].join("\n"));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,13 +149,13 @@ mod tests {
|
||||||
token: None,
|
token: None,
|
||||||
ignore_extras: false,
|
ignore_extras: false,
|
||||||
};
|
};
|
||||||
let mut lines: Vec<String> = Vec::new();
|
let mut lines = Vec::new();
|
||||||
|
|
||||||
//when
|
//when
|
||||||
skip(&cli, |line| lines.push(line))?;
|
skip(&cli, &mut lines)?;
|
||||||
|
|
||||||
//then
|
//then
|
||||||
assert_eq!(lines, vec!["gamma"]);
|
assert_eq!(String::from_utf8(lines)?, "gamma\n");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,19 +169,20 @@ mod tests {
|
||||||
token: Some(String::from("one")),
|
token: Some(String::from("one")),
|
||||||
ignore_extras: false,
|
ignore_extras: false,
|
||||||
};
|
};
|
||||||
let mut lines: Vec<String> = Vec::new();
|
let mut lines = Vec::new();
|
||||||
|
|
||||||
//when
|
//when
|
||||||
skip(&cli, |line| lines.push(line))?;
|
skip(&cli, &mut lines)?;
|
||||||
|
|
||||||
//then
|
//then
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
lines,
|
String::from_utf8(lines)?,
|
||||||
vec![
|
vec![
|
||||||
"Or help one fainting robin",
|
"Or help one fainting robin",
|
||||||
"Unto his nest again,",
|
"Unto his nest again,",
|
||||||
"I shall not live in vain."
|
"I shall not live in vain.\n"
|
||||||
]
|
]
|
||||||
|
.join("\n")
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -210,14 +197,14 @@ mod tests {
|
||||||
token: Some(String::from("or")),
|
token: Some(String::from("or")),
|
||||||
ignore_extras: false,
|
ignore_extras: false,
|
||||||
};
|
};
|
||||||
let mut lines: Vec<String> = Vec::new();
|
let mut lines = Vec::new();
|
||||||
|
|
||||||
//when
|
//when
|
||||||
skip(&cli, |line| lines.push(line))?;
|
skip(&cli, &mut lines)?;
|
||||||
|
|
||||||
//then
|
//then
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
lines,
|
String::from_utf8(lines)?,
|
||||||
vec![
|
vec![
|
||||||
//Lorem ipsum dolor sit amet, -- +2 = 2
|
//Lorem ipsum dolor sit amet, -- +2 = 2
|
||||||
//consectetur adipiscing elit,
|
//consectetur adipiscing elit,
|
||||||
|
@ -226,8 +213,9 @@ mod tests {
|
||||||
"Ut enim ad minim veniam,",
|
"Ut enim ad minim veniam,",
|
||||||
"quis nostrud exercitation ullamco",
|
"quis nostrud exercitation ullamco",
|
||||||
"laboris nisi ut aliquip ex ea",
|
"laboris nisi ut aliquip ex ea",
|
||||||
"commodo consequat."
|
"commodo consequat.\n"
|
||||||
]
|
]
|
||||||
|
.join("\n")
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -242,14 +230,14 @@ mod tests {
|
||||||
token: Some(String::from("or")),
|
token: Some(String::from("or")),
|
||||||
ignore_extras: true,
|
ignore_extras: true,
|
||||||
};
|
};
|
||||||
let mut lines: Vec<String> = Vec::new();
|
let mut lines = Vec::new();
|
||||||
|
|
||||||
//when
|
//when
|
||||||
skip(&cli, |line| lines.push(line))?;
|
skip(&cli, &mut lines)?;
|
||||||
|
|
||||||
//then
|
//then
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
lines,
|
String::from_utf8(lines)?,
|
||||||
vec![
|
vec![
|
||||||
//Lorem ipsum dolor sit amet, -- 1
|
//Lorem ipsum dolor sit amet, -- 1
|
||||||
//consectetur adipiscing elit,
|
//consectetur adipiscing elit,
|
||||||
|
@ -258,8 +246,9 @@ mod tests {
|
||||||
//Ut enim ad minim veniam,
|
//Ut enim ad minim veniam,
|
||||||
//quis nostrud exercitation ullamco
|
//quis nostrud exercitation ullamco
|
||||||
//laboris nisi ut aliquip ex ea -- 4
|
//laboris nisi ut aliquip ex ea -- 4
|
||||||
"commodo consequat."
|
"commodo consequat.\n"
|
||||||
]
|
]
|
||||||
|
.join("\n")
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
10
src/main.rs
10
src/main.rs
|
@ -1,15 +1,9 @@
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use skip::{skip, Cli, Result};
|
use skip::{skip, Cli, Result};
|
||||||
use std::io::Write;
|
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
|
let mut stdout = std::io::stdout();
|
||||||
|
|
||||||
let stdout = std::io::stdout();
|
skip(&cli, &mut stdout)
|
||||||
let mut output = stdout.lock();
|
|
||||||
|
|
||||||
skip(&cli, |line| match writeln!(output, "{}", line) {
|
|
||||||
Err(_) => (),
|
|
||||||
Ok(_) => (),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue