Packages
ex_cldr
1.4.2
2.47.5
2.47.4
2.47.3
2.47.2
2.47.1
2.47.0
2.46.0
2.45.2
2.45.1
2.45.0
2.44.1
2.44.0
2.43.2
2.43.1
2.43.0
2.42.0
2.41.1
2.41.0
2.40.4
2.40.3
2.40.2
2.40.1
2.40.0
2.39.2
2.39.1
2.39.0
2.38.1
2.38.0
2.37.5
2.37.4
2.37.3
retired
2.37.2
2.37.1
2.37.0
2.36.0
2.35.1
2.35.0
retired
2.34.2
2.34.1
2.34.0
2.33.2
2.33.1
2.33.1-rc.0
2.33.0
2.32.1
2.32.0
2.31.0
2.30.0
2.29.0
2.28.0
2.27.1
2.27.0
retired
2.26.3
2.26.2
2.26.1
2.26.0
2.25.0
2.24.2
2.24.1
2.24.0
2.24.0-rc.6
2.24.0-rc.5
2.24.0-rc.4
2.24.0-rc.3
2.24.0-rc.2
2.24.0-rc.1
2.24.0-rc.0
2.23.2
2.23.1
2.23.0
2.22.1
2.22.0
2.21.0
2.20.0
2.20.0-rc.3
2.20.0-rc.2
2.20.0-rc.1
2.20.0-rc.0
2.19.1
2.19.0
2.18.2
2.18.1
2.18.0
2.18.0-rc.0
2.17.2
2.17.1
2.17.0
2.16.2
2.16.1
2.16.1-rc.0
2.16.0
2.15.0
2.14.1
2.14.0
2.14.0-rc.0
2.13.0
2.12.1
2.12.0
2.11.1
2.11.0
2.10.2
2.10.1
2.10.0
retired
2.9.0
2.8.1
2.8.0
2.7.2
2.7.1
2.7.0
2.6.2
2.6.1
2.6.0
2.5.0
2.4.3
2.4.2
2.4.1
2.4.0
2.3.2
2.3.1
2.3.0
2.2.7
2.2.6
2.2.5
2.2.4
2.2.3
2.2.2
2.2.1
2.2.0
2.1.0
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
2.0.0-rc.3
retired
2.0.0-rc.2
retired
2.0.0-rc.1
retired
2.0.0-rc.0
retired
1.8.2
1.8.1
1.8.0
1.7.1
1.7.0
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.2
1.5.1
1.5.0
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
retired
1.4.0-rc.3
retired
1.4.0-rc.2
retired
1.4.0-rc.1
retired
1.4.0-rc.0
retired
1.3.2
1.3.1
1.3.0
1.2.0
1.1.0
1.0.0
1.0.0-rc.3
retired
1.0.0-rc.2
retired
1.0.0-rc.1
retired
1.0.0-rc.0
retired
0.13.1
0.13.0
0.12.2
retired
0.12.1
retired
0.12.0
retired
0.11.0
retired
0.10.0
retired
0.9.0
retired
0.8.3
retired
0.8.2
retired
0.8.1
retired
0.8.0
retired
0.7.0
retired
0.6.2
retired
0.6.1
retired
0.6.0
retired
0.5.2
retired
0.5.1
retired
0.5.0
retired
0.4.2
retired
0.4.1
retired
0.4.0
retired
0.3.0
retired
0.2.1
retired
0.2.0
retired
0.1.3
retired
0.1.2
retired
0.1.1
retired
0.1.0
retired
0.0.20
retired
0.0.19
retired
0.0.18
retired
0.0.17
retired
0.0.16
retired
0.0.15
retired
0.0.14
retired
0.0.13
retired
0.0.12
retired
0.0.11
retired
0.0.10
retired
0.0.8
retired
0.0.7
retired
0.0.6
retired
0.0.5
retired
0.0.4
retired
0.0.3
retired
Common Locale Data Repository (CLDR) functions for Elixir to localize and format numbers, dates, lists, messages, languages, territories and units with support for over 700 locales for internationalized (i18n) and localized (L10N) applications.
Current section
Files
Jump to
Current section
Files
lib/cldr/helpers/map.ex
defmodule Cldr.Map do
@moduledoc """
Functions for transforming maps, keys and values.
"""
@doc """
Recursively traverse a map and invoke a function for each key/
value pair that transforms the map.
* `map` is any `Map.t`
* `function` is a function or function reference that
is called for each key/value pair of the provided map
Returns:
* The `map` transformed by the recursive application of `function`
## Examples
"""
@spec deep_map(Map.t(), function :: function()) :: Map.t()
def deep_map(map, function) when is_map(map) do
Enum.map(map, fn
{k, v} when is_map(v) or is_list(v) ->
{k, deep_map(v, function)}
{k, v} ->
function.({k, v})
end)
|> Enum.into(%{})
end
def deep_map([head | rest], fun) do
[deep_map(head, fun) | deep_map(rest, fun)]
end
def deep_map(nil, _fun) do
nil
end
def deep_map(value, fun) do
fun.(value)
end
@doc """
Recursively traverse a map and invoke a function for each key
and a function for each value that transform the map.
* `map` is any `Map.t`
* `key_function` is a function or function reference that
is called for each key of the provided map and any keys
of any submaps
* `value_function` is a function or function reference that
is called for each value of the provided map and any values
of any submaps
Returns:
* The `map` transformed by the recursive application of `key_function`
and `value_function`
## Examples
"""
@spec deep_map(Map.t(), key_function :: function(), value_function :: function()) :: Map.t()
def deep_map(map, key_function, value_function)
def deep_map(map, key_function, value_function) when is_map(map) do
Enum.map(map, fn
{k, v} when is_map(v) or is_list(v) ->
{key_function.(k), deep_map(v, key_function, value_function)}
{k, v} ->
{key_function.(k), value_function.(v)}
end)
|> Enum.into(%{})
end
def deep_map([head | rest], key_fun, value_fun) do
[deep_map(head, key_fun, value_fun) | deep_map(rest, key_fun, value_fun)]
end
def deep_map(nil, _key_fun, _value_fun) do
nil
end
def deep_map(value, _key_fun, value_fun) do
value_fun.(value)
end
@doc """
Transforms a `map`'s `String.t` keys to `atom()` keys.
* `map` is any `Map.t`
* `options` is a keyword list of options. The
available option is:
* `:only_existing` which is set to `true` will
only convert the binary key to an atom if the atom
already exists. The default is `false`.
## Examples
"""
def atomize_keys(map, options \\ [only_existing: false]) do
deep_map(map, &atomize_element(&1, options[:only_existing]), &identity/1)
end
@doc """
Transforms a `map`'s `String.t` values to `atom()` values.
* `map` is any `Map.t`
* `options` is a keyword list of options. The
available option is:
* `:only_existing` which is set to `true` will
only convert the binary value to an atom if the atom
already exists. The default is `false`.
## Examples
"""
def atomize_values(map, options \\ [only_existing: false]) do
deep_map(map, &identity/1, &atomize_element(&1, options[:only_existing]))
end
@doc """
Transforms a `map`'s `atom()` keys to `String.t` keys.
* `map` is any `Map.t`
## Examples
"""
def stringify_keys(map) do
deep_map(
map,
fn
k when is_atom(k) -> Atom.to_string(k)
k -> k
end,
&identity/1
)
end
@doc """
Transforms a `map`'s keys to `Integer.t` keys.
* `map` is any `Map.t`
The map key is converted to an `integer` from
either an `atom` or `String.t` only when the
key is comprised of `integer` digits.
Keys which cannot be converted to an `integer`
are returned unchanged.
## Examples
"""
def integerize_keys(map) do
deep_map(map, &integerize_element/1, &identity/1)
end
@doc """
Transforms a `map`'s values to `Integer.t` values.
* `map` is any `Map.t`
The map value is converted to an `integer` from
either an `atom` or `String.t` only when the
value is comprised of `integer` digits.
Keys which cannot be converted to an integer
are returned unchanged.
## Examples
"""
def integerize_values(map) do
deep_map(map, &identity/1, &integerize_element/1)
end
@doc """
Transforms a `map`'s values to `Float.t` values.
* `map` is any `Map.t`
The map value is converted to a `float` from
either an `atom` or `String.t` only when the
value is comprised of a valid float forma.
Keys which cannot be converted to a `float`
are returned unchanged.
## Examples
"""
def floatize_values(map) do
deep_map(map, &identity/1, &floatize_element/1)
end
@doc """
Rename map keys from `from` to `to`
* `map` is any `Map.t`
* `from` is any value map key
* `to` is any valud map key
## Examples
"""
def rename_key(map, from, to) do
deep_map(
map,
fn
^from -> to
other -> other
end,
&identity/1
)
end
@doc """
Convert map keys from `camelCase` to `snake_case`
* `map` is any `Map.t`
## Examples
"""
def underscore_keys(map = %{}) do
deep_map(map, &underscore/1, &identity/1)
end
@doc """
Removes any leading underscores from `map`
keys.
* `map` is any `Map.t`
## Examples
"""
def remove_leading_underscores(map) do
deep_map(map, &String.replace_prefix(&1, "_", ""), &identity/1)
end
@doc """
Returns the result of deep merging a list of maps
## Examples
"""
def merge_map_list([h | []]) do
h
end
def merge_map_list([h | t]) do
deep_merge(h, merge_map_list(t))
end
def merge_map_list([]) do
[]
end
@doc """
Deep merge two maps
* `left` is any `Map.t`
* `right` is any `Map.t`
## Examples
"""
def deep_merge(left, right) do
Map.merge(left, right, &deep_resolve/3)
end
# Key exists in both maps, and both values are maps as well.
# These can be merged recursively.
defp deep_resolve(_key, left = %{}, right = %{}) do
deep_merge(left, right)
end
# Key exists in both maps, but at least one of the values is
# NOT a map. We fall back to standard merge behavior, preferring
# the value on the right.
defp deep_resolve(_key, _left, right) do
right
end
@doc """
Delete all members of a map that have a
key in the list of keys
## Examples
"""
def delete_in(%{} = map, keys) when is_list(keys) do
Enum.reject(map, fn {k, _v} -> k in keys end)
|> Enum.map(fn {k, v} -> {k, delete_in(v, keys)} end)
|> Enum.into(%{})
end
def delete_in(map, keys) when is_list(map) and is_binary(keys) do
delete_in(map, [keys])
end
def delete_in(map, keys) when is_list(map) do
Enum.reject(map, fn {k, _v} -> k in keys end)
|> Enum.map(fn {k, v} -> {k, delete_in(v, keys)} end)
end
def delete_in(%{} = map, keys) when is_binary(keys) do
delete_in(map, [keys])
end
def delete_in(other, _keys) do
other
end
def from_keyword(keyword) do
Enum.into(keyword, %{})
end
defp identity(x), do: x
defp atomize_element(x, true) when is_binary(x) do
String.to_existing_atom(x)
rescue
ArgumentError ->
x
end
defp atomize_element(x, false) when is_binary(x) do
String.to_atom(x)
end
defp atomize_element(x, _) do
x
end
@integer_reg Regex.compile!("^[0-9]+$")
defp integerize_element(x) when is_atom(x) do
integer =
x
|> Atom.to_string()
|> integerize_element
if is_integer(integer) do
integer
else
x
end
end
defp integerize_element(x) when is_binary(x) do
if Regex.match?(@integer_reg, x) do
String.to_integer(x)
else
x
end
end
defp integerize_element(x) do
x
end
@float_reg Regex.compile!("^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$")
defp floatize_element(x) when is_atom(x) do
x
|> Atom.to_string()
|> floatize_element
end
defp floatize_element(x) when is_binary(x) do
if Regex.match?(@float_reg, x) do
String.to_float(x)
else
x
end
end
defp floatize_element(x) do
x
end
@doc """
Convert a camelCase string or atome to a snake_case
* `string` is a `String.t` or `atom()` to be
transformed
This is the code of Macro.underscore with modifications.
The change is to cater for strings in the format:
This_That
which in Macro.underscore gets formatted as
this__that (note the double underscore)
when we actually want
that_that
## Examples
"""
@spec underscore(string :: String.t() | atom()) :: String.t()
def underscore(atom) when is_atom(atom) do
"Elixir." <> rest = Atom.to_string(atom)
underscore(rest)
end
def underscore(<<h, t::binary>>) do
<<to_lower_char(h)>> <> do_underscore(t, h)
end
def underscore("") do
""
end
# h is upper case, next char is not uppercase, or a _ or . => and prev != _
defp do_underscore(<<h, t, rest::binary>>, prev)
when h >= ?A and h <= ?Z and not (t >= ?A and t <= ?Z) and t != ?. and t != ?_ and t != ?- and
prev != ?_ do
<<?_, to_lower_char(h), t>> <> do_underscore(rest, t)
end
# h is uppercase, previous was not uppercase or _
defp do_underscore(<<h, t::binary>>, prev)
when h >= ?A and h <= ?Z and not (prev >= ?A and prev <= ?Z) and prev != ?_ do
<<?_, to_lower_char(h)>> <> do_underscore(t, h)
end
# h is dash "-" -> replace with underscore "_"
defp do_underscore(<<?-, t::binary>>, _) do
<<?_>> <> underscore(t)
end
# h is .
defp do_underscore(<<?., t::binary>>, _) do
<<?/>> <> underscore(t)
end
# Any other char
defp do_underscore(<<h, t::binary>>, _) do
<<to_lower_char(h)>> <> do_underscore(t, h)
end
defp do_underscore(<<>>, _) do
<<>>
end
def to_upper_char(char) when char >= ?a and char <= ?z, do: char - 32
def to_upper_char(char), do: char
def to_lower_char(char) when char == ?-, do: ?_
def to_lower_char(char) when char >= ?A and char <= ?Z, do: char + 32
def to_lower_char(char), do: char
end