File Coverage

blib/lib/Time/R.pm
Criterion Covered Total %
statement 169 226 74.7
branch 69 140 49.2
condition 11 21 52.3
subroutine 23 36 63.8
pod 16 16 100.0
total 288 439 65.6


line stmt bran cond sub pod time code
1 2     2   968 use strict;
  2         5  
  2         54  
2 2     2   9 use warnings;
  2         3  
  2         135  
3             package Time::R;
4             $Time::R::VERSION = '0.024';
5             # ABSTRACT: Handle recurrences.
6              
7             use overload (
8 0     0   0 '""' => sub { shift->to_string; },
9 0     0   0 bool => sub { 1 },
10 2         21 fallback => 1,
11 2     2   17 );
  2         3  
12              
13 2     2   161 use Carp qw/ croak /;
  2         4  
  2         87  
14 2     2   10 use Time::C;
  2         4  
  2         33  
15 2     2   8 use Time::C::Sentinel;
  2         3  
  2         71  
16 2     2   9 use Function::Parameters qw/ :strict /;
  2         3  
  2         13  
17              
18              
19              
20 4 50 33 4 1 24 method new ($c: $start, :$end = undef, :$years = 0, :$months = 0, :$weeks = 0, :$days = 0, :$hours = 0, :$minutes = 0, :$seconds = 0) {
  4 50       30  
  4 100       9  
  4 100       15  
  4 50       12  
  4 50       16  
  4 50       15  
  4 50       29  
  4 50       15  
  4 50       11  
  4         11  
  4         13  
  4         15  
  4         8  
21 4         32 bless({
22             start => $start,
23             end => $end,
24             years => $years,
25             months => $months,
26             weeks => $weeks,
27             days => $days,
28             hours => $hours,
29             minutes => $minutes,
30             seconds => $seconds,
31             }, $c)->_validate_start($start);
32             }
33              
34 4 50   4   14 method _validate_start ($r: $new_start) {
  4 50       15  
  4         8  
  4         8  
  4         8  
35 4 50 33     38 croak "->start(): Not a Time::C object: $new_start" unless ref $new_start and $new_start->isa('Time::C');
36              
37 4         17 return $r;
38             }
39              
40              
41              
42 37 50   37 1 83 method start ($r: $new_start = undef) :lvalue {
  37 50       91  
  37         55  
  37         58  
  37         46  
43             my $setter = sub {
44 0     0   0 $r->_validate_start($_[0])->{start} = $_[0];
45              
46 0 0       0 return $r if defined $new_start;
47 0         0 return $_[0];
48 37         91 };
49              
50 37 50       85 return $setter->($new_start) if defined $new_start;
51              
52 37         102 sentinel value => $r->{start}, set => $setter;
53             }
54              
55              
56 59 50   59 1 127 method current ($r: $new_current = undef) :lvalue {
  59 50       117  
  59         82  
  59         93  
  59         68  
57 59   66     211 my $current = $r->{current} // $r->start->clone();
58              
59             my $setter = sub {
60 29     29   54 $r->{current} = $_[0];
61              
62 29 50       56 return $r if defined $new_current;
63 29         73 return $_[0];
64 59         194 };
65              
66 59 50       133 return $setter->($new_current) if defined $new_current;
67              
68 59         139 sentinel value => $current, set => $setter;
69             }
70              
71              
72 50 50   50 1 107 method end ($r: $new_end = undef) :lvalue {
  50 50       99  
  50         79  
  50         79  
  50         60  
73             my $setter = sub {
74 1     1   2 $r->{end} = $_[0];
75              
76 1 50       4 return $r if defined $new_end;
77 1         3 return $_[0];
78 50         117 };
79              
80 50 50       114 return $setter->($new_end) if defined $new_end;
81              
82 50         115 sentinel value => $r->{end}, set => $setter;
83             }
84              
85              
86 44 50   44 1 100 method years ($r: $new_years = undef) :lvalue {
  44 50       91  
  44         65  
  44         69  
  44         58  
87             my $setter = sub {
88 0     0   0 return $r->{years} = $_[0];
89 44         103 };
90              
91 44 50       95 if (defined $new_years) { $setter->($new_years); return $r; }
  0         0  
  0         0  
92              
93 44         113 sentinel value => $r->{years}, set => $setter;
94             }
95              
96              
97 191 50   191 1 410 method months ($r: $new_months = undef) :lvalue {
  191 50       361  
  191         248  
  191         288  
  191         237  
98             my $setter = sub {
99 0     0   0 return $r->{months} = $_[0];
100 191         419 };
101              
102 191 50       398 if (defined $new_months) { $setter->($new_months); return $r; }
  0         0  
  0         0  
103              
104 191         487 sentinel value => $r->{months}, set => $setter;
105             }
106              
107              
108 29 50   29 1 68 method weeks ($r: $new_weeks = undef) :lvalue {
  29 50       57  
  29         43  
  29         48  
  29         37  
109             my $setter = sub {
110 0     0   0 return $r->{weeks} = $_[0];
111 29         85 };
112              
113 29 50       69 if (defined $new_weeks) { $setter->($new_weeks); return $r; }
  0         0  
  0         0  
114              
115 29         76 sentinel value => $r->{weeks}, set => $setter;
116             }
117              
118              
119 29 50   29 1 69 method days ($r: $new_days = undef) :lvalue {
  29 50       60  
  29         43  
  29         44  
  29         46  
120             my $setter = sub {
121 0     0   0 return $r->{days} = $_[0];
122 29         96 };
123              
124 29 50       70 if (defined $new_days) { $setter->($new_days); return $r; }
  0         0  
  0         0  
125              
126 29         72 sentinel value => $r->{days}, set => $setter;
127             }
128              
129              
130 29 50   29 1 73 method hours ($r: $new_hours = undef) :lvalue {
  29 50       64  
  29         42  
  29         49  
  29         36  
131             my $setter = sub {
132 0     0   0 return $r->{hours} = $_[0];
133 29         71 };
134              
135 29 50       62 if (defined $new_hours) { $setter->($new_hours); return $r; }
  0         0  
  0         0  
136              
137 29         76 sentinel value => $r->{hours}, set => $setter;
138             }
139              
140              
141 29 50   29 1 68 method minutes ($r: $new_minutes = undef) :lvalue {
  29 50       61  
  29         41  
  29         53  
  29         36  
142             my $setter = sub {
143 0     0   0 return $r->{minutes} = $_[0];
144 29         69 };
145              
146 29 50       68 if (defined $new_minutes) { $setter->($new_minutes); return $r; }
  0         0  
  0         0  
147              
148 29         71 sentinel value => $r->{minutes}, set => $setter;
149             }
150              
151              
152 29 50   29 1 71 method seconds ($r: $new_seconds = undef) :lvalue {
  29 50       62  
  29         50  
  29         40  
  29         38  
153             my $setter = sub {
154 0     0   0 return $r->{seconds} = $_[0];
155 29         69 };
156              
157 29 50       66 if (defined $new_seconds) { $setter->($new_seconds); return $r; }
  0         0  
  0         0  
158              
159 29         70 sentinel value => $r->{seconds}, set => $setter;
160             }
161              
162              
163              
164 29 50   29 1 1038 method next ($r:) {
  29 50       67  
  29         44  
  29         38  
165 29         60 my $c = $r->current;
166 29         107 my $n = $r->start->clone;
167              
168 29 100       109 if ($r->years) {
169 5         9 my $i = 1;
170             LOOP: {
171 5         18 my $y = $n->clone;
  15         33  
172 15         32 $y->year += ($r->years * $i++);
173 15 100       67 redo LOOP if $y->epoch <= $c->epoch;
174              
175 5         24 $n = $y;
176             }
177             }
178 29 100       135 if ($r->months) {
179 24         42 my $i = 1;
180             LOOP: {
181 24         30 my $m = $n->clone;
  162         381  
182 162         357 $m->month += ($r->months * $i++);
183 162 100       714 redo LOOP if $m->epoch <= $c->epoch;
184              
185 24         105 $n = $m;
186             }
187             }
188 29 50       136 if ($r->weeks) { do { $n->week += $r->weeks } until $n->epoch > $c->epoch; }
  0         0  
  0         0  
189 29 50       96 if ($r->days) { do { $n->day += $r->days } until $n->epoch > $c->epoch; }
  0         0  
  0         0  
190 29 50       99 if ($r->hours) { do { $n->hour += $r->hours } until $n->epoch > $c->epoch; }
  0         0  
  0         0  
191 29 50       104 if ($r->minutes) { do { $n->minute += $r->minutes } until $n->epoch > $c->epoch; }
  0         0  
  0         0  
192 29 50       92 if ($r->seconds) { do { $n->second += $r->seconds } until $n->epoch > $c->epoch; }
  0         0  
  0         0  
193 29 100 100     106 return undef if defined $r->end and $n->epoch > $r->end->epoch;
194              
195 26         135 $r->current = $n;
196 26         130 return $n;
197             }
198              
199              
200 0 0   0 1 0 method upcoming ($r:) {
  0 0       0  
  0         0  
  0         0  
201 0         0 my $c = $r->current->clone;
202 0         0 $r->latest();
203 0         0 my $n = $r->next();
204 0 0       0 $r->current = $c if not defined $n;
205 0         0 return $n;
206             }
207              
208              
209 0 0   0 1 0 method latest ($r:) {
  0 0       0  
  0         0  
  0         0  
210 0         0 my @until = $r->reset->until(Time::C->now($r->start->tz));
211              
212 0         0 return $until[-1];
213             }
214              
215              
216 1 50   1 1 5 method until ($r: $end) {
  1 50       3  
  1         3  
  1         3  
  1         1  
217 1 50 33     11 croak "\$end is not a Time::C object" unless ref $end and $end->isa('Time::C');
218 1 50 33     4 $end = $r->end if defined $r->end and $r->end->epoch < $end->epoch;
219              
220 1         6 my @results = $r->current();
221 1   66     6 push @results, $_ while ($_ = $r->next() and $_->epoch <= $end->epoch);
222 1 50       9 $r->current = $results[-1] if @results;
223              
224 1         8 return @results;
225             }
226              
227              
228 0 0   0 1   method reset ($r:) {
  0 0          
  0            
  0            
229 0           $r->current = $r->start->clone();
230 0           return $r;
231             }
232              
233             1;
234              
235             __END__