Abstract::Meta::Class - Simple meta object protocol implementation.
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); 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);
Meta object protocol implementation,
package Dummy; use Abstract::Meta::Class ':all'; has '$.attr1' => (default => 0); has '&.att3' => (required => 1); use Dummy; my $obj = Dummy->new; #dies - att3 required
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;
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;
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'); my $obj = Dummy->new(array => {}, hash => []) #dies incompatible types.
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
- 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');
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);
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.
Install cleanup method
Install destructor method
Install constructor
Applies constructor parameters.
Returns attributes for meta class
Mutator sets attributes for the meta class
Returns true if cleanup method was generated
Sets clean up
Returns true is destroy method was generated
Sets set_destructor flag.
Returns initialise method's name default is 'initialise'
Returns is class is an abstract class.
Set an abstract class flag.
Mutator sets initialise_method for the meta class
Returns associated class name
Mutator sets associated class name
Returns all_attributes for all inherited meta classes
Returns attribute object
Adds class to meta repository.
Returns meta class object for passed in class name.
Returns meta attribute class
Creates a meta attribute.
Takes attribute name, and the following attribute options: see also Abstract::Meta::Attribute
Creates an abstract method
Installs attribute methods.
Adds code reference to the class symbol table. Takes a class name, method name and CODE reference.
Returns a list of attributes that need be validated and all that have default value
Abstract::Meta::Attribute
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.
Adrian Witas, <adrian@webapp.strefa.pl</gt>
To install Abstract::Meta::Class, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Abstract::Meta::Class
CPAN shell
perl -MCPAN -e shell install Abstract::Meta::Class
For more information on module installation, please visit the detailed CPAN module installation guide.