| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Module::Overview; |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=head1 NAME |
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
Module::Overview - print/graph module(s) information |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
use Module::Overview; |
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
my $mo = Module::Overview->new({ |
|
12
|
|
|
|
|
|
|
'module_name' => 'Module::Overview', |
|
13
|
|
|
|
|
|
|
}); |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
print $mo->text_simpletable; |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
my $graph = $mo->graph; # Graph::Easy |
|
18
|
|
|
|
|
|
|
open my $DOT, '|dot -Tpng -o graph.png' or die ("Cannot open pipe to dot: $!"); |
|
19
|
|
|
|
|
|
|
print $DOT $graph->as_graphviz; |
|
20
|
|
|
|
|
|
|
close $DOT; |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=cut |
|
23
|
|
|
|
|
|
|
|
|
24
|
1
|
|
|
1
|
|
61915
|
use warnings; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
27
|
|
|
25
|
1
|
|
|
1
|
|
5
|
use strict; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
33
|
|
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
our $VERSION = '0.01'; |
|
28
|
|
|
|
|
|
|
|
|
29
|
1
|
|
|
1
|
|
21
|
use 5.010; |
|
|
1
|
|
|
|
|
6
|
|
|
|
1
|
|
|
|
|
40
|
|
|
30
|
|
|
|
|
|
|
|
|
31
|
1
|
|
|
1
|
|
887
|
use Class::Sniff; |
|
|
1
|
|
|
|
|
262625
|
|
|
|
1
|
|
|
|
|
45
|
|
|
32
|
1
|
|
|
1
|
|
13
|
use Text::SimpleTable; |
|
|
1
|
|
|
|
|
4
|
|
|
|
1
|
|
|
|
|
23
|
|
|
33
|
1
|
|
|
1
|
|
1724
|
use Module::ExtractUse; |
|
|
1
|
|
|
|
|
173058
|
|
|
|
1
|
|
|
|
|
36
|
|
|
34
|
1
|
|
|
1
|
|
10
|
use Graph::Easy; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
25
|
|
|
35
|
1
|
|
|
1
|
|
5
|
use Carp 'confess'; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
56
|
|
|
36
|
|
|
|
|
|
|
|
|
37
|
1
|
|
|
1
|
|
5
|
use base 'Class::Accessor::Fast'; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
776
|
|
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
__PACKAGE__->mk_accessors(qw{ |
|
40
|
|
|
|
|
|
|
module_name |
|
41
|
|
|
|
|
|
|
recursive |
|
42
|
|
|
|
|
|
|
recursion_filter |
|
43
|
|
|
|
|
|
|
hide_methods |
|
44
|
|
|
|
|
|
|
}); |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
sub new { |
|
47
|
2
|
|
|
2
|
1
|
47483
|
my $class = shift; |
|
48
|
2
|
|
|
|
|
36
|
my $self = $class->SUPER::new(@_); |
|
49
|
|
|
|
|
|
|
|
|
50
|
2
|
50
|
|
|
|
35
|
confess('module_name is mandatory property') |
|
51
|
|
|
|
|
|
|
if not $self->module_name; |
|
52
|
|
|
|
|
|
|
|
|
53
|
2
|
|
|
|
|
29
|
return $self; |
|
54
|
|
|
|
|
|
|
} |
|
55
|
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
sub get { |
|
57
|
2
|
|
|
2
|
1
|
4
|
my $self = shift; |
|
58
|
2
|
|
33
|
|
|
8
|
my $module_name = shift || $self->{'module_name'}; |
|
59
|
|
|
|
|
|
|
|
|
60
|
2
|
|
|
|
|
4
|
my $recursion_filter = $self->{'recursion_filter'}; |
|
61
|
|
|
|
|
|
|
|
|
62
|
2
|
|
|
|
|
5
|
my %overview; |
|
63
|
|
|
|
|
|
|
|
|
64
|
1
|
|
|
1
|
|
11
|
eval qq{ use $module_name }; |
|
|
1
|
|
|
1
|
|
2
|
|
|
|
1
|
|
|
|
|
12
|
|
|
|
1
|
|
|
|
|
10
|
|
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
12
|
|
|
|
2
|
|
|
|
|
231
|
|
|
65
|
2
|
50
|
|
|
|
40
|
warn 'error loading "'.$module_name.'" - '.$@ if $@; |
|
66
|
|
|
|
|
|
|
|
|
67
|
2
|
|
|
|
|
24
|
my $sniff = Class::Sniff->new({class => $module_name}); |
|
68
|
2
|
|
|
|
|
1639034
|
my $euse = Module::ExtractUse->new; |
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
#my $graph = $sniff->graph; # Graph::Easy |
|
71
|
|
|
|
|
|
|
#print $sniff->report; |
|
72
|
|
|
|
|
|
|
#print join("\n", $sniff->methods), "\n"; |
|
73
|
2
|
|
|
|
|
25
|
$overview{'class'} = $module_name; |
|
74
|
2
|
|
|
|
|
618
|
$overview{'parents'} = [ |
|
75
|
2
|
|
|
|
|
39
|
grep { not ($_ ~~ [qw(Exporter)]) } # skip uninteresting |
|
76
|
2
|
|
|
|
|
10
|
grep { $_ !~ m{^[0-9._]+$} } # skip perl versions |
|
77
|
|
|
|
|
|
|
$sniff->parents |
|
78
|
|
|
|
|
|
|
]; |
|
79
|
2
|
|
|
|
|
13
|
delete $overview{'parents'} |
|
80
|
2
|
50
|
|
|
|
6
|
if not @{$overview{'parents'}}; |
|
81
|
5
|
|
|
|
|
18
|
$overview{'classes'} = [ |
|
82
|
5
|
|
|
|
|
20
|
grep { not ($_ ~~ $overview{'parents'}) } # skip parents |
|
83
|
5
|
|
|
|
|
16
|
grep { not ($_ ~~ [qw(Exporter)]) } # skip uninteresting |
|
84
|
7
|
|
|
|
|
25
|
grep { $_ !~ m{^[0-9._]+$} } # skip perl versions |
|
85
|
2
|
|
|
|
|
12
|
grep { $_ ne $module_name } # skip self |
|
86
|
|
|
|
|
|
|
$sniff->classes |
|
87
|
|
|
|
|
|
|
]; |
|
88
|
2
|
|
|
|
|
10
|
delete $overview{'classes'} |
|
89
|
2
|
50
|
|
|
|
6
|
if not @{$overview{'classes'}}; |
|
90
|
|
|
|
|
|
|
|
|
91
|
2
|
|
|
|
|
8
|
my $module_name_path = $module_name.'.pm'; |
|
92
|
2
|
|
|
|
|
11
|
$module_name_path =~ s{::}{/}g; |
|
93
|
2
|
50
|
33
|
|
|
151
|
if (exists $INC{$module_name_path} and (-r $INC{$module_name_path})) { |
|
94
|
2
|
|
|
|
|
14
|
$euse->extract_use($INC{$module_name_path}); |
|
95
|
2
|
|
|
|
|
75086
|
$DB::single=1; |
|
96
|
5
|
50
|
|
|
|
19
|
$overview{'uses'} = [ |
|
97
|
7
|
|
|
|
|
17
|
grep { (not $recursion_filter) or ($_ =~ m/$recursion_filter/) } # filter modules |
|
98
|
9
|
|
|
|
|
34
|
grep { not ($_ ~~ $overview{'parents'}) } # skip parents |
|
99
|
10
|
|
|
|
|
80
|
grep { not ($_ ~~ [qw(strict warnings constant vars Exporter)]) } # skip uninteresting |
|
100
|
2
|
|
|
|
|
13
|
grep { $_ !~ m{^[0-9._]+$} } # skip perl versions |
|
101
|
|
|
|
|
|
|
sort |
|
102
|
|
|
|
|
|
|
$euse->array |
|
103
|
|
|
|
|
|
|
]; |
|
104
|
2
|
|
|
|
|
11
|
delete $overview{'uses'} |
|
105
|
2
|
100
|
|
|
|
4
|
if not @{$overview{'uses'}}; |
|
106
|
|
|
|
|
|
|
} |
|
107
|
|
|
|
|
|
|
|
|
108
|
2
|
|
|
|
|
3
|
my (@methods, @methods_imported); |
|
109
|
2
|
|
|
|
|
4
|
while (my ($method, $classes) = each %{$sniff->{methods}}) { |
|
|
60
|
|
|
|
|
191
|
|
|
110
|
58
|
|
|
|
|
59
|
my $class = ${$classes}[0]; |
|
|
58
|
|
|
|
|
87
|
|
|
111
|
58
|
100
|
|
|
|
165
|
my $method_desc = $method.'()'.($class ne $module_name ? ' ['.$class.']' : ''); |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
# source - Pod::Coverage _get_syms() |
|
114
|
|
|
|
|
|
|
# see if said method wasn't just imported from elsewhere |
|
115
|
1
|
|
|
1
|
|
5720
|
my $glob = do { no strict 'refs'; \*{$class.'::'.$method} }; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
816
|
|
|
|
58
|
|
|
|
|
60
|
|
|
|
58
|
|
|
|
|
59
|
|
|
|
58
|
|
|
|
|
172
|
|
|
116
|
58
|
|
|
|
|
168
|
my $o = B::svref_2object($glob); |
|
117
|
|
|
|
|
|
|
# in 5.005 this flag is not exposed via B, though it exists |
|
118
|
58
|
|
50
|
|
|
65
|
my $imported_cv = eval { B::GVf_IMPORTED_CV() } || 0x80; |
|
119
|
58
|
|
|
|
|
126
|
my $imported = $o->GvFLAGS & $imported_cv; |
|
120
|
|
|
|
|
|
|
|
|
121
|
58
|
100
|
|
|
|
108
|
if ($imported) { |
|
122
|
18
|
|
|
|
|
27
|
push @methods_imported, $method_desc; |
|
123
|
18
|
|
|
|
|
38
|
next; |
|
124
|
|
|
|
|
|
|
} |
|
125
|
|
|
|
|
|
|
|
|
126
|
40
|
|
|
|
|
103
|
push @methods, $method_desc; |
|
127
|
|
|
|
|
|
|
} |
|
128
|
2
|
100
|
66
|
|
|
47
|
$overview{'methods'} = [ sort @methods ] |
|
129
|
|
|
|
|
|
|
if @methods and (not $self->{'hide_methods'}); |
|
130
|
2
|
100
|
66
|
|
|
21
|
$overview{'methods_imported'} = [ sort @methods_imported ] |
|
131
|
|
|
|
|
|
|
if @methods_imported and (not $self->{'hide_methods'}); |
|
132
|
|
|
|
|
|
|
|
|
133
|
2
|
|
|
|
|
77
|
return \%overview; |
|
134
|
|
|
|
|
|
|
} |
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
sub text_simpletable { |
|
137
|
2
|
|
|
2
|
1
|
2148
|
my $self = shift; |
|
138
|
2
|
|
33
|
|
|
17
|
my $module_name = shift || $self->{'module_name'}; |
|
139
|
|
|
|
|
|
|
|
|
140
|
2
|
|
|
|
|
11
|
my $module_overview = $self->get($module_name); |
|
141
|
2
|
|
|
|
|
358
|
my $table = Text::SimpleTable->new(16, 60); |
|
142
|
|
|
|
|
|
|
|
|
143
|
2
|
|
|
|
|
93
|
$table->row('class', $module_overview->{'class'}); |
|
144
|
2
|
50
|
33
|
|
|
174
|
if ($module_overview->{'parents'} || $module_overview->{'classes'}) { |
|
145
|
2
|
|
|
|
|
10
|
$table->hr; |
|
146
|
|
|
|
|
|
|
} |
|
147
|
2
|
50
|
|
|
|
37
|
if ($module_overview->{'parents'}) { |
|
148
|
2
|
|
|
|
|
5
|
$table->row('parents', join("\n", @{$module_overview->{'parents'}})); |
|
|
2
|
|
|
|
|
11
|
|
|
149
|
|
|
|
|
|
|
} |
|
150
|
2
|
50
|
|
|
|
136
|
if ($module_overview->{'classes'}) { |
|
151
|
2
|
|
|
|
|
4
|
$table->row('classes', join("\n", @{$module_overview->{'classes'}})); |
|
|
2
|
|
|
|
|
11
|
|
|
152
|
|
|
|
|
|
|
} |
|
153
|
2
|
100
|
|
|
|
124
|
if ($module_overview->{'uses'}) { |
|
154
|
1
|
|
|
|
|
4
|
$table->hr; |
|
155
|
1
|
|
|
|
|
11
|
$table->row('uses', join("\n", @{$module_overview->{'uses'}})); |
|
|
1
|
|
|
|
|
5
|
|
|
156
|
|
|
|
|
|
|
} |
|
157
|
2
|
100
|
|
|
|
82
|
if ($module_overview->{'methods'}) { |
|
158
|
1
|
|
|
|
|
5
|
$table->hr; |
|
159
|
1
|
|
|
|
|
14
|
$table->row('methods', join("\n", @{$module_overview->{'methods'}})); |
|
|
1
|
|
|
|
|
10
|
|
|
160
|
|
|
|
|
|
|
} |
|
161
|
2
|
100
|
|
|
|
161
|
if ($module_overview->{'methods_imported'}) { |
|
162
|
1
|
|
|
|
|
3
|
$table->hr; |
|
163
|
1
|
|
|
|
|
11
|
$table->row('methods_imported', join("\n", @{$module_overview->{'methods_imported'}})); |
|
|
1
|
|
|
|
|
5
|
|
|
164
|
|
|
|
|
|
|
} |
|
165
|
2
|
|
|
|
|
98
|
return $table->draw; |
|
166
|
|
|
|
|
|
|
} |
|
167
|
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
sub graph { |
|
169
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
170
|
0
|
|
0
|
|
|
|
my $module_name = shift || $self->{'module_name'}; |
|
171
|
0
|
|
0
|
|
|
|
my $graph = shift || Graph::Easy->new(); |
|
172
|
|
|
|
|
|
|
|
|
173
|
0
|
|
|
|
|
|
my $recursion_filter = $self->{'recursion_filter'}; |
|
174
|
0
|
0
|
0
|
|
|
|
return $graph |
|
175
|
|
|
|
|
|
|
if ($recursion_filter and ($module_name !~ m/$recursion_filter/)); |
|
176
|
|
|
|
|
|
|
|
|
177
|
0
|
|
|
|
|
|
my $module_overview = $self->get($module_name); |
|
178
|
|
|
|
|
|
|
|
|
179
|
0
|
|
|
|
|
|
$graph->add_node($module_name)->set_attributes({'font-size' => '150%', 'textstyle' => 'bold', 'fill' => 'lightgrey'}); |
|
180
|
0
|
0
|
|
|
|
|
if ($module_overview->{'parents'}) { |
|
181
|
0
|
|
|
|
|
|
my $module_name_parent = $module_name.' parent'; |
|
182
|
0
|
|
|
|
|
|
$graph->add_node($module_name_parent)->set_attributes({ |
|
183
|
|
|
|
|
|
|
'label' => 'parent', |
|
184
|
|
|
|
|
|
|
'shape' => 'ellipse', |
|
185
|
|
|
|
|
|
|
'font-size' => '75%', |
|
186
|
|
|
|
|
|
|
}); |
|
187
|
0
|
|
|
|
|
|
$graph->add_edge_once($module_name => $module_name_parent); |
|
188
|
|
|
|
|
|
|
|
|
189
|
0
|
|
|
|
|
|
foreach my $parent (@{$module_overview->{'parents'}}) { |
|
|
0
|
|
|
|
|
|
|
|
190
|
0
|
|
|
|
|
|
$graph->add_node($parent); |
|
191
|
|
|
|
|
|
|
|
|
192
|
0
|
|
|
|
|
|
my $e = $graph->add_edge_once($module_name_parent, $parent); |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
#my $e = $graph->add_edge_once($module_name, $parent, 'parent'); |
|
195
|
|
|
|
|
|
|
|
|
196
|
0
|
0
|
0
|
|
|
|
$self->graph($parent, $graph) |
|
197
|
|
|
|
|
|
|
if ($e and $self->{'recursive'}); |
|
198
|
|
|
|
|
|
|
} |
|
199
|
|
|
|
|
|
|
} |
|
200
|
0
|
0
|
|
|
|
|
if ($module_overview->{'uses'}) { |
|
201
|
0
|
|
|
|
|
|
my $module_name_use = $module_name.' use'; |
|
202
|
0
|
|
|
|
|
|
$graph->add_node($module_name_use)->set_attributes({ |
|
203
|
|
|
|
|
|
|
'label' => 'use', |
|
204
|
|
|
|
|
|
|
'shape' => 'ellipse', |
|
205
|
|
|
|
|
|
|
'font-size' => '75%', |
|
206
|
|
|
|
|
|
|
}); |
|
207
|
0
|
|
|
|
|
|
$graph->add_edge_once($module_name => $module_name_use); |
|
208
|
|
|
|
|
|
|
|
|
209
|
0
|
|
|
|
|
|
foreach my $use (@{$module_overview->{'uses'}}) { |
|
|
0
|
|
|
|
|
|
|
|
210
|
0
|
|
|
|
|
|
$graph->add_node($use); |
|
211
|
|
|
|
|
|
|
|
|
212
|
0
|
|
|
|
|
|
my $e = $graph->add_edge_once($module_name_use, $use); |
|
213
|
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
#my $e = $graph->add_edge_once($module_name, $use, 'use'); |
|
215
|
|
|
|
|
|
|
|
|
216
|
0
|
0
|
0
|
|
|
|
$self->graph($use, $graph) |
|
217
|
|
|
|
|
|
|
if ($e and $self->{'recursive'}); |
|
218
|
|
|
|
|
|
|
} |
|
219
|
|
|
|
|
|
|
} |
|
220
|
0
|
0
|
|
|
|
|
if ($module_overview->{'methods'}) { |
|
221
|
0
|
|
|
|
|
|
my $module_name_methods = $module_name.' methods'; |
|
222
|
0
|
|
|
|
|
|
$graph->add_node($module_name_methods)->set_attributes({ |
|
223
|
0
|
|
|
|
|
|
'label' => join('\n', @{$module_overview->{'methods'}}), |
|
224
|
|
|
|
|
|
|
'font-size' => '75%', |
|
225
|
|
|
|
|
|
|
'align' => 'left', |
|
226
|
|
|
|
|
|
|
'borderstyle' => 'dashed', |
|
227
|
|
|
|
|
|
|
}); |
|
228
|
0
|
|
|
|
|
|
$graph->add_edge_once($module_name => $module_name_methods, 'methods'); |
|
229
|
|
|
|
|
|
|
} |
|
230
|
0
|
0
|
|
|
|
|
if ($module_overview->{'methods_imported'}) { |
|
231
|
0
|
|
|
|
|
|
my $module_name_methods = $module_name.' methods_imported'; |
|
232
|
0
|
|
|
|
|
|
$graph->add_node($module_name_methods)->set_attributes({ |
|
233
|
0
|
|
|
|
|
|
'label' => join('\n', @{$module_overview->{'methods_imported'}}), |
|
234
|
|
|
|
|
|
|
'font-size' => '75%', |
|
235
|
|
|
|
|
|
|
'align' => 'left', |
|
236
|
|
|
|
|
|
|
'borderstyle' => 'dashed', |
|
237
|
|
|
|
|
|
|
}); |
|
238
|
0
|
|
|
|
|
|
$graph->add_edge_once($module_name => $module_name_methods, 'methods imported'); |
|
239
|
|
|
|
|
|
|
} |
|
240
|
|
|
|
|
|
|
|
|
241
|
0
|
|
|
|
|
|
return $graph; |
|
242
|
|
|
|
|
|
|
} |
|
243
|
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
'OV?'; |
|
245
|
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
__END__ |