philiprehberger-interval

Tests Gem Version Last updated

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:

Star the repo

🐛 Report issues

💡 Suggest features

❤️ Sponsor development

🌐 All Open Source Projects

💻 GitHub Profile

🔗 LinkedIn Profile

License

MIT