plymio_vekil v0.1.0 Plymio.Vekil.Term View Source

This module implements the Plymio.Vekil protocol using a Map where the proxies (keys) are atoms and the foroms (values) hold any valid term.

The default when creating a term vekil is to create a Plymio.Vekil.Forom.Term forom but any vekil can hold any forom.

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

Module State

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

FieldAliasesPurpose
:dict:dhold the map of proxies v forom
:forom_normalisesee Plymio.Vekil.Form field description
:proxy_normalisesee Plymio.Vekil.Form field description

See Plymio.Vekil.Form for an explanation of :forom_normalise and :proxy_normalise.

Test Environent

See also notes in Plymio.Vekil.

The vekil created in the example below of new/1 is returned by vekil_helper_term_vekil_example1/0.

iex> {:ok, vekil} = new()
...> dict = [
...>    x_add_1: quote(do: x = x + 1),
...>    x_mult_x: quote(do: x = x * x),
...>    x_sub_1: quote(do: x = x - 1),
...>    value_42: 42,
...>    value_x_add_1: :x_add_1,
...>    proxy_x_add_1: [forom: :x_add_1] |> Plymio.Vekil.Forom.Proxy.new!
...> ]
...> {:ok, vekil} = vekil |> update(dict: dict)
...> match?(%VEKILTERM{}, vekil)
true

Link to this section Summary

Link to this section Types

Link to this section Functions

Link to this function forom_normalise(vekil, value \\ []) View Source
forom_normalise(any(), any()) :: {:ok, {forom(), t()}} | {:error, error()}

See Plymio.Vekil.forom_normalise/2

The default action is to create a term forom (Plymio.Vekil.Forom.Term).

Examples

Here the value being normalised is a keyword:

iex> %VEKILTERM{} = vekil = vekil_helper_term_vekil_example1()
...> value = [a: 1, b: 2, c: 3]
...> {:ok, {forom, %VEKILTERM{}}} = vekil |> VEKILPROT.forom_normalise(value)
...> {:ok, {value, _}} = forom |> FOROMPROT.realise
...> value
[a: 1, b: 2, c: 3]

An atom is normalise to a term forom, not a proxy forom:

iex> %VEKILTERM{} = vekil = vekil_helper_term_vekil_example1()
...> value = :x_add_1
...> {:ok, {forom, %VEKILTERM{}}} = vekil |> VEKILPROT.forom_normalise(value)
...> {:ok, {value, _}} = forom |> FOROMPROT.realise
...> value
:x_add_1

An existing forom is returned unchanged.

iex> %VEKILTERM{} = vekil = vekil_helper_term_vekil_example1()
...> {:ok, %Plymio.Vekil.Forom.Form{} = forom} = quote(do: x = x + 1)
...>   |> Plymio.Vekil.Forom.Form.normalise
...> {:ok, {forom, %VEKILTERM{}}} = vekil |> VEKILPROT.forom_normalise(forom)
...> {:ok, {forms, _}} = forom |> FOROMPROT.realise
...> forms |> harnais_helper_test_forms!(binding: [x: 2])
{3, ["x = x + 1"]}
Link to this function has_proxy?(vekil, proxy) View Source
has_proxy?(t(), any()) :: boolean()

See Plymio.Vekil.has_proxy?/2

Note: the proxy is not normalised in any way.

Examples

Here a known proxy is tested for:

iex> vekil_helper_term_vekil_example1()
...> |> VEKILPROT.has_proxy?(:x_sub_1)
true

An unknown proxy returns false

iex> vekil_helper_term_vekil_example1()
...> |> VEKILPROT.has_proxy?(:not_a_proxy)
false

iex> vekil_helper_term_vekil_example1()
...> |> VEKILPROT.has_proxy?(%{a: 1})
false
Link to this function new(opts \\ []) View Source
new(any()) :: {:ok, t()} | {:error, error()}

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

Examples

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

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

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

The vekil dictionary can be supplied as a Map or Keyword. It will be validated to ensure all the proxies are atoms and all the forom are valid forms.

A term vekil does not recognise / normalise atom values (e.g. the :x_add_1 value for :value_x_add_1 below) as a proxy; it is just a term. When a proxy is wanted, it must be given explicitly (see entry for proxy_x_add_1). See also the fetch examples.

