Class: Timeprice::Point

Inherits:
Data
  • Object
show all
Defined in:
lib/timeprice/point.rb

Overview

A (currency, date) pair used as input to compare.

The library accepts either a Point or a 2-element array. Arrays may be ordered either way (‘[“USD”, “2010”]` or `[“2010”, “USD”]`) — the year and currency are detected by shape. This mirrors what the CLI already tolerates and removes the only “which slot is which?” footgun.

Examples:

Timeprice::Point.new(currency: "USD", date: "2010")
Timeprice::Point.coerce(["USD", "2010"])
Timeprice::Point.coerce(["2010", "USD"])

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#currencyObject (readonly)

Returns the value of attribute currency

Returns:

  • (Object)

    the current value of currency



15
16
17
# File 'lib/timeprice/point.rb', line 15

def currency
  @currency
end

#dateObject (readonly)

Returns the value of attribute date

Returns:

  • (Object)

    the current value of date



15
16
17
# File 'lib/timeprice/point.rb', line 15

def date
  @date
end

Class Method Details

.coerce(input) ⇒ Point

Coerce input into a Point. Accepts:

- {Point} (returned as-is)
- 2-element Array of [currency, date] in either order

Parameters:

Returns:

Raises:

  • (ArgumentError)

    if shape can’t be recognised



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/timeprice/point.rb', line 23

def self.coerce(input)
  case input
  in Point
    input
  in [_, _]
    a, b = input.map(&:to_s)
    currency = [a, b].find { |s| s.match?(/\A[A-Za-z]{3}\z/) }
    date     = [a, b].find { |s| s.match?(/\A\d{4}(-\d{2}(-\d{2})?)?\z/) }
    raise ArgumentError, malformed_pair_message(input) if currency.nil? || date.nil?

    new(currency: currency.upcase, date: date)
  else
    raise ArgumentError, "Expected Timeprice::Point or [currency, date] tuple, got #{input.inspect}"
  end
end

.malformed_pair_message(input) ⇒ Object



39
40
41
42
# File 'lib/timeprice/point.rb', line 39

def self.malformed_pair_message(input)
  "Could not detect currency + date in #{input.inspect} " \
    "(expected a 3-letter currency and a YYYY[-MM[-DD]] date)"
end

Instance Method Details

#fx_anchor_dateString

Resolve ‘date` to a full YYYY-MM-DD for FX lookup.

Coarser grains anchor to a representative day:

- "YYYY"    → mid-year (YYYY-06-30)
- "YYYY-MM" → mid-month (YYYY-MM-15)
- "YYYY-MM-DD" → passes through

Returns:

  • (String)

Raises:

  • (ArgumentError)

    if ‘date` doesn’t match any supported shape



53
54
55
56
57
58
59
60
# File 'lib/timeprice/point.rb', line 53

def fx_anchor_date
  case date.to_s
  when /\A\d{4}\z/         then "#{date}-06-30"
  when /\A\d{4}-\d{2}\z/   then "#{date}-15"
  when /\A\d{4}-\d{2}-\d{2}\z/ then date.to_s
  else raise ArgumentError, "Invalid date for Point: #{date.inspect}"
  end
end