File Coverage

blib/lib/IO/Easy/File.pm
Criterion Covered Total %
statement 132 170 77.6
branch 26 48 54.1
condition 8 14 57.1
subroutine 19 21 90.4
pod 10 10 100.0
total 195 263 74.1


line stmt bran cond sub pod time code
1             package IO::Easy::File;
2              
3 6     6   38 use Class::Easy;
  6         10  
  6         44  
4              
5 6     6   2275 use Encode qw(decode encode perlio_ok is_utf8);
  6         19276  
  6         1027  
6              
7 6     6   35 use Fcntl ':seek';
  6         11  
  6         1159  
8              
9 6     6   46 use File::Spec;
  6         11  
  6         372  
10             our $FS = 'File::Spec';
11              
12 6     6   32 use IO::Easy;
  6         12  
  6         86  
13 6     6   957 use base qw(IO::Easy);
  6         15  
  6         625  
14              
15 6     6   7244 use IO::Dir;
  6         196903  
  6         13808  
16              
17             our $PART = 1 << 20;
18             our $ENC = '';
19              
20             sub _init {
21 5     5   10 my $self = shift;
22            
23 5         28 return $self->_init_layer;
24            
25             }
26              
27             sub type {
28 10     10 1 54 return 'file';
29             }
30              
31             sub enc {
32 16     16 1 838 my $self = shift;
33 16         33 my $enc = shift;
34            
35 16 100 66     339 return $self->{enc} || $ENC
36             unless $enc;
37            
38 1         8 $self->{enc} = $enc;
39 1         5 return $self->_init_layer;
40             }
41              
42             sub _init_layer {
43 12     12   23 my $self = shift;
44            
45 12         38 my $enc = $self->enc;
46            
47 12 100 66     84 if (!defined $enc or $enc eq '') {
48             # binary reading
49 8         30 $self->{layer} = ':raw';
50             } else {
51 4         17 my $enc_ok = perlio_ok ($enc);
52 4 50       2396 unless ($enc_ok) {
53 0         0 warn "selected encoding ($enc) are not perlio savvy";
54 0         0 return undef;
55             }
56 4         16 $self->{layer} = ":encoding($enc)";
57             }
58 12         35 return $self;
59             }
60              
61             sub layer {
62 6     6 1 252 my $self = shift;
63 6         10 my $layer = shift;
64            
65 6         18 $self->_init_layer;
66            
67 6 50       41 return $self->{layer}
68             unless $layer;
69            
70 0         0 my $old_layer = $self->{layer};
71 0         0 $self->{layer} = $layer;
72            
73 0         0 return $old_layer;
74             }
75              
76             sub part {
77 15     15 1 25 my $self = shift;
78 15         23 my $part = shift;
79            
80 15 50 33     127 return $self->{part} || $PART
81             unless $part;
82            
83 0         0 $self->{part} = $part;
84             }
85              
86             sub contents {
87 3     3 1 915 my $self = shift;
88            
89 3         12 my $enc = $self->enc;
90            
91 3         14 my $io_layer = $self->layer;
92            
93 3         4 my $fh;
94 3 50       149 open ($fh, "<$io_layer", $self->{path})
95             || die "cannot open file $self->{path}: $!";
96            
97 3         134 my $contents;
98            
99 3         13 my $part = $self->part;
100 3         5 my $buff;
101            
102 3         112 while (read ($fh, $buff, $part)) {
103 3         93 $contents .= $buff;
104             }
105            
106 3         40 close ($fh);
107            
108 3         20 return $contents;
109             }
110              
111             sub store {
112 11     11 1 34 my $self = shift;
113            
114 11         26 my $fh;
115 11 50       111042 open ($fh, ">:raw", $self->{path})
116             || die "cannot open file $self->{path}: $!";
117            
118             # todo: check for status
119 11         283 print $fh @_;
120            
121 11         239 close $fh;
122            
123 11         67 return 1;
124             }
125              
126             sub store_if_empty {
127 0     0 1 0 my $self = shift;
128 0 0       0 return if -e $self;
129            
130 0         0 $self->store (@_);
131             }
132              
133             sub move {
134 0     0 1 0 my $self = shift;
135 0         0 my $to = shift;
136            
137             # rename function is highly dependent on os, don't rely on it
138 0         0 my $from_file = $self->path;
139 0         0 my $to_file = $to;
140 0 0       0 $to_file = $to->path
141             if ref $to eq 'IO::Easy::File';
142            
143 0 0       0 $to_file = $FS->join($to->path, $self->file_name)
144             if ref $to eq 'IO::Easy::Dir';
145            
146 0         0 $to = IO::Easy::File->new ($to_file);
147            
148 0         0 $to->dir_path->create; # create dir if necessary
149            
150 0         0 print 'move from: ', $from_file, ' to: ', $to_file, "\n";
151            
152 0 0       0 unless (open (IN, $from_file)) {
153 0         0 warn "can't open $from_file: $!";
154 0         0 return;
155             }
156 0 0       0 unless (open (OUT, '>', $to_file)) {
157 0         0 warn "can't open $to_file: $!";
158 0         0 return;
159             }
160              
161 0         0 binmode(IN);
162 0         0 binmode(OUT);
163            
164 0         0 my $buff;
165            
166 0         0 my $part = $self->part;
167            
168             # TODO: async
169            
170 0         0 while (read(IN, $buff, $part)) {
171 0         0 print OUT $buff;
172             }
173            
174 0         0 close IN;
175 0         0 close OUT;
176            
177 0         0 unlink $from_file;
178            
179 0         0 $self->{path} = $to_file;
180            
181             }
182              
183             sub string_reader {
184 12     12 1 50661 my $self = shift;
185 12         25 my $sub = shift;
186 12         50 my %params = @_;
187            
188             # because we can't seek in characters
189 12         17 my $fh;
190 12 50       903 open ($fh, '<:raw', $self->{path}) or return;
191              
192 12         33 my $seek_pos = 0;
193 12 100       122 if ($params{reverse}) {
194 6 50       73 if (seek ($fh, 0, SEEK_END)) {
195 6         17 $seek_pos = tell ($fh);
196             } else {
197 0         0 return;
198             }
199             }
200            
201 12         64 my $buffer_size = $self->part;
202            
203 12         27 my $remains = '';
204 12         13 my $buffer;
205 12         16 my $read_cnt = 0;
206            
207 12         19 my $c = 10;
208            
209 12 100       37 if ($params{reverse}) {
210 6         14 do {
211 6         12 $seek_pos -= $buffer_size;
212 6 50       24 $seek_pos = 0
213             if $seek_pos < 0;
214              
215 6         33 seek ($fh, $seek_pos, SEEK_SET);
216 6         503 $read_cnt = read ($fh, $buffer, $buffer_size);
217              
218 6         4758 my @lines = split /^/, $buffer . 'aaa';
219            
220 6 50       569 if ($lines[$#lines] eq 'aaa') {
221 6         19 $lines[$#lines] = '';
222             } else {
223 0         0 $lines[$#lines] =~ s/aaa$//s;
224             }
225            
226 6         21 $lines[$#lines] = $lines[$#lines] . $remains;
227 6         15 $remains = shift @lines;
228            
229 6         30 for (my $i = $#lines; $i >= 0; $i--) {
230 18432         107775 chomp $lines[$i];
231 18432         30691 &$sub ($lines[$i]);
232             }
233            
234             } while $seek_pos > 0;
235             } else {
236 6         14 do {
237             # seek ($fh, $seek_pos, SEEK_SET);
238 6         203 $read_cnt = read ($fh, $buffer, $buffer_size);
239            
240 6         14 $seek_pos += $buffer_size;
241            
242 6         5237 my @lines = split /^/, $buffer . 'aaa';
243            
244 6 50       609 if ($lines[$#lines] eq 'aaa') {
245 6         15 $lines[$#lines] = '';
246             } else {
247 0         0 $lines[$#lines] =~ s/aaa$//s;
248             }
249            
250 6         16 $lines[0] = $remains . $lines[0];
251 6         12 $remains = pop @lines;
252            
253 6         19 foreach my $line (@lines) {
254 18432         64955 chomp $line;
255 18432         32801 &$sub ($line);
256             }
257            
258             } while $read_cnt == $buffer_size;
259            
260             }
261            
262 12         2803 chomp $remains;
263 12         46 &$sub ($remains);
264              
265             # @{$lines_ref} = ( $self->{'sep_is_regex'} ) ?
266             # $text =~ /(.*?$self->{'rec_sep'}|.+)/gs :
267             # $text =~ /(.*?\Q$self->{'rec_sep'}\E|.+)/gs ;
268              
269             }
270              
271             sub __data__files {
272            
273 4     4   2370 my ($caller) = caller;
274 4   50     13 $caller ||= '';
275            
276 6     6   70 no strict 'refs';
  6         14  
  6         3407  
277            
278 4         6 my $fh = *{"${caller}::DATA"}{IO};
  4         16  
279 4 100 66     16 if (@_ and defined *{$_[0]}{IO}) {
  4         31  
280 2         3 $fh = *{$_[0]}{IO};
  2         7  
281             }
282            
283 4         14 local $/;
284 4         6 my $buf;
285             my $data_position;
286 4         479 eval "\$data_position = tell (\$fh); \$buf = <\$fh>; seek (\$fh, \$data_position, 0);";
287            
288 4         594 my @files = split /\s*#+\s+#*\s*(?=IO::Easy)/s, $buf;
289            
290 4         9 my $response = {};
291            
292 4         10 foreach my $contents (@files) {
293            
294 12         49 my ($key, $value) = split (/\s+#+\s+/, $contents, 2);
295            
296 12 100       30 next unless defined $key;
297            
298 8         40 $key =~ s/IO::Easy(?:::File)?\s+//;
299            
300 8         30 $response->{$key} = $value;
301             }
302            
303 4         24 return $response;
304             }
305              
306              
307             sub touch {
308 9     9 1 2000232 my $self = shift;
309            
310 9 100       432 if(-e $self->{path})
311             {
312 3 50       12 if(-f _)
313             {
314 3         6 my $t = time;
315            
316 3 50       230032 die "can't utime $self->{path}: $!"
317             unless utime $t, $t, $self->{path};
318             }
319             else
320             {
321 0         0 warn "not a file: $self->{path}\n";
322             }
323             }
324             else
325             {
326 6         40 $self->store;
327             }
328              
329 9         36 return 1;
330             }
331              
332              
333             1;
334              
335             =head1 NAME
336              
337             IO::Easy::File - IO::Easy child class for operations with files.
338              
339             =head1 METHODS
340              
341             =head2 contents, path, extension, dir_path
342              
343             my $io = IO::Easy->new ('.');
344             my $file = $io->append('example.txt')->as_file;
345             print $file->contents; # prints file content
346             print $file->path; # prints file path, in this example it's './example.txt'
347              
348             =cut
349              
350             =head2 store, store_if_empty
351              
352             IO::Easy::File has 2 methods for saving file: store and store_if_empty
353              
354             my $io = IO::Easy->new ('.');
355             my $file = $io->append('example.txt')->as_file;
356             my $content = "Some text goes here";
357              
358             $file->store($content); # saves the variable $content to file
359              
360             $file->store_if_empty ($content); # saves the variable $content to file, only
361             # if there's no such a file existing.
362              
363             =cut
364              
365             =head2 string_reader
366              
367             read strings from file in normal or reverse order
368              
369             $io->string_reader (sub {
370             my $s = shift;
371              
372             print $s;
373             });
374              
375             read from file end
376              
377             $io->string_reader (sub {
378             my $s = shift;
379              
380             print $s;
381             }, reverse => 1);
382              
383             =cut
384              
385             =head2 __data__files
386              
387             parse __DATA__ section and return hash of file contents encoded as:
388              
389             __DATA__
390              
391             ########################
392             # IO::Easy file1
393             ########################
394              
395             FILE1 CONTENTS
396              
397             ########################
398             # IO::Easy file2
399             ########################
400              
401             FILE2 CONTENTS
402              
403             returns
404              
405             {
406             file1 => 'FILE1 CONTENTS',
407             file2 => 'FILE2 CONTENTS',
408             }
409              
410             =cut
411              
412             =head2 enc
413              
414             file encoding for reading and writing files. by default '', which is :raw for
415             PerlIO. you can redefine it by providing supported encoding, as example utf-8 or ascii
416              
417             =cut
418              
419             =head2 layer
420              
421             PerlIO layer name for reading and writing files. you can redefine it by providing argument
422              
423             =cut
424              
425             =head2 part
426              
427             chunk size for file reading, storing and moving
428              
429             =cut
430              
431             =head2 move
432              
433             moving file to another path
434              
435             =cut
436              
437             =head2 type
438              
439             always 'file'
440              
441             =head2 touch
442              
443             similar to unix touch command - updates file timestamp
444              
445             =cut
446              
447             =head1 AUTHOR
448              
449             Ivan Baktsheev, C<< >>
450              
451             =head1 BUGS
452              
453             Please report any bugs or feature requests to my email address,
454             or through the web interface at L.
455             I will be notified, and then you'll automatically be notified
456             of progress on your bug as I make changes.
457              
458             =head1 SUPPORT
459              
460              
461              
462             =head1 ACKNOWLEDGEMENTS
463              
464              
465              
466             =head1 COPYRIGHT & LICENSE
467              
468             Copyright 2007-2009 Ivan Baktsheev
469              
470             This program is free software; you can redistribute it and/or modify it
471             under the same terms as Perl itself.
472              
473              
474             =cut
475              
476             __DATA__