File Coverage

blib/lib/App/Pods2Site/Util.pm
Criterion Covered Total %
statement 70 94 74.4
branch 12 38 31.5
condition 7 16 43.7
subroutine 15 17 88.2
pod 0 8 0.0
total 104 173 60.1


line stmt bran cond sub pod time code
1             package App::Pods2Site::Util;
2            
3 2     2   12 use strict;
  2         2  
  2         45  
4 2     2   8 use warnings;
  2         3  
  2         191  
5            
6             our $VERSION = '1.003';
7             my $version = $VERSION;
8             $VERSION = eval $VERSION;
9            
10             our $IS_WINDOWS = $^O eq 'MSWin32';
11             our $IS_PACKED = $ENV{PAR_0} ? 1 : 0;
12             our $SHELL_ARG_DELIM = $IS_WINDOWS ? '"' : "'";
13             our $PATH_SEP = $IS_WINDOWS ? ';' : ':';
14            
15 2     2   17 use Exporter qw(import);
  2         4  
  2         102  
16             our @EXPORT_OK =
17             qw
18             (
19             $IS_WINDOWS
20             $IS_PACKED
21             $SHELL_ARG_DELIM
22             $PATH_SEP
23             slashify
24             trim
25             readData
26             writeData
27             createSpinner
28             writeUTF8File
29             readUTF8File
30             expandAts
31             );
32            
33 2     2   1126 use JSON;
  2         21857  
  2         11  
34 2     2   244 use File::Basename;
  2         4  
  2         1611  
