Skip to content

Commit 3654d3c

Browse files
committed
Support L in dom field
1 parent 268094a commit 3654d3c

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
@@ -77,6 +77,8 @@ def parse_date(str)
7777
["15-59/15 * * * *", "2014-02-01 15:45", "2014-02-01 16:15",4],
7878
["15-59/15 * * * *", "2014-02-01 15:46", "2014-02-01 16:15",3],
7979
["15-59/15 * * * *", "2014-02-01 15:46", "2014-02-01 16:15",2],
80+
["* * L 2 *", "2015-02-01 15:36", "2015-02-28 00:00",1],
81+
["* * L 2 *", "2016-02-01 15:36", "2016-02-29 00:00",1]
8082
].each do |line, now, expected_next,num|
8183
it "returns #{expected_next} for '#{line}' when now is #{now}" do
8284
parsed_now = parse_date(now)
@@ -156,6 +158,8 @@ def parse_date(str)
156158
["15-59/15 * * * *", "2014-02-01 15:36", "2014-02-01 15:30"],
157159
["15-59/15 * * * *", "2014-02-01 15:45", "2014-02-01 15:30"],
158160
["15-59/15 * * * *", "2014-02-01 15:46", "2014-02-01 15:45"],
161+
["* * L 2 *", "2014-02-01 15:36", "2013-02-28 23:59"],
162+
["* * L 2 *", "2017-02-01 15:36", "2016-02-29 23:59"]
159163
].each do |line, now, expected_next|
160164
it "should return #{expected_next} for '#{line}' when now is #{now}" do
161165
now = parse_date(now)
@@ -176,6 +180,19 @@ def parse_date(str)
176180
it 'should raise error when given an invalid cronline' do
177181
expect { CronParser.new('* * * *') }.to raise_error('not a valid cronline')
178182
end
183+
184+
it 'should not raise error when L is passed in DOM field' do
185+
expect { CronParser.new('* * L * *').next }.not_to raise_error
186+
end
187+
188+
(0..4).each do |n|
189+
next if n == 2
190+
it "should raise error when L is passed in #{n} field" do
191+
spec = Array.new(5) { '*' }
192+
spec[n] = 'L'
193+
expect { CronParser.new(spec.join(' ')).next }.to raise_error("'L' specification is supported only for DOM field")
194+
end
195+
end
179196
end
180197

181198
RSpec.describe "time source" do

0 commit comments

Comments
 (0)