Packages

ISO/HL7 FHIR Application Server

Current section

Files

Jump to
hl7 lib xema utils.ex
Raw

lib/xema/utils.ex

defmodule Xema.Utils do
@moduledoc """
Some utilities for Xema.
"""
@doc """
Converts the given `string` to an existing atom. Returns `nil` if the
atom does not exist.
## Examples
iex> import Xema.Utils
iex> to_existing_atom(:my_atom)
:my_atom
iex> to_existing_atom("my_atom")
:my_atom
iex> to_existing_atom("not_existing_atom")
nil
"""
@spec to_existing_atom(String.t() | atom) :: atom | nil
def to_existing_atom(atom) when is_atom(atom), do: atom
def to_existing_atom(string) when is_binary(string) do
String.to_existing_atom(string)
rescue
_ -> nil
end
@doc """
Returns whether the given `key` exists in the given `value`.
Returns true if
* `value` is a map and contains `key` as a key.
* `value` is a keyword and contains `key` as a key.
* `value` is a list of tuples with `key`as the first element.
## Examples
iex> alias Xema.Utils
iex> Utils.has_key?(%{foo: 5}, :foo)
true
iex> Utils.has_key?([foo: 5], :foo)
true
iex> Utils.has_key?([{"foo", 5}], "foo")
true
iex> Utils.has_key?([{"foo", 5}], "bar")
false
iex> Utils.has_key?([], "bar")
false
"""
@spec has_key?(map | keyword | [{String.t(), any}], any) :: boolean
def has_key?([], _), do: false
def has_key?(value, key) when is_map(value), do: Map.has_key?(value, key)
def has_key?(value, key) when is_list(value) do
case Keyword.keyword?(value) do
true -> Keyword.has_key?(value, key)
false -> Enum.any?(value, fn {k, _} -> k == key end)
end
end
@doc """
Returns `nil` if `uri_1` and `uri_2` are `nil`.
Parses a URI when the other URI is `nil`.
Merges URIs if both are not nil.
"""
@spec update_uri(URI.t() | String.t() | nil, URI.t() | String.t() | nil) ::
URI.t() | nil
def update_uri(nil, nil), do: nil
def update_uri(uri_1, nil), do: URI.parse(uri_1)
def update_uri(nil, uri_2), do: URI.parse(uri_2)
def update_uri(uri_1, uri_2), do: URI.merge(uri_1, uri_2)
@doc """
Returns the size of a `list` or `tuple`.
"""
@spec size(list | tuple) :: integer
def size(list) when is_list(list), do: length(list)
def size(tuple) when is_tuple(tuple), do: tuple_size(tuple)
@doc """
Converts a `map` with integer keys or integer keys represented as strings to
a sorted list.
Returns an ok tuple with the list or an `:error` atom.
## Options:
* `keys` - if `true` the resulting list has `{key, value}` items, with false
the list contains the values. Defaults to `[keys: true]`.
## Examples
iex> alias Xema.Utils
iex> Utils.to_sorted_list(%{2 => "b", 3 => "c", 1 => "a"})
{:ok, [{1, "a"}, {2, "b"}, {3, "c"}]}
iex> Utils.to_sorted_list(%{"2" => "b", "3" => "c", "1" => "a"})
{:ok, [{"1", "a"}, {"2", "b"}, {"3", "c"}]}
iex> Utils.to_sorted_list(%{"2" => "b", "x" => "c", "1" => "a"})
:error
iex> Utils.to_sorted_list(%{"2" => "b", "3" => "c", "1" => "a"}, keys: true)
{:ok, [{"1", "a"}, {"2", "b"}, {"3", "c"}]}
iex> Utils.to_sorted_list(%{"2" => "b", "3" => "c", "1" => "a"}, keys: false)
{:ok, ["a", "b", "c"]}
"""
@spec to_sorted_list(map(), keys: boolean()) :: {:ok, list()} | :error
def to_sorted_list(map, opts \\ [keys: true]) do
result =
Enum.reduce_while(map, [], fn {key, _value} = item, acc ->
case to_integer(key) do
{:ok, integer} -> {:cont, [{integer, item(item, opts)} | acc]}
:error -> {:halt, nil}
end
end)
case result do
nil ->
:error
list ->
list =
list
|> Enum.sort_by(fn {index, _value} -> index end)
|> Enum.map(fn {_index, value} -> value end)
{:ok, list}
end
end
defp item(item, keys: true), do: item
defp item({_key, value}, keys: false), do: value
defp to_integer(value) when is_integer(value), do: {:ok, value}
defp to_integer(value) when is_binary(value) do
case Integer.parse(value) do
{integer, ""} -> {:ok, integer}
_error -> :error
end
end
defp to_integer(_value), do: :error
end