ex_structable v0.3.0 ExStructable View Source

The use-able module.

These methods are added to the module that has use ExStructable:

def new(args, override_opts \\ []) # ...
def put(struct = %_{}, args, override_opts \\ []) # ...

@docs are added to your module for the above methods. Run mix doc to see them.

Example usage:

iex> defmodule Line do
...>   @enforce_keys [:length, :x, :y]
...>   defstruct [:length, :x, :y]
...>
...>   use ExStructable # Adds `new` and `put` dynamically
...>
...>   # Optional hook
...>   @impl true
...>   def validate_struct(line, _options) do
...>     if line.length <= 0 do
...>       raise ArgumentError, "Invalid length found"
...>     end
...>
...>     line
...>   end
...> end
...>
...> Line.new(length: 1, x: 1, y: 2) |> inspect()
"%ExStructableTest.Line{length: 1, x: 1, y: 2}"

And new fails when validate_struct/2 fails:

...> Line.new(length: -2, x: 1, y: 2)
** (ArgumentError) Invalid length found

Here is an example of the put method usage:

...> Line.new(length: 1, x: 1, y: 2) |> Line.put(length: 3) |> inspect()
"%ExStructableTest.Line{length: 3, x: 1, y: 2}"

And put method validation failure:

...> Line.new(length: 1, x: 1, y: 2) |> Line.put(length: -3, x: 2)
** (ArgumentError) Invalid length found

Configuration

Options

The use macro has optional arguments. See __using__/1.

You can even pass these options to the new and put methods:

...> Line.new([length: -3, x: 1, y: 2], [validate_struct: false])
"%ExStructableTest.Line{length: -3, x: 1, y: 2}"

Hooks

For more optional hooks like validate_struct/2 (see ExStructable.Hooks).

ExConstructor Integration

You can use ExConstructor at the same time using use_ex_constructor_library: true:

iex> defmodule Line2 do
...>   defstruct [:length_in_cm, :x, :y]
...>
...>   use ExStructable, use_ex_constructor_library: true
...>
...>   @impl true
...>   def validate_struct(line, _options) do
...>     if line.length_in_cm <= 0 do
...>       raise ArgumentError, "Invalid length found"
...>     end
...>
...>     line
...>   end
...> end
...>
...> # We can now pass camelcase arguments
...> Line2.new(lengthInCm: 1, x: 1, y: 2) |> inspect()
"%ExStructableTest.Line2{length_in_cm: 1, x: 1, y: 2}"

And validation still fails as expected:

...> Line2.new(lengthInCm: -3, x: 1, y: 2) |> inspect()
** (ArgumentError) Invalid length found

(Do not put use ExConstructor as that is added to your module when the option use_ex_constructor_library is set to a truthy value).

If you want to pass args to ExConstructor:

use ExStructable, use_ex_constructor_library: [
  # args for `use ExConstructor` here
]

Link to this section Summary

Types

Key value pairs to put into the struct

Options passed to use ExStructable, new, and put

Usually is a struct, may not be if validate_struct/2 is overriden and returns something else

Functions

Add new and put functions to the caller’s module

The doctest below shows the default values of the of the possible use and override_opts, and their descriptions

Link to this section Types

Link to this type args() View Source
args() :: keyword() | %{required(atom() | String.t()) => any()}

Key value pairs to put into the struct.

Link to this type options() View Source
options() :: keyword()

Options passed to use ExStructable, new, and put.

Link to this type validation_result() View Source
validation_result() :: struct() | any()

Usually is a struct, may not be if validate_struct/2 is overriden and returns something else.

Link to this section Functions

Link to this macro __using__(options) View Source (macro)

Add new and put functions to the caller’s module.

The doctest below shows the default values of the of the possible use and override_opts, and their descriptions.

iex> default_options()
[
  # Call validate_struct callback?
  validate_struct: true,
  # Use library https://github.com/appcues/exconstructor .
  # Is a boolean or Keyword List of options to be passed to
  # `use ExConstructor`.
  use_ex_constructor_library: false,
  # The name of the `new` function to define in your module.
  new_function_name: :new,
  # The name of the `put` function to define in your module.
  put_function_name: :put,
  # Throw KeyError on passing unknown key, and
  # throw ArgumentError if a key from `@enforce_keys` is missing.
  strict_keys: true
]