Class: NxtStateMachine::StateMachine
- Inherits:
-
Object
- Object
- NxtStateMachine::StateMachine
- Defined in:
- lib/nxt_state_machine/state_machine.rb
Instance Attribute Summary collapse
-
#callbacks ⇒ Object
readonly
Returns the value of attribute callbacks.
-
#class_context ⇒ Object
readonly
Returns the value of attribute class_context.
-
#defuse_registry ⇒ Object
readonly
Returns the value of attribute defuse_registry.
-
#error_callback_registry ⇒ Object
readonly
Returns the value of attribute error_callback_registry.
-
#events ⇒ Object
readonly
Returns the value of attribute events.
-
#initial_state ⇒ Object
Returns the value of attribute initial_state.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#options ⇒ Object
readonly
Returns the value of attribute options.
Instance Method Summary collapse
- #after_transition(from:, to:, run: nil, &block) ⇒ Object
- #all_states_except(*excluded) ⇒ Object
- #all_transitions_from_to(from: all_states, to: all_states) ⇒ Object
- #any_state ⇒ Object (also: #all_states)
- #around_transition(from:, to:, run: nil, &block) ⇒ Object
- #before_transition(from:, to:, run: nil, &block) ⇒ Object
- #can_transition!(event, from) ⇒ Object
- #can_transition?(event_name, from) ⇒ Boolean
- #configure(&block) ⇒ Object
- #current_state_name(context) ⇒ Object
- #defuse(errors = [], from:, to:) ⇒ Object
- #event(name, **options, &block) ⇒ Object
- #event_methods ⇒ Object
- #events_for_state(state) ⇒ Object
- #find_error_callback(error, transition) ⇒ Object
- #get_state_with(method = nil, &block) ⇒ Object
-
#initialize(name, class_context, event_registry, **opts) ⇒ StateMachine
constructor
A new instance of StateMachine.
- #on_error(error = StandardError, from:, to:, run: nil, &block) ⇒ Object
- #on_error!(error = StandardError, from:, to:, run: nil, &block) ⇒ Object
- #on_success(from:, to:, run: nil, &block) ⇒ Object
- #run_after_callbacks(transition, context) ⇒ Object
-
#run_before_callbacks(transition, context) ⇒ Object
TODO: Everything that require context should live in some sort of proxy.
- #run_callbacks(transition, kind, context) ⇒ Object
- #run_success_callbacks(transition, context) ⇒ Object
- #set_state_with(method = nil, &block) ⇒ Object
- #set_state_with!(method = nil, &block) ⇒ Object
- #state(*names, **opts, &block) ⇒ Object
- #states(*names, **opts, &block) ⇒ Object
- #target(context) ⇒ Object
- #transitions ⇒ Object
Constructor Details
#initialize(name, class_context, event_registry, **opts) ⇒ StateMachine
Returns a new instance of StateMachine.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# File 'lib/nxt_state_machine/state_machine.rb', line 3 def initialize(name, class_context, event_registry, **opts) @name = name @class_context = class_context @options = opts @states = NxtStateMachine::StateRegistry.new @transitions = [] @events = event_registry @callbacks = CallbackRegistry.new @error_callback_registry = ErrorCallbackRegistry.new @defuse_registry = DefuseRegistry.new @initial_state = nil end |
Instance Attribute Details
#callbacks ⇒ Object (readonly)
Returns the value of attribute callbacks.
18 19 20 |
# File 'lib/nxt_state_machine/state_machine.rb', line 18 def callbacks @callbacks end |
#class_context ⇒ Object (readonly)
Returns the value of attribute class_context.
18 19 20 |
# File 'lib/nxt_state_machine/state_machine.rb', line 18 def class_context @class_context end |
#defuse_registry ⇒ Object (readonly)
Returns the value of attribute defuse_registry.
18 19 20 |
# File 'lib/nxt_state_machine/state_machine.rb', line 18 def defuse_registry @defuse_registry end |
#error_callback_registry ⇒ Object (readonly)
Returns the value of attribute error_callback_registry.
18 19 20 |
# File 'lib/nxt_state_machine/state_machine.rb', line 18 def error_callback_registry @error_callback_registry end |
#events ⇒ Object (readonly)
Returns the value of attribute events.
18 19 20 |
# File 'lib/nxt_state_machine/state_machine.rb', line 18 def events @events end |
#initial_state ⇒ Object
Returns the value of attribute initial_state.
19 20 21 |
# File 'lib/nxt_state_machine/state_machine.rb', line 19 def initial_state @initial_state end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
18 19 20 |
# File 'lib/nxt_state_machine/state_machine.rb', line 18 def name @name end |
#options ⇒ Object (readonly)
Returns the value of attribute options.
18 19 20 |
# File 'lib/nxt_state_machine/state_machine.rb', line 18 def @options end |
Instance Method Details
#after_transition(from:, to:, run: nil, &block) ⇒ Object
124 125 126 |
# File 'lib/nxt_state_machine/state_machine.rb', line 124 def after_transition(from:, to:, run: nil, &block) callbacks.register(from, to, :after, run, block) end |
#all_states_except(*excluded) ⇒ Object
87 88 89 |
# File 'lib/nxt_state_machine/state_machine.rb', line 87 def all_states_except(*excluded) all_states - excluded end |
#all_transitions_from_to(from: all_states, to: all_states) ⇒ Object
66 67 68 |
# File 'lib/nxt_state_machine/state_machine.rb', line 66 def all_transitions_from_to(from: all_states, to: all_states) transitions.select { |transition| transition.transitions_from_to?(from, to) } end |
#any_state ⇒ Object Also known as: all_states
74 75 76 |
# File 'lib/nxt_state_machine/state_machine.rb', line 74 def any_state states.values.map(&:enum) end |
#around_transition(from:, to:, run: nil, &block) ⇒ Object
144 145 146 |
# File 'lib/nxt_state_machine/state_machine.rb', line 144 def around_transition(from:, to:, run: nil, &block) callbacks.register(from, to, :around, run, block) end |
#before_transition(from:, to:, run: nil, &block) ⇒ Object
120 121 122 |
# File 'lib/nxt_state_machine/state_machine.rb', line 120 def before_transition(from:, to:, run: nil, &block) callbacks.register(from, to, :before, run, block) end |
#can_transition!(event, from) ⇒ Object
115 116 117 118 |
# File 'lib/nxt_state_machine/state_machine.rb', line 115 def can_transition!(event, from) return true if can_transition?(event, from) raise NxtStateMachine::Errors::TransitionNotDefined, "No transition :#{event} for state :#{from} defined" end |
#can_transition?(event_name, from) ⇒ Boolean
110 111 112 113 |
# File 'lib/nxt_state_machine/state_machine.rb', line 110 def can_transition?(event_name, from) event = events.resolve!(event_name) event && event.event_transitions.key?(from) end |
#configure(&block) ⇒ Object
148 149 150 151 |
# File 'lib/nxt_state_machine/state_machine.rb', line 148 def configure(&block) instance_exec(&block) self end |
#current_state_name(context) ⇒ Object
181 182 183 |
# File 'lib/nxt_state_machine/state_machine.rb', line 181 def current_state_name(context) Callable.new(get_state_with).bind(context).call(target(context)) end |
#defuse(errors = [], from:, to:) ⇒ Object
132 133 134 |
# File 'lib/nxt_state_machine/state_machine.rb', line 132 def defuse(errors = [], from:, to:) defuse_registry.register(from, to, errors) end |
#event(name, **options, &block) ⇒ Object
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/nxt_state_machine/state_machine.rb', line 91 def event(name, **, &block) name = name.to_sym event = Event.new(name, self, **, &block) events.register(name, event) Event::Names.set_state_method_map(name).each do |event_name, set_state_method| class_context.define_method event_name do |*args, **opts| event.state_machine.can_transition!(name, event.state_machine.current_state_name(self)) transition = event.event_transitions.resolve!(event.state_machine.current_state_name(self)) # Transition is build every time and thus should be thread safe! transition.build_transition(event, self, set_state_method, *args, **opts) end end class_context.define_method "can_#{name}?" do event.state_machine.can_transition?(name, event.state_machine.current_state_name(self)) end end |
#event_methods ⇒ Object
78 79 80 81 82 83 |
# File 'lib/nxt_state_machine/state_machine.rb', line 78 def event_methods event_names = events.keys event_names_with_bang = event_names.map { |e| e + '!' } (event_names + event_names_with_bang).map(&:to_sym) end |
#events_for_state(state) ⇒ Object
70 71 72 |
# File 'lib/nxt_state_machine/state_machine.rb', line 70 def events_for_state(state) events.values.select { |event| event.transitions_from?(state) } end |
#find_error_callback(error, transition) ⇒ Object
166 167 168 |
# File 'lib/nxt_state_machine/state_machine.rb', line 166 def find_error_callback(error, transition) error_callback_registry.resolve(error, transition) end |
#get_state_with(method = nil, &block) ⇒ Object
21 22 23 |
# File 'lib/nxt_state_machine/state_machine.rb', line 21 def get_state_with(method = nil, &block) @get_state_with ||= (method || block) || raise_missing_configuration_error(:get_state_with) end |
#on_error(error = StandardError, from:, to:, run: nil, &block) ⇒ Object
136 137 138 |
# File 'lib/nxt_state_machine/state_machine.rb', line 136 def on_error(error = StandardError, from:, to:, run: nil, &block) error_callback_registry.register(from, to, error, run, block) end |
#on_error!(error = StandardError, from:, to:, run: nil, &block) ⇒ Object
140 141 142 |
# File 'lib/nxt_state_machine/state_machine.rb', line 140 def on_error!(error = StandardError, from:, to:, run: nil, &block) error_callback_registry.register!(from, to, error, run, block) end |
#on_success(from:, to:, run: nil, &block) ⇒ Object
128 129 130 |
# File 'lib/nxt_state_machine/state_machine.rb', line 128 def on_success(from:, to:, run: nil, &block) callbacks.register(from, to, :success, run, block) end |
#run_after_callbacks(transition, context) ⇒ Object
158 159 160 |
# File 'lib/nxt_state_machine/state_machine.rb', line 158 def run_after_callbacks(transition, context) run_callbacks(transition, :after, context) end |
#run_before_callbacks(transition, context) ⇒ Object
TODO: Everything that require context should live in some sort of proxy
154 155 156 |
# File 'lib/nxt_state_machine/state_machine.rb', line 154 def run_before_callbacks(transition, context) run_callbacks(transition, :before, context) end |
#run_callbacks(transition, kind, context) ⇒ Object
170 171 172 173 174 175 176 177 178 179 |
# File 'lib/nxt_state_machine/state_machine.rb', line 170 def run_callbacks(transition, kind, context) current_callbacks = callbacks.resolve!(transition, kind) return unless current_callbacks.any? current_callbacks.each do |callback| Callable.new(callback).bind(context).call(transition) end true end |
#run_success_callbacks(transition, context) ⇒ Object
162 163 164 |
# File 'lib/nxt_state_machine/state_machine.rb', line 162 def run_success_callbacks(transition, context) run_callbacks(transition, :success, context) end |
#set_state_with(method = nil, &block) ⇒ Object
25 26 27 |
# File 'lib/nxt_state_machine/state_machine.rb', line 25 def set_state_with(method = nil, &block) @set_state_with ||= (method || block) || raise_missing_configuration_error(:set_state_with) end |
#set_state_with!(method = nil, &block) ⇒ Object
29 30 31 |
# File 'lib/nxt_state_machine/state_machine.rb', line 29 def set_state_with!(method = nil, &block) @set_state_with_bang ||= (method || block) || raise_missing_configuration_error(:set_state_with!) end |
#state(*names, **opts, &block) ⇒ Object
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/nxt_state_machine/state_machine.rb', line 33 def state(*names, **opts, &block) defaults = { initial: false } opts.reverse_merge!(defaults) machine = self Array(names).map do |name| if opts.fetch(:initial) && initial_state.present? raise NxtStateMachine::Errors::InitialStateAlreadyDefined, ":#{initial_state.enum} was already defined as the initial state" else state = new_state_class(&block).new(name, self, **opts.reverse_merge(index: states.size)) states.register(name, state) self.initial_state = state if opts.fetch(:initial) class_context.define_method "#{name}?" do machine.current_state_name(self) == name end state end end end |
#states(*names, **opts, &block) ⇒ Object
55 56 57 58 59 60 |
# File 'lib/nxt_state_machine/state_machine.rb', line 55 def states(*names, **opts, &block) # method overloading in ruby ;-) return @states unless names.any? state(*names, **opts, &block) end |
#target(context) ⇒ Object
185 186 187 188 |
# File 'lib/nxt_state_machine/state_machine.rb', line 185 def target(context) @target_method ||= ([:target] || :itself) context.send(@target_method) end |
#transitions ⇒ Object
62 63 64 |
# File 'lib/nxt_state_machine/state_machine.rb', line 62 def transitions @transitions ||= events.values.flat_map(&:event_transitions) end |