View Source Vela behaviour (Vela v1.1.0)
Vela
is a tiny library providing easy management of
validated cached state with some history.
Including use Vela
in your module would turn the module
into struct, setting field accordingly to the specification,
passed as a parameter.
Vela
allows the following configurable parameters per field:
limit
— length of the series to keep (default:5
)compare_by
— comparator extraction function to extract the value, to be used for comparison, from the underlying terms (default:& &1
)comparator
— the function that accepts a series name and two values and returns the greater one to be used inVela.δ/1
(default:&</2
)threshold
— if specified, the inserted value is checked to fit inδ ± threshold
; whether it does not, it goes toerrors
(float() | nil
, default:nil
)validator
— the function to be used to invalidate the accumulated values (default:fn _ -> true end
)sorter
— the function to be used to sort values within one serie, if none is given, it sorts in the natural order, FIFO, newest is the one topop
corrector
— the function to be used to correct the values rejected byvalidator
; the function should return{:ok, corrected_value}
to enforce insertion intoVela
, or:error
if the value cannot be corrected and should be nevertheless rejectederrors
— number of errors to keep (default:5
)
Also, Vela accepts :__meta__
keyword parameter for the cases when the consumer needs
the very custom meta to be passed to the struct.
Vela
implements Access
behaviour.
Usage
defmodule Vela.Test do
use Vela,
series1: [limit: 3, errors: 1], # no validation
series2: [limit: 2, validator: Vela.Test]
series3: [
compare_by: &Vela.Test.comparator/1,
validator: &Vela.Test.validator/2
]
@behaviour Vela.Validator
@impl Vela.Validator
def valid?(_serie, value), do: value > 0
@spec comparator(%{created_at :: DateTime.t()}) :: DateTime.t()
def comparator(%{created_at: created_at}),
do: created_at
@spec validator(value :: t()) :: boolean()
def validator(value),
do: is_integer(value) and value > 300
end
In the example above, before any structure update attempt
(via Access
,) this valid?/2
function would be called.
If it returns true
, the value gets inserted / updated, and
the series behind is truncated if needed. It it returns false
,
the state is not updated, and the value is put into the map
under __errors__
key of the struct. The length of errors
is also configurable via errors:
keyword parameter.
Summary
Types
The type of comparator function to be passed as :comparator
keyword parameter
to the series.
The type of sorter function to be passed as :sorter
keyword parameter
to the series.
Configuration options used by the outmost world
Represents a key-value pair in errors and unmatched
Options allowed in series configuration
Series configuration
Represents a key in the Vela structure
The type of sorter function to be passed as :sorter
keyword parameter
to the series.
Represents the internal state aka per-vela property container
Represents the struct created by this behaviour module
The type of validator function to be passed as :validator
keyword parameter
to the series.
Represents a value in the Vela structure
Callbacks
Returns a keyword with series as keys and the average value as a value
Returns configuration needed to proceed with the interface Vela
exposes.
Returns {min, max}
tuple for each serie, using the comparator given as a second parameter,
or a default comparator for this serie.
Empties series in Vela
given as an input, meta stays untouched.
Checks if Vela
given as an input is empty
Checks two velas given as an input for equality
Merges two Vela
s, using resolver/3
given as the third argument in a case of ambiguity.
Removes obsoleted elements from the series using the validator given as a second parameter, or a default validator for this serie.
Returns a keyword with series as keys and the hottest value as a value
Functions
Empties the values for all series of Vela
given.
Returns true
if the Vela
is empty, false
otherwise.
Returns true
if velas given as arguments are of the same type and
series values equal for each serie.
Flat maps the series using fun
and returns the keyword with
duplicated keys and mapped values.
Maps the series using fun
and returns the new Vela
instance with series mapped
Merges two Vela
s given using resolver/3
function.
Inserts the new value into the serie, going through all the validation and sorting.
Slices the Vela
given as a first agrument, returning the keyword with series and topmost
value as a value.
Returns {min, max}
tuple for each serie, using the comparator given as a second parameter,
or a default comparator for each serie.
Types
The type of comparator function to be passed as :comparator
keyword parameter
to the series.
The type of sorter function to be passed as :sorter
keyword parameter
to the series.
@type exposed_option() ::
:sorter | :compare_by | :comparator | :corrector | :threshold | :validator
Configuration options used by the outmost world
Represents a key-value pair in errors and unmatched
@type option() :: {:limit, non_neg_integer()} | {:type, any()} | {:initial, [term()]} | {:compare_by, (value() -> any())} | {:comparator, comparator()} | {:threshold, number()} | {:validator, validator()} | {:sorter, sorter()} | {:corrector, corrector()} | {:errors, keyword()}
Options allowed in series configuration
@type options() :: [option()]
Series configuration
@type serie() :: atom()
Represents a key in the Vela structure
The type of sorter function to be passed as :sorter
keyword parameter
to the series.
@type state() :: Access.t()
Represents the internal state aka per-vela property container
@type t() :: %{ :__struct__ => atom(), :__errors__ => [kv()], :__meta__ => state(), optional(serie()) => [value()] }
Represents the struct created by this behaviour module
The type of validator function to be passed as :validator
keyword parameter
to the series.
@type value() :: any()
Represents a value in the Vela structure
Callbacks
Returns a keyword with series as keys and the average value as a value
Example:
iex> defmodule XY do
...> use Vela, x: [], y: []
...> end
...> XY.average(struct(XY, x: [1, 2, 3], y: [5, 7, 9]), &(Enum.sum(&1) / length(&1)))
[x: 2.0, y: 7.0]
...> defmodule Averager do
...> def average(values), do: Enum.sum(values) / length(values)
...> end
...> XY.average(struct(XY, x: [1, 2, 3], y: [5, 7, 9]), Averager)
[x: 2.0, y: 7.0]
@callback config(serie(), key :: exposed_option(), vela :: t()) :: option()
Returns configuration needed to proceed with the interface Vela
exposes.
Example:
iex> defmodule VC do
...> use Vela, a: [validator: VC], b: [], c: []
...> @behaviour Vela.Validator
...> @impl Vela.Validator
...> def valid?(:a, value), do: not is_nil(value)
...> end
...> VC.config(:a, :comparator, struct(VC, []))
@callback delta(vela :: t(), comparator :: nil | (serie(), value(), value() -> boolean())) :: [ {atom(), {value(), value()}} ]
Returns {min, max}
tuple for each serie, using the comparator given as a second parameter,
or a default comparator for this serie.
Empties series in Vela
given as an input, meta stays untouched.
Checks if Vela
given as an input is empty
Checks two velas given as an input for equality
Merges two Vela
s, using resolver/3
given as the third argument in a case of ambiguity.
Used by: Vela.merge/3
.
Removes obsoleted elements from the series using the validator given as a second parameter, or a default validator for this serie.
@callback series() :: [serie()]
Returns series defined by this Vela
as a list of atoms.
Example:
iex> defmodule V do
...> use Vela, a: [], b: [], c: []
...> end
...> V.series()
[:a, :b, :c]
Returns a keyword with series as keys and the hottest value as a value
Example:
iex> defmodule AB do
...> use Vela, a: [], b: [], c: []
...> end
...> AB.slice(struct(AB, [a: [1, 2], b: [3], c: []]))
[a: 1, b: 3]
Functions
Empties the values for all series of Vela
given.
Returns true
if the Vela
is empty, false
otherwise.
Returns true
if velas given as arguments are of the same type and
series values equal for each serie.
This function does not check internal state, only the values.
Flat maps the series using fun
and returns the keyword with
duplicated keys and mapped values.
Example:
defmodule EO do
use Vela,
even: [limit: 2],
odd: [limit: 2]
def flat_map(%EO{} = v),
do: Vela.flat_map(v, & {&1, &2+1})
end
EO.flat_map(struct(EO, [even: [2, 4], odd: [1, 3]]))
#⇒ [even: 3, even: 5, odd: 2, odd: 4]
@spec map( vela :: t(), (kv() -> value()) | (serie(), value() -> value()) | ({serie(), value()} -> {serie(), value()}) ) :: t()
Maps the series using fun
and returns the new Vela
instance with series mapped
Merges two Vela
s given using resolver/3
function.
This function does not allow merging states, the first argument wins. To update state,
use update_state/2
.
Inserts the new value into the serie, going through all the validation and sorting.
If the value has not passed validation, it’s put into :__errors__
internal list.
If the new length of the serie exceeds the limit set for this serie, the last value
(after sorting) gets discarded.
@spec slice( t(), :slice | {:average, ([value()] -> value()) | module()} | ({serie(), value()} -> value()) ) :: [{serie(), value()}]
Slices the Vela
given as a first agrument, returning the keyword with series and topmost
value as a value.
The second argument might be:
{:average, averager}
to return an averaged value, assumingVela.average/2
callback is defined,:slice
to return the sliced value in the list of values, assumingVela.slice/1
is defined,({serie, values} -> value)
function to perform slicing ad-hoc
Returns {min, max}
tuple for each serie, using the comparator given as a second parameter,
or a default comparator for each serie.