state_machine 0.7.5 → 0.7.6
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +10 -0
- data/README.rdoc +1 -1
- data/Rakefile +9 -2
- data/lib/state_machine.rb +17 -12
- data/lib/state_machine/assertions.rb +4 -5
- data/lib/state_machine/callback.rb +27 -21
- data/lib/state_machine/condition_proxy.rb +1 -1
- data/lib/state_machine/eval_helpers.rb +1 -2
- data/lib/state_machine/event.rb +3 -3
- data/lib/state_machine/event_collection.rb +5 -6
- data/lib/state_machine/integrations/active_record.rb +25 -16
- data/lib/state_machine/integrations/active_record/locale.rb +1 -0
- data/lib/state_machine/integrations/data_mapper.rb +6 -9
- data/lib/state_machine/integrations/data_mapper/observer.rb +5 -5
- data/lib/state_machine/integrations/sequel.rb +5 -7
- data/lib/state_machine/machine.rb +65 -55
- data/lib/state_machine/machine_collection.rb +15 -17
- data/lib/state_machine/matcher_helpers.rb +1 -0
- data/lib/state_machine/state.rb +6 -4
- data/lib/state_machine/state_collection.rb +3 -3
- data/lib/state_machine/transition.rb +3 -3
- data/test/unit/eval_helpers_test.rb +18 -0
- data/test/unit/event_collection_test.rb +30 -0
- data/test/unit/integrations/active_record_test.rb +78 -8
- data/test/unit/integrations/data_mapper_test.rb +77 -0
- data/test/unit/integrations/sequel_test.rb +54 -2
- data/test/unit/machine_collection_test.rb +20 -0
- data/test/unit/machine_test.rb +154 -5
- data/test/unit/state_test.rb +17 -3
- data/test/unit/transition_test.rb +27 -0
- metadata +2 -2
@@ -109,19 +109,19 @@ module StateMachine
|
|
109
109
|
# state machines for each observed class.
|
110
110
|
def add_transition_callback(type, *args, &block)
|
111
111
|
if args.any? && !args.first.is_a?(Hash)
|
112
|
-
# Specific
|
113
|
-
|
112
|
+
# Specific machine(s) being targeted
|
113
|
+
names = args
|
114
114
|
args = args.last.is_a?(Hash) ? [args.pop] : []
|
115
115
|
else
|
116
116
|
# Target all state machines
|
117
|
-
|
117
|
+
names = nil
|
118
118
|
end
|
119
119
|
|
120
120
|
# Add the transition callback to each class being observed
|
121
121
|
observing.each do |klass|
|
122
122
|
state_machines =
|
123
|
-
if
|
124
|
-
|
123
|
+
if names
|
124
|
+
names.map {|name| klass.state_machines.fetch(name)}
|
125
125
|
else
|
126
126
|
klass.state_machines.values
|
127
127
|
end
|
@@ -84,17 +84,14 @@ module StateMachine
|
|
84
84
|
# you can build two state machines (one public and one protected) like so:
|
85
85
|
#
|
86
86
|
# class Vehicle < Sequel::Model
|
87
|
-
# # Allow both machines to share the same state
|
88
|
-
# alias_method :public_state, :state
|
89
|
-
# alias_method :public_state=, :state=
|
90
|
-
#
|
91
87
|
# set_restricted_columns :state_event # Prevent access to events in the first machine
|
92
88
|
#
|
93
89
|
# state_machine do
|
94
90
|
# # Define private events here
|
95
91
|
# end
|
96
92
|
#
|
97
|
-
#
|
93
|
+
# # Allow both machines to share the same state
|
94
|
+
# state_machine :public_state, :attribute => :state do
|
98
95
|
# # Define public events here
|
99
96
|
# end
|
100
97
|
# end
|
@@ -231,7 +228,7 @@ module StateMachine
|
|
231
228
|
|
232
229
|
# Adds a validation error to the given object
|
233
230
|
def invalidate(object, attribute, message, values = [])
|
234
|
-
object.errors.add(attribute, generate_message(message, values))
|
231
|
+
object.errors.add(self.attribute(attribute), generate_message(message, values))
|
235
232
|
end
|
236
233
|
|
237
234
|
# Resets any errors previously added when invalidating the given object
|
@@ -242,8 +239,9 @@ module StateMachine
|
|
242
239
|
protected
|
243
240
|
# Skips defining reader/writer methods since this is done automatically
|
244
241
|
def define_state_accessor
|
242
|
+
name = self.name
|
245
243
|
owner_class.validates_each(attribute) do |record, attr, value|
|
246
|
-
machine = record.class.state_machine(
|
244
|
+
machine = record.class.state_machine(name)
|
247
245
|
machine.invalidate(record, attr, :invalid) unless machine.states.match(record)
|
248
246
|
end
|
249
247
|
end
|
@@ -113,14 +113,14 @@ module StateMachine
|
|
113
113
|
#
|
114
114
|
# Callbacks are supported for hooking before and after every possible
|
115
115
|
# transition in the machine. Each callback is invoked in the order in which
|
116
|
-
# it was defined. See StateMachine::Machine#before_transition
|
117
|
-
#
|
118
|
-
#
|
116
|
+
# it was defined. See StateMachine::Machine#before_transition and
|
117
|
+
# StateMachine::Machine#after_transition for documentation on how to define
|
118
|
+
# new callbacks.
|
119
119
|
#
|
120
|
-
# *Note* that callbacks only get executed within the context of an event.
|
121
|
-
#
|
122
|
-
#
|
123
|
-
#
|
120
|
+
# *Note* that callbacks only get executed within the context of an event. As
|
121
|
+
# a result, if a class has an initial state when it's created, any callbacks
|
122
|
+
# that would normally get executed when the object enters that state will
|
123
|
+
# *not* get triggered.
|
124
124
|
#
|
125
125
|
# For example,
|
126
126
|
#
|
@@ -229,7 +229,7 @@ module StateMachine
|
|
229
229
|
#
|
230
230
|
# [Vehicle, Switch, Project].each do |klass|
|
231
231
|
# klass.state_machines.each do |attribute, machine|
|
232
|
-
# machine.before_transition
|
232
|
+
# machine.before_transition StateMachineObserver.method(:before_transition)
|
233
233
|
# end
|
234
234
|
# end
|
235
235
|
#
|
@@ -300,10 +300,10 @@ module StateMachine
|
|
300
300
|
# in the new owner class (the original will remain unchanged).
|
301
301
|
def find_or_create(owner_class, *args, &block)
|
302
302
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
303
|
-
|
303
|
+
name = args.first || :state
|
304
304
|
|
305
305
|
# Find an existing machine
|
306
|
-
if owner_class.respond_to?(:state_machines) && machine = owner_class.state_machines[
|
306
|
+
if owner_class.respond_to?(:state_machines) && machine = owner_class.state_machines[name]
|
307
307
|
# Only create a new copy if changes are being made to the machine in
|
308
308
|
# a subclass
|
309
309
|
if machine.owner_class != owner_class && (options.any? || block_given?)
|
@@ -316,7 +316,7 @@ module StateMachine
|
|
316
316
|
machine.instance_eval(&block) if block_given?
|
317
317
|
else
|
318
318
|
# No existing machine: create a new one
|
319
|
-
machine = new(owner_class,
|
319
|
+
machine = new(owner_class, name, options, &block)
|
320
320
|
end
|
321
321
|
|
322
322
|
machine
|
@@ -347,7 +347,7 @@ module StateMachine
|
|
347
347
|
end
|
348
348
|
|
349
349
|
# Draw each of the class's state machines
|
350
|
-
klass.state_machines.
|
350
|
+
klass.state_machines.each_value do |machine|
|
351
351
|
machine.draw(options)
|
352
352
|
end
|
353
353
|
end
|
@@ -365,8 +365,9 @@ module StateMachine
|
|
365
365
|
# The class that the machine is defined in
|
366
366
|
attr_accessor :owner_class
|
367
367
|
|
368
|
-
# The
|
369
|
-
|
368
|
+
# The name of the machine, used for scoping methods generated for the
|
369
|
+
# machine as a whole (not states or events)
|
370
|
+
attr_reader :name
|
370
371
|
|
371
372
|
# The events that trigger transitions. These are sorted, by default, in
|
372
373
|
# the order in which they were defined.
|
@@ -402,7 +403,7 @@ module StateMachine
|
|
402
403
|
# Creates a new state machine for the given attribute
|
403
404
|
def initialize(owner_class, *args, &block)
|
404
405
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
405
|
-
assert_valid_keys(options, :initial, :action, :plural, :namespace, :integration, :messages, :use_transactions)
|
406
|
+
assert_valid_keys(options, :attribute, :initial, :action, :plural, :namespace, :integration, :messages, :use_transactions)
|
406
407
|
|
407
408
|
# Find an integration that matches this machine's owner class
|
408
409
|
if integration = options[:integration] ? StateMachine::Integrations.find(options[:integration]) : StateMachine::Integrations.match(owner_class)
|
@@ -414,7 +415,8 @@ module StateMachine
|
|
414
415
|
options = {:use_transactions => true}.merge(options)
|
415
416
|
|
416
417
|
# Set machine configuration
|
417
|
-
@
|
418
|
+
@name = args.first || :state
|
419
|
+
@attribute = options[:attribute] || @name
|
418
420
|
@events = EventCollection.new(self)
|
419
421
|
@states = StateCollection.new(self)
|
420
422
|
@callbacks = {:before => [], :after => []}
|
@@ -467,10 +469,9 @@ module StateMachine
|
|
467
469
|
include instance_helper_module
|
468
470
|
end
|
469
471
|
|
470
|
-
# Record this machine as matched to the
|
471
|
-
#
|
472
|
-
|
473
|
-
owner_class.state_machines[attribute] = self
|
472
|
+
# Record this machine as matched to the name in the current owner class.
|
473
|
+
# This will override any machines mapped to the same name in any superclasses.
|
474
|
+
owner_class.state_machines[name] = self
|
474
475
|
end
|
475
476
|
|
476
477
|
# Sets the initial state of the machine. This can be either the static name
|
@@ -484,22 +485,27 @@ module StateMachine
|
|
484
485
|
states.each {|state| state.initial = (state.name == @initial_state)}
|
485
486
|
end
|
486
487
|
|
488
|
+
# Gets the actual name of the attribute on the machine's owner class that
|
489
|
+
# stores data with the given name.
|
490
|
+
def attribute(name = :state)
|
491
|
+
name == :state ? @attribute : :"#{self.name}_#{name}"
|
492
|
+
end
|
493
|
+
|
487
494
|
# Defines a new instance method with the given name on the machine's owner
|
488
495
|
# class. If the method is already defined in the class, then this will not
|
489
496
|
# override it.
|
490
497
|
#
|
491
498
|
# Example:
|
492
499
|
#
|
493
|
-
# attribute = machine.attribute
|
494
500
|
# machine.define_instance_method(:state_name) do |machine, object|
|
495
501
|
# machine.states.match(object)
|
496
502
|
# end
|
497
503
|
def define_instance_method(method, &block)
|
498
|
-
|
504
|
+
name = self.name
|
499
505
|
|
500
506
|
@instance_helper_module.class_eval do
|
501
507
|
define_method(method) do |*args|
|
502
|
-
block.call(self.class.state_machine(
|
508
|
+
block.call(self.class.state_machine(name), self, *args)
|
503
509
|
end
|
504
510
|
end
|
505
511
|
end
|
@@ -515,11 +521,11 @@ module StateMachine
|
|
515
521
|
# machine.states.keys
|
516
522
|
# end
|
517
523
|
def define_class_method(method, &block)
|
518
|
-
|
524
|
+
name = self.name
|
519
525
|
|
520
526
|
@class_helper_module.class_eval do
|
521
527
|
define_method(method) do |*args|
|
522
|
-
block.call(self.state_machine(
|
528
|
+
block.call(self.state_machine(name), self, *args)
|
523
529
|
end
|
524
530
|
end
|
525
531
|
end
|
@@ -616,7 +622,7 @@ module StateMachine
|
|
616
622
|
# end
|
617
623
|
#
|
618
624
|
# class Vehicle < ActiveRecord::Base
|
619
|
-
# state_machine :state_id, :initial => :parked do
|
625
|
+
# state_machine :attribute => :state_id, :initial => :parked do
|
620
626
|
# event :ignite do
|
621
627
|
# transition :parked => :idling
|
622
628
|
# end
|
@@ -824,7 +830,7 @@ module StateMachine
|
|
824
830
|
end
|
825
831
|
alias_method :other_states, :state
|
826
832
|
|
827
|
-
# Gets the current value stored in the given object's
|
833
|
+
# Gets the current value stored in the given object's attribute.
|
828
834
|
#
|
829
835
|
# For example,
|
830
836
|
#
|
@@ -834,13 +840,15 @@ module StateMachine
|
|
834
840
|
# end
|
835
841
|
# end
|
836
842
|
#
|
837
|
-
# vehicle = Vehicle.new
|
838
|
-
# Vehicle.state_machine.read(vehicle)
|
839
|
-
|
840
|
-
|
843
|
+
# vehicle = Vehicle.new # => #<Vehicle:0xb7d94ab0 @state="parked">
|
844
|
+
# Vehicle.state_machine.read(vehicle, :state) # => "parked" # Equivalent to vehicle.state
|
845
|
+
# Vehicle.state_machine.read(vehicle, :event) # => nil # Equivalent to vehicle.state_event
|
846
|
+
def read(object, attribute, ivar = false)
|
847
|
+
attribute = self.attribute(attribute)
|
848
|
+
ivar ? object.instance_variable_get("@#{attribute}") : object.send(attribute)
|
841
849
|
end
|
842
850
|
|
843
|
-
# Sets a new value in the given object's
|
851
|
+
# Sets a new value in the given object's attribute.
|
844
852
|
#
|
845
853
|
# For example,
|
846
854
|
#
|
@@ -850,11 +858,13 @@ module StateMachine
|
|
850
858
|
# end
|
851
859
|
# end
|
852
860
|
#
|
853
|
-
# vehicle = Vehicle.new
|
854
|
-
# Vehicle.state_machine.write(vehicle, 'idling')
|
855
|
-
# vehicle
|
856
|
-
|
857
|
-
|
861
|
+
# vehicle = Vehicle.new # => #<Vehicle:0xb7d94ab0 @state="parked">
|
862
|
+
# Vehicle.state_machine.write(vehicle, :state, 'idling') # => Equivalent to vehicle.state = 'idling'
|
863
|
+
# Vehicle.state_machine.write(vehicle, :event, 'park') # => Equivalent to vehicle.state_event = 'park'
|
864
|
+
# vehicle.state # => "idling"
|
865
|
+
# vehicle.event # => "park"
|
866
|
+
def write(object, attribute, value)
|
867
|
+
object.send("#{self.attribute(attribute)}=", value)
|
858
868
|
end
|
859
869
|
|
860
870
|
# Defines one or more events for the machine and the transitions that can
|
@@ -1112,12 +1122,12 @@ module StateMachine
|
|
1112
1122
|
#
|
1113
1123
|
# class Vehicle
|
1114
1124
|
# # Only specifies one parameter (the object being transitioned)
|
1115
|
-
# before_transition
|
1125
|
+
# before_transition all => :parked do |vehicle|
|
1116
1126
|
# vehicle.set_alarm
|
1117
1127
|
# end
|
1118
1128
|
#
|
1119
1129
|
# # Specifies 2 parameters (object being transitioned and actual transition)
|
1120
|
-
# before_transition
|
1130
|
+
# before_transition all => :parked do |vehicle, transition|
|
1121
1131
|
# vehicle.set_alarm(transition)
|
1122
1132
|
# end
|
1123
1133
|
# end
|
@@ -1143,7 +1153,7 @@ module StateMachine
|
|
1143
1153
|
# before_transition [:first_gear, :idling] => :parked, :on => :park, :do => :take_off_seatbelt
|
1144
1154
|
#
|
1145
1155
|
# # With conditional callback:
|
1146
|
-
# before_transition
|
1156
|
+
# before_transition all => :parked, :do => :take_off_seatbelt, :if => :seatbelt_on?
|
1147
1157
|
#
|
1148
1158
|
# # Using helpers:
|
1149
1159
|
# before_transition all - :stalled => same, :on => any - :crash, :do => :update_dashboard
|
@@ -1205,7 +1215,7 @@ module StateMachine
|
|
1205
1215
|
#
|
1206
1216
|
# Configuration options:
|
1207
1217
|
# * <tt>:name</tt> - The name of the file to write to (without the file extension).
|
1208
|
-
# Default is "#{owner_class.name}_#{
|
1218
|
+
# Default is "#{owner_class.name}_#{name}"
|
1209
1219
|
# * <tt>:path</tt> - The path to write the graph file to. Default is the
|
1210
1220
|
# current directory (".").
|
1211
1221
|
# * <tt>:format</tt> - The image format to generate the graph in.
|
@@ -1217,7 +1227,7 @@ module StateMachine
|
|
1217
1227
|
# * <tt>:output</tt> - Whether to generate the output of the graph
|
1218
1228
|
def draw(options = {})
|
1219
1229
|
options = {
|
1220
|
-
:name => "#{owner_class.name}_#{
|
1230
|
+
:name => "#{owner_class.name}_#{name}",
|
1221
1231
|
:path => '.',
|
1222
1232
|
:format => 'png',
|
1223
1233
|
:font => 'Arial',
|
@@ -1272,7 +1282,7 @@ module StateMachine
|
|
1272
1282
|
define_action_helpers if action
|
1273
1283
|
|
1274
1284
|
# Gets the state name for the current value
|
1275
|
-
define_instance_method(
|
1285
|
+
define_instance_method(attribute(:name)) do |machine, object|
|
1276
1286
|
machine.states.match!(object).name
|
1277
1287
|
end
|
1278
1288
|
end
|
@@ -1289,7 +1299,7 @@ module StateMachine
|
|
1289
1299
|
# Adds predicate method to the owner class for determining the name of the
|
1290
1300
|
# current state
|
1291
1301
|
def define_state_predicate
|
1292
|
-
define_instance_method("#{
|
1302
|
+
define_instance_method("#{name}?") do |machine, object, state|
|
1293
1303
|
machine.states.matches?(object, state)
|
1294
1304
|
end
|
1295
1305
|
end
|
@@ -1298,31 +1308,31 @@ module StateMachine
|
|
1298
1308
|
# events
|
1299
1309
|
def define_event_helpers
|
1300
1310
|
# Gets the events that are allowed to fire on the current object
|
1301
|
-
define_instance_method(
|
1311
|
+
define_instance_method(attribute(:events)) do |machine, object|
|
1302
1312
|
machine.events.valid_for(object).map {|event| event.name}
|
1303
1313
|
end
|
1304
1314
|
|
1305
1315
|
# Gets the next possible transitions that can be run on the current
|
1306
1316
|
# object
|
1307
|
-
define_instance_method(
|
1317
|
+
define_instance_method(attribute(:transitions)) do |machine, object, *args|
|
1308
1318
|
machine.events.transitions_for(object, *args)
|
1309
1319
|
end
|
1310
1320
|
|
1311
1321
|
# Add helpers for interacting with the action
|
1312
1322
|
if action
|
1313
|
-
attribute = self.attribute
|
1314
|
-
|
1315
1323
|
# Tracks the event / transition to invoke when the action is called
|
1324
|
+
event_attribute = attribute(:event)
|
1325
|
+
event_transition_attribute = attribute(:event_transition)
|
1316
1326
|
@instance_helper_module.class_eval do
|
1317
|
-
attr_writer
|
1327
|
+
attr_writer event_attribute
|
1318
1328
|
|
1319
1329
|
protected
|
1320
|
-
attr_accessor
|
1330
|
+
attr_accessor event_transition_attribute
|
1321
1331
|
end
|
1322
1332
|
|
1323
1333
|
# Interpret non-blank events as present
|
1324
|
-
define_instance_method(
|
1325
|
-
event =
|
1334
|
+
define_instance_method(attribute(:event)) do |machine, object|
|
1335
|
+
event = machine.read(object, :event, true)
|
1326
1336
|
event && !(event.respond_to?(:empty?) && event.empty?) ? event.to_sym : nil
|
1327
1337
|
end
|
1328
1338
|
end
|
@@ -1334,7 +1344,7 @@ module StateMachine
|
|
1334
1344
|
action = self.action
|
1335
1345
|
private_method = owner_class.private_method_defined?(action_hook)
|
1336
1346
|
|
1337
|
-
if (owner_class.method_defined?(action_hook) || private_method) && !owner_class.state_machines.any? {|
|
1347
|
+
if (owner_class.method_defined?(action_hook) || private_method) && !owner_class.state_machines.any? {|name, machine| machine.action == action && machine != self}
|
1338
1348
|
# Action is defined and hasn't already been overridden by another machine
|
1339
1349
|
@instance_helper_module.class_eval do
|
1340
1350
|
# Override the default action to invoke the before / after hooks
|
@@ -1358,9 +1368,9 @@ module StateMachine
|
|
1358
1368
|
# automatically determined by either calling +pluralize+ on the attribute
|
1359
1369
|
# name or adding an "s" to the end of the name.
|
1360
1370
|
def define_scopes(custom_plural = nil)
|
1361
|
-
plural = custom_plural || (
|
1371
|
+
plural = custom_plural || (name.to_s.respond_to?(:pluralize) ? name.to_s.pluralize : "#{name}s")
|
1362
1372
|
|
1363
|
-
[
|
1373
|
+
[name, plural].uniq.each do |name|
|
1364
1374
|
[:with, :without].each do |kind|
|
1365
1375
|
method = "#{kind}_#{name}"
|
1366
1376
|
|
@@ -5,9 +5,9 @@ module StateMachine
|
|
5
5
|
# values are only set if the machine's attribute doesn't already exist
|
6
6
|
# (which must mean the defaults are being skipped)
|
7
7
|
def initialize_states(object)
|
8
|
-
|
9
|
-
value = machine.read(object)
|
10
|
-
machine.write(object, machine.initial_state(object).value) if value.nil? || value.respond_to?(:empty?) && value.empty?
|
8
|
+
each_value do |machine|
|
9
|
+
value = machine.read(object, :state)
|
10
|
+
machine.write(object, :state, machine.initial_state(object).value) if value.nil? || value.respond_to?(:empty?) && value.empty?
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
@@ -17,19 +17,19 @@ module StateMachine
|
|
17
17
|
run_action = [true, false].include?(events.last) ? events.pop : true
|
18
18
|
|
19
19
|
# Generate the transitions to run for each event
|
20
|
-
transitions = events.collect do |
|
20
|
+
transitions = events.collect do |event_name|
|
21
21
|
# Find the actual event being run
|
22
22
|
event = nil
|
23
|
-
detect do |
|
24
|
-
event = machine.events[
|
23
|
+
detect do |name, machine|
|
24
|
+
event = machine.events[event_name, :qualified_name]
|
25
25
|
end
|
26
26
|
|
27
|
-
raise InvalidEvent, "#{
|
27
|
+
raise InvalidEvent, "#{event_name.inspect} is an unknown state machine event" unless event
|
28
28
|
|
29
29
|
# Get the transition that will be performed for the event
|
30
30
|
unless transition = event.transition_for(object)
|
31
31
|
machine = event.machine
|
32
|
-
machine.invalidate(object,
|
32
|
+
machine.invalidate(object, :state, :invalid_transition, [[:event, event_name]])
|
33
33
|
end
|
34
34
|
|
35
35
|
transition
|
@@ -107,7 +107,7 @@ module StateMachine
|
|
107
107
|
# vehicle.state_event_transition # => #<StateMachine::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>
|
108
108
|
def fire_event_attributes(object, action, complete = true)
|
109
109
|
# Get the transitions to fire for each applicable machine
|
110
|
-
transitions = map {|
|
110
|
+
transitions = map {|name, machine| machine.action == action ? machine.events.attribute_transition_for(object, true) : nil}.compact
|
111
111
|
return yield if transitions.empty?
|
112
112
|
|
113
113
|
# The value generated by the yielded block (the actual action)
|
@@ -118,27 +118,25 @@ module StateMachine
|
|
118
118
|
begin
|
119
119
|
result = Transition.perform(transitions, :after => complete) do
|
120
120
|
# Prevent events from being evaluated multiple times if actions are nested
|
121
|
-
transitions.each {|transition|
|
121
|
+
transitions.each {|transition| transition.machine.write(object, :event, nil)}
|
122
122
|
action_value = yield
|
123
123
|
end
|
124
124
|
rescue Exception
|
125
|
-
# Revert
|
125
|
+
# Revert object modifications
|
126
126
|
transitions.each do |transition|
|
127
|
-
|
128
|
-
|
127
|
+
transition.machine.write(object, :event, transition.event)
|
128
|
+
transition.machine.write(object, :event_transition, nil) if complete
|
129
129
|
end
|
130
130
|
|
131
131
|
raise
|
132
132
|
end
|
133
133
|
|
134
134
|
transitions.each do |transition|
|
135
|
-
attribute = transition.attribute
|
136
|
-
|
137
135
|
# Revert event unless transition was successful
|
138
|
-
|
136
|
+
transition.machine.write(object, :event, transition.event) unless complete && result
|
139
137
|
|
140
138
|
# Track transition if partial transition completed successfully
|
141
|
-
|
139
|
+
transition.machine.write(object, :event_transition, !complete && result ? transition : nil)
|
142
140
|
end
|
143
141
|
end
|
144
142
|
|