File Coverage

blib/lib/Attribute/Storage.pm
Criterion Covered Total %
statement 112 118 94.9
branch 51 70 72.8
condition 6 6 100.0
subroutine 17 17 100.0
pod 5 7 71.4
total 191 218 87.6


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2008-2014 -- leonerd@leonerd.org.uk
5              
6             package Attribute::Storage;
7              
8 9     9   179547 use strict;
  9         22  
  9         333  
9 9     9   78 use warnings;
  9         15  
  9         232  
10              
11 9     9   55 use Carp;
  9         17  
  9         1209  
12              
13             our $VERSION = '0.09';
14              
15             require XSLoader;
16             XSLoader::load( __PACKAGE__, $VERSION );
17              
18 9     9   54 use B qw( svref_2object );
  9         17  
  9         2112  
19              
20             =head1 NAME
21              
22             C - declare and retrieve named attributes about CODE
23             references
24              
25             =head1 SYNOPSIS
26              
27             package My::Package;
28              
29             use Attribute::Storage;
30              
31             sub Title :ATTR(CODE)
32             {
33             my $package = shift;
34             my ( $title ) = @_;
35              
36             return $title;
37             }
38              
39             package main;
40              
41             use Attribute::Storage qw( get_subattr );
42             use My::Package;
43              
44             sub myfunc :Title('The title of my function')
45             {
46             ...
47             }
48              
49             print "Title of myfunc is: ".get_subattr(\&myfunc, 'Title')."\n";
50              
51             =head1 DESCRIPTION
52              
53             This package provides a base, where a package using it can define handlers for
54             particular code attributes. Other packages, using the package that defines the
55             code attributes, can then use them to annotate subs.
56              
57             This is similar to C, with the following key differences:
58              
59             =over 4
60              
61             =item *
62              
63             C will store the value returned by the attribute handling
64             code, and provides convenient lookup functions to retrieve it later.
65             C simply invokes the handling code.
66              
67             =item *
68              
69             C immediately executes the attribute handling code at
70             compile-time. C defers invocation so it can look up the
71             symbolic name of the sub the attribute is attached to. C
72             uses L to provide the name of the sub at invocation time, using the name of
73             the underlying C.
74              
75             =item *
76              
77             C works just as well on anonymous subs as named ones.
78              
79             =item *
80              
81             C is safe to use on code that will be reloaded, because it
82             executes handlers immediately. C will only execute
83             handlers at defined phases such as C or C, and cannot reexecute
84             the handlers in a file once it has been reloaded.
85              
86             =back
87              
88             =cut
89              
90             sub import
91             {
92 10     10   68 my $class = shift;
93 10 50       55 return unless $class eq __PACKAGE__;
94              
95             # TODO
96             #Attribute::Lexical->import( 'CODE:ATTR' => \&handle_attr_ATTR );
97              
98 10         129 my $caller = caller;
99              
100             my $sub = sub {
101 28     28   28495 my ( $pkg, $ref, @attrs ) = @_;
102 31         591 grep {
103 28         45 my ( $attrname, $opts ) = m/^([A-Za-z_][0-9A-Za-z_]*)(?:\((.*)\))?$/s;
104 31 100       105 defined $opts or $opts = "";
105 31 100       1277 $attrname eq "ATTR" ?
106             handle_attr_ATTR( $pkg, $ref, $attrname, $opts ) :
107             handle_attr ( $pkg, $ref, $attrname, $opts );
108             } @attrs;
109 10         55 };
110              
111 9     9   57 no strict 'refs';
  9         30  
  9         4009  
112 10         22 *{$caller . "::MODIFY_CODE_ATTRIBUTES"} = $sub;
  10         63  
113              
114             # Some simple Exporter-like logic. Just does function refs
115 10         107 foreach my $symb ( @_ ) {
116 11 50       93 $sub = __PACKAGE__->can( $symb ) or croak __PACKAGE__." has no function '$symb'";
117 11         19 *{$caller . "::$symb"} = $sub;
  11         620  
118             }
119             }
120              
121             =head1 ATTRIBUTES
122              
123             Each attribute that the defining package wants to define should be done using
124             a marked subroutine, in a way similar to L. When a sub in
125             the using package is marked with such an attribute, the code is executed,
126             passing in the arguments. Whatever it returns is stored, to be returned later
127             when queried by C or C. The return value must be
128             defined, or else the attribute will be marked as a compile error for perl to
129             handle accordingly.
130              
131             Only C attributes are supported at present.
132              
133             sub AttributeName :ATTR(CODE)
134             {
135             my $package = shift;
136             my ( $attr, $args, $here ) = @_;
137             ...
138             return $value;
139             }
140              
141             At attachment time, the optional string that may appear within brackets
142             following the attribute's name is parsed as a Perl expression in list context.
143             If this succeeds, the values are passed as a list to the handling code. If
144             this fails, an error is returned to the perl compiler. If no string is
145             present, then an empty list is passed to the handling code.
146              
147             package Defining;
148              
149             sub NameMap :ATTR(CODE)
150             {
151             my $package = shift;
152             my @strings = @_;
153              
154             return { map { m/^(.*)=(.*)$/ and ( $1, $2 ) } @strings };
155             }
156              
157             package Using;
158              
159             use Defining;
160              
161             sub somefunc :NameMap("foo=FOO","bar=BAR","splot=WIBBLE") { ... }
162              
163             my $map = get_subattr("somefunc", "NameMap");
164             # Will yield:
165             # { foo => "FOO",
166             # bar => "BAR",
167             # splot => "WIBBLE" }
168              
169             Note that it is impossible to distinguish
170              
171             sub somefunc :NameMap { ... }
172             sub somefunc :NameMap() { ... }
173              
174             It is possible to create attributes that do not parse their argument as a perl
175             list expression, instead they just pass the plain string as a single argument.
176             For this, add the C flag to the C list.
177              
178             sub Title :ATTR(CODE,RAWDATA)
179             {
180             my $package = shift;
181             my ( $text ) = @_;
182              
183             return $text;
184             }
185              
186             sub thingy :Title(Here is the title for thingy) { ... }
187              
188             To obtain the name of the function to which the attribute is being applied,
189             use the C flag to the C list.
190              
191             sub Callable :ATTR(CODE,NAME)
192             {
193             my $package = shift;
194             my ( $subname, @args ) = @_;
195              
196             print "The Callable attribute is being applied to $package :: $subname\n";
197              
198             return;
199             }
200              
201             When applied to an anonymous function (C), the name will appear
202             as C<__ANON__>.
203              
204             Normally it is an error to attempt to apply the same attribute more than once
205             to the same function. Sometimes however, it would make sense for an attribute
206             to be applied many times. If the C list is given the C flag,
207             then applying it more than once will be allowed. Each invocation of the
208             handling code will be given the previous value that was returned, or C
209             for the first time. It is up to the code to perform whatever merging logic is
210             required.
211              
212             sub Description :ATTR(CODE,MULTI,RAWDATA)
213             {
214             my $package = shift;
215             my ( $olddesc, $more ) = @_;
216              
217             return defined $olddesc ? "$olddesc$more\n" : "$more\n";
218             }
219              
220             sub Argument :ATTR(CODE,MULTI)
221             {
222             my $package = shift;
223             my ( $args, $argname ) = @_;
224              
225             push @$args, $argname;
226             return $args;
227             }
228              
229             sub Option :ATTR(CODE,MULTI)
230             {
231             my $package = shift;
232             my ( $opts, $optname ) = @_;
233              
234             $opts and exists $opts->{$optname} and
235             croak "Already have the $optname option";
236              
237             $opts->{$optname}++;
238             return $opts;
239             }
240              
241             ...
242              
243             sub do_copy
244             :Description(Copy from SOURCE to DESTINATION)
245             :Description(Optionally preserves attributes)
246             :Argument("SOURCE")
247             :Argument("DESTINATION")
248             :Option("attrs")
249             :Option("verbose")
250             {
251             ...
252             }
253              
254             =cut
255              
256             sub handle_attr_ATTR
257             {
258 9     9 0 24 my ( $pkg, $ref, undef, $opts ) = @_;
259              
260 9         36 my $attrs = _get_attr_hash( $ref, 1 );
261              
262 9         15 my %type;
263 9         47 foreach ( split m/\s*,\s*/, $opts ) {
264 12 100       63 m/^CODE$/ and next;
265              
266 3 50       17 m/^SCALAR|HASH|ARRAY$/ and
267             croak "Only CODE attributes are supported currently";
268              
269 3 100       13 m/^RAWDATA$/ and
270             ( $type{raw} = 1 ), next;
271              
272 2 100       11 m/^MULTI$/ and
273             ( $type{multi} = 1 ), next;
274              
275 1 50       7 m/^NAME$/ and
276             ( $type{name} = 1 ), next;
277              
278 0         0 croak "Unrecognised attribute option $_";
279             }
280              
281 9         31 $attrs->{ATTR} = \%type;
282              
283 9         43 return 0;
284             }
285              
286             sub handle_attr
287             {
288 22     22 0 44 my ( $pkg, $ref, $attrname, $opts ) = @_;
289              
290 22 50       157 my $cv = $pkg->can( $attrname ) or return 1;
291 22 50       88 my $cvattrs = _get_attr_hash( $cv, 0 ) or return 1;
292 22 50       78 my $type = $cvattrs->{ATTR} or return 1;
293              
294 22         43 my @opts;
295 22 100       53 if( $type->{raw} ) {
296 1         4 @opts = ( $opts );
297             }
298             else {
299 21         23 @opts = do {
300 9     9   48 no strict;
  9         14  
  9         6661  
301 21 50       1678 defined $opts ? eval $opts : ();
302             };
303              
304 21 50       107 if( $@ ) {
305 0         0 my ( $msg ) = $@ =~ m/^(.*) at \(eval \d+\) line \d+\.$/;
306 0         0 croak "Unable to parse $attrname - $msg";
307             }
308             }
309              
310 22         91 my $attrs = _get_attr_hash( $ref, 1 );
311              
312 22 100       62 if( $type->{name} ) {
313 2         26 unshift @opts, svref_2object( $ref )->GV->NAME;
314             }
315              
316 22 100       75 if( $type->{multi} ) {
317 3         6 unshift @opts, $attrs->{$attrname};
318             }
319             else {
320 19 100       297 exists $attrs->{$attrname} and
321             croak "Already have the $attrname attribute";
322             }
323              
324 21         31 my $value = eval { $cv->( $pkg, @opts ) };
  21         58  
325 21 50       697 die $@ if $@;
326 21 50       56 defined $value or return 1;
327              
328 21         44 $attrs->{$attrname} = $value;
329              
330 21         139 return 0;
331             }
332              
333             =head1 FUNCTIONS
334              
335             =cut
336              
337             =head2 $attrs = get_subattrs( $sub )
338              
339             Returns a HASH reference containing all the attributes defined on the given
340             sub. The sub should either be passed as a CODE reference, or as a name in the
341             caller's package. If no attributes are defined, a reference to an empty HASH
342             is returned.
343              
344             The returned HASH reference is a new shallow clone, the caller may modify this
345             hash arbitrarily without breaking the stored data, or other users of it.
346              
347             =cut
348              
349             sub get_subattrs
350             {
351 1     1 1 1 my ( $sub ) = @_;
352              
353 1 50       4 defined $sub or croak "Need a sub";
354              
355 1         1 my $cv;
356 1 50       3 if( ref $sub ) {
357 1         2 $cv = $sub;
358             }
359             else {
360 0         0 my $caller = caller;
361 0         0 $cv = $caller->can( $sub );
362 0 0       0 defined $cv or croak "$caller has no sub $sub";
363             }
364              
365 1 50       2 return { %{ _get_attr_hash( $cv, 0 ) || {} } }; # clone
  1         10  
366             }
367              
368             =head2 $value = get_subattr( $sub, $attrname )
369              
370             Returns the value of a single named attribute on the given sub. The sub should
371             either be passed as a CODE reference, or as a name in the caller's package. If
372             the attribute is not defined, C is returned.
373              
374             =cut
375              
376             sub get_subattr
377             {
378 45     45 1 682 my ( $sub, $attr ) = @_;
379              
380 45 50       98 defined $sub or croak "Need a sub";
381              
382 45         44 my $cv;
383 45 100       86 if( ref $sub ) {
384 42         50 $cv = $sub;
385             }
386             else {
387 3         8 my $caller = caller;
388 3         22 $cv = $caller->can( $sub );
389 3 50       9 defined $cv or croak "$caller has no sub $sub";
390             }
391              
392 45 100       208 my $attrhash = _get_attr_hash( $cv, 0 ) or return undef;
393 28         122 return $attrhash->{$attr};
394             }
395              
396             =head2 $sub = apply_subattrs( @attrs_kvlist, $sub )
397              
398             A utility function to help apply attributes dynamically to the given CODE
399             reference. The CODE reference is given last so that calls to the function
400             appear similar in visual style to the same applied at compiletime.
401              
402             apply_subattrs
403             Title => "Here is my title",
404             sub { return $title };
405              
406             Is equivalent to
407              
408             sub :Title(Here is my title) { return $title }
409              
410             except that because its arguments are evaluated at runtime, they can be
411             calculated by other code in ways that the compiletime version cannot.
412              
413             As the attributes are given in a key-value pair list, it is allowed to apply
414             the same attribute multiple times; and the attributes are applied in the order
415             given. The value of each attribute should be a plain string exactly as it
416             would appear between the parentheses. Specifically, if the attribute does not
417             use the C flag, it should be a valid perl expression. As this is
418             still evaluated using an C call, take care when handling
419             potentially-unsafe or user-supplied data.
420              
421             =head2 $sub = apply_subattrs_for_pkg( $pkg, @attrs_kvlist, $sub )
422              
423             As C but allows passing a specific package name, rather than
424             using C.
425              
426             =cut
427              
428             sub apply_subattrs_for_pkg
429             {
430 1     1 1 4 my $pkg = shift;
431 1         2 my $sub = pop;
432              
433 1         3 while( @_ ) {
434 1         3 my $attr = shift;
435 1         1 my $value = shift;
436 1         11 attributes->import( $pkg, $sub, "$attr($value)" );
437             }
438              
439 1         119 return $sub;
440             }
441              
442             sub apply_subattrs
443             {
444 1     1 1 15 apply_subattrs_for_pkg( scalar caller, @_ );
445             }
446              
447             =head2 %subs = find_subs_with_attr( $pkg, $attrname, %opts )
448              
449             A utility function to find CODE references in the given package that have the
450             name attribute applied. The symbol table is checked for the given package,
451             looking for CODE references that have the named attribute applied. These are
452             returned in a key-value list, where the key gives the name of the function and
453             the value is a CODE reference to it.
454              
455             C<$pkg> can also be a reference to an array containing multiple package names,
456             which will be searched in order with earlier ones taking precedence over later
457             ones. This, for example, allows for subclass searching over an entire class
458             heirarchy of packages, via the use of L:
459              
460             %subs = find_subs_with_attr( [ mro::get_linear_isa $class ], $attrname );
461              
462             Takes the following named options:
463              
464             =over 8
465              
466             =item matching => Regexp | CODE
467              
468             If present, gives a filter regexp or CODE reference to apply to symbol names.
469              
470             $name =~ $matching
471             $matching->( local $_ = $name )
472              
473             =item filter => CODE
474              
475             If present, gives a filter CODE reference to apply to the function references
476             before they are accepted as results. Note that this allows the possibility
477             that the first match for a given method name to be rejected, while later ones
478             are accepted.
479              
480             $filter->( $cv, $name, $package )
481              
482             =back
483              
484             =cut
485              
486             sub find_subs_with_attr
487             {
488 5     5 1 4324 my ( $pkg, $attrname, %opts ) = @_;
489              
490 5         8 my $matching = $opts{matching};
491 5 100       18 $matching = do {
492 1         2 my $re = $matching;
493 6     6   45 sub { $_ =~ $re }
494 1         8 } if ref $matching eq "Regexp";
495              
496 5         6 my $filter = $opts{filter};
497              
498 5         6 my %ret;
499              
500 5 100       15 foreach $pkg ( ref $pkg ? @$pkg : $pkg ) {
501 9     9   81 no strict 'refs';
  9         20  
  9         1409  
502              
503 6         75 foreach my $symname ( keys %{$pkg."::"} ) {
  6         28  
504             # First definition wins
505 42 50       91 exists $ret{$symname} and next;
506              
507             # Perl seems to cache mechods in derived class symbol tables
508             # Skip these entries
509 42 100       177 my $cv = $pkg->can( $symname ) or next;
510              
511 35 100 100     92 $matching and not $matching->( local $_ = $symname ) and next;
512              
513 29 100       63 next unless defined get_subattr( $cv, $attrname );
514              
515 14 100 100     35 $filter and not $filter->( $cv, $symname, $pkg ) and next;
516              
517 13         42 $ret{$symname} = $cv;
518             }
519             }
520              
521 5         41 return %ret;
522             }
523              
524             =head1 AUTHOR
525              
526             Paul Evans
527              
528             =cut
529              
530             0x55AA;