alexpeachey / end_state

A State Machine implementation
MIT License
9 stars 5 forks source link

Add support for machine-wide concluders #30

Open dhawt opened 9 years ago

dhawt commented 9 years ago

I would like the ability to define a machine-wide concluder to be run for all transitions, so I can implement functionality that is run when any transition occurs on the machine.

Example: trigger an event when the state of a machine changes in any way.

brianvh commented 9 years ago

Hmm... I think the tricky thing with something like this would be determining when this auto-concluder would be run, among the list of concluders for any particular transition. It's possible to say "always be the last concluder", but that means it's not possible to take action after this machine-wide concluder would run. It's the same issue with a concluder that always ran first.

This is why the t.persistence_on feature is simply another concluder (albeit with a special name). When/how it's called is handled on a transition-by-transition basis. Sometimes you want the object to persist early, sometimes you want it late. It's a huge "it depends" situation...

charlierudolph commented 9 years ago

I'd say that run in order of definition. If you define the machine-wide concluder before defining the transition level concluders it runs before. If defined after, it runs after

alexpeachey commented 9 years ago

I'm not convinced this is a good idea. However, I think if implemented we can get around the "when is it run" but not having a machine-wide concluder.

Rather the better solution would be to have some new transition hooks added: before_concluding and after_concluding. Rather than your traditional "callbacks" that usually take a block, these would be defined in the same way as the transitions. The difference would be they would apply to all transitions on the machine. Similarly we could added before_guarding and after_guarding. (Though I'm not sure on guards if it matters so much when they happen as they should not modify anything.)

So they would end up looking/working like this:

before_concluding do |transition|
  transition.concluder PrepFinalization
  transition.concluder AdditionalSetup
end

after_concluding do |transition|
  transition.persistence_on
  transition.concluder CleanUp
end