Module: Timeprice::Inflation
- Defined in:
- lib/timeprice/inflation.rb
Overview
CPI-based inflation adjustment for the Supported::COUNTRIES list.
Class Method Summary collapse
-
.adjust(amount:, from:, to:, country:) ⇒ InflationResult
Adjust ‘amount` from date `from` to date `to` using country CPI.
-
.lookup_index(data, key) ⇒ Object
Returns [index_value, granularity_symbol].
-
.merge_granularity(a, b) ⇒ Object
If either end fell back to annual_from_monthly_avg, propagate that label; else if either is annual, propagate :annual; else :monthly.
- .missing_cpi_message(key, data, monthly, annual) ⇒ Object
-
.rate(from:, to:, country:) ⇒ Float
Inflation rate as decimal (e.g. 0.42 = 42%).
Class Method Details
.adjust(amount:, from:, to:, country:) ⇒ InflationResult
Adjust ‘amount` from date `from` to date `to` using country CPI.
Dates accept “YYYY” or “YYYY-MM”.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/timeprice/inflation.rb', line 34 def adjust(amount:, from:, to:, country:) data = DataLoader.load_cpi(country) from_index, from_gran = lookup_index(data, from) to_index, to_gran = lookup_index(data, to) ratio = to_index.to_f / from_index InflationResult.new( amount: amount.to_f * ratio, original_amount: amount.to_f, from: from, to: to, country: country.to_s.upcase, from_index: from_index, to_index: to_index, granularity: merge_granularity(from_gran, to_gran) ) end |
.lookup_index(data, key) ⇒ Object
Returns [index_value, granularity_symbol]
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 92 93 |
# File 'lib/timeprice/inflation.rb', line 64 def lookup_index(data, key) key = key.to_s monthly = data["monthly"] || {} annual = data["annual"] || {} case key when /\A\d{4}-\d{2}\z/ if monthly.key?(key) [monthly[key], :monthly] else year = key[0, 4] raise DataNotFound, (key, data, monthly, annual) unless annual.key?(year) [annual[year], :annual] end when /\A\d{4}\z/ if annual.key?(key) [annual[key], :annual] else months = monthly.select { |k, _| k.start_with?("#{key}-") } raise DataNotFound, (key, data, monthly, annual) if months.empty? avg = months.values.sum.to_f / months.size [avg, :annual_from_monthly_avg] end else raise ArgumentError, "Invalid date format: #{key.inspect} (use YYYY or YYYY-MM)" end end |
.merge_granularity(a, b) ⇒ Object
If either end fell back to annual_from_monthly_avg, propagate that label; else if either is annual, propagate :annual; else :monthly.
112 113 114 115 116 117 |
# File 'lib/timeprice/inflation.rb', line 112 def merge_granularity(a, b) return :annual_from_monthly_avg if a == :annual_from_monthly_avg || b == :annual_from_monthly_avg return :annual if a == :annual || b == :annual :monthly end |
.missing_cpi_message(key, data, monthly, annual) ⇒ Object
95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/timeprice/inflation.rb', line 95 def (key, data, monthly, annual) country = data["country"] ranges = [] if monthly.any? ks = monthly.keys.sort ranges << "monthly #{ks.first}..#{ks.last}" end if annual.any? ks = annual.keys.sort ranges << "annual #{ks.first}..#{ks.last}" end hint = ranges.empty? ? "" : " (supported: #{ranges.join(", ")})" "No CPI data for #{key.inspect} in #{country}#{hint}" end |
.rate(from:, to:, country:) ⇒ Float
Inflation rate as decimal (e.g. 0.42 = 42%).
58 59 60 61 |
# File 'lib/timeprice/inflation.rb', line 58 def rate(from:, to:, country:) result = adjust(amount: 1.0, from: from, to: to, country: country) result.amount - 1.0 end |