xgrepx/
lib.rs

1
2//! This runs the entire grep functionalities.
3
4
5use std::{fs, env, error::Error};
6
7pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
8    let contents = fs::read_to_string(config.filename)?;
9
10    let results = if config.ignore_case {
11        search_case_insensitive(&config.query, &contents)
12    }else {
13        search(&config.query, &contents)
14    };
15
16    for line in results {
17        println!("{}", line);
18    }
19
20    Ok(())
21}
22
23/// Config struct with a constructor new() \
24/// Use to generate a config
25pub struct Config {
26    /// this is what to search for
27    pub query: String,
28    /// this is the path to file we want to search
29    pub filename: String,
30    /// whether to make case case_insensitive or not
31    pub ignore_case: bool
32}
33
34impl Config {
35    pub fn new(mut args: impl Iterator<Item = String>) -> Result<Config, &'static str> {
36
37        // skip into first argument
38        args.next();
39
40        // retrieve second value, query
41        let query = match args.next() {
42            Some(arg) => arg,
43            None => return Err("Didn't get a query string")
44        };
45
46        // retrieve third value, filename
47        let filename = match args.next() {
48            Some(arg) => arg,
49            None => return Err("Didn't get a filename")
50        };
51
52        let ignore_case = env::var("IGNORE_CASE").is_ok();
53
54        Ok(Config {
55            query,
56            filename,
57            ignore_case
58        })
59    }
60}
61
62// todo: use hashmap to add line number to result
63/// Search functionality is here \
64/// This search ensures case_sensitive query \
65/// @params: query => what to search for \
66/// @params: content => contents of file to search
67pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
68    // using iterator to filter lines
69    contents
70        .lines()
71        .filter(|line| line.contains(query))
72        .collect()
73
74}
75
76/// Case_insensitive form of search
77pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
78    let query = query.to_lowercase();
79
80    contents
81        .lines()
82        .filter(
83            |line|
84                line
85                    .to_lowercase()
86                    .contains(&query)
87        )
88        .collect()
89
90}
91
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    #[test]
98    fn case_sensitive() {
99        let query = "duct";
100        let contents = "\
101Rust:
102safe, fast, productive.
103Duct tape
104Pick three.";
105
106        assert_eq!(vec!["safe, fast, productive."], search(query, contents))
107    }
108
109    #[test]
110    fn case_insensitive() {
111        let query = "rUsT";
112        let contents = "\
113Rust:
114safe, fast, productive.
115Pick three.
116Trust me.";
117
118        assert_eq!(
119            vec!["Rust:", "Trust me."],
120            search_case_insensitive(query, contents)
121        )
122    }
123}