Open alexpeachey opened 9 years ago
I probably should tag @brianvh and @charlierudolph so they know I put this here.
:+1: Helps encapsulate a lot of things and simplifies the class we hand off to the user.
I think I'm on board with this change, for the most part. I think it would make things much clearer if I could see how the EndState::Machine
class was implemented.
I assume the plan would be to deprecate the existing EndState::StateMachine
inheritance interface? Also, is this method reminiscent of how the Naught Builder class operates?
Yes, I kind of based this off of what Naught did. I kind of like it being more of a class Generator/Builder.
In my mind EndState::Machine
would be fairly simple. It's job is to new up a EndState::StateMachineConfiguration
that it yields in the build
method. It then grabs it after yielding and dynamically creates a new class. Right now my thought is this class would be a subclass of EndState::StateMachine
but it doesn't have to be. I'm thinking the EndState::StateMachine
is where all the method missing stuff and instance level transition of the current one live so it's good to have these in a class that could be subclassed. However, it doesn't need to be that way and build
could actually dynamically build the whole class (likely with some heredocs). We could also turn EndState::StateMachine
into a module that we just extend the class we are building with.
There's a lot of room for exactly how this gets executed but that's some more rambling on what I'm thinking.
Also, since I imagine it's possible some people may actually want some custom functionality in their generated class we could add another method onto the configuration similar to what I did with ActiveNull. And we just create a module that we dump the block into and mix into the class we are building.
MyMachine = EndState::Machine.build do |machine|
machine.transition first: :second, as: :shift_up do |transition|
transition.guard SomeGuard
transition.concluder SomeConcluder
end
machine.custom do
def some_special_method
# Cool stuff unique to my machine.
end
end
end
Right now, to create a machine we have the developer subclass EndState::StateMachine and then just use a bunch of class macros to define the machine. This works just fine except, as was pointed out in a recent pull request, we have the StateMachine class responsible for 2 large things, the first is the configuration/definition part, and the second is the actual working machine that acts as a delegator wrapping the stateful object.
I find the subclassing here odd because the subclass doesn't override anything in the super class and gets all of it's behavior and function from the macros. So your typical StateMachine class is just several calls to the transition macro. On the other hand the Guard and Concluder subclasses make sense because you are basically providing an implementation and overriding a default method in each. They also likely have additional build out that has all the logic for how to do what they need to do to guard or conclude the transition.
An alternative way we can handle the machine generation would be using a builder that actually creates a machine class for us. The classes created would still actually be subclasses of a StateMachine class, but rather than create a class like you do now it would be more like this:
With this setup,
MyMachine
is still a subclass ofStateMachine
but it doesn't have all those class methods it does now. You still doMyMachine.new(stateful_object)
and everything else works the same. The difference is a new thingEndState::Machine
has abuild
method that yields a newStateMachineConfiguration
object that has an instance methodtransition
on it that is used to define the transitions. That object then holds all the transition maps, event-aliases, etc. Thebuild
method then creates a new class that is a subclass ofStateMachine
and has it's configuration set to what was built using the builder.Thoughts?