iex> {:ok, vekil} = [dict: [
...>    x_add_1: [forom: quote(do: x = x + 1)] |> FOROMFORM.new!,
...>    x_mul_x: [forom: quote(do: x = x * x)] |> FOROMFORM.new!,
...>    x_sub_1: [forom: quote(do: x = x - 1)] |> FOROMFORM.new!,
...>    value_42: 42,
...>    value_x_add_1: :x_add_1,
...>    proxy_x_add_1: [forom: :x_add_1] |> Plymio.Vekil.Forom.Proxy.new!
...> ]] |> new()
...> match?(%VEKILTERM{}, vekil)
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 proxy_delete(vekil, proxies) View Source
proxy_delete(t(), any()) :: {:ok, t()} | {:error, error()}

See Plymio.Vekil.proxy_delete/2

Note proxies are normalised.

Examples

Here a known proxy is deleted and then fetched, causing an error:

iex> {:ok, %VEKILTERM{} = vekil} = vekil_helper_term_vekil_example1()
...> |> VEKILPROT.proxy_delete(:x_sub_1)
...> {:error, error} = vekil |> VEKILPROT.proxy_fetch([:x_add_1, :x_sub_1])
...> error |> Exception.message
"proxy invalid, got: :x_sub_1"

This example deletes :x_mul_x and but provides quote(do: x = x * x * x) as the default in the following get:

iex> {:ok, %VEKILTERM{} = vekil} = vekil_helper_term_vekil_example1()
...> |> VEKILPROT.proxy_delete(:x_mul_x)
...> {:ok, {forom, %VEKILTERM{}}} = vekil
...> |> VEKILPROT.proxy_get([:x_add_1, :x_mul_x, :x_sub_1], quote(do: x = x * x * x))
...> {:ok, {forms, _}} = forom |> FOROMPROT.realise
...> forms |> harnais_helper_test_forms!(binding: [x: 7])
{511, ["x = x + 1", "x = x * x * x", "x = x - 1"]}

Deleting unknown proxies does not cause an error:

iex> {:ok, %VEKILTERM{} = vekil} = vekil_helper_term_vekil_example1()
...> |> VEKILPROT.proxy_delete([:x_sub_1, :not_a_proxy, :x_mul_x])
...> vekil |> Plymio.Vekil.Utility.vekil?
true
Link to this function proxy_fetch(vekil, proxies) View Source
proxy_fetch(t(), any()) :: {:ok, {product(), t()}} | {:error, error()}

See Plymio.Vekil.proxy_fetch/2.

Examples

A single proxy is requested:

iex> {:ok, {forom, %VEKILTERM{}}} = vekil_helper_term_vekil_example1()
...> |> VEKILPROT.proxy_fetch(:value_42)
...> {:ok, {value, _}} = forom |> FOROMPROT.realise
...> value
42

Two proxies are requested:

iex> {:ok, {forom, %VEKILTERM{}}} = vekil_helper_term_vekil_example1()
...> |> VEKILPROT.proxy_fetch([:value_42, :value_x_add_1])
...> {:ok, {values, _}} = forom |> FOROMPROT.realise
...> values
[42, :x_add_1]

In the example vekil the proxy :value_x_add_ is a term forom holding a simple atom (:x_add_):

iex> {:ok, {forom, %VEKILTERM{}}} = vekil_helper_term_vekil_example1()
...> |> VEKILPROT.proxy_fetch(:value_x_add_1)
...> {:ok, {value, _}} = forom |> FOROMPROT.realise
...> value
:x_add_1

But the proxy :proxy_x_add_1 does hold a proxy forom pointing to the :x_add_1 proxy:

iex> {:ok, {forom, %VEKILTERM{}}} = vekil_helper_term_vekil_example1()
...> |> VEKILPROT.proxy_get(:proxy_x_add_1)
...> {:ok, {form, _}} = forom |> FOROMPROT.realise
...> form |> harnais_helper_test_forms!(binding: [x: 7])
{8, ["x = x + 1"]}

proxies is nil / empty. Note the use and override of the :realise_default field:

iex> {:ok, {forom, %VEKILTERM{}}} = vekil_helper_term_vekil_example1()
...> |> VEKILPROT.proxy_fetch(nil)
...> {:ok, {value, _}} = forom |> FOROMPROT.realise
...> value |> Plymio.Fontais.Guard.is_value_unset
true

iex> {:ok, {forom, %VEKILTERM{}}} = vekil_helper_term_vekil_example1()
...> |> VEKILPROT.proxy_fetch([])
...> {:ok, {value, _}} = forom |> FOROMPROT.realise(realise_default: nil)
...> value
nil

One or more proxies not found

iex> {:error, error} = vekil_helper_term_vekil_example1()
...> |> VEKILPROT.proxy_fetch(:not_a_proxy)
...> error |> Exception.message
"proxy invalid, got: :not_a_proxy"

