plymio_vekil v0.1.0 Plymio.Vekil.Forom.List View Source

The module implements the Plymio.Vekil.Forom protocol and manages a list of other forom

See Plymio.Vekil.Forom for the definitions of the protocol functions.

See Plymio.Vekil for an explanation of the test environment.

Module State

See Plymio.Vekil.Forom for the common fields.

The default :produce_default is an empty list.

The default :realise_default is an empty list.

The module’s state is held in a struct with the following field(s):

FieldAliasesPurpose
:foromholds the list of child forom

Link to this section Summary

Functions

new/1 takes an optional opts and creates a new forom returning {:ok, forom}

new!/1 calls new/1 and, if the result is {:ok, instance} returns the instance

normalise/1 creates a new forom from its argument unless the argument is already one

produce/2 takes a forom and an optional opts

realise/2 takes a forom and an optional opts, calls produce/2, and then gets (Keyword.get_values/2) the :forom key values

update!/2 calls update/2 and, if the result is {:ok, instance} returns the instance

Link to this section Types

Link to this type t() View Source
t() :: %Plymio.Vekil.Forom.List{
  forom: term(),
  produce_default: term(),
  protocol_impl: term(),
  protocol_name: term(),
  realise_default: term()
}

Link to this section Functions

Link to this function new(opts \\ []) View Source
new(any()) :: {:ok, t()} | {:error, error()}

new/1 takes an optional opts and creates a new forom returning {:ok, forom}.

Examples

iex> {:ok, forom} = new()
...> match?(%FOROMLIST{}, forom)
true

Plymio.Vekil.Utility.forom?/1 returns true if the value implements Plymio.Vekil.Forom

iex> {:ok, forom} = new()
...> forom |> Plymio.Vekil.Utility.forom?
true

The list is passed using the :forom key:

iex> {:ok, forom1} = FOROMFORM.new(forom: quote(do: x = x + 1))
...> {:ok, forom} = new(forom: forom1)
...> forom |> Plymio.Vekil.Utility.forom?
true

iex> {:ok, forom} = new(
...>    forom: [
...>      FOROMTERM.new!(forom: 42),
...>      FOROMFORM.new!(forom: quote(do: x = x * x * x)),
...>      FOROMPROXY.new!(forom: :x_sub_1),
...> ])
...> forom |> Plymio.Vekil.Utility.forom?
true
Link to this function new!(opts \\ []) View Source
new!(any()) :: t() | no_return()

new!/1 calls new/1 and, if the result is {:ok, instance} returns the instance.

Link to this function normalise(value) View Source
normalise(any()) :: {:ok, struct()} | {:error, error()}

normalise/1 creates a new forom from its argument unless the argument is already one.

The function tries to make it as as convenient as possible to create a new forom, making some assumptions and may not return a list forom.

If the argument is a list, each element is treated as below and the created forom uses to create a list forom.

If an atom is found, a Plymio.Vekil.Forom.Proxy is created.

If the argument is a valid form (Macro.validate/1) a new Plymio.Vekil.Forom.Form is created.

Any other argument creates a Plymio.Vekil.Forom.Term.

Examples

Here a form is recognised:

iex> {:ok, %FOROMFORM{} = forom} = quote(do: x = x + 1) |> normalise
...> {:ok, {form, _}} = forom |> FOROMPROT.realise
...> form |> harnais_helper_test_forms!(binding: [x: 6])
{7, ["x = x + 1"]}

Here the argument is an atom and a proxy forom is created. Note a vekil is needed to resolve the proxy.

iex> {:ok, %FOROMPROXY{} = forom} = :x_mul_x |> normalise
...> realise_opts = [vekil: vekil_helper_form_vekil_example1()]
...> {:ok, {form, _}} = forom |> FOROMPROT.realise(realise_opts)
...> form |> harnais_helper_test_forms!(binding: [x: 3])
{9, ["x = x * x"]}

A list of atoms works. Note the returned forom is a list forom.

