package Getopt::Dakkar::Role::Command;
use Getopt::Dakkar::Style qw(role);
with 'Getopt::Dakkar::Role::Piece';
has options => ( is => 'ro', isa => ArrayRef, default => sub { [] } );
has parameters => ( is => 'ro', isa => ArrayRef, default => sub { [] } );
has subcommands => ( is => 'ro', isa => ArrayRef, default => sub { [] } );
sub parse($self,$args,$stash) {
my $stash = $self->_parse($args,$stash);
if (my $op = $self->op) {
return $stash->$op();
}
return $stash;
}
sub _parse($self,$args,$stash) {
my $argpack = Getopt::Dakkar::ArgPack->new({getopt=>$self});
while ($args->@*) {
my $this = $args->[0];
if ($self->_looks_like_option($this)
and not $self->_is_terminator($this)) {
if (my $match = $self->_match_option($this)) {
my $option = $match->parse($args,$stash);
$argpack->options->{$match->name} = $option;
}
else {
Getopt::Dakkar::X::BadOption->throw({
input => $this,
});
}
}
elsif (my $match = $self->_match_subcommand($this)) {
shift $args->@*;
$stash //= $self->_make_stash($argpack);
my $op = $self->op;
$stash->$op($argpack);
$match->parse($args,$stash);
}
else {
shift $args->@* if $self->_is_terminator($this);
for my $parameter ($self->parameters->@*) {
my $argument = $parameter->parse($args,$stash);
$argpack->arguments->{$argument->name} = $argument;
}
if ($args->@*) {
Getopt::Dakkar::X::ExtraArgs->throw({
args => $args,
});
}
}
}
return $stash;
}
sub _is_terminator($self,$arg) { return $arg eq q{--} }
sub _looks_like_option($self,$arg) { return $arg =~ /^-/ }
sub _match_option($self,$arg) {
for my $option ($self->options->@*) {
return $option if $option->match($arg);
}
return undef;
}
sub _match_subcommand($self,$arg) {
for my $subcommand ($self->subcommands->@*) {
return $subcommand if $subcommand->match($arg);
}
return undef;
}
sub match($self,$arg) {
return !! grep { $_ eq $arg } $self->matching_strings->@*;
}