Packages

An easy to use and pipe friendly way to have named arugments

Current section

Files

Jump to
argument_names lib argument_names.ex
Raw

lib/argument_names.ex

defmodule ArgumentNames do
@moduledoc """
Documentation for `ArgumentNames`.
"""
@doc """
Defines a function with named arguments
## Examples
defmodule Foo do
require ArgumentNames
import ArgumentNames
defnamed div(first, second) do
first / second
end
end
Foo.div(2, 4)
#=> 0.5
Foo.div(second ~> 4, 2)
#=> 0.5
"""
defmacro defnamed({name, meta, args} = call, do: expr) do
name_and_args = {:"call_#{name}", meta, args}
outer_args = Macro.escape(args)
quote do
@doc false
def unquote(name_and_args) do
unquote(expr)
end
defmacro unquote(call) do
outer_args = unquote(outer_args)
args = unquote(args)
split_args =
args
|> Enum.group_by(fn
{:~>, _, _} -> true
_ -> false
end)
arg_arr = :array.from_list(args)
arr =
List.foldl(split_args[true] || [], :array.new(length(args)), fn
{:~>, _, [{var_name, _, _}, val]}, acc ->
idx =
Enum.find_index(outer_args, fn {outer_name, _, _} ->
var_name == outer_name
end)
:array.set(idx, val, acc)
end)
arr =
List.foldl(split_args[false] || [], arr, fn
val, acc ->
set_array(0, acc, val)
end)
{{:., [], [
{:__aliases__, [alias: false], [__MODULE__]},
:"call_#{unquote(name)}"
]}, [], :array.to_list(arr)}
end
end
end
@doc false
def set_array(idx, array, val) do
if :array.get(idx, array) == :undefined do
:array.set(idx, val, array)
else
set_array(idx + 1, array, val)
end
end
end