File Coverage

blib/lib/ProgressMonitor/Stringify/Fields/Counter.pm
Criterion Covered Total %
statement 72 76 94.7
branch 16 26 61.5
condition 2 6 33.3
subroutine 11 11 100.0
pod 1 1 100.0
total 102 120 85.0


line stmt bran cond sub pod time code
1             package ProgressMonitor::Stringify::Fields::Counter;
2            
3 2     2   23574 use warnings;
  2         5  
  2         58  
4 2     2   10 use strict;
  2         3  
  2         57  
5            
6 2     2   11 use ProgressMonitor::State;
  2         3  
  2         187  
7             require ProgressMonitor::Stringify::Fields::AbstractField if 0;
8            
9             # Attributes:
10             # overflow
11             # Precomputed string to show when the field overflows
12             # unknown
13             # Precomputed string to show when the field is unknown
14             # index
15             # Keeps track of which idle delimiter should be rendered
16             # lastCount
17             # The previous count string (to trigger idle rendering)
18             #
19             use classes
20 2         17 extends => 'ProgressMonitor::Stringify::Fields::AbstractField',
21             new => 'new',
22 2     2   9 attrs_pr => ['overflow', 'unknown', 'index', 'lastLeft', 'lastRight'];
  2         3  
23            
24             sub new
25             {
26 1     1   14 my $class = shift;
27 1         3 my $cfg = shift;
28            
29 1         14 my $self = $class->SUPER::_new($cfg, $CLASS);
30            
31 1         9 $cfg = $self->_get_cfg;
32            
33 1         11 my $digits = $cfg->get_digits;
34 1         7 my $delim = $cfg->get_delimiter;
35            
36             # compute the width depending on what will be rendered
37             #
38 1 50       31 $self->_set_width($digits + ($cfg->get_showTotal ? length($delim) + $digits : 0));
39            
40 1         4 $self->{$ATTR_overflow} = $cfg->get_overflowCharacter x $digits;
41 1         10 $self->{$ATTR_unknown} = $cfg->get_unknownCharacter x $digits;
42 1         65 $self->{$ATTR_index} = 0;
43 1         5 $self->{$ATTR_lastLeft} = '';
44 1         3 $self->{$ATTR_lastRight} = '';
45            
46 1         17 return $self;
47             }
48            
49             sub render
50             {
51 23     23 1 30 my $self = shift;
52 23         26 my $state = shift;
53 23         34 my $ticks = shift;
54 23         25 my $totalTicks = shift;
55 23         23 my $clean = shift;
56            
57 23         71 my $cfg = $self->_get_cfg;
58 23         35 my $hasOverflow = 0;
59 23         57 my $digits = $cfg->get_digits;
60            
61             # first render the left part, but show overflow if it gets too large
62             #
63 23         143 my $l = sprintf("%.*u", $digits, $ticks);
64 23 50       56 if (length($l) > $digits)
65             {
66 0         0 $l = $self->{$ATTR_overflow};
67 0         0 $hasOverflow = 1;
68             }
69            
70 23         28 my $delim = '';
71 23         27 my $r = '';
72            
73 23 50       62 if ($cfg->get_showTotal)
74             {
75             # now render the right part, and watch for overflow
76             #
77 23 100       134 $r = defined($totalTicks) ? sprintf("%.*u", $digits, $totalTicks) : $self->{$ATTR_unknown};
78 23 50       47 if (length($r) > $digits)
79             {
80 0         0 $r = $self->{$ATTR_overflow};
81 0         0 $hasOverflow = 1;
82             }
83            
84             # unless we're requested to be clean and if there was overflow, or no
85             # change in the left/right parts), twirl the idle sequence
86             #
87 23         61 $delim = $cfg->get_delimiter;
88 23 100       115 if ($state != STATE_DONE)
89             {
90 22 100 33     174 if (!$clean && ($hasOverflow || ($l eq $self->{$ATTR_lastLeft} && $r eq $self->{$ATTR_lastRight})))
      33        
91             {
92 10         100 my $seq = $cfg->get_idleDelimiterSequence;
93 10         65 $delim = $seq->[$self->{$ATTR_index}++ % @$seq];
94             }
95             }
96             }
97            
98 23         44 $self->{$ATTR_lastLeft} = $l;
99 23         47 $self->{$ATTR_lastRight} = $r;
100            
101 23         86 return "$l$delim$r";
102             }
103            
104             ###
105            
106             package ProgressMonitor::Stringify::Fields::CounterConfiguration;
107            
108 2     2   1638 use strict;
  2         4  
  2         55  
109 2     2   10 use warnings;
  2         3  
  2         112  
