File Coverage

blib/lib/App/JobLog/Command/when.pm
Criterion Covered Total %
statement 39 78 50.0
branch 0 16 0.0
condition 0 25 0.0
subroutine 13 18 72.2
pod 3 5 60.0
total 55 142 38.7


line stmt bran cond sub pod time code
1             package App::JobLog::Command::when;
2             $App::JobLog::Command::when::VERSION = '1.040';
3             # ABSTRACT: when you'll be done for the day
4              
5 2     2   1643 use App::JobLog -command;
  2         4  
  2         15  
6 2     2   736 use Modern::Perl;
  2         4  
  2         12  
7 2         11 use Class::Autouse qw(
8             App::JobLog::Log
9             App::JobLog::Log::Day
10 2     2   223 );
  2         4  
11 2     2   122 use autouse 'App::JobLog::TimeGrammar' => qw(parse daytime);
  2         3  
  2         13  
12 2     2   148 use autouse 'Carp' => qw(carp);
  2         4  
  2         9  
13 2     2   165 use autouse 'Getopt::Long::Descriptive' => qw(prog_name);
  2         4  
  2         8  
14 2         8 use autouse 'App::JobLog::Config' => qw(
15             columns
16             is_hidden
17             merge
18 2     2   110 );
  2         4  
19 2         9 use autouse 'App::JobLog::Log::Format' => qw(
20             display
21             single_interval
22             summary
23 2     2   177 );
  2         4  
24 2     2   174 use autouse 'App::JobLog::Time' => qw(today now);
  2         4  
  2         9  
25              
26 2     2   158 use constant FULL_FORMAT => '%l:%M:%S %p on %A, %B %d, %Y';
  2         11  
  2         104  
27 2     2   9 use constant SAME_YEAR_FORMAT => '%l:%M:%S %p on %A, %B %d';
  2         4  
  2         99  
28 2     2   10 use constant SAME_WEEK_FORMAT => '%l:%M:%S %p on %A';
  2         4  
  2         83  
29 2     2   9 use constant SAME_DAY_FORMAT => '%l:%M:%S %p';
  2         4  
  2         1986  
