This code:
#!/usr/bin/env perl
use strict;
use warnings;
use Class::Sniff;
use HTML::TokeParser::Simple;
my @sniffs = Class::Sniff->new_from_namespace({
namespace => 'HTML::TokeParser::Simple',
universal => 1,
});
my $graph = $sniffs[0]->combine_graphs( @sniffs[ 1 .. $#sniffs ] );
my $graphviz = $graph->as_graphviz();
open my $DOT, '|dot -Tpng -o graph.png' or die("Cannot open pipe to dot: $!");
print $DOT $graphviz;
... produces this graph.
It's a bit hackish, but now, as long as your code is loaded in memory when you run this, you can easily generate full inheritance graphs for your application.
sub new_from_namespace {
my ( $class, $arg_for ) = @_;
my $namespace = delete $arg_for->{namespace}
or Carp::croak("new_from_namespace requires a 'namespace' argument");
my @sniffs;
my %seen;
my $new_sniff = sub {
my $symbol_name = shift;
no warnings 'numeric';
return if $seen{$symbol_name}++; # prevent infinite loops
if ( $symbol_name =~ /^$namespace/ ) {
$symbol_name =~ s/::$//;
$arg_for->{class} = $symbol_name;
push @sniffs => Class::Sniff->new($arg_for);
}
return 1;
};
B::walksymtable( \%::, 'NAME', $new_sniff );
return @sniffs;
}
Just for giggles, I ran it with the namespace of '.'. Since Perl cannot distinguish between OO and procedural code you see every namespace loaded.
Here's a closer look at the %B:: inheritance hierarchy.
Re:Blimey
Ovid on 2009-02-16T09:35:42
Wow. I'm practically blushing over here
:) If you can think of anything else I could add which can be determined via runtime analysis (though a combination of this and Perl::Critic might be good), let me know. I still have lots of bugs and loose ends to work out, but I'm happy to know it's helping folks.