cargo_minigrepx719/
lib.rs

1//! Mini-grep
2//!
3//! `Mini-grep` is a searching tool to print texts that match the contents of the specified file at the file path
4
5use std::env;
6use std::error::Error;
7use std::fs;
8
9pub struct Config {
10    pub query: String,
11    pub file_path: String,
12    pub ignore_case: bool,
13}
14
15impl Config {
16    pub fn build(mut args: impl Iterator<Item = String>) -> Result<Config, &'static str> {
17        args.next();
18
19        let query = match args.next() {
20            Some(arg) => arg,
21            None => return Err("Didn't get a query string"),
22        };
23
24        let file_path = match args.next() {
25            Some(arg) => arg,
26            None => return Err("Didn't get a file path"),
27        };
28
29        let ignore_case = env::var("IGNORE_CASE").is_ok();
30
31        Ok(Config {
32            query,
33            file_path,
34            ignore_case,
35        })
36    }
37}
38
39/// Runs the Searching Functionality
40///
41/// # Examples
42/// ```
43/// let config = minigrep::Config {
44///     query: String::from("hello"),
45///     file_path: String::from("./poem.txt"),
46///     ignore_case: true
47/// };
48///
49/// let res = minigrep::run(config);
50///
51/// assert!(res.is_ok());
52/// ```
53pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
54    let contents = fs::read_to_string(config.file_path)?;
55
56    let results = if config.ignore_case {
57        search_case_insensitive(&config.query, &contents)
58    } else {
59        search(&config.query, &contents)
60    };
61
62    for line in results {
63        println!("{line}");
64    }
65
66    Ok(())
67}
68
69pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
70    contents
71        .lines()
72        .filter(|line| line.contains(query))
73        .collect()
74}
75
76pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
77    let query = query.to_lowercase();
78
79    contents
80        .lines()
81        .filter(|line| line.to_lowercase().contains(&query))
82        .collect()
83}
84
85#[cfg(test)]
86mod tests {
87    use super::*;
88
89    #[test]
90    fn case_sensitive() {
91        let query = "duct";
92        let contents = "\
93Rust:
94safe, fast, productive.
95Pick three.
96Duck tape.";
97
98        assert_eq!(vec!["safe, fast, productive."], search(query, contents));
99    }
100
101    #[test]
102    fn case_insensitive() {
103        let query = "rUsT";
104        let contents = "\
105Rust:
106safe, fast, productive.
107Pick three.
108Trust me.";
109
110        assert_eq!(
111            vec!["Rust:", "Trust me."],
112            search_case_insensitive(query, contents)
113        );
114    }
115}