]>
Commit | Line | Data |
---|---|---|
74b04a01 XL |
1 | use std::env; |
2 | use std::error::Error; | |
3 | use std::fs; | |
4 | ||
5 | pub struct Config { | |
6 | pub query: String, | |
7 | pub filename: String, | |
04454e1e | 8 | pub ignore_case: bool, |
74b04a01 XL |
9 | } |
10 | ||
11 | // ANCHOR: ch13 | |
12 | impl Config { | |
a2a8927a | 13 | pub fn new(args: &[String]) -> Result<Config, &'static str> { |
74b04a01 XL |
14 | if args.len() < 3 { |
15 | return Err("not enough arguments"); | |
16 | } | |
17 | ||
18 | let query = args[1].clone(); | |
19 | let filename = args[2].clone(); | |
20 | ||
04454e1e | 21 | let ignore_case = env::var("IGNORE_CASE").is_ok(); |
74b04a01 XL |
22 | |
23 | Ok(Config { | |
24 | query, | |
25 | filename, | |
04454e1e | 26 | ignore_case, |
74b04a01 XL |
27 | }) |
28 | } | |
29 | } | |
30 | // ANCHOR_END: ch13 | |
31 | ||
32 | pub fn run(config: Config) -> Result<(), Box<dyn Error>> { | |
33 | let contents = fs::read_to_string(config.filename)?; | |
34 | ||
04454e1e | 35 | let results = if config.ignore_case { |
74b04a01 | 36 | search_case_insensitive(&config.query, &contents) |
04454e1e FG |
37 | } else { |
38 | search(&config.query, &contents) | |
74b04a01 XL |
39 | }; |
40 | ||
41 | for line in results { | |
42 | println!("{}", line); | |
43 | } | |
44 | ||
45 | Ok(()) | |
46 | } | |
47 | ||
48 | pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { | |
49 | let mut results = Vec::new(); | |
50 | ||
51 | for line in contents.lines() { | |
52 | if line.contains(query) { | |
53 | results.push(line); | |
54 | } | |
55 | } | |
56 | ||
57 | results | |
58 | } | |
59 | ||
60 | pub fn search_case_insensitive<'a>( | |
61 | query: &str, | |
62 | contents: &'a str, | |
63 | ) -> Vec<&'a str> { | |
64 | let query = query.to_lowercase(); | |
65 | let mut results = Vec::new(); | |
66 | ||
67 | for line in contents.lines() { | |
68 | if line.to_lowercase().contains(&query) { | |
69 | results.push(line); | |
70 | } | |
71 | } | |
72 | ||
73 | results | |
74 | } | |
75 | ||
76 | #[cfg(test)] | |
77 | mod tests { | |
78 | use super::*; | |
79 | ||
80 | #[test] | |
81 | fn case_sensitive() { | |
82 | let query = "duct"; | |
83 | let contents = "\ | |
84 | Rust: | |
85 | safe, fast, productive. | |
86 | Pick three. | |
87 | Duct tape."; | |
88 | ||
89 | assert_eq!(vec!["safe, fast, productive."], search(query, contents)); | |
90 | } | |
91 | ||
92 | #[test] | |
93 | fn case_insensitive() { | |
94 | let query = "rUsT"; | |
95 | let contents = "\ | |
96 | Rust: | |
97 | safe, fast, productive. | |
98 | Pick three. | |
99 | Trust me."; | |
100 | ||
101 | assert_eq!( | |
102 | vec!["Rust:", "Trust me."], | |
103 | search_case_insensitive(query, contents) | |
104 | ); | |
105 | } | |
106 | } |