Class::Sniff Now Detects "Unreachable" Methods

Ovid on 2009-02-01T15:21:13

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.