Developer-Dashboard
view release on metacpan or search on metacpan
lib/Developer/Dashboard/CLI/Progress.pm view on Meta::CPAN
package Developer::Dashboard::CLI::Progress;
use strict;
use warnings;
our $VERSION = '3.14';
# new(%args)
# Constructs a terminal progress renderer for restart/stop lifecycle commands.
# Input: title string, arrayref of task hashes, output stream handle, and dynamic flag.
# Output: Developer::Dashboard::CLI::Progress object.
sub new {
my ( $class, %args ) = @_;
my $tasks = $args{tasks} || [];
die 'Progress tasks must be an array reference' if ref($tasks) ne 'ARRAY';
my @order = map { $_->{id} } @{$tasks};
my %task_lookup = map {
my $task = $_;
my $id = $task->{id} || die 'Progress task missing id';
$id => {
id => $id,
label => $task->{label} || $id,
status => 'pending',
}
} @{$tasks};
my $stream = $args{stream} || \*STDERR;
my $self = bless {
title => $args{title} || 'dashboard progress',
order => \@order,
tasks => \%task_lookup,
stream => $stream,
dynamic => $args{dynamic} ? 1 : 0,
color => $args{color} ? 1 : 0,
rendered => 0,
}, $class;
$self->render;
return $self;
}
# callback()
# Returns a callback that updates task state from runtime lifecycle events.
# Input: none.
# Output: coderef that accepts one hash reference event.
sub callback {
my ($self) = @_;
return sub {
my ($event) = @_;
$self->update($event);
};
}
# update($event)
# Applies one lifecycle progress event to the tracked task board.
# Input: hash reference with task_id, status, and optional label.
# Output: true value.
sub update {
my ( $self, $event ) = @_;
return 1 if !$event || ref($event) ne 'HASH';
my $id = $event->{task_id} || return 1;
my $task = $self->{tasks}{$id} || return 1;
$task->{status} = $event->{status} if defined $event->{status} && $event->{status} ne '';
$task->{label} = $event->{label} if defined $event->{label} && $event->{label} ne '';
$self->render;
return 1;
}
# finish()
# Finalizes the rendered board by ensuring a trailing newline after dynamic redraws.
# Input: none.
# Output: true value.
sub finish {
my ($self) = @_;
return 1 if !$self->{dynamic} || !$self->{rendered};
my $stream = $self->{stream};
print {$stream} "\n";
return 1;
}
# render()
# Renders the full task board to the configured output stream.
# Input: none.
# Output: true value.
sub render {
my ($self) = @_;
my $stream = $self->{stream};
my $board = $self->render_text;
if ( $self->{dynamic} && $self->{rendered} ) {
my $line_count = scalar( split /\n/, $board );
for ( 1 .. $line_count ) {
print {$stream} "\e[1A\e[2K";
}
}
print {$stream} $board;
$self->{rendered} = 1;
return 1;
}
# render_text()
# Builds the current task board text for terminal output.
# Input: none.
# Output: multi-line string.
sub render_text {
my ($self) = @_;
my @lines = ( $self->{title} );
for my $id ( @{ $self->{order} } ) {
my $task = $self->{tasks}{$id} || next;
my $prefix = $self->_status_prefix( $task->{status} );
push @lines, sprintf '%s %s', $self->_colorize( $prefix, $task->{status} ), $task->{label};
}
return join( "\n", @lines ) . "\n";
}
# _status_prefix($status)
# Maps one task status to the terminal marker shown beside the task label.
# Input: status string.
# Output: short ASCII marker string.
( run in 2.142 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )