minigrep_megastary/
lib.rs

1//! # minigrep_megastary
2//!
3//! `minigrep_megastary` is a result of going through Rust book's chapter 12 and onwards.
4
5use std::error::Error;
6use std::{env, fs};
7
8pub struct Config {
9    pub query: String,
10    pub file_path: String,
11    pub ignore_case: bool,
12}
13
14impl Config {
15    /// Parses command line arguments and returns Config object containing query, path to file and ignore case state from ENV variable
16    ///
17    /// # Examples
18    ///
19    /// ```
20    /// use std::env;
21    /// use minigrep::Config;
22    ///
23    /// // Returns Config object unless
24    /// Config::build(env::args()).unwrap();
25    /// ```
26    pub fn build(mut args: impl Iterator<Item = String>) -> Result<Config, &'static str> {
27        // Skip first argument, which is path to executable
28        args.next();
29
30        let query = match args.next() {
31            Some(arg) => arg,
32            None => return Err("Fuck"),
33        };
34
35        let file_path = match args.next() {
36            Some(arg) => arg,
37            None => return Err("Fuck"),
38        };
39
40        let ignore_case: bool = env::var("IGNORE_CASE").is_ok();
41
42        Ok(Config {
43            query,
44            file_path,
45            ignore_case,
46        })
47    }
48}
49
50pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
51    let contents = fs::read_to_string(config.file_path)?;
52
53    let results = if config.ignore_case {
54        search_case_insensitive(&config.query, &contents)
55    } else {
56        search(&config.query, &contents)
57    };
58
59    for line in results {
60        println!("{line}");
61    }
62
63    Ok(())
64}
65
66fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
67    contents
68        .lines()
69        .filter(|line| line.contains(query))
70        .collect()
71}
72
73fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
74    contents
75        .lines()
76        .filter(|line| line.to_lowercase().contains(query))
77        .collect()
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83
84    #[test]
85    fn case_sensitive() {
86        let query = "duct";
87        let contents = "\
88Rust:
89Safe, fast, productive.
90Ducts are like plague.
91Pick three.";
92
93        assert_eq!(vec!["Safe, fast, productive."], search(query, contents));
94    }
95
96    #[test]
97    fn case_insensitive() {
98        let query = "duct";
99        let contents = "\
100Rust:
101Safe, fast, productive.
102Ducts are like plague.
103Pick three.";
104
105        assert_eq!(
106            vec!["Safe, fast, productive.", "Ducts are like plague."],
107            search_case_insensitive(query, contents)
108        );
109    }
110}