File Coverage

blib/lib/Taskwarrior/Kusarigama/Plugin/Renew.pm
Criterion Covered Total %
statement 49 50 98.0
branch 7 12 58.3
condition n/a
subroutine 14 15 93.3
pod 0 4 0.0
total 70 81 86.4


line stmt bran cond sub pod time code
1             package Taskwarrior::Kusarigama::Plugin::Renew;
2             our $AUTHORITY = 'cpan:YANICK';
3             # ABSTRACT: create a follow-up task upon completion
4             $Taskwarrior::Kusarigama::Plugin::Renew::VERSION = '0.12.0';
5              
6 1     1   144806 use 5.10.0;
  1         7  
7 1     1   5 use strict;
  1         1  
  1         17  
8 1     1   4 use warnings;
  1         1  
  1         22  
9              
10 1     1   340 use Clone 'clone';
  1         1976  
  1         46  
11 1     1   436 use List::AllUtils qw/ any /;
  1         13380  
  1         69  
12              
13 1     1   425 use Moo;
  1         6613  
  1         4  
14 1     1   1508 use MooseX::MungeHas;
  1         3074  
  1         6  
15              
16             extends 'Taskwarrior::Kusarigama::Plugin';
17              
18             with 'Taskwarrior::Kusarigama::Hook::OnExit',
19             'Taskwarrior::Kusarigama::Hook::OnAdd';
20              
21 1     1   1074 use experimental 'postderef';
  1         2743  
  1         4  
22              
23             has custom_uda => sub{ +{
24 0     0   0 renew => 'creates a follow-up task upon closing',
25             rdue => 'next task due date',
26             rwait => "next task 'wait' period",
27             rscheduled => "next task 'scheduled' period",
28             } };
29              
30             sub r_calc {
31 1     1 0 2 my ( $self, $expr ) = @_;
32              
33 1 50       7 if( $expr =~ /
34             ^ (?<cond>.*?) \? (?<true>.*?) : (?<false>.*) $
35             /x ) {
36 1 50   1   642 $expr = $self->calc($+{cond}) eq 'true' ? $+{true} : $+{false};
  1         305  
  1         344  
  1         26  
37             }
38              
39 1         113 return $self->calc($expr);
40             }
41              
42             sub process_exit_task {
43 1     1 0 3 my ( $self, $task ) = @_;
44              
45 1 50   2   6 return unless any { $task->{$_} } qw/ renew rdue rwait rscheduled /;
  2         6  
46              
47 1         389 require Taskwarrior::Kusarigama::Task;
48 1         17 $task = Taskwarrior::Kusarigama::Task->new( $self->tw->run_task, { %$task } )->clone;
49              
50 1         4 delete $task->{$_} for qw/ due wait scheduled /;
51              
52 1         4 $self->on_add($task);
53              
54 1         3 $task->save;
55              
56             printf "created follow-up task %d - '%s'\n",
57 1         51 $task->{id}, $task->{description};
58             }
59              
60             sub on_exit {
61 1     1 0 3423 my( $self, @tasks ) = @_;
62              
63 1 50       27 return unless $self->command eq 'done';
64              
65 1         111 $self->process_exit_task($_) for @tasks;
66             }
67              
68             sub on_add {
69 1     1 0 11 my( $self, $task ) = @_;
70              
71 1         3 for my $field ( qw/ due wait scheduled / ) {
72 3 50       82 next if $task->{$field};
73              
74 3 100       11 my $value = $task->{ 'r' . $field } or next;
75              
76 1         2 my $due = $task->{due};
77              
78 1         3 $value =~ s/due/$due/g;
79              
80 1         4 $task->{$field} = $self->r_calc($value);
81             }
82             }
83              
84             1;
85              
86             __END__
87              
88             =pod
89              
90             =encoding UTF-8
91              
92             =head1 NAME
93              
94             Taskwarrior::Kusarigama::Plugin::Renew - create a follow-up task upon completion
95              
96             =head1 VERSION
97              
98             version 0.12.0
99              
100             =head1 SYNOPSIS
101              
102             $ task add water the plants rdue:now+5d rwait:now+4d
103              
104             =head1 DESCRIPTION
105              
106             The native recurring tasks in Taskwarrior create
107             new tasks after a given lapse of time, no matter if
108             the already-existing task was completed or not.
109              
110             This type of recurrence will create a new instance
111             of the task upon the completion of the previous one.
112             This is useful for tasks where having hard-set
113             periods don't make sense (think 'watering the plants').
114              
115             Note that no susbequent task is created if a task
116             is deleted instead of completed.
117              
118             The plugin creates 4 new UDAs. C<renew>, a boolean
119             indicating that the task should be renewing, and C<rdue>, C<rwait>
120             and C<rscheduled>, the formula for the values to use upon creation/renewal.
121              
122             C<renew> is optional and only required if none of the
123             C<r*> attributes is present.
124              
125             Since the waiting period is often dependent on the due value,
126             as a convenience if the string C<due> is found in C<rwait> or C<rscheduled>,
127             it will be substitued by the C<rdue> value. So
128              
129             $ task add rdue:now+1week rwait:-3days+due Do Laundry
130              
131             # equivalent to
132              
133             $ task add rdue:now+1week rwait:now+1week-3days Do Laundry
134              
135             Why C<-3days+due> and not C<due-3days>? Because it seems that
136             C<task> does some weeeeeird parsing with C<due>.
137              
138             $ task add project:due-b Do Laundry
139             Cannot subtract strings
140              
141             (see L<https://bug.tasktools.org/browse/TW-1900>)
142              
143             =head2 Date calculations
144              
145             This plugin adds a trinary operator to all of the
146             C<r*> attributes.
147              
148             task add do the thing rdue:"eom - now < 1w ? eom+1m : eom"
149              
150             In this example, we want to do the thing at least once a month,
151             but if we do it in the last week of the month, we're satisfied
152             and set the new deadline at the end of next month.
153              
154             =head1 AUTHOR
155              
156             Yanick Champoux <yanick@cpan.org>
157              
158             =head1 COPYRIGHT AND LICENSE
159              
160             This software is copyright (c) 2019, 2018, 2017 by Yanick Champoux.
161              
162             This is free software; you can redistribute it and/or modify it under
163             the same terms as the Perl 5 programming language system itself.
164              
165             =cut