The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

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;