File Coverage

blib/lib/Aspect/Pointcut/And.pm
Criterion Covered Total %
statement 92 108 85.1
branch 42 58 72.4
condition n/a
subroutine 10 11 90.9
pod 6 7 85.7
total 150 184 81.5


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