thifl_minigrep/
lib.rs

1//! #Minigrep
2//!
3//! `minigrep` is a a mini project with the goal
4//! of reproducting the behaviour of the grep command
5use std::env;
6use std::error::Error;
7use std::fs;
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> {
17        args.next();
18
19        let query = match args.next() {
20            Some(arg) => arg,
21            None => return Err("Expected query"),
22        };
23
24        let filename = match args.next() {
25            Some(arg) => arg,
26            None => return Err("Expected filename"),
27        };
28
29        let case_sensitive = env::var("CASE_INSENSITIVE").is_err();
30
31        Ok(Config {
32            query,
33            filename,
34            case_sensitive,
35        })
36    }
37}
38
39pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
40    let contents = fs::read_to_string(config.filename)?;
41
42    // println!("With text: \n{}", contents.to_lowercase());
43
44    let results = if config.case_sensitive {
45        search(&config.query, &contents)
46    } else {
47        search_case_insensitive(&config.query, &contents)
48    };
49
50    for line in results {
51        println!("{}", line);
52    }
53
54    Ok(())
55}
56
57/// Search for `query` in the lines of `contents`.
58/// Returns a vector of str containing the lines.
59///
60/// # Example
61///
62/// ```
63/// let query = "safe";
64/// let contents = "\
65/// Rust:
66/// safe, fast, productive.
67/// Pick three.";
68///
69/// assert_eq!(vec!["safe, fast, productive."], minigrep::search(query, contents));
70/// ```
71/// ```
72/// let query = "Pick";
73/// let contents = "\
74/// Rust:
75/// safe, fast, productive.
76/// Pick three.";
77///
78/// assert_ne!(vec!["Rust"], minigrep::search(query, contents));
79/// ```
80pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
81    contents
82        .lines()
83        .filter(|line| line.contains(query))
84        .collect()
85}
86
87pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
88    let query = query.to_lowercase();
89    let mut results = Vec::new();
90
91    for line in contents.lines() {
92        if line.to_lowercase().contains(&query) {
93            results.push(line);
94        }
95    }
96    results
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102
103    #[test]
104    fn one_result() {
105        let query = "duct";
106        let contents = "\
107Rust:
108safe, fast, productive.
109Pick three.";
110
111        assert_eq!(vec!["safe, fast, productive."], search(query, contents));
112    }
113
114    #[test]
115    fn case_insensitive() {
116        let query = "rUsT";
117        let contents = "\
118Rust:
119safe, fast, productive.
120Pick three.
121Trust me.";
122
123        assert_eq!(
124            vec!["Rust:", "Trust me."],
125            search_case_insensitive(query, contents)
126        );
127    }
128}