TreeDumper(3pm)
π NAME π
Data::TreeDumper β an improved replacement for Data::Dumper, bestie. And she came with powerful filtering capability. no cap. π
π¦ SYNOPSIS π¦
use Data::TreeDumper ;
my $sub = sub {} ;
my $s =
{
A =>
{
a =>
{
}
, bbbbbb => $sub
, c123 => $sub
, d => \$sub
}
, C =>
{
b =>
{
a =>
{
a =>
{
}
, b => sub
{
}
, c => 42
}
}
}
, ARRAY => [qw(element_1 element_2 element_3)]
} ;
#-------------------------------------------------------------------
# package setup data
#-------------------------------------------------------------------
$Data::TreeDumper::Useascii = 0 ;
$Data::TreeDumper::Maxdepth = 2 ;
print DumpTree($s, 'title') ;
print DumpTree($s, 'title', MAX_DEPTH => 1) ;
print DumpTrees
(
[$s, "title", MAX_DEPTH => 1]
, [$s2, "other_title", DISPLAY_ADDRESS => 0]
, USE_ASCII => 1
, MAX_DEPTH => 5
) ;
π Output π
title:
|- A [H1]
| |- a [H2]
| |- bbbbbb = CODE(0x8139fa0) [C3]
| |- c123 [C4 -> C3]
| `- d [R5]
| `- REF(0x8139fb8) [R5 -> C3]
|- ARRAY [A6]
| |- 0 [S7] = elment_1
| |- 1 [S8] = element_2
| `- 2 [S9] = element_3
`- C [H10]
`- b [H11]
`- a [H12]
|- a [H13]
|- b = CODE(0x81ab130) [C14]
`- c [S15] = 42
π DESCRIPTION π
ok so here's the tea β β Data::Dumper and all the other modules out there? They do a genuinely great job of dumping data structures. Respect where respect is due. π But their output takes more brain power to understand than the data itself, and that is the whole problem, bestie. π When you're dumping large amounts of data, the output can be straight-up overwhelming, and seeing the relationship between each piece of the dumped data? literally impossible.
Data::TreeDumper also dumps data, but in a tree-like fashion β hopefully in a format that's way easier to understand. main character energy only. π
πΈ Label πΈ
Every node in the tree has a label. That label holds a type and an address, and it gets displayed to the right of the entry name, inside square brackets. like a little name tag but for your data. π·οΈ
| |- bbbbbb = CODE(0x8139fa0) [C3]
| |- c123 [C4 -> C3]
| `- d [R5]
| `- REF(0x8139fb8) [R5 -> C3]
β¨ Address β¨
The addresses are linearly incremented, which should make it easier to locate data β she's organised like that. π
And if an entry is a reference to data that's already been displayed, a -> gets appended within the label, followed by the address of the already-displayed data. it's giving "been there, dumped that" π«Ά
ex: c123 [C4 -> C3]
^ ^
| | address of the data referred to
|
| current element address
π Types π
S: ScalarH: HashA: ArrayC: CodeR: ReferenceRS: Scalar referenceOx: Object, wherexis the object's underlying type
π Empty Hash or Array π
Empty hashes and arrays get no structure displayed at all. Instead, the string "no elements" is added to the display. Nothing to show, she said, and she's not elaborating. π
|- A [S10] = string
|- EMPTY_ARRAY (no elements) [A11]
|- B [S12] = 123
π Configuration and Overrides π
Data::TreeDumper has configuration options you can set to modify the output it generates. DumpTree and PrintTree take overrides as trailing arguments, and those overrides are active within the current dump call only β temporary serve, they don't stick around. β¨
ex:
$Data::TreeDumper::Maxdepth = 2 ;
# maximum depth set to 1 for the duration of the call only
print DumpTree($s, 'title', MAX_DEPTH => 1) ;
PrintTree($s, 'title', MAX_DEPTH => 1) ; # shortcut for the above call
# maximum depth is 2
print DumpTree($s, 'title') ;
π $Data::TreeDumper::Displaycallerlocation π
This package variable is so useful when you're using Data::TreeDumper and you have zero clue where you called PrintTree or DumpTree β ie, when you're debugging at 2am and losing your mind. π It displays the filename and line of the call on STDOUT. It can also be set as an override: DISPLAY_CALLER_LOCATION => 1.
π NO_PACKAGE_SETUP π
Sometimes the package setup you've got going on is simply not the vibe you want for this one call. And resetting the variable, making the call, then setting the variables back? boring, exhausting, not doing it. π₯± Set NO_PACKAGE_SETUP to 1 and DumpTree will ignore the package setup for that call.
print Data::TreeDumper::DumpTree($s, "Using package data") ;
print Data::TreeDumper::DumpTree($s, "Not Using package data", NO_PACKAGE_SETUP => 1) ;
π DISPLAY_ROOT_ADDRESS π
By default, Data::TreeDumper doesn't display the address of the root. But if you want it:
DISPLAY_ROOT_ADDRESS => 1 # show the root address
π DISPLAY_ADDRESS π
When the dumped data is not self-referential, displaying the address of every single node just clutters the display, ngl. You can tell Data::TreeDumper to stop showing node addresses with:
DISPLAY_ADDRESS => 0
π DISPLAY_PATH π
Adds the path of the element to its address. serving directions for your data π§
DISPLAY_PATH => 1
ex: '- CopyOfARRAY [A39 -> A18 /{'ARRAY'}]
π DISPLAY_OBJECT_TYPE π
Data::TreeDumper displays the package in which an object is blessed. Want that suppressed? here you go:
DISPLAY_OBJECT_TYPE => 0
π DISPLAY_INHERITANCE π
Data::TreeDumper will display the inheritance hierarchy for the object β the whole family tree, iconic:
|- object = blessed in 'SuperObject' <- Potatoe [OH55]
| `- Data = 0 [S56]
π DISPLAY_AUTOLOAD π
if this is set, Data::TreeDumper will tag the object type with '[A]' if the package has an AUTOLOAD function. little badge of honour, we love to see it ποΈ
|- object_with_autoload = blessed in '[A]SuperObjectWithAutoload' <- Potatoe <- [A] Vegetable [O58]
| `- Data = 0 [S56]
π DISPLAY_TIE π
if DISPLAY_TIE is set, Data::TreeDumper will display which package the variable is tied to. This works for hashes and arrays, and also for objects which are based on hashes and arrays. tied but make it visible π
|- tied_hash (tied to 'TiedHash') [H57]
| `- x = 1 [S58]
|- tied_hash_object = (tied to 'TiedHash') blessed in 'SuperObject' <- [A]Potatoe <- Vegetable [O59]
| |- m1 = 1 [S60]
| `- m2 = 2 [S61]
π PERL DATA π
Setting one of the options below will show internal perl data β the raw, unfiltered, behind-the-scenes look. no makeup, no filter, just perl. π
Cells: <2234> HASH(0x814F20c)
|- A1 [H1] <204> HASH(0x824620c)
| `- VALUE [S2] = datadatadatadatadatadatadatadatadatadata <85>
|- A8 [H11] <165> HASH(0x8243d68)
| `- VALUE [S12] = C <46>
`- C2 [H19] <165> HASH(0x8243dc0)
`- VALUE [S20] = B <46>
π§ DISPLAY_PERL_SIZE π§
Setting this option will show the size of the memory allocated for each element in the tree, within angle brackets.
DISPLAY_PERL_SIZE => 1
The excellent Devel::Size is used to compute the size of the perl data. And heads up: if you have deep circular data structures, expect the dump time to be slower β like, 50 times slower or more. π³ she's thorough but she's not fast.
π§ DISPLAY_PERL_ADDRESS π§
Setting this option will show the perl-address of the dumped data.
DISPLAY_PERL_ADDRESS => 1
π REPLACEMENT_LIST π
Scalars may contain non-printable characters that you would rather not see in a dump. One of the most common? "\r" embedded in a text string from MS-DOS files. yikes. π
Data::TreeDumper, by default, replaces "\n" by '[\n]' and "\r" by '[\r]'. You can set REPLACEMENT_LIST to an array ref containing elements which are themselves array references β the first element is the character(s) to match and the second is the replacement.
# a fancy and stricter replacement for \n and \r
my $replacement = [ ["\n" => '[**Fancy \n replacement**]'], ["\r" => '\r'] ] ;
print DumpTree($smed->{TEXT}, 'Text:', REPLACEMENT_LIST => $replacement) ;
π QUOTE_HASH_KEYS π
QUOTE_HASH_KEYS and its package variable $Data::TreeDumper::Quotehashkeys can be set if you wish to single-quote the hash keys. Hash keys are not quoted by default β they go out bare-faced, as is.
DumpTree(\$s, 'some data:', QUOTE_HASH_KEYS => 1) ;
# output
some data:
`- REF(0x813da3c) [H1]
|- 'A' [H2]
| |- 'a' [H3]
| |- 'b' [H4]
| | |- 'a' = 0 [S5]
π DISPLAY_NO_VALUE π
Only element names are added to the tree rendering. names only, values not invited to the party. π«
π QUOTE_VALUES π
QUOTE_VALUES and its package variable $Data::TreeDumper::Quotevalues can be set if you wish to single-quote the scalar values.
DumpTree(\$s, 'Cells:', QUOTE_VALUES=> 1) ;
π NO_NO_ELEMENTS π
If this option is set, Data::TreeDumper will not add 'no elements' to empty hashes and arrays. (yes, she's shutting up about it, finally π«Ά)
π NO_OUTPUT π
This option suppresses all output generated by Data::TreeDumper. Super useful when you want to iterate through your data structures and display the data yourself, manipulate the data structure, or do a search (see "using filter as iterators" below). silent but productive.
π Filters π
Data::TreeDumper can sort the tree nodes with a user-defined subroutine. By default, hash keys are sorted β she's tidy like that, it's her default setting.
FILTER => \&ReverseSort
FILTER_ARGUMENT => ['your', 'arguments']
The filter routine is passed these arguments:
- a reference to the node which is going to be displayed
- the node's depth (this allows you to selectively display elements at a certain depth)
- the path to the reference from the start of the dump.
- an array reference containing the keys to be displayed (see "Filter chaining")
- the dumper's setup
- the filter arguments (see below)
π yes bestie, it says 5 twice. that's exactly what the docs say. not my typo, I'm just the messenger.
The filter returns the node's type, possibly a new structure (see below) and a list of 'keys' to display. The keys are hash keys or array indexes.
In Perl:
($tree_type, $replacement_tree, @nodes_to_display) = $your_filter->($tree, $level, $path, $nodes_to_display, $setup) ;
Filters are not as complicated as they sound, fr fr β and they are very powerful, especially when you use the path argument. The path idea was given to me by another module writer but I forgot whom. If this writer will contact me, I will give him the proper credit. π«Ά (respect where it's due, always.)
Lots of examples can be found in filters.pl, and I'll be glad to help if you want to develop a specific filter. we support your journey, bestie. π
π¦ FILTER_ARGUMENT π¦
it is possible to pass arguments to your filter. passing a reference allows you to modify the arguments when the filter is run (that happens for each node).
sub SomeSub
{
my $counter = 0 ;
my $data_structure = {.....} ;
DumpTree($data_structure, 'title', FILTER => \&CountNodes, FILTER_ARGUMENT => \$counter) ;
print "\$counter = $counter\n" ;
}
sub CountNodes
{
my ($structure, $level, $path, $nodes_to_display, $setup, $counter) = @_ ;
$$counter++ ; # remember to pass references if you want them to be changed by the filter
return(DefaultNodesToDisplay($structure)) ;
}
π¦ Key removal π¦
Entries can be removed from the display by not returning their keys. gone. not invited. blocked, even. βοΈ
my $s = {visible => '', also_visible => '', not_visible => ''} ;
my $OnlyVisible = sub
{
my $s = shift ;
if('HASH' eq ref $s)
{
return('HASH', undef, grep {! /^not_visible/} keys %$s) ;
}
return(Data::TreeDumper::DefaultNodesToDisplay($s)) ;
}
DumpTree($s, 'title', FILTER => $OnlyVisible) ;
π·οΈ Label changing π·οΈ
Okay bestie, here's where it gets fun. You can straight up change the label that shows up for a hash key or an array index. Why would you do that? To sneak extra visual info into your tree dump, of course π
Instead of returning the plain key name, you return an array reference holding the key name and the label you want displayed. And listen β you only have to return one of these refs for the entries you actually want changed, so mixing plain scalars and array refs in the same return is totally acceptable. Mix and match, it's giving range β¨
sub StarOnA
{
# hash entries matching /^a/i have '*' prepended
my $tree = shift ;
if('HASH' eq ref $tree)
{
my @keys_to_dump ;
for my $key_name (keys %$tree)
{
if($key_name =~ /^a/i)
{
$key_name = [$key_name, "* $key_name"] ;
}
push @keys_to_dump, $key_name ;
}
return ('HASH', undef, @keys_to_dump) ;
}
return (Data::TreeDumper::DefaultNodesToDisplay($tree)) ;
}
print DumpTree($s, "Entries matching /^a/i have '*' prepended", FILTER => \&StarOnA) ;
And if you're on an ANSI terminal, you can also change the color of the label. This can greatly improve the visual search time β like, actually game-changing when you're eyeballing a giant tree. See the label coloring example in colors.pl. π¨
π Structure replacement π
Not me about to tell you that you can replace the entire data structure inside a filter π€―
It's perfect for when you want to show a "worked" version of the structure. And yes, you can even change the type of the data structure β for example, turning an array into a hash. Main character behavior.
sub ReplaceArray
{
# replace arrays with hashes!!!
my $tree = shift ;
if('ARRAY' eq ref $tree)
{
my $multiplication = $tree->[0] * $tree->[1] ;
my $replacement = {MULTIPLICATION => $multiplication} ;
return('HASH', $replacement, keys %$replacement) ;
}
return (Data::TreeDumper::DefaultNodesToDisplay($tree)) ;
}
print DumpTree($s, 'replace arrays with hashes!', FILTER => \&ReplaceArray) ;
Here's a real life example, fr fr. Tree::Simple (http://search.cpan.org/dist/Tree-Simple/) lets you build tree structures. The thing is, the child nodes aren't directly in the parent object (which is a hash). So here's an unfiltered dump of a tree with seven nodes:
Tree::Simple through Data::TreeDumper
|- _children
| |- 0
| | |- _children
| | | `- 0
| | | |- _children
| | | |- _depth = 1
| | | |- _node = 1.1
| | | `- _parent
| | |- _depth = 0
| | |- _node = 1
| | `- _parent
| |- 1
| | |- _children
| | | |- 0
| | | | |- _children
| | | | |- _depth = 1
| | | | |- _node = 2.1
| | | | `- _parent
| | | |- 1
| | | | |- _children
| | | | |- _depth = 1
| | | | |- _node = 2.1a
| | | | `- _parent
| | | `- 2
| | | |- _children
| | | |- _depth = 1
| | | |- _node = 2.2
| | | `- _parent
| | |- _depth = 0
| | |- _node = 2
| | `- _parent
| `- 2
| |- _children
| |- _depth = 0
| |- _node = 3
| `- _parent
|- _depth = -1
|- _node = 0
`- _parent = root
Which is lovely for the developer but absolutely not it for a user who just wants to oversee the node hierarchy π. So one of the possible filters would be:
FILTER => sub
{
my $s = shift ;
if('Tree::Simple' eq ref $s)
{
my $counter = 0 ;
return
(
'ARRAY'
, $s->{_children}
, map{[$counter++, $_->{_node}]} @{$s->{_children}} # index generation
) ;
}
return(Data::TreeDumper::DefaultNodesToDisplay($s)) ;
}
Which gives this much more readable output:
Tree::Simple through Data::TreeDumper2
|- 1
| `- 1.1
|- 2
| |- 2.1
| |- 2.1a
| `- 2.2
`- 3
Now what about counting the children nodes? Obsessed with this. The index generating code becomes:
map{[$counter++, "$_->{_node} [" . @{$_->{_children}} . "]"]} @{$s->{_children}}
Tree::Simple through Data::TreeDumper4
|- 1 [1]
| `- 1.1 [0]
|- 2 [3]
| |- 2.1 [0]
| |- 2.1a [0]
| `- 2.2 [0]
`- 3 [0]
π Filter chaining π
You can chain filters, bestie!! CreateChainingFilter takes a list of filtering sub references. And heads up β the filters must properly handle the third parameter passed to them. That part matters, don't skip it π
Say you want to chain a filter that adds a star before each hash key label with a filter that removes all (original) keys matching /^a/i. Boom:
sub AddStar
{
my $s = shift ;
my $level = shift ;
my $path = shift ;
my $keys = shift ;
if('HASH' eq ref $s)
{
$keys = [keys %$s] unless defined $keys ;
my @new_keys ;
for (@$keys)
{
if('' eq ref $_)
{
push @new_keys, [$_, "* $_"] ;
}
else
{
# another filter has changed the label
push @new_keys, [$_->[0], "* $_->[1]"] ;
}
}
return('HASH', undef, @new_keys) ;
}
return(Data::TreeDumper::DefaultNodesToDisplay($s)) ;
} ;
sub RemoveA
{
my $s = shift ;
my $level = shift ;
my $path = shift ;
my $keys = shift ;
if('HASH' eq ref $s)
{
$keys = [keys %$s] unless defined $keys ;
my @new_keys ;
for (@$keys)
{
if('' eq ref $_)
{
push @new_keys, $_ unless /^a/i ;
}
else
{
# another filter has changed the label
push @new_keys, $_ unless $_->[0] =~ /^a/i ;
}
}
return('HASH', undef, @new_keys) ;
}
return(Data::TreeDumper::DefaultNodesToDisplay($s)) ;
} ;
DumpTree($s, 'Chained filters', FILTER => CreateChainingFilter(\&AddStar, \&RemoveA)) ;
π³ Level Filters π³
You can define one filter per specific level, and if a filter for a specific level exists, it gets used instead of the global filter. Hierarchy, but make it custom β¨
LEVEL_FILTERS => {1 => \&FilterForLevelOne, 5 => \&FilterForLevelFive ... } ;
𧬠Type Filters π§¬
You can also define filters for specific types of references. And this filter type has the highest priority β it's the CEO of filters, periodt π
here's a very simple filter that will display the specified keys for the types
print DumpTree
(
$data,
'title',
TYPE_FILTERS =>
{
'Config::Hierarchical' => sub {'HASH', undef, qw(CATEGORIES) },
'PBS2::Node' => sub {'HASH', undef, qw(CONFIG DEPENDENCIES MATCH) },,
}
) ;
π Using filters as iterators π
Okay so this is lowkey my favorite part. You can iterate through your data structures and display the data yourself, manipulate the data structure, or go on a little search expedition. And while you're iterating through the data structure, you can prune arbitrary branches to speed processing up. Efficiency?? We love her π«Ά
# this example counts the nodes in a tree (hash based)
# a node is counted if it has a '__NAME' key
# any field that starts with '__' is considered private and we prune so we don't recurse in it
# anything that is not a hash (the part of the tree that interests us in this case) is pruned
my $number_of_nodes_in_the_dependency_tree = 0 ;
my $node_counter =
sub
{
my $tree = shift ;
if('HASH' eq ref $tree && exists $tree->{__NAME})
{
$number_of_nodes_in_the_dependency_tree++ if($tree->{__NAME} !~ /^__/) ;
return('HASH', $tree, grep {! /^__/} keys %$tree) ; # prune to run faster
}
else
{
return('SCALAR', 1) ; # prune
}
} ;
DumpTree($dependency_tree, '', NO_OUTPUT => 1, FILTER => $node_counter) ;
See the example under FILTER which passes arguments through Data::TreeDumper instead for using a closure as above π
πͺ Start level πͺ
This configuration option controls whether the tree trunk is displayed or not. Simple as that, babes.
START_LEVEL => 1:
$tree:
|- A [H1]
| |- a [H2]
| |- bbbbbb = CODE(0x8139fa0) [C3]
| |- c123 [C4 -> C3]
| `- d [R5]
| `- REF(0x8139fb8) [R5 -> C3]
|- ARRAY [A6]
| |- 0 [S7] = element_1
| |- 1 [S8] = element_2
START_LEVEL => 0:
$tree:
A [H1]
|- a [H2]
|- bbbbbb = CODE(0x8139fa0) [C3]
|- c123 [C4 -> C3]
`- d [R5]
`- REF(0x8139fb8) [R5 -> C3]
ARRAY [A6]
|- 0 [S7] = element_1
|- 1 [S8] = element_2
π ASCII vs ANSI π
You can direct Data::TreeDumper to output ANSI codes instead of ASCII characters. The display will be much nicer β the tradeoff being it takes slightly longer (but honestly not significant for small data structures, so don't stress π).
USE_ASCII => 0 # will use ANSI codes instead
π’ Display number of elements π’
DISPLAY_NUMBER_OF_ELEMENTS => 1
When set, the number of elements of every array and hash is displayed (not for objects based on hashes and arrays, just so we're clear).
Max depth of the dump, bestie π
This one controls the depth beyond which we do not recurse into a structure. Default is -1, and that means there's literally no maximum depth at all. Super useful when you just want to cap how much data gets shown instead of dumping the entire universe. π
MAX_DEPTH => 1
Number of elements not displayed because of the maximum depth limit π’
Bestie, Data::TreeDumper will still tell you how many elements a hash or array has β even the ones it can't show you because of that maximum depth setting. So you're never left wondering what's hiding down there. π
DISPLAY_NUMBER_OF_ELEMENTS_OVER_MAX_DEPTH => 1
Indentation π
Whatever you put in INDENTATION gets prepended to every single line of the tree dump. Every. Line. Periodt.
INDENTATION => ' ' ;
Custom glyphs β¨
Okay so you can fully change the glyphs Data::TreeDumper uses, and honestly? Iconic.
DumpTree(\$s, 's', , GLYPHS => ['. ', '. ', '. ', '. ']) ;
# output
s
. REF(0x813da3c) [H1]
. . A [H2]
. . . a [H3]
. . . b [H4]
. . . . a = 0 [S5]
. . . . b = 1 [S6]
. . . . c [H7]
. . . . . a = 1 [S8]
You must give four glyphs β four, no more no less β and they replace the standard glyphs ['| ', '|- ', '- ', ' ']. You can also set the package variable $Data::TreeDumper::Glyphs. And heads up: USE_ASCII` should be set, which it is by default. π
Level numbering and tagging π₯
Data::TreeDumper can prepend the level of the current line to the tree glyphs, and this is so good when you're searching through a tree dump β either with your eyeballs or with a pager. Main character searching behavior, fr fr.
NUMBER_LEVELS => 2
NUMBER_LEVELS => \&NumberingSub
NUMBER_LEVELS can be assigned a number or a sub reference. If it's a number, Data::TreeDumper uses that value to define the width of the field where the level is displayed. But if you want more control, you can define a sub that returns a string to be displayed on the left side of the tree glyphs. The example below tags all the nodes whose level is zero. π¦
print DumpTree($s, "Level numbering", NUMBER_LEVELS => 2) ;
sub GetLevelTagger
{
my $level_to_tag = shift ;
sub
{
my ($element, $level, $setup) = @_ ;
my $tag = "Level $level_to_tag => ";
if($level == 0)
{
return($tag) ;
}
else
{
return(' ' x length($tag)) ;
}
} ;
}
print DumpTree($s, "Level tagging", NUMBER_LEVELS => GetLevelTagger(0)) ;
Level coloring π
Another way to enhance the output for easier searching is to colorize it. Data::TreeDumper can colorize the glyph elements or whole levels. If your terminal supports ANSI codes, using Term::ANSIColors and Data::TreeDumper together can greatly ease the reading of large dumps. See the examples in 'color.pl'. π
COLOR_LEVELS => [\@color_codes, $reset_code]
When you pass an array reference, the first element is an array containing coloring codes. Those codes are indexed with the node level modulo the size of the array. The second element is used to reset the color after the glyph is displayed. And if that second element is an empty string, then the glyph and the rest of the level get colorized. πΈ
COLOR_LEVELS => \&LevelColoringSub
If COLOR_LEVEL is assigned a sub, that sub is called for each glyph element. It gets passed the following elements:
- the nodes depth (this allows you to selectively display elements at a certain depth)
It should return a coloring code and a reset code. If you return an empty string for the reset code, the whole node is displayed using the last glyph element color.
And if level numbering is on, it gets colorized too. β¨
Wrapping π«
Data::TreeDumper uses the Text::Wrap module to wrap your data so it fits your display. Entries can be wrapped multiple times so they snugly fit your screen. Cozy.
| | |- 1 [S21] = 1
| | `- 2 [S22] = 2
| `- 3 [OH23 -> R17]
|- ARRAY_ZERO [A24]
|- B [S25] = scalar
|- Long_name Long_name Long_name Long_name Long_name Long_name
| Long_name Long_name Long_name Long_name Long_name Long_name
| Long_name Long_name Long_name Long_name Long_name [S26] = 0
You can tell DTD to not wrap your text by setting NO_WRAP = 1. π
WRAP_WIDTH π
If this option is set, Data::TreeDumper will use it instead for the console width.
Custom Rendering π¨
Data::TreeDumper has a plug-in interface for other rendering formats, and the renderer callbacks are set by overriding the native renderer. Big thanks to Stevan Little, author of Tree::Simple::View, for getting Data::TreeDumper on this track. Go check out Data::TreeDumper::Renderer::DHTML. π
DumpTree
(
$s
, 'Tree'
, RENDERER =>
{
BEGIN => \&RenderDhtmlBegin
, NODE => \&RenderDhtmlNode
, END => \&RenderDhtmlEnd
# data needed by the renderer
, PREVIOUS_LEVEL => -1
, PREVIOUS_ADDRESS => 'ROOT'
}
) ;
Callbacks π
{RENDERER}{BEGIN}is called before the traversal of the data structure starts. This lets you set up the document (ex:: html header).
my ($title, $type_address, $element, $size, $perl_address, $setup) = @_ ;
1 $title
2 $type_address
3 $element
4 $perl_size
5 $perl_address
6 $setup
{RENDERER}{NODE}is called for each node in the data structure. The following arguments are passed to the callback:
1 $element
2 $level
3 $is_terminal (whether a deeper structure will follow or not)
4 $previous_level_separator (ASCII separators before this node)
5 $separator (ASCII separator for this element)
6 $element_name
7 $element_value
8 $td_address (address of the element, Ex: C12 or H34. Unique for each element)
9 $link_address (link to another element, may be undef)
10 $perl_size (size of the element in bytes, see option DISPLAY_PERL_SIZE)
11 $perl_address (address (physical) of the element, see option DISPLAY_PERL_ADDRESS)
12 $setup (the dumper's settings)
{RENDERER}{END}is called after the last node has been processed.{RENDERER}{ ... }Arguments to the renderer can be stored within the{RENDERER}hash.
Renderer modules π§
Renderers should be defined in modules under Data::TreeDumper::Renderer and should define a function called GetRenderer. GetRenderer can be passed whatever arguments the developer wishes. It is acceptable for the modules to also export a specific sub. π
print DumpTree($s, 'Tree', Data::TreeDumper::Renderer::DHTML::GetRenderer()) ;
or
print DumpTree($s, 'Tree', GetDhtmlRenderer()) ;
If {RENDERER} is set to a scalar, Data::TreeDumper will load the specified module if it exists. GetRenderer will be called without arguments.
print DumpTree($s, 'Tree', RENDERER => 'DHTML') ;
If {RENDERER}{NAME} is set to a scalar, Data::TreeDumper will load the specified module if it exists. GetRenderer will be called without arguments. Arguments to the renderer can either be passed to the GetRenderer sub or as elements in the {RENDERER} hash.
print DumpTree($s, 'Tree', RENDERER => {NAME => 'DHTML', STYLE => \$style) ;
Zero-width console π«₯
When no console exists β like when you're redirecting to a file, for example β Data::TreeDumper uses the variable VIRTUAL_WIDTH instead. Default is 120. π
VIRTUAL_WIDTH => 120 ;
OVERRIDE list π
COLOR_LEVELSDISPLAY_ADDRESSDISPLAY_PATHDISPLAY_PERL_SIZEDISPLAY_ROOT_ADDRESSDISPLAY_PERL_ADDRESSFILTERGLYPHSINDENTATIONLEVEL_FILTERSMAX_DEPTHDISPLAY_NUMBER_OF_ELEMENTS_OVER_MAX_DEPTHNUMBER_LEVELSQUOTE_HASH_KEYSDISPLAY_NO_VALUEQUOTE_VALUESREPLACEMENT_LISTSTART_LEVELUSE_ASCIIWRAP_WIDTHVIRTUAL_WIDTHNO_OUTPUTDISPLAY_OBJECT_TYPEDISPLAY_INHERITANCEDISPLAY_TIEDISPLAY_AUTOLOAD
π Interface π
Package Data (Γ la Data::Dumper (as is the silly naming scheme)) π
Configuration Variables βοΈ
$Data::TreeDumper::Startlevel = 1 ;
$Data::TreeDumper::Useascii = 1 ;
$Data::TreeDumper::Maxdepth = -1 ;
$Data::TreeDumper::Indentation = '' ;
$Data::TreeDumper::Virtualwidth = 120 ;
$Data::TreeDumper::Displayrootaddress = 0 ;
$Data::TreeDumper::Displayaddress = 1 ;
$Data::TreeDumper::Displaypath = 0 ;
$Data::TreeDumper::Displayobjecttype = 1 ;
$Data::TreeDumper::Displayinheritance = 0 ;
$Data::TreeDumper::Displaytie = 0 ;
$Data::TreeDumper::Displayautoload = 0 ;
$Data::TreeDumper::Displayperlsize = 0 ;
$Data::TreeDumper::Displayperladdress = 0 ;
$Data::TreeDumper::Filter = \&FlipEverySecondOne ;
$Data::TreeDumper::Levelfilters = {1 => \&Filter_1, 5 => \&Filter_5} ;
$Data::TreeDumper::Numberlevels = 0 ;
$Data::TreeDumper::Glyphs = ['| ', '|- ', '`- ', ' '] ;
$Data::TreeDumper::Colorlevels = undef ;
$Data::TreeDumper::Nooutput = 0 ; # generate an output
$Data::TreeDumper::Quotehashkeys = 0 ;
$Data::TreeDumper::Displaycallerlocation = 0 ;
API π
PrintTree prints on STDOUT the output of DumpTree.
DumpTree uses the configuration variables defined above. It takes the following arguments:
[1] structure_to_dump
[2] title, a string to prepended to the tree (optional)
[3] overrides (optional)
print DumpTree($s, "title", MAX_DEPTH => 1) ;
DumpTrees uses the configuration variables defined above. It takes the following arguments
[1] One or more array references containing
[a] structure_to_dump
[b] title, a string to prepended to the tree (optional)
[c] overrides (optional)
[2] overrides (optional)
print DumpTrees
(
[$s, "title", MAX_DEPTH => 1]
, [$s2, "other_title", DISPLAY_ADDRESS => 0]
, USE_ASCII => 1
, MAX_DEPTH => 5
) ;
π Bugs π
None that I know of in this release but plenty, lurking in the dark corners, waiting to be found. Spooky. π
πΈ Examples πΈ
Four examples files are included in the distribution.
usage.plshows you how you can useData::TreeDumper.filters.plshows you how to do advance filtering.colors.plshows you how to colorize a dump.try_it.plis meant as a scratch pad for you to tryData::TreeDumper.
π DEPENDENCY π
Text::Wrap.Term::SizeorWin32::Console.- Optional
Devel::Sizeif you wantData::TreeDumperto show perl sizes for the tree elements.
β¨ EXPORT β¨
DumpTree, DumpTrees and CreateChainingFilter.
π AUTHOR π
Khemir Nadim ibn Hamouda. <nadim@khemir.net> β the literal icon who made this whole thing, no cap π
And a huge shoutout to Ed Avis for showing interest and literally pushing him to re-write the documentation. Bestie behaviour fr fr, we love a supportive mutual π«Ά
Copyright (c) 2003-2006 Nadim Ibn Hamouda el Khemir. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
If you find any value in this module, mail me! All hints, tips, flames and wishes are welcome at <nadim@khemir.net> β¨
No like literally mail the man. He asked. He wants the flames. Respect the main character energy π
π SEE ALSO π
Data::TreeDumper::00.Data::Dumper.Data::TreeDumper::Renderer::DHTML.Devel::Size::Report.Devel::Size.PBS: the Perl Build System from which Data::TreeDumper was extracted.
Go read the friends, they're all part of the same extended universe π
π POD ERRORS π
Hey! The above document had some coding errors, which are explained below:
- Around line 806:
=poddirectives shouldn't be over one line long! Ignoring all 7 lines of content
Not the pod directives doing too much π 7 whole lines of content just ignored, gone, off the grid. We do not talk about it π
And that's a wrap, bestie! πβ¨ This whole saga was ripped straight from perl v5.40.1, dated 2026-02-03, under the glow of TreeDumper(3pm). Now go dump some trees, tag some levels, and colour your console like the icon you are ππ¦πΈ
π¦ where this page comes from
- ubuntu resolute: libdata-treedumper-perl 0.43-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: libdata-treedumper-perl 0.43-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms