Packages

harnais_form: The Quoted Form Harness for the Harnais Family

Current section

Files

Jump to
harnais_form lib form.ex
Raw

lib/form.ex

defmodule Harnais.Form do
@moduledoc ~S"""
Functions for Testing Quoted Forms
## Documentation Terms
In the documentation these terms, usually in *italics*, are used to mean the same thing.
### *form* and *forms*
A *form* is a quoted form (`Macro.t`). A *forms* is a list of zero, one or more *form*s
### *opts*
An *opts* is a `Keyword` list.
## Bang and Query Functions
All functions have a bang peer.
`harnais_form/1`, `harnais_forms/1` and all compare functions
(e.g. `harnais_form_compare/3`) have a query peer
(e.g. `harnais_form_compare?/3`).
These functions do not appear in the function list to stop clutter. (They are `@doc false`).
"""
use Plymio.Codi
alias Harnais.Error, as: HEE
alias Harnais.Form.Schatten, as: HAS
alias Harnais.List, as: HUL
use Harnais.Error.Attribute
use Harnais.Form.Attribute
use Harnais.Form.Attribute.Schatten
@codi_opts [
{@plymio_codi_key_vekil, Plymio.Vekil.Codi.__vekil__()}
]
import Plymio.Fontais.Option,
only: [
opts_normalise: 1,
opts_validate: 1
]
import Plymio.Fontais.Form,
only: [
forms_edit: 2
]
@type ast :: Harnais.ast()
@type asts :: Harnais.asts()
@type form :: Harnais.form()
@type forms :: Harnais.forms()
@type opts :: Harnais.opts()
@type error :: Harnais.error()
@harnais_form_message_text_form_compare_failed "form compare failed"
@doc ~S"""
`harnais_form_test_forms/2` takes a *forms* with optional
*opts* and evaluate the *forms*, after processing any
options.
It returns `{:ok, {answer, forms}}` if evaluation succeeds, else
`{:error, error}`.
The `forms` in the result will be the form after any transformed have
been applied.
> This function calls `Harnais.Form.Schatten.produce_schatten/2` with common options prepended to any supplied *opts*. Its documentation should be read to understand the production process and allowed options.
## Examples
iex> harnais_form_test_forms(42)
{:ok, {42, 42}}
iex> quote(do: x = 42) |> harnais_form_test_forms
{:ok, {42, quote(do: x = 42)}}
iex> quote(do: x = 42) |> harnais_form_test_forms(
...> transform_opts: [transform: fn _ -> 42 end])
{:ok, {42, 42}}
iex> quote(do: x = 42) |> harnais_form_test_forms(
...> transform: [fn ast -> {ast, 42} end, fn {_ast,ndx} -> ndx end])
{:ok, {42, 42}}
iex> {:error, error} = quote(do: x = 42) |> harnais_form_test_forms(
...> transform: fn _ -> %{a: 1} end)
...> error |> Harnais.Error.export_exception
{:ok, [error: [[m: "form invalid, got: %{a: 1}"]]]}
iex> quote(do: x = 42) |> harnais_form_test_forms(
...> postwalk: fn _ -> 43 end)
{:ok, {43, 43}}
iex> quote(do: x = 42) |> harnais_form_test_forms(
...> postwalk: fn snippet ->
...> case snippet do
...> {:x, [], module} when is_atom(module) -> quote(do: a)
...> # passthru
...> x -> x
...> end
...> end)
{:ok, {42, quote(do: a = 42)}}
iex> quote(do: x = 42) |> harnais_form_test_forms(
...> replace_vars: [x: quote(do: a)])
{:ok, {42, quote(do: a = 42)}}
iex> quote(do: x = var!(a)) |> harnais_form_test_forms(
...> eval_binding: [b: 99],
...> replace_vars: [a: quote(do: b)])
{:ok, {99, quote(do: x = var!(b))}}
iex> quote(do: x = a) |> harnais_form_test_forms(
...> eval_binding: [b: 99],
...> replace_vars: [a: Macro.var(:b, nil)])
{:ok, {99, quote(do: x = unquote(Macro.var(:b, nil)))}}
iex> {:error, error} = harnais_form_test_forms(%{a: 1})
...> error |> Harnais.Error.export_exception
{:ok, [error: [[m: "form invalid, got: %{a: 1}"]]]}
Bang examples:
iex> harnais_form_test_forms!(42)
{42, 42}
iex> quote(do: x = 42) |> harnais_form_test_forms!(
...> transform: fn _ -> %{a: 1} end)
** (ArgumentError) form invalid, got: %{a: 1}
iex> quote(do: x = 42) |> harnais_form_test_forms!(
...> postwalk: fn _ -> 42 end)
{42, 42}
iex> quote(do: x = a) |> harnais_form_test_forms!(
...> eval_binding: [b: 99],
...> replace_vars: [a: Macro.var(:b, nil)])
{99, quote(do: x = unquote(Macro.var(:b, nil)))}
iex> harnais_form_test_forms!(%{a: 1})
** (ArgumentError) form invalid, got: %{a: 1}
"""
@spec harnais_form_test_forms(forms, opts) :: {:ok, any} | {:error, error}
def harnais_form_test_forms(forms, opts \\ [])
def harnais_form_test_forms(nil, _opts) do
{:ok, nil}
end
def harnais_form_test_forms(forms, opts) do
with {:ok, opts} <- opts |> opts_normalise,
{:ok, {values, %HAS{}}} <-
forms |> HAS.produce_schatten(@harnais_form_test_forms_default_opts ++ opts) do
{:ok, values |> Keyword.values() |> List.to_tuple()}
else
{:error, %{__exception__: true}} = result -> result
end
end
@doc ~S"""
`harnais_form_transform_forms/2` takes a *forms* together with optional
*opts* and transforms the *forms* returning `{:ok, forms}` or `{:error, error}`
Note the transformed *forms* do *not* have to be quoted forms.
## Transformations
The function is a convenience wrapper for `Plymio.Fontais.Form.forms_edit/2` and the transforms include :
1. `:postwalk`
1. `:prewalk`
1. `:transform`
1. `:replace_vars`
1. `:rename_vars`
1. `:rename_atoms`
1. `:rename_funs`
## Examples
iex> harnais_form_transform_forms(42)
{:ok, [42]}
iex> quote(do: x = 42) |> harnais_form_transform_forms
{:ok, [quote(do: x = 42)]}
iex> quote(do: x = 42) |> harnais_form_transform_forms(
...> transform: fn _ -> 42 end)
{:ok, [42]}
iex> quote(do: x = 42) |> harnais_form_transform_forms(
...> transform: [fn form -> {form, 42} end, fn {_form,ndx} -> ndx end])
{:ok, [42]}
iex> quote(do: x = 42) |> harnais_form_transform_forms(
...> transform: fn _ -> %{a: 1} end)
{:ok, [%{a: 1}]}
iex> quote(do: x = 42) |> harnais_form_transform_forms(
...> postwalk: fn _ -> 42 end)
{:ok, [42]}
The next two examples show the `x` var being renamed. The first
uses an explicit `:postwalk` while the second uses `:rename_vars`.
iex> quote(do: x = 42) |> harnais_form_transform_forms(
...> postwalk: fn snippet ->
...> case snippet do
...> {:x, [], module} when is_atom(module) -> quote(do: a)
...> # passthru
...> x -> x
...> end
...> end)
{:ok, [quote(do: a = 42)]}
iex> quote(do: x = 42) |> harnais_form_transform_forms(
...> replace_vars: [x: quote(do: a)])
{:ok, [quote(do: a = 42)]}
The *opts*, if any, are validated:
iex> {:error, error} = quote(do: x = 42) |> harnais_form_transform_forms(:opts_not_keyword)
...> error |> Exception.message
"transform failed, got: opts invalid, got: :opts_not_keyword"
The *forms* are validated:
iex> {:error, error} = %{a: 1} |> harnais_form_transform_forms
...> error |> Exception.message
"forms invalid, got invalid indices: [0]"
Bang examples:
iex> harnais_form_transform_forms!(42)
[42]
iex> quote(do: x = 42) |> harnais_form_transform_forms!(
...> transform: [fn ast -> {ast, 42} end, fn {_ast,ndx} -> ndx end])
[42]
iex> harnais_form_transform_forms!(quote(do: x = 42),
...> replace_vars: [x: quote(do: a)])
[quote(do: a = 42)]
iex> quote(do: x = 42) |> harnais_form_transform_forms!(
...> replace_vars: [x: quote(do: a)])
{:ok, quote(do: a = 42)}
[quote(do: a = 42)]
iex> {:error, error} = harnais_form_transform_forms(%{a: 1})
...> error |> Exception.message
"forms invalid, got invalid indices: [0]"
iex> {:error, error} = harnais_form_transform_forms(quote(do: x = 42), :opts_not_keyword)
...> error |> Exception.message
"transform failed, got: opts invalid, got: :opts_not_keyword"
"""
@spec harnais_form_transform_forms(forms, opts) :: {:ok, any} | {:error, error}
def harnais_form_transform_forms(forms, opts \\ [])
def harnais_form_transform_forms(forms, []) do
forms |> harnais_forms
end
def harnais_form_transform_forms(forms, opts) do
with {:ok, opts} <- opts |> opts_validate,
{:ok, forms} <- forms |> harnais_forms,
{:ok, _forms} = result <- forms |> forms_edit(opts) do
result
else
{:error, %{__exception__: true} = error} ->
HEE.new_error_result(m: "transform failed", v: error)
end
end
@doc_harnais_form_format_form ~S"""
`harnais_form_format_form/2` takes either a *form* or string as its argument, together with optional *opts*.
A form is converted first to text using `Macro.to_string/1`, reduced
(`Plymio.Fontais.Form.forms_reduce/1`) and then the text is passed
through the Elixir code formatter (`Code.format_string!/2`),
together with the *opts*.
It returns `{:ok, text}` if normalisation succeeds, else `{:error, error}`
## Examples
iex> harnais_form_format_form(42)
{:ok, "42"}
iex> harnais_form_format_form(:atom)
{:ok, ":atom"}
iex> harnais_form_format_form("string")
{:ok, "string"}
Quoted form:
iex> quote(do: Map.get( %{a: 1}, :a, 42)) |> harnais_form_format_form
{:ok, "Map.get(%{a: 1}, :a, 42)"}
Already text but "untidy":
iex> "Map.get( %{a: 1}, :a, 42) " |> harnais_form_format_form
{:ok, "Map.get(%{a: 1}, :a, 42)"}
"""
@doc_harnais_form_format_forms ~S"""
`harnais_form_format_forms/2` takes a *forms*, and optional *opts*,
and formats each *form* using `harnais_form_format_form/2` returning
`{:ok, texts}`.
## Examples
iex> [quote(do: x = x + 1),
...> quote(do: x = x * x ),
...> quote(do: x=x-1 )
...> ] |> harnais_form_format_forms
{:ok, ["x = x + 1", "x = x * x", "x = x - 1"]}
iex> [quote(do: x = x + 1),
...> quote(do: x = x * x),
...> quote(do: x = x - 1)
...> ] |> harnais_form_format_forms!
["x = x + 1", "x = x * x", "x = x - 1"]
"""
@doc ~S"""
`harnais_form_compare_texts/3` takes two arguments, either forms or strings, together with (optional) *opts*.
Each argument is normalised to text using `harnais_form_format_form/2` and then compared (`Kernel.==/2`).
It returns `{:ok, text}` if the compare succeeds, else `{:error, error}`
## Examples
iex> harnais_form_compare_texts(42, 42)
{:ok, "42"}
iex> harnais_form_compare_texts(
...> quote(do: Map.get( %{a: 1}, :a, 42)),
...> "Map.get(%{a: 1}, :a, 42)")
{:ok, "Map.get(%{a: 1}, :a, 42)"}
iex> harnais_form_compare_texts(
...> quote(do: Map.get(%{a: 1}, :a, 42)),
...> "Map.get( %{a: 1}, :a, 42)")
{:ok, "Map.get(%{a: 1}, :a, 42)"}
iex> {:error, error} = harnais_form_compare_texts(quote(do: x = 42), "x = 41")
...> error |> Exception.message
"form compare failed, reason=:mismatch, type=:arg, value1=x = 42, value2=x = 41"
iex> {:error, error} = harnais_form_compare_texts("x = 42", quote(do: x = 41))
...> error |> Harnais.Error.export_exception
{:ok, [error: [[m: "form compare failed", r: :mismatch, t: :arg, v1: "x = 42", v2: "x = 41"]]]}
Query examples:
iex> harnais_form_compare_texts?(42, 42)
true
iex> harnais_form_compare_texts?(
...> quote(do: (def f(x,y), do: x + y)),
...> "def(f(x, y)) do\n x + y\n end")
true
iex> harnais_form_compare_texts?(quote(do: x = 42), "x = 41")
false
iex> harnais_form_compare_texts?("x = 42", quote(do: x = 41))
false
Bang examples:
iex> harnais_form_compare_texts!(42, 42)
"42"
iex> harnais_form_compare_texts!(
...> quote(do: Map.get(%{a: 1}, :a, 42)),
...> "Map.get( %{a: 1}, :a, 42)")
"Map.get(%{a: 1}, :a, 42)"
iex> harnais_form_compare_texts!(
...> quote(do: (def f(x,y), do: x + y)),
...> "def(f(x, y)) do\n x + y\n end")
"def(f(x, y)) do\n x + y\nend"
iex> harnais_form_compare_texts!(quote(do: x = 42), "x = 41")
** (Harnais.Error) form compare failed, reason=:mismatch, type=:arg, value1=x = 42, value2=x = 41
"""
@spec harnais_form_compare_texts(any, any, opts) :: {:ok, binary} | {:error, error}
def harnais_form_compare_texts(actual_code, expect_code, opts \\ [])
def harnais_form_compare_texts(actual_code, expect_code, opts) do
with {:ok, actual_text} <- actual_code |> harnais_form_format_form(opts),
{:ok, expect_text} <- expect_code |> harnais_form_format_form(opts) do
case actual_text == expect_text do
true ->
{:ok, actual_text}
_ ->
HEE.new_error_result(
m: @harnais_form_message_text_form_compare_failed,
t: @harnais_error_value_field_type_arg,
r: @harnais_error_reason_mismatch,
v1: actual_text,
v2: expect_text
)
end
else
{:error, %{__exception__: true}} = result -> result
end
end
@doc ~S"""
`harnais_form_compare_forms/3` takes two arguments and optional *opts*.
If either argument is text (i.e binary), it performs a textual
comparison using `harnais_form_compare_texts/3` and returns `{:ok, first_argument}`
if the compare succeeds, else returns the `{:error, error}`.
If both arguments are forms, it runs `Macro.postwalk/3` on both,
collecting each form's `snippets` in the accumulator, and then calls
`Harnais.List.harnais_list_compare/2` to compare the two
accumulators returning `{:ok, first_argument}` else `{:error, error}`
from the list compare.
## Examples
Mixed form and text:
iex> harnais_form_compare_forms(42, "42")
{:ok, 42}
iex> harnais_form_compare_forms(
...> quote(do: Map.get( %{a: 1}, :a, 42)),
...> "Map.get(%{a: 1}, :a, 42)")
{:ok, quote(do: Map.get(%{a: 1}, :a, 42))}
iex> harnais_form_compare_forms(
...> quote(do: (def f(x,y), do: x + y)),
...> "def(f(x, y)) do\n x + y\n end")
{:ok, quote(do: (def f(x,y), do: x + y))}
Both forms:
iex> harnais_form_compare_forms(42, 42)
{:ok, 42}
iex> harnais_form_compare_forms(
...> quote(do: Map.get( %{a: 1}, :a, 42)),
...> quote(do: Map.get(%{a: 1}, :a, 42)))
{:ok, quote(do: Map.get(%{a: 1}, :a, 42))}
iex> {:error, error} = harnais_form_compare_forms(
...> quote(do: Map.get( %{a: 1}, :a, 42)),
...> quote(do: Map.get(%{a: 1}, :a, 41)))
...> error |> Exception.message
"form compare failed, reason=:mismatch, type=:value, location=9, value1=42, value2=41"
Note vars with same name (`:x`) but in different modules (`ModA` v `ModB`) will be cuaght:
iex> {:error, error} = harnais_form_compare_forms(
...> Macro.var(:x, ModA),
...> Macro.var(:x, ModB))
...> error |> Exception.message
"form compare failed, reason=:mismatch, type=:value, location=0, value1={:x, [], ModA}, value2={:x, [], ModB}"
Query examples:
iex> harnais_form_compare_forms?(
...> quote(do: Map.get( %{a: 1}, :a, 42)),
...> "Map.get(%{a: 1}, :a, 42)")
true
iex> harnais_form_compare_forms?(quote(do: x = 42), "x = 41")
false
iex> harnais_form_compare_forms?(
...> Macro.var(:x, ModA),
...> Macro.var(:x, ModB))
false
Bang examples:
iex> harnais_form_compare_forms!(42, "42")
42
iex> harnais_form_compare_forms!(quote(do: x = 42), "x = 41")
** (Harnais.Error) form compare failed, reason=:mismatch, type=:arg, value1=x = 42, value2=x = 41
iex> harnais_form_compare_forms!(
...> Macro.var(:x, ModA),
...> Macro.var(:x, ModB))
** (Harnais.Error) form compare failed, reason=:mismatch, type=:value, location=0, value1={:x, [], ModA}, value2={:x, [], ModB}
"""
@spec harnais_form_compare_forms(ast, any, opts) ::
{:ok, form} | {:ok, binary} | {:error, error}
def harnais_form_compare_forms(actual_code, expect_code, opts \\ [])
def harnais_form_compare_forms(actual_code, expect_code, opts)
when is_binary(actual_code) or is_binary(expect_code) do
# do a text compare
harnais_form_compare_texts(actual_code, expect_code, opts)
|> case do
{:ok, _} -> {:ok, actual_code}
x -> x
end
end
def harnais_form_compare_forms(actual_code, expect_code, opts) do
with {:ok, actual_form} <- actual_code |> harnais_form,
{:ok, expect_form} <- expect_code |> harnais_form do
actual_snippets =
actual_form
|> Macro.postwalk([], fn snippet, snippets -> {nil, [snippet | snippets]} end)
|> elem(1)
|> Enum.reverse()
expect_snippets =
expect_form
|> Macro.postwalk([], fn snippet, snippets -> {nil, [snippet | snippets]} end)
|> elem(1)
|> Enum.reverse()
case HUL.harnais_list_compare(actual_snippets, expect_snippets, opts) do
{:ok, _} ->
{:ok, actual_code}
{:error, %Harnais.Error{} = error} ->
{:error,
error
|> struct!([
{@harnais_error_field_message, @harnais_form_message_text_form_compare_failed}
])}
x ->
x
end
end
end
@doc_harnais_form ~S"""
`harnais_form/1` tests whether the argument is a quoted form and,
if true, returns `{:ok, form}` else returns `{:error, error}`.
(Delegated to `Harnais.Utility.form_validate/1`)
## Examples
iex> harnais_form(42)
{:ok, 42}
iex> harnais_form(:atom)
{:ok, :atom}
iex> {:error, error} = harnais_form(%{a: 1})
...> error |> Exception.message
"form invalid, got: %{a: 1}"
ies> Macro.escape(%{a: 1}) |> harnais_form
{:ok, Macro.escape(%{a: 1})}
Query examples:
iex> harnais_form?(42)
true
iex> harnais_form?(quote(do: x = 42))
true
iex> harnais_form?(%{a: 1})
false
Bang examples:
iex> harnais_form!(42)
42
iex> harnais_form!(quote(do: x = 42))
quote(do: x = 42)
iex> harnais_form!(%{a: 1})
** (ArgumentError) form invalid, got: %{a: 1}
"""
@doc_harnais_forms ~S"""
`harnais_forms/1` validates the *forms* returning `{:ok, forms}` if
all are valid, else `{:error, error}`.
(Delegated to `Harnais.Utility.forms_normalise/1`)
## Examples
iex> [1, 2, 3] |> harnais_forms
{:ok, [1, 2, 3]}
iex> 1 |> harnais_forms
{:ok, [1]}
iex> [1, {2, 2}, :three] |> harnais_forms
{:ok, [1, {2, 2}, :three]}
Query examples:
iex> [1, 2, 3] |> harnais_forms?
true
iex> [1, {2, 2}, :three] |> harnais_forms?
true
iex> [1, {2, 2, 2}, %{c: 3}] |> harnais_forms?
false
Bang examples:
iex> [1, 2, 3] |> harnais_forms!
[1, 2, 3]
iex> [1, {2, 2}, :three] |> harnais_forms!
[1, {2, 2}, :three]
iex> [1, {2, 2, 2}, %{c: 3}] |> harnais_forms!
** (ArgumentError) forms invalid, got invalid indices: [1, 2]
"""
@quote_result_list_no_return quote(do: list | no_return)
@quote_result_text_no_return quote(do: String.t() | no_return)
@quote_result_texts_no_return quote(do: [String.t()] | no_return)
@quote_result_form_no_return quote(do: form | no_return)
@quote_result_forms_no_return quote(do: forms | no_return)
@quote_result_form_result quote(do: {:ok, form} | {:error, error})
@quote_result_forms_no_return quote(do: forms | no_return)
@quote_result_forms_texts_result quote(do: {:ok, [String.t()]} | {:error, error})
[
delegate: [
name: :harnais_form,
as: :form_validate,
to: Harnais.Utility,
doc: @doc_harnais_form,
args: :form,
spec_args: :any,
since: "0.1.0",
result: @quote_result_form_result
],
bang: [
doc: false,
as: :harnais_form,
args: :form,
since: "0.1.0",
result: @quote_result_form_no_return
],
query: [doc: false, as: :harnais_form, args: :form, since: "0.1.0", result: true],
delegate: [
name: :harnais_forms,
as: :forms_normalise,
to: Harnais.Utility,
doc: @doc_harnais_forms,
args: :forms,
spec_args: :any,
since: "0.1.0",
result: @quote_result_form_result
],
bang: [
doc: false,
as: :harnais_forms,
args: :forms,
since: "0.1.0",
result: @quote_result_forms_no_return
],
query: [doc: false, as: :harnais_forms, args: :forms, since: "0.1.0", result: true],
bang: [
doc: false,
as: :harnais_form_transform_forms,
args: :form,
since: "0.1.0",
result: @quote_result_list_no_return
],
bang: [
doc: false,
as: :harnais_form_transform_forms,
args: [:form, :opts],
since: "0.1.0",
result: @quote_result_list_no_return
],
bang: [
doc: false,
as: :harnais_form_compare_forms,
args: [:form1, :form2],
since: "0.1.0",
result: @quote_result_forms_no_return
],
bang: [
doc: false,
as: :harnais_form_compare_forms,
args: [:form1, :form2, :opts],
since: "0.1.0",
result: @quote_result_forms_no_return
],
query: [
doc: false,
as: :harnais_form_compare_forms,
args: [:form1, :form2],
since: "0.1.0",
result: true
],
query: [
doc: false,
as: :harnais_form_compare_forms,
args: [:form1, :form2, :opts],
since: "0.1.0",
result: true
],
bang: [
doc: false,
as: :harnais_form_compare_texts,
args: [:code1, :code2],
since: "0.1.0",
result: @quote_result_text_no_return
],
bang: [
doc: false,
as: :harnais_form_compare_texts,
args: [:code1, :code2, :opts],
since: "0.1.0",
result: @quote_result_text_no_return
],
query: [
doc: false,
as: :harnais_form_compare_texts,
args: [:code1, :code2],
since: "0.1.0",
result: true
],
query: [
doc: false,
as: :harnais_form_compare_texts,
args: [:code1, :code2, :opts],
since: "0.1.0",
result: true
],
bang: [
doc: false,
as: :harnais_form_test_forms,
args: :forms,
since: "0.1.0",
result: @quote_result_forms_no_return
],
bang: [
doc: false,
as: :harnais_form_test_forms,
args: [:forms, :opts],
since: "0.1.0",
result: @quote_result_forms_no_return
],
delegate: [
name: :harnais_form_format_form,
as: :form_format,
to: Harnais.Form.Utility,
doc: false,
args: :form,
spec_args: :any,
spec_result: @quote_result_forms_texts_result
],
delegate: [
name: :harnais_form_format_form,
as: :form_format,
to: Harnais.Form.Utility,
doc: @doc_harnais_form_format_form,
args: [:form, :opts],
spec_args: [:any, :any],
spec_result: @quote_result_forms_texts_result
],
bang: [
doc: false,
as: :harnais_form_format_form,
args: :form,
since: "0.1.0",
result: @quote_result_text_no_return
],
bang: [
doc: false,
as: :harnais_form_format_form,
args: [:form, :opts],
since: "0.1.0",
result: @quote_result_text_no_return
],
delegate: [
name: :harnais_form_format_forms,
as: :forms_format,
to: Harnais.Form.Utility,
doc: false,
args: :forms,
spec_args: :any,
spec_result: @quote_result_forms_texts_result
],
delegate: [
name: :harnais_form_format_forms,
as: :forms_format,
to: Harnais.Form.Utility,
doc: @doc_harnais_form_format_forms,
args: [:forms, :opts],
spec_args: [:any, :any],
spec_result: @quote_result_forms_texts_result
],
bang: [
doc: false,
as: :harnais_form_format_forms,
args: :forms,
since: "0.1.0",
result: @quote_result_texts_no_return
],
bang: [
doc: false,
as: :harnais_form_format_forms,
args: [:forms, :opts],
since: "0.1.0",
result: @quote_result_texts_no_return
]
]
|> Enum.flat_map(fn {pattern, opts} ->
[pattern: [pattern: pattern] ++ opts]
end)
|> CODI.reify_codi(@codi_opts)
end