iex> {:ok, %FOROMLIST{} = forom} = [:x_add_1, :x_mul_x, :x_sub_1] |> normalise
...> realise_opts = [vekil: vekil_helper_form_vekil_example1()]
...> {:ok, {form, _}} = forom |> FOROMPROT.realise(realise_opts)
...> form |> harnais_helper_test_forms!(binding: [x: 7])
{63, ["x = x + 1", "x = x * x", "x = x - 1"]}

A mixture works:

iex> {:ok, %FOROMLIST{} = forom} = [
...>   42,
...>   quote(do: x = x * x * x),
...>   :x_sub_1
...> ] |> normalise
...> realise_opts = [vekil: vekil_helper_form_vekil_example1()]
...> {:ok, {values, _}} = forom |> FOROMPROT.realise(realise_opts)
...> values |> harnais_helper_show_forms
{:ok, ["42", "x = x * x * x", "x = x - 1"]}

The other examples don’t really highlight that the child forom of a list forom can themselves be list forom.

iex> {:ok, forom1} = [:x_sub_1, :x_add_1, :x_mul_x] |> normalise
...> {:ok, forom2} = [
...>    quote(do: x = x + 9),
...>    quote(do: x = x - 5),
...>    quote(do: x = x * x * x),
...> ] |> normalise
...> {:ok, forom3} = :x_funs |> normalise
...> {:ok, forom} = [forom1, forom2, forom3] |> normalise
...> realise_opts = [vekil: vekil_helper_form_vekil_example1()]
...> {:ok, {forms, _}} = forom |> FOROMPROT.realise(realise_opts)
...> forms |> harnais_helper_test_forms!(binding: [x: 3])
{4831203, ["x = x - 1", "x = x + 1", "x = x * x",
           "x = x + 9", "x = x - 5", "x = x * x * x",
           "x = x + 1", "x = x * x", "x = x - 1"]}

Anything else creates a term forom:

iex> {:ok, %FOROMTERM{} = forom} = %{a: 1} |> normalise
...> {:ok, {value, _}} = forom |> FOROMPROT.realise
...> value
%{a: 1}
Link to this function produce(forom, opts \\ []) View Source
produce(t(), opts()) :: {:ok, {product(), t()}} | {:error, error()}

produce/2 takes a forom and an optional opts.

It calls produce/2 on each of the forom’s children and merges their products into a single Keyword returning {:ok, {product, forom}}

Examples

Here the list contains integers:

iex> {:ok, forom} = new(
...>    forom: [
...>      FOROMTERM.new!(forom: 7),
...>      FOROMTERM.new!(forom: 33),
...>      FOROMTERM.new!(forom: 2),
...> ])
...> {:ok, {product, %FOROMLIST{}}} = forom |> FOROMPROT.produce
...> product |> Keyword.get_values(:forom) |> Enum.sum
42

Here the list contains code snippets:

iex> {:ok, forom} = [forom: [
...>    FOROMFORM.new!(forom: quote(do: x = x + 1)),
...>    FOROMFORM.new!(forom: quote(do: x = x * x)),
...>    FOROMFORM.new!(forom: quote(do: x = x - 1))
...> ]] |> FOROMLIST.new
...> {:ok, {product, _}} = forom |> FOROMPROT.produce
...> product |> Keyword.get_values(:forom)
...> |> harnais_helper_test_forms!(binding: [x: 3])
{15, ["x = x + 1", "x = x * x", "x = x - 1"]}

As an aside, and same example, normalise/1 helps reduce the boilerplace:

iex> {:ok, forom} = [
...>    quote(do: x = x + 1),
...>    quote(do: x = x * x),
...>    quote(do: x = x - 1)
...> ] |> normalise
...> {:ok, {product, _}} = forom |> FOROMPROT.produce
...> product |> Keyword.get_values(:forom)
...> |> harnais_helper_test_forms!(binding: [x: 3])
{15, ["x = x + 1", "x = x * x", "x = x - 1"]}

A similar example to the one above but the list contains proxy foroms which are recursively produced. Note the proxy foroms need a vekil to resolve the proxies.

