1use std::fs;
6use std::error::Error;
7use std::env;
8
9pub struct Config {
10 pub query: String,
11 pub filename: String,
12 pub case_sensitive: bool,
13}
14
15impl Config {
16 pub fn new(mut args: env::Args) -> Result<Config, &'static str> {
18 args.next();
19 let query = match args.next() {
20 Some(arg) => arg,
21 None => return Err("Didn't get a query string")
22 };
23
24 let filename = match args.next() {
25 Some(arg) => arg,
26 None => return Err("Didn't get a file name")
27 };
28
29 let case_sensitive = env::var("CASE_INSENSITIVE").is_err();
30
31 Ok(Config { query, filename, case_sensitive })
32 }
33
34}
35
36
37pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
48 let contents = fs::read_to_string(config.filename)?;
49 println!("&config.query: {}, &contents: {}", &config.query, &contents);
50 let results = if config.case_sensitive {
51 search(&config.query, &contents)
52 } else {
53 search_case_insensitive(&config.query, &contents)
54 };
55
56 for line in results {
57 println!("{}", line);
58 };
59
60 Ok(())
61}
62
63pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
64 contents.lines().filter(|line| line.contains(query)).collect()
65 }
74
75pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
76 let query = query.to_lowercase();
77 contents.lines().filter(|line| line.to_lowercase().contains(&query)).collect()
78 }
89
90#[cfg(test)]
91mod tests {
92 use super::{search, search_case_insensitive};
93
94 #[test]
95 fn case_sensitive() {
96 let query = "duct";
97 let contents = "\
98Rust:
99safe, fast, productive.
100Pick three.
101Duct tape.";
102
103 assert_eq!(vec!["safe, fast, productive."], search(query, contents));
104 }
105
106 #[test]
107 fn case_insensitve() {
108 let query = "rust";
109 let contents = "\
110Rust:
111safe, fast, productive.
112Pick three.
113Trust me.";
114
115 assert_eq!(vec!["Rust:", "Trust me."], search_case_insensitive(query, contents));
116 }
117}