File Coverage

blib/lib/Time/Crontab.pm
Criterion Covered Total %
statement 84 85 98.8
branch 22 26 84.6
condition 24 33 72.7
subroutine 19 19 100.0
pod 2 4 50.0
total 151 167 90.4


line stmt bran cond sub pod time code
1             package Time::Crontab;
2              
3 2     2   13668 use 5.008005;
  2         4  
4 2     2   6 use strict;
  2         1  
  2         30  
5 2     2   12 use warnings;
  2         2  
  2         47  
6 2     2   7 use Carp qw/croak/;
  2         1  
  2         109  
7 2     2   945 use List::MoreUtils qw/all any uniq firstidx/;
  2         13988  
  2         10  
8 2     2   1867 use Set::Crontab;
  2         1161  
  2         1746  
9              
10             our $VERSION = "0.04";
11              
12             my @keys = qw/minute hour day month day_of_week/;
13             my @ranges = (
14             [0..59], #minute
15             [0..23], #hour
16             [1..31], #day
17             [1..12], #month
18             [0..7], #day of week
19             );
20             my %month_strs = (
21             jan => 1,
22             feb => 2,
23             mar => 3,
24             apr => 4,
25             may => 5,
26             jun => 6,
27             jul => 7,
28             aug => 8,
29             sep => 9,
30             oct => 10,
31             nov => 11,
32             dec => 12,
33             );
34             my %dow_strs = (
35             sun => 0,
36             mon => 1,
37             tue => 2,
38             wed => 3,
39             thu => 4,
40             fri => 5,
41             sat => 6,
42             );
43              
44             sub includes {
45 132     132 0 156 my ($list,$include) = @_;
46             my %include = map {
47 132         168 $_ => 1
  3669         4835  
48             } @$include;
49 132     1912   949 all { exists $include{$_} } @$list;
  1912         2173  
50             }
51              
52             sub new {
53 31     31 1 973 my ($class,$str) = @_;
54 31         55 my $self = bless {}, $class;
55 31         66 $self->_compile($str);
56 23         68 $self;
57             }
58              
59             sub _compile {
60 31     31   38 my ($self, $str) = @_;
61              
62 31         84 $str =~ s/^\s+//g;
63 31         97 $str =~ s/\s+$//g;
64 31         147 my @rules = split /\s+/, $str;
65 31 100       416 croak 'incorrect cron field:'.$str if @rules != 5;
66 29         30 my %rules;
67 29         29 my $i=0;
68 29         39 for my $rule_o ( @rules ) {
69 136         132 my $rule = $rule_o;
70 136         179 my $key = $keys[$i];
71 136         120 my $range = $ranges[$i];
72 136 100       218 if ( $key eq 'month' ) {
73             my $replace = sub {
74 2     2   5 my $month = lc(shift);
75 2 50       10 exists $month_strs{$month} ? $month_strs{$month} : $month;
76 27         68 };
77 27         75 $rule =~ s!^([a-z]{3})$!$replace->($1);!ie;
  2         3  
78             }
79 136 100       211 if ( $key eq 'day_of_week' ) {
80             my $replace = sub {
81 2     2   6 my $dow = lc(shift);
82 2 50       13 exists $dow_strs{$dow} ? $dow_strs{$dow} : $dow;
83 26         56 };
84 26         88 $rule =~ s!^([a-z]{3})$!$replace->($1)!ie;
  2         5  
85             }
86 136         368 my $set_crontab = Set::Crontab->new($rule, $range);
87 136         7596 my @expand = $set_crontab->list();
88 136 100       1429 croak "bad format $key: $rule_o($rule)" unless @expand;
89 132 100       235 croak "bad range $key: $rule_o($rule)" unless includes(\@expand, $range);
90 130 100       727 if ( $key eq 'day_of_week' ) {
91             #day of week
92 23 100   72   80 if ( any { $_ == 7 } @expand ) {
  72         79  
93 9         16 unshift @expand, 0;
94             }
95 23         139 @expand = uniq @expand;
96             }
97 130         243 $rules{$key} = \@expand;
98 130         493 $i++;
99             }
100              
101 23         64 $self->{rules} = \%rules;
102             }
103              
104             sub _contains {
105 83     83   97 my ($self, $key, $num) = @_;
106 83     394   188 any { $_ == $num } @{$self->{rules}->{$key}};
  394         585  
  83         233  
107             }
108              
109             sub _contains_any {
110 74     74   92 my ($self, $key) = @_;
111 74     280   230 my $key_i = firstidx { $_ eq $key} @keys;
  280         261  
112 74         150 my $range = $ranges[$key_i];
113 74         93 my $rule = $self->{rules}->{$key};
114              
115 74 100       143 if (@$range != @$rule) {
116 42         220 return 0;
117             }
118 32         27 for my $idx (0..$#{$range}) {
  32         82  
119 877 50       1342 if ($range->[$idx] != $rule->[$idx]) {
120 0         0 return 0;
121             }
122             }
123 32         132 return 1;
124             }
125              
126             sub match {
127 19     19 1 19 my $self = shift;
128 19         416 my @lt = localtime($_[0]);
129 19 100 66     56 if ( $self->_contains('minute', $lt[1])
      66        
130             && $self->_contains('hour', $lt[2])
131             && $self->_contains('month', $lt[4]+1) ) {
132             # dow and dom is a bit complicated
133 18 50 100     31 if (
      100        
      66        
      66        
      66        
      100        
      66        
      66        
      33        
134             $self->_contains_any('day') && $self->_contains_any('day_of_week')
135             ||
136             $self->_contains_any('day') && $self->_contains('day_of_week', $lt[6])
137             ||
138             $self->_contains('day', $lt[3]) && $self->_contains_any('day_of_week')
139             ||
140             ! $self->_contains_any('day') && ! $self->_contains_any('day_of_week') && (
141             $self->_contains('day', $lt[3]) || $self->_contains('day_of_week', $lt[6]) )
142             ) {
143 10         203 return 1;
144             }
145 8         236 return;
146             }
147 1         26 return;
148             }
149              
150             sub dump {
151 4     4 0 17 shift->{rules};
152             }
153              
154             1;
155             __END__