File Coverage

blib/lib/Dancer2/FileUtils.pm
Criterion Covered Total %
statement 55 55 100.0
branch 12 14 85.7
condition n/a
subroutine 17 17 100.0
pod 8 9 88.8
total 92 95 96.8


line stmt bran cond sub pod time code
1             # ABSTRACT: File utility helpers
2             $Dancer2::FileUtils::VERSION = '0.400000';
3             use strict;
4 153     153   135972 use warnings;
  153         276  
  153         3945  
5 153     153   678  
  153         294  
  153         3231  
6             use File::Basename ();
7 153     153   708 use File::Spec;
  153         296  
  153         1884  
8 153     153   649 use Carp;
  153         293  
  153         2784  
9 153     153   704  
  153         382  
  153         9127  
10             use Exporter 'import';
11 153     153   957 our @EXPORT_OK = qw(
  153         363  
  153         83869  
12             dirname open_file path read_file_content read_glob_content
13             path_or_empty set_file_mode normalize_path escape_filename
14             );
15              
16              
17             my @parts = @_;
18             my $path = File::Spec->catfile(@parts);
19 15436     15436 1 37558  
20 15436         89551 return normalize_path($path);
21             }
22 15436         32374  
23             my @parts = @_;
24             my $path = path(@parts);
25              
26 2     2 1 2025 # return empty if it doesn't exist
27 2         7 return -e $path ? $path : '';
28             }
29              
30 2 100       28  
31             my $fh = shift;
32             my $charset = 'utf-8';
33 241     241 1 14589 binmode $fh, ":encoding($charset)";
34             return $fh;
35             }
36 82     82 1 181  
37 82         161 my ( $mode, $filename ) = @_;
38 22     22   177  
  22         71  
  22         152  
  82         1543  
39 82         53295 open my $fh, $mode, $filename
40             or croak "Can't open '$filename' using mode '$mode': $!";
41              
42             return set_file_mode($fh);
43 64     64 1 308 }
44              
45 64 100   1   3203 my $file = shift or return;
  1         7  
  1         2  
  1         5  
46             my $fh = open_file( '<', $file );
47              
48 61         1015 return wantarray
49             ? read_glob_content($fh)
50             : scalar read_glob_content($fh);
51             }
52 33 100   33 1 16315  
53 32         97 my $fh = shift;
54              
55             my @content = <$fh>;
56 30 100       126 close $fh;
57              
58             return wantarray ? @content : join '', @content;
59             }
60              
61 31     31 1 45  
62             # this is a revised version of what is described in
63 31         978 # http://www.linuxjournal.com/content/normalizing-path-names-bash
64 31         795 # by Mitch Frazier
65             my $path = shift or return;
66 31 100       313 my $seqregex = qr{
67             [^/]* # anything without a slash
68             /\.\.(/|\z) # that is accompanied by two dots as such
69             }x;
70              
71             $path =~ s{/\./}{/}g;
72             while ( $path =~ s{$seqregex}{} ) {}
73              
74 15445 50   15445 0 31681 #see https://rt.cpan.org/Public/Bug/Display.html?id=80077
75 15445         32647 $path =~ s{^//}{/};
76             return $path;
77             }
78              
79             my $filename = shift or return;
80 15445         26142  
81 15445         53554 # based on escaping used in CHI::Driver. Our use-case is one-way,
82             # so we allow utf8 chars to be escaped, but NEVER do the inverse
83             # operation.
84 15445         20446 $filename =~ s/([^A-Za-z0-9_\=\-\~])/sprintf("+%02x", ord($1))/ge;
85 15445         56262 return $filename;
86             }
87              
88             1;
89 51 50   51 1 2712  
90              
91             =pod
92              
93             =encoding UTF-8
94 51         158  
  12         41  
