File Coverage

blib/lib/Class/Declare/Attributes.pm
Criterion Covered Total %
statement 413 490 84.2
branch 17 30 56.6
condition 32 296 10.8
subroutine 122 151 80.7
pod 1 1 100.0
total 585 968 60.4


line stmt bran cond sub pod time code
1             # $Revision: 1515 $
2             package Class::Declare::Attributes;
3              
4 15     15   203992 use 5.006;
  15         47  
5 15     15   87 use strict;
  15         27  
  15         400  
6 15     15   61 use warnings;
  15         24  
  15         559  
7 15     15   10746 use attributes;
  15         20312  
  15         92  
8              
9 15     15   15390 use Class::Declare qw( :modifiers );
  15         344059  
  15         2755  
10 15     15   4703 use File::Spec::Functions qw();
  15         5295  
  15         397  
11 15     15   82 use base qw( Class::Declare );
  15         35  
  15         1307  
12 15     15   89 use vars qw( $VERSION $REVISION );
  15         24  
  15         8102  
13              
14             $VERSION = '0.10';
15             $REVISION = '$Revision: 1515 $';
16              
17             # need to copy the export symbols from Class::Declare
18             # to permit Class::Declare::Attributes to provide attribute modifiers
19             *EXPORT_OK = *Class::Declare::EXPORT_OK;
20             *EXPORT_TAGS = *Class::Declare::EXPORT_TAGS;
21              
22              
23             # declare the 'attributes' helper routines
24 0         0 BEGIN {
25              
26             # define the attributes that are wrapped by this class
27 15     15   75 my %__ATTR__ = map { $_ => 1 } qw( abstract
  105         221  
28             class
29             restricted
30             static
31             public
32             protected
33             private );
34              
35             # suppress the warnings surrounding the use of attributes that may be
36             # reserved for future use
37             # - this is naughty ... oh, well ... can be changed if necessary
38             # - we want to suppress this warning without disabling all warnings
39             # - we previously set $^W to 0, but this is very heavy handed, so
40             # let's try the following
41             $SIG{__WARN__} = sub {
42             # if we detect a violation caused by C::D::A, then suppress it,
43             # otherwise let it through
44 180         92096 my $pkg = __PACKAGE__;
45             ( $_[0] =~ /attribute may clash .+? reserved word: (\w+)/o ||
46             $_[0] =~ /^Declaration of (\w+) .+? package $pkg .+? reserved word/o )
47             # ensure the attribute belongs to C::D::A
48 180 50 33     3313 and ( $__ATTR__{ $1 } )
      33        
49             and return 1; # do nothing
50              
51             # otherwise, return the standard warn() response
52 0         0 warn $_[0];
53 15         134 }; # $SIG{__WARN__}()
54              
55              
56             # keep a log of calls made to set the attributes
57 15         40 my %__PKGS__ = ();
58 15         2544 my %__DONE__ = ();
59              
60              
61             # MODIFY_CODE_ATTRIBUTES()
62             #
63             # Keep a reference of the and type of attribute for each method specified as
64             #
65             # sub method : type { ... }
66             #
67             sub MODIFY_CODE_ATTRIBUTES
68             {
69 186     186   16433 my ( $pkg , $ref , @attr ) = @_;
70              
71             # only consider the attributes that we know about
72 186         294 my @unknown; undef @unknown;
  186         329  
73 186         403 foreach my $attr ( @attr ) {
74             # if this not an attribute we care about, then add it to the list of
75             # attributes to return
76             push @unknown , $attr
77 186 50 0     613 and next unless ( exists $__ATTR__{ $attr } );
78              
79             # have we already assigned one of our attributes to this target?
80             # - if we have, then we should raise an error
81 186 50       725 if ( defined ( my $previous = $__PKGS__{ $pkg }->{ $ref } ) ) {
82             # if this reference has already been assigned one of our attributes,
83             # then we have a problem if we are attempting to now assign a different
84             # attribute
85             # - something declared with the same attribute twice is not a problem
86             # as we just ignore the subsequent assignment
87 0 0       0 next if ( $previous eq $attr );
88              
89             # two conflicting attribute assignments
90 0         0 die "conflicting CODE attribute assignments of '$previous' "
91             . "and '$attr' in $pkg";
92             }
93              
94             # store this attribute assignment
95 186         524 $__PKGS__{ $pkg }->{ $ref } = $attr;
96            
97             # assign the CORE 'method' attribute to this reference as well
98             # - each code reference assigned a Class::Declare::Attributes interface
99             # is also actually a method
100 186         664 attributes::->import( CORE => $ref => 'method' );
101             }
102              
103             # if we have any unknown attributes, then return them
104 186 50       4112 return @unknown if ( @unknown );
105              
106             # otherwise, there's nothing more to do
107 186         542 return;
108             } # MODIFY_CODE_ATTRIBUTES()
109              
110              
111             # FETCH_CODE_ATTRIBUTES()
112             #
113             # Return the type of attribute for the given package and reference
114             sub FETCH_CODE_ATTRIBUTES
115             {
116 2825     2825   29367 my ( $pkg , $ref ) = @_;
117              
118             # if this is known package and reference, then return its attributes
119 2825         6417 return $__PKGS__{ $pkg }->{ $ref };
120             } # FETCH_CODE_ATTRIBUTES()
121              
122              
123              
124             # __init__()
125             #
126             # Initialise the code wrapping for Class::Declare-style methods
127             # - this needs to be called either at INIT time or when declare() is called
128             # to ensure dynamically loaded modules are handled correctly and the
129             # strict() setting is obeyed
130             sub __init__
131             {
132 147     147   280554 my $self = __PACKAGE__->static( shift );
133 147 50       3696 my @pkg = ( defined $_[0] ) ? ( $_[0] ) : keys %__PKGS__;
134              
135             # iterate through the given package(s)
136 147         383 foreach my $pkg ( @pkg ) {
137 15     15   110 no strict 'refs';
  15         36  
  15         1394  
138              
139             # do we have strict checking for this package on?
140 540         2563 my $strict = $pkg->strict;
141              
142             # if we have strict checking off and we've seen this package before
143             # then we should ensure we 'unnwrap' all wrapped routines
144 540 100       10079 unless ( $strict ) {
145 42 50       133 if ( my $wrapped = delete $__DONE__{ $pkg } ) {
146 0         0 while ( my ( $glob , $ref ) = each %{ $wrapped } ) {
  0         0  
147 15     15   358 no warnings 'redefine';
  15         33  
  15         1810  
148              
149 0         0 *{ $glob } = $ref;
  0         0  
150             }
151             }
152              
153             # no point proceeding, since we don't have strict checking on
154 42         171 return;
155             }
156              
157             # iterate through the symbol tree of this package
158 498         860 my $pkg_ = $pkg . '::';
159 498         536 my @names = keys %{ $pkg_ };
  498         3391  
160 498         1244 foreach my $name ( @names ) {
161 15     15   80 no warnings 'once';
  15         29  
  15         2185  
162              
163             # if we don't have a normal symbol table entry, then skip
164             # - occasionally we will find a reference here not a GLOB
165 9330         7708 my $sym = ${ $pkg_ }{ $name };
  9330         23286  
166 9330 50       14950 ( ref $sym ) and next;
167              
168             # if we don't have a CODE reference then we can't proceed
169 9330 100       7160 my $ref = *{ $sym }{ CODE } or next;
  9330         27190  
170 3343         9064 my @attr = grep { defined } attributes::get( $ref );
  3341         8756  
171              
172             # filter attributes that don't belong to the list fo C::D attributes
173 3343         6402 @attr = grep { defined } grep { $__ATTR__{ $_ } } @attr;
  138         308  
  654         999  
174              
175             # if there are no attributes, then there's nothing to do
176 3343 100       9488 ( @attr ) or next;
177              
178             # extract the name of this subroutine
179 138         338 my $glob = $pkg_ . $name;
180              
181             # if we have strict access checking, then "wrap" this routine
182 138 50       305 if ( $strict ) {
183 15     15   85 no warnings 'redefine';
  15         28  
  15         2400  
184              
185 138         193 my $type = $attr[0];
186 138     2841   523 *{ $glob } = sub { $pkg->$type( $_[0] , $glob ); goto $ref };
  138         435  
  2841         343158  
  2409         69560  
187              
188             # make note that this method has been wrapped
189             # - store the original CODE reference for this glob
190 138         648 $__DONE__{ $pkg }->{ $glob } = $ref;
191             }
192             }
193             }
194             } # __init__()
195              
196             } # BEGIN()
197              
198              
199             # require()
200             #
201             # Load the given class using Perl's require(), ensuring __init__() is called
202             # after the class has been successfully loaded. This is to ensure the correct
203             # subroutine wrappers are put in place.
204             #
205             # If the given class contains ';' then we assume that it's the string of the
206             # class rather than the filename, so we simply eval() that, rather than trying
207             # to load it from the filesystem.
208             sub require : class
209             {
210 76     112 1 142 my $self = shift;
211             # if there's no class then there's nothing to do
212 76 50       223 my $class = shift or return undef;
213              
214             # do we have a file or the text of the class?
215 76 50       390 if ( $class =~ m/;/o ) {
216             # we assume we have the body of a class, so we just eval() it
217 76   33 137   8129 eval $class;
  121   33 121   63859  
  121   33 137   3424  
  121   33 25   1272  
  137   33 25   74845  
  137   33 25   4051  
  137   33 25   3593  
  121   33 25   63810  
  121   33 25   3486  
  121   33 9   1390  
  137   0 9   75530  
  137   0 25   4074  
  137   33 25   5745  
  25   33 25   10088  
  25   33 9   481  
  25   0 9   532  
  256   0 18   9878  
  256   33 2   1455  
  25   0 18   3336  
  25   33 18   9649  
  25   33 18   469  
  120   33 2   205  
  120   0 18   9316  
  25   33 50   1341  
  25   33 58   438  
  25   33 58   8424  
  120   33 50   570  
  120   33 2   697  
  25   0 2   12351  
  25   0 2   427  
  25   0 2   78  
  1216   0 2   1601  
  1216   0 2   2764  
  9   0 2   79  
  9   0 2   18  
  9   0 2   337  
  9   0 2   62  
  25   0 2   14834  
  25   0 2   2153  
  25   0 2   705  
  25   0 2   8166  
  25   0 2   493  
  16   0 2   387  
  16   0 2   8215  
  25   0 2   3637  
  25   0 2   394  
  9   0 2   48  
  0   0 50   0  
  0   33 58   0  
  9   33 58   1023  
  9   33 50   16  
  9   33 2   39  
  16   0 2   9805  
  16   0 2   424  
  25   0 2   1387  
  9   0 2   19  
  9   0 2   51  
  608   0 2   811  
  624   0 2   10604  
  25   0 2   460  
  25   0 2   387  
  25   0 2   17194  
  25   0 2   765  
  25   0 2   644  
  25   0 2   14244  
  18   0 2   433  
  18   0 2   368  
  2   0 2   88  
  2   0 2   13  
  2   0 2   3  
  18   0 2   9652  
  18   0 98   478  
  18   33 114   46  
  50   33 114   13261  
  50   33 98   1452  
  50   33 2   149  
  50   0 2   1224  
  22   0 2   890  
  58   0 2   17746  
  58   0 2   1662  
  104   0 2   292  
  104   0 2   563  
  26   0 2   1926  
  58   0 2   20263  
  58   0 2   1604  
  56   0 2   150  
  56   0 2   197  
  26   0 2   1161  
  50   0 2   23183  
  50   0 2   1430  
  48   0 2   130  
  48   0 2   186  
  22   0 2   1008  
  2   0 2   4  
  2   0 2   10  
  0   0 2   0  
  0     0   0  
  2     0   21  
  2     0   6  
  2     0   155  
  2     0   14  
  2     0   4  
  2     0   400  
  2     0   42  
  2     0   5  
  2     0   11  
  0     0   0  
  0     0   0  
  2     48   678  
  2     48   4  
  2     0   17  
  0     48   0  
  0     0   0  
  2     48   228  
  2     0   7  
  2     48   8  
  0     0   0  
  0     0   0  
  2     48   227  
  2     0   4  
  2     0   14  
  0     0   0  
  0     0   0  
  2     0   15  
  2     0   5  
  2     0   70  
  2     0   11  
  2     0   4  
  2     0   1274  
  2     0   17  
  2     0   16  
  2         72  
  2         10  
  2         4  
  2         590  
  2         12  
  2         5  
  2         64  
  2         10  
  2         3  
  2         1008  
  2         20  
  2         5  
  2         12  
  48         59  
  48         193  
  2         472  
  2         4  
  2         7  
  0         0  
  0         0  
  2         171  
  2         4  
  2         7  
  0         0  
  0         0  
  2         175  
  2         4  
  2         12  
  0         0  
  0         0  
  2         12  
  2         3  
  2         61  
  2         9  
  2         2  
  2         226  
  2         10  
  2         4  
  2         8  
  0         0  
  0         0  
  2         478  
  2         4  
  2         9  
  0         0  
  0         0  
  2         180  
  2         4  
  2         7  
  0         0  
  0         0  
  2         175  
  2         5  
  2         7  
  0         0  
  0         0  
  2         11  
  2         4  
  2         50  
  2         9  
  2         2  
  2         958  
  50         6076  
  50         1381  
  50         177  
  50         198  
  10         306  
  58         7148  
  58         1649  
  58         147  
  58         260  
  14         462  
  58         6876  
  58         2443  
  58         150  
  58         201  
  14         531  
  96         6134  
  96         1570  
  50         612  
  50         179  
  14         491  
  0         0  
  0         0  
  2         173  
  2         3  
  2         8  
  0         0  
  0         0  
  2         179  
  2         4  
  2         7  
  0         0  
  0         0  
  2         13  
  2         2  
  2         60  
  2         8  
  2         3  
  2         231  
  2         11  
  2         3  
  2         10  
  0         0  
  0         0  
  2         467  
  2         2  
  2         8  
  0         0  
  0         0  
  2         176  
  2         3  
  2         7  
  0         0  
  0         0  
  2         194  
  2         4  
  2         8  
  0         0  
  0         0  
  2         18  
  2         5  
  2         77  
  2         13  
  2         4  
  2         1247  
  2         15  
  2         2  
  2         59  
  2         8  
  2         3  
  2         521  
  2         13  
  2         4  
  2         68  
  2         10  
  2         3  
  2         894  
  2         13  
  2         2  
  2         21  
  48         62  
  48         174  
  2         512  
  2         3  
  2         9  
  0         0  
  0         0  
  2         187  
  2         4  
  2         7  
  0         0  
  0         0  
  2         183  
  2         4  
  2         7  
  0         0  
  0         0  
  2         14  
  2         3  
  2         94  
  2         12  
  2         3  
  2         272  
  2         12  
  2         2  
  2         10  
  0         0  
  0         0  
  2         491  
  2         4  
  2         8  
  0         0  
  0         0  
  2         172  
  2         4  
  2         7  
  0         0  
  0         0  
  2         174  
  2         2  
  2         8  
  96         35996  
  96         2846  
  98         311  
  114         42755  
  114         3241  
  114         334  
  114         43956  
  114         4299  
  114         375  
  98         36602  
  98         2896  
  98         281  
  2         4  
  2         532  
  2         12  
  2         4  
  2         65  
  2         10  
  2         2  
  2         870  
  2         13  
  2         2  
  2         13  
  48         63  
  48         166  
  2         477  
  2         4  
  2         8  
  0         0  
  0         0  
  2         193  
  2         3  
  2         20  
  0         0  
  0         0  
  2         220  
  2         4  
  2         8  
  0         0  
  0         0  
  2         13  
  2         4  
  2         64  
  2         8  
  2         3  
  2         273  
  2         10  
  2         3  
  2         11  
  0         0  
  0         0  
  2         553  
  2         4  
  2         9  
  0         0  
  0         0  
  2         206  
  2         3  
  2         9  
  0         0  
  0         0  
  2         184  
  2         3  
  2         6  
  0         0  
  0         0  
  2         15  
  2         2  
  2         165  
  2         14  
  2         2  
  2         1123  
218              
219             # otherwise we have to load the file from disk
220             } else {
221             # convert the class into a file name
222 0         0 my $file = File::Spec::Functions::catfile( split '::' , $class ) . '.pm';
223              
224             # attempt to load the file
225             # - return undef if there's a problem
226 0         0 eval { require $file };
  0         0  
227             }
228              
229             # if there were any problems, then we should fail
230 76 50       280 ( $@ ) and return undef;
231              
232             # if we've loaded this class, then ensure __init__() is called
233 76         360 $self->__init__;
234              
235 76         234 1; # everything is OK
236 15     15   93 } # require()
  15         28  
  15         124  
237              
238              
239             # for modules loaded by use(), ensure __init__() is called prior to code
240             # execution
241 15     15   482424 INIT { __PACKAGE__->__init__ }
242              
243              
244             1; # end of module
245             __END__