Filename | /Users/timbo/perl5/perlbrew/perls/perl-5.18.2/lib/site_perl/5.18.2/PPI/Document.pm |
Statements | Executed 2278433 statements in 3.07s |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
94225 | 1 | 1 | 1.08s | 2.00s | _add_location | PPI::Document::
144 | 1 | 1 | 636ms | 3.24s | index_locations | PPI::Document::
144 | 1 | 1 | 576ms | 1.23s | serialize | PPI::Document::
79763 | 2 | 1 | 466ms | 587ms | _visual_length | PPI::Document::
94225 | 1 | 1 | 256ms | 286ms | _logical_line_and_file | PPI::Document::
79763 | 1 | 1 | 95.9ms | 95.9ms | tab_width | PPI::Document::
191549 | 7 | 1 | 80.1ms | 80.1ms | CORE:match (opcode) | PPI::Document::
288 | 2 | 2 | 6.81ms | 13.2s | new (recurses: max depth 1, inclusive time 3.10ms) | PPI::Document::
144 | 1 | 1 | 667µs | 667µs | _setattr | PPI::Document::
1 | 1 | 1 | 189µs | 259µs | BEGIN@86 | PPI::Document::
1 | 1 | 1 | 142µs | 211µs | BEGIN@74 | PPI::Document::
1 | 1 | 1 | 12µs | 24µs | BEGIN@66 | PPI::Document::
1 | 1 | 1 | 8µs | 33µs | BEGIN@76 | PPI::Document::
1 | 1 | 1 | 8µs | 57µs | BEGIN@92 | PPI::Document::
1 | 1 | 1 | 8µs | 8µs | BEGIN@80 | PPI::Document::
1 | 1 | 1 | 7µs | 39µs | BEGIN@69 | PPI::Document::
1 | 1 | 1 | 6µs | 22µs | BEGIN@77 | PPI::Document::
1 | 1 | 1 | 6µs | 45µs | BEGIN@79 | PPI::Document::
1 | 1 | 1 | 6µs | 37µs | BEGIN@93 | PPI::Document::
1 | 1 | 1 | 6µs | 37µs | BEGIN@96 | PPI::Document::
1 | 1 | 1 | 6µs | 36µs | BEGIN@94 | PPI::Document::
1 | 1 | 1 | 6µs | 35µs | BEGIN@95 | PPI::Document::
1 | 1 | 1 | 3µs | 3µs | BEGIN@70 | PPI::Document::
1 | 1 | 1 | 3µs | 3µs | BEGIN@67 | PPI::Document::
1 | 1 | 1 | 3µs | 3µs | BEGIN@68 | PPI::Document::
1 | 1 | 1 | 3µs | 3µs | BEGIN@71 | PPI::Document::
1 | 1 | 1 | 3µs | 3µs | BEGIN@72 | PPI::Document::
1 | 1 | 1 | 3µs | 3µs | BEGIN@73 | PPI::Document::
0 | 0 | 0 | 0s | 0s | STORABLE_freeze | PPI::Document::
0 | 0 | 0 | 0s | 0s | STORABLE_thaw | PPI::Document::
0 | 0 | 0 | 0s | 0s | __ANON__[:192] | PPI::Document::
0 | 0 | 0 | 0s | 0s | __ANON__[:208] | PPI::Document::
0 | 0 | 0 | 0s | 0s | __ANON__[:223] | PPI::Document::
0 | 0 | 0 | 0s | 0s | __ANON__[:238] | PPI::Document::
0 | 0 | 0 | 0s | 0s | __ANON__[:490] | PPI::Document::
0 | 0 | 0 | 0s | 0s | __ANON__[:505] | PPI::Document::
0 | 0 | 0 | 0s | 0s | __ANON__[:820] | PPI::Document::
0 | 0 | 0 | 0s | 0s | _clear | PPI::Document::
0 | 0 | 0 | 0s | 0s | _error | PPI::Document::
0 | 0 | 0 | 0s | 0s | complete | PPI::Document::
0 | 0 | 0 | 0s | 0s | errstr | PPI::Document::
0 | 0 | 0 | 0s | 0s | flush_locations | PPI::Document::
0 | 0 | 0 | 0s | 0s | get_cache | PPI::Document::
0 | 0 | 0 | 0s | 0s | hex_id | PPI::Document::
0 | 0 | 0 | 0s | 0s | insert_after | PPI::Document::
0 | 0 | 0 | 0s | 0s | insert_before | PPI::Document::
0 | 0 | 0 | 0s | 0s | load | PPI::Document::
0 | 0 | 0 | 0s | 0s | normalized | PPI::Document::
0 | 0 | 0 | 0s | 0s | readonly | PPI::Document::
0 | 0 | 0 | 0s | 0s | replace | PPI::Document::
0 | 0 | 0 | 0s | 0s | save | PPI::Document::
0 | 0 | 0 | 0s | 0s | scope | PPI::Document::
0 | 0 | 0 | 0s | 0s | set_cache | PPI::Document::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package PPI::Document; | ||||
2 | |||||
3 | =pod | ||||
4 | |||||
5 | =head1 NAME | ||||
6 | |||||
7 | PPI::Document - Object representation of a Perl document | ||||
8 | |||||
9 | =head1 INHERITANCE | ||||
10 | |||||
11 | PPI::Document | ||||
12 | isa PPI::Node | ||||
13 | isa PPI::Element | ||||
14 | |||||
15 | =head1 SYNOPSIS | ||||
16 | |||||
17 | use PPI; | ||||
18 | |||||
19 | # Load a document from a file | ||||
20 | my $Document = PPI::Document->new('My/Module.pm'); | ||||
21 | |||||
22 | # Strip out comments | ||||
23 | $Document->prune('PPI::Token::Comment'); | ||||
24 | |||||
25 | # Find all the named subroutines | ||||
26 | my $sub_nodes = $Document->find( | ||||
27 | sub { $_[1]->isa('PPI::Statement::Sub') and $_[1]->name } | ||||
28 | ); | ||||
29 | my @sub_names = map { $_->name } @$sub_nodes; | ||||
30 | |||||
31 | # Save the file | ||||
32 | $Document->save('My/Module.pm.stripped'); | ||||
33 | |||||
34 | =head1 DESCRIPTION | ||||
35 | |||||
36 | The C<PPI::Document> class represents a single Perl "document". A | ||||
37 | C<PPI::Document> object acts as a root L<PPI::Node>, with some | ||||
38 | additional methods for loading and saving, and working with | ||||
39 | the line/column locations of Elements within a file. | ||||
40 | |||||
41 | The exemption to its L<PPI::Node>-like behavior this is that a | ||||
42 | C<PPI::Document> object can NEVER have a parent node, and is always | ||||
43 | the root node in a tree. | ||||
44 | |||||
45 | =head2 Storable Support | ||||
46 | |||||
47 | C<PPI::Document> implements the necessary C<STORABLE_freeze> and | ||||
48 | C<STORABLE_thaw> hooks to provide native support for L<Storable>, | ||||
49 | if you have it installed. | ||||
50 | |||||
51 | However if you want to clone clone a Document, you are highly recommended | ||||
52 | to use the internal C<$Document-E<gt>clone> method rather than Storable's | ||||
53 | C<dclone> function (although C<dclone> should still work). | ||||
54 | |||||
55 | =head1 METHODS | ||||
56 | |||||
57 | Most of the things you are likely to want to do with a Document are | ||||
58 | probably going to involve the methods from L<PPI::Node> class, of which | ||||
59 | this is a subclass. | ||||
60 | |||||
61 | The methods listed here are the remaining few methods that are truly | ||||
62 | Document-specific. | ||||
63 | |||||
64 | =cut | ||||
65 | |||||
66 | 2 | 19µs | 2 | 36µs | # spent 24µs (12+12) within PPI::Document::BEGIN@66 which was called:
# once (12µs+12µs) by PPI::BEGIN@23 at line 66 # spent 24µs making 1 call to PPI::Document::BEGIN@66
# spent 12µs making 1 call to strict::import |
67 | 2 | 16µs | 1 | 3µs | # spent 3µs within PPI::Document::BEGIN@67 which was called:
# once (3µs+0s) by PPI::BEGIN@23 at line 67 # spent 3µs making 1 call to PPI::Document::BEGIN@67 |
68 | 2 | 22µs | 1 | 3µs | # spent 3µs within PPI::Document::BEGIN@68 which was called:
# once (3µs+0s) by PPI::BEGIN@23 at line 68 # spent 3µs making 1 call to PPI::Document::BEGIN@68 |
69 | 2 | 19µs | 2 | 71µs | # spent 39µs (7+32) within PPI::Document::BEGIN@69 which was called:
# once (7µs+32µs) by PPI::BEGIN@23 at line 69 # spent 39µs making 1 call to PPI::Document::BEGIN@69
# spent 32µs making 1 call to Exporter::import |
70 | 2 | 15µs | 1 | 3µs | # spent 3µs within PPI::Document::BEGIN@70 which was called:
# once (3µs+0s) by PPI::BEGIN@23 at line 70 # spent 3µs making 1 call to PPI::Document::BEGIN@70 |
71 | 2 | 14µs | 1 | 3µs | # spent 3µs within PPI::Document::BEGIN@71 which was called:
# once (3µs+0s) by PPI::BEGIN@23 at line 71 # spent 3µs making 1 call to PPI::Document::BEGIN@71 |
72 | 2 | 14µs | 1 | 3µs | # spent 3µs within PPI::Document::BEGIN@72 which was called:
# once (3µs+0s) by PPI::BEGIN@23 at line 72 # spent 3µs making 1 call to PPI::Document::BEGIN@72 |
73 | 2 | 14µs | 1 | 3µs | # spent 3µs within PPI::Document::BEGIN@73 which was called:
# once (3µs+0s) by PPI::BEGIN@23 at line 73 # spent 3µs making 1 call to PPI::Document::BEGIN@73 |
74 | 2 | 88µs | 1 | 211µs | # spent 211µs (142+69) within PPI::Document::BEGIN@74 which was called:
# once (142µs+69µs) by PPI::BEGIN@23 at line 74 # spent 211µs making 1 call to PPI::Document::BEGIN@74 |
75 | |||||
76 | 2 | 23µs | 2 | 58µs | # spent 33µs (8+25) within PPI::Document::BEGIN@76 which was called:
# once (8µs+25µs) by PPI::BEGIN@23 at line 76 # spent 33µs making 1 call to PPI::Document::BEGIN@76
# spent 25µs making 1 call to overload::import |
77 | 2 | 20µs | 2 | 37µs | # spent 22µs (6+15) within PPI::Document::BEGIN@77 which was called:
# once (6µs+15µs) by PPI::BEGIN@23 at line 77 # spent 22µs making 1 call to PPI::Document::BEGIN@77
# spent 15µs making 1 call to overload::import |
78 | |||||
79 | 2 | 31µs | 2 | 84µs | # spent 45µs (6+39) within PPI::Document::BEGIN@79 which was called:
# once (6µs+39µs) by PPI::BEGIN@23 at line 79 # spent 45µs making 1 call to PPI::Document::BEGIN@79
# spent 39µs making 1 call to vars::import |
80 | # spent 8µs within PPI::Document::BEGIN@80 which was called:
# once (8µs+0s) by PPI::BEGIN@23 at line 84 | ||||
81 | 1 | 300ns | $VERSION = '1.215'; | ||
82 | 1 | 5µs | @ISA = 'PPI::Node'; | ||
83 | 1 | 4µs | $errstr = ''; | ||
84 | 1 | 14µs | 1 | 8µs | } # spent 8µs making 1 call to PPI::Document::BEGIN@80 |
85 | |||||
86 | 2 | 92µs | 1 | 259µs | # spent 259µs (189+70) within PPI::Document::BEGIN@86 which was called:
# once (189µs+70µs) by PPI::BEGIN@23 at line 86 # spent 259µs making 1 call to PPI::Document::BEGIN@86 |
87 | |||||
88 | # Document cache | ||||
89 | 1 | 400ns | my $CACHE = undef; | ||
90 | |||||
91 | # Convenience constants related to constants | ||||
92 | 2 | 23µs | 2 | 107µs | # spent 57µs (8+49) within PPI::Document::BEGIN@92 which was called:
# once (8µs+49µs) by PPI::BEGIN@23 at line 92 # spent 57µs making 1 call to PPI::Document::BEGIN@92
# spent 49µs making 1 call to constant::import |
93 | 2 | 20µs | 2 | 68µs | # spent 37µs (6+31) within PPI::Document::BEGIN@93 which was called:
# once (6µs+31µs) by PPI::BEGIN@23 at line 93 # spent 37µs making 1 call to PPI::Document::BEGIN@93
# spent 31µs making 1 call to constant::import |
94 | 2 | 19µs | 2 | 66µs | # spent 36µs (6+30) within PPI::Document::BEGIN@94 which was called:
# once (6µs+30µs) by PPI::BEGIN@23 at line 94 # spent 36µs making 1 call to PPI::Document::BEGIN@94
# spent 30µs making 1 call to constant::import |
95 | 2 | 23µs | 2 | 65µs | # spent 35µs (6+30) within PPI::Document::BEGIN@95 which was called:
# once (6µs+30µs) by PPI::BEGIN@23 at line 95 # spent 35µs making 1 call to PPI::Document::BEGIN@95
# spent 30µs making 1 call to constant::import |
96 | 2 | 2.17ms | 2 | 68µs | # spent 37µs (6+31) within PPI::Document::BEGIN@96 which was called:
# once (6µs+31µs) by PPI::BEGIN@23 at line 96 # spent 37µs making 1 call to PPI::Document::BEGIN@96
# spent 31µs making 1 call to constant::import |
97 | |||||
- - | |||||
102 | ##################################################################### | ||||
103 | # Constructor and Static Methods | ||||
104 | |||||
105 | =pod | ||||
106 | |||||
107 | =head2 new | ||||
108 | |||||
109 | # Simple construction | ||||
110 | $doc = PPI::Document->new( $filename ); | ||||
111 | $doc = PPI::Document->new( \$source ); | ||||
112 | |||||
113 | # With the readonly attribute set | ||||
114 | $doc = PPI::Document->new( $filename, | ||||
115 | readonly => 1, | ||||
116 | ); | ||||
117 | |||||
118 | The C<new> constructor takes as argument a variety of different sources of | ||||
119 | Perl code, and creates a single cohesive Perl C<PPI::Document> | ||||
120 | for it. | ||||
121 | |||||
122 | If passed a file name as a normal string, it will attempt to load the | ||||
123 | document from the file. | ||||
124 | |||||
125 | If passed a reference to a C<SCALAR>, this is taken to be source code and | ||||
126 | parsed directly to create the document. | ||||
127 | |||||
128 | If passed zero arguments, a "blank" document will be created that contains | ||||
129 | no content at all. | ||||
130 | |||||
131 | In all cases, the document is considered to be "anonymous" and not tied back | ||||
132 | to where it was created from. Specifically, if you create a PPI::Document from | ||||
133 | a filename, the document will B<not> remember where it was created from. | ||||
134 | |||||
135 | The constructor also takes attribute flags. | ||||
136 | |||||
137 | At this time, the only available attribute is the C<readonly> flag. | ||||
138 | |||||
139 | Setting C<readonly> to true will allow various systems to provide | ||||
140 | additional optimisations and caching. Note that because C<readonly> is an | ||||
141 | optimisation flag, it is off by default and you will need to explicitly | ||||
142 | enable it. | ||||
143 | |||||
144 | Returns a C<PPI::Document> object, or C<undef> if parsing fails. | ||||
145 | |||||
146 | =cut | ||||
147 | |||||
148 | # spent 13.2s (6.81ms+13.2) within PPI::Document::new which was called 288 times, avg 46.0ms/call:
# 144 times (4.55ms+13.2s) by PPI::Document::File::new at line 62 of PPI/Document/File.pm, avg 92.0ms/call
# 144 times (2.26ms+-2.26ms) by PPI::Lexer::lex_tokenizer at line 221 of PPI/Lexer.pm, avg 0s/call | ||||
149 | 288 | 94µs | local $_; # An extra one, just in case | ||
150 | 288 | 236µs | my $class = ref $_[0] ? ref shift : shift; | ||
151 | |||||
152 | 288 | 235µs | unless ( @_ ) { | ||
153 | 144 | 558µs | 144 | 842µs | my $self = $class->SUPER::new; # spent 842µs making 144 calls to PPI::Node::new, avg 6µs/call |
154 | 144 | 514µs | $self->{readonly} = ! 1; | ||
155 | 144 | 100µs | $self->{tab_width} = 1; | ||
156 | 144 | 644µs | return $self; | ||
157 | } | ||||
158 | |||||
159 | # Check constructor attributes | ||||
160 | 144 | 47µs | my $source = shift; | ||
161 | 144 | 93µs | my %attr = @_; | ||
162 | 144 | 106µs | my $timeout = delete $attr{timeout}; | ||
163 | 144 | 45µs | if ( $timeout and ! PPI::Util::HAVE_ALARM() ) { | ||
164 | Carp::croak("This platform does not support PPI parser timeouts"); | ||||
165 | } | ||||
166 | |||||
167 | # Check the data source | ||||
168 | 144 | 119µs | if ( ! defined $source ) { | ||
169 | $class->_error("An undefined value was passed to PPI::Document::new"); | ||||
170 | |||||
171 | } elsif ( ! ref $source ) { | ||||
172 | # Catch people using the old API | ||||
173 | 144 | 965µs | 144 | 506µs | if ( $source =~ /(?:\012|\015)/ ) { # spent 506µs making 144 calls to PPI::Document::CORE:match, avg 4µs/call |
174 | Carp::croak("API CHANGE: Source code should only be passed to PPI::Document->new as a SCALAR reference"); | ||||
175 | } | ||||
176 | |||||
177 | # When loading from a filename, use the caching layer if it exists. | ||||
178 | 144 | 101µs | if ( $CACHE ) { | ||
179 | my $file = $source; | ||||
180 | my $source = PPI::Util::_slurp( $file ); | ||||
181 | unless ( ref $source ) { | ||||
182 | # Errors returned as plain string | ||||
183 | return $class->_error($source); | ||||
184 | } | ||||
185 | |||||
186 | # Retrieve the document from the cache | ||||
187 | my $document = $CACHE->get_document($source); | ||||
188 | return $class->_setattr( $document, %attr ) if $document; | ||||
189 | |||||
190 | if ( $timeout ) { | ||||
191 | eval { | ||||
192 | local $SIG{ALRM} = sub { die "alarm\n" }; | ||||
193 | alarm( $timeout ); | ||||
194 | $document = PPI::Lexer->lex_source( $$source ); | ||||
195 | alarm( 0 ); | ||||
196 | }; | ||||
197 | } else { | ||||
198 | $document = PPI::Lexer->lex_source( $$source ); | ||||
199 | } | ||||
200 | if ( $document ) { | ||||
201 | # Save in the cache | ||||
202 | $CACHE->store_document( $document ); | ||||
203 | return $class->_setattr( $document, %attr ); | ||||
204 | } | ||||
205 | } else { | ||||
206 | 144 | 56µs | if ( $timeout ) { | ||
207 | eval { | ||||
208 | local $SIG{ALRM} = sub { die "alarm\n" }; | ||||
209 | alarm( $timeout ); | ||||
210 | my $document = PPI::Lexer->lex_file( $source ); | ||||
211 | return $class->_setattr( $document, %attr ) if $document; | ||||
212 | alarm( 0 ); | ||||
213 | }; | ||||
214 | } else { | ||||
215 | 144 | 988µs | 144 | 13.2s | my $document = PPI::Lexer->lex_file( $source ); # spent 13.2s making 144 calls to PPI::Lexer::lex_file, avg 92.0ms/call |
216 | 144 | 2.06ms | 288 | 804µs | return $class->_setattr( $document, %attr ) if $document; # spent 667µs making 144 calls to PPI::Document::_setattr, avg 5µs/call
# spent 137µs making 144 calls to PPI::Util::TRUE, avg 952ns/call |
217 | } | ||||
218 | } | ||||
219 | |||||
220 | } elsif ( _SCALAR0($source) ) { | ||||
221 | if ( $timeout ) { | ||||
222 | eval { | ||||
223 | local $SIG{ALRM} = sub { die "alarm\n" }; | ||||
224 | alarm( $timeout ); | ||||
225 | my $document = PPI::Lexer->lex_source( $$source ); | ||||
226 | return $class->_setattr( $document, %attr ) if $document; | ||||
227 | alarm( 0 ); | ||||
228 | }; | ||||
229 | } else { | ||||
230 | my $document = PPI::Lexer->lex_source( $$source ); | ||||
231 | return $class->_setattr( $document, %attr ) if $document; | ||||
232 | } | ||||
233 | |||||
234 | } elsif ( _ARRAY0($source) ) { | ||||
235 | $source = join '', map { "$_\n" } @$source; | ||||
236 | if ( $timeout ) { | ||||
237 | eval { | ||||
238 | local $SIG{ALRM} = sub { die "alarm\n" }; | ||||
239 | alarm( $timeout ); | ||||
240 | my $document = PPI::Lexer->lex_source( $source ); | ||||
241 | return $class->_setattr( $document, %attr ) if $document; | ||||
242 | alarm( 0 ); | ||||
243 | }; | ||||
244 | } else { | ||||
245 | my $document = PPI::Lexer->lex_source( $source ); | ||||
246 | return $class->_setattr( $document, %attr ) if $document; | ||||
247 | } | ||||
248 | |||||
249 | } else { | ||||
250 | $class->_error("Unknown object or reference was passed to PPI::Document::new"); | ||||
251 | } | ||||
252 | |||||
253 | # Pull and store the error from the lexer | ||||
254 | my $errstr; | ||||
255 | if ( _INSTANCE($@, 'PPI::Exception::Timeout') ) { | ||||
256 | $errstr = 'Timed out while parsing document'; | ||||
257 | } elsif ( _INSTANCE($@, 'PPI::Exception') ) { | ||||
258 | $errstr = $@->message; | ||||
259 | } elsif ( $@ ) { | ||||
260 | $errstr = $@; | ||||
261 | $errstr =~ s/\sat line\s.+$//; | ||||
262 | } elsif ( PPI::Lexer->errstr ) { | ||||
263 | $errstr = PPI::Lexer->errstr; | ||||
264 | } else { | ||||
265 | $errstr = "Unknown error parsing Perl document"; | ||||
266 | } | ||||
267 | PPI::Lexer->_clear; | ||||
268 | $class->_error( $errstr ); | ||||
269 | } | ||||
270 | |||||
271 | sub load { | ||||
272 | Carp::croak("API CHANGE: File names should now be passed to PPI::Document->new to load a file"); | ||||
273 | } | ||||
274 | |||||
275 | # spent 667µs within PPI::Document::_setattr which was called 144 times, avg 5µs/call:
# 144 times (667µs+0s) by PPI::Document::new at line 216, avg 5µs/call | ||||
276 | 144 | 158µs | my ($class, $document, %attr) = @_; | ||
277 | 144 | 188µs | $document->{readonly} = !! $attr{readonly}; | ||
278 | 144 | 479µs | return $document; | ||
279 | } | ||||
280 | |||||
281 | =pod | ||||
282 | |||||
283 | =head2 set_cache $cache | ||||
284 | |||||
285 | As of L<PPI> 1.100, C<PPI::Document> supports parser caching. | ||||
286 | |||||
287 | The default cache class L<PPI::Cache> provides a L<Storable>-based | ||||
288 | caching or the parsed document based on the MD5 hash of the document as | ||||
289 | a string. | ||||
290 | |||||
291 | The static C<set_cache> method is used to set the cache object for | ||||
292 | C<PPI::Document> to use when loading documents. It takes as argument | ||||
293 | a L<PPI::Cache> object (or something that C<isa> the same). | ||||
294 | |||||
295 | If passed C<undef>, this method will stop using the current cache, if any. | ||||
296 | |||||
297 | For more information on caching, see L<PPI::Cache>. | ||||
298 | |||||
299 | Returns true on success, or C<undef> if not passed a valid param. | ||||
300 | |||||
301 | =cut | ||||
302 | |||||
303 | sub set_cache { | ||||
304 | my $class = ref $_[0] ? ref shift : shift; | ||||
305 | |||||
306 | if ( defined $_[0] ) { | ||||
307 | # Enable the cache | ||||
308 | my $object = _INSTANCE(shift, 'PPI::Cache') or return undef; | ||||
309 | $CACHE = $object; | ||||
310 | } else { | ||||
311 | # Disable the cache | ||||
312 | $CACHE = undef; | ||||
313 | } | ||||
314 | |||||
315 | 1; | ||||
316 | } | ||||
317 | |||||
318 | =pod | ||||
319 | |||||
320 | =head2 get_cache | ||||
321 | |||||
322 | If a document cache is currently set, the C<get_cache> method will | ||||
323 | return it. | ||||
324 | |||||
325 | Returns a L<PPI::Cache> object, or C<undef> if there is no cache | ||||
326 | currently set for C<PPI::Document>. | ||||
327 | |||||
328 | =cut | ||||
329 | |||||
330 | sub get_cache { | ||||
331 | $CACHE; | ||||
332 | } | ||||
333 | |||||
- - | |||||
338 | ##################################################################### | ||||
339 | # PPI::Document Instance Methods | ||||
340 | |||||
341 | =pod | ||||
342 | |||||
343 | =head2 readonly | ||||
344 | |||||
345 | The C<readonly> attribute indicates if the document is intended to be | ||||
346 | read-only, and will never be modified. This is an advisory flag, that | ||||
347 | writers of L<PPI>-related systems may or may not use to enable | ||||
348 | optimisations and caches for your document. | ||||
349 | |||||
350 | Returns true if the document is read-only or false if not. | ||||
351 | |||||
352 | =cut | ||||
353 | |||||
354 | sub readonly { | ||||
355 | $_[0]->{readonly}; | ||||
356 | } | ||||
357 | |||||
358 | =pod | ||||
359 | |||||
360 | =head2 tab_width [ $width ] | ||||
361 | |||||
362 | In order to handle support for C<location> correctly, C<Documents> | ||||
363 | need to understand the concept of tabs and tab width. The C<tab_width> | ||||
364 | method is used to get and set the size of the tab width. | ||||
365 | |||||
366 | At the present time, PPI only supports "naive" (width 1) tabs, but we do | ||||
367 | plan on supporting arbitrary, default and auto-sensing tab widths later. | ||||
368 | |||||
369 | Returns the tab width as an integer, or C<die>s if you attempt to set the | ||||
370 | tab width. | ||||
371 | |||||
372 | =cut | ||||
373 | |||||
374 | # spent 95.9ms within PPI::Document::tab_width which was called 79763 times, avg 1µs/call:
# 79763 times (95.9ms+0s) by PPI::Document::_visual_length at line 740, avg 1µs/call | ||||
375 | 79763 | 9.13ms | my $self = shift; | ||
376 | 79763 | 191ms | return $self->{tab_width} unless @_; | ||
377 | $self->{tab_width} = shift; | ||||
378 | } | ||||
379 | |||||
380 | =pod | ||||
381 | |||||
382 | =head2 save | ||||
383 | |||||
384 | $document->save( $file ) | ||||
385 | |||||
386 | The C<save> method serializes the C<PPI::Document> object and saves the | ||||
387 | resulting Perl document to a file. Returns C<undef> on failure to open | ||||
388 | or write to the file. | ||||
389 | |||||
390 | =cut | ||||
391 | |||||
392 | sub save { | ||||
393 | my $self = shift; | ||||
394 | local *FILE; | ||||
395 | open( FILE, '>', $_[0] ) or return undef; | ||||
396 | print FILE $self->serialize or return undef; | ||||
397 | close FILE or return undef; | ||||
398 | return 1; | ||||
399 | } | ||||
400 | |||||
401 | =pod | ||||
402 | |||||
403 | =head2 serialize | ||||
404 | |||||
405 | Unlike the C<content> method, which shows only the immediate content | ||||
406 | within an element, Document objects also have to be able to be written | ||||
407 | out to a file again. | ||||
408 | |||||
409 | When doing this we need to take into account some additional factors. | ||||
410 | |||||
411 | Primarily, we need to handle here-docs correctly, so that are written | ||||
412 | to the file in the expected place. | ||||
413 | |||||
414 | The C<serialize> method generates the actual file content for a given | ||||
415 | Document object. The resulting string can be written straight to a file. | ||||
416 | |||||
417 | Returns the serialized document as a string. | ||||
418 | |||||
419 | =cut | ||||
420 | |||||
421 | # spent 1.23s (576ms+656ms) within PPI::Document::serialize which was called 144 times, avg 8.55ms/call:
# 144 times (576ms+656ms) by Perl::Critic::Document::AUTOLOAD at line 41 of Perl/Critic/Document.pm, avg 8.55ms/call | ||||
422 | 144 | 65µs | my $self = shift; | ||
423 | 144 | 7.81ms | 144 | 431ms | my @tokens = $self->tokens; # spent 431ms making 144 calls to PPI::Node::tokens, avg 2.99ms/call |
424 | |||||
425 | # The here-doc content buffer | ||||
426 | 144 | 97µs | my $heredoc = ''; | ||
427 | |||||
428 | # Start the main loop | ||||
429 | 144 | 85µs | my $output = ''; | ||
430 | 144 | 12.9ms | foreach my $i ( 0 .. $#tokens ) { | ||
431 | 94225 | 16.1ms | my $Token = $tokens[$i]; | ||
432 | |||||
433 | # Handle normal tokens | ||||
434 | 94225 | 292ms | 94225 | 91.6ms | unless ( $Token->isa('PPI::Token::HereDoc') ) { # spent 91.6ms making 94225 calls to UNIVERSAL::isa, avg 972ns/call |
435 | 94224 | 104ms | 94224 | 133ms | my $content = $Token->content; # spent 133ms making 94224 calls to PPI::Token::content, avg 1µs/call |
436 | |||||
437 | # Handle the trivial cases | ||||
438 | 94224 | 13.0ms | 4 | 3µs | unless ( $heredoc ne '' and $content =~ /\n/ ) { # spent 3µs making 4 calls to PPI::Document::CORE:match, avg 700ns/call |
439 | 94223 | 10.2ms | $output .= $content; | ||
440 | 94223 | 29.0ms | next; | ||
441 | } | ||||
442 | |||||
443 | # We have pending here-doc content that needs to be | ||||
444 | # inserted just after the first newline in the content. | ||||
445 | 1 | 1µs | if ( $content eq "\n" ) { | ||
446 | # Shortcut the most common case for speed | ||||
447 | $output .= $content . $heredoc; | ||||
448 | } else { | ||||
449 | # Slower and more general version | ||||
450 | $content =~ s/\n/\n$heredoc/; | ||||
451 | $output .= $content; | ||||
452 | } | ||||
453 | |||||
454 | 1 | 500ns | $heredoc = ''; | ||
455 | 1 | 300ns | next; | ||
456 | } | ||||
457 | |||||
458 | # This token is a HereDoc. | ||||
459 | # First, add the token content as normal, which in this | ||||
460 | # case will definately not contain a newline. | ||||
461 | 1 | 1µs | 1 | 1µs | $output .= $Token->content; # spent 1µs making 1 call to PPI::Token::content |
462 | |||||
463 | # Now add all of the here-doc content to the heredoc buffer. | ||||
464 | 1 | 3µs | 1 | 4µs | foreach my $line ( $Token->heredoc ) { # spent 4µs making 1 call to PPI::Token::HereDoc::heredoc |
465 | 5 | 2µs | $heredoc .= $line; | ||
466 | } | ||||
467 | |||||
468 | 1 | 500ns | if ( $Token->{_damaged} ) { | ||
469 | # Special Case: | ||||
470 | # There are a couple of warning/bug situations | ||||
471 | # that can occur when a HereDoc content was read in | ||||
472 | # from the end of a file that we silently allow. | ||||
473 | # | ||||
474 | # When writing back out to the file we have to | ||||
475 | # auto-repair these problems if we arn't going back | ||||
476 | # on to the end of the file. | ||||
477 | |||||
478 | # When calculating $last_line, ignore the final token if | ||||
479 | # and only if it has a single newline at the end. | ||||
480 | my $last_index = $#tokens; | ||||
481 | if ( $tokens[$last_index]->{content} =~ /^[^\n]*\n$/ ) { | ||||
482 | $last_index--; | ||||
483 | } | ||||
484 | |||||
485 | # This is a two part test. | ||||
486 | # First, are we on the last line of the | ||||
487 | # content part of the file | ||||
488 | my $last_line = List::MoreUtils::none { | ||||
489 | $tokens[$_] and $tokens[$_]->{content} =~ /\n/ | ||||
490 | } (($i + 1) .. $last_index); | ||||
491 | if ( ! defined $last_line ) { | ||||
492 | # Handles the null list case | ||||
493 | $last_line = 1; | ||||
494 | } | ||||
495 | |||||
496 | # Secondly, are their any more here-docs after us, | ||||
497 | # (with content or a terminator) | ||||
498 | my $any_after = List::MoreUtils::any { | ||||
499 | $tokens[$_]->isa('PPI::Token::HereDoc') | ||||
500 | and ( | ||||
501 | scalar(@{$tokens[$_]->{_heredoc}}) | ||||
502 | or | ||||
503 | defined $tokens[$_]->{_terminator_line} | ||||
504 | ) | ||||
505 | } (($i + 1) .. $#tokens); | ||||
506 | if ( ! defined $any_after ) { | ||||
507 | # Handles the null list case | ||||
508 | $any_after = ''; | ||||
509 | } | ||||
510 | |||||
511 | # We don't need to repair the last here-doc on the | ||||
512 | # last line. But we do need to repair anything else. | ||||
513 | unless ( $last_line and ! $any_after ) { | ||||
514 | # Add a terminating string if it didn't have one | ||||
515 | unless ( defined $Token->{_terminator_line} ) { | ||||
516 | $Token->{_terminator_line} = $Token->{_terminator}; | ||||
517 | } | ||||
518 | |||||
519 | # Add a trailing newline to the terminating | ||||
520 | # string if it didn't have one. | ||||
521 | unless ( $Token->{_terminator_line} =~ /\n$/ ) { | ||||
522 | $Token->{_terminator_line} .= "\n"; | ||||
523 | } | ||||
524 | } | ||||
525 | } | ||||
526 | |||||
527 | # Now add the termination line to the heredoc buffer | ||||
528 | 1 | 1µs | if ( defined $Token->{_terminator_line} ) { | ||
529 | $heredoc .= $Token->{_terminator_line}; | ||||
530 | } | ||||
531 | } | ||||
532 | |||||
533 | # End of tokens | ||||
534 | |||||
535 | 144 | 58µs | if ( $heredoc ne '' ) { | ||
536 | # If the file doesn't end in a newline, we need to add one | ||||
537 | # so that the here-doc content starts on the next line. | ||||
538 | unless ( $output =~ /\n$/ ) { | ||||
539 | $output .= "\n"; | ||||
540 | } | ||||
541 | |||||
542 | # Now we add the remaining here-doc content | ||||
543 | # to the end of the file. | ||||
544 | $output .= $heredoc; | ||||
545 | } | ||||
546 | |||||
547 | 144 | 3.36ms | $output; | ||
548 | } | ||||
549 | |||||
550 | =pod | ||||
551 | |||||
552 | =head2 hex_id | ||||
553 | |||||
554 | The C<hex_id> method generates an unique identifier for the Perl document. | ||||
555 | |||||
556 | This identifier is basically just the serialized document, with | ||||
557 | Unix-specific newlines, passed through MD5 to produce a hexadecimal string. | ||||
558 | |||||
559 | This identifier is used by a variety of systems (such as L<PPI::Cache> | ||||
560 | and L<Perl::Metrics>) as a unique key against which to store or cache | ||||
561 | information about a document (or indeed, to cache the document itself). | ||||
562 | |||||
563 | Returns a 32 character hexadecimal string. | ||||
564 | |||||
565 | =cut | ||||
566 | |||||
567 | sub hex_id { | ||||
568 | PPI::Util::md5hex($_[0]->serialize); | ||||
569 | } | ||||
570 | |||||
571 | =pod | ||||
572 | |||||
573 | =head2 index_locations | ||||
574 | |||||
575 | Within a document, all L<PPI::Element> objects can be considered to have a | ||||
576 | "location", a line/column position within the document when considered as a | ||||
577 | file. This position is primarily useful for debugging type activities. | ||||
578 | |||||
579 | The method for finding the position of a single Element is a bit laborious, | ||||
580 | and very slow if you need to do it a lot. So the C<index_locations> method | ||||
581 | will index and save the locations of every Element within the Document in | ||||
582 | advance, making future calls to <PPI::Element::location> virtually free. | ||||
583 | |||||
584 | Please note that this index should always be cleared using C<flush_locations> | ||||
585 | once you are finished with the locations. If content is added to or removed | ||||
586 | from the file, these indexed locations will be B<wrong>. | ||||
587 | |||||
588 | =cut | ||||
589 | |||||
590 | # spent 3.24s (636ms+2.60) within PPI::Document::index_locations which was called 144 times, avg 22.5ms/call:
# 144 times (636ms+2.60s) by Perl::Critic::Document::AUTOLOAD at line 41 of Perl/Critic/Document.pm, avg 22.5ms/call | ||||
591 | 144 | 52µs | my $self = shift; | ||
592 | 144 | 7.77ms | 144 | 500ms | my @tokens = $self->tokens; # spent 500ms making 144 calls to PPI::Node::tokens, avg 3.47ms/call |
593 | |||||
594 | # Whenever we hit a heredoc we will need to increment by | ||||
595 | # the number of lines in it's content section when when we | ||||
596 | # encounter the next token with a newline in it. | ||||
597 | 144 | 64µs | my $heredoc = 0; | ||
598 | |||||
599 | # Find the first Token without a location | ||||
600 | 144 | 66µs | my ($first, $location) = (); | ||
601 | 144 | 308µs | foreach ( 0 .. $#tokens ) { | ||
602 | 144 | 71µs | my $Token = $tokens[$_]; | ||
603 | 144 | 118µs | next if $Token->{_location}; | ||
604 | |||||
605 | # Found the first Token without a location | ||||
606 | # Calculate the new location if needed. | ||||
607 | 144 | 59µs | if ($_) { | ||
608 | $location = | ||||
609 | $self->_add_location( $location, $tokens[$_ - 1], \$heredoc ); | ||||
610 | } else { | ||||
611 | 144 | 7.49ms | 288 | 692µs | my $logical_file = # spent 414µs making 144 calls to PPI::Document::File::filename, avg 3µs/call
# spent 278µs making 144 calls to UNIVERSAL::can, avg 2µs/call |
612 | $self->can('filename') ? $self->filename : undef; | ||||
613 | 144 | 279µs | $location = [ 1, 1, 1, 1, $logical_file ]; | ||
614 | } | ||||
615 | 144 | 29µs | $first = $_; | ||
616 | 144 | 96µs | last; | ||
617 | } | ||||
618 | |||||
619 | # Calculate locations for the rest | ||||
620 | 144 | 113µs | if ( defined $first ) { | ||
621 | 144 | 149µs | foreach ( $first .. $#tokens ) { | ||
622 | 94225 | 23.1ms | my $Token = $tokens[$_]; | ||
623 | 94225 | 38.8ms | $Token->{_location} = $location; | ||
624 | 94225 | 111ms | 94225 | 2.00s | $location = $self->_add_location( $location, $Token, \$heredoc ); # spent 2.00s making 94225 calls to PPI::Document::_add_location, avg 21µs/call |
625 | |||||
626 | # Add any here-doc lines to the counter | ||||
627 | 94225 | 345ms | 94226 | 99.2ms | if ( $Token->isa('PPI::Token::HereDoc') ) { # spent 99.2ms making 94225 calls to UNIVERSAL::isa, avg 1µs/call
# spent 3µs making 1 call to PPI::Token::HereDoc::heredoc |
628 | $heredoc += $Token->heredoc + 1; | ||||
629 | } | ||||
630 | } | ||||
631 | } | ||||
632 | |||||
633 | 144 | 4.06ms | 1; | ||
634 | } | ||||
635 | |||||
636 | # spent 2.00s (1.08+925ms) within PPI::Document::_add_location which was called 94225 times, avg 21µs/call:
# 94225 times (1.08s+925ms) by PPI::Document::index_locations at line 624, avg 21µs/call | ||||
637 | 94225 | 20.2ms | my ($self, $start, $Token, $heredoc) = @_; | ||
638 | 94225 | 43.9ms | my $content = $Token->{content}; | ||
639 | |||||
640 | # Does the content contain any newlines | ||||
641 | 94225 | 271ms | 94225 | 33.7ms | my $newlines =()= $content =~ /\n/g; # spent 33.7ms making 94225 calls to PPI::Document::CORE:match, avg 358ns/call |
642 | 94225 | 118ms | 94225 | 286ms | my ($logical_line, $logical_file) = # spent 286ms making 94225 calls to PPI::Document::_logical_line_and_file, avg 3µs/call |
643 | $self->_logical_line_and_file($start, $Token, $newlines); | ||||
644 | |||||
645 | 94225 | 380ms | 78626 | 579ms | unless ( $newlines ) { # spent 579ms making 78626 calls to PPI::Document::_visual_length, avg 7µs/call |
646 | # Handle the simple case | ||||
647 | return [ | ||||
648 | $start->[LOCATION_LINE], | ||||
649 | $start->[LOCATION_CHARACTER] + length($content), | ||||
650 | $start->[LOCATION_COLUMN] | ||||
651 | + $self->_visual_length( | ||||
652 | $content, | ||||
653 | $start->[LOCATION_COLUMN] | ||||
654 | ), | ||||
655 | $logical_line, | ||||
656 | $logical_file, | ||||
657 | ]; | ||||
658 | } | ||||
659 | |||||
660 | # This is the more complex case where we hit or | ||||
661 | # span a newline boundary. | ||||
662 | 15599 | 3.79ms | my $physical_line = $start->[LOCATION_LINE] + $newlines; | ||
663 | 15599 | 13.5ms | my $location = [ $physical_line, 1, 1, $logical_line, $logical_file ]; | ||
664 | 15599 | 2.55ms | if ( $heredoc and $$heredoc ) { | ||
665 | 1 | 200ns | $location->[LOCATION_LINE] += $$heredoc; | ||
666 | 1 | 100ns | $location->[LOCATION_LOGICAL_LINE] += $$heredoc; | ||
667 | 1 | 200ns | $$heredoc = 0; | ||
668 | } | ||||
669 | |||||
670 | # Does the token have additional characters | ||||
671 | # after their last newline. | ||||
672 | 15599 | 57.5ms | 15599 | 19.1ms | if ( $content =~ /\n([^\n]+?)\z/ ) { # spent 19.1ms making 15599 calls to PPI::Document::CORE:match, avg 1µs/call |
673 | 1137 | 1.17ms | $location->[LOCATION_CHARACTER] += length($1); | ||
674 | 1137 | 1.67ms | 1137 | 8.08ms | $location->[LOCATION_COLUMN] += # spent 8.08ms making 1137 calls to PPI::Document::_visual_length, avg 7µs/call |
675 | $self->_visual_length( | ||||
676 | $1, $location->[LOCATION_COLUMN], | ||||
677 | ); | ||||
678 | } | ||||
679 | |||||
680 | 15599 | 38.9ms | $location; | ||
681 | } | ||||
682 | |||||
683 | # spent 286ms (256+29.9) within PPI::Document::_logical_line_and_file which was called 94225 times, avg 3µs/call:
# 94225 times (256ms+29.9ms) by PPI::Document::_add_location at line 642, avg 3µs/call | ||||
684 | 94225 | 20.1ms | my ($self, $start, $Token, $newlines) = @_; | ||
685 | |||||
686 | # Regex taken from perlsyn, with the correction that there's no space | ||||
687 | # required between the line number and the file name. | ||||
688 | 94225 | 22.6ms | if ($start->[LOCATION_CHARACTER] == 1) { | ||
689 | 14462 | 81.7ms | 27256 | 25.7ms | if ( $Token->isa('PPI::Token::Comment') ) { # spent 25.7ms making 27256 calls to UNIVERSAL::isa, avg 943ns/call |
690 | 1668 | 4.81ms | 3336 | 3.39ms | if ( # spent 2.55ms making 1668 calls to PPI::Token::content, avg 2µs/call
# spent 843µs making 1668 calls to PPI::Document::CORE:match, avg 505ns/call |
691 | $Token->content =~ m< | ||||
692 | \A | ||||
693 | \# \s* | ||||
694 | line \s+ | ||||
695 | (\d+) \s* | ||||
696 | (?: (\"?) ([^\"]* [^\s\"]) \2 )? | ||||
697 | \s* | ||||
698 | \z | ||||
699 | >xms | ||||
700 | ) { | ||||
701 | return $1, ($3 || $start->[LOCATION_LOGICAL_FILE]); | ||||
702 | } | ||||
703 | } | ||||
704 | elsif ( $Token->isa('PPI::Token::Pod') ) { | ||||
705 | 146 | 337µs | 146 | 318µs | my $content = $Token->content; # spent 318µs making 146 calls to PPI::Token::content, avg 2µs/call |
706 | 146 | 15µs | my $line; | ||
707 | 146 | 84µs | my $file = $start->[LOCATION_LOGICAL_FILE]; | ||
708 | 146 | 24µs | my $end_of_directive; | ||
709 | 146 | 835µs | 146 | 478µs | while ( # spent 478µs making 146 calls to PPI::Document::CORE:match, avg 3µs/call |
710 | $content =~ m< | ||||
711 | ^ | ||||
712 | \# \s*? | ||||
713 | line \s+? | ||||
714 | (\d+) (?: (?! \n) \s)* | ||||
715 | (?: (\"?) ([^\"]*? [^\s\"]) \2 )?? | ||||
716 | \s*? | ||||
717 | $ | ||||
718 | >xmsg | ||||
719 | ) { | ||||
720 | ($line, $file) = ($1, ( $3 || $file ) ); | ||||
721 | $end_of_directive = pos $content; | ||||
722 | } | ||||
723 | |||||
724 | 146 | 77µs | if (defined $line) { | ||
725 | pos $content = $end_of_directive; | ||||
726 | my $post_directive_newlines =()= $content =~ m< \G [^\n]* \n >xmsg; | ||||
727 | return $line + $post_directive_newlines - 1, $file; | ||||
728 | } | ||||
729 | } | ||||
730 | } | ||||
731 | |||||
732 | return | ||||
733 | 94225 | 293ms | $start->[LOCATION_LOGICAL_LINE] + $newlines, | ||
734 | $start->[LOCATION_LOGICAL_FILE]; | ||||
735 | } | ||||
736 | |||||
737 | sub _visual_length { | ||||
738 | 79763 | 21.1ms | my ($self, $content, $pos) = @_; | ||
739 | |||||
740 | 79763 | 66.9ms | 79763 | 95.9ms | my $tab_width = $self->tab_width; # spent 95.9ms making 79763 calls to PPI::Document::tab_width, avg 1µs/call |
741 | 79763 | 1.09ms | my ($length, $vis_inc); | ||
742 | |||||
743 | 79763 | 363ms | 79763 | 25.5ms | return length $content if $content !~ /\t/; # spent 25.5ms making 79763 calls to PPI::Document::CORE:match, avg 319ns/call |
744 | |||||
745 | # Split the content in tab and non-tab parts and calculate the | ||||
746 | # "visual increase" of each part. | ||||
747 | for my $part ( split(/(\t)/, $content) ) { | ||||
748 | if ($part eq "\t") { | ||||
749 | $vis_inc = $tab_width - ($pos-1) % $tab_width; | ||||
750 | } | ||||
751 | else { | ||||
752 | $vis_inc = length $part; | ||||
753 | } | ||||
754 | $length += $vis_inc; | ||||
755 | $pos += $vis_inc; | ||||
756 | } | ||||
757 | |||||
758 | $length; | ||||
759 | } | ||||
760 | |||||
761 | =pod | ||||
762 | |||||
763 | =head2 flush_locations | ||||
764 | |||||
765 | When no longer needed, the C<flush_locations> method clears all location data | ||||
766 | from the tokens. | ||||
767 | |||||
768 | =cut | ||||
769 | |||||
770 | sub flush_locations { | ||||
771 | shift->_flush_locations(@_); | ||||
772 | } | ||||
773 | |||||
774 | =pod | ||||
775 | |||||
776 | =head2 normalized | ||||
777 | |||||
778 | The C<normalized> method is used to generate a "Layer 1" | ||||
779 | L<PPI::Document::Normalized> object for the current Document. | ||||
780 | |||||
781 | A "normalized" Perl Document is an arbitrary structure that removes any | ||||
782 | irrelevant parts of the document and refactors out variations in style, | ||||
783 | to attempt to approach something that is closer to the "true meaning" | ||||
784 | of the Document. | ||||
785 | |||||
786 | See L<PPI::Normal> for more information on document normalization and | ||||
787 | the tasks for which it is useful. | ||||
788 | |||||
789 | Returns a L<PPI::Document::Normalized> object, or C<undef> on error. | ||||
790 | |||||
791 | =cut | ||||
792 | |||||
793 | sub normalized { | ||||
794 | # The normalization process will utterly destroy and mangle | ||||
795 | # anything passed to it, so we are going to only give it a | ||||
796 | # clone of ourself. | ||||
797 | PPI::Normal->process( $_[0]->clone ); | ||||
798 | } | ||||
799 | |||||
800 | =pod | ||||
801 | |||||
802 | =head1 complete | ||||
803 | |||||
804 | The C<complete> method is used to determine if a document is cleanly | ||||
805 | structured, all braces are closed, the final statement is | ||||
806 | fully terminated and all heredocs are fully entered. | ||||
807 | |||||
808 | Returns true if the document is complete or false if not. | ||||
809 | |||||
810 | =cut | ||||
811 | |||||
812 | sub complete { | ||||
813 | my $self = shift; | ||||
814 | |||||
815 | # Every structure has to be complete | ||||
816 | $self->find_any( sub { | ||||
817 | $_[1]->isa('PPI::Structure') | ||||
818 | and | ||||
819 | ! $_[1]->complete | ||||
820 | } ) | ||||
821 | and return ''; | ||||
822 | |||||
823 | # Strip anything that isn't a statement off the end | ||||
824 | my @child = $self->children; | ||||
825 | while ( @child and not $child[-1]->isa('PPI::Statement') ) { | ||||
826 | pop @child; | ||||
827 | } | ||||
828 | |||||
829 | # We must have at least one statement | ||||
830 | return '' unless @child; | ||||
831 | |||||
832 | # Check the completeness of the last statement | ||||
833 | return $child[-1]->_complete; | ||||
834 | } | ||||
835 | |||||
- - | |||||
840 | ##################################################################### | ||||
841 | # PPI::Node Methods | ||||
842 | |||||
843 | # We are a scope boundary | ||||
844 | ### XS -> PPI/XS.xs:_PPI_Document__scope 0.903+ | ||||
845 | sub scope { 1 } | ||||
846 | |||||
- - | |||||
851 | ##################################################################### | ||||
852 | # PPI::Element Methods | ||||
853 | |||||
854 | sub insert_before { | ||||
855 | return undef; | ||||
856 | # die "Cannot insert_before a PPI::Document"; | ||||
857 | } | ||||
858 | |||||
859 | sub insert_after { | ||||
860 | return undef; | ||||
861 | # die "Cannot insert_after a PPI::Document"; | ||||
862 | } | ||||
863 | |||||
864 | sub replace { | ||||
865 | return undef; | ||||
866 | # die "Cannot replace a PPI::Document"; | ||||
867 | } | ||||
868 | |||||
- - | |||||
873 | ##################################################################### | ||||
874 | # Error Handling | ||||
875 | |||||
876 | # Set the error message | ||||
877 | sub _error { | ||||
878 | $errstr = $_[1]; | ||||
879 | undef; | ||||
880 | } | ||||
881 | |||||
882 | # Clear the error message. | ||||
883 | # Returns the object as a convenience. | ||||
884 | sub _clear { | ||||
885 | $errstr = ''; | ||||
886 | $_[0]; | ||||
887 | } | ||||
888 | |||||
889 | =pod | ||||
890 | |||||
891 | =head2 errstr | ||||
892 | |||||
893 | For error that occur when loading and saving documents, you can use | ||||
894 | C<errstr>, as either a static or object method, to access the error message. | ||||
895 | |||||
896 | If a Document loads or saves without error, C<errstr> will return false. | ||||
897 | |||||
898 | =cut | ||||
899 | |||||
900 | sub errstr { | ||||
901 | $errstr; | ||||
902 | } | ||||
903 | |||||
- - | |||||
908 | ##################################################################### | ||||
909 | # Native Storable Support | ||||
910 | |||||
911 | sub STORABLE_freeze { | ||||
912 | my $self = shift; | ||||
913 | my $class = ref $self; | ||||
914 | my %hash = %$self; | ||||
915 | return ($class, \%hash); | ||||
916 | } | ||||
917 | |||||
918 | sub STORABLE_thaw { | ||||
919 | my ($self, undef, $class, $hash) = @_; | ||||
920 | bless $self, $class; | ||||
921 | foreach ( keys %$hash ) { | ||||
922 | $self->{$_} = delete $hash->{$_}; | ||||
923 | } | ||||
924 | $self->__link_children; | ||||
925 | } | ||||
926 | |||||
927 | 1 | 2µs | 1; | ||
928 | |||||
929 | =pod | ||||
930 | |||||
931 | =head1 TO DO | ||||
932 | |||||
933 | - May need to overload some methods to forcefully prevent Document | ||||
934 | objects becoming children of another Node. | ||||
935 | |||||
936 | =head1 SUPPORT | ||||
937 | |||||
938 | See the L<support section|PPI/SUPPORT> in the main module. | ||||
939 | |||||
940 | =head1 AUTHOR | ||||
941 | |||||
942 | Adam Kennedy E<lt>adamk@cpan.orgE<gt> | ||||
943 | |||||
944 | =head1 SEE ALSO | ||||
945 | |||||
946 | L<PPI>, L<http://ali.as/> | ||||
947 | |||||
948 | =head1 COPYRIGHT | ||||
949 | |||||
950 | Copyright 2001 - 2011 Adam Kennedy. | ||||
951 | |||||
952 | This program is free software; you can redistribute | ||||
953 | it and/or modify it under the same terms as Perl itself. | ||||
954 | |||||
955 | The full text of the license can be found in the | ||||
956 | LICENSE file included with this module. | ||||
957 | |||||
958 | =cut | ||||
# spent 80.1ms within PPI::Document::CORE:match which was called 191549 times, avg 418ns/call:
# 94225 times (33.7ms+0s) by PPI::Document::_add_location at line 641, avg 358ns/call
# 79763 times (25.5ms+0s) by PPI::Document::_visual_length at line 743, avg 319ns/call
# 15599 times (19.1ms+0s) by PPI::Document::_add_location at line 672, avg 1µs/call
# 1668 times (843µs+0s) by PPI::Document::_logical_line_and_file at line 690, avg 505ns/call
# 146 times (478µs+0s) by PPI::Document::_logical_line_and_file at line 709, avg 3µs/call
# 144 times (506µs+0s) by PPI::Document::new at line 173, avg 4µs/call
# 4 times (3µs+0s) by PPI::Document::serialize at line 438, avg 700ns/call |