Skip to content

Commit

Permalink
hooks: set $_ to substructure pointed by current step
Browse files Browse the repository at this point in the history
  • Loading branch information
mr-mixas committed Nov 3, 2017
1 parent 85c6ced commit 0cae0ef
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 14 deletions.
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,17 +80,20 @@ list of regular expressions. Empty hash or empty list for `keys` means all
keys. Sequence in `keys` and `regs` lists defines result sequence. `keys`
have higher priority than `regs`.

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
subsstructures as second passed to it when executed, $\_ set to current
substructure. Some true (match) value or false (doesn't match) value expected
as output.

Sample:

$spath = [
[1,7], # first spep
{regs => qr/foo/} # second step
[1,7], # first spep
{regs => qr/foo/} # second step
sub { exists $_->{bar} } # third step
];

Since v0.50 hooks (coderefs) as steps supported. Path as first argument and
stack of references (arrayref) as second passed to it when executed. Some true
(match) value or false (doesn't match) value expected as output.

See [Struct::Path::PerlStyle](https://metacpan.org/pod/Struct::Path::PerlStyle) if you're looking for human friendly path
definition method.

Expand Down
16 changes: 10 additions & 6 deletions lib/Struct/Path.pm
Original file line number Diff line number Diff line change
Expand Up @@ -104,17 +104,20 @@ list of regular expressions. Empty hash or empty list for C<keys> means all
keys. Sequence in C<keys> and C<regs> lists defines result sequence. C<keys>
have higher priority than C<regs>.
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
subsstructures as second passed to it when executed, $_ set to current
substructure. Some true (match) value or false (doesn't match) value expected
as output.
Sample:
$spath = [
[1,7], # first spep
{regs => qr/foo/} # second step
[1,7], # first spep
{regs => qr/foo/} # second step
sub { exists $_->{bar} } # third step
];
Since v0.50 hooks (coderefs) as steps supported. Path as first argument and
stack of references (arrayref) as second passed to it when executed. Some true
(match) value or false (doesn't match) value expected as output.
See L<Struct::Path::PerlStyle> if you're looking for human friendly path
definition method.
Expand Down Expand Up @@ -310,6 +313,7 @@ sub spath($$;@) {
delete ${$refs->[-1]}->{$_} if ($opts{delete} and $sc == $#{$spath});
}
} elsif (ref $step eq 'CODE') {
local $_ = ${$refs->[-1]};
$step->($path, $refs) and push @next, $path, $refs;
} else {
croak "Unsupported thing in the path, step #$sc";
Expand Down
28 changes: 26 additions & 2 deletions t/10-spath-address.t
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
use 5.006;
use strict;
use warnings;
use Test::More tests => 36;
use Test::More tests => 38;

use Struct::Path qw(spath);

use Storable qw(freeze);
$Storable::canonical = 1;

use lib "t";
use _common qw($s_array $s_mixed);
use _common qw($s_array $s_mixed t_dump);

my (@r, $frozen_s);

Expand Down Expand Up @@ -258,5 +258,29 @@ is_deeply(
"code refs in the path (grep defined)"
);

do {
local $_ = 'must remain unchanged';

my $data = [
{ k => 'one', v => 1 },
{ k => 'two', v => 2, s => { k => 1 } },
{ k => 'two', v => 2, s => { k => 2 } },
];

my $dfltvar = sub {
$_->{k} eq 'two' and
exists $_->{s} and $_->{s}->{k} < 2
};

@r = spath($data, [ [],$dfltvar,{keys => ['k','s']} ]);
is_deeply(
\@r,
[\'two',\{k => 1}],
'$_ usage'
) || diag t_dump \@r;

is($_, 'must remain unchanged', 'Default var ($_) locality check');
};

# original structure must remain unchanged
ok($frozen_s eq freeze($s_mixed));

0 comments on commit 0cae0ef

Please sign in to comment.