use std::{fs, error::Error, env};
pub struct Config {
pub query: String,
pub filename: String,
pub case_sensitive: bool,
}
impl Config {
pub fn new(args: &[String]) -> Result<Config, &'static str> {
if args.len() < 3{
return Err("not enough arguments");
}
let str = &args[1];
let file = &args[2];
let case_sensitive = env::var("CASE_INSENSITIVE").is_err();
println!("{} at {}", str, file);
Ok(Config {
query: str.to_string(),
filename: file.to_string(),
case_sensitive,
})
}
}
pub fn find_query_in_file(config: &Config) -> Result<(), Box<dyn Error>> {
let contents =
fs::read_to_string(&config.filename)?;
println!("With text:\n{}", contents);
if config.case_sensitive {
for line in search(&config.query, &contents) {
println!("{}", line);
}
} else {
for line in search_case_insensitive(&config.query, &contents) {
println!("{}", line);
}
}
Ok(())
}
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
contents.lines()
.filter(|line| line.contains(query))
.collect()
}
pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
let lowercase_query = query.to_lowercase();
contents.lines()
.filter(|line| line.to_lowercase().contains(&lowercase_query))
.collect()
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_search() {
let query = "duct";
let contents = "\
Rust:
safe, fast, productive.
Pick three.";
assert_eq!(
vec!["safe, fast, productive."],
search(query, contents)
);
}
#[test]
fn test_search_case_insensitive() {
let query = "rUsT";
let contents = "\
Rust:
safe, fast, productive.
Pick three.
Trust me.";
assert_eq!(
vec!["Rust:", "Trust me."],
search_case_insensitive(query, contents)
);
}
}