NAME
Abstract::Meta::Class - Simple meta object protocol implementation.
SYNOPSIS
package Dummy;
use Abstract::Meta::Class ':all';
has '$.attr1' => (default => 0);
has '%.attrs2' => (default => {a => 1, b => 3}, item_accessor => 'attr2');
has '@.atts3' => (default => [1, 2, 3], required => 1, item_accessor => 'attr3');
has '&.att3' => (required => 1);
has '$.att4' => (default => sub { 'stuff' } , required => 1);
my $dummt = Dummy->new(
att3 => 3,
);
use Dummy;
my $obj = Dummy->new(attr3 => sub {});
my $attr1 = $obj->attr1; #0
$obj->set_attr1(1);
$obj->attr2('c', 4);
$obj->attrs2 #{a => 1, b => 3. c => 4};
my $val_a = $obj->attr2('a');
my $item_1 = $obj->attr3(1);
$obj->count_attrs3();
$obj->push_attrs3(4);
DESCRIPTION
Meta object protocol implementation,
hash/array storage type
To speed up bless time as well optimise memory usage you can use Array storage type. (Hash is the default storage type)
package Dummy;
use Abstract::Meta::Class ':all';
storage_type 'Array';
has '$.attr1' => (default => 0);
has '%.attrs2' => (default => {a => 1, b => 3}, item_accessor => 'attr2');
has '@.attrs3' => (default => [1, 2, 3], required => 1, item_accessor => 'attr3');
has '&.attr4' => (required => 1);
has '$.attr5';
has '$.attr6' => (default => sub { 'stuff' } , required => 1);
my $dummy = Dummy->new(
attr4 => sub {},
);
use Data::Dumper;
warn Dumper $dummy;
# bless [0, {a =>1,b => 3}, [1,2,3],sub{},undef,sub {}], 'Dummy'
simple validation and default values
package Dummy;
use Abstract::Meta::Class ':all';
has '$.attr1' => (default => 0);
has '&.att3' => (required => 1);
use Dummy;
my $obj = Dummy->new; #dies - att3 required
utility methods for an array type
While specyfing array type of attribute
the following methods are added (count || push || pop || shift || unshift)_accessor.
package Dummy;
use Abstract::Meta::Class ':all';
has '@.array' => (item_accessor => 'array_item');
use Dummy;
my $obj = Dummy->new;
$obj->count_array();
$obj->push_array(1);
my $x = $obj->array_item(0);
my $y = $obj->pop_array;
#NOTE scalar, array context sensitive
my $array_ref = $obj->array;
my @array = $obj->array;
item accessor method for complex types
While specyfing an array or a hash type of attribute then
you may specify item_accessor for get/set value by hash key or array index.
package Dummy;
use Abstract::Meta::Class ':all';
has '%.hash' => (item_accessor => 'hash_item');
use Dummy;
my $obj = Dummy->new;
$obj->hash_item('key1', 'val1');
$obj->hash_item('key2', 'val2');
my $val = $obj->hash_item('key1');
#NOTE scalar, array context sensitive
my $hash_ref = $obj->hash;
my %hash = $obj->hash;
perl types validation
Dy default all complex types are validated against its definition.
package Dummy;
use Abstract::Meta::Class ':all';
has '%.hash' => (item_accessor => 'hash_item');
has '@.array' => (item_accessor => 'array_item');
use Dummy;
my $obj = Dummy->new(array => {}, hash => []) #dies incompatible types.
associations
This module handles different types of associations(to one, to many, to many ordered).
You may also use bidirectional association by using the_other_end option,
NOTE: When using the_other_end automatic association/deassociation happens,
celanup method is installed.
package Class;
use Abstract::Meta::Class ':all';
has '$.to_one' => (associated_class => 'AssociatedClass');
has '@.ordered' => (associated_class => 'AssociatedClass');
has '%.to_many' => (associated_class => 'AssociatedClass', item_accessor => 'many', index_by => 'id');
use Class;
use AssociatedClass;
my $obj1 = Class->new(to_one => AssociatedClass->new);
my $obj2 = Class->new(ordered => [AssociatedClass->new]);
# NOTE: context sensitive (scalar, array)
my @association_objs = $obj2->ordered;
my @array_ref = $obj2->ordered;
my $obj3 = Class->new(to_many => [AssociatedClass->new(id =>'001'), AssociatedClass->new(id =>'002')]);
my $association_obj = $obj3->many('002);
# NOTE: context sensitive (scalar, array)
my @association_objs = values %{$obj3->to_many};
my $hash_ref = $obj3->to_many;
- bidirectional associations (the_other_end attribute)
package Master;
use Abstract::Meta::Class ':all';
has '$.name';
has '%.details' => (associated_class => 'Detail', the_other_end => 'master', item_accessor => 'detail', index_by => 'id');
package Detail;
use Abstract::Meta::Class ':all';
has '$.id' => (required => 1);
has '$.master' => (
associated_class => 'Master',
the_other_end => 'details'
);
use Master;
use Detail;
my @details = (
Detail->new(id => 1),
Detail->new(id => 2),
Detail->new(id => 3),
);
my $master = Master->new(name => 'foo', details => [@details]);
print $details[0]->master->name;
- while using an array/hash association storage remove_<attribute_name> | add_<attribute_name> are added.
$master->add_details(Detail->new(id => 4),);
$master->remove_details($details[0]);
#cleanup method is added to class, that deassociates all bidirectional associations
decorators
....- on_validate
- on_change
- on_read
- initialise_method
package Triggers;
use Abstract::Meta::Class ':all';
has '@.y' => (
on_change => sub {
my ($self, $attribute_name, $scope, $value_ref, $index) = @_;
# scope -> mutator, item_accessor
... do some stuff
# process further in standard way by returning true
$self;
},
# replaces standard read
on_read => sub {
my ($self, $attr_name, $scope, $index)
#scope can be: item_accessor, accessor
...
#return requested value
},
item_accessor => 'y_item'
);
use Triggers;
my $obj = Triggers->new(y => [1,2,3]);
- add hoc decorators
package Class;
use Abstract::Meta::Class ':all';
has '%.attrs' => (item_accessor => 'attr');
my $attr = DynamicInterceptor->meta->attribute('attrs');
my $obj = DynamicInterceptor->new(attrs => {a => 1, b => 2});
my $a = $obj->attr('a');
my %hook_access_log;
my $ncode_ref = sub {
my ($self, $attribute, $scope, $key) = @_;
#do some stuff
# or
if ($scope eq 'accessor') {
return $values;
} else {
return $values->{$key};
}
};
$attr->set_on_read($ncode_ref);
# from now it will apply to Class::attrs calls.
my $a = $obj->attr('a');
abstract methods/classes
package BaseClass;
use Abstract::Meta::Class ':all';
has '$.attr1';
abstract => 'method1';
package Class;
use base 'BaseClass';
sub method1 {};
use Class;
my $obj = BaseClass->new;
# abstract classes
package InterfaceA;
use Abstract::Meta::Class ':all';
abstract_class;
abstract => 'method1';
abstract => 'method2';
package ClassA;
use base 'InterfaceA';
sub method1 {};
sub method2 {};
use Class;
my $classA = Class->new;
package Class;
use Abstract::Meta::Class ':all';
has 'attr1';
has 'interface_attr' => (associated_class => 'InterfaceA', required => 1);
use Class;
my $obj = Class->new(interface_attr => $classA);
external attributes storage
You may want store attributes values outside the blessed reference, then you may
use transistent keyword (Inside Out Objects)
package Transistent;
use Abstract::Meta::Class ':all';
has '$.attr1';
has '$.x' => (required => 1);
has '$.t' => (transistent => 1);
has '%.th' => (transistent => 1);
has '@.ta' => (transistent => 1);
use Transistent;
my $obj = Transistent->new(attr1 => 1, x => 2, t => 3, th => {a =>1}, ta => [1,2,3]);
use Data::Dumper;
print Dumper $obj;
Cleanup and DESTORY methods are added to class, that delete externally stored attributes.
METHODS
- new
- install_cleanup
-
Install cleanup method
- install_destructor
-
Install destructor method
- install_constructor
-
Install constructor
- apply_contructor_parameters
-
Applies constructor parameters.
- meta
- attributes
-
Returns attributes for meta class
- set_attributes
-
Mutator sets attributes for the meta class
- has_cleanup_method
-
Returns true if cleanup method was generated
- set_cleanup_method
-
Sets clean up
- has_destory_method
-
Returns true is destroy method was generated
- set_destroy_method
-
Sets set_destructor flag.
- initialise_method
-
Returns initialise method's name default is 'initialise'
- is_abstract
-
Returns is class is an abstract class.
- set_abstract
-
Set an abstract class flag.
- set_initialise_method
-
Mutator sets initialise_method for the meta class
- associated_class
-
Returns associated class name
- set_associated_class
-
Mutator sets associated class name
- all_attributes
-
Returns all_attributes for all inherited meta classes
- attribute
-
Returns attribute object
- super_classes
- install_meta_class
-
Adds class to meta repository.
- meta_class
-
Returns meta class object for passed in class name.
- add_attribute
- attribute_class
-
Returns meta attribute class
- has
-
Creates a meta attribute.
Takes attribute name, and the following attribute options: see also Abstract::Meta::Attribute
- storage_type
-
Sets storage type for the attributes. allowed values are Array/Hash
- abstract
-
Creates an abstract method
- abstract_class
-
Creates an abstract method
- install_abstract_methods
- install_attribute_methods
-
Installs attribute methods.
- add_method
-
Adds code reference to the class symbol table. Takes a class name, method name and CODE reference.
- remove_method
-
Adds code reference to the class symbol table. Takes a class name, method name and CODE reference.
- constructor_attributes
-
Returns a list of attributes that need be validated and all that have default value
SEE ALSO
COPYRIGHT AND LICENSE
The Abstract::Meta::Class 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.
AUTHOR
Adrian Witas, adrian@webapp.strefa.pl