Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions lib/ice_cube/rules/daily_rule.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@ module IceCube

class DailyRule < ValidatedRule

include Validations::HourOfDay
include Validations::MinuteOfHour
include Validations::SecondOfMinute
include Validations::DayOfMonth
include Validations::DayOfWeek
include Validations::Day
include Validations::MonthOfYear
# include Validations::DayOfYear # n/a

include Validations::DailyInterval

def initialize(interval = 1)
Expand All @@ -11,6 +20,26 @@ def initialize(interval = 1)
reset
end

def verify_alignment(value, freq, rule_part)
return unless freq == :wday || freq == :day
return unless @validations[:interval]

interval_validation = @validations[:interval].first
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe worth moving this interval-checking into a util that we can use in both places

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'm not 100% happy with some of the duplication & super-calling either. I'll see what I can do.

interval_value = (rule_part == :interval) ? value : interval_validation.interval
return if interval_value == 1

if freq == :wday
return if (interval_value % 7).zero?
return if Array(@validations[:day]).empty?
message = "day can only be used with multiples of interval(7)"
else
(fixed_validation = other_fixed_value_validations.first) or return
message = "#{fixed_validation.key} can only be used with interval(1)"
end

yield ArgumentError.new(message)
end

end

end
9 changes: 9 additions & 0 deletions lib/ice_cube/rules/hourly_rule.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@ module IceCube

class HourlyRule < ValidatedRule

include Validations::HourOfDay
include Validations::MinuteOfHour
include Validations::SecondOfMinute
include Validations::DayOfMonth
include Validations::DayOfWeek
include Validations::Day
include Validations::MonthOfYear
include Validations::DayOfYear

include Validations::HourlyInterval

def initialize(interval = 1)
Expand Down
9 changes: 9 additions & 0 deletions lib/ice_cube/rules/minutely_rule.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@ module IceCube

class MinutelyRule < ValidatedRule

include Validations::HourOfDay
include Validations::MinuteOfHour
include Validations::SecondOfMinute
include Validations::DayOfMonth
include Validations::DayOfWeek
include Validations::Day
include Validations::MonthOfYear
include Validations::DayOfYear

include Validations::MinutelyInterval

def initialize(interval = 1)
Expand Down
22 changes: 22 additions & 0 deletions lib/ice_cube/rules/monthly_rule.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@ module IceCube

class MonthlyRule < ValidatedRule

include Validations::HourOfDay
include Validations::MinuteOfHour
include Validations::SecondOfMinute
include Validations::DayOfMonth
include Validations::DayOfWeek
include Validations::Day
include Validations::MonthOfYear
# include Validations::DayOfYear # n/a

include Validations::MonthlyInterval

def initialize(interval = 1)
Expand All @@ -11,6 +20,19 @@ def initialize(interval = 1)
reset
end

def verify_alignment(value, freq, rule_part)
return unless freq == :month
return unless @validations[:interval]

interval_validation = @validations[:interval].first
interval_value = (rule_part == :interval) ? value : interval_validation.interval
return if interval_value == 1 || (interval_value % 12).zero?
return if other_fixed_value_validations.empty?

message = "month_of_year can only be used with interval(1) or multiples of interval(12)"
yield ArgumentError.new(message)
end

end

end
9 changes: 9 additions & 0 deletions lib/ice_cube/rules/secondly_rule.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@ module IceCube

class SecondlyRule < ValidatedRule

include Validations::HourOfDay
include Validations::MinuteOfHour
include Validations::SecondOfMinute
include Validations::DayOfMonth
include Validations::DayOfWeek
include Validations::Day
include Validations::MonthOfYear
include Validations::DayOfYear

include Validations::SecondlyInterval

def initialize(interval = 1)
Expand Down
11 changes: 10 additions & 1 deletion lib/ice_cube/rules/weekly_rule.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@ module IceCube

class WeeklyRule < ValidatedRule

include Validations::HourOfDay
include Validations::MinuteOfHour
include Validations::SecondOfMinute
# include Validations::DayOfMonth # n/a
include Validations::DayOfWeek
include Validations::Day
include Validations::MonthOfYear
# include Validations::DayOfYear # n/a

