mmgrep/
lib.rs

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