From 7fce4340deb0b6337bbd7ef6071ee42529db222d Mon Sep 17 00:00:00 2001 From: dakkar Date: Fri, 13 Jul 2018 13:09:26 +0100 Subject: vaguely parse commands --- lib/Getopt/Dakkar/Role/Command.pm | 76 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 lib/Getopt/Dakkar/Role/Command.pm (limited to 'lib/Getopt/Dakkar/Role/Command.pm') diff --git a/lib/Getopt/Dakkar/Role/Command.pm b/lib/Getopt/Dakkar/Role/Command.pm new file mode 100644 index 0000000..b96c410 --- /dev/null +++ b/lib/Getopt/Dakkar/Role/Command.pm @@ -0,0 +1,76 @@ +package Getopt::Dakkar::Role::Command; +use Getopt::Dakkar::Style qw(role); +with 'Getopt::Dakkar::Role::Piece'; +# VERSION +# ABSTRACT: a command + +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=undef) { + my $stash = $self->_parse($args); + if (my $op = $self->op) { + $stash->$op(); + } +} + +sub _parse($self,$args,$stash=undef) { + 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)) { + # ->parse will remove $this (or parts of + # it, if it's a bundle) and shift its own arguments + # out of $args + my $option = $match->parse($args,$self); + $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->@*) { + # ->parse will remove the argument(s) from $args + my $argument = $parameter->parse($args,$self); + $argpack->arguments->{$argument->name} = $argument; + } + + # if we've parsed all arguments, and there's still stuff + # in the input, something is wrong: complain + 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); + } +} +sub _match_subcommand($self,$arg) { + for my $subcommand ($self->subcommands->@*) { + return $subcommand if $subcommand->match($arg); + } +} -- cgit v1.2.3