File Coverage

blib/lib/Parse/Crontab/Schedule.pm
Criterion Covered Total %
statement 68 68 100.0
branch 22 24 91.6
condition 3 3 100.0
subroutine 14 14 100.0
pod 3 3 100.0
total 110 112 98.2


line stmt bran cond sub pod time code
1             package Parse::Crontab::Schedule;
2 5     5   55361 use 5.008_001;
  5         17  
  5         210  
3 5     5   25 use strict;
  5         7  
  5         175  
4 5     5   25 use warnings;
  5         7  
  5         141  
5 5     5   26 use Carp;
  5         6  
  5         443  
6 5     5   1482 use Try::Tiny;
  5         3213  
  5         374  
7              
8 5     5   2388 use Parse::Crontab::Schedule::Entity;
  5         499  
  5         222  
9              
10 5     5   43 use Mouse;
  5         8  
  5         69  
11              
12             my @SCHEDULES = qw/minute hour day month day_of_week/;
13              
14             has $_ => (
15             is => 'rw',
16             ) for @SCHEDULES;
17              
18             has user => (
19             is => 'ro',
20             isa => 'Maybe[Str]',
21             );
22              
23             has definition => (
24             is => 'ro',
25             isa => 'Str',
26             );
27              
28 5     5   2324 no Mouse;
  5         12  
  5         30  
29              
30             my %DEFINITIONS = (
31             yearly => '0 0 1 1 *',
32             annually => '0 0 1 1 *',
33             monthly => '0 0 1 * *',
34             weekly => '0 0 * * 0',
35             daily => '0 0 * * *',
36             hourly => '0 * * * *',
37             reboot => '@reboot',
38             );
39              
40             my %ENTITY_PARAMS = (
41             minute => {
42             range => [0,59],
43             },
44             hour => {
45             range => [0,23],
46             },
47             day => {
48             range => [1,31],
49             },
50             month => {
51             range => [1,12],
52             aliases => [qw/jan feb mar apr may jun jul aug sep oct nov dec/],
53             },
54             day_of_week => {
55             range => [0,7],
56             aliases => [qw/sun mon tue wed thu fri sat/],
57             },
58             );
59              
60             sub BUILD {
61 17     17 1 4047 my $self = shift;
62              
63 17         23 my %s;
64 17 100       73 if (my $def = $self->definition) {
65 6         17 my $definition = $DEFINITIONS{$def};
66 6 50       18 croak sprintf('bad time specifier: [%s]', $def) unless $definition;
67              
68 6 100       21 if ($def ne 'reboot') {
69 5         36 @s{@SCHEDULES} = split /\s+/, $definition;
70             }
71             }
72             else {
73 11         145 $s{$_} = $self->$_ for @SCHEDULES;
74             }
75              
76 17 100       71 if (exists $s{minute}) {
77 16         31 for my $schedule (@SCHEDULES) {
78 79         79 my $entity;
79             try {
80 79         1197 $entity = Parse::Crontab::Schedule::Entity->new(
81             entity => $s{$schedule},
82 79     79   2579 %{$ENTITY_PARAMS{$schedule}},
83             field => $schedule,
84             );
85             }
86             catch {
87 2     2   259 croak "bad $schedule: $_";
88 79         537 };
89 77         1404 $self->$schedule($entity);
90             }
91             }
92             }
93              
94             sub parse {
95 3     3 1 3837 my ($cls, $str) = @_;
96              
97 3         14 my @s = split /\s+/, $str;
98 3         6 my %args;
99 3         7 for my $schedule (@SCHEDULES) {
100 15         19 my $arg = shift @s;
101 15         32 $args{$schedule} = $arg;
102             }
103              
104 3         62 my $self = $cls->new(%args);
105              
106 3 100       14 if (my @warns = $self->_check_warnings) {
107 1         28 croak join "\n", @warns;
108             }
109 2         9 $self;
110             }
111              
112             sub _check_warnings {
113 11     11   16 my $self = shift;
114              
115 11         10 my @warnings;
116 11 100       297 if ($self->minute.'' eq '*') {
117 4         10 push @warnings,
118             q{Specifying '*' for minutes means EVERY MINUTES. You really want to do that and to remove this warning, specify '*/1' explicitly.}
119             }
120 11 100 100     41 if ($self->day_of_week.'' ne '*' && $self->day.'' ne '*') {
121 1         3 push @warnings,
122             q{Both specifying 'day_of_week' and 'day' field causes unexpected behavior. You should seperate job entries.}
123             }
124 11         42 @warnings;
125             }
126              
127             sub match {
128 7     7 1 1454 my ($self, %args) = @_;
129              
130 7         18 for my $s (qw/minute hour month/) {
131 19 100       86 return unless $self->$s->match($args{$s});
132             }
133              
134 5 100       28 if ($self->day_of_week.'' ne '*') {
135 2 50       7 croak q{args year is not specified. could detect day_of_week.} unless $args{year};
136              
137 2         705 require Time::Piece;
138 2         29289 my $str = sprintf '%04d-%02d-%02d', $args{year}, $args{month}, $args{day};
139 2         10 my $day = Time::Piece->strptime($str, '%Y-%m-%d');
140              
141 2 100       117 return unless $self->day_of_week->match($day->day_of_week);
142             }
143             else {
144 3 100       13 return unless $self->day->match($args{day});
145             }
146              
147 3         18 1; # matched
148             }
149              
150             __PACKAGE__->meta->make_immutable;
151             __END__