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
- #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
117 118 119 |
# File 'lib/nxt_state_machine/state_machine.rb', line 117 def after_transition(from:, to:, run: nil, &block) callbacks.register(from, to, :after, run, block) end |
#all_states_except(*excluded) ⇒ Object
80 81 82 |
# File 'lib/nxt_state_machine/state_machine.rb', line 80 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
137 138 139 |
# File 'lib/nxt_state_machine/state_machine.rb', line 137 def around_transition(from:, to:, run: nil, &block) callbacks.register(from, to, :around, run, block) end |
#before_transition(from:, to:, run: nil, &block) ⇒ Object
113 114 115 |
# File 'lib/nxt_state_machine/state_machine.rb', line 113 def before_transition(from:, to:, run: nil, &block) callbacks.register(from, to, :before, run, block) end |
#can_transition!(event, from) ⇒ Object
108 109 110 111 |
# File 'lib/nxt_state_machine/state_machine.rb', line 108 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
103 104 105 106 |
# File 'lib/nxt_state_machine/state_machine.rb', line 103 def can_transition?(event_name, from) event = events.resolve!(event_name) event && event.event_transitions.key?(from) end |
#configure(&block) ⇒ Object
141 142 143 144 |
# File 'lib/nxt_state_machine/state_machine.rb', line 141 def configure(&block) instance_exec(&block) self end |
#current_state_name(context) ⇒ Object
174 175 176 |
# File 'lib/nxt_state_machine/state_machine.rb', line 174 def current_state_name(context) Callable.new(get_state_with).bind(context).call(target(context)) end |
#defuse(errors = [], from:, to:) ⇒ Object
125 126 127 |
# File 'lib/nxt_state_machine/state_machine.rb', line 125 def defuse(errors = [], from:, to:) defuse_registry.register(from, to, errors) end |
#event(name, **options, &block) ⇒ Object
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/nxt_state_machine/state_machine.rb', line 84 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 |
#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
159 160 161 |
# File 'lib/nxt_state_machine/state_machine.rb', line 159 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
129 130 131 |
# File 'lib/nxt_state_machine/state_machine.rb', line 129 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
133 134 135 |
# File 'lib/nxt_state_machine/state_machine.rb', line 133 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
121 122 123 |
# File 'lib/nxt_state_machine/state_machine.rb', line 121 def on_success(from:, to:, run: nil, &block) callbacks.register(from, to, :success, run, block) end |
#run_after_callbacks(transition, context) ⇒ Object
151 152 153 |
# File 'lib/nxt_state_machine/state_machine.rb', line 151 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
147 148 149 |
# File 'lib/nxt_state_machine/state_machine.rb', line 147 def run_before_callbacks(transition, context) run_callbacks(transition, :before, context) end |
#run_callbacks(transition, kind, context) ⇒ Object
163 164 165 166 167 168 169 170 171 172 |
# File 'lib/nxt_state_machine/state_machine.rb', line 163 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
155 156 157 |
# File 'lib/nxt_state_machine/state_machine.rb', line 155 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
178 179 180 181 |
# File 'lib/nxt_state_machine/state_machine.rb', line 178 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 |