Ex_money - money with currency type

ex_money is a package to manage a money data type and provide localised formatting, arithmetic, exchange rates, basic financial calculations and serialization with a special attention on preserving precision.

CLDR data drives the localisation capabilities. As a result ex_money knows about each currencies precision, separators, grouping and symbols in any of about 500 locales.

Version 3.2.4 is out this week with a new ability to parse money strings. Some examples follow:

  # These are the strings available for a given currency
  # and locale that are recognised during parsing
  iex> Cldr.Currency.strings_for_currency :AUD, "de"
  ["aud", "au$", "australischer dollar", "australische dollar"]

  # Parsing can be localised
  iex> Money.parse "12 346 dollar australien", locale: "fr"
  #Money<:AUD, 12346>

  iex> Money.parse "A$ 12346", locale: "en"
  #Money<:AUD, 12346>

  # Note that the decimal separator in the "de" locale
  # is a `.`
  iex> Money.parse "AU$ 12346,45", locale: "de"
  #Money<:AUD, 12346.45>

  # Round trip formatting is supported
  iex> {:ok, string} = Cldr.Number.to_string 1234, Money.Cldr, currency: :AUD
  {:ok, "A$1,234.00"}
  iex> Money.parse string
  #Money<:AUD, 1234.00>

  # Fuzzy matching is possible
  iex> Money.parse("100 eurosports", fuzzy: 0.8)
  #Money<:EUR, 100>

  iex> Money.parse("100 eurosports", fuzzy: 0.9)
  {:error,
   {Money.Invalid, "Unable to create money from \"eurosports\" and \"100\""}}

  # Eligible currencies can be filtered by type
  iex> Money.parse("100 eurosports", fuzzy: 0.8, currency_filter: [:current, :tender])
  #Money<:EUR, 100>
17 Likes

Love it! Used this just the other week to greatly simplify a project i was working on

1 Like

Using already in a project, documentation is clean.

1 Like

I think money_sql is a great example of an Ecto custom type working in concert with a DB-side user defined type (in this case a composite type).

https://github.com/kipcole9/money_sql/blob/master/lib/money/ecto/money_ecto_composite_type.ex

4 Likes

ex_money 5.0.0 is released today. The main focus is supporting the new Elixir 1.10 Enum.sort/2 functionality that greatly helps express semantic sorting for structs like money, dates and so on.

Enum.sort/2 example

iex> list = [Money.new(:USD, 100), Money.new(:USD, 200)]
[#Money<:USD, 100>, #Money<:USD, 200>]
iex> Enum.sort list, Money
[#Money<:USD, 100>, #Money<:USD, 200>]
iex> Enum.sort list, {:asc, Money}
[#Money<:USD, 100>, #Money<:USD, 200>]
iex> Enum.sort list, {:desc, Money}
[#Money<:USD, 200>, #Money<:USD, 100>]

Breaking Changes

In order to support the new Enum.sort/2, the Money.compare/2 function needs to return :lt, :gt or :eq. Previous releases of Money.compare/2 return 1, 0 or -1 following the model set by Decimal.

In ex_money version 5.0.0, the returns from Money.compare/2 and Money.cmp/2 are swapped to now align with what Elixir expects.

Users of ex_money will need to replace calls to Money.cmp/2 with calls to Money.compare/2. Similarly, calls to Money.compare/2 should be replaced with calls to Money.cmp/2.

Relationship to the Decimal library

decimal is going through the same transition with its releases 1.9 and 2.0. The changes to ex_money have been tested on all releases of decimal from 1.6 up to 1.9.0-rc.0 and on decimal master branch which is 2.0.0-dev. The plan is that no new releases of ex_money should be required to support any modern decimal release.

Links

6 Likes