use strict;
use warnings FATAL => 'all';
+sub DEBUG () { 0 }
+
+BEGIN {
+ if ($ENV{WEB_SIMPLE_DISPATCHPARSER_DEBUG}) {
+ no warnings 'redefine';
+ *DEBUG = sub () { 1 }
+ }
+}
+
+sub diag { if (DEBUG) { warn $_[0] } }
+
sub new { bless({}, ref($_[0])||$_[0]) }
sub _blam {
# ?<param spec>
/\G\?/gc and
return $self->_parse_param_handler($_, 'query');
+
+ # %<param spec>
+ /\G\%/gc and
+ return $self->_parse_param_handler($_, 'body');
}
return; # () will trigger the blam in our caller
}
my ($self) = @_;
for ($_[1]) {
# trailing / -> require / on end of URL
- /\G(?:(?=\s)|$)/gc and
+ /\G(?:(?=[+|\)])|$)/gc and
return '$';
# word chars only -> exact path part match
/\G(\w+)/gc and
my $unpacker = Web::Simple::ParamParser->can("get_unpacked_${type}_from");
for ($_[1]) {
- my (@required, @single, %multi, $star, $multistar) = @_;
+ my (@required, @single, %multi, $star, $multistar, %positional, $have_kw);
+ my $pos_idx = 0;
PARAM: { do {
- # per param flag
+ # ?:foo or ?@:foo
- my $multi = 0;
+ my $is_kw = /\G\:/gc;
# ?@foo or ?@*
- /\G\@/gc and $multi = 1;
+ my $multi = /\G\@/gc;
# @* or *
- if (/\G\*/) {
+ if (/\G\*/gc) {
+
+ $self->_blam("* is always named; no need to supply :") if $is_kw;
$multi ? ($multistar = 1) : ($star = 1);
+
+ $have_kw = 1;
+
+ if ($star && $multistar) {
+ $self->_blam("Can't use * and \@* in the same parameter match");
+ }
} else {
# @foo= or foo= or @foo~ or foo~
-
+
/\G(\w+)/gc or $self->_blam('Expected parameter name');
my $name = $1;
# record the key in the right category depending on the multi (@) flag
- $multi ? (push @single, $name) : ($multi{$name} = 1);
+ $multi ? ($multi{$name} = 1) : (push @single, $name);
+
+ # record positional or keyword
+
+ $is_kw ? ($have_kw = 1) : ($positional{$name} = $pos_idx++);
}
} while (/\G\&/gc) }
foreach my $name (@required) {
return unless exists $raw->{$name};
}
- my %p;
+ my (%p, %done);
+ my @p = (undef) x $pos_idx;
foreach my $name (
@single,
($star
: ()
)
) {
- $p{$name} = $raw->{$name}->[-1] if exists $raw->{$name};
+ if (exists $raw->{$name}) {
+ if (exists $positional{$name}) {
+ $p[$positional{$name}] = $raw->{$name}->[-1];
+ } else {
+ $p{$name} = $raw->{$name}->[-1];
+ }
+ }
+ $done{$name} = 1;
}
foreach my $name (
keys %multi,
($multistar
- ? (grep { !exists $p{$_} } keys %$raw)
+ ? (grep { !exists $done{$_} && !exists $multi{$_} } keys %$raw)
: ()
)
) {
- $p{$name} = $raw->{$name}||[];
+ if (exists $positional{$name}) {
+ $p[$positional{$name}] = $raw->{$name}||[];
+ } else {
+ $p{$name} = $raw->{$name}||[];
+ }
}
- return ({}, \%p);
+ $p[$pos_idx] = \%p if $have_kw;
+ return ({}, @p);
};
}
}