App-JobLog

 view release on metacpan or  search on metacpan

lib/App/JobLog/Command/when.pm  view on Meta::CPAN

use autouse 'Getopt::Long::Descriptive' => qw(prog_name);
use autouse 'App::JobLog::Config'       => qw(
  columns
  is_hidden
  merge
);
use autouse 'App::JobLog::Log::Format' => qw(
  display
  single_interval
  summary
);
use autouse 'App::JobLog::Time' => qw(today now);

use constant FULL_FORMAT      => '%l:%M:%S %p on %A, %B %d, %Y';
use constant SAME_YEAR_FORMAT => '%l:%M:%S %p on %A, %B %d';
use constant SAME_WEEK_FORMAT => '%l:%M:%S %p on %A';
use constant SAME_DAY_FORMAT  => '%l:%M:%S %p';

sub execute {
    my ( $self, $opt, $args ) = @_;

    my $tags          = $opt->tag         || [];
    my $excluded_tags = $opt->exclude_tag || [];
    my $match         = $opt->match       || [];
    my $no_match      = $opt->no_match    || [];

    # validate regexes, if any, while generating test

    my $test =
      App::JobLog::Command::summary::_make_test( $tags, $excluded_tags, $match,
        $no_match, undef );

    # parse time expression
    my $days;
    my $start = ( join ' ', @$args ) || 'today';
    eval { ( $days, undef ) = summary "$start through today", $test, {} };
    $self->usage_error($@) if $@;

    # check for long task
    my ($last_e) = App::JobLog::Log->new->last_event;
    if ( $last_e && $last_e->is_open ) {
        my ( $then, $today ) = ( $last_e->start, today );
        if (
            !(
                   $then->year == $today->year
                && $then->month == $today->month
                && $then->day == $today->day
            )
          )
        {
            print <<END;

WARNING! The last event in the log has been open since before 12:00 am today!

END
        }
    }
    my $remaining = 0;
    $remaining += $_->time_remaining for @$days;
    if ( $remaining == 0 ) {
        say "\nyou are just now done";
    }
    else {
        my $then = now->add( seconds => $remaining );
        my $format;
        if ( $then->year == now->year ) {
            my $delta = abs $then->delta_days(now)->in_units('days');
            if ( $delta > 7 ) {
                $format = SAME_YEAR_FORMAT;
            }
            elsif ( $then->month == now->month && $then->day == now->day ) {
                $format = SAME_DAY_FORMAT;
            }
            else {
                $format = SAME_WEEK_FORMAT;
            }
        }
        else {
            $format = FULL_FORMAT;
        }
        if ( $then < now ) {
            $then = ( $days->[-1]->last_event->end // now )->add( seconds => $remaining );
            say "\nyou were finished at " . $then->strftime($format);
        }
        else {
            say "\nyou will be finished at " . $then->strftime($format);
        }
        print "\n";
    }
}

sub usage_desc { '%c ' . __PACKAGE__->name . ' %o <date or date range>' }

sub abstract {
    'report when work is done for the day';
}

sub full_description {
    <<END
Calculate when you'll be done for the day given how much work you've already done.
If no time expression is provided, all task time since the beginning of the day
is considered. A useful time expression is 'pay period' (equivalently, 'pay', 'payperiod',
or 'pp').

It is possible that you won't want all tasks in the log in the given period included in the 
time worked sum. As with the summary command, events may be filtered in numerous ways: by tag,
or terms used in descriptions.  If tags to match are provided, only those events
that contain at least one such tag will be shown. If tags not to match are provided, only those
events that contain none of these tags will be shown.

If you provide description filters to match or avoid, these will be interpreted as regexes. Try 'perldoc perlre'
for more details, or perhaps 'perldoc perlretut' (these will only work if you have the Perl documentation
installed on your machine). If you don't want to worry about regular expressions, simple strings will work.
Prefix your expression with '(?i)' to turn off case sensitivity. And don't enclose regexes in slashes or any other
sort of delimiter. Use 'ab', not '/ab/' or 'm!ab!', etc. Finally, you may need to enclose your regexes in single quotes
to prevent the shell from trying to interpret them.
END
}

sub options {
    return (
        [
                "Use '@{[prog_name]} help "
              . __PACKAGE__->name
              . '\' to see full details.'
        ],
        [],
        [
            'tag|t=s@',
            'filter events to include only those with given tags; '
              . 'multiple tags may be specified'
        ],
        [
            'exclude-tag|T=s@',
            'filter events to exclude those with given tags; '
              . 'multiple tags may be specified'
        ],
        [
            'match|m=s@',
'filter events to include only those one of whose descriptions matches the given regex; '
              . 'multiple regexes may be specified'
        ],
        [
            'no-match|M=s@',
'filter events to include only those one of whose descriptions do not match the given regex; '
              . 'multiple regexes may be specified'



( run in 0.458 second using v1.01-cache-2.11-cpan-d7a12ab2c7f )