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

NAME

Class::Maker - classes, reflection, schema, serialization, attribute- and multiple inheritance

SYNOPSIS

use Class::Maker qw(class);

class Human, { isa => [qw( ParentClass )],

        public =>
        {
                string  => [qw(name lastname)],

                ref             => [qw(father mother)],

                array   => [qw(friends)],

                custom  => [qw(anything)],
        },

        private =>
        {
                int     => [qw(dummy1 dummy2)],
        },

        configure =>
        {
                ctor => 'create',

                explicit => 0,
        },
};

sub Human::greeting : method { my $this = shift;

                printf 'This is %s (%d)', $this->name, $this->uid;
}

class UnixUser, { isa => [qw( Human )],

        public =>
        {
                int             => [qw(uid gid)],

                string  => [qw(username)],
        },
};

        my $a = Human->new( uid => 1, gid => 2, name => Bart );

        $a->father( Human->new( name => Houmer ) );

        $a->greeting();

        $a->uid = 12;

        $a->_dummy1( 'bla' );

DESCRIPTION

Class::Maker introduces the concept of classes via a "class" function. It automatically creates packages, ISA, new and attribute-handlers. The classes can inherit from common perl-classes and class-maker classes. Single and multiple inheritance is supported.

This package is for everybody who wants to program oo-perl and does not really feel comfortable with the common way.

Java-like reflection is also implemented and allows one to inspect the class properties and methods during runtime. This is helpfull for implementing persistance and serialization. A Tangram (see cpan) schema generator is included to the package, so one can use Tangram object-persistance on the fly as long as he uses Class::Maker classes.

INTRODUCTION

When you want to program oo-perl, mostly you suffer under the flexibility of perl. It is so flexibel, you have to do alot by hand. Here an example (slightly modified) from perltoot perl documentation for demonstration:

package Person;

@ISA = qw(Something);

sub new { my $self = {}; $self->{NAME} = undef; $self->{AGE} = undef; bless($self); # but see below return $self; }

sub name { my $self = shift; if (@_) { $self->{NAME} = shift } return $self->{NAME}; }

sub age { my $self = shift; if (@_) { $self->{AGE} = shift } return $self->{AGE}; }

After using cpan modules for some time, i felt still very uncomfortable because i am used to c++ which has really straightforward class decleration style. It looks really beautiful. I love good looking syntax. So i have written a "class" function which <easily> creates perl classes. And i want it to be smoothly integrated into perl code with comprehensive handling of package issues etc:

use Class::Maker qw(class);

class Person, { isa => [ Something ],

        public =>
        {
                scalar => [qw( name age )],
        },
};

When using "class", you do not explictly need "package". The function does all symbol creation for you. It is more a class decleration (like in java/cpp/..):

CLASS FUNCTION

The 'class' function is very central to Class::Maker. It may be called with or without braces.

        Syntax:         class 'NAME' is optional , {DESCRIPTORS};

        The parantheses for the class() function are optional.

        'NAME' is the Name for the class. It is also the name for the package where the symbols for the class are created.

                Examples:       'Animal', 'Animal::Spider', 'Histology::Structures::Epithelia'

                Normally the class is created related to the main package:

                        Example:
                                        package Far::Far::Away;

                                        class 'Galaxy',
                                        {
                                        };

                'Galaxy' would become to 'main::Galaxy'.

                Feature: If you want it below the current package, just add a '.' or '*' in front of the class name:

                        Example:
                                        package Far::Far::Away;

                                        class '.Galaxy',
                                        {
                                        };

                '.Galaxy' would become 'Far::Far::Away::Galaxy'.

        {DESCRIPTORS}

        is a hashref. The entries are called FIELDS and are described below.

FIELDS

Fields are the keys in the hashref given as the second (or first if the first argument (classname) is omitted) argument to "class". Here are the basic fields (for adding new fields read the Class::Maker::Basic::Fields).

isa
        Arguments: arrayref

        Same as the @ISA array in an package (see perltoot). Additionally following special features are added:

                a) when the name is started with an '.' or '*' the package name is extrapolated to that name:

                        Example:
                                        package Far::Far::Away;

                                        class Galaxy,
                                        {
                                                isa => [qw( .AnotherGalaxy )],
                                        };

                        '.AnotherGalaxy' becomes expanded to 'Far::Far::Away::AnotherGalaxy'.
The attribute group (attr|attributes|private|public)
        Arguments: hashref

        This keys are 'type-identifiers' (no fear, its simple), which help you to sort things.

        In general these are used to create handlers for the type. It is somehow like the get/set
        like method functions to access class-properties, but its more generalized and not so
        restrictive.

        By default, every non-known type-identifier is a simple scalar handler. Class::Maker will
        not warn you at any point, if you use a unknown type-identifier.

                Example:

                        int => [qw(id)],

                leads to a attribute-handler which can be used like:

                        $obj->id( 123 );

                        my $value = $obj->id;

                Because the default handler is an lvalue function, the following call is also valid:

                        $obj->id = 5678;
private
        All properties in the 'private' section, get a '_' prepended to their names.

        private =>
        {
                int             => [qw(uid gid)],
        },

        So you must access 'uid' with $obj->_uid();
public|attribute|attr
        public =>
        {
                int             => [qw(uid gid)],

                string  => [qw(name lastname)],

                ref             => [qw(father mother)],

                array   => [qw(friends)],

                custom  => [qw(anything)],
        }
configure
        This Field is for general options. Basicly following options are supported:

                a) new: The name of the default constructor is 'new'. With this option you can change the
                name to something of your choice. For instance:

                        new => 'connect'

                        could be used for database objects. So you would use

                        my $obj AnyClass->connect( );

                        to create an AnyClass object.

                b) explicit: Internally an instance of a class hold all properties/attributes in an hash
                (The object is blessed with a hash-ref). The keys are normally exactly the same as you
                declare in the descriptors. But when you do inheritance, you may have name clashes if a
                parent object uses the same name for property. To compensate that problem, set explicit
                to something true (i.e. 1). This will lead to internal prepending of the classname to the
                key name:

                Example:

                'A' inherits 'B'. Both have a 'name' property. With explicit internally the fields
                are distinct:

                        A::name
                        B::name

                CAVEAT: This does not collide with attribute-overloading/inheritance ! Because the first
                attribute-handler in the isa-tree is always called. You do not have to care for this.

                Only use this feature, if you have fear that name clashes could appear, beside overloading. Per default
                it is turned off, because i suppose that most class designers care for name clashes themselfs.

                c) I<private>

                        - prefix string (default '_') for private functions can be changed with this.

                Example:

                        private =>
                        {
                                int => [qw(dummy1)],
                        },
                        configure =>
                        {
                                private => { prefix => '__' },
                        },

                would force to access 'dummy1' via ->__dummy1().
automethod
        Reserved.
has
        Reserved. Is planned to be used for 'has a' relationships.
default
        Reserved. In future here you can give default values for class attributes.
version
        Give the class/objects a version number. Internally the $VERSION is set to that value.
can
        Here you can manually list all class methods. So under reflection you can inspect this field.
        This obsolete and is not recommended, because there is a better mechinism implemented.
        If you declare a function use the ': method' identifier/attribute.

        Example:

        sub AnyClass::calc : method
        {
                my $this = shift;

        }

        This is important, because when the class is reflected all subs which have the attribute ': method'
        are handled as 'methods', all others are 'functions'.
persistance
        Here you can set options and add information for the reflect-function. You can also add custom information,
        you may want to process when you reflect objects.

        Example:

                For example the tangram-schema generator looks for an 'abstract' key, to handle this class as an abstract
                class:

                persistance =>
                {
                        abstract => 1,
                },

                You can read more about Persistance under the Class::Maker::Extension::Persistance manpage.

INTERNALS

Following happens in the background, when using 'class':

creates a package "Person". =item sets @Person::ISA to the [ 'Something' ]. =item creates method handlers for the attributes (including lvalue methods). =over 4 while only "hash" and "array" keys are keywords, any other will result in a simple get/set method (this is very usefull for pseudo types, wich can be later implemented).
exports a default constructor "Person::new()" =item which handles argument initialization =item has a mechanism for initializing the parent objects (including MI) =item so you don't need to do it yourself =item creates $Person::CLASS holding a hashref to the structure [the second argument] =item good for reflection: i.e. you can get runtime information about the class =over 4 =item usable for dependency/class walking =item creating on-the-fly persistance => in combination with Tangram (through reflection) =item it creates the complete tangram schema tree (Tangram users know how hard it is =item to have x hand-maintained schema-hashes => here you get everything automatic). =back

PERFORMANCE

I never benchmarked Class::Maker. Because the internal representation is just the same as for standard perl-classes, only a minimal delay in the constructor (during scan through the class hirarchy for _init() routines) is apparent.

EXAMPLES

HOW TO WRITE A MODULE WITH Class::Maker

See the Class::Maker::Examples manpage for examples how to write basic data-type-like classes and basic classes used for i.e. e-commerce applications.

EXPORT

facultativ: qw(reflect schema) obligat: qw(class)

class by default.

KNOWN BUGS/PROBLEMS

        * isa => [qw( )] isnt in sync with @ISA. When @ISA (or isa) is modified after initation, the $reflex->{isa} will only
        represent the state during object initiation.

AUTHOR

Author: Murat Uenalan (muenalan@cpan.org)

Contributions (Ideas or Code):

        - Terrence Brannon

COPYRIGHT

(c) 2001 by Murat Uenalan. All rights reserved. Note: This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

SEE ALSO

perl(1), perlboot, perltoot, perltootc

Search for Class::Maker::* at CPAN

Also at CPAN: Class::*, Tangram

LITERATURE

[1] Object-oriented Perl, Damian Conway [2] Perl Cookbook, Nathan Torkington et al.

2 POD Errors

The following errors were encountered while parsing the POD:

Around line 719:

=back without =over

Around line 737:

'=item' outside of any '=over'