defmodule MapHelpers do @doc """ Checks if `map1`'s entries are all contained in `map2`. ## Options - `:recursive` - Recursively checks if a value is map (Default: `false`) ## Examples ``` iex> submap?(%{}, %{}) true iex> submap?(%{a: 1, b: 2}, %{a: 1, b: 2, c: 3}) true iex> submap?(%{a: 1, b: 2, c: 3}, %{a: 1, b: 2}) false iex> submap?(%{a: 1, b: %{}}, %{a: 1, b: %{c: 1}}) false iex> submap?(%{a: 1, b: %{}}, %{a: 1, b: %{c: 1}}, recursive: true) true ``` """ @spec submap?(map, map, [option]) :: boolean when option: {:recursive, boolean} def submap?(map1, map2, opts \\ []) when is_map(map1) and is_map(map2) do recursive = Keyword.get(opts, :recursive, false) map1 |> Enum.all?(fn {k, v} when is_map(v) and recursive -> m = map2[k] is_map(m) && submap?(v, m) {k, v} -> map2[k] === v end) end @doc """ Equivalent to `submap?(map1, map2, recursive: true)`. """ @spec deep_submap?(map, map) :: boolean def deep_submap?(map1, map2), do: submap?(map1, map2, recursive: true) end