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 the foo state to the bar state, this method would be named foo_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 Storable.

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, Storable, the test scripts in the distribution.

AUTHOR

James G. Smith <jsmith@cpan.org>

COPYRIGHT

Copyright (C) 2002 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.