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,466 @@
1
+ == state_machine
2
+
3
+ +state_machine+ adds support for creating state machines for attributes on any
4
+ Ruby class.
5
+
6
+ == Resources
7
+
8
+ API
9
+
10
+ * http://api.pluginaweek.org/state_machine
11
+
12
+ Bugs
13
+
14
+ * http://pluginaweek.lighthouseapp.com/projects/13288-state_machine
15
+
16
+ Development
17
+
18
+ * http://github.com/pluginaweek/state_machine
19
+
20
+ Source
21
+
22
+ * git://github.com/pluginaweek/state_machine.git
23
+
24
+ == Description
25
+
26
+ State machines make it dead-simple to manage the behavior of a class. Too often,
27
+ the state of an object is kept by creating multiple boolean attributes and
28
+ deciding how to behave based on the values. This can become cumbersome and
29
+ difficult to maintain when the complexity of your class starts to increase.
30
+
31
+ +state_machine+ simplifies this design by introducing the various parts of a real
32
+ state machine, including states, events, transitions, and callbacks. However,
33
+ the api is designed to be so simple you don't even need to know what a
34
+ state machine is :)
35
+
36
+ Some brief, high-level features include:
37
+ * Defining state machines on any Ruby class
38
+ * Multiple state machines on a single class
39
+ * Namespaced state machines
40
+ * before/after transition hooks with explicit transition requirements
41
+ * ActiveRecord integration
42
+ * DataMapper integration
43
+ * Sequel integration
44
+ * State predicates
45
+ * State-driven instance / class behavior
46
+ * State values of any data type
47
+ * Dynamically-generated state values
48
+ * Event parallelization
49
+ * Attribute-based event transitions
50
+ * Inheritance
51
+ * Internationalization
52
+ * GraphViz visualization creator
53
+
54
+ Examples of the usage patterns for some of the above features are shown below.
55
+ You can find much more detailed documentation in the actual API.
56
+
57
+ == Usage
58
+
59
+ === Example
60
+
61
+ Below is an example of many of the features offered by this plugin, including:
62
+ * Initial states
63
+ * Namespaced states
64
+ * Transition callbacks
65
+ * Conditional transitions
66
+ * State-driven instance behavior
67
+ * Customized state values
68
+ * Parallel events
69
+
70
+ Class definition:
71
+
72
+ class Vehicle
73
+ attr_accessor :seatbelt_on
74
+
75
+ state_machine :state, :initial => :parked do
76
+ before_transition :parked => any - :parked, :do => :put_on_seatbelt
77
+
78
+ after_transition :on => :crash, :do => :tow
79
+ after_transition :on => :repair, :do => :fix
80
+ after_transition any => :parked do |vehicle, transition|
81
+ vehicle.seatbelt_on = false
82
+ end
83
+
84
+ event :park do
85
+ transition [:idling, :first_gear] => :parked
86
+ end
87
+
88
+ event :ignite do
89
+ transition :stalled => same, :parked => :idling
90
+ end
91
+
92
+ event :idle do
93
+ transition :first_gear => :idling
94
+ end
95
+
96
+ event :shift_up do
97
+ transition :idling => :first_gear, :first_gear => :second_gear, :second_gear => :third_gear
98
+ end
99
+
100
+ event :shift_down do
101
+ transition :third_gear => :second_gear, :second_gear => :first_gear
102
+ end
103
+
104
+ event :crash do
105
+ transition all - [:parked, :stalled] => :stalled, :unless => :auto_shop_busy?
106
+ end
107
+
108
+ event :repair do
109
+ transition :stalled => :parked, :if => :auto_shop_busy?
110
+ end
111
+
112
+ state :parked do
113
+ def speed
114
+ 0
115
+ end
116
+ end
117
+
118
+ state :idling, :first_gear do
119
+ def speed
120
+ 10
121
+ end
122
+ end
123
+
124
+ state :second_gear do
125
+ def speed
126
+ 20
127
+ end
128
+ end
129
+ end
130
+
131
+ state_machine :alarm_state, :initial => :active, :namespace => 'alarm' do
132
+ event :enable do
133
+ transition all => :active
134
+ end
135
+
136
+ event :disable do
137
+ transition all => :off
138
+ end
139
+
140
+ state :active, :value => 1
141
+ state :off, :value => 0
142
+ end
143
+
144
+ def initialize
145
+ @seatbelt_on = false
146
+ super() # NOTE: This *must* be called, otherwise states won't get initialized
147
+ end
148
+
149
+ def put_on_seatbelt
150
+ @seatbelt_on = true
151
+ end
152
+
153
+ def auto_shop_busy?
154
+ false
155
+ end
156
+
157
+ def tow
158
+ # tow the vehicle
159
+ end
160
+
161
+ def fix
162
+ # get the vehicle fixed by a mechanic
163
+ end
164
+ end
165
+
166
+ *Note* the comment made on the +initialize+ method in the class. In order for
167
+ state machine attributes to be properly initialized, <tt>super()</tt> must be called.
168
+ See StateMachine::MacroMethods for more information about this.
169
+
170
+ Using the above class as an example, you can interact with the state machine
171
+ like so:
172
+
173
+ vehicle = Vehicle.new # => #<Vehicle:0xb7cf4eac @state="parked", @seatbelt_on=false>
174
+ vehicle.state # => "parked"
175
+ vehicle.state_name # => :parked
176
+ vehicle.parked? # => true
177
+ vehicle.can_ignite? # => true
178
+ vehicle.ignite_transition # => #<StateMachine::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>
179
+ vehicle.state_events # => [:ignite]
180
+ vehicle.state_transitions # => [#<StateMachine::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>]
181
+ vehicle.speed # => 0
182
+
183
+ vehicle.ignite # => true
184
+ vehicle.parked? # => false
185
+ vehicle.idling? # => true
186
+ vehicle.speed # => 10
187
+ vehicle # => #<Vehicle:0xb7cf4eac @state="idling", @seatbelt_on=true>
188
+
189
+ vehicle.shift_up # => true
190
+ vehicle.speed # => 10
191
+ vehicle # => #<Vehicle:0xb7cf4eac @state="first_gear", @seatbelt_on=true>
192
+
193
+ vehicle.shift_up # => true
194
+ vehicle.speed # => 20
195
+ vehicle # => #<Vehicle:0xb7cf4eac @state="second_gear", @seatbelt_on=true>
196
+
197
+ # The bang (!) operator can raise exceptions if the event fails
198
+ vehicle.park! # => StateMachine::InvalidTransition: Cannot transition state via :park from :second_gear
199
+
200
+ # Generic state predicates can raise exceptions if the value does not exist
201
+ vehicle.state?(:parked) # => false
202
+ vehicle.state?(:invalid) # => IndexError: :invalid is an invalid name
203
+
204
+ # Namespaced machines have uniquely-generated methods
205
+ vehicle.alarm_state # => 1
206
+ vehicle.alarm_state_name # => :active
207
+
208
+ vehicle.can_disable_alarm? # => true
209
+ vehicle.disable_alarm # => true
210
+ vehicle.alarm_state # => 0
211
+ vehicle.alarm_state_name # => :off
212
+ vehicle.can_enable_alarm? # => true
213
+
214
+ vehicle.alarm_off? # => true
215
+ vehicle.alarm_active? # => false
216
+
217
+ # Events can be fired in parallel
218
+ vehicle.fire_events(:shift_down, :enable_alarm) # => true
219
+ vehicle.state_name # => :first_gear
220
+ vehicle.alarm_state_name # => :active
221
+
222
+ vehicle.fire_events!(:ignite, :enable_alarm) # => StateMachine::InvalidTransition: Cannot run events in parallel: ignite, enable_alarm
223
+
224
+ == Integrations
225
+
226
+ In addition to being able to define state machines on all Ruby classes, a set of
227
+ out-of-the-box integrations are available for some of the more popular Ruby
228
+ libraries. These integrations add library-specific behavior, allowing for state
229
+ machines to work more tightly with the conventions defined by those libraries.
230
+
231
+ The integrations currently available include:
232
+ * ActiveRecord models
233
+ * DataMapper resources
234
+ * Sequel models
235
+
236
+ A brief overview of these integrations is described below.
237
+
238
+ === ActiveRecord
239
+
240
+ The ActiveRecord integration adds support for database transactions, automatically
241
+ saving the record, named scopes, validation errors, and observers. For example,
242
+
243
+ class Vehicle < ActiveRecord::Base
244
+ state_machine :initial => :parked do
245
+ before_transition :parked => any - :parked, :do => :put_on_seatbelt
246
+ after_transition any => :parked do |vehicle, transition|
247
+ vehicle.seatbelt = 'off'
248
+ end
249
+
250
+ event :ignite do
251
+ transition :parked => :idling
252
+ end
253
+
254
+ state :first_gear, :second_gear do
255
+ validates_presence_of :seatbelt_on
256
+ end
257
+ end
258
+
259
+ def put_on_seatbelt
260
+ ...
261
+ end
262
+ end
263
+
264
+ class VehicleObserver < ActiveRecord::Observer
265
+ # Callback for :ignite event *before* the transition is performed
266
+ def before_ignite(vehicle, transition)
267
+ # log message
268
+ end
269
+
270
+ # Generic transition callback *after* the transition is performed
271
+ def after_transition(vehicle, transition)
272
+ Audit.log(vehicle, transition)
273
+ end
274
+ end
275
+
276
+ For more information about the various behaviors added for ActiveRecord state
277
+ machines, see StateMachine::Integrations::ActiveRecord.
278
+
279
+ === DataMapper
280
+
281
+ Like the ActiveRecord integration, the DataMapper integration adds support for
282
+ database transactions, automatically saving the record, named scopes, Extlib-like
283
+ callbacks, validation errors, and observers. For example,
284
+
285
+ class Vehicle
286
+ include DataMapper::Resource
287
+
288
+ property :id, Serial
289
+ property :state, String
290
+
291
+ state_machine :initial => :parked do
292
+ before_transition :parked => any - :parked, :do => :put_on_seatbelt
293
+ after_transition any => :parked do |transition|
294
+ self.seatbelt = 'off' # self is the record
295
+ end
296
+
297
+ event :ignite do
298
+ transition :parked => :idling
299
+ end
300
+
301
+ state :first_gear, :second_gear do
302
+ validates_present :seatbelt_on
303
+ end
304
+ end
305
+
306
+ def put_on_seatbelt
307
+ ...
308
+ end
309
+ end
310
+
311
+ class VehicleObserver
312
+ include DataMapper::Observer
313
+
314
+ observe Vehicle
315
+
316
+ # Callback for :ignite event *before* the transition is performed
317
+ before_transition :on => :ignite do |transition|
318
+ # log message (self is the record)
319
+ end
320
+
321
+ # Generic transition callback *after* the transition is performed
322
+ after_transition do |transition|
323
+ Audit.log(self, transition) # self is the record
324
+ end
325
+ end
326
+
327
+ *Note* that the DataMapper::Observer integration is optional and only available
328
+ when the dm-observer library is installed.
329
+
330
+ For more information about the various behaviors added for DataMapper state
331
+ machines, see StateMachine::Integrations::DataMapper.
332
+
333
+ === Sequel
334
+
335
+ Like the ActiveRecord integration, the Sequel integration adds support for
336
+ database transactions, automatically saving the record, named scopes, validation
337
+ errors and callbacks. For example,
338
+
339
+ class Vehicle < Sequel::Model
340
+ state_machine :initial => :parked do
341
+ before_transition :parked => any - :parked, :do => :put_on_seatbelt
342
+ after_transition any => :parked do |transition|
343
+ self.seatbelt = 'off' # self is the record
344
+ end
345
+
346
+ event :ignite do
347
+ transition :parked => :idling
348
+ end
349
+
350
+ state :first_gear, :second_gear do
351
+ validates_presence_of :seatbelt_on
352
+ end
353
+ end
354
+
355
+ def put_on_seatbelt
356
+ ...
357
+ end
358
+ end
359
+
360
+ For more information about the various behaviors added for Sequel state
361
+ machines, see StateMachine::Integrations::Sequel.
362
+
363
+ == Compatibility
364
+
365
+ Although state_machine introduces a simplified syntax, it still remains
366
+ backwards compatible with previous versions and other state-related libraries.
367
+ For example, transitions and callbacks can continue to be defined like so:
368
+
369
+ class Vehicle
370
+ state_machine :initial => :parked do
371
+ before_transition :from => :parked, :except_to => :parked, :do => :put_on_seatbelt
372
+ after_transition :to => :parked do |transition|
373
+ self.seatbelt = 'off' # self is the record
374
+ end
375
+
376
+ event :ignite do
377
+ transition :from => :parked, :to => :idling
378
+ end
379
+ end
380
+ end
381
+
382
+ Although this verbose syntax will most likely always be supported, it is
383
+ recommended that any state machines eventually migrate to the syntax introduced
384
+ in version 0.6.0.
385
+
386
+ == Tools
387
+
388
+ === Generating graphs
389
+
390
+ This library comes with built-in support for generating di-graphs based on the
391
+ events, states, and transitions defined for a state machine using GraphViz[http://www.graphviz.org].
392
+ This requires that both the <tt>ruby-graphviz</tt> gem and graphviz library be
393
+ installed on the system.
394
+
395
+ ==== Examples
396
+
397
+ To generate a graph for a specific file / class:
398
+
399
+ rake state_machine:draw FILE=vehicle.rb CLASS=Vehicle
400
+
401
+ To save files to a specific path:
402
+
403
+ rake state_machine:draw FILE=vehicle.rb CLASS=Vehicle TARGET=files
404
+
405
+ To customize the image format / orientation:
406
+
407
+ rake state_machine:draw FILE=vehicle.rb CLASS=Vehicle FORMAT=jpg ORIENTATION=landscape
408
+
409
+ To generate multiple state machine graphs:
410
+
411
+ rake state_machine:draw FILE=vehicle.rb,car.rb CLASS=Vehicle,Car
412
+
413
+ *Note* that this will generate a different file for every state machine defined
414
+ in the class. The generated files will use an output filename of the format
415
+ #{class_name}_#{machine_name}.#{format}.
416
+
417
+ For examples of actual images generated using this task, see those under the
418
+ examples folder.
419
+
420
+ ==== Ruby on Rails Integration
421
+
422
+ There is a special integration Rake task for generating state machines for
423
+ classes used in a Ruby on Rails application. This task will load the application
424
+ environment, meaning that it's unnecessary to specify the actual file to load.
425
+
426
+ For example,
427
+
428
+ rake state_machine:draw:rails CLASS=Vehicle
429
+
430
+ ==== Merb Integration
431
+
432
+ Like Ruby on Rails, there is a special integration Rake task for generating
433
+ state machines for classes used in a Merb application. This task will load the
434
+ application environment, meaning that it's unnecessary to specify the actual
435
+ files to load.
436
+
437
+ For example,
438
+
439
+ rake state_machine:draw:merb CLASS=Vehicle
440
+
441
+ === Interactive graphs
442
+
443
+ Jean Bovet - {Visual Automata Simulator}[http://www.cs.usfca.edu/~jbovet/vas.html].
444
+ This is a great tool for "simulating, visualizing and transforming finite state
445
+ automata and Turing Machines". This tool can help in the creation of states and
446
+ events for your models. It is cross-platform, written in Java.
447
+
448
+ == Testing
449
+
450
+ To run the entire test suite (will test ActiveRecord, DataMapper, and Sequel
451
+ integrations if the proper dependencies are available):
452
+
453
+ rake test
454
+
455
+ Target specific versions of integrations like so:
456
+
457
+ rake test AR_VERSION=2.0.0 DM_VERSION=0.9.4 SEQUEL_VERSION=2.8.0
458
+
459
+ == Dependencies
460
+
461
+ By default, there are no dependencies. If using specific integrations, those
462
+ dependencies are listed below.
463
+
464
+ * ActiveRecord[http://rubyonrails.org] integration: 2.0.0 or later
465
+ * DataMapper[http://datamapper.org] integration: 0.9.4 or later
466
+ * Sequel[http://sequel.rubyforge.org] integration: 2.8.0 or later
@@ -0,0 +1,98 @@
1
+ require 'rake/testtask'
2
+ require 'rake/rdoctask'
3
+ require 'rake/gempackagetask'
4
+ require 'rake/contrib/sshpublisher'
5
+
6
+ spec = Gem::Specification.new do |s|
7
+ s.name = 'state_machine'
8
+ s.version = '0.8.0'
9
+ s.platform = Gem::Platform::RUBY
10
+ s.summary = 'Adds support for creating state machines for attributes on any Ruby class'
11
+ s.description = s.summary
12
+
13
+ s.files = FileList['{examples,lib,tasks,test}/**/*'] + %w(CHANGELOG.rdoc init.rb LICENSE Rakefile README.rdoc) - FileList['test/*.log']
14
+ s.require_path = 'lib'
15
+ s.has_rdoc = true
16
+ s.test_files = Dir['test/**/*_test.rb']
17
+
18
+ s.author = 'Aaron Pfeifer'
19
+ s.email = 'aaron@pluginaweek.org'
20
+ s.homepage = 'http://www.pluginaweek.org'
21
+ s.rubyforge_project = 'pluginaweek'
22
+ end
23
+
24
+ desc 'Default: run all tests.'
25
+ task :default => :test
26
+
27
+ desc "Test the #{spec.name} plugin."
28
+ Rake::TestTask.new(:test) do |t|
29
+ t.libs << 'lib'
30
+ t.test_files = spec.test_files
31
+ t.verbose = true
32
+ end
33
+
34
+ begin
35
+ require 'rcov/rcovtask'
36
+ namespace :test do
37
+ desc "Test the #{spec.name} plugin with Rcov."
38
+ Rcov::RcovTask.new(:rcov) do |t|
39
+ t.libs << 'lib'
40
+ t.test_files = spec.test_files
41
+ t.rcov_opts << '--exclude="^(?!lib/)"'
42
+ t.verbose = true
43
+ end
44
+ end
45
+ rescue LoadError
46
+ end
47
+
48
+ desc "Generate documentation for the #{spec.name} plugin."
49
+ Rake::RDocTask.new(:rdoc) do |rdoc|
50
+ rdoc.rdoc_dir = 'rdoc'
51
+ rdoc.title = spec.name
52
+ rdoc.template = '../rdoc_template.rb'
53
+ rdoc.options << '--line-numbers' << '--inline-source'
54
+ rdoc.rdoc_files.include('README.rdoc', 'CHANGELOG.rdoc', 'LICENSE', 'lib/**/*.rb')
55
+ end
56
+
57
+ desc 'Generate a gemspec file.'
58
+ task :gemspec do
59
+ File.open("#{spec.name}.gemspec", 'w') do |f|
60
+ f.write spec.to_ruby
61
+ end
62
+ end
63
+
64
+ Rake::GemPackageTask.new(spec) do |p|
65
+ p.gem_spec = spec
66
+ p.need_tar = true
67
+ p.need_zip = true
68
+ end
69
+
70
+ desc 'Publish the beta gem.'
71
+ task :pgem => [:package] do
72
+ Rake::SshFilePublisher.new('aaron@pluginaweek.org', '/home/aaron/gems.pluginaweek.org/public/gems', 'pkg', "#{spec.name}-#{spec.version}.gem").upload
73
+ end
74
+
75
+ desc 'Publish the API documentation.'
76
+ task :pdoc => [:rdoc] do
77
+ Rake::SshDirPublisher.new('aaron@pluginaweek.org', "/home/aaron/api.pluginaweek.org/public/#{spec.name}", 'rdoc').upload
78
+ end
79
+
80
+ desc 'Publish the API docs and gem'
81
+ task :publish => [:pgem, :pdoc, :release]
82
+
83
+ desc 'Publish the release files to RubyForge.'
84
+ task :release => [:gem, :package] do
85
+ require 'rubyforge'
86
+
87
+ ruby_forge = RubyForge.new.configure
88
+ ruby_forge.login
89
+
90
+ %w(gem tgz zip).each do |ext|
91
+ file = "pkg/#{spec.name}-#{spec.version}.#{ext}"
92
+ puts "Releasing #{File.basename(file)}..."
93
+
94
+ ruby_forge.add_release(spec.rubyforge_project, spec.name, spec.version, file)
95
+ end
96
+ end
97
+
98
+ Dir['tasks/**/*.rake'].each {|rake| load rake}
@@ -0,0 +1,11 @@
1
+ class AutoShop
2
+ state_machine :initial => :available do
3
+ event :tow_vehicle do
4
+ transition :available => :busy
5
+ end
6
+
7
+ event :fix_vehicle do
8
+ transition :busy => :available
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ class Car < Vehicle
2
+ state_machine do
3
+ event :reverse do
4
+ transition [:parked, :idling, :first_gear] => :backing_up
5
+ end
6
+
7
+ event :park do
8
+ transition :backing_up => :parked
9
+ end
10
+
11
+ event :idle do
12
+ transition :backing_up => :idling
13
+ end
14
+
15
+ event :shift_up do
16
+ transition :backing_up => :first_gear
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,51 @@
1
+ class Users < Application
2
+ # GET /users
3
+ def index
4
+ @users = User.all
5
+ display @users
6
+ end
7
+
8
+ # GET /users/1
9
+ def show(id)
10
+ @user = User.get(id)
11
+ raise NotFound unless @user
12
+ display @user
13
+ end
14
+
15
+ # GET /users/new
16
+ def new
17
+ only_provides :html
18
+ @user = User.new
19
+ display @user
20
+ end
21
+
22
+ # GET /users/1/edit
23
+ def edit(id)
24
+ only_provides :html
25
+ @user = User.get(id)
26
+ raise NotFound unless @user
27
+ display @user
28
+ end
29
+
30
+ # POST /users
31
+ def create(user)
32
+ @user = User.new(user)
33
+ if @user.save
34
+ redirect resource(@user), :message => {:notice => "User was successfully created"}
35
+ else
36
+ message[:error] = "User failed to be created"
37
+ render :new
38
+ end
39
+ end
40
+
41
+ # PUT /users/1
42
+ def update(id, user)
43
+ @user = User.get(id)
44
+ raise NotFound unless @user
45
+ if @user.update_attributes(user)
46
+ redirect resource(@user)
47
+ else
48
+ display @user, :edit
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,28 @@
1
+ class User
2
+ include DataMapper::Resource
3
+
4
+ property :id, Serial
5
+ property :name, String
6
+
7
+ validates_present :name, :state, :access_state
8
+
9
+ state_machine :initial => :unregistered do
10
+ event :register do
11
+ transition :unregistered => :registered
12
+ end
13
+
14
+ event :unregister do
15
+ transition :registered => :unregistered
16
+ end
17
+ end
18
+
19
+ state_machine :access_state, :initial => :enabled do
20
+ event :enable do
21
+ transition all => :enabled
22
+ end
23
+
24
+ event :disable do
25
+ transition all => :disabled
26
+ end
27
+ end
28
+ end