rndmator 0.1.0

Command-line utility to toss a coin, roll dice and randomly choose from a list.
Documentation
use clap::{App, AppSettings, Arg};
use regex::Regex;
use rndmator::{choose_from_list, coin_toss, random_number, roll_dice};

fn main() {
    let range_validator = Regex::new(r"^(\d+)\.\.(\d+)$").unwrap();

    let opts = App::new("rndmator")
        .version(env!("CARGO_PKG_VERSION"))
        .author(env!("CARGO_PKG_AUTHORS"))
        .about("Command-line utility to randomly choose from a list, roll dice or toss a coin.")
        .setting(AppSettings::ArgRequiredElseHelp)
        .setting(AppSettings::ColoredHelp)
        .arg(
            Arg::new("repeat")
                .global(true)
                .about("Repeat action <n> number of times")
                .short('r')
                .long("repeat")
                .value_name("n")
                .takes_value(true)
                .validator(|n| match n.parse::<u8>() {
                    Ok(_) => Ok(()),
                    Err(_) => Err(String::from("Value provided is not a valid number.")),
                }),
        )
        .subcommand(
            App::new("list")
                .about("Randomly choose an item from a list")
                .short_flag('l')
                .arg(
                    Arg::new("LIST")
                        .about("The list to choose an item from")
                        .required(true)
                        .index(1),
                )
                .arg(
                    Arg::new("amount")
                        .short('a')
                        .long("amount")
                        .about("Amount of items to choose from list")
                        .default_value("1")
                        .takes_value(true),
                )
                .arg(
                    Arg::new("delimiter")
                        .short('d')
                        .long("delim")
                        .about("The delimiter used to separate items")
                        .default_value(",")
                        .takes_value(true),
                ),
        )
        .subcommand(
            App::new("coin").about("Toss a coin").short_flag('c').arg(
                Arg::new("tosses")
                    .short('t')
                    .long("tosses")
                    .about("Number of tosses")
                    .default_value("1")
                    .takes_value(true),
            ),
        )
        .subcommand(
            App::new("dice").about("Roll a dice").short_flag('d').arg(
                Arg::new("sides")
                    .short('s')
                    .long("sides")
                    .about("Number of sides of the dice")
                    .default_value("6")
                    .takes_value(true),
            ),
        )
        .subcommand(
            App::new("number")
                .about("Random number between range")
                .short_flag('n')
                .arg(
                    Arg::new("RANGE")
                        .index(1)
                        .about("Range to choose from. e.g. 1..10")
                        .required(true)
                        .validator(|range| {
                            if range_validator.is_match(range) {
                                return Ok(());
                            }
                            Err(String::from("Value doesn't match the format of 1..10"))
                        }),
                ),
        )
        .get_matches();

    let mut repeat: u8 = 1;

    if let Some(r) = opts.value_of("repeat") {
        repeat = r.parse().unwrap();
    }

    (1..=repeat).for_each(|_| {
        if let Some(ref matches) = opts.subcommand_matches("list") {
            if let Some(list) = matches.value_of("LIST") {
                let delimiter = match matches.value_of("delimiter") {
                    Some(delimiter) => delimiter,
                    None => ",",
                };
                let amount: u8 = match matches.value_of("amount") {
                    Some(amount) => match amount.parse() {
                        Ok(amount) => amount,
                        Err(_) => 1,
                    },
                    None => 1,
                };
                let items: Vec<&str> = list.split(delimiter).collect();
                choose_from_list(&items, amount);
            }
        }

        if let Some(ref matches) = opts.subcommand_matches("coin") {
            if let Some(tosses) = matches.value_of("tosses") {
                let tosses: u8 = tosses.parse().unwrap();
                coin_toss(tosses);
            }
        }

        if let Some(ref matches) = opts.subcommand_matches("dice") {
            if let Some(sides) = matches.value_of("sides") {
                let sides: f32 = sides.parse().unwrap();
                roll_dice(sides);
            }
        }

        if let Some(ref matches) = opts.subcommand_matches("number") {
            if let Some(range) = matches.value_of("RANGE") {
                if let Some(captures) = range_validator.captures(range) {
                    let lower_bound: u16 = captures.get(1).unwrap().as_str().parse().unwrap();
                    let upper_bound: u16 = captures.get(2).unwrap().as_str().parse().unwrap();
                    random_number(lower_bound, upper_bound);
                }
            }
        }
    });
}