Module: Ace::B36ts::Atoms::FormatSpecs

Defined in:
lib/ace/b36ts/atoms/format_specs.rb

Overview

Format specifications for granular timestamp encoding.

Defines 7 format types with varying precision and length:

  • 2sec (6 chars, ~1.85s precision) - default

  • month (2 chars, month precision)

  • week (3 chars, week precision)

  • day (3 chars, day precision)

  • 40min (4 chars, 40-minute block precision)

  • 50ms (7 chars, ~50ms precision)

  • ms (8 chars, ~1.4ms precision)

Day/week disambiguation (3-char formats):

  • Day format: 3rd character in 0-30 range

  • Week format: 3rd character in 31-35 range

Examples:

Access format specifications

FormatSpecs::FORMATS[:"2sec"]  # => FormatSpec for 6-char IDs
FormatSpecs::FORMATS[:month]   # => FormatSpec for 2-char IDs

Defined Under Namespace

Classes: FormatSpec

Constant Summary collapse

FORMATS =

All supported format specifications

{
  "2sec": FormatSpec.new(
    name: :"2sec",
    length: 6,
    precision_desc: "~1.85s",
    pattern: /\A[0-9a-z]{6}\z/i
  ),
  month: FormatSpec.new(
    name: :month,
    length: 2,
    precision_desc: "month",
    pattern: /\A[0-9a-z]{2}\z/i
  ),
  week: FormatSpec.new(
    name: :week,
    length: 3,
    precision_desc: "week",
    pattern: /\A[0-9a-z]{3}\z/i
  ),
  day: FormatSpec.new(
    name: :day,
    length: 3,
    precision_desc: "day",
    pattern: /\A[0-9a-z]{3}\z/i
  ),
  "40min": FormatSpec.new(
    name: :"40min",
    length: 4,
    precision_desc: "40min",
    pattern: /\A[0-9a-z]{4}\z/i
  ),
  "50ms": FormatSpec.new(
    name: :"50ms",
    length: 7,
    precision_desc: "~50ms",
    pattern: /\A[0-9a-z]{7}\z/i
  ),
  ms: FormatSpec.new(
    name: :ms,
    length: 8,
    precision_desc: "~1.4ms",
    pattern: /\A[0-9a-z]{8}\z/i
  )
}.freeze
DAY_FORMAT_MAX =

Day/week disambiguation for 3-char formats Day format: 3rd char (day value) is 0-30 Week format: 3rd char (week value) is 31-35

30
WEEK_FORMAT_MIN =
31
WEEK_FORMAT_MAX =
35
SPLIT_LEVELS =
%i[month week day block].freeze

Class Method Summary collapse

Class Method Details

.all_formatsArray<Symbol>

Get all format names

Returns:

  • (Array<Symbol>)

    List of supported format names



103
104
105
# File 'lib/ace/b36ts/atoms/format_specs.rb', line 103

def all_formats
  FORMATS.keys
end

.all_lengthsArray<Integer>

Get all supported lengths

Returns:

  • (Array<Integer>)

    List of supported ID lengths



110
111
112
# File 'lib/ace/b36ts/atoms/format_specs.rb', line 110

def all_lengths
  FORMATS.values.map(&:length).uniq.sort
end

.detect_from_id(encoded_id, alphabet: CompactIdEncoder::DEFAULT_ALPHABET) ⇒ Symbol?

Detect format from ID string For 3-char IDs, uses the 3rd character value to distinguish day vs week

Parameters:

  • encoded_id (String)

    The encoded ID string

  • alphabet (String) (defaults to: CompactIdEncoder::DEFAULT_ALPHABET)

    Base36 alphabet

Returns:

  • (Symbol, nil)

    Detected format name or nil if invalid



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/ace/b36ts/atoms/format_specs.rb', line 138

def detect_from_id(encoded_id, alphabet: CompactIdEncoder::DEFAULT_ALPHABET)
  return nil if encoded_id.nil? || encoded_id.empty?

  # Validate all characters are in the alphabet
  # Use Set for faster character validation (O(1) vs O(n))
  alphabet_set = (alphabet == CompactIdEncoder::DEFAULT_ALPHABET) ? CompactIdEncoder::DEFAULT_ALPHABET_SET : alphabet.chars.to_set
  return nil unless encoded_id.downcase.chars.all? { |c| alphabet_set.include?(c) }

  length = encoded_id.length

  case length
  when 2
    :month
  when 3
    # Disambiguate day vs week by 3rd character value
    third_char_value = alphabet.index(encoded_id[2].downcase)
    return nil if third_char_value.nil?

    if third_char_value <= DAY_FORMAT_MAX
      :day
    elsif third_char_value <= WEEK_FORMAT_MAX
      :week
    end
    # Note: With base36 (values 0-35), day covers 0-30 and week covers 31-35,
    # so all valid values are handled. This branch implicitly returns nil
    # only if alphabet validation fails (which is caught earlier).
  when 4
    :"40min"
  when 6
    :"2sec"
  when 7
    :"50ms"
  when 8
    :ms
  end
end

.get(name) ⇒ FormatSpec?

Get format specification by name

Parameters:

  • name (Symbol)

    Format name (:“2sec”, :month, :week, :day, :“40min”, :“50ms”, :ms)

Returns:

  • (FormatSpec, nil)

    Format specification or nil if not found



88
89
90
# File 'lib/ace/b36ts/atoms/format_specs.rb', line 88

def get(name)
  FORMATS[name]
end

.valid_format?(name) ⇒ Boolean

Check if format name is valid

Parameters:

  • name (Symbol)

    Format name to check

Returns:

  • (Boolean)

    True if format is supported



96
97
98
# File 'lib/ace/b36ts/atoms/format_specs.rb', line 96

def valid_format?(name)
  FORMATS.key?(name)
end

.valid_split_levels?(levels) ⇒ Boolean

Validate split level ordering and hierarchy

Parameters:

  • levels (Array<Symbol>)

    Split levels to validate

Returns:

  • (Boolean)

    True if split levels are valid



118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/ace/b36ts/atoms/format_specs.rb', line 118

def valid_split_levels?(levels)
  return false unless levels.is_a?(Array)
  return false if levels.empty?
  return false unless levels.all? { |level| SPLIT_LEVELS.include?(level) }
  return false unless levels.uniq.length == levels.length
  return false unless levels.first == :month

  indices = levels.map { |level| SPLIT_LEVELS.index(level) }
  return false unless indices == indices.sort
  return false if levels.include?(:block) && !levels.include?(:day)

  true
end