qmuntal / stateless

Go library for creating finite state machines
BSD 2-Clause "Simplified" License
942 stars 49 forks source link

how to access trigger's parameters in OnTransitioned and OnUnhandledTrigger #16

Closed okhowang closed 3 years ago

qmuntal commented 3 years ago

As of today there is no way to access trigger's parameters in that methods. Could you elaborate on why you need them?

They could be added as a context value to not break the backwards compatible if that is necessary.

okhowang commented 3 years ago

It's just like #5 I want have a common trigger for example EXIT and handle EXIT for all state. I think I can do it in OnTransitioned or OnUnhandledTrigger. but I couldn't access trigger's parameters

qmuntal commented 3 years ago

OnTransitioned should not be used for defining an state machine properties, as it is not part of the state machine definition.

A correct way to achieve what you want is to use substates, where the parent state handles the EXIT trigger.

Example:

const (
  triggerCall = "Call"
  triggerExit = "Exit"
)

const (
  stateParent = "Parent"
  state1      = "state1"
  state2      = "state2"
  stateExit   = "stateExit"
)

func main() {
  sm := stateless.NewStateMachine(state1)
  sm.Configure(state1).SubstateOf(stateParent)
  sm.Configure(state2).SubstateOf(stateParent)
  sm.Configure(stateParent).Permit(triggerExit, stateExit)
}

image

okhowang commented 3 years ago

thanks, but how can I do some action in both parent and substate. there is no ExitFrom currently. substate may need do something for EXIT trigger, but no other tigger when exiting

qmuntal commented 3 years ago

Try using OnExit in the parent state together with GetTransition, which will allow you to perform a generic exit action and also specific actions based on the exit trigger or even based on the source/destination.

const (
 triggerCall = "Call"
 triggerExit = "Exit"
)

const (
  stateParent = "Parent"
  state1      = "state1"
  state2      = "state2"
  stateExit   = "stateExit"
)

func Test1(t *testing.T) {
  sm := stateless.NewStateMachine(state1)
  sm.Configure(state1).SubstateOf(stateParent)
  sm.Configure(state2).SubstateOf(stateParent)
  sm.Configure(stateParent).
    Permit(triggerExit, stateExit).
    OnExit(func(ctx context.Context, _ ...interface{}) error {
      t := stateless.GetTransition(ctx)
      switch t.Trigger {
      case triggerExit:
        fmt.Println("on exit from triggerExit")
      default:
        fmt.Println("do nothing")
      }
      return nil
    })
    sm.Fire(triggerExit)
}