File Coverage

blib/lib/Dist/Zilla/Plugin/Munge/Whitespace.pm
Criterion Covered Total %
statement 17 64 26.5
branch 0 14 0.0
condition 0 6 0.0
subroutine 6 14 42.8
pod 0 2 0.0
total 23 100 23.0


line stmt bran cond sub pod time code
1 1     1   393 use 5.006; # our
  1         2  
2 1     1   3 use strict;
  1         1  
  1         19  
3 1     1   12 use warnings;
  1         1  
  1         64  
4              
5             package Dist::Zilla::Plugin::Munge::Whitespace;
6              
7             our $VERSION = '0.001001';
8              
9             # ABSTRACT: Strip superfluous spaces from pesky files.
10              
11             our $AUTHORITY = 'cpan:KENTNL'; # AUTHORITY
12              
13 1     1   443 use Moose qw( has with around );
  1         317612  
  1         6  
14 1     1   4786 use Dist::Zilla::Role::FileMunger 1.000; # munge_file
  1         30151  
  1         301  
15              
16             with 'Dist::Zilla::Role::FileMunger';
17              
18             has 'preserve_trailing' => ( is => 'ro', isa => 'Bool', lazy => 1, default => sub { undef } );
19             has 'preserve_cr' => ( is => 'ro', isa => 'Bool', lazy => 1, default => sub { undef } );
20             has 'filename' => ( is => 'ro', isa => 'ArrayRef', lazy => 1, default => sub { [] } );
21             has 'match' => ( is => 'ro', isa => 'ArrayRef', lazy => 1, default => sub { [] } );
22              
23             has '_match_expr' => ( is => 'ro', isa => 'RegexpRef', lazy_build => 1 );
24             has '_eol_kill_expr' => ( is => 'ro', isa => 'RegexpRef', lazy_build => 1 );
25              
26             around dump_config => sub {
27             my ( $orig, $self, @args ) = @_;
28             my $config = $self->$orig(@args);
29             my $localconf = $config->{ +__PACKAGE__ } = {};
30              
31             for my $attr (qw( preserve_trailing preserve_cr filename match )) {
32             next unless $self->meta->find_attribute_by_name($attr)->has_value($self);
33             $localconf->{$attr} = $self->can($attr)->($self);
34             }
35              
36             $localconf->{ q[$] . __PACKAGE__ . '::VERSION' } = $VERSION
37             unless __PACKAGE__ eq ref $self;
38              
39             return $config;
40             };
41              
42             __PACKAGE__->meta->make_immutable;
43 1     1   10 no Moose;
  1         2  
  1         6  
