class Finite::StateMachine
The State
Machine class. Represents the whole state machine
Attributes
machines[RW]
callbacks[R]
events[R]
initial[R]
states[R]
Public Class Methods
new(initial_state, klass, &block)
click to toggle source
Create a new state machine
@param initial_state [Symbol] the initial state of this state machine @param klass [Class] the class of the state machine @param block [Block] the block of code that creates it
# File lib/finite/machine.rb, line 16 def initialize(initial_state, klass, &block) @class = klass @initial = initial_state @states = Hash.new @events = Hash.new @callbacks = {before: Hash.new , after: Hash.new} instance_eval &block end
Public Instance Methods
add_event(event_name, &block)
click to toggle source
Add an event to the state machine
@param event_name [Symbol] the event you are trying to add @param block [Block] the block of code that creates an event @raise [Exception] if the event already exists
# File lib/finite/machine.rb, line 30 def add_event(event_name, &block) # We don't want to randomly override things that we shouldn't raise "Method already taken can_#{event_name}?" if @class.methods.include?(:"can_#{event_name}?") raise "Method already taken #{event_name}" if @class.methods.include?(:"#{event_name}") raise 'Event #{event_name} already exists. Rename or combine the events' if events.include? event_name event = Event.new(event_name, &block) @events[event_name] = event # Add the states from the transition event.transitions.each_value do |transition| add_state transition.to add_state transition.from end # Creates the method can_event_name? @class.send(:define_method, :"can_#{event_name}?") do event.transitions.key? current_state.name end # Creates the method event_name @class.send(:define_method, :"#{event_name}") do if event.transitions.key? current_state.name # Makes sure the transition can happen transition = event.transitions[current_state.name] if transition.condition.nil? or self.instance_exec(&transition.condition) new_state = states[event.transitions[current_state.name].to] # Call all of the "before event" callbacks event.callbacks[:before].each do |callback| self.instance_eval &callback end # Call all of the before_all callbacks if callbacks[:before].key? :all callbacks[:before][:all].each do |callback| self.instance_eval &callback end end # Call the "before state" callbacks if callbacks[:before].key? new_state.name callbacks[:before][new_state.name].each do |callback| self.instance_eval &callback end end # Set the current state @current_state = new_state # call the "after state" callbacks if callbacks[:after].key? current_state.name callbacks[:after][current_state.name].each do |callback| self.instance_eval &callback end end # call the "after all" callbacks if callbacks[:after].key? :all callbacks[:after][:all].each do |callback| self.instance_eval &callback end end # Call the "after event" callbacks event.callbacks[:after].each do |callback| self.instance_eval &callback end self end end end end
add_state(state)
click to toggle source
Add a state to the the state machine if the state hasn’t already been created
@param state [Symbol] the state you are trying to add
# File lib/finite/machine.rb, line 109 def add_state(state) if not @states.include? state # Prevents arbitrarily overriding methods that you shouldn't be raise "Method already taken #{state}?" if @class.methods.include?(:"#{state}?") @states[state] = State.new(state) @class.send(:define_method, :"#{state}?"){current_state == state} end end
Private Instance Methods
event(name, &block)
click to toggle source
The event method for the dsl
@param name [Symbol] the name of the event @param block [Block] the block of code that creates events
# File lib/finite/machine.rb, line 123 def event(name, &block) add_event name, &block end