Packages

Money functions for operations on and localization of a money data type with support for ISO 4217 currencies and ISO 24165 digial tokens (crypto currencies).

Current section

Files

Jump to
ex_money lib money parser.ex
Raw

lib/money/parser.ex

defmodule Money.Parser do
@moduledoc false
import NimbleParsec
@whitespace [?\s, ?\t]
def whitespace do
repeat(utf8_char(@whitespace))
|> label("whitespace")
end
@separators [?., ?,, , , ?、, ?︐, ?︑, ?﹐, ?﹑, ?,, ?、, ? ]
def separators do
utf8_char(@separators)
|> label("separators")
end
@decimal_places [?., ?․, ?。, ?︒, ?﹒, ?., ?。]
def decimal_place do
utf8_char(@decimal_places)
|> label("decimal place character")
end
@left_parens [?(]
def left_paren do
utf8_char(@left_parens)
|> label("left parenthesis")
end
@right_parens [?)]
def right_paren do
utf8_char(@right_parens)
|> label("right parenthesis")
end
@digits [?0..?9]
def digits do
repeat(ascii_char([?0..?9]))
|> label("digits")
end
@minus [?-]
def minus do
ascii_char(@minus)
end
def positive_number do
digits()
|> repeat(separators() |> concat(digits()))
|> optional(decimal_place() |> concat(digits()))
|> label("positive number")
end
def negative_number do
choice([
ignore(minus())
|> concat(positive_number()),
positive_number()
|> ignore(minus())
])
|> reduce({List, :to_string, []})
|> map(:add_minus_sign)
|> label("negative number")
end
def add_minus_sign(arg) do
"-" <> arg
end
def number do
choice([negative_number(), positive_number()])
|> reduce({List, :to_string, []})
|> unwrap_and_tag(:amount)
|> label("number")
end
@invalid_chars @separators ++
@decimal_places ++
@digits ++
@minus ++
@left_parens ++
@right_parens
@currency Enum.map(@invalid_chars, fn s -> {:not, s} end)
def currency do
utf8_char(@currency)
|> times(min: 1)
|> reduce({List, :to_string, []})
|> unwrap_and_tag(:currency)
|> label("currency code, symbol or name")
end
def money_with_currency do
choice([
number()
|> ignore(optional(whitespace()))
|> optional(currency())
|> eos(),
optional(currency())
|> ignore(optional(whitespace()))
|> concat(number())
|> eos()
])
end
def accounting_format do
choice([
ignore(left_paren())
|> ignore(optional(whitespace()))
|> concat(number())
|> ignore(optional(whitespace()))
|> optional(currency())
|> ignore(optional(whitespace()))
|> ignore(right_paren()),
ignore(left_paren())
|> ignore(optional(whitespace()))
|> optional(currency())
|> ignore(optional(whitespace()))
|> concat(number())
|> ignore(optional(whitespace()))
|> ignore(right_paren())
])
|> map(:change_sign)
end
def change_sign({:amount, amount}) do
revised_number =
case amount do
<<"-", number::binary>> -> number
number -> "-" <> number
end
{:amount, revised_number}
end
def change_sign(other), do: other
end