NAME

Module::Generic - Generic Module to inherit from

SYNOPSIS

package MyModule;
BEGIN
{
    use strict;
    use Module::Generic;
    our( @ISA ) = qw( Module::Generic );
};

VERSION

v0.11.9

DESCRIPTION

Module::Generic as its name says it all, is a generic module to inherit from. It contains standard methods that may howerver be bypassed by the module using Module::Generic.

As an added benefit, it also contains a powerfull AUTOLOAD transforming any hash object key into dynamic methods and also recognize the dynamic routine a la AutoLoader from which I have shamelessly copied in the AUTOLOAD code. The reason is that while AutoLoader provides the user with a convenient AUTOLOAD, I wanted a way to also keep the functionnality of Module::Generic AUTOLOAD that were not included in AutoLoader. So the only solution was a merger.

METHODS

import()

import() is used for the AutoLoader mechanism and hence is not a public method. It is just mentionned here for info only.

new()

new() will create a new object for the package, pass any argument it might receive to the special standard routine init that must exist. Then it returns what returns init().

To protect object inner content from sneaking by thrid party, you can declare the package global variable OBJECT_PERMS and give it a Unix permission. It will then work just like Unix permission. That is, if permission is 700, then only the module who generated the object may read/write content of the object. However, if you set 755, the, other may look into the content of the object, but may not modify it. 777, as you would have guessed, allow other to modify the content of an object. If OBJECT_PERMS is not defined, permissions system is not activated and hence anyone may access and possibibly modify the content of your object.

If the module runs under mod_perl, it is recognized and a clean up registered routine is declared to Apache to clean up the content of the object.

clear_error

Clear all error from the object and from the available global variable $ERROR.

This is a handy method to use at the beginning of other methods of calling package, so the end user may do a test such as:

$obj->some_method( 'some arguments' );
die( $obj->error() ) if( $obj->error() );

## some_method() would then contain something like:
sub some_method
{
    my $self = shift( @_ );
    ## Clear all previous error, so we may set our own later one eventually
    $self->clear_error();
    ## ...
}

This way the end user may be sure that if $obj-error()> returns true something wrong has occured.

error()

Set the current error, do a warn on it and returns undef():

if( $some_condition )
{
    return( $self->error( "Some error." ) );
}

Note that you do not have to worry about a trailing line feed sequence. error() takes care of it.

Note also that by calling error() it will not clear the current error. For that you have to call clear_error() explicitly.

Also, when an error is set, the global variable ERROR is set accordingly. This is especially usefull, when your initiating an object and that an error occured. At that time, since the object could not be initiated, the end user can not use the object to get the error message, and then can get it using the global module variable ERROR, for example:

my $obj = Some::Package->new ||
die( $Some::Package::ERROR, "\n" );
errors()

Used by error() to store the error sent to him for history.

It returns an array of all error that have occured in lsit context, and the last error in scalar context.

errstr()

Set/get the error string, period. It does not produce any warning like error would do.

get()

Uset to get an object data key value:

$obj->set( 'verbose' => 1, 'debug' => 0 );
## ...
my $verbose = $obj->get( 'verbose' );
my @vals = $obj->get( qw( verbose debug ) );
print( $out "Verbose level is $vals[ 0 ] and debug level is $vals[ 1 ]\n" );

This is no more needed, as it has been more conveniently bypassed by the AUTOLOAD generic routine with chich you may say:

$obj->verbose( 1 );
$obj->debug( 0 );
## ...
my $verbose = $obj->verbose();

Much better, no?

init()

This is the new() package object initializer. It is called by new() and is used to set up any parameter provided in a hash like fashion:

my $obj My::Module->new( 'verbose' => 1, 'debug' => 0 );

You may want to superseed init() to have suit your needs.

init() needs to returns the object it received in the first place or an error if something went wrong, such as:

sub init
{
    my $self = shift( @_ );
    my $dbh  = DB::Object->connect() ||
    return( $self->error( "Unable to connect to database server." ) );
    $self->{ 'dbh' } = $dbh;
    return( $self );
}

In this example, using error will set the global variable $ERROR that will contain the error, so user can say:

my $obj = My::Module->new() || die( $My::Module::ERROR );

If the global variable VERBOSE, DEBUG, VERSION are defined in the module, and that they do not exist as an object key, they will be set automatically and accordingly to those global variable.

The supported data type of the object generated by the new method may either be a hash reference or a glob reference. Those supported data types may very well be extended to an array reference in a near future.

message()

message() is used to display verbose/debug output. It will display something to the extend that either verbose or debug are toggled on.

If so, all debugging message will be prepended by ## to highlight the fact that this is a debugging message.

Addionally, if a number is provided as first argument to message(), it will be treated as the minimum required level of debugness. So, if the current debug state level is not equal or superior to the one provided as first argument, the message will not be displayed.

