File Coverage

blib/lib/Class/Declare/Attributes.pm
Criterion Covered Total %
statement 401 490 81.8
branch 15 30 50.0
condition 18 296 6.0
subroutine 116 116 100.0
pod 1 1 100.0
total 551 933 59.0


line stmt bran cond sub pod time code
1             package Class::Declare::Attributes;
2              
3 14     14   191181 use 5.006;
  14         55  
4 14     14   63 use strict;
  14         36  
  14         360  
5 14     14   70 use warnings;
  14         34  
  14         581  
6 14     14   10049 use attributes;
  14         19911  
  14         98  
7              
8 14     14   14415 use Class::Declare qw( :modifiers );
  14         300552  
  14         2372  
9 14     14   3416 use File::Spec::Functions qw();
  14         4016  
  14         361  
10 14     14   74 use base qw( Class::Declare );
  14         24  
  14         1194  
11 14     14   80 use vars qw( $VERSION $REVISION );
  14         23  
  14         7589  
12              
13             $VERSION = '0.12';
14             $REVISION = '$Revision: 1515 $';
15              
16             # need to copy the export symbols from Class::Declare
17             # to permit Class::Declare::Attributes to provide attribute modifiers
18             *EXPORT_OK = *Class::Declare::EXPORT_OK;
19             *EXPORT_TAGS = *Class::Declare::EXPORT_TAGS;
20              
21              
22             # declare the 'attributes' helper routines
23             {
24             # moving "my" declarations out of BEGIN for Perl v5.8.4
25             # - this avoids "Bizarre copy of HASH in leavesub" error
26             # - this is a bug fixed in v5.8.5
27             # - see http://perlmonks.org/index.pl?node_id=361620 for more details
28             my %__ATTR__;
29             my %__PKGS__;
30             my %__DONE__;
31              
32 0         0 BEGIN {
33              
34             # define the attributes that are wrapped by this class
35 14     14   36 %__ATTR__ = map { $_ => 1 } qw( abstract
  98         204  
36             class
37             restricted
38             static
39             public
40             protected
41             private );
42              
43             # suppress the warnings surrounding the use of attributes that may be
44             # reserved for future use
45             # - this is naughty ... oh, well ... can be changed if necessary
46             # - we want to suppress this warning without disabling all warnings
47             # - we previously set $^W to 0, but this is very heavy handed, so
48             # let's try the following
49             $SIG{__WARN__} = sub {
50             # if we detect a violation caused by C::D::A, then suppress it,
51             # otherwise let it through
52 121         74840 my $pkg = __PACKAGE__;
53             ( $_[0] =~ /attribute may clash .+? reserved word: (\w+)/o ||
54             $_[0] =~ /^Declaration of (\w+) .+? package $pkg .+? reserved word/o )
55             # ensure the attribute belongs to C::D::A
56 121 50 33     2428 and ( $__ATTR__{ $1 } )
      33        
57             and return 1; # do nothing
58              
59             # otherwise, return the standard warn() response
60 0         0 warn $_[0];
61 14         112 }; # $SIG{__WARN__}()
62              
63              
64             # keep a log of calls made to set the attributes
65 14         40 %__PKGS__ = ();
66 14         2667 %__DONE__ = ();
67              
68              
69             # MODIFY_CODE_ATTRIBUTES()
70             #
71             # Keep a reference of the and type of attribute for each method specified as
72             #
73             # sub method : type { ... }
74             #
75             sub MODIFY_CODE_ATTRIBUTES
76             {
77 127     127   8020 my ( $pkg , $ref , @attr ) = @_;
78              
79             # only consider the attributes that we know about
80 127         206 my @unknown; undef @unknown;
  127         240  
81 127         332 foreach my $attr ( @attr ) {
82             # if this not an attribute we care about, then add it to the list of
83             # attributes to return
84             push @unknown , $attr
85 127 50 0     446 and next unless ( exists $__ATTR__{ $attr } );
86              
87             # have we already assigned one of our attributes to this target?
88             # - if we have, then we should raise an error
89 127 50       926 if ( defined ( my $previous = $__PKGS__{ $pkg }->{ $ref } ) ) {
90             # if this reference has already been assigned one of our attributes,
91             # then we have a problem if we are attempting to now assign a different
92             # attribute
93             # - something declared with the same attribute twice is not a problem
94             # as we just ignore the subsequent assignment
95 0 0       0 next if ( $previous eq $attr );
96              
97             # two conflicting attribute assignments
98 0         0 die "conflicting CODE attribute assignments of '$previous' "
99             . "and '$attr' in $pkg";
100             }
101              
102             # store this attribute assignment
103 127         411 $__PKGS__{ $pkg }->{ $ref } = $attr;
104            
105             # assign the CORE 'method' attribute to this reference as well
106             # - each code reference assigned a Class::Declare::Attributes interface
107             # is also actually a method
108 127         491 attributes::->import( CORE => $ref => 'method' );
109             }
110              
111             # if we have any unknown attributes, then return them
112 127 50       3297 return @unknown if ( @unknown );
113              
114             # otherwise, there's nothing more to do
115 127         492 return;
116             } # MODIFY_CODE_ATTRIBUTES()
117              
118              
119             # FETCH_CODE_ATTRIBUTES()
120             #
121             # Return the type of attribute for the given package and reference
122             sub FETCH_CODE_ATTRIBUTES
123             {
124 2699     2699   41807 my ( $pkg , $ref ) = @_;
125              
126             # if this is known package and reference, then return its attributes
127 2699         8886 return $__PKGS__{ $pkg }->{ $ref };
128             } # FETCH_CODE_ATTRIBUTES()
129              
130              
131              
132             # __init__()
133             #
134             # Initialise the code wrapping for Class::Declare-style methods
135             # - this needs to be called either at INIT time or when declare() is called
136             # to ensure dynamically loaded modules are handled correctly and the
137             # strict() setting is obeyed
138             sub __init__
139             {
140 102     102   243897 my $self = __PACKAGE__->static( shift );
141 102 50       2774 my @pkg = ( defined $_[0] ) ? ( $_[0] ) : keys %__PKGS__;
142              
143             # iterate through the given package(s)
144 102         269 foreach my $pkg ( @pkg ) {
145 14     14   87 no strict 'refs';
  14         24  
  14         1197  
146              
147             # do we have strict checking for this package on?
148 393         2267 my $strict = $pkg->strict;
149              
150             # if we have strict checking off and we've seen this package before
151             # then we should ensure we 'unnwrap' all wrapped routines
152 393 50       8861 unless ( $strict ) {
153 0 0       0 if ( my $wrapped = delete $__DONE__{ $pkg } ) {
154 0         0 while ( my ( $glob , $ref ) = each %{ $wrapped } ) {
  0         0  
155 14     14   222 no warnings 'redefine';
  14         28  
  14         1723  
156              
157 0         0 *{ $glob } = $ref;
  0         0  
158             }
159             }
160              
161             # no point proceeding, since we don't have strict checking on
162 0         0 return;
163             }
164              
165             # iterate through the symbol tree of this package
166 393         844 my $pkg_ = $pkg . '::';
167 393         533 my @names = keys %{ $pkg_ };
  393         3759  
168 393         1275 foreach my $name ( @names ) {
169 14     14   77 no warnings 'once';
  14         22  
  14         2151  
170              
171             # if we don't have a normal symbol table entry, then skip
172             # - occasionally we will find a reference here not a GLOB
173 8266         9453 my $sym = ${ $pkg_ }{ $name };
  8266         29139  
174 8266 50       18366 ( ref $sym ) and next;
175              
176             # if we don't have a CODE reference then we can't proceed
177 8266 100       8601 my $ref = *{ $sym }{ CODE } or next;
  8266         32710  
178 3203         12641 my @attr = grep { defined } attributes::get( $ref );
  3204         12930  
179              
180             # filter attributes that don't belong to the list fo C::D attributes
181 3203         7816 @attr = grep { defined } grep { $__ATTR__{ $_ } } @attr;
  127         328  
  632         1462  
182              
183             # if there are no attributes, then there's nothing to do
184 3203 100       13342 ( @attr ) or next;
185              
186             # extract the name of this subroutine
187 127         348 my $glob = $pkg_ . $name;
188              
189             # if we have strict access checking, then "wrap" this routine
190 127 50       346 if ( $strict ) {
191 14     14   93 no warnings 'redefine';
  14         22  
  14         2306  
192              
193 127         232 my $type = $attr[0];
194 127     2817   555 *{ $glob } = sub { $pkg->$type( $_[0] , $glob ); goto $ref };
  127         490  
  2817         380471  
  2385         87502  
195              
196             # make note that this method has been wrapped
197             # - store the original CODE reference for this glob
198 127         858 $__DONE__{ $pkg }->{ $glob } = $ref;
199             }
200             }
201             }
202             } # __init__()
203              
204             } # BEGIN()
205              
206             } # closure
207              
208              
209             # require()
210             #
211             # Load the given class using Perl's require(), ensuring __init__() is called
212             # after the class has been successfully loaded. This is to ensure the correct
213             # subroutine wrappers are put in place.
214             #
215             # If the given class contains ';' then we assume that it's the string of the
216             # class rather than the filename, so we simply eval() that, rather than trying
217             # to load it from the filesystem.
218             sub require : class
219             {
220 52     96 1 91 my $self = shift;
221             # if there's no class then there's nothing to do
222 52 50       188 my $class = shift or return undef;
223              
224             # do we have a file or the text of the class?
225 52 50       279 if ( $class =~ m/;/o ) {
226             # we assume we have the body of a class, so we just eval() it
227 52   33 120   7021 eval $class;
  104   33 120   55237  
  104   33 104   3416  
  104   33 8   686  
  120   0 8   72741  
  120   0 8   4222  
  120   0 8   2821  
  120   0 8   68680  
  120   0 8   4725  
  120   0 8   692  
  104   0 8   66484  
  104   0 8   3821  
  104   0 8   4338  
  8   0 8   51  
  8   0 8   13  
  8   0 8   59  
  192   0 1   362  
  192   0 1   1024  
  8   0 1   2510  
  8   0 1   15  
  8   0 1   40  
  104   0 1   220  
  104   0 1   981  
  8   0 57   986  
  8   33 49   25  
  8   33 57   45  
  104   33 49   221  
  104   33 1   366  
  8   0 1   949  
  8   0 1   15  
  8   0 1   48  
  1216   0 1   2078  
  1216   0 1   3665  
  8   0 1   55  
  8   0 1   14  
  8   0 1   316  
  8   0 1   42  
  8   0 1   14  
  8   0 1   1243  
  8   0 1   43  
  8   0 1   11  
  8   0 1   34  
  0   0 1   0  
  0   0 1   0  
  8   0 1   2374  
  8   0 1   20  
  8   0 1   31  
  0   0 57   0  
  0   33 41   0  
  8   33 57   953  
  8   33 57   16  
  8   33 1   35  
  0   0 1   0  
  0   0 1   0  
  8   0 1   988  
  8   0 1   17  
  8   0 1   33  
  608   0 1   917  
  608   0 1   1667  
  8   0 1   57  
  8   0 1   16  
  8   0 1   286  
  8   0 1   37  
  8   0 1   11  
  8   0 1   5155  
  1   0 1   17  
  1   0 1   3  
  1   0 1   99  
  1   0 1   9  
  1   0 1   3  
  1   0 1   411  
  1   0 113   9  
  1   33 97   3  
  57   33 97   19480  
  57   33 113   2020  
  57   33 1   199  
  57   0 1   901  
  25   0 1   981  
  49   0 1   22163  
  49   0 1   1909  
  48   0 1   178  
  48   0 1   226  
  21   0 1   1733  
  57   0 1   26353  
  57   0 1   2288  
  56   0 1   258  
  56   0 1   259  
  25   0 1   1719  
  49   0 1   20935  
  49   0 1   1797  
  48   0 1   152  
  48   0 1   226  
  21   0 1   1365  
  1   0 1   3  
  1   0 1   7  
  0   0 1   0  
  0         0  
  1         6  
  1         2  
  1         27  
  1         35  
  1         2  
  1         176  
  1         8  
  1         1  
  1         5  
  0         0  
  0         0  
  1         239  
  1         2  
  1         6  
  0         0  
  0         0  
  1         88  
  1         1  
  1         4  
  0         0  
  0         0  
  1         112  
  1         1  
  1         8  
  0         0  
  0         0  
  1         5  
  1         2  
  1         28  
  1         3  
  1         1  
  1         584  
  1         11  
  1         2  
  1         47  
  1         8  
  1         2  
  1         396  
  1         10  
  1         2  
  1         53  
  1         4  
  1         1  
  1         551  
  1         11  
  1         2  
  1         8  
  0         0  
  0         0  
  1         464  
  1         2  
  1         8  
  0         0  
  0         0  
  1         170  
  1         2  
  1         8  
  0         0  
  0         0  
  1         150  
  1         3  
  1         6  
  0         0  
  0         0  
  1         12  
  1         3  
  1         57  
  1         7  
  1         2  
  1         244  
  1         10  
  1         2  
  1         13  
  0         0  
  0         0  
  1         443  
  1         4  
  1         10  
  0         0  
  0         0  
  1         182  
  1         3  
  1         7  
  0         0  
  0         0  
  1         194  
  1         4  
  1         7  
  0         0  
  0         0  
  1         13  
  1         3  
  1         52  
  1         7  
  1         2  
  1         971  
  57         8642  
  57         2123  
  57         299  
  57         253  
  13         654  
  41         7153  
  41         1447  
  41         112  
  41         226  
  9         426  
  57         8653  
  57         2901  
  57         167  
  57         263  
  13         734  
  56         9111  
  56         2106  
  57         497  
  57         337  
  13         776  
  0         0  
  0         0  
  1         164  
  1         3  
  1         6  
  0         0  
  0         0  
  1         226  
  1         2  
  1         8  
  0         0  
  0         0  
  1         6  
  1         2  
  1         70  
  1         6  
  1         2  
  1         185  
  1         5  
  1         1  
  1         5  
  0         0  
  0         0  
  1         433  
  1         2  
  1         7  
  0         0  
  0         0  
  1         151  
  1         4  
  1         5  
  0         0  
  0         0  
  1         165  
  1         3  
  1         7  
  0         0  
  0         0  
  1         12  
  1         3  
  1         69  
  1         7  
  1         3  
  1         907  
  1         11  
  1         3  
  1         51  
  1         8  
  1         2  
  1         428  
  1         18  
  1         3  
  1         89  
  1         14  
  1         3  
  1         1226  
  1         23  
  1         1  
  1         9  
  0         0  
  0         0  
  1         715  
  1         4  
  1         10  
  0         0  
  0         0  
  1         264  
  1         5  
  1         10  
  0         0  
  0         0  
  1         233  
  1         4  
  1         11  
  0         0  
  0         0  
  1         34  
  1         2  
  1         35  
  1         5  
  1         1  
  1         273  
  1         9  
  1         2  
  1         10  
  0         0  
  0         0  
  1         411  
  1         3  
  1         7  
  0         0  
  0         0  
  1         161  
  1         3  
  1         7  
  0         0  
  0         0  
  1         159  
  1         3  
  1         6  
  112         55336  
  112         4245  
  113         408  
  97         44251  
  97         3246  
  97         348  
  97         40325  
  97         4211  
  97         340  
  113         55554  
  113         4440  
  113         459  
  1         3  
  1         410  
  1         11  
  1         3  
  1         48  
  1         6  
  1         3  
  1         738  
  1         6  
  1         1  
  1         7  
  0         0  
  0         0  
  1         515  
  1         10  
  1         8  
  0         0  
  0         0  
  1         145  
  1         2  
  1         14  
  0         0  
  0         0  
  1         181  
  1         2  
  1         4  
  0         0  
  0         0  
  1         15  
  1         4  
  1         58  
  1         27  
  1         3  
  1         265  
  1         8  
  1         3  
  1         8  
  0         0  
  0         0  
  1         388  
  1         2  
  1         4  
  0         0  
  0         0  
  1         176  
  1         3  
  1         7  
  0         0  
  0         0  
  1         145  
  1         2  
  1         7  
  0         0  
  0         0  
  1         13  
  1         3  
  1         54  
  1         8  
  1         2  
  1         1014  
228              
229             # otherwise we have to load the file from disk
230             } else {
231             # convert the class into a file name
232 0         0 my $file = File::Spec::Functions::catfile( split '::' , $class ) . '.pm';
233              
234             # attempt to load the file
235             # - return undef if there's a problem
236 0         0 eval { require $file };
  0         0  
237             }
238              
239             # if there were any problems, then we should fail
240 52 50       224 ( $@ ) and return undef;
241              
242             # if we've loaded this class, then ensure __init__() is called
243 52         296 $self->__init__;
244              
245 52         211 1; # everything is OK
246 14     14   119 } # require()
  14         25  
  14         103  
247              
248              
249             # for modules loaded by use(), ensure __init__() is called prior to code
250             # execution
251 14     14   274597 INIT { __PACKAGE__->__init__ }
252              
253              
254             1; # end of module
255             __END__