File Coverage

blib/lib/Anansi/ComponentManager.pm
Criterion Covered Total %
statement 6 539 1.1
branch 0 338 0.0
condition 0 3 0.0
subroutine 2 21 9.5
pod 11 16 68.7
total 19 917 2.0


line stmt bran cond sub pod time code
1             package Anansi::ComponentManager;
2              
3              
4             =head1 NAME
5              
6             Anansi::ComponentManager - A base module definition for related process management.
7              
8             =head1 SYNOPSIS
9              
10             package Anansi::ComponentManagerExample;
11              
12             use base qw(Anansi::ComponentManager);
13              
14             sub doSomethingElse {
15             my ($self, $channel, %parameters) = @_;
16             }
17              
18             Anansi::ComponentManager::addChannel(
19             'Anansi::ComponentManagerExample',
20             'SOME_MANAGER_CHANNEL' => Anansi::ComponentManagerExample->doSomethingElse
21             );
22              
23             1;
24              
25             package Anansi::ComponentManagerExample::ComponentExample;
26              
27             use base qw(Anansi::Component);
28              
29             sub priority {
30             my ($self, $channel, %parameters) = @_;
31             my $PRIORITY = {
32             'Anansi::ComponentManagerExample::AnotherComponentExample' => 'HIGHER',
33             'Anansi::ComponentManagerExample::YetAnotherComponentExample' => 'LOWER',
34             'Anansi::ComponentManagerExample::SomeOtherComponentExample' => 'SAME',
35             'Anansi::ComponentManagerExample::ADifferentComponentExample' => 1,
36             'Anansi::ComponentManagerExample::EtcComponentExample' => 0,
37             'Anansi::ComponentManagerExample::AndSoOnComponentExample' => -1,
38             };
39             return $PRIORITY;
40             }
41              
42             sub validate {
43             my ($self, $channel, %parameters) = @_;
44             return 1;
45             }
46              
47             sub doSomething {
48             my ($self, $channel, %parameters) = @_;
49             }
50              
51             Anansi::Component::addChannel(
52             'Anansi::ComponentManagerExample::ComponentExample',
53             'PRIORITY_OF_VALIDATE' => Anansi::ComponentManagerExample::ComponentExample->priority
54             );
55             Anansi::Component::addChannel(
56             'Anansi::ComponentManagerExample::ComponentExample',
57             'VALIDATE_AS_APPROPRIATE' => Anansi::ComponentManagerExample::ComponentExample->validate
58             );
59             Anansi::Component::addChannel(
60             'Anansi::ComponentManagerExample::ComponentExample',
61             'SOME_COMPONENT_CHANNEL' => Anansi::ComponentManagerExample::ComponentExample->doSomething
62             );
63              
64             1;
65              
66             package main;
67              
68             use Anansi::ComponentManagerExample;
69              
70             my $object = Anansi::ComponentManagerExample->new();
71             my $component = $object->addComponent();
72             my $result = $object->channel(
73             $component,
74             'SOME_COMPONENT_CHANNEL',
75             someParameter => 'some data',
76             anotherParameter => 'some more data',
77             );
78              
79             my $another = Anansi::ComponentManagerExample->new(
80             IDENTIFICATION => 'Another component',
81             );
82             $result = $object->channel(
83             'Another component',
84             'SOME_COMPONENT_CHANNEL',
85             aParameter => 'more data?',
86             );
87              
88             1;
89              
90             =head1 DESCRIPTION
91              
92             This is a base module definition for the management of modules that deal with
93             related functionality. This management module provides the mechanism to handle
94             multiple related functionality modules at the same time, loading and creating an
95             object of the most appropriate module to handle each situation by using the
96             VALIDATE_AS_APPROPRIATE and PRIORITY_OF_VALIDATE component channels. In order
97             to simplify the recognition of related L modules, each
98             component is required to have the same base namespace as it's manager.
99              
100             =cut
101              
102              
103             our $VERSION = '0.10';
104              
105 1     1   48990 use base qw(Anansi::Singleton);
  1         3  
  1         2137  
106              
107 1     1   47897 use Anansi::Actor;
  1         33298  
  1         10  
