ifun-grep 0.1.0

A simple fake grep.
Documentation
//! ifun_grep is a string search library
//!
//! Supports case sensitive search.
//!

use std::error::Error;
use std::{env, fs};

/// the struct `Config` defines command line params.
///
/// # Example
///
/// ```
/// let search = String::from("let");
/// let config = ifun_grep::Config {
///     search,
///     file_path:String::from("hello.txt"),
///     ignore_case:false,
/// };
///
/// ```
pub struct Config {
    pub search: String,
    pub file_path: String,
    pub ignore_case: bool,
}

impl Config {
    // fn new(args: &Vec<String>) -> Self {
    //     if args.len() < 3 {
    //         panic!("至少传入2个参数")
    //     }
    //     let search = args[1].clone();
    //     let file_path = args[2].clone();

    //     Config { search, file_path }
    // }
    pub fn build(args: &Vec<String>) -> Result<Config, &'static str> {
        if args.len() < 3 {
            return Err("至少传入2个参数");
        }
        let search = args[1].clone();
        let file_path = args[2].clone();

        let ignore_case = env::var("IGNORE_CASE").is_ok();

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

/// the fun is used to execute search
///
/// # example
/// ```
/// let search = String::from("let");
/// let config = ifun_grep::Config {
///     search,
///     file_path:String::from("hello.txt"),
///     ignore_case:false,
/// };
///
/// let result = ifun_grep::run(config);
///
/// assert!(result.is_ok());
/// ```
///
pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
    let content = fs::read_to_string(config.file_path)?;

    // println!("read the content:\n{content}");
    let result;
    if config.ignore_case {
        result = find_insensitive(&config.search, &content);
    } else {
        result = find(&config.search, &content);
    }
    for line in result {
        println!("{line}");
    }

    Ok(())
}

/// the fun is used to execute search. it's case sensitive
///
/// # example
///
/// ```
/// let search = "rust";
/// let content = "\
/// nice. rust
/// I'm hboot.
/// hello world.
/// Rust
/// ";

/// assert_eq!(vec!["nice. rust"], ifun_grep::find(search, content));
/// ```
///
pub fn find<'a>(search: &str, content: &'a str) -> Vec<&'a str> {
    let mut result = vec![];
    for line in content.lines() {
        if line.contains(search) {
            // 符合,包含了指定字符串
            result.push(line);
        }
    }

    result
}
/// the fun is used to execute search. it's case sensitive
///
/// # example
///
/// ```
/// let search = "rust";
/// let content = "\
/// nice. rust
/// I'm hboot.
/// hello world.
/// Rust
/// ";
/// assert_eq!(vec!["nice. rust","Rust"], ifun_grep::find_insensitive(search, content));
/// ```
///
pub fn find_insensitive<'a>(search: &str, content: &'a str) -> Vec<&'a str> {
    let mut result = vec![];
    // 搜索 字符串转小写
    let search = search.to_lowercase();

    for line in content.lines() {
        // 文本行内容转小写
        if line.to_lowercase().contains(&search) {
            // 符合,包含了指定字符串
            result.push(line);
        }
    }

    result
}
#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn case_sensitive() {
        let search = "rust";
        let content = "\
nice. rust
I'm hboot.
hello world.
Rust
";

        assert_eq!(vec!["nice. rust"], find(search, content));
    }

    #[test]
    fn case_insensitive() {
        let search = "rust";
        let content = "\
nice. rust
I'm hboot.
hello world.
Rust
";

        assert_eq!(
            vec!["nice. rust", "Rust"],
            find_insensitive(search, content)
        );
    }
}