whenever/lib/outputs/cron.rb

117 lines
3.6 KiB
Ruby

module Whenever
module Output
class Cron
attr_accessor :time, :task
def initialize(time = nil, task = nil, at = nil)
@time = time
@task = task
@at = at.is_a?(String) ? (Chronic.parse(at) || 0) : (at || 0)
end
def self.output(time, job)
out = new(time, job.output, job.at)
"#{out.time_in_cron_syntax} #{out.task}"
end
def time_in_cron_syntax
case @time
when Symbol then parse_symbol
when String then parse_as_string
else parse_time
end
end
protected
def parse_symbol
shortcut = case @time
when :reboot then '@reboot'
when :year, :yearly then '@annually'
when :day, :daily then '@daily'
when :midnight then '@midnight'
when :month, :monthly then '@monthly'
when :week, :weekly then '@weekly'
when :hour, :hourly then '@hourly'
end
if shortcut
if @at > 0
raise ArgumentError, "You cannot specify an ':at' when using the shortcuts for times."
else
return shortcut
end
else
parse_as_string
end
end
def parse_time
timing = Array.new(5, '*')
case @time
when 0.seconds...1.minute
raise ArgumentError, "Time must be in minutes or higher"
when 1.minute...1.hour
minute_frequency = @time / 60
timing[0] = comma_separated_timing(minute_frequency, 59)
when 1.hour...1.day
hour_frequency = (@time / 60 / 60).round
timing[0] = @at.is_a?(Time) ? @at.min : @at
timing[1] = comma_separated_timing(hour_frequency, 23)
when 1.day...1.month
day_frequency = (@time / 24 / 60 / 60).round
timing[0] = @at.is_a?(Time) ? @at.min : 0
timing[1] = @at.is_a?(Time) ? @at.hour : @at
timing[2] = comma_separated_timing(day_frequency, 31, 1)
when 1.month..12.months
month_frequency = (@time / 30 / 24 / 60 / 60).round
timing[0] = @at.is_a?(Time) ? @at.min : 0
timing[1] = @at.is_a?(Time) ? @at.hour : 0
timing[2] = @at.is_a?(Time) ? @at.day : (@at.zero? ? 1 : @at)
timing[3] = comma_separated_timing(month_frequency, 12, 1)
else
return parse_as_string
end
timing.join(' ')
end
def parse_as_string
return unless @time
string = @time.to_s
timing = Array.new(4, '*')
timing[0] = @at.is_a?(Time) ? @at.min : 0
timing[1] = @at.is_a?(Time) ? @at.hour : 0
return (timing << 'mon-fri') * " " if string.downcase.index('weekday')
return (timing << 'sat,sun') * " " if string.downcase.index('weekend')
%w(sun mon tue wed thu fri sat).each do |day|
return (timing << day) * " " if string.downcase.index(day)
end
raise ArgumentError, "Couldn't parse: #{@time}"
end
def comma_separated_timing(frequency, max, start = 0)
return start if frequency.blank? || frequency.zero?
return '*' if frequency == 1
return frequency if frequency > (max * 0.5).ceil
original_start = start
start += frequency unless (max + 1).modulo(frequency).zero? || start > 0
output = (start..max).step(frequency).to_a
max_occurances = (max.to_f / (frequency.to_f)).round
max_occurances += 1 if original_start.zero?
output[0, max_occurances].join(',')
end
end
end
end