File Coverage

blib/lib/ProgressMonitor/Stringify/ToStream.pm
Criterion Covered Total %
statement 33 80 41.2
branch 0 26 0.0
condition 0 9 0.0
subroutine 11 16 68.7
pod 0 2 0.0
total 44 133 33.0


line stmt bran cond sub pod time code
1             package ProgressMonitor::Stringify::ToStream;
2            
3 1     1   1109 use warnings;
  1         2  
  1         32  
4 1     1   5 use strict;
  1         1  
  1         28  
5            
6 1     1   5 use ProgressMonitor::State;
  1         2  
  1         78  
7            
8 1     1   5 use constant BACKSPACE => "\b";
  1         1  
  1         46  
9 1     1   15 use constant SPACE => ' ';
  1         2  
  1         61  
10            
11             require ProgressMonitor::Stringify::AbstractMonitor if 0;
12            
13             # Attributes:
14             # backspaces (string)
15             # Precomputed string with backspaces used to return to the beginning so as
16             # to wipe out the previous write.
17             #
18             use classes
19 1         11 extends => 'ProgressMonitor::Stringify::AbstractMonitor',
20             new => 'new',
21             attrs_pr => ['backspaces', 'needBS'],
22 1     1   5 ;
  1         1  
23            
24             sub new
25             {
26 0     0     my $class = shift;
27 0           my $cfg = shift;
28            
29 0           my $self = $class->SUPER::_new($cfg, $CLASS);
30            
31             # initialize the rest
32             #
33 0           $self->{$ATTR_backspaces} = undef;
34 0           $self->{$ATTR_needBS} = 0;
35            
36 0           return $self;
37             }
38            
39             sub render
40             {
41 0     0 0   my $self = shift;
42            
43 0           local $| = 1;
44            
45 0           my $bs = $self->{$ATTR_backspaces};
46 0 0         $bs = $self->{$ATTR_backspaces} = BACKSPACE x $self->get_width unless $bs;
47            
48 0           my $cfg = $self->_get_cfg;
49 0           my $stream = $cfg->get_stream;
50 0           my $bsAfter = $cfg->get_backspaceAfterRender;
51             # render and print
52             #
53 0 0 0       print $stream $bs if (!$bsAfter && $self->{$ATTR_needBS});
54 0           my $s = $self->_toString;
55 0           print $stream $s;
56 0 0         $self->{$ATTR_needBS} = ($s !~ /\n$/ ? 1 : 0);
57 0 0 0       print $stream $bs if ($bsAfter && $self->{$ATTR_needBS});
58            
59 0 0         if ($self->_get_state == STATE_DONE)
60             {
61             # run the end routine
62             #
63 0           my $atEndStrategy = $cfg->get_atEndStrategy;
64 0 0         if ($atEndStrategy eq 'wipe')
    0          
65             {
66             # space it out and return us to beginning
67             #
68 0 0         print $stream $bs unless $bsAfter;
69 0           print $stream SPACE x $self->get_width;
70 0           print $stream $bs;
71             }
72             elsif ($atEndStrategy eq 'newline')
73             {
74             # get us to a new line
75             #
76 0           print $stream "\n";
77             }
78             else
79             {
80             # the strategy is 'none'...
81             #
82             }
83             }
84            
85 0           return;
86             }
87            
88             sub setErrorMessage
89             {
90 0     0 0   my $self = shift;
91 0           my $msg = $self->SUPER::setErrorMessage(shift());
92            
93 0 0         if ($msg)
94             {
95 0           my $stream = $self->_get_cfg->get_stream;
96 0           print $stream "\n$msg\n";
97 0           $self->{$ATTR_needBS} = 0;
98            
99 0           $self->render;
100             }
101             }
102            
103             ###
104            
105             package ProgressMonitor::Stringify::ToStreamConfiguration;
106            
107 1     1   803 use strict;
  1         1  
  1         85  
108 1     1   5 use warnings;
  1         3  
  1         29  
109            
110 1     1   6 use Scalar::Util qw(openhandle);
  1         2  
  1         106  
111            
112             my $tsPlatform = $^O eq 'MSWin32' ? 'Win32' : 'Unix';
113 1     1   791 eval "use Term::Size::$tsPlatform";
  1         19018  
  1         79  
114             die("Platform specific use failed: $@") if $@;
115            
116             # Attributes
117             # stream (handle)
118             # This is the stream to write to. Defaults to '\*STDOUT'.
119             # The stream must be able to handle backspacing in order to properly
120             # show the fields. Also, this presumes things won't go awry if the
121             # width set exceeds the streams 'display width' (e.g. a terminal window),
122             # causing linewrapping to occur.
123             # atEndStrategy (string, default => 'newline')
124             # 'wipe' : the rendered data will be cleared on completion, cursor
125             # at the point where it started.
126             # 'newline': the rendered data will be left, a newline positions the
127             # cursor on next line.
128             # 'none' : the rendered data will be left, the cursor remains at the
129             # end
130             # backspaceAfterRender (boolean, default => 0)
131             # Whether the cursor should be backspaced to the start of the render or
132             # left at the end of the render
133             #
134             use classes
135 1         5 extends => 'ProgressMonitor::Stringify::AbstractMonitorConfiguration',
136             attrs => ['stream', 'atEndStrategy', 'backspaceAfterRender'],
137 1     1   9 ;
  1         2  
