NAME
Class::HPLOO - Easier way to declare classes on Perl, based in the popular class {...} style and ePod.
DESCRIPTION
This is the implemantation of OO-Classes for HPL. This brings an easy way to create PM classes, but with HPL resources/style.
USAGE
use
Class::HPLOO ;
class Foo
extends
Bar , Baz {
attr ( array foo_list ,
int
age , string name , foo )
## define attributes.
vars (
$GLOBAL_VAR
) ;
## same as: use vars qw($GLOBAL_VAR);
my
(
$local_var
) ;
## constructor/initializer:
sub
Foo {
$this
->{attr} =
$_
[0] ;
}
## methods with input variables declared:
sub
get_pages (
$base
, \
@pages
, \
%options
) {
my
@htmls
;
if
(
$options
{proxy} ) { ... }
foreach
my
$pages_i
(
@pages
) {
my
$url
=
"$base/$pages_i"
;
my
$html
= get(
$url
) ;
push
(
@htmls
,
$html
) ;
$this
->cache(
$url
,
$html
) ;
}
return
@htmls
;
}
## methos like a normal Perl sub:
sub
cache {
my
(
$url
,
$html
) =
@_
;
$this
->{CACHE}{
$url
} =
$html
;
}
sub
attributes_example {
$this
->set_foo_list(
qw(a b c d e f)
) ;
my
@l
=
$this
->get_foo_list ;
$this
->set_age(30) ;
$this
->set_name(
"Joe"
) ;
$this
->set_foo(
time
() ) ;
"NAME: "
.
$this
->get_name .
"\n"
;
"AGE: "
.
$this
->get_age .
"\n"
;
"FOO: "
.
$this
->get_foo .
"\n"
;
}
}
## Example of use of the class:
package
main ;
my
$foo
= new Foo(123) ;
CONTRUCTOR
The "method" new() is automatically declared by Class::HPLOO, then it calls the initializer that is a method with the name of the class, like Java.
class Foo
extends
{
## initializer:
sub
Foo {
$this
->{attr} =
$_
[0] ;
}
}
** Note that what the initializer returns is ignored! Unless you return a new constructed object or UNDEF. Return UNDEF (a constant of the class) makes the creation of the object return undef.
DESTRUCTOR
Use DESTROY() like a normal Perl package.
Class VERSION
From Class::HPLOO 0.12, you can define the class version in it's declaration:
class Foo [0.01]
extends
bar , baz {
...
}
This is just a replacement of the original Perl syntax:
$VERSION
=
'0.01'
;
SUBs
The syntax for subs was extend to allow argument definitions:
Class Foo {
sub
add(
$x
,
$y
) {
return
$x
+
$y
;
}
}
Also you can define HASH and ARRAY arguments:
Class Foo {
sub
add( \
@list
,
$n
, \
%hash
) {
foreach
my
$list_i
(
@list
) {
$list_i
+=
$n
;
}
}
}
This new syntax for arguments make much more easy to create functions and paste references for HASHes and ARRAYs.
INLINE SUBs
From version 0.18 is possible to define inline functions directly in the class code:
class Foo {
sub
normal_perl_sub {
"PERL SUB> @_\n"
;
}
sub
[C]
int
add(
int
x ,
int
y ) {
int
res = x + y ;
return
res ;
}
}
The parser for the INLINE SUBs is defined by:
sub
[\w+].*?{...}
| | |
| | ---> body.
| --->
sub
/function/method header.
---> language
So, basically is possible to use any language that Inline supports. Here's a Java example:
class Foo {
sub
[Java] public void msg( String txt ) {
System.out.println(txt) ;
}
}
Enjoy! ;-P
ATTRIBUTES , GLOBAL VARS & LOCAL VARS
You can use 3 types of definitions for class variables:
ATTRIBUTES
The main difference of an attribute of normal Perl variables, is the existence of the methods set and get for each attribute/key. Also an attribute can have a type definition and a handler, soo each value can be automatically formatted before be really set.
For better OO and persistence of objects ATTRIBUTES should be the main choice.
To set an attribute you use:
To define:
attr( type name ,
ref
type name , array name , hash name ,
sub
id )
To set:
$this
->set_name(
$val
) ;
## or:
$this
->{name} =
$val
;
To get:
my
$foo
=
$this
->get_name ;
## or:
my
$foo
=
$this
->{name} ;
The attr() definition has this syntax:
REF? ARRAY?|HASH? TYPE? NAME
- NAME
-
The name of the attribute.
An attribute only can be set by set_name() and get by get_name(). It also has a tied key with it's NAME in the HASH reference of the object.
- TYPE (optional)
-
Tells the type of the attribute. If not defined any will be used as default.
Standart types:
- any
-
Accept any type of value.
- string | str
-
A normal string.
- boolean | bool
-
A boolean value. Also accept 'true' and 'false' strings.
- integer | int
-
An integer that accepts only [0-9] digits.
- floating | float
-
A floating point, with the format /\d+\.\d+/. If /\.\d+$/ doesn't exists '.0' will be added in the end.
- sub
-
Define an attribute as a sub call:
class foo {
attr(
sub
id ) ;
sub
id() {
return
123 ; }
}
## call:
$foo
->id() ;
## or
print
" $foo->{id} \n"
;
- Object
-
This type will accept only object types or a defined object class:
class Foo {
attr ( XML::Smart xml , object any_obj , obj any_obj2 , UNIVERSAL any_obj3 ) ;
}
In the example above the attribute xml will accept only objects from XML::Smart, or objects that inherites from XML::Smart. The attribute any_obj will aceept any type of object. You can see that the types object, obj and UNIVERSAL are all the same.
Personalized types:
To create your own type you can use this syntax:
attr(
&mytypex
foo ) ;
Then you need to create the sub that will handle the type format:
sub
mytypex (
$value
) {
$value
=~ s/x/y/gi ;
## do some formatting.
return
$value
;
## return the value
}
Note that a type will handle one value/SCALAR per time. Soo, the same type can be used for array attributes or not:
attr(
&mytypex
foo , array
&mytypex
list ) ;
Soo, in the definition above, when list is set with some ARRAY, eache element of the array will be past one by one to the &mytypex sub.
- REF (optional)
-
Tells that the value is a reference. Soo, you need to always set it with a reference:
attr(
ref
foo ) ;
...
$this
->set_foo( \
$var
) ;
## or
$this
->set_foo( [1 , 2 , 3] ) ;
- ARRAY or HASH (optional)
-
Tells that the value is an array or a hash of some type.
Soo, for this type:
attr( array
int
ages ) ;
You can set and get without references:
$this
->set_ages(20 , 25 , 30 ,
'invalid'
, 40) ;
...
my
@ages
=
$this
->get_ages ;
Note that in this example, all the values of the array will be formated to integer. Soo, the value 'invalid' will be set to undef.
The attribute definition was created to handle object databases and the persistence of objects created with Class::HPLOO. Soo, for object persistence you should use only ATTRIBUTES and GLOBAL VARS.
Note that for object persistence, keys sets in the HASH reference of the object, that aren't defined as attributes, own't be saved. Soo, for the attr() definition below, the key foo won't be persistent:
attr( str bar ,
int
baz ) ;
$this
->{bar} =
'persistent'
;
$this
->{foo} =
'not persistent'
;
GLOBAL VARS
To set a global variable (static variable of a class), you use this syntax:
vars (
$foo
,
@bar
,
%baz
) ;
Actually this is the same to write:
** Note that a global variable is just a normal Perl variable, with a public access in it's package/class.
LOCAL VARS
This are just variables with private access (only accessed by the scope defined with it).
my
(
$foo
,
@bar
,
%baz
) ;
** Note that a local variable is just a normal Perl variable accessed only through it's scope.
Persistence with HDB::Object
From Class::HPLOO/0.16 we can use HDB::Object as a base class for persitence.
Example of class built with it:
use
Class::HPLOO ;
class User
extends
HDB::Object {
attr( user , pass , name ,
int
age ) ;
sub
User(
$user
,
$pass
,
$name
,
$age
) {
$this
->{user} =
$user
;
$this
->{pass} =
$pass
;
$this
->{name} =
$name
;
$this
->{age} =
time
;
}
}
When you create the object it will be automatically stored in the HDB database:
my
$user
= new User(
'joe'
,
'123'
,
'Joe Smith'
, 30) ;
...
$user
=
undef
;
## Destroy and automatically save (insert into table User).
To load an already stored object you should use the method load():
my
$user
= load User(
"user eq 'joe'"
) ;
$user
->{age} = 40 ;
$user
=
undef
;
## Destroy and automatically save (update col age).
** Note that you don't need to care about the DB, including the creation of the table! Is everything automatic.
METHODS
All the methods of the classes are declared like a normal sub.
You can declare the input variables to receive the arguments of the method:
sub
methodx (
$arg1
,
$arg2
, \
@listref
, \
%hasref
,
@rest
) {
...
}
## Calling:
$foo
->methodx(123 , 456 , [0,1,2] , {
k1
=>
'x'
} , 7 , 8 , 9 ) ;
PREDEFINED METHODS
- ATTRS
-
Return the list of attributes in the declaration order.
- __CLASS__
-
A constant that returns the name of the class.
HTML BLOCKS
You can use HTML blocks in the class like in HPL documents:
class Foo {
sub
test {
<% html_test>(123) ;
}
<% html_test(
$n
)
<hr>
NUMBER:
$n
<hr>
%>
}
SUB CLASSES
From version 0.04+ you can declare sub-classes:
class foo {
class subfoo { ... }
}
You also can handle the base name of a class adding "." in the begin of the class name:
class foo {
class .in { ... }
}
In the example above, the class name .in will be translated as foo::in.
USE_BASE
By default the code generated by Class::HPLOO is stand alone, so you don't need to install Class::HPLOO to run it, but as disadvantage the code to be loaded by a group of classes built with Class::HPLOO will be bigger.
As an option you can use the USE_BASE parameter, that will define the use of the class Class::HPLOO::Base in the @ISA path, so all the common codes for class that are built by Class::HPLOO will be shared, saving memory and load time:
That will generate this code:
@ISA
=
qw(Class::HPLOO::Base UNIVERSAL)
;
my
$CLASS
=
'Foo'
;
sub
__CLASS__ {
'Foo'
} ;
use
Class::HPLOO::Base ;
}
Without USE_BASE this is the default code to be generated:
@ISA
=
qw(UNIVERSAL)
;
my
$CLASS
=
'Foo'
;
sub
__CLASS__ {
'Foo'
} ;
sub
new {
if
( !
defined
&Foo
&&
@ISA
> 1 ) {
foreach
my
$ISA_i
(
@ISA
) {
return
&{
"$ISA_i\::new"
}(
@_
)
if
defined
&{
"$ISA_i\::new"
} ;
}
}
my
$class
=
shift
;
my
$this
=
bless
({} ,
$class
) ;
no
warnings ;
my
$undef
= \
''
;
sub
UNDEF {
$undef
} ;
my
$ret_this
=
defined
&Foo
?
$this
->Foo(
@_
) :
undef
;
if
(
ref
(
$ret_this
) && UNIVERSAL::isa(
$ret_this
,
$class
) ) {
$this
=
$ret_this
}
elsif
(
$ret_this
==
$undef
) {
$this
=
undef
}
return
$this
;
}
sub
SUPER {
my
(
$pack
,
undef
,
undef
,
$sub0
) =
caller
(1) ;
unshift
(
@_
,
$pack
)
if
( (!
ref
(
$_
[0]) &&
$_
[0] ne
$pack
) || (
ref
(
$_
[0]) && !UNIVERSAL::isa(
$_
[0] ,
$pack
)) ) ;
my
$sub
=
$sub0
;
$sub
=~ s/.*?(\w+)$/$1/ ;
$sub
=
'new'
if
$sub0
=~ /(?:^|::)
$sub
\::
$sub
$/ ;
$sub
=
"SUPER::$sub"
;
$_
[0]->
$sub
(
@_
[1..
$#_
]) ;
}
}
DUMP
You can dump the generated code:
** The nice option just try to make a cleaner code.
BUILD
The script "build-hploo.pl" can be used to convert .hploo files to .pm files.
So you can write a Perl Module with Class::HPLOO and release it as a normal .pm file without need Class::HPLOO installed.
If you have ePod (0.03+) installed you can use ePod to write your documentation. For .hploo files the ePod need to be always after __END__.
Note that ePod accepts POD syntax too, so you still can use normal POD for documentation.
SEE ALSO
Perl6::Classes, HPL, HDB::Object, HDB.
AUTHOR
Graciliano M. P. <gmpassos@cpan.org>
I will appreciate any type of feedback (include your opinions and/or suggestions). ;-P
COPYRIGHT
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.