File Coverage

blib/lib/Term/YAP.pm
Criterion Covered Total %
statement 53 61 86.8
branch 4 12 33.3
condition n/a
subroutine 15 16 93.7
pod n/a
total 72 89 80.9


line stmt bran cond sub pod time code
1             package Term::YAP;
2 8     8   570574 use strict;
  8         29  
  8         249  
3 8     8   46 use warnings;
  8         16  
  8         179  
4 8     8   40 use Carp;
  8         17  
  8         645  
5              
6             our $VERSION = '0.08'; # VERSION
7              
8             =head1 NAME
9              
10             Term::YAP - show pulsed progress bar in terminal
11              
12             =cut
13              
14 8     8   725 use Types::Standard 1.000005 qw(Str Int Bool Num FileHandle);
  8         76878  
  8         84  
15 8     8   10537 use Time::HiRes 1.9726 qw(usleep time);
  8         2996  
  8         142  
16 8     8   1976 use Moo 2.000002;
  8         14253  
  8         53  
17 8     8   25442 use namespace::clean 0.26;
  8         7810  
  8         48  
18              
19             =head1 SYNOPSIS
20              
21             use Term::YAP;
22             my $yap = Term::YAP->new( { name => 'Checking', rotate => 0, time => 1 } );
23             $yap->start(); # start the pulse
24             # do something between
25             $yap->stop() # stop it
26              
27             =head1 DESCRIPTION
28              
29             Term::YAP is a L<Moo> based class to implement a "pulse" bar in a terminal. A
30             pulse bar doesn't actually keep track of progress from any task being executed
31             but at least shows that the program is working in something instead of showing
32             nothing for the end user.
33              
34             This is the parent class and some methods were not implemented, you probably
35             want to look for subclasses to get an implementation.
36              
37             This module started as a shamelessly copy from L<Term::Pulse>, nowadays it
38             keeps the same features but with a different implementation.
39              
40             =head1 EXPORT
41              
42             Nothing.
43              
44             =head1 ATTRIBUTES
45              
46             All attributes are optional and have their respective default values.
47              
48             =head2 name
49              
50             A simple message displayed before the pulse. The default value is 'Working'.
51              
52             =cut
53              
54             has name =>
55             ( is => 'ro', isa => Str, default => 'Working', reader => 'get_name' );
56              
57             =head2 rotatable
58              
59             Boolean. Rotates the pulse if set to true. It is false by default.
60              
61             =cut
62              
63             has rotatable =>
64             ( is => 'ro', isa => Bool, default => 0, reader => 'is_rotatable' );
65              
66             =head2 time
67              
68             Boolean. Display the elapsed time if set to 1. Turn off by default.
69              
70             =cut
71              
72             has time => ( is => 'ro', isa => Bool, default => 0, reader => 'show_time' );
73              
74             =head2 size
75              
76             Set the pulse size. The default value is 16.
77              
78             =cut
79              
80             has size => ( is => 'ro', isa => Int, default => 16, reader => 'get_size' );
81              
82             =head2 start_time
83              
84             The time (Unix Epoch) that the pulse bar started in seconds.
85              
86             This attribute is "private".
87              
88             =cut
89              
90             has start_time => (
91             is => 'rw',
92             isa => Num,
93             reader => '_get_start',
94             writer => '_set_start',
95             );
96              
97             =head2 usleep
98              
99             The microseconds elapsed that each pulse has between each other. The default value is 200000.
100              
101             This attribute is "private".
102              
103             =cut
104              
105             has usleep =>
106             ( is => 'ro', isa => Num, reader => '_get_usleep', default => 200000 );
107              
108             =head2 running
109              
110             Boolean. If true, the pulse was started, false otherwise.
111              
112             =cut
113              
114             has running => (
115             is => 'ro',
116             isa => Bool,
117             reader => 'is_running',
118             writer => '_set_running',
119             default => 0
120             );
121              
122             =head2 output
123             Defines a L<IO::File> object where the output is written. Created to make it
124             easier for testing, specially because the output is designed for better view
125             in a terminal.
126             Defaults to C<*STDOUT{IO}>.
127             =cut
128              
129             has output => (
130             is => 'ro',
131             isa => FileHandle,
132             reader => 'to_output',
133             writer => '_set_output',
134             default => sub { *STDOUT{IO} }
135             );
136              
137             =head2 debug
138              
139             Boolean. If true, additional messages (which will mangle output) will by
140             printed to C<STDOUT>.
141              
142             Defaults to false.
143              
144             =cut
145              
146             has debug => (
147             is => 'rw',
148             isa => Bool,
149             reader => 'is_debug',
150             writer => 'set_debug',
151             default => 0
152             );
153              
154             =head1 METHODS
155              
156             =head2 is_running
157              
158             Getter for C<running> attribute.
159              
160             =head2 BUILD
161              
162             Install handlers for signals C<INT> and C<__DIE__>.
163              
164             =cut
165              
166             sub BUILD {
167 9     9   60488 my $self = shift;
168 9     0   317 $SIG{INT} = sub { $self->stop };
  0         0  
169 9     1   141 $SIG{__DIE__} = sub { $self->stop };
  1         546  
170             }
171              
172             =head2 get_name
173              
174             Returns the value of the name attribute.
175              
176             =head2 is_rotatable
177              
178             Returns the value of rotatable attribute.
179              
180             =head2 show_time
181              
182             Returns the value of time attribute.
183              
184             =head2 get_size
185              
186             Returns the value of size attribute.
187              
188             =head2 start
189              
190             Starts the pulse. Returns the value of C<running> attribute.
191              
192             =head2 is_debug
193              
194             Returns the value set of C<debug> attribute.
195              
196             =head2 set_debug
197              
198             Setter for the C<debug> attribute.
199              
200             =cut
201              
202             sub start {
203 18     18   1670 return shift->is_running();
204             }
205              
206             sub _is_enough {
207 1     1   82 confess '_is_enough() method must be overrided by subclasses of Term::YAP';
208             }
209              
210             sub _keep_pulsing {
211 5     5   109 my $self = shift;
212 5         127 my @mark = qw(- \ | / - \ | /);
213 5         242 $| = 1;
214 5         171 my $name = $self->get_name();
215 5         209 my $rotate = $self->is_rotatable();
216 5         96 my $size = $self->get_size();
217 5         132 my $time = $self->show_time();
218 5         117 my $start = time();
219 5         917 $self->_set_start($start);
220 5         568 my $fh = $self->to_output();
221              
222 5         69 INFINITE: while (1) {
223              
224             # forward
225 5         120 foreach my $index ( 1 .. $size ) {
226 80 50       2032 my $mark = $rotate ? $mark[ $index % 8 ] : q{=};
227 80         6312 printf $fh "$name...[%s%s%s]", q{ } x ( $index - 1 ), $mark,
228             q{ } x ( $size - $index );
229 80 50       3255 printf $fh " (%f sec elapsed)", ( time - $start ) if $time;
230 80         1113 printf $fh "\r";
231 80 100       6280 last INFINITE if ( $self->_is_enough() );
232 75         464 $self->_sleep();
233             }
234              
235             # backward
236 0         0 foreach my $index ( 1 .. $size ) {
237 0 0       0 my $mark = $rotate ? $mark[ ( $index % 8 ) * -1 ] : q{=};
238 0         0 printf $fh "$name...[%s%s%s]", q{ } x ( $size - $index ), $mark,
239             q{ } x ( $index - 1 );
240 0 0       0 printf $fh " (%f sec elapsed)", ( time - $start ) if $time;
241 0         0 printf $fh "\r";
242 0 0       0 last INFINITE if ( $self->_is_enough() );
243 0         0 $self->_sleep();
244             }
245              
246             }
247              
248 5         236 return ( time() - $self->_get_start() );
249              
250             }
251              
252             =head2 stop
253              
254             Stop the pulse and return elapsed time.
255              
256             =cut
257              
258             sub stop {
259 16     16   381 return shift->_report;
260             }
261              
262             sub _report {
263 16     16   76 my $self = shift;
264 16         230 my $fh = $self->to_output;
265 16         1121 printf $fh "%s%sDone%s\n", $self->get_name(),
266             q{.} x ( $self->get_size + 1 ),
267             ' ';
268 16         144 return 1;
269             }
270              
271             sub _sleep {
272 90     90   212 my $self = shift;
273 90         17981903 usleep( $self->_get_usleep() );
274             }
275              
276             =head1 SEE ALSO
277              
278             =over
279              
280             =item *
281              
282             L<Term::Pulse>
283              
284             =item *
285              
286             L<Moo>
287              
288             =back
289              
290             =head1 AUTHOR
291              
292             Alceu Rodrigues de Freitas Junior, E<lt>arfreitas@cpan.orgE<gt>
293              
294             L<Term::Pulse> was originally created by Yen-Liang Chen, E<lt>alec at cpan.comE<gt>
295              
296             =head1 COPYRIGHT AND LICENSE
297              
298             This software is copyright (c) 2015 of Alceu Rodrigues de Freitas Junior,
299             E<lt>arfreitas@cpan.orgE<gt>
300              
301             This file is part of Term-YAP distribution.
302              
303             Term-YAP is free software: you can redistribute it and/or modify
304             it under the terms of the GNU General Public License as published by
305             the Free Software Foundation, either version 3 of the License, or
306             (at your option) any later version.
307              
308             Term-YAP is distributed in the hope that it will be useful,
309             but WITHOUT ANY WARRANTY; without even the implied warranty of
310             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
311             GNU General Public License for more details.
312              
313             You should have received a copy of the GNU General Public License
314             along with Term-YAP. If not, see <http://www.gnu.org/licenses/>.
315              
316             =cut
317              
318             1;