For example:

## Set debugness to 3
$obj->debug( 3 );
## This message will not be printed
$obj->message( 4, "Some detailed debugging stuff that we might not want." );
## This will be displayed
$obj->message( 2, "Some more common message we want the user to see." );

Now, why debug is used and not verbose level? Well, because mostly, the verbose level needs only to be true, that is equal to 1 to be efficient. You do not really need to have a verbose level greater than 1. However, the debug level usually may have various level.

set()

set() sets object inner data type and takes arguments in a hash like fashion:

$obj->set( 'verbose' => 1, 'debug' => 0 );
subclasses( [ CLASS ] )

This method try to guess all the existing sub classes of the provided CLASS.

If CLASS is not provided, the class into which was blessed the calling object will be used instead.

It returns an array of subclasses in list context and a reference to an array of those subclasses in scalar context.

If an error occured, undef is returned and an error is set accordingly. The latter can be retrieved using the error method.

AUTOLOAD

The special AUTOLOAD() routine is called by perl when no mathing routine was found in the module.

AUTOLOAD() will then try hard to process the request. For example, let's assue we have a routine foo.

It will first, check if an equivalent entry of the routine name that was called exist in the hash reference of the object. If there is and that more than one argument were passed to this non existing routine, those arguments will be stored as a reference to an array as a value of the key in the object. Otherwise the single argument will simply be stored as the value of the key of the object.

Then, if called in list context, it will return a array if the value of the key entry was an array reference, or a hash list if the value of the key entry was a hash reference, or finally the value of the key entry.

If this non existing routine that was called is actually defined, the routine will be redeclared and the arguments passed to it.

If this fails too, it will try to check for an AutoLoadable file in auto/PackageName/routine_name.al

If the filed exists, it will be required, the routine name linked into the package name space and finally called with the arguments.

If the require process failed or if the AutoLoadable routine file did not exist, AUTOLOAD() will check if the special routine EXTRA_AUTOLOAD() exists in the module. If it does, it will call it and pass it the arguments. Otherwise, AUTOLOAD will die with a message explaining that the called routine did not exist and could not be found in the current class.

SPECIAL METHODS

_set_get_class( $field, $struct_hash, @_ )

Given a field name, a dynamic class fiels definition hash (dictionary), and optional arguments, this special method will create perl packages on the fly.

For example, consider the following:

#!/usr/local/bin/perl
BEGIN
{
	use strict;
	use Data::Dumper;
};

{
	my $o = MyClass->new( debug => 3 );
	$o->setup->age( 42 );
	print( "Age is: ", $o->setup->age, "\n" );
	print( "Setup object is: ", $o->setup, "\n" );
	$o->setup->billing->interval( 'month' );
	print( "Billing interval is: ", $o->setup->billing->interval, "\n" );
	print( "Billing object is: ", $o->setup->billing, "\n" );
	$o->setup->rgb( 255, 122, 100 );
	print( "rgb: ", join( ', ', @{$o->setup->rgb} ), "\n" );
	exit( 0 );
}

package MyClass;
BEGIN
{
	use strict;
	use lib './lib';
	use parent qw( Module::Generic );
};

sub setup 
{
	return( shift->_set_get_class( 'setup',
	{
	name => { type => 'scalar' },
	age => { type => 'number' },
	metadata => { type => 'hash' },
	rgb => { type => 'array' },
	url => { type => 'uri' },
	online => { type => 'boolean' },
	created => { type => 'datetime' },
	billing => { type => 'class', definition =>
		{
		interval => { type => 'scalar' },
		frequency => { type => 'number' },
		nickname => { type => 'scalar' },
		}}
	}) );
}

1;

__END__

This will yield:

Age is: 42
Setup object is: MyClass::Setup=HASH(0x7fa805abcb20)
Billing interval is: month
Billing object is: MyClass::Setup::Billing=HASH(0x7fa804ec3f40)
rgb: 255, 122, 100

The advantage of this over _set_get_hash_as_object is that here one controls what fields / method are supported and with which data type.

_set_get_hash_as_object( $field, '$class_name', @_ )

Given a field name, a class name and an argument list, this will create dynamically classes so that each key / value pairs can be accessed as methods.

Also it does this recursively while handling looping, in which case, it will reuse the object previously created, and also it takes care of adapting the hash key to a proper field name, so something like 99more-options would become more_options. If the value itself is a hash, it processes it recursively transforming 99more-options to a proper package name MoreOptions prepended by $class_name provided as argument or whatever upper package was used in recursion processing.

COPYRIGHT

Copyright (c) 2000-2014 DEGUEST Pte. Ltd.

CREDITS

Jacques Deguest <jack@deguest.jp>

SEE ALSO