bgrp/
lib.rs

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