File Coverage

blib/lib/FileCache/Appender.pm
Criterion Covered Total %
statement 31 36 86.1
branch 11 12 91.6
condition 2 5 40.0
subroutine 6 7 85.7
pod 3 3 100.0
total 53 63 84.1


line stmt bran cond sub pod time code
1             package FileCache::Appender;
2 2     2   105916 use strict;
  2         4  
  2         67  
3 2     2   11 use warnings;
  2         4  
  2         91  
4             our $VERSION = "0.03";
5             $VERSION = eval $VERSION;
6              
7 2     2   10 use Carp;
  2         7  
  2         159  
8 2     2   2440 use Path::Tiny;
  2         37444  
  2         706  
9              
10             =head1 NAME
11              
12             FileCache::Appender - cache file handles opened for appending
13              
14             =head1 VERSION
15              
16             This document describes FileCache::Appender version 0.03
17              
18             =head1 SYNOPSIS
19              
20             use FileCache::Appender;
21             # returns cached file handle, or opens file for appending
22             my $fh = FileCache::Appender->file($path);
23              
24             =head1 DESCRIPTION
25              
26             Caches file handles opened for appending. Helps to reduce number of I/O operations if you are appending data to many files.
27              
28             =head1 METHODS
29              
30             =cut
31              
32             my $global;
33              
34             =head2 $class->new(%args)
35              
36             Creates a new object. The following parameters are allowed:
37              
38             =over 4
39              
40             =item B
41              
42             maximum number of file handles to cache. If cache reaches this size, each time
43             you requesting a new file handle, one of the existing will be removed from the
44             cache.
45              
46             =item B
47              
48             if directory in which file should be opened doesn't exist, create it
49              
50             =back
51              
52             =cut
53              
54             sub new {
55 2     2 1 22946 my ( $class, %args ) = @_;
56 2         6 $args{_fd_cache} = {};
57 2         6 $args{_open_count} = 0;
58 2   100     11 $args{max_open} ||= 512;
59 2         8 return bless \%args, $class;
60             }
61              
62             =head2 $self->file($path)
63              
64             returns file handle for the file specified by I<$path>. If file handle for the
65             file is not in the cache, will open file for appending and cache file handle.
66              
67             =cut
68              
69             sub file {
70 16     16 1 6969 my ( $self, $path ) = @_;
71 16         35 $path = path($path)->absolute;
72 16 50       593 unless ( ref $self ) {
73 0   0     0 $self = $global ||= $self->new;
74             }
75 16         33 my $cache = $self->{_fd_cache};
76 16 100       41 unless ( $cache->{$path} ) {
77 12 100       69 if ( $self->{_open_count} == $self->{max_open} ) {
78 8         118 delete $cache->{ ( keys %$cache )[ rand $self->{_open_count}-- ] };
79             }
80 12 100       31 if ( $self->{mkpath} ) {
81 2         8 my $dir = path( $path->dirname );
82 2 100       57 $dir->exists or $dir->mkpath;
83             }
84 12 100       525 open my $fd, ">>", $path or croak "Couldn't open $path: $!";
85 11         648 $self->{_open_count}++;
86 11         27 $cache->{$path} = $fd;
87             }
88 15         1014 return $cache->{$path};
89             }
90              
91             =head2 $self->clear
92              
93             clear the cache
94              
95             =cut
96              
97             sub clear {
98 0     0 1   my $self = shift;
99 0           $self->{_fd_cache} = {};
100 0           $self->{_open_count} = 0;
101 0           return;
102             }
103              
104             1;
105              
106             __END__