elixirmoney / money

Elixir library for working with Money safer, easier, and fun... Is an interpretation of the Fowler's Money pattern in fun.prog.
https://hex.pm/packages/money/
MIT License
826 stars 139 forks source link

Better error messages regarding currency mismatch #199

Closed esse closed 1 year ago

esse commented 1 year ago

Hey there,

when working with Money we spotted two cases that gaves us a real headache.

  1. When we load stuff from DB we sometimes forgot to cast it from maps to Money struct. Current version of Money would simply raise argument error, saying:
iex(6)> Money.add(%{amount: 100, currency: "GBP"},  %{amount: 100, currency: "GBP"})
** (ArgumentError) Currency of GBP must be the same as GBP
    (money 1.12.1) lib/money.ex:747: Money.fail_currencies_must_be_equal/2

which makes us scratching our heads. This PR ensures that this function will be called only if the function is called with two Money structs - so when it makes sense. Changing the error message to:

iex(1)> Money.add(%{amount: 100, currency: "GBP"},  %{amount: 100, currency: "GBP"})
** (FunctionClauseError) no function clause matching in Money.add/2

    The following arguments were given to Money.add/2:

        # 1
        %{amount: 100, currency: "GBP"}

        # 2
        %{amount: 100, currency: "GBP"}

    Attempted function clauses (showing 4 out of 4):

        def add(%Money{amount: a, currency: cur}, %Money{amount: b, currency: cur})
        def add(%Money{amount: amount, currency: cur}, addend) when is_integer(addend)
        def add(%Money{} = m, addend) when is_float(addend)
        def add(%Money{} = a, %Money{} = b)

    (money 1.12.1) lib/money.ex:429: Money.add/2
  1. Sometimes we also forgot ot cast currency to atom and when you try to add two money structs, one with string currency and one with atom one you also are going to get cryptic message:

This PR changes that message to:

iex(1)> Money.add( %Money{amount: 100, currency: "GBP"},  %Money{amount: 100, currency: :GBP})
** (ArgumentError) Currency of "GBP" must be the same as :GBP
    (money 1.12.1) lib/money.ex:747: Money.fail_currencies_must_be_equal/2

so it should be more obvious what is going on.

Nitrino commented 1 year ago

Hi @esse Good catch. This error message also blew my mind 😄 Thanks for your contribution ❤️