1use std::{env, fs};
2use std::error::Error;
3
4pub struct Config {
5 keyword: String,
6 file_path: String,
7 case_insensitive: bool,
8}
9
10impl Config {
11 pub fn new(mut args: env::Args) -> Result<Self, &'static str> {
12 args.next();
13 let keyword = match args.next() {
14 None => return Err("not find 'keyword' arguments"),
15 Some(keyword) => keyword
16 };
17 let file_path = match args.next() {
18 None => return Err("not find 'file_path' arguments"),
19 Some(file_path) => file_path
20 };
21 Ok(Config {
22 keyword,
23 file_path,
24 case_insensitive: env::var("CASE_INSENSITIVE").is_err(),
26 })
27 }
28}
29
30pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
31 let content = fs::read_to_string(&config.file_path)?;
32 let result = if config.case_insensitive {
33 search_case_insensitive(&config.keyword, &content)
34 } else {
35 search(&config.keyword, &content)
36 };
37 for line in result {
38 println!("{}", line);
39 }
40 Ok(())
41}
42
43pub fn search<'a>(query: &str, content: &'a str) -> Vec<&'a str> {
44 content.lines()
45 .filter(|line| line.contains(query))
46 .collect()
47}
48
49pub fn search_case_insensitive<'a>(query: &str, content: &'a str) -> Vec<&'a str> {
50 content.lines()
51 .filter(|line| line.to_lowercase().contains(&query.to_lowercase()))
52 .collect()
53}
54
55#[cfg(test)]
56mod test {
57 use super::*;
58
59 #[test]
60 fn one_result() {
61 let query = "duct";
62 let content = "Rust\nsafe, fast, productive.\nPick three.";
63 assert_eq!(vec!["safe, fast, productive."], search(query, content));
64 }
65}