eaverdeja_minigrep/
lib.rs1use std::env;
2use std::error::Error;
3use std::fs;
4
5pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
16 let contents = fs::read_to_string(config.file_path)?;
17
18 let results = if config.ignore_case {
19 search_case_insensitive(&config.query, &contents)
20 } else {
21 search(&config.query, &contents)
22 };
23
24 for line in results {
25 println!("{line}");
26 }
27
28 Ok(())
29}
30
31pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
49 contents
50 .lines()
51 .filter(|line| line.contains(query))
52 .collect()
53}
54
55pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
56 let query = query.to_lowercase();
57
58 contents
59 .lines()
60 .filter(|line| line.to_lowercase().contains(&query))
61 .collect()
62}
63
64pub struct Config {
65 pub query: String,
66 pub file_path: String,
67 pub ignore_case: bool,
68}
69
70impl Config {
71 pub fn build(mut args: impl Iterator<Item = String>) -> Result<Config, &'static str> {
72 args.next(); let query = match args.next() {
75 Some(arg) => arg,
76 None => return Err("Didn't get a query string"),
77 };
78
79 let file_path = match args.next() {
80 Some(arg) => arg,
81 None => return Err("Didn't get a file path"),
82 };
83
84 let ignore_case = env::var("IGNORE_CASE").is_ok();
85
86 Ok(Config {
87 query,
88 file_path,
89 ignore_case,
90 })
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn case_sensitive() {
100 let query = "duct";
101 let contents = "\
102Rust:
103safe, fast, productive.
104Pick three.
105Duct tape.";
106
107 assert_eq!(vec!["safe, fast, productive."], search(query, contents));
108 }
109
110 #[test]
111 fn case_insensitive() {
112 let query = "rUsT";
113 let contents = "\
114Rust:
115safe, fast, productive.
116Pick three.
117Trust me.";
118
119 assert_eq!(
120 vec!["Rust:", "Trust me."],
121 search_case_insensitive(query, contents)
122 )
123 }
124}