[perl] 複雑なデータ構造のvalue を一気に書き換える方法

ハッシュと配列の参照が入り交じったような複雑なデータ構造の、全value を均等に加工したかったので次の様にしてみました。

use strict;
use Perl6::Say;
use Data::Dumper;

sub cook_hash {
    my ( $rh, $rf_cook ) = @_;
    my %tmp;
    for ( keys %$rh ) {
        if ( ref $rh->{$_} eq '' ) {
            $tmp{$_} = $rf_cook->( $rh->{$_} );    # ここで加工を実行
        }
        elsif ( ref $rh->{$_} eq 'HASH' ) {
            $tmp{$_} = cook_hash( $rh->{$_}, $rf_cook );
        }
        elsif ( ref $rh->{$_} eq 'ARRAY' ) {
            $tmp{$_} = cook_array( $rh->{$_}, $rf_cook );
        }
        else {
            # SCALAR, CODE, REF, GLOB, Objects は加工しないで元の値を採用
            $tmp{$_} = $rh->{$_};
        }
    }

    return \%tmp;
}

sub cook_array {
    my ( $ra, $rf_cook ) = @_;
    my @tmp;
    for (@$ra) {
        if ( ref $_ eq '' ) {
            push @tmp, $rf_cook->($_);    # ここで加工を実行
        }
        elsif ( ref $_ eq 'HASH' ) {
            push @tmp, cook_hash( $_, $rf_cook );
        }
        elsif ( ref $_ eq 'ARRAY' ) {
            push @tmp, cook_array( $_, $rf_cook );
        }
        else {
            push @tmp, $_;
        }
    }
    return \@tmp;
}

my $rh_testdata = {
    'a' => 1,
    'b' => {
        'aa' => 1,
        'ab' => [ 1, 2, 3, \'test', 5 ],
        'ac' => 3,
    },
    'c' => 3,
    'd' => 4,
    'e' => 5,
};

# 実行
say Dumper cook_hash( $rh_testdata, sub { 'cooked' . shift } );

cook_hash とcook_array がそれぞれ再帰になっており、かつお互いに呼び合うような構造でもあり、ちょっと面白いなと思いました。

実行結果は次の通り。

perl test.pl 
$VAR1 = {
          'e' => 'cooked5',
          'c' => 'cooked3',
          'a' => 'cooked1',
          'b' => {
                   'ab' => [
                             'cooked1',
                             'cooked2',
                             'cooked3',
                             \'test',
                             'cooked5'
                           ],
                   'ac' => 'cooked3',
                   'aa' => 'cooked1'
                 },
          'd' => 'cooked4'
        };

意図したようにvalue が処理されています。ホクホク。


すでに似たモジュールがある気が激しくしています!
ご存知でしたらぜひ教えてくださいませ。