package AbstractClass;
$VERSION = 0.12;
use Carp;
sub bless ($@) {
my $class = $_[1] || caller();
if (exists $Registered{$class}) {
confess("Cannot bless objects into abstract class $class");
}
else {
CORE::bless(shift, $class);
}
}
$text = '
#line 1 "(AbstractClass loaded for MYPACK)"
package MYPACK;
sub import {
my $pkg = shift;
return if $pkg eq "MYPACK";
foreach my $meth (@ABSTRACT_METHODS) {
my $does = $pkg->can($meth);
if (not defined($does)) {
Carp::croak("Class $pkg must define $meth for class MYPACK");
}
else {
my $override = MYPACK->can($meth);
if (defined ($override) and $does == $override) {
Carp::confess("Class $pkg cannot inherit $meth from MYPACK")
+;
}
}
}
$pkg->SUPER::import(@_);
}
1;
';
sub import {
shift; # Don't need my class name
my $base = caller();
$Registered{$base}++;
*{"$base\::bless"} = *bless;
@{"$base\::ABSTRACT_METHODS"} = @_;
my $eval_str = $text;
$eval_str =~ s/MYPACK/$base/g;
eval($eval_str) or confess("Cannot execute:\n$eval_str\n\nError $@")
+;
}
1;
__END__
=head1 NAME
AbstractClass - Makes classes into abstract classes.
=head1 SYNOPSIS
In module SomeAbstractClass.pm:
package SomeAbstractClass;
use AbstractClass;
@ABSTRACT_METHODS = qw(foo bar);
or more compactly:
package SomeAbstractClass;
use AbstractClass qw(foo bar);
=head1 DESCRIPTION
An abstract class is a class which defines methods
that must be overridden in classes that wish to inherit
from it which are not themselves abstract classes.
Normally the abstract class will then provide methods
whose implementations need these methods to exist.
Whether or not it is an abstract class, it would crash
at some point if the methods were missing. By moving
the check to when you first load the class, you can find
problems immediately and get better reporting of the
requirement.
It is customary to not have any objects in an abstract
class. This module provides some enforcement of this
rule by overriding bless in abstract classes.
=head1 BUGS
Abstract classes are implemented with special import
functions. Therefore this does not play well with
Exporter. Also due to unfortunate restrictions in the
implementation of Perl's SUPER pseudo-package, multiple
inheritance will not play well with abstract classes. If
you wish to use the capabilities of abstract classes and
multiple inheritance, you may wish to look at the more
intrusive Class::Contract.
This mechanism also means that if you define multiple
classes in a single file then you must manually import
each derived class to test it. When each class is in its
own module, this happens automatically when you use the
module.
It is not hard to get around the rule that objects cannot
belong to an abstract class. To fix that would require
overriding the core bless method, which brings up issues
of its own.
=head1 AUTHOR
AbstractBase was written by Ben Tilly <ben_tilly@hotmail.com>.
This module may be copied and modified on the same terms as
Perl itself.
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.
|