File Coverage

blib/lib/PPI/Normal.pm
Criterion Covered Total %
statement 59 59 100.0
branch 13 18 72.2
condition 5 9 55.5
subroutine 14 14 100.0
pod 3 4 75.0
total 94 104 90.3


line stmt bran cond sub pod time 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 64     64   398 use strict;
  64         111  
  64         1486  
38 64     64   269 use Carp ();
  64         136  
  64         1010  
39 64     64   254 use List::Util 1.33 ();
  64         947  
  64         1128  
40 64     64   266 use PPI::Util '_Document';
  64         134  
  64         3441  
41 64     64   472 use PPI::Document::Normalized ();
  64         147  
  64         1223  
42 64     64   22307 use PPI::Normal::Standard ();
  64         134  
  64         1302  
43 64     64   337 use PPI::Singletons '%LAYER';
  64         120  
  64         6934  
44              
45             our $VERSION = '1.276';
46              
47             # With the registration mechanism in place, load in the main set of
48             # normalization methods to initialize the store.
49             PPI::Normal::Standard->import;
50              
51              
52              
53              
54             #####################################################################
55             # Configuration
56              
57             =pod
58              
59             =head2 register $function => $layer, ...
60              
61             The C method is used by normalization method providers to
62             tell the normalization engines which functions need to be run, and
63             in which layer they apply.
64              
65             Provide a set of key/value pairs, where the key is the full name of the
66             function (in string form), and the value is the layer (see description
67             of the layers above) in which it should be run.
68              
69             Returns true if all functions are registered, or C on error.
70              
71             =cut
72              
73             sub register {
74 66     66 1 158 my $class = shift;
75 66         249 while ( @_ ) {
76             # Check the function
77 322         396 my $function = shift;
78             SCOPE: {
79 64     64   419 no strict 'refs';
  64         129  
  64         23884  
  322         343  
80 322 50 33     645 defined $function and defined &{"$function"}
  322         1043  
81             or Carp::croak("Bad function name provided to PPI::Normal");
82             }
83              
84             # Has it already been added?
85 322 100   651   1006 if ( List::Util::any { $_ eq $function } map @{$_}, values %LAYER ) {
  651         873  
  644         1466  
86 1         5 return 1;
87             }
88              
89             # Check the layer to add it to
90 321         723 my $layer = shift;
91 321 50 33     1286 defined $layer and $layer =~ /^(?:1|2)$/
92             or Carp::croak("Bad layer provided to PPI::Normal");
93              
94             # Add to the layer data store
95 321         370 push @{ $LAYER{$layer} }, $function;
  321         807  
96             }
97              
98 65         261 1;
99             }
100              
101              
102              
103              
104              
105             #####################################################################
106             # Constructor and Accessors
107              
108             =pod
109              
110             =head2 new
111              
112             my $level_1 = PPI::Normal->new;
113             my $level_2 = PPI::Normal->new(2);
114              
115             Creates a new normalization object, to which Document objects
116             can be passed to be normalized.
117              
118             Of course, what you probably REALLY want is just to call
119             L's C method.
120              
121             Takes an optional single parameter of the normalisation layer
122             to use, which at this time can be either "1" or "2".
123              
124             Returns a new C object, or C on error.
125              
126             =cut
127              
128             sub new {
129 15     15 1 1061 my $class = shift;
130 15 100 100     90 my $layer = @_ ?
    100          
131             (defined $_[0] and ! ref $_[0] and $_[0] =~ /^[12]$/) ? shift : return undef
132             : 1;
133              
134             # Create the object
135 9         22 my $object = bless {
136             layer => $layer,
137             }, $class;
138              
139 9         17 $object;
140             }
141              
142             =pod
143              
144             =head1 layer
145              
146             The C accessor returns the normalisation layer of the object.
147              
148             =cut
149              
150 14     14 0 1586 sub layer { $_[0]->{layer} }
151              
152              
153              
154              
155              
156             #####################################################################
157             # Main Methods
158              
159             =pod
160              
161             =head2 process
162              
163             The C method takes anything that can be converted to a
164             L (object, SCALAR ref, filename), loads it and
165             applies the normalisation process to the document.
166              
167             Returns a L object, or C on error.
168              
169             =cut
170              
171             sub process {
172 11 100   11 1 303 my $self = ref $_[0] ? shift : shift->new;
173              
174             # PPI::Normal objects are reusable, but not re-entrant
175 11 50       53 return undef if $self->{Document};
176              
177             # Get or create the document
178 11 50       29 $self->{Document} = _Document(shift) or return undef;
179              
180             # Work out what functions we need to call
181 11         42 my @functions = map { @{ $LAYER{$_} } } ( 1 .. $self->layer );
  15         15  
  15         71  
182              
183             # Execute each function
184 11         24 foreach my $function ( @functions ) {
185 64     64   440 no strict 'refs';
  64         119  
  64         8208  
186 34         46 &{"$function"}( $self->{Document} );
  34         119  
187             }
188              
189             # Create the normalized Document object
190             my $Normalized = PPI::Document::Normalized->new(
191             Document => $self->{Document},
192 11 50       95 version => __PACKAGE__->VERSION,
193             functions => \@functions,
194             ) or return undef;
195              
196             # Done, clean up
197 11         26 delete $self->{Document};
198 11         30 return $Normalized;
199             }
200              
201             1;
202              
203             =pod
204              
205             =head1 NOTES
206              
207             The following normalisation layers are implemented. When writing
208             plugins, you should register each transformation function with the
209             appropriate layer.
210              
211             =head2 Layer 1 - Insignificant Data Removal
212              
213             The basic step common to all normalization, layer 1 scans through the
214             Document and removes all whitespace, comments, POD, and anything else
215             that returns false for its C method.
216              
217             It also checks each Element and removes known-useless sub-element
218             metadata such as the Element's physical position in the file.
219              
220             =head2 Layer 2 - Significant Element Removal
221              
222             After the removal of the insignificant data, Layer 2 removed larger, more
223             complex, and superficially "significant" elements, that can be removed
224             for the purposes of normalisation.
225              
226             Examples from this layer include pragmas, now-useless statement
227             separators (since the PDOM tree is holding statement elements), and
228             several other minor bits and pieces.
229              
230             =head2 Layer 3 - TO BE COMPLETED
231              
232             This version of the forward-port of the Perl::Compare functionality
233             to the 0.900+ API of PPI only implements Layer 1 and 2 at this time.
234              
235             =head1 TO DO
236              
237             - Write the other 4-5 layers :)
238              
239             =head1 SUPPORT
240              
241             See the L in the main module.
242              
243             =head1 AUTHOR
244              
245             Adam Kennedy Eadamk@cpan.orgE
246              
247             =head1 COPYRIGHT
248              
249             Copyright 2005 - 2011 Adam Kennedy.
250              
251             This program is free software; you can redistribute
252             it and/or modify it under the same terms as Perl itself.
253              
254             The full text of the license can be found in the
255             LICENSE file included with this module.
256              
257             =cut