View Source Finitomata.Transition (Finitomata v0.25.0)

The internal representation of Transition.

It includes from and to states, and the event, all represented as atoms.

Summary

Types

The event in FSM

The kind of event

The state of FSM

t()

The transition is represented by from and to states and the event.

Functions

Returns the list of all the transitions, matching the options.

Returns the list of all the transitions, matching the from state and the event.

Returns true if the transition fromto is allowed, false otherwise.

Returns keyword list of {Finitomata.Transition.state(), [Finitomata.Transition.event()]} for transitions which do not have a determined to state.

Returns the continuation from the state given which inevitably lead to other state(s).

Returns keyword list of {Finitomata.Transition.state(), Finitomata.Transition.event()} tuples for determined transition from the current state.

Returns {:ok, {event(), state()}} tuple if there is a determined transition from the current state, :error otherwise.

Returns the state after starting one, so-called entry state.

Returns the kind of event.

Returns the not ordered list of events, including or excluding the internal starting and ending transitions :__start__ and __end__ according to the second argument.

Returns the states before ending one, so-called exit states.

Returns all the states which inevitably lead to the ending one.

Returns all the hard transitions which inevitably lead to the next state (events ending with an exclamation sign,) which makes the FSM to go to the next state with :continue callback.

Returns all the loops aka internal paths where starting and ending states are the same one.

Returns all the paths from starting to ending state.

Returns true if the state from hsa an outgoing transition with event, false otherwise.

Returns the not ordered list of states, including or excluding the starting and ending states :* according to the second argument.

Types

@type event() :: atom()

The event in FSM

@type event_kind() :: :soft | :hard | :normal

The kind of event

@type state() :: atom()

The state of FSM

@type t() :: %Finitomata.Transition{
  from: state(),
  to: state() | [state()],
  event: event()
}

The transition is represented by from and to states and the event.

Functions

Link to this function

allowed(transitions, options \\ [])

View Source
@spec allowed([t()],
  from: state(),
  to: state(),
  with: event(),
  as: :states | :transitions
) :: [
  {state(), state(), event()}
]

Returns the list of all the transitions, matching the options.

Used internally for the validations.

iex> {:ok, transitions} =
...>   Finitomata.Mermaid.parse(
...>     "idle --> |to_s1| s1\n" <>
...>     "s1 --> |to_s2| s2\n" <>
...>     "s1 --> |to_s3| s3\n" <>
...>     "s2 --> |to_s3| s3")
...> Finitomata.Transition.allowed(transitions, to: [:idle, :*])
[{:*, :idle, :__start__}, {:s3, :*, :__end__}]
iex> Finitomata.Transition.allowed(transitions, from: :s1)
[{:s1, :s2, :to_s2}, {:s1, :s3, :to_s3}]
iex> Finitomata.Transition.allowed(transitions, from: :s1, to: :s3)
[{:s1, :s3, :to_s3}]
iex> Finitomata.Transition.allowed(transitions, from: :s1, with: :to_s3)
[{:s1, :s3, :to_s3}]
iex> Finitomata.Transition.allowed(transitions, from: :s2, with: :to_s2)
[]
Link to this function

allowed(transitions, from, event)

View Source
@spec allowed([t()], state(), event()) :: [state()]

Returns the list of all the transitions, matching the from state and the event.

Used internally for the validations.

iex> {:ok, transitions} =
...>   Finitomata.PlantUML.parse("[*] --> s1 : foo\ns1 --> s2 : ok\ns2 --> [*] : ko")
...> Finitomata.Transition.allowed(transitions, :s1, :foo)
[:s2]
...> Finitomata.Transition.allowed(transitions, :s1, :*)
[]
Link to this function

allowed?(transitions, from, to)

View Source
@spec allowed?([t()], state(), state()) :: boolean()

Returns true if the transition fromto is allowed, false otherwise.

iex> {:ok, transitions} =
...>   Finitomata.PlantUML.parse("[*] --> s1 : foo\ns1 --> s2 : ok\ns2 --> [*] : ko")
...> Finitomata.Transition.allowed?(transitions, :s1, :s2)
true
...> Finitomata.Transition.allowed?(transitions, :s1, :*)
false
@spec ambiguous([t()]) :: [{state(), {event(), state()}}]

Returns keyword list of {Finitomata.Transition.state(), [Finitomata.Transition.event()]} for transitions which do not have a determined to state.

Used internally for the validations.

