Skip to content

Commit

Permalink
Added support for conflicts_with?
Browse files Browse the repository at this point in the history
  • Loading branch information
seejohnrun committed Jan 1, 2012
1 parent a0d923f commit 88bb48a
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 3 deletions.
47 changes: 44 additions & 3 deletions lib/ice_cube/schedule.rb
Expand Up @@ -125,9 +125,7 @@ def occurrences(closing_time)

# All of the occurrences
def all_occurrences
unless end_time || recurrence_rules.all?(&:terminating?)
raise ArgumentError.new('Rule must specify either an until date or a count to use #all_occurrences')
end
raise ArgumentError.new('Rule must specify either an until date or a count to use #all_occurrences') unless terminating?
find_occurrences(start_time)
end

Expand Down Expand Up @@ -180,6 +178,43 @@ def occurring_at?(time)
end
end

# Determine if this schedule conflicts with another schedule
# @param [IceCube::Schedule] other_schedule - The schedule to compare to
# @param [Time] closing_time - the last time to consider
# @return [Boolean] whether or not the schedules conflict at all
def conflicts_with?(other_schedule, closing_time = nil)
unless terminating? || other_schedule.terminating? || closing_time
raise ArgumentError.new 'At least one schedule must be terminating to use #conflicts_with?'
end
# Pick the terminating schedule, and other schedule
# No need to reverse if terminating? or there is a closing time
terminating_schedule = self
unless terminating? || closing_time
terminating_schedule, other_schedule = other_schedule, terminating_schedule
end
# Go through each occurrence of the terminating schedule and determine
# if the other occurs at that time
last_time = nil
terminating_schedule.each_occurrence do |time|
if closing_time && time > closing_time
last_time = closing_time
break
end
last_time = time
return true if other_schedule.occurring_at?(time)
end
# Due to durations, we need to walk up to the end time, and verify in the
# other direction
if last_time
other_schedule.each_occurrence do |time|
break if time > last_time
return true if terminating_schedule.occurring_at?(time)
end
end
# No conflict, return false
false
end

# Determine if the schedule occurs at a specific time
def occurs_at?(time)
occurs_between?(time, time)
Expand Down Expand Up @@ -261,6 +296,12 @@ def self.from_hash(data, options = {})
schedule
end

# Determine if the schedule will end
# @return [Boolean] true if ending, false if repeating forever
def terminating?
end_time || recurrence_rules.all?(&:terminating?)
end

private

# Reset all rules for another run
Expand Down
97 changes: 97 additions & 0 deletions spec/examples/schedule_spec.rb
Expand Up @@ -4,6 +4,103 @@

include IceCube

describe :conflicts_with? do

it 'should raise an error if both are not terminating' do
schedules = 2.times.map do
schedule = IceCube::Schedule.new(Time.now)
schedule.rrule IceCube::Rule.daily
schedule
end
lambda do
schedules.first.conflicts_with?(schedules.last)
end.should raise_error ArgumentError
end

it 'should not raise error if both are non-terminating closing time present' do
schedule1 = IceCube::Schedule.new Time.now
schedule1.rrule IceCube::Rule.weekly
schedule2 = IceCube::Schedule.new Time.now
schedule2.rrule IceCube::Rule.weekly
lambda do
schedule1.conflicts_with?(schedule2, Time.now + IceCube::ONE_DAY)
end.should_not raise_error
end

it 'should not raise an error if one is non-terminating' do
schedule1 = IceCube::Schedule.new Time.now
schedule1.rrule IceCube::Rule.weekly
schedule2 = IceCube::Schedule.new Time.now
schedule2.rrule IceCube::Rule.weekly.until(Time.now)
lambda do
schedule1.conflicts_with?(schedule2)
end.should_not raise_error
end

it 'should not raise an error if the other is non-terminating' do
schedule1 = IceCube::Schedule.new Time.now
schedule1.rrule IceCube::Rule.weekly.until(Time.now)
schedule2 = IceCube::Schedule.new Time.now
schedule2.rrule IceCube::Rule.weekly
lambda do
schedule1.conflicts_with?(schedule2)
end.should_not raise_error
end

it 'should return true if conflict is present' do
start_time = Time.now
schedule1 = IceCube::Schedule.new(start_time)
schedule1.rrule IceCube::Rule.daily
schedule2 = IceCube::Schedule.new(start_time)
schedule2.rrule IceCube::Rule.daily
conflict = schedule1.conflicts_with?(schedule2, start_time + IceCube::ONE_DAY)
conflict.should be_true
end

it 'should return false if conflict is not present' do
start_time = Time.now
schedule1 = IceCube::Schedule.new(start_time)
schedule1.rrule IceCube::Rule.weekly.day(:tuesday)
schedule2 = IceCube::Schedule.new(start_time)
schedule2.rrule IceCube::Rule.weekly.day(:monday)
conflict = schedule1.conflicts_with?(schedule2, start_time + IceCube::ONE_DAY)
conflict.should be_false
end

it 'should return true if conflict is present based on duration' do
start_time = Time.now
schedule1 = IceCube::Schedule.new(start_time, :duration => IceCube::ONE_DAY + 1)
schedule1.rrule IceCube::Rule.weekly.day(:monday)
schedule2 = IceCube::Schedule.new(start_time)
schedule2.rrule IceCube::Rule.weekly.day(:tuesday)
conflict = schedule1.conflicts_with?(schedule2, start_time + IceCube::ONE_WEEK)
conflict.should be_true
end

it 'should return true if conflict is present based on duration - other way' do
start_time = Time.now
schedule1 = IceCube::Schedule.new(start_time)
schedule1.rrule IceCube::Rule.weekly.day(:tuesday)
schedule2 = IceCube::Schedule.new(start_time, :duration => IceCube::ONE_DAY + 1)
schedule2.rrule IceCube::Rule.weekly.day(:monday)
conflict = schedule1.conflicts_with?(schedule2, start_time + IceCube::ONE_WEEK)
conflict.should be_true
end

it 'should return false if conflict is past closing_time' do
start_time = Time.local(2011, 1, 1, 12) # Sunday
schedule1 = IceCube::Schedule.new(start_time)
schedule1.rrule IceCube::Rule.weekly.day(:friday)
schedule2 = IceCube::Schedule.new(start_time)
schedule2.rrule IceCube::Rule.weekly.day(:friday)
schedule2.conflicts_with?(schedule1, start_time + IceCube::ONE_WEEK).
should be_true
schedule2.conflicts_with?(schedule1, start_time + IceCube::ONE_DAY).
should be_false
end

end

describe :each do

it 'should be able to yield occurrences for a schedule' do
Expand Down

0 comments on commit 88bb48a

Please sign in to comment.