Anansi-Library

 view release on metacpan or  search on metacpan

lib/Anansi/Library.pm  view on Meta::CPAN

        $self->libraryExample();
        $self->LibraryExample::libraryExample();
    }

    1;

=head1 DESCRIPTION

This is a base module definition that manages the functionality extension of
module object instances.

=cut


our $VERSION = '0.03';

my $LIBRARY = {};


=head1 METHODS

=cut


=head2 abstractClosure

    my $CLOSURE = Anansi::Library->abstractClosure(
        'Some::Namespace',
        'someKey' => 'some data',
        'anotherKey' => 'Subroutine::Namespace',
        'yetAnotherKey' => Namespace::someSubroutine,
    );
    $CLOSURE->anotherKey();
    $CLOSURE->yetAnotherKey();

    sub Subroutine::Namespace {
        my ($self, $closure, %parameters) = @_;
        my $abc = ${$closure}{abc} || 'something';
        ${$closure}{def} = 'anything';
    }

=over 4

=item class I<(Blessed Hash B<or> String, Required)>

Either an object of this namespace or this module's namespace.

=item abstract I<(String, Required)>

The namespace to associate with the closure's encapsulating object.

=item parameters I<(Hash, Optional)>

Named parameters where either the key is the name of a variable stored within
the closure and the value is it's data or when the value is a subroutine the key
is the name of a generated method of the closure's encapsulating object that
runs the subroutine and passes it a reference to the closure.

=back

Creates both an anonymous hash to act as a closure variable and a blessed object
as the closure's encapsulating accessor.  Supplied data is either stored within
the closure using the key as the name or in the case of a subroutine, accessed
by an auto-generated method of that name.  Closure is achieved by passing a
reference to the anonymous hash to the supplied subroutines via the
auto-generated methods.

=cut


sub abstractClosure {
    my ($class, $abstract, %parameters) = @_;
    return if(ref($abstract) !~ /^$/);
    return if($abstract !~ /[a-zA-Z]+[a-zA-Z0-9_]*(::[a-zA-Z]+[a-zA-Z0-9_]*)+$/);
    my $ABSTRACT = {
        NAMESPACE => $abstract,
    };
    my $CLOSURE = {
    };
    foreach my $key (keys(%parameters)) {
        next if(ref($key) !~ /^$/);
        next if($key !~ /^[a-zA-Z_]*[a-zA-Z0-9_]+$/);
        next if('NAMESPACE' eq $key);
        if(ref($parameters{$key}) =~ /^CODE$/i) {
            *{$abstract.'::'.$key} = sub {
                my ($self, @PARAMETERS) = @_;
                return &{$parameters{$key}}($self, $CLOSURE, (@PARAMETERS));
            };
        } elsif(ref($parameters{$key}) !~ /^$/i) {
            ${$CLOSURE}{$key} = $parameters{$key};
        } elsif($parameters{$key} =~ /^[a-zA-Z]+[a-zA-Z0-9_]*(::[a-zA-Z]+[a-zA-Z0-9_]*)+$/) {
            if(exists(&{$parameters{$key}})) {
                *{$abstract.'::'.$key} = sub {
                    my ($self, @PARAMETERS) = @_;
                    return &{\&{$parameters{$key}}}($self, $CLOSURE, (@PARAMETERS));
                };
            } else {
                ${$CLOSURE}{$key} = $parameters{$key}
            }
        } else {
            ${$CLOSURE}{$key} = $parameters{$key};
        }
    }
    return bless($ABSTRACT, $abstract);
}


=head2 abstractObject

    my $OBJECT = Anansi::Library->abstractObject(
        'Some::Namespace',
        'someKey' => 'some data',
        'anotherKey' => 'Subroutine::Namespace',
        'yetAnotherKey' => Namespace::someSubroutine,
    );
    $OBJECT->anotherKey();
    $OBJECT->yetAnotherKey();

    sub Subroutine::Namespace {
        my ($self, %parameters) = @_;
        my $abc = $self->{abc} || 'something';
        $self->{def} = 'anything';
    }

=over 4

=item class I<(Blessed Hash B<or> String, Required)>

Either an object of this namespace or this module's namespace.

=item abstract I<(String, Required)>

The namespace to associate with the object.

=item parameters I<(Hash, Required)>

Named parameters where either the key is the name of a variable stored within
the object and the value is it's data or when the value is a subroutine the key
is the name of a namespace method.

=back

Creates a blessed object.  Supplied data is either stored within the object or
in the case of a subroutine as a namespace method of that name.

=cut


sub abstractObject {
    my ($class, $abstract, %parameters) = @_;
    return if(ref($abstract) !~ /^$/);
    return if($abstract !~ /[a-zA-Z]+[a-zA-Z0-9_]*(::[a-zA-Z]+[a-zA-Z0-9_]*)+$/);
    my $ABSTRACT = {
        NAMESPACE => $abstract,
    };
    foreach my $key (keys(%parameters)) {
        next if(ref($key) !~ /^$/);
        next if($key !~ /^[a-zA-Z_]*[a-zA-Z0-9_]+$/);
        next if('NAMESPACE' eq $key);
        if(ref($parameters{$key}) =~ /^CODE$/i) {
            *{$abstract.'::'.$key} = $parameters{$key};
        } elsif(ref($parameters{$key}) !~ /^$/i) {
            $ABSTRACT->{$key} = $parameters{$key};
        } elsif($parameters{$key} =~ /^[a-zA-Z]+[a-zA-Z0-9_]*(::[a-zA-Z]+[a-zA-Z0-9_]*)+$/) {
            if(exists(&{$parameters{$key}})) {
                *{$abstract.'::'.$key} = *{$parameters{$key}};
            } else {
                $ABSTRACT->{$key} = $parameters{$key}
            }
        } else {
            $ABSTRACT->{$key} = $parameters{$key};
        }
    }
    return bless($ABSTRACT, $abstract);
}


=head2 hasAncestor

    my $MODULE_ARRAY = $OBJECT->hasAncestor();
    if(defined($MODULE_ARRAY));

    if(1 == $OBJECT->hasAncestor(
        'Some::Module',
        'Another::Module',
        'Etc'
    ));

=over 4

=item self I<(Blessed Hash, Required)>

An object of this namespace.

=item name I<(Array B<or> String, Optional)>

A namespace or an array of namespaces.

=back

Either returns an array of all the loaded modules that the object inherits from
or whether the object inherits from all of the specified loaded modules with a
B<1> I<(one)> for yes and B<0> I<(zero)> for no.

=cut


sub hasAncestor {
    return if(0 == scalar(@_));
    my $self = shift(@_);
    return if(ref($self) =~ /^(|ARRAY|CODE|FORMAT|GLOB|HASH|IO|LVALUE|REF|Regexp|SCALAR|VSTRING)$/i);
    my %modules;
    while(my ($name, $value) = each(%INC)) {
        next if($name !~ /\.pm$/);
        $name =~ s/\.pm//;
        $name =~ s/\//::/g if($name =~ /\//);
        next if(!$self->isa($name));
        next if($self eq $name);
        $modules{$name} = 1;
    }
    if(0 == scalar(@_)) {
        return [( keys(%modules) )] if(0 < scalar(keys(%modules)));
        return;
    }
    while(0 < scalar(@_)) {
        my $name = shift(@_);
        return 0 if(ref($name) !~ /^$/);
        return 0 if(!defined($modules{$name}));
    }
    return 1;
}


=head2 hasDescendant



( run in 1.693 second using v1.01-cache-2.11-cpan-39bf76dae61 )