Current section
Files
Jump to
Current section
Files
lib/codi/pattern/other/other.ex
defmodule Plymio.Codi.Pattern.Other do
@moduledoc ~S"""
This module collects the *other*, simple patterns.
See `Plymio.Codi` for an overview and documentation terms.
## Pattern: *form*
The *form* pattern is a convenience to embed arbitrary code.
Valid keys in the *cpo* are:
| Key | Aliases |
| :--- | :--- |
| `:form` | *:forms, :ast, :asts* |
## Examples
A simple example with four functions:
iex> {:ok, {forms, _}} = [
...> form: quote(do: def(add_1(x), do: x + 1)),
...> ast: quote(do: def(sqr_x(x), do: x * x)),
...> forms: [
...> quote(do: def(sub_1(x), do: x - 1)),
...> quote(do: def(sub_2(x), do: x - 2)),
...> ]
...> ] |> produce_codi
...> forms |> harnais_helper_show_forms!
["def(add_1(x)) do\n x + 1\n end",
"def(sqr_x(x)) do\n x * x\n end",
"def(sub_1(x)) do\n x - 1\n end",
"def(sub_2(x)) do\n x - 2\n end"]
Here the subtraction functions are renamed:
iex> {:ok, {forms, _}} = [
...> form: quote(do: def(add_1(x), do: x + 1)),
...> ast: quote(do: def(sqr_x(x), do: x * x)),
...> forms: [
...> forms: [quote(do: def(sub_1(x), do: x - 1)),
...> quote(do: def(sub_2(x), do: x - 2))],
...> forms_edit: [rename_funs: [sub_1: :decr_1, sub_2: :take_away_2]]]
...> ] |> produce_codi
...> forms |> harnais_helper_show_forms!
["def(add_1(x)) do\n x + 1\n end",
"def(sqr_x(x)) do\n x * x\n end",
"def(decr_1(x)) do\n x - 1\n end",
"def(take_away_2(x)) do\n x - 2\n end"]
In this example the edits are "global" and applied to *all* produced forms:
iex> forms_edit = [rename_funs: [
...> sub_1: :decr_1,
...> sub_2: :take_away_2,
...> add_1: :incr_1,
...> sqr_x: :power_2]
...> ]
...> {:ok, {forms, _}} = [
...> form: quote(do: def(add_1(x), do: x + 1)),
...> ast: quote(do: def(sqr_x(x), do: x * x)),
...> forms: [quote(do: def(sub_1(x), do: x - 1)),
...> quote(do: def(sub_2(x), do: x - 2))],
...> ] |> produce_codi(forms_edit: forms_edit)
...> forms |> harnais_helper_show_forms!
["def(incr_1(x)) do\n x + 1\n end",
"def(power_2(x)) do\n x * x\n end",
"def(decr_1(x)) do\n x - 1\n end",
"def(take_away_2(x)) do\n x - 2\n end"]
## Pattern: *since*
The *since* pattern builds a `@since` module attribute form.
Valid keys in the *cpo* are:
| Key | Aliases |
| :--- | :--- |
| `:since` | |
## Examples
The value must be a string and is validated by `Version.parse/1`:
iex> {:ok, {forms, _}} = [
...> since: "1.7.9"
...> ] |> produce_codi
...> forms |> harnais_helper_show_forms!
["@since(\"1.7.9\")"]
iex> {:error, error} = [
...> since: "1.2.3.4.5"
...> ] |> produce_codi
...> error |> Exception.message
"since invalid, got: 1.2.3.4.5"
## Pattern: *deprecated*
The *deprecated* pattern builds a `@deprecated` module attribute form.
Valid keys in the *cpo* are:
| Key | Aliases |
| :--- | :--- |
| `:deprecated` | |
## Examples
The value must be a string.
iex> {:ok, {forms, _}} = [
...> deprecated: "This function has been deprecated since 1.7.9"
...> ] |> produce_codi
...> forms |> harnais_helper_show_forms!
["@deprecated(\"This function has been deprecated since 1.7.9\")"]
"""
alias Plymio.Codi, as: CODI
use Plymio.Fontais.Attribute
use Plymio.Codi.Attribute
import Plymio.Fontais.Guard,
only: [
is_value_unset: 1
]
import Plymio.Codi.Error,
only: [
new_error_result: 1
]
import Plymio.Fontais.Option,
only: [
opts_take_canonical_keys: 2,
opts_create_aliases_dict: 1
]
import Plymio.Codi.Utility,
only: [
validate_since: 1,
validate_deprecated: 1
]
import Plymio.Codi.CPO,
only: [
cpo_fetch_form: 1,
cpo_get_since: 1,
cpo_get_deprecated: 1,
cpo_done_with_edited_form: 2
]
@pattern_form_kvs_alias [
@plymio_codi_key_alias_pattern,
@plymio_codi_key_alias_status,
@plymio_codi_key_alias_form,
@plymio_codi_key_alias_forms_edit
]
@pattern_form_dict_alias @pattern_form_kvs_alias
|> opts_create_aliases_dict
@doc false
def cpo_pattern_form_normalise(opts, dict \\ nil) do
opts |> opts_take_canonical_keys(dict || @pattern_form_dict_alias)
end
@pattern_since_kvs_alias [
@plymio_codi_key_alias_pattern,
@plymio_codi_key_alias_status,
@plymio_codi_key_alias_since,
@plymio_codi_key_alias_forms_edit
]
@pattern_since_dict_alias @pattern_since_kvs_alias
|> opts_create_aliases_dict
@doc false
def cpo_pattern_since_normalise(opts, dict \\ nil) do
opts |> opts_take_canonical_keys(dict || @pattern_since_dict_alias)
end
@pattern_deprecated_kvs_alias [
@plymio_codi_key_alias_pattern,
@plymio_codi_key_alias_status,
@plymio_codi_key_alias_deprecated,
@plymio_codi_key_alias_forms_edit
]
@pattern_deprecated_dict_alias @pattern_deprecated_kvs_alias
|> opts_create_aliases_dict
@doc false
def cpo_pattern_deprecated_normalise(opts, dict \\ nil) do
opts |> opts_take_canonical_keys(dict || @pattern_deprecated_dict_alias)
end
@doc false
def express_pattern(codi, pattern, opts)
def express_pattern(%CODI{} = state, pattern, cpo)
when pattern == @plymio_codi_pattern_form do
with {:ok, cpo} <- cpo |> cpo_pattern_form_normalise,
{:ok, form} <- cpo |> cpo_fetch_form,
{:ok, cpo} <- cpo |> cpo_done_with_edited_form(form) do
{:ok, {cpo, state}}
else
{:error, %{__exception__: true}} = result -> result
end
end
def express_pattern(%CODI{} = state, pattern, cpo)
when pattern == @plymio_codi_pattern_since do
with {:ok, since} <- cpo |> cpo_get_since do
since
|> is_value_unset
|> case do
true ->
# drop the pattern
{:ok, {[], state}}
_ ->
with {:ok, since} <- since |> validate_since do
pattern_form =
quote do
@since unquote(since)
end
with {:ok, cpo} <- cpo |> cpo_done_with_edited_form(pattern_form) do
{:ok, {cpo, state}}
else
{:error, %{__exception__: true}} = result -> result
end
else
{:error, %{__exception__: true}} = result -> result
end
end
else
{:error, %{__exception__: true}} = result -> result
end
end
def express_pattern(%CODI{} = state, pattern, cpo)
when pattern == @plymio_codi_pattern_deprecated do
with {:ok, deprecated} <- cpo |> cpo_get_deprecated do
deprecated
|> is_value_unset
|> case do
true ->
# drop the pattern
{:ok, {[], state}}
_ ->
with {:ok, deprecated} <- deprecated |> validate_deprecated do
pattern_form =
quote do
@deprecated unquote(deprecated)
end
with {:ok, cpo} <- cpo |> cpo_done_with_edited_form(pattern_form) do
{:ok, {cpo, state}}
else
{:error, %{__exception__: true}} = result -> result
end
else
{:error, %{__exception__: true}} = result -> result
end
end
else
{:error, %{__exception__: true}} = result -> result
end
end
def express_pattern(_codi, pattern, opts) do
new_error_result(m: "proxy pattern #{inspect(pattern)} invalid", v: opts)
end
end