state_machines 0.201.0 → 0.202.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/state_machines/async_mode/async_events.rb +8 -4
- data/lib/state_machines/machine/utilities.rb +27 -0
- data/lib/state_machines/machine.rb +2 -3
- data/lib/state_machines/state.rb +3 -3
- data/lib/state_machines/transition.rb +10 -8
- data/lib/state_machines/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e579c5afa633f1402bfd1e1a5ebd0c446ff410eb3b06940d74dce0d0e024f530
|
|
4
|
+
data.tar.gz: 629c2f403c71e966e98c5d35c64fa8ffa99caaa8e5aced5e205a569eb867e811
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1bf56f62b3f6e495fc799ba48d499c0bb7325dfdb3c24d1f8aafc2c9daaade581bef63495e8562a633ee32d2ca3870e8e8131052d97bb152c793ab86f0a3c0fb
|
|
7
|
+
data.tar.gz: f2ae6e891727b60a4310160fbfa7044b4b949a8bccb9f8f80d7d3733dda6e528bf14f3449e7ab420b35d84ef971a6e6349e43a162e16b735e0be61e2ae7571be
|
|
@@ -114,8 +114,7 @@ module StateMachines
|
|
|
114
114
|
end
|
|
115
115
|
|
|
116
116
|
Async do
|
|
117
|
-
|
|
118
|
-
machine.events[event_name].fire(self, *args) || raise(StateMachines::InvalidTransition.new(self, machine, event_name))
|
|
117
|
+
fire_with_bang(machine, event_name, *args)
|
|
119
118
|
end
|
|
120
119
|
end
|
|
121
120
|
|
|
@@ -140,11 +139,11 @@ module StateMachines
|
|
|
140
139
|
|
|
141
140
|
if defined?(::Async::Task) && ::Async::Task.current?
|
|
142
141
|
# Already in async context, just fire directly with bang behavior
|
|
143
|
-
machine
|
|
142
|
+
fire_with_bang(machine, event_name, *args)
|
|
144
143
|
else
|
|
145
144
|
# Create async context and wait for result (may raise exception)
|
|
146
145
|
Async do
|
|
147
|
-
machine
|
|
146
|
+
fire_with_bang(machine, event_name, *args)
|
|
148
147
|
end.wait
|
|
149
148
|
end
|
|
150
149
|
end
|
|
@@ -199,6 +198,11 @@ module StateMachines
|
|
|
199
198
|
|
|
200
199
|
private
|
|
201
200
|
|
|
201
|
+
# Fires the event on the given machine, raising InvalidTransition on failure
|
|
202
|
+
def fire_with_bang(machine, event_name, *)
|
|
203
|
+
machine.events[event_name].fire(self, *) || raise(StateMachines::InvalidTransition.new(self, machine, event_name))
|
|
204
|
+
end
|
|
205
|
+
|
|
202
206
|
# Check if this event method should have async versions
|
|
203
207
|
def async_method_for_event?(event_method)
|
|
204
208
|
# Find which machine contains this event
|
|
@@ -55,6 +55,33 @@ module StateMachines
|
|
|
55
55
|
target.method_defined?(method) || target.private_method_defined?(method)
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
+
# Generates the warning message for a method conflict, including where
|
|
59
|
+
# the conflicting method was defined (when it has a Ruby source
|
|
60
|
+
# location) and which class the state machine is being defined on
|
|
61
|
+
def method_conflict_message(scope, method, defined_in)
|
|
62
|
+
scope_label = scope == :class ? 'Class' : 'Instance'
|
|
63
|
+
defined_in_name = defined_in.name && !defined_in.name.empty? ? defined_in.name : defined_in.to_s
|
|
64
|
+
location = conflicting_method_location(scope, method, defined_in)
|
|
65
|
+
location_label = location ? " at #{location[0]}:#{location[1]}" : ''
|
|
66
|
+
|
|
67
|
+
"#{scope_label} method \"#{method}\" is already defined in #{defined_in_name}#{location_label}, " \
|
|
68
|
+
'use generic helper instead or set StateMachines::Machine.ignore_method_conflicts = true. ' \
|
|
69
|
+
"Defining #{name.inspect} state machine on #{owner_class}."
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Looks up the source location of the conflicting method. Returns nil
|
|
73
|
+
# for methods without a Ruby source (e.g. C-defined methods like
|
|
74
|
+
# Kernel#fail) and for the machine's own helper modules, where the
|
|
75
|
+
# location would just point inside this gem
|
|
76
|
+
def conflicting_method_location(scope, method, defined_in)
|
|
77
|
+
return if @helper_modules.value?(defined_in)
|
|
78
|
+
|
|
79
|
+
target = scope == :class && defined_in.is_a?(Class) ? defined_in.singleton_class : defined_in
|
|
80
|
+
target.instance_method(method).source_location
|
|
81
|
+
rescue NameError
|
|
82
|
+
nil
|
|
83
|
+
end
|
|
84
|
+
|
|
58
85
|
# Pluralizes the given word using #pluralize (if available) or simply
|
|
59
86
|
# adding an "s" to the end of the word
|
|
60
87
|
def pluralize(word)
|
|
@@ -355,7 +355,7 @@ module StateMachines
|
|
|
355
355
|
# module that gets included in every Object. As a result, state_machine will
|
|
356
356
|
# generate the following warning:
|
|
357
357
|
#
|
|
358
|
-
# Instance method "open" is already defined in Object, use generic helper instead or set StateMachines::Machine.ignore_method_conflicts = true.
|
|
358
|
+
# Instance method "open" is already defined in Object, use generic helper instead or set StateMachines::Machine.ignore_method_conflicts = true. Defining :state state machine on Vehicle.
|
|
359
359
|
#
|
|
360
360
|
# Even though you may not be using Kernel's implementation of the "open"
|
|
361
361
|
# instance method, state_machine isn't aware of this and, as a result, stays
|
|
@@ -517,8 +517,7 @@ module StateMachines
|
|
|
517
517
|
|
|
518
518
|
if block_given?
|
|
519
519
|
if !self.class.ignore_method_conflicts && (conflicting_ancestor = owner_class_ancestor_has_method?(scope, method))
|
|
520
|
-
|
|
521
|
-
warn "#{scope == :class ? 'Class' : 'Instance'} method \"#{method}\" is already defined in #{ancestor_name}, use generic helper instead or set StateMachines::Machine.ignore_method_conflicts = true."
|
|
520
|
+
warn method_conflict_message(scope, method, conflicting_ancestor)
|
|
522
521
|
else
|
|
523
522
|
name = self.name
|
|
524
523
|
helper_module.class_eval do
|
data/lib/state_machines/state.rb
CHANGED
|
@@ -289,8 +289,8 @@ module StateMachines
|
|
|
289
289
|
def add_predicate
|
|
290
290
|
predicate_method = "#{qualified_name}?"
|
|
291
291
|
|
|
292
|
-
if machine.send(:owner_class_ancestor_has_method?, :instance, predicate_method)
|
|
293
|
-
warn_about_method_conflict(predicate_method,
|
|
292
|
+
if (conflicting_ancestor = machine.send(:owner_class_ancestor_has_method?, :instance, predicate_method))
|
|
293
|
+
warn_about_method_conflict(predicate_method, conflicting_ancestor)
|
|
294
294
|
elsif machine.send(:owner_class_has_method?, :instance, predicate_method)
|
|
295
295
|
warn_about_method_conflict(predicate_method, machine.owner_class)
|
|
296
296
|
else
|
|
@@ -308,7 +308,7 @@ module StateMachines
|
|
|
308
308
|
def warn_about_method_conflict(method, defined_in)
|
|
309
309
|
return if StateMachines::Machine.ignore_method_conflicts
|
|
310
310
|
|
|
311
|
-
warn
|
|
311
|
+
warn machine.send(:method_conflict_message, :instance, method, defined_in)
|
|
312
312
|
end
|
|
313
313
|
end
|
|
314
314
|
end
|
|
@@ -407,9 +407,7 @@ module StateMachines
|
|
|
407
407
|
else
|
|
408
408
|
# Capture current fiber's Thread.current storage to preserve object identity
|
|
409
409
|
# This is needed for compatibility but has limitations with dynamic assignments
|
|
410
|
-
parent_fiber_locals =
|
|
411
|
-
storage[key] = Thread.current[key]
|
|
412
|
-
end
|
|
410
|
+
parent_fiber_locals = capture_thread_locals
|
|
413
411
|
|
|
414
412
|
# Create a new fiber to run the block
|
|
415
413
|
fiber = Fiber.new do
|
|
@@ -428,11 +426,7 @@ module StateMachines
|
|
|
428
426
|
end
|
|
429
427
|
|
|
430
428
|
# Export the final thread storage state along with the result
|
|
431
|
-
|
|
432
|
-
storage[key] = Thread.current[key]
|
|
433
|
-
end
|
|
434
|
-
|
|
435
|
-
[halted ? :halted : :completed, thread_storage]
|
|
429
|
+
[halted ? :halted : :completed, capture_thread_locals]
|
|
436
430
|
rescue StandardError => e
|
|
437
431
|
# Store the exception for re-raising
|
|
438
432
|
[:error, e]
|
|
@@ -459,6 +453,14 @@ module StateMachines
|
|
|
459
453
|
end
|
|
460
454
|
end
|
|
461
455
|
|
|
456
|
+
# Snapshots the current fiber's Thread.current storage, preserving object
|
|
457
|
+
# identity of the stored values
|
|
458
|
+
def capture_thread_locals
|
|
459
|
+
Thread.current.keys.each_with_object({}) do |key, storage|
|
|
460
|
+
storage[key] = Thread.current[key]
|
|
461
|
+
end
|
|
462
|
+
end
|
|
463
|
+
|
|
462
464
|
# Unwraps a result returned from a pausable fiber, re-raising any exception
|
|
463
465
|
# captured inside the fiber and importing its exported thread storage
|
|
464
466
|
def unwrap_fiber_result(result)
|