Skip to content

Commit

Permalink
regexps supported in hash keys list
Browse files Browse the repository at this point in the history
  • Loading branch information
mr-mixas committed Dec 15, 2018
1 parent f7c2284 commit bf42b7c
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 17 deletions.
8 changes: 4 additions & 4 deletions README.md
Expand Up @@ -59,10 +59,10 @@ Path is a list of 'steps', each represents nested level in the structure.
Arrayref as a step stands for ARRAY and must contain desired items indexes or
be empty (means "all items"). Sequence for indexes define result sequence.

Hashref represent HASH and may contain keys `K`, `R` or be empty. `K` may
contain list of desired keys, `R` must contain list of compiled regular
expressions. Empty hash or empty list for `K` means all keys. Sequence in `K`
and `R` lists define result sequence. `K` have higher priority than `R`.
Hashref represent HASH and may contain key `K` or be empty. `K`'s value
should be a list of desired keys and compiled regular expressions. Empty
hash or empty list for `K` means all keys, sequence in the list define
resulting sequence.

Coderef step is a hook - subroutine which may filter and/or modify
structure. Path as first argument and a stack (arrayref) of refs to traversed
Expand Down
24 changes: 15 additions & 9 deletions lib/Struct/Path.pm
Expand Up @@ -83,10 +83,10 @@ Path is a list of 'steps', each represents nested level in the structure.
Arrayref as a step stands for ARRAY and must contain desired items indexes or
be empty (means "all items"). Sequence for indexes define result sequence.
Hashref represent HASH and may contain keys C<K>, C<R> or be empty. C<K> may
contain list of desired keys, C<R> must contain list of compiled regular
expressions. Empty hash or empty list for C<K> means all keys. Sequence in C<K>
and C<R> lists define result sequence. C<K> have higher priority than C<R>.
Hashref represent HASH and may contain key C<K> or be empty. C<K>'s value
should be a list of desired keys and compiled regular expressions. Empty
hash or empty list for C<K> means all keys, sequence in the list define
resulting sequence.
Coderef step is a hook - subroutine which may filter and/or modify
structure. Path as first argument and a stack (arrayref) of refs to traversed
Expand Down Expand Up @@ -123,6 +123,7 @@ sub implicit_step {
return 1 if (exists $_[0]->{R} and @{$_[0]->{R}});
return 1 unless (exists $_[0]->{K});
return 1 unless (@{$_[0]->{K}});
ref $_ eq 'Regexp' && return 1 for (@{$_[0]->{K}})
} else { # hooks
return 1;
}
Expand Down Expand Up @@ -284,12 +285,17 @@ sub path($$;@) {
}

if ($t eq 'K') {
for (@{$step->{K}}) {
unless ($opts{expand} or exists ${$refs->[-1]}->{$_}) {
croak "{$_} doesn't exist, step #$sc" if $opts{strict};
next;
for my $i (@{$step->{K}}) {
if (ref $i eq 'Regexp') {
push @{$items}, grep { $_ =~ $i }
keys %{${$refs->[-1]}};
} else {
unless ($opts{expand} or exists ${$refs->[-1]}->{$i}) {
croak "{$i} doesn't exist, step #$sc" if $opts{strict};
next;
}
push @{$items}, $i;
}
push @{$items}, $_;
}
} else {
for my $g (@{$step->{R}}) {
Expand Down
8 changes: 6 additions & 2 deletions t/implicit_step.t
Expand Up @@ -3,7 +3,7 @@
use 5.006;
use strict;
use warnings;
use Test::More tests => 8;
use Test::More tests => 9;

use Struct::Path qw(implicit_step);

Expand Down Expand Up @@ -42,9 +42,13 @@ ok(
"Hash regs"
);

ok(
implicit_step({K => ['a', qr/abc/]}),
"Hash regs"
);

ok(
implicit_step(sub{}),
"Filter"
);


23 changes: 21 additions & 2 deletions t/path-address.t
Expand Up @@ -2,7 +2,7 @@
use 5.006;
use strict;
use warnings;
use Test::More tests => 38;
use Test::More tests => 40;

use Struct::Path qw(path);

Expand Down Expand Up @@ -206,7 +206,7 @@ is_deeply(
"get {a}[0]{a2c}"
);

# use regexps as keys specificators
# deprecated
@r = path($s_mixed, [ {R => [qr/a/]},[0],{R => [qr/a2(a|c)/]} ]);
@r = sort { (keys %{${$a}})[0] cmp (keys %{${$b}})[0] } @r; # sort by key (random keys access)
is_deeply(
Expand All @@ -215,6 +215,7 @@ is_deeply(
"get {/a/}[0]{/a2(a|c)/}"
);

# deprecated
@r = path($s_mixed, [ {R => [qr/a/]},[0],{K => ['a2c'], R => [qr/a2(a|c)/]} ]);
push @r, sort { (keys %{${$a}})[0] cmp (keys %{${$b}})[0] } splice @r, 1; # sort last two items by key
is_deeply(
Expand All @@ -223,6 +224,24 @@ is_deeply(
"get {/a/}[0]{/a2(a|c)/,a2c} (keys has higher priority than regs)"
);

# regexps for keys specificators
@r = path($s_mixed, [ {K => [qr/a/]},[0],{K => [qr/a2(a|c)/]} ]);
@r = sort { (keys %{${$a}})[0] cmp (keys %{${$b}})[0] } @r; # sort by key (random keys access)
is_deeply(
\@r,
[\{a2aa => 0},\{a2ca => []}],
"get {/a/}[0]{/a2(a|c)/}"
);

# mix regular keys and regexps
@r = path($s_mixed, [ {K => [qr/a/]},[0],{K => ['a2c', qr/a2(a|c)/]} ]);
push @r, sort { (keys %{${$a}})[0] cmp (keys %{${$b}})[0] } splice @r, 1; # sort last two items by key
is_deeply(
\@r,
[\{a2ca => []},\{a2aa => 0},\{a2ca => []}],
"get {/a/}[0]{/a2(a|c)/,a2c} (keys has higher priority than regs)"
);

# code refs in the path
my $back = sub { # perform "step back"
pop @{$_[0]};
Expand Down

0 comments on commit bf42b7c

Please sign in to comment.