Extend API of complex source-code parsing CPAN module
Now all these statements contain strings with prefix PPI::


I know this is true of all things in PPI itself, and its a very popular convention.

But I suspect there are cases where things may enter the Document without actually being =~ /^PPI::/.

Also, it seems to me that what you're optimising for is a less frequent usecase than you should be optimising for:

$x-&gt;isa("PPI::Whatever")


Should be more heavily used in real code than

"PPI::Whatever" eq $x-&gt;class


Either way, you can do better than

 "Whatever" eq $x-&gt;name


You could do

 $x-&gt;is_named('Whatever');


But that's still gross because "you're not using @ISA".

 $x-&gt;is("Whatever")


This could work, but now you're in a bind:

What happens if $x does not subclass whatever class the is method was added on?

These are all, IME, big annoying problems that your desired approach simply makes more complicated to paper over a minor detail.

Which is especially silly when

$x-&gt;isa("PPI::Whatever")


Will work, on everything, both PPI and not.

That doesn't mean a "name" attribute wouldn't be useful, but it needs to be said that you should not be proposing to use it as the prime deciding mechanism, and should probably only be for diagnostics.

Given all of the above, a functional API is going to be much more to your liking.

use PPI::Naming qw( is_named is_an );
# not ISA aware
if ( is_named( $object, 'Whatever' ) ) {
         ....
}
# ISA aware
if ( is_an( $object, 'Whatever' ) ) {

}


is_named would be straight forward:

sub is_named {
  my ( $object, $name ) = @_;

  return undef unless defined blessed( $object );

  # This allows somebody to specify "=Whatever" and have it mean
  # "Whatever.pm" instead of "PPI::Whatever"
  if ( $name =~ /^=(.*$)/ ) {
     return $object-&gt;class eq "$1";    
  }
  return $object-&gt;class eq 'PPI::' . $name;
}


is_an would be a little more complicated.

use MRO::Compat;
use Scalar::Util qw( blessed );
sub is_an { 
  my ( $object, $name ) = @_;

  my $class = blessed($object);
  return undef unless defined $class;

  # This allows somebody to specify "=Whatever" and have it mean
  # "Whatever.pm" instead of "PPI::Whatever"
  if ( $name =~ /^=(.*$)/ ) {
    return $object-&gt;isa("$1");
  }
  for my $parent ( mro::get_linear_isa($class) ){
    return 1 if $parent eq "PPI::" . $name;
  }
}


The biggest benefit of this approach is there's almost no room for error. There's no chance that one of your objects could be missing the magic methods you require.

Related Reading


MRO::Compat
Scalar::Util