Shopify / measured

Encapsulate measurements and their units in Ruby and Ruby on Rails.
MIT License
337 stars 28 forks source link

Dynamic conversions #151

Open AlexB52 opened 1 year ago

AlexB52 commented 1 year ago

This PR attempts to solve #59 by allowing dynamic unit system definitions.

Current unit system definitions assume units are all proportional to each other y = a * x. This change allows any conversion but removes the ability to cache dynamic unit systems, which might be good enough for small ones.

You can create dynamic systems by passing a conversion and a reverse_conversion proc and an optional conversion description. Please take a look at the Temperature example below. The PR also has temperature acceptance tests as proof of concept.

Notes:

Measured::Temperature = Measured.build do
  unit :C, aliases: [:c, :celsius]

  unit :K, value: [
    {
      conversion: ->(k) { k - BigDecimal('273.15') },
      reverse_conversion: ->(c) { c + BigDecimal('273.15') },
      description: 'celsius + 273.15'
    }, 'C'], aliases: [:k, :kelvin]

  unit :F, value: [
    {
      conversion: ->(f) { (f-32) * Rational(5,9) },
      reverse_conversion: ->(c) { c * Rational(9,5) + 32 },
      description: '9 * celsius / 5 + 32'
    }, 'C'], aliases: [:f, :farenheit]
end