From 7edc8740619600dc57ab61a0a619e41a0d69898d Mon Sep 17 00:00:00 2001 From: runebaas Date: Thu, 31 Oct 2019 01:14:46 +0100 Subject: [PATCH] Allow multiple cookie files, add the -c parameter and improve error handling --- .gitignore | 1 + src/main.rs | 38 ++++++++++++++-------- src/utils/fortunes_reader.rs | 61 ++++++++++++++++++++++++++++++++++-- src/utils/helpers.rs | 15 +++++++++ src/utils/mod.rs | 1 + src/utils/options_parser.rs | 3 ++ 6 files changed, 103 insertions(+), 16 deletions(-) create mode 100644 src/utils/helpers.rs diff --git a/.gitignore b/.gitignore index ebdff5a..dec33ba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target **/*.rs.bk /.idea +/cookies diff --git a/src/main.rs b/src/main.rs index a8c3d82..514f3ce 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,6 @@ mod utils; use crate::utils::*; use clap::{App, Arg}; -use rand::prelude::*; fn main() { // specify app @@ -48,11 +47,23 @@ fn main() { .arg(Arg::with_name("case_insensitive") .short("i") .help("Ignore case for -m patterns. ") + .takes_value(false)) + .arg(Arg::with_name("show_cookie") + .short("c") + .help("Show the cookie file from which the fortune came.") .takes_value(false)); let options = options_parser::parse(app); // get fortunes - let mut fortunes = fortunes_reader::get_all(options.filename.clone()); + let cookie = match fortunes_reader::get_random_cookie() { + Some(fortunes) => fortunes, + None => { + println!("No fortune files found"); + std::process::exit(1); + } + }; + + let mut fortunes = cookie.fortunes; // filter by max length if options.short_fortunes || options.long_fortunes { @@ -65,7 +76,18 @@ fn main() { } // get a random one - let the_fortune = get_random_fortune(fortunes); + let the_fortune = match helpers::get_random_from_vec(fortunes) { + Some(f) => f, + None => { + println!("No fortunes found with these parameters"); + std::process::exit(1); + } + }; + + // reveal the cookie + if options.show_cookie { + println!("({})\n%", cookie.name); + } // print it ✨ println!("{}", the_fortune); @@ -74,13 +96,3 @@ fn main() { waiter::wait(the_fortune) } } - -fn get_random_fortune(fortunes: Vec) -> String { - let total_fortunes = fortunes.len(); - if total_fortunes == 0 { - return "No Fortunes found with these parameters...".to_owned(); - } - let random_fortune = rand::thread_rng().gen_range(0, total_fortunes); - - fortunes.get(random_fortune).unwrap().trim().to_owned() -} diff --git a/src/utils/fortunes_reader.rs b/src/utils/fortunes_reader.rs index 8482f7a..6a1bb37 100644 --- a/src/utils/fortunes_reader.rs +++ b/src/utils/fortunes_reader.rs @@ -1,12 +1,67 @@ +use crate::utils::helpers::{get_random_from_vec, own_vec}; use std::{fs, path, process}; -pub fn get_all(filename: String) -> Vec { +pub fn get_random_cookie() -> Option { + let fortune_files = find_fortune_files(); + if let Some(selected_file) = get_random_from_vec(fortune_files) { + let fortunes = read_fortune_file(&selected_file); + let cookie = Cookie { + name: selected_file, + fortunes, + }; + Some(cookie) + } else { + None + } +} + +fn find_fortune_files() -> Vec { + let locations = get_paths(); + let mut all_files: Vec = vec![]; + + for loc in locations { + let full_path = path::Path::new(&loc); + if full_path.exists() { + if let Ok(files) = fs::read_dir(full_path.canonicalize().unwrap()) { + for file in files { + if let Ok(f) = file { + if is_fortfile(&f.path().to_str().unwrap()) { + all_files.push(f.path().to_str().unwrap().to_owned()); + } + } + } + } + } + } + + all_files +} + +fn is_fortfile(path: &str) -> bool { + !path.contains('.') +} + +fn read_fortune_file(filename: &str) -> Vec { if !path::Path::new(&filename).exists() { println!("File '{}' does not found", filename); process::exit(1); } let fortune_file = fs::read_to_string(filename).expect("Cannot read fortune file"); - let fortunes: Vec = fortune_file.split('%').map(ToOwned::to_owned).collect(); - fortunes + fortune_file.split('%').map(ToOwned::to_owned).collect() +} + +#[cfg(windows)] +fn get_paths() -> Vec { + own_vec(vec!["./fortunes", "./cookies"]) +} + +#[cfg(unix)] +fn get_paths() -> Vec { + own_vec(vec!["./fortunes", "./cookies", "/lib/share/games/fortunes"]) +} + +pub struct Cookie { + pub name: String, + pub fortunes: Vec, } diff --git a/src/utils/helpers.rs b/src/utils/helpers.rs new file mode 100644 index 0000000..b055bf1 --- /dev/null +++ b/src/utils/helpers.rs @@ -0,0 +1,15 @@ +use rand::*; + +pub fn get_random_from_vec(vector: Vec) -> Option { + let length = vector.len(); + if length == 0 { + return None; + } + let random_element = rand::thread_rng().gen_range(0, length); + + Some(vector.get(random_element).unwrap().trim().to_owned()) +} + +pub fn own_vec(input: Vec<&str>) -> Vec { + input.into_iter().map(ToOwned::to_owned).collect() +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index d6d76c1..f548cae 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,3 +1,4 @@ pub mod fortunes_reader; +pub mod helpers; pub mod options_parser; pub mod waiter; diff --git a/src/utils/options_parser.rs b/src/utils/options_parser.rs index 899f21d..8011703 100644 --- a/src/utils/options_parser.rs +++ b/src/utils/options_parser.rs @@ -17,6 +17,7 @@ pub fn parse(app: App) -> Parameters { None => String::new(), }, case_insensitive: matches.is_present("case_insensitive"), + show_cookie: matches.is_present("show_cookie"), }; options @@ -33,4 +34,6 @@ pub struct Parameters { pub pattern: String, pub case_insensitive: bool, + + pub show_cookie: bool, }