minigrep_bahadir/
lib.rs

1//! This is a crate created for educational purposes 
2//! of learning the Rust language.
3//! I followed the instructions from "The Rust Programming Language" book.
4
5use std::env;
6use std::error::Error;
7use std::fs;
8
9#[cfg(test)]
10mod tests {
11    use super::*;
12
13    #[test]
14    fn case_sensitive() {
15        let query = "duct";
16        let contents = "\
17Rust:
18safe, fast, productive.
19Pick three.
20Duct tape.";
21
22        assert_eq!(vec!["safe, fast, productive."], search(query, contents));
23    }
24
25    #[test]
26    fn case_insensitive() {
27        let query = "rUsT";
28        let contents = "\
29Rust:
30safe, fast, productive.
31Pick three.
32Trust me.";
33
34        assert_eq!(
35            vec!["Rust:", "Trust me."],
36            search_case_insensitive(query, contents)
37        );
38    }
39}
40
41pub struct Config {
42    pub query: String,
43    pub file_path: String,
44    pub ignore_case: bool,
45}
46
47impl Config {
48    pub fn build(mut args: impl Iterator<Item = String>) -> Result<Config, &'static str> {
49        // this is necessary because first env var is always the name of the program so we call
50        // args.next() and do nothing with its return value.
51        args.next();
52        let query = match args.next() {
53            Some(arg) => arg,
54            None => return Err("Query string is not specified."),
55        };
56        let file_path = match args.next() {
57            Some(arg) => arg,
58            None => return Err("File path is not specified."),
59        };
60        let ignore_case = env::var("IGNORE_CASE").is_ok();
61
62        Ok(Config {
63            query,
64            file_path,
65            ignore_case,
66        })
67    }
68}
69
70pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
71    contents
72        .lines()
73        .filter(|line| line.contains(query))
74        .collect()
75}
76pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
77    let query = query.to_lowercase();
78    contents
79        .lines()
80        .filter(|line| line.to_lowercase().contains(&query))
81        .collect()
82}
83
84pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
85    let contents = fs::read_to_string(config.file_path)?;
86
87    let results = if config.ignore_case {
88        search_case_insensitive(&config.query, &contents)
89    } else {
90        search(&config.query, &contents)
91    };
92
93    for line in results {
94        println!("{line}");
95    }
96
97    Ok(())
98}