lib/rufus/scheduler/cronline.rb in rufus-scheduler-3.2.0 vs lib/rufus/scheduler/cronline.rb in rufus-scheduler-3.2.1
- old
+ new
@@ -1,7 +1,7 @@
#--
-# Copyright (c) 2006-2015, John Mettraux, jmettraux@gmail.com
+# Copyright (c) 2006-2016, John Mettraux, jmettraux@gmail.com
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
@@ -65,11 +65,11 @@
offset = items.length - 5
@seconds = offset == 1 ? parse_item(items[0], 0, 59) : [ 0 ]
@minutes = parse_item(items[0 + offset], 0, 59)
@hours = parse_item(items[1 + offset], 0, 24)
- @days = parse_item(items[2 + offset], 1, 31)
+ @days = parse_item(items[2 + offset], -30, 31)
@months = parse_item(items[3 + offset], 1, 12)
@weekdays, @monthdays = parse_weekdays(items[4 + offset])
[ @seconds, @minutes, @hours, @months ].each do |es|
@@ -186,13 +186,13 @@
time
end
# Returns an array of 6 arrays (seconds, minutes, hours, days,
# months, weekdays).
- # This method is used by the cronline unit tests.
+ # This method is mostly used by the cronline specs.
#
- def to_array
+ def to_a
[
toa(@seconds),
toa(@minutes),
toa(@hours),
@@ -201,10 +201,11 @@
toa(@weekdays),
toa(@monthdays),
@timezone
]
end
+ alias to_array to_a
# Returns a quickly computed approximation of the frequency for this
# cron line.
#
# #brute_frequency, on the other hand, will compute the frequency by
@@ -317,37 +318,37 @@
def parse_weekdays(item)
return nil if item == '*'
- items = item.downcase.split(',')
-
weekdays = nil
monthdays = nil
- items.each do |it|
+ item.downcase.split(',').each do |it|
- if m = it.match(/^(.+)#(l|-?[12345])$/)
+ WEEKDAYS.each_with_index { |a, i| it.gsub!(/#{a}/, i.to_s) }
+ it = it.gsub(/([^#])l/, '\1#-1')
+ # "5L" == "5#-1" == the last Friday
+
+ if m = it.match(/\A(.+)#(l|-?[12345])\z/)
+
fail ArgumentError.new(
"ranges are not supported for monthdays (#{it})"
) if m[1].index('-')
- expr = it.gsub(/#l/, '#-1')
+ it = it.gsub(/#l/, '#-1')
- (monthdays ||= []) << expr
+ (monthdays ||= []) << it
else
- expr = it.dup
- WEEKDAYS.each_with_index { |a, i| expr.gsub!(/#{a}/, i.to_s) }
-
fail ArgumentError.new(
- "invalid weekday expression (#{it})"
- ) if expr !~ /^0*[0-7](-0*[0-7])?$/
+ "invalid weekday expression (#{item})"
+ ) if it !~ /\A0*[0-7](-0*[0-7])?\z/
- its = expr.index('-') ? parse_range(expr, 0, 7) : [ Integer(expr) ]
+ its = it.index('-') ? parse_range(it, 0, 7) : [ Integer(it) ]
its = its.collect { |i| i == 7 ? 0 : i }
(weekdays ||= []).concat(its)
end
end
@@ -370,11 +371,11 @@
r = sc_sort(r)
Set.new(r)
end
- RANGE_REGEX = /^(\*|\d{1,2})(?:-(\d{1,2}))?(?:\/(\d{1,2}))?$/
+ RANGE_REGEX = /\A(\*|-?\d{1,2})(?:-(-?\d{1,2}))?(?:\/(\d{1,2}))?\z/
def parse_range(item, min, max)
return %w[ L ] if item == 'L'
@@ -384,30 +385,44 @@
fail ArgumentError.new(
"cannot parse #{item.inspect}"
) unless m
+ mmin = min == -30 ? 1 : min # days
+
sta = m[1]
- sta = sta == '*' ? min : sta.to_i
+ sta = sta == '*' ? mmin : sta.to_i
edn = m[2]
edn = edn ? edn.to_i : sta
edn = max if m[1] == '*'
inc = m[3]
inc = inc ? inc.to_i : 1
fail ArgumentError.new(
+ "#{item.inspect} positive/negative ranges not allowed"
+ ) if (sta < 0 && edn > 0) || (sta > 0 && edn < 0)
+
+ fail ArgumentError.new(
+ "#{item.inspect} descending day ranges not allowed"
+ ) if min == -30 && sta > edn
+
+ fail ArgumentError.new(
"#{item.inspect} is not in range #{min}..#{max}"
) if sta < min || edn > max
+ fail ArgumentError.new(
+ "#{item.inspect} increment must be greater than zero"
+ ) if inc == 0
+
r = []
val = sta
loop do
v = val
- v = 0 if max == 24 && v == 24
+ v = 0 if max == 24 && v == 24 # hours
r << v
break if inc == 1 && val == edn
val += inc
break if inc > 1 && val > edn
val = min if val > max
@@ -419,14 +434,24 @@
def sub_match?(time, accessor, values)
value = time.send(accessor)
return true if values.nil?
- return true if values.include?('L') && (time + DAY_S).day == 1
- return true if value == 0 && accessor == :hour && values.include?(24)
+ if accessor == :day
+ values.each do |v|
+ return true if v == 'L' && (time + DAY_S).day == 1
+ return true if v.to_i < 0 && (time + (1 - v) * DAY_S).day == 1
+ end
+ end
+
+ if accessor == :hour
+
+ return true if value == 0 && values.include?(24)
+ end
+
values.include?(value)
end
def monthday_match?(date, values)
@@ -464,10 +489,10 @@
d = d + WEEK_S
break if d.month != date.month
neg = neg - 1
end
- [ "#{WEEKDAYS[date.wday]}##{pos}", "#{WEEKDAYS[date.wday]}##{neg}" ]
+ [ "#{date.wday}##{pos}", "#{date.wday}##{neg}" ]
end
end
end