NAME

SADI::Simple::Base - Hash-based abstract super-class for all SADI objects

SYNOPSIS

use base qw( SADI::Base );

$self->throw ("This is an error");

DESCRIPTION

This is a hash-based implementation of a general sadi super-class. Most SADI objects should inherit from this.

ACKNOWLEDGEMENTS

Thanks to Martin Senger, the original author of this code, and also to Edward Kawas who refactored it into it's current form.

ACCESSIBLE ATTRIBUTES

Most of the SADI objects are just containers of other objects (attributes, members). Therefore, in order to crete a new SADI object it is often enough to inherit from this SADI::Base and to list allowed attributes. The object lists only new, additional, attributes (those defined in its parent classes are already available).

This is done by creating a closure with a list of allowed attribute names. These names correspond with the allowed get and set methods. For example:

  {
    my %_allowed =
        (
	 id         => undef,
	 namespace  => undef,
	 );
  }

The closure above allows to call:

$obj->id;                    # a get method
$obj->id ('my id');          # a set method

$obj->namespace;             # a get method
$obj->namespace ('my ns');   # a set method

Well, not yet. The closure also needs two methods that access these (and only these - that is why it is a closure, after all) attributes. Here they are:

  {
    my %_allowed =
	(
	 id         => undef,
	 namespace  => undef,
	 );
    sub _accessible {
	my ($self, $attr) = @_;
	exists $_allowed{$attr} or $self->SUPER::_accessible ($attr);
    }
    sub _attr_prop {
	my ($self, $attr_name, $prop_name) = @_;
	my $attr = $_allowed {$attr_name};
	return ref ($attr) ? $attr->{$prop_name} : $attr if $attr;
	return $self->SUPER::_attr_prop ($attr_name, $prop_name);
    }
  }

More about these methods in a moment.

Each attribute has also associated some properties (that is why we need the second method in the closure, the _attr_prop). For example:

  {
    my %_allowed =
	(
	 id         => undef,
	 namespace  => undef,
	 date  => {type => SADI::Base->DATETIME},
	 numbers      => {type => SADI::Base->INTEGER, is_array => 1},
     primitive  => {type => SADI::Base->BOOLEAN},
	 );
    ...
  }

The recognized property names are:

type

It defines a type of its attribute. It can be a primitive type - one of those defined as constants in SADI::Base (e.g. "SADI::Base->INTEGER") - or a name of a real object (e.g. SADI::RDF::Core).

When an attribute new value is being set it is checked against this type, and an exception is thrown if the value does not comply with the type.

Default type (used also when the whole properties are undef) is "SADI::Base->STRING".

is_array

A boolean property. If set to true it allows to set more values to this attribute. It also allows to call a method prefixed with add_ to add a new value (or values) to this attribute.

Default value is false.

Recognized values for true are: 1, yes, true, + and ano. Anything else is considered false.

readonly

A boolean property. If set to true the atribute can only be read.

post

A property containing a reference to a subroutine. This subroutine is called after a new value was set. It allows to do some post-processing. For example:

  {
    my %_allowed =
	(
	 value  => {post => sub { shift->{isValueCDATA} = 0; } },
	 );
    ...
  }

Now we know what attribute properties are - so we can define what these methods in closure do (even though you do not need to know - unless The Law of Leaky Abstractions starts showing).

_accessible ($attr_name)

Return 1 if the parameter $attr_name is an allowed name to be set/get in this class; otherwise, pass it to the parent class.

_attr_prop ($attr_name, $prop_name)

Return a value of a property given by name $prop_name for given attribute $attr_name; if such attribute does not exist here, pass it to the parent class.

THROWING EXCEPTIONS

One of the functionalities that SADI::Base provides is the ability to throw() exceptions with pretty stack traces.

throw

Throw an exception. An argument is an error message.

format_stack

Return a nicely formatted stack trace. The resul includes also an error message given as a scalar argument. Usually, this method is not called directly but via throw (unless enable_throw_with_stack was set to true).

print $self->format_stack ("Something terrible happen.");

OTHER SUBROUTINES

new

Create an empty hash-based object. Then call init() in order to do any initializing steps. This class provides only an empty init() but sub-classes may have it richer. Finally, fill the new object with the given arguments (name/value pairs). The filling is done via set methods - which means that only attributes allowed for this particular object can be used.

Arguments are name/value pairs. A special case is allowed: when a single element argument occurs, it is treated as a "value". For example, it is allowed to write:

$sadiint = new SADI::Data::Integer (42);

instead of a long way (doing the same):

$sadiint = new SADI::Data::Integer (value => 42);

init

Called after an object has been created (in new()) and before the values given in the constructor have been set. No arguments.

If your sub-class implements this method, make sure that it calls also the same method of its super class:

sub init {
    my ($self) = shift;
    $self->SUPER::init();
    # ... here do what you wish to do
    # ...
}

toString

Return an (almost) human-readable description of any object.

Without any parameter, it stringifies the caller object (self). Otherwise it stringifies the object given as parameter.

    print $self->toString;

    my $good_stuff = { yes => [1,2,3],
		       no  => { net => 'R', nikoliv => 'C' },
		   };
    print $self->toString ($good_stuff);