Skip to main content

minigrep_tool_cli/
lib.rs

1use crate::CaseMode::CaseSensitive;
2use CaseMode::CaseInsensitive;
3use std::error::Error;
4use std::{env, fs};
5
6pub fn run(config: &Config) -> Result<(), Box<dyn Error>> {
7    let content = fs::read_to_string(&config.file_path)?;
8
9    search(&config.query, &content, &config.case_mode)
10        .iter()
11        .for_each(|matching_string| println!("Found {matching_string}"));
12
13    Ok(())
14}
15
16fn search<'a>(query: &str, content: &'a str, case_mode: &CaseMode) -> Vec<&'a str> {
17    content
18        .lines()
19        .filter(|l| match case_mode {
20            CaseSensitive => l.contains(query),
21            CaseInsensitive => l.to_lowercase().contains(&query.to_lowercase()),
22        })
23        .collect::<Vec<_>>()
24}
25
26enum CaseMode {
27    CaseInsensitive,
28    CaseSensitive,
29}
30
31pub struct Config {
32    pub query: String,
33    pub file_path: String,
34    pub(crate) case_mode: CaseMode,
35}
36impl Config {
37    pub fn build(mut arguments: impl Iterator<Item = String>) -> Result<Self, &'static str> {
38        arguments.next();
39
40        let query = arguments.next().ok_or("query string not supplied")?;
41        let file_path = arguments.next().ok_or("file path not supplied")?;
42        let case_mode = Self::case_mode()?;
43
44        Ok(Config {
45            query,
46            file_path,
47            case_mode,
48        })
49    }
50
51    fn case_mode() -> Result<CaseMode, &'static str> {
52        let case_mode = match env::var("CASE_MODE").as_deref().unwrap_or("sensitive") {
53            "sensitive" => CaseSensitive,
54            "insensitive" => CaseInsensitive,
55            _ => return Err("Invalid case mode"),
56        };
57        Ok(case_mode)
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    #[test]
66    fn finds_a_case_sensitive_matching_result() {
67        let query = "duct";
68        let content = "\
69Rust:
70safe, fast, productive.
71Pick three.
72Duct tape.";
73
74        let results = search(query, content, &CaseSensitive);
75
76        assert_eq!(vec!["safe, fast, productive."], results)
77    }
78
79    #[test]
80    fn finds_case_sensitive_matching_result() {
81        let query = "RuSt";
82        let content = "\
83Rust:
84safe, fast, productive.
85Pick three.
86Duct tape.";
87        let results = search(query, content, &CaseInsensitive);
88
89        assert_eq!(vec!["Rust:"], results);
90    }
91}