1use std::error::Error;
2use std::fs;
3use std::env;
4
5pub struct Config {
6 pub query: String,
7 pub filename: String,
8 pub case_sensitive: bool,
9}
10
11impl Config {
12 pub fn new(mut args: env::Args) -> 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 filename = match args.next() {
21 Some(arg) => arg,
22 None => return Err("Didn't get a file name"),
23 };
24
25 let case_sensitive = env::var("CASE_INSENSITIVE").is_err();
26
27 Ok(Config { query, filename , case_sensitive})
28 }
29}
30
31pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
32 let contents = fs::read_to_string(config.filename)?;
33
34 let results = if config.case_sensitive{
35 search(&config.query, &contents)
36 } else {
37 search_case_insensitive(&config.query, &contents)
38 };
39
40 for line in results {
41 println!("{}",line)
42 }
43 Ok(())
44}
45
46pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
47 contents.lines().filter(|line| line.contains(query)).collect()
48 }
56
57pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
58 contents.lines().filter(|line| line.to_lowercase().contains(&query.to_lowercase())).collect()
59 }
70
71#[cfg(test)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn case_sensitive() {
78 let query = "duct";
79 let contents = "\
80Rust:
81safe , fast , productive.
82Pick three.";
83 assert_eq!(vec!["safe , fast , productive."], search(query, contents));
84 }
85
86 #[test]
87 fn case_insensitive() {
88 let query = "rUST";
89 let contents = "\
90Rust:
91safe, fast, productive.
92Pick three.
93Trust me.";
94 assert_eq!(
95 vec!["Rust:", "Trust me."],
96 search_case_insensitive(query, contents)
97 );
98 }
99}