lib/cron_tab.rb
# Extracted from dpklib, Ruby library released under same license as Ruby.
class CronTab
attr_accessor :min, :hour, :mday, :mon, :wday, :command
WDAY = %w(sun mon tue wed thu fri sat)
FormatError = Class.new(StandardError)
def initialize(str)
super()
self.min, self.hour, self.mday, self.mon, self.wday =
CronTab.parse_timedate(str)
self.command = str.scan( /(?:\S+\s+){5}(.*)/ ).shift
end
def ===(rhs)
judge_date = proc {
b = true
b = b && (mday === rhs.mday)
b = b && (mon === rhs.mon)
b = b && (wday === rhs.wday)
}
judge_hour = proc {
b = true
b = b && (min === rhs.min)
b = b && (hour === rhs.hour)
}
case rhs
when Time
judge_hour.call && judge_date.call
when Dpklib::Hour
judge_hour.call
when Date
judge_date.call
else
super
end
end
alias include? ===;
class NextSeeker
attr_accessor :scalar, :field, :lower_seeker
def initialize(s, f, l)
self.scalar = s
self.field = f
self.lower_seeker = l
end
def succ
if lower_seeker.nil? || lower_seeker.succ then
self.scalar = field.nextof(scalar)
scalar
else
lower_seeker.recursive_zero
self.scalar += 1
succ
end
end
def recursive_zero
self.scalar = 0
lower_seeker && lower_seeker.recursive_zero
end
end #/NextSeeker
class YearField
def nextof(nowyear)
nowyear
end
end #/YearField
def nexttime(nowtime = Time.now)
nowmin = nowtime.min + 1
seeker_min = NextSeeker.new(nowmin, min, nil)
seeker_hour = NextSeeker.new(nowtime.hour, hour, seeker_min)
seeker_mday = NextSeeker.new(nowtime.mday, mday, seeker_hour)
seeker_mon = NextSeeker.new(nowtime.mon, mon, seeker_mday)
seeker_year = NextSeeker.new(nowtime.year, YearField.new, seeker_mon)
seeker_year.succ
Time.local(seeker_year.scalar,
seeker_mon.scalar,
seeker_mday.scalar,
seeker_hour.scalar,
seeker_min.scalar, 0)
end
def waitsec(nowtime = Time.now)
nexttime(nowtime).to_i - nowtime.to_i
end
def self.parse_timedate(str)
minute, hour, day_of_month, month, day_of_week =
str.scan(/^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/).shift
day_of_week = day_of_week.downcase.gsub(/#{WDAY.join("|")}/){
WDAY.index($&)
}
[
parse_field(minute, 0, 59),
parse_field(hour, 0, 23),
parse_field(day_of_month, 1, 31),
parse_field(month, 1, 12),
parse_field(day_of_week, 0, 6),
]
end
class Field
attr_accessor :range, :every
def initialize(r, e)
self.range = r
self.every = e
end
def ===(rhs)
b = true
b = b && ( (rhs - range.first) % every == 0 )
b = b && ( range === rhs )
end
def nextof(now)
if now < range.first then
nextof(range.first)
elsif range.last < now || (range.exclude_end? && range.last <= now) then
nil
else
now + ( (now - range.first) % every )
end
end
end
class FieldSet
attr_accessor :fields
def initialize(f)
self.fields = f
end
def ===(rhs)
b = false
fields.each { |field|
b ||= (field === rhs)
}
b
end
def nextof(now)
ret = nil
fields.each { |field|
field_nextof = field.nextof(now)
ret = field_nextof if ret.nil? || (field_nextof && field_nextof < ret)
}
ret
end
end
def self.parse_field(str, first, last)
list = str.split(",")
list.map!{|r|
r, every = r.split("/")
every = every ? every.to_i : 1
f,l = r.split("-")
range = if f == "*"
first..last
elsif l.nil?
f.to_i .. f.to_i
elsif f.to_i < first
raise FormatError.new("out of range (#{f} for #{first})")
elsif last < l.to_i
raise FormatError.new("out of range (#{l} for #{last})")
else
f.to_i .. l.to_i
end
Field.new(range, every)
}
FieldSet.new(list)
end
#alias parse new
#alias [] new
end #/CronTab