enum_state_machine 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +12 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. metadata +83 -130
  6. data/.rvmrc +0 -1
  7. data/enum_state_machine.gemspec +0 -25
  8. data/lib/enum_state_machine.rb +0 -9
  9. data/lib/enum_state_machine/assertions.rb +0 -36
  10. data/lib/enum_state_machine/branch.rb +0 -225
  11. data/lib/enum_state_machine/callback.rb +0 -232
  12. data/lib/enum_state_machine/core.rb +0 -12
  13. data/lib/enum_state_machine/core_ext.rb +0 -2
  14. data/lib/enum_state_machine/core_ext/class/state_machine.rb +0 -5
  15. data/lib/enum_state_machine/error.rb +0 -13
  16. data/lib/enum_state_machine/eval_helpers.rb +0 -87
  17. data/lib/enum_state_machine/event.rb +0 -257
  18. data/lib/enum_state_machine/event_collection.rb +0 -141
  19. data/lib/enum_state_machine/extensions.rb +0 -149
  20. data/lib/enum_state_machine/graph.rb +0 -92
  21. data/lib/enum_state_machine/helper_module.rb +0 -17
  22. data/lib/enum_state_machine/initializers.rb +0 -4
  23. data/lib/enum_state_machine/initializers/rails.rb +0 -22
  24. data/lib/enum_state_machine/integrations.rb +0 -97
  25. data/lib/enum_state_machine/integrations/active_model.rb +0 -585
  26. data/lib/enum_state_machine/integrations/active_model/locale.rb +0 -11
  27. data/lib/enum_state_machine/integrations/active_model/observer.rb +0 -33
  28. data/lib/enum_state_machine/integrations/active_model/observer_update.rb +0 -42
  29. data/lib/enum_state_machine/integrations/active_model/versions.rb +0 -31
  30. data/lib/enum_state_machine/integrations/active_record.rb +0 -548
  31. data/lib/enum_state_machine/integrations/active_record/locale.rb +0 -20
  32. data/lib/enum_state_machine/integrations/active_record/versions.rb +0 -123
  33. data/lib/enum_state_machine/integrations/base.rb +0 -100
  34. data/lib/enum_state_machine/machine.rb +0 -2292
  35. data/lib/enum_state_machine/machine_collection.rb +0 -86
  36. data/lib/enum_state_machine/macro_methods.rb +0 -518
  37. data/lib/enum_state_machine/matcher.rb +0 -123
  38. data/lib/enum_state_machine/matcher_helpers.rb +0 -54
  39. data/lib/enum_state_machine/node_collection.rb +0 -222
  40. data/lib/enum_state_machine/path.rb +0 -120
  41. data/lib/enum_state_machine/path_collection.rb +0 -90
  42. data/lib/enum_state_machine/state.rb +0 -297
  43. data/lib/enum_state_machine/state_collection.rb +0 -112
  44. data/lib/enum_state_machine/state_context.rb +0 -138
  45. data/lib/enum_state_machine/state_enum.rb +0 -23
  46. data/lib/enum_state_machine/transition.rb +0 -470
  47. data/lib/enum_state_machine/transition_collection.rb +0 -245
  48. data/lib/enum_state_machine/version.rb +0 -3
  49. data/lib/enum_state_machine/yard.rb +0 -8
  50. data/lib/enum_state_machine/yard/handlers.rb +0 -12
  51. data/lib/enum_state_machine/yard/handlers/base.rb +0 -32
  52. data/lib/enum_state_machine/yard/handlers/event.rb +0 -25
  53. data/lib/enum_state_machine/yard/handlers/machine.rb +0 -344
  54. data/lib/enum_state_machine/yard/handlers/state.rb +0 -25
  55. data/lib/enum_state_machine/yard/handlers/transition.rb +0 -47
  56. data/lib/enum_state_machine/yard/templates.rb +0 -3
  57. data/lib/enum_state_machine/yard/templates/default/class/html/setup.rb +0 -30
  58. data/lib/enum_state_machine/yard/templates/default/class/html/state_machines.erb +0 -12
  59. data/lib/tasks/enum_state_machine.rake +0 -1
  60. data/lib/tasks/enum_state_machine.rb +0 -24
  61. data/lib/yard-enum_state_machine.rb +0 -2
  62. data/test/functional/state_machine_test.rb +0 -1066
  63. data/test/unit/integrations/active_model_test.rb +0 -1245
  64. data/test/unit/integrations/active_record_test.rb +0 -2551
  65. data/test/unit/integrations/base_test.rb +0 -104
  66. data/test/unit/integrations_test.rb +0 -71
  67. data/test/unit/invalid_event_test.rb +0 -20
  68. data/test/unit/invalid_parallel_transition_test.rb +0 -18
  69. data/test/unit/invalid_transition_test.rb +0 -115
  70. data/test/unit/machine_collection_test.rb +0 -603
  71. data/test/unit/machine_test.rb +0 -3395
  72. data/test/unit/state_machine_test.rb +0 -31
