class BBLib::Cron

Constants

PARTS
REPLACE
SPECIAL_EXP

Attributes

parts[R]

Public Class Methods

next(exp, count: 1, time: Time.now) click to toggle source
# File lib/bblib/classes/cron.rb, line 26
def self.next(exp, count: 1, time: Time.now)
  BBLib::Cron.new(exp).next(count: count, time: time)
end
numeralize(exp) click to toggle source
# File lib/bblib/classes/cron.rb, line 42
def self.numeralize(exp)
  REPLACE.each do |k, v|
    v.each do |r|
      exp = exp.to_s.gsub(r.to_s, k.to_s)
    end
  end
  exp
end
prev(exp, count: 1, time: Time.now) click to toggle source
# File lib/bblib/classes/cron.rb, line 30
def self.prev(exp, count: 1, time: Time.now)
  BBLib::Cron.new(exp).prev(count: count, time: time)
end
valid?(exp) click to toggle source
# File lib/bblib/classes/cron.rb, line 34
def self.valid?(exp)
  !(numeralize(exp) =~ /\A(.*?\s){4,5}.*?\S\z/).nil?
end

Public Instance Methods

expression=(e) click to toggle source
# File lib/bblib/classes/cron.rb, line 18
def expression=(e)
  e = e.to_s.downcase
  SPECIAL_EXP.each { |x, v| e = x if v.include?(e) }
  @expression = e
  parse
  e
end
next(exp = expression, count: 1, time: Time.now) click to toggle source
# File lib/bblib/classes/cron.rb, line 8
def next(exp = expression, count: 1, time: Time.now)
  self.expression = exp unless exp == expression
  closest(count: count, time: time, direction: 1)
end
prev(exp = expression, count: 1, time: Time.now) click to toggle source
# File lib/bblib/classes/cron.rb, line 13
def prev(exp = expression, count: 1, time: Time.now)
  self.expression = exp unless exp == expression
  closest(count: count, time: time, direction: -1)
end
time_match?(time) click to toggle source
# File lib/bblib/classes/cron.rb, line 51
def time_match?(time)
  (@parts[:minute].empty? || @parts[:minute].include?(time.min)) &&
  (@parts[:hour].empty? || @parts[:hour].include?(time.hour)) &&
  (@parts[:day].empty? || @parts[:day].include?(time.day)) &&
  (@parts[:weekday].empty? || @parts[:weekday].include?(time.wday)) &&
  (@parts[:month].empty? || @parts[:month].include?(time.month)) &&
  (@parts[:year].empty? || @parts[:year].include?(time.year))
end
valid?(exp) click to toggle source
# File lib/bblib/classes/cron.rb, line 38
def valid?(exp)
  BBLib::Cron.valid?(exp)
end

Private Instance Methods

closest(direction: 1, count: 1, time: Time.now) click to toggle source
# File lib/bblib/classes/cron.rb, line 95
def closest(direction: 1, count: 1, time: Time.now)
  return unless @expression
  results = (1..count).flat_map do |_i|
    time = next_time(time + 60 * direction, direction)
  end
  count <= 1 ? results.first : results.compact
end
next_day(time, direction) click to toggle source
# File lib/bblib/classes/cron.rb, line 132
def next_day(time, direction)
  return time if @parts[:day].empty?
  time += 24*60*60 * direction until @parts[:day].include?(time.day)
  time
end
next_hour(time, direction) click to toggle source
# File lib/bblib/classes/cron.rb, line 122
def next_hour(time, direction)
  return time if @parts[:hour].empty?
  until @parts[:hour].include?(time.hour)
    time -= time.min * 60 if direction.positive?
    time += (59 - time.min) * 60 if direction.negative?
    time += 60*60 * direction
  end
  time
end
next_min(time, direction) click to toggle source
# File lib/bblib/classes/cron.rb, line 116
def next_min(time, direction)
  return time if @parts[:minute].empty?
  time += 60 * direction until @parts[:minute].include?(time.min)
  time
end
next_month(time, direction) click to toggle source
# File lib/bblib/classes/cron.rb, line 144
def next_month(time, direction)
  return time if @parts[:month].empty?
  until @parts[:month].include?(time.month)
    original = time.month
    min      = direction.positive? ? 0 : 59
    hour     = direction.positive? ? 0 : 23
    day      = direction.positive? ? 1 : 31
    month = BBLib.loop_between(time.month + direction, 1, 12)
    year  = if direction.positive? && month == 1
              time.year + 1
            elsif direction.negative? && month == 12
              time.year - 1
            else
              time.year
            end
    time  = Time.new(year, month, day, hour, min)
    if direction.negative? && time.month == original
      time -= 24 * 60 * 60 while time.month == original
    end
  end
  time
end
next_time(time, direction) click to toggle source
# File lib/bblib/classes/cron.rb, line 103
def next_time(time, direction)
  original = time.dup
  safety = 0
  methods = [:next_year, :next_month, :next_weekday, :next_day, :next_hour, :next_min]
  until safety >= 1_000_000 || time_match?(time)
    methods.each do |sym|
      time = send(sym, time, direction)
    end
    safety += 1
  end
  time - (time.sec.zero? ? 0 : original.sec)
end
next_weekday(time, direction) click to toggle source
# File lib/bblib/classes/cron.rb, line 138
def next_weekday(time, direction)
  return time if @parts[:weekday].empty?
  time += 24*60*60 * direction until @parts[:weekday].include?(time.wday)
  time
end
next_year(time, direction) click to toggle source
# File lib/bblib/classes/cron.rb, line 167
def next_year(time, direction)
  return time if @parts[:year].empty?
  until @parts[:year].include?(time.year)
    day   = direction.positive? ? 1 : 31
    hour  = direction.positive? ? 0 : 23
    min   = direction.positive? ? 0 : 59
    month = direction.positive? ? 1 : 12
    time  = Time.new(time.year + direction, month, day, hour, min)
  end
  time
end
parse() click to toggle source
# File lib/bblib/classes/cron.rb, line 67
def parse
  @parts = {}
  PARTS.keys.zip(@expression.split(' ')).to_h.each do |part, piece|
    info = PARTS[part]
    @parts[part] = parse_cron_numbers(piece, info[:min], info[:max], Time.now.send(info[:send]))
  end
end
parse_cron_numbers(exp, min, max, qmark) click to toggle source
# File lib/bblib/classes/cron.rb, line 75
def parse_cron_numbers(exp, min, max, qmark)
  numbers = []
  return numbers if exp == '*'
  exp = Cron.numeralize(exp).gsub('?', qmark.to_s).gsub('*', "#{min}-#{max}")
  exp.scan(/\*\/\d+|\d+\/\d+|\d+-\d+\/\d+/).each do |s|
    range = s.split('/').first.split('-').map(&:to_i) + [max]
    divisor = s.split('/').last.to_i
    Range.new(*range[0..1]).each_with_index do |i, index|
      numbers.push(i) if index.zero? || (index % divisor).zero?
    end
    exp = exp.sub(s, '')
  end
  exp.scan(/\d+\-\d+/).each do |e|
    nums = e.scan(/\d+/).map(&:to_i)
    numbers.push(Range.new(*nums).to_a)
  end
  numbers.push(exp.scan(/\d+/).map(&:to_i))
  numbers.flatten.uniq.sort.reject { |r| r < min || r > max }
end
simple_init(*args) click to toggle source
# File lib/bblib/classes/cron.rb, line 62
def simple_init(*args)
  @parts = {}
  self.expression = args.first if args.first.is_a?(String)
end