summaryrefslogtreecommitdiff
path: root/lib/Getopt/Dakkar/Role/Command.pm
blob: 444a9a4d598ae43f2c6112f3ffc2c5a0730b5e6d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
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,$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)) {
                # ->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,$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->@*) {
                # ->parse will remove the argument(s) from $args 
                my $argument = $parameter->parse($args,$stash);
                $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,
                });
            }
            # hmmm. what about 'ls foo -l' ? 
        }
    }
    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->@*;
}