include Validations::WeeklyInterval

attr_reader :week_start
Expand All @@ -28,7 +37,7 @@ def realign(step_time, start_time)
time = TimeUtil::TimeWrapper.new(start_time)
offset = wday_offset(step_time, start_time)
time.add(:day, offset)
time.to_time
super step_time, time.to_time
end

# Calculate how many days to the first wday validation in the correct
Expand Down
9 changes: 9 additions & 0 deletions lib/ice_cube/rules/yearly_rule.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@ module IceCube

class YearlyRule < ValidatedRule

include Validations::HourOfDay
include Validations::MinuteOfHour
include Validations::SecondOfMinute
include Validations::DayOfMonth
include Validations::DayOfWeek
include Validations::Day
include Validations::MonthOfYear
include Validations::DayOfYear

include Validations::YearlyInterval

def initialize(interval = 1)
Expand Down
12 changes: 11 additions & 1 deletion lib/ice_cube/time_util.rb
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,17 @@ def clear_below(type)
end
end

private
def hour=(value)
@time += (value * ONE_HOUR) - (@time.hour * ONE_HOUR)
end

def min=(value)
@time += (value * ONE_MINUTE) - (@time.min * ONE_MINUTE)
end

def sec=(value)
@time += (value) - (@time.sec)
end

def clear_sec
@time.sec > 0 ? @time -= @time.sec : @time
Expand Down
40 changes: 31 additions & 9 deletions lib/ice_cube/validated_rule.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,6 @@ class ValidatedRule < Rule

include Validations::ScheduleLock

include Validations::HourOfDay
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 to splitting these out so we can only have them where they make sense

include Validations::MinuteOfHour
include Validations::SecondOfMinute
include Validations::DayOfMonth
include Validations::DayOfWeek
include Validations::Day
include Validations::MonthOfYear
include Validations::DayOfYear

include Validations::Count
include Validations::Until

Expand Down Expand Up @@ -51,6 +42,14 @@ def other_interval_validations
Array(@validations[base_interval_validation.type])
end

def other_fixed_value_validations
@validations.values.flatten.select { |v|
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: do / end on multi-line blocks

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, sure. 😄

I've always been more partial to Jim Weirich's semantic brace style, and I try to sneak it in when I can:

  • Use { } for blocks that return values (functional)
  • Use do / end for blocks that are executed for side effects (procedural)

It actually turns out that doing it this way, it works out that very often it's the same as the single-line vs. multi-line style, because of the kinds of things that go into procedural vs. functional blocks.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay I can be down with that - I like the idea :)

interval_type = (v.type == :wday ? :day : v.type)
v.class < Validations::FixedValue &&
interval_type == base_interval_validation.type
}
end

# Compute the next time after (or including) the specified time in respect
# to the given start time
def next_time(time, start_time, closing_time)
Expand Down Expand Up @@ -185,6 +184,29 @@ def validation_names
VALIDATION_ORDER & @validations.keys
end

def verify_alignment(value, freq, rule_part, options={})
@validations[:interval] or return
interval_validation = @validations[:interval].first
interval_validation.type == freq or return
fixed_validations = other_fixed_value_validations
(last_validation = fixed_validations.min_by(&:value)) or return

alignment = (value - last_validation.value) % interval_validation.interval
return if alignment.zero?

validation_values = fixed_validations.map(&:value).join(', ')
if rule_part == :interval
message = "interval(#{value}) " \
"must be a multiple of " \
"intervals in #{last_validation.key}(#{validation_values})"
else
message = "intervals in #{last_validation.key}(#{validation_values}, #{value}) " \
"must be multiples of " \
"interval(#{interval_validation.interval})"
end
yield ArgumentError.new(message)
end

end

end
6 changes: 5 additions & 1 deletion lib/ice_cube/validations/daily_interval.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ module Validations::DailyInterval

# Add a new interval validation
def interval(interval)
@interval = normalized_interval(interval)
interval = normalized_interval(interval)
verify_alignment(interval, :wday, :interval) { |error| raise error }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we yield this error up instead of just raiseing it?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is so that it gives a more relevant trace, since it appears from the called interval public method interface, instead of raising from somewhere deeper down.

