lib/runbox/utils/map.ex

defmodule Runbox.Utils.Map do
  @moduledoc group: :utilities
  @moduledoc """
  A set of utility functions for Maps.
  """

  @doc """
  Follows the `path` in the (deep) map, defaulting to `default` if some of the
  objects on the path is missing.

  ## Example
      iex> object = %{"some" => %{"deep" => %{"object" => "data"}}}
      ...> Runbox.Utils.Map.get_path(object, ["some", "deep", "object"])
      "data"
      iex> Runbox.Utils.Map.get_path(object, ["non-existent"], "default")
      "default"
  """
  @spec get_path(map(), [binary() | atom()], any()) :: any()
  def get_path(map, path, default \\ nil)
  def get_path(map, [_ | _], default) when not is_map(map), do: default

  def get_path(map, [el], default) do
    Map.get(map, el, default)
  end

  def get_path(obj, [], default) do
    obj || default
  end

  def get_path(map, [el | rest], default) do
    get_path(Map.get(map, el, %{}), rest, default)
  end
end