NAME

PAB3 - Perl Application Builder

SYNOPSIS

use PAB3;

DESCRIPTION

PAB3 provides a framework for building rapid applications in Perl5. It also includes a template handler for producing output. This part is defined here.

Examples

Following example loads a template from template1.tpx, does a loop over the %ENV variable and produces output on STDOUT.

-------------------------------------------------------------------
test1.pl
-------------------------------------------------------------------

#!/usr/bin/perl -w

use PAB3;

my $pab = PAB3->new();

$pab->make_script_and_run( 'template1.tpx' );

-------------------------------------------------------------------
template1.tpx
-------------------------------------------------------------------

i am from <*=$0*>

my environment looks like:

<* LOOP HASH %ENV *>
<* PRINT $_ . ' = ' . $ENV{$_} . "\n" *>
<* END LOOP *>

METHODS

new ( [%arg] )

Creates a new instance of PAB3 template handler class.

Posible arguments are:

path_cache     => path to save parsed templates
path_template  => path to the template files
auto_cache     => create cache files automatically. 'path_cache' is required
prg_start      => begin of program sequence, default is '<*'
prg_end        => end of program sequence, default is '*>'
cmd_sep        => command separator, to define more directives in one program
                  sequence, default is ';;'
record_name    => name of default record in loops, default is '$_'
logger         => reference to a PAB3::Logger class
warn           => warn on error, default is OFF
die            => die on error, default is ON
class_name     => name of the variable for this class. eg '$pab'
                  It is needed when templates including templates. If its
                  undefined, a variable $PAB3::_CURRENT will
                  be used as a reference to the current PAB3 class.

Example:

$pab = PAB3->new(
    'path_cache'    => '/path/to/cache',
    'path_template' => '/path/to/template-files',
);
setenv ()

Set some useful variables to the interpreters environment

these variables are:

$ENV{'SCRIPT_PATH'}   : path to the main script
$ENV{'SCRIPT'}        : name of the main script
make_script ( $template )
make_script ( $template, $cache )
make_script ( $template, '', $package )
make_script ( $template, $cache, $package )

Generates a perl script from $template file. If $cache file is defined the script will be saved into the cache file. If cache file already exists and the template has not been modified, the function will break here an return. If cache file has not been specified the script will be compiled into the memory as a package. The name of this package can be defined in the third parameter. If $package has not been specified the package from caller(0) is used.

Returns TRUE on success or FALSE on error.

Example:

$pab->make_script( 'template.htm' )
    or die $pab->error();

See also run_script, make_script_and_run

run_script ( $template )
run_script ( '', $cache )
run_script ( '', $cache, $package )

Runs a perl script which has been generated by make_script(). If $cache file is specified, the script will be loaded from there and be compiled into memory as a package. The name of this package can be defined in the third parameter. If $package has not been specified the package from caller(0) is used.

Returns a TRUE on success or FALSE on error.

Example:

$pab->run_script( 'template.htm' )
    or die $pab->error();

See also make_script, make_script_and_run, PAB3::require_and_run

make_script_and_run ( $template )
make_script_and_run ( $template, $cache )
make_script_and_run ( $template, $cache, $package )

Combines the two functions above. If $package has not been specified the package from caller(0) is used.

Returns a TRUE value on success or FALSE if an error occurs.

Example:

$pab->make_script_and_run(
    'template.htm',
    'template.pl'
) or die $pab->error();

See also make_script, run_script

register_loop ( $id, $source, $s_type )
register_loop ( $id, $source, $s_type, $record, $r_type )
register_loop ( $id, $source, $s_type, $record, $r_type, $object )
register_loop ( $id, $source, $s_type, $record, $r_type, $object, $arg )
register_loop ( $id, $source, $s_type, $record, $r_type, $object, $arg, $fixed )

Registers a loop which can be used inside templates.

You do not need to define loops in this way. You can also write it directly in the template. But if you want using hashmaps, you need to go in this way.

Arguments

$id

Loop identifier

$source

the source for the loop.

$s_type

the type of the source. One of these constants: PAB_ARRAY, PAB_HASH or PAB_FUNC

$record

the record for the loop.

$r_type

the type of the record. One of these constants: PAB_SCALAR, PAB_FUNC, PAB_ARRAY or PAB_HASH

$object

a object for $source or $record functions.

$arg

arguments passed to the source if it is a function, as an array reference

$fixed

installes the loop as fixed. it can not be overwritten

Combinations

Following combinations are possible:

 --------------------------------------
|   Source   |   Record   |   Object   |
 --------------------------------------
| PAB_ARRAY  | PAB_SCALAR |     -      |
| PAB_ARRAY  | PAB_FUNC   |    yes     |
| PAB_HASH   | PAB_SCALAR |     -      |
| PAB_HASH   | PAB_FUNC   |    yes     |
| PAB_FUNC   | PAB_SCALAR |    yes     |
| PAB_FUNC   | PAB_ARRAY  |    yes     |
| PAB_FUNC   | PAB_HASH   |    yes     |
 --------------------------------------

Source as Array, Record as Scalar

# definition
register_loop( 'id', 'source' => PAB_ARRAY, 'record' => PAB_SCALAR )

# result
foreach $record( @source ) {
}

Source as Array, Record as Function

# definition
register_loop( 'id', 'source' => PAB_ARRAY, 'record' => PAB_FUNC )

# result
foreach <iv>( @source ) {
     &record( <iv> );
}

Source as Array, Record as Function, Object

# definition
register_loop( 'id', 'source' => PAB_ARRAY, 'record' => PAB_FUNC, 'object' )

# result
foreach <iv>( @source ) {
     $object->record( <iv> );
}

Source as Hash, Record as Scalar

# definition
register_loop( 'id', 'source' => PAB_HASH, 'record' => PAB_SCALAR )

# result
foreach $record( keys %source ) {
}

Source as Hash, Record as Function

# definition
register_loop( 'id', 'source' => PAB_HASH, 'record' => PAB_FUNC )

# result
foreach <iv>( keys %source ) {
    &record( <iv> );
}

Source as Hash, Record as Function, Object

# definition
register_loop( 'id', 'source' => PAB_HASH, 'record' => PAB_FUNC, 'object' )

# result
foreach <iv>( keys %source ) {
    $object->record( <iv> );
}

Source as Function, Record as Scalar

# definition
register_loop( 'id', 'source' => PAB_FUNC, 'record' => PAB_SCALAR )

# result
while( $record = &source( @$arg ) ) {
}

Source as Function, Record as Scalar, Object

# definition
register_loop( 'id', 'source' => PAB_FUNC, 'record' => PAB_SCALAR, 'object' )

# result
while( $record = $object->source( @$arg ) ) {
}

Source as Function, Record as Array

# definition
register_loop( 'id', 'source' => PAB_FUNC, 'record' => PAB_ARRAY )

# result
while( @record = &source( @$arg ) ) {
}

Source as Function, Record as Hash

# definition
register_loop( 'id', 'source' => PAB_FUNC, 'record' => PAB_HASH )

# result
while( %record = &source( @$arg ) ) {
}

Source as Function, Record as Function

# definition
register_loop( 'id', 'source' => PAB_FUNC, 'record' => PAB_FUNC )

# result
while( <iv> = &source( @$arg ) ) {
    &record( <iv> );
}

Source as Function, Record as Function, Object

# definition
register_loop( 'id', 'source' => PAB_FUNC, 'record' => PAB_FUNC, 'object' )

# result
while( <iv> = $object->source( @$arg ) ) {
    &record( $object, <iv> );
}

Examples

Example of a loop over an array with record as subroutine:

use PAB3 qw(:const);

my @Array1 = ( 1, 2, 3 );

$pab->register_loop(
    'MYLOOP', 'Array1' => PAB_ARRAY , 'init_record' => PAB_FUNC
);

sub init_record {
    $Record = shift;
    ...
}

Example of an enumeration loop:

$pab->register_loop(
    'MYLOOP', 'enum' => PAB_FUNC, 'Record' => PAB_SCALAR
);

$Counter = 10;

sub enum {
     if( $Counter == 0 ) {
         $Counter = 10;
         return 0;
     }
     return $Counter --;
}

--- inside the template ---

<* LOOP MYLOOP *>
<* PRINT $Record . "\n" *>
<* END LOOP *>

See also

-LOOP-.

add_hashmap ( $loop_id, $hashname, $fieldmap )
add_hashmap ( $loop_id, $hashname, $fieldmap, $hm_save )

Add a hashmap to the parser. Hashmaps are designed to translate hashes in templates into arrays in the parsed script. For example: you use $var->{'Key'} in your template. With a hashmap you can convert it into an array like $var->[0] without taking care of the indices. This can noticable make the execution time faster.

Parameters

$loop_id

Defines the loop to search for If it is defined the program sequences inside the loop will be converted. Otherwise the complete template will be used for.

$hashname

Specifies the name of the hash to be translated.

$fieldmap

Can be a reference to an array of fieldnames or a reference to a hash containing fieldnames as keys and the assiocated indices as values.

$hm_save

If $fieldmap is an arrayref, the new generated hashmap can be saved in this parameter.

Return Values

Returns TRUE on success or FALSE if it fails.

Example

@data = (
    [ 'Smith', 'John', 33 ],
    [ 'Thomson', 'Peggy', 45 ],
    [ 'Johanson', 'Gustav', 27 ],
);
@fields = ( 'Name', 'Prename', 'Age' );

$pab->register_loop( 'Person', 'data' => PAB_ARRAY, 'per' => PAB_SCALAR );
$pab->add_hashmap( 'Person', 'per', \@fields );

$pab->make_script_and_run( 'template' );

--- template ---

<* LOOP Person *>
<* = $per->{'Prename'} . ' ' . $per->{'Name'} *> is <* = $per->{'Age'} *> years old
<* END LOOP *>

Warning

If an empty result from a db query is returned, no hashmap can be created. If your template needs to be compiled and uses hashmaps, which are empty, you will get an error. You should recompile affected templates once by running them with valid hashmaps. Or you can use a hashmap cache handler. See more at PAB3::HashMapCache.

reset ()

Resets loops and hashmaps in the PAB3 class.

Returns allways a TRUE value.

require ( $filename )

Loads the required file and compiles it into a package and runs it once it has been changed.

Example:

&PAB3::require( 'config.inc.pl' );
require_and_run ( $filename )

Loads the required file and compiles it into a package once it has been changed. Runs it on every call.

Example:

&PAB3::require_and_run( 'dosomething.pl' );

PAB3 LANGUAGE SYNTAX

The little extended language is needed to extract the PAB and Perl elements from the rest of the template. By default program sequences are included in <* ... *> and directives are separated by ;; . This parameters can be overwritten in new().

Some Examples

<p><* PRINT localtime *></p>

<*
    my $MyVar = int( rand( 3 ) );;
    my @MyText =
        (
            'I wish you a nice day.',
            'Was happy to see you.',
            'Would be nice to see you back.'
        )
*>

<* IF $MyVar == 0 *>
<p>I wish you a nice day.</p>
<* ELSIF $MyVar == 1 *>
<p>Was happy to see you.</p>
<* ELSE *>
<p>Would be nice to see you back.</p>
<* END IF *>

<!-- OR SHORTLY -->

<p><* PRINT $MyText[$MyVar] *></p>

Directives

The following list explains the directives available in PAB3. The description is using the default program and command separators. All directives are case insensitive.

= <expression>

Prints the output returned from <expression>. Performance notice: Tests are showing the double of speed when expressions are combined as strings instead of using multiple argmuents. For example:

faster:
<* PRINT $x . ' some data: ' . $str *>

slower:
<* PRINT $x, ' some data: ', $str *>

Joining several PRINT directives into one directive does not realy affect to the speed, because the optimizer will do it automatically.

<* PRINT <expression> *>

or shortly

<* =<expression>      *>

Example:

<* PRINT $0, "\n" *>
<* PRINT 'Now: ' . time . "\n" *>
<* = 'Or formated: ' . &PAB3::Utils::strftime( '%c', time ) *>
: <expression>
<expression>

Executes <expression> wihout printing the output. This is also the default action if no directive has been specified.

<* : <expression> *>

or

<* <expression>     *>

Example:

<* : $MyVar = 1 *>
<* : &mySub( $MyVar ) *>
<* $X = $Y *>
IF <condition>
ELSIF <condition>
ELSE
END IF

Enclosed block is processed if the <condition> is true.

<* IF <condition>    *>
...
<* ELSIF <condition> *>
...
<* ELSE              *>
...
<* END IF            *>
INCLUDE <template>

Process another template file. Please note the "class_name" in new().

<* INCLUDE <template.file> *>
-LOOP-
LOOP <id>
LOOP <id> <exp1>
LOOP <id> <exp1> <exp2>
END LOOP

Performs a predefined loop or a loop which has been registered by register_loop. In predifened loops like ARRAY, FOR and HASH, <exp1> is used as source and <exp2> is used as record. In userdefined loops <exp1> is used as record and <exp2> is used as argument.

<* LOOP <id> [<exp1> [<exp2>]] *>
...
<* END LOOP                    *>

Theses loops are predefined:

<* LOOP ARRAY <array> [<record>] *>

<* LOOP FOR   <array> [<record>] *>
  
<* LOOP HASH  <hash>  [<record>] *>

Example of an ARRAY loop: (FOR does the same like ARRAY)

<* LOOP ARRAY @INC $_ *>
<*   PRINT $_ . "\n" *>
<* END LOOP *>

Example of a HASH loop:

<* LOOP HASH %ENV $_ *>
<*   PRINT $_ . ' = ' . $ENV{$_} . "\n" *>
<* END LOOP *>

An example of a self defined loop:

This example also shows the use of the PAB3::DB class.

--- inside the perl script ---

use PAB3 qw(:const);
use PAB3::DB;
use PAB3::Utils qw(:default);

$pab = PAB3->new( ... );
$db = PAB3::DB->connect( ... );

$r_gb = $db->query( 'SELECT * FROM guestbook ORDER BY Time DESC' );

$pab->register_loop(
     'GUESTBOOK', 'fetch_hash' => PAB_FUNC, 'row' => PAB_HASH, '$r_gb'
);

$pab->make_script_and_run( 'template.htm' );

--- inside the template ---

<* LOOP GUESTBOOK *>
<* PRINT $row{'Submitter'} *> wrote at 
<* PRINT &strftime( '%c', $row{'Time'} ) *> 
the following comment:<br>
<blockquote><* PRINT $row{'Comment'} *></blockquote>
<hr noshade size="1">
<* END LOOP *>

Second example of a self defined loop:

This example shows a implementation of guestbook example above, which can run faster. It uses an array instead of a hash as record. The Translation will be set by add_hashmap(). The template must not be changed.

--- inside the perl script ---

use PAB3 qw(:const);
use PAB3::DB;
use PAB3::Utils qw(:default);

$pab = PAB3->new( ... );
$db = PAB3::DB->connect( ... );

$r_gb = $db->query( 'SELECT * FROM guestbook ORDER BY Time DESC' );

$pab->register_loop(
     'GUESTBOOK', 'fetch_array', PAB_FUNC, 'row', PAB_ARRAY, '$r_gb'
);
$pab->add_hashmap( 'GUESTBOOK', 'row', [ $r_gb->fetch_names() ] );

$pab->make_script_and_run( 'template.htm' );

--- inside the template ---

<* LOOP GUESTBOOK *>
<* PRINT $row{'Submitter'} *> wrote at 
<* PRINT &strftime( '%c', $row{'Time'} ) *> 
the following comment:<br>
<blockquote><* PRINT $row{'Comment'} *></blockquote>
<hr noshade size="1">
<* END LOOP *>

See also register_loop, add_hashmap, PAB3::DB, PAB3::Utils

SUB <expression>
END SUB

Defines a subroutine in the style local <expression> = sub { ... };.

<* SUB <expression> *>
...
<* END SUB          *>

Example:

<* SUB *action *>
<* PRINT $ENV{'SCRIPT'} . '?do=' . ( $_[0] || '' ) *>
<* END SUB *>

<a href="<* &action( 'open' ) *>">Open</a>
COMMENTS

Comments are copied.

<* #... *>

Example:

# comment out directives.
<* #PRINT $foo *>
!X <directive>

This special directive prints the content in <directive> as a new directive. It can be useful to generate templates from templates.

<* !X <directive> *>

Example:

<* $foo = '$bar' *>

<* !X PRINT $foo *>

produces: <* PRINT $bar *>

<* !X PRINT "\$foo" *>

produces: <* PRINT $foo *>

EXPORTS

By default nothing is exported. To export constants like PAB_SCALAR etc. you can use the export tag ":const"

AUTHORS

Christian Mueller <christian_at_hbr1.com>

COPYRIGHT

The PAB3 module is free software. You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.