File Coverage

blib/lib/Aspect/Pointcut/And.pm
Criterion Covered Total %
statement 95 111 85.5
branch 42 58 72.4
condition n/a
subroutine 11 12 91.6
pod 6 7 85.7
total 154 188 81.9


line stmt bran cond sub pod time code
1             package Aspect::Pointcut::And;
2              
3 21     21   83 use strict;
  21         28  
  21         575  
4 21     21   80 use warnings;
  21         23  
  21         471  
5 21     21   76 use Aspect::Pointcut::Logic ();
  21         22  
  21         18858  
6              
7             our $VERSION = '0.97_06';
8             our @ISA = 'Aspect::Pointcut::Logic';
9              
10              
11              
12              
13              
14             ######################################################################
15             # Constructor
16              
17             sub new {
18 97     97 1 159 my $class = shift;
19 97         209 my @parts = @_;
20              
21             # Validate the pointcut subexpressions
22 97         192 foreach my $part ( @parts ) {
23 195 50       4611 next if Params::Util::_INSTANCE($part, 'Aspect::Pointcut');
24 0         0 Carp::croak("Attempted to apply pointcut logic to non-pointcut '$part'");
25             }
26              
27             # Collapse nested and statements at constructor time so we don't have
28             # to do so multiple times later on during currying.
29 97         212 while ( scalar grep { $_->isa('Aspect::Pointcut::And') } @parts ) {
  238         890  
30             @parts = map {
31 14 100       25 $_->isa('Aspect::Pointcut::And') ? @$_ : $_
  28         106  
32             } @parts;
33             }
34              
35 97         681 $class->SUPER::new(@parts);
36             }
37              
38              
39              
40              
41              
42             ######################################################################
43             # Weaving Methods
44              
45             sub compile_weave {
46 65     65 1 95 my $self = shift;
47              
48             # Handle special cases
49             my @children = grep {
50 138 50       662 ref $_ or $_ ne 1
51             } map {
52 65         129 $_->compile_weave
  138         542  
53             } @$self;
54 65 50       199 unless ( @children ) {
55             # Potential bug, but why would we legitimately be empty
56 0         0 return 1;
57             }
58 65 100       206 if ( @children == 1 ) {
59 61         186 return $children[0];
60             }
61              
62             # Collapse string conditions together,
63             # and further collapse code conditions together.
64 4         8 my @string = ();
65 4         7 my @code = ();
66 4         10 foreach my $child ( @children ) {
67 8 50       14 unless ( ref $child ) {
68 8         9 push @string, $child;
69 8         10 next;
70             }
71 0 0       0 if ( @string ) {
72 0         0 my $group = join ' and ', map { "( $_ )" } @string;
  0         0  
73 0         0 push @code, eval "sub () { $group }";
74 0         0 @string = ();
75             }
76 0         0 push @code, $child;
77             }
78              
79 4 50       11 if ( @string ) {
80 4         7 my $group = join ' and ', map { "( $_ )" } @string;
  8         19  
81 4 50       17 unless ( @code ) {
82             # This is the only thing we have
83 4         13 return $group;
84             }
85 0         0 push @code, eval "sub () { $group }";
86             }
87              
88             # Join the groups
89             return sub {
90 0     0   0 foreach my $child ( @code ) {
91 0 0       0 return 0 unless $child->();
92             }
93 0         0 return 1;
94 0         0 };
95             }
96              
97             sub compile_runtime {
98 10     10 1 22 my $self = shift;
99              
100             # Handle special cases
101             my @children = grep {
102 20 100       120 ref $_ or $_ ne 1
103             } map {
104 10         23 $_->compile_runtime
  20         67  
105             } @$self;
106 10 50       28 unless ( @children ) {
107             # Potential bug, but why would we legitimately be empty
108 0         0 return 1;
109             }
110 10 50       34 if ( @children == 1 ) {
111 0         0 return $children[0];
112             }
113              
114             # Collapse string conditions together,
115             # and further collapse code conditions together.
116 10         18 my @string = ();
117 10         14 my @code = ();
118 10         19 foreach my $child ( @children ) {
119 20 100       202 unless ( ref $child ) {
120 18         24 push @string, $child;
121 18         23 next;
122             }
123 2 50       6 if ( @string ) {
124 2         6 my $group = join ' and ', map { "( $_ )" } @string;
  2         12  
125 2         173 push @code, eval "sub () { $group }";
126 2         8 @string = ();
127             }
128 2         4 push @code, $child;
129             }
130              
131 10 100       227 if ( @string ) {
132 8         12 my $group = join ' and ', map { "( $_ )" } @string;
  16         49  
133 8 50       18 unless ( @code ) {
134             # This is the only thing we have
135 8         47 return $group;
136             }
137 0         0 push @code, eval "sub () { $group }";
138             }
139              
140             # Join the groups
141             return sub {
142 4     4   10 foreach my $child ( @code ) {
143 8 100       91 return 0 unless $child->();
144             }
145 2         53 return 1;
146 2         15 };
147             }
148              
149             sub match_contains {
150 117     117 1 490 my $self = shift;
151 117         148 my $type = shift;
152 117 50       584 my $count = $self->isa($type) ? 1 : 0;
153 117         661 foreach my $child ( @$self ) {
154 242         681 $count += $child->match_contains($type);
155             }
156 117         383 return $count;
157             }
158              
159             sub match_runtime {
160 68     68 0 107 my $self = shift;
161 68         156 foreach my $child ( @$self ) {
162 102 100       497 return 1 if $child->match_runtime;
163             }
164 3         10 return 0;
165             }
166              
167             sub curry_weave {
168 66     66 1 2906 my $self = shift;
169 66         196 my @list = @$self;
170              
171             # Curry down our children. Anything that is not relevant at weave
172             # time is considered to always match, but curries to null.
173             # In an AND scenario, any "always" match can be savely removed.
174 66         146 @list = grep { defined $_ } map { $_->curry_weave } @list;
  70         203  
  142         422  
175              
176             # If none are left, curry us away to nothing
177 66 50       208 return unless @list;
178              
179             # If only one remains, curry us away to just that child
180 66 100       266 return $list[0] if @list == 1;
181              
182             # Create our clone to hold the curried subset
183 4         14 return ref($self)->new( @list );
184             }
185              
186             sub curry_runtime {
187 68     68 1 1956 my $self = shift;
188 68         190 my @list = @$self;
189              
190             # Should we strip out the call pointcuts
191 68         115 my $strip = shift;
192 68 100       246 unless ( defined $strip ) {
193             # Are there any elements that MUST exist at run-time?
194 67 100       191 if ( $self->match_runtime ) {
195             # If we have any nested logic that themselves contain
196             # call pointcuts, we can't strip.
197             $strip = not scalar grep {
198 64 100       117 $_->isa('Aspect::Pointcut::Logic')
  141         638  
199             and
200             $_->match_contains('Aspect::Pointcut::Call')
201             } @list;
202             } else {
203             # Nothing at runtime, so we can strip
204 3         13 $strip = 1;
205             }
206             }
207              
208             # Curry down our children
209 77         237 @list = grep { defined $_ } map {
210 68 100       138 $_->isa('Aspect::Pointcut::Call')
  150 100       822  
211             ? $strip
212             ? $_->curry_runtime($strip)
213             : $_
214             : $_->curry_runtime($strip)
215             } @list;
216              
217             # If none are left, curry us away to nothing
218 68 100       202 return unless @list;
219              
220             # If only one remains, curry us away to just that child
221 65 100       261 return $list[0] if @list == 1;
222              
223             # Create our clone to hold the curried subset
224 11         38 return ref($self)->new( @list );
225             }
226              
227             1;
228              
229             __END__