#!perl
use strict;
use warnings;
use lib 't/lib';
use Test::More tests => 16;
use Test::SmallWarn;
# must happen here to register warnings category
BEGIN { use_ok( 'UNIVERSAL::can' ) };
{
package Logger;
use Scalar::Util 'blessed';
use vars '$AUTOLOAD';
sub new
{
my ($class, $object) = @_;
bless { object => $object, calls => [] }, $class;
}
sub object
{
my $self = shift;
return $self->{object} if blessed( $self );
return $self;
}
sub calls
{
my $self = shift;
return $self->{calls};
}
sub can
{
my ($self, $name) = @_;
my $object = $self->object();
return $self->SUPER::can( $name ) if $object->isa( __PACKAGE__ );
my $wrapped_method = $self->object->can( $name );
}
sub DESTROY {}
sub AUTOLOAD
{
my $self = shift;
my ($method) = $AUTOLOAD =~ /::(\w+)$/;
return unless my $coderef = $self->object->can( $method );
push @{ $self->calls() }, $method;
$self->object->$coderef( @_ );
}
package Logged;
sub new
{
my $class = shift;
bless \$class, $class;
}
sub foo
{
my $self = shift;
return 'foo'; }
package Liar;
use vars '$AUTOLOAD';
sub can
{
my $self = shift;
return Logger->can( shift );
}
sub DESTROY {}
sub AUTOLOAD
{
my $self = shift;
my ($method) = $AUTOLOAD =~ /::(\w+)$/;
return Logger->$method( @_ );
}
}
my $logger = Logger->new( 'Logged' );
my $can_new = $logger->can( 'new' );
my $can_foo = $logger->can( 'foo' );
ok( defined $can_new, 'can() should return true for defined class methods' );
ok( defined &$can_new, '... returning a code reference' );
is( $can_foo, \&Logged::foo, '... the correct code reference' );
my $uncan_foo;
warning_like { $uncan_foo = UNIVERSAL::can( $logger, 'foo' ) }
qr/Called UNIVERSAL::can\(\) as a function, not a method at t.class.t/,
'calling UNIVERSAL::can() as function on invocant should warn';
ok( defined $uncan_foo, 'UNIVERSAL::can() should return true then too' );
ok( defined &$uncan_foo, '... returning a code reference' );
is( $uncan_foo, \&Logged::foo, '... the correct code reference' );
my $can_calls = Logger->can( 'calls' );
ok( defined $can_calls,
'can() should return true for methods called as class methods' );
my $can_falls = Logger->can( 'falls' );
ok( ! defined $can_falls,
'... and false for nonexistant methods' );
my $uncan_liar;
warning_like { $uncan_liar = UNIVERSAL::can( 'Liar', 'new' ) }
qr/Called UNIVERSAL::can\(\) as a function, not a method at t.class.t/,
'calling UNIVERSAL::can() as function on class name invocant should warn';
{
no warnings;
warnings_are { $uncan_liar = UNIVERSAL::can( 'Liar', 'new' ) }
[], '... but only with warnings enabled';
}
{
no warnings 'UNIVERSAL::can';
warnings_are { $uncan_liar = UNIVERSAL::can( 'Liar', 'new' ) }
[], '... and not with warnings diabled for UNIVERSAL::can';
}
ok( defined $uncan_liar, 'can() should return true for class can() method' );
ok( defined &$uncan_liar, '... returning a code reference' );
is( $uncan_liar, \&Logger::new, '... the correct code reference' );
syntax highlighted by Code2HTML, v. 0.9.1