random_name_generator 0.4.0

Random Name Generator
Documentation
use clap::{Arg, ArgAction, ArgMatches, command};
use rnglib::{Language, RNG, RNGError};

static HELP_TEMPLATE: &str = "{about} {version}

Usage: rng

Options:
{options}
";

fn main() -> Result<(), RNGError> {
    let matches = cmd().get_matches();

    let count: usize = *get_number(&matches).ok_or(RNGError::ParsingError)?;
    let rng = get_rng(&matches)?;

    if matches.get_flag("no-prefix") {
        println!(
            "{}",
            rng.generate_names_string(count, matches.get_flag("short"))
        );
    } else {
        println!(
            "{}: {}",
            rng.name,
            rng.generate_names_string(count, matches.get_flag("short"))
        );
    }

    Ok(())
}

#[allow(clippy::too_many_lines)]
fn cmd() -> clap::Command {
    command!()
        .help_template(HELP_TEMPLATE)
        .arg(
            Arg::new("demonic")
                .short('d')
                .long("demonic")
                .required(false)
                .action(ArgAction::SetTrue),
        )
        .arg(
            Arg::new("elven")
                .short('e')
                .long("elven")
                .required(false)
                .action(ArgAction::SetTrue),
        )
        .arg(
            Arg::new("fantasy")
                .short('f')
                .long("fantasy")
                .required(false)
                .action(ArgAction::SetTrue),
        )
        .arg(
            Arg::new("goblin")
                .short('g')
                .long("goblin")
                .required(false)
                .action(ArgAction::SetTrue),
        )
        .arg(
            Arg::new("klingon")
                .short('k')
                .long("klingon")
                .required(false)
                .action(ArgAction::SetTrue),
        )
        .arg(
            Arg::new("roman")
                .short('r')
                .long("roman")
                .required(false)
                .action(ArgAction::SetTrue),
        )
        .arg(
            Arg::new("curse")
                .short('c')
                .long("curse")
                .required(false)
                .action(ArgAction::SetTrue)
                .help("[UNDER CONSTRUCTION]"),
        )
        .arg(
            Arg::new("german-curse")
                .long("german-curse")
                .required(false)
                .action(ArgAction::SetTrue)
                .help("[UNDER CONSTRUCTION]"),
        )
        .arg(
            Arg::new("flipmode")
                .short('x')
                .long("flipmode")
                .required(false)
                .action(ArgAction::SetTrue)
                .help("Flipmode is the greatest! (Random language)"),
        )
        .arg(
            Arg::new("russian")
                .long("russian")
                .required(false)
                .action(ArgAction::SetTrue)
                .help("Use Russian language file, if available"),
        )
        .arg(
            Arg::new("short")
                .long("short")
                .required(false)
                .action(ArgAction::SetTrue)
                .help("Creates shorter names"),
        )
        .arg(
            Arg::new("raw")
                .long("raw")
                .required(false)
                .value_name("FILE")
                .help("Reads in a raw language file"),
        )
        .arg(
            Arg::new("no-prefix")
                .short('p')
                .long("no-prefix")
                .required(false)
                .action(ArgAction::SetTrue)
                .help("Don't print language chosen (for use with -x)"),
        )
        .arg(
            Arg::new("number")
                .short('n')
                .long("number")
                .required(false)
                .default_value("2")
                .value_parser(clap::value_parser!(usize))
                .help("Number of names created."),
        )
        .arg_required_else_help(true)
}

fn get_number(matches: &ArgMatches) -> Option<&usize> {
    matches
        .try_get_one::<usize>("number")
        .expect("Could not read a threshold value")
}

fn get_rng(matches: &ArgMatches) -> Result<RNG, RNGError> {
    let is_russian = matches.get_flag("russian");

    if matches.get_flag("demonic") {
        RNG::try_from(&Language::Demonic)
    } else if matches.get_flag("elven") {
        filter_russian(is_russian, &Language::Elven, &Language::Эльфийский)
    } else if matches.get_flag("fantasy") {
        filter_russian(is_russian, &Language::Fantasy, &Language::Фантазия)
    } else if matches.get_flag("goblin") {
        filter_russian(is_russian, &Language::Goblin, &Language::Гоблин)
    } else if matches.get_flag("klingon") {
        RNG::try_from(&Language::Klingon)
    } else if matches.get_flag("roman") {
        filter_russian(is_russian, &Language::Roman, &Language::Римский)
    } else if matches.get_flag("curse") {
        RNG::try_from(&Language::Curse)
    } else if matches.get_flag("german-curse") {
        RNG::try_from(&Language::GermanCurse)
    } else if matches.get_flag("flipmode") {
        Ok(RNG::random())
    } else {
        let raw = matches
            .get_one::<String>("raw")
            .ok_or(RNGError::ParsingError)?;
        RNG::new_from_file(raw.clone())
    }
}

fn filter_russian(
    is_russian: bool,
    english: &Language,
    russian: &Language,
) -> Result<RNG, RNGError> {
    if is_russian {
        RNG::try_from(russian)
    } else {
        RNG::try_from(english)
    }
}

#[test]
fn verify_cmd() {
    cmd().debug_assert();
}