Class: Finity::Machine

Inherits:
Object
  • Object
show all
Defined in:
lib/finity/machine.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(klass, options = {}, &block) ⇒ Machine

Initialize a new state machine within the provided class and define methods for querying the current state and initiating transitions. The current state must be bound to the including instance, otherwise there may be problems due to caching between requests.



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/finity/machine.rb', line 31

def initialize klass, options = {}, &block
  @klass, @states, @events = klass, {}, {}
  instance_eval &block if block_given?
  @initial = current = options.delete(:initial) || initial
  @klass.send :define_method, :current do |*args|
    unless self.instance_variable_defined? :@current
      self.instance_variable_set :@current, current
    end
    self.instance_variable_get :@current
  end
  @klass.send :define_method, :event! do |*args|
    self.instance_variable_set :@current, (
      klass.finity.update self, self.current, *args
    )
  end
  @klass.send :define_method, :state? do |*args|
    self.current.eql? *args
  end
end

Instance Attribute Details

#eventsObject

Returns the value of attribute events.



25
26
27
# File 'lib/finity/machine.rb', line 25

def events
  @events
end

#statesObject

Returns the value of attribute states.



25
26
27
# File 'lib/finity/machine.rb', line 25

def states
  @states
end

Instance Method Details

#event(name, options = {}, &block) ⇒ Object

Register an event and evaluate the block for transitions.



63
64
65
66
# File 'lib/finity/machine.rb', line 63

def event name, options = {}, &block
  name.is_a?(Array) ? name.each { |value| event value, options, &block } :
    @events[name] = Event.new(name, options, &block)
end

#initialObject

Return the name of the initial state.



52
53
54
# File 'lib/finity/machine.rb', line 52

def initial
  @initial ||= @states.keys.first unless @states.first.nil?
end

#state(name, options = {}) ⇒ Object

Register a state, or a set of states.



57
58
59
60
# File 'lib/finity/machine.rb', line 57

def state name, options = {}
  name.is_a?(Array) ? name.each { |value| state value, options } :
    @states[name] = State.new(name, options)
end

#update(object, current, event) ⇒ Object

An event occured, so update the state machine by evaluating the transition functions and notify the left and entered state, but only if the event leads to a transition that triggers a state change.



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/finity/machine.rb', line 71

def update object, current, event
  now ||= @states[current]
  if state = @events[event].handle(object, now)
    if @states[state].nil?
      raise InvalidState, "Invalid state #{state}"
    end
    if state.eql? current
      now.cycle object
    else
      now.leave object
      now = @states[current = state]
      now.enter object
    end
  end
  current
end