ShorterMaps
~M sigil for map shorthand. ~M{a} ~> %{a: a}
{:shorter_maps, "~> 2.0"},
New Features
v2.0
- Backward incompatible change: keys must now be separated with commas.
-
Struct names are still followed by a space:
~M{%Person id, name} -
"Mixed mode" allows non-matching keys and variables, e.g.
~M{key_1, key_2, key_3: other_var}=>%{key_1: key_1, key_2: key_2, key_3: other_var}
v1.2
-
Added support for map update syntax (
~M{old_map|first_name last_name}), instead of writing%{old_map|first_name: first_name, last_name: last_name}. Works with both~mand~M.
v1.1
-
Added support for leading underscore variables (
~M{_id name} = person), which allows specifying structural requirements while minimizing compiler warnings for unused variables.
Motivation
Code like %{id: id, name: name, address: address} occurs with high frequency
in many programming languages. In Elixir, additional uses occur as we pattern
match to destructure existing maps.
ES6 provided javascript with a shorthand to create maps with keys inferred by
variable names, and allowed destructuring those maps into variables named for
the keys. ShorterMaps provides that functionality to Elixir.
Credits
ShorterMaps adds additional features to the original project, ShortMaps,
located here. The reasons for the divergence are summarized
here.
Syntax Overview => Macro Expansions
~M and ~m can be used to replace maps anywhere in your code. Here are the syntactic variants the macro exposes:
-
Atom keys:
~M{a, b}=>%{a: a, b: b} -
String keys:
~m{a, b}=>%{"a" => a, "b" => b} -
Structs:
~M{%Person id name}=>%Person{id: id, name: name} -
Pinned variables:
~M{^a, b}=>%{a: ^a, b: b} -
Ignore matching:
~M{_a, b}=>%{a: _a, b: b} -
Map update:
~M{old|a, b, c}=>%{old|a: a, b: b, c: c} -
Mixed mode:
~M{a, b: b_alt}=>%{a: a, b: b_alt}
Note: you must import ShorterMaps for the sigils to work.
Example Usage
iex> import ShorterMaps
...> name = "Chris"
...> id = 6
...> ~M{name, id}
%{name: "Chris", id: 6}
...> # String Keys:
...> ~m{name, id}
%{"name" => "Chris", "id" => 6}
...> # Structs:
...> defmodule MyStruct do
...> defstruct [id: nil]
...> end
...> ~M{%MyStruct id}
%MyStruct{id: 6}Pattern matching:
iex> map = %{a: 1, b: 2, c: 3}
...> ~M{a, b} = map
...> a
1
# in function heads:
...> defmodule MyModule do
...> def my_func(~M{name, _id}), do: {:id_present, name}
...> def my_func(~M{name}), do: {:no_id, name}
...> end
iex> MyModule.my_func(%{name: "Chris"})
{:no_id, "Chris"}
...> MyModule.my_func(%{name: "Chris", id: 1})
{:id_present, "Chris"}
# Update syntax:
iex> old_map = %{id: 1, name: "Chris"}
...> id = 7
...> ~M{old_map|id} # => %{old_map|id: id}
%{id: 7, name: "Chris"}
# Mixed keys:
iex> old_map = %{id: 1, first_name: "Chris", last_name: "Meyer"}
...> new_id = 6
...> first_name = "C"
...> ~M{old_map|id: new_id, first_name}
%{id: 6, first_name: "C", last_name: "Meyer"}