plymio_codi v0.3.1 Plymio.Codi.Pattern.Bang View Source

The bang patterns builds bang functions (e.g. myfun!(arg)) using existing base functions (e.g. myfun(arg)).

When the base function returns {:ok, value}, the bang function returns value.

If the base function returns {:error, error}, the error is raised.

Bang functions can be built with, optionally, with a @doc, @since and/or @spec.

See Plymio.Codi for an overview and documentation terms.

Note if the base function is in another module, the base mfa {module, function, arity} is validated i.e. the function must exist in the module with the given arity.

If :fun_doc is not in the pattern opts, a default of :bang is used. (It can be disabled by explicitly setting :fun_doc to nil)

Pattern: bang

Valid keys in the cpo are:

KeyAliases
:bang_module:module, :fun_mod, :bang_module, :function_module
:bang_name:name, :fun_name, :function_name
:bang_args:args, :fun_args, :function_args
:bang_arity:arity, :fun_arity, :function_arity
:bang_doc:doc, :fun_doc, :function_doc
:spec_args
:spec_result:result, :fun_result, :function_result
:since

Examples

Here is the common case of a bang function for a function in the same module. Note the automatically generated :bang-format @doc and explicitly specified @since:

iex> {:ok, {forms, _}} = [
...>   bang: [as: :fun_tre, arity: 3, since: "1.7.9"]
...> ] |> produce_codi
...> forms |> harnais_helper_format_forms!
["@doc \"Bang function for `fun_tre/3`\"",
 "@since \"1.7.9\"",
 "def(fun_tre!(var1, var2, var3)) do",
 "  case(fun_tre(var1, var2, var3)) do",
 "    {:ok, value} ->",
 "      value",
 "",
 "    {:error, error} ->",
 "      raise(error)",
 "  end",
 "end"]

Here the other function is in a different module(ModuleA):

iex> {:ok, {forms, _}} = [
...>   bang: [as: :fun_tre, arity: 3, to: ModuleA, since: "1.7.9"]
...> ] |> produce_codi
...> forms |> harnais_helper_format_forms!
["@doc \"Bang function for `ModuleA.fun_tre/3`\"",
 "@since \"1.7.9\"",
 "def(fun_tre!(var1, var2, var3)) do",
 "  case(ModuleA.fun_tre(var1, var2, var3)) do",
 "    {:ok, value} ->",
 "      value",
 "",
 "    {:error, error} ->",
 "      raise(error)",
 "  end",
 "end"]

The :fun_args can be supplied to improve the definition. Note the :fun_doc is set to false.

iex> {:ok, {forms, _}} = [
...>   bang: [as: :fun_tre, args: [:x, :y, :z], to: ModuleA, fun_doc: false]
...> ] |> produce_codi
...> forms |> harnais_helper_format_forms!
["@doc false", "def(fun_tre!(x, y, z)) do",
 "  case(ModuleA.fun_tre(x, y, z)) do",
 "    {:ok, value} ->",
 "      value",
 "",
 "    {:error, error} ->",
 "      raise(error)",
 "  end",
 "end"]

Similary, if the cpo contains a :spec_result key, a @spec will be generated. The second example has an explicit :spec_args

iex> {:ok, {forms, _}} = [
...>   bang: [as: :fun_tre, args: [:x, :y, :z], module: ModuleA, result: :tuple]
...> ] |> produce_codi
...> forms |> harnais_helper_format_forms!
["@doc \"Bang function for `ModuleA.fun_tre/3`\"",
 "@spec fun_tre!(any, any, any) :: tuple",
 "def(fun_tre!(x, y, z)) do",
 "  case(ModuleA.fun_tre(x, y, z)) do",
 "    {:ok, value} ->",
 "      value",
 "",
 "    {:error, error} ->",
 "      raise(error)",
 "  end",
 "end"]

iex> {:ok, {forms, _}} = [
...>   bang: [as: :fun_tre, args: [:x, :y, :z], module: ModuleA,
...>          spec_args: [:integer, :binary, :atom], result: :tuple]
...> ] |> produce_codi
...> forms |> harnais_helper_format_forms!
["@doc \"Bang function for `ModuleA.fun_tre/3`\"",
 "@spec fun_tre!(integer, binary, atom) :: tuple",
 "def(fun_tre!(x, y, z)) do",
 "  case(ModuleA.fun_tre(x, y, z)) do",
 "    {:ok, value} ->",
 "      value",
 "",
 "    {:error, error} ->",
 "      raise(error)",
 "  end",
 "end"]

Pattern: bang_module

The bang_module pattern builds a bang function for one or more functions in a module. As with :bang a @doc or @since can be generated at the same time.

Valid keys in the cpo are:

KeyAliases
:bang_module:to, :module, :fun_mod, :fun_module, :function_module
:bang_doc:doc, :fun_doc, :function_doc
:take
:drop
:filter
:reject
:since

Examples

Here a bang function will be generated for all the functions in the module.

iex> {:ok, {forms, _}} = [
...>   bang_module: [module: ModuleA],
...> ] |> produce_codi
...> forms |> harnais_helper_format_forms!
["@doc \"Bang function for `ModuleA.fun_due/2`\"",
 "def(fun_due!(var1, var2)) do",
 "  case(ModuleA.fun_due(var1, var2)) do",
 "    {:ok, value} ->",
 "      value",
 "",
 "    {:error, error} ->",
 "      raise(error)",
 "  end",
 "end",
 "@doc \"Bang function for `ModuleA.fun_one/1`\"",
 "def(fun_one!(var1)) do", "  case(ModuleA.fun_one(var1)) do",
 "    {:ok, value} ->",
 "      value",
 "",
 "    {:error, error} ->",
 "      raise(error)",
 "  end",
 "end",
 "@doc \"Bang function for `ModuleA.fun_tre/3`\"",
 "def(fun_tre!(var1, var2, var3)) do",
 "  case(ModuleA.fun_tre(var1, var2, var3)) do",
 "    {:ok, value} ->",
 "      value",
 "",
 "    {:error, error} ->",
 "      raise(error)",
 "  end",
 "end"]

In the same way as :delegate_module the functions can be selected using e.g. :take. Here :since is also given.

iex> {:ok, {forms, _}} = [
...>   bang_module: [module: ModuleA, take: :fun_due, since: "1.7.9"],
...> ] |> produce_codi
...> forms |> harnais_helper_format_forms!
["@doc \"Bang function for `ModuleA.fun_due/2`\"",
 "@since \"1.7.9\"",
 "def(fun_due!(var1, var2)) do",
 "  case(ModuleA.fun_due(var1, var2)) do",
 "    {:ok, value} ->",
 "      value",
 "",
 "    {:error, error} ->",
 "      raise(error)",
 "  end",
 "end"]