snp_sminigrep/
lib.rs

1//! # Lib Crate
2//! 
3//! メインにだらだら書いていたロジックへの責務を分離してここに全てイレタ
4use std::{env, error::Error, fs};
5
6
7// NOTE: don't have to specify the return type 
8pub fn run (config: Config) -> Result<(), Box<dyn Error>> {
9    let contents = fs::read_to_string(config.file_path)?;
10
11    let result = if config.ignore_case {
12        search_case_insensitive(&config.query, &contents)
13    } else {
14        search(&config.query, &contents)
15    };
16    for line in result {
17        println!("{}", line);
18    }
19    Ok(())
20}
21
22pub struct Config {
23    pub query: String,
24    pub file_path: String,
25    pub ignore_case: bool,
26}
27
28impl Config {
29
30    /// ユーザー入力から設定インスタンスの生成を試みる
31    /// 失敗した場合はエラー
32    /// 
33    /// # example
34    /// 
35    /// ```
36    /// let config = Config::build(env::args()).unwrap_or_else(|err| {
37    ///     eprintln!("Problem parsing arguments: {err}");
38    ///     process::exit(1);
39    /// });
40    /// ```
41    pub fn build (mut args: impl Iterator<Item = String>) -> Result<Config, &'static str> {
42        args.next();
43        let query = match args.next() {
44            Some(value) => value,
45            None => return Err("Didn't get a query string."),
46        };
47        let file_path = match args.next() {
48            Some(value) => value,
49            None => return Err("Didn't get a file_path string."),
50        };
51        Ok(
52            Config {
53                query,
54                file_path,
55                ignore_case: env::var("IGNORE_CASE").is_ok(),
56            }
57        )
58    }
59}
60
61pub fn search<'c> (query: &str, contents: &'c str) -> Vec<&'c str> {
62    contents.lines()
63        .filter(|line| line.contains(query))
64        .collect()
65}
66
67pub fn search_case_insensitive<'c>(query: &str, contents: &'c str) -> Vec<&'c str> {
68    let query = query.to_lowercase();
69    let mut result = vec![];
70    for line in contents.lines() {
71        if line.to_lowercase().contains(&query) {
72            result.push(line);
73        }
74    }
75    return result;
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81    #[test]
82    fn case_sensitive() {
83        let query  = "duct";
84        let contents = "\
85Rust:
86safe, fast, productive.
87Pick three.";
88        assert_eq!(vec!["safe, fast, productive."], search(query, contents));
89    }
90    fn search_case_insensitive() {
91        let query  = "rUsT";
92        let contents = "\
93Rust:
94safe, fast, productive.
95Pick three.
96Trust me.
97Duct tape.";
98        assert_eq!(vec!["Rust:", "Trust me."], search(query, contents));
99    }
100}