Module: Timeprice::Compare Private
- Defined in:
- lib/timeprice/compare.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.
Compare combines FX and inflation across two (currency, date) points.
CONVENTION (critical): convert at SOURCE date first, then inflate in destination currency. See README.md “Compare semantics” section.
This preserves purchasing-power equivalence in the destination economy. The naive alternative (inflate in source currency first, then convert at destination date) double-counts source-country inflation because nominal FX rates already absorb relative inflation between the two currencies.
If a future refactor flips the order, the regression test in spec/timeprice/compare_spec.rb will fail.
The supported public entry point is compare. Direct references will move to ‘Timeprice::Internal::Compare` in a future release.
Class Method Summary collapse
-
.fx_only_result(amount:, from_point:, to_point:, to_country:, fx_result:) ⇒ Object
private
Same-date branch: no time-elapsed inflation, so the FX leg alone is the answer.
-
.resolve_points(from, to) ⇒ Object
private
Coerce both points and resolve to_country.
-
.run(amount:, from:, to:) ⇒ CompareResult
private
Compare an amount across two (currency, date) points.
Class Method Details
.fx_only_result(amount:, from_point:, to_point:, to_country:, fx_result:) ⇒ 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.
Same-date branch: no time-elapsed inflation, so the FX leg alone is the answer. Builds a CompareResult with cpi_ratio=1.0.
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/timeprice/compare.rb', line 95 def fx_only_result(amount:, from_point:, to_point:, to_country:, fx_result:) CompareResult.new( amount: fx_result.amount, original_amount: amount.to_f, from_currency: from_point.currency, from_date: from_point.date.to_s, to_currency: to_point.currency, to_date: to_point.date.to_s, country: to_country, fx_rate: fx_result.rate, cpi_ratio: 1.0, converted_amount: fx_result.amount, granularity: fx_result.granularity ) end |
.resolve_points(from, to) ⇒ 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.
Coerce both points and resolve to_country.
112 113 114 115 116 117 118 119 120 121 |
# File 'lib/timeprice/compare.rb', line 112 def resolve_points(from, to) from_point = Point.coerce(from) to_point = Point.coerce(to) fail UnsupportedCurrency, from_point.currency unless Supported.country_for_currency(from_point.currency) to_country = Supported.country_for_currency(to_point.currency) fail UnsupportedCurrency, to_point.currency unless to_country [from_point, to_point, to_country] end |
.run(amount:, from:, to:) ⇒ CompareResult
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.
Compare an amount across two (currency, date) points.
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/timeprice/compare.rb', line 47 def run(amount:, from:, to:) from_point, to_point, to_country = resolve_points(from, to) # Step 1: convert at source date into destination currency. fx_result = Exchange.convert( amount: amount, from: from_point.currency, to: to_point.currency, date: from_point.fx_anchor_date ) converted = fx_result.amount # Step 2: inflate that destination-currency amount from source date to # destination date using destination-country CPI. When both points # share a date there's no time-elapsed inflation to apply — short- # circuit with a ratio of 1.0 so daily-grain FX dates (which CPI's # monthly-max resolution can't accept) still resolve cleanly. if from_point.date == to_point.date return fx_only_result( amount: amount, from_point: from_point, to_point: to_point, to_country: to_country, fx_result: fx_result ) end infl = Inflation.adjust( amount: converted, from: from_point.date.to_s, to: to_point.date.to_s, country: to_country ) CompareResult.new( amount: infl.amount, original_amount: amount.to_f, from_currency: from_point.currency, from_date: from_point.date.to_s, to_currency: to_point.currency, to_date: to_point.date.to_s, country: to_country, fx_rate: fx_result.rate, cpi_ratio: infl.to_index.to_f / infl.from_index, converted_amount: converted, granularity: Granularity.merge(fx_result.granularity, infl.granularity) ) end |