File Coverage

blib/lib/ProgressBar/Stack.pm
Criterion Covered Total %
statement 181 195 92.8
branch 40 58 68.9
condition 20 35 57.1
subroutine 25 28 89.2
pod 12 22 54.5
total 278 338 82.2


line stmt bran cond sub pod time code
1             package ProgressBar::Stack;
2            
3             require 5.006;
4            
5             $VERSION = "1.01";
6            
7 1     1   37028 use strict;
  1         2  
  1         43  
8 1     1   5 use warnings;
  1         3  
  1         253  
9            
10             require Exporter;
11             our @ISA = qw(Exporter);
12             our @EXPORT = qw(
13             &init_progress &update_progress &sub_progress &for_progress &file_progress
14             &map_progress &reduce_progress &push_progress &pop_progress
15             );
16            
17 1     1   76262 use Time::HiRes;
  1         2451  
  1         5  
18            
19             use constant {
20 1         1784 PSTART => 0,
21             PEND => 1,
22             PMESSAGE => 2,
23             PFACTOR => 3,
24 1     1   148 };
  1         1  
25            
26             sub new($;%)
27             {
28 9     9 0 925 my $module = shift;
29 9         40 my %param = @_;
30 9         120 my $self = {
31             progressstack => [[0,100,"",1]],
32             starttime => Time::HiRes::time,
33             lastprogresstime => Time::HiRes::time,
34             lastprogress => 0,
35             actuallastprogress => 0,
36             count => 100,
37             minupdatetime => 0.1, # seconds
38             minupdatevalue => 0.1, # percents
39             forceupdatevalue => 1, # percents
40             renderer => \&defRenderer,
41             };
42 9         25 foreach(qw(count minupdatetime minupdatevalue forceupdatevalue)) {
43 36 100       90 if(defined($param{$_})) {
44 11 50       29 if(ref($param{$_}) ne "") {
45 0         0 die "'$_' must be scalar";
46             }
47 11         37 $self->{$_} = $param{$_}*1.;
48             }
49             }
50 9         26 $self->{progressstack}[0][PEND] = $self->{count};
51 9         27 $self->{nextminupdate} = $self->{minupdatevalue} + $self->{lastprogress};
52 9         22 $self->{nextforceupdate} = $self->{forceupdatevalue} + $self->{lastprogress};
53 9         19 $self->{nexttimeupdate} = $self->{minupdatetime} + $self->{lastprogresstime};
54 9 100       22 if(defined($param{message})) {
55 4         12 $self->{progressstack}[0][PMESSAGE] = $param{message};
56             }
57 9 50       26 if(defined($param{renderer})) {
58 9 50       27 if(ref($param{renderer}) ne "CODE") {
59 0         0 die "'renderer' must be 'CODE'";
60             }
61 9         15 $self->{renderer} = $param{renderer};
62             }
63 9         22 bless $self, $module;
64 9         30 &{$self->{renderer}}(0,$self->{progressstack}[0][PMESSAGE],$self);
  9         608  
65 9         84 return $self;
66             }
67            
68             sub defRenderer($;$$)
69             {
70 0     0 0 0 my $val = shift;
71 0         0 my $message = shift;
72 0         0 my $self = shift;
73 0         0 my $progress=sprintf("%5.1f", $val);
74 0         0 my $etatime = $self->remaining_time();
75 0 0       0 my $eta=$etatime>=0?sprintf("%d:%02d", int($etatime/60), int($etatime)%60):"?:??";
76 0         0 local $|=1;
77 0         0 print "\r".(" " x 70)."\r[".("#" x int($progress/5)).(" " x (20-int($progress/5)))."] ${progress}% ETA: $eta ${message}";
78             }
79            
80             sub update($;$$)
81             {
82 187     187 0 365 my ($self, $progress, $action) = @_;
83 187         267 my ($s, $e, $lastaction, $curfactor) = @{$self->{progressstack}[-1]};
  187         625  
84 187 100       602 $progress = $self->{count} if !defined($progress);
85 187 100       627 $action=$lastaction if !defined($action);
86 187         324 $progress=$progress*$curfactor+$s;
87 187         310 $self->{actuallastprogress}=$progress;
88             # Suppress too often updates
89             # Time check should be the last as it's the slowest
90 187 100 100     1607 return if($action eq $lastaction && $progress<$self->{count} &&
      66        
      66        
91             ($progress<$self->{nextminupdate} ||
92             ($progress<$self->{nextforceupdate} &&
93             Time::HiRes::time<$self->{nexttimeupdate}))
94             );
95 183         387 $self->{progressstack}[-1][PMESSAGE]=$action;
96 183 50       493 $self->{lastprogress}=$progress>$self->{count}?$self->{count}:$progress;
97 183         499 $self->{lastprogresstime}=Time::HiRes::time;
98 183         357 $self->{nextminupdate} = $self->{minupdatevalue} + $self->{lastprogress};
99 183         400 $self->{nextforceupdate} = $self->{forceupdatevalue} + $self->{lastprogress};
100 183         324 $self->{nexttimeupdate} = $self->{minupdatetime} + $self->{lastprogresstime};
101 183         360 &{$self->{renderer}}($progress/$self->{count}*100,$action,$self);
  183         687  
102             }
103            
104             sub push($$$)
105             {
106 28     28 0 39 my ($self, $_s, $_e) = @_;
107 28         31 my ($s, $e, $lastaction, $curfactor) = @{$self->{progressstack}[-1]};
  28         69  
108 28         42 $_s=$_s*$curfactor+$s;
109 28         34 $_e=$_e*$curfactor+$s;
110 28 100       28 push @{$self->{progressstack}}, [$_s, $_e, $lastaction, $_e<=$_s?0:($_e-$_s)/$self->{count}];
  28         143  
111             }
112            
113             sub pop($)
114             {
115 28     28 0 35 my $self = shift;
116 28 50       31 if(scalar @{$self->{progressstack}} == 1) {
  28         76  
117 0         0 die "Attempt to pop from empty progress stack!";
118 0         0 return;
119             }
120 28         33 pop @{$self->{progressstack}};
  28         104  
121             }
122            
123             sub sub($&$) {
124 9     9 0 35 my ($self, $code, $end) = @_;
125 9         13 my $start = $self->{actuallastprogress};
126 9         12 my ($s, $e) = @{$self->{progressstack}[-1]};
  9         20  
127 9 50       39 $start = $e<=$s?0:($start-$s)*$self->{count}/($e-$s);
128 9         26 $self->push($start, $end);
129 9         15 my @retval = &{$code}();
  9         26  
130 9         61 $self->update();
131 9         57 $self->pop();
132 9         33 return @retval;
133             }
134            
135             sub for($&@) {
136 15     15 0 80 my $self = shift;
137 15         19 my $code = shift;
138 15         20 my $nelem = scalar @_;
139 15 50       31 return if !$nelem;
140 15         15 local $_;
141 15         19 my $i=0;
142 15         52 my $stepsize = $self->{count}/$nelem*$self->{progressstack}[-1][PFACTOR];
143 15         24 my $curs = $self->{progressstack}[-1][PSTART];
144 15         36 $self->push(0, $self->{count}/$nelem);
145 15         31 my $stacktop = $self->{progressstack}[-1];
146 15         21 foreach(@_) {
147 87 100       1803389 if($i++) {
148             # Time check should be the last as it's the slowest
149 72 50 33     996 $self->update() if $stacktop->[PEND]>=$self->{nextminupdate} &&
      66        
150             ($stacktop->[PEND]>=$self->{nextforceupdate} ||
151             Time::HiRes::time>=$self->{nexttimeupdate});
152 72         405 $stacktop->[PSTART] = $stacktop->[PEND];
153 72         114 $stacktop->[PEND] = $i*$stepsize+$curs;
154             }
155             # Code must be the last operator in the cycle,
156             # because it's allowed to do next or last from there
157 87         91 &{$code}();
  87         176  
158             }
159 15 50       200334 $self->update() if($i);
160 15         109 $self->pop();
161             }
162            
163             sub map($&@) {
164 1     1 0 2 my $self = shift;
165 1         2 my $code = shift;
166 1         3 my $nelem = scalar @_;
167 1 50       4 return {} if !$nelem;
168 1         3 local $_;
169 1         2 my $i=0;
170 1         2 my @res;
171 1         6 my $stepsize = $self->{count}/$nelem*$self->{progressstack}[-1][PFACTOR];
172 1         3 my $curs = $self->{progressstack}[-1][PSTART];
173 1         11 $self->push(0, $self->{count}/$nelem);
174 1         3 my $stacktop = $self->{progressstack}[-1];
175 1         3 foreach(@_) {
176 4 100       46 if($i++) {
177             # Time check should be the last as it's the slowest
178 3 50 33     25 $self->update() if $stacktop->[PEND]>=$self->{nextminupdate} &&
      33        
179             ($stacktop->[PEND]>=$self->{nextforceupdate} ||
180             Time::HiRes::time>=$self->{nexttimeupdate});
181 3         25 $stacktop->[PSTART] = $stacktop->[PEND];
182 3         6 $stacktop->[PEND] = $i*$stepsize+$curs;
183             }
184             # Code must be the last operator in the cycle,
185             # because it's allowed to do next or last from there
186 4         6 CORE::push @res, &{$code}();
  4         10  
187             }
188 1 50       17 $self->update() if($i);
189 1         9 $self->pop();
190 1         6 return @res;
191             }
192            
193             sub reduce($&@) {
194 1     1 0 9 my $self = shift;
195 1         5 my $code = shift;
196 1         3 local $_;
197 1         2 my $i=0;
198 1         8 my $caller = caller;
199 1 50       16 $caller = caller(1) if($caller eq "ProgressBar::Stack");
200 1     1   6 no strict "refs";
  1         3  
  1         74  
201 1         3 local(*{$caller."::a"}) = \my $a;
  1         12  
202 1         4 local(*{$caller."::b"}) = \my $b;
  1         5  
203 1     1   6 use strict "refs";
  1         2  
  1         1172  
204            
205 1         3 $a = shift;
206 1         4 my $nelem = scalar @_;
207 1 50       5 return $a if !$nelem;
208 1         11 my $stepsize = $self->{count}/$nelem*$self->{progressstack}[-1][PFACTOR];
209 1         4 my $curs = $self->{progressstack}[-1][PSTART];
210 1         17 $self->push(0, $self->{count}/$nelem);
211 1         2 my $stacktop = $self->{progressstack}[-1];
212 1         5 foreach (@_) {
213 99999 100       420536 if($i++) {
214             # Time check should be the last as it's the slowest
215 99998 100 66     624606 $self->update() if $stacktop->[PEND]>=$self->{nextminupdate} &&
      66        
216             ($stacktop->[PEND]>=$self->{nextforceupdate} ||
217             Time::HiRes::time>=$self->{nexttimeupdate});
218 99998         124231 $stacktop->[PSTART] = $stacktop->[PEND];
219 99998         155756 $stacktop->[PEND] = $i*$stepsize+$curs;
220             }
221 99999         101176 $b = $_;
222 99999         97454 $a = &{$code}();
  99999         214747  
223             }
224 1 50       16 $self->update() if($i);
225 1         7 $self->pop();
226 1         8702 return $a;
227             }
228            
229             sub file($&*) {
230 2     2 0 4 my $self = shift;
231 2         4 my $code = shift;
232 2         4 my $fh = shift;
233 2         3 my $curpos = tell $fh;
234 2   50     26 my $flength = (stat($fh))[7]||1;
235 2         4 local $_;
236 2         3 my $lastpos = $curpos;
237 2         8 my $stepsize = $self->{count}*$self->{progressstack}[-1][PFACTOR]/$flength;
238 2         4 my $factorstep = $self->{progressstack}[-1][PFACTOR]/$flength;
239 2         5 my $curs = $self->{progressstack}[-1][PSTART];
240 2         8 $self->push($curpos*$self->{count}/$flength, $curpos*$self->{count}/$flength);
241 2         5 my $stacktop = $self->{progressstack}[-1];
242 2         22 while(<$fh>) {
243 19 50 33     168 $self->update() if $stacktop->[PEND]>=$self->{nextminupdate} &&
      66        
244             ($stacktop->[PEND]>=$self->{nextforceupdate} ||
245             Time::HiRes::time>=$self->{nexttimeupdate});
246 19         131 $curpos = tell $fh;
247 19         24 $stacktop->[PSTART] = $stacktop->[PEND];
248 19         35 $stacktop->[PEND] = $curpos*$stepsize+$curs;
249 19         26 $stacktop->[PFACTOR] = ($curpos-$lastpos)*$factorstep;
250 19         22 $lastpos = $curpos;
251             # Code must be the last operator in the cycle,
252             # because it's allowed to do next or last from there
253 19         21 &{$code}();
  19         42  
254             }
255 2         26 $self->update();
256 2         16 $self->pop();
257             }
258            
259             sub running_time($) {
260 11     11 1 162 my $self = shift;
261 11         80 $self->{lastprogresstime} - $self->{starttime};
262             }
263            
264             sub total_time($) {
265 11     11 1 17 my $self = shift;
266 11 100       110 $self->{lastprogress} ? ($self->{lastprogresstime} - $self->{starttime})/$self->{lastprogress}*$self->{count}:-1;
267             }
268            
269             sub remaining_time($) {
270 11     11 1 20 my $self = shift;
271 11 100       94 $self->{lastprogress} ? ($self->{lastprogresstime} - $self->{starttime})/$self->{lastprogress}*($self->{count}-$self->{lastprogress}):-1;
272             }
273            
274             my $curprogress;
275            
276             sub init_progress(%) {
277 8     8 1 83947 $curprogress = new ProgressBar::Stack(@_);
278             }
279            
280             sub update_progress(;$$) {
281 26     26 1 231 $curprogress->update(@_);
282             }
283            
284             sub sub_progress(&$) {
285 7     7 1 1083 return $curprogress->sub(@_);
286             }
287            
288             sub for_progress(&@) {
289 3     3 1 47 $curprogress->for(@_);
290             }
291            
292             sub map_progress(&@) {
293 1     1 1 11 return $curprogress->map(@_);
294             }
295            
296             sub reduce_progress(&@) {
297 1     1 1 10169 return $curprogress->reduce(@_);
298             }
299            
300             sub file_progress(&*) {
301 2     2 1 39 return $curprogress->file(@_);
302             }
303            
304             sub push_progress($$) {
305 0     0 1   $curprogress->push(@_);
306             }
307            
308             sub pop_progress() {
309 0     0 1   $curprogress->pop();
310             }
311            
312             1;
313            
314             =head1 NAME
315            
316             ProgressBar::Stack - Progress bar implementation with stack support and useful loop wrappers
317            
318             =head1 SYNOPSIS
319            
320             use ProgressBar::Stack;
321            
322             init_progress;
323             sleep(1);
324             update_progress 20;
325             sleep(2);
326             update_progress 60;
327             sleep(2);
328             update_progress 100;
329             print "\n";
330            
331             init_progress(message => "Calculating");
332             my $sum = 0;
333             for_progress {
334             $sum+=$_;
335             sleep(1);
336             } 0..10;
337             print "\nSum = $sum\n";
338            
339             =head1 DESCRIPTION
340            
341             C creates a convenient framework for adding progress bars to long processes.
342             Sometimes you have long process which consists of several subprocesses, some of which have
343             cycles (including nested ones), some called several times and so on. If you want to display
344             continuous progress bar from 0% to 100% for such complex process, you will have bad times
345             calculating current percentage for each subprocess. C does much of dirty work
346             for you.
347            
348             Note that C provides only simple console renderer of current progress.
349             If you want to use it in some GUI application, you should write your own renderer and pass it
350             to C (see below).
351            
352             There are two interfaces provided: one is object-oriented, the other is not. Non-OO interface
353             actually creates single object and delegates all calls to it. Practically using non-OO interface is
354             enough in many cases, especially taking into account that different threads will have independent
355             progress bars, but for some windowed applications several progress bars might be necessary.
356            
357             =head2 Non-OO interface
358            
359             All functions of non-OO interface are exported by default.
360            
361             =over 4
362            
363             =item init_progress %parameters
364            
365             Initializes progress bar and updates it to 0%. Parameters (all optional) include:
366            
367             =over 4
368            
369             =item message
370            
371             Default message describing the action performed. This will be passed to
372             renderer and displayed to the user. Can be overridden later by C calls.
373            
374             Default value: empty string.
375            
376             =item count
377            
378             Maximum value for your progress bar. This takes effect when you call C or C.
379             Example:
380            
381             init_progress(count => 2);
382             sleep(1);
383             update_progress(1); # means half of process is done
384             sleep(2);
385             update_progress(2); # means whole process is done
386            
387             Default value: 100.
388            
389             Actually it's better not to use this parameter at all always scaling your progress bar from 0 to 100.
390            
391             =item renderer
392            
393             Subroutine to be called when progress bar should be updated. Note that calling C
394             doesn't mean this C will be called for sure. C may suppress calls to the
395             C in order not to update progress bar too fast.
396            
397             C receives three parameters: C<$value>, C<$message> and C<$progress>. C<$value> is float
398             value between 0 and 100 (regardless of C parameter) which represents current progress.
399             C<$message> is supplementary message describing current action. C<$progress> is progress
400             bar object, which you can use to access some advanced parameters. For example if you want to
401             calculate estimated time, you can use $progress->{starttime} to get time when the process started.
402             See also C, C and C.
403            
404             Default renderer provides simple console output like this:
405            
406             [##### ] 25.0% ETA: 0:05 Message
407            
408             =item minupdatetime
409            
410             Time in seconds during which updates of progress bar (C calls) are disabled unless message
411             changed, progress bar changed more than C (see below) or reached 100%.
412            
413             Default value is 0.1.
414            
415             =item minupdatevalue
416            
417             Progress bar update will be disabled if difference between current and previous value less than this
418             parameter unless message changed or progress bar reached 100%.
419            
420             Default value is 0.1.
421            
422             =item forceupdatevalue
423            
424             Progress bar update will be enabled if difference between current and previous value exceeds this
425             parameter even if C haven't passed yet.
426            
427             Default value is 1.
428            
429             =back
430            
431             =item update_progress VALUE, MESSAGE
432            
433             =item update_progress VALUE
434            
435             =item update_progress
436            
437             Inform progress bar that it should be updated to value C and message should be
438             changed to C. If C is omitted, last message on current stack level will be used:
439            
440             init_progress;
441             update_progress 0, "Outside";
442             sleep 1;
443             update_progress 20; # "Outside" message will be used
444             sleep 1;
445             sub_progress {
446             update_progress 0, "Inside";
447             sleep 1;
448             update_progress 50; # "Inside" message will be used
449             sleep 1;
450             } 70;
451             sleep 1;
452             update_progress 80; # "Outside" message will be used again
453            
454             If VALUE is omitted, then maximal value will be used (specified by C in C, 100
455             by default). Progress bar will be updated for sure if it reached 100% or message changed since last
456             time. Otherwise actual update (call to C) may not be performed depending on
457             C, C and C parameters (see C).
458            
459             =item sub_progress BLOCK, VALUE
460            
461             Pushes current progress bar range and message to the stack, shortens range to C<[curvalue, VALUE]>
462             (where C determined by the latest C call), evaluates block, calls
463             C and pops current state back. This function lets you defining subprocesses, inside
464             which you can use whole range [0, 100] in C calls as for top-level process. Example:
465            
466             init_progress;
467             # This subprocess uses [0, 50] progress bar range
468             sub_progress {
469             sleep 2;
470             # 20% will be displayed, because we're inside subprocess
471             update_progress 40;
472             sleep 2;
473             # 40% will be displayed, because we're inside subprocess
474             update_progress 80;
475             sleep 1;
476             # note that at the end of subprocess update_progress
477             # is called automatically, thus 50% will be displayed
478             } 50;
479             # This subprocess uses [50, 100] progress bar range
480             sub_progress {
481             sleep 1;
482             # 75%
483             update_progress 50;
484             sleep 1;
485             # 100% will be displayed automatically
486             } 100;
487            
488             In general any call of function, which works long enough to update progress by its own, should be
489             wrapped into C, because function should not care whether it's top-level process or
490             part of any subprocess:
491            
492             # Pass of some long process
493             sub pass() {
494             update_progress 0, "Performing pass";
495             sleep(1);
496             update_progress 50;
497             sleep(1);
498             update_progress 100; # just for the case it's top-level process
499             }
500             # Process consisting of two passes:
501             init_progress;
502             sub_progress {pass} 50; # will display 25%, then 50%
503             sub_progress {pass} 100; # will display 75%, then 100%
504            
505             Of course C can be unlimitedly nested. Example:
506            
507             init_progress;
508             sub_progress {
509             sub_progress {
510             update_progress 0, "First step of first step";
511             sleep(1);
512             update_progress 50; # 10% displayed
513             sleep(1);
514             } 40;
515             sub_progress {
516             update_progress 0, "Last step of first step";
517             sleep(1);
518             update_progress 50; # 35% displayed
519             sleep(1);
520             } 100
521             } 50;
522             sub_progress {
523             update_progress 0, "Last step";
524             sleep(1);
525             update_progress 50; # 75% displayed
526             sleep(1);
527             } 100;
528            
529             If C returns value, it will be returned by C.
530            
531             =item for_progress BLOCK, LIST
532            
533             Evaluates C for each element from C, loading its elements consequently into C<$_>. For
534             each iteration C is called reducing the progress bar range to appropriate part assuming
535             that each iteration takes the same time. At the end of iteration C is called
536             automatically. You can use C and C as in normal C cycle. Example:
537            
538             init_progress;
539             for_progress {
540             sleep 1;
541             } 1..10;
542            
543             In this example progress bar will display 10%, 20% and so on till 100%.
544            
545             Inside C you can call C changing C from 0 to 100, which represents
546             progress of current iteration:
547            
548             init_progress;
549             for_progress {
550             update_progress(0, "Processing $_");
551             sleep 1;
552             update_progress(50, "Processing $_");
553             sleep 1;
554             } qw(Banana Apple Pear Grapes);
555            
556             You will see the following sequence of progress bar updates:
557            
558             [ ] 0.0% ETA: ?:?? Processing Banana
559             [## ] 12.5% ETA: 0:06 Processing Banana
560             [##### ] 25.0% ETA: 0:05 Processing Banana
561             [##### ] 25.0% ETA: 0:05 Processing Apple
562             [####### ] 37.5% ETA: 0:04 Processing Apple
563             [########## ] 50.0% ETA: 0:03 Processing Apple
564             [########## ] 50.0% ETA: 0:03 Processing Pear
565             [############ ] 62.5% ETA: 0:03 Processing Pear
566             [############### ] 75.0% ETA: 0:02 Processing Pear
567             [############### ] 75.0% ETA: 0:02 Processing Grapes
568             [################# ] 87.5% ETA: 0:01 Processing Grapes
569             [####################] 100.0% ETA: 0:00 Processing Grapes
570            
571             Of course nested loops work fine also:
572            
573             init_progress;
574             for_progress {
575             for_progress {
576             sleep 1;
577             } 1..$_;
578             } 1..5;
579            
580             Note that this progress bar will become slower to the end as C assumes each iteration
581             takes the same time, but latter iterations of outer C are obviously slower.
582            
583             =item map_progress BLOCK, LIST
584            
585             Similar to C but works like C returning list of processed elements:
586            
587             init_progress();
588             my @lengths = map_progress {
589             sleep(1);
590             length($_);
591             } qw(Banana Apple Pear Grapes);
592            
593             =item reduce_progress BLOCK, LIST
594            
595             Similar to C but works like C returning accumulated value:
596            
597             init_progress(minupdatevalue => 1);
598             print "\nSum of cubes from 1 to 1000000 = ".reduce_progress {$a + $b*$b*$b} 1..1000000;
599            
600             Note that this works much slower than simple C (about 4-5 times as measured).
601             Thus use carefully in cases when single iteration is very short. You may consider optimizing the
602             process decomposing the loop into two nested ones and using progress for outer only like this:
603            
604             use List::Util qw(reduce);
605             init_progress;
606             print "\nSum of cubes from 1 to 1000000 = ".reduce {$a + $b}
607             map_progress {reduce {$a + $b} map {$_*$_*$_} $_*1000-999..$_*1000} 1..1000;
608            
609             =item file_progress BLOCK, FH
610            
611             Similar to C but reads text file by given filehandle C line by line. Progress range
612             is based on current offset inside the file and file size. Thus filesize should be known for this
613             filehandle. Example:
614            
615             init_progress;
616             open(F, "test.txt") || die "$!";
617             my $nbytes = 0;
618             file_progress {
619             $nbytes+=length($_);
620             sleep(1);
621             } \*F;
622             print "\nLength = $nbytes\n";
623            
624             =item push_progress START, END
625            
626             Low-level function to put new progress range into stack. Also the last message is saved there.
627             Generally you shouldn't use it unless you extend capabilities of this module.
628            
629             =item pop_progress
630            
631             Low-level function to remove current progress range from stack, activating previous progress range
632             and message. It will C if you call it on empty stack. Generally you shouldn't use it unless you
633             extend capabilities of this module.
634            
635             =back
636            
637             =head2 Object-oriented interface
638            
639             Object-oriented interface is pretty similar to subroutine interface described above. To get the
640             progress bar object, instead of C you should call C (parameters
641             are the same). All methods of this object are the same as functions above, but without suffix
642             '_progress' in the title (C, C, C, C, C, C, C and C).
643             Parameters are the same except that first parameter is the object. Thus, one of above examples
644             may be rewritten as following:
645            
646             my $p = new ProgressBar::Stack;
647             $p->for(sub {
648             $p->for(sub {
649             sleep 1;
650             }, 1..$_);
651             }, 1..5);
652            
653             =over 4
654            
655             =item running_time
656            
657             =item remaining_time
658            
659             =item total_time
660            
661             These methods return running time (more precisely, time between C or C call and
662             the latest call of the renderer), estimated remaining time and estimated total time. All times are in
663             seconds, float numbers (C is used internally). These methods have no non-OO
664             counterparts as they should be used inside renderer only where object is always available as third
665             parameter. You may use them like this:
666            
667             init_progress(renderer => sub {
668             $progress = $_[2];
669             print "Remaining time: ".$progress->remaining_time()."\n";
670             });
671            
672             Estimated time calculation simply divides running time by current progress value, so estimation will
673             be incorrect if process speed changes significantly. When estimation cannot be calculated (progress is
674             still at 0%) C and C return -1.
675            
676             =back
677            
678             =head1 COPYRIGHT
679            
680             Copyright (c) 2009-2010 Tagir Valeev . All rights reserved.
681             This program is free software; you can redistribute it and/or
682             modify it under the same terms as Perl itself.
683            
684             =cut