Files
gh-vanman2024-cli-builder-p…/skills/clap-patterns/templates/value-parser.rs
2025-11-30 09:04:14 +08:00

110 lines
2.8 KiB
Rust

/// Value Parser Template with Custom Validation
///
/// This template demonstrates:
/// - Custom value parsers
/// - Range validation
/// - Format validation (regex)
/// - Error handling with helpful messages
use clap::Parser;
use std::ops::RangeInclusive;
const PORT_RANGE: RangeInclusive<usize> = 1..=65535;
/// Parse and validate port number
fn port_in_range(s: &str) -> Result<u16, String> {
let port: usize = s
.parse()
.map_err(|_| format!("`{}` isn't a valid port number", s))?;
if PORT_RANGE.contains(&port) {
Ok(port as u16)
} else {
Err(format!(
"port not in range {}-{}",
PORT_RANGE.start(),
PORT_RANGE.end()
))
}
}
/// Validate email format (basic validation)
fn validate_email(s: &str) -> Result<String, String> {
if s.contains('@') && s.contains('.') && s.len() > 5 {
Ok(s.to_string())
} else {
Err(format!("`{}` is not a valid email address", s))
}
}
/// Parse percentage (0-100)
fn parse_percentage(s: &str) -> Result<u8, String> {
let value: u8 = s
.parse()
.map_err(|_| format!("`{}` isn't a valid number", s))?;
if value <= 100 {
Ok(value)
} else {
Err("percentage must be between 0 and 100".to_string())
}
}
/// Validate directory exists
fn validate_directory(s: &str) -> Result<std::path::PathBuf, String> {
let path = std::path::PathBuf::from(s);
if path.exists() && path.is_dir() {
Ok(path)
} else {
Err(format!("directory does not exist: {}", s))
}
}
#[derive(Parser)]
#[command(name = "validator")]
#[command(about = "CLI with custom value parsers and validation")]
struct Cli {
/// Port number (1-65535)
#[arg(short, long, value_parser = port_in_range)]
port: u16,
/// Email address
#[arg(short, long, value_parser = validate_email)]
email: String,
/// Success threshold percentage (0-100)
#[arg(short, long, value_parser = parse_percentage, default_value = "80")]
threshold: u8,
/// Working directory (must exist)
#[arg(short, long, value_parser = validate_directory)]
workdir: Option<std::path::PathBuf>,
/// Number of retries (1-10)
#[arg(
short,
long,
default_value = "3",
value_parser = clap::value_parser!(u8).range(1..=10)
)]
retries: u8,
}
fn main() {
let cli = Cli::parse();
println!("Configuration:");
println!(" Port: {}", cli.port);
println!(" Email: {}", cli.email);
println!(" Threshold: {}%", cli.threshold);
println!(" Retries: {}", cli.retries);
if let Some(workdir) = cli.workdir {
println!(" Working directory: {}", workdir.display());
}
// Your application logic here
println!("\nValidation passed! All inputs are valid.");
}