Class: Finite::StateMachine

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

Overview

The State Machine class. Represents the whole state machine

Class Attribute Summary collapse

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(initial_state, klass, &block) ⇒ StateMachine

Create a new state machine

Parameters:

  • initial_state (Symbol)

    the initial state of this state machine

  • klass (Class)

    the class of the state machine

  • block (Block)

    the block of code that creates it



16
17
18
19
20
21
22
23
# 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

Class Attribute Details

.machinesObject

Returns the value of attribute machines.



6
7
8
# File 'lib/finite/machine.rb', line 6

def machines
  @machines
end

Instance Attribute Details

#callbacksObject (readonly)

Returns the value of attribute callbacks.



9
10
11
# File 'lib/finite/machine.rb', line 9

def callbacks
  @callbacks
end

#eventsObject (readonly)

Returns the value of attribute events.



9
10
11
# File 'lib/finite/machine.rb', line 9

def events
  @events
end

#initialObject (readonly)

Returns the value of attribute initial.



9
10
11
# File 'lib/finite/machine.rb', line 9

def initial
  @initial
end

#statesObject (readonly)

Returns the value of attribute states.



9
10
11
# File 'lib/finite/machine.rb', line 9

def states
  @states
end

Instance Method Details

#add_event(event_name, &block) ⇒ Object

Add an event to the state machine

Parameters:

  • event_name (Symbol)

    the event you are trying to add

  • block (Block)

    the block of code that creates an event

Raises:

  • (Exception)

    if the event already exists



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# 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
  event.transitions.each_value do |transition|
    add_state transition.to
    add_state transition.from
  end
  @class.send(:define_method, :"can_#{event_name}?") do
    event.transitions.key? current_state.name
  end
  @class.send(:define_method, :"#{event_name}") do
    if event.transitions.key? current_state.name

      event.callbacks[:before].each do |callback|
        self.instance_eval &callback
      end

      if callbacks[:before].key? :all
        callbacks[:before][:all].each do |callback|
          self.instance_eval &callback
        end
      end

      new_state = states[event.transitions[current_state.name].to]

      if callbacks[:before].key? new_state.name
        callbacks[:before][new_state.name].each do |callback|
          self.instance_eval &callback
        end
      end
      @current_state = new_state

      if callbacks[:after].key? :all
        callbacks[:after][:all].each do |callback|
          self.instance_eval &callback
        end
      end
      if callbacks[:after].key? current_state.name
        callbacks[:after][current_state.name].each do |callback|
          self.instance_eval &callback
        end
      end

      event.callbacks[:after].each do |callback|
        self.instance_eval &callback
      end
    else
      raise 'Invalid Transition'
    end
  end
end

#add_state(state) ⇒ Object

Add a state to the the state machine if the state hasn’t already been created

Parameters:

  • state (Symbol)

    the state you are trying to add



90
91
92
93
94
95
96
97
# File 'lib/finite/machine.rb', line 90

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