File Coverage

blib/lib/Data/Visitor/Tiny.pm
Criterion Covered Total %
statement 33 33 100.0
branch 9 10 90.0
condition 5 6 83.3
subroutine 7 7 100.0
pod 1 1 100.0
total 55 57 96.4


line stmt bran cond sub pod time code
1 2     2   195805 use v5.10;
  2         42  
2 2     2   19 use strict;
  2         5  
  2         87  
3 2     2   17 use warnings;
  2         5  
  2         226  
4              
5             package Data::Visitor::Tiny;
6             # ABSTRACT: Recursively walk data structures
7              
8             our $VERSION = '0.001';
9              
10 2     2   18 use Carp qw/croak/;
  2         5  
  2         189  
11 2     2   17 use Exporter 5.57 qw/import/;
  2         42  
  2         940  
12              
13             our @EXPORT = qw/visit/;
14              
15             #pod =func visit
16             #pod
17             #pod visit( $ref, sub { ... } );
18             #pod
19             #pod The C function takes a hashref or arrayref and recursively visits
20             #pod all values via pre-order traversal, calling the provided callback for each
21             #pod value. Only hashrefs and arrayrefs are traversed; objects, even if they
22             #pod override hash or array dereference, are only ever treated as values. Hash
23             #pod keys are sorted lexicographically before iteration, ensuring consistent
24             #pod visitation order in the face of Perl's hash order randomization.
25             #pod
26             #pod Within the callback, the C<$_> variable is set to the value of the node.
27             #pod The callback also receives three arguments: C<$key>, C<$valueref>, and
28             #pod C<$context>. The C<$key> is the hash key or array index of the value. The
29             #pod C<$valueref> is a scalar reference to the value; use it to modify the value
30             #pod in place. The C<$context> is a hashref for tracking state throughout the
31             #pod visiting process. Context keys beginning with '_' are reserved for
32             #pod C; you may store whatever other keys/values you need.
33             #pod The only key provided currently is C<_depth>, which starts at 0 and
34             #pod reflects how deep the visitor has recursed.
35             #pod
36             #pod The C function returns the context object.
37             #pod
38             #pod =cut
39              
40             sub visit {
41 6     6 1 22101 my ( $ref, $fcn ) = @_;
42 6         32 my $ctx = { _depth => 0 };
43 6         36 _visit( $ref, $fcn, $ctx );
44 6         25 return $ctx;
45             }
46              
47             sub _visit {
48 21     21   65 my ( $ref, $fcn, $ctx ) = @_;
49 21         94 my $type = ref($ref);
50 21 50 66     118 croak("'$ref' is not an ARRAY or HASH")
51             unless $type eq 'ARRAY' || $type eq 'HASH';
52 21 100       161 my @elems = $type eq 'ARRAY' ? ( 0 .. $#$ref ) : ( sort keys %$ref );
53 21         77 for my $idx (@elems) {
54 54         111 my ( $v, $vr );
55 54 100       160 $v = $type eq 'ARRAY' ? $ref->[$idx] : $ref->{$idx};
56 54 100       154 $vr = $type eq 'ARRAY' ? \( $ref->[$idx] ) : \( $ref->{$idx} );
57 54         125 local $_ = $v;
58             # Wrap $fcn in dummy for loop to guard against bare 'next' in $fcn
59 54         121 for my $dummy (0) { $fcn->( $idx, $vr, $ctx ) }
  54         148  
60 54 100 100     4824 if ( ref($v) eq 'ARRAY' || ref($v) eq 'HASH' ) {
61 15         37 $ctx->{_depth}++;
62 15         91 _visit( $v, $fcn, $ctx );
63 15         81 $ctx->{_depth}--;
64             }
65             }
66             }
67              
68             1;
69              
70              
71             # vim: ts=4 sts=4 sw=4 et tw=75:
72              
73             __END__