95 51         279 =head1 NAME
96              
97             Dancer2::FileUtils - File utility helpers
98              
99             =head1 VERSION
100              
101             version 0.400000
102              
103             =head1 SYNOPSIS
104              
105             use Dancer2::FileUtils qw/dirname path path_or_empty/;
106              
107             # for 'path/to/file'
108             my $dir = dirname($path); # returns 'path/to'
109             my $path = path($path); # returns '/abs/path/to/file'
110             my $path = path_or_empty($path); # returns '' if file doesn't exist
111              
112              
113             use Dancer2::FileUtils qw/path read_file_content/;
114              
115             my $content = read_file_content( path( 'folder', 'folder', 'file' ) );
116             my @content = read_file_content( path( 'folder', 'folder', 'file' ) );
117              
118              
119             use Dancer2::FileUtils qw/read_glob_content set_file_mode/;
120              
121             open my $fh, '<', $file or die "$!\n";
122             set_file_mode($fh);
123             my @content = read_glob_content($fh);
124             my $content = read_glob_content($fh);
125              
126              
127             use Dancer2::FileUtils qw/open_file/;
128              
129             my $fh = open_file('<', $file) or die $message;
130              
131              
132             use Dancer2::FileUtils 'set_file_mode';
133              
134             set_file_mode($fh);
135              
136             =head1 DESCRIPTION
137              
138             Dancer2::FileUtils includes a few file related utilities that Dancer2
139             uses internally. Developers may use it instead of writing their own
140             file reading subroutines or using additional modules.
141              
142             =head1 FUNCTIONS
143              
144             =head2 my $path = path( 'folder', 'folder', 'filename');
145              
146             Provides comfortable path resolution, internally using L<File::Spec>. 'path'
147             does not verify paths, it just normalizes the path.
148              
149             =head2 my $path = path_or_empty('folder, 'folder','filename');
150              
151             Like path, but returns '' if path doesn't exist.
152              
153             =head2 dirname
154              
155             use Dancer2::FileUtils 'dirname';
156              
157             my $dir = dirname($path);
158              
159             Exposes L<File::Basename>'s I<dirname>, to allow fetching a directory name from
160             a path. On most OS, returns all but last level of file path. See
161             L<File::Basename> for details.
162              
163             =head2 set_file_mode($fh);
164              
165             use Dancer2::FileUtils 'set_file_mode';
166              
167             set_file_mode($fh);
168              
169             Applies charset setting from Dancer2's configuration. Defaults to utf-8 if no
170             charset setting.
171              
172             =head2 my $fh = open_file('<', $file) or die $message;
173              
174             use Dancer2::FileUtils 'open_file';
175             my $fh = open_file('<', $file) or die $message;
176              
177             Calls open and returns a filehandle. Takes in account the 'charset' setting
178             from Dancer2's configuration to open the file in the proper encoding (or
179             defaults to utf-8 if setting not present).
180              
181             =head2 my $content = read_file_content($file);
182              
183             use Dancer2::FileUtils 'read_file_content';
184              
185             my @content = read_file_content($file);
186             my $content = read_file_content($file);
187              
188             Returns either the content of a file (whose filename is the input), or I<undef>
189             if the file could not be opened.
190              
191             In array context it returns each line (as defined by $/) as a separate element;
192             in scalar context returns the entire contents of the file.
193              
194             =head2 my $content = read_glob_content($fh);
195              
196             use Dancer2::FileUtils 'read_glob_content';
197              
198             open my $fh, '<', $file or die "$!\n";
199             binmode $fh, ':encoding(utf-8)';
200             my @content = read_glob_content($fh);
201             my $content = read_glob_content($fh);
202              
203             Similar to I<read_file_content>, only it accepts a file handle. It is
204             assumed that the appropriate PerlIO layers are applied to the file handle.
205             Returns the content and B<closes the file handle>.
206              
207             =head2 my $norm_path=normalize_path ($path);
208              
209             =head2 my $escaped_filename = escape_filename( $filename );
210              
211             Escapes characters in a filename that may alter a path when concatenated.
212              
213             use Dancer2::FileUtils 'escape_filename';
214              
215             my $safe = escape_filename( "a/../b.txt" ); # a+2f+2e+2e+2fb+2etxt
216              
217             =head1 EXPORT
218              
219             Nothing by default. You can provide a list of subroutines to import.
220              
221             =head1 AUTHOR
222              
223             Dancer Core Developers
224              
225             =head1 COPYRIGHT AND LICENSE
226              
227             This software is copyright (c) 2022 by Alexis Sukrieh.
228              
229             This is free software; you can redistribute it and/or modify it under
230             the same terms as the Perl 5 programming language system itself.
231              
232             =cut