Not on the CPAN yet because it's not finished and I don't have documentation, but I'm hosting it on github. Here's a passing test program:
#!/usr/bin/perl
use strict;
use warnings;
use Test::Most qw/no_plan die/;
use Class::Sniff;
{
package Abstract;
sub new { bless {} => shift }
sub foo { }
sub bar { }
sub baz { }
package Child1;
our @ISA = 'Abstract';
sub foo { }
package Child2;
our @ISA = 'Abstract';
sub foo { }
sub bar { }
package Grandchild;
our @ISA = qw;
sub foo { } # diamond inheritance
sub bar { } # Not a problem because it's inherited through 1 path
sub quux { } # no inheritance
}
can_ok 'Class::Sniff', 'new';
my $sniff = Class::Sniff->new( { class => 'Grandchild' } );
can_ok $sniff, 'paths';
my $expected_paths = [
[ 'Grandchild', 'Child1', 'Abstract' ],
[ 'Grandchild', 'Child2', 'Abstract' ]
];
eq_or_diff [$sniff->paths], $expected_paths,
'... and it should report inheritance paths';
{
package One;
our @ISA = qw/Two Three/;
package Two;
package Three;
our @ISA = qw/Four Six/;
package Four;
our @ISA = 'Five';
package Five;
package Six;
}
# 5
# |
# 4 6
# | /
# 2 3
# \ |
# 1
# 1 -> 2
# 1 -> 3 -> 4 -> 5
# 1 -> 3 -> 6
my $complex_sniff = Class::Sniff->new({class => 'One'});
$expected_paths = [
[ 'One', 'Two' ],
[ 'One', 'Three', 'Four', 'Five' ],
[ 'One', 'Three', 'Six' ]
];
eq_or_diff [$complex_sniff->paths], $expected_paths,
'... even for convoluted hierarchies';
can_ok $sniff, 'overridden';
my $expected_overridden = {
'bar' => [ 'Grandchild', 'Abstract', 'Child2' ],
'foo' => [ 'Grandchild', 'Child1', 'Abstract', 'Child2' ]
};
eq_or_diff $sniff->overridden, $expected_overridden,
'... and it should return an HoA with overridden methods and the classes';
can_ok $sniff, 'unreachable';
my $expected_unreachable = {
'bar' => [ 'Child2' ],
'foo' => [ 'Child2' ]
};
eq_or_diff $sniff->unreachable, $expected_unreachable,
'... and it should return an HoA with unreachable methods and the classes';
"Unreachable" methods are those which are unreachable by Perl's left-most, depth-first inheritance search order. I don't have support for C3. Also, it's possible to call "unreachable" methods by explicit name and I can't check for that (even PPI would have limitations here), but so far, I'm pretty pleased with this.
Update: OK, I lied. I just added docs and it's on its way to the CPAN.