NAME
StateMachine::Gestinanna - provides context and state machine for wizard-like applications
SYNOPSIS
package My::Wizard;
@ISA = qw(StateMachine::Gestinanna);
%EDGES => {
# state edge descriptions
start => {
show => {
# conditions for transition
},
.
:
},
.
:
};
# code for state transitions
sub start_to_show {
my $statemachine = shift;
# do something if going from start to show
}
###
package main;
my $sm = new My::Wizard(context => $context);
$sm -> process($data);
my $state = $sm -> state;
DESCRIPTION
StateMachine::Gestinanna is designed to make creation of web-based wizards almost trivial. The module supports inheritance of state information and methods so classes of wizards may be created.
StateMachine::Gestinanna inherits from Class::Container. This allows specialized state machine classes to be created that do more than just manage a state. For example, the Gestinanna web application framework specializes StateMachine::Gestinanna to provide support for views using the Template Toolkit.
CREATING A STATE MACHINE
The state machine consists of two parts: the conditions for transitioning between states (the edges), and the code that is run when there is a state transition. The meaning of a particular state (e.g., displaying a web page) is left to the application using the state machine. This allows for maximum flexibility in user interfaces.
Edge Descriptions
The package variable %EDGES
contains the edge descriptions. The keys of the hash are the states the edges are from and refer to a hash whose keys are the states the edges are to. These keys then point to a hash with a description of the requirements for an edge transition
In addition to requirements that should be suitable for Data::FormValidator (see Data::FormValidator for more information) the overrides
key is available. This is a hash of variables to values. The values will override any data associated with the variables for deciding if that particular transition is appropriate. The data is passed along to the transition handler. See StateMachine::Gestinanna::Examples::MailForm for an example of how this can be used.
Code Run During a Transition
Three different methods may be associated with a transition. In this section, replace from
and to
in the method names with the names of the appropriate states.
If the code needs to preempt the expected target state, it can return the name of the new state. The state machine will start over with the new target state.
When no error states are returned (undef
is returned) and the transition is successful, the state machine will halt.
Data associated with the error state may be stored in the `error' data root before returning the error state.
$sm -> add_data('error', { hash of data };
- from_to_to
-
This method handles the complete transition and is the only method used if it is available. The name of this method is based on the name of the two states:
${from_state}_to_${to_state}
. For example, if we are transitioning from thefoo
state to thebar
state, this method would be namedfoo_to_bar
. - post_from
-
If the
from_to_to
method is unavailable, this method is called, if it is available. - pre_to
-
If the
from_to_to
method is unavailable, this method is called, if it is available.
Throwing Exceptions
The state machine will catch any exceptions of the StateMachine::Gestinanna::Exception class and try to extract a new target state and supplimental data. This exception class inherits from the Error module.
Inheritance
State machines have two forms of inheritance: ISA and HASA.
ISA Inheritance
State machines can inherit all, some, or none of the edges in their inheritance tree. The default is to merge all the edges from all the super-classes. This behavior may be changed by using the _INHERIT
key.
%EDGES = (
_INHERIT => 'SUPER',
.
:
);
The following values are recognized.
- ALL
-
This is the default behavior. All edges from all the classes in
@ISA
are inherited. If the same edge is in multiple classes, the requirements are merged (may be modified by specifying the _INHERIT flag in the requirements section for a particular edge). - SUPER
-
This is similar to inheritance in Perl. The first class in the
@ISA
tree that has a particular edge describes that edge. - NONE
-
This is used to keep any edges from being inherited.
Note that this setting does not affect the inheritance of class methods. The code triggered by a transition follows the inheritance rules of Perl.
HASA Inheritance
A state machine may contain copies of other state machines and put their state names in their own name space. For example, if a module by the name of My::First::Machine
has a state of step1
and a second module has the following HASA definition, then step1
becomes the new state of first_step1
in My::Second::Machine
.
package My::Second::Machine;
%HASA = (
first => 'My::First::Machine',
);
The methods called on transition may be overridden in the parent machine by defining them with the prefix: My::Second::Machine::first_state1_to_first_state2 overrides My::First::Machine::state1_to_state2. This is done outside Perl's inheritance mechanisms, so calling the method on the state machine object will not show the same behavior.
METHODS
add_data ($root, $data)
This will add the information in $data to the internal data stored in the state machine. The data will be placed under $root. If $root contains periods (.), it will be split on them and serve as a set of keys into a multi-dimensional hash.
can ($old_state, $new_state)
This will return a code reference if code is defined to be run on a transition from $old_state
to $new_state
. This will follow ISA and HASA inheritance. Code references are cached.
If called with one argument, this will defer to UNIVERSAL::can
. This will not follow HASA inheritance.
clear_data ($root)
This will remove all data under $root that is stored in the state machine.
context ($context)
If called with no arguments, returns a string representing the current context of the state machine. If called with a single argument, restores the state machine to the context represented by $context
.
The context is serialized using YAML.
data ($root)
This will retrieve a hash of data stored in the state machine. The $root can be used to retrieve only a sub-set of the data.
Parts of the $root may be separated by periods (.). For example, data("foo.bar")
will return $data{foo}{bar}. data("foo")
will retrieve anything added with add_data("foo", {})
.
The following roots are used by the state machine:
- in
-
This is the data given to the
process
method. This is used to determine which state the machine should transition to. - out
-
This is the data processed by the Data::FormValidator object for the selected state. Additional processing may take place in the code triggered by the transition.
- error
-
This is any data specified for the error state transition (the returned error state from a transition handler).
invalid ( )
Returns a reference to a list of keys in the input data that are considered invalid by the validator for the new state.
missing ( )
Returns a reference to a list of keys that are missing in the input data as determined by the validator for the new state.
new (%config)
Constructs a new state machine instance. Any class initialization will take place also the first time the class is used. This involves caching inherited information and creating the validators. Any changes to the %EDGES hash will be ignored after this takes place.
The %config hash may have the following items. Note that Class::Container is used as the parent class.
- context
-
This is a string previously returned by the
context
method. This can be used to set the machine to a previous state. - state
-
This will set the machine to the given state regardless of the context.
process ($data)
Given a reference to a hash of data, this will select the appropriate state to transition to, and then transition to the new state. This is usually the method you need.
select_state ( )
Given the data and current state in the context, selects the new state. This is used internally by process
.
selected_state ( )
Returns the state most recently selected by the select_state
method. If no state was selected, it will return undef
or the current state, depending on what select_state
decides.
state ($state)
If called without an argument, returns the current state. If called with an argument, sets the state to the argument and returns the previous state.
transit ($state)
This will try and transition from the current state to the new state $state
. If there are any errors, error states may be processed. This is used internally by process
.
unknown ( )
Returns a reference to a list of keys in the input data that are unknown to the validator for the new state.
SEE ALSO
Class::Container, Data::FormValidator, Error, StateMachine::Gestinanna::Examples::MailForm, YAML, the test scripts in the distribution.
AUTHOR
James G. Smith <jsmith@cpan.org>
COPYRIGHT
Copyright (C) 2002-2004 Texas A&M University. All Rights Reserved.
This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.