Module: Timeprice::Metadata Private
- Defined in:
- lib/timeprice/metadata.rb
Overview
This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.
Describes the bundled dataset so external surfaces (the website, other tools) can render dropdowns, date pickers, and version pills without hardcoding country lists, currency lists, or date ranges.
See metadata for the public entry point.
Direct references will move to ‘Timeprice::Internal::Metadata` in a future release.
Constant Summary collapse
- COUNTRY_NAMES =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
ISO 3166-style display names for the countries shipped today.
{ "AU" => "Australia", "CA" => "Canada", "CN" => "China", "EU" => "Eurozone", "JP" => "Japan", "KR" => "South Korea", "RU" => "Russia", "UK" => "United Kingdom", "US" => "United States", "VN" => "Vietnam", }.freeze
- CURRENCY_NAMES =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
ISO 4217 display names for the currencies shipped today.
{ "AUD" => "Australian dollar", "CAD" => "Canadian dollar", "CNY" => "Chinese yuan", "EUR" => "Euro", "GBP" => "British pound", "JPY" => "Japanese yen", "KRW" => "South Korean won", "RUB" => "Russian ruble", "USD" => "US dollar", "VND" => "Vietnamese dong", }.freeze
Class Method Summary collapse
-
.build ⇒ MetadataSnapshot
private
Build the metadata snapshot.
-
.country_entry(country) ⇒ Object
private
Range info comes from the manifest (‘cpi_ranges`), pre-computed at manifest generation time.
- .deep_freeze(value) ⇒ Object private
- .derive_cpi_ranges(code) ⇒ Object private
-
.fx_entry(manifest) ⇒ Object
private
Bounds come from the manifest (‘fx.daily_min`/`fx.daily_max`).
Class Method Details
.build ⇒ MetadataSnapshot
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Build the metadata snapshot.
51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/timeprice/metadata.rb', line 51 def build manifest = DataLoader.load_manifest countries = (manifest["countries"] || []).map { |c| country_entry(c) } currencies = Supported.currencies.map { |code| { code: code, name: CURRENCY_NAMES[code] || code } } MetadataSnapshot.new( version: VERSION, generated_at: manifest["generated_at"], countries: deep_freeze(countries), currencies: deep_freeze(currencies), fx: deep_freeze(fx_entry(manifest)) ) end |
.country_entry(country) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Range info comes from the manifest (‘cpi_ranges`), pre-computed at manifest generation time. Falls back to walking the CPI file for any country missing the field — older manifests, or local data roots produced by hand.
68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/timeprice/metadata.rb', line 68 def country_entry(country) code = country["code"] ranges = country["cpi_ranges"] || derive_cpi_ranges(code) per_granularity = ranges.each_with_object({}) do |(gran, range), acc| acc[gran.to_sym] = { min: range["min"], max: range["max"] } end { code: code, name: COUNTRY_NAMES[code] || code, currency: country["currency"], granularities: country["granularities"] || per_granularity.keys.map(&:to_s), cpi: per_granularity, } end |
.deep_freeze(value) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
113 114 115 116 117 118 119 |
# File 'lib/timeprice/metadata.rb', line 113 def deep_freeze(value) case value when Hash then value.each_value { |v| deep_freeze(v) }.freeze when Array then value.each { |v| deep_freeze(v) }.freeze else value.frozen? ? value : value.freeze end end |
.derive_cpi_ranges(code) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
83 84 85 86 87 88 89 90 91 92 |
# File 'lib/timeprice/metadata.rb', line 83 def derive_cpi_ranges(code) cpi = DataLoader.load_cpi(code) series = cpi["series"] || {} series.each_with_object({}) do |(granularity, points), acc| next unless points.is_a?(Hash) && !points.empty? keys = points.keys.sort acc[granularity] = { "min" => keys.first, "max" => keys.last } end end |
.fx_entry(manifest) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Bounds come from the manifest (‘fx.daily_min`/`fx.daily_max`). Older manifests without those keys: peek at the earliest/latest year files.
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/timeprice/metadata.rb', line 96 def fx_entry(manifest) fx = manifest["fx"] || {} base = fx["base"] years = fx["daily_years"] || [] return { base: base, daily_min: nil, daily_max: nil } if years.empty? daily_min = fx["daily_min"] daily_max = fx["daily_max"] if daily_min.nil? || daily_max.nil? first = DataLoader.load_fx_year(years.min) last = DataLoader.load_fx_year(years.max) daily_min ||= (first["rates"] || {}).keys.min daily_max ||= (last["rates"] || {}).keys.max end { base: base, daily_min: daily_min, daily_max: daily_max } end |