File Coverage

blib/lib/Anansi/Library.pm
Criterion Covered Total %
statement 4 125 3.2
branch 0 104 0.0
condition n/a
subroutine 2 10 20.0
pod 6 6 100.0
total 12 245 4.9


line stmt bran cond sub pod time code
1             package Anansi::Library;
2              
3              
4             =head1 NAME
5              
6             Anansi::Library - A base module definition for object functionality extension.
7              
8             =head1 SYNOPSIS
9              
10             # Note: As 'base' needs a module file, this package must be declared in 'LibraryExample.pm'.
11             package LibraryExample;
12              
13             use base qw(Anansi::Library);
14              
15             sub libraryExample {
16             my ($self, %parameters) = @_;
17             }
18              
19             1;
20              
21             # Note: This package should be declared in 'ClassExample.pm'.
22             package ClassExample;
23              
24             use base qw(Anansi::Class LibraryExample);
25              
26             sub classExample {
27             my ($self, %parameters) = @_;
28             $self->libraryExample();
29             $self->LibraryExample::libraryExample();
30             }
31              
32             1;
33              
34             =head1 DESCRIPTION
35              
36             This is a base module definition that manages the functionality extension of
37             module object instances.
38              
39             =cut
40              
41              
42             our $VERSION = '0.03';
43              
44             my $LIBRARY = {};
45              
46              
47             =head1 METHODS
48              
49             =cut
50              
51              
52             =head2 abstractClosure
53              
54             my $CLOSURE = Anansi::Library->abstractClosure(
55             'Some::Namespace',
56             'someKey' => 'some data',
57             'anotherKey' => 'Subroutine::Namespace',
58             'yetAnotherKey' => Namespace::someSubroutine,
59             );
60             $CLOSURE->anotherKey();
61             $CLOSURE->yetAnotherKey();
62              
63             sub Subroutine::Namespace {
64             my ($self, $closure, %parameters) = @_;
65             my $abc = ${$closure}{abc} || 'something';
66             ${$closure}{def} = 'anything';
67             }
68              
69             =over 4
70              
71             =item class I<(Blessed Hash B String, Required)>
72              
73             Either an object of this namespace or this module's namespace.
74              
75             =item abstract I<(String, Required)>
76              
77             The namespace to associate with the closure's encapsulating object.
78              
79             =item parameters I<(Hash, Optional)>
80              
81             Named parameters where either the key is the name of a variable stored within
82             the closure and the value is it's data or when the value is a subroutine the key
83             is the name of a generated method of the closure's encapsulating object that
84             runs the subroutine and passes it a reference to the closure.
85              
86             =back
87              
88             Creates both an anonymous hash to act as a closure variable and a blessed object
89             as the closure's encapsulating accessor. Supplied data is either stored within
90             the closure using the key as the name or in the case of a subroutine, accessed
91             by an auto-generated method of that name. Closure is achieved by passing a
92             reference to the anonymous hash to the supplied subroutines via the
93             auto-generated methods.
94              
95             =cut
96              
97              
98             sub abstractClosure {
99 0     0 1   my ($class, $abstract, %parameters) = @_;
100 0 0         return if(ref($abstract) !~ /^$/);
101 0 0         return if($abstract !~ /[a-zA-Z]+[a-zA-Z0-9_]*(::[a-zA-Z]+[a-zA-Z0-9_]*)+$/);
102 0           my $ABSTRACT = {
103             NAMESPACE => $abstract,
104             };
105 0           my $CLOSURE = {
106             };
107 0           foreach my $key (keys(%parameters)) {
108 0 0         next if(ref($key) !~ /^$/);
109 0 0         next if($key !~ /^[a-zA-Z_]*[a-zA-Z0-9_]+$/);
110 0 0         next if('NAMESPACE' eq $key);
111 0 0         if(ref($parameters{$key}) =~ /^CODE$/i) {
    0          
    0          
112 0           *{$abstract.'::'.$key} = sub {
113 0     0     my ($self, @PARAMETERS) = @_;
114 0           return &{$parameters{$key}}($self, $CLOSURE, (@PARAMETERS));
  0            
115 0           };
116             } elsif(ref($parameters{$key}) !~ /^$/i) {
117 0           ${$CLOSURE}{$key} = $parameters{$key};
  0            
118             } elsif($parameters{$key} =~ /^[a-zA-Z]+[a-zA-Z0-9_]*(::[a-zA-Z]+[a-zA-Z0-9_]*)+$/) {
119 0 0         if(exists(&{$parameters{$key}})) {
  0            
120 0           *{$abstract.'::'.$key} = sub {
121 0     0     my ($self, @PARAMETERS) = @_;
122 0           return &{\&{$parameters{$key}}}($self, $CLOSURE, (@PARAMETERS));
  0            
  0            
123 0           };
124             } else {
125 0           ${$CLOSURE}{$key} = $parameters{$key}
  0            
126             }
127             } else {
128 0           ${$CLOSURE}{$key} = $parameters{$key};
  0            
129             }
130             }
131 0           return bless($ABSTRACT, $abstract);
132             }
133              
134              
135             =head2 abstractObject
136              
137             my $OBJECT = Anansi::Library->abstractObject(
138             'Some::Namespace',
139             'someKey' => 'some data',
140             'anotherKey' => 'Subroutine::Namespace',
141             'yetAnotherKey' => Namespace::someSubroutine,
142             );
143             $OBJECT->anotherKey();
144             $OBJECT->yetAnotherKey();
145              
146             sub Subroutine::Namespace {
147             my ($self, %parameters) = @_;
148             my $abc = $self->{abc} || 'something';
149             $self->{def} = 'anything';
150             }
151              
152             =over 4
153              
154             =item class I<(Blessed Hash B String, Required)>
155              
156             Either an object of this namespace or this module's namespace.
157              
158             =item abstract I<(String, Required)>
159              
160             The namespace to associate with the object.
161              
162             =item parameters I<(Hash, Required)>
163              
164             Named parameters where either the key is the name of a variable stored within
165             the object and the value is it's data or when the value is a subroutine the key
166             is the name of a namespace method.
167              
168             =back
169              
170             Creates a blessed object. Supplied data is either stored within the object or
171             in the case of a subroutine as a namespace method of that name.
172              
173             =cut
174              
175              
176             sub abstractObject {
177 0     0 1   my ($class, $abstract, %parameters) = @_;
178 0 0         return if(ref($abstract) !~ /^$/);
179 0 0         return if($abstract !~ /[a-zA-Z]+[a-zA-Z0-9_]*(::[a-zA-Z]+[a-zA-Z0-9_]*)+$/);
180 0           my $ABSTRACT = {
181             NAMESPACE => $abstract,
182             };
183 0           foreach my $key (keys(%parameters)) {
184 0 0         next if(ref($key) !~ /^$/);
185 0 0         next if($key !~ /^[a-zA-Z_]*[a-zA-Z0-9_]+$/);
186 0 0         next if('NAMESPACE' eq $key);
187 0 0         if(ref($parameters{$key}) =~ /^CODE$/i) {
    0          
    0          
188 0           *{$abstract.'::'.$key} = $parameters{$key};
  0            
189             } elsif(ref($parameters{$key}) !~ /^$/i) {
190 0           $ABSTRACT->{$key} = $parameters{$key};
191             } elsif($parameters{$key} =~ /^[a-zA-Z]+[a-zA-Z0-9_]*(::[a-zA-Z]+[a-zA-Z0-9_]*)+$/) {
192 0 0         if(exists(&{$parameters{$key}})) {
  0            
193 0           *{$abstract.'::'.$key} = *{$parameters{$key}};
  0            
  0            
194             } else {
195 0           $ABSTRACT->{$key} = $parameters{$key}
196             }
197             } else {
198 0           $ABSTRACT->{$key} = $parameters{$key};
199             }
200             }
201 0           return bless($ABSTRACT, $abstract);
202             }
203              
204              
205             =head2 hasAncestor
206              
207             my $MODULE_ARRAY = $OBJECT->hasAncestor();
208             if(defined($MODULE_ARRAY));
209              
210             if(1 == $OBJECT->hasAncestor(
211             'Some::Module',
212             'Another::Module',
213             'Etc'
214             ));
215              
216             =over 4
217              
218             =item self I<(Blessed Hash, Required)>
219              
220             An object of this namespace.
221              
222             =item name I<(Array B String, Optional)>
223              
224             A namespace or an array of namespaces.
225              
226             =back
227              
228             Either returns an array of all the loaded modules that the object inherits from
229             or whether the object inherits from all of the specified loaded modules with a
230             B<1> I<(one)> for yes and B<0> I<(zero)> for no.
231              
232             =cut
233              
234              
235             sub hasAncestor {
236 0 0   0 1   return if(0 == scalar(@_));
237 0           my $self = shift(@_);
238 0 0         return if(ref($self) =~ /^(|ARRAY|CODE|FORMAT|GLOB|HASH|IO|LVALUE|REF|Regexp|SCALAR|VSTRING)$/i);
239 0           my %modules;
240 0           while(my ($name, $value) = each(%INC)) {
241 0 0         next if($name !~ /\.pm$/);
242 0           $name =~ s/\.pm//;
243 0 0         $name =~ s/\//::/g if($name =~ /\//);
244 0 0         next if(!$self->isa($name));
245 0 0         next if($self eq $name);
246 0           $modules{$name} = 1;
247             }
248 0 0         if(0 == scalar(@_)) {
249 0 0         return [( keys(%modules) )] if(0 < scalar(keys(%modules)));
250 0           return;
251             }
252 0           while(0 < scalar(@_)) {
253 0           my $name = shift(@_);
254 0 0         return 0 if(ref($name) !~ /^$/);
255 0 0         return 0 if(!defined($modules{$name}));
256             }
257 0           return 1;
258             }
259              
260              
261             =head2 hasDescendant
262              
263             my $MODULE_ARRAY = $OBJECT->hasDescendant();
264             if(defined($MODULE_ARRAY));
265              
266             if(1 == $OBJECT->hasDescendant('Some::Module', 'Another::Module', 'Etc'));
267              
268             =over 4
269              
270             =item self I<(Blessed Hash, Required)>
271              
272             An object of this namespace.
273              
274             =item name I<(Array B String, Optional)>
275              
276             A namespace or an array of namespaces.
277              
278             =back
279              
280             Either returns an array of all the loaded modules that the object is inherited
281             from or whether the object is inherited from all of the specified loaded
282             modules with a B<1> I<(one)> for yes and B<0> I<(zero)> for no.
283              
284             =cut
285              
286              
287             sub hasDescendant {
288 0 0   0 1   return if(0 == scalar(@_));
289 0           my $self = shift(@_);
290 0 0         return if(ref($self) =~ /^(|ARRAY|CODE|FORMAT|GLOB|HASH|IO|LVALUE|REF|Regexp|SCALAR|VSTRING)$/i);
291 0           my %modules;
292 0           while(my ($name, $value) = each(%INC)) {
293 0 0         next if($name !~ /\.pm$/);
294 0           $name =~ s/\.pm//;
295 0 0         $name =~ s/\//::/g if($name =~ /\//);
296 0 0         next if(!$name->isa($self));
297 0 0         next if($self eq $name);
298 0           $modules{$name} = 1;
299             }
300 0 0         if(0 == scalar(@_)) {
301 0 0         return [( keys(%modules) )] if(0 < scalar(keys(%modules)));
302 0           return;
303             }
304 0           while(0 < scalar(@_)) {
305 0           my $name = shift(@_);
306 0 0         return 0 if(ref($name) !~ /^$/);
307 0 0         return 0 if(!defined($modules{$name}));
308             }
309 0           return 1;
310             }
311              
312              
313             =head2 hasLoaded
314              
315             my $MODULE_ARRAY = $OBJECT->hasLoaded();
316             if(defined($MODULE_ARRAY));
317              
318             my $MODULE_ARRAY = Anansi::Library->hasLoaded();
319             if(defined($MODULE_ARRAY));
320              
321             if(1 == $OBJECT->hasLoaded(
322             'Some::Module',
323             'Another::Module',
324             'Etc'
325             ));
326              
327             if(1 == Anansi::Library->hasLoaded(
328             'Some::Module',
329             'Another::Module',
330             'Etc'
331             ));
332              
333             =over 4
334              
335             =item self I<(Blessed Hash, Required)>
336              
337             An object of this namespace.
338              
339             =item name I<(Array B String, Optional)>
340              
341             A namespace or an array of namespaces.
342              
343             =back
344              
345             Either returns an array of all the loaded modules or whether all of the
346             specified modules have been loaded with a B<1> I<(one)> for yes and B<0>
347             I<(zero)> for no.
348              
349             =cut
350              
351              
352             sub hasLoaded {
353 0 0   0 1   return if(0 == scalar(@_));
354 0           my $self = shift(@_);
355 0 0         return if(ref($self) =~ /^(|ARRAY|CODE|FORMAT|GLOB|HASH|IO|LVALUE|REF|Regexp|SCALAR|VSTRING)$/i);
356 0           my %modules;
357 0           while(my ($name, $value) = each(%INC)) {
358 0 0         next if($name !~ /\.pm$/);
359 0           $name =~ s/\.pm//;
360 0 0         $name =~ s/\//::/g if($name =~ /\//);
361 0           $modules{$name} = 1;
362             }
363 0 0         if(0 == scalar(@_)) {
364 0 0         return [( keys(%modules) )] if(0 < scalar(keys(%modules)));
365 0           return;
366             }
367 0           while(0 < scalar(@_)) {
368 0           my $name = shift(@_);
369 0 0         return 0 if(ref($name) !~ /^$/);
370 0 0         return 0 if(!defined($modules{$name}));
371             }
372 0           return 1;
373             }
374              
375              
376             =begin comment
377              
378             ################################################################################
379              
380             =head2 hasParameter
381              
382             my $RESULT = Anansi::Library->hasParameter(
383             EXPECTED => [
384             {
385             SOME_VALUE => {
386             REQUIREMENT => 'OPTIONAL',
387             VALUE => [2,4,6,8,10]
388             },
389             ANOTHER_VALUE => {
390             VALUE => 24
391             },
392             ETC => {
393             REQUIREMENT => 'OPTIONAL'
394             }
395             }
396             ],
397             SUPPLIED => {
398             SOME_VALUE => 3,
399             ANOTHER_VALUE => 15
400             }
401             );
402             if(-1 == $RESULT) {
403             } elsif(0 == $RESULT || 1 == $RESULT || 2 == $RESULT) {
404             }
405              
406             Determines whether the contents of SUPPLIED matches a pattern set out within
407             EXPECTED. EXPECTED is either a HASH or an ARRAY of HASHES with each HASH
408             containing a number of keys that mirror the keys contained within the SUPPLIED
409             HASH.
410              
411             #=cut
412              
413              
414             sub hasParameter {
415             my ($self, %parameters) = @_;
416             return -1 if(!defined($parameters{EXPECTED}));
417             return -1 if(!defined($parameters{SUPPLIED}));
418             return -1 if(ref($parameters{SUPPLIED}) !~ /^HASH$/i);
419             my @expected;
420             if(ref($parameters{EXPECTED}) =~ /^ARRAY$/i) {
421             @expected = (@{$parameters{EXPECTED}});
422             } elsif(ref($parameters{EXPECTED}) =~ /^HASH$/i) {
423             @expected = ($parameters{EXPECTED});
424             } else {
425             return -1;
426             }
427             my $valid = -1;
428             for(my $index = 0; $index < scalar(@expected); $index++) {
429             next if(ref($expected[$index]) !~ /^HASH$/i);
430             $match = 1;
431             while(my ($suppliedKey, $suppliedValue) = each(%{$parameters{SUPPLIED}})) {
432             if(!defined(%{$expected[$index]}->{$suppliedKey})) {
433             $match = 0;
434             last;
435             }
436             }
437             if($match) {
438             $valid = $index;
439             last;
440             }
441             $match = 1;
442             while(my ($expectedKey, $expectedValue) = each(%{$expected[$index]})) {
443             next if(ref($expectedKey) !~ /^$/);
444             next if(ref($expectedValue) !~ /^HASH$/i);
445             my $required = 1;
446             if(!defined($expectedValue->{REQUIREMENT})) {
447             } elsif(ref($expectedValue->{REQUIREMENT}) !~ /^$/) {
448             } elsif($expectedValue->{REQUIREMENT} =~ /^OPTIONAL$/i) {
449             $required = 0 if(!defined(%{$parameters{SUPPLIED}}->{$expectedKey}));
450             }
451             if($required) {
452             next if(!defined($expectedValue->{VALUE}));
453             my @expectedValues;
454             if(ref($expectedValue->{VALUE}) =~ /^ARRAY$/i) {
455             @expectedValues = [(@{$expectedValue->{VALUE}})];
456             } elsif(ref($expectedValue->{VALUE}) =~ /^HASH$/i) {
457             @expectedValues = [$expectedValue->{VALUE}];
458             }
459             my $valued;
460             if(0 < scalar(@expectedValues)) {
461             $valued = 0;
462             foreach my $value (@expectedValues) {
463             if(ref($value) =~ /^$/) {
464             if($value == %{$parameters{SUPPLIED}}->{$expectedKey}) {
465             $valued = 1;
466             last;
467             }
468             } elsif(ref($value) =~ /^HASH$/i) {
469             if(defined(%{%{$parameters{SUPPLIED}}->{$expectedKey}}->{REFERENCE})) {
470             last if(%{%{$parameters{SUPPLIED}}->{$expectedKey}}->{REFERENCE} ne ref(%{$parameters{SUPPLIED}}->{$expectedKey}));
471             }
472             if(defined(%{%{$parameters{SUPPLIED}}->{$expectedKey}}->{REFERENCE})) {
473             } else {
474             $valued = 1;
475             last;
476             }
477             }
478             }
479             } else {
480             $valued = 1;
481             }
482             if(0 == $valued) {
483             $match = 0;
484             last;
485             }
486             }
487             }
488             if($match) {
489             $valid = $index;
490             last;
491             }
492             }
493             return $valid;
494             }
495              
496             ################################################################################
497              
498             =end comment
499              
500             =cut
501              
502              
503             =head2 hasSubroutine
504              
505             my $SUBROUTINE_ARRAY = $OBJECT->hasSubroutine();
506             if(defined($SUBROUTINE_ARRAY));
507              
508             if(1 == $OBJECT->hasSubroutine(
509             'someSubroutine',
510             'anotherSubroutine',
511             'etc'
512             ));
513              
514             =over 4
515              
516             =item self I<(Blessed Hash, Required)>
517              
518             An object of this namespace.
519              
520             =item name I<(Array B String, Optional)>
521              
522             A namespace or an array of namespaces.
523              
524             =back
525              
526             Either returns an array of all the subroutines in the loaded module or whether
527             the loaded module has all of the specified subroutines with a B<1> I<(one)> for
528             yes and B<0> I<(zero)> for no.
529              
530             =cut
531              
532              
533             sub hasSubroutine {
534 0 0   0 1   return if(0 == scalar(@_));
535 0           my $self = shift(@_);
536 0 0         return if(ref($self) =~ /^(|ARRAY|CODE|FORMAT|GLOB|HASH|IO|LVALUE|REF|Regexp|SCALAR|VSTRING)$/i);
537 1     1   80687 no strict 'refs';
  1         3  
  1         242  
538 0           my %subroutines = map { $_ => 1 } grep { exists &{"$self\::$_"} } keys %{"$self\::"};
  0            
  0            
  0            
  0            
539 0 0         if(0 == scalar(@_)) {
540 0 0         return [( keys(%subroutines) )] if(0 < scalar(keys(%subroutines)));
541 0           return;
542             }
543 0           while(0 < scalar(@_)) {
544 0           my $name = shift(@_);
545 0 0         return 0 if(ref($name) !~ /^$/);
546 0 0         return 0 if(!defined($subroutines{$name}));
547             }
548 0           return 1;
549             }
550              
551              
552             =head1 NOTES
553              
554             This module is designed to make it simple, easy and quite fast to code your
555             design in perl. If for any reason you feel that it doesn't achieve these goals
556             then please let me know. I am here to help. All constructive criticisms are
557             also welcomed.
558              
559             =cut
560              
561              
562 1     1   148 INIT {
563             }
564              
565              
566             =head1 AUTHOR
567              
568             Kevin Treleaven treleaven I net>
569              
570             =cut
571              
572              
573             1;