pub struct CliParser<'a> { /* private fields */ }Expand description
CLI argument parser
Parses command-line arguments according to a CommandDefinition.
The parser handles both positional arguments and named options
with type conversion and validation.
§Lifetime
The parser holds a reference to a CommandDefinition and therefore
has a lifetime parameter 'a that must outlive the parser.
§Example
use dynamic_cli::parser::cli_parser::CliParser;
use dynamic_cli::config::schema::{
CommandDefinition, OptionDefinition, ArgumentType
};
use std::collections::HashMap;
let definition = CommandDefinition {
name: "test".to_string(),
aliases: vec![],
description: "Test command".to_string(),
required: false,
arguments: vec![],
options: vec![
OptionDefinition {
name: "verbose".to_string(),
short: Some("v".to_string()),
long: Some("verbose".to_string()),
option_type: ArgumentType::Bool,
required: false,
default: Some("false".to_string()),
description: "Verbose output".to_string(),
choices: vec![],
repeatable: false,
option_parameters: HashMap::new(),
}
],
implementation: "handler".to_string(),
continue_on_failure: false,
requires_success: false,
};
let parser = CliParser::new(&definition);
let args = vec!["-v".to_string()];
let parsed = parser.parse(&args).unwrap();
assert_eq!(parsed.get("verbose"), Some(&"true".to_string()));Implementations§
Source§impl<'a> CliParser<'a>
impl<'a> CliParser<'a>
Sourcepub fn new(definition: &'a CommandDefinition) -> Self
pub fn new(definition: &'a CommandDefinition) -> Self
Sourcepub fn parse(&self, args: &[String]) -> Result<HashMap<String, String>>
pub fn parse(&self, args: &[String]) -> Result<HashMap<String, String>>
Parse command-line arguments into a HashMap of strings
Thin, non-breaking wrapper around Self::parse_typed for callers
that only deal in scalar values. Any ParsedValue::Repeated entry
(i.e. any repeatable: true option) is silently dropped from the
result — no command definition predating DD-024 can have one, so
existing callers see no behaviour change. Once the dispatch layer
is migrated to consume crate::parser::ParsedArgs directly
(#39, in progress — the type exists but interface/cli.rs and
interface/repl.rs still call this method, not parse_typed),
this method can be removed.
§Arguments
args- Slice of argument strings (excluding the command name)
§Returns
A HashMap mapping argument/option names to their string values. All values are stored as strings after type validation.
§Errors
ParseError::MissingArgumentif required arguments are missingParseError::MissingOptionif required options are missingParseError::UnknownOptionif an unrecognized option is providedParseError::TypeParseErrorif a value cannot be converted to its expected typeParseError::TooManyArgumentsif more positional arguments than expected
§Example
use dynamic_cli::parser::cli_parser::CliParser;
use dynamic_cli::config::schema::{
CommandDefinition, ArgumentDefinition, ArgumentType
};
let definition = CommandDefinition {
name: "greet".to_string(),
aliases: vec![],
description: "Greet someone".to_string(),
required: false,
arguments: vec![
ArgumentDefinition {
name: "name".to_string(),
arg_type: ArgumentType::String,
required: true,
description: "Name".to_string(),
validation: vec![],
secure: false,
}
],
options: vec![],
implementation: "handler".to_string(),
continue_on_failure: false,
requires_success: false,
};
let parser = CliParser::new(&definition);
let result = parser.parse(&["Alice".to_string()]).unwrap();
assert_eq!(result.get("name"), Some(&"Alice".to_string()));Sourcepub fn parse_typed(
&self,
args: &[String],
) -> Result<HashMap<String, ParsedValue>>
pub fn parse_typed( &self, args: &[String], ) -> Result<HashMap<String, ParsedValue>>
Parse command-line arguments into a HashMap of ParsedValue
Like Self::parse, but preserves repeatable options as
ParsedValue::Repeated instead of dropping them. This is the
method that actually implements DD-024 parsing; parse() is a
filtering wrapper around it.
§Arguments
args- Slice of argument strings (excluding the command name)
§Errors
In addition to the errors documented on Self::parse:
ParseError::UnknownDiscriminantif the token following a repeatable option’s flag is not in that option’schoicesParseError::UnknownOptionParameterif akey=valuepair uses a key not declared inoption_parameters[discriminant]ParseError::MissingRequiredOptionParameterif a required key is absent from an occurrenceParseError::DuplicateOptionOccurrenceif the same discriminant is supplied twice with identicalkey=valuepairs
Sourcepub fn parse_typed_segment(
&self,
args: &[String],
) -> Result<(HashMap<String, ParsedValue>, usize)>
pub fn parse_typed_segment( &self, args: &[String], ) -> Result<(HashMap<String, ParsedValue>, usize)>
Parse command-line arguments, stopping cleanly at a segment boundary instead of erroring on positional-arity overflow (DD-026, #52).
Shares Self::parse_typed’s token loop and every option-parsing
helper it calls (Self::parse_long_option, Self::parse_short_option,
Self::parse_repeatable_occurrence) unchanged. The only
difference is what happens when a bare (non-flag) token is reached
once positional_index has already reached
self.definition.arguments.len(): where Self::parse_typed
calls Self::parse_positional_argument and gets back
crate::error::ParseError::too_many_arguments, this method stops
the loop immediately instead — without consuming that token,
without erroring — then runs the same finishing steps
(apply_defaults / validate_required_arguments /
validate_required_options) on whatever was accumulated so far.
Self::parse_typed itself is not modified by this method’s
existence: it keeps calling Self::parse_positional_argument
directly and erroring immediately on overflow, so Self::parse
and any existing caller keep today’s exact behaviour.
§Returns
(parsed, consumed), where consumed is the number of tokens of
args that belong to this command. When the loop reaches the end
of args with no leftover boundary token (the single-command,
non-chained case), consumed == args.len() and parsed is
identical to what Self::parse_typed would return for the same
input.
§Errors
Same as Self::parse_typed for every case other than
positional-arity overflow, which this method never raises — an
overflowing bare token is reported to the caller via consumed
instead, for crate::registry::CommandRegistry::resolve_name to
resolve as the next chain segment.
§Example
use dynamic_cli::parser::cli_parser::{CliParser, ParsedValue};
use dynamic_cli::config::schema::{
CommandDefinition, ArgumentDefinition, ArgumentType
};
let definition = CommandDefinition {
name: "config".to_string(),
aliases: vec![],
description: "Configure a source".to_string(),
required: false,
arguments: vec![
ArgumentDefinition {
name: "source".to_string(),
arg_type: ArgumentType::Path,
required: true,
description: "Source file".to_string(),
validation: vec![],
secure: false,
}
],
options: vec![],
implementation: "config_handler".to_string(),
continue_on_failure: false,
requires_success: false,
};
let parser = CliParser::new(&definition);
// "solve" is the next chained command's name — arity for "config"
// (one positional) is already satisfied by "model.yml".
let args = vec!["model.yml".to_string(), "solve".to_string()];
let (parsed, consumed) = parser.parse_typed_segment(&args).unwrap();
assert_eq!(consumed, 1);
assert_eq!(
parsed.get("source"),
Some(&ParsedValue::Scalar("model.yml".to_string()))
);Auto Trait Implementations§
impl<'a> Freeze for CliParser<'a>
impl<'a> RefUnwindSafe for CliParser<'a>
impl<'a> Send for CliParser<'a>
impl<'a> Sync for CliParser<'a>
impl<'a> Unpin for CliParser<'a>
impl<'a> UnsafeUnpin for CliParser<'a>
impl<'a> UnwindSafe for CliParser<'a>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more