File Coverage

lib/Schedule/Week.pm
Criterion Covered Total %
statement 123 131 93.8
branch 30 34 88.2
condition 4 9 44.4
subroutine 23 24 95.8
pod 0 17 0.0
total 180 215 83.7


line stmt bran cond sub pod time code
1             package Schedule::Week;
2              
3 1     1   32462 use 5.008008;
  1         4  
  1         45  
4 1     1   5 use strict;
  1         2  
  1         36  
5 1     1   5 use warnings;
  1         14  
  1         31  
6              
7 1     1   998 use Readonly;
  1         3511  
  1         79  
8 1     1   7 use Carp;
  1         2  
  1         2641  
9              
10             require Exporter;
11              
12             our @ISA = qw(Exporter);
13              
14             our %EXPORT_TAGS = ( 'days' => [ qw(
15             $MONDAY $TUESDAY $WEDNESDAY $THURSDAY $FRIDAY $SATURDAY $SUNDAY
16             ) ] );
17              
18             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'days'} } );
19              
20             our $VERSION = '1.0';
21              
22             our Readonly::Scalar $SUNDAY = 0;
23             our Readonly::Scalar $MONDAY = 1;
24             our Readonly::Scalar $TUESDAY = 2;
25             our Readonly::Scalar $WEDNESDAY = 3;
26             our Readonly::Scalar $THURSDAY = 4;
27             our Readonly::Scalar $FRIDAY = 5;
28             our Readonly::Scalar $SATURDAY = 6;
29              
30             sub new {
31              
32 8     8 0 16731 my $class = shift;
33              
34 8         34 my $self = {
35             'ts' => _initialize_schedule()
36             };
37              
38 8         36 return bless $self, $class;
39             }
40              
41             # Day convenience accessors
42             sub sunday {
43 20     20 0 13752 my ($self, $hours_array_ref, $state) = @_;
44 20         442 $self->hours_for_day($SUNDAY, $hours_array_ref, $state);
45             }
46              
47             sub monday {
48 15     15 0 11786 my ($self, $hours_array_ref, $state) = @_;
49 15         55 $self->hours_for_day($MONDAY, $hours_array_ref, $state);
50             }
51              
52             sub tuesday {
53 15     15 0 12150 my ($self, $hours_array_ref, $state) = @_;
54 15         65 $self->hours_for_day($TUESDAY, $hours_array_ref, $state);
55             }
56              
57             sub wednesday {
58 15     15 0 12579 my ($self, $hours_array_ref, $state) = @_;
59 15         56 $self->hours_for_day($WEDNESDAY, $hours_array_ref, $state);
60             }
61              
62             sub thursday {
63 15     15 0 12238 my ($self, $hours_array_ref, $state) = @_;
64 15         83 $self->hours_for_day($THURSDAY, $hours_array_ref, $state);
65             }
66              
67             sub friday {
68 15     15 0 9592 my ($self, $hours_array_ref, $state) = @_;
69 15         54 $self->hours_for_day($FRIDAY, $hours_array_ref, $state);
70             }
71              
72             sub saturday {
73 20     20 0 14548 my ($self, $hours_array_ref, $state) = @_;
74 20         59 $self->hours_for_day($SATURDAY, $hours_array_ref, $state);
75             }
76              
77             # set or get hours across all days
78             sub hours {
79              
80 80     80 0 223439 my ($self, $hours_array_ref, $state) = @_;
81              
82 80         124 my @hour_states;
83              
84 80 100       727 if (! defined $hours_array_ref) {
85 1         200 croak 'Missing reference to array of hours to get/set!';
86             }
87              
88 79 100       236 if (ref($hours_array_ref) ne 'ARRAY') {
89 1         88 croak "$hours_array_ref is not a reference to an array!";
90             }
91              
92 78 100       218 if (defined $state) {
93 27 50       84 $state = ($state == 0) ? 0 : 1;
94 27         76 for my $day ($SUNDAY ... $SATURDAY) {
95 189         296 $hour_states[$day] = [];
96 189         438 for my $hour (@{$hours_array_ref}) {
  189         278  
97 364         649 $self->{'ts'}->[$day]->[$hour] = $state;
98 364         712 push(@{$hour_states[$day]}, $state);
  364         17542  
99             }
100             }
101             }
102              
103              
104 78 100       200 if (scalar(@hour_states) == 0) {
105 51         91 for my $day ($SUNDAY ... $SATURDAY) {
106 357         1120 $hour_states[$day] = [];
107 357         390 for my $hour (@{$hours_array_ref}) {
  357         680  
108 385         355 push(@{$hour_states[$day]},
  385         2161  
109             $self->{'ts'}->[$day]->[$hour]);
110             }
111             }
112             }
113              
114 78         509 return @hour_states;
115             }
116              
117             # Reset all bits in arrays to 0
118             sub reset {
119 3     3 0 14422 my $self = shift;
120 3         10 $self->{'ts'} = _initialize_schedule();
121             }
122              
123             # Does this day have any hours scheduled?
124             sub has_hours {
125              
126 35     35 0 12188 my ($self, $day) = @_;
127              
128 35 50 33     175 if (($day < $SUNDAY) || ($day > $SATURDAY)) {
129 0         0 croak "Day number $day is invalid";
130             }
131              
132 35         35 return grep(/1/, @{$self->{'ts'}->[$day]});
  35         481  
133             }
134              
135             sub hours_for_day {
136 235     235 0 208385 my ($self, $day, $hours_ref, $state) = @_;
137              
138 235 50 33     1578 if (($day < $SUNDAY) || ($day > $SATURDAY)) {
139 0         0 croak "Day number $day is invalid";
140             }
141              
142 235 50 66     2310 if ((defined $hours_ref) && (ref($hours_ref) ne 'ARRAY')) {
143 0         0 croak "$hours_ref is not a reference to an array!";
144             }
145              
146 235         393 my @hour_states = ();
147              
148             # Want all hour states for the day
149 235 100       525 if (! defined $hours_ref) {
150 14         20 return @{$self->{'ts'}->[$day]};
  14         870  
151             }
152              
153 221 100       408 if (defined($state)) {
154 31 100       206 $state = ($state == 0) ? 0 : 1;
155 31         43 for my $h (@{$hours_ref}) {
  31         72  
156 109         176 $self->{'ts'}->[$day]->[$h] = $state;
157 109         214 push(@hour_states, $self->{'ts'}->[$day]->[$h]);
158             }
159             }
160              
161 221 100       506 if (scalar(@hour_states) == 0) {
162 190         328 for my $h (@{$hours_ref}) {
  190         372  
163 352         1056 push(@hour_states, $self->{'ts'}->[$day]->[$h]);
164             }
165             }
166              
167 221         1150 return @hour_states;
168             }
169              
170             # Return 1 or 0 to indicate if the passed in time falls in the
171             # active periods of this schedule. If no time stamp is passed
172             # in, defaults to now.
173              
174             sub is_active {
175              
176 4     4 0 26 my ($self, $ts) = @_;
177              
178             # Default to now
179 4 100       15 $ts = time() if not defined $ts;
180 4         335 my ($hr, $day) = (localtime())[2, 6];
181              
182 4 100       43 return ($self->{'ts'}->[$day]->[$hr] == 1) ? 1 : 0;
183             }
184              
185             # Serialize a schedule into a string of 168 1s and 0s
186              
187             sub serialize {
188 4     4 0 1040 my $self = shift;
189              
190 4         8 my $serialized = "";
191              
192 4         10 for my $day ($SUNDAY ... $SATURDAY) {
193 28         107 $serialized .= join('', @{$self->{'ts'}->[$day]});
  28         226  
194             }
195              
196 4         19 return $serialized;
197             }
198              
199             # Return an instantiated schedule made from the passed in
200             # serialized string
201              
202             sub deserialize {
203 5     5 0 10165 my $serialized = shift;
204              
205 5 100       18 if (! defined $serialized) {
206 1         186 croak "Must pass in a serialized schedule!";
207             }
208              
209 4 100       18 if (length($serialized) != 168) {
210 1         153 croak "Passed in serialized schedule is not 168 hours (chars) long!";
211             }
212              
213 3 100       23 if ($serialized =~ m/[^01]+/) {
214 1         157 croak "Passed in serialized schedule must be all 1s and 0s";
215             }
216              
217 2         6 my $offset = 0;
218              
219 2         3 my $hours_in_day = 24;
220              
221 2         11 my $schedule = Schedule::Week->new();
222              
223             # Localize for map() in loop below
224 2         3 local $_;
225              
226 2         9 for my $day ($SUNDAY ... $SATURDAY) {
227 14         28 my $day_template = substr($serialized, $offset, $hours_in_day);
228              
229             # Explicitly convert to integers to keep perl from guessing that
230             # values are 1 character strings
231 14         79 my @hours = map { int($_); } (split('', $day_template));
  336         749  
232              
233 14         65 $schedule->{'ts'}->[$day] = \@hours;
234 14         41 $offset += $hours_in_day;
235             }
236              
237 2         8 return $schedule;
238             }
239              
240             # Set hours on or off for all weekdays in one shot or retrieve values
241             # for same.
242             sub weekday_hours {
243 0     0 0 0 my ($self, $hours_ref, $state) = @_;
244              
245 0         0 my @results;
246              
247 0         0 for my $day ($MONDAY ... $FRIDAY) {
248 0         0 push(@results, [$self->hours_for_day($day, $hours_ref, $state)]);
249             }
250              
251 0         0 return @results;
252             }
253              
254             # Set hours on or off for all weekends in one shot or retrieve values for
255             # same.
256             sub weekend_hours {
257 1     1 0 4122 my ($self, $hours_ref, $state) = @_;
258              
259 1         3 my @results;
260              
261 1         3 for my $day ($SATURDAY, $SUNDAY) {
262 2         5 push(@results, [$self->hours_for_day($day, $hours_ref, $state)]);
263             }
264              
265 1         4 return @results;
266             }
267              
268             ### Private methods
269             sub _initialize_schedule {
270              
271 11     11   25 my @schedule = ();
272 11         35 $schedule[$SUNDAY] = _initialize_hours(0);
273 11         26 $schedule[$MONDAY] = _initialize_hours(0);
274 11         23 $schedule[$TUESDAY] = _initialize_hours(0);
275 11         28 $schedule[$WEDNESDAY] = _initialize_hours(0);
276 11         26 $schedule[$THURSDAY] = _initialize_hours(0);
277 11         176 $schedule[$FRIDAY] = _initialize_hours(0);
278 11         25 $schedule[$SATURDAY] = _initialize_hours(0);
279              
280 11         46 return \@schedule;
281             }
282              
283             sub _initialize_hours {
284              
285 77     77   152 my $v = shift;
286              
287             return [
288             # Hours of day, starting with 12 AM (hour 00 aka midnight)
289 77         390 $v, $v, $v, $v, $v, $v, $v, $v,
290             $v, $v, $v, $v, $v, $v, $v, $v,
291             $v, $v, $v, $v, $v, $v, $v, $v,
292             ];
293              
294             }
295              
296             1;