RTypes v0.2.1 RTypes View Source

RTypes is an Elixir library which helps automatically create a validation function for a given user type. The function can be used to check the shape of the data after de-serialisation or in unit-tests.

Let's suppose we have a type

@type t :: 0..255

and we have a value x. To ensure that our value corresponds to the type t we can use the function

def t?(x) when is_integer(x) and x >= 0 and x <= 255, do: true
def t?(_), do: false

Now, if we have a compound type

@type list_of_ts :: [t]

and a value xs, we can use is_list/1 guard on xs and then ensure that all elements of the list conform to t. And if we have a more complex structure

@type state(a, b) :: %{key1: {a, b}, key2: list_of_ts()}

and a value s, we can check that s is a map which has keys key1 and key2, apply the logic above for the value of key2 and for any concrete types a and b we can check that he value of key1 is a tuple of length 2 and its elements conform to a and b respectively. So we just recursively apply those checks.

Usage

The library defines make_validator/1 and make_predicate/1 macros, and make_validator/3 and make_predicate/3 functions which can be used at run time. The difference between the two is that a validator returns :ok or {:error, reason} where reason explains what went wrong, while a predicate returns only true or false and is somewhat faster.

iex> require RTypes
iex> port_number? = RTypes.make_predicate(:inet.port_number())
iex> port_number?.(8080)
true
iex> port_number?.(80000)
false
iex> validate_is_kwlist = RTypes.make_validator(Keyword, :t, [{:type, 0, :pos_integer, []}])
iex> validate_is_kwlist.(key1: 4, key2: 5)
:ok
iex> match?({:error, _reason}, validate_is_kwlist.([1, 2, 3]))
true

Link to this section Summary

Types

t:error_decription/1 is a keyword list which details the validation error.

Functions

derive(code) deprecated
derive!(code) deprecated

Derive a predicate for the given type expression.

Return a predicate given a module name, type name, and type parameters.

Derive a validtation function for the given type expression.

Derive a validation function given a module name, type name, and type parameters.

Link to this section Types

Link to this type

error_description() View Source
error_description() :: [
  message: String.t(),
  term: term(),
  ctx: [term()],
  types: [RType.Extractor.unfolded_type()]
]

t:error_decription/1 is a keyword list which details the validation error.

Link to this section Functions

This macro is deprecated. use make_predicate/1 instead.
Link to this function

derive(mod, type_name, type_args) View Source

This function is deprecated. use make_predicate/3 instead.
This macro is deprecated. use make_validator/1 instead.
Link to this function

derive!(mod, type_name, type_args) View Source

This function is deprecated. use make_validator/3 instead.
Link to this function

format_error_description(desc) View Source
format_error_description(error_description()) :: String.t()

Link to this macro

make_predicate(code) View Source (macro)

Derive a predicate for the given type expression.

iex> require RTypes
iex> non_neg_integer? = RTypes.make_predicate(non_neg_integer())
iex> non_neg_integer?.(10)
true
iex> non_neg_integer?.(0)
true
iex> non_neg_integer?.(-3)
false
iex> non_neg_integer?.(:ok)
false
Link to this function

make_predicate(mod, type_name, type_args) View Source
make_predicate(module(), atom(), [RTypes.Extractor.type()]) ::
  (any() -> boolean())

Return a predicate given a module name, type name, and type parameters.

The predicate behaves the same way as the one produced by make_predicate/1 macro.

Link to this macro

make_validator(code) View Source (macro)

Derive a validtation function for the given type expression.

Usage

iex> require RTypes
iex> validate_port_number = RTypes.make_validator(:inet.port_number())
iex> validate_port_number.(8080)
:ok
iex> match?({:error, _}, validate_port_number.(70000))
true

iex> validate_kw_list = RTypes.make_validator(Keyword.t(pos_integer()))
iex> validate_kw_list.([a: 1, b: 2])
:ok

Note that the macro expects its argument provided as in

MyModule.my_type(arg1, arg2)

The returned function either returns :ok or {:error, reason} where reason details what went wrong.

Link to this function

make_validator(mod, type_name, type_args) View Source
make_validator(module(), atom(), [RTypes.Extractor.type()]) ::
  (term() -> :ok | {:error, error_description()})

Derive a validation function given a module name, type name, and type parameters.

Type parameters must be of some concrete type.

Example

iex> validate_kw_list = RTypes.make_validator(Keyword, :t, [{:type, 0, :pos_integer, []}])
iex> validate_kw_list.(key1: 4, key2: 5)
:ok

The function returns either :ok or {:error, error_description} where error_description details what went wrong.