File Coverage

blib/lib/Object/Pluggable.pm
Criterion Covered Total %
statement 102 164 62.2
branch 39 82 47.5
condition 9 30 30.0
subroutine 16 20 80.0
pod 8 8 100.0
total 174 304 57.2


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