File Coverage

blib/lib/Anansi/Component.pm
Criterion Covered Total %
statement 6 92 6.5
branch 0 58 0.0
condition n/a
subroutine 2 9 22.2
pod 4 4 100.0
total 12 163 7.3


line stmt bran cond sub pod time code
1             package Anansi::Component;
2              
3              
4             =head1 NAME
5              
6             Anansi::Component - A base module definition for related processes that are managed.
7              
8             =head1 SYNOPSIS
9              
10             package Anansi::ComponentManagerExample::ComponentExample;
11              
12             use base qw(Anansi::Component);
13              
14             sub validate {
15             return 1;
16             }
17              
18             sub doSomething {
19             my ($self, $channel, %parameters) = @_;
20             }
21              
22             Anansi::Component::addChannel(
23             'Anansi::ComponentManagerExample::ComponentExample',
24             'VALIDATE_AS_APPROPRIATE' => Anansi::ComponentManagerExample::ComponentExample->validate
25             );
26             Anansi::Component::addChannel(
27             'Anansi::ComponentManagerExample::ComponentExample',
28             'SOME_COMPONENT_CHANNEL' => Anansi::ComponentManagerExample::ComponentExample->doSomething
29             );
30              
31             1;
32              
33             package Anansi::ComponentManagerExample;
34              
35             use base qw(Anansi::ComponentManager);
36              
37             sub doSomethingElse {
38             my ($self, $channel, %parameters) = @_;
39             }
40              
41             Anansi::ComponentManager::addChannel(
42             'Anansi::ComponentManagerExample',
43             'SOME_MANAGER_CHANNEL' => Anansi::ComponentManagerExample->doSomethingElse
44             );
45              
46             1;
47              
48             package main;
49              
50             use Anansi::ComponentManagerExample;
51              
52             my $object = Anansi::ComponentManagerExample->new();
53             my $component = $object->addComponent();
54             my $result = $object->channel(
55             $component,
56             'SOME_COMPONENT_CHANNEL',
57             someParameter => 'some data',
58             );
59              
60             1;
61              
62             =head1 DESCRIPTION
63              
64             This is a base module definition for related functionality modules. This module
65             provides the mechanism to be handled by a L module.
66             In order to simplify the recognition and management of related I
67             modules, each component is required to have the same base namespace as it's
68             manager. Uses L.
69              
70             =cut
71              
72              
73             our $VERSION = '0.07';
74              
75 1     1   88400 use base qw(Anansi::Class);
  1         2  
  1         898  
76              
77 1     1   15074 use Anansi::Actor;
  1         65155  
  1         9  