35            
36             my $FILE_SEP = $IS_WINDOWS ? '\\' : '/';
37             my $DATAFILE = '.pods2site';
38             my $JSON = JSON->new()->utf8()->pretty()->canonical();
39             my @SPINNERPOSITIONS = ('|', '/', '-', '\\', '-');
40            
41             # pass in a path and ensure it contains the native form of slash vs backslash
42             # (or force either one)
43             #
44             sub slashify
45             {
46 96     96 0 1574 my $s = shift;
47 96   66     349 my $fsep = shift || $FILE_SEP;
48            
49 96         281 my $dblStart = $s =~ s#^[\\/]{2}##;
50 96         493 $s =~ s#[/\\]+#$fsep#g;
51            
52 96 50       429 return $dblStart ? "$fsep$fsep$s" : $s;
53             }
54            
55             # trim off any ws at front/end of a string
56             #
57             sub trim
58             {
59 12     12 0 27 my $s = shift;
60            
61 12 50       66 $s =~ s/^\s+|\s+$//g if defined($s);
62            
63 12         35 return $s;
64             }
65            
66             sub writeData
67             {
68 5     5 0 14 my $dir = shift;
69 5         28 my $section = shift;
70 5         20 my $data = shift;
71            
72 5   100     14 my $allData = readData($dir) || {};
73 5         59 $allData->{$section} = $data;
74            
75 5         23 my $df = slashify("$dir/$DATAFILE");
76 5 50       250 open (my $fh, '> :raw :bytes', $df) or die("Failed to open '$df': $!\n");
77 5         141 print $fh $JSON->encode($allData);
78 5         211 close($fh);
79             }
80            
81             sub readData
82             {
83 9     9 0 19 my $dir = shift;
84 9         23 my $section = shift;
85            
86 9         13 my $data;
87            
88 9         38 my $df = slashify("$dir/$DATAFILE");
89 9 100       118 if (-f $df)
90             {
91 5 50       203 open (my $fh, '< :raw :bytes', $df) or die("Failed to open '$df': $!\n");
92 5         11 my $buf;
93 5         122 my $szExpected = -s $df;
94 5         97 my $szRead = read($fh, $buf, -s $df);
95 5 50 33     57 die("Failed to read from '$df': $!\n") unless ($szRead && $szRead == $szExpected);
96 5         38 close($fh);
97 5         113 $data = $JSON->decode($buf);
98 5 100       31 $data = $data->{$section} if $section;
99             }
100            
101 9         59 return $data;
102             }
103            
104             sub createSpinner
105             {
106 9     9 0 16 my $args = shift;
107            
108 9     35   49 my $spinner = sub {};
109 9 0 33     65 if (-t STDOUT && $args->isVerboseLevel(0) && !$args->isVerboseLevel(2))
      33        
110             {
111 0         0 my $pos = 0;
112             $spinner = sub
113             {
114 0   0 0   0 my $v = shift || '';
115 0         0 print " $SPINNERPOSITIONS[$pos++] $v\r";
116 0 0       0 $pos = 0 if $pos > $#SPINNERPOSITIONS;
117 0         0 };
118             }
119            
120 9         28 return $spinner;
121             }
122            
123             sub writeUTF8File
124             {
125 21     21 0 33 my $file = shift;
126 21         27 my $data = shift;
127            
128 21 50   1   1282 open (my $fh, '> :encoding(UTF-8)', $file) or die("Failed to open '$file': $!\n");
  1         15  
  1         8  
  1         21  
129 21         3230 print $fh $data;
130 21         1158 close($fh);
131             }
132            
133             sub readUTF8File
134             {
135 3     3 0 8 my $file = shift;
136            
137 3 50       99 open (my $fh, '< :encoding(UTF-8)', $file) or die("Failed to open '$file': $!\n");
138 3         290 local $/ = undef;
139 3         101 my $data = <$fh>;
140 3         76 close($fh);
141            
142 3         32 return $data;
143             }
144            
145             # expand any array elements using '@xyz' as new line elements read from 'xyz'
146             # also, handle recursion where included files itself refers to further files
147             # possibly using relative paths
148             #
149             sub expandAts
150             {
151 3     3 0 7 my $dirctx = shift;
152            
153 3         7 my @a;
154 3         16 foreach my $e (@_)
155             {
156 19 50       35 if ($e =~ /^@(.+)/)
157             {
158             # if we find a filename use as-if its absolute, otherwise tack on
159             # the current dir context
160             #
161 0         0 my $fn = $1;
162 0 0       0 $fn = File::Spec->file_name_is_absolute($fn) ? $fn : "$dirctx/$fn";
163            
164             # recursively read file contents into the array
165             # using the current files directory as the new dir context
166             #
167 0         0 push(@a, expandAts(dirname($fn), __readLines($fn)))
168             }
169             else
170             {
171             # just keep the value as-is
172             #
173 19         28 push(@a, $e);
174             }
175             }
176 3         14 return @a;
177             }
178            
179             # read all lines from a file and return as an array
180             # supports line continuation, e.g. a line with '\' at the end causes
181             # appending the line after etc, in order to create a single line.
182             # - a line starting with '#' will be ignored as a comment
183             # - all lines will be trimmed from space at each end
184             # - an empty line will be ignored
185             #
186             sub __readLines
187             {
188 0     0   0 my $fn = slashify(File::Spec->rel2abs(shift()));
189            
190 0 0       0 die("No such file: '$fn'\n") unless -f $fn;
191            
192 0         0 my @lines;
193 0 0       0 open (my $fh, '<', $fn) or die("Failed to open '$fn': $!\n");
194 0         0 my $line;
195 0         0 while (defined($line = <$fh>))
196             {
197 0         0 chomp($line);
198            
199             # handle lines with line continuation
200             # until no more continuation is found
201             #
202 0 0       0 if ($line =~ s#\\\s*$##)
203             {
204             # append lines...
205             #
206 0         0 $line .= <$fh>;
207            
208             # ...and repeat, unless we hit eof
209             #
210 0 0       0 redo unless eof($fh);
211             }
212            
213             # if the resulting line is a comment line, ignore it
214             #
215 0 0       0 if ($line !~ /^\s*#/)
216             {
217             # ensure removing any trailing line continuation is removed
218             # (can happen if there is no extra line after a line continuation, just eof)
219             #
220 0         0 $line =~ s#\\\s*$##;
221            
222             # trim the ends, and add it - but only if it's not empty
223             #
224 0         0 $line = trim($line);
225 0 0       0 push(@lines, $line) if $line;
226             }
227             }
228 0         0 close($fh);
229            
230 0         0 return @lines;
231             }
232            
233             1;