lib.rs (2778B)
1 use std::fs; 2 use std::error::Error; 3 use std::env; 4 5 pub fn run(cf: Config) -> Result<(), Box<dyn Error>> { 6 let contents = fs::read_to_string(&cf.file)?; 7 let matches = if cf.case_sensitive { 8 search(&contents, &cf.pattern).unwrap() 9 } else { 10 search_case_insensitive(&contents, &cf.pattern).unwrap() 11 }; 12 13 for i in matches { 14 println!("{}", i); 15 } 16 Ok(()) 17 } 18 19 pub struct Config { 20 file: String, 21 pattern: String, 22 case_sensitive: bool, 23 } 24 25 impl Config { 26 pub fn new(args: Vec<String>) -> Result<Config, &'static str> { 27 if args.len() < 3 { 28 return Err("not enough arguments"); 29 } 30 let file = args[1].clone(); 31 let pattern = args[2].clone(); 32 33 let case_sensitive = env::var("CASE_SENSITIVE").is_err(); 34 Ok(Config { file, pattern, case_sensitive }) 35 } 36 } 37 38 pub fn search_case_insensitive( 39 contents: &String, 40 pattern: &String 41 ) -> Result<Vec<String>, Box<dyn Error>> { 42 let mut matches = Vec::new(); 43 let pattern = pattern.to_lowercase(); 44 45 for line in contents.split("\n") { 46 if line.to_lowercase().contains(&pattern) { 47 matches.push(line.to_string()); 48 } 49 } 50 51 Ok(matches) 52 } 53 54 55 pub fn search(contents: &String, pattern: &String) -> Result<Vec<String>, Box<dyn Error>> { 56 let mut matches = Vec::new(); 57 for line in contents.split("\n") { 58 if line.contains(pattern) { 59 matches.push(line.to_string()); 60 } 61 } 62 63 Ok(matches) 64 } 65 66 #[cfg(test)] 67 mod tests { 68 use super::*; 69 70 #[test] 71 #[should_panic(expected = "not enough arguments")] 72 fn config_new_too_many_args() { 73 let args: Vec<String> = vec!["a".to_string(), "b".to_string()]; 74 Config::new(args).unwrap(); 75 } 76 77 #[test] 78 fn simple_search() { 79 let l1 = "line 1 grepped here"; 80 let l2 = "line 2 skipped"; 81 let l3 = "line 3 grepped here"; 82 83 let content = format!("{}\n{}\n{}\n", l1, l2, l3); 84 let pattern = "here".to_string(); 85 println!("{}", content); 86 87 let matches = search(&content, &pattern).unwrap(); 88 assert_eq!(&matches[0], l1); 89 assert_eq!(&matches[1], l3); 90 } 91 92 #[test] 93 fn case_sensitive() { 94 let content = "Lock the door\nBlock the door\n".to_string(); 95 let pattern = "lock".to_string(); 96 let matches = search(&content, &pattern).unwrap(); 97 assert_eq!(matches, vec!["Block the door"]); 98 } 99 100 #[test] 101 fn case_insensitive() { 102 let content = "Lock the door\nBlock the door\n".to_string(); 103 let pattern = "lOcK".to_string(); 104 let matches = search_case_insensitive(&content, &pattern).unwrap(); 105 assert_eq!(matches, vec!["Lock the door", "Block the door"]); 106 } 107 108 }