| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Data::Tubes::Util::Output; |
|
2
|
3
|
|
|
3
|
|
82678
|
use strict; |
|
|
3
|
|
|
|
|
14
|
|
|
|
3
|
|
|
|
|
146
|
|
|
3
|
3
|
|
|
3
|
|
18
|
use warnings; |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
97
|
|
|
4
|
3
|
|
|
3
|
|
437
|
use English qw< -no_match_vars >; |
|
|
3
|
|
|
|
|
3150
|
|
|
|
3
|
|
|
|
|
18
|
|
|
5
|
3
|
|
|
3
|
|
1105
|
use 5.010; |
|
|
3
|
|
|
|
|
11
|
|
|
6
|
3
|
|
|
3
|
|
18
|
use File::Path qw< make_path >; |
|
|
3
|
|
|
|
|
39
|
|
|
|
3
|
|
|
|
|
207
|
|
|
7
|
3
|
|
|
3
|
|
19
|
use File::Basename qw< dirname >; |
|
|
3
|
|
|
|
|
4
|
|
|
|
3
|
|
|
|
|
277
|
|
|
8
|
|
|
|
|
|
|
our $VERSION = '0.737'; |
|
9
|
|
|
|
|
|
|
|
|
10
|
3
|
|
|
3
|
|
519
|
use Log::Log4perl::Tiny qw< :easy :dead_if_first >; |
|
|
3
|
|
|
|
|
13946
|
|
|
|
3
|
|
|
|
|
22
|
|
|
11
|
3
|
|
|
3
|
|
2408
|
use Mo qw< default >; |
|
|
3
|
|
|
|
|
1519
|
|
|
|
3
|
|
|
|
|
16
|
|
|
12
|
|
|
|
|
|
|
has binmode => (default => ':raw'); |
|
13
|
|
|
|
|
|
|
has footer => (); |
|
14
|
|
|
|
|
|
|
has header => (); |
|
15
|
|
|
|
|
|
|
has interlude => (); |
|
16
|
|
|
|
|
|
|
has output => (default => \*STDOUT); |
|
17
|
|
|
|
|
|
|
has policy => (default => undef); |
|
18
|
|
|
|
|
|
|
has track => ( |
|
19
|
|
|
|
|
|
|
default => sub { |
|
20
|
|
|
|
|
|
|
return { |
|
21
|
|
|
|
|
|
|
files => 0, |
|
22
|
|
|
|
|
|
|
records => 0, |
|
23
|
|
|
|
|
|
|
chars_file => 0, |
|
24
|
|
|
|
|
|
|
chars_total => 0, |
|
25
|
|
|
|
|
|
|
}; |
|
26
|
|
|
|
|
|
|
} |
|
27
|
|
|
|
|
|
|
); |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
sub open { |
|
30
|
31
|
|
|
31
|
1
|
67
|
my ($self, $hint) = @_; |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
# reset some tracking parameters |
|
33
|
31
|
|
|
|
|
61
|
my $track = $self->track(); |
|
34
|
31
|
|
|
|
|
167
|
$track->{files}++; |
|
35
|
31
|
|
|
|
|
47
|
$track->{records} = 0; |
|
36
|
31
|
|
|
|
|
48
|
$track->{chars_file} = 0; |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# get new filehandle |
|
39
|
|
|
|
|
|
|
my ($fh, $fh_releaser) = |
|
40
|
31
|
|
|
|
|
70
|
@{$track}{qw< current_fh current_fh_releaser>} = $self->get_fh($hint); |
|
|
31
|
|
|
|
|
101
|
|
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
# do header handling |
|
43
|
31
|
|
|
|
|
110
|
$self->_print($fh, $self->header(), $track); |
|
44
|
|
|
|
|
|
|
|
|
45
|
31
|
|
|
|
|
98
|
return $fh; |
|
46
|
|
|
|
|
|
|
} ## end sub open |
|
47
|
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
sub __open_file { |
|
49
|
30
|
|
|
30
|
|
241
|
my ($filename, $binmode) = @_; |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# ensure its directory exists |
|
52
|
30
|
|
|
|
|
3027
|
make_path(dirname($filename), {error => \my $errors}); |
|
53
|
30
|
50
|
|
|
|
164
|
if (@$errors) { |
|
54
|
0
|
|
|
|
|
0
|
my ($error) = values %{$errors->[0]}; |
|
|
0
|
|
|
|
|
0
|
|
|
55
|
0
|
|
|
|
|
0
|
LOGCONFESS "make_path() for '$filename': $error"; |
|
56
|
|
|
|
|
|
|
} |
|
57
|
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
# can open the file, at last |
|
59
|
30
|
50
|
|
1
|
|
2478
|
CORE::open my $fh, '>', $filename |
|
|
1
|
|
|
|
|
7
|
|
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
8
|
|
|
60
|
|
|
|
|
|
|
or LOGCONFESS "open('$filename'): $OS_ERROR"; |
|
61
|
30
|
|
|
|
|
1088
|
binmode $fh, $binmode; |
|
62
|
|
|
|
|
|
|
|
|
63
|
30
|
|
|
|
|
1591
|
return $fh; |
|
64
|
|
|
|
|
|
|
} ## end sub __open_file |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
sub get_fh { |
|
67
|
31
|
|
|
31
|
1
|
56
|
my ($self, $handle) = @_; |
|
68
|
31
|
|
33
|
|
|
104
|
$handle //= $self->output(); |
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
# define a default releaser, but not for GLOBs as they have their own |
|
71
|
|
|
|
|
|
|
# life outside of here |
|
72
|
|
|
|
|
|
|
my $releaser = ref($handle) eq 'GLOB' ? undef : sub { |
|
73
|
30
|
50
|
|
30
|
|
1597
|
CORE::close $_[0] or LOGCONFESS "close(): $OS_ERROR"; |
|
74
|
30
|
|
|
|
|
99
|
return undef; |
|
75
|
31
|
100
|
|
|
|
324
|
}; |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
# if $handle is a factory, treat it as such |
|
78
|
31
|
100
|
|
|
|
77
|
if (ref($handle) eq 'CODE') { |
|
79
|
29
|
|
|
|
|
68
|
my @items = $handle->($self); |
|
80
|
29
|
|
|
|
|
63
|
$handle = shift @items; |
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
# override the $releaser if and only if the factory instructed to |
|
83
|
|
|
|
|
|
|
# do so. Otherwise, the default one will be kept. |
|
84
|
29
|
50
|
|
|
|
77
|
$releaser = shift @items if @items; |
|
85
|
|
|
|
|
|
|
} ## end if (ref($handle) eq 'CODE') |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
# now, we either have a filehandle, or a filename |
|
88
|
31
|
100
|
|
|
|
75
|
return ($handle, $releaser) if ref($handle) eq 'GLOB'; |
|
89
|
30
|
|
|
|
|
97
|
return (__open_file($handle, $self->binmode()), $releaser); |
|
90
|
|
|
|
|
|
|
} ## end sub get_fh |
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub release_fh { |
|
93
|
31
|
|
|
31
|
1
|
59
|
my ($self, $fh) = @_; |
|
94
|
31
|
|
|
|
|
60
|
my $track = $self->track(); |
|
95
|
31
|
100
|
|
|
|
174
|
if (my $releaser = delete $track->{current_fh_releaser}) { |
|
96
|
30
|
|
|
|
|
60
|
$releaser->($fh); |
|
97
|
|
|
|
|
|
|
} |
|
98
|
31
|
|
|
|
|
55
|
delete $track->{current_fh}; |
|
99
|
31
|
|
|
|
|
167
|
return undef; |
|
100
|
|
|
|
|
|
|
} ## end sub release_fh |
|
101
|
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
sub close { |
|
103
|
31
|
|
|
31
|
1
|
63
|
my ($self, $fh, $track) = @_; |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
# do footer handling |
|
106
|
31
|
|
|
|
|
79
|
$self->_print($fh, $self->footer(), $track); |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
# call close, prepare $fh for other possible records |
|
109
|
31
|
|
|
|
|
72
|
return $self->release_fh($fh); |
|
110
|
|
|
|
|
|
|
} ## end sub close |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
sub just_close { |
|
113
|
18
|
|
|
18
|
1
|
32
|
my $self = shift; |
|
114
|
18
|
|
|
|
|
41
|
my $track = $self->track(); |
|
115
|
18
|
100
|
|
|
|
341
|
my $fh = $track->{current_fh} or return; |
|
116
|
7
|
|
|
|
|
21
|
$self->close($fh, $track); |
|
117
|
7
|
|
|
|
|
90
|
return; |
|
118
|
|
|
|
|
|
|
} ## end sub just_close |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
sub print { |
|
121
|
37
|
|
|
37
|
1
|
1472
|
my $self = shift; |
|
122
|
|
|
|
|
|
|
|
|
123
|
37
|
|
33
|
|
|
93
|
my $iterator = ref($_[0]) && $_[0]; |
|
124
|
37
|
|
|
|
|
99
|
my $checker = $self->checker(); |
|
125
|
37
|
|
|
|
|
180
|
my $track = $self->track(); |
|
126
|
37
|
|
|
|
|
124
|
my $fh = $track->{current_fh}; |
|
127
|
37
|
|
|
|
|
93
|
my $interlude = $self->interlude(); |
|
128
|
|
|
|
|
|
|
|
|
129
|
37
|
|
|
|
|
121
|
while ('necessary') { |
|
130
|
76
|
50
|
|
|
|
168
|
my $record = $iterator ? $iterator->() : shift(@_); |
|
131
|
76
|
100
|
|
|
|
146
|
last unless defined $record; |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
# get filehandle if needed |
|
134
|
39
|
|
66
|
|
|
150
|
$fh ||= $self->open(); |
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
# print interlude if we have previous records, increase count |
|
137
|
|
|
|
|
|
|
$self->_print($fh, $interlude, $track) |
|
138
|
39
|
100
|
|
|
|
89
|
if $track->{records}; |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
# print record |
|
141
|
39
|
|
|
|
|
88
|
$self->_print($fh, $record, $track); |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
# increment number of records, for next print |
|
144
|
39
|
|
|
|
|
62
|
$track->{records}++; |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
# do checks if activated |
|
147
|
39
|
100
|
100
|
|
|
114
|
$fh = $self->close($fh, $track) |
|
148
|
|
|
|
|
|
|
if $checker && (!$checker->($self)); |
|
149
|
|
|
|
|
|
|
} ## end while ('necessary') |
|
150
|
|
|
|
|
|
|
|
|
151
|
37
|
|
|
|
|
89
|
return; |
|
152
|
|
|
|
|
|
|
} ## end sub print |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
sub _print { |
|
155
|
109
|
|
|
109
|
|
385
|
my ($self, $fh, $data, $track) = @_; |
|
156
|
109
|
100
|
|
|
|
206
|
return unless defined $data; |
|
157
|
91
|
50
|
|
|
|
149
|
$data = $data->($self) if ref $data; |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
# do print data |
|
160
|
91
|
50
|
|
|
|
158
|
ref($fh) or LOGCONFESS("$fh is not a reference"); |
|
161
|
91
|
50
|
|
|
|
107
|
print {$fh} $data or LOGCONFESS "print(): $OS_ERROR"; |
|
|
91
|
|
|
|
|
293
|
|
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
# update trackers |
|
164
|
91
|
|
|
|
|
136
|
my $new_chars = length($data); |
|
165
|
91
|
|
|
|
|
108
|
$track->{chars_file} += $new_chars; |
|
166
|
91
|
|
|
|
|
106
|
$track->{chars_total} += $new_chars; |
|
167
|
|
|
|
|
|
|
|
|
168
|
91
|
|
|
|
|
121
|
return $new_chars; |
|
169
|
|
|
|
|
|
|
} ## end sub _print |
|
170
|
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
sub default_check { |
|
172
|
28
|
|
|
28
|
1
|
44
|
my $self = shift; |
|
173
|
|
|
|
|
|
|
|
|
174
|
28
|
50
|
|
|
|
60
|
my $policy = $self->policy() |
|
175
|
|
|
|
|
|
|
or return 1; # no policy, always fine |
|
176
|
28
|
|
|
|
|
198
|
my $track = $self->track(); |
|
177
|
28
|
50
|
|
|
|
167
|
if (my $mr = $policy->{records_threshold}) { |
|
178
|
28
|
100
|
|
|
|
146
|
return 0 if $track->{records} >= $mr; |
|
179
|
|
|
|
|
|
|
} |
|
180
|
4
|
50
|
|
|
|
9
|
if (my $cpf = $policy->{characters_threshold}) { |
|
181
|
0
|
0
|
|
|
|
0
|
return 0 if $track->{chars_file} >= $cpf; |
|
182
|
|
|
|
|
|
|
} |
|
183
|
4
|
|
|
|
|
15
|
return 1; |
|
184
|
|
|
|
|
|
|
} ## end sub default_check |
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
sub checker { |
|
187
|
37
|
|
|
37
|
1
|
68
|
my $self = shift; |
|
188
|
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
# allow for overriding tout-court |
|
190
|
37
|
50
|
|
|
|
175
|
if (my $method = $self->can('check')) { |
|
191
|
0
|
|
|
|
|
0
|
return $method; # will eventually be called in the right way |
|
192
|
|
|
|
|
|
|
} |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
# if no policy is set, there's no reason to do checks |
|
195
|
37
|
100
|
|
|
|
119
|
my $policy = $self->policy() or return; |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
# at this point, let's use the default_check, whatever it is |
|
198
|
27
|
|
|
|
|
265
|
return $self->can('default_check'); |
|
199
|
|
|
|
|
|
|
} ## end sub checker |
|
200
|
|
|
|
|
|
|
|
|
201
|
18
|
|
|
18
|
|
1111
|
sub DESTROY { shift->just_close() } |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
sub writer { |
|
204
|
0
|
|
|
0
|
1
|
0
|
my $package = shift; |
|
205
|
0
|
|
|
|
|
0
|
my $self = $package->new(@_); |
|
206
|
0
|
|
|
0
|
|
0
|
return sub { return $self->print(@_) }; |
|
|
0
|
|
|
|
|
0
|
|
|
207
|
|
|
|
|
|
|
} |
|
208
|
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
1; |