branston 0.3.6 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. data/lib/branston/app/controllers/scenarios_controller.rb +6 -5
  2. data/lib/branston/app/controllers/stories_controller.rb +101 -89
  3. data/lib/branston/app/models/story.rb +30 -1
  4. data/lib/branston/app/models/user.rb +4 -0
  5. data/lib/branston/app/views/iterations/index.html.erb +1 -1
  6. data/lib/branston/app/views/layouts/_header.html.erb +1 -2
  7. data/lib/branston/app/views/scenarios/_scenario.html.erb +6 -3
  8. data/lib/branston/app/views/scenarios/_scenarios.html.erb +4 -2
  9. data/lib/branston/app/views/stories/_form.html.erb +15 -4
  10. data/lib/branston/app/views/stories/_story.html.erb +26 -6
  11. data/lib/branston/app/views/stories/edit.html.erb +3 -3
  12. data/lib/branston/app/views/stories/index.html.erb +22 -3
  13. data/lib/branston/app/views/stories/new.html.erb +2 -2
  14. data/lib/branston/app/views/stories/show.html.erb +3 -3
  15. data/lib/branston/config/routes.rb +7 -4
  16. data/lib/branston/coverage/app-controllers-application_controller_rb.html +1 -1
  17. data/lib/branston/coverage/app-controllers-iterations_controller_rb.html +1 -1
  18. data/lib/branston/coverage/app-controllers-outcomes_controller_rb.html +1 -1
  19. data/lib/branston/coverage/app-controllers-preconditions_controller_rb.html +1 -1
  20. data/lib/branston/coverage/app-controllers-releases_controller_rb.html +1 -1
  21. data/lib/branston/coverage/app-controllers-scenarios_controller_rb.html +18 -12
  22. data/lib/branston/coverage/app-controllers-sessions_controller_rb.html +1 -1
  23. data/lib/branston/coverage/app-controllers-stories_controller_rb.html +193 -121
  24. data/lib/branston/coverage/app-controllers-user_roles_controller_rb.html +1 -1
  25. data/lib/branston/coverage/app-controllers-users_controller_rb.html +1 -1
  26. data/lib/branston/coverage/app-helpers-application_helper_rb.html +1 -1
  27. data/lib/branston/coverage/app-helpers-iterations_helper_rb.html +1 -1
  28. data/lib/branston/coverage/app-helpers-outcomes_helper_rb.html +1 -1
  29. data/lib/branston/coverage/app-helpers-preconditions_helper_rb.html +1 -1
  30. data/lib/branston/coverage/app-helpers-releases_helper_rb.html +1 -1
  31. data/lib/branston/coverage/app-helpers-sessions_helper_rb.html +1 -1
  32. data/lib/branston/coverage/app-helpers-stories_helper_rb.html +1 -1
  33. data/lib/branston/coverage/app-helpers-user_roles_helper_rb.html +1 -1
  34. data/lib/branston/coverage/app-models-iteration_rb.html +1 -1
  35. data/lib/branston/coverage/app-models-outcome_rb.html +1 -1
  36. data/lib/branston/coverage/app-models-participation_rb.html +1 -1
  37. data/lib/branston/coverage/app-models-precondition_rb.html +1 -1
  38. data/lib/branston/coverage/app-models-release_rb.html +1 -1
  39. data/lib/branston/coverage/app-models-scenario_rb.html +1 -1
  40. data/lib/branston/coverage/app-models-story_rb.html +192 -18
  41. data/lib/branston/coverage/app-models-user_rb.html +33 -9
  42. data/lib/branston/coverage/app-models-user_role_rb.html +1 -1
  43. data/lib/branston/coverage/index.html +13 -13
  44. data/lib/branston/coverage/lib-client_rb.html +1 -1
  45. data/lib/branston/coverage/lib-faker_extras_rb.html +1 -1
  46. data/lib/branston/coverage/lib-story_generator_rb.html +1 -1
  47. data/lib/branston/db/development.sqlite3 +0 -0
  48. data/lib/branston/db/migrate/20091223100903_add_status_to_story.rb +11 -0
  49. data/lib/branston/db/pristine.sqlite3 +0 -0
  50. data/lib/branston/db/schema.rb +5 -3
  51. data/lib/branston/db/test.sqlite3 +0 -0
  52. data/lib/branston/lib/branston.rb +4 -2
  53. data/lib/branston/log/development.log +4970 -0
  54. data/lib/branston/log/test.log +88225 -0
  55. data/lib/branston/test/blueprints.rb +10 -7
  56. data/lib/branston/test/functional/scenarios_controller_test.rb +22 -15
  57. data/lib/branston/test/functional/stories_controller_test.rb +51 -30
  58. data/lib/branston/test/unit/story_test.rb +47 -7
  59. data/lib/branston/test/unit/user_test.rb +4 -0
  60. data/lib/branston/tmp/performance/BrowsingTest#test_homepage_process_time_flat.txt +3 -2
  61. data/lib/branston/tmp/performance/BrowsingTest#test_homepage_process_time_graph.html +2041 -1307
  62. data/lib/branston/tmp/performance/BrowsingTest#test_homepage_process_time_tree.txt +7922 -7922
  63. data/lib/branston/vendor/plugins/state_machine/CHANGELOG.rdoc +298 -0
  64. data/lib/branston/vendor/plugins/state_machine/LICENSE +20 -0
  65. data/lib/branston/vendor/plugins/state_machine/README.rdoc +466 -0
  66. data/lib/branston/vendor/plugins/state_machine/Rakefile +98 -0
  67. data/lib/branston/vendor/plugins/state_machine/examples/AutoShop_state.png +0 -0
  68. data/lib/branston/vendor/plugins/state_machine/examples/Car_state.png +0 -0
  69. data/lib/branston/vendor/plugins/state_machine/examples/TrafficLight_state.png +0 -0
  70. data/lib/branston/vendor/plugins/state_machine/examples/Vehicle_state.png +0 -0
  71. data/lib/branston/vendor/plugins/state_machine/examples/auto_shop.rb +11 -0
  72. data/lib/branston/vendor/plugins/state_machine/examples/car.rb +19 -0
  73. data/lib/branston/vendor/plugins/state_machine/examples/merb-rest/controller.rb +51 -0
  74. data/lib/branston/vendor/plugins/state_machine/examples/merb-rest/model.rb +28 -0
  75. data/lib/branston/vendor/plugins/state_machine/examples/merb-rest/view_edit.html.erb +24 -0
  76. data/lib/branston/vendor/plugins/state_machine/examples/merb-rest/view_index.html.erb +23 -0
  77. data/lib/branston/vendor/plugins/state_machine/examples/merb-rest/view_new.html.erb +13 -0
  78. data/lib/branston/vendor/plugins/state_machine/examples/merb-rest/view_show.html.erb +17 -0
  79. data/lib/branston/vendor/plugins/state_machine/examples/rails-rest/controller.rb +43 -0
  80. data/lib/branston/vendor/plugins/state_machine/examples/rails-rest/migration.rb +11 -0
  81. data/lib/branston/vendor/plugins/state_machine/examples/rails-rest/model.rb +23 -0
  82. data/lib/branston/vendor/plugins/state_machine/examples/rails-rest/view_edit.html.erb +25 -0
  83. data/lib/branston/vendor/plugins/state_machine/examples/rails-rest/view_index.html.erb +23 -0
  84. data/lib/branston/vendor/plugins/state_machine/examples/rails-rest/view_new.html.erb +14 -0
  85. data/lib/branston/vendor/plugins/state_machine/examples/rails-rest/view_show.html.erb +17 -0
  86. data/lib/branston/vendor/plugins/state_machine/examples/traffic_light.rb +7 -0
  87. data/lib/branston/vendor/plugins/state_machine/examples/vehicle.rb +31 -0
  88. data/lib/branston/vendor/plugins/state_machine/init.rb +1 -0
  89. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/assertions.rb +36 -0
  90. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/callback.rb +189 -0
  91. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/condition_proxy.rb +94 -0
  92. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/eval_helpers.rb +67 -0
  93. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/event.rb +252 -0
  94. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/event_collection.rb +122 -0
  95. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/extensions.rb +149 -0
  96. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/guard.rb +230 -0
  97. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/integrations/active_record/locale.rb +11 -0
  98. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/integrations/active_record/observer.rb +41 -0
  99. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/integrations/active_record.rb +492 -0
  100. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/integrations/data_mapper/observer.rb +139 -0
  101. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/integrations/data_mapper.rb +351 -0
  102. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/integrations/sequel.rb +322 -0
  103. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/integrations.rb +68 -0
  104. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/machine.rb +1467 -0
  105. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/machine_collection.rb +155 -0
  106. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/matcher.rb +123 -0
  107. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/matcher_helpers.rb +54 -0
  108. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/node_collection.rb +152 -0
  109. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/state.rb +249 -0
  110. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/state_collection.rb +112 -0
  111. data/lib/branston/vendor/plugins/state_machine/lib/state_machine/transition.rb +394 -0
  112. data/lib/branston/vendor/plugins/state_machine/lib/state_machine.rb +388 -0
  113. data/lib/branston/vendor/plugins/state_machine/state_machine.gemspec +30 -0
  114. data/lib/branston/vendor/plugins/state_machine/tasks/state_machine.rake +1 -0
  115. data/lib/branston/vendor/plugins/state_machine/tasks/state_machine.rb +30 -0
  116. data/lib/branston/vendor/plugins/state_machine/test/classes/switch.rb +11 -0
  117. data/lib/branston/vendor/plugins/state_machine/test/functional/state_machine_test.rb +941 -0
  118. data/lib/branston/vendor/plugins/state_machine/test/test_helper.rb +4 -0
  119. data/lib/branston/vendor/plugins/state_machine/test/unit/assertions_test.rb +40 -0
  120. data/lib/branston/vendor/plugins/state_machine/test/unit/callback_test.rb +455 -0
  121. data/lib/branston/vendor/plugins/state_machine/test/unit/condition_proxy_test.rb +328 -0
  122. data/lib/branston/vendor/plugins/state_machine/test/unit/eval_helpers_test.rb +120 -0
  123. data/lib/branston/vendor/plugins/state_machine/test/unit/event_collection_test.rb +326 -0
  124. data/lib/branston/vendor/plugins/state_machine/test/unit/event_test.rb +743 -0
  125. data/lib/branston/vendor/plugins/state_machine/test/unit/guard_test.rb +908 -0
  126. data/lib/branston/vendor/plugins/state_machine/test/unit/integrations/active_record_test.rb +1367 -0
  127. data/lib/branston/vendor/plugins/state_machine/test/unit/integrations/data_mapper_test.rb +962 -0
  128. data/lib/branston/vendor/plugins/state_machine/test/unit/integrations/sequel_test.rb +859 -0
  129. data/lib/branston/vendor/plugins/state_machine/test/unit/integrations_test.rb +42 -0
  130. data/lib/branston/vendor/plugins/state_machine/test/unit/invalid_event_test.rb +7 -0
  131. data/lib/branston/vendor/plugins/state_machine/test/unit/invalid_transition_test.rb +7 -0
  132. data/lib/branston/vendor/plugins/state_machine/test/unit/machine_collection_test.rb +938 -0
  133. data/lib/branston/vendor/plugins/state_machine/test/unit/machine_test.rb +2004 -0
  134. data/lib/branston/vendor/plugins/state_machine/test/unit/matcher_helpers_test.rb +37 -0
  135. data/lib/branston/vendor/plugins/state_machine/test/unit/matcher_test.rb +155 -0
  136. data/lib/branston/vendor/plugins/state_machine/test/unit/node_collection_test.rb +207 -0
  137. data/lib/branston/vendor/plugins/state_machine/test/unit/state_collection_test.rb +280 -0
  138. data/lib/branston/vendor/plugins/state_machine/test/unit/state_machine_test.rb +31 -0
  139. data/lib/branston/vendor/plugins/state_machine/test/unit/state_test.rb +795 -0
  140. data/lib/branston/vendor/plugins/state_machine/test/unit/transition_test.rb +1212 -0
  141. metadata +81 -2
