File Coverage

blib/lib/ProgressMonitor/Stringify/Fields/ETA.pm
Criterion Covered Total %
statement 99 119 83.1
branch 11 28 39.2
condition 1 9 11.1
subroutine 18 19 94.7
pod 1 2 50.0
total 130 177 73.4


line stmt bran cond sub pod time code
1             package ProgressMonitor::Stringify::Fields::ETA;
2            
3 2     2   32645 use warnings;
  2         5  
  2         69  
4 2     2   11 use strict;
  2         6  
  2         69  
5            
6 2     2   12 use ProgressMonitor::State;
  2         5  
  2         159  
7             require ProgressMonitor::Stringify::Fields::AbstractField if 0;
8            
9 2     2   2095 use Time::HiRes qw(time);
  2         5195  
  2         10  
10            
11 2     2   443 use constant MINUTE => 60;
  2         5  
  2         184  
12 2     2   11 use constant HOUR => 60 * MINUTE;
  2         4  
  2         113  
13 2     2   13 use constant DAY => 24 * HOUR;
  2         3  
  2         110  
14            
15 2     2   9 no strict 'refs';
  2         3  
  2         98  
16             use classes
17 2         21 extends => 'ProgressMonitor::Stringify::Fields::AbstractField',
18             new => 'new',
19             attrs_pr => ['start', 'index', 'lastHH', 'lastMM', 'lastSS', 'lastDelim', 'lastTime', 'lastLeft'],
20 2     2   9 ;
  2         4  
21            
22             sub new
23             {
24 1     1   17 my $class = shift;
25 1         2 my $cfg = shift;
26            
27 1         15 my $self = $class->SUPER::_new($cfg, $CLASS);
28            
29 1         12 $cfg = $self->_get_cfg;
30            
31             # we only wish to portray up to 23:59:49 at this point
32             #
33 1         3 my $delim = $cfg->get_mainDelimiter;
34 1         6 my $delimLen = length($delim);
35 1         10 $self->_set_width(2 + $delimLen + 2 + $delimLen + 2);
36            
37 1         3 my $ofc = $cfg->get_unknownCharacter;
38 1         6 $self->{$ATTR_start} = 0;
39 1         3 $self->{$ATTR_index} = 0;
40 1         8 $self->{$ATTR_lastHH} = $self->{$ATTR_lastMM} = $self->{$ATTR_lastSS} = "$ofc$ofc";
41 1         14 $self->{$ATTR_lastDelim} = $delim;
42 1         4 $self->{$ATTR_lastTime} = 0;
43 1         3 $self->{$ATTR_lastLeft} = 0;
44            
45 1         10 return $self;
46             }
47            
48             sub render
49             {
50 3     3 1 5 my $self = shift;
51 3         4 my $state = shift;
52 3         4 my $ticks = shift;
53 3         3 my $totalTicks = shift;
54 3         3 my $clean = shift;
55            
56 3         11 my $now = time;
57 3         7 my $timeSinceStart = $now - $self->{$ATTR_start};
58 3         14 my $cfg = $self->_get_cfg;
59 3         8 my $hh = $self->{$ATTR_lastHH};
60 3         7 my $mm = $self->{$ATTR_lastMM};
61 3         6 my $ss = $self->{$ATTR_lastSS};
62 3         5 my $delim = $self->{$ATTR_lastDelim};
63            
64 3 100       9 if (!$self->{$ATTR_start})
65             {
66             # this is the first call - just render 'unknown'
67             #
68 1         4 $self->{$ATTR_start} = $self->{$ATTR_lastTime} = $now;
69             }
70             else
71             {
72            
73 2 100       6 if ($state == STATE_DONE)
74             {
75 1         5 my $ofc = $cfg->get_unknownCharacter;
76 1         7 $hh = $mm = $ss = "$ofc$ofc";
77 1 50       19 ($hh, $mm, $ss) = $self->__fmtHMS($timeSinceStart) if $timeSinceStart < DAY;
78             }
79             else
80             {
81             # to avoid too much flickering, only update at the given rate
82             #
83 1 50       7 if ($now >= $self->{$ATTR_lastTime} + $cfg->get_maxUpdateRate)
84             {
85             # flicker delimiter
86             #
87 0         0 my $seq = $cfg->get_idleDelimiterSequence;
88 0         0 $delim = $seq->[$self->{$ATTR_index}++ % @$seq];
89            
90             # try to ensure we have some information to predict on
91             #
92 0 0 0     0 my $ratio = defined($totalTicks) && $totalTicks > 0 ? $ticks / $totalTicks : 0;
93 0 0       0 if ($ratio > $cfg->get_waitForRatio)
94             {
95 0         0 my $left = int($timeSinceStart * ((1 - $ratio) / $ratio));
96 0 0       0 $left = DAY if $left > DAY;
97 0 0 0     0 if ($clean || $left != $self->{$ATTR_lastLeft})
98             {
99 0         0 ($hh, $mm, $ss) = $self->__fmtHMS($left);
100 0         0 $delim = $cfg->get_mainDelimiter;
101             }
102 0         0 $self->{$ATTR_lastLeft} = $left;
103             }
104 0         0 $self->{$ATTR_lastTime} = $now;
105             }
106             }
107             }
108            
109 3         15 $self->{$ATTR_lastHH} = $hh;
110 3         5 $self->{$ATTR_lastMM} = $mm;
111 3         6 $self->{$ATTR_lastSS} = $ss;
112 3         6 $self->{$ATTR_lastDelim} = $delim;
113 3         22 return sprintf("%s%s%s%s%s", $hh, $delim, $mm, $delim, $ss);
114             }
115            
116             sub completed
117             {
118 0     0 0 0 my $self = shift;
119            
120             # We're done - report the actual time it took
121             # but check for overflow
122             #
123 0         0 my $cfg = $self->_get_cfg;
124 0         0 my $ofc = $cfg->get_unknownCharacter;
125 0         0 my ($hh, $mm, $ss);
126 0         0 $hh = $mm = $ss = "$ofc$ofc";
127 0         0 my $timeSinceStart = time - $self->{$ATTR_start};
128 0 0       0 ($hh, $mm, $ss) = $self->__fmtHMS($timeSinceStart) if $timeSinceStart < DAY;
129 0         0 my $delim = $cfg->get_mainDelimiter;
130            
131 0         0 return sprintf("%s%s%s%s%s", $hh, $delim, $mm, $delim, $ss);
132             }
133            
134             sub __fmtHMS
135             {
136 1     1   2 my $self = shift;
137 1         3 my $time = shift;
138            
139 1         2 my $fmt = '%02u';
140 1         7 my $hh = sprintf($fmt, int($time / DAY));
141 1         6 my $mm = sprintf("%02u", int(($time % DAY) / MINUTE));
142 1         3 my $ss = sprintf("%02u", $time % MINUTE);
143            
144 1         6 return ($hh, $mm, $ss);
145             }
146            
147             ###
148            
149             package ProgressMonitor::Stringify::Fields::ETAConfiguration;
150            
151 2     2   4623 use strict;
  2         3  
  2         60  
152 2     2   9 use warnings;
  2         3  
  2         74  
153            
154 2     2   10 no strict 'refs';
  2         4  
  2         136  
155             use classes
156 2         10 extends => 'ProgressMonitor::Stringify::Fields::AbstractFieldConfiguration',
157             attrs => ['unknownCharacter', 'mainDelimiter', 'idleDelimiterSequence', 'waitForRatio', 'maxUpdateRate'],
158 2     2   8 ;
  2         4  
159            
160             sub defaultAttributeValues
161             {
162 1     1   5 my $self = shift;
163            
164             return {
165 1         2 %{$self->SUPER::defaultAttributeValues()},
  1         12  
166             unknownCharacter => '-',
167             mainDelimiter => ':',
168             idleDelimiterSequence => [' ', ':'],
169             waitForRatio => 0.01,
170             maxUpdateRate => 1,
171             };
172             }
173            
174             sub checkAttributeValues
175             {
176 1     1   3 my $self = shift;
177            
178 1         9 $self->SUPER::checkAttributeValues;
179            
180 1 50       4 X::Usage->throw("unknownCharacter should have a length of 1") unless length($self->get_unknownCharacter) == 1;
181 1         11 my $seq = $self->get_idleDelimiterSequence;
182 1 50       8 X::Usage->throw("idleDelimiterSequence must be an array") unless ref($seq) eq 'ARRAY';
183 1         4 my $len = length($self->get_mainDelimiter);
184 1         6 for (@$seq)
185             {
186 2 50       8 X::Usage->throw("all idleDelimiterSequence elements must have same length as mainDelimiter") if length($_) != $len;
187             }
188 1 50 33     5 X::Usage->throw("0 < waitForRatio <= 1") if ($self->get_waitForRatio < 0 || $self->get_waitForRatio > 1);
189 1 50       36 X::Usage->throw("maxUpdateRate can not be negative") if $self->get_waitForRatio < 0;
190            
191 1         8 return;
192             }
193            
194             ############################
195            
196             =head1 NAME
197            
198             ProgressMonitor::Stringify::Field::ETA - a field implementation that renders progress
199             as a time-to-completion.
200            
201             =head1 VERSION
202            
203             Version 0.01
204            
205             =head1 DESCRIPTION
206            
207             @@TODO@@
208            
209             =head1 AUTHOR
210            
211             Kenneth Olwing, C<< >>
212            
213             =head1 BUGS
214            
215             I wouldn't be surprised! If you can come up with a minimal test that shows the
216             problem I might be able to take a look. Even better, send me a patch.
217            
218             Please report any bugs or feature requests to
219             C, or through the web interface at
220             L.
221             I will be notified, and then you'll automatically be notified of progress on
222             your bug as I make changes.
223            
224             =head1 SUPPORT
225            
226             You can find documentation for this module with the perldoc command.
227            
228             perldoc ProgressMonitor
229            
230             You can also look for information at:
231            
232             =over 4
233            
234             =item * AnnoCPAN: Annotated CPAN documentation
235            
236             L
237            
238             =item * CPAN Ratings
239            
240             L
241            
242             =item * RT: CPAN's request tracker
243            
244             L
245            
246             =item * Search CPAN
247            
248             L
249            
250             =back
251            
252             =head1 ACKNOWLEDGEMENTS
253            
254             Thanks to my family. I'm deeply grateful for you!
255            
256             =head1 COPYRIGHT & LICENSE
257            
258             Copyright 2006,2007 Kenneth Olwing, all rights reserved.
259            
260             This program is free software; you can redistribute it and/or modify it
261             under the same terms as Perl itself.
262            
263             =cut
264            
265             1; # End of ProgressMonitor::Stringify::Fields::ETA