Skip to content

🧩 Aeon::Period – 4 + 1 Architecture

Aeon::Period defines time itself—measurable, movable, and mutable.


1️⃣ Logical View

Purpose:
Aeon::Period encapsulates a bounded span of time (starts_at..ends_at) and provides fluent arithmetic for navigation (>>, <<), growth (+, -), and scaling (*, /).
It’s the mathematical heart of Aeon.

Key Responsibilities - Represent finite time spans with absolute precision. - Provide clear operator semantics (shift vs grow vs scale). - Remain immutable: all mutations return new objects. - Support construction by starts_at + ends_at or start + duration.

Attributes

Field Type Description
starts_at datetime Inclusive start
ends_at datetime Exclusive end
duration numeric Derived seconds

2️⃣ Process View

Operation Meaning Example
>> Shift forward period >> 1.week
<< Shift backward period << 2.days
+ Grow (extend end) period + 1.day
- Shrink (reduce end) period - 1.hour
* / / Scale (around start) period * 2 → double length

All operations are pure functions producing new Aeon::Period instances.


3️⃣ Development View

File: app/models/aeon/period.rb

Implementation Highlights

class Aeon::Period
  attr_reader :starts_at, :ends_at

  def initialize(starts_at:, ends_at:)
    @starts_at, @ends_at = starts_at, ends_at
  end

  def duration = ends_at - starts_at
  def range    = starts_at..ends_at

  def +(delta) = new_with(ends_at: ends_at + to_seconds(delta))
  def -(delta) = new_with(ends_at: ends_at - to_seconds(delta))
  def >>(delta)= new_with(starts_at: starts_at + to_seconds(delta), ends_at: ends_at + to_seconds(delta))
  def <<(delta)= new_with(starts_at: starts_at - to_seconds(delta), ends_at: ends_at - to_seconds(delta))
  def *(factor)= new_with(ends_at: starts_at + duration * factor)
  def /(factor)
    raise ZeroDivisionError if factor.to_f.zero?
    *(1.0 / factor)
  end

  private
  def to_seconds(v)
    case v
    when Numeric then v
    when ActiveSupport::Duration then v.to_i
    when Aeon::Period, Range then v.end - v.begin
    else raise ArgumentError, "Unsupported delta #{v.class}"
    end
  end

  def new_with(**opts)
    Aeon::Period.new(starts_at: opts[:starts_at] || starts_at,
                     ends_at:   opts[:ends_at]   || ends_at)
  end
end

4️⃣ Physical View

Attribute Description
Storage None (in-memory object)
Runtime Ruby object within app memory
Used by Aeon::PeriodQuery, Aeon::CacheWindow, Aeon::Mutator

Dependencies: ActiveSupport durations.


➕ 1 Scenario View

Scenario A: Shifting a Calendar View

march = Aeon::Period.new(starts_at: Date.new(2025,3,1), ends_at: Date.new(2025,3,31))
march >> 1.month  # => April window

Scenario B: Expanding Cache Range

window = period * 1.5 + 1.week
# Doubles duration, then grows by one week

Observability:
No persistence; debug output via inspect.
Argus logs when used indirectly through Timekeeper.