30              
31             sub execute {
32 0     0 1   my ( $self, $opt, $args ) = @_;
33              
34 0   0       my $tags = $opt->tag || [];
35 0   0       my $excluded_tags = $opt->exclude_tag || [];
36 0   0       my $match = $opt->match || [];
37 0   0       my $no_match = $opt->no_match || [];
38              
39             # validate regexes, if any, while generating test
40              
41 0           my $test =
42             App::JobLog::Command::summary::_make_test( $tags, $excluded_tags, $match,
43             $no_match, undef );
44              
45             # parse time expression
46 0           my $days;
47 0   0       my $start = ( join ' ', @$args ) || 'today';
48 0           eval { ( $days, undef ) = summary "$start through today", $test, {} };
  0            
49 0 0         $self->usage_error($@) if $@;
50              
51             # check for long task
52 0           my ($last_e) = App::JobLog::Log->new->last_event;
53 0 0 0       if ( $last_e && $last_e->is_open ) {
54 0           my ( $then, $today ) = ( $last_e->start, today );
55 0 0 0       if (
      0        
56             !(
57             $then->year == $today->year
58             && $then->month == $today->month
59             && $then->day == $today->day
60             )
61             )
62             {
63 0           print <
64              
65             WARNING! The last event in the log has been open since before 12:00 am today!
66              
67             END
68             }
69             }
70 0           my $remaining = 0;
71 0           $remaining += $_->time_remaining for @$days;
72 0 0         if ( $remaining == 0 ) {
73 0           say "\nyou are just now done";
74             }
75             else {
76 0           my $then = now->add( seconds => $remaining );
77 0           my $format;
78 0 0         if ( $then->year == now->year ) {
79 0           my $delta = abs $then->delta_days(now)->in_units('days');
80 0 0 0       if ( $delta > 7 ) {
    0          
81 0           $format = SAME_YEAR_FORMAT;
82             }
83             elsif ( $then->month == now->month && $then->day == now->day ) {
84 0           $format = SAME_DAY_FORMAT;
85             }
86             else {
87 0           $format = SAME_WEEK_FORMAT;
88             }
89             }
90             else {
91 0           $format = FULL_FORMAT;
92             }
93 0 0         if ( $then < now ) {
94 0   0       $then = ( $days->[-1]->last_event->end // now )->add( seconds => $remaining );
95 0           say "\nyou were finished at " . $then->strftime($format);
96             }
97             else {
98 0           say "\nyou will be finished at " . $then->strftime($format);
99             }
100 0           print "\n";
101             }
102             }
103              
104 0     0 1   sub usage_desc { '%c ' . __PACKAGE__->name . ' %o ' }
105              
106             sub abstract {
107 0     0 1   'report when work is done for the day';
108             }
109              
110             sub full_description {
111             <
112             Calculate when you'll be done for the day given how much work you've already done.
113             If no time expression is provided, all task time since the beginning of the day
114             is considered. A useful time expression is 'pay period' (equivalently, 'pay', 'payperiod',
115             or 'pp').
116              
117             It is possible that you won't want all tasks in the log in the given period included in the
118             time worked sum. As with the summary command, events may be filtered in numerous ways: by tag,
119             or terms used in descriptions. If tags to match are provided, only those events
120             that contain at least one such tag will be shown. If tags not to match are provided, only those
121             events that contain none of these tags will be shown.
122              
123             If you provide description filters to match or avoid, these will be interpreted as regexes. Try 'perldoc perlre'
124             for more details, or perhaps 'perldoc perlretut' (these will only work if you have the Perl documentation
125             installed on your machine). If you don't want to worry about regular expressions, simple strings will work.
126             Prefix your expression with '(?i)' to turn off case sensitivity. And don't enclose regexes in slashes or any other
127             sort of delimiter. Use 'ab', not '/ab/' or 'm!ab!', etc. Finally, you may need to enclose your regexes in single quotes
128             to prevent the shell from trying to interpret them.
129             END
130 0     0 0   }
131              
132             sub options {
133             return (
134             [
135 0     0 0   "Use '@{[prog_name]} help "
  0            
136             . __PACKAGE__->name
137             . '\' to see full details.'
138             ],
139             [],
140             [
141             'tag|t=s@',
142             'filter events to include only those with given tags; '
143             . 'multiple tags may be specified'
144             ],
145             [
146             'exclude-tag|T=s@',
147             'filter events to exclude those with given tags; '
148             . 'multiple tags may be specified'
149             ],
150             [
151             'match|m=s@',
152             'filter events to include only those one of whose descriptions matches the given regex; '
153             . 'multiple regexes may be specified'
154             ],
155             [
156             'no-match|M=s@',
157             'filter events to include only those one of whose descriptions do not match the given regex; '
158             . 'multiple regexes may be specified'
159             ],
160             [ 'no-vacation|V', 'do not display vacation hours' ],
161             );
162             }
163              
164             1;
165              
166             =pod
167              
168             =encoding UTF-8
169              
170             =head1 NAME
171              
172             App::JobLog::Command::when - when you'll be done for the day
173              
174             =head1 VERSION
175              
176             version 1.040
177              
178             =head1 SYNOPSIS
179              
180             houghton@NorthernSpy:~job when --help
181             job
182              
183             job when [-MmTtV] [long options...]
184             Use 'job help when' to see full details.
185            
186             -t --tag filter events to include only those with given
187             tags; multiple tags may be specified
188             -T --exclude-tag filter events to exclude those with given tags;
189             multiple tags may be specified
190             -m --match filter events to include only those one of
191             whose descriptions matches the given regex;
192             multiple regexes may be specified
193             -M --no-match filter events to include only those one of
194             whose descriptions do not match the given
195             regex; multiple regexes may be specified
196             -V --no-vacation do not display vacation hours
197             --help this usage screen
198             houghton@NorthernSpy:~$ job w payperiod
199            
200             you will be finished at 7:17:32 pm
201              
202             =head1 DESCRIPTION
203              
204             B says when you will be able to punch out for the day. It does this by iterating over
205             the days in some range of dates, adding up the time worked and subtracted the work hours expected. If no argument
206             is given, the range only includes the current day. (See the C parameter of L.)
207             If you wish to use the pay period as your interval, you need to have defined the C parameter of
208             L.
209              
210             Various options are provided to facilitate eliminating certain tasks from the calculation. This is useful if you
211             have more than one employer and you are committed to working a certain number of hours a day for each.
212              
213             =head1 ACKNOWLEDGEMENTS
214              
215             This command was inspired by my wife Paula, who frequently wanted to know when I'd be done for the day. In an earlier
216             incarnation of this application one obtained it by passing in the option C<-p> and I knew it as the Paula feature.
217              
218             =head1 SEE ALSO
219              
220             L, L, L, L,
221             L
222              
223             =head1 AUTHOR
224              
225             David F. Houghton
226              
227             =head1 COPYRIGHT AND LICENSE
228              
229             This software is copyright (c) 2011 by David F. Houghton.
230              
231             This is free software; you can redistribute it and/or modify it under
232             the same terms as the Perl 5 programming language system itself.
233              
234             =cut
235              
236             __END__