Module: Timeprice::Sources::Coverage

Defined in:
lib/timeprice/sources/coverage.rb

Overview

Computes coverage strings for bundled data sources at runtime by reading the structured ‘provenance` blocks in v3 data files. The Sources attribution registry stays a pure data table; Coverage is the only place that touches the filesystem.

Class Method Summary collapse

Class Method Details

.cpi(country) ⇒ Object



27
28
29
30
31
32
33
34
35
# File 'lib/timeprice/sources/coverage.rb', line 27

def cpi(country)
  data = DataLoader.load_cpi(country)
  monthly = data.dig("series", "monthly") || {}
  annual  = data.dig("series", "annual") || {}
  parts = []
  parts << "monthly #{monthly.keys.min}..#{monthly.keys.max} (#{monthly.size})" if monthly.any?
  parts << "annual #{annual.keys.min}..#{annual.keys.max} (#{annual.size})" if annual.any?
  parts.join(", ")
end

.ecb_summaryObject

Frankfurter (ECB) → daily EUR/GBP/JPY in per-year files. Range derived from the manifest’s ‘daily_years` list.



47
48
49
50
51
52
# File 'lib/timeprice/sources/coverage.rb', line 47

def ecb_summary
  years = DataLoader.load_manifest.dig("fx", "daily_years") || []
  return "no ECB data" if years.empty?

  "USD↔EUR/GBP/JPY daily #{years.first}..#{years.last}"
end

.for(src) ⇒ String

Parameters:

  • src (Hash)

    one entry from Sources::ATTRIBUTIONS

Returns:

  • (String)


17
18
19
20
21
22
23
24
25
# File 'lib/timeprice/sources/coverage.rb', line 17

def for(src)
  case src[:kind]
  when "cpi" then cpi(src[:country])
  when "fx"  then fx(src[:id])
  else "n/a"
  end
rescue StandardError => e
  "(coverage unavailable: #{e.message})"
end

.fx(id) ⇒ Object



37
38
39
40
41
42
43
# File 'lib/timeprice/sources/coverage.rb', line 37

def fx(id)
  case id
  when "fx_ecb" then ecb_summary
  when "fx_vnd" then vnd_summary
  else "n/a"
  end
end

.vnd_summaryObject

All annual FX (today only VND) lives in data/fx/usd/_annual.json.



55
56
57
58
59
60
61
62
63
# File 'lib/timeprice/sources/coverage.rb', line 55

def vnd_summary
  fallback = DataLoader.load_fx_annual_fallback
  years = (fallback&.dig("annual") || {})
          .select { |_y, ccy_hash| ccy_hash.key?("VND") }
          .keys.map(&:to_i).sort
  return "no VND data" if years.empty?

  "USD↔VND #{years.first}..#{years.last}"
end