Module: StateMachines::AsyncMode::AsyncEvents
- Defined in:
- lib/state_machines/async_mode/async_events.rb
Overview
Async-aware event firing capabilities using the async gem
Instance Method Summary collapse
-
#async_fire_event(event_name, *args) ⇒ Object
Fires an event asynchronously using Async Returns an Async::Task that can be awaited for the result.
-
#async_fire_event!(event_name, *args) ⇒ Object
Fires an event asynchronously using Async and raises exception on failure Returns an Async::Task that raises StateMachines::InvalidTransition when awaited.
-
#async_fire_events(*event_names) ⇒ Object
Fires multiple events asynchronously across different state machines Returns an array of Async::Tasks for concurrent execution.
-
#fire_event_async(event_name, *args) ⇒ Object
Fires an event asynchronously and waits for completion This is a convenience method that creates and waits for the task.
-
#fire_event_async!(event_name, *args) ⇒ Object
Fires an event asynchronously and waits for result, raising exceptions on failure This is a convenience method that creates and waits for the task.
-
#fire_events_async(*event_names) ⇒ Object
Fires multiple events asynchronously and waits for all completions Returns results in the same order as the input events.
-
#fire_events_concurrent(*event_names) ⇒ Object
Fires multiple events concurrently within an async context This method should be called from within an Async block.
-
#has_async_machines? ⇒ Boolean
Check if this object has any async-enabled state machines.
-
#method_missing(method_name, *args, **kwargs, &block) ⇒ Object
Dynamically handle individual event async methods This provides launch_async, launch_async!, arm_weapons_async, etc.
-
#respond_to_missing?(method_name, include_private = false) ⇒ Boolean
Check if we should respond to async methods for this event.
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method_name, *args, **kwargs, &block) ⇒ Object
Dynamically handle individual event async methods This provides launch_async, launch_async!, arm_weapons_async, etc.
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/state_machines/async_mode/async_events.rb', line 154 def method_missing(method_name, *args, **kwargs, &block) method_str = method_name.to_s # Check if this is an async event method if method_str.end_with?('_async!') # Remove the _async! suffix to get the base event method base_method = method_str.chomp('_async!').to_sym # Check if the base method exists and this machine is async-enabled if respond_to?(base_method) && async_method_for_event?(base_method) return handle_individual_event_async_bang(base_method, *args, **kwargs) end elsif method_str.end_with?('_async') # Remove the _async suffix to get the base event method base_method = method_str.chomp('_async').to_sym # Check if the base method exists and this machine is async-enabled if respond_to?(base_method) && async_method_for_event?(base_method) return handle_individual_event_async(base_method, *args, **kwargs) end end # If not an async method, call the original method_missing super end |
Instance Method Details
#async_fire_event(event_name, *args) ⇒ Object
Fires an event asynchronously using Async Returns an Async::Task that can be awaited for the result
Example:
Async do
task = vehicle.async_fire_event(:ignite)
result = task.wait # => true/false
end
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/state_machines/async_mode/async_events.rb', line 15 def async_fire_event(event_name, *args) # Find the machine that has this event machine = self.class.state_machines.values.find { |m| m.events[event_name] } unless machine raise ArgumentError, "Event #{event_name} not found in any state machine" end # Must be called within an Async context unless defined?(::Async::Task) && ::Async::Task.current? raise RuntimeError, "async_fire_event must be called within an Async context. Use: Async { vehicle.async_fire_event(:event) }" end Async do machine.events[event_name].fire(self, *args) end end |
#async_fire_event!(event_name, *args) ⇒ Object
Fires an event asynchronously using Async and raises exception on failure Returns an Async::Task that raises StateMachines::InvalidTransition when awaited
Example:
Async do
begin
task = vehicle.async_fire_event!(:ignite)
result = task.wait
puts "Event fired successfully!"
rescue StateMachines::InvalidTransition => e
puts "Transition failed: #{e.}"
end
end
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/state_machines/async_mode/async_events.rb', line 103 def async_fire_event!(event_name, *args) # Find the machine that has this event machine = self.class.state_machines.values.find { |m| m.events[event_name] } unless machine raise ArgumentError, "Event #{event_name} not found in any state machine" end # Must be called within an Async context unless defined?(::Async::Task) && ::Async::Task.current? raise RuntimeError, "async_fire_event! must be called within an Async context. Use: Async { vehicle.async_fire_event!(:event) }" end Async do # Use the bang version which raises exceptions on failure machine.events[event_name].fire(self, *args) || raise(StateMachines::InvalidTransition.new(self, machine, event_name)) end end |
#async_fire_events(*event_names) ⇒ Object
Fires multiple events asynchronously across different state machines Returns an array of Async::Tasks for concurrent execution
Example:
Async do
tasks = vehicle.async_fire_events(:ignite, :buy_insurance)
results = tasks.map(&:wait) # => [true, true]
end
41 42 43 |
# File 'lib/state_machines/async_mode/async_events.rb', line 41 def async_fire_events(*event_names) event_names.map { |event_name| async_fire_event(event_name) } end |
#fire_event_async(event_name, *args) ⇒ Object
Fires an event asynchronously and waits for completion This is a convenience method that creates and waits for the task
Example:
result = vehicle.fire_event_async(:ignite) # => true/false
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/state_machines/async_mode/async_events.rb', line 50 def fire_event_async(event_name, *args) raise NoMethodError, "undefined method `fire_event_async' for #{self}" unless has_async_machines? # Find the machine that has this event machine = self.class.state_machines.values.find { |m| m.events[event_name] } unless machine raise ArgumentError, "Event #{event_name} not found in any state machine" end if defined?(::Async::Task) && ::Async::Task.current? # Already in async context, just fire directly machine.events[event_name].fire(self, *args) else # Create async context and wait for result Async do machine.events[event_name].fire(self, *args) end.wait end end |
#fire_event_async!(event_name, *args) ⇒ Object
Fires an event asynchronously and waits for result, raising exceptions on failure This is a convenience method that creates and waits for the task
Example:
begin
result = vehicle.fire_event_async!(:ignite)
puts "Event fired successfully!"
rescue StateMachines::InvalidTransition => e
puts "Transition failed: #{e.}"
end
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/state_machines/async_mode/async_events.rb', line 132 def fire_event_async!(event_name, *args) raise NoMethodError, "undefined method `fire_event_async!' for #{self}" unless has_async_machines? # Find the machine that has this event machine = self.class.state_machines.values.find { |m| m.events[event_name] } unless machine raise ArgumentError, "Event #{event_name} not found in any state machine" end if defined?(::Async::Task) && ::Async::Task.current? # Already in async context, just fire directly with bang behavior machine.events[event_name].fire(self, *args) || raise(StateMachines::InvalidTransition.new(self, machine, event_name)) else # Create async context and wait for result (may raise exception) Async do machine.events[event_name].fire(self, *args) || raise(StateMachines::InvalidTransition.new(self, machine, event_name)) end.wait end end |
#fire_events_async(*event_names) ⇒ Object
Fires multiple events asynchronously and waits for all completions Returns results in the same order as the input events
Example:
results = vehicle.fire_events_async(:ignite, :buy_insurance) # => [true, true]
75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/state_machines/async_mode/async_events.rb', line 75 def fire_events_async(*event_names) raise NoMethodError, "undefined method `fire_events_async' for #{self}" unless has_async_machines? if defined?(::Async::Task) && ::Async::Task.current? # Already in async context, run concurrently tasks = event_names.map { |event_name| async_fire_event(event_name) } tasks.map(&:wait) else # Create async context and run concurrently Async do tasks = event_names.map { |event_name| async_fire_event(event_name) } tasks.map(&:wait) end.wait end end |
#fire_events_concurrent(*event_names) ⇒ Object
Fires multiple events concurrently within an async context This method should be called from within an Async block
Example:
Async do
results = vehicle.fire_events_concurrent(:ignite, :buy_insurance)
end
272 273 274 275 276 277 278 279 |
# File 'lib/state_machines/async_mode/async_events.rb', line 272 def fire_events_concurrent(*event_names) unless defined?(::Async::Task) && ::Async::Task.current? raise RuntimeError, "fire_events_concurrent must be called within an Async context" end tasks = async_fire_events(*event_names) tasks.map(&:wait) end |
#has_async_machines? ⇒ Boolean
Check if this object has any async-enabled state machines
196 197 198 |
# File 'lib/state_machines/async_mode/async_events.rb', line 196 def has_async_machines? self.class.state_machines.any? { |name, machine| machine.async_mode_enabled? } end |
#respond_to_missing?(method_name, include_private = false) ⇒ Boolean
Check if we should respond to async methods for this event
181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/state_machines/async_mode/async_events.rb', line 181 def respond_to_missing?(method_name, include_private = false) # Only provide async methods if this object has async-enabled machines return super unless has_async_machines? method_str = method_name.to_s if method_str.end_with?('_async!') || method_str.end_with?('_async') base_method = method_str.chomp('_async!').chomp('_async').to_sym return respond_to?(base_method) && async_method_for_event?(base_method) end super end |