Often in Statemachines, duplication can arise. For example, the vending machine in our examples may need periodic repairs. It’s not certain which state the vending machine will be in when the repair man arrives. So all states should have a transition into the Repair Mode state.
Superstates

In this diagram, both the Waiting
and Paid
states
have a transition to the Repair Mode invoked by the repair
event. Duplication! We can dry this up by using the Superstate
construct. See below:

Here we introduce the Operational superstate. Both the
Waiting
and Paid
states are contained within
the superstate which implies that they inherit all of the superstate’s
transitions.
That means we only need one transition into the Repair
Mode
state from the Operational
superstate to
achieve the same behavior as the solution in diagram 1.
One Statemachine may have multiple superstates. And every superstate may contain other superstates. That is, superstates can be nested.
History State
The solution in diagram 2 has an advantage over diagram
1. In diagram 11, once the repair man is done he
triggers the operate event and the vending machine transitions into the
Waiting
event. This is unfortunate.
Even if the vending machine was in the Paid
state before
the repair man came along, it will be in the Waiting
state
after he leaves. Shouldn’t it go back into the Paid
state?
Superstates come with the history state
which solves this
problem. Every superstate will remember which state it is in before the
superstate is exited. This memory is stored in a pseudo state called
the history state
.
Transitions that end in the history state will recall the last active state of the superstate and enter it.
You can see the history state being use in diagram 2. In this solution, the history state allows the vending machine to return from a repair session into the same state it was in before, as though nothing happened at all.
Code
The following code builds the Statemachine in diagram 2. Watch out for
the _H
. This is how the history state is denoted. If you
have a superstate named foo
, then it’s history state will
be named foo_H
.
1 require 'rubygems'
2 require 'statemachine'
3
4 vending_machine = statemachine.build do
5 superstate :operational do
6 trans :waiting, :dollar, :paid
7 trans :paid, :selection, :waiting
8 trans :waiting, :selection, :waiting
9 trans :paid, :dollar, :paid
10
11 event :repair, :repair_mode, Proc.new { puts "Entering Repair Mode" }
12 end
13
14 trans :repair_mode, :operate, :operational_H, Proc.new { puts "Exiting Repair Mode" }
15
16 on_entry_of :waiting, Proc.new { puts "Entering Waiting State" }
17 on_entry_of :paid, Proc.new { puts "Entering Paid State" }
18 end
19
20 vending_machine.repair
21 vending_machine.operate
22 vending_machine.dollar
23 vending_machine.repair
24 vending_machine.operate
Output:
1 Entering Repair Mode
2 Exiting Repair Mode
3 Entering Waiting State
4 Entering Paid State
5 Entering Repair Mode
6 Exiting Repair Mode
7 Entering Paid State
Next we should cover pseudo states.