Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Are you nobody, too?
How dreary to be somebody!
114 changes: 114 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
use std::error::Error;
use std::fs;
use std::env;

pub struct Config {
pub query: String,
pub filename: 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(arg) => arg,
None => return Err("Didn't get a query string"),
};

let filename = match args.next() {
Some(arg) => arg,
None => return Err("Didn't get a file path"),
};

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

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

pub fn new(args: &[String]) -> Result<Config, &'static str> {
if args.len() < 3 {
return Err("not enough arguments");
}
let query = args[1].clone();
let filename = args[2].clone();

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

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

pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
let contents = fs::read_to_string(config.filename)?;

let results = if config.ignore_case {
search_case_insensitive(&config.query, &contents)
} else {
search(&config.query, &contents)
};

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

Ok(())
}

pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
contents
.lines()
.filter(|line| line.contains(query))
.collect()
}

pub fn search_case_insensitive<'a>(
query: &str,
contents: &'a str,
) -> Vec<&'a str> {
contents
.lines()
.filter(|line| line.contains(&query.to_lowercase()))
.collect()
}

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

#[test]
fn case_sensitive() {
let query = "duct";
let contents = "\
Rust:
safe, fast, productive.
Pick three.
Duct tape.";
assert_eq!(vec!["safe, fast, productive."], search(query, contents));
}

#[test]
fn case_insensitive() {
let query = "rUsT";
let contents = "\
Rust:
safe, fast, productive.
Pick three.
Trust me.";
assert_eq!(
vec!["Rust:", "Trust me."],
search_case_insensitive(query, contents)
);
}
}
34 changes: 9 additions & 25 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,17 @@
use std::{env, fs};
use std::{env, process};

use minigrep::Config;

fn main() {
let args: Vec<String> = env::args().collect();

let config = Config::new(&args);

println!("Searching for {}", config.query);
println!("In file {}", config.filename);
let config = Config::build(env::args()).unwrap_or_else(|err| {
eprintln!("Problem parsing arguments: {err}");
process::exit(1);
});

let contents = fs::read_to_string(config.filename)
.expect("Something went wrong reading the file");

println!("With text:\n{}", contents);
}

struct Config {
query: String,
filename: String,
}

impl Config {
fn new(args: &[String]) -> Config {
if args.len() < 3 {
panic!("not anough arguments");
}
let query = args[1].clone();
let filename = args[2].clone();

Config {query, filename}
if let Err(e) = minigrep::run(config) {
eprintln!("Application error: {e}");
process::exit(1);
}
}