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.