Packages

Named arguments in Elixir

Current section

Files

Jump to
named_arguments lib named_arguments.ex
Raw

lib/named_arguments.ex

defmodule NamedArguments do
@moduledoc """
NamedArguments allows you to have python-like named arguments with defaults.
This module defines two macros (for `def` and `defp`) that can merge passed arguments
with default values specified in function head.
defmodule TestModule do
use NamedArguments
def func(opts \\ [age: 18, name: "Samar"]) do
IO.puts opts[:age]
IO.puts opts[:name]
end
end
"""
@doc false
defmacro __using__(_opts) do
quote do
import Kernel, except: [def: 2, defp: 2]
import unquote(__MODULE__)
end
end
for fun_name <- ~w(def defp)a do
defmacro unquote(fun_name)(defn = {_, _, args}, do: body) do
fun = unquote(fun_name)
quote do
Kernel.unquote(fun)(unquote(defn)) do
merge_args(unquote(args))
unquote(body)
end
end
end
end
defmacro merge_args([]), do: nil
defmacro merge_args(nil), do: nil
defmacro merge_args([{:\\, _, [var_key, {:%{}, _, default_args}]} | rest])
when is_list(default_args) do
quote do
var!(unquote(var_key)) =
Map.merge(Enum.into(unquote(default_args), %{}), var!(unquote(var_key)))
merge_args(unquote(rest))
end
end
defmacro merge_args([{:\\, _, [var_key, default_args]} | rest]) when is_list(default_args) do
quote do
var!(unquote(var_key)) =
cond do
Keyword.keyword?(unquote(default_args)) ->
Keyword.merge(unquote(default_args), var!(unquote(var_key)))
true ->
var!(unquote(var_key))
end
merge_args(unquote(rest))
end
end
defmacro merge_args([_ | rest]) do
quote do: merge_args(unquote(rest))
end
end