File Coverage

blib/lib/Term/MultiSpinner.pm
Criterion Covered Total %
statement 16 18 88.8
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 22 24 91.6


line stmt bran cond sub pod time code
1             package Term::MultiSpinner;
2              
3 2     2   20395 use strict;
  2         4  
  2         69  
4 2     2   8 use warnings;
  2         3  
  2         49  
5 2     2   45 use 5.006_000;
  2         7  
  2         133  
6             our $VERSION = '0.01';
7              
8             =head1 NAME
9              
10             Term::MultiSpinner - Term::Spinner with multiple spinners
11              
12             =head1 SYNOPSIS
13              
14             use Term::MultiSpinner;
15              
16             my $spinner = Term::MultiSpinner->new();
17             while(... a complicated async loop ...) {
18             if(... can read some data ...) {
19             $spinner->advance(0);
20             # read stuff
21             $spinner->finish(0) if $done_reading;
22             }
23             if(... can write some data ...) {
24             $spinner->advance(1);
25             # write stuff
26             $spinner->finish(1) if $done_writing;
27             }
28             }
29             undef $spinner; # clears final spinner output by default.
30              
31             =head1 DESCRIPTION
32              
33             This is a subclass of L<Term::Spinner>, see those docs first.
34              
35             This class provides multiple spinners on the same line, to
36             represent the state of several asynchronous long-running
37             tasks. Ideal for a complex C<select>-based loop, a L<POE>
38             process, etc.
39              
40             Another good place to use it is if you have a long queue of
41             short tasks to complete and can only do a small number in
42             parallel at a time. Use the first spinner to indicate when
43             a task is taken from the queue and started, and the second
44             spinner to indicate task completion.
45              
46             The docs below only indicate deviations from the interface
47             of L<Term::Spinner>, see those docs for the basic information.
48              
49             =cut
50              
51 2     2   8 use Carp qw/croak/;
  2         2  
  2         128  
52 2     2   558 use IO::Handle;
  2         5760  
  2         84  
53              
54 2     2   415 use Moose;
  0            
  0            
55             extends 'Term::Spinner';
56              
57             has '_spinners' => (
58             is => 'rw',
59             isa => 'ArrayRef',
60             default => sub { [] },
61             );
62              
63             has '_suppress_draw' => (
64             is => 'rw',
65             isa => 'Bool',
66             default => 0,
67             );
68              
69             =head1 METHODS
70              
71             =head2 clear
72              
73             =cut
74              
75             sub clear {
76             my ($self) = @_;
77              
78             my $drawn = $self->_drawn;
79             return if !$drawn;
80              
81             $self->output_handle->print(
82             "\010" x $drawn,
83             q{ } x $drawn,
84             "\010" x $drawn,
85             );
86             $self->_drawn(0);
87             }
88              
89             =head2 draw
90              
91             =cut
92              
93             sub draw {
94             my ($self) = @_;
95              
96             return if $self->_suppress_draw;
97              
98             $self->clear();
99             $self->output_handle->print(
100             join(q{}, map { $self->spin_chars->[$_] } @{$self->_spinners})
101             );
102             $self->_drawn(scalar(@{$self->_spinners}));
103             }
104              
105             =head2 advance
106              
107             Requires an argument, which is the integer spinner slot to advance.
108             The first spinner is C<0>. The number of spinners on the screen
109             will always automagically expand to include the entire range of
110             C<0> through the highest number you've directly accessed.
111              
112             =cut
113              
114             sub advance {
115             my ($self, $which) = @_;
116              
117             croak "advance() requires a spinner number"
118             if !defined $which;
119              
120             my $spinners = $self->_spinners;
121              
122             if($which > $#$spinners) {
123             push(@$spinners, 0) for (1..($which-$#$spinners));
124             }
125             $spinners->[$which] = ($spinners->[$which] + 1) % $#{$self->spin_chars};
126             $self->draw();
127             }
128              
129             =head2 finish
130              
131             Requires an argument, which is the integer spinner slot to finish.
132             The first spinner is C<0>. The number of spinners on the screen
133             will always automagically expand to include the entire range of
134             C<0> through the highest number you've directly accessed.
135              
136             =cut
137              
138             sub finish {
139             my ($self, $which) = @_;
140              
141             croak "finish() requires a spinner number"
142             if !defined $which;
143              
144             $self->_spinners->[$which] = $#{$self->spin_chars};
145             $self->draw();
146             }
147              
148             =head2 advance_all
149              
150             Calls L</advance> on all spinners.
151              
152             =cut
153              
154             sub advance_all {
155             my ($self) = @_;
156              
157             $self->_suppress_draw(1);
158             $self->advance($_) for (0..$#{$self->_spinners});
159             $self->_suppress_draw(0);
160             $self->draw();
161             }
162              
163             =head2 finish_all
164              
165             Calls L</finish> on all spinners.
166              
167             =cut
168              
169             sub finish_all {
170             my ($self) = @_;
171              
172             $self->_suppress_draw(1);
173             $self->finish($_) for (0..$#{$self->_spinners});
174             $self->_suppress_draw(0);
175             $self->draw();
176             }
177              
178             sub _destruct_cleanup {
179             my ($self) = @_;
180              
181             $self->finish_all if $self->finish_on_destruct;
182             $self->clear if $self->clear_on_destruct;
183             }
184              
185             no Moose;
186              
187             =head1 AUTHOR
188              
189             Brandon L. Black, E<lt>blblack@gmail.comE<gt>
190              
191             =head1 COPYRIGHT AND LICENSE
192              
193             Copyright 2007 Brandon L. Black
194              
195             This library is free software; you can redistribute it and/or modify
196             it under the same terms as Perl itself.
197              
198             =cut
199              
200             1;