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

NAME

Class::Interface - A class for implementing/extending interfaces/abstracts in Perl.

SYNOPSIS

Declaring an interface

  package Bouncable;

  use Class::Interface;
  &interface;   # this actually declares the interface

  sub bounce;
  sub getBounceBack;

  1;

This creates an interface (a contract between classes if you like) that specifies that each class implementing the Bouncable interface must have an implementation of the routines bounce and getBounceBack.

Declaring an implementing class

  package Ball;

  use Class::Interface;
  &implements( 'Bouncable' );

  sub bounce {
    my $self = shift;
    print "The ball is bouncing @ ".$self->getBounceBack." strength"
  }

  sub getBounceBack {
    return 10;
  }

  1;

Declaring an abstract

  package AbstractInterestCalculator;

  use Class::Interface;
  &abstract;   # this actually declares this class to be abstract;

  use Class::AccessorMaker {
    interest => 5.1,
    maxInterestValue => 0,
  }

  # a hook for doing calculations
  sub calculate {
    my ( $self, $value ) = @_;

    $self->prepare();
    $value += $self->getInterestValue( $value );

    return $value;
  }

  sub prepare;          # prepare calculations
  sub getInterstValue;  # get the interest value

  1;

Extending from an abstract class

  package LowInterestCalculator;

  use Class::Interface;
  &extends( 'AbstractInterestCalculator' );

  sub prepare {
    my ( $self ) = @_;
    $self->interest(1.3);

    # we don't give interest if the value of the account is or
    # exceeds $10.000
    $self->maxInterestValue(10000)
  }

  sub getInterstValue {
    my ( $self, $value ) = @_

    if ( $self->maxInterestValue &&
         $value >= $self->maxInterestValue ) {
      return 0;
    }

    $value *= $self->interest;

    return $value;
  }

DESCRIPTION

Performs some underwater perl-magic to ensure interfaces are interfaces and classes that implement the interface actually do so.

INTERFACE RULES

  • An interface must use the Class::Interface module.

  • An interface must call the 'interface' method.

  • An interface must declare at least one routine

  • Routines may not have an implementation

ABSTRACT RULES

  • An abstract must use the Class::Interface module.

  • An abstract must call the 'abstract' method.

  • An abstract must declare at least one abstract routine.

ROUTINE RULES

  • Routines must be declared as one of:

    - sub routine;
    - sub routine {}

    NOTE: When using curly braces in routine declarations they must stay on the same line. The amount of whitespace between them and/or the routine name is free of ruling.

ANNOTATIONS

It helps to think of these methods as Java style annotations. But instead of calling them with @interface you use &interface.

&interface()

Turns the calling class into an interface.

&abstract()

Turns the calling class into an abstract.

&implements()

Loads the given interfaces and checks the calling class for presence of the wanted routines.

If all goes well pushes the name of the interface to the ISA array of the class.

&extends()

Loads the given abstract class and checks the calling class for presence of the abstract routines.

If all goes well pushes the name of the abstract class to the ISA array of the class.

MAGIC CONSTRUCTORS

To add even more Java behaviour to perl...

Extending or implementing classes that do not already have a constructor can get one injected automaticly.

The code for such a routine is as follows:

  sub new {
    my $class = ref($_[0]) || $_[0]; shift;
    my $self  = bless({}, $class);

    my %value = @_;
    foreach my $field ( keys %value ) {
      $self->$field( $value{$field} ) if $self->can( $field )
    }

    return $self
  }

In english: An object with a hashref is setup. The constructor can be called like this:

  my $object = Object->new( attribute1 => "value",
                            attribute2 => [ qw(a b c)],
                           );

if attributeX exists as an accessor routine in the object it will be set by calling the actual routine.

I would strongly advice using something like Class::AccessorMaker though...

If you want magic constructors; set $Class::Interface::AUTO_CONSTRUCTOR to 1

ERROR HANDLING

If anything fails uses Carp::croak. Once you set $Class::Interface::CONFESS to 1 it will spill the guts using confess.

FAQ

Q: Will it see the routines I create dynamicly?

Using things like Class::AccessorMaker accessors are dynamcly created. Class contracts can specify some getters to be present. Does Class::Interface recognize them?

A: Yes.

The checks implements() and extends() perform happen well after use time. So using Class::AccessorMaker is save. It performs it magic in use time. Any class that will dynamicly create methods in use time should be usable with Class::Interface.

CAVEATS, BUGS, ETC.

Order of annotations

If your class extends an abstract which provides methods for an interface you are implementing you must first call the &extends annotation.

So:

  &extends('Runner');
  &implements('Runnable');

And not:

  &implements('Runnable');
  &extends('Runner');

SEE ALSO

Carp, UNIVERSAL

AUTHOR

Hartog C. de Mik

COPYRIGHT

(cc-sa) 2008, Hartog C. de Mik

cc-sa : http://creativecommons.org/licenses/by-sa/3.0/