when-cron 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +5 -2
- data/lib/when-cron/cron/cron.rb +19 -18
- data/lib/when-cron/cron/cron_part.rb +30 -1
- data/lib/when-cron/cron/validator.rb +112 -0
- data/spec/lib/when/cron/cron_part_spec.rb +15 -0
- data/spec/lib/when/cron/cron_spec.rb +26 -0
- data/spec/lib/when/cron/validator_spec.rb +108 -0
- data/spec/spec_helper.rb +0 -3
- data/when-cron.gemspec +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 420cf2151fc72d5f0b8826761b8b5f0a826539d0
|
4
|
+
data.tar.gz: 43452faf5af725c4c9b6e73a123beea17ac51285
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b9b1fb00c0b8239626e911b6d438eb97573571825977f05d910a15d7b1ac0e56d6fe6f8baf77fc1ea2fab95af4a390c1a821893b4b47a254d08f68f4df8710e7
|
7
|
+
data.tar.gz: 8c230d9008b79afc09e9d1a48d36fc853a644a3b9bb031498ccd2f533fdbcfe744180b879027d8fddbb7bea132ca98bff082dbfb098b358341c9cf44c2c7b303
|
data/README.md
CHANGED
@@ -22,11 +22,14 @@ Compare to anything that has an interface like Ruby's Time class with ==.
|
|
22
22
|
|
23
23
|
```When::Cron.new('* * * * *') == Time.now # => true```
|
24
24
|
|
25
|
-
|
25
|
+
Numbers, *, and abbreviations (SUN, JAN, etc) are supported for values.
|
26
|
+
|
27
|
+
, - and / are supported as operators.
|
26
28
|
|
27
29
|
```When::Cron.valid?('a b c d e') # => false```
|
30
|
+
```When::Cron.valid('a b c d e') # => nil```
|
28
31
|
|
29
|
-
When::Cron will
|
32
|
+
When::Cron will only validate your string when specifically asked. This allows faster analysis of previously validated strings, but might lead to silent failures for invalid strings.
|
30
33
|
|
31
34
|
```When::Cron.new('100 * * * *') == Time.now # => false```
|
32
35
|
|
data/lib/when-cron/cron/cron.rb
CHANGED
@@ -1,35 +1,36 @@
|
|
1
1
|
module When
|
2
2
|
class Cron
|
3
3
|
def self.valid?(cron)
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
true
|
4
|
+
Validator.valid?(cron)
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.valid(cron)
|
8
|
+
new(cron) if valid?(cron)
|
10
9
|
end
|
11
10
|
|
12
11
|
def initialize(cron)
|
13
|
-
|
12
|
+
@cron = cron
|
14
13
|
end
|
15
14
|
|
16
15
|
def ==(time)
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
16
|
+
@parsed ||= parse(@cron)
|
17
|
+
|
18
|
+
@minute == time.min &&
|
19
|
+
@hour == time.hour &&
|
20
|
+
@day == time.day &&
|
21
|
+
@month == time.month &&
|
22
|
+
@wday == time.wday
|
24
23
|
end
|
25
24
|
|
25
|
+
private
|
26
|
+
|
26
27
|
def parse(string)
|
27
28
|
strings = string.split(' ')
|
28
29
|
@minute = CronPart.new(strings[0])
|
29
|
-
@hour
|
30
|
-
@day
|
31
|
-
@month
|
32
|
-
@wday
|
30
|
+
@hour = CronPart.new(strings[1])
|
31
|
+
@day = CronPart.new(strings[2])
|
32
|
+
@month = CronPart.new(strings[3])
|
33
|
+
@wday = CronPart.new(strings[4])
|
33
34
|
end
|
34
35
|
end
|
35
36
|
end
|
@@ -2,11 +2,36 @@ module When
|
|
2
2
|
class CronPart
|
3
3
|
class InvalidString < StandardError; end
|
4
4
|
|
5
|
+
REMAP = {
|
6
|
+
'SUN' => '0',
|
7
|
+
'MON' => '1',
|
8
|
+
'TUE' => '2',
|
9
|
+
'WED' => '3',
|
10
|
+
'THU' => '4',
|
11
|
+
'FRI' => '5',
|
12
|
+
'SAT' => '6',
|
13
|
+
|
14
|
+
'JAN' => '1',
|
15
|
+
'FEB' => '2',
|
16
|
+
'MAR' => '3',
|
17
|
+
'APR' => '4',
|
18
|
+
'MAY' => '5',
|
19
|
+
'JUN' => '6',
|
20
|
+
'JUL' => '7',
|
21
|
+
'AUG' => '8',
|
22
|
+
'SEP' => '9',
|
23
|
+
'OCT' => '10',
|
24
|
+
'NOV' => '11',
|
25
|
+
'DEC' => '12',
|
26
|
+
}
|
27
|
+
|
5
28
|
def initialize(cron_part)
|
29
|
+
@cron_part = cron_part
|
6
30
|
@part = parse(cron_part)
|
7
31
|
end
|
8
32
|
|
9
33
|
def ==(int)
|
34
|
+
@part ||= parse(@cron_part)
|
10
35
|
@part == int
|
11
36
|
end
|
12
37
|
|
@@ -22,10 +47,14 @@ module When
|
|
22
47
|
elsif cron_part == '*'
|
23
48
|
Wildcard.new
|
24
49
|
else
|
25
|
-
|
50
|
+
to_int(cron_part)
|
26
51
|
end
|
27
52
|
end
|
28
53
|
|
54
|
+
def to_int(cron_part)
|
55
|
+
to_valid_int(REMAP[cron_part.upcase] || cron_part)
|
56
|
+
end
|
57
|
+
|
29
58
|
def to_valid_int(cron_part)
|
30
59
|
int = cron_part.to_i
|
31
60
|
if int.to_s == cron_part
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module When
|
2
|
+
class Cron
|
3
|
+
class Validator
|
4
|
+
MONTHS = {
|
5
|
+
'JAN' => '1',
|
6
|
+
'FEB' => '2',
|
7
|
+
'MAR' => '3',
|
8
|
+
'APR' => '4',
|
9
|
+
'MAY' => '5',
|
10
|
+
'JUN' => '6',
|
11
|
+
'JUL' => '7',
|
12
|
+
'AUG' => '8',
|
13
|
+
'SEP' => '9',
|
14
|
+
'OCT' => '10',
|
15
|
+
'NOV' => '11',
|
16
|
+
'DEC' => '12',
|
17
|
+
}
|
18
|
+
|
19
|
+
WDAYS = {
|
20
|
+
'SUN' => '0',
|
21
|
+
'MON' => '1',
|
22
|
+
'TUE' => '2',
|
23
|
+
'WED' => '3',
|
24
|
+
'THU' => '4',
|
25
|
+
'FRI' => '5',
|
26
|
+
'SAT' => '6',
|
27
|
+
}
|
28
|
+
|
29
|
+
NOT_BASIC_CHARS = /[^\d,\/\*\-]/
|
30
|
+
NOT_BASIC_OR_LETTERS = /[^\d,\/\*\-a-zA-Z]/
|
31
|
+
|
32
|
+
def self.valid?(cron)
|
33
|
+
v = new(cron)
|
34
|
+
v.correct_number_of_parts? &&
|
35
|
+
v.min_correct? &&
|
36
|
+
v.hour_correct? &&
|
37
|
+
v.day_correct? &&
|
38
|
+
v.month_correct? &&
|
39
|
+
v.wday_correct?
|
40
|
+
end
|
41
|
+
|
42
|
+
attr_reader :cron
|
43
|
+
|
44
|
+
def initialize(cron)
|
45
|
+
@cron = cron
|
46
|
+
end
|
47
|
+
|
48
|
+
def parts
|
49
|
+
@parts ||= cron.split(' ')
|
50
|
+
end
|
51
|
+
|
52
|
+
def min
|
53
|
+
parts[0]
|
54
|
+
end
|
55
|
+
|
56
|
+
def hour
|
57
|
+
parts[1]
|
58
|
+
end
|
59
|
+
|
60
|
+
def day
|
61
|
+
parts[2]
|
62
|
+
end
|
63
|
+
|
64
|
+
def month
|
65
|
+
parts[3]
|
66
|
+
end
|
67
|
+
|
68
|
+
def wday
|
69
|
+
parts[4]
|
70
|
+
end
|
71
|
+
|
72
|
+
def correct_number_of_parts?
|
73
|
+
cron.split(' ').count == 5
|
74
|
+
end
|
75
|
+
|
76
|
+
def min_correct?
|
77
|
+
correct_range?(min, 0..59) &&
|
78
|
+
!(min =~ NOT_BASIC_CHARS)
|
79
|
+
end
|
80
|
+
|
81
|
+
def hour_correct?
|
82
|
+
correct_range?(hour, 0..23) &&
|
83
|
+
!(hour =~ NOT_BASIC_CHARS)
|
84
|
+
end
|
85
|
+
|
86
|
+
def day_correct?
|
87
|
+
correct_range?(day, 1..31) &&
|
88
|
+
!(day =~ NOT_BASIC_CHARS)
|
89
|
+
end
|
90
|
+
|
91
|
+
def month_correct?
|
92
|
+
correct_range?(month, 1..12) &&
|
93
|
+
month.scan(/[a-zA-Z]+/).all? { |w| MONTHS[w.upcase] } &&
|
94
|
+
!(month =~ NOT_BASIC_OR_LETTERS)
|
95
|
+
end
|
96
|
+
|
97
|
+
def wday_correct?
|
98
|
+
correct_range?(wday, 0..6) &&
|
99
|
+
wday.scan(/[a-zA-Z]+/).all? { |w| WDAYS[w.upcase] } &&
|
100
|
+
!(wday =~ NOT_BASIC_OR_LETTERS)
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def correct_range?(part, range)
|
106
|
+
part.scan(/\d+/).all? do |digits|
|
107
|
+
range === digits.to_i
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -143,4 +143,19 @@ describe CronPart do
|
|
143
143
|
expect(cron_part == 8).to eq false
|
144
144
|
end
|
145
145
|
end
|
146
|
+
|
147
|
+
context 'abbreviations' do
|
148
|
+
CronPart::REMAP.each do |abbr, val|
|
149
|
+
cron_part = CronPart.new(abbr)
|
150
|
+
|
151
|
+
it "returns true for #{abbr} => #{val}" do
|
152
|
+
expect(cron_part == val.to_i).to eq true
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'returns false for #{abbr} => #{val} +/- 1' do
|
156
|
+
expect(cron_part == val.to_i + 1).to eq false
|
157
|
+
expect(cron_part == val.to_i - 1).to eq false
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
146
161
|
end
|
@@ -14,6 +14,20 @@ describe Cron do
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
+
describe '.valid' do
|
18
|
+
context 'a valid cron string is given' do
|
19
|
+
it 'returns a new cron object' do
|
20
|
+
expect(Cron.valid('* * * * *')).to be_kind_of Cron
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'an invalid cron string is given' do
|
25
|
+
it 'returns nil' do
|
26
|
+
expect(Cron.valid('* * * * * *')).to be_nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
17
31
|
describe '#==' do
|
18
32
|
context 'simple cron' do
|
19
33
|
let(:cron) { Cron.new('30 12 15 6 6') }
|
@@ -36,5 +50,17 @@ describe Cron do
|
|
36
50
|
expect(cron == now - 3600).to eq false
|
37
51
|
end
|
38
52
|
end
|
53
|
+
|
54
|
+
context 'abbreviations' do
|
55
|
+
let(:cron) { Cron.new('* * * JUN SAT')}
|
56
|
+
|
57
|
+
it 'returns true for now' do
|
58
|
+
expect(cron == now).to eq true
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'returns false for a day earlier' do
|
62
|
+
expect(cron == now - 3600 * 24).to eq false
|
63
|
+
end
|
64
|
+
end
|
39
65
|
end
|
40
66
|
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
include When
|
3
|
+
|
4
|
+
describe Cron::Validator do
|
5
|
+
describe '.valid?' do
|
6
|
+
context 'number of parts' do
|
7
|
+
it 'returns true with 5 space separated parts' do
|
8
|
+
expect(Cron::Validator.valid?('* * * * *')).to be true
|
9
|
+
end
|
10
|
+
|
11
|
+
[ 1, 3, 6, 9 ].each do |i|
|
12
|
+
cron = (['*'] * i).join(' ')
|
13
|
+
it "returns false for '#{cron}'" do
|
14
|
+
expect(Cron::Validator.valid?(cron)).to be false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
context 'minutes' do
|
19
|
+
[ '0', '1', '59' ].each do |min|
|
20
|
+
it "returns true when minute is #{min}" do
|
21
|
+
expect(Cron::Validator.valid?("#{min} * * * *")).to be true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
[ '60', '134', '75' ].each do |min|
|
26
|
+
it "returns false when minute is #{min}" do
|
27
|
+
expect(Cron::Validator.valid?("#{min} * * * *")).to be false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'hours' do
|
33
|
+
[ '0', '5', '23' ].each do |hour|
|
34
|
+
it "returns true when hour is #{hour}" do
|
35
|
+
expect(Cron::Validator.valid?("* #{hour} * * *")).to be true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
[ '24', '50', '999' ].each do |hour|
|
40
|
+
it "returns false when hour is #{hour}" do
|
41
|
+
expect(Cron::Validator.valid?("* #{hour} * * *")).to be false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'days' do
|
47
|
+
[ '1', '5', '31' ].each do |day|
|
48
|
+
it "returns true when day is #{day}" do
|
49
|
+
expect(Cron::Validator.valid?("* * #{day} * *")).to be true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
[ '0', '32', '467' ].each do |day|
|
54
|
+
it "returns false when day is #{day}" do
|
55
|
+
expect(Cron::Validator.valid?("* * #{day} * *")).to be false
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'months' do
|
61
|
+
[ '1', '5', '12', 'JAN', 'jan', 'AUG', 'DEC' ].each do |month|
|
62
|
+
it "returns true when month is #{month}" do
|
63
|
+
expect(Cron::Validator.valid?("* * * #{month} *")).to be true
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
[ '0', '32', '467', 'MEY', 'JIN' ].each do |month|
|
68
|
+
it "returns false when month is #{month}" do
|
69
|
+
expect(Cron::Validator.valid?("* * * #{month} *")).to be false
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'wdays' do
|
75
|
+
[ '0', '5', '6', 'Mon', 'TUE', 'thu', 'saT' ].each do |wday|
|
76
|
+
it "returns true when wday is #{wday}" do
|
77
|
+
expect(Cron::Validator.valid?("* * * * #{wday}")).to be true
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
[ '7', '32', '467', 'MIN', 'TUW' ].each do |wday|
|
82
|
+
it "returns false when wday is #{wday}" do
|
83
|
+
expect(Cron::Validator.valid?("* * * * #{wday}")).to be false
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'characters' do
|
89
|
+
[ '!', '&', '[', '\\' ].each do |char|
|
90
|
+
5.times do |i|
|
91
|
+
cron = [ '*', '*', '*', '*' ].insert(i, char).join(' ')
|
92
|
+
it "returns false for #{cron}" do
|
93
|
+
expect(Cron::Validator.valid?(cron)).to eq false
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
[ '-', '*', '/', ',' ].each do |char|
|
99
|
+
5.times do |i|
|
100
|
+
cron = [ '*', '*', '*', '*' ].insert(i, char).join(' ')
|
101
|
+
it "returns true for #{cron}" do
|
102
|
+
expect(Cron::Validator.valid?(cron)).to eq true
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
data/spec/spec_helper.rb
CHANGED
data/when-cron.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "when-cron"
|
7
|
-
spec.version = '1.0.
|
7
|
+
spec.version = '1.0.2'
|
8
8
|
spec.authors = ["TH"]
|
9
9
|
spec.email = ["tylerhartland7@gmail.com"]
|
10
10
|
spec.description = %q{A basic cron implementation.}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: when-cron
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- TH
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-08-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -102,12 +102,14 @@ files:
|
|
102
102
|
- lib/when-cron/cron/cron_interval.rb
|
103
103
|
- lib/when-cron/cron/cron_part.rb
|
104
104
|
- lib/when-cron/cron/cron_range.rb
|
105
|
+
- lib/when-cron/cron/validator.rb
|
105
106
|
- lib/when-cron/cron/wildcard.rb
|
106
107
|
- spec/lib/when/cron/cron_array_spec.rb
|
107
108
|
- spec/lib/when/cron/cron_interval_spec.rb
|
108
109
|
- spec/lib/when/cron/cron_part_spec.rb
|
109
110
|
- spec/lib/when/cron/cron_range_spec.rb
|
110
111
|
- spec/lib/when/cron/cron_spec.rb
|
112
|
+
- spec/lib/when/cron/validator_spec.rb
|
111
113
|
- spec/lib/when/cron/wildcard_spec.rb
|
112
114
|
- spec/lib/when_spec.rb
|
113
115
|
- spec/spec_helper.rb
|
@@ -142,7 +144,7 @@ test_files:
|
|
142
144
|
- spec/lib/when/cron/cron_part_spec.rb
|
143
145
|
- spec/lib/when/cron/cron_range_spec.rb
|
144
146
|
- spec/lib/when/cron/cron_spec.rb
|
147
|
+
- spec/lib/when/cron/validator_spec.rb
|
145
148
|
- spec/lib/when/cron/wildcard_spec.rb
|
146
149
|
- spec/lib/when_spec.rb
|
147
150
|
- spec/spec_helper.rb
|
148
|
-
has_rdoc:
|