philiprehberger-interval
Interval data type with open/closed boundaries, arithmetic, merging, and gap finding
Requirements
- Ruby >= 3.1
Installation
Add to your Gemfile:
gem "philiprehberger-interval"
Or install directly:
gem install philiprehberger-interval
Usage
require "philiprehberger/interval"
a = Philiprehberger::Interval.new(1, 5)
b = Philiprehberger::Interval.new(3, 8)
a.overlaps?(b) # => true
a.intersect(b) # => [3, 5]
a.union(b) # => [1, 8]
a.include?(4) # => true
Interval Types
Supports closed, open, and half-open boundaries:
closed = Philiprehberger::Interval.new(1, 5, type: :closed) # [1, 5] (default)
open = Philiprehberger::Interval.new(1, 5, type: :open) # (1, 5)
left_open = Philiprehberger::Interval.new(1, 5, type: :left_open) # (1, 5]
right_open = Philiprehberger::Interval.new(1, 5, type: :right_open) # [1, 5)
closed.include?(5) # => true
right_open.include?(5) # => false
Interval Arithmetic
interval = Philiprehberger::Interval.new(2, 8)
interval.shift(3) # => [5, 11]
interval.scale(2, anchor: :left) # => [2, 14]
interval.scale(0.5, anchor: :center) # => [3.5, 6.5]
interval.split(3) # => [[2, 4], [4, 6], [6, 8]]
interval.clamp(10) # => 8
Merging Intervals
intervals = [
Philiprehberger::Interval.new(1, 5),
Philiprehberger::Interval.new(3, 7),
Philiprehberger::Interval.new(10, 15)
]
Philiprehberger::Interval.merge(intervals)
# => [[1, 7], [10, 15]]
Finding Gaps
Philiprehberger::Interval.gaps(intervals)
# => [[7, 10]]
Finding a Common Intersection
Compute the overlap shared by every interval, or nil if any pair is disjoint:
Philiprehberger::Interval.intersection([
Philiprehberger::Interval.new(1, 10),
Philiprehberger::Interval.new(3, 8),
Philiprehberger::Interval.new(5, 12)
])
# => [5, 8]
With Time Values
shift = Philiprehberger::Interval.new(Time.new(2026, 1, 1, 9), Time.new(2026, 1, 1, 17))
shift.include?(Time.new(2026, 1, 1, 12)) # => true
API
| Method | Description |
|---|---|
.new(start, finish, type:) |
Create an interval (:closed, :open, :left_open, :right_open) |
#type |
Return the interval boundary type |
#overlaps?(other) |
Check if two intervals overlap (respects boundary types) |
#contains?(other) |
Check if interval fully contains another |
#adjacent?(other) |
Check if intervals are touching but not overlapping |
#intersect(other) |
Return the overlap between two intervals |
#union(other) |
Return the combined interval |
#subtract(other) |
Remove another interval, returning remaining parts |
#size |
Length of the interval |
#include?(point) |
Check if a point falls within the interval (respects boundary types) |
#shift(delta) |
Return new interval shifted by delta, preserving type |
#scale(factor, anchor:) |
Scale width around anchor (:center, :left, :right) |
#split(n) |
Split into n equal sub-intervals |
#clamp(value) |
Clamp value to interval bounds |
.merge(intervals) |
Merge overlapping intervals into non-overlapping set |
.gaps(intervals) |
Find gaps between a set of intervals |
.intersection(intervals) |
Common overlap of a collection of intervals, or nil |
Development
bundle install
bundle exec rspec
bundle exec rubocop
Support
If you find this project useful: