| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Aspect::Advice; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 1 |  |  | 1 |  | 6 | use strict; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 42 |  | 
| 4 | 1 |  |  | 1 |  | 7 | use warnings; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 41 |  | 
| 5 | 1 |  |  | 1 |  | 7 | use Carp; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 90 |  | 
| 6 | 1 |  |  | 1 |  | 8 | use Aspect::AdviceContext; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 39 |  | 
| 7 | 1 |  |  | 1 |  | 7 | use Aspect::Weaver; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 792 |  | 
| 8 |  |  |  |  |  |  |  | 
| 9 |  |  |  |  |  |  | sub new { | 
| 10 | 9 |  |  | 9 | 0 | 16 | my ($class, $type, $code, $pointcut) = @_; | 
| 11 | 9 |  |  |  |  | 63 | my $self = bless { | 
| 12 |  |  |  |  |  |  | weaver   => Aspect::Weaver->new, # a weaver that will install advice code | 
| 13 |  |  |  |  |  |  | hooks    => undef,               # list of Hook::LexWrap hooks | 
| 14 |  |  |  |  |  |  | type     => $type,               # before or after | 
| 15 |  |  |  |  |  |  | code     => $code,               # the advice code | 
| 16 |  |  |  |  |  |  | pointcut => $pointcut,           # the advice pointcut | 
| 17 |  |  |  |  |  |  | }, $class; | 
| 18 | 9 |  |  |  |  | 35 | $self->install; | 
| 19 | 9 |  |  |  |  | 16037 | return $self; | 
| 20 |  |  |  |  |  |  | } | 
| 21 |  |  |  |  |  |  |  | 
| 22 |  |  |  |  |  |  | # private --------------------------------------------------------------------- | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  | sub install { | 
| 25 | 9 |  |  | 9 | 0 | 18 | my $self     = shift; | 
| 26 | 9 |  |  |  |  | 30 | my $weaver   = $self->weaver; | 
| 27 | 9 |  |  |  |  | 26 | my $type     = $self->type; | 
| 28 | 9 |  |  |  |  | 31 | my $pointcut = $self->pointcut; | 
| 29 | 9 |  |  |  |  | 28 | my $code     = $self->code; | 
| 30 |  |  |  |  |  |  | # find all pointcuts that are staticaly matched | 
| 31 |  |  |  |  |  |  | # wrap the method with advice code and install the wrapper | 
| 32 | 9 |  |  |  |  | 31 | for my $sub_name ($weaver->get_sub_names) { | 
| 33 | 21906 | 100 |  |  |  | 42167 | next unless $pointcut->match_define($sub_name); | 
| 34 | 9 |  |  |  |  | 80 | my $wrapped_code = $self->wrap_code($type, $code, $pointcut, $sub_name); | 
| 35 | 9 |  |  |  |  | 66 | $self->add_hooks | 
| 36 |  |  |  |  |  |  | ($weaver->install($type, $sub_name, $wrapped_code)); | 
| 37 |  |  |  |  |  |  | } | 
| 38 |  |  |  |  |  |  | } | 
| 39 |  |  |  |  |  |  |  | 
| 40 |  |  |  |  |  |  | # return wrapper sub to be installed instead of original | 
| 41 |  |  |  |  |  |  | # wrapper sub creates context then calls advice code | 
| 42 |  |  |  |  |  |  | # it runs only if the pointcut answers true to match_run() | 
| 43 |  |  |  |  |  |  | sub wrap_code { | 
| 44 | 9 |  |  | 9 | 0 | 31 | my ($self, $type, $code, $pointcut, $sub_name) = @_; | 
| 45 |  |  |  |  |  |  |  | 
| 46 |  |  |  |  |  |  | return sub { | 
| 47 |  |  |  |  |  |  | # hacked Hook::LexWrap calls hooks with 3 params | 
| 48 | 14 |  |  | 14 |  | 23 | my ($params, $original, $return_value) = @_; | 
| 49 | 14 |  |  |  |  | 22 | my $runtime_context = {}; | 
| 50 | 14 | 100 |  |  |  | 179 | return unless $pointcut->match_run($sub_name, $runtime_context); | 
| 51 |  |  |  |  |  |  |  | 
| 52 |  |  |  |  |  |  | # create context for advice code | 
| 53 | 13 |  |  |  |  | 90 | my $advice_context = Aspect::AdviceContext->new( | 
| 54 |  |  |  |  |  |  | sub_name       => $sub_name, | 
| 55 |  |  |  |  |  |  | type           => $type, | 
| 56 |  |  |  |  |  |  | pointcut       => $pointcut, | 
| 57 |  |  |  |  |  |  | params         => $params, | 
| 58 |  |  |  |  |  |  | return_value   => $return_value, | 
| 59 |  |  |  |  |  |  | original       => $original, | 
| 60 |  |  |  |  |  |  | %$runtime_context, | 
| 61 |  |  |  |  |  |  | ); | 
| 62 |  |  |  |  |  |  |  | 
| 63 |  |  |  |  |  |  | # execute advice code with its context | 
| 64 | 13 | 50 |  |  |  | 40 | if (wantarray) | 
|  |  | 50 |  |  |  |  |  | 
| 65 | 0 |  |  |  |  | 0 | { () = &$code($advice_context) } | 
| 66 |  |  |  |  |  |  | elsif (defined wantarray) | 
| 67 | 13 |  |  |  |  | 38 | { my $dummy = &$code($advice_context) } | 
| 68 |  |  |  |  |  |  | else | 
| 69 | 0 |  |  |  |  | 0 | { &$code($advice_context) } | 
| 70 |  |  |  |  |  |  |  | 
| 71 |  |  |  |  |  |  | # if proceeding to original, modify params, else modify return value | 
| 72 | 13 | 100 | 100 |  |  | 100 | if ($type eq 'before' && $advice_context->proceed) | 
| 73 | 4 |  |  |  |  | 12 | { @$params = $advice_context->params } | 
| 74 |  |  |  |  |  |  | else | 
| 75 | 9 |  |  |  |  | 23 | { $_[-1] = $advice_context->return_value } | 
| 76 | 9 |  |  |  |  | 107 | }; | 
| 77 |  |  |  |  |  |  | } | 
| 78 |  |  |  |  |  |  |  | 
| 79 | 9 |  |  | 9 | 0 | 17 | sub add_hooks { push @{shift->{hooks}}, shift } | 
|  | 9 |  |  |  |  | 136 |  | 
| 80 |  |  |  |  |  |  |  | 
| 81 | 9 |  |  | 9 | 0 | 27 | sub weaver   { shift->{weaver}   } | 
| 82 | 9 |  |  | 9 | 0 | 24 | sub type     { shift->{type}     } | 
| 83 | 9 |  |  | 9 | 0 | 17 | sub code     { shift->{code}     } | 
| 84 | 9 |  |  | 9 | 0 | 20 | sub pointcut { shift->{pointcut} } | 
| 85 |  |  |  |  |  |  |  | 
| 86 |  |  |  |  |  |  | 1; | 
| 87 |  |  |  |  |  |  |  | 
| 88 |  |  |  |  |  |  | =head1 NAME | 
| 89 |  |  |  |  |  |  |  | 
| 90 |  |  |  |  |  |  | Aspect::Advice - change how Perl code is run at a pointcut | 
| 91 |  |  |  |  |  |  |  | 
| 92 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 93 |  |  |  |  |  |  |  | 
| 94 |  |  |  |  |  |  | # creating using public interface: trace calls to Account subs | 
| 95 |  |  |  |  |  |  | use Aspect; | 
| 96 |  |  |  |  |  |  | before { print 'called: '. shift->sub_name } call qw/^Account::/; | 
| 97 |  |  |  |  |  |  |  | 
| 98 |  |  |  |  |  |  | # creating using internal interface | 
| 99 |  |  |  |  |  |  | use Aspect::Advice; | 
| 100 |  |  |  |  |  |  | $advice = Aspect::Advice->new(before => | 
| 101 |  |  |  |  |  |  | { print 'called: '. shift->sub_name }, | 
| 102 |  |  |  |  |  |  | call qw/^Account::/ | 
| 103 |  |  |  |  |  |  | ); | 
| 104 |  |  |  |  |  |  |  | 
| 105 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 106 |  |  |  |  |  |  |  | 
| 107 |  |  |  |  |  |  | An advice is composed of a pointcut and some code that will run at the | 
| 108 |  |  |  |  |  |  | pointcut. The code is run C or C the pointcut, depending | 
| 109 |  |  |  |  |  |  | on advice C. | 
| 110 |  |  |  |  |  |  |  | 
| 111 |  |  |  |  |  |  | You do not normally create advice using the constructor. By C | 
| 112 |  |  |  |  |  |  | L, you get 2 subs imported: C and C, | 
| 113 |  |  |  |  |  |  | that do what you need. They also store the advice if called in void | 
| 114 |  |  |  |  |  |  | context, so you do not need to keep in scope. The advice code will be | 
| 115 |  |  |  |  |  |  | removed when the advice object is destroyed. | 
| 116 |  |  |  |  |  |  |  | 
| 117 |  |  |  |  |  |  | The advice code is given one parameter: an L. You | 
| 118 |  |  |  |  |  |  | use this object to change the parameter list for the matched sub, modify | 
| 119 |  |  |  |  |  |  | return value, find out information about the matched sub, and more. | 
| 120 |  |  |  |  |  |  |  | 
| 121 |  |  |  |  |  |  | This class has no public methods that do anything, but there are | 
| 122 |  |  |  |  |  |  | accessors C, C, C , and C, if you  | 
| 123 |  |  |  |  |  |  | need them. | 
| 124 |  |  |  |  |  |  |  | 
| 125 |  |  |  |  |  |  | =head1 SEE ALSO | 
| 126 |  |  |  |  |  |  |  | 
| 127 |  |  |  |  |  |  | See the L pod for a guide to the Aspect module. | 
| 128 |  |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  | =cut |