Data::...sformer(3pm)
π Data::Transformer π β the Data::Transformer(3pm) page, but make it group chat π
straight outta the User Contributed Perl Documentation, bestie. buckle up, we're going in. π¦
πΈ NAME πΈ
Data::Transformer β traverse a data structure, altering it in place. yes. in place. no copy. we go in and we redecorate. periodt. π
π SYNOPSIS π
four whole vibes, pick your fighter:
β¨ A: SIMPLE USAGE β¨
use Data::Transformer;
# A: SIMPLE USAGE:
# trim extra whitespace from normal strings inside %data.
my $trim = sub { local($_)=shift; $$_ =~ s/^\s*//; $$_ =~ s/\s*$//; };
my $t = Data::Transformer->new(normal=>$trim);
$t->traverse(\%data);
okay so you got a lil coderef, you hand it to new() keyed by normal, you traverse(\%data), and every normal string inside %data gets its extra whitespace trimmed. it's giving β¨glow upβ¨.
π₯ B: MORE COMPLEX USAGE π₯
the brief: (a) uppercase all keys in all hashes contained in $data, and (b) convert any arrays to hashes. two jobs. one transformer. iconic.
# B: MORE COMPLEX USAGE:
# (a) uppercase all keys in all hashes contained in $data
# and (b) convert any arrays to hashes:
my $uc_hash = sub {
my $h = shift;
my @keys = keys %h;
foreach (@keys) {
my $uc = uc($_);
if ($uc ne $_ && !exists($h->{$uc})) {
$h->{$uc} = $h->{$_};
delete $h->{$_};
} elsif ($uc ne $_) {
die "Bad key $_: '$uc' exists already";
}
}
};
my $ar_conv = sub {
my %h = @{$_[0]};
return sub { \%h };
};
my $t = Data::Transformer->new(
hash => $uc_hash,
array => $ar_conv,
node_limit => 500_000 );
eval { $t->traverse($data) };
warn "Could not complete transformation: $@" if $@;
notice the node_limit => 500_000? yeah. that's not a flex, that's a necessity β see the CAVEATS, bestie, it gets real in there. and the eval + warn? that's the "if it goes feral, at least we find out" energy. π
π¦ C: NON-DESTRUCTIVE TRAVERSAL π¦
plot twist: you don't actually have to change anything. just vibe. collect intel. π
# C: NON-DESTRUCTIVE TRAVERSAL
# You don't actually have to change anything...
my $size = 0;
my $t = Data::Transformer->new(
normal => sub { $size+=length(${ $_[0] }) },
hash => sub { $size+=length($_) for keys %{ $_[0] } },
);
my $nodes = $t->tranverse(\%data);
print "Number of nodes: $nodes\n";
print "Size of keys + values: $size\n";
(yes, the example literally says tranverse up there. we are reproducing the example exactly, typos and all, no cap. π do NOT come for me.)
π D: OBJECTS INSIDE A DATA STRUCTURE π
# D: OBJECTS INSIDE A DATA STRUCTURE
# Affect objects by using the class name as a key:
my $t = Data::Transformer->new(
'My::Class' => sub { shift->set_foo('bar') }
);
want to touch objects? use the class name as the key. that's the whole trick. main character move honestly. π
π DESCRIPTION π
πΈ Data type callbacks πΈ
the basic idea β and I'm quoting the vibe here β is that you provide a callback subroutine for each type of data that you wish to affect or collect information from. one callback per data type. match made in heaven. π
the constructor, new(), expects a hash with at least one of these keys:
normalβ for normal, non-reference data. the everyday girlies.arrayβ for array references. πhashβ for hash references. ποΈcodeβ for anonymous subroutines (coderefs). π€scalarβ for scalar references. β¨globβ for globs (such as filehandle holders). π
in every single case, the value is a coderef representing the callback for the data type in question. coderef in, magic out.
now the tea β: array and hash are special β they're the ones that get traversed into. they're not just leaves, they're doorways. πͺ
you can affect objects inside the data structure by specifying a callback keyed to the name of the class they belong to. but β and this is important β they are not automatically recursed into, even if they happen to be blessed hash or array references. blessed β invited in. π
same energy for scalar references: a scalar reference is not automatically traversed into, even if it may contain a reference to an arrayref or a hashref. to make the module traverse into scalar references, you need to return a coderef encapsulating a different data type in the scalar handler β which changes them and prompts a reiteration over that data point. and yes, this applies to objects as well. π«Ά
π Additional option for the constructor π
node_limitβ if you give it an integer value, it overrides the default node processing limit of2**16. it cannot be set higher than2**20-1. that's the ceiling. don't test it. π«
β¨ traverse() β¨
the traverse() method returns the number of nodes processed. and ngl, that number might not match either the number of nodes in the actual data structure or the number of nodes after the transformation. here's why:
- Reiteration into a particular node may have occurred, which increments the node count.
- Blessed references (objects) will not normally be iterated into β they're merely treated as leaves in the data structure. π
- The processing code you passed to the constructor may well affect the number of nodes. you did that. that's on you. π
π₯ Note on data type changes π₯
want to change a data type β like replacing an array with a hash, as in example B up there? you have to return a coderef from the callback for the original data type. that coderef encapsulates the replacement data for the node in question. β¨
after the node has been replaced like that, it gets re-evaluated so any transformations you defined for the new data type get applied. glow up on top of glow up.
π¨ be careful of potential infinite loops when doing this with more than one data type at a time, or when replacing coderefs with other coderefs. also β because of reiteration β complex changes of large data structures may require setting the node processing limit higher than the default. do with that information what you will. π
π Note on circular references π
data structures containing circular references should not cause problems. Data::Transformer will skip any node containing a reference which has already been processed. it's seen it. it's not going back. it's protecting its peace. π§
π¨ CAVEATS π¨
okay bestie, real talk. it is not feasible to use this module for very large data structures. accordingly, there is a hard node processing boundary of 2**20-1 (about 1 million); attempting to set the limit higher results in an immediate, fatal error. immediately. fatally. no warning shot. π
for the vast majority of cases, though, the default limit of 2**16 (about 65 thousand) should be more than enough. she's generous. she's fine. π«Ά
π SEE ALSO π
the author is aware of two modules doing similar things β check them out if this one doesn't fit your needs:
Data::Rmapby Brad Bowman πΈData::Walkby Guido Flohr πΈ
π AUTHOR π
Baldur Kristinsson <bk@mbl.is>, 2006 β legend behaviour, honestly.
Copyright (c) 2006 Baldur Kristinsson. All rights reserved.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
and that's the whole page, bestie π β this one came to you via perl v5.36.0, dated 2022-11-21, and it's called Data::Transformer(3pm). go forth and traverse responsibly. slay. π
β¨
π¦ where this page comes from
- debian bookworm: libdata-transformer-perl 0.04-3 Β· GPL-1.0-or-later OR Artistic-1.0-Perl
- debian trixie: libdata-transformer-perl 0.04-3 Β· GPL-1.0-or-later OR Artistic-1.0-Perl
- ubuntu noble: libdata-transformer-perl 0.04-3 Β· GPL-1.0-or-later OR Artistic-1.0-Perl
- ubuntu resolute: libdata-transformer-perl 0.04-3 Β· GPL-1.0-or-later OR Artistic-1.0-Perl
- ubuntu stonking: libdata-transformer-perl 0.04-3 Β· GPL-1.0-or-later OR Artistic-1.0-Perl
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms