class Linesmen::Timeline

This class deals with timeline operations. We understand timelines here as a sequence of non-contiguous events. The methods here are mostly boolean operations. This article may help you to understand them: www.wikiwand.com/en/Boolean_operations_on_polygons

Attributes

time_ranges[R]

Public Class Methods

new(*time_ranges) click to toggle source
# File lib/linesmen/timeline.rb, line 11
def initialize(*time_ranges)
  @time_ranges = time_ranges
  ensure_no_overlapping!
end

Public Instance Methods

!@()
Alias for: invert
&(other)
Alias for: intersect
+(other)
Alias for: union
-(other)
Alias for: subtract
gross_duration() click to toggle source
# File lib/linesmen/timeline.rb, line 54
def gross_duration
  time_ranges.last.end - time_ranges.first.begin
end
hours() click to toggle source
# File lib/linesmen/timeline.rb, line 70
def hours
  minutes / 60
end
intersect(other) click to toggle source
# File lib/linesmen/timeline.rb, line 34
def intersect(other)
  case other
  when Range    then intersect_time_ranges(other)
  when Timeline then intersect_time_ranges(*other.time_ranges)
  end
end
Also aliased as: &
invert() click to toggle source
# File lib/linesmen/timeline.rb, line 43
def invert
  Timeline.new(
    *time_ranges.map.with_index do |range, index|
      next if index.zero?
      time_ranges[index - 1].end..range.begin
    end.compact
  )
end
Also aliased as: !@
minutes() click to toggle source
# File lib/linesmen/timeline.rb, line 66
def minutes
  seconds / 60
end
net_duration() click to toggle source
# File lib/linesmen/timeline.rb, line 58
def net_duration
  time_ranges.sum(0) do |time_range|
    time_range.end - time_range.begin
  end
end
Also aliased as: seconds
seconds()
Alias for: net_duration
subtract(other) click to toggle source
# File lib/linesmen/timeline.rb, line 25
def subtract(other)
  case other
  when Range    then subtract_time_ranges(other)
  when Timeline then subtract_time_ranges(*other.time_ranges)
  end
end
Also aliased as: -
union(other) click to toggle source
# File lib/linesmen/timeline.rb, line 16
def union(other)
  case other
  when Range    then Timeline.new(*(time_ranges + [other]))
  when Timeline then Timeline.new(*(time_ranges + other.time_ranges))
  end
end
Also aliased as: +

Private Instance Methods

ensure_no_overlapping!() click to toggle source
# File lib/linesmen/timeline.rb, line 76
def ensure_no_overlapping!
  @time_ranges.sort_by!(&:begin)
  time_ranges.each_with_index do |time_range, index|
    next if index.zero?
    prev_range = time_ranges[index - 1]
    next unless prev_range.overlaps?(time_range)
    @time_ranges[index - 1] = union_two_ranges(prev_range, time_range)
    @time_ranges.delete_at(index)
    return ensure_no_overlapping!
  end
end
intersect_time_ranges(*other_ranges) click to toggle source
# File lib/linesmen/timeline.rb, line 108
def intersect_time_ranges(*other_ranges)
  Timeline.new(
    *time_ranges.reduce([]) do |memo, r|
      memo +
        other_ranges
        .select { |o| r.overlaps?(o) }
        .map    { |o| [intersect_two_ranges(r, o)].compact }
        .flatten
    end
  )
end
intersect_timelines(*other_timelines) click to toggle source
# File lib/linesmen/timeline.rb, line 126
def intersect_timelines(*other_timelines)
  intersect_time_ranges(*other_timelines.map(&:time_ranges).flatten)
end
intersect_two_ranges(range_a, range_b) click to toggle source
# File lib/linesmen/timeline.rb, line 120
def intersect_two_ranges(range_a, range_b)
  s = [range_a.begin, range_b.begin].max
  e = [range_a.end, range_b.end].min
  (s..e) if s < e
end
subtract_time_ranges(*other_ranges) click to toggle source
# File lib/linesmen/timeline.rb, line 92
def subtract_time_ranges(*other_ranges)
  return self if other_ranges.empty?
  o = other_ranges.first
  r = time_ranges.detect { |range| range.overlaps?(o) }
  return subtract_time_ranges(*other_ranges[1..-1]) unless r
  new_time_ranges = time_ranges - [r] + subtract_two_ranges(r, o)
  Timeline.new(*new_time_ranges).send(:subtract_time_ranges, *other_ranges)
end
subtract_two_ranges(range_a, range_b) click to toggle source
# File lib/linesmen/timeline.rb, line 101
def subtract_two_ranges(range_a, range_b)
  [
    ((range_a.begin..(range_b.begin - 1)) if range_a.begin < range_b.begin),
    (((range_b.end + 1)..range_a.end)     if range_b.end   < range_a.end)
  ].compact
end
union_two_ranges(range_a, range_b) click to toggle source
# File lib/linesmen/timeline.rb, line 88
def union_two_ranges(range_a, range_b)
  [range_a.begin, range_a.end].min..[range_b.begin, range_b.end].max
end