minigrep_megastary/
lib.rs1use std::error::Error;
6use std::{env, fs};
7
8pub struct Config {
9 pub query: String,
10 pub file_path: String,
11 pub ignore_case: bool,
12}
13
14impl Config {
15 pub fn build(mut args: impl Iterator<Item = String>) -> Result<Config, &'static str> {
27 args.next();
29
30 let query = match args.next() {
31 Some(arg) => arg,
32 None => return Err("Fuck"),
33 };
34
35 let file_path = match args.next() {
36 Some(arg) => arg,
37 None => return Err("Fuck"),
38 };
39
40 let ignore_case: bool = env::var("IGNORE_CASE").is_ok();
41
42 Ok(Config {
43 query,
44 file_path,
45 ignore_case,
46 })
47 }
48}
49
50pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
51 let contents = fs::read_to_string(config.file_path)?;
52
53 let results = if config.ignore_case {
54 search_case_insensitive(&config.query, &contents)
55 } else {
56 search(&config.query, &contents)
57 };
58
59 for line in results {
60 println!("{line}");
61 }
62
63 Ok(())
64}
65
66fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
67 contents
68 .lines()
69 .filter(|line| line.contains(query))
70 .collect()
71}
72
73fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
74 contents
75 .lines()
76 .filter(|line| line.to_lowercase().contains(query))
77 .collect()
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn case_sensitive() {
86 let query = "duct";
87 let contents = "\
88Rust:
89Safe, fast, productive.
90Ducts are like plague.
91Pick three.";
92
93 assert_eq!(vec!["Safe, fast, productive."], search(query, contents));
94 }
95
96 #[test]
97 fn case_insensitive() {
98 let query = "duct";
99 let contents = "\
100Rust:
101Safe, fast, productive.
102Ducts are like plague.
103Pick three.";
104
105 assert_eq!(
106 vec!["Safe, fast, productive.", "Ducts are like plague."],
107 search_case_insensitive(query, contents)
108 );
109 }
110}