harnais v1.0.0 Harnais.Utility View Source
Miscellaneous Utility Functions
Link to this section Summary
Functions
form_validate/1
calls Macro.validate/1
on the argument (the expected form)
and if the result is :ok
returns {:ok, form}, else {:error, error}
forms_normalise/1
takes zero, one or more form and normalises them to a forms returning {:ok, forms}
forms_reduce/1
takes a zero, one or more form, normalises them, and reduces the forms to a single
form using Kernel.SpecialForms.unquote_splicing/1
forms_validate/1
validates the forms using form_validate/1
on each form, returning {:ok, forms}
if all are valid, else {:error, error}
map_collate0_enum/2
take an enum and map/1 function and
applies the arity 1 function to each element of the enum in an
Enum.reduce_while/2
loop
opts_canon_keys/2
takes an opts list, together with a lookup dictionary and replaces each key with its canonical value from the dictionary, returning {:ok, opts}
opts_canon_keys!/2
takes an opts list, together with a lookup dictionary and replaces each key with its canonical value from the dictionary. Unknown keys raise a KeyError
opts_canonical_keys/2
takes a derivable opts, together with a key alias dict
opts_create_aliases_dict/1
does the same job as opts_create_alias_tuples/1
but returns a key alias dict
opts_maybe_canon_keys/2
takes an opts list, together with a lookup dictionary and replaces any key in the dictionary with its dictionary value, returning the updated opts
opts_normalise/
expects a derivable opts and returns {:ok, opts}
opts_sort_keys/
takes an opts list, together with a list of sort keys, and returns the opts sorted in the sort keys order. Duplicate keys follow one after another
opts_validate/1
returns {:ok, opts}
if the argument is an opts
opts_validate_keys!/2
takes an opts list, together with the list of valid keys, and check there are no unknown keys in opts, raising a KeyError
if so, else returning the opts
Link to this section Types
Link to this section Functions
form_validate/1
calls Macro.validate/1
on the argument (the expected form)
and if the result is :ok
returns {:ok, form}, else {:error, error}
.
Examples
iex> 1 |> form_validate
{:ok, 1}
iex> nil |> form_validate # nil is a valid ast
{:ok, nil}
iex> [:x, :y] |> form_validate
{:ok, [:x, :y]}
iex> form = {:x, :y} # this 2tuple is a valid form without escaping
...> form |> form_validate
{:ok, {:x, :y}}
iex> {:error, error} = {:x, :y, :z} |> form_validate
...> error |> Exception.message
"form invalid, got: {:x, :y, :z}"
iex> {:error, error} = %{a: 1, b: 2, c: 3} |> form_validate # map not a valid form
...> error |> Exception.message
"form invalid, got: %{a: 1, b: 2, c: 3}"
iex> form = %{a: 1, b: 2, c: 3} |> Macro.escape # escaped map is a valid form
...> form |> form_validate
{:ok, %{a: 1, b: 2, c: 3} |> Macro.escape}
forms_normalise/1
takes zero, one or more form and normalises them to a forms returning {:ok, forms}
.
The list is first flattened and any nils
removed before splicing.
Examples
iex> {:ok, forms} = quote(do: a = x + y) |> forms_normalise
...> forms |> hd |> Macro.to_string
"a = x + y"
iex> {:ok, forms} = [
...> quote(do: a = x + y),
...> quote(do: a * c)
...> ] |> forms_normalise
...> forms |> Macro.to_string
"[a = x + y, a * c]"
iex> nil |> forms_normalise
{:ok, []}
iex> {:ok, form} = [
...> quote(do: a = x + y),
...> nil,
...> [
...> quote(do: b = a / c),
...> nil,
...> quote(do: d = b * b),
...> ],
...> quote(do: e = a + d),
...> ] |> forms_normalise
...> form |> Macro.to_string
"[a = x + y, b = a / c, d = b * b, e = a + d]"
forms_reduce/1
takes a zero, one or more form, normalises them, and reduces the forms to a single
form using Kernel.SpecialForms.unquote_splicing/1
.
If the reduction suceeds, {:ok, reduced_form}
is returned, else {:error, error}
.
An empty list reduces to {:ok, nil}
.
Examples
iex> {:ok, reduced_form} = quote(do: a = x + y) |> forms_reduce
...> reduced_form |> Macro.to_string
"a = x + y"
iex> {:ok, reduced_form} = [
...> quote(do: a = x + y),
...> quote(do: a * c)
...> ] |> forms_reduce
...> reduced_form |> Macro.to_string
"(\n a = x + y\n a * c\n)"
iex> {:ok, form} = nil |> forms_reduce
...> form |> Macro.to_string
"nil"
iex> {:ok, form} = [
...> quote(do: a = x + y),
...> nil,
...> [
...> quote(do: b = a / c),
...> nil,
...> quote(do: d = b * b),
...> ],
...> quote(do: e = a + d),
...> ] |> forms_reduce
...> form |> Macro.to_string
"(\n a = x + y\n b = a / c\n d = b * b\n e = a + d\n)"
forms_validate/1
validates the forms using form_validate/1
on each form, returning {:ok, forms}
if all are valid, else {:error, error}
.
Examples
iex> [1, 2, 3] |> forms_validate
{:ok, [1, 2, 3]}
iex> [1, {2, 2}, :three] |> forms_validate
{:ok, [1, {2, 2}, :three]}
iex> {:error, error} = [1, {2, 2, 2}, %{c: 3}] |> forms_validate
...> error |> Exception.message
"forms invalid, got invalid indices: [1, 2]"
map_collate0_enum/2
take an enum and map/1 function and
applies the arity 1 function to each element of the enum in an
Enum.reduce_while/2
loop.
The mapper must return either {:ok, value}
or {:error, error}
.
If the latter, the Enum.reduce_while/2
is halted, returning the
{:error, error}
.
Otherwise the value
from each {:ok, value}
result are collected
into a list and {:ok, values}
returned.
Examples
iex> fun = fn v -> {:ok, v} end
...> [1,2,3] |> map_collate0_enum(fun)
{:ok, [1,2,3]}
iex> fun = fn
...> 3 -> {:error, %ArgumentError{message: "argument is 3"}}
...> v -> {:ok, v}
...> end
...> {:error, error} = [1,2,3] |> map_collate0_enum(fun)
...> error |> Exception.message
"argument is 3"
iex> fun = :not_a_fun
...> {:error, error} = [1,2,3] |> map_collate0_enum(fun)
...> error |> Exception.message
"fun/1 function invalid, got: :not_a_fun"
iex> fun = fn v -> {:ok, v} end
...> {:error, error} = 42 |> map_collate0_enum(fun)
...> error |> Exception.message
"enum invalid, got: 42"
opts_canon_keys(opts(), alias_dict()) :: {:ok, opts()} | {:error, {opts(), opts()}}
opts_canon_keys/2
takes an opts list, together with a lookup dictionary and replaces each key with its canonical value from the dictionary, returning {:ok, opts}
.
If there are any unknown keys, {:error, {known_opts, unknown_opts}}
is returned.
Examples
iex> [a: 1, b: 2, c: 3] |> opts_canon_keys(%{a: :x, b: :y, c: :z})
{:ok, [x: 1, y: 2, z: 3]}
iex> [a: 11, p: 1, b: 22, q: 2, c: 33, r: 3] |> opts_canon_keys(%{a: :x, b: :y, c: :z})
{:error, {[x: 11, y: 22, z: 33], [p: 1, q: 2, r: 3]}}
opts_canon_keys!(opts(), alias_dict()) :: opts() | no_return()
opts_canon_keys!/2
takes an opts list, together with a lookup dictionary and replaces each key with its canonical value from the dictionary. Unknown keys raise a KeyError
.
Examples
iex> [a: 1, b: 2, c: 3] |> opts_canon_keys!(%{a: :x, b: :y, c: :z})
[x: 1, y: 2, z: 3]
iex> [x: 1, y: 3, z: 3] |> opts_canon_keys!(%{a: 1, b: 2, c: 3})
** (KeyError) key :x not found in: %{a: 1, b: 2, c: 3}
opts_canonical_keys(opts(), alias_dict()) :: {:ok, opts()} | {:error, error()}
opts_canonical_keys/2
takes a derivable opts, together with a key alias dict.
Each key in the opts
is replaced with its (canonical) value from the dictionary, returning {:ok, canon_opts}
.
If there are any unknown keys, {:error, error}
, where error
is a KeyError
, will be returned.
Examples
iex> [a: 1, b: 2, c: 3] |> opts_canonical_keys(%{a: :x, b: :y, c: :z})
{:ok, [x: 1, y: 2, z: 3]}
iex> [a: 1, b: 2, c: 3] |> opts_canonical_keys([a: :x, b: :y, c: :z])
{:ok, [x: 1, y: 2, z: 3]}
iex> [a: 11, p: 1, b: 22, q: 2, c: 33, r: 3] |> opts_canonical_keys(%{a: :x, b: :y, c: :z})
{:error, %KeyError{key: [:p, :q, :r], term: %{a: :x, b: :y, c: :z}}}
iex> {:error, error} = [a: 1, b: 2, c: 3]
...> |> opts_canonical_keys([a_canon: :a, b_canon: [:b], c_canon: [:c, :cc]])
...> error |> Exception.message
"key alias dict invalid, got: %{a_canon: :a, b_canon: [:b], c_canon: [:c, :cc]}"
opts_create_aliases_dict(alias_kvs()) :: alias_dict()
opts_create_aliases_dict/1
does the same job as opts_create_alias_tuples/1
but returns a key alias dict.
Examples
iex> [a: nil, b: [:b1], c: [:c1, :c2, :c3]] |> opts_create_aliases_dict
%{a: :a, b: :b, b1: :b, c: :c, c1: :c, c2: :c, c3: :c}
opts_maybe_canon_keys(opts(), alias_dict()) :: {:ok, opts()}
opts_maybe_canon_keys/2
takes an opts list, together with a lookup dictionary and replaces any key in the dictionary with its dictionary value, returning the updated opts.
Examples
iex> [a: 1, b: 2, c: 3] |> opts_maybe_canon_keys(%{a: :x, b: :y, c: :z})
[x: 1, y: 2, z: 3]
iex> [a: 11, p: 1, b: 22, q: 2, c: 33, r: 3] |> opts_maybe_canon_keys(%{a: :x, b: :y, c: :z})
[x: 11, p: 1, y: 22, q: 2, z: 33, r: 3]
opts_normalise/
expects a derivable opts and returns {:ok, opts}
.
Any other argument causes {:error, error}
to be returned.
Examples
iex> [] |> opts_normalise
{:ok, []}
iex> %{a: 1, b: 2, c: 3} |> opts_normalise
{:ok, [a: 1, b: 2, c: 3]}
iex> %{"a" => 1, :b => 2, :c => 3} |> opts_normalise
{:error, %KeyError{key: "a", term: %{:b => 2, :c => 3, "a" => 1}}}
iex> {:error, error} = 42 |> opts_normalise
...> error |> Exception.message
"opts not derivable, got: 42"
iex> [a: nil, b: [:b1], c: [:c1, :c2, :c3]] |> opts_normalise
{:ok, [a: nil, b: [:b1], c: [:c1, :c2, :c3]]}
opts_sort_keys(opts(), alias_keys()) :: opts()
opts_sort_keys/
takes an opts list, together with a list of sort keys, and returns the opts sorted in the sort keys order. Duplicate keys follow one after another.
Any keys found but not given in the sort keys follow the sorted keys in the returned opts. Any key in the sort list not found in the opts is ignored.
Examples
iex> [a: 1, b: 2, c: 3, d: 4] |> opts_sort_keys([:c, :a])
[c: 3, a: 1, b: 2, d: 4]
iex> [a: 1, b: 2, c: 3, d: 4] |> opts_sort_keys([:d, :x, :b, :z])
[d: 4, b: 2, a: 1, c: 3]
opts_validate/1
returns {:ok, opts}
if the argument is an opts.
Any other argument causes {:error, error}
to be returned.
Examples
iex> [] |> opts_validate
{:ok, []}
iex> {:error, error} = %{a: 1, b: 2, c: 3} |> opts_validate
...> error |> Exception.message
"opts invalid, got: %{a: 1, b: 2, c: 3}"
iex> {:error, error} = %{"a" => 1, :b => 2, :c => 3} |> opts_validate
...> error |> Exception.message
"opts invalid, got: %{:b => 2, :c => 3, \"a\" => 1}"
iex> {:error, error} = 42 |> opts_validate
...> error |> Exception.message
"opts invalid, got: 42"
iex> [a: nil, b: [:b1], c: [:c1, :c2, :c3]] |> opts_validate
{:ok, [a: nil, b: [:b1], c: [:c1, :c2, :c3]]}
opts_validate_keys!/2
takes an opts list, together with the list of valid keys, and check there are no unknown keys in opts, raising a KeyError
if so, else returning the opts.
Examples
iex> [a: 1, b: 2, c: 3] |> opts_validate_keys!([:a, :b, :c])
[a: 1, b: 2, c: 3]
iex> [a: 1, b: 2, c: 3] |> opts_validate_keys!([:a, :b])
** (KeyError) key [:c] not found in: [:a, :b]
iex> [a: 1, b: 2, c: 3] |> opts_validate_keys!([])
[a: 1, b: 2, c: 3]