Class: Tod::Shift

Inherits:
Object
  • Object
show all
Defined in:
lib/tod/shift.rb

Overview

Shift is a range-like class that handles wrapping around midnight. For example, the Shift of 2300 to 0200 would include 0100.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(beginning, ending, exclude_end = false) ⇒ Shift

Returns a new instance of Shift.

Raises:

  • (ArgumentError)


8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/tod/shift.rb', line 8

def initialize(beginning, ending, exclude_end=false)
  raise ArgumentError, "beginning can not be nil" unless beginning
  raise ArgumentError, "ending can not be nil" unless ending
  unless [true, false].include? exclude_end
    raise ArgumentError, "exclude_end must be true or false"
  end

  @beginning = beginning
  @ending = ending
  @exclude_end = exclude_end

  normalized_ending = ending.to_i
  normalized_ending += TimeOfDay::NUM_SECONDS_IN_DAY if normalized_ending < beginning.to_i

  @range = Range.new(beginning.to_i, normalized_ending, @exclude_end)

  freeze # Shift instances are value objects
end

Instance Attribute Details

#beginningObject (readonly)

Returns the value of attribute beginning.



6
7
8
# File 'lib/tod/shift.rb', line 6

def beginning
  @beginning
end

#endingObject (readonly)

Returns the value of attribute ending.



6
7
8
# File 'lib/tod/shift.rb', line 6

def ending
  @ending
end

#rangeObject (readonly)

Returns the value of attribute range.



6
7
8
# File 'lib/tod/shift.rb', line 6

def range
  @range
end

Instance Method Details

#==(other) ⇒ Object



66
67
68
# File 'lib/tod/shift.rb', line 66

def ==(other)
  @range == other.range
end

#contains?(shift) ⇒ Boolean

Returns:

  • (Boolean)


52
53
54
# File 'lib/tod/shift.rb', line 52

def contains?(shift)
  self.include?(shift.beginning) && self.include?(shift.ending)
end

#durationObject

Return shift duration in seconds. if ending is lower than beginning this method will calculate the duration as the ending time is from the following day



58
59
60
# File 'lib/tod/shift.rb', line 58

def duration
  @range.last - @range.first
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


70
71
72
# File 'lib/tod/shift.rb', line 70

def eql?(other)
  @range.eql?(other.range)
end

#exclude_end?Boolean

Returns:

  • (Boolean)


62
63
64
# File 'lib/tod/shift.rb', line 62

def exclude_end?
  @exclude_end
end

#hashObject



74
75
76
# File 'lib/tod/shift.rb', line 74

def hash
  @range.hash
end

#include?(tod) ⇒ Boolean

Returns true if the time of day is inside the shift, false otherwise.

Returns:

  • (Boolean)


28
29
30
31
32
# File 'lib/tod/shift.rb', line 28

def include?(tod)
  second = tod.to_i
  second += TimeOfDay::NUM_SECONDS_IN_DAY if second < @range.first
  @range.cover?(second)
end

#overlaps?(other) ⇒ Boolean

Returns true if ranges overlap, false otherwise.

Returns:

  • (Boolean)


35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/tod/shift.rb', line 35

def overlaps?(other)
  max_seconds = TimeOfDay::NUM_SECONDS_IN_DAY

  # Standard case, when Shifts are on the same day
  a, b = [self, other].map(&:range).sort_by(&:first)
  op = a.exclude_end? ? :> : :>=
  return true if a.last.send(op, b.first)

  # Special cases, when Shifts span to the next day
  return false if (a.last < max_seconds) && (b.last < max_seconds)

  a = Range.new(a.first, a.last - max_seconds, a.exclude_end?) if a.last > max_seconds
  b = Range.new(b.first, b.last - max_seconds, b.exclude_end?) if b.last > max_seconds
  a, b = [a, b].sort_by(&:last)
  b.last.send(op, a.last) && a.last.send(op, b.first)
end

#slide(seconds) ⇒ Object

Move start and end by a number of seconds and return new shift.



79
80
81
# File 'lib/tod/shift.rb', line 79

def slide(seconds)
  self.class.new(beginning + seconds, ending + seconds, exclude_end?)
end