iex> {:ok, transitions} =
...>   Finitomata.Mermaid.parse(
...>     "idle --> |to_s1| s1\n" <>
...>     "s1 --> |to_s2| s2\n" <>
...>     "s1 --> |to_s3| s3\n" <>
...>     "s2 --> |to_s1| s3\n" <>
...>     "s2 --> |ambiguous| s3\n" <>
...>     "s2 --> |ambiguous| s4\n" <>
...>     "s3 --> |determined| s3\n" <>
...>     "s3 --> |determined| s4\n")
...> Finitomata.Transition.ambiguous(transitions)
[s3: {:determined, [:s3, :s4]}, s2: {:ambiguous, [:s3, :s4]}]
Link to this function

continuation(states \\ :states, from, transitions)

View Source
@spec continuation(:states | :transitions, state(), [t()]) ::
  nil | [Finitomata.Transition.Path.t()] | [t()]

Returns the continuation from the state given which inevitably lead to other state(s).

All the transitions from this state are hard (ending with !,) which makes the FSM to go through all these states in :continue callbacks.

iex> {:ok, transitions} =
...>   Finitomata.PlantUML.parse("[*] --> entry : start\nentry --> exit : go!\nexit --> done : finish\ndone --> [*] : terminate")
...> Finitomata.Transition.continuation(:entry, Finitomata.Transition.hard(:transitions, transitions))
[%Finitomata.Transition.Path{from: :entry, to: :exit, path: [go!: :exit]}]
@spec determined([t()]) :: [{state(), {event(), state()}}]

Returns keyword list of {Finitomata.Transition.state(), Finitomata.Transition.event()} tuples for determined transition from the current state.

The transition is determined, if it is the only transition allowed from the state.

Used internally for the validations.

iex> {:ok, transitions} =
...>   Finitomata.Mermaid.parse(
...>     "idle --> |to_s1| s1\n" <>
...>     "s1 --> |to_s2| s2\n" <>
...>     "s1 --> |to_s3| s3\n" <>
...>     "s2 --> |to_s1| s3\n" <>
...>     "s2 --> |ambiguous| s3\n" <>
...>     "s2 --> |ambiguous| s4\n" <>
...>     "s3 --> |determined| s3\n" <>
...>     "s3 --> |determined| s4\n")
...> Finitomata.Transition.determined(transitions)
[s4: :__end__, s3: :determined, idle: :to_s1]
Link to this function

determined(transitions, state)

View Source
@spec determined([t()], state()) :: {:ok, {event(), state()}} | :error

Returns {:ok, {event(), state()}} tuple if there is a determined transition from the current state, :error otherwise.

The transition is determined, if it is the only transition allowed from the state.

Used internally for the validations.

iex> {:ok, transitions} =
...>   Finitomata.Mermaid.parse(
...>     "idle --> |to_s1| s1\n" <>
...>     "s1 --> |to_s2| s2\n" <>
...>     "s1 --> |to_s3| s3\n" <>
...>     "s2 --> |to_s3| s3")
...> Finitomata.Transition.determined(transitions, :s1)
:error
iex> Finitomata.Transition.determined(transitions, :s2)
{:ok, {:to_s3, :s3}}
iex> Finitomata.Transition.determined(transitions, :s3)
{:ok, {:__end__, :*}}
Link to this function

entry(what \\ :state, transitions)

View Source
@spec entry(:state | :transition, [t()]) :: state()

Returns the state after starting one, so-called entry state.

iex> {:ok, transitions} =
...>   Finitomata.PlantUML.parse("[*] --> entry : foo\nentry --> exit : go\nexit --> [*] : terminate")
...> Finitomata.Transition.entry(transitions)
:entry
@spec event_kind(event() | t()) :: event_kind()

Returns the kind of event.

If event ends up with an exclamation sign, it’s :hard, meaning the respective transition would be initiated automatically when the from state of such a transition is reached.

If event ends up with a question mark, it’s :soft, meaning no error would have been reported in a case transition fails.

Otherwise the event is :normal.

iex> {:ok, [_, hard, _]} =
...>   Finitomata.PlantUML.parse("[*] --> entry : foo\nentry --> exit : go!\nexit --> [*] : terminate")
...> Finitomata.Transition.event_kind(hard)
:hard
Link to this function

events(transitions, purge_internal \\ false)

View Source
@spec events([t()], boolean()) :: [state()]

Returns the not ordered list of events, including or excluding the internal starting and ending transitions :__start__ and __end__ according to the second argument.

iex> {:ok, transitions} =
...>   Finitomata.Mermaid.parse("s1 --> |ok| s2\ns1 --> |ko| s3")
...> Finitomata.Transition.events(transitions, true)
[:ok, :ko]
...> Finitomata.Transition.events(transitions)
[:__start__, :ok, :ko, :__end__]
Link to this function

