View Source Protean.Builder (Protean v0.1.0)
API for defining Protean machines.
This module is imported by default when use Protean
is spawned.
defining-a-machine
Defining a machine
At the outermost level, machines are specified as a keyword list, usually associated with the
@machine
module attribute of the defining module.
@machine [
states: [
# ...
]
]
For the most part, a machine definition is similar to a compound or parallel state definition,
except that it allows for an addition :assigns
option to specify the default assigns for the
machine context.
@machine [
assigns: %{
# ...
},
# ...
]
The top-level machine can be parallel by specifying type: :parallel
:
@machine [
type: :parallel,
states: [
# ...
]
]
See compound/2
and parallel/2
for corresponding options.
Link to this section Summary
Types
Additional state stored in the machine context.
Functions
Builds an atomic state.
Builds a compound state.
Builds a delayed transition.
Builds a final state.
Builds a pattern-matching event transition.
Builds a parallel state.
Specification for a spawned process linked to a parent state.
Specification for a spawned stream linked to a parent state.
Specification for a spawned task linked to a parent state.
Builds a transition.
Link to this section Types
@type action() :: Protean.Action.t() | term()
@type assigns() :: Enumerable.t()
Additional state stored in the machine context.
The specified assigns will be converted to a map/0
.
@type atomic_state_option() :: {:spawn, spawns()} | {:entry, actions()} | {:exit, actions()} | {:always, transitions()} | {:after, delayed_transitions()} | {:on, event_transitions()}
@type atomic_state_options() :: [atomic_state_option()]
@type compound_machine_option() :: {:assigns, assigns()} | compound_state_option()
@type compound_state_option() :: atomic_state_option() | {:initial, state_name()} | {:states, states()} | {:done, transitions()}
@type compound_state_options() :: [compound_state_option()]
@type delayed_transition() :: [delayed_transition_option()]
@type delayed_transition_option() :: transition_option() | {:delay, milliseconds :: non_neg_integer()}
@type delayed_transitions() :: [delayed_transition()]
@type event_transition() :: {matcher :: function() | term(), transition()}
@type event_transitions() :: [event_transition()]
@type final_state_options() :: [final_state_option()]
@type machine_options() :: [compound_machine_option()] | [parallel_machine_option()]
@type parallel_machine_option() :: {:type, :parallel} | {:assigns, assigns()} | parallel_machine_option()
@type parallel_state_option() :: atomic_state_option() | {:states, states()} | {:done, transitions()}
@type parallel_state_options() :: [parallel_state_option()]
@type spawn_option() :: {:id, String.t()} | {:done, transitions()} | {:error, transitions()} | {:autoforward, boolean()}
@type spawn_options() :: [spawn_option()]
@type state() :: {state_name(), keyword()}
@type states() :: [state()]
@type transition() :: [transition_option()]
@type transition_option() :: {:target, state_name()} | {:actions, actions()} | {:guard, Protean.Guard.t()}
@type transition_options() :: [transition_option()]
@type transitions() :: [transition()]
Link to this section Functions
@spec atomic(state_name(), atomic_state_options()) :: state()
Builds an atomic state.
Atomic states are simple states that cannot define children, but represent some intermediary state of the machine.
states: [
atomic(:loading,
# ...
)
]
options
Options
:spawn
- list of processes to spawn, seeproc/2
,task/2
,stream/2
;:entry
- actions to execute when entering this state;:exit
- actions to execute when exiting this state;:always
- transitions to immediately take when their guard is true, seetransition/1
;:after
- transitions to take after a given delay, seedelay/2
;:on
- transitions to take in response to an event, seematch/2
.
@spec compound(state_name(), compound_state_options()) :: state()
Builds a compound state.
Compound states have children defined by a :states
list, of which only one will be active at
a given time. They additional define an :initial
attribute specifying which child should
become active if we transition directly to the compound state.
states: [
compound(:parent,
initial: :child_a,
states: [
atomic(:child_a)
]
)
]
Compound states can define a :done
transition that will be taken if one of its final
children become active. In the example below, the :parent
state will transition to its
sibling if the final :child_b
state is entered.
states: [
compound(:parent,
initial: :child_a,
done: transition(target: :sibling),
states: [
atomic(:child_a,
# ...
),
final(:child_b)
]
)
]
options
Options
:initial
(required) - child state to enter when entering the compound state;:states
(required) - one or more child states;:done
- transition to take if afinal
child state is entered;- all options available to
atomic/2
.
@spec delay(milliseconds :: non_neg_integer() | term(), transition_options()) :: keyword()
Builds a delayed transition.
Delayed transitions run automatically after the given delay so long as the machine is still in the state that defined it and any given guard allows it.
Accepts the same options as transition/1
.
@spec final(state_name(), final_state_options()) :: state()
Builds a final state.
Final states are a variation of atomic states that represent some form of completion. Final
states cannot define transitions of their own, but entering a final state can trigger a
transition in a compound or parallel parent. See compound/2
and parallel/2
.
states: [
final(:completed)
]
options
Options
:entry
- actions to execute when entering this state;:exit
- actions to execute when exiting this state (as a result of a parent transition).
Builds a pattern-matching event transition.
Accepts the same options as transition/1
.
example
Example
on: [
match({:event_with_payload, _payload}, action: :save_payload),
match(%Events.OtherEvent{}, target: :other)
]
@spec parallel(state_name(), parallel_state_options()) :: state()
Builds a parallel state.
Parallel states have child states defined by a :states
list, all of which will be considered
active concurrently when the parallel state is active.
states: [
parallel(:parent,
states: [
atomic(:child_a,
entry: :child_a_action
),
atomic(:child_b,
entry: :child_b_action
)
]
)
]
In the example above, transitioning to :parent
would enter both child states and cause both
of their entry actions to execute.
Parallel states can define a :done
transition that will be taken when all of its children
are in a final state. Usually, this means the parallel state's children are compound states
with active final children.
states: [
parallel(:parent,
done: transition(target: :sibling),
states: [
compound(:compound_a,
states: [
atomic(:a_child1),
final(:a_child2)
]
),
compound(:compound_b,
states: [
atomic(:b_child1),
final(:b_child2)
]
)
]
)
]
In the example above, the parent parallel state will transition to its sibling once both compound states have active final children.
options
Options
:states
(required) - one or more child states, all of which will be concurrently entered when the parallel state becomes active;:done
- transition to take when all children are in a final state.- all options available to
atomic/2
.
@spec proc(term(), spawn_options()) :: keyword()
Specification for a spawned process linked to a parent state.
@spec stream(term(), spawn_options()) :: keyword()
Specification for a spawned stream linked to a parent state.
@spec task(term(), spawn_options()) :: keyword()
Specification for a spawned task linked to a parent state.
@spec transition(transition_options()) :: keyword()
Builds a transition.
options
Options
:target
- the target state of the transition;:actions
- one or more actions that should be executed when the transition occurs;:guard
- condition that must be true in order for the transition to occur.
guards
Guards
See Protean.Guard
TODO