Class: Philiprehberger::Interval::Range

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/philiprehberger/interval/range.rb

Overview

Represents a closed interval [start, finish] over any Comparable type.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(start, finish) ⇒ Range

Create a new interval.

Parameters:

  • start (Comparable)

    the start value

  • finish (Comparable)

    the end value

Raises:

  • (Error)

    if start > finish



20
21
22
23
24
25
# File 'lib/philiprehberger/interval/range.rb', line 20

def initialize(start, finish)
  raise Error, 'start must be <= finish' if start > finish

  @start = start
  @finish = finish
end

Instance Attribute Details

#finishComparable (readonly)

Returns the end of the interval.

Returns:

  • (Comparable)

    the end of the interval



13
14
15
# File 'lib/philiprehberger/interval/range.rb', line 13

def finish
  @finish
end

#startComparable (readonly)

Returns the start of the interval.

Returns:

  • (Comparable)

    the start of the interval



10
11
12
# File 'lib/philiprehberger/interval/range.rb', line 10

def start
  @start
end

Instance Method Details

#<=>(other) ⇒ Integer

Compare intervals by start then finish.

Parameters:

Returns:

  • (Integer)


104
105
106
107
# File 'lib/philiprehberger/interval/range.rb', line 104

def <=>(other)
  result = @start <=> other.start
  result.zero? ? @finish <=> other.finish : result
end

#==(other) ⇒ Boolean

Returns:

  • (Boolean)


110
111
112
# File 'lib/philiprehberger/interval/range.rb', line 110

def ==(other)
  other.is_a?(self.class) && @start == other.start && @finish == other.finish
end

#adjacent?(other) ⇒ Boolean

Check if this interval is adjacent to another (touching but not overlapping).

Parameters:

  • other (Range)

    the other interval

Returns:

  • (Boolean)


47
48
49
# File 'lib/philiprehberger/interval/range.rb', line 47

def adjacent?(other)
  @finish == other.start || other.finish == @start
end

#contains?(other) ⇒ Boolean

Check if this interval fully contains another.

Parameters:

  • other (Range)

    the other interval

Returns:

  • (Boolean)


39
40
41
# File 'lib/philiprehberger/interval/range.rb', line 39

def contains?(other)
  @start <= other.start && @finish >= other.finish
end

#include?(point) ⇒ Boolean

Check if a point is within the interval.

Parameters:

  • point (Comparable)

    the point to check

Returns:

  • (Boolean)


96
97
98
# File 'lib/philiprehberger/interval/range.rb', line 96

def include?(point)
  point >= @start && point <= @finish
end

#inspectString

Returns:

  • (String)


120
121
122
# File 'lib/philiprehberger/interval/range.rb', line 120

def inspect
  "#<#{self.class} #{self}>"
end

#intersect(other) ⇒ Range?

Return the intersection of two overlapping intervals.

Parameters:

  • other (Range)

    the other interval

Returns:

  • (Range, nil)

    the intersection, or nil if no overlap



55
56
57
58
59
# File 'lib/philiprehberger/interval/range.rb', line 55

def intersect(other)
  return nil unless overlaps?(other)

  self.class.new([@start, other.start].max, [@finish, other.finish].min)
end

#overlaps?(other) ⇒ Boolean

Check if this interval overlaps with another.

Parameters:

  • other (Range)

    the other interval

Returns:

  • (Boolean)


31
32
33
# File 'lib/philiprehberger/interval/range.rb', line 31

def overlaps?(other)
  @start <= other.finish && other.start <= @finish
end

#sizeNumeric

Return the size (length) of the interval.

Returns:

  • (Numeric)

    the difference between finish and start



88
89
90
# File 'lib/philiprehberger/interval/range.rb', line 88

def size
  @finish - @start
end

#subtract(other) ⇒ Array<Range>

Subtract another interval from this one.

Parameters:

  • other (Range)

    the interval to subtract

Returns:

  • (Array<Range>)

    zero, one, or two remaining intervals



75
76
77
78
79
80
81
82
83
# File 'lib/philiprehberger/interval/range.rb', line 75

def subtract(other)
  return [self.class.new(@start, @finish)] unless overlaps?(other)
  return [] if other.contains?(self)

  result = []
  result << self.class.new(@start, other.start) if @start < other.start
  result << self.class.new(other.finish, @finish) if other.finish < @finish
  result
end

#to_sString

Returns:

  • (String)


115
116
117
# File 'lib/philiprehberger/interval/range.rb', line 115

def to_s
  "[#{@start}, #{@finish}]"
end

#union(other) ⇒ Range?

Return the union of two overlapping or adjacent intervals.

Parameters:

  • other (Range)

    the other interval

Returns:

  • (Range, nil)

    the union, or nil if not overlapping/adjacent



65
66
67
68
69
# File 'lib/philiprehberger/interval/range.rb', line 65

def union(other)
  return nil unless overlaps?(other) || adjacent?(other)

  self.class.new([@start, other.start].min, [@finish, other.finish].max)
end