moj_minigrep 0.1.0

A minigrep written for learning purposes.
Documentation
use std::{error::Error, fs, env};

pub struct Config {
  pub query: String,
  pub file_path: String,
  pub ignore_case: bool
}

impl Config {
  pub fn build(
      mut args: impl Iterator<Item = String>,
      ) -> Result<Config, &'static str> {
    args.next();
    
    let query = match args.next() {
      Some(q) => q,
      None => return Err("No arguments found")
    };
    
    let file_path = match args.next() {
      Some(p) => p,
      None => return Err("No file path")
    };
    
    let ignore_case = env::var("IGNORE_CASE").is_ok();

    Ok(Config { query, file_path, ignore_case })
  }
}

pub fn run(config: Config) -> Result<(), Box<dyn Error>>{
  let content = fs::read_to_string(config.file_path)?;
  
  println!("Found:");
  let result = if config.ignore_case {
    search_case_insensitive(&config.query, content.as_str())
  }
  else {
    search(&config.query, content.as_str())
  };

  for line in result {
    println!("{line}");
  }

  Ok(())
}


/// Searches for lines containing a given text
/// 
/// # Examples
/// 
/// ## Regular search
/// ```
/// let content = "trt\nhehe\nmrt";
/// let query = "rt";
/// 
/// assert_eq!(vec!["trt", "mrt"], moj_minigrep::search(query, content));
/// ```
/// 
/// ## Case sensitive search
/// ```
/// let content = "trt\nhehe\nmrt";
/// let query = "Rt";
/// 
/// assert_ne!(vec!["trt", "mrt"], moj_minigrep::search(query, content));
/// ```
/// 
pub fn search<'a>(query: &str, content: &'a str) -> Vec<&'a str> {  
  content
    .lines()
    .filter(|line| line.contains(query))
    .collect()
}

pub fn search_case_insensitive<'a>(query: &str, content: &'a str) -> Vec<&'a str> {
  let mut result = Vec::new();
  let query = query.to_lowercase();
  for line in content.lines().enumerate() {
    if line.1.to_lowercase().contains(&query) {
      result.push(line.1);
    }
  }
  result
}


#[cfg(test)]
mod tests {
  use super::*;
  
  #[test]
  fn case_sensitive() {
    let query = "duct";
    let content = "\
Rust:
safe, fast, productive.
Pick three.
Duct tape.";

    assert_eq!(vec!["safe, fast, productive."], search(query, content));
  }

  #[test]
  fn case_insensitive() {
    let query = "rUst";
    let content = "\
Rust:
safe, fast, productive.
Pick three.
Trust me.";

    assert_eq!(
      vec!["Rust:", "Trust me."], 
      search_case_insensitive(query, content)
    );
  }
}