derek_minigrep/
lib.rs

1use std::error::Error;
2use std::{env, fs};
3
4#[derive(Debug)]
5pub struct Config {
6    pub query: String,
7    pub path: String,
8    pub ignore_case: bool,
9}
10
11impl Config {
12    /// Create config
13    /// # Example
14    /// ```
15    /// use std::env;
16    /// use minigrep::Config;
17    ///
18    /// let config = Config::build(vec!["minigrep".to_string(), "query".to_string(), "path".to_string()].into_iter()).expect("create config error");
19    /// assert_eq!(config.query, "query".to_string());
20    /// assert_eq!(config.path, "path".to_string());
21    /// assert_eq!(config.ignore_case, false);
22    /// ```
23    pub fn build(mut args: impl Iterator<Item=String>) -> Result<Config, &'static str> {
24        args.next();
25
26        let query = match args.next() {
27            Some(arg) => arg,
28            None => return Err("Didn't get a query string"),
29        };
30
31        let path = match args.next() {
32            Some(arg) => arg,
33            None => return Err("Didn't get a file name"),
34        };
35
36        let ignore_case = env::var("IGNORE_CASE").is_ok();
37
38        Ok(Config { query, path, ignore_case })
39    }
40}
41
42pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
43    let contents = fs::read_to_string(config.path)?;
44    
45    let results = if config.ignore_case {
46        search_case_insensitive(&config.query, &contents)
47    } else {
48        search(&config.query, &contents)
49    };
50
51    for result in results {
52        println!("{}", result);
53    }
54
55    Ok(())
56}
57
58pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
59    contents.lines().filter(|line| {line.contains(query)}).collect()
60}
61
62pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
63    contents.lines().filter(|line| { line.to_lowercase().contains(&query.to_lowercase()) }).collect()
64}
65
66#[cfg(test)]
67mod tests {
68    use super::*;
69
70    fn get_test_data() -> &'static str {
71        "\
72        Rust:\nsafe, fast, productive. Pick three.\nDuct tape.\nTrust me."
73    }
74
75    #[test]
76    fn case_sensitive() {
77        let query = "duct";
78        assert_eq!(vec!["safe, fast, productive. Pick three."], search(query, get_test_data()));
79    }
80
81    #[test]
82    fn case_insensitive() {
83        let query = "rUsT";
84        assert_eq!(vec!["Rust:", "Trust me."], search_case_insensitive(query, get_test_data()));
85    }
86}