Instantly share code, notes, and snippets.

Embed
What would you like to do?
Pushing the limits on generating functions at compile time
defmodule Cldr.Number.Generate.ShortFormats do
@moduledoc """
Generates a set of functions to process the various
:short and :long formats for numbers.
"""
alias Cldr.Number.{System, Format}
defmacro __using__(_options \\ []) do
def_to_string() ++ def_do_to_string()
end
@docp """
Generates one function for each type of short format (currently there
are three defined: :decimal_short, :decimal_long, :currency_short).
The function signature matches that of the other `to_string/3` functions
defined in Cldr.Number. However these functions retain a format as an
atom which means these short forms will dispatch to the functions defined
below. This lets us preserve the internal api which is
`to_string(number, format, options)` but branch to the specific functions
that then decompose each of the different short formats.
"""
defp def_to_string do
for style <- Format.short_format_styles() do
quote do
defp to_string(number, unquote(style), options) do
locale = options[:locale]
number_system = options[:number_system]
|> System.system_name_from(locale)
number
|> do_to_short_string(unquote(style), locale, number_system, options)
end
end
end
end
@docp """
Generates one function for the cartesian product of locale, number_system,
style and format. Thats about 2 * 3 * 10 functions per locale. There are
511 locales in total used in testing which so far means compilation takes about 4 hours.
In development (7 locales) and most production environments (< 30
locales) this would not appear to be an issue.
"""
def def_do_to_string do
for locale <- Cldr.known_locales(), # 511 in test environment
number_system <- System.number_system_names_for(locale), # Typically 2
style <- Format.short_format_styles_for(locale, number_system), # Currently 3 of them
format <- Format.formats_for(locale, number_system) |> Map.get(style) # about 10
do
quote do
@spec do_to_short_string(number, atom, Locale.t, binary, Keyword.t) :: List.t
range = String.to_integer(elem(format, 0))
def do_to_short_string(number, unquote(style), unquote(locale), unquote(number_system), options)
when number < unquote(range) do
# Select the format based upon the number
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment