File Coverage

blib/lib/Coat.pm
Criterion Covered Total %
statement 176 190 92.6
branch 41 56 73.2
condition 6 9 66.6
subroutine 36 37 97.3
pod 3 6 50.0
total 262 298 87.9


line stmt bran cond sub pod time code
1             package Coat;
2              
3 43     43   1118855 use strict;
  43         109  
  43         1994  
4 43     43   250 use warnings;
  43         85  
  43         1366  
5 43     43   246 use Carp 'confess';
  43         112  
  43         3585  
6 43     43   44992 use Symbol;
  43         83205  
  43         4565  
7 43     43   303 use B 'svref_2object';
  43         89  
  43         2896  
8              
9 43     43   362 use Exporter;
  43         89  
  43         1606  
10 43     43   862 use base 'Exporter';
  43         188  
  43         5618  
11 43     43   228 use vars qw(@EXPORT $VERSION $AUTHORITY);
  43         130  
  43         15205  
12              
13 43     43   24223 use Coat::Meta;
  43         773  
  43         1198  
14 43     43   32516 use Coat::Object;
  43         115  
  43         5724  
15 43     43   25909 use Coat::Types;
  43         127  
  43         67932  
16              
17             $VERSION = '0.502';
18             $AUTHORITY = 'cpan:SUKRIA';
19              
20             # our exported keywords for class description
21             @EXPORT = qw(has extends before after around);
22              
23             # Prototypes for private methods
24             sub _bind_coderef_to_symbol($$);
25             sub _extends_class($;$);
26             sub _value_is_valid($$);
27             sub _compile_around_modifier(@);
28             sub _build_sub_with_hook($$);
29              
30             ##############################################################################
31             # Public static methods
32             ##############################################################################
33              
34             # has() declares an attribute and builds the corresponding accessors
35             sub has {
36 102     102 0 1615 my ( $attr_name, %options ) = @_;
37 102 50       337 confess "Attribute is a reference, cannot declare" if ref($attr_name);
38              
39 102   33     507 my $class = $options{'!caller'} || getscope();
40 102         466 my $accessor = "${class}::${attr_name}";
41              
42             # handle here attr overloading (eg: has '+foo' overload SUPER::foo)
43 102 100       443 if ($attr_name =~ /^\+(\S+)$/) {
44 4         13 $attr_name = $1;
45            
46 4         16 my $inherited_attrs = Coat::Meta->all_attributes( $class );
47 4 50       13 (exists $inherited_attrs->{$attr_name}) ||
48             confess "Cannot overload unknown attribute ($attr_name)";
49            
50 4         7 %options = (%{$inherited_attrs->{$attr_name}}, %options );
  4         27  
51             }
52              
53 102         14120 my $attr_meta = Coat::Meta->attribute( $class, $attr_name, \%options);
54 100         485 my $accessor_code = _accessor_for_attr($attr_name);
55              
56             # now bind the subref to the appropriate symbol in the caller class
57 100         332 _bind_coderef_to_symbol( $accessor_code, $accessor );
58              
59 100         197 my $handles = $attr_meta->{'handles'};
60 100 100 66     415 if ($handles && ref $handles eq 'HASH') {
61              
62 1         2 foreach my $method ( keys %{$handles} ) {
  1         4  
63 2         4 my $handler = "${class}::${method}";
64 2         5 my $handle = $handles->{$method};
65             my $handles_code = sub {
66 2     2   6 my ( $self, @args ) = @_;
67              
68 2 50       5 if ( $self->$attr_name->can( $handle ) ) {
69 2         8 return $self->$attr_name->$handle( @args );
70             }
71             else {
72 0         0 confess( 'Cannot call ' . $handle . ' from ' . $attr_name );
73             }
74 2         14 };
75 2         5 _bind_coderef_to_symbol( $handles_code, $handler );
76             }
77             }
78              
79 100         193 my $predicate = $attr_meta->{'predicate'};
80 100 100       233 if ($predicate) {
81 1         10 my $full = "${class}::$predicate";
82 1     7   6 my $predicate_code = sub { exists $_[0]->{$attr_name} };
  7         79  
83 1         3 _bind_coderef_to_symbol( $predicate_code => $full );
84             }
85              
86 100         194 my $clearer = $attr_meta->{'clearer'};
87 100 100       524 if ($clearer) {
88 1         3 my $full = "${class}::$clearer";
89 1     3   6 my $clearer_code = sub { delete $_[0]->{$attr_name} };
  3         13  
90 1         3 _bind_coderef_to_symbol( $clearer_code => $full );
91             }
92             }
93              
94             # the public inheritance method, takes a list of class we should inherit from
95             sub extends {
96 26     26 0 2403 my (@mothers) = @_;
97 26 50       88 confess "Cannot extend without a class name"
98             unless @mothers;
99 26         99 _extends_class( \@mothers, getscope() );
100             }
101              
102             # the before hook catches the call to an inherited method and exectue
103             # the code given before the inherited method is called.
104             sub before {
105 4     4 1 47 my ( $method, $code ) = @_;
106 4         9 my $class = getscope();
107 4         19 Coat::Meta->before_modifiers( $class, $method, $code );
108 4         10 _build_sub_with_hook( $class, $method );
109             }
110              
111             # the after hook catches the call to an inherited method and executes
112             # the code after the inherited method is called
113             sub after {
114 7     7 1 58 my ( $method, $code ) = @_;
115 7         22 my $class = getscope();
116 7         52 Coat::Meta->after_modifiers( $class, $method, $code );
117 7         17 _build_sub_with_hook( $class, $method );
118             }
119              
120             # the around hook catches the call to an inherited method and lets you do
121             # whatever you want with it, you get the coderef of the parent method and the
122             # args, you play !
123             sub around {
124 5     5 1 33 my ( $method, $code ) = @_;
125 5         30 my $class = getscope();
126 5         19 Coat::Meta->around_modifiers( $class, $method, $code );
127 5         18 _build_sub_with_hook( $class, $method );
128             }
129              
130             # we override the import method to actually force the "strict" and "warnings"
131             # modes to children and also to force the Coat::Object inheritance.
132             sub import {
133 94     94   35081 my $caller = caller;
134 94 100       601 return if $caller eq 'main';
135 84         231 my $class_name = getscope();
136              
137             # import strict and warnings
138 84         1342 strict->import;
139 84         1120 warnings->import;
140              
141             # delcare the class
142 84         660 Coat::Meta->class( $class_name );
143              
144             # be sure Coat::Object is known as a valid class
145 84         323 Coat::Meta->class('Coat::Object');
146              
147             # the class *cannot* be named like a built-in type!
148 84 50       283 (grep /^$class_name$/, Coat::Types::list_all_builtin_type_constraints) &&
149             confess "Class cannot be named like a built-in type constraint ($class_name)";
150              
151             # register the class as a valid type
152 84         1540 Coat::Types::find_or_create_type_constraint( $class_name );
153              
154             # force inheritance from Coat::Object
155 84         336 _extends_class( ['Coat::Object'], $class_name );
156              
157 84         115008 Coat->export_to_level( 1, @_ );
158             }
159              
160             # clean the namespace when the module is unloaded (no Coat).
161             # This is mostly stolen from Moose.
162             sub unimport {
163 43     43   491 no strict 'refs';
  43         88  
  43         29273  
164 0     0   0 my $class = caller();
165              
166             # loop through the exports ...
167 0         0 foreach my $name ( @EXPORT ) {
168              
169             # if we find one ...
170 0 0       0 if ( defined &{ $class . '::' . $name } ) {
  0         0  
171 0         0 my $keyword = \&{ $class . '::' . $name };
  0         0  
172              
173             # make sure it is from Coat
174             my $pkg_name =
175 0         0 eval { svref_2object($keyword)->GV->STASH->NAME };
  0         0  
176 0 0       0 next if $@;
177 0 0       0 next if $pkg_name ne 'Coat';
178              
179             # and if it is from Coat then undef the slot
180 0         0 delete ${ $class . '::' }{$name};
  0         0  
181             }
182             }
183             }
184              
185             ##############################################################################
186             # Protected methods (only called from Coat::* friends)
187             ##############################################################################
188              
189             # The scope is used for saving attribute properties, we want to have
190             # one namespace per class that inherits from us
191             sub getscope {
192 228     228 0 380 my ($self) = @_;
193              
194 228 50       609 if ( defined $self ) {
195 0         0 return ref($self);
196             }
197             else {
198 228         939 return scalar caller 1;
199             }
200             }
201              
202             ##############################################################################
203             # Private methods
204             ##############################################################################
205              
206              
207             # TODO : Should find a way to build optimized non-mutable accessors here
208             # It's ugly to get and check the meta of the attribute whenver using the setter or the
209             # getter.
210             sub _accessor_for_attr {
211 100     100   188 my ($name) = @_;
212              
213             return sub {
214 276     276   25304 my ( $self, $value ) = @_;
215 276         1333 my $meta = Coat::Meta->has( ref($self), $name );
216              
217             # setter
218 276 100       753 if ( @_ > 1 ) {
219 185 50       551 confess "Cannot set a read-only attribute ($name)"
220             if ($meta->{'is'} eq 'ro');
221              
222 185         867 $value = Coat::Types->validate( $meta, $name, $value );
223 143         623 $self->{$name} = $value;
224              
225 143 100       544 $meta->{'trigger'}->($self, $value)
226             if defined $meta->{'trigger'};
227            
228 143         486 return $value;
229             }
230              
231             # getter
232             else {
233 91 100 100     458 $self->{$name} = Coat::Meta->attr_default( $self, $name)
234             if ($meta->{lazy} && !defined($self->{$name}));
235            
236 91         1050 return $self->{$name};
237             }
238 100         657 };
239             }
240              
241             # The idea here is to loop on each coderef given
242             # and build subs to ensure the orig coderef is correctly propagated.
243             # -> We rewrite the "around" hooks defined to pass their coderef neighboor as
244             # a first argument.
245             # (big thank to STEVAN's Class::MOP here, which was helpful with the idea of
246             # $compile_around_method)
247             sub _compile_around_modifier(@) {
248             {
249 9     9   13 my $orig = shift;
  14         30  
250 14 100       45 return $orig unless @_;
251              
252 5         6 my $hook = shift;
253 5     5   31 @_ = ( sub { $hook->( $orig, @_ ) }, @_ );
  5         422  
254 5         8 redo;
255             }
256             }
257              
258             # This one is the wrapper builder for method with hooks.
259             # It can mix up before, after and around hooks.
260             sub _build_sub_with_hook($$) {
261 16     16   23 my ( $class, $method ) = @_;
262              
263 16         55 my $parents = Coat::Meta->family( $class );
264 16         25 my $super = undef;
265              
266             # we have to find where in the inheritance tree $super is providing
267             # $method
268 16         32 foreach my $parent_class (@$parents) {
269             # looking for the first inherited method
270 32         33 my $coderef;
271             {
272 43     43   281 no strict 'refs';
  43         103  
  43         24196  
  32         50  
273 32         36 $coderef = *{ "${parent_class}::${method}" };
  32         170  
274             }
275 32 100       129 $super = $parent_class if defined &$coderef;
276             }
277              
278             # $method not found, something is wrong there
279 16 50       53 confess "Unable to find method \"$method\" in inherited classes"
280             unless defined $super;
281              
282 16         39 my $full_method = "${class}::${method}";
283 16         27 my $super_method = *{ qualify_to_ref( $method => $super ) };
  16         53  
284              
285 16         383 my ( $before, $after, $around ) = (
286             Coat::Meta->before_modifiers( $class, $method ),
287             Coat::Meta->after_modifiers ( $class, $method ),
288             Coat::Meta->around_modifiers( $class, $method ),
289             );
290              
291             my $modified_method_code = sub {
292 9     9   3102 my ( $self, @args ) = @_;
293 9         19 my @result;
294             my $result;
295              
296 9         33 $_->(@_) for @$before;
297              
298 9         52 my $around_modifier =
299             _compile_around_modifier( \&$super_method, @$around );
300              
301             ( defined wantarray )
302 9 100       54 ? (
    100          
303             wantarray
304             ? ( @result = $around_modifier->(@_) )
305             : ( $result = $around_modifier->(@_) )
306             )
307             : ( $around_modifier->(@_) );
308              
309 9         1016 $_->(@_) for @$after;
310              
311 9 100       89 return unless defined wantarray;
312 6 100       27 return wantarray ? @result : $result;
313 16         108 };
314              
315             # now bind the new method to the appropriate symbol
316 16         39 _bind_coderef_to_symbol( $modified_method_code, $full_method );
317             }
318              
319             # the private method for declaring inheritance, we can here overide the
320             # caller class with a random one, useful for our internal cooking, see import().
321             sub _extends_class($;$) {
322 110     110   741 my ( $mothers, $class ) = @_;
323 110 50       2041 $class = getscope() unless defined $class;
324              
325             # then we inherit from all the mothers given, if they are valid
326 110         309 foreach my $mother (@$mothers) {
327             # class is unknown, never been loaded, let's try to import it
328 113 100       523 unless ( Coat::Meta->exists($mother) ) {
329 4     2   252 eval "use $mother";
  2     2   744  
  2         53  
  2         32  
  2         748  
  1         29  
  1         13  
330 4 100       283 confess "Could not load class ($mother) because : $@" if $@;
331 3         8 $mother->import;
332             }
333 112         488 Coat::Meta->extends( $class, $mother );
334             }
335              
336             # Add all the mothers to our ancestors.
337             # The extends mechanism overwrite the @ISA list.
338 43     43   268 { no strict 'refs'; @{"${class}::ISA"} = @$mothers; }
  43         88  
  43         4655  
  109         181  
  109         155  
  109         2947  
339             }
340              
341             sub _bind_coderef_to_symbol($$) {
342 120     120   199 my ( $coderef, $symbol ) = @_;
343             {
344 43     43   325 no strict 'refs';
  43         101  
  43         1489  
  120         201  
345 43     43   275 no warnings 'redefine', 'prototype';
  43         91  
  43         3471  
346 120         2895 *$symbol = $coderef;
347             }
348             }
349              
350              
351              
352             1;
353             __END__