View Source es6_maps
Enables ES6-like shorthand usage of Elixir maps.
Why?
When writing code that heavily utilizes structures and passes complex objects through multiple layers, it's common to frequently use map literals.
This often results in repetitive code patterns such as ctx = %{variable: variable, user: user, ...} or %{variable: variable, user: user, ...} = ctx.
I believe that introducing a shorthand form of object creation to Elixir enhances the language's ergonomics and is a natural extension of its existing map literals syntax. This feature will be immediately familiar to JavaScript and Rust developers, and similar shorthands are present in other languages such as Go.
Installation
The package can be installed by adding es6_maps to your list of dependencies and compilers in mix.exs:
def project do
[
app: :testme,
version: "0.1.0",
compilers: [:es6_maps | Mix.compilers()],
deps: deps()
]
end
def deps do
[
{:es6_maps, "~> 0.2.0", runtime: false}
]
endUsage
Creating maps
iex> {hello, foo, bar} = {"world", 1, 2}
iex> %{hello, foo, bar: bar}
%{hello: "world", foo: 1, bar: 2}Destructuring maps
iex> %{hello, foo} = %{hello: "world", foo: 1, bar: 2}
iex> hello
"world"
iex> foo
1Updating maps
iex> map = %{hello: "world", foo: 1, bar: 2}
iex> foo = :baz
iex> %{map | foo, bar: :bong}
%{hello: "world", foo: :baz, bar: :bong}Structs
All of the above work for structs as well:
defmodule MyStruct do
defstruct [:hello, :foo, :bar]
end
iex> {foo, bar} = {1, 2}
iex> %MyStruct{foo, bar, hello: "world"}
%MyStruct{foo: 1, bar: 2, hello: "world"}
iex> struct = %MyStruct{foo: 1, bar: 2}
iex> hello = "world"
iex> %MyStruct{struct | hello}
%MyStruct{foo: 1, bar: 2, hello: "world"}
iex> %MyStruct{hello} = %MyStruct{hello: "world", foo: 1}
iex> hello
"world"Converting existing code to use ES6-style maps
es6_maps includes a formatting task that will convert your existing map & struct literals into the shorthand style:
mix es6_maps.format 'lib/**/*.ex' 'test/**/*.exs'
The formatting task manipulates the AST, not raw strings, so it's precise and will only change your code by:
- changing map keys into the shorthand form;
- reordering map keys so the shorthand form comes first;
- formatting the results with
mix format.
See mix help es6_maps.format for more options and information.
Going back to old-style maps
You can revert all of the ES6-style shorthand uses with the --revert format flag:
mix es6_maps.format --revert lib/myapp/myapp.ex
How does it work?
es6_maps replaces in runtime the Elixir compiler's elixir_map module.
The module's expand_map/4 function is wrapped with a function that replaces map keys %{k} as if they were %{k: k}.
After es6_maps runs as one of the Mix compilers, the Elixir compiler will use the replaced functions to compile the rest of the code.
[!IMPORTANT] By the nature of this solution it's tightly coupled to the internal Elixir implementation. The current version of
es6_mapsshould work for Elixir 1.15, 1.16 and the upcoming 1.17 version, but may break in the future.