ice_cube_cron 0.0.5 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +2 -0
- data/README.md +5 -3
- data/lib/ice_cube_cron/expression_parser.rb +85 -53
- data/lib/ice_cube_cron/parser_attribute.rb +14 -4
- data/lib/ice_cube_cron/rule_builder.rb +38 -15
- data/lib/ice_cube_cron/version.rb +1 -1
- data/spec/lib/ice_cube_cron/base_spec.rb +120 -62
- data/spec/lib/ice_cube_cron/expression_parser_spec.rb +190 -69
- data/spec/lib/ice_cube_cron/rule_builder_spec.rb +104 -12
- metadata +2 -3
- data/Gemfile.lock +0 -72
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1b14af35504a36135e5f349fa1daa0436c608848
|
4
|
+
data.tar.gz: a5344d84ce8b858875732e5c594c93444a8afc22
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bb37fb552f54bfacf7cd4c05ad2ad24682732dc0804b9e7d43abc67187c86f811ab289bab932109c49d85252f7fa571e7c8cb5d37e114ba623fa7645d3419940
|
7
|
+
data.tar.gz: 8d1e857a18f5510ec8f88a23bbaf11a2371414b8f6d96950325f06413999e3a6ba186c253f4a9492a4e7ce869da0467575cee2c40b08cc5b1def62d4e9c6386a
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -45,7 +45,7 @@ require 'ice_cube_cron'
|
|
45
45
|
schedule = ::IceCube::Schedule.from_cron(::Date.current, "* * * * 5")
|
46
46
|
|
47
47
|
# using hash
|
48
|
-
schedule = ::IceCube::Schedule.from_cron(::Date.new(2015, 1, 5), :
|
48
|
+
schedule = ::IceCube::Schedule.from_cron(::Date.new(2015, 1, 5), :day_of_month => 5)
|
49
49
|
|
50
50
|
schedule.occurrences_between(::Date.new(2015, 3, 5), ::Date.new(2015, 6, 5))
|
51
51
|
# => [2015-03-05 00:00:00 UTC, 2015-04-05 00:00:00 UTC, 2015-05-05 00:00:00 UTC, 2015-06-05 00:00:00 UTC]
|
@@ -53,7 +53,7 @@ schedule.occurrences_between(::Date.new(2015, 3, 5), ::Date.new(2015, 6, 5))
|
|
53
53
|
|
54
54
|
## recurrence rule examples (date)
|
55
55
|
|
56
|
-
|desc|interval|year|month|
|
56
|
+
|desc|interval|year|month|day_of_month|day_of_week|
|
57
57
|
|----|-------:|---:|----:|--:|------:|
|
58
58
|
|1st of every month||||1||
|
59
59
|
|1st and 15th of every month||||1,15||
|
@@ -69,4 +69,6 @@ schedule.occurrences_between(::Date.new(2015, 3, 5), ::Date.new(2015, 6, 5))
|
|
69
69
|
- Does not yet support all recurrence options. More coming.
|
70
70
|
|
71
71
|
## todo
|
72
|
-
- Add support for
|
72
|
+
- Add support for W special character
|
73
|
+
- Change hash param `day` to `day_of_month`
|
74
|
+
- Improve expression validation
|
@@ -6,21 +6,23 @@ module IceCubeCron # :nodoc:
|
|
6
6
|
include ::IceCubeCron::ParserAttribute
|
7
7
|
|
8
8
|
EXPRESSION_PART_DEFAULTS = {
|
9
|
-
:
|
10
|
-
:
|
11
|
-
:
|
12
|
-
:
|
13
|
-
:
|
14
|
-
:
|
9
|
+
:interval => 1,
|
10
|
+
:year => nil,
|
11
|
+
:month => nil,
|
12
|
+
:day_of_month => nil,
|
13
|
+
:day_of_week => nil,
|
14
|
+
:hour => nil,
|
15
|
+
:minute => nil,
|
16
|
+
:until => nil
|
15
17
|
}
|
16
18
|
|
17
19
|
EXPRESSION_PART_KEYS = [
|
18
|
-
:
|
19
|
-
:
|
20
|
-
:
|
21
|
-
:
|
22
|
-
:
|
23
|
-
:
|
20
|
+
:minute,
|
21
|
+
:hour,
|
22
|
+
:day_of_month,
|
23
|
+
:month,
|
24
|
+
:day_of_week,
|
25
|
+
:year
|
24
26
|
]
|
25
27
|
|
26
28
|
##
|
@@ -43,7 +45,11 @@ module IceCubeCron # :nodoc:
|
|
43
45
|
self.expression_hash = EXPRESSION_PART_DEFAULTS.dup
|
44
46
|
|
45
47
|
expression_parts.each do |name, val|
|
46
|
-
|
48
|
+
begin
|
49
|
+
send("#{name}=", val)
|
50
|
+
rescue NoMethodError
|
51
|
+
raise ArgumentError, "Invalid parameter: #{name}"
|
52
|
+
end
|
47
53
|
end
|
48
54
|
end
|
49
55
|
|
@@ -51,41 +57,47 @@ module IceCubeCron # :nodoc:
|
|
51
57
|
ExpressionParser.sanitize_integer_param(val, 1)
|
52
58
|
end
|
53
59
|
|
54
|
-
parser_attribute_accessor :
|
60
|
+
parser_attribute_accessor :day_of_month do |val|
|
55
61
|
ExpressionParser.sanitize_day_param(val)
|
56
62
|
end
|
63
|
+
_define_parser_attribute_aliases(:day, :day_of_month, :day_of_month=)
|
57
64
|
|
58
65
|
parser_attribute_accessor :month do |val|
|
59
66
|
ExpressionParser.sanitize_integer_array_param(val)
|
60
67
|
end
|
61
68
|
|
62
|
-
parser_attribute_accessor :until
|
63
|
-
|
64
69
|
parser_attribute_accessor :year do |val|
|
65
70
|
ExpressionParser.sanitize_integer_array_param(val)
|
66
71
|
end
|
67
72
|
|
68
|
-
parser_attribute_accessor :
|
73
|
+
parser_attribute_accessor :day_of_week do |val|
|
69
74
|
ExpressionParser.sanitize_week_day_param(val)
|
70
75
|
end
|
76
|
+
_define_parser_attribute_aliases(:weekday, :day_of_week, :day_of_week=)
|
71
77
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
def string_to_expression_parts(expression_str)
|
76
|
-
return {} if expression_str.nil?
|
78
|
+
parser_attribute_accessor :hour do |val|
|
79
|
+
ExpressionParser.sanitize_integer_array_param(val)
|
80
|
+
end
|
77
81
|
|
78
|
-
|
82
|
+
parser_attribute_accessor :minute do |val|
|
83
|
+
ExpressionParser.sanitize_integer_array_param(val)
|
84
|
+
end
|
79
85
|
|
80
|
-
|
81
|
-
expression_parts.select! do |_key, value|
|
82
|
-
next false if value.nil?
|
83
|
-
next false if value == '*'
|
86
|
+
parser_attribute_accessor :until
|
84
87
|
|
85
|
-
|
86
|
-
|
88
|
+
##
|
89
|
+
# Sanitize given value to a valid day parameter
|
90
|
+
#
|
91
|
+
def self.sanitize_day_param(param)
|
92
|
+
return nil if param.blank?
|
93
|
+
return param if param.is_a?(::Array)
|
94
|
+
return [param] if param.is_a?(::Integer)
|
87
95
|
|
88
|
-
|
96
|
+
param.to_s.split(',').map do |element|
|
97
|
+
next -1 if element == 'L'
|
98
|
+
|
99
|
+
ExpressionParser.sanitize_integer_array_param(element)
|
100
|
+
end.flatten.uniq
|
89
101
|
end
|
90
102
|
|
91
103
|
##
|
@@ -98,19 +110,26 @@ module IceCubeCron # :nodoc:
|
|
98
110
|
end
|
99
111
|
|
100
112
|
##
|
101
|
-
# Sanitize given value to
|
113
|
+
# Sanitize given value to an integer array
|
102
114
|
#
|
103
|
-
|
115
|
+
#--
|
116
|
+
# rubocop:disable Metrics/AbcSize
|
117
|
+
#++
|
118
|
+
def self.sanitize_integer_array_param(param)
|
104
119
|
return nil if param.blank?
|
105
120
|
return param if param.is_a?(::Array)
|
106
121
|
return [param] if param.is_a?(::Integer)
|
107
122
|
|
108
|
-
param.
|
109
|
-
|
110
|
-
|
111
|
-
|
123
|
+
param.split(',').map do |element|
|
124
|
+
if element =~ /[0-9]+\-[0-9]+/
|
125
|
+
parts = element.split('-')
|
126
|
+
(parts[0].to_i..parts[1].to_i).to_a
|
127
|
+
else
|
128
|
+
element.to_i
|
129
|
+
end
|
112
130
|
end.flatten.uniq
|
113
131
|
end
|
132
|
+
# rubocop:enable Metrics/AbcSize
|
114
133
|
|
115
134
|
##
|
116
135
|
# Sanitize given value to a valid weekday parameter
|
@@ -129,26 +148,39 @@ module IceCubeCron # :nodoc:
|
|
129
148
|
end
|
130
149
|
end
|
131
150
|
|
151
|
+
private
|
152
|
+
|
132
153
|
##
|
133
|
-
#
|
154
|
+
# Split a cron string and extract the LAST interval that appears
|
134
155
|
#
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
156
|
+
def split_parts_and_interval(expression_str)
|
157
|
+
interval = nil
|
158
|
+
parts = expression_str.split(/ +/).map do |part|
|
159
|
+
part, part_interval = part.split('/')
|
160
|
+
interval = part_interval unless part_interval.blank?
|
161
|
+
next nil if part.blank? || part == '*'
|
162
|
+
|
163
|
+
part
|
164
|
+
end
|
142
165
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
166
|
+
[parts, interval]
|
167
|
+
end
|
168
|
+
|
169
|
+
##
|
170
|
+
# Split string expression into parts
|
171
|
+
#
|
172
|
+
def string_to_expression_parts(expression_str)
|
173
|
+
return {} if expression_str.nil?
|
174
|
+
|
175
|
+
parts, interval = split_parts_and_interval(expression_str)
|
176
|
+
|
177
|
+
expression_parts = ::Hash[EXPRESSION_PART_KEYS.zip(parts)]
|
178
|
+
expression_parts.select! do |_key, value|
|
179
|
+
!value.nil?
|
180
|
+
end
|
181
|
+
expression_parts.merge!(:interval => interval) unless interval.nil?
|
182
|
+
|
183
|
+
expression_parts
|
151
184
|
end
|
152
|
-
# rubocop:enable Metrics/AbcSize
|
153
185
|
end
|
154
186
|
end
|
@@ -4,12 +4,14 @@ module IceCubeCron # :nodoc: all
|
|
4
4
|
base.extend(::IceCubeCron::ParserAttribute::ClassMethods)
|
5
5
|
end
|
6
6
|
|
7
|
+
private
|
8
|
+
|
7
9
|
attr_accessor :expression_hash
|
8
10
|
|
9
11
|
module ClassMethods # :nodoc:
|
10
12
|
def parser_attribute_accessor(attr_name, &cleanser)
|
11
|
-
getter = "
|
12
|
-
setter = "
|
13
|
+
getter = "#{attr_name}".to_sym
|
14
|
+
setter = "#{attr_name}=".to_sym
|
13
15
|
|
14
16
|
define_method(getter) do
|
15
17
|
expression_hash[getter]
|
@@ -20,8 +22,16 @@ module IceCubeCron # :nodoc: all
|
|
20
22
|
expression_hash[getter] = val
|
21
23
|
end
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
+
_define_parser_attribute_aliases(attr_name, getter, setter)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def _define_parser_attribute_aliases(attr_name, getter, setter)
|
31
|
+
alias_method "repeat_#{attr_name}=".to_sym, setter
|
32
|
+
alias_method "repeat_#{attr_name}".to_sym, getter
|
33
|
+
alias_method "cron_#{attr_name}=".to_sym, setter
|
34
|
+
alias_method "cron_#{attr_name}".to_sym, getter
|
25
35
|
end
|
26
36
|
end
|
27
37
|
end
|
@@ -8,9 +8,10 @@ module IceCubeCron # :nodoc:
|
|
8
8
|
#
|
9
9
|
def build_rule(expression)
|
10
10
|
rule = build_root_recurrence_rule(expression)
|
11
|
-
rule =
|
11
|
+
rule = build_year_rules(rule, expression)
|
12
12
|
rule = build_weekday_rule(rule, expression)
|
13
|
-
rule = rule
|
13
|
+
rule = build_day_rules(rule, expression)
|
14
|
+
rule = build_time_rules(rule, expression)
|
14
15
|
rule = rule.until(expression.until) unless expression.until.blank?
|
15
16
|
|
16
17
|
rule
|
@@ -24,31 +25,53 @@ module IceCubeCron # :nodoc:
|
|
24
25
|
|
25
26
|
private
|
26
27
|
|
28
|
+
# rubocop:disable Metrics/AbcSize
|
29
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
30
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
31
|
+
def build_root_recurrence_rule(expression) # :nodoc:
|
32
|
+
return ::IceCube::Rule.minutely(expression.interval) if expression.minute.blank?
|
33
|
+
return ::IceCube::Rule.hourly(expression.interval) if expression.hour.blank?
|
34
|
+
unless nth_day?(expression.day_of_week)
|
35
|
+
return ::IceCube::Rule.weekly(expression.interval) if expression.day_of_month.blank? && !expression.day_of_week.blank?
|
36
|
+
return ::IceCube::Rule.daily(expression.interval) if expression.day_of_month.blank?
|
37
|
+
end
|
38
|
+
return ::IceCube::Rule.monthly(expression.interval) if expression.month.blank?
|
39
|
+
|
40
|
+
::IceCube::Rule.yearly(expression.interval)
|
41
|
+
end
|
42
|
+
# rubocop:enable Metrics/AbcSize
|
43
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
44
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
45
|
+
|
46
|
+
# :nodoc:
|
47
|
+
def build_year_rules(rule, expression)
|
48
|
+
rule = rule.year(*expression.year) unless expression.year.blank?
|
49
|
+
rule = rule.month_of_year(*expression.month) unless expression.month.blank?
|
50
|
+
|
51
|
+
rule
|
52
|
+
end
|
53
|
+
|
27
54
|
# :nodoc:
|
28
55
|
def build_weekday_rule(rule, expression)
|
29
|
-
return rule.day_of_week(*expression.
|
30
|
-
return rule.day(*expression.
|
56
|
+
return rule.day_of_week(*expression.day_of_week) if !expression.day_of_week.blank? && nth_day?(expression.day_of_week)
|
57
|
+
return rule.day(*expression.day_of_week) unless expression.day_of_week.blank?
|
31
58
|
|
32
59
|
rule
|
33
60
|
end
|
34
61
|
|
35
62
|
# :nodoc:
|
36
|
-
def
|
37
|
-
rule = rule.
|
38
|
-
rule = rule.month_of_year(*expression.month) unless expression.month.blank?
|
63
|
+
def build_day_rules(rule, expression)
|
64
|
+
rule = rule.day_of_month(*expression.day_of_month) unless expression.day_of_month.blank?
|
39
65
|
|
40
66
|
rule
|
41
67
|
end
|
42
68
|
|
43
|
-
#
|
44
|
-
def
|
45
|
-
|
46
|
-
|
47
|
-
return ::IceCube::Rule.monthly(expression.interval) unless expression.day.blank?
|
48
|
-
return ::IceCube::Rule.weekly(expression.interval) unless expression.weekday.blank?
|
69
|
+
# :nodoc:
|
70
|
+
def build_time_rules(rule, expression)
|
71
|
+
rule = rule.hour_of_day(*expression.hour) unless expression.hour.blank? || expression.hour == [0]
|
72
|
+
rule = rule.minute_of_hour(*expression.minute) unless expression.minute.blank? || expression.minute == [0]
|
49
73
|
|
50
|
-
|
74
|
+
rule
|
51
75
|
end
|
52
|
-
# rubocop:enable Metrics/AbcSize
|
53
76
|
end
|
54
77
|
end
|