110            
111             # Attributes
112             # digits (integer)
113             # The number of digits in the counter field (and the total)
114             # delimiter (string)
115             # The delimiter between counter and total
116             # idleDelimiterSequence (array ref with strings)
117             # The sequence of states that the delimiter should show when nothing else
118             # moves (note: defining this to [] effectively turns off idle twirl)
119             # overflowCharacter (character)
120             # The character to use if the field overflows (e.g. digits are 2 and counter is 100)
121             # unknownCharacter (character)
122             # The character to use for the total if undef (unknown)
123             # showTotal (boolean)
124             # Whether total field should be shown (this includes delimiter, and if no
125             # total, then no delimiter, then no idle delimiter twirl)
126             #
127             use classes
128 2         10 extends => 'ProgressMonitor::Stringify::Fields::AbstractFieldConfiguration',
129             attrs => ['digits', 'delimiter', 'idleDelimiterSequence', 'overflowCharacter', 'unknownCharacter', 'showTotal'],
130 2     2   10 ;
  2         4  
131            
132             sub defaultAttributeValues
133             {
134 1     1   3 my $self = shift;
135            
136             return {
137 1         3 %{$self->SUPER::defaultAttributeValues()},
  1         10  
138             digits => 5,
139             delimiter => '/',
140             idleDelimiterSequence => ['\\', '/'],
141             overflowCharacter => '#',
142             unknownCharacter => '?',
143             showTotal => 1,
144             };
145             }
146            
147             sub checkAttributeValues
148             {
149 1     1   3 my $self = shift;
150            
151 1         9 $self->SUPER::checkAttributeValues;
152            
153 1 50       6 X::Usage->throw("digits must be > 0") if $self->get_digits < 1;
154 1 50       10 X::Usage->throw("overflowCharacter must have length 1") if length($self->get_overflowCharacter) != 1;
155 1 50       9 X::Usage->throw("unknownCharacter must have length 1") if length($self->get_unknownCharacter) != 1;
156 1 50       10 X::Usage->throw("delimiter must have a length") if length($self->get_delimiter) < 1;
157 1         11 my $seq = $self->get_idleDelimiterSequence;
158 1 50       10 X::Usage->throw("idleDelimiterSequence must be an array") unless ref($seq) eq 'ARRAY';
159 1         4 my $len = length($self->get_delimiter);
160 1         7 for (@$seq)
161             {
162 2 50       16 X::Usage->throw("all idleDelimiterSequence elements must have same length as delimiter") if length($_) != $len;
163             }
164            
165 1         4 return;
166             }
167            
168             ############################
169            
170             =head1 NAME
171            
172             ProgressMonitor::Stringify::Field::Counter - a field implementation that renders progress
173             as a counter.
174            
175             =head1 SYNOPSIS
176            
177             # call someTask and give it a monitor to call us back
178             #
179             my $counter = ProgressMonitor::Stringify::Fields::Counter->new;
180             someTask(ProgressMonitor::Stringify::ToStream->new({fields => [ $counter ]});
181            
182             =head1 DESCRIPTION
183            
184             This is a fixed size field representing progress as a counter with or without the total
185             displayed alongside, e.g. '00512/03000' meaning 512 ticks completed out of 3000.
186            
187             Inherits from ProgressMonitor::Stringify::Fields::AbstractField.
188            
189             =head1 METHODS
190            
191             =over 2
192            
193             =item new( $hashRef )
194            
195             Configuration data:
196            
197             =over 2
198            
199             =item digits (default => 5)
200            
201             The number of digits it should use. With the default it can thus indicate up
202             to '99999'. Values above that will be printed using the overflow character.
203            
204             =item delimiter (default => '/')
205            
206             The delimiter string between the current and total values.
207            
208             =item idleDelimiterSequence (default => ['\\', '/'])
209            
210             When progress is made but with tick count not advancing, this sequence is used
211             to show that something is happening. It should be a list of strings with each string
212             having the same length as the delimiter. As idle work is done, the sequence will
213             be stepped through, but immediately revert to the regular delimiter as soon as
214             a tick is detected.
215            
216             =item overflowCharacter (default => '#')
217            
218             The character to be used when the value is to large to fit using the given amount
219             of digits.
220            
221             =item unknownCharacter (default => '?')
222            
223             The character to use when the total is unknown.
224            
225             =item showTotal (default => 1)
226            
227             Turns on or off the total display. With no total displayed, no delimiter displayed
228             and hence, no idleness shown either.
229            
230             =back
231            
232             =back
233            
234             =head1 AUTHOR
235            
236             Kenneth Olwing, C<< >>
237            
238             =head1 BUGS
239            
240             I wouldn't be surprised! If you can come up with a minimal test that shows the
241             problem I might be able to take a look. Even better, send me a patch.
242            
243             Please report any bugs or feature requests to
244             C, or through the web interface at
245             L.
246             I will be notified, and then you'll automatically be notified of progress on
247             your bug as I make changes.
248            
249             =head1 SUPPORT
250            
251             You can find general documentation for this module with the perldoc command:
252            
253             perldoc ProgressMonitor
254            
255             =head1 ACKNOWLEDGEMENTS
256            
257             Thanks to my family. I'm deeply grateful for you!
258            
259             =head1 COPYRIGHT & LICENSE
260            
261             Copyright 2006,2007 Kenneth Olwing, all rights reserved.
262            
263             This program is free software; you can redistribute it and/or modify it
264             under the same terms as Perl itself.
265            
266             =cut
267            
268             1; # End of ProgressMonitor::Stringify::Fields::Counter