Pattern matching map with optional keys

elixir

Solution

You can use `Map.merge/2`:

defmodule Handler do
  @defaults %{print_times: 2, color: "Blue"}

  def handle_my_map(map) do
    %{text: text, print_times: times, color: color} = merge_defaults(map)
    Enum.each(1..times, fn (_) -> IO.puts ["(", color, "): ", text] end)
  end

  defp merge_defaults(map) do
    Map.merge(@defaults, map)
  end
end

If you want to allow nils, you can use `Map.merge/3` and change `merge_defaults/1` to:

defp merge_defaults(map) do
  Map.merge(@defaults, map, fn _key, default, val -> val || default end)
end

Problem

I have a function which receives a map with many keys, some of them are optional. How can I write the function signature comprehending the map while allowing the optional keys to default to something? ``` def handle_my_map(%{text: text, print_times: print_times, # this I want to default to 2 color: color # this I want to default to "Blue" }) do Enum.each(1..print_times, fn (_) -> IO.puts ["(", color, "): ", text] end) end Test.handle_my_map(%{text: "here", print_times: 5, color: "Red"}) # (Red): here # (Red): here # (Red): here # (Red): here # (Red): here handle_my_map(%{text: "there"}) # => MatchError! ``` I would like it to be: ``` handle_my_map(%{text: "where", print_times: 3}) # (Blue): where # (Blue): where # (Blue): where handle_my_map(%{text: "there"}) # (Blue): there # (Blue): there ``` Something like ruby's keyword arguments: ``` def handle_my_map(text: nil, print_times: 2, color: 'Blue') ```

Original source