138            
139             sub defaultAttributeValues
140             {
141 0     0     my $self = shift;
142            
143 0           return {%{$self->SUPER::defaultAttributeValues()}, stream => \*STDOUT, atEndStrategy => 'newline', backspaceAfterRender => 0};
  0            
144             }
145            
146             sub checkAttributeValues
147             {
148 0     0     my $self = shift;
149            
150 0           $self->SUPER::checkAttributeValues();
151            
152 0           my $stream = $self->get_stream;
153 0 0         X::Usage->throw("not an open handle") unless openhandle($stream);
154            
155             # try to actually get the columns for the given stream and adapt the maxwidth to it
156             # if it's not explicitly set - failing this, fall back to a hardcoded 79...
157             #
158 0 0         if (!$self->get_maxWidth)
159             {
160 0           my $cols;
161 0           eval "\$cols = Term::Size::${tsPlatform}::chars \$stream;";
162 0 0 0       $self->set_maxWidth(($cols && !$@) ? $cols - 1 : 79);
163             }
164            
165 0           my $aes = $self->get_atEndStrategy;
166 0 0         X::Usage->throw("invalid value for atEndStrategy: $aes") unless $aes =~ /^(?:none|wipe|newline)$/;
167            
168 0           return;
169             }
170            
171             ############################
172            
173             =head1 NAME
174            
175             ProgressMonitor::Stringify::ToStream - a monitor implementation that prints
176             stringified feedback to a stream.
177            
178             =head1 SYNOPSIS
179            
180             ...
181             # call someTask and give it a monitor that prints to stdout
182             #
183             someTask(ProgressMonitor::Stringify::ToStream->new({fields => [ ... ]}));
184            
185             =head1 DESCRIPTION
186            
187             This is a concrete implementation of a ProgressMonitor. It will send the stringified
188             feedback to a stream and backspace to continously overwrite. Optionally, it will
189             clear the feedback entirely, leaving the cursor where it was.
190            
191             Note that this is probably most useful to send to either stdout/stderr. Sending to
192             a basic disk file probably won't many people happy...See ToCallback if you want to
193             be more clever.
194            
195             Also, this assumes that backspacing will work correctly which may not be true if
196             the width is so large that the terminal window starts on a new line. Use the inherited
197             configuration 'maxWidth' to limit the width if you have the necessary information.
198            
199             Inherits from ProgressMonitor::Stringify::AbstractMonitor.
200            
201             =head1 METHODS
202            
203             =over 2
204            
205             =item new( $hashRef )
206            
207             Configuration data:
208            
209             =over 2
210            
211             =item stream (default => \*STDOUT)
212            
213             This is the stream to write to. Defaults to '\*STDOUT'.
214            
215             The stream must be able to handle backspacing in order to properly
216             show the fields. Unless the maxWidth is explicitly set, it will be
217             set by checking the stream using Term::Size(::).
218            
219             =item atEndStrategy (default => 'newline')
220            
221             =over 2
222            
223             =item wipe
224            
225             The rendered data will be cleared on completion, cursor at the point where it started.
226            
227             =item newline
228            
229             The rendered data will be left, a newline positions the cursor on next line.
230            
231             =item none
232            
233             The rendered data will be left, the cursor remains at the end.
234            
235             =back
236            
237             =back
238            
239             =back
240            
241             =head1 AUTHOR
242            
243             Kenneth Olwing, C<< >>
244            
245             =head1 BUGS
246            
247             I wouldn't be surprised! If you can come up with a minimal test that shows the
248             problem I might be able to take a look. Even better, send me a patch.
249            
250             Please report any bugs or feature requests to
251             C, or through the web interface at
252             L.
253             I will be notified, and then you'll automatically be notified of progress on
254             your bug as I make changes.
255            
256             =head1 SUPPORT
257            
258             You can find general documentation for this module with the perldoc command:
259            
260             perldoc ProgressMonitor
261            
262             =head1 ACKNOWLEDGEMENTS
263            
264             Thanks to my family. I'm deeply grateful for you!
265            
266             =head1 COPYRIGHT & LICENSE
267            
268             Copyright 2006,2007 Kenneth Olwing, all rights reserved.
269            
270             This program is free software; you can redistribute it and/or modify it
271             under the same terms as Perl itself.
272            
273             =cut
274            
275             1; # End of ProgressMonitor::Stringify::ToStream