@@ -0,0 +1,394 @@
1
+ module StateMachine
2
+ # An invalid transition was attempted
3
+ class InvalidTransition < StandardError
4
+ end
5
+
6
+ # A transition represents a state change for a specific attribute.
7
+ #
8
+ # Transitions consist of:
9
+ # * An event
10
+ # * A starting state
11
+ # * An ending state
12
+ class Transition
13
+ class << self
14
+ # Runs one or more transitions in parallel. All transitions will run
15
+ # through the following steps:
16
+ # 1. Before callbacks
17
+ # 2. Persist state
18
+ # 3. Invoke action
19
+ # 4. After callbacks (if configured)
20
+ # 5. Rollback (if action is unsuccessful)
21
+ #
22
+ # Configuration options:
23
+ # * <tt>:action</tt> - Whether to run the action configured for each transition
24
+ # * <tt>:after</tt> - Whether to run after callbacks
25
+ #
26
+ # If a block is passed to this method, that block will be called instead
27
+ # of invoking each transition's action.
28
+ def perform(transitions, options = {})
29
+ # Validate that the transitions are for separate machines / attributes
30
+ attributes = transitions.map {|transition| transition.attribute}.uniq
31
+ raise ArgumentError, 'Cannot perform multiple transitions in parallel for the same state machine attribute' if attributes.length != transitions.length
32
+
33
+ success = false
34
+
35
+ # Run before callbacks. If any callback halts, then the entire chain
36
+ # is halted for every transition.
37
+ if transitions.all? {|transition| transition.before}
38
+ # Persist the new state for each attribute
39
+ transitions.each {|transition| transition.persist}
40
+
41
+ # Run the actions associated with each machine
42
+ begin
43
+ results = {}
44
+ success =
45
+ if block_given?
46
+ # Block was given: use the result for each transition
47
+ result = yield
48
+ transitions.each {|transition| results[transition.action] = result}
49
+ !!result
50
+ elsif options[:action] == false
51
+ # Skip the action
52
+ true
53
+ else
54
+ # Run each transition's action (only once)
55
+ object = transitions.first.object
56
+ transitions.all? do |transition|
57
+ action = transition.action
58
+ action && !results.include?(action) ? results[action] = object.send(action) : true
59
+ end
60
+ end
61
+ rescue Exception
62
+ # Action failed: rollback
63
+ transitions.each {|transition| transition.rollback}
64
+ raise
65
+ end
66
+
67
+ # Run after callbacks even when the actions failed. The :after option
68
+ # is ignored if the transitions were unsuccessful.
69
+ transitions.each {|transition| transition.after(results[transition.action], success)} unless options[:after] == false && success
70
+
71
+ # Rollback the transitions if the transaction was unsuccessful
72
+ transitions.each {|transition| transition.rollback} unless success
73
+ end
74
+
75
+ success
76
+ end
77
+
78
+ # Runs one or more transitions within a transaction. See StateMachine::Transition.perform
79
+ # for more information.
80
+ def perform_within_transaction(transitions, options = {})
81
+ success = false
82
+ transitions.first.within_transaction do
83
+ success = perform(transitions, options)
84
+ end
85
+
86
+ success
87
+ end
88
+ end
89
+
90
+ # The object being transitioned
91
+ attr_reader :object
92
+
93
+ # The state machine for which this transition is defined
94
+ attr_reader :machine
95
+
96
+ # The event that triggered the transition
97
+ attr_reader :event
98
+
99
+ # The fully-qualified name of the event that triggered the transition
100
+ attr_reader :qualified_event
101
+
102
+ # The original state value *before* the transition
103
+ attr_reader :from
104
+
105
+ # The original state name *before* the transition
106
+ attr_reader :from_name
107
+
108
+ # The original fully-qualified state name *before* transition
109
+ attr_reader :qualified_from_name
110
+
111
+ # The new state value *after* the transition
112
+ attr_reader :to
113
+
114
+ # The new state name *after* the transition
115
+ attr_reader :to_name
116
+
117
+ # The new fully-qualified state name *after* the transition
118
+ attr_reader :qualified_to_name
119
+
120
+ # The arguments passed in to the event that triggered the transition
121
+ # (does not include the +run_action+ boolean argument if specified)
122
+ attr_accessor :args
123
+
124
+ # The result of invoking the action associated with the machine
125
+ attr_reader :result
126
+
127
+ # Creates a new, specific transition
128
+ def initialize(object, machine, event, from_name, to_name, read_state = true) #:nodoc:
129
+ @object = object
130
+ @machine = machine
131
+ @args = []
132
+
133
+ # Event information
134
+ event = machine.events.fetch(event)
135
+ @event = event.name
136
+ @qualified_event = event.qualified_name
137
+
138
+ # From state information
139
+ from_state = machine.states.fetch(from_name)
140
+ @from = read_state ? machine.read(object, :state) : from_state.value
141
+ @from_name = from_state.name
142
+ @qualified_from_name = from_state.qualified_name
143
+
144
+ # To state information
145
+ to_state = machine.states.fetch(to_name)
146
+ @to = to_state.value
147
+ @to_name = to_state.name
148
+ @qualified_to_name = to_state.qualified_name
149
+ end
150
+
151
+ # The attribute which this transition's machine is defined for
152
+ def attribute
153
+ machine.attribute
154
+ end
155
+
156
+ # The action that will be run when this transition is performed
157
+ def action
158
+ machine.action
159
+ end
160
+
161
+ # Does this transition represent a loopback (i.e. the from and to state
162
+ # are the same)
163
+ #
164
+ # == Example
165
+ #
166
+ # machine = StateMachine.new(Vehicle)
167
+ # StateMachine::Transition.new(Vehicle.new, machine, :park, :parked, :parked).loopback? # => true
168
+ # StateMachine::Transition.new(Vehicle.new, machine, :park, :idling, :parked).loopback? # => false
169
+ def loopback?
170
+ from_name == to_name
171
+ end
172
+
173
+ # A hash of all the core attributes defined for this transition with their
174
+ # names as keys and values of the attributes as values.
175
+ #
176
+ # == Example
177
+ #
178
+ # machine = StateMachine.new(Vehicle)
179
+ # transition = StateMachine::Transition.new(Vehicle.new, machine, :ignite, :parked, :idling)
180
+ # transition.attributes # => {:object => #<Vehicle:0xb7d60ea4>, :attribute => :state, :event => :ignite, :from => 'parked', :to => 'idling'}
181
+ def attributes
182
+ @attributes ||= {:object => object, :attribute => attribute, :event => event, :from => from, :to => to}
183
+ end
184
+
185
+ # Runs the actual transition and any before/after callbacks associated
186
+ # with the transition. The action associated with the transition/machine
187
+ # can be skipped by passing in +false+.
188
+ #
189
+ # == Examples
190
+ #
191
+ # class Vehicle
192
+ # state_machine :action => :save do
193
+ # ...
194
+ # end
195
+ # end
196
+ #
197
+ # vehicle = Vehicle.new
198
+ # transition = StateMachine::Transition.new(vehicle, machine, :ignite, :parked, :idling)
199
+ # transition.perform # => Runs the +save+ action after setting the state attribute
200
+ # transition.perform(false) # => Only sets the state attribute
201
+ def perform(*args)
202
+ run_action = [true, false].include?(args.last) ? args.pop : true
203
+ self.args = args
204
+
205
+ # Run the transition
206
+ self.class.perform_within_transaction([self], :action => run_action)
207
+ end
208
+
209
+ # Runs a block within a transaction for the object being transitioned.
210
+ # By default, transactions are a no-op unless otherwise defined by the
211
+ # machine's integration.
212
+ def within_transaction
213
+ machine.within_transaction(object) do
214
+ yield
215
+ end
216
+ end
217
+
218
+ # Runs the machine's +before+ callbacks for this transition. Only
219
+ # callbacks that are configured to match the event, from state, and to
220
+ # state will be invoked.
221
+ #
222
+ # Once the callbacks are run, they cannot be run again until this transition
223
+ # is reset.
224
+ #
225
+ # == Example
226
+ #
227
+ # class Vehicle
228
+ # state_machine do
229
+ # before_transition :on => :ignite, :do => lambda {|vehicle| ...}
230
+ # end
231
+ # end
232
+ #
233
+ # vehicle = Vehicle.new
234
+ # transition = StateMachine::Transition.new(vehicle, machine, :ignite, :parked, :idling)
235
+ # transition.before
236
+ def before
237
+ result = false
238
+
239
+ catch(:halt) do
240
+ unless @before_run
241
+ callback(:before)
242
+ @before_run = true
243
+ end
244
+
245
+ result = true
246
+ end
247
+
248
+ result
249
+ end
250
+
251
+ # Transitions the current value of the state to that specified by the
252
+ # transition. Once the state is persisted, it cannot be persisted again
253
+ # until this transition is reset.
254
+ #
255
+ # == Example
256
+ #
257
+ # class Vehicle
258
+ # state_machine do
259
+ # event :ignite do
260
+ # transition :parked => :idling
261
+ # end
262
+ # end
263
+ # end
264
+ #
265
+ # vehicle = Vehicle.new
266
+ # transition = StateMachine::Transition.new(vehicle, Vehicle.state_machine, :ignite, :parked, :idling)
267
+ # transition.persist
268
+ #
269
+ # vehicle.state # => 'idling'
270
+ def persist
271
+ unless @persisted
272
+ machine.write(object, :state, to)
273
+ @persisted = true
274
+ end
275
+ end
276
+
277
+ # Runs the machine's +after+ callbacks for this transition. Only
278
+ # callbacks that are configured to match the event, from state, and to
279
+ # state will be invoked.
280
+ #
281
+ # The result can be used to indicate whether the associated machine action
282
+ # was executed successfully.
283
+ #
284
+ # Once the callbacks are run, they cannot be run again until this transition
285
+ # is reset.
286
+ #
287
+ # == Halting
288
+ #
289
+ # If any callback throws a <tt>:halt</tt> exception, it will be caught
290
+ # and the callback chain will be automatically stopped. However, this
291
+ # exception will not bubble up to the caller since +after+ callbacks
292
+ # should never halt the execution of a +perform+.
293
+ #
294
+ # == Example
295
+ #
296
+ # class Vehicle
297
+ # state_machine do
298
+ # after_transition :on => :ignite, :do => lambda {|vehicle| ...}
299
+ #
300
+ # event :ignite do
301
+ # transition :parked => :idling
302
+ # end
303
+ # end
304
+ # end
305
+ #
306
+ # vehicle = Vehicle.new
307
+ # transition = StateMachine::Transition.new(vehicle, Vehicle.state_machine, :ignite, :parked, :idling)
308
+ # transition.after(true)
309
+ def after(result = nil, success = true)
310
+ @result = result
311
+
312
+ catch(:halt) do
313
+ unless @after_run
314
+ callback(:after, :success => success)
315
+ @after_run = true
316
+ end
317
+ end
318
+
319
+ true
320
+ end
321
+
322
+ # Rolls back changes made to the object's state via this transition. This
323
+ # will revert the state back to the +from+ value.
324
+ #
325
+ # == Example
326
+ #
327
+ # class Vehicle
328
+ # state_machine :initial => :parked do
329
+ # event :ignite do
330
+ # transition :parked => :idling
331
+ # end
332
+ # end
333
+ # end
334
+ #
335
+ # vehicle = Vehicle.new # => #<Vehicle:0xb7b7f568 @state="parked">
336
+ # transition = StateMachine::Transition.new(vehicle, Vehicle.state_machine, :ignite, :parked, :idling)
337
+ #
338
+ # # Persist the new state
339
+ # vehicle.state # => "parked"
340
+ # transition.persist
341
+ # vehicle.state # => "idling"
342
+ #
343
+ # # Roll back to the original state
344
+ # transition.rollback
345
+ # vehicle.state # => "parked"
346
+ def rollback
347
+ reset
348
+ machine.write(object, :state, from)
349
+ end
350
+
351
+ # Resets any tracking of which callbacks have already been run and whether
352
+ # the state has already been persisted
353
+ def reset
354
+ @before_run = @persisted = @after_run = false
355
+ end
356
+
357
+ # Generates a nicely formatted description of this transitions's contents.
358
+ #
359
+ # For example,
360
+ #
361
+ # transition = StateMachine::Transition.new(object, machine, :ignite, :parked, :idling)
362
+ # transition # => #<StateMachine::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>
363
+ def inspect
364
+ "#<#{self.class} #{%w(attribute event from from_name to to_name).map {|attr| "#{attr}=#{send(attr).inspect}"} * ' '}>"
365
+ end
366
+
367
+ protected
368
+ # Gets a hash of the context defining this unique transition (including
369
+ # event, from state, and to state).
370
+ #
371
+ # == Example
372
+ #
373
+ # machine = StateMachine.new(Vehicle)
374
+ # transition = StateMachine::Transition.new(Vehicle.new, machine, :ignite, :parked, :idling)
375
+ # transition.context # => {:on => :ignite, :from => :parked, :to => :idling}
376
+ def context
377
+ @context ||= {:on => event, :from => from_name, :to => to_name}
378
+ end
379
+
380
+ # Runs the callbacks of the given type for this transition. This will
381
+ # only invoke callbacks that exactly match the event, from state, and
382
+ # to state that describe this transition.
383
+ #
384
+ # Additional callback parameters can be specified. By default, this
385
+ # transition is also passed into callbacks.
386
+ def callback(type, context = {})
387
+ context = self.context.merge(context)
388
+
389
+ machine.callbacks[type].each do |callback|
390
+ callback.call(object, context, self)
391
+ end
392
+ end
393
+ end
394
+ end