Class: Foobara::StateMachine

Inherits:
Object
  • Object
show all
Includes:
Callbacks, Sugar, TransitionLog, Transitions, Validations
Defined in:
foobara-0.0.141/projects/state_machine/src/state_machine.rb,
foobara-0.0.141/projects/state_machine/src/sugar.rb,
foobara-0.0.141/projects/state_machine/src/callbacks.rb,
foobara-0.0.141/projects/state_machine/src/log_entry.rb,
foobara-0.0.141/projects/state_machine/src/transitions.rb,
foobara-0.0.141/projects/state_machine/src/validations.rb,
foobara-0.0.141/projects/state_machine/src/transition_log.rb,
foobara-0.0.141/projects/state_machine/lib/foobara/state_machine.rb

Overview

TODO: allow quick creation of a statemachine either through better options to #initialize or a .for method.

Defined Under Namespace

Modules: Callbacks, Sugar, TransitionLog, Transitions, Validations Classes: InvalidTransition, LogEntry

Class Attribute Summary collapse

Instance Attribute Summary collapse

Attributes included from TransitionLog

#log

Attributes included from Callbacks

#callback_registry

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Concern

foobara_class_methods_module_for, foobara_concern?, included

Methods included from TransitionLog

#log_transition

Methods included from Callbacks

#register_transition_callback

Constructor Details

#initialize(*args, owner: nil, target_attribute: nil, **options) ⇒ StateMachine

owner is optional. It can help with certain callbacks. It’s also required if planning to use the target_attribute feature



52
53
54
55
56
57
58
59
60
61
62
# File 'foobara-0.0.141/projects/state_machine/src/state_machine.rb', line 52

def initialize(*args, owner: nil, target_attribute: nil, **options)
  self.owner = owner

  super

  if target_attribute
    self.target_attribute = target_attribute
  else
    self.current_state = self.class.initial_state
  end
end

Class Attribute Details

.initial_stateObject

Returns the value of attribute initial_state.



19
20
21
# File 'foobara-0.0.141/projects/state_machine/src/state_machine.rb', line 19

def initial_state
  @initial_state
end

.non_terminal_statesObject

Returns the value of attribute non_terminal_states.



19
20
21
# File 'foobara-0.0.141/projects/state_machine/src/state_machine.rb', line 19

def non_terminal_states
  @non_terminal_states
end

.raw_transition_mapObject

Returns the value of attribute raw_transition_map.



19
20
21
# File 'foobara-0.0.141/projects/state_machine/src/state_machine.rb', line 19

def raw_transition_map
  @raw_transition_map
end

.stateObject

Returns the value of attribute state.



19
20
21
# File 'foobara-0.0.141/projects/state_machine/src/state_machine.rb', line 19

def state
  @state
end

.statesObject

Returns the value of attribute states.



19
20
21
# File 'foobara-0.0.141/projects/state_machine/src/state_machine.rb', line 19

def states
  @states
end

.terminal_statesObject

Returns the value of attribute terminal_states.



19
20
21
# File 'foobara-0.0.141/projects/state_machine/src/state_machine.rb', line 19

def terminal_states
  @terminal_states
end

.transitionObject

Returns the value of attribute transition.



19
20
21
# File 'foobara-0.0.141/projects/state_machine/src/state_machine.rb', line 19

def transition
  @transition
end

.transition_mapObject

Returns the value of attribute transition_map.



19
20
21
# File 'foobara-0.0.141/projects/state_machine/src/state_machine.rb', line 19

def transition_map
  @transition_map
end

.transitionsObject

Returns the value of attribute transitions.



19
20
21
# File 'foobara-0.0.141/projects/state_machine/src/state_machine.rb', line 19

def transitions
  @transitions
end

Instance Attribute Details

#ownerObject

Returns the value of attribute owner.



48
49
50
# File 'foobara-0.0.141/projects/state_machine/src/state_machine.rb', line 48

def owner
  @owner
end

#target_attributeObject

Returns the value of attribute target_attribute.



48
49
50
# File 'foobara-0.0.141/projects/state_machine/src/state_machine.rb', line 48

def target_attribute
  @target_attribute
end

Class Method Details

.for(transition_map) ⇒ Object



40
41
42
43
44
45
# File 'foobara-0.0.141/projects/state_machine/src/state_machine.rb', line 40

def for(transition_map)
  klass = Class.new(self)

  klass.set_transition_map(transition_map)
  klass
end

.set_transition_map(transition_map, initial_state: nil, states: nil, terminal_states: nil, transitions: nil) ⇒ Object



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'foobara-0.0.141/projects/state_machine/src/state_machine.rb', line 22

def set_transition_map(transition_map, initial_state: nil, states: nil, terminal_states: nil, transitions: nil)
  self.raw_transition_map = transition_map

  self.initial_state = initial_state
  self.states = states
  self.terminal_states = terminal_states
  self.transitions = transitions

  desugarize_transition_map
  determine_states_and_transitions

  create_enums
  create_state_predicate_methods
  create_transition_methods
  create_can_methods
  create_register_callback_methods
end

Instance Method Details

#allowed_transitionsObject



105
106
107
108
109
110
111
# File 'foobara-0.0.141/projects/state_machine/src/state_machine.rb', line 105

def allowed_transitions
  if in_terminal_state?
    []
  else
    self.class.transition_map[current_state].keys
  end
end

#can?(transition) ⇒ Boolean

Returns:

  • (Boolean)


113
114
115
# File 'foobara-0.0.141/projects/state_machine/src/state_machine.rb', line 113

def can?(transition)
  self.class.transition_map[current_state].key?(transition)
end

#current_stateObject



64
65
66
67
68
69
70
# File 'foobara-0.0.141/projects/state_machine/src/state_machine.rb', line 64

def current_state
  if target_attribute
    owner.send(target_attribute) || self.class.initial_state
  else
    @current_state
  end
end

#current_state=(state) ⇒ Object



72
73
74
75
76
77
78
# File 'foobara-0.0.141/projects/state_machine/src/state_machine.rb', line 72

def current_state=(state)
  if target_attribute
    owner.send("#{target_attribute}=", state)
  else
    @current_state = state
  end
end

#in_terminal_state?Boolean

Returns:

  • (Boolean)


122
123
124
# File 'foobara-0.0.141/projects/state_machine/src/state_machine.rb', line 122

def in_terminal_state?
  self.class.terminal_states.include?(current_state)
end

#perform_transition!(transition, &block) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'foobara-0.0.141/projects/state_machine/src/state_machine.rb', line 80

def perform_transition!(transition, &block)
  from = current_state

  transition_map = self.class.transition_map

  if in_terminal_state?
    raise InvalidTransition,
          "#{current_state} is a terminal state so no transitions from here are allowed."
  end

  unless transition_map[current_state].key?(transition)
    raise InvalidTransition,
          "Cannot perform #{transition} from #{current_state}. Expected one of #{allowed_transitions}."
  end

  to = transition_map[current_state][transition]

  conditions = { from:, transition:, to: }

  callback_registry.runner(**conditions).callback_data(state_machine: self, **conditions).run do
    block.call if block_given?
    update_current_state(**conditions)
  end
end

#update_current_state(**conditions) ⇒ Object



117
118
119
120
# File 'foobara-0.0.141/projects/state_machine/src/state_machine.rb', line 117

def update_current_state(**conditions)
  self.current_state = conditions[:to]
  log_transition(**conditions)
end