verify_alignment(interval, :day, :interval) { |error| raise error }

@interval = interval
replace_validations_for(:interval, [Validation.new(@interval)])
clobber_base_validations(:wday, :day)
self
Expand Down
6 changes: 6 additions & 0 deletions lib/ice_cube/validations/day.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ def day(*days)
raise ArgumentError, "expecting Integer or Symbol value for day, got #{day.inspect}"
end
day = TimeUtil.sym_to_wday(day)
verify_alignment(day, :wday, :day) { |error| raise error }

validations_for(:day) << Validation.new(day)
end
clobber_base_validations(:wday, :day)
Expand All @@ -25,6 +27,10 @@ def initialize(day)
@day = day
end

def key
:day
end

def type
:wday
end
Expand Down
5 changes: 5 additions & 0 deletions lib/ice_cube/validations/day_of_month.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ def day_of_month(*days)
unless day.is_a?(Integer)
raise ArgumentError, "expecting Integer value for day, got #{day.inspect}"
end
verify_alignment(day, :day, :day_of_month) { |error| raise error }
validations_for(:day_of_month) << Validation.new(day)
end
clobber_base_validations(:day, :wday)
Expand All @@ -22,6 +23,10 @@ def initialize(day)
@day = day
end

def key
:day_of_month
end

def type
:day
end
Expand Down
23 changes: 23 additions & 0 deletions lib/ice_cube/validations/hour_of_day.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,31 @@ def hour_of_day(*hours)
unless hour.is_a?(Integer)
raise ArgumentError, "expecting Integer value for hour, got #{hour.inspect}"
end

verify_alignment(hour, :hour, :hour_of_day) { |error| raise error }

validations_for(:hour_of_day) << Validation.new(hour)
end
clobber_base_validations(:hour)
self
end

def realign(opening_time, start_time)
return super unless validations[:hour_of_day]
freq = base_interval_validation.interval

first_hour = Array(validations[:hour_of_day]).min_by(&:value)
time = TimeUtil::TimeWrapper.new(start_time, false)
if freq > 1
offset = first_hour.validate(opening_time, start_time)
time.add(:hour, offset - freq)
else
time.hour = first_hour.value
end

super opening_time, time.to_time
end

class Validation < Validations::FixedValue

attr_reader :hour
Expand All @@ -23,6 +42,10 @@ def initialize(hour)
@hour = hour
end

def key
:hour_of_day
end

def type
:hour
end
Expand Down
2 changes: 2 additions & 0 deletions lib/ice_cube/validations/hourly_interval.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ module IceCube
module Validations::HourlyInterval

def interval(interval)
verify_alignment(interval, :hour, :interval) { |error| raise error }

@interval = normalized_interval(interval)
replace_validations_for(:interval, [Validation.new(@interval)])
clobber_base_validations(:hour)
Expand Down
16 changes: 16 additions & 0 deletions lib/ice_cube/validations/minute_of_hour.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,24 @@ def minute_of_hour(*minutes)
unless minute.is_a?(Integer)
raise ArgumentError, "expecting Integer value for minute, got #{minute.inspect}"
end

verify_alignment(minute, :min, :minute_of_hour) { |error| raise error }

validations_for(:minute_of_hour) << Validation.new(minute)
end
clobber_base_validations(:min)
self
end

def realign(opening_time, start_time)
return super unless validations[:minute_of_hour]

first_minute = validations[:minute_of_hour].min_by(&:value)
time = TimeUtil::TimeWrapper.new(start_time, false)
time.min = first_minute.value
super opening_time, time.to_time
end

class Validation < Validations::FixedValue

attr_reader :minute
Expand All @@ -22,6 +34,10 @@ def initialize(minute)
@minute = minute
end

def key
:minute_of_hour
end

def type
:min
end
Expand Down
2 changes: 2 additions & 0 deletions lib/ice_cube/validations/minutely_interval.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ module IceCube
module Validations::MinutelyInterval

def interval(interval)
verify_alignment(interval, :min, :interval) { |error| raise error }

@interval = normalized_interval(interval)
replace_validations_for(:interval, [Validation.new(@interval)])
clobber_base_validations(:min)
Expand Down
Loading