lib.rs
 1  use std::env;
 2  use std::error::Error;
 3  use std::fs;
 4  
 5  pub struct Config {
 6      pub query: String,
 7      pub file_path: String,
 8      pub ignore_case: bool,
 9  }
10  
11  impl Config {
12      pub fn build(mut args: impl Iterator<Item = String>) -> Result<Config, &'static str> {
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  
25          let ignore_case = env::var("IGNORE_CASE").is_ok();
26  
27          Ok(Config {
28              query,
29              file_path,
30              ignore_case,
31          })
32      }
33  }
34  
35  pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
36      let contents = fs::read_to_string(config.file_path)?;
37  
38      let results = if config.ignore_case {
39          search_case_insensitive(&config.query, &contents)
40      } else {
41          search(&config.query, &contents)
42      };
43  
44      for line in results {
45          println!("{line}");
46      }
47  
48      Ok(())
49  }
50  
51  pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
52      contents
53          .lines()
54          .filter(|line| line.contains(query))
55          .collect()
56  }
57  
58  pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
59      contents
60          .lines()
61          .filter(|line| line.to_lowercase().contains(&query.to_lowercase()))
62          .collect()
63  }
64  
65  #[cfg(test)]
66  mod tests {
67      use super::*;
68  
69      #[test]
70      fn case_sensitive() {
71          let query = "duct";
72          let contents = "\
73  Rust:
74  safe, fast, productive.
75  Pick three.
76  Duct tape.";
77  
78          assert_eq!(vec!["safe, fast, productive."], search(query, contents));
79      }
80  
81      #[test]
82      fn case_insensitive() {
83          let query = "rUst";
84          let contents = "\
85  Rust:
86  safe, fast, productive.
87  Pick three.
88  Trust me.";
89  
90          assert_eq!(
91              vec!["Rust:", "Trust me."],
92              search_case_insensitive(query, contents)
93          );
94      }
95  }