78              
79              
80             my %CHANNELS;
81              
82              
83             =head1 METHODS
84              
85             =cut
86              
87              
88             =head2 Anansi::Class
89              
90             See L for details. A parent module of L.
91              
92             =cut
93              
94              
95             =head3 DESTROY
96              
97             See L for details.
98              
99             =cut
100              
101              
102             =head3 finalise
103              
104             See L for details. A virtual method.
105              
106             =cut
107              
108              
109             =head3 implicate
110              
111             See L for details. A virtual method.
112              
113             =cut
114              
115              
116             =head3 import
117              
118             See L for details.
119              
120             =cut
121              
122              
123             =head3 initialise
124              
125             See L for details. A virtual method.
126              
127             =cut
128              
129              
130             =head3 new
131              
132             See L for details.
133              
134             =cut
135              
136              
137             =head3 old
138              
139             See L for details.
140              
141             =cut
142              
143              
144             =head3 used
145              
146             See L for details.
147              
148             =cut
149              
150              
151             =head3 uses
152              
153             See L for details.
154              
155             =cut
156              
157              
158             =head3 using
159              
160             See L for details.
161              
162             =cut
163              
164              
165             =head2 addChannel
166              
167             if(1 == Anansi::Component->addChannel(
168             someChannel => 'Some::subroutine',
169             anotherChannel => Some::subroutine,
170             yetAnotherChannel => $AN_OBJECT->someSubroutine,
171             etcChannel => sub {
172             my $self = shift(@_);
173             }
174             ));
175              
176             if(1 == $OBJECT->addChannel(
177             someChannel => 'Some::subroutine',
178             anotherChannel => Some::subroutine,
179             yetAnotherChannel => $AN_OBJECT->someSubroutine,
180             etcChannel => sub {
181             my $self = shift(@_);
182             }
183             ));
184              
185             =over 4
186              
187             =item self I<(Blessed Hash B String, Required)>
188              
189             An object or string of this namespace.
190              
191             =item parameters I<(Hash, Optional)>
192              
193             Named parameters where the key is the name of the channel and the value is
194             either a namespace string or code reference to an existing subroutine or an
195             anonymous subroutine definition.
196              
197             =back
198              
199             Defines the responding subroutine for the named component channels.
200              
201             =cut
202              
203              
204             sub addChannel {
205 0     0 1   my ($self, %parameters) = @_;
206 0           my $package = $self;
207 0 0         $package = ref($self) if(ref($self) !~ /^$/);
208 0 0         return 0 if(0 == scalar(keys(%parameters)));
209 0           foreach my $key (keys(%parameters)) {
210 0 0         if(ref($key) !~ /^$/) {
    0          
    0          
    0          
211 0           return 0;
212             } elsif(ref($parameters{$key}) =~ /^CODE$/i) {
213             } elsif(ref($parameters{$key}) !~ /^$/) {
214 0           return 0;
215             } elsif($parameters{$key} =~ /^[a-zA-Z]+[a-zA-Z0-9_]*(::[a-zA-Z]+[a-zA-Z0-9_]*)*$/) {
216 0 0         if(exists(&{$parameters{$key}})) {
  0 0          
  0            
217             } elsif(exists(&{$package.'::'.$parameters{$key}})) {
218             } else {
219 0           return 0;
220             }
221             } else {
222 0           return 0;
223             }
224             }
225 0 0         $CHANNELS{$package} = {} if(!defined($CHANNELS{$package}));
226 0           foreach my $key (keys(%parameters)) {
227 0 0         if(ref($parameters{$key}) =~ /^CODE$/i) {
    0          
228 0           ${$CHANNELS{$package}}{$key} = sub {
229 0     0     my ($self, $channel, @PARAMETERS) = @_;
230 0           return &{$parameters{$key}}($self, $channel, (@PARAMETERS));
  0            
231 0           };
232             } elsif($parameters{$key} =~ /^[a-zA-Z]+[a-zA-Z0-9_]*(::[a-zA-Z]+[a-zA-Z0-9_]*)*$/) {
233 0 0         if(exists(&{$parameters{$key}})) {
  0            
234 0           ${$CHANNELS{$package}}{$key} = sub {
235 0     0     my ($self, $channel, @PARAMETERS) = @_;
236 0           return &{\&{$parameters{$key}}}($self, $channel, (@PARAMETERS));
  0            
  0            
237 0           };
238             } else {
239 0           ${$CHANNELS{$package}}{$key} = sub {
240 0     0     my ($self, $channel, @PARAMETERS) = @_;
241 0           return &{\&{$package.'::'.$parameters{$key}}}($self, $channel, (@PARAMETERS));
  0            
  0            
242 0           };
243             }
244             }
245             }
246 0           return 1;
247             }
248              
249              
250             =head2 channel
251              
252             Anansi::Component->channel('Anansi::Component::Example');
253              
254             $OBJECT->channel();
255              
256             Anansi::Component->channel(
257             'Anansi::Component::Example',
258             'someChannel',
259             someParameter => 'something'
260             );
261              
262             $OBJECT->channel(
263             'someChannel',
264             someParameter => 'something'
265             );
266              
267             Has a floating first parameter, dependant on how the subroutine is called.
268              
269             =over 4
270              
271             =item self I<(Blessed Hash B String, Required)>
272              
273             An object or string of this namespace.
274              
275             =item channel I<(String, Optional)>
276              
277             The name of the channel to pass control to.
278              
279             =item parameters I<(Scalar B Array B Hash, Optional)>
280              
281             The parameters to pass to the channel.
282              
283             =back
284              
285             Either returns an array of the available channels or passes the supplied
286             parameters to the named channel. Returns B on error.
287              
288             =cut
289              
290              
291             sub channel {
292 0     0 1   my $self = shift(@_);
293 0 0         $self = shift(@_) if('Anansi::Component' eq $self);
294 0           my $package = $self;
295 0 0         $package = ref($self) if(ref($self) !~ /^$/);
296 0 0         if(0 == scalar(@_)) {
297 0 0         return [] if(!defined($CHANNELS{$package}));
298 0           return [( keys(%{$CHANNELS{$package}}) )];
  0            
299             }
300 0           my ($channel, @parameters) = @_;
301 0 0         return if(ref($channel) !~ /^$/);
302 0 0         return if(!defined($CHANNELS{$package}));
303 0 0         return if(!defined(${$CHANNELS{$package}}{$channel}));
  0            
304 0           return &{${$CHANNELS{$package}}{$channel}}($self, $channel, (@parameters));
  0            
  0            
305             }
306              
307              
308             =head2 componentManagers
309              
310             my $managers = Anansi::Component->componentManagers();
311              
312             my $managers = Anansi::Component::componentManagers('Anansi::ComponentManagerExample::ComponentExample');
313              
314             my $managers = $OBJECT->componentManagers();
315              
316             =over 4
317              
318             =item self I<(Blessed Hash B String, Required)>
319              
320             An object or string of this namespace.
321              
322             =back
323              
324             Either returns an ARRAY of all of the available component managers or an ARRAY
325             containing the current component's manager.
326              
327             =cut
328              
329              
330             sub componentManagers {
331 0     0 1   my ($self, %parameters) = @_;
332 0           my $package = $self;
333 0 0         $package = ref($package) if(ref($package) !~ /^$/);
334 0 0         if('Anansi::Component' eq $package) {
335 0           my %modules = Anansi::Actor->modules();
336 0           my @managers;
337 0           foreach my $module (keys(%modules)) {
338 0 0         next if('Anansi::ComponentManager' eq $module);
339 0           require $modules{$module};
340 0 0         next if(!eval { $module->isa('Anansi::ComponentManager') });
  0            
341 0           push(@managers, $module);
342             }
343 0           return [(@managers)];
344             }
345 0           my @namespaces = split(/::/, $package);
346 0 0         return [] if(scalar(@namespaces) < 2);
347 0           pop(@namespaces);
348 0           my $namespace = join('::', @namespaces);
349 0           my $filename = join('/', @namespaces).'.pm';
350 0           require $filename;
351 0 0         return [] if(!eval { $namespace->isa('Anansi::ComponentManager') });
  0            
352 0           return [$namespace];
353             }
354              
355              
356             =head2 removeChannel
357              
358             if(1 == Anansi::Component::removeChannel(
359             'Anansi::ComponentManagerExample::ComponentExample',
360             'someChannel',
361             'anotherChannel',
362             'yetAnotherChannel',
363             'etcChannel'
364             ));
365              
366             if(1 == $OBJECT->removeChannel(
367             'someChannel',
368             'anotherChannel',
369             'yetAnotherChannel',
370             'etcChannel'
371             ));
372              
373             =over 4
374              
375             =item self I<(Blessed Hash B String, Required)>
376              
377             An object or string of this namespace.
378              
379             =item parameters I<(String B Array, Required)>
380              
381             A string or array of strings containing the name of a channel.
382              
383             =back
384              
385             Undefines the responding subroutine for the named component channels. Returns
386             B<1> I<(one)> on success or B<0> I<(zero)> on failure.
387              
388             =cut
389              
390              
391             sub removeChannel {
392 0     0 1   my ($self, @parameters) = @_;
393 0           my $package = $self;
394 0 0         $package = ref($self) if(ref($self) !~ /^$/);
395 0 0         return 0 if(0 == scalar(@parameters));
396 0 0         return 0 if(!defined($CHANNELS{$package}));
397 0           foreach my $key (@parameters) {
398 0 0         return 0 if(!defined(${$CHANNELS{$package}}{$key}));
  0            
399             }
400 0           foreach my $key (@parameters) {
401 0           delete ${$CHANNELS{$package}}{$key};
  0            
402             }
403 0           return 1;
404             }
405              
406              
407             =head1 NOTES
408              
409             This module is designed to make it simple, easy and quite fast to code your
410             design in perl. If for any reason you feel that it doesn't achieve these goals
411             then please let me know. I am here to help. All constructive criticisms are
412             also welcomed.
413              
414             =cut
415              
416              
417             =head1 AUTHOR
418              
419             Kevin Treleaven treleaven I net>
420              
421             =cut
422              
423              
424             1;