108              
109             my %CHANNELS;
110             my %COMPONENTS;
111             my %IDENTIFICATIONS;
112             my %PRIORITIES;
113              
114              
115             =head1 METHODS
116              
117             =cut
118              
119              
120             =head2 Anansi::Class
121              
122             See L for details. A parent module of L.
123              
124             =cut
125              
126              
127             =head3 DESTROY
128              
129             See L for details. Overridden by L.
130              
131             =cut
132              
133              
134             =head3 finalise
135              
136             See L for details. A virtual method.
137              
138             =cut
139              
140              
141             =head3 implicate
142              
143             See L for details. A virtual method.
144              
145             =cut
146              
147              
148             =head3 import
149              
150             See L for details.
151              
152             =cut
153              
154              
155             =head3 initialise
156              
157             See L for details. Overridden by L. A virtual method.
158              
159             =cut
160              
161              
162             =head3 new
163              
164             See L for details.
165              
166             =cut
167              
168              
169             =head3 old
170              
171             See L for details.
172              
173             =cut
174              
175              
176             =head3 used
177              
178             See L for details.
179              
180             =cut
181              
182              
183             =head3 uses
184              
185             See L for details.
186              
187             =cut
188              
189              
190             =head3 using
191              
192             See L for details.
193              
194             =cut
195              
196              
197             =head2 Anansi::Singleton
198              
199             See L for details. A parent module of L.
200              
201             =cut
202              
203              
204             =head3 Anansi::Class
205              
206             See L for details. A parent module of L.
207              
208             =cut
209              
210              
211             =head3 DESTROY
212              
213             See L for details. Overrides L.
214              
215             =cut
216              
217              
218             =head3 fixate
219              
220             See L for details. A virtual method.
221              
222             =cut
223              
224              
225             =head3 new
226              
227             See L for details. Overrides L.
228              
229             =cut
230              
231              
232             =head3 reinitialise
233              
234             See L for details. Overridden by L. A virtual method.
235              
236             =cut
237              
238              
239             =head2 addChannel
240              
241             if(1 == Anansi::ComponentManager->addChannel(
242             someChannel => 'Some::subroutine',
243             anotherChannel => Some::subroutine,
244             yetAnotherChannel => $AN_OBJECT->someSubroutine,
245             etcChannel => sub {
246             my $self = shift(@_);
247             }
248             ));
249              
250             if(1 == $OBJECT->addChannel(
251             someChannel => 'Some::subroutine',
252             anotherChannel => Some::subroutine,
253             yetAnotherChannel => $AN_OBJECT->someSubroutine,
254             etcChannel => sub {
255             my $self = shift(@_);
256             }
257             ));
258              
259             =over 4
260              
261             =item self I<(Blessed Hash B String, Required)>
262              
263             Either an object or a string of this namespace.
264              
265             =item parameters I<(Hash, Required)>
266              
267             Named parameters where the key is the name of the channel and the value is
268             either a namespace string or code reference to an existing subroutine or an
269             anonymous subroutine definition.
270              
271             =back
272              
273             Defines the responding subroutine for the named component manager channels.
274              
275             =cut
276              
277              
278             sub addChannel {
279 0     0 1   my ($self, %parameters) = @_;
280 0           my $package = $self;
281 0 0         $package = ref($self) if(ref($self) !~ /^$/);
282 0 0         return 0 if(0 == scalar(keys(%parameters)));
283 0           foreach my $key (keys(%parameters)) {
284 0 0         if(ref($key) !~ /^$/) {
    0          
    0          
    0          
285 0           return 0;
286             } elsif(ref($parameters{$key}) =~ /^CODE$/i) {
287             } elsif(ref($parameters{$key}) !~ /^$/) {
288 0           return 0;
289             } elsif($parameters{$key} =~ /^[a-zA-Z]+[a-zA-Z0-9_]*(::[a-zA-Z]+[a-zA-Z0-9_]*)*$/) {
290 0 0         if(exists(&{$parameters{$key}})) {
  0 0          
  0            
291             } elsif(exists(&{$package.'::'.$parameters{$key}})) {
292             } else {
293 0           return 0;
294             }
295             } else {
296 0           return 0;
297             }
298             }
299 0 0         $CHANNELS{$package} = {} if(!defined($CHANNELS{$package}));
300 0           foreach my $key (keys(%parameters)) {
301 0 0         if(ref($parameters{$key}) =~ /^CODE$/i) {
    0          
302 0           ${$CHANNELS{$package}}{$key} = sub {
303 0     0     my ($self, $channel, @PARAMETERS) = @_;
304 0           return &{$parameters{$key}}($self, $channel, (@PARAMETERS));
  0            
305 0           };
306             } elsif($parameters{$key} =~ /^[a-zA-Z]+[a-zA-Z0-9_]*(::[a-zA-Z]+[a-zA-Z0-9_]*)*$/) {
307 0 0         if(exists(&{$parameters{$key}})) {
  0            
308 0           ${$CHANNELS{$package}}{$key} = sub {
309 0     0     my ($self, $channel, @PARAMETERS) = @_;
310 0           return &{\&{$parameters{$key}}}($self, $channel, (@PARAMETERS));
  0            
  0            
311 0           };
312             } else {
313 0           ${$CHANNELS{$package}}{$key} = sub {
314 0     0     my ($self, $channel, @PARAMETERS) = @_;
315 0           return &{\&{$package.'::'.$parameters{$key}}}($self, $channel, (@PARAMETERS));
  0            
  0            
316 0           };
317             }
318             }
319             }
320 0           return 1;
321             }
322              
323              
324             =head2 addComponent
325              
326             my $identification = Anansi::ComponentManager->addComponent(
327             undef,
328             someParameter => 'some value'
329             );
330             if(defined($identification));
331              
332             my $identification = $OBJECT->addComponent(
333             undef,
334             someParameter => 'some value'
335             );
336             if(defined($identification));
337              
338             my $identification = Anansi::ComponentManager->addComponent(
339             'some identifier',
340             someParameter => 'some value'
341             );
342             if(defined($identification));
343              
344             my $identification = $OBJECT->addComponent(
345             'some identifier',
346             someParameter => 'some value'
347             );
348             if(defined($identification));
349              
350             =over 4
351              
352             =item self I<(Blessed Hash B String, Required)>
353              
354             An object or string of this namespace.
355              
356             =item identification I<(String, Required)>
357              
358             The name to associate with the component.
359              
360             =item parameters I<(Scalar B Array, Optional)>
361              
362             The list of parameters to pass to the I channel of
363             every component module found on the system.
364              
365             =back
366              
367             Creates a new component object and stores the object for indirect interaction by
368             the implementer of the component manager. A unique identifier for the object
369             may either be supplied or automatically generated and is returned as a means of
370             referencing the object.
371              
372             Note: The process of selecting the component to use requires each component to
373             validate it's own appropriateness. Therefore this process makes use of a
374             VALIDATE_AS_APPROPRIATE component channel which is expected to return either a
375             B<1> I<(one)> or a B<0> I<(zero)> representing B or
376             B. If this component channel does not exist it is assumed that
377             the component is not designed to be implemented in this way. A component may
378             also provide a PRIORITY_OF_VALIDATE component channel to aid in validating where
379             multiple components may be appropriate to different degrees. If this component
380             channel does not exist it is assumed that the component has the lowest priority.
381              
382             =cut
383              
384              
385             sub addComponent {
386 0     0 1   my ($self, $identification, @parameters) = @_;
387 0           my $package = $self;
388 0 0         $package = ref($self) if(ref($self) !~ /^$/);
389 0 0         if(!defined($identification)) {
    0          
    0          
    0          
390 0           $identification = $self->componentIdentification();
391             } elsif(ref($identification) !~ /^$/) {
392 0           return;
393             } elsif($identification =~ /^\s*$/) {
394 0           return;
395             } elsif(defined($COMPONENTS{$package})) {
396 0 0         return $identification if(defined(${$COMPONENTS{$package}}{$identification}));
  0            
397 0           my %reverse = map { ${$COMPONENTS{$package}}{$_} => $_ } (keys(%{$COMPONENTS{$package}}));
  0            
  0            
  0            
398 0 0         return $reverse{$identification} if(defined($reverse{$identification}));
399 0 0         return if(defined($IDENTIFICATIONS{$identification}));
400 0           %reverse = map { $IDENTIFICATIONS{$_} => $_ } (keys(%IDENTIFICATIONS));
  0            
401 0 0         return if(defined($reverse{$identification}));
402             }
403 0           my $alias = '';
404 0 0         if($identification !~ /^\d{20}$/) {
405 0           $alias = $identification;
406 0           $identification = $self->componentIdentification();
407             }
408 0           my $components = $self->components();
409 0 0         return if(ref($components) !~ /^ARRAY$/i);
410 0           my $priority = $self->priorities(
411             PARAMETERS => [(@parameters)],
412             );
413 0 0         return if(!defined($priority));
414 0           my $OBJECT;
415 0           while(0 <= $priority) {
416 0           my $components = $self->priorities(
417             PRIORITY => $priority,
418             );
419 0 0         next if(!defined($components));
420 0 0         next if(ref($components) !~ /^ARRAY$/i);
421 0           foreach my $component (@{$components}) {
  0            
422 0           my $valid = &{\&{'Anansi::Component::channel'}}($component, 'VALIDATE_AS_APPROPRIATE', (@parameters));
  0            
  0            
423 0 0         next if(!defined($valid));
424 0 0         if($valid) {
425 0           $OBJECT = Anansi::Actor->new(PACKAGE => $component, (@parameters));
426 0           last;
427             }
428             }
429 0 0         last if(defined($OBJECT));
430 0           $priority--;
431             }
432 0 0         return if(!defined($OBJECT));
433 0 0         $COMPONENTS{$package} = {} if(!defined($COMPONENTS{$package}));
434 0           ${$COMPONENTS{$package}}{$identification} = $OBJECT;
  0            
435 0           $self->uses(
436             'COMPONENT_'.$identification => $OBJECT,
437             );
438 0           $IDENTIFICATIONS{$identification} = $alias;
439 0           return $identification;
440             }
441              
442              
443             =head2 channel
444              
445             Anansi::ComponentManager->channel('Anansi::ComponentManager::Example');
446              
447             $OBJECT->channel();
448              
449             Anansi::ComponentManager->channel(
450             'Anansi::ComponentManager::Example',
451             'someChannel',
452             someParameter => 'something'
453             );
454              
455             $OBJECT->channel('someChannel', someParameter => 'something');
456              
457             =over 4
458              
459             =item self I<(Blessed Hash B String, Required)>
460              
461             An object or string of this namespace.
462              
463             =item channel I<(String, Optional)>
464              
465             The name that is associated with the component's channel.
466              
467             =item parameters I<(Scalar B Array, Optional)>
468              
469             The list of parameters to pass to the component's channel.
470              
471             =back
472              
473             Either returns an array of the available channels or passes the supplied
474             parameters to the named channel. Returns B on error.
475              
476             =cut
477              
478              
479             sub channel {
480 0     0 1   my $self = shift(@_);
481 0 0         $self = shift(@_) if('Anansi::ComponentManager' eq $self);
482 0           my $package = $self;
483 0 0         $package = ref($self) if(ref($self) !~ /^$/);
484 0 0         if(0 == scalar(@_)) {
485 0 0         return [] if(!defined($CHANNELS{$package}));
486 0           return [( keys(%{$CHANNELS{$package}}) )];
  0            
487             }
488 0           my ($channel, @parameters) = @_;
489 0 0         return if(ref($channel) !~ /^$/);
490 0 0         return if(!defined($CHANNELS{$package}));
491 0 0         return if(!defined(${$CHANNELS{$package}}{$channel}));
  0            
492 0           return &{${$CHANNELS{$package}}{$channel}}($self, $channel, (@parameters));
  0            
  0            
493             }
494              
495              
496             =head2 component
497              
498             my $returned;
499             my $channels = Anansi::ComponentManager->component($component);
500             if(defined($channels)) {
501             foreach my $channel (@{$channels}) {
502             next if('SOME_CHANNEL' ne $channel);
503             $returned = Anansi::ComponentManager->component(
504             $component,
505             $channel,
506             anotherParameter => 'another value'
507             );
508             }
509             }
510              
511             my @returned;
512             $OBJECT->addComponent(undef, someParameter => 'some value');
513             my $components = $OBJECT->component();
514             if(defined($components)) {
515             foreach my $component (@{$components}) {
516             my $channels = $OBJECT->component($component);
517             if(defined($channels)) {
518             foreach my $channel (@{$channels}) {
519             next if('SOME_CHANNEL' ne $channel);
520             push(@returned, $OBJECT->component(
521             $component,
522             $channel,
523             anotherParameter => 'another value'
524             ));
525             }
526             }
527             }
528             }
529              
530             =over 4
531              
532             =item self I<(Blessed Hash B String, Required)>
533              
534             An object or string of this namespace.
535              
536             =item identification I<(String, Optional)>
537              
538             The name associated with the component.
539              
540             =item channel I<(String, Optional)>
541              
542             The name that is associated with the component's channel.
543              
544             =item parameters I<(Scalar B Array, Optional)>
545              
546             The list of parameters to pass to the component's channel.
547              
548             =back
549              
550             Either returns an array of all of the available components or an array of all
551             of the channels available through an identified component or interacts with an
552             identified component using one of it's channels. Returns an B on
553             failure.
554              
555             =cut
556              
557              
558             sub component {
559 0     0 1   my $self = shift(@_);
560 0           my $package = $self;
561 0 0         $package = ref($self) if(ref($self) !~ /^$/);
562 0 0         return if(!defined($COMPONENTS{$package}));
563 0           my %reverse = map { $IDENTIFICATIONS{$_} => $_ } (keys(%IDENTIFICATIONS));
  0            
564 0 0         if(0 == scalar(@_)) {
565 0           my @identifications;
566 0           foreach my $identification (keys(%{$COMPONENTS{$package}})) {
  0            
567 0 0         if(defined($IDENTIFICATIONS{$identification})) {
    0          
568 0           push(@identifications, $identification);
569             } elsif(defined($reverse{$identification})) {
570 0           push(@identifications, $reverse{$identification});
571             }
572             }
573 0           return [( @identifications )];
574             }
575 0           my $identification = shift(@_);
576 0 0         return if(!defined($identification));
577 0           my $OBJECT;
578 0 0         if(defined(${$COMPONENTS{$package}}{$identification})) {
  0 0          
  0            
579 0           $OBJECT = ${$COMPONENTS{$package}}{$identification};
  0            
580             } elsif(defined(${$COMPONENTS{$package}}{$reverse{$identification}})) {
581 0           $OBJECT = ${$COMPONENTS{$package}}{$reverse{$identification}};
  0            
582             } else {
583 0           return;
584             }
585 0 0         return $OBJECT->channel() if(0 == scalar(@_));
586 0           my ($channel, @parameters) = @_;
587 0           return $OBJECT->channel($channel, (@parameters));
588             }
589              
590              
591             =head2 componentIdentification
592              
593             my $identification = Anansi::ComponentManager->componentIdentification();
594              
595             my $alias = 'An identifying phrase';
596             my $identification = $OBJECT->componentIdentification($alias);
597             if(defined($identification)) {
598             print 'The "'.$alias.'" component already exists with the "'.$identification.'" identification.'."\n";
599             }
600              
601             =over 4
602              
603             =item self I<(Blessed Hash, Required)>
604              
605             An object of this namespace.
606              
607             =item identification I<(String, Optional)>
608              
609             A component identification.
610              
611             =back
612              
613             Either generates a volatile B<20> I<(twenty)> digit identification string that
614             is unique within the executing script or determines whether a component exists
615             with the specified I. Returns the unique identification string
616             on success or an B on failure.
617              
618             =cut
619              
620              
621             sub componentIdentification {
622 0     0 1   my ($self, $identification) = @_;
623 0           my %reverse = map { $IDENTIFICATIONS{$_} => $_ } (keys(%IDENTIFICATIONS));
  0            
624 0 0         if(!defined($identification)) {
    0          
    0          
    0          
    0          
625 0           my ($second, $minute, $hour, $day, $month, $year) = localtime(time);
626 0           my $random;
627 0           do {
628 0           $random = int(rand(1000000));
629 0           $identification = sprintf("%4d%02d%02d%02d%02d%02d%06d", $year + 1900, $month, $day, $hour, $minute, $second, $random);
630             } while(defined($IDENTIFICATIONS{$identification}));
631             } elsif(ref($identification) !~ /^$/) {
632 0           return;
633             } elsif($identification =~ /^\s*$/) {
634 0           return;
635             } elsif(defined($IDENTIFICATIONS{$identification})) {
636             } elsif(defined($reverse{$identification})) {
637 0           return $reverse{$identification};
638             } else {
639 0           return;
640             }
641 0           return $identification;
642             }
643              
644              
645             =head2 components
646              
647             my $components = Anansi::ComponentManager->components();
648             if(ref($components) =~ /^ARRAY$/i) {
649             foreach my $component (@{$components}) {
650             }
651             }
652              
653             my $components = Anansi::ComponentManager::components('Some::Namespace');
654             if(ref($components) =~ /^ARRAY$/i) {
655             foreach my $component (@{$components}) {
656             }
657             }
658              
659             my $components = $OBJECT->components();
660             if(ref($components) =~ /^ARRAY$/i) {
661             foreach my $component (@{$components}) {
662             }
663             }
664              
665             =over 4
666              
667             =item self I<(Blessed Hash B String, Required)>
668              
669             An object or string of this namespace.
670              
671             =back
672              
673             Either returns an array of all of the available components or an array
674             containing the current component manager's components.
675              
676             =cut
677              
678              
679             sub components {
680 0     0 1   my $self = shift(@_);
681 0           my $package = $self;
682 0 0         $package = ref($package) if(ref($package) !~ /^$/);
683 0           my %modules = Anansi::Actor->modules();
684 0           my @components;
685 0 0         if('Anansi::ComponentManager' eq $package) {
686 0           foreach my $module (keys(%modules)) {
687 0 0         next if('Anansi::Component' eq $module);
688 0           require $modules{$module};
689 0 0         next if(!eval { $module->isa('Anansi::Component') });
  0            
690 0           push(@components, $module);
691             }
692 0           return [(@components)];
693             }
694 0           my @namespaces = split(/::/, $package);
695 0           my $namespace = join('::', @namespaces).'::';
696 0           foreach my $module (keys(%modules)) {
697 0 0         next if($module !~ /^${namespace}[^:]+$/);
698 0           require $modules{$module};
699 0 0         next if(!eval { $module->isa('Anansi::Component') });
  0            
700 0           push(@components, $module);
701             }
702 0           return [(@components)];
703             }
704              
705              
706             =head2 initialise
707              
708             Overrides L.
709              
710             =over 4
711              
712             =item self I<(Blessed Hash, Required)>
713              
714             An object of this namespace.
715              
716             =item parameters I<(Hash, Optional)>
717              
718             Named parameters supplied to the L method.
719              
720             =over 4
721              
722             =item IDENTIFICATION I<(String, Optional)>
723              
724             A unique component identification.
725              
726             =back
727              
728             =back
729              
730             Enables the conglomeration of L
731             and L
732             through a specified I parameter. Called just after module
733             instance object creation.
734              
735             =cut
736              
737              
738             sub initialise {
739 0     0 1   my ($self, %parameters) = @_;
740 0 0         if(defined($parameters{IDENTIFICATION})) {
741 0           my $identification = $parameters{IDENTIFICATION};
742 0 0         if(!defined($self->componentIdentification($identification))) {
743 0           delete $parameters{IDENTIFICATION};
744 0           $self->addComponent(
745             $identification,
746             %parameters
747             );
748             }
749             }
750             }
751              
752              
753             =head2 priorities
754              
755             my $priorities = $self->priorities();
756             if(defined($priorities)) {
757             for(my $priority = $priorities; -1 < $priority; $priority--) {
758             my $components = $self->priorities(
759             PRIORITY => $priority,
760             );
761             next if(!defined($components));
762             foreach my $component (@{$components}) {
763             }
764             }
765             }
766              
767             =over 4
768              
769             =item self I<(Blessed Hash B String, Required)>
770              
771             An object or string of this namespace.
772              
773             =item parameters I<(Hash, Optional)>
774              
775             Named parameters.
776              
777             =over 4
778              
779             =item PARAMETERS I<(Array B Scalar, Optional)>
780              
781             An array or single value containing the parameters to pass to the
782             PRIORITY_OF_VALIDATE component channel.
783              
784             =item PRIORITY I<(String, Optional)>
785              
786             Either a component namespace or a priority value of B<0> I<(zero)> or greater
787             where B<0> I<(zero)> represents the lowest priority.
788              
789             =back
790              
791             =back
792              
793             Either returns the highest component priority, the list of all the component
794             namespaces that have the component priority supplied as the I
795             parameter or the component priority of the component given it's namespace
796             supplied as the I parameter.
797              
798             =cut
799              
800              
801             sub priorities {
802 0     0 1   my ($self, %parameters) = @_;
803 0           my $package = $self;
804 0 0         $package = ref($package) if(ref($package) !~ /^$/);
805 0 0         return if('Anansi::ComponentManager' eq $package);
806              
807 0           my %components;
808              
809             sub priorities_component {
810 0     0 0   my (%parameters) = @_;
811 0 0         return if(!defined($parameters{COMPONENT}));
812 0 0         return if(ref($parameters{COMPONENT}) !~ /^$/);
813 0 0         return if($parameters{COMPONENT} =~ /^\s*$/);
814 0 0         if(!defined($components{$parameters{COMPONENT}})) {
815 0           $components{$parameters{COMPONENT}} = {
816             HIGHER => {},
817             LOWER => {},
818             SAME => {},
819             };
820             }
821 0           my $prioritise = &{\&{'Anansi::Component::channel'}}($parameters{COMPONENT}, 'PRIORITY_OF_VALIDATE', (@{$parameters{PARAMETERS}}));
  0            
  0            
  0            
822 0 0         return if(!defined($prioritise));
823 0 0         return if(ref($prioritise) !~ /^HASH$/i);
824 0           while(my ($componentName, $componentPriority) = each(%{$prioritise})) {
  0            
825 0 0         next if(!defined($componentName));
826 0 0         next if(!defined($componentPriority));
827 0 0         next if(ref($componentPriority) !~ /^$/);
828 0 0         if($componentPriority =~ /^\s*LOWER\s*/i) {
    0          
    0          
829 0           $componentPriority = -1;
830             } elsif($componentPriority =~ /^\s*HIGHER\s*/i) {
831 0           $componentPriority = 1;
832             } elsif($componentPriority =~ /^\s*SAME\s*/i) {
833 0           $componentPriority = 0;
834             }
835 0 0         next if($componentPriority !~ /^\s*(|\-|\+)\d+\s*$/);
836 0 0         if($componentPriority < 0) {
    0          
837 0           priorities_prioritise(
838             HIGHER => $parameters{COMPONENT},
839             LOWER => $componentName,
840             );
841             } elsif(0 < $componentPriority) {
842 0           priorities_prioritise(
843             HIGHER => $componentName,
844             LOWER => $parameters{COMPONENT},
845             );
846             } else {
847 0           priorities_prioritise(
848             SAME => [($parameters{COMPONENT}, $componentName)],
849             );
850             }
851             }
852             }
853              
854             sub priorities_higher {
855 0     0 0   my (%parameters) = @_;
856 0 0         return if(!defined($parameters{HIGHER}));
857 0 0         return if(ref($parameters{HIGHER}) !~ /^$/);
858 0 0         return if($parameters{HIGHER} =~ /^\s*$/);
859 0 0         return if(!defined($parameters{COMPONENT}));
860 0 0         return if(ref($parameters{COMPONENT}) !~ /^$/);
861 0 0         return if($parameters{COMPONENT} =~ /^\s*$/);
862 0 0         if(!defined($components{$parameters{COMPONENT}})) {
863 0           $components{$parameters{COMPONENT}} = {
864             HIGHER => {},
865             LOWER => {},
866             SAME => {},
867             };
868             }
869 0 0         if(!defined($components{$parameters{HIGHER}})) {
870 0           $components{$parameters{HIGHER}} = {
871             HIGHER => {},
872             LOWER => {},
873             SAME => {},
874             };
875             }
876 0           my $isHigher = 1;
877 0           foreach my $lower (keys(%{${$components{$parameters{COMPONENT}}}{LOWER}})) {
  0            
  0            
878 0 0         next if(defined(${${$components{$lower}}{HIGHER}}{$parameters{HIGHER}}));
  0            
  0            
879 0 0         if(defined(${${$components{$lower}}{SAME}}{$parameters{HIGHER}})) {
  0            
  0            
880 0           $isHigher = 0;
881 0           next;
882             }
883 0           ${${$components{$parameters{HIGHER}}}{LOWER}}{$lower} = 0;
  0            
  0            
884 0           ${${$components{$lower}}{HIGHER}}{$parameters{HIGHER}} = 0;
  0            
  0            
885 0           my $wasHigher = priorities_higher(
886             COMPONENT => $lower,
887             HIGHER => $parameters{HIGHER},
888             );
889 0 0         if(!defined($wasHigher)) {
    0          
890             } elsif(0 == $wasHigher) {
891 0           priorities_same(
892             COMPONENT => $parameters{HIGHER},
893             SAME => $lower,
894             );
895 0           $isHigher = 0;
896             }
897             }
898 0           return isHigher;
899             }
900              
901             sub priorities_lower {
902 0     0 0   my (%parameters) = @_;
903 0 0         return if(!defined($parameters{COMPONENT}));
904 0 0         return if(ref($parameters{COMPONENT}) !~ /^$/);
905 0 0         return if($parameters{COMPONENT} =~ /^\s*$/);
906 0 0         return if(!defined($parameters{LOWER}));
907 0 0         return if(ref($parameters{LOWER}) !~ /^$/);
908 0 0         return if($parameters{LOWER} =~ /^\s*$/);
909 0 0         if(!defined($components{$parameters{COMPONENT}})) {
910 0           $components{$parameters{COMPONENT}} = {
911             HIGHER => {},
912             LOWER => {},
913             SAME => {},
914             };
915             }
916 0 0         if(!defined($components{$parameters{LOWER}})) {
917 0           $components{$parameters{LOWER}} = {
918             HIGHER => {},
919             LOWER => {},
920             SAME => {},
921             };
922             }
923 0           my $isLower = 1;
924 0           foreach my $higher (keys(%{${$components{$parameters{COMPONENT}}}{HIGHER}})) {
  0            
  0            
925 0 0         next if(defined(${${$components{$higher}}{LOWER}}{$parameters{LOWER}}));
  0            
  0            
926 0 0         if(defined(${${$components{$higher}}{SAME}}{$parameters{LOWER}})) {
  0            
  0            
927 0           $isLower = 0;
928 0           next;
929             }
930 0           ${${$components{$higher}}{LOWER}}{$parameters{LOWER}} = 0;
  0            
  0            
931 0           ${${$components{$parameters{LOWER}}}{HIGHER}}{$higher} = 0;
  0            
  0            
932 0           my $wasLower = priorities_lower(
933             COMPONENT => $higher,
934             LOWER => $parameters{LOWER},
935             );
936 0 0         if(!defined($wasLower)) {
    0          
937             } elsif(0 == $wasLower) {
938 0           priorities_same(
939             COMPONENT => $parameters{LOWER},
940             SAME => $higher,
941             );
942 0           $isLower = 0;
943             }
944             }
945 0           return isLower;
946             }
947              
948             sub priorities_prioritise {
949 0     0 0   my (%parameters) = @_;
950 0 0         if(defined($parameters{SAME})) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
951 0 0         return if(ref($parameters{SAME}) !~ /^ARRAY$/i);
952 0           foreach my $component (@{$parameters{SAME}}) {
  0            
953 0 0         return if(ref($component) !~ /^$/);
954 0 0         return if($component =~ /^\s*$/);
955             }
956 0           for(my $index = 1; $index < scalar(@{$parameters{SAME}}); $index++) {
  0            
957 0 0         next if(${$parameters{SAME}}[0] eq ${$parameters{SAME}}[$index]);
  0            
  0            
958 0           priorities_same(
959 0           COMPONENT => ${$parameters{SAME}}[0],
960 0           SAME => ${$parameters{SAME}}[$index],
961             );
962             }
963             } elsif(!defined($parameters{HIGHER})) {
964 0           return;
965             } elsif(ref($parameters{HIGHER}) !~ /^$/) {
966 0           return;
967             } elsif($parameters{HIGHER} =~ /^\s*$/) {
968 0           return;
969             } elsif(!defined($parameters{LOWER})) {
970 0           return;
971             } elsif(ref($parameters{LOWER}) !~ /^$/) {
972 0           return;
973             } elsif($parameters{LOWER} =~ /^\s*$/) {
974 0           return;
975             } elsif($parameters{HIGHER} eq $parameters{LOWER}) {
976 0           return;
977             } else {
978 0 0         if(!defined($components{$parameters{HIGHER}})) {
979 0           $components{$parameters{HIGHER}} = {
980             HIGHER => {},
981             LOWER => {},
982             SAME => {},
983             };
984             }
985 0 0         if(!defined($components{$parameters{LOWER}})) {
986 0           $components{$parameters{LOWER}} = {
987             HIGHER => {},
988             LOWER => {},
989             SAME => {},
990             };
991             }
992 0 0         if(${${$components{$parameters{HIGHER}}}{LOWER}}{$parameters{LOWER}}) {
  0 0          
  0            
  0            
993 0           return;
994 0           } elsif(${${$components{$parameters{HIGHER}}}{HIGHER}}{$parameters{LOWER}}) {
995 0           priorities_same(
996             COMPONENT => $parameters{LOWER},
997             SAME => $parameters{HIGHER},
998             );
999             } else {
1000 0           ${${$components{$parameters{HIGHER}}}{LOWER}}{$parameters{LOWER}} = 0;
  0            
  0            
1001 0           ${${$components{$parameters{LOWER}}}{HIGHER}}{$parameters{HIGHER}} = 0;
  0            
  0            
1002 0           my $wasLower = priorities_lower(
1003             COMPONENT => $parameters{HIGHER},
1004             LOWER => $parameters{LOWER},
1005             );
1006 0           my $wasHigher = priorities_higher(
1007             COMPONENT => $parameters{LOWER},
1008             HIGHER => $parameters{HIGHER},
1009             );
1010             }
1011             }
1012             }
1013              
1014             sub priorities_same {
1015 0     0 0   my (%parameters) = @_;
1016 0 0         return if(!defined($parameters{COMPONENT}));
1017 0 0         return if(ref($parameters{COMPONENT}) !~ /^$/);
1018 0 0         return if($parameters{COMPONENT} =~ /^\s*$/);
1019 0 0         return if(!defined($parameters{SAME}));
1020 0 0         return if(ref($parameters{SAME}) !~ /^$/);
1021 0 0         return if($parameters{SAME} =~ /^\s*$/);
1022 0 0         return if($parameters{COMPONENT} eq $parameters{SAME});
1023 0 0         if(!defined($components{$parameters{COMPONENT}})) {
1024 0           $components{$parameters{COMPONENT}} = {
1025             HIGHER => {},
1026             LOWER => {},
1027             SAME => {},
1028             };
1029             }
1030 0 0         if(!defined($components{$parameters{SAME}})) {
1031 0           $components{$parameters{SAME}} = {
1032             HIGHER => {},
1033             LOWER => {},
1034             SAME => {},
1035             };
1036             }
1037 0 0         if(defined(${${$components{$parameters{COMPONENT}}}{LOWER}}{$parameters{SAME}})) {
  0            
  0            
1038 0           delete ${${$components{$parameters{COMPONENT}}}{LOWER}}{$parameters{SAME}};
  0            
  0            
1039 0           delete ${${$components{$parameters{SAME}}}{HIGHER}}{$parameters{COMPONENT}};
  0            
  0            
1040             }
1041 0 0         if(defined(${${$components{$parameters{COMPONENT}}}{HIGHER}}{$parameters{SAME}})) {
  0            
  0            
1042 0           delete ${${$components{$parameters{SAME}}}{LOWER}}{$parameters{COMPONENT}};
  0            
  0            
1043 0           delete ${${$components{$parameters{COMPONENT}}}{HIGHER}}{$parameters{SAME}};
  0            
  0            
1044             }
1045 0 0         if(!defined(${${$components{$parameters{COMPONENT}}}{SAME}}{$parameters{SAME}})) {
  0            
  0            
1046 0           ${${$components{$parameters{COMPONENT}}}{SAME}}{$parameters{SAME}} = 0;
  0            
  0            
1047 0           ${${$components{$parameters{SAME}}}{SAME}}{$parameters{COMPONENT}} = 0;
  0            
  0            
1048 0           foreach my $component (keys(%{${$components{$parameters{COMPONENT}}}{SAME}})) {
  0            
  0            
1049 0 0         next if($component eq $parameters{SAME});
1050 0 0         next if(defined(${${$components{$component}}{SAME}}{$parameters{SAME}}));
  0            
  0            
1051 0 0         if(defined(${${$components{$component}}{LOWER}}{$parameters{SAME}})) {
  0 0          
  0            
  0            
1052 0           delete ${${$components{$component}}{LOWER}}{$parameters{SAME}};
  0            
  0            
1053 0           delete ${${$components{$parameters{SAME}}}{HIGHER}}{$component};
  0            
  0            
1054 0           } elsif(defined(${${$components{$component}}{HIGHER}}{$parameters{SAME}})) {
1055 0           delete ${${$components{$parameters{SAME}}}{LOWER}}{$component};
  0            
  0            
1056 0           delete ${${$components{$component}}{HIGHER}}{$parameters{SAME}};
  0            
  0            
1057             }
1058 0           ${${$components{$component}}{SAME}}{$parameters{SAME}} = 0;
  0            
  0            
1059 0           ${${$components{$parameters{SAME}}}{SAME}}{$component} = 0;
  0            
  0            
1060 0           foreach my $lower (keys(%{${$components{$component}}{LOWER}})) {
  0            
  0            
1061 0 0         next if(defined(${$components{$parameters{SAME}}}{$lower}));
  0            
1062 0           priorities_lower(
1063             COMPONENT => $parameters{SAME},
1064             LOWER => $lower,
1065             );
1066             }
1067 0           foreach my $higher (keys(%{${$components{$component}}{HIGHER}})) {
  0            
  0            
1068 0 0         next if(defined(${$components{$parameters{SAME}}}{$higher}));
  0            
1069 0           priorities_higher(
1070             COMPONENT => $parameters{SAME},
1071             HIGHER => $higher,
1072             );
1073             }
1074             }
1075 0           foreach my $component (keys(%{${$components{$parameters{SAME}}}{SAME}})) {
  0            
  0            
1076 0 0         next if($component eq $parameters{COMPONENT});
1077 0 0         next if(defined(${${$components{$component}}{SAME}}{$parameters{COMPONENT}}));
  0            
  0            
1078 0 0         if(defined(${${$components{$component}}{LOWER}}{$parameters{COMPONENT}})) {
  0 0          
  0            
  0            
1079 0           delete ${${$components{$component}}{LOWER}}{$parameters{COMPONENT}};
  0            
  0            
1080 0           delete ${${$components{$parameters{COMPONENT}}}{HIGHER}}{$component};
  0            
  0            
1081 0           } elsif(defined(${${$components{$component}}{HIGHER}}{$parameters{COMPONENT}})) {
1082 0           delete ${${$components{$parameters{COMPONENT}}}{LOWER}}{$component};
  0            
  0            
1083 0           delete ${${$components{$component}}{HIGHER}}{$parameters{COMPONENT}};
  0            
  0            
1084             }
1085 0           ${${$components{$component}}{SAME}}{$parameters{COMPONENT}} = 0;
  0            
  0            
1086 0           ${${$components{$parameters{COMPONENT}}}{SAME}}{$component} = 0;
  0            
  0            
1087 0           foreach my $lower (keys(%{${$components{$component}}{LOWER}})) {
  0            
  0            
1088 0 0         next if(defined(${$components{$parameters{COMPONENT}}}{$lower}));
  0            
1089 0           priorities_lower(
1090             COMPONENT => $parameters{COMPONENT},
1091             LOWER => $lower,
1092             );
1093             }
1094 0           foreach my $higher (keys(%{${$components{$component}}{HIGHER}})) {
  0            
  0            
1095 0 0         next if(defined(${$components{$parameters{COMPONENT}}}{$higher}));
  0            
1096 0           priorities_higher(
1097             COMPONENT => $parameters{COMPONENT},
1098             HIGHER => $higher,
1099             );
1100             }
1101             }
1102             }
1103             }
1104              
1105 0           my $COMPONENTS = $self->components();
1106 0 0         return if(ref($COMPONENTS) !~ /^ARRAY$/i);
1107 0 0         $PRIORITIES{$package} = {} if(!defined($PRIORITIES{$package}));
1108 0 0         $PRIORITIES{$package} = {} if(ref($PRIORITIES{$package}) !~ /^HASH$/i);
1109 0 0         if(0 == scalar(keys(%{$PRIORITIES{$package}}))) {
  0            
1110 0           foreach my $component (@{$COMPONENTS}) {
  0            
1111 0           priorities_component(
1112             COMPONENT => $component,
1113 0           PARAMETERS => [(@{$parameters{PARAMETERS}})],
1114             );
1115             }
1116 0           my $priorities = 0;
1117 0           my $reduced = 1;
1118 0   0       while(scalar(keys(%{$PRIORITIES{$package}})) < scalar(keys(%components)) && $reduced) {
  0            
1119 0           $reduced = 0;
1120 0           foreach my $component (keys(%components)) {
1121 0 0         next if(defined(${$PRIORITIES{$package}}{$component}));
  0            
1122 0           my $hasLower = 0;
1123 0           foreach my $lower (keys(%{${$components{$component}}{LOWER}})) {
  0            
  0            
1124 0 0         if(!defined(${$PRIORITIES{$package}}{$lower})) {
  0 0          
  0            
1125 0           $hasLower = 1;
1126 0           last;
1127             } elsif($priorities == ${$PRIORITIES{$package}}{$lower}) {
1128 0           $hasLower = 1;
1129 0           last;
1130             }
1131             }
1132 0 0         if(0 == $hasLower) {
1133 0           ${$PRIORITIES{$package}}{$component} = $priorities;
  0            
1134 0           foreach my $same (keys(%{${$components{$component}}{SAME}})) {
  0            
  0            
1135 0           ${$PRIORITIES{$package}}{$same} = $priorities;
  0            
1136             }
1137 0           $reduced = 1;
1138             }
1139             }
1140 0           $priorities++;
1141             }
1142             }
1143 0 0         if(!defined($parameters{PRIORITY})) {
    0          
    0          
    0          
1144 0           my $priorities = 0;
1145 0           foreach my $priority (keys(%{$PRIORITIES{$package}})) {
  0            
1146 0 0         $priorities = ${$PRIORITIES{$package}}{$priority} if($priorities < ${$PRIORITIES{$package}}{$priority});
  0            
  0            
1147             }
1148 0           return $priorities;
1149             } elsif(ref($parameters{PRIORITY}) !~ /^$/) {
1150 0           } elsif($parameters{PRIORITY} =~ /^\s*\d+\s*$/) {
1151 0           my @priorities;
1152 0           foreach my $priority (keys(%{$PRIORITIES{$package}})) {
  0            
1153 0 0         push(@priorities, $priority) if($parameters{PRIORITY} == ${$PRIORITIES{$package}}{$priority});
  0            
1154             }
1155 0 0         return if(0 == scalar(@priorities));
1156 0           return [(@priorities)];
1157             } elsif(defined(${$PRIORITIES{$package}}{$parameters{PRIORITY}})) {
1158 0           return ${$PRIORITIES{$package}}{$parameters{PRIORITY}};
  0            
1159             }
1160 0           return;
1161             }
1162              
1163              
1164             =head2 reinitialise
1165              
1166             Overrides L.
1167              
1168             =over 4
1169              
1170             =item self I<(Blessed Hash, Required)>
1171              
1172             An object of this namespace.
1173              
1174             =item parameters I<(Hash, Optional)>
1175              
1176             Named parameters supplied to the L method.
1177              
1178             =over 4
1179              
1180             =item IDENTIFICATION I<(String, Optional)>
1181              
1182             A unique component identification.
1183              
1184             =back
1185              
1186             =back
1187              
1188             Enables the conglomeration of L
1189             and L
1190             through a specified I parameter. Called just after module
1191             instance object creation.
1192              
1193             =cut
1194              
1195              
1196             sub reinitialise {
1197 0     0 1   my ($self, %parameters) = @_;
1198 0 0         if(defined($parameters{IDENTIFICATION})) {
1199 0           my $identification = $parameters{IDENTIFICATION};
1200 0 0         if(!defined($self->componentIdentification($identification))) {
1201 0           delete $parameters{IDENTIFICATION};
1202 0           $self->addComponent(
1203             $identification,
1204             %parameters
1205             );
1206             }
1207             }
1208             }
1209              
1210              
1211             =head2 removeChannel
1212              
1213             if(1 == Anansi::ComponentManager::removeChannel(
1214             'Anansi::ComponentManagerExample',
1215             'someChannel',
1216             'anotherChannel',
1217             'yetAnotherChannel',
1218             'etcChannel'
1219             ));
1220              
1221             if(1 == $OBJECT->removeChannel(
1222             'someChannel',
1223             'anotherChannel',
1224             'yetAnotherChannel',
1225             'etcChannel'
1226             ));
1227              
1228             =over 4
1229              
1230             =item self I<(Blessed Hash B String, Required)>
1231              
1232             An object or string of this namespace.
1233              
1234             =item parameters I<(Scalar B Array, Required)>
1235              
1236             The channels to remove.
1237              
1238             =back
1239              
1240             Undefines the responding subroutine for the named component manager's channels.
1241              
1242             =cut
1243              
1244              
1245             sub removeChannel {
1246 0     0 1   my ($self, @parameters) = @_;
1247 0           my $package = $self;
1248 0 0         $package = ref($self) if(ref($self) !~ /^$/);
1249 0 0         return 0 if(0 == scalar(@parameters));
1250 0 0         return 0 if(!defined($CHANNELS{$package}));
1251 0           foreach my $key (@parameters) {
1252 0 0         return 0 if(!defined(${$CHANNELS{$package}}{$key}));
  0            
1253             }
1254 0           foreach my $key (@parameters) {
1255 0           delete ${$CHANNELS{$package}}{$key};
  0            
1256             }
1257 0           return 1;
1258             }
1259              
1260              
1261             =head2 removeComponent
1262              
1263             if(1 == Anansi::ComponentManager::removeComponent(
1264             'Anansi::ComponentManagerExample',
1265             'someComponent',
1266             'anotherComponent',
1267             'yetAnotherComponent',
1268             'etcComponent'
1269             ));
1270              
1271             if(1 == $OBJECT->removeComponent(
1272             'someComponent',
1273             'anotherComponent',
1274             'yetAnotherComponent',
1275             'etcComponent'
1276             ));
1277              
1278             =over 4
1279              
1280             =item self I<(Blessed Hash B String, Required)>
1281              
1282             An object or string of this namespace.
1283              
1284             =item parameters I<(Array, Required)>
1285              
1286             A string or array of strings containing the name of a component.
1287              
1288             =back
1289              
1290             Releases a named component instance for garbage collection. Returns a B<1>
1291             I<(one)> or a B<0> I<(zero)> representing B or B.
1292              
1293             =cut
1294              
1295              
1296             sub removeComponent {
1297 0     0 1   my ($self, @parameters) = @_;
1298 0           my $package = $self;
1299 0 0         $package = ref($self) if(ref($self) !~ /^$/);
1300 0 0         return 0 if(0 == scalar(@parameters));
1301 0 0         return 0 if(!defined($COMPONENTS{$package}));
1302 0           my %reverse = map { $IDENTIFICATIONS{$_} => $_ } (keys(%IDENTIFICATIONS));
  0            
1303 0           foreach my $key (@parameters) {
1304 0 0         if(defined(${$COMPONENTS{$package}}{$key})) {
  0 0          
  0            
1305             } elsif(!defined(${$COMPONENTS{$package}}{$reverse{$key}})) {
1306 0           return 0;
1307             }
1308             }
1309 0           foreach my $key (@parameters) {
1310 0 0         if(defined(${$COMPONENTS{$package}}{$key})) {
  0 0          
  0            
1311 0           delete ${$COMPONENTS{$package}}{$key};
  0            
1312 0           $self->used('COMPONENT_'.$key);
1313             } elsif(defined(${$COMPONENTS{$package}}{$reverse{$key}})) {
1314 0           delete ${$COMPONENTS{$package}}{$reverse{$key}};
  0            
1315 0           $self->used('COMPONENT_'.$key);
1316             }
1317             }
1318 0           return 1;
1319             }
1320              
1321              
1322             =head1 NOTES
1323              
1324             This module is designed to make it simple, easy and quite fast to code your
1325             design in perl. If for any reason you feel that it doesn't achieve these goals
1326             then please let me know. I am here to help. All constructive criticisms are
1327             also welcomed.
1328              
1329             =cut
1330              
1331              
1332             =head1 AUTHOR
1333              
1334             Kevin Treleaven treleaven I net>
1335              
1336             =cut
1337              
1338              
1339             1;