num2words 1.2.0

Convert numbers like 42 to forty-two
Documentation
use ::num2words::{Currency, Lang, Num2Words};
use std::env;
use std::str::FromStr;

const HELP: &str = r#"NAME:
    num2words - convert numbers into words

USAGE:
    num2words <number> [options]
    num2words --help

VERSION:
    {{VERSION}}

COMMANDS:
GLOBAL OPTIONS:
    -l, --lang [value]          set language (default: "en")
    -t, --to [output]           set output (default: "cardinal")
    -p, --prefer [preference]   add a language preference (default: none)
    -h, --help                  show help
    -v, --version               print the version

AVAILABLE LANGUAGES:
    en:      English
    fr:      French (France and Canada)
    fr_BE:   French (Belgium and the Democratic Republic of the Congo)
    fr_CH:   French (Swiss Confederation and Aosta Valley)
    uk:      Ukrainian

AVAILABLE OUTPUTS:
    cardinal:      forty-two (42)
    ordinal:       forty-second (42)
    ordinal_num:   42nd (42)
    year:          nineteen oh-one (1901)
    currency:      forty-two dollars and one cent (42.01)

AVAILABLE CURRENCIES:
    ISO 4217 code      - USD, EUR, GBP, etc.
    generic currencies - DINAR, DOLLAR, PESO, RIYAL"#;

fn get_version() -> String {
    let version = env!("CARGO_PKG_VERSION");
    let mut words = vec![];

    for num in version.split('.') {
        if let Ok(i) = String::from(num).parse::<i64>() {
            if let Ok(word) = Num2Words::new(i).prefer("oh").to_words() {
                words.push(word);
            }
        }
    }

    format!("v{} (version {})", version, words.join(" point "))
}

fn help() {
    println!("{}", HELP.replace("{{VERSION}}", get_version().as_str()))
}

fn handle_cmd(n: String, mut args: std::env::Args) {
    if let Some(mut num) = Num2Words::parse(&n) {
        while let Some(arg) = args.next() {
            match arg.as_str() {
                "--lang" | "-l" => match args.next() {
                    Some(l) => {
                        if let Ok(v) = Lang::from_str(l.as_str()) {
                            num = num.lang(v);
                        } else {
                            eprintln!("Error: invalid language");
                            return;
                        }
                    }
                    None => {
                        help();
                        return;
                    }
                },
                "--prefer" | "-p" => match args.next() {
                    Some(p) => num = num.prefer(p),
                    None => {
                        help();
                        return;
                    }
                },
                "--to" | "-t" => match args.next() {
                    Some(t) => {
                        if let Ok(v) = Currency::from_str(t.as_str()) {
                            num = num.currency(v);
                        } else {
                            match t.as_str() {
                                "cardinal" => {
                                    num = num.cardinal();
                                }
                                "ordinal" => {
                                    num = num.ordinal();
                                }
                                "ordinal_num" => {
                                    num = num.ordinal_num();
                                }
                                "year" => {
                                    num = num.year();
                                }
                                _ => {
                                    eprintln!("Error: invalid to tag");
                                    return;
                                }
                            }
                        }
                    }
                    None => {
                        help();
                        return;
                    }
                },
                _ => continue,
            }
        }

        match num.to_words() {
            Ok(v) => println!("{}", v),
            Err(err) => eprintln!("Error: {}", err),
        }
    } else {
        eprintln!("Error: cannot parse number");
    }
}

fn main() {
    let mut args = env::args();
    args.next();

    match args.next() {
        Some(num) => match num.as_str() {
            "--help" | "-h" => help(),
            "--version" | "-v" => {
                println!("{} {}", env!("CARGO_PKG_NAME"), get_version())
            }
            _ => handle_cmd(num, args),
        },
        None => help(),
    }
}