Filename | /Users/timbo/perl5/perlbrew/perls/perl-5.18.2/lib/site_perl/5.18.2/Perl/Critic/Policy/ErrorHandling/RequireCarping.pm |
Statements | Executed 22 statements in 1.21ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 17µs | 81µs | BEGIN@19 | Perl::Critic::Policy::ErrorHandling::RequireCarping::
1 | 1 | 1 | 16µs | 16µs | BEGIN@10 | Perl::Critic::Policy::ErrorHandling::RequireCarping::
1 | 1 | 1 | 10µs | 31µs | BEGIN@18 | Perl::Critic::Policy::ErrorHandling::RequireCarping::
1 | 1 | 1 | 9µs | 12µs | default_severity | Perl::Critic::Policy::ErrorHandling::RequireCarping::
1 | 1 | 1 | 9µs | 9µs | supported_parameters | Perl::Critic::Policy::ErrorHandling::RequireCarping::
1 | 1 | 1 | 7µs | 666µs | BEGIN@15 | Perl::Critic::Policy::ErrorHandling::RequireCarping::
1 | 1 | 1 | 7µs | 18µs | BEGIN@11 | Perl::Critic::Policy::ErrorHandling::RequireCarping::
1 | 1 | 1 | 7µs | 10µs | BEGIN@12 | Perl::Critic::Policy::ErrorHandling::RequireCarping::
1 | 1 | 1 | 7µs | 27µs | BEGIN@13 | Perl::Critic::Policy::ErrorHandling::RequireCarping::
0 | 0 | 0 | 0s | 0s | _determine_if_list_is_a_plain_list_and_get_last_child | Perl::Critic::Policy::ErrorHandling::RequireCarping::
0 | 0 | 0 | 0s | 0s | _find_last_element_in_subexpression | Perl::Critic::Policy::ErrorHandling::RequireCarping::
0 | 0 | 0 | 0s | 0s | _find_last_flattened_argument_list_element | Perl::Critic::Policy::ErrorHandling::RequireCarping::
0 | 0 | 0 | 0s | 0s | _is_complex_expression_token | Perl::Critic::Policy::ErrorHandling::RequireCarping::
0 | 0 | 0 | 0s | 0s | _is_element_contained_in_subroutine | Perl::Critic::Policy::ErrorHandling::RequireCarping::
0 | 0 | 0 | 0s | 0s | _is_element_in_namespace_main | Perl::Critic::Policy::ErrorHandling::RequireCarping::
0 | 0 | 0 | 0s | 0s | _is_postfix_operator | Perl::Critic::Policy::ErrorHandling::RequireCarping::
0 | 0 | 0 | 0s | 0s | _is_simple_list_element_token | Perl::Critic::Policy::ErrorHandling::RequireCarping::
0 | 0 | 0 | 0s | 0s | _last_flattened_argument_list_element_ends_in_newline | Perl::Critic::Policy::ErrorHandling::RequireCarping::
0 | 0 | 0 | 0s | 0s | applies_to | Perl::Critic::Policy::ErrorHandling::RequireCarping::
0 | 0 | 0 | 0s | 0s | default_themes | Perl::Critic::Policy::ErrorHandling::RequireCarping::
0 | 0 | 0 | 0s | 0s | violates | Perl::Critic::Policy::ErrorHandling::RequireCarping::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | ############################################################################## | ||||
2 | # $URL$ | ||||
3 | # $Date$ | ||||
4 | # $Author$ | ||||
5 | # $Revision$ | ||||
6 | ############################################################################## | ||||
7 | |||||
8 | package Perl::Critic::Policy::ErrorHandling::RequireCarping; | ||||
9 | |||||
10 | 2 | 42µs | 1 | 16µs | # spent 16µs within Perl::Critic::Policy::ErrorHandling::RequireCarping::BEGIN@10 which was called:
# once (16µs+0s) by Module::Pluggable::Object::_require at line 10 # spent 16µs making 1 call to Perl::Critic::Policy::ErrorHandling::RequireCarping::BEGIN@10 |
11 | 2 | 19µs | 2 | 29µs | # spent 18µs (7+11) within Perl::Critic::Policy::ErrorHandling::RequireCarping::BEGIN@11 which was called:
# once (7µs+11µs) by Module::Pluggable::Object::_require at line 11 # spent 18µs making 1 call to Perl::Critic::Policy::ErrorHandling::RequireCarping::BEGIN@11
# spent 11µs making 1 call to strict::import |
12 | 2 | 17µs | 2 | 14µs | # spent 10µs (7+4) within Perl::Critic::Policy::ErrorHandling::RequireCarping::BEGIN@12 which was called:
# once (7µs+4µs) by Module::Pluggable::Object::_require at line 12 # spent 10µs making 1 call to Perl::Critic::Policy::ErrorHandling::RequireCarping::BEGIN@12
# spent 4µs making 1 call to warnings::import |
13 | 2 | 24µs | 2 | 47µs | # spent 27µs (7+20) within Perl::Critic::Policy::ErrorHandling::RequireCarping::BEGIN@13 which was called:
# once (7µs+20µs) by Module::Pluggable::Object::_require at line 13 # spent 27µs making 1 call to Perl::Critic::Policy::ErrorHandling::RequireCarping::BEGIN@13
# spent 20µs making 1 call to Exporter::import |
14 | |||||
15 | 1 | 200ns | # spent 666µs (7+659) within Perl::Critic::Policy::ErrorHandling::RequireCarping::BEGIN@15 which was called:
# once (7µs+659µs) by Module::Pluggable::Object::_require at line 17 | ||
16 | :booleans :characters :severities :classification :data_conversion | ||||
17 | 1 | 25µs | 2 | 1.32ms | }; # spent 666µs making 1 call to Perl::Critic::Policy::ErrorHandling::RequireCarping::BEGIN@15
# spent 659µs making 1 call to Exporter::import |
18 | 2 | 23µs | 2 | 52µs | # spent 31µs (10+22) within Perl::Critic::Policy::ErrorHandling::RequireCarping::BEGIN@18 which was called:
# once (10µs+22µs) by Module::Pluggable::Object::_require at line 18 # spent 31µs making 1 call to Perl::Critic::Policy::ErrorHandling::RequireCarping::BEGIN@18
# spent 22µs making 1 call to Exporter::import |
19 | 2 | 1.02ms | 2 | 146µs | # spent 81µs (17+64) within Perl::Critic::Policy::ErrorHandling::RequireCarping::BEGIN@19 which was called:
# once (17µs+64µs) by Module::Pluggable::Object::_require at line 19 # spent 81µs making 1 call to Perl::Critic::Policy::ErrorHandling::RequireCarping::BEGIN@19
# spent 64µs making 1 call to base::import |
20 | |||||
21 | 1 | 800ns | our $VERSION = '1.121'; | ||
22 | |||||
23 | #----------------------------------------------------------------------------- | ||||
24 | |||||
25 | 1 | 4µs | 1 | 66µs | Readonly::Scalar my $EXPL => [ 283 ]; # spent 66µs making 1 call to Readonly::Scalar |
26 | |||||
27 | #----------------------------------------------------------------------------- | ||||
28 | |||||
29 | # spent 9µs within Perl::Critic::Policy::ErrorHandling::RequireCarping::supported_parameters which was called:
# once (9µs+0s) by Perl::Critic::Policy::new at line 88 of Perl/Critic/Policy.pm | ||||
30 | return ( | ||||
31 | { | ||||
32 | 1 | 12µs | name => 'allow_messages_ending_with_newlines', | ||
33 | description => q{Don't complain about die or warn if the message ends in a newline.}, | ||||
34 | default_string => '1', | ||||
35 | behavior => 'boolean', | ||||
36 | }, | ||||
37 | { | ||||
38 | name => 'allow_in_main_unless_in_subroutine', | ||||
39 | description => q{Don't complain about die or warn in main::, unless in a subroutine.}, | ||||
40 | default_string => '0', | ||||
41 | behavior => 'boolean', | ||||
42 | }, | ||||
43 | ); | ||||
44 | } | ||||
45 | |||||
46 | 1 | 2µs | # spent 12µs (9+2) within Perl::Critic::Policy::ErrorHandling::RequireCarping::default_severity which was called:
# once (9µs+2µs) by Perl::Critic::Policy::get_severity at line 331 of Perl/Critic/Policy.pm | ||
47 | sub default_themes { return qw( core pbp maintenance certrule ) } | ||||
48 | sub applies_to { return 'PPI::Token::Word' } | ||||
49 | |||||
50 | #----------------------------------------------------------------------------- | ||||
51 | |||||
52 | sub violates { | ||||
53 | my ( $self, $elem, undef ) = @_; | ||||
54 | |||||
55 | my $alternative; | ||||
56 | if ( $elem eq 'warn' ) { | ||||
57 | $alternative = 'carp'; | ||||
58 | } | ||||
59 | elsif ( $elem eq 'die' ) { | ||||
60 | $alternative = 'croak'; | ||||
61 | } | ||||
62 | else { | ||||
63 | return; | ||||
64 | } | ||||
65 | |||||
66 | return if ! is_function_call($elem); | ||||
67 | |||||
68 | if ($self->{_allow_messages_ending_with_newlines}) { | ||||
69 | return if _last_flattened_argument_list_element_ends_in_newline($elem); | ||||
70 | } | ||||
71 | |||||
72 | return if $self->{_allow_in_main_unless_in_subroutine} | ||||
73 | && !$self->_is_element_contained_in_subroutine( $elem ) | ||||
74 | && $self->_is_element_in_namespace_main( $elem ); # RT #56619 | ||||
75 | |||||
76 | my $desc = qq{"$elem" used instead of "$alternative"}; | ||||
77 | return $self->violation( $desc, $EXPL, $elem ); | ||||
78 | } | ||||
79 | |||||
80 | #----------------------------------------------------------------------------- | ||||
81 | |||||
82 | sub _last_flattened_argument_list_element_ends_in_newline { | ||||
83 | my $die_or_warn = shift; | ||||
84 | |||||
85 | my $last_flattened_argument = | ||||
86 | _find_last_flattened_argument_list_element($die_or_warn) | ||||
87 | or return $FALSE; | ||||
88 | |||||
89 | if ( $last_flattened_argument->isa('PPI::Token::Quote') ) { | ||||
90 | my $last_flattened_argument_string = | ||||
91 | $last_flattened_argument->string(); | ||||
92 | if ( | ||||
93 | $last_flattened_argument_string =~ m{ \n \z }xms | ||||
94 | or ( | ||||
95 | ( | ||||
96 | $last_flattened_argument->isa('PPI::Token::Quote::Double') | ||||
97 | or $last_flattened_argument->isa('PPI::Token::Quote::Interpolate') | ||||
98 | ) | ||||
99 | and $last_flattened_argument_string =~ m{ [\\] n \z }xms | ||||
100 | ) | ||||
101 | ) { | ||||
102 | return $TRUE; | ||||
103 | } | ||||
104 | } | ||||
105 | elsif ( $last_flattened_argument->isa('PPI::Token::HereDoc') ) { | ||||
106 | return $TRUE; | ||||
107 | } | ||||
108 | |||||
109 | return $FALSE | ||||
110 | } | ||||
111 | |||||
112 | #----------------------------------------------------------------------------- | ||||
113 | # Here starts the fun. Explanation by example: | ||||
114 | # | ||||
115 | # Let's say we've got the following (contrived) statement: | ||||
116 | # | ||||
117 | # die q{Isn't }, ( $this, ( " fun?\n" ) , ) if "It isn't Monday."; | ||||
118 | # | ||||
119 | # This statement should pass because the last parameter that die is going to | ||||
120 | # get is C<" fun?\n">. | ||||
121 | # | ||||
122 | # The approach is to first find the last non-flattened parameter. If this | ||||
123 | # is a simple token, we're done. Else, it's some aggregate thing. We can't | ||||
124 | # tell what C<some_function( "foo\n" )> is going to do, so we give up on | ||||
125 | # anything other than a PPI::Structure::List. | ||||
126 | # | ||||
127 | # There are three possible scenarios for the children of a List: | ||||
128 | # | ||||
129 | # * No children of the List, i.e. the list looks like C< ( ) >. | ||||
130 | # * One PPI::Statement::Expression element. | ||||
131 | # * One PPI::Statement element. That's right, an instance of the base | ||||
132 | # statement class and not some subclass. *sigh* | ||||
133 | # | ||||
134 | # In the first case, we're done. The latter two cases get treated | ||||
135 | # identically. We get the last child of the Statement and start the search | ||||
136 | # all over again. | ||||
137 | # | ||||
138 | # Back to our example. The PPI tree for this expression is | ||||
139 | # | ||||
140 | # PPI::Document | ||||
141 | # PPI::Statement | ||||
142 | # PPI::Token::Word 'die' | ||||
143 | # PPI::Token::Quote::Literal 'q{Isn't }' | ||||
144 | # PPI::Token::Operator ',' | ||||
145 | # PPI::Structure::List ( ... ) | ||||
146 | # PPI::Statement::Expression | ||||
147 | # PPI::Token::Symbol '$this' | ||||
148 | # PPI::Token::Operator ',' | ||||
149 | # PPI::Structure::List ( ... ) | ||||
150 | # PPI::Statement::Expression | ||||
151 | # PPI::Token::Quote::Double '" fun?\n"' | ||||
152 | # PPI::Token::Operator ',' | ||||
153 | # PPI::Token::Word 'if' | ||||
154 | # PPI::Token::Quote::Double '"It isn't Monday.\n"' | ||||
155 | # PPI::Token::Structure ';' | ||||
156 | # | ||||
157 | # We're starting with the Word containing 'die' (it could just as well be | ||||
158 | # 'warn') because the earlier parts of validate() have taken care of any | ||||
159 | # other possibility. We're going to scan forward through 'die's siblings | ||||
160 | # until we reach what we think the end of its parameters are. So we get | ||||
161 | # | ||||
162 | # 1. A Literal. A perfectly good argument. | ||||
163 | # 2. A comma operator. Looks like we've got more to go. | ||||
164 | # 3. A List. Another argument. | ||||
165 | # 4. The Word 'if'. Oops. That's a postfix operator. | ||||
166 | # | ||||
167 | # Thus, the last parameter is the List. So, we've got to scan backwards | ||||
168 | # through the components of the List; again, the goal is to find the last | ||||
169 | # value in the flattened list. | ||||
170 | # | ||||
171 | # Before decending into the List, we check that it isn't a subroutine call by | ||||
172 | # looking at its prior sibling. In this case, the prior sibling is a comma | ||||
173 | # operator, so it's fine. | ||||
174 | # | ||||
175 | # The List has one Expression element as we expect. We grab the Expression's | ||||
176 | # last child and start all over again. | ||||
177 | # | ||||
178 | # 1. The last child is a comma operator, which Perl will ignore, so we | ||||
179 | # skip it. | ||||
180 | # 2. The comma's prior sibling is a List. This is the last significant | ||||
181 | # part of the outer list. | ||||
182 | # 3. The List's prior sibling isn't a Word, so we can continue because the | ||||
183 | # List is not a parameter list. | ||||
184 | # 4. We go through the child Expression and find that the last child of | ||||
185 | # that is a PPI::Token::Quote::Double, which is a simple, non-compound | ||||
186 | # token. We return that and we're done. | ||||
187 | |||||
188 | sub _find_last_flattened_argument_list_element { | ||||
189 | my $die_or_warn = shift; | ||||
190 | |||||
191 | # Zoom forward... | ||||
192 | my $current_candidate = | ||||
193 | _find_last_element_in_subexpression($die_or_warn); | ||||
194 | |||||
195 | # ... scan back. | ||||
196 | while ( | ||||
197 | $current_candidate | ||||
198 | and not _is_simple_list_element_token( $current_candidate ) | ||||
199 | and not _is_complex_expression_token( $current_candidate ) | ||||
200 | ) { | ||||
201 | if ( $current_candidate->isa('PPI::Structure::List') ) { | ||||
202 | $current_candidate = | ||||
203 | _determine_if_list_is_a_plain_list_and_get_last_child( | ||||
204 | $current_candidate, | ||||
205 | $die_or_warn | ||||
206 | ); | ||||
207 | } elsif ( not $current_candidate->isa('PPI::Token') ) { | ||||
208 | return; | ||||
209 | } else { | ||||
210 | $current_candidate = $current_candidate->sprevious_sibling(); | ||||
211 | } | ||||
212 | } | ||||
213 | |||||
214 | return if not $current_candidate; | ||||
215 | return if _is_complex_expression_token( $current_candidate ); | ||||
216 | |||||
217 | my $penultimate_element = $current_candidate->sprevious_sibling(); | ||||
218 | if ($penultimate_element) { | ||||
219 | # Bail if we've got a Word in front of the Element that isn't | ||||
220 | # the original 'die' or 'warn' or anything else that isn't | ||||
221 | # a comma or dot operator. | ||||
222 | if ( $penultimate_element->isa('PPI::Token::Operator') ) { | ||||
223 | if ( | ||||
224 | $penultimate_element ne $COMMA | ||||
225 | and $penultimate_element ne $PERIOD | ||||
226 | ) { | ||||
227 | return; | ||||
228 | } | ||||
229 | } elsif ( $penultimate_element != $die_or_warn ) { | ||||
230 | return | ||||
231 | } | ||||
232 | } | ||||
233 | |||||
234 | return $current_candidate; | ||||
235 | } | ||||
236 | |||||
237 | #----------------------------------------------------------------------------- | ||||
238 | # This is the part where we scan forward from the 'die' or 'warn' to find | ||||
239 | # the last argument. | ||||
240 | |||||
241 | sub _find_last_element_in_subexpression { | ||||
242 | my $die_or_warn = shift; | ||||
243 | |||||
244 | my $last_following_sibling; | ||||
245 | my $next_sibling = $die_or_warn; | ||||
246 | while ( | ||||
247 | $next_sibling = $next_sibling->snext_sibling() | ||||
248 | and not _is_postfix_operator( $next_sibling ) | ||||
249 | ) { | ||||
250 | $last_following_sibling = $next_sibling; | ||||
251 | } | ||||
252 | |||||
253 | return $last_following_sibling; | ||||
254 | } | ||||
255 | |||||
256 | #----------------------------------------------------------------------------- | ||||
257 | # Ensure that the list isn't a parameter list. Find the last element of it. | ||||
258 | |||||
259 | sub _determine_if_list_is_a_plain_list_and_get_last_child { | ||||
260 | my ($list, $die_or_warn) = @_; | ||||
261 | |||||
262 | my $prior_sibling = $list->sprevious_sibling(); | ||||
263 | |||||
264 | if ( $prior_sibling ) { | ||||
265 | # Bail if we've got a Word in front of the List that isn't | ||||
266 | # the original 'die' or 'warn' or anything else that isn't | ||||
267 | # a comma operator. | ||||
268 | if ( $prior_sibling->isa('PPI::Token::Operator') ) { | ||||
269 | if ( $prior_sibling ne $COMMA ) { | ||||
270 | return; | ||||
271 | } | ||||
272 | } elsif ( $prior_sibling != $die_or_warn ) { | ||||
273 | return | ||||
274 | } | ||||
275 | } | ||||
276 | |||||
277 | my @list_children = $list->schildren(); | ||||
278 | |||||
279 | # If zero children, nothing to look for. | ||||
280 | # If multiple children, then PPI is not giving us | ||||
281 | # anything we understand. | ||||
282 | return if scalar (@list_children) != 1; | ||||
283 | |||||
284 | my $list_child = $list_children[0]; | ||||
285 | |||||
286 | # If the child isn't an Expression or it is some other subclass | ||||
287 | # of Statement, we again don't understand PPI's output. | ||||
288 | return if not is_ppi_expression_or_generic_statement($list_child); | ||||
289 | |||||
290 | my @statement_children = $list_child->schildren(); | ||||
291 | return if scalar (@statement_children) < 1; | ||||
292 | |||||
293 | return $statement_children[-1]; | ||||
294 | } | ||||
295 | |||||
296 | |||||
297 | #----------------------------------------------------------------------------- | ||||
298 | 1 | 4µs | 2 | 39µs | Readonly::Hash my %POSTFIX_OPERATORS => # spent 34µs making 1 call to Readonly::Hash
# spent 4µs making 1 call to Perl::Critic::Utils::hashify |
299 | hashify qw{ if unless while until for foreach }; | ||||
300 | |||||
301 | sub _is_postfix_operator { | ||||
302 | my $element = shift; | ||||
303 | |||||
304 | if ( | ||||
305 | $element->isa('PPI::Token::Word') | ||||
306 | and $POSTFIX_OPERATORS{$element} | ||||
307 | ) { | ||||
308 | return $TRUE; | ||||
309 | } | ||||
310 | |||||
311 | return $FALSE; | ||||
312 | } | ||||
313 | |||||
314 | |||||
315 | 1 | 2µs | 1 | 28µs | Readonly::Array my @SIMPLE_LIST_ELEMENT_TOKEN_CLASSES => # spent 28µs making 1 call to Readonly::Array |
316 | qw{ | ||||
317 | PPI::Token::Number | ||||
318 | PPI::Token::Word | ||||
319 | PPI::Token::DashedWord | ||||
320 | PPI::Token::Symbol | ||||
321 | PPI::Token::Quote | ||||
322 | PPI::Token::HereDoc | ||||
323 | }; | ||||
324 | |||||
325 | sub _is_simple_list_element_token { | ||||
326 | my $element = shift; | ||||
327 | |||||
328 | return $FALSE if not $element->isa('PPI::Token'); | ||||
329 | |||||
330 | foreach my $class (@SIMPLE_LIST_ELEMENT_TOKEN_CLASSES) { | ||||
331 | return $TRUE if $element->isa($class); | ||||
332 | } | ||||
333 | |||||
334 | return $FALSE; | ||||
335 | } | ||||
336 | |||||
337 | |||||
338 | #----------------------------------------------------------------------------- | ||||
339 | # Tokens that can't possibly be part of an expression simple | ||||
340 | # enough for us to examine. | ||||
341 | |||||
342 | 1 | 2µs | 1 | 30µs | Readonly::Array my @COMPLEX_EXPRESSION_TOKEN_CLASSES => # spent 30µs making 1 call to Readonly::Array |
343 | qw{ | ||||
344 | PPI::Token::ArrayIndex | ||||
345 | PPI::Token::QuoteLike | ||||
346 | PPI::Token::Regexp | ||||
347 | PPI::Token::Cast | ||||
348 | PPI::Token::Label | ||||
349 | PPI::Token::Separator | ||||
350 | PPI::Token::Data | ||||
351 | PPI::Token::End | ||||
352 | PPI::Token::Prototype | ||||
353 | PPI::Token::Attribute | ||||
354 | PPI::Token::Unknown | ||||
355 | }; | ||||
356 | |||||
357 | sub _is_complex_expression_token { | ||||
358 | my $element = shift; | ||||
359 | |||||
360 | return $FALSE if not $element->isa('PPI::Token'); | ||||
361 | |||||
362 | foreach my $class (@COMPLEX_EXPRESSION_TOKEN_CLASSES) { | ||||
363 | return $TRUE if $element->isa($class); | ||||
364 | } | ||||
365 | |||||
366 | return $FALSE; | ||||
367 | } | ||||
368 | |||||
369 | #----------------------------------------------------------------------------- | ||||
370 | # Check whether the given element is contained in a subroutine. | ||||
371 | |||||
372 | sub _is_element_contained_in_subroutine { | ||||
373 | my ( $self, $elem ) = @_; | ||||
374 | |||||
375 | my $parent = $elem; | ||||
376 | while ( $parent = $parent->parent() ) { | ||||
377 | $parent->isa( 'PPI::Statement::Sub' ) and return $TRUE; | ||||
378 | $parent->isa( 'PPI::Structure::Block' ) or next; | ||||
379 | my $prior_elem = $parent->sprevious_sibling() or next; | ||||
380 | $prior_elem->isa( 'PPI::Token::Word' ) | ||||
381 | and 'sub' eq $prior_elem->content() | ||||
382 | and return $TRUE; | ||||
383 | } | ||||
384 | |||||
385 | return $FALSE; | ||||
386 | } | ||||
387 | |||||
388 | #----------------------------------------------------------------------------- | ||||
389 | # Check whether the given element is in main:: | ||||
390 | |||||
391 | sub _is_element_in_namespace_main { | ||||
392 | my ( $self, $elem ) = @_; | ||||
393 | my $current_elem = $elem; | ||||
394 | my $prior_elem; | ||||
395 | |||||
396 | while ( $current_elem ) { | ||||
397 | while ( $prior_elem = $current_elem->sprevious_sibling() ) { | ||||
398 | if ( $prior_elem->isa( 'PPI::Statement::Package' ) ) { | ||||
399 | return 'main' eq $prior_elem->namespace(); | ||||
400 | } | ||||
401 | } continue { | ||||
402 | $current_elem = $prior_elem; | ||||
403 | } | ||||
404 | $current_elem = $current_elem->parent(); | ||||
405 | } | ||||
406 | |||||
407 | return $TRUE; | ||||
408 | } | ||||
409 | |||||
410 | 1 | 9µs | 1; | ||
411 | |||||
412 | __END__ |