diff --git a/config.go b/config.go index dcaeb11..c237334 100644 --- a/config.go +++ b/config.go @@ -49,7 +49,7 @@ func (sc *StateConfiguration) Machine() *StateMachine { // and enter the target state. func (sc *StateConfiguration) InitialTransition(targetState State) *StateConfiguration { if sc.sr.HasInitialState { - panic(fmt.Sprintf("stateless: This state has already been configured with an initial transition (%s).", sc.sr.InitialTransitionTarget)) + panic(fmt.Sprintf("stateless: This state has already been configured with an initial transition (%v).", sc.sr.InitialTransitionTarget)) } if targetState == sc.State() { panic("stateless: Setting the current state as the target destination state is not allowed.") @@ -169,7 +169,7 @@ func (sc *StateConfiguration) SubstateOf(superstate State) *StateConfiguration { state := sc.sr.State // Check for accidental identical cyclic configuration if state == superstate { - panic(fmt.Sprintf("stateless: Configuring %s as a substate of %s creates an illegal cyclic configuration.", state, superstate)) + panic(fmt.Sprintf("stateless: Configuring %v as a substate of %v creates an illegal cyclic configuration.", state, superstate)) } // Check for accidental identical nested cyclic configuration @@ -181,7 +181,7 @@ func (sc *StateConfiguration) SubstateOf(superstate State) *StateConfiguration { for activeSc.Superstate != nil { // Check if superstate is already added to hashset if _, ok := supersets[activeSc.Superstate.state()]; ok { - panic(fmt.Sprintf("stateless: Configuring %s as a substate of %s creates an illegal nested cyclic configuration.", state, supersets)) + panic(fmt.Sprintf("stateless: Configuring %v as a substate of %v creates an illegal nested cyclic configuration.", state, supersets)) } supersets[activeSc.Superstate.state()] = empty activeSc = sc.lookup(activeSc.Superstate.state()) diff --git a/example_test.go b/example_test.go index a93551c..b5e8e5f 100644 --- a/example_test.go +++ b/example_test.go @@ -81,7 +81,7 @@ func Example() { phoneCall.Fire(triggerSetVolume, 11) phoneCall.Fire(triggerPlacedOnHold) phoneCall.Fire(triggerPhoneHurledAgainstWall) - fmt.Printf("State is %s\n", phoneCall.MustState()) + fmt.Printf("State is %v\n", phoneCall.MustState()) // Output: // [Phone Call] placed for : [qmuntal] diff --git a/graph.go b/graph.go index c27a3ae..93b850b 100644 --- a/graph.go +++ b/graph.go @@ -25,7 +25,7 @@ func (g *graph) FormatStateMachine(sm *StateMachine) string { initialState, err := sm.State(context.Background()) if err == nil { sb.WriteString("\n init [label=\"\", shape=point];") - sb.WriteString(fmt.Sprintf("\n init -> {%s}[style = \"solid\"]", initialState)) + sb.WriteString(fmt.Sprintf("\n init -> {%v}[style = \"solid\"]", initialState)) } sb.WriteString("\n}") return sb.String() @@ -52,7 +52,7 @@ func (g *graph) formatActions(sr *stateRepresentation) string { func (g *graph) formatOneState(sr *stateRepresentation) string { var sb strings.Builder - sb.WriteString(fmt.Sprintf("\t%s [label=\"%s", sr.State, sr.State)) + sb.WriteString(fmt.Sprintf("\t%v [label=\"%v", sr.State, sr.State)) act := g.formatActions(sr) if act != "" { sb.WriteString("|") @@ -64,7 +64,7 @@ func (g *graph) formatOneState(sr *stateRepresentation) string { func (g *graph) formatOneCluster(sr *stateRepresentation) string { var sb strings.Builder - sb.WriteString(fmt.Sprintf("\nsubgraph cluster_%s {\n\tlabel=\"%s", sr.State, sr.State)) + sb.WriteString(fmt.Sprintf("\nsubgraph cluster_%v {\n\tlabel=\"%v", sr.State, sr.State)) act := g.formatActions(sr) if act != "" { sb.WriteString("\n----------\n") diff --git a/statemachine.go b/statemachine.go index 2d33e4d..98316b8 100644 --- a/statemachine.go +++ b/statemachine.go @@ -49,9 +49,9 @@ type UnhandledTriggerActionFunc = func(ctx context.Context, state State, trigger // DefaultUnhandledTriggerAction is the default unhandled trigger action. func DefaultUnhandledTriggerAction(_ context.Context, state State, trigger Trigger, unmetGuards []string) error { if len(unmetGuards) != 0 { - return fmt.Errorf("stateless: Trigger '%s' is valid for transition from state '%s' but a guard conditions are not met. Guard descriptions: '%v", trigger, state, unmetGuards) + return fmt.Errorf("stateless: Trigger '%v' is valid for transition from state '%v' but a guard conditions are not met. Guard descriptions: '%v", trigger, state, unmetGuards) } - return fmt.Errorf("stateless: No valid leaving transitions are permitted from state '%s' for trigger '%s', consider ignoring the trigger", state, trigger) + return fmt.Errorf("stateless: No valid leaving transitions are permitted from state '%v' for trigger '%v', consider ignoring the trigger", state, trigger) } // A StateMachine is an abstract machine that can be in exactly one of a finite number of states at any given time. @@ -216,7 +216,7 @@ func (sm *StateMachine) CanFireCtx(ctx context.Context, trigger Trigger, args .. func (sm *StateMachine) SetTriggerParameters(trigger Trigger, argumentTypes ...reflect.Type) { config := triggerWithParameters{Trigger: trigger, ArgumentTypes: argumentTypes} if _, ok := sm.triggerConfig[config.Trigger]; ok { - panic(fmt.Sprintf("stateless: Parameters for the trigger '%s' have already been configured.", trigger)) + panic(fmt.Sprintf("stateless: Parameters for the trigger '%v' have already been configured.", trigger)) } sm.triggerConfig[trigger] = config } @@ -236,6 +236,9 @@ func (sm *StateMachine) Fire(trigger Trigger, args ...interface{}) error { // // There is no rollback mechanism in case there is an action error after the state has been changed. // Guard clauses or error states can be used gracefully handle this situations. +// +// The context is passed down to all actions and callbacks called within the scope of this method. +// There is no context error checking, although it may be implemented in future releases. func (sm *StateMachine) FireCtx(ctx context.Context, trigger Trigger, args ...interface{}) error { return sm.internalFire(ctx, trigger, args...) } @@ -366,7 +369,7 @@ func (sm *StateMachine) internalFireOne(ctx context.Context, trigger Trigger, ar case *dynamicTriggerBehaviour: destination, ok := t.ResultsInTransitionFrom(ctx, source, args...) if !ok { - err = fmt.Errorf("stateless: Dynamic handler for trigger %s in state %s has failed", trigger, source) + err = fmt.Errorf("stateless: Dynamic handler for trigger %v in state %v has failed", trigger, source) } else { transition := Transition{Source: source, Destination: destination, Trigger: trigger} err = sm.handleTransitioningTrigger(ctx, representativeState, transition, args...) @@ -449,7 +452,7 @@ func (sm *StateMachine) enterState(ctx context.Context, sr *stateRepresentation, } } if !isValidForInitialState { - panic(fmt.Sprintf("stateless: The target (%s) for the initial transition is not a substate.", sr.InitialTransitionTarget)) + panic(fmt.Sprintf("stateless: The target (%v) for the initial transition is not a substate.", sr.InitialTransitionTarget)) } initialTranslation := Transition{Source: transition.Source, Destination: sr.InitialTransitionTarget, Trigger: transition.Trigger, isInitial: true} sr = sm.stateRepresentation(sr.InitialTransitionTarget) diff --git a/statemachine_test.go b/statemachine_test.go index 40c0b11..44e2259 100644 --- a/statemachine_test.go +++ b/statemachine_test.go @@ -1222,10 +1222,10 @@ func TestStateMachine_InitialTransition_Ordering(t *testing.T) { }) sm.OnTransitioning(func(_ context.Context, tr Transition) { - actualOrdering = append(actualOrdering, fmt.Sprintf("OnTransitioning%s%s", tr.Source, tr.Destination)) + actualOrdering = append(actualOrdering, fmt.Sprintf("OnTransitioning%v%v", tr.Source, tr.Destination)) }) sm.OnTransitioned(func(_ context.Context, tr Transition) { - actualOrdering = append(actualOrdering, fmt.Sprintf("OnTransitioned%s%s", tr.Source, tr.Destination)) + actualOrdering = append(actualOrdering, fmt.Sprintf("OnTransitioned%v%v", tr.Source, tr.Destination)) }) sm.Fire(triggerX) diff --git a/states.go b/states.go index 964aba9..7effa04 100644 --- a/states.go +++ b/states.go @@ -99,7 +99,7 @@ func (sr *stateRepresentation) findHandler(ctx context.Context, trigger Trigger, } } if len(metResults) > 1 { - panic(fmt.Sprintf("stateless: Multiple permitted exit transitions are configured from state '%s' for trigger '%s'. Guard clauses must be mutually exclusive.", sr.State, trigger)) + panic(fmt.Sprintf("stateless: Multiple permitted exit transitions are configured from state '%v' for trigger '%v'. Guard clauses must be mutually exclusive.", sr.State, trigger)) } if len(metResults) == 1 { result, ok = metResults[0], true