44              
45              
46              
47              
48              
49              
50              
51 0     0 0   sub mvp_multivalue_args { return qw{ filename match } }
52              
53             sub munge_file {
54 0     0 0   my ( $self, $file ) = @_;
55 0 0         return unless $file->name =~ $self->_match_expr;
56 0 0         if ( $file->isa('Dist::Zilla::File::FromCode') ) {
57 0           return $self->_munge_from_code($file);
58             }
59 0           return $self->_munge_static($file);
60             }
61              
62             sub _build__match_expr {
63 0     0     my ($self) = @_;
64 0           my (@matches) = @{ $self->match };
  0            
65 0 0         if ( scalar @{ $self->filename } ) {
  0            
66 0           unshift @matches, sprintf q[\A(?:%s)\z], join q[|], map { quotemeta } @{ $self->filename };
  0            
  0            
67             }
68 0           my $combined = join q[|], @matches;
69              
70             ## no critic (RegularExpressions::RequireDotMatchAnything)
71             ## no critic (RegularExpressions::RequireLineBoundaryMatching)
72             ## no critic (RegularExpressions::RequireExtendedFormatting)
73              
74 0           return qr/$combined/;
75             }
76              
77             sub _build__eol_kill_expr {
78 0     0     my ($self) = @_;
79              
80             ## no critic (RegularExpressions::RequireDotMatchAnything)
81             ## no critic (RegularExpressions::RequireLineBoundaryMatching)
82             ## no critic (RegularExpressions::RequireExtendedFormatting)
83              
84 0           my $bad_bits = qr//;
85 0           my $end_line;
86 0 0         if ( not $self->preserve_trailing ) {
87              
88             # Add horrible spaces to end
89 0           $bad_bits = qr/[\x{20}\x{09}]+/;
90             }
91 0 0         if ( $self->preserve_cr ) {
92              
93             # preserve CR keeps the CR optional as part of the EOL lookahead.
94 0           $end_line = qr/(?=\x{0D}?\x{0A}|\z)/;
95             }
96             else {
97             # No-preserve CR swallows any CRs directly before the EOL lookahead.
98 0           $end_line = qr/\x{0D}?(?=\x{0A}|\z)/;
99             }
100              
101 0           return qr/${bad_bits}${end_line}/;
102             }
103              
104             sub _munge_string {
105 0     0     my ( $self, $name, $string ) = @_;
106 0           $self->log_debug( [ 'Stripping trailing whitespace from %s', $name ] );
107              
108 0 0 0       if ( $self->preserve_cr and $self->preserve_trailing ) {
109              
110             # Noop, both EOL transformations
111             }
112             else {
113             ## no critic (RegularExpressions::RequireDotMatchAnything)
114             ## no critic (RegularExpressions::RequireLineBoundaryMatching)
115             ## no critic (RegularExpressions::RequireExtendedFormatting)
116              
117 0           my $expr = $self->_eol_kill_expr;
118 0           $string =~ s/$expr//g;
119             }
120 0           return $string;
121             }
122              
123             sub _munge_from_code {
124 0     0     my ( $self, $file ) = @_;
125 0 0 0       if ( $file->can('code_return_type') and 'text' ne $file->code_return_type ) {
126 0           $self->log_debug( [ 'Skipping %s: does not return text', $file->name ] );
127 0           return;
128             }
129 0           $self->log_debug( [ 'Munging FromCode (prep): %s', $file->name ] );
130 0           my $orig_coderef = $file->code();
131             $file->code(
132             sub {
133 0     0     $self->log_debug( [ 'Munging FromCode (write): %s', $file->name ] );
134 0           my $content = $file->$orig_coderef();
135 0           return $self->_munge_string( $file->name, $content );
136             },
137 0           );
138 0           return;
139             }
140              
141             sub _munge_static {
142 0     0     my ( $self, $file ) = @_;
143 0           $self->log_debug( [ 'Munging Static file: %s', $file->name ] );
144 0           my $content = $file->content;
145 0           $file->content( $self->_munge_string( $file->name, $content ) );
146 0           return;
147             }
148              
149             1;
150              
151             __END__
152              
153             =pod
154              
155             =encoding UTF-8
156              
157             =head1 NAME
158              
159             Dist::Zilla::Plugin::Munge::Whitespace - Strip superfluous spaces from pesky files.
160              
161             =head1 VERSION
162              
163             version 0.001001
164              
165             =head1 DESCRIPTION
166              
167             This plugin can be used with Dist::Zilla to remove remove white-space from selected files.
168              
169             In its default mode of operation, it will strip trailing white-space from the selected files in the following forms:
170              
171             =over 4
172              
173             =item * C<0x20>: The literal space character
174              
175             =item * C<0x9>: The literal tab character, otherwise known as C<\t>
176              
177             =item * C<0xD>: The Carriage Return character, otherwise known as C<\r> ( But only immediately before a \n )
178              
179             =back
180              
181             =for comment nobody cares
182              
183             =for Pod::Coverage mvp_multivalue_args munge_file
184              
185             =head1 USAGE
186              
187             [Munge::Whitespace]
188             filename = LICENSE ; *Cough*: https://github.com/Perl-Toolchain-Gang/Software-License/pull/30
189             filename = Changes
190             match = lib/*.pm
191              
192             ; Power User Options
193             ; Note: turning both of these options on at present would be idiotic.
194             ; unless you like applying substituion regex to whole files just to duplicate a string
195             preserve_trailing = 1 ; Don't nom trailing \s and \t
196             preserve_cr = 1 ; Don't turn \r\n into \n
197              
198             Note: This is just a standard munger, and will munge any files it gets told to munge.
199              
200             It will not however write files out anywhere or make your source tree all pretty.
201              
202             It will however scrub the files you have on their way out to your dist, or on their way out
203             to any other plugins you might have, like L<< C<CopyFromRelease>|Dist::Zilla::Plugin::CopyFilesFromRelease >>
204             or L<< C<CopyFromBuild>|Dist::Zilla::Plugin::CopyFilesFromBuild >>, and a smart player can probably combine
205             parts of this with either of those and have their dist automatically cleaned up for them when they run C<dzil build>.
206              
207             They might also enjoy the luxurious benefits of having sensitive white-space accidentally sent to a magical wonderland,
208             which breaks their code, or have a glorious race condition where something important they were working on and hadn't
209             gotten committed to git yet get eaten due to the file on disk getting updated, and their editor dutifully rejoicing
210             and prompting to reload their file, which may make them respond to the pavlovian conditioning to click "OK",
211             followed by much wailing and gnashing of teeth.
212              
213             Please enjoy our quality product, from the team at FootGuns Inc.
214              
215             =head1 TODO
216              
217             =over 4
218              
219             =item * C<finder> support.
220              
221             I figured I could, but C<YKW,FI>.
222              
223             =item * tests
224              
225             Would be useful. But dogfood for now.
226              
227             =item * indentation normalization
228              
229             Sounds like work.
230              
231             =back
232              
233             =head1 AUTHOR
234              
235             Kent Fredric <kentnl@cpan.org>
236              
237             =head1 COPYRIGHT AND LICENSE
238              
239             This software is copyright (c) 2017 by Kent Fredric <kentfredric@gmail.com>.
240              
241             This is free software; you can redistribute it and/or modify it under
242             the same terms as the Perl 5 programming language system itself.
243              
244             =cut