minigrep_sopesto/
lib.rs

1//! # Minigrep
2//! `minigrip` es una aplicación hecha siguiendo la guía del libro *The Rust Programming Lenguage*.  
3//! La misma busca recrear de forma minimalista la aplicación `grep`.
4use std::error::Error;
5use std::{env, fs};
6
7///Estructura para la configuración y transpaso de información hacia las funciones.
8/// # Definición
9///```
10///pub struct Config{
11///  pub consulta: String,
12///  pub ruta:     String,
13///  pub distinguir: bool,
14///}
15///```
16pub struct Config{
17  pub consulta: String,
18  pub ruta:     String,
19  pub distinguir: bool,
20}
21
22impl Config{
23  ///Inicializador de la estructura Config.
24  ///# Ejemplo
25  ///```
26  ///use std::env;
27  ///use std::process;
28  ///use minigrip::Config;
29  /// 
30  ///let config = Config::build(env::args()).unwrap_or_else(|err|{
31  ///  eprintln!("Problema pasando argumentos: {err}");
32  ///  process::exit(1);
33  ///});
34  ///``` 
35  pub fn build(mut args: impl Iterator<Item = String>) -> Result<Config, &'static str>{
36    args.next();
37
38    let consulta = match args.next(){
39      Some(arg) => arg,
40      None => return Err("No se especificó el texto de búsqueda"),
41    };
42    let ruta = match args.next(){
43      Some(arg) => arg,
44      None => return Err("No se especificó la ruta del archivo"),
45    };
46
47    let distinguir = env::var("IGNORE_CASE").is_ok();
48    
49    Ok(Config{consulta, ruta, distinguir})
50  }
51}
52
53///Ejecuta la lógica del programa.
54///# Ejemplo
55///```
56///use std::env;
57///use std::process;
58///use minigrip::Config;
59/// 
60///let config = Config::build(env::args()).unwrap_or_else(|err|{
61///  eprintln!("Problema pasando argumentos: {err}");
62///  process::exit(1);
63///});
64///if let Err(e) = minigrep::run(config) {
65///  eprintln!("Error: {e}");
66///  process::exit(1)
67///} 
68///``` 
69pub fn run(config: Config) -> Result<(), Box<dyn Error>>{
70  let contenido = fs::read_to_string(config.ruta)?;
71  
72  let resultado = if config.distinguir{
73    busqueda(&config.consulta, &contenido)
74  }else{
75    buscar_distinguido(&config.consulta, &contenido)
76  };
77  
78  for linea in resultado{
79    println!("{linea}");
80  }
81  Ok(())
82}
83
84fn busqueda<'a>(consulta: &str, contenido: &'a str) -> Vec<&'a str>{
85  contenido
86    .lines()
87    .filter(
88      |linea| 
89        linea.contains(consulta)
90    )
91    .collect()
92}
93
94fn buscar_distinguido<'a>(consulta: &str, contenido: &'a str) -> Vec<&'a str>{
95  let consulta = consulta.to_lowercase();
96  contenido
97    .lines()
98    .filter(
99      |linea| 
100        linea.to_lowercase().contains(&consulta)
101    )
102    .collect()
103}
104
105#[cfg(test)]
106mod test{
107  use super::*;
108
109  #[test]
110  fn un_resultado() {
111    let consulta = "duct";
112    let contenido = "\
113Rust:
114safe, fast, productive.
115Pick three.";
116    
117    assert_eq!(vec!["safe, fast, productive."], busqueda(consulta, contenido));
118  }
119
120  #[test]
121  fn distinguido() {
122    let consulta = "duct";
123    let contenido = "\
124Rust:
125safe, fast, productive.
126Pick three.
127Duct tape.";
128    
129    assert_eq!(vec!["safe, fast, productive."], busqueda(consulta, contenido));
130  }
131
132  #[test]
133  fn no_distinguido() {
134    let consulta = "rUsT";
135    let contenido = "\
136Rust:
137safe, fast, productive.
138Pick three.
139Trust me.";
140    
141    assert_eq!(vec!["Rust:", "Trust me."], buscar_distinguido(consulta, contenido));
142  }
143}