@@ -1,138 +0,0 @@
1
- require 'enum_state_machine/assertions'
2
- require 'enum_state_machine/eval_helpers'
3
-
4
- module EnumStateMachine
5
- # A method was called in an invalid state context
6
- class InvalidContext < Error
7
- end
8
-
9
- # Represents a module which will get evaluated within the context of a state.
10
- #
11
- # Class-level methods are proxied to the owner class, injecting a custom
12
- # <tt>:if</tt> condition along with method. This assumes that the method has
13
- # support for a set of configuration options, including <tt>:if</tt>. This
14
- # condition will check that the object's state matches this context's state.
15
- #
16
- # Instance-level methods are used to define state-driven behavior on the
17
- # state's owner class.
18
- #
19
- # == Examples
20
- #
21
- # class Vehicle
22
- # class << self
23
- # attr_accessor :validations
24
- #
25
- # def validate(options, &block)
26
- # validations << options
27
- # end
28
- # end
29
- #
30
- # self.validations = []
31
- # attr_accessor :state, :simulate
32
- #
33
- # def moving?
34
- # self.class.validations.all? {|validation| validation[:if].call(self)}
35
- # end
36
- # end
37
- #
38
- # In the above class, a simple set of validation behaviors have been defined.
39
- # Each validation consists of a configuration like so:
40
- #
41
- # Vehicle.validate :unless => :simulate
42
- # Vehicle.validate :if => lambda {|vehicle| ...}
43
- #
44
- # In order to scope validations to a particular state context, the class-level
45
- # +validate+ method can be invoked like so:
46
- #
47
- # machine = EnumStateMachine::Machine.new(Vehicle)
48
- # context = EnumStateMachine::StateContext.new(machine.state(:first_gear))
49
- # context.validate(:unless => :simulate)
50
- #
51
- # vehicle = Vehicle.new # => #<Vehicle:0xb7ce491c @simulate=nil, @state=nil>
52
- # vehicle.moving? # => false
53
- #
54
- # vehicle.state = 'first_gear'
55
- # vehicle.moving? # => true
56
- #
57
- # vehicle.simulate = true
58
- # vehicle.moving? # => false
59
- class StateContext < Module
60
- include Assertions
61
- include EvalHelpers
62
-
63
- # The state machine for which this context's state is defined
64
- attr_reader :machine
65
-
66
- # The state that must be present in an object for this context to be active
67
- attr_reader :state
68
-
69
- # Creates a new context for the given state
70
- def initialize(state)
71
- @state = state
72
- @machine = state.machine
73
-
74
- state_name = state.name
75
- machine_name = machine.name
76
- @condition = lambda {|object| object.class.state_machine(machine_name).states.matches?(object, state_name)}
77
- end
78
-
79
- # Creates a new transition that determines what to change the current state
80
- # to when an event fires from this state.
81
- #
82
- # Since this transition is being defined within a state context, you do
83
- # *not* need to specify the <tt>:from</tt> option for the transition. For
84
- # example:
85
- #
86
- # state_machine do
87
- # state :parked do
88
- # transition :to => :idling, :on => [:ignite, :shift_up] # Transitions to :idling
89
- # transition :from => [:idling, :parked], :on => :park, :unless => :seatbelt_on? # Transitions to :parked if seatbelt is off
90
- # end
91
- # end
92
- #
93
- # See EnumStateMachine::Machine#transition for a description of the possible
94
- # configurations for defining transitions.
95
- def transition(options)
96
- assert_valid_keys(options, :from, :to, :on, :if, :unless)
97
- raise ArgumentError, 'Must specify :on event' unless options[:on]
98
- raise ArgumentError, 'Must specify either :to or :from state' unless !options[:to] ^ !options[:from]
99
-
100
- machine.transition(options.merge(options[:to] ? {:from => state.name} : {:to => state.name}))
101
- end
102
-
103
- # Hooks in condition-merging to methods that don't exist in this module
104
- def method_missing(*args, &block)
105
- # Get the configuration
106
- if args.last.is_a?(Hash)
107
- options = args.last
108
- else
109
- args << options = {}
110
- end
111
-
112
- # Get any existing condition that may need to be merged
113
- if_condition = options.delete(:if)
114
- unless_condition = options.delete(:unless)
115
-
116
- # Provide scope access to configuration in case the block is evaluated
117
- # within the object instance
118
- proxy = self
119
- proxy_condition = @condition
120
-
121
- # Replace the configuration condition with the one configured for this
122
- # proxy, merging together any existing conditions
123
- options[:if] = lambda do |*condition_args|
124
- # Block may be executed within the context of the actual object, so
125
- # it'll either be the first argument or the executing context
126
- object = condition_args.first || self
127
-
128
- proxy.evaluate_method(object, proxy_condition) &&
129
- Array(if_condition).all? {|condition| proxy.evaluate_method(object, condition)} &&
130
- !Array(unless_condition).any? {|condition| proxy.evaluate_method(object, condition)}
131
- end
132
-
133
- # Evaluate the method on the owner class with the condition proxied
134
- # through
135
- machine.owner_class.send(*args, &block)
136
- end
137
- end
138
- end
@@ -1,23 +0,0 @@
1
- require 'power_enum'
2
-
3
- module EnumStateMachine
4
- module StateEnum
5
- def self.included(base)
6
- base.extend ClassMethods if defined?(PowerEnum)
7
- end
8
-
9
- module ClassMethods
10
- def has_state_enum(state_attr, enum_attr, enum_opts = {})
11
- has_enumerated enum_attr, enum_opts
12
-
13
- define_method "#{state_attr}" do
14
- public_send("#{enum_attr}").to_s
15
- end
16
-
17
- define_method "#{state_attr}=" do |value|
18
- public_send("#{enum_attr}=", value)
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,470 +0,0 @@
1
- require 'enum_state_machine/transition_collection'
2
- require 'enum_state_machine/error'
3
-
4
- module EnumStateMachine
5
- # An invalid transition was attempted
6
- class InvalidTransition < Error
7
- # The machine attempting to be transitioned
8
- attr_reader :machine
9
-
10
- # The current state value for the machine
11
- attr_reader :from
12
-
13
- def initialize(object, machine, event) #:nodoc:
14
- @machine = machine
15
- @from_state = machine.states.match!(object)
16
- @from = machine.read(object, :state)
17
- @event = machine.events.fetch(event)
18
- errors = machine.errors_for(object)
19
-
20
- message = "Cannot transition #{machine.name} via :#{self.event} from #{from_name.inspect}"
21
- message << " (Reason(s): #{errors})" unless errors.empty?
22
- super(object, message)
23
- end
24
-
25
- # The event that triggered the failed transition
26
- def event
27
- @event.name
28
- end
29
-
30
- # The fully-qualified name of the event that triggered the failed transition
31
- def qualified_event
32
- @event.qualified_name
33
- end
34
-
35
- # The name for the current state
36
- def from_name
37
- @from_state.name
38
- end
39
-
40
- # The fully-qualified name for the current state
41
- def qualified_from_name
42
- @from_state.qualified_name
43
- end
44
- end
45
-
46
- # A set of transition failed to run in parallel
47
- class InvalidParallelTransition < Error
48
- # The set of events that failed the transition(s)
49
- attr_reader :events
50
-
51
- def initialize(object, events) #:nodoc:
52
- @events = events
53
-
54
- super(object, "Cannot run events in parallel: #{events * ', '}")
55
- end
56
- end
57
-
58
- # A transition represents a state change for a specific attribute.
59
- #
60
- # Transitions consist of:
61
- # * An event
62
- # * A starting state
63
- # * An ending state
64
- class Transition
65
- # The object being transitioned
66
- attr_reader :object
67
-
68
- # The state machine for which this transition is defined
69
- attr_reader :machine
70
-
71
- # The original state value *before* the transition
72
- attr_reader :from
73
-
74
- # The new state value *after* the transition
75
- attr_reader :to
76
-
77
- # The arguments passed in to the event that triggered the transition
78
- # (does not include the +run_action+ boolean argument if specified)
79
- attr_accessor :args
80
-
81
- # The result of invoking the action associated with the machine
82
- attr_reader :result
83
-
84
- # Whether the transition is only existing temporarily for the object
85
- attr_writer :transient
86
-
87
- # Determines whether the curreny ruby implementation supports pausing and
88
- # resuming transitions
89
- def self.pause_supported?
90
- !defined?(RUBY_ENGINE) || %w(ruby maglev).include?(RUBY_ENGINE)
91
- end
92
-
93
- # Creates a new, specific transition
94
- def initialize(object, machine, event, from_name, to_name, read_state = true) #:nodoc:
95
- @object = object
96
- @machine = machine
97
- @args = []
98
- @transient = false
99
- @resume_block = nil
100
-
101
- @event = machine.events.fetch(event)
102
- @from_state = machine.states.fetch(from_name)
103
- @from = read_state ? machine.read(object, :state) : @from_state.value
104
- @to_state = machine.states.fetch(to_name)
105
- @to = @to_state.value
106
-
107
- reset
108
- end
109
-
110
- # The attribute which this transition's machine is defined for
111
- def attribute
112
- machine.attribute
113
- end
114
-
115
- # The action that will be run when this transition is performed
116
- def action
117
- machine.action
118
- end
119
-
120
- # The event that triggered the transition
121
- def event
122
- @event.name
123
- end
124
-
125
- # The fully-qualified name of the event that triggered the transition
126
- def qualified_event
127
- @event.qualified_name
128
- end
129
-
130
- # The human-readable name of the event that triggered the transition
131
- def human_event
132
- @event.human_name(@object.class)
133
- end
134
-
135
- # The state name *before* the transition
136
- def from_name
137
- @from_state.name
138
- end
139
-
140
- # The fully-qualified state name *before* the transition
141
- def qualified_from_name
142
- @from_state.qualified_name
143
- end
144
-
145
- # The human-readable state name *before* the transition
146
- def human_from_name
147
- @from_state.human_name(@object.class)
148
- end
149
-
150
- # The new state name *after* the transition
151
- def to_name
152
- @to_state.name
153
- end
154
-
155
- # The new fully-qualified state name *after* the transition
156
- def qualified_to_name
157
- @to_state.qualified_name
158
- end
159
-
160
- # The new human-readable state name *after* the transition
161
- def human_to_name
162
- @to_state.human_name(@object.class)
163
- end
164
-
165
- # Does this transition represent a loopback (i.e. the from and to state
166
- # are the same)
167
- #
168
- # == Example
169
- #
170
- # machine = EnumStateMachine.new(Vehicle)
171
- # EnumStateMachine::Transition.new(Vehicle.new, machine, :park, :parked, :parked).loopback? # => true
172
- # EnumStateMachine::Transition.new(Vehicle.new, machine, :park, :idling, :parked).loopback? # => false
173
- def loopback?
174
- from_name == to_name
175
- end
176
-
177
- # Is this transition existing for a short period only? If this is set, it
178
- # indicates that the transition (or the event backing it) should not be
179
- # written to the object if it fails.
180
- def transient?
181
- @transient
182
- end
183
-
184
- # A hash of all the core attributes defined for this transition with their
185
- # names as keys and values of the attributes as values.
186
- #
187
- # == Example
188
- #
189
- # machine = EnumStateMachine.new(Vehicle)
190
- # transition = EnumStateMachine::Transition.new(Vehicle.new, machine, :ignite, :parked, :idling)
191
- # transition.attributes # => {:object => #<Vehicle:0xb7d60ea4>, :attribute => :state, :event => :ignite, :from => 'parked', :to => 'idling'}
192
- def attributes
193
- @attributes ||= {:object => object, :attribute => attribute, :event => event, :from => from, :to => to}
194
- end
195
-
196
- # Runs the actual transition and any before/after callbacks associated
197
- # with the transition. The action associated with the transition/machine
198
- # can be skipped by passing in +false+.
199
- #
200
- # == Examples
201
- #
202
- # class Vehicle
203
- # state_machine :action => :save do
204
- # ...
205
- # end
206
- # end
207
- #
208
- # vehicle = Vehicle.new
209
- # transition = EnumStateMachine::Transition.new(vehicle, machine, :ignite, :parked, :idling)
210
- # transition.perform # => Runs the +save+ action after setting the state attribute
211
- # transition.perform(false) # => Only sets the state attribute
212
- # transition.perform(Time.now) # => Passes in additional arguments and runs the +save+ action
213
- # transition.perform(Time.now, false) # => Passes in additional arguments and only sets the state attribute
214
- def perform(*args)
215
- run_action = [true, false].include?(args.last) ? args.pop : true
216
- self.args = args
217
-
218
- # Run the transition
219
- !!TransitionCollection.new([self], :actions => run_action).perform
220
- end
221
-
222
- # Runs a block within a transaction for the object being transitioned.
223
- # By default, transactions are a no-op unless otherwise defined by the
224
- # machine's integration.
225
- def within_transaction
226
- machine.within_transaction(object) do
227
- yield
228
- end
229
- end
230
-
231
- # Runs the before / after callbacks for this transition. If a block is
232
- # provided, then it will be executed between the before and after callbacks.
233
- #
234
- # Configuration options:
235
- # * +before+ - Whether to run before callbacks.
236
- # * +after+ - Whether to run after callbacks. If false, then any around
237
- # callbacks will be paused until called again with +after+ enabled.
238
- # Default is true.
239
- #
240
- # This will return true if all before callbacks gets executed. After
241
- # callbacks will not have an effect on the result.
242
- def run_callbacks(options = {}, &block)
243
- options = {:before => true, :after => true}.merge(options)
244
- @success = false
245
-
246
- halted = pausable { before(options[:after], &block) } if options[:before]
247
-
248
- # After callbacks are only run if:
249
- # * An around callback didn't halt after yielding
250
- # * They're enabled or the run didn't succeed
251
- after if !(@before_run && halted) && (options[:after] || !@success)
252
-
253
- @before_run
254
- end
255
-
256
- # Transitions the current value of the state to that specified by the
257
- # transition. Once the state is persisted, it cannot be persisted again
258
- # until this transition is reset.
259
- #
260
- # == Example
261
- #
262
- # class Vehicle
263
- # state_machine do
264
- # event :ignite do
265
- # transition :parked => :idling
266
- # end
267
- # end
268
- # end
269
- #
270
- # vehicle = Vehicle.new
271
- # transition = EnumStateMachine::Transition.new(vehicle, Vehicle.state_machine, :ignite, :parked, :idling)
272
- # transition.persist
273
- #
274
- # vehicle.state # => 'idling'
275
- def persist
276
- unless @persisted
277
- machine.write(object, :state, to)
278
- @persisted = true
279
- end
280
- end
281
-
282
- # Rolls back changes made to the object's state via this transition. This
283
- # will revert the state back to the +from+ value.
284
- #
285
- # == Example
286
- #
287
- # class Vehicle
288
- # state_machine :initial => :parked do
289
- # event :ignite do
290
- # transition :parked => :idling
291
- # end
292
- # end
293
- # end
294
- #
295
- # vehicle = Vehicle.new # => #<Vehicle:0xb7b7f568 @state="parked">
296
- # transition = EnumStateMachine::Transition.new(vehicle, Vehicle.state_machine, :ignite, :parked, :idling)
297
- #
298
- # # Persist the new state
299
- # vehicle.state # => "parked"
300
- # transition.persist
301
- # vehicle.state # => "idling"
302
- #
303
- # # Roll back to the original state
304
- # transition.rollback
305
- # vehicle.state # => "parked"
306
- def rollback
307
- reset
308
- machine.write(object, :state, from)
309
- end
310
-
311
- # Resets any tracking of which callbacks have already been run and whether
312
- # the state has already been persisted
313
- def reset
314
- @before_run = @persisted = @after_run = false
315
- @paused_block = nil
316
- end
317
-
318
- # Determines equality of transitions by testing whether the object, states,
319
- # and event involved in the transition are equal
320
- def ==(other)
321
- other.instance_of?(self.class) &&
322
- other.object == object &&
323
- other.machine == machine &&
324
- other.from_name == from_name &&
325
- other.to_name == to_name &&
326
- other.event == event
327
- end
328
-
329
- # Generates a nicely formatted description of this transitions's contents.
330
- #
331
- # For example,
332
- #
333
- # transition = EnumStateMachine::Transition.new(object, machine, :ignite, :parked, :idling)
334
- # transition # => #<EnumStateMachine::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>
335
- def inspect
336
- "#<#{self.class} #{%w(attribute event from from_name to to_name).map {|attr| "#{attr}=#{send(attr).inspect}"} * ' '}>"
337
- end
338
-
339
- private
340
- # Runs a block that may get paused. If the block doesn't pause, then
341
- # execution will continue as normal. If the block gets paused, then it
342
- # will take care of switching the execution context when it's resumed.
343
- #
344
- # This will return true if the given block halts for a reason other than
345
- # getting paused.
346
- def pausable
347
- begin
348
- halted = !catch(:halt) { yield; true }
349
- rescue Exception => error
350
- raise unless @resume_block
351
- end
352
-
353
- if @resume_block
354
- @resume_block.call(halted, error)
355
- else
356
- halted
357
- end
358
- end
359
-
360
- # Pauses the current callback execution. This should only occur within
361
- # around callbacks when the remainder of the callback will be executed at
362
- # a later point in time.
363
- def pause
364
- raise ArgumentError, 'around_transition callbacks cannot be called in multiple execution contexts in java implementations of Ruby. Use before/after_transitions instead.' unless self.class.pause_supported?
365
-
366
- unless @resume_block
367
- require 'continuation' unless defined?(callcc)
368
- callcc do |block|
369
- @paused_block = block
370
- throw :halt, true
371
- end
372
- end
373
- end
374
-
375
- # Resumes the execution of a previously paused callback execution. Once
376
- # the paused callbacks complete, the current execution will continue.
377
- def resume
378
- if @paused_block
379
- halted, error = callcc do |block|
380
- @resume_block = block
381
- @paused_block.call
382
- end
383
-
384
- @resume_block = @paused_block = nil
385
-
386
- raise error if error
387
- !halted
388
- else
389
- true
390
- end
391
- end
392
-
393
- # Runs the machine's +before+ callbacks for this transition. Only
394
- # callbacks that are configured to match the event, from state, and to
395
- # state will be invoked.
396
- #
397
- # Once the callbacks are run, they cannot be run again until this transition
398
- # is reset.
399
- def before(complete = true, index = 0, &block)
400
- unless @before_run
401
- while callback = machine.callbacks[:before][index]
402
- index += 1
403
-
404
- if callback.type == :around
405
- # Around callback: need to handle recursively. Execution only gets
406
- # paused if:
407
- # * The block fails and the callback doesn't run on failures OR
408
- # * The block succeeds, but after callbacks are disabled (in which
409
- # case a continuation is stored for later execution)
410
- return if catch(:cancel) do
411
- callback.call(object, context, self) do
412
- before(complete, index, &block)
413
-
414
- pause if @success && !complete
415
- throw :cancel, true unless @success
416
- end
417
- end
418
- else
419
- # Normal before callback
420
- callback.call(object, context, self)
421
- end
422
- end
423
-
424
- @before_run = true
425
- end
426
-
427
- action = {:success => true}.merge(block_given? ? yield : {})
428
- @result, @success = action[:result], action[:success]
429
- end
430
-
431
- # Runs the machine's +after+ callbacks for this transition. Only
432
- # callbacks that are configured to match the event, from state, and to
433
- # state will be invoked.
434
- #
435
- # Once the callbacks are run, they cannot be run again until this transition
436
- # is reset.
437
- #
438
- # == Halting
439
- #
440
- # If any callback throws a <tt>:halt</tt> exception, it will be caught
441
- # and the callback chain will be automatically stopped. However, this
442
- # exception will not bubble up to the caller since +after+ callbacks
443
- # should never halt the execution of a +perform+.
444
- def after
445
- unless @after_run
446
- # First resume previously paused callbacks
447
- if resume
448
- catch(:halt) do
449
- type = @success ? :after : :failure
450
- machine.callbacks[type].each {|callback| callback.call(object, context, self)}
451
- end
452
- end
453
-
454
- @after_run = true
455
- end
456
- end
457
-
458
- # Gets a hash of the context defining this unique transition (including
459
- # event, from state, and to state).
460
- #
461
- # == Example
462
- #
463
- # machine = EnumStateMachine.new(Vehicle)
464
- # transition = EnumStateMachine::Transition.new(Vehicle.new, machine, :ignite, :parked, :idling)
465
- # transition.context # => {:on => :ignite, :from => :parked, :to => :idling}
466
- def context
467
- @context ||= {:on => event, :from => from_name, :to => to_name}
468
- end
469
- end
470
- end