iex> {:ok, forom} = [forom: [
...>    FOROMPROXY.new!(forom: :x_add_1),
...>    FOROMPROXY.new!(forom: :x_mul_x),
...>    FOROMPROXY.new!(forom: :x_sub_1)
...> ]] |> FOROMLIST.new
...> produce_opts = [vekil: vekil_helper_form_vekil_example1()]
...> {:ok, {product, _}} = forom |> FOROMPROT.produce(produce_opts)
...> product |> Keyword.get_values(:forom)
...> |> harnais_helper_test_forms!(binding: [x: 3])
{15, ["x = x + 1", "x = x * x", "x = x - 1"]}

An empty forom does not produce any :forom keys so the :produce_default value is returned. Here the default :produce_default is an empty list.

iex> {:ok, forom} = new()
...> {:ok, {product, _}} = forom |> FOROMPROT.produce
...> product |> Keyword.get_values(:forom)
[]

Same example but the :produce_default value is set:

iex> {:ok, forom} = new()
...> {:ok, {product, _}} = forom
...> |> FOROMPROT.produce(produce_default: [forom: 1, forom: :due, forom: "tre"])
...> product |> Keyword.get_values(:forom)
[1, :due, "tre"]
Link to this function realise(forom, opts \\ []) View Source
realise(t(), opts()) :: {:ok, {any(), t()}} | {:error, error()}

realise/2 takes a forom and an optional opts, calls produce/2, and then gets (Keyword.get_values/2) the :forom key values.

The example are essentially the same as produce/2

Examples

iex> {:ok, forom} = new(
...>    forom: [
...>      FOROMTERM.new!(forom: 7),
...>      FOROMTERM.new!(forom: 33),
...>      FOROMTERM.new!(forom: 2),
...> ])
...> {:ok, {values, %FOROMLIST{}}} = forom |> FOROMPROT.realise
...> values |> Enum.sum
42

iex> {:ok, forom} = [forom: [
...>    FOROMFORM.new!(forom: quote(do: x = x + 1)),
...>    FOROMFORM.new!(forom: quote(do: x = x * x)),
...>    FOROMFORM.new!(forom: quote(do: x = x - 1))
...> ]] |> FOROMLIST.new
...> {:ok, {forms, _}} = forom |> FOROMPROT.realise
...> forms |> harnais_helper_test_forms!(binding: [x: 3])
{15, ["x = x + 1", "x = x * x", "x = x - 1"]}

iex> {:ok, forom} = [forom: [
...>    FOROMPROXY.new!(forom: :x_add_1),
...>    FOROMPROXY.new!(forom: :x_mul_x),
...>    FOROMPROXY.new!(forom: :x_sub_1)
...> ]] |> FOROMLIST.new
...> realise_opts = [vekil: vekil_helper_form_vekil_example1()]
...> {:ok, {forms, _}} = forom |> FOROMPROT.realise(realise_opts)
...> forms |> harnais_helper_test_forms!(binding: [x: 3])
{15, ["x = x + 1", "x = x * x", "x = x - 1"]}

iex> {:ok, forom} = [:x_add_1, :x_mul_x, :x_sub_1] |> normalise
...> realise_opts = [vekil: vekil_helper_form_vekil_example1()]
...> {:ok, {forms, _}} = forom |> FOROMPROT.realise(realise_opts)
...> forms |> harnais_helper_test_forms!(binding: [x: 3])
{15, ["x = x + 1", "x = x * x", "x = x - 1"]}

iex> {:ok, forom} = new()
...> {:ok, {values, _forom}} = forom |> FOROMPROT.realise
...> values
[]
Link to this function update(t, opts \\ []) View Source
update(t(), opts()) :: {:ok, t()} | {:error, error()}

update/2 implements Plymio.Vekil.Forom.update/2.

Examples

iex> {:ok, forom} = new(forom: FOROMTERM.new!(forom: 7))
...> {:ok, forom} = forom |> FOROMPROT.update(
...>    forom: [FOROMTERM.new!(forom: 33), FOROMTERM.new!(forom: 2)])
...> {:ok, {values, %FOROMLIST{}}} = forom |> FOROMPROT.realise
...> values |> Enum.sum
35
Link to this function update!(t, opts \\ []) View Source
update!(t(), any()) :: t() | no_return()

update!/2 calls update/2 and, if the result is {:ok, instance} returns the instance.