Skip to content

Commit f7f6fcb

Browse files
committed
Support L in dom field
1 parent 5ff2cd5 commit f7f6fcb

File tree

2 files changed

+25
-3
lines changed

2 files changed

+25
-3
lines changed

lib/cron_parser.rb

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,14 +136,18 @@ def last(now = @time_source.now, num=1)
136136
end
137137

138138

139-
SUBELEMENT_REGEX = %r{^(\d+)(-(\d+)(/(\d+))?)?$}
140-
def parse_element(elem, allowed_range)
139+
SUBELEMENT_REGEX = %r{^(\d+|l)(-(\d+)(/(\d+))?)?$}
140+
def parse_element(elem, allowed_range, field_name = nil)
141141
values = elem.split(',').map do |subel|
142142
if subel =~ /^\*/
143143
step = subel.length > 1 ? subel[2..-1].to_i : 1
144144
stepped_range(allowed_range, step)
145145
else
146146
if SUBELEMENT_REGEX === subel
147+
if field_name != :dom && $1.include?('l')
148+
raise ArgumentError, "'L' specification is supported only for DOM field"
149+
end
150+
147151
if $5 # with range
148152
stepped_range($1.to_i..$3.to_i, $5.to_i)
149153
elsif $3 # range without step
@@ -186,6 +190,7 @@ def interpolate_weekdays_without_cache(year, month)
186190
# then we only need to match *one* for cron to run the job:
187191
if not (mday_field == '*' and wday_field == '*')
188192
valid_mday = [] if mday_field == '*'
193+
valid_mday = [(t.next_month - 1).day] if mday_field == 'l'
189194
valid_wday = [] if wday_field == '*'
190195
end
191196
# Careful: crontabs may use either 0 or 7 for Sunday:
@@ -251,7 +256,7 @@ def time_specs
251256
{
252257
:minute => parse_element(tokens[0], 0..59), #minute
253258
:hour => parse_element(tokens[1], 0..23), #hour
254-
:dom => parse_element(tokens[2], 1..31), #DOM
259+
:dom => parse_element(tokens[2], 1..31, :dom), #DOM
255260
:month => parse_element(tokens[3], 1..12), #mon
256261
:dow => parse_element(tokens[4], 0..6) #DOW
257262
}

spec/cron_parser_spec.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ def parse_date(str)
7878
["15-59/15 * * * *", "2014-02-01 15:45", "2014-02-01 16:15",4],
7979
["15-59/15 * * * *", "2014-02-01 15:46", "2014-02-01 16:15",3],
8080
["15-59/15 * * * *", "2014-02-01 15:46", "2014-02-01 16:15",2],
81+
["* * L 2 *", "2015-02-01 15:36", "2015-02-28 00:00",1],
82+
["* * L 2 *", "2016-02-01 15:36", "2016-02-29 00:00",1]
8183
].each do |line, now, expected_next,num|
8284
it "returns #{expected_next} for '#{line}' when now is #{now}" do
8385
parsed_now = parse_date(now)
@@ -157,6 +159,8 @@ def parse_date(str)
157159
["15-59/15 * * * *", "2014-02-01 15:36", "2014-02-01 15:30"],
158160
["15-59/15 * * * *", "2014-02-01 15:45", "2014-02-01 15:30"],
159161
["15-59/15 * * * *", "2014-02-01 15:46", "2014-02-01 15:45"],
162+
["* * L 2 *", "2014-02-01 15:36", "2013-02-28 23:59"],
163+
["* * L 2 *", "2017-02-01 15:36", "2016-02-29 23:59"]
160164
].each do |line, now, expected_next|
161165
it "should return #{expected_next} for '#{line}' when now is #{now}" do
162166
now = parse_date(now)
@@ -177,6 +181,19 @@ def parse_date(str)
177181
it 'should raise error when given an invalid cronline' do
178182
expect { CronParser.new('* * * *') }.to raise_error('not a valid cronline')
179183
end
184+
185+
it 'should not raise error when L is passed in DOM field' do
186+
expect { CronParser.new('* * L * *').next }.not_to raise_error
187+
end
188+
189+
(0..4).each do |n|
190+
next if n == 2
191+
it "should raise error when L is passed in #{n} field" do
192+
spec = Array.new(5) { '*' }
193+
spec[n] = 'L'
194+
expect { CronParser.new(spec.join(' ')).next }.to raise_error("'L' specification is supported only for DOM field")
195+
end
196+
end
180197
end
181198

182199
describe "time source" do

0 commit comments

Comments
 (0)