NAME

OOP::Perlish::Class::Abstract

DESCRIPTION

Quickly and easily create abstract classes, which can easily be tested for via 'isa' or OOP::Perlish::Class::Accessor->implements( [ 'ClassA', 'ClassB' ] ); ('implements' is a polymorphism test, not an inheritance test, and is generally preferred)

SYNOPSIS

Defining an abstract class
package MyAbstractClass;
use base qw(OOP::Perlish::Class::Abstract);

BEGIN { 
   __PACKAGE__->_interfaces( 
       my_interface => 'required',
       my_optional_interface => 'optional',
       my_optional_but_true => 'optional_true',
   );
};
Later in an implementation class:
package MyImplementationClass;
use base qw(MyAbstractClass);

sub my_interface
{
   my ($self) = @_;

   return 'foo';
}
Meanwhile, in a consuming class
package MyConsumerClass;
use base qw(OOP::Perlish::Class);

BEGIN {
   __PACKAGE__->_accessors(
       foo => {
           type => 'OBJECT',
           implements => [ 'MyAbstractClass' ],
       },
   );
};

sub quux
{
   my ($self) = @_;

   return $self->foo()->my_interface();
}
And finally, when used:
my $foo = MyImplementationClass->new();
my $bar = MyConsumerClass->new( foo => $foo );

print $bar->quux() . $/;

USAGE

The module provides handlers for 'required', 'optional', and 'optional_true' types of interface definitions via the following built-in method factories:

############################################################################################
## Return a subroutine for the required interfaces
############################################################################################
sub ____oop_perlish_class_interface_impl_required
{
    my ( $self, $name ) = @_;
    my $class = ref($self) || $self;

    $self->____OOP_PERLISH_CLASS_REQUIRED_INTERFACES()->{$name} = 1;

    return sub { confess("Interface $name is required, but was not defined in $class (nor in the ancestory of $class)"); };
}

############################################################################################
## Return a subroutine for the optional (false) interfaces
############################################################################################
sub ____oop_perlish_class_interface_impl_optional
{
    my ( $self, $name ) = @_;
    return sub { return; };
}

############################################################################################
## Return a subroutine for optional_true interfaces
############################################################################################
sub ____oop_perlish_class_interface_impl_optional_true
{
    my ( $self, $name ) = @_;
    return sub { return 1; };
}

if you wish to add additional handlers for an abstract class; simply define a method with the type prefixed with ____oop_perlish_class_interface_impl_ e.g.:

sub ____oop_perlish_class_interface_impl_my_type
{
   return sub { return 'default sub for my_type'; };
}

Which would allow you to specify in the _interfaces() call

BEGIN { 
   __PACKAGE__->_interfaces( 
       my_interface => 'my_type',
   );
};

This is mostly useful for specifying default interfaces that are expected to return references to (possibly empty) hashes or arrays.

DIAGNOSTICS

invokes confess() whenever a method is called that was 'required' but never defined. 
invokes confess() whenever a type is specified in __PACKAGE__->_interfaces() that does not have a handler defined.
invokes confess() whenever an object is instantiated via new and is missing a required interface definition;