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

The query patterns build query functions (e.g. myfun?(arg)) using existing base functions (e.g. myfun(arg)).

When the base function returns {:ok, value}, the query function returns true. Otherwise false is returned.

Query 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 :query is used. (It can be disabled by explicitly setting :fun_doc to nil)

Pattern: query

Valid keys in the cpo are:

KeyAliases
:query_module:module, :fun_mod, :query_module, :function_module
:query_name:name, :fun_name, :function_name
:query_args:args, :fun_args, :function_args
:query_arity:arity, :fun_arity, :function_arity
:query_doc:doc, :fun_doc, :function_doc
:typespec_spec_spec_args:spec_args
:typespec_spec_result::result, :spec_result, :fun_result, :function_result
:since

Examples

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

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

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

iex> {:ok, {forms, _}} = [
...>   query: [as: :fun_tre, arity: 3, to: ModuleA, since: "1.7.9"]
...> ] |> produce_codi
...> forms |> harnais_helper_format_forms!
["@doc \"Query 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, _} ->",
 "      true",
 "",
 "    _ ->",
 "      false",
 "  end",
 "end"]

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

iex> {:ok, {forms, _}} = [
...>   query: [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, _} ->",
 "      true", "",
 "    _ ->",
 "      false",
 "  end",
 "end"]

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

note the @spec result is always boolean and any given value will be ignored.

iex> {:ok, {forms, _}} = [
...>   query: [as: :fun_tre, args: [:x, :y, :z], module: ModuleA, result: true]
...> ] |> produce_codi
...> forms |> harnais_helper_format_forms!
["@doc \"Query function for `ModuleA.fun_tre/3`\"",
 "@spec fun_tre?(any, any, any) :: boolean",
 "def(fun_tre?(x, y, z)) do",
 "  case(ModuleA.fun_tre(x, y, z)) do",
 "    {:ok, _} ->",
 "      true",
 "",
 "    _ ->",
 "      false",
 "  end",
 "end"]

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

Pattern: query_module

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

Valid keys in the cpo are:

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

Examples

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

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

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

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