rustbook

Toy programs and snippets for The Rust Programming Language book
Log | Files | Refs

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 }