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)

32
33
34
# File 'lib/fat_core/range.rb', line 32

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 empty array


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 74

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 operation requires objects have pred and succ methods"
  end
  # return [] unless self.overlaps?(other)
  if proper_superset_of?(other)
    [(min..other.min.pred),
     (other.max.succ..max)]
  elsif subset_of?(other)
    []
  elsif overlaps?(other) && other.min <= min
    [(other.max.succ .. max)]
  elsif overlaps?(other) && other.max >= max
    [(min .. other.min.pred)]
  else
    []
  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
# File 'lib/fat_core/range.rb', line 135

def gaps(ranges)
  if ranges.empty?
    [self.clone]
  elsif spanned_by?(ranges)
    []
  else
    ranges = ranges.sort_by {|r| r.min}
    gaps = []
    cur_point = min
    ranges.each do |rr|
      if rr.min > cur_point
        start_point = cur_point
        end_point = rr.min.pred
        gaps << (start_point..end_point)
      end
      cur_point = rr.max.succ
    end
    if cur_point < max
      gaps << (cur_point..max)
    end
    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: &


57
58
59
60
# File 'lib/fat_core/range.rb', line 57

def intersection(other)
  return nil unless self.overlaps?(other)
  ([self.min, other.min].max..[self.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
11
12
# 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)
  else
    nil
  end
end

#left_contiguous?(other) ⇒ Boolean

Is self on the left of and contiguous to other?

Returns:

  • (Boolean)

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

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.


162
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
# File 'lib/fat_core/range.rb', line 162

def overlaps(ranges)
  if ranges.empty? || spanned_by?(ranges)
    []
  else
    ranges = ranges.sort_by {|r| r.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)

52
53
54
55
# File 'lib/fat_core/range.rb', line 52

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

#proper_subset_of?(other) ⇒ Boolean

Returns:

  • (Boolean)

40
41
42
# File 'lib/fat_core/range.rb', line 40

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

#proper_superset_of?(other) ⇒ Boolean

Returns:

  • (Boolean)

48
49
50
# File 'lib/fat_core/range.rb', line 48

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)

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

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 {|r| r.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)

36
37
38
# File 'lib/fat_core/range.rb', line 36

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

#superset_of?(other) ⇒ Boolean

Returns:

  • (Boolean)

44
45
46
# File 'lib/fat_core/range.rb', line 44

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

#tex_quoteObject

Allow erb documents can directly interpolate ranges


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

def tex_quote
  to_s
end

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


63
64
65
66
# File 'lib/fat_core/range.rb', line 63

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