exit(what \\ :states, transitions)

View Source
@spec exit(:states | :transitions, [t()]) :: [state()]

Returns the states before ending one, so-called exit states.

iex> {:ok, transitions} =
...>   Finitomata.Mermaid.parse(
...>     "entry --> |process| processing\nprocessing --> |ok| success\nprocessing --> |ko| error"
...>   )
...> Finitomata.Transition.exit(transitions)
[:error, :success]
Link to this function

exiting(what \\ :states, transitions)

View Source
@spec exiting(:states | :transitions, [t()]) ::
  Enumerable.t([t()]) | [Finitomata.Transition.Path.t()]

Returns all the states which inevitably lead to the ending one.

All the transitions from these states to the ending one are hard (ending with !,) which makes the FSM to go through all these states in :continue callbacks.

iex> {:ok, transitions} =
...>   Finitomata.PlantUML.parse("[*] --> entry : start\nentry --> exit : go!\nexit --> [*] : terminate")
...> Finitomata.Transition.exiting(transitions)
[%Finitomata.Transition.Path{from: :entry, to: :*, path: [go!: :exit, terminate: :*]}]
Link to this function

hard(states \\ :states, transitions)

View Source
@spec hard(:states | :transitions, [t()]) ::
  Enumerable.t(t()) | [Finitomata.Transition.Path.t()]

Returns all the hard transitions which inevitably lead to the next state (events ending with an exclamation sign,) which makes the FSM to go to the next state with :continue callback.

iex> {:ok, transitions} =
...>   Finitomata.PlantUML.parse("[*] --> entry : start\nentry --> exit : go!\nexit --> [*] : terminate")
...> Finitomata.Transition.hard(transitions)
[entry: :go!]
...> Finitomata.Transition.hard(:transitions, transitions)
[%Finitomata.Transition{from: :entry, to: :exit, event: :go!}]
Link to this function

loops(what \\ :states, transitions)

View Source
@spec loops(:states | :transitions, [t()]) ::
  Enumerable.t(t()) | [Finitomata.Transition.Path.t()]

Returns all the loops aka internal paths where starting and ending states are the same one.

iex> {:ok, transitions} =
...>   Finitomata.PlantUML.parse("[*] --> s1 : foo\ns1 --> s2 : ok\ns2 --> s1 : ok\ns2 --> [*] : ko")
...> Finitomata.Transition.loops(transitions)
[%Finitomata.Transition.Path{from: :s1, to: :s1, path: [ok: :s2, ok: :s1]},
 %Finitomata.Transition.Path{from: :s2, to: :s2, path: [ok: :s1, ok: :s2]}]
Link to this function

paths(what \\ :states, transitions, from \\ :*, to \\ :*)

View Source
@spec paths(:states | :transitions, [t()], state(), state()) ::
  Enumerable.t(t()) | [Finitomata.Transition.Path.t()]

Returns all the paths from starting to ending state.

iex> {:ok, transitions} =
...>   Finitomata.PlantUML.parse("[*] --> s1 : foo\ns1 --> s2 : ok\ns1 --> s3 : ok\ns2 --> [*] : ko\ns3 --> [*] : ko")
...> Finitomata.Transition.paths(transitions)
[%Finitomata.Transition.Path{from: :*, to: :*, path: [foo: :s1, ok: :s2, ko: :*]},
 %Finitomata.Transition.Path{from: :*, to: :*, path: [foo: :s1, ok: :s3, ko: :*]}]
Link to this function

responds?(transitions, from, event)

View Source
@spec responds?([t()], state(), event()) :: boolean()

Returns true if the state from hsa an outgoing transition with event, false otherwise.

iex> {:ok, transitions} =
...>   Finitomata.PlantUML.parse("[*] --> s1 : foo\ns1 --> s2 : ok\ns2 --> [*] : ko")
...> Finitomata.Transition.responds?(transitions, :s1, :ok)
true
...> Finitomata.Transition.responds?(transitions, :s1, :ko)
false
Link to this function

states(transitions, purge_internal \\ false)

View Source
@spec states([t()], boolean()) :: [state()]

Returns the not ordered list of states, including or excluding the starting and ending states :* according to the second argument.

iex> {:ok, transitions} =
...>   Finitomata.PlantUML.parse("[*] --> s1 : foo\ns1 --> s2 : ok\ns2 --> [*] : ko")
...> Finitomata.Transition.states(transitions, true)
[:s1, :s2]
...> Finitomata.Transition.states(transitions)
[:*, :s1, :s2]