class Zhong::At

Strongly inspired by the Clockwork At class

Constants

WDAYS

Attributes

hour[RW]
minute[RW]
wday[RW]

Public Class Methods

deserialize(at) click to toggle source
# File lib/zhong/at.rb, line 30
def self.deserialize(at)
  parse_serialized(MessagePack.unpack(at))
end
new(minute: nil, hour: nil, wday: nil, grace: 0.seconds) click to toggle source
# File lib/zhong/at.rb, line 34
def initialize(minute: nil, hour: nil, wday: nil, grace: 0.seconds)
  @minute = minute
  @hour = hour
  @wday = wday
  @grace = grace

  raise ArgumentError unless valid?
end
parse(at, grace: 0.seconds) click to toggle source
# File lib/zhong/at.rb, line 20
def self.parse(at, grace: 0.seconds)
  if at.respond_to?(:each)
    MultiAt.new(at.map { |a| parse_at(a, grace) })
  else
    parse_at(at, grace)
  end
rescue ArgumentError
  raise FailedToParse, at
end

Private Class Methods

parse_at(at, grace) click to toggle source
# File lib/zhong/at.rb, line 87
def self.parse_at(at, grace)
  case at
  when /\A([[:alpha:]]+)\s+(.*)\z/
    wday = WDAYS[$1.downcase]

    raise FailedToParse, at unless wday

    parsed_time = parse_at($2, grace)
    parsed_time.wday = wday
    parsed_time
  when /\A(\d{1,2}):(\d\d)\z/
    new(minute: $2.to_i, hour: $1.to_i, grace: grace)
  when /\A\*{1,2}:(\d\d)\z/
    new(minute: $1.to_i, grace: grace)
  when /\A(\d{1,2}):\*{1,2}\z/
    new(hour: $1.to_i, grace: grace)
  when /\A\*{1,2}:\*{1,2}\z/
    new(grace: grace)
  else
    raise FailedToParse, at
  end
end
parse_serialized(at) click to toggle source
# File lib/zhong/at.rb, line 78
def self.parse_serialized(at)
  if at.is_a?(Array)
    MultiAt.new(at.map { |a| parse_serialized(a) })
  else
    new(minute: at["m"], hour: at["h"], wday: at["w"], grace: at["g"])
  end
end

Public Instance Methods

==(other) click to toggle source
# File lib/zhong/at.rb, line 74
def ==(other)
  other.class == self.class && other.state == state
end
as_json() click to toggle source
# File lib/zhong/at.rb, line 66
def as_json
  {m: @minute, h: @hour, w: @wday, g: @grace}
end
next_at(time = Time.now) click to toggle source
# File lib/zhong/at.rb, line 43
def next_at(time = Time.now)
  at_time = at_time_day_hour_minute_adjusted(time)

  grace_cutoff = time.change(sec: 0) - @grace

  if at_time < grace_cutoff
    at_time + if @wday.nil?
                @hour.nil? ? 1.hour : 1.day
              else
                1.week
              end
  else
    at_time
  end
end
serialize() click to toggle source
# File lib/zhong/at.rb, line 70
def serialize
  MessagePack.pack(as_json)
end
to_s() click to toggle source
# File lib/zhong/at.rb, line 59
def to_s
  str = "#{formatted_time(@hour)}:#{formatted_time(@minute)}"
  str += " on #{WDAYS.invert[@wday].capitalize}" if @wday

  str
end

Protected Instance Methods

formatted_time(t) click to toggle source
# File lib/zhong/at.rb, line 113
def formatted_time(t)
  if t.nil?
    "**"
  else
    t.to_s.rjust(2, "0")
  end
end
state() click to toggle source
# File lib/zhong/at.rb, line 121
def state
  [@minute, @hour, @wday]
end

Private Instance Methods

at_time_day_hour_minute_adjusted(time) click to toggle source
# File lib/zhong/at.rb, line 139
def at_time_day_hour_minute_adjusted(time)
  at_time_hour_minute_adjusted(time) + (@wday ? (@wday - time.wday) : 0).days
end
at_time_hour_minute_adjusted(time) click to toggle source
# File lib/zhong/at.rb, line 127
def at_time_hour_minute_adjusted(time)
  if @minute && @hour
    time.change(hour: @hour, min: @minute)
  elsif @minute
    time.change(min: @minute)
  elsif @hour && @hour != time.hour
    time.change(hour: @hour)
  else
    time.change(sec: 0)
  end
end
valid?() click to toggle source
# File lib/zhong/at.rb, line 143
def valid?
  (@minute.nil? || (0..59).cover?(@minute)) &&
    (@hour.nil? || (0..23).cover?(@hour)) &&
    (@wday.nil? || (0..6).cover?(@wday))
end