Module: PROIEL::Chronology

Defined in:
lib/proiel/chronology.rb

Overview

Methods for parsing chronological descriptions. Extra care is taken to get the interpretation of centuries and ranges involving the transition between 1 BC and AD 1 correct.

Class Method Summary collapse

Class Method Details

.midpoint(s) ⇒ Integer

Computes the chronological midpoint of a chronological description.

Examples:

midpoint('1000')         # => 1000
midpoint('1000 BC')      # => -1000
midpoint('1000-1020')    # => 1010

Parameters:

  • s (String)

    chronological description

Returns:

  • (Integer)

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/proiel/chronology.rb', line 21

def self.midpoint(s)
  i = parse(s)

  if i.is_a?(Array)
    # Handle missing Julian year 0 by shifting years after 1 BC down by 1 and then shifting the midpoint back
    # up again unless negative
    if i.first < 0 and i.last > 0
      y = (i.first + i.last - 1) / 2.0
      if y < 0
        y.floor
      else
        (y + 1).floor
      end
    else
      ((i.first + i.last) / 2.0).floor # a non-integer midpoint is within the year of the integer part
    end
  elsif i.is_a?(Integer)
    i
  else
    raise ArgumentError, 'integer or array expected'
  end
end

.parse(s) ⇒ Integer, Array<Integer,Integer>

Parses a chronological description. The syntax of chronological descriptions is explained in the [PROIEL XML documentation](proiel.github.io/handbook/developer/proielxml.html#chronological-data).

Examples:

parse('1000')         # => 1000
parse('1000 BC')      # => -1000
parse('1000-1020')    # => [1000,1020]
parse('1000 BC-1020') # => [-1000,1020]

Parameters:

  • s (String)

    chronological description

Returns:

  • (Integer, Array<Integer,Integer>)

57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/proiel/chronology.rb', line 57

def self.parse(s)
  case s
  when /^\s*(?:c\.\s+)?(\d+)(\s+BC)?\s*$/
    i = $1.to_i
    multiplier = $2 ? -1 : 1
    (i * multiplier).to_i.tap do |i|
      # There is no year zero in the Julian calendar
      raise ArgumentError, 'invalid year' if i.zero?
    end
  when /^\s*(1st|2nd|3rd|\d+th)\s+c\.\s*$/
    a = $1.to_i * 100
    [a - 99, a]
  when /^\s*(1st|2nd|3rd|\d+th)\s+c\.\s+BC\s*$/
    a = -$1.to_i * 100
    [a, a + 99]
  when /^\s*(?:c\.\s+)?\d+(\s+BC)?\s*-\s*(c\.\s+)?\d+(\s+BC)?\s*$/
    s.split('-').map { |i| parse(i) }.tap do |from, to|
      raise ArgumentError, 'invalid range' unless from < to
    end
  else
    raise ArgumentError, 'unexpected format'
  end
end