NAME

App::karr::Role::CliArgs - Role providing option-aware CLI positional-argument parsing

VERSION

version 0.600

DESCRIPTION

This role recovers the real positional arguments from the argv MooX::Cmd echoes back into a command's execute(). Because MooX::Options runs with protect_argv, that argv still holds every original token -- option flags, the values they consumed, and the positionals -- in their original order. positional_args subtracts the option tokens back out (using the consuming command's own _options_data) to yield the positionals, and check_positional_args rejects surplus positionals before a command does any work. A bare -- ends option processing, so everything after it is a positional however option-shaped it looks.

The same walk answers one question earlier in the run: normalize_option_argv respells the option flags in an argv with underscores, which bin/karr does before MooX::Cmd dispatches so that a dashed option name survives whatever stands in front of it.

Command classes provide _options_data and _options_config via MooX::Options.

positional_args

my @positional = $self->positional_args($args_ref);

In a command class that composes this role, recovers the real positional arguments from $args_ref -- the argv MooX::Cmd echoes back into execute(), which under protect_argv still holds every original token: recognised option flags, the values they consumed, and the positionals, in their original order. Returns the positionals only, in order, as plain strings. An abbreviated option consumes its value exactly as its full spelling does, so karr edit 1 --prio high yields the same single positional as karr edit 1 --priority high; a dash-prefixed token that abbreviates nothing consumes nothing (a genuine typo is already rejected upstream by MooX::Options). A bare -- ends option processing, so every token after it is returned as a positional however option-shaped it looks. Never dies -- an argument list with no positionals returns an empty list.

normalize_option_argv

@ARGV = $class->normalize_option_argv(\@ARGV);

Returns $args_ref in the spelling that survives MooX::Options in every argv position (tickets #256 and #259). Two things change and nothing else does:

  • Every long option flag is respelled with underscores -- --claimed-by becomes --claimed_by. Both spellings mean the same option to karr; only this one reaches Getopt::Long intact from behind another flag.

  • A value that looks like a flag is joined to its own option with an =, so --body --we-ird comes back as one token, --body=--we-ird. The value is unchanged -- it keeps its dashes, and that is the point: as a separate token it could still be folded when something recognised stands one place in front of the option. A declared short alias is resolved to its long name to carry the value (-a --we-ird becomes --append_body=--we-ird), because -a=VALUE is not an assignment to Getopt::Long; an abbreviation keeps its own spelling.

Positionals, options whose value is not flag-shaped, an option that already carries its value inline, and every token after a bare -- are returned untouched. It reads the option table and nothing else, so unlike the two methods above it is called as a class method, before any command object exists: bin/karr runs it over argv for the command class MooX::Cmd is about to dispatch to, and bin/karr-foundation over its own.

check_positional_args

$self->check_positional_args($args_ref, $max);

In a command class that composes this role, dies with a usage message ("unexpected extra argument(s): '...'\n", followed by the command's usage string if it has one) when $args_ref resolves to more than $max positionals via "positional_args"; otherwise returns nothing. The message starts with the unexpected extra argument marker "is_usage_error" in App::karr::Error recognises, so bin/karr's central handler exits 2 (ADR 0002), not 1. There is no minimum-arity check here -- a missing required positional is each command's own concern -- this only rejects surplus. Call it before a command does any work: kanban-md's cobra Args validators run before RunE the same way, and karr's batch commands rely on the comma list (parsed by "parse_ids" in App::karr::Role::BoardAccess) as the one and only way to pass more than one id, so a second bare positional is always a mistake rather than an alternate batch syntax.

SUPPORT

Issues

Please report bugs and feature requests on GitHub at https://github.com/Getty/karr/issues.

IRC

Join #langertha on irc.perl.org or message Getty directly.

CONTRIBUTING

Contributions are welcome! Please fork the repository and submit a pull request.

AUTHOR

Torsten Raudssus <getty@cpan.org>

COPYRIGHT AND LICENSE

This software is Copyright (c) 2026 by Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/.

This is free software, licensed under:

The Artistic License 2.0 (GPL Compatible)