File Coverage

blib/lib/POE/Component/Pluggable.pm
Criterion Covered Total %
statement 91 152 59.8
branch 32 76 42.1
condition 9 30 30.0
subroutine 14 18 77.7
pod 8 8 100.0
total 154 284 54.2


line stmt bran cond sub pod time code
1             package POE::Component::Pluggable;
2             $POE::Component::Pluggable::VERSION = '1.28';
3             #ABSTRACT: A base class for creating plugin-enabled POE Components.
4              
5 1     1   23691 use strict;
  1         2  
  1         31  
6 1     1   5 use warnings;
  1         1  
  1         28  
7 1     1   5 use Carp;
  1         2  
  1         94  
8 1     1   617 use POE::Component::Pluggable::Pipeline;
  1         2  
  1         45  
9 1     1   591 use POE::Component::Pluggable::Constants qw(:ALL);
  1         3  
  1         1966  
10              
11             sub _pluggable_init {
12 1     1   270 my ($self, %opts) = @_;
13              
14 1         12 $self->{'_pluggable_' . lc $_} = delete $opts{$_} for keys %opts;
15 1 50       5 $self->{_pluggable_reg_prefix} = 'plugin_' if !$self->{_pluggable_reg_prefix};
16 1 50       3 $self->{_pluggable_prefix} = 'pluggable_' if !$self->{_pluggable_prefix};
17              
18 1 50       7 if (ref $self->{_pluggable_types} eq 'ARRAY') {
    0          
19 1         2 $self->{_pluggable_types} = { map { $_ => $_ } @{ $self->{_pluggable_types} } };
  1         4  
  1         3  
20             }
21             elsif (ref $self->{_pluggable_types} ne 'HASH') {
22 0         0 croak "Argument 'types' must be supplied";
23             }
24              
25 1         3 return 1;
26             }
27              
28             sub _pluggable_destroy {
29 1     1   441 my ($self) = @_;
30 1         1 $self->plugin_del( $_ ) for keys %{ $self->plugin_list() };
  1         6  
31 1         2 return;
32             }
33              
34             sub _pluggable_event {
35 0     0   0 return;
36             }
37              
38             sub _pluggable_process {
39 5     5   1500 my ($self, $type, $event, @args) = @_;
40              
41 5 50 33     17 if (!defined $type || !defined $event) {
42 0         0 carp 'Please supply an event type and name!';
43 0         0 return;
44             }
45              
46 5         6 $event = lc $event;
47 5         6 my $pipeline = $self->pipeline;
48 5         5 my $prefix = $self->{_pluggable_prefix};
49 5         32 $event =~ s/^\Q$prefix\E//;
50 5         10 my $sub = join '_', $self->{_pluggable_types}{$type}, $event;
51 5         5 my $return = PLUGIN_EAT_NONE;
52 5         5 my $self_ret = $return;
53              
54 5 50       37 if ($self->can($sub)) {
    50          
55 0         0 eval { $self_ret = $self->$sub( $self, @args ) };
  0         0  
56 0         0 $self->_handle_error($self, $sub, $self_ret);
57             }
58             elsif ( $self->can('_default') ) {
59 0         0 eval { $self_ret = $self->_default( $self, $sub, @args ) };
  0         0  
60 0         0 $self->_handle_error($self, '_default', $self_ret);
61             }
62              
63 5 50       9 return $return if $self_ret == PLUGIN_EAT_PLUGIN;
64 5 50       7 $return = PLUGIN_EAT_ALL if $self_ret == PLUGIN_EAT_CLIENT;
65 5 50       11 return PLUGIN_EAT_ALL if $self_ret == PLUGIN_EAT_ALL;
66              
67 5         5 for my $plugin (@{ $pipeline->{PIPELINE} }) {
  5         11  
68 4 50 33     30 if ($self eq $plugin
      33        
69             || !$pipeline->{HANDLES}{$plugin}{$type}{$event}
70             && !$pipeline->{HANDLES}{$plugin}{$type}{all}) {
71 0         0 next;
72             }
73              
74 4         4 my $ret = PLUGIN_EAT_NONE;
75              
76 4         12 my $alias = ($pipeline->get($plugin))[1];
77 4 100       20 if ($plugin->can($sub)) {
    50          
78 2         3 eval { $ret = $plugin->$sub($self,@args) };
  2         5  
79 2         461 $self->_handle_error($plugin, $sub, $ret, $alias);
80             }
81             elsif ( $plugin->can('_default') ) {
82 0         0 eval { $ret = $plugin->_default($self,$sub,@args) };
  0         0  
83 0         0 $self->_handle_error($plugin, '_default', $ret, $alias);
84             }
85              
86 4 100       7 $ret = PLUGIN_EAT_NONE unless defined $ret;
87 4 50       5 return $return if $ret == PLUGIN_EAT_PLUGIN;
88 4 50       8 $return = PLUGIN_EAT_ALL if $ret == PLUGIN_EAT_CLIENT;
89 4 50       9 return PLUGIN_EAT_ALL if $ret == PLUGIN_EAT_ALL;
90             }
91              
92 5         9 return $return;
93             }
94              
95             sub _handle_error {
96 2     2   5 my ($self, $object, $sub, $return, $source) = @_;
97 2 50       11 $source = defined $source ? "plugin '$source'" : 'self';
98              
99 2 50 33     13 if ($@) {
    100 33        
      0        
      66        
100 0         0 chomp $@;
101 0         0 my $error = "$sub call on $source failed: $@";
102 0 0       0 warn "$error\n" if $self->{_pluggable_debug};
103              
104 0 0       0 $self->_pluggable_event(
105             "$self->{_pluggable_prefix}plugin_error",
106             $error, ($object == $self ? ($object, $source) : ()),
107             );
108             }
109             elsif ( !defined $return ||
110             ($return != PLUGIN_EAT_NONE
111             && $return != PLUGIN_EAT_PLUGIN
112             && $return != PLUGIN_EAT_CLIENT
113             && $return != PLUGIN_EAT_ALL) ) {
114 1         8 my $error = "$sub call on $source did not return a valid EAT constant";
115 1 50       3 warn "$error\n" if $self->{_pluggable_debug};
116              
117 1 50       6 $self->_pluggable_event(
118             "$self->{_pluggable_prefix}plugin_error",
119             $error, ($object == $self ? ($object, $source) : ()),
120             );
121             }
122              
123 2         63 return;
124             }
125              
126             # accesses the plugin pipeline
127             sub pipeline {
128 9     9 1 10 my ($self) = @_;
129 9         8 eval { $self->{_PLUGINS}->isa('POE::Component::Pluggble::Pipeline') };
  9         56  
130 9 100       25 $self->{_PLUGINS} = POE::Component::Pluggable::Pipeline->new($self) if $@;
131 9         18 return $self->{_PLUGINS};
132             }
133              
134             # Adds a new plugin object
135             sub plugin_add {
136 1     1 1 737 my ($self, $name, $plugin) = @_;
137              
138 1 50 33     27 if (!defined $name || !defined $plugin) {
139 0         0 carp 'Please supply a name and the plugin object to be added!';
140 0         0 return;
141             }
142              
143 1         6 return $self->pipeline->push($name, $plugin);
144             }
145              
146             # Removes a plugin object
147             sub plugin_del {
148 1     1 1 2 my ($self, $name) = @_;
149              
150 1 50       2 if (!defined $name) {
151 0         0 carp 'Please supply a name/object for the plugin to be removed!';
152 0         0 return;
153             }
154              
155 1         3 my $return = scalar $self->pipeline->remove($name);
156 1         2 return $return;
157             }
158              
159             # Gets the plugin object
160             sub plugin_get {
161 0     0 1 0 my ($self, $name) = @_;
162              
163 0 0       0 if (!defined $name) {
164 0         0 carp 'Please supply a name/object for the plugin to be removed!';
165 0         0 return;
166             }
167              
168 0         0 return scalar $self->pipeline->get($name);
169             }
170              
171             # Lists loaded plugins
172             sub plugin_list {
173 1     1 1 2 my ($self) = @_;
174 1         2 my $pipeline = $self->pipeline;
175              
176 1         2 my %return = map {$pipeline->{PLUGS}{$_} => $_} @{ $pipeline->{PIPELINE} };
  1         4  
  1         2  
177 1         7 return \%return;
178             }
179              
180             # Lists loaded plugins in order!
181             sub plugin_order {
182 0     0 1 0 my ($self) = @_;
183 0         0 return $self->pipeline->{PIPELINE};
184             }
185              
186             sub plugin_register {
187 1     1 1 199 my ($self, $plugin, $type, @events) = @_;
188 1         2 my $pipeline = $self->pipeline;
189              
190 1 50       2 if (!grep { $_ eq $type } keys %{ $self->{_pluggable_types} }) {
  1         5  
  1         9  
191 0         0 carp "The event type '$type' is not supported!";
192 0         0 return;
193             }
194              
195 1 50       3 if (!defined $plugin) {
196 0         0 carp 'Please supply the plugin object to register events for!';
197 0         0 return;
198             }
199              
200 1 50       3 if (!@events) {
201 0         0 carp 'Please supply at least one event to register!';
202 0         0 return;
203             }
204              
205 1         3 for my $ev (@events) {
206 1 50 33     4 if (ref $ev and ref $ev eq 'ARRAY') {
207 0         0 $pipeline->{HANDLES}{$plugin}{$type}{lc $_} = 1 for @$ev;
208             }
209             else {
210 1         13 $pipeline->{HANDLES}{$plugin}{$type}{lc $ev} = 1;
211             }
212             }
213              
214 1         3 return 1;
215             }
216              
217             sub plugin_unregister {
218 0     0 1   my ($self, $plugin, $type, @events) = @_;
219 0           my $pipeline = $self->pipeline;
220              
221 0 0         if (!grep { $_ eq $type } keys %{ $self->{_pluggable_types} }) {
  0            
  0            
222 0           carp "The event type '$type' is not supported!";
223 0           return;
224             }
225              
226 0 0         if (!defined $plugin) {
227 0           carp 'Please supply the plugin object to register!';
228 0           return;
229             }
230              
231 0 0         if (!@events) {
232 0           carp 'Please supply at least one event to unregister!';
233 0           return;
234             }
235              
236 0           for my $ev (@events) {
237 0 0 0       if (ref $ev and ref $ev eq "ARRAY") {
238 0           for my $e (map { lc } @$ev) {
  0            
239 0 0         if (!delete $pipeline->{HANDLES}{$plugin}{$type}{$e}) {
240 0           carp "The event '$e' does not exist!";
241 0           next;
242             }
243             }
244             }
245             else {
246 0           $ev = lc $ev;
247 0 0         if (!delete $pipeline->{HANDLES}{$plugin}{$type}{$ev}) {
248 0           carp "The event '$ev' does not exist!";
249 0           next;
250             }
251             }
252             }
253              
254 0           return 1;
255             }
256              
257             qq[Plug me in];
258              
259             __END__