File Coverage

blib/lib/CallGraph/Dumper.pm
Criterion Covered Total %
statement 53 54 98.1
branch 17 18 94.4
condition 7 9 77.7
subroutine 8 8 100.0
pod 2 3 66.6
total 87 92 94.5


line stmt bran cond sub pod time code
1             package CallGraph::Dumper;
2              
3             $VERSION = '0.55';
4              
5 1     1   6 use strict;
  1         1  
  1         30  
6 1     1   5 use warnings;
  1         3  
  1         23  
7 1     1   6 use Carp;
  1         2  
  1         749  
8              
9             =head1 NAME
10              
11             CallGraph::Dumper - Dump a call graph into a string representation
12              
13             =head1 SYNOPSIS
14              
15             my $dumper = CallGraph::Dumper->new(root => $root,
16             indent => 8, dups => 0);
17             print $dumper->dump;
18              
19             =head1 DESCRIPTION
20              
21             This module dumps a call graph into a string representation. The output
22             looks something like this:
23              
24             MAIN
25             EXTSUB *
26             1 SUB1
27             SUB11
28             SUB12
29             SUB2
30             SUB1 (1)
31             SUB21
32              
33             This means that MAIN calls EXTSUB, which is labeled with an asterisk because it
34             is external (meaning it is not defined within the program that was parsed),
35             SUB1, and SUB2. SUB1 calls SUB11 and SUB12. SUB2 calls SUB1; to avoid
36             duplication, a link is made by labeling SUB1 with a 1. This is the default
37             behavior, with 'dups' => 0. When dups => 1, the branch is duplicated:
38              
39             MAIN
40             EXTSUB *
41             SUB1
42             SUB11
43             SUB12
44             SUB2
45             SUB1
46             SUB11
47             SUB12
48             SUB21
49              
50             In case of recursion, the label system is used even with dups => 1, to avoid
51             an endless loop.
52              
53             =head1 METHODS
54              
55             =over
56              
57             =item my $sub = CallGraph::Dumper->new(root => $root, option => value, ...)
58              
59             Creates a new dumper. The root option must be given and it must be a
60             CallGraph::Node object. The other options are the following:
61              
62             =over
63              
64             =item indent
65            
66             The number of spaces to indent each call level. The default is 8.
67              
68             =item dups
69              
70             If true, duplicate a branch that has already been called. If false,
71             place a level pointing to the first place where the branch was defined.
72             The default is false.
73              
74             =back
75              
76             =cut
77              
78             sub new {
79 6     6 1 15 my ($class, %opts) = @_;
80 6   33     49 my $self = bless {
81             indent => 8,
82             dups => 0,
83             %opts,
84             }, ref $class || $class;
85 6 50       22 unless ($self->{root}) { croak "${class}->new: unspecified 'root'" }
  0         0  
86 6         12 $self->init;
87 6         17 $self;
88             }
89              
90             sub init {
91 6     6 0 10 my ($self) = @_;
92 6         14 $self->{tree} = $self->{root};
93             }
94              
95             =item my $dump = $dumper->dump
96              
97             Turn the call graph into a string representation.
98              
99             =cut
100              
101             sub dump {
102 6     6 1 10 my ($self) = @_;
103 6         196 $self->{labels} = {}; # used for linking duplicate calls
104 6         10 $self->{used} = {}; # used for linking duplicate calls
105 6         11 $self->{label_count} = 1; # used for linking duplicate calls
106 6         15 $self->_paint($self->{tree});
107 6         19 $self->_dump($self->{tree}, 0);
108             }
109              
110             sub _paint {
111 59     59   105 my ($self, $node, %parents) = @_;
112 59         127 my $name = $node->name;
113 59         88 my $parents = $self->{parents};
114 59 100       100 if ($parents{$name}) {
115             #warn "found a loop at $name\n";
116 4         7 $self->{reuse}{$name} = 1;
117 4         26 return;
118             } else {
119 55         74 $parents{$name} = 1;
120             }
121 55 100 100     209 if(! $self->{dups} and defined $self->{reuse}{$name}) {
122 4         12 $self->{reuse}{$name} = 1;
123             } else {
124 51         112 $self->{reuse}{$name} = 0;
125 51         115 for my $child ($node->calls) {
126 53         123 $self->_paint($child, %parents);
127             }
128             }
129            
130             }
131              
132             # n
133             sub _dump {
134 58     58   68 my ($self, $node, $level) = @_;
135 58         53 my $ret;
136 58         179 my $name = $node->name;
137 58         85 my $sw = $self->{indent};
138 58 100       107 my $left_label = $level == 0 ? '' : ' ' x $sw;
139 58 100       122 my $right_label = $node->type eq 'external' ? ' *' : '';
140 58 100 100     257 if (not $self->{labels}{$name} and $self->{reuse}{$name}) {
141 7         17 $self->{labels}{$name} = $self->{label_count}++;
142             }
143 58         84 my $label = $self->{labels}{$name};
144              
145 58 100       93 if ($label) {
146 15 100       29 if (! $self->{used}{$name}) {
147 7         13 $self->{used}{$name} = 1;
148 7         26 $left_label = sprintf "%-${sw}i", $label;
149             } else {
150 8         16 $right_label = " ($label)";
151             }
152             }
153 58         138 $ret .= $left_label . ' ' x ($sw * ($level-1)) ."$name" . $right_label . "\n";
154              
155 58 100       104 unless ($right_label) {
156 44         96 for my $child ($node->calls) {
157 52         124 $ret .= $self->_dump($child, $level+1);
158             }
159             }
160 58         219 $ret;
161             }
162              
163              
164             1;
165              
166             =back
167              
168             =head1 VERSION
169              
170             0.55
171              
172             =head1 SEE ALSO
173              
174             L, L, L
175              
176             =head1 AUTHOR
177              
178             Ivan Tubert Eitub@cpan.orgE
179              
180             =head1 COPYRIGHT
181              
182             Copyright (c) 2004 Ivan Tubert. All rights reserved. This program is free
183             software; you can redistribute it and/or modify it under the same terms as
184             Perl itself.
185              
186             =cut
187              
188