iex> {:error, error} = vekil_helper_term_vekil_example1()
...> |> VEKILPROT.proxy_fetch([:missing_proxy, :x_sub_1, :not_a_proxy])
...> error |> Exception.message
"proxies invalid, got: [:missing_proxy, :not_a_proxy]"
Link to this function proxy_get(vekil, proxies) View Source
proxy_get(t(), proxies()) :: {:ok, {product(), t()}} | {:error, error()}

See Plymio.Vekil.proxy_get/2

Examples

A single known, proxy is requested with no default

iex> {:ok, {forom, %VEKILTERM{}}} = vekil_helper_term_vekil_example1()
...> |> VEKILPROT.proxy_get(:value_42)
...> {:ok, {value, _}} = forom |> FOROMPROT.realise
...> value
42

Two known proxies are requested:

iex> {:ok, {forom, %VEKILTERM{}}} = vekil_helper_term_vekil_example1()
...> |> VEKILPROT.proxy_get([:value_42, :value_x_add_1])
...> {:ok, {values, _}} = forom |> FOROMPROT.realise
...> values
[42, :x_add_1]

A single unknown, proxy is requested with no default. The the :realise_default has been overridden.

iex> {:ok, {forom, %VEKILTERM{}}} = vekil_helper_term_vekil_example1()
...> |> VEKILPROT.proxy_get(:not_a_proxy)
...> {:ok, {value, _}} = forom
...> |> FOROMPROT.realise(realise_default: :proxy_not_found)
...> value
:proxy_not_found
Link to this function proxy_get(vekil, proxies, default) View Source
proxy_get(t(), any(), any()) ::
  {:ok, {product(), t()}} | {:error, error()}

See Plymio.Vekil.proxy_get/3

Examples

A single unknown proxy is requested with a default:

iex> {:ok, {forom, %VEKILTERM{}}} = vekil_helper_term_vekil_example1()
...> |> VEKILPROT.proxy_get(:value_42, 123)
...> {:ok, {value, _}} = forom |> FOROMPROT.realise
...> value
42

A mix of known and unknown proxies, together with a default:

iex> {:ok, {forom, %VEKILTERM{}}} = vekil_helper_term_vekil_example1()
...> |> VEKILPROT.proxy_get([:missing_proxy, :value_42, :not_a_proxy], 123)
...> {:ok, {values, _}} = forom |> FOROMPROT.realise
...> values
[123, 42, 123]
Link to this function proxy_put(vekil, tuples) View Source
proxy_put(t(), any()) :: {:ok, t()} | {:error, error()}

See Plymio.Vekil.proxy_put/2

Examples

A list of {proxy,value} tuples can be given. Since a form vekil’s proxy is an atom, Keyword syntax can be used:

iex> {:ok, %VEKILTERM{} = vekil} = VEKILTERM.new()
...> {:ok, %VEKILTERM{} = vekil} = vekil |> VEKILPROT.proxy_put(
...>    one: 1, due: :two, tre: "three")
...> {:ok, {forom, %VEKILTERM{}}} = vekil |> VEKILPROT.proxy_fetch(:tre)
...> {:ok, {value, _}} = forom |> FOROMPROT.realise
...> value
"three"
Link to this function proxy_put(vekil, proxy, forom) View Source
proxy_put(t(), any(), any()) :: {:ok, t()} | {:error, error()}

See Plymio.Vekil.proxy_put/3

Examples

This example puts a proxy into an empty vekil and then fetches it.

iex> {:ok, %VEKILTERM{} = vekil} = VEKILTERM.new()
...> {:ok, %VEKILTERM{} = vekil} = vekil
...>    |> VEKILPROT.proxy_put(:z, %{a: 1})
...> {:ok, {forom, %VEKILTERM{}}} = vekil |> VEKILPROT.proxy_fetch(:z)
...> {:ok, {value, _}} = forom |> FOROMPROT.realise
...> value
%{a: 1}
Link to this function update(t, opts \\ []) View Source
update(t(), opts()) :: {:ok, t()} | {:error, error()}

update/2 takes a vekil and opts and update the field(s) in the vekil from the {field,value} tuples in the opts.

Examples

iex> {:ok, vekil} = new()
...> dict = [
...>    an_integer: 42,
...>    an_atom: :nothing_special,
...>    a_string: "Hello World!",
...> ]
...> {:ok, vekil} = vekil |> update(dict: dict)
...> match?(%VEKILTERM{}, vekil)
true
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.