Class: FSM::Machine

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

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(target_class) ⇒ Machine

Returns a new instance of Machine.



5
6
7
8
9
10
# File 'lib/fsm/machine.rb', line 5

def initialize(target_class)
  @target_class = target_class
  self.states = []
  self.transitions = []
  self.current_state_attribute_name = :state
end

Instance Attribute Details

#current_state_attribute_nameObject

Returns the value of attribute current_state_attribute_name.



3
4
5
# File 'lib/fsm/machine.rb', line 3

def current_state_attribute_name
  @current_state_attribute_name
end

#initial_state_nameObject

Returns the value of attribute initial_state_name.



3
4
5
# File 'lib/fsm/machine.rb', line 3

def initial_state_name
  @initial_state_name
end

#statesObject

Returns the value of attribute states.



3
4
5
# File 'lib/fsm/machine.rb', line 3

def states
  @states
end

#transitionsObject

Returns the value of attribute transitions.



3
4
5
# File 'lib/fsm/machine.rb', line 3

def transitions
  @transitions
end

Class Method Details

.[](includer) ⇒ Object



12
13
14
# File 'lib/fsm/machine.rb', line 12

def self.[](includer)
  (@machines ||= {})[includer]
end

.[]=(*args) ⇒ Object



16
17
18
# File 'lib/fsm/machine.rb', line 16

def self.[]=(*args)
  (@machines ||= {})[args.first] = args.last
end

.get_current_state_name(target) ⇒ Object



41
42
43
44
# File 'lib/fsm/machine.rb', line 41

def self.get_current_state_name(target)
  value = target.send(Machine[target.class].current_state_attribute_name)
  (value && value.is_a?(String)) ? value.intern : value
end

.set_current_state_name(target, value) ⇒ Object



46
47
48
# File 'lib/fsm/machine.rb', line 46

def self.set_current_state_name(target, value)
  target.send("#{Machine[target.class].current_state_attribute_name}=", value)
end

Instance Method Details

#available_transitions(target) ⇒ Object



60
61
62
63
64
# File 'lib/fsm/machine.rb', line 60

def available_transitions(target)
  current_state_name = Machine.get_current_state_name(target)
  state = state_for_name(current_state_name)
  state.transitions.values
end

#build_transition_methodsObject



67
68
69
70
71
72
# File 'lib/fsm/machine.rb', line 67

def build_transition_methods
  names = self.transitions.map() {|transition| transition.name}.uniq
  names.each do |name|
    define_transition_method(name)
  end
end

#dot(options = {}) ⇒ Object



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

def dot(options = {})
  format = options[:format] || :png
  extension = options[:extension] || format
  file_name = options[:outfile] || "#{@target_class.name.downcase}.#{extension}" 
  cmd = "dot -T#{format} -o#{file_name}"
  IO.popen cmd, 'w' do |io| 
    io.write to_dot
  end 
  raise 'dot failed' unless $?.success? 
end

#reachable_states(target) ⇒ Object



51
52
53
54
55
56
57
58
# File 'lib/fsm/machine.rb', line 51

def reachable_states(target)
  reachables = []
  current_state_name = Machine.get_current_state_name(target)
  self.states.map do |state|
    reachables += state.to_states if state.name == current_state_name
  end
  reachables
end

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



20
21
22
23
24
# File 'lib/fsm/machine.rb', line 20

def state(name, options = {})
  raise "State is already defined: '#{name}'" if self.state_for_name(name, true)
  self.states << State.new(name, options)
  self.initial_state_name=(name) unless self.initial_state_name
end

#state_for_name(name, quiet = false) ⇒ Object

Lookup a State by it’s name raises ArgumentError if state can not be found unless quiet is set to true

Raises:

  • (ArgumentError)


76
77
78
79
80
# File 'lib/fsm/machine.rb', line 76

def state_for_name(name, quiet = false)
  state = self.states.detect() {|state| state.name == name}
  raise ArgumentError.new("Unknonw state '#{name}'") unless quiet || state
  state
end

#to_dotObject



82
83
84
85
86
87
# File 'lib/fsm/machine.rb', line 82

def to_dot
  dots = self.transitions.map do |transition|
    "  #{transition.from.name} -> #{transition.to.name}"
  end
  "digraph FSM {\n#{dots.join(";\n")}\n}"
end

#transition(name, from_name, to_name, options = {}) ⇒ Object

Raises:

  • (ArgumentError)


31
32
33
34
35
36
37
38
39
# File 'lib/fsm/machine.rb', line 31

def transition(name, from_name, to_name, options = {})
  raise ArgumentError.new("name, from_name and to_name are required") if name.nil? || from_name.nil? || to_name.nil?
  
  from_state = self.state_for_name(from_name)
  to_state = self.state_for_name(to_name)
  transition = Transition.new(name, from_state, to_state, options)
  from_state.add_transition(transition)
  self.transitions << transition
end