UNIVERSAL::DOES - Provides UNIVERSAL::DOES() method for older perls


UNIVERSAL-DOES documentation Contained in the UNIVERSAL-DOES distribution.

Index


Code Index:

NAME

Top

UNIVERSAL::DOES - Provides UNIVERSAL::DOES() method for older perls

VERSION

Top

This document describes UNIVERSAL::DOES version 0.004.

SYNOPSIS

Top

	# if you require UNIVERSAL::DOES, you can say the following:
	require UNIVERSAL::DOES
		 unless defined &UNIVERSAL::DOES;

	# you can call DOES() in any perls
	$class->DOES($role);
	$object->DOES($role);

	# also, this provides a does() function
	use UNIVERSAL::DOES qw(does);

	# use does($thing, $role), instead of UNIVERSAL::isa($thing, $role)
	does($thing, $role);   # $thing can be non-invocant
	does($thing, 'ARRAY'); # also ok, $thing may have overloaded @{}

DESCRIPTION

Top

UNIVERSAL::DOES provides a UNIVERSAL::DOES() method for compatibility with perl 5.10.x.

This module also provides a does() function that checks something does some roles, suggested in perltodo.

FUNCTIONS

Top

does($thing, $role)

does checks if $thing performs the role $role. If the thing is an object or class, it simply checks $thing->DOES($role). Otherwise it tells whether the thing can be dereferenced as an array/hash/etc.

Unlike UNIVERSAL::isa(), it is semantically correct to use does for something unknown and to use it for reftype.

This function handles overloading. For example, does($thing, 'ARRAY') returns true if the thing is an array reference, or if the thing is an object with overloaded @{}.

This is not exported by default.

METHODS

Top

The following description is just copied from UNIVERSAL in perl 5.10.1.

$obj->DOES( $ROLE )
CLASS->DOES( $ROLE )

DOES checks if the object or class performs the role ROLE. A role is a named group of specific behavior (often methods of particular names and signatures), similar to a class, but not necessarily a complete class by itself. For example, logging or serialization may be roles.

DOES and isa are similar, in that if either is true, you know that the object or class on which you call the method can perform specific behavior. However, DOES is different from isa in that it does not care how the invocant performs the operations, merely that it does. (isa of course mandates an inheritance relationship. Other relationships include aggregation, delegation, and mocking.)

By default, classes in Perl only perform the UNIVERSAL role, as well as the role of all classes in their inheritance. In other words, by default DOES responds identically to isa.

There is a relationship between roles and classes, as each class implies the existence of a role of the same name. There is also a relationship between inheritance and roles, in that a subclass that inherits from an ancestor class implicitly performs any roles its parent performs. Thus you can use DOES in place of isa safely, as it will return true in all places where isa will return true (provided that any overridden DOES and isa methods behave appropriately).

NOTES

Top

"UNIVERSAL::DOES()" in perl5100delta says:

The UNIVERSAL class has a new method, DOES(). It has been added to solve semantic problems with the isa() method. isa() checks for inheritance, while DOES() has been designed to be overridden when module authors use other types of relations between classes (in addition to inheritance).

"A does() built-in" in perltodo says:

Like ref(), only useful. It would call the DOES method on objects; it would also tell whether something can be dereferenced as an array/hash/etc., or used as a regexp, etc. http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2007-03/msg00481.html

DEPENDENCIES

Top

Perl 5.5.3 or later.

BUGS

Top

No bugs have been reported.

Please report any bugs or feature requests to the author.

AUTHOR

Top

Goro Fuji (gfx) <gfuji(at)cpan.org>

SEE ALSO

Top

UNIVERSAL.

LICENSE AND COPYRIGHT

Top


UNIVERSAL-DOES documentation Contained in the UNIVERSAL-DOES distribution.

package UNIVERSAL::DOES;

use 5.005_03;

$VERSION = '0.004';

use Exporter;
@ISA       = qw(Exporter);
@EXPORT_OK = qw(does);

use strict;

*UNIVERSAL::DOES = \&DOES
	unless defined &UNIVERSAL::DOES;

# Take compatibility rather than performance.
sub DOES :method {
	my($invocant, $role) = @_;

	if(@_ != 2){
		require Carp;
		Carp::croak('Usage: invocant->DOES(kind)');
	}

	my $e = do{
		local $@;
		eval{ $invocant->isa($role) } and return 1;
		$@;
	};

	if($e){
		$e =~ s/\b isa \b/DOES/xmsg;
		die $e;
	}

	return 0;
}

my %operator_of = (
	SCALAR => '${}',
	ARRAY  => '@{}',
	HASH   => '%{}',
	CODE   => '&{}',
	GLOB   => '*{}',
);

sub does {
	my($thing, $role) = @_;

	if(@_ != 2){
		require Carp;
		Carp::croak('Usage: does(thing, role)');
	}

	return 0 unless $thing && $role;

	my $e = do{
		local $@;
		eval{ $thing->DOES($role) } and return 1;
		$@;
	};

	if($e){ # $thing is not an invocant
		return ref($thing) eq $role; # ARRAY, HASH, etc.
	}
	elsif(ref($thing)){ # $thins is an object
		my $operator = $operator_of{$role} or return 0;

		return $thing->can('()')             # overloaded?
			&& $thing->can('(' . $operator); # with the dereferencing operator?
	}

	return 0;
}

1;
__END__