Class: Range

Inherits:
Object
  • Object
show all
Defined in:
lib/fat_core/range.rb

Instance Method Summary collapse

Instance Method Details

#contiguous?(other) ⇒ Boolean

Returns:

  • (Boolean)

30
31
32
# File 'lib/fat_core/range.rb', line 30

def contiguous?(other)
  left_contiguous?(other) || right_contiguous?(other)
end

#difference(other) ⇒ Object Also known as: -

The difference method, -, removes the overlapping part of the other argument from self. Because in the case where self is a superset of the other range, this will result in the difference being two non-contiguous ranges, this returns an array of ranges. If there is no overlap or if self is a subset of the other range, return an array of self


72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/fat_core/range.rb', line 72

def difference(other)
  unless max.respond_to?(:succ) && min.respond_to?(:pred) &&
         other.max.respond_to?(:succ) && other.min.respond_to?(:pred)
    raise 'Range difference requires objects have pred and succ methods'
  end
  if subset_of?(other)
    # (4..7) - (0..10)
    []
  elsif proper_superset_of?(other)
    # (4..7) - (5..5) -> [(4..4), (6..7)]
    [(min..other.min.pred), (other.max.succ..max)]
  elsif overlaps?(other) && other.min <= min
    # (4..7) - (2..5) -> (6..7)
    [(other.max.succ..max)]
  elsif overlaps?(other) && other.max >= max
    # (4..7) - (6..10) -> (4..5)
    [(min..other.min.pred)]
  else
    [self]
  end
end

#gaps(ranges) ⇒ Object

If this range is not spanned by the ranges collectively, return an array of ranges representing the gaps in coverage. Otherwise return an empty array.


135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/fat_core/range.rb', line 135

def gaps(ranges)
  if ranges.empty?
    [clone]
  elsif spanned_by?(ranges)
    []
  else
    ranges = ranges.sort_by(&:min)
    gaps = []
    cur_point = min
    ranges.each do |rr|
      break if rr.min > max
      if rr.min > cur_point
        start_point = cur_point
        end_point = rr.min.pred
        gaps << (start_point..end_point)
        cur_point = rr.max.succ
      elsif rr.max >= cur_point
        cur_point = rr.max.succ
      end
    end
    gaps << (cur_point..max) if cur_point <= max
    gaps
  end
end

#has_overlaps_within?(ranges) ⇒ Boolean

Return whether any of the ranges that are within self overlap one another

Returns:

  • (Boolean)

97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/fat_core/range.rb', line 97

def has_overlaps_within?(ranges)
  result = false
  unless ranges.empty?
    ranges.each do |r1|
      next unless overlaps?(r1)
      result =
        ranges.any? do |r2|
          r1.object_id != r2.object_id && overlaps?(r2) &&
            r1.overlaps?(r2)
        end
      return true if result
    end
  end
  result
end

#intersection(other) ⇒ Object Also known as: &


55
56
57
58
# File 'lib/fat_core/range.rb', line 55

def intersection(other)
  return nil unless overlaps?(other)
  ([min, other.min].max..[max, other.max].min)
end

#join(other) ⇒ Object

Return a range that concatenates this range with other; return nil if the ranges are not contiguous.


4
5
6
7
8
9
10
# File 'lib/fat_core/range.rb', line 4

def join(other)
  if left_contiguous?(other)
    Range.new(min, other.max)
  elsif right_contiguous?(other)
    Range.new(other.min, max)
  end
end

#left_contiguous?(other) ⇒ Boolean

Is self on the left of and contiguous to other?

Returns:

  • (Boolean)

13
14
15
16
17
18
19
# File 'lib/fat_core/range.rb', line 13

def left_contiguous?(other)
  if max.respond_to?(:succ)
    max.succ == other.min
  else
    max == other.min
  end
end

#overlaps(ranges) ⇒ Object

Similar to gaps, but within this range return the /overlaps/ among the given ranges. If there are no overlaps, return an empty array. Don’t consider overlaps in the ranges that occur outside of self.


163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/fat_core/range.rb', line 163

def overlaps(ranges)
  if ranges.empty? || spanned_by?(ranges)
    []
  else
    ranges = ranges.sort_by(&:min)
    overlaps = []
    cur_point = nil
    ranges.each do |rr|
      # Skip ranges outside of self
      next if rr.max < min || rr.min > max
      # Initialize cur_point to max of first range
      if cur_point.nil?
        cur_point = rr.max
        next
      end
      # We are on the second or later range
      if rr.min < cur_point
        start_point = rr.min
        end_point = cur_point
        overlaps << (start_point..end_point)
      end
      cur_point = rr.max
    end
    overlaps
  end
end

#overlaps?(other) ⇒ Boolean

Returns:

  • (Boolean)

50
51
52
53
# File 'lib/fat_core/range.rb', line 50

def overlaps?(other)
  (cover?(other.min) || cover?(other.max) ||
   other.cover?(min) || other.cover?(max))
end

#proper_subset_of?(other) ⇒ Boolean

Returns:

  • (Boolean)

38
39
40
# File 'lib/fat_core/range.rb', line 38

def proper_subset_of?(other)
  min > other.min && max < other.max
end

#proper_superset_of?(other) ⇒ Boolean

Returns:

  • (Boolean)

46
47
48
# File 'lib/fat_core/range.rb', line 46

def proper_superset_of?(other)
  min < other.min && max > other.max
end

#right_contiguous?(other) ⇒ Boolean

Is self on the right of and contiguous to other?

Returns:

  • (Boolean)

22
23
24
25
26
27
28
# File 'lib/fat_core/range.rb', line 22

def right_contiguous?(other)
  if other.max.respond_to?(:succ)
    other.max.succ == min
  else
    other.max == min
  end
end

#spanned_by?(ranges) ⇒ Boolean

Return true if the given ranges collectively cover this range without overlaps.

Returns:

  • (Boolean)

115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/fat_core/range.rb', line 115

def spanned_by?(ranges)
  joined_range = nil
  ranges.sort_by(&:min).each do |r|
    unless joined_range
      joined_range = r
      next
    end
    joined_range = joined_range.join(r)
    break if joined_range.nil?
  end
  if !joined_range.nil?
    joined_range.min <= min && joined_range.max >= max
  else
    false
  end
end

#subset_of?(other) ⇒ Boolean

Returns:

  • (Boolean)

34
35
36
# File 'lib/fat_core/range.rb', line 34

def subset_of?(other)
  min >= other.min && max <= other.max
end

#superset_of?(other) ⇒ Boolean

Returns:

  • (Boolean)

42
43
44
# File 'lib/fat_core/range.rb', line 42

def superset_of?(other)
  min <= other.min && max >= other.max
end

#tex_quoteObject

Allow erb documents can directly interpolate ranges


191
192
193
# File 'lib/fat_core/range.rb', line 191

def tex_quote
  to_s
end

#union(other) ⇒ Object Also known as: +


61
62
63
64
# File 'lib/fat_core/range.rb', line 61

def union(other)
  return nil unless overlaps?(other) || contiguous?(other)
  ([min, other.min].min..[max, other.max].max)
end