File Coverage

blib/lib/File/Stamped.pm
Criterion Covered Total %
statement 87 99 87.8
branch 27 48 56.2
condition 12 24 50.0
subroutine 21 21 100.0
pod 3 3 100.0
total 150 195 76.9


line stmt bran cond sub pod time code
1             package File::Stamped;
2 7     7   736680 use strict;
  7         16  
  7         333  
3 7     7   39 use warnings;
  7         14  
  7         213  
4 7     7   178 use 5.008001;
  7         30  
  7         333  
5             our $VERSION = '0.08';
6 7     7   42 use Carp ();
  7         25  
  7         167  
7 7     7   11120 use POSIX ();
  7         146212  
  7         209  
8 7     7   1024 use SelectSaver ();
  7         4846  
  7         121  
9 7     7   39 use File::Path ();
  7         12  
  7         106  
10 7     7   39 use File::Basename ();
  7         12  
  7         26974  
11              
12             sub new {
13 6     6 1 5372 my $class = shift;
14 6 50       51 my %args = @_==1?%{$_[0]}:@_;
  0         0  
15 6 50 66     68 if (exists($args{pattern}) && exists($args{callback})) {
16 0         0 Carp::croak "Both 'pattern' and 'callback' cannot be specified.";
17             }
18 6 50 66     63 unless (exists($args{pattern}) || exists($args{callback})) {
19 0         0 Carp::croak "You need to specify 'pattern' or 'callback'.";
20             }
21 6 50 66     77 if (defined $args{symlink} && ! -l $args{symlink} && -e _) {
      66        
22 0         0 Carp::croak "File '$args{symlink}' already exists (not a symlink)";
23             }
24 6   66     69 my $callback = delete($args{callback}) || _make_callback_from_pattern(delete($args{pattern}));
25 6         15 my $self = bless \do { local *FH }, $class;
  6         73  
26 6         87 tie *$self, $class, $self;
27 6         69 %args = (
28             autoflush => 1,
29             close_after_write => 1,
30             iomode => '>>:utf8',
31             rotationtime => 1,
32             callback => $callback,
33             auto_make_dir => 0,
34             %args,
35             );
36 6         30 for my $k (keys %args) {
37 37         113 *$self->{$k} = $args{$k};
38             }
39 6         410 return $self;
40             }
41              
42             sub TIEHANDLE {
43             (
44 6 50 33 6   85 ( defined( $_[1] ) && UNIVERSAL::isa( $_[1], __PACKAGE__ ) )
45             ? $_[1]
46             : shift->new(@_)
47             );
48             }
49              
50 4     4   68 sub PRINT { shift->print(@_) }
51              
52 3     3   40 sub WRITE { shift->syswrite(@_) }
53              
54             sub _gen_filename {
55 14     14   3000981 my $self = shift;
56 14         68 return *$self->{callback}->(*$self);
57             }
58              
59             sub _make_callback_from_pattern {
60 5     5   87 my ($pattern) = shift;
61              
62             return sub {
63 12     12   26 my $self = shift;
64 12         46 my $time = time();
65 12 50       59 if ( $time > 1 ) {
66 12         33 $time = $time - $time % $self->{rotationtime};
67             }
68 12         2185 return POSIX::strftime($pattern, localtime($time));
69 5         49 };
70             }
71              
72             sub _gen_symlink {
73 12     12   49 my ($self, $fname) = @_;
74              
75 12 100       63 if (defined(my $symlink = *$self->{symlink})) {
76 2 100       31 if (-l $symlink) {
77 1         15 my $link = readlink $symlink;
78 1 50 33     12 if (defined $link && $link ne $fname) {
79 0         0 unlink $symlink;
80             }
81             }
82 2         50 symlink $fname, $symlink;
83             }
84             }
85              
86             sub _output {
87 12     12   38 my ($self, $callback) = @_;
88              
89 12         47 my $fname = $self->_gen_filename();
90 12 100       433 if (*$self->{auto_make_dir}) {
91 2         376 File::Path::make_path(File::Basename::dirname($fname));
92             }
93 12         26 my $fh;
94 12 50       43 if (*$self->{fh}) {
95 0 0 0     0 if ($fname eq *$self->{fname} && *$self->{pid}==$$) {
96 0         0 $fh = delete *$self->{fh};
97             } else {
98 0         0 my $fh = delete *$self->{fh};
99 0 0       0 close $fh if $fh;
100             }
101             }
102              
103 12         62 $fh = $callback->($fh, $fname);
104              
105 12 50       46 if (*$self->{close_after_write}) {
106 12         174 close $fh;
107             } else {
108 0         0 *$self->{fh} = $fh;
109 0         0 *$self->{fname} = $fname;
110 0         0 *$self->{pid} = $$;
111             }
112             }
113              
114             sub print {
115 8     8 1 35 my $self = shift;
116              
117 8         18 my @msg = @_;
118              
119             $self->_output(sub {
120 8     8   67 my ($fh, $fname) = @_;
121 8 50       26 unless ($fh) {
122 8 50       576 open $fh, *$self->{iomode}, $fname or die "Cannot open file($fname): $!";
123 8 50       39 if (*$self->{autoflush}) {
124 8         61 my $saver = SelectSaver->new($fh);
125 8         213 $|=1;
126             }
127 8         197 $self->_gen_symlink($fname);
128             }
129 8 50       12 print {$fh} @msg
  8         653  
130             or die "Cannot write to $fname: $!";
131              
132 8         22 $fh;
133 8         61 });
134             }
135              
136             sub syswrite {
137 4     4 1 11 my $self = shift;
138              
139 4         9 my ($buf, @args) = @_;
140              
141             $self->_output(sub {
142 4     4   32 my ($fh, $fname) = @_;
143 4 50       11 unless ($fh) {
144 4 50       214 open $fh, *$self->{iomode}, $fname or die "Cannot open file($fname): $!";
145 4         14 $self->_gen_symlink($fname);
146             }
147 4 50       106 my $res = @args == 0 ? CORE::syswrite($fh, $buf)
    100          
    100          
148             : @args == 1 ? CORE::syswrite($fh, $buf, $args[0])
149             : @args == 2 ? CORE::syswrite($fh, $buf, $args[0], $args[1])
150             : Carp::croak 'Too many arguments for syswrite';
151 4 50       12 die "Cannot write to $fname: $!" unless $res;
152              
153 4         8 $fh;
154 4         101 });
155             }
156              
157             1;
158             __END__