| Filename | /Users/timbo/perl5/perlbrew/perls/perl-5.18.2/lib/site_perl/5.18.2/PPI/Normal.pm |
| Statements | Executed 59 statements in 689µs |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 472µs | 619µs | PPI::Normal::BEGIN@107 |
| 1 | 1 | 1 | 47µs | 60µs | PPI::Normal::register |
| 1 | 1 | 1 | 14µs | 26µs | PPI::Normal::BEGIN@37 |
| 1 | 1 | 1 | 10µs | 20µs | PPI::Normal::BEGIN@83 |
| 1 | 1 | 1 | 10µs | 46µs | PPI::Normal::BEGIN@40 |
| 1 | 1 | 1 | 7µs | 18µs | PPI::Normal::BEGIN@260 |
| 1 | 1 | 1 | 6µs | 33µs | PPI::Normal::BEGIN@43 |
| 1 | 1 | 1 | 5µs | 5µs | PPI::Normal::BEGIN@44 |
| 5 | 1 | 1 | 4µs | 4µs | PPI::Normal::CORE:match (opcode) |
| 1 | 1 | 1 | 3µs | 3µs | PPI::Normal::BEGIN@41 |
| 1 | 1 | 1 | 3µs | 3µs | PPI::Normal::BEGIN@38 |
| 1 | 1 | 1 | 3µs | 3µs | PPI::Normal::BEGIN@39 |
| 0 | 0 | 0 | 0s | 0s | PPI::Normal::__ANON__[:89] |
| 0 | 0 | 0 | 0s | 0s | PPI::Normal::layer |
| 0 | 0 | 0 | 0s | 0s | PPI::Normal::new |
| 0 | 0 | 0 | 0s | 0s | PPI::Normal::process |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | package PPI::Normal; | ||||
| 2 | |||||
| 3 | =pod | ||||
| 4 | |||||
| 5 | =head1 NAME | ||||
| 6 | |||||
| 7 | PPI::Normal - Normalize Perl Documents | ||||
| 8 | |||||
| 9 | =head2 DESCRIPTION | ||||
| 10 | |||||
| 11 | Perl Documents, as created by PPI, are typically filled with all sorts of | ||||
| 12 | mess such as whitespace and comments and other things that don't effect | ||||
| 13 | the actual meaning of the code. | ||||
| 14 | |||||
| 15 | In addition, because there is more than one way to do most things, and the | ||||
| 16 | syntax of Perl itself is quite flexible, there are many ways in which the | ||||
| 17 | "same" code can look quite different. | ||||
| 18 | |||||
| 19 | PPI::Normal attempts to resolve this by providing a variety of mechanisms | ||||
| 20 | and algorithms to "normalize" Perl Documents, and determine a sort of base | ||||
| 21 | form for them (although this base form will be a memory structure, and | ||||
| 22 | not something that can be turned back into Perl source code). | ||||
| 23 | |||||
| 24 | The process itself is quite complex, and so for convenience and | ||||
| 25 | extensibility it has been separated into a number of layers. At a later | ||||
| 26 | point, it will be possible to write Plugin classes to insert additional | ||||
| 27 | normalization steps into the various different layers. | ||||
| 28 | |||||
| 29 | In addition, you can choose to do the normalization only as deep as a | ||||
| 30 | particular layer, depending on aggressively you want the normalization | ||||
| 31 | process to be. | ||||
| 32 | |||||
| 33 | =head1 METHODS | ||||
| 34 | |||||
| 35 | =cut | ||||
| 36 | |||||
| 37 | 2 | 19µs | 2 | 38µs | # spent 26µs (14+12) within PPI::Normal::BEGIN@37 which was called:
# once (14µs+12µs) by PPI::BEGIN@27 at line 37 # spent 26µs making 1 call to PPI::Normal::BEGIN@37
# spent 12µs making 1 call to strict::import |
| 38 | 2 | 15µs | 1 | 3µs | # spent 3µs within PPI::Normal::BEGIN@38 which was called:
# once (3µs+0s) by PPI::BEGIN@27 at line 38 # spent 3µs making 1 call to PPI::Normal::BEGIN@38 |
| 39 | 2 | 17µs | 1 | 3µs | # spent 3µs within PPI::Normal::BEGIN@39 which was called:
# once (3µs+0s) by PPI::BEGIN@27 at line 39 # spent 3µs making 1 call to PPI::Normal::BEGIN@39 |
| 40 | 2 | 21µs | 2 | 82µs | # spent 46µs (10+36) within PPI::Normal::BEGIN@40 which was called:
# once (10µs+36µs) by PPI::BEGIN@27 at line 40 # spent 46µs making 1 call to PPI::Normal::BEGIN@40
# spent 36µs making 1 call to Exporter::import |
| 41 | 2 | 22µs | 1 | 3µs | # spent 3µs within PPI::Normal::BEGIN@41 which was called:
# once (3µs+0s) by PPI::BEGIN@27 at line 41 # spent 3µs making 1 call to PPI::Normal::BEGIN@41 |
| 42 | |||||
| 43 | 2 | 31µs | 2 | 60µs | # spent 33µs (6+27) within PPI::Normal::BEGIN@43 which was called:
# once (6µs+27µs) by PPI::BEGIN@27 at line 43 # spent 33µs making 1 call to PPI::Normal::BEGIN@43
# spent 27µs making 1 call to vars::import |
| 44 | # spent 5µs within PPI::Normal::BEGIN@44 which was called:
# once (5µs+0s) by PPI::BEGIN@27 at line 52 | ||||
| 45 | 1 | 300ns | $VERSION = '1.215'; | ||
| 46 | |||||
| 47 | # Registered function store | ||||
| 48 | 1 | 5µs | %LAYER = ( | ||
| 49 | 1 => [], | ||||
| 50 | 2 => [], | ||||
| 51 | ); | ||||
| 52 | 1 | 42µs | 1 | 5µs | } # spent 5µs making 1 call to PPI::Normal::BEGIN@44 |
| 53 | |||||
| - - | |||||
| 58 | ##################################################################### | ||||
| 59 | # Configuration | ||||
| 60 | |||||
| 61 | =pod | ||||
| 62 | |||||
| 63 | =head2 register $function => $layer, ... | ||||
| 64 | |||||
| 65 | The C<register> method is used by normalization method providers to | ||||
| 66 | tell the normalization engines which functions need to be run, and | ||||
| 67 | in which layer they apply. | ||||
| 68 | |||||
| 69 | Provide a set of key/value pairs, where the key is the full name of the | ||||
| 70 | function (in string form), and the value is the layer (see description | ||||
| 71 | of the layers above) in which it should be run. | ||||
| 72 | |||||
| 73 | Returns true if all functions are registered, or C<undef> on error. | ||||
| 74 | |||||
| 75 | =cut | ||||
| 76 | |||||
| 77 | # spent 60µs (47+13) within PPI::Normal::register which was called:
# once (47µs+13µs) by PPI::Normal::Standard::import at line 43 of PPI/Normal/Standard.pm | ||||
| 78 | 1 | 400ns | my $class = shift; | ||
| 79 | 1 | 300ns | while ( @_ ) { | ||
| 80 | # Check the function | ||||
| 81 | 5 | 1µs | my $function = shift; | ||
| 82 | 1 | 300ns | SCOPE: { | ||
| 83 | 6 | 117µs | 2 | 31µs | # spent 20µs (10+11) within PPI::Normal::BEGIN@83 which was called:
# once (10µs+11µs) by PPI::BEGIN@27 at line 83 # spent 20µs making 1 call to PPI::Normal::BEGIN@83
# spent 11µs making 1 call to strict::unimport |
| 84 | 5 | 4µs | defined $function and defined &{"$function"} | ||
| 85 | or Carp::croak("Bad function name provided to PPI::Normal"); | ||||
| 86 | } | ||||
| 87 | |||||
| 88 | # Has it already been added? | ||||
| 89 | 5 | 28µs | 5 | 8µs | if ( List::MoreUtils::any { $_ eq $function } ) { # spent 8µs making 5 calls to List::MoreUtils::any, avg 2µs/call |
| 90 | return 1; | ||||
| 91 | } | ||||
| 92 | |||||
| 93 | # Check the layer to add it to | ||||
| 94 | 5 | 1µs | my $layer = shift; | ||
| 95 | 5 | 15µs | 5 | 4µs | defined $layer and $layer =~ /^(?:1|2)$/ # spent 4µs making 5 calls to PPI::Normal::CORE:match, avg 900ns/call |
| 96 | or Carp::croak("Bad layer provided to PPI::Normal"); | ||||
| 97 | |||||
| 98 | # Add to the layer data store | ||||
| 99 | 5 | 5µs | push @{ $LAYER{$layer} }, $function; | ||
| 100 | } | ||||
| 101 | |||||
| 102 | 1 | 3µs | 1; | ||
| 103 | } | ||||
| 104 | |||||
| 105 | # With the registration mechanism in place, load in the main set of | ||||
| 106 | # normalization methods to initialize the store. | ||||
| 107 | 2 | 246µs | 2 | 715µs | # spent 619µs (472+147) within PPI::Normal::BEGIN@107 which was called:
# once (472µs+147µs) by PPI::BEGIN@27 at line 107 # spent 619µs making 1 call to PPI::Normal::BEGIN@107
# spent 97µs making 1 call to PPI::Normal::Standard::import |
| 108 | |||||
| - - | |||||
| 113 | ##################################################################### | ||||
| 114 | # Constructor and Accessors | ||||
| 115 | |||||
| 116 | =pod | ||||
| 117 | |||||
| 118 | =head2 new | ||||
| 119 | |||||
| 120 | my $level_1 = PPI::Normal->new; | ||||
| 121 | my $level_2 = PPI::Normal->new(2); | ||||
| 122 | |||||
| 123 | Creates a new normalization object, to which Document objects | ||||
| 124 | can be passed to be normalized. | ||||
| 125 | |||||
| 126 | Of course, what you probably REALLY want is just to call | ||||
| 127 | L<PPI::Document>'s C<normalize> method. | ||||
| 128 | |||||
| 129 | Takes an optional single parameter of the normalisation layer | ||||
| 130 | to use, which at this time can be either "1" or "2". | ||||
| 131 | |||||
| 132 | Returns a new C<PPI::Normal> object, or C<undef> on error. | ||||
| 133 | |||||
| 134 | =begin testing new after PPI::Document 12 | ||||
| 135 | |||||
| 136 | # Check we actually set the layer at creation | ||||
| 137 | my $layer_1 = PPI::Normal->new; | ||||
| 138 | isa_ok( $layer_1, 'PPI::Normal' ); | ||||
| 139 | is( $layer_1->layer, 1, '->new creates a layer 1' ); | ||||
| 140 | my $layer_1a = PPI::Normal->new(1); | ||||
| 141 | isa_ok( $layer_1a, 'PPI::Normal' ); | ||||
| 142 | is( $layer_1a->layer, 1, '->new(1) creates a layer 1' ); | ||||
| 143 | my $layer_2 = PPI::Normal->new(2); | ||||
| 144 | isa_ok( $layer_2, 'PPI::Normal' ); | ||||
| 145 | is( $layer_2->layer, 2, '->new(2) creates a layer 2' ); | ||||
| 146 | |||||
| 147 | # Test bad things | ||||
| 148 | is( PPI::Normal->new(3), undef, '->new only allows up to layer 2' ); | ||||
| 149 | is( PPI::Normal->new(undef), undef, '->new(evil) returns undef' ); | ||||
| 150 | is( PPI::Normal->new("foo"), undef, '->new(evil) returns undef' ); | ||||
| 151 | is( PPI::Normal->new(\"foo"), undef, '->new(evil) returns undef' ); | ||||
| 152 | is( PPI::Normal->new([]), undef, '->new(evil) returns undef' ); | ||||
| 153 | is( PPI::Normal->new({}), undef, '->new(evil) returns undef' ); | ||||
| 154 | |||||
| 155 | =end testing | ||||
| 156 | |||||
| 157 | =cut | ||||
| 158 | |||||
| 159 | sub new { | ||||
| 160 | my $class = shift; | ||||
| 161 | my $layer = @_ ? | ||||
| 162 | (defined $_[0] and ! ref $_[0] and $_[0] =~ /^[12]$/) ? shift : return undef | ||||
| 163 | : 1; | ||||
| 164 | |||||
| 165 | # Create the object | ||||
| 166 | my $object = bless { | ||||
| 167 | layer => $layer, | ||||
| 168 | }, $class; | ||||
| 169 | |||||
| 170 | $object; | ||||
| 171 | } | ||||
| 172 | |||||
| 173 | =pod | ||||
| 174 | |||||
| 175 | =head1 layer | ||||
| 176 | |||||
| 177 | The C<layer> accessor returns the normalisation layer of the object. | ||||
| 178 | |||||
| 179 | =cut | ||||
| 180 | |||||
| 181 | sub layer { $_[0]->{layer} } | ||||
| 182 | |||||
| - - | |||||
| 187 | ##################################################################### | ||||
| 188 | # Main Methods | ||||
| 189 | |||||
| 190 | =pod | ||||
| 191 | |||||
| 192 | =head2 process | ||||
| 193 | |||||
| 194 | The C<process> method takes anything that can be converted to a | ||||
| 195 | L<PPI::Document> (object, SCALAR ref, filename), loads it and | ||||
| 196 | applies the normalisation process to the document. | ||||
| 197 | |||||
| 198 | Returns a L<PPI::Document::Normalized> object, or C<undef> on error. | ||||
| 199 | |||||
| 200 | =begin testing process after new 15 | ||||
| 201 | |||||
| 202 | my $doc1 = PPI::Document->new(\'print "Hello World!\n";'); | ||||
| 203 | isa_ok( $doc1, 'PPI::Document' ); | ||||
| 204 | my $doc2 = \'print "Hello World!\n";'; | ||||
| 205 | my $doc3 = \' print "Hello World!\n"; # comment'; | ||||
| 206 | my $doc4 = \'print "Hello World!\n"'; | ||||
| 207 | |||||
| 208 | # Normalize them at level 1 | ||||
| 209 | my $layer1 = PPI::Normal->new(1); | ||||
| 210 | isa_ok( $layer1, 'PPI::Normal' ); | ||||
| 211 | my $nor11 = $layer1->process($doc1->clone); | ||||
| 212 | my $nor12 = $layer1->process($doc2); | ||||
| 213 | my $nor13 = $layer1->process($doc3); | ||||
| 214 | isa_ok( $nor11, 'PPI::Document::Normalized' ); | ||||
| 215 | isa_ok( $nor12, 'PPI::Document::Normalized' ); | ||||
| 216 | isa_ok( $nor13, 'PPI::Document::Normalized' ); | ||||
| 217 | |||||
| 218 | # The first 3 should be the same, the second not | ||||
| 219 | is_deeply( { %$nor11 }, { %$nor12 }, 'Layer 1: 1 and 2 match' ); | ||||
| 220 | is_deeply( { %$nor11 }, { %$nor13 }, 'Layer 1: 1 and 3 match' ); | ||||
| 221 | |||||
| 222 | # Normalize them at level 2 | ||||
| 223 | my $layer2 = PPI::Normal->new(2); | ||||
| 224 | isa_ok( $layer2, 'PPI::Normal' ); | ||||
| 225 | my $nor21 = $layer2->process($doc1); | ||||
| 226 | my $nor22 = $layer2->process($doc2); | ||||
| 227 | my $nor23 = $layer2->process($doc3); | ||||
| 228 | my $nor24 = $layer2->process($doc4); | ||||
| 229 | isa_ok( $nor21, 'PPI::Document::Normalized' ); | ||||
| 230 | isa_ok( $nor22, 'PPI::Document::Normalized' ); | ||||
| 231 | isa_ok( $nor23, 'PPI::Document::Normalized' ); | ||||
| 232 | isa_ok( $nor24, 'PPI::Document::Normalized' ); | ||||
| 233 | |||||
| 234 | # The first 3 should be the same, the second not | ||||
| 235 | is_deeply( { %$nor21 }, { %$nor22 }, 'Layer 2: 1 and 2 match' ); | ||||
| 236 | is_deeply( { %$nor21 }, { %$nor23 }, 'Layer 2: 1 and 3 match' ); | ||||
| 237 | is_deeply( { %$nor21 }, { %$nor24 }, 'Layer 2: 1 and 4 match' ); | ||||
| 238 | |||||
| 239 | =end testing | ||||
| 240 | |||||
| 241 | =cut | ||||
| 242 | |||||
| 243 | sub process { | ||||
| 244 | my $self = ref $_[0] ? shift : shift->new; | ||||
| 245 | |||||
| 246 | # PPI::Normal objects are reusable, but not re-entrant | ||||
| 247 | return undef if $self->{Document}; | ||||
| 248 | |||||
| 249 | # Get or create the document | ||||
| 250 | $self->{Document} = _Document(shift) or return undef; | ||||
| 251 | |||||
| 252 | # Work out what functions we need to call | ||||
| 253 | my @functions = (); | ||||
| 254 | foreach ( 1 .. $self->layer ) { | ||||
| 255 | push @functions, @{ $LAYER{$_} }; | ||||
| 256 | } | ||||
| 257 | |||||
| 258 | # Execute each function | ||||
| 259 | foreach my $function ( @functions ) { | ||||
| 260 | 2 | 93µs | 2 | 28µs | # spent 18µs (7+10) within PPI::Normal::BEGIN@260 which was called:
# once (7µs+10µs) by PPI::BEGIN@27 at line 260 # spent 18µs making 1 call to PPI::Normal::BEGIN@260
# spent 10µs making 1 call to strict::unimport |
| 261 | &{"$function"}( $self->{Document} ); | ||||
| 262 | } | ||||
| 263 | |||||
| 264 | # Create the normalized Document object | ||||
| 265 | my $Normalized = PPI::Document::Normalized->new( | ||||
| 266 | Document => $self->{Document}, | ||||
| 267 | version => $VERSION, | ||||
| 268 | functions => \@functions, | ||||
| 269 | ) or return undef; | ||||
| 270 | |||||
| 271 | # Done, clean up | ||||
| 272 | delete $self->{Document}; | ||||
| 273 | return $Normalized; | ||||
| 274 | } | ||||
| 275 | |||||
| 276 | 1 | 2µs | 1; | ||
| 277 | |||||
| 278 | =pod | ||||
| 279 | |||||
| 280 | =head1 NOTES | ||||
| 281 | |||||
| 282 | The following normalisation layers are implemented. When writing | ||||
| 283 | plugins, you should register each transformation function with the | ||||
| 284 | appropriate layer. | ||||
| 285 | |||||
| 286 | =head2 Layer 1 - Insignificant Data Removal | ||||
| 287 | |||||
| 288 | The basic step common to all normalization, layer 1 scans through the | ||||
| 289 | Document and removes all whitespace, comments, POD, and anything else | ||||
| 290 | that returns false for its C<significant> method. | ||||
| 291 | |||||
| 292 | It also checks each Element and removes known-useless sub-element | ||||
| 293 | metadata such as the Element's physical position in the file. | ||||
| 294 | |||||
| 295 | =head2 Layer 2 - Significant Element Removal | ||||
| 296 | |||||
| 297 | After the removal of the insignificant data, Layer 2 removed larger, more | ||||
| 298 | complex, and superficially "significant" elements, that can be removed | ||||
| 299 | for the purposes of normalisation. | ||||
| 300 | |||||
| 301 | Examples from this layer include pragmas, now-useless statement | ||||
| 302 | separators (since the PDOM tree is holding statement elements), and | ||||
| 303 | several other minor bits and pieces. | ||||
| 304 | |||||
| 305 | =head2 Layer 3 - TO BE COMPLETED | ||||
| 306 | |||||
| 307 | This version of the forward-port of the Perl::Compare functionality | ||||
| 308 | to the 0.900+ API of PPI only implements Layer 1 and 2 at this time. | ||||
| 309 | |||||
| 310 | =head1 TO DO | ||||
| 311 | |||||
| 312 | - Write the other 4-5 layers :) | ||||
| 313 | |||||
| 314 | =head1 SUPPORT | ||||
| 315 | |||||
| 316 | See the L<support section|PPI/SUPPORT> in the main module. | ||||
| 317 | |||||
| 318 | =head1 AUTHOR | ||||
| 319 | |||||
| 320 | Adam Kennedy E<lt>adamk@cpan.orgE<gt> | ||||
| 321 | |||||
| 322 | =head1 COPYRIGHT | ||||
| 323 | |||||
| 324 | Copyright 2005 - 2011 Adam Kennedy. | ||||
| 325 | |||||
| 326 | This program is free software; you can redistribute | ||||
| 327 | it and/or modify it under the same terms as Perl itself. | ||||
| 328 | |||||
| 329 | The full text of the license can be found in the | ||||
| 330 | LICENSE file included with this module. | ||||
| 331 | |||||
| 332 | =cut | ||||
# spent 4µs within PPI::Normal::CORE:match which was called 5 times, avg 900ns/call:
# 5 times (4µs+0s) by PPI::Normal::register at line 95, avg 900ns/call |