Data-Rmap

 view release on metacpan or  search on metacpan

lib/Data/Rmap.pm  view on Meta::CPAN

 use Lingua::EN::Numbers::Easy;

 $words = [ 1, \2, { key => 3 } ];
 $nums = dclone $words;
 rmap { $_ = $N{$_} || $_ } $nums;


 # Make an assertion about a structure
 use Data::Dump;
 rmap_ref {
    blessed($_) && $_->isa('Question') && defined($_->name)
        or die "Question doesn't have a name:", dump($_);
 } @pages;


 # Traverse a tree using localize state
 $tree = [
     one =>
     two =>
     [
         three_one =>
         three_two =>
         [
             three_three_one =>
         ],
         three_four =>
     ],
     four =>
     [
         [
             five_one_one =>
         ],
     ],
 ];

 @path = ('q');
 rmap_to {
     if(ref $_) {
         local(@path) = (@path, 1); # ARRAY adds a new level to the path
         $_[0]->recurse(); # does stuff within local(@path)'s scope
     } else {
         print join('.', @path), " = $_ \n"; # show the scalar's path
     }
     $path[-1]++; # bump last element (even when it was an aref)
 } ARRAY|VALUE, $tree;

 # OUTPUT
 # q.1 = one
 # q.2 = two
 # q.3.1 = three_one
 # q.3.2 = three_two
 # q.3.3.1 = three_three_one
 # q.3.4 = three_four
 # q.4 = four
 # q.5.1.1 = five_one_one

 # replace CODE with "<CODE>"
 $ perl -MData::Rmap=:all -E 'say join ":", rmap_code { "<CODE>" } sub{},sub{}'
 <CODE>:<CODE>

 # look inside code refs with PadWalker
 $ perl -MData::Rmap=:all -MSub::Identify=:all -MPadWalker=:all -MSub::Name
   use 5.10.0;
   my $s = sub {}; sub A::a { $s };
   say join ", ",
    rmap_code {
        sub_fullname($_),                       # name string
        map { $_[0]->recurse } closed_over($_)  # then recurse the sub innards
    } \*A::a, subname b => sub { $s };
   # A::a, main::__ANON__, main::b

=head1 Troubleshooting

Beware comma after block:

 rmap { print }, 1..3;
               ^-------- bad news, you get an empty list:
 rmap(sub { print $_; }), 1..3;

If you don't import a function, perl's confusion may produce:

 $ perl -MData::Rmap -le 'rmap_scalar { print } 1'
 Can't call method "rmap_scalar" without a package or object reference...

 $ perl -MData::Rmap -le 'rmap_scalar { $_++ } 1'
 Can't call method "rmap_scalar" without a package or object reference...

If there's two paths to an element, both will need to be cut.

If there's two paths to an element, one will be taken randomly when
there is an intervening hash.

Autovivification can lead to "Deep recursion" warnings if you test
C<< exists $_->{this}{that} >> instead of
C<< exists $_->{this} && exists $_->{this}{that} >>
as you may follow a long chain of "this"s
Alternatively use the "no autovivification" pragma to avoid this problem.

=head1 TODO

put for @_ in wrapper to allow parameters in a different wrapper,
solve localizing problem.

Store custom localized data about the traversal.
Seems too difficult and ugly when compare to doing it at the call site.
Should support multiple reentrancy so avoid the symbol table.

C<rmap_args { } $data_structure, @args> form to pass parameters.
Could potentially help localizing needs.  (Maybe only recurse last item)

Benchmark.  Use array based object and/or direct access internally.

Think about permitting different callback for different types.
The prototype syntax is a bit too flaky....

Ensure that no memory leaks are possible, leaking the closure.

=head1 SEE ALSO

map, grep, L<Storable>'s dclone, L<Scalar::Util>'s reftype and blessed

Faint traces of treemap:



( run in 0.974 second using v1.01-cache-2.11-cpan-39bf76dae61 )