Safe::Isa - Call isa, can, does and DOES safely on things that may not be objects
use strict;
use warnings;
{ package Foo; sub new { bless({}, $_[0]) } }
{ package Bar; our @ISA = qw(Foo); sub bar { 1 } }
my $foo = Foo->new;
my $bar = Bar->new;
my $blam = [ 42 ];
# basic isa usage -
$foo->isa('Foo'); # true
$bar->isa('Foo'); # true
$blam->isa('Foo'); # BOOM
$foo->can('bar'); # false
$bar->can('bar'); # true
$blam->can('bar'); # BOOM
# Safe::Isa usage -
use Safe::Isa;
$foo->$_isa('Foo'); # true
$bar->$_isa('Foo'); # true
$blam->$_isa('Foo'); # false, no boom today
$foo->$_can('bar'); # false
$bar->$_can('bar'); # true
$blam->$_can('bar'); # false, no boom today
Similarly:
$maybe_an_object->$_does('RoleName'); # true or false, no boom today
$maybe_an_object->$_DOES('RoleName'); # true or false, no boom today
And just in case we missed a method or two:
$maybe_an_object->$_call_if_object(name => @args);
$maybe_an_object->$_call_if_can(name => @args);
Or to re-use a previous example for purposes of explication:
$foo->$_call_if_object(isa => 'Foo'); # true
$bar->$_call_if_object(isa => 'Foo'); # true
$blam->$_call_if_object(isa => 'Foo'); # false, no boom today
How many times have you found yourself writing:
if ($obj->isa('Something')) {
and then shortly afterwards cursing and changing it to:
if (Scalar::Util::blessed($obj) and $obj->isa('Something')) {
Right. That's why this module exists.
Since perl allows us to provide a subroutine reference or a method name to
the -> operator when used as a method call, and a subroutine doesn't require
the invocant to actually be an object, we can create safe versions of isa,
can and friends by using a subroutine reference that only tries to call the
method if it's used on an object. So:
my $isa_Foo = $maybe_an_object->$_call_if_object(isa => 'Foo');
is equivalent to
my $isa_Foo = do {
if (Scalar::Util::blessed($maybe_an_object)) {
$maybe_an_object->isa('Foo');
} else {
undef;
}
};
Note that we don't handle trying class names, because many things are valid
class names that you might not want to treat as one (like say ``Matt'') - the
is_module_name function from the Module::Runtime manpage is a good way to check for
something you might be able to call methods on if you want to do that.
We are careful to make sure that scalar/list context is preserved for the
method that is eventually called.
$maybe_an_object->$_isa('Foo');
If called on an object, calls isa on it and returns the result, otherwise
returns nothing.
$maybe_an_object->$_can('Foo');
If called on an object, calls can on it and returns the result, otherwise
returns nothing.
$maybe_an_object->$_does('Foo');
If called on an object, calls does on it and returns the result, otherwise
returns nothing. If the does method does not exist, returns nothing rather
than failing.
$maybe_an_object->$_DOES('Foo');
If called on an object, calls DOES on it and returns the result, otherwise
returns nothing. On perl versions prior to 5.10.0, the built in core DOES
method doesn't exist. If the method doesn't exist, this will fall back to
calling isa just like the core DOES method.
$maybe_an_object->$_call_if_object(method_name => @args);
If called on an object, calls method_name on it and returns the result,
otherwise returns nothing.
$maybe_an_object->$_call_if_can(name => @args);
If called on an object, calls can on it; if that returns true, then
calls method_name on it and returns the result; if any condition is false
returns nothing.
I gave a lightning talk on this module (and curry and the Import::Into manpage) at
YAPC::NA 2013.
mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk>
None yet. Well volunteered? :)
Copyright (c) 2012 the Safe::Isa AUTHOR and CONTRIBUTORS
as listed above.
This library is free software and may be distributed under the same terms
as perl itself.
|