File Coverage

blib/lib/Syntax/Check.pm
Criterion Covered Total %
statement 72 73 98.6
branch 28 38 73.6
condition 4 6 66.6
subroutine 13 14 92.8
pod 2 2 100.0
total 119 133 89.4


line stmt bran cond sub pod time code
1             package Syntax::Check;
2              
3 3     3   392268 use warnings;
  3         23  
  3         105  
4 3     3   17 use strict;
  3         5  
  3         82  
5 3     3   14 use feature 'say';
  3         7  
  3         316  
6              
7 3     3   19 use Carp qw(croak confess);
  3         6  
  3         199  
8 3     3   783 use Data::Dumper;
  3         7107  
  3         166  
9 3     3   18 use Exporter qw(import);
  3         5  
  3         118  
10 3     3   17 use File::Path qw(make_path);
  3         6  
  3         210  
11 3     3   926 use File::Temp qw(tempdir);
  3         24294  
  3         197  
12 3     3   1927 use Module::Installed::Tiny qw(module_installed);
  3         3184  
  3         175  
13 3     3   3239 use PPI;
  3         340951  
  3         2135  
14              
15             our $VERSION = '1.02';
16              
17             sub new {
18 7     7 1 32161 my ($class, %p) = @_;
19              
20 7 100 66     231 if (! exists $p{file} || ! -f $p{file}) {
21 1         208 croak "new() requires a file name as its first parameter";
22             }
23              
24 6         54 my $self = bless {%p}, $class;
25              
26 6         41 return $self;
27             }
28             sub check {
29 6     6 1 33 my ($self) = @_;
30              
31 6         153 my $doc = PPI::Document->new($self->{file});
32              
33 6         36762 my $includes = $doc->find('PPI::Statement::Include');
34              
35 6         7260 for my $include (@$includes) {
36              
37 34         199 my $module = $include->module;
38 34         973 my $package = $module;
39              
40 34 100       99 if ($module eq lc $module) {
41             # Skip pragmas
42 12 100       209 say "Skipping assumed pragma '$module'" if $self->{verbose};
43 12         38 next;
44             }
45              
46 22 50       53 next if $module eq 'Carp';
47 22         146 $module =~ s|::|/|g;
48 22 100       149 if (my ($dir, $file) = $module =~ m|^(.*)/(.*)$|) {
49 20         37 $file .= '.pm';
50 20         45 my $path = "$dir/$file";
51              
52 20 100       82 if (module_installed($package)) {
53             # Skip includes that are actually installed
54 5 100       226 say "Skipping available module '$package'" if $self->{verbose};
55 5         21 next;
56             }
57             else {
58 15         7021 $self->_create_lib_dir;
59              
60 15 50       319 if (! -d "$self->{lib}/$dir") {
61             # Create the module directory structure
62 15 50       2970 make_path("$self->{lib}/$dir") or die $!;
63             }
64              
65 15 50       374 if (! -f "$self->{lib}/$path") {
66             # Create the module file
67 15 50       893 open my $wfh, '>', "$self->{lib}/$path" or die $!;
68 15         127 print $wfh '1;';
69 15 50       520 close $wfh or die $!;
70             }
71             }
72             }
73             else {
74             # Single-word module, ie. no directory structure
75 2         7 $self->_create_lib_dir;
76              
77 2         8 my $module_file = "$module.pm";
78 2 50       48 if (! -f "$self->{lib}/$module_file") {
79             # Create the module file
80 2 50       118 open my $wfh, '>', "$self->{lib}/$module_file" or die $!;
81 2         24 print $wfh '1;';
82 2 50       68 close $wfh or die $!;
83             }
84             }
85             }
86              
87              
88 6 50       39 if (! $self->{lib}) {
89 0         0 `perl -c $self->{file}`;
90             }
91             else {
92 6         150022 `perl -I$self->{lib} -c $self->{file}`;
93             }
94             }
95             sub _create_lib_dir {
96 17     17   41 my ($self) = @_;
97 17 100 66     259 if (! exists $self->{lib} || ! -d $self->{lib}) {
98 6 100       29 $self->{cleanup} = exists $self->{keep} ? ! $self->{keep} : 1;
99 6         25 $self->{lib} = tempdir(CLEANUP => $self->{cleanup});
100 6 100       2754 say "Created temp lib dir '$self->{lib}'" if $self->{verbose};
101             }
102             }
103       0     sub __placeholder {}
104              
105             1;
106             __END__
107              
108             =head1 NAME
109              
110             Syntax::Check - Wraps 'perl -c' so it works even if modules are unavailable
111              
112             =for html
113             <a href="http://travis-ci.org/stevieb9/mock-sub"><img src="https://secure.travis-ci.org/stevieb9/syntax-check.png"/>
114             <a href='https://coveralls.io/github/stevieb9/syntax-check?branch=master'><img src='https://coveralls.io/repos/stevieb9/syntax-check/badge.svg?branch=master&service=github' alt='Coverage Status' /></a>
115              
116              
117             =head1 DESCRIPTION
118              
119             This module is a wrapper around C<perl -c> for situations where you're trying
120             to do a syntax check on a Perl file, but the libraries that are C<use>d by the
121             file are not available to the file.
122              
123             =head1 SYNOPSIS
124              
125             Binary:
126              
127             syncheck [--verbose] [--keep] perl_filename.ext
128              
129             Library:
130              
131             use Syntax::Check;
132              
133             Syntax::Check->new(%opts, $filename)->check;
134              
135             =head1 BINARY PROGRAM syncheck
136              
137             Installed with this library is a binary application that uses the library.
138              
139             Usage:
140              
141             syncheck [-k] [-v] perl_file_name.ext
142              
143             =head2 --keep|-k
144              
145             If supplied, we will keep the temporary library directory structure in your
146             temp dir. By default we delete this directory upon program completion.
147              
148             =head2 --verbose|-v
149              
150             Supply this argument to get verbose output.
151              
152             =head2 perl_file.ext
153              
154             This argument is mandatory, and must follow all others. It's the file you want
155             to perform syntax checking on.
156              
157             =head1 METHODS
158              
159             =head2 new(%p, $file)
160              
161             Instantiates and returns a new C<Syntax::Check> object.
162              
163             Parameters:
164              
165             keep => Bool
166              
167             Optional, Bool. Delete the temporary library directory structure after the run
168             finishes.
169              
170             Default: False
171              
172             verbose => Bool
173              
174             Optional, Bool: Enable verbose output.
175              
176             Default: False
177              
178             $file
179              
180             Mandatory, String: The name of the Perl file to operate on.
181              
182             =head2 check()
183              
184             Performs the introspection of the Perl file we're operating on, hides away the
185             fact that we have library includes that aren't available, and performs a
186             C<perl -c> on the file.
187              
188             =head1 AUTHOR
189              
190             Steve Bertrand, C<< <steveb at cpan.org> >>
191              
192             =head1 LICENSE AND COPYRIGHT
193              
194             Copyright 2020 Steve Bertrand.
195              
196             This program is free software; you can redistribute it and/or modify it
197             under the terms of the the Artistic License (2.0). You may obtain a
198             copy of the full license at:
199              
200             L<http://www.perlfoundation.org/artistic_license_2_0>