plymio_codi v0.3.1 Plymio.Codi.Pattern.Delegate View Source
The delegate patterns build Kernel.defdelegate/2 call(s).
Delegated functions can be built with, optionally, with a @doc,
@since and/or @spec.
See Plymio.Codi for an overview and documentation terms
Note the delegated mfa: {module, function, arity} is validated
i.e. the function must exist in the module with the given
arity.
If :delegate_doc is not in the pattern opts, a default of
:delegate is used. (It can be disabled by explicily setting
:fun_doc to nil - not false).
Pattern: delegate
Valid keys in the cpo are:
| Key | Aliases |
|---|---|
:delegate_module | :to, :module, :fun_mod, :fun_module, :function_module |
:delegate_name | :as |
:delegate_doc | :doc, :fun_doc, :function_doc |
:delegate_args | :args, :fun_args, :function_args |
:delegate_arity | :arity, :fun_arity, :function_arity |
:fun_name | :name, :function_name |
:spec_args | |
:spec_result | :result, :fun_result, :function_result |
:since |
Examples
A simple case. Note the automatically generated :delegate-format @doc.
iex> {:ok, {forms, _}} = [
...> delegate: [name: :fun_one, arity: 1, module: ModuleA],
...> delegate: [name: :fun_due, arity: 2, module: ModuleA],
...> delegate: [name: :fun_tre, arity: 3, module: ModuleA]
...> ] |> produce_codi
...> forms |> harnais_helper_format_forms!
["@doc \"Delegated to `ModuleA.fun_one/1`\"",
"defdelegate(fun_one(var1), to: ModuleA)",
"@doc \"Delegated to `ModuleA.fun_due/2`\"",
"defdelegate(fun_due(var1, var2), to: ModuleA)",
"@doc \"Delegated to `ModuleA.fun_tre/3`\"",
"defdelegate(fun_tre(var1, var2, var3), to: ModuleA)"]
Here showing the auto-generated @doc disabled.
iex> {:ok, {forms, _}} = [
...> delegate: [name: :fun_one, arity: 1, module: ModuleA, doc: nil],
...> ] |> produce_codi
...> forms |> harnais_helper_format_forms!
["defdelegate(fun_one(var1), to: ModuleA)"]
This example shows explicit function arguments (:args) being given:
iex> {:ok, {forms, _}} = [
...> delegate: [name: :fun_one, args: :opts, module: ModuleA, doc: nil],
...> ] |> produce_codi
...> forms |> harnais_helper_format_forms!
["defdelegate(fun_one(opts), to: ModuleA)"]
Delegating to a different function name (:as):
iex> {:ok, {forms, _}} = [
...> delegate: [name: :fun_3, as: :fun_tre, args: [:opts, :key, :value], module: ModuleA],
...> ] |> produce_codi
...> forms |> harnais_helper_format_forms!
["@doc \"Delegated to `ModuleA.fun_tre/3`\"",
"defdelegate(fun_3(opts, key, value), to: ModuleA, as: :fun_tre)"]
Here a @doc, @since, and @spec are generated. Note in the first
example the :spec_args are explicily given as well as the
:spec_result. In the second no :spec_args are given and the
arity used.
iex> {:ok, {forms, _}} = [
...> delegate: [name: :fun_one, arity: 1, module: ModuleA,
...> since: "1.7.9", spec_args: :integer, spec_result: :tuple],
...> ] |> produce_codi
...> forms |> harnais_helper_format_forms!
["@doc \"Delegated to `ModuleA.fun_one/1`\"",
"@since \"1.7.9\"",
"@spec fun_one(integer) :: tuple",
"defdelegate(fun_one(var1), to: ModuleA)"]
iex> {:ok, {forms, _}} = [
...> delegate: [name: :fun_one, arity: 1, module: ModuleA,
...> since: "1.7.9", spec_result: :tuple],
...> ] |> produce_codi
...> forms |> harnais_helper_format_forms!
["@doc \"Delegated to `ModuleA.fun_one/1`\"",
"@since \"1.7.9\"",
"@spec fun_one(any) :: tuple",
"defdelegate(fun_one(var1), to: ModuleA)"]
Showing validation of the mfa:
iex> {:error, error} = [
...> delegate: [name: :fun_one, arity: 2, module: ModuleZ],
...> ] |> produce_codi
...> error |> Exception.message
"mfa {ModuleZ, :fun_one, 2} module unknown"
iex> {:error, error} = [
...> delegate: [name: :fun_1, arity: 2, module: ModuleA],
...> ] |> produce_codi
...> error |> Exception.message
"mfa {ModuleA, :fun_1, 2} function unknown"
iex> {:error, error} = [
...> delegate: [name: :fun_one, arity: 2, module: ModuleA],
...> ] |> produce_codi
...> error |> Exception.message
"mfa {ModuleA, :fun_one, 2} arity unknown"
Pattern: delegate_module
The delegate_module pattern builds a delegate function for one or more functions in a module.
As with :delegate, @doc and/or @since can be generated at the same time.
Valid keys in the cpo are:
| Key | Aliases |
|---|---|
:delegate_module | :to :module, :fun_module, :fun_mod, :function_module |
:delegate_doc | :doc, :fun_doc, :function_doc |
:take | |
:drop | |
:filter | |
:reject | |
:since |
To determine which functions to delegate, the “function v arity”
(fva) for the module is first obtained by calling e.g. ModuleA.__info__(:functions).
The delegate options can include :take, :drop, :filter or
:reject keys to “edit” the fva..
The first two take zero, one or more function names
and are used in a call to e.g. Keyword.take/2 with the fva.
The second two keys require an arity 1 function (predicate) passed a
{fun,arity} tuple, returning true or false and is used with e.g. Enum.filter/2.
Note the fva edits are applied in order of occurence so
:take-ing a function already:reject-ed will do nothing.
Here all functions in the module (ModuleA) are wanted with auto-generated @doc and @since:
iex> {:ok, {forms, _}} = [
...> delegate_module: [module: ModuleA, since: "1.7.9"],
...> ] |> produce_codi
...> forms |> harnais_helper_format_forms!
["@doc \"Delegated to `ModuleA.fun_due/2`\"",
"@since \"1.7.9\"",
"defdelegate(fun_due(var1, var2), to: ModuleA)",
"@doc \"Delegated to `ModuleA.fun_one/1`\"",
"@since \"1.7.9\"",
"defdelegate(fun_one(var1), to: ModuleA)",
"@doc \"Delegated to `ModuleA.fun_tre/3`\"",
"@since \"1.7.9\"",
"defdelegate(fun_tre(var1, var2, var3), to: ModuleA)"]
Here arity 2 funs are selected, and @doc is disabled.
iex> {:ok, {forms, _}} = [
...> delegate_module: [
...> module: ModuleA, doc: nil,
...> filter: fn {_fun,arity} -> arity == 3 end],
...> ] |> produce_codi
...> forms |> harnais_helper_format_forms!
["defdelegate(fun_tre(var1, var2, var3), to: ModuleA)"]