hsume2-state_machine 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. data/CHANGELOG.rdoc +413 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +717 -0
  4. data/Rakefile +77 -0
  5. data/examples/AutoShop_state.png +0 -0
  6. data/examples/Car_state.png +0 -0
  7. data/examples/TrafficLight_state.png +0 -0
  8. data/examples/Vehicle_state.png +0 -0
  9. data/examples/auto_shop.rb +11 -0
  10. data/examples/car.rb +19 -0
  11. data/examples/merb-rest/controller.rb +51 -0
  12. data/examples/merb-rest/model.rb +28 -0
  13. data/examples/merb-rest/view_edit.html.erb +24 -0
  14. data/examples/merb-rest/view_index.html.erb +23 -0
  15. data/examples/merb-rest/view_new.html.erb +13 -0
  16. data/examples/merb-rest/view_show.html.erb +17 -0
  17. data/examples/rails-rest/controller.rb +43 -0
  18. data/examples/rails-rest/migration.rb +11 -0
  19. data/examples/rails-rest/model.rb +23 -0
  20. data/examples/rails-rest/view_edit.html.erb +25 -0
  21. data/examples/rails-rest/view_index.html.erb +23 -0
  22. data/examples/rails-rest/view_new.html.erb +14 -0
  23. data/examples/rails-rest/view_show.html.erb +17 -0
  24. data/examples/traffic_light.rb +7 -0
  25. data/examples/vehicle.rb +31 -0
  26. data/init.rb +1 -0
  27. data/lib/state_machine.rb +448 -0
  28. data/lib/state_machine/alternate_machine.rb +79 -0
  29. data/lib/state_machine/assertions.rb +36 -0
  30. data/lib/state_machine/branch.rb +224 -0
  31. data/lib/state_machine/callback.rb +236 -0
  32. data/lib/state_machine/condition_proxy.rb +94 -0
  33. data/lib/state_machine/error.rb +13 -0
  34. data/lib/state_machine/eval_helpers.rb +86 -0
  35. data/lib/state_machine/event.rb +304 -0
  36. data/lib/state_machine/event_collection.rb +139 -0
  37. data/lib/state_machine/extensions.rb +149 -0
  38. data/lib/state_machine/initializers.rb +4 -0
  39. data/lib/state_machine/initializers/merb.rb +1 -0
  40. data/lib/state_machine/initializers/rails.rb +25 -0
  41. data/lib/state_machine/integrations.rb +110 -0
  42. data/lib/state_machine/integrations/active_model.rb +502 -0
  43. data/lib/state_machine/integrations/active_model/locale.rb +11 -0
  44. data/lib/state_machine/integrations/active_model/observer.rb +45 -0
  45. data/lib/state_machine/integrations/active_model/versions.rb +31 -0
  46. data/lib/state_machine/integrations/active_record.rb +424 -0
  47. data/lib/state_machine/integrations/active_record/locale.rb +20 -0
  48. data/lib/state_machine/integrations/active_record/versions.rb +143 -0
  49. data/lib/state_machine/integrations/base.rb +91 -0
  50. data/lib/state_machine/integrations/data_mapper.rb +392 -0
  51. data/lib/state_machine/integrations/data_mapper/observer.rb +210 -0
  52. data/lib/state_machine/integrations/data_mapper/versions.rb +62 -0
  53. data/lib/state_machine/integrations/mongo_mapper.rb +272 -0
  54. data/lib/state_machine/integrations/mongo_mapper/locale.rb +4 -0
  55. data/lib/state_machine/integrations/mongo_mapper/versions.rb +110 -0
  56. data/lib/state_machine/integrations/mongoid.rb +357 -0
  57. data/lib/state_machine/integrations/mongoid/locale.rb +4 -0
  58. data/lib/state_machine/integrations/mongoid/versions.rb +18 -0
  59. data/lib/state_machine/integrations/sequel.rb +428 -0
  60. data/lib/state_machine/integrations/sequel/versions.rb +36 -0
  61. data/lib/state_machine/machine.rb +1873 -0
  62. data/lib/state_machine/machine_collection.rb +87 -0
  63. data/lib/state_machine/matcher.rb +123 -0
  64. data/lib/state_machine/matcher_helpers.rb +54 -0
  65. data/lib/state_machine/node_collection.rb +157 -0
  66. data/lib/state_machine/path.rb +120 -0
  67. data/lib/state_machine/path_collection.rb +90 -0
  68. data/lib/state_machine/state.rb +271 -0
  69. data/lib/state_machine/state_collection.rb +112 -0
  70. data/lib/state_machine/transition.rb +458 -0
  71. data/lib/state_machine/transition_collection.rb +244 -0
  72. data/lib/tasks/state_machine.rake +1 -0
  73. data/lib/tasks/state_machine.rb +27 -0
  74. data/test/files/en.yml +17 -0
  75. data/test/files/switch.rb +11 -0
  76. data/test/functional/alternate_state_machine_test.rb +122 -0
  77. data/test/functional/state_machine_test.rb +993 -0
  78. data/test/test_helper.rb +4 -0
  79. data/test/unit/assertions_test.rb +40 -0
  80. data/test/unit/branch_test.rb +890 -0
  81. data/test/unit/callback_test.rb +701 -0
  82. data/test/unit/condition_proxy_test.rb +328 -0
  83. data/test/unit/error_test.rb +43 -0
  84. data/test/unit/eval_helpers_test.rb +222 -0
  85. data/test/unit/event_collection_test.rb +358 -0
  86. data/test/unit/event_test.rb +985 -0
  87. data/test/unit/integrations/active_model_test.rb +1097 -0
  88. data/test/unit/integrations/active_record_test.rb +2021 -0
  89. data/test/unit/integrations/base_test.rb +99 -0
  90. data/test/unit/integrations/data_mapper_test.rb +1909 -0
  91. data/test/unit/integrations/mongo_mapper_test.rb +1611 -0
  92. data/test/unit/integrations/mongoid_test.rb +1591 -0
  93. data/test/unit/integrations/sequel_test.rb +1523 -0
  94. data/test/unit/integrations_test.rb +61 -0
  95. data/test/unit/invalid_event_test.rb +20 -0
  96. data/test/unit/invalid_parallel_transition_test.rb +18 -0
  97. data/test/unit/invalid_transition_test.rb +77 -0
  98. data/test/unit/machine_collection_test.rb +599 -0
  99. data/test/unit/machine_test.rb +3043 -0
  100. data/test/unit/matcher_helpers_test.rb +37 -0
  101. data/test/unit/matcher_test.rb +155 -0
  102. data/test/unit/node_collection_test.rb +217 -0
  103. data/test/unit/path_collection_test.rb +266 -0
  104. data/test/unit/path_test.rb +485 -0
  105. data/test/unit/state_collection_test.rb +310 -0
  106. data/test/unit/state_machine_test.rb +31 -0
  107. data/test/unit/state_test.rb +924 -0
  108. data/test/unit/transition_collection_test.rb +2102 -0
  109. data/test/unit/transition_test.rb +1541 -0
  110. metadata +207 -0
@@ -0,0 +1,7 @@
1
+ class TrafficLight
2
+ state_machine :initial => :stop do
3
+ event :cycle do
4
+ transition :stop => :proceed, :proceed => :caution, :caution => :stop
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,31 @@
1
+ class Vehicle
2
+ state_machine :initial => :parked do
3
+ event :park do
4
+ transition [:idling, :first_gear] => :parked
5
+ end
6
+
7
+ event :ignite do
8
+ transition :stalled => same, :parked => :idling
9
+ end
10
+
11
+ event :idle do
12
+ transition :first_gear => :idling
13
+ end
14
+
15
+ event :shift_up do
16
+ transition :idling => :first_gear, :first_gear => :second_gear, :second_gear => :third_gear
17
+ end
18
+
19
+ event :shift_down do
20
+ transition :third_gear => :second_gear, :second_gear => :first_gear
21
+ end
22
+
23
+ event :crash do
24
+ transition [:first_gear, :second_gear, :third_gear] => :stalled
25
+ end
26
+
27
+ event :repair do
28
+ transition :stalled => :parked
29
+ end
30
+ end
31
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'state_machine'
@@ -0,0 +1,448 @@
1
+ require 'state_machine/machine'
2
+
3
+ # A state machine is a model of behavior composed of states, events, and
4
+ # transitions. This helper adds support for defining this type of
5
+ # functionality on any Ruby class.
6
+ module StateMachine
7
+ module MacroMethods
8
+ # Creates a new state machine with the given name. The default name, if not
9
+ # specified, is <tt>:state</tt>.
10
+ #
11
+ # Configuration options:
12
+ # * <tt>:attribute</tt> - The name of the attribute to store the state value
13
+ # in. By default, this is the same as the name of the machine.
14
+ # * <tt>:initial</tt> - The initial state of the attribute. This can be a
15
+ # static state or a lambda block which will be evaluated at runtime
16
+ # (e.g. lambda {|vehicle| vehicle.speed == 0 ? :parked : :idling}).
17
+ # Default is nil.
18
+ # * <tt>:initialize</tt> - Whether to automatically initialize the attribute
19
+ # by hooking into #initialize on the owner class. Default is true.
20
+ # * <tt>:action</tt> - The instance method to invoke when an object
21
+ # transitions. Default is nil unless otherwise specified by the
22
+ # configured integration.
23
+ # * <tt>:namespace</tt> - The name to use for namespacing all generated
24
+ # state / event instance methods (e.g. "heater" would generate
25
+ # :turn_on_heater and :turn_off_heater for the :turn_on/:turn_off events).
26
+ # Default is nil.
27
+ # * <tt>:integration</tt> - The name of the integration to use for adding
28
+ # library-specific behavior to the machine. Built-in integrations
29
+ # include :active_model, :active_record, :data_mapper, :mongo_mapper, and
30
+ # :sequel. By default, this is determined automatically.
31
+ #
32
+ # Configuration options relevant to ORM integrations:
33
+ # * <tt>:plural</tt> - The pluralized version of the name. By default, this
34
+ # will attempt to call +pluralize+ on the name. If this method is not
35
+ # available, an "s" is appended. This is used for generating scopes.
36
+ # * <tt>:messages</tt> - The error messages to use when invalidating
37
+ # objects due to failed transitions. Messages include:
38
+ # * <tt>:invalid</tt>
39
+ # * <tt>:invalid_event</tt>
40
+ # * <tt>:invalid_transition</tt>
41
+ # * <tt>:use_transactions</tt> - Whether transactions should be used when
42
+ # firing events. Default is true unless otherwise specified by the
43
+ # configured integration.
44
+ #
45
+ # This also expects a block which will be used to actually configure the
46
+ # states, events and transitions for the state machine. *Note* that this
47
+ # block will be executed within the context of the state machine. As a
48
+ # result, you will not be able to access any class methods unless you refer
49
+ # to them directly (i.e. specifying the class name).
50
+ #
51
+ # For examples on the types of state machine configurations and blocks, see
52
+ # the section below.
53
+ #
54
+ # == Examples
55
+ #
56
+ # With the default name/attribute and no configuration:
57
+ #
58
+ # class Vehicle
59
+ # state_machine do
60
+ # event :park do
61
+ # ...
62
+ # end
63
+ # end
64
+ # end
65
+ #
66
+ # The above example will define a state machine named "state" that will
67
+ # store the value in the +state+ attribute. Every vehicle will start
68
+ # without an initial state.
69
+ #
70
+ # With a custom name / attribute:
71
+ #
72
+ # class Vehicle
73
+ # state_machine :status, :attribute => :status_value do
74
+ # ...
75
+ # end
76
+ # end
77
+ #
78
+ # With a static initial state:
79
+ #
80
+ # class Vehicle
81
+ # state_machine :status, :initial => :parked do
82
+ # ...
83
+ # end
84
+ # end
85
+ #
86
+ # With a dynamic initial state:
87
+ #
88
+ # class Vehicle
89
+ # state_machine :status, :initial => lambda {|vehicle| vehicle.speed == 0 ? :parked : :idling} do
90
+ # ...
91
+ # end
92
+ # end
93
+ #
94
+ # == Class Methods
95
+ #
96
+ # The following class methods will be automatically generated by the
97
+ # state machine based on the *name* of the machine. Any existing methods
98
+ # will not be overwritten.
99
+ # * <tt>human_state_name(state)</tt> - Gets the humanized value for the
100
+ # given state. This may be generated by internationalization libraries if
101
+ # supported by the integration.
102
+ # * <tt>human_state_event_name(event)</tt> - Gets the humanized value for
103
+ # the given event. This may be generated by internationalization
104
+ # libraries if supported by the integration.
105
+ #
106
+ # For example,
107
+ #
108
+ # class Vehicle
109
+ # state_machine :state, :initial => :parked do
110
+ # event :ignite do
111
+ # transition :parked => :idling
112
+ # end
113
+ #
114
+ # event :shift_up do
115
+ # transition :idling => :first_gear
116
+ # end
117
+ # end
118
+ # end
119
+ #
120
+ # Vehicle.human_state_name(:parked) # => "parked"
121
+ # Vehicle.human_state_name(:first_gear) # => "first gear"
122
+ # Vehicle.human_state_event_name(:park) # => "park"
123
+ # Vehicle.human_state_event_name(:shift_up) # => "shift up"
124
+ #
125
+ # == Instance Methods
126
+ #
127
+ # The following instance methods will be automatically generated by the
128
+ # state machine based on the *name* of the machine. Any existing methods
129
+ # will not be overwritten.
130
+ # * <tt>state</tt> - Gets the current value for the attribute
131
+ # * <tt>state=(value)</tt> - Sets the current value for the attribute
132
+ # * <tt>state?(name)</tt> - Checks the given state name against the current
133
+ # state. If the name is not a known state, then an ArgumentError is raised.
134
+ # * <tt>state_name</tt> - Gets the name of the state for the current value
135
+ # * <tt>human_state_name</tt> - Gets the human-readable name of the state
136
+ # for the current value
137
+ # * <tt>state_events(requirements = {})</tt> - Gets the list of events that
138
+ # can be fired on the current object's state (uses the *unqualified* event
139
+ # names)
140
+ # * <tt>state_transitions(requirements = {})</tt> - Gets the list of
141
+ # transitions that can be made on the current object's state
142
+ # * <tt>state_paths(requirements = {})</tt> - Gets the list of sequences of
143
+ # transitions that can be run from the current object's state
144
+ #
145
+ # The <tt>state_events</tt>, <tt>state_transitions</tt>, and <tt>state_paths</tt>
146
+ # helpers all take an optional set of requirements for determining what's
147
+ # available for the current object. These requirements include:
148
+ # * <tt>:from</tt> - One or more states to transition from. If none are
149
+ # specified, then this will be the object's current state.
150
+ # * <tt>:to</tt> - One or more states to transition to. If none are
151
+ # specified, then this will match any to state.
152
+ # * <tt>:on</tt> - One or more events to transition on. If none are
153
+ # specified, then this will match any event.
154
+ # * <tt>:guard</tt> - Whether to guard transitions with the if/unless
155
+ # conditionals defined for each one. Default is true.
156
+ #
157
+ # For example,
158
+ #
159
+ # class Vehicle
160
+ # state_machine :state, :initial => :parked do
161
+ # event :ignite do
162
+ # transition :parked => :idling
163
+ # end
164
+ #
165
+ # event :park do
166
+ # transition :idling => :parked
167
+ # end
168
+ # end
169
+ # end
170
+ #
171
+ # vehicle = Vehicle.new
172
+ # vehicle.state # => "parked"
173
+ # vehicle.state_name # => :parked
174
+ # vehicle.human_state_name # => "parked"
175
+ # vehicle.state?(:parked) # => true
176
+ #
177
+ # # Changing state
178
+ # vehicle.state = 'idling'
179
+ # vehicle.state # => "idling"
180
+ # vehicle.state_name # => :idling
181
+ # vehicle.state?(:parked) # => false
182
+ #
183
+ # # Getting current event / transition availability
184
+ # vehicle.state_events # => [:park]
185
+ # vehicle.park # => true
186
+ # vehicle.state_events # => [:ignite]
187
+ # vehicle.state_events(:from => :idling) # => [:park]
188
+ # vehicle.state_events(:to => :parked) # => []
189
+ #
190
+ # vehicle.state_transitions # => [#<StateMachine::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>]
191
+ # vehicle.ignite
192
+ # vehicle.state_transitions # => [#<StateMachine::Transition attribute=:state event=:park from="idling" from_name=:idling to="parked" to_name=:parked>]
193
+ #
194
+ # vehicle.state_transitions(:on => :ignite) # => []
195
+ #
196
+ # # Getting current path availability
197
+ # vehicle.state_paths # => [
198
+ # # [#<StateMachine::Transition attribute=:state event=:park from="idling" from_name=:idling to="parked" to_name=:parked>,
199
+ # # #<StateMachine::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>]
200
+ # # ]
201
+ # vehicle.state_paths(:guard => false) # =>
202
+ # # [#<StateMachine::Transition attribute=:state event=:park from="idling" from_name=:idling to="parked" to_name=:parked>,
203
+ # # #<StateMachine::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>]
204
+ # # ]
205
+ #
206
+ # == Attribute initialization
207
+ #
208
+ # For most classes, the initial values for state machine attributes are
209
+ # automatically assigned when a new object is created. However, this
210
+ # behavior will *not* work if the class defines an +initialize+ method
211
+ # without properly calling +super+.
212
+ #
213
+ # For example,
214
+ #
215
+ # class Vehicle
216
+ # state_machine :state, :initial => :parked do
217
+ # ...
218
+ # end
219
+ # end
220
+ #
221
+ # vehicle = Vehicle.new # => #<Vehicle:0xb7c8dbf8 @state="parked">
222
+ # vehicle.state # => "parked"
223
+ #
224
+ # In the above example, no +initialize+ method is defined. As a result,
225
+ # the default behavior of initializing the state machine attributes is used.
226
+ #
227
+ # In the following example, a custom +initialize+ method is defined:
228
+ #
229
+ # class Vehicle
230
+ # state_machine :state, :initial => :parked do
231
+ # ...
232
+ # end
233
+ #
234
+ # def initialize
235
+ # end
236
+ # end
237
+ #
238
+ # vehicle = Vehicle.new # => #<Vehicle:0xb7c77678>
239
+ # vehicle.state # => nil
240
+ #
241
+ # Since the +initialize+ method is defined, the state machine attributes
242
+ # never get initialized. In order to ensure that all initialization hooks
243
+ # are called, the custom method *must* call +super+ without any arguments
244
+ # like so:
245
+ #
246
+ # class Vehicle
247
+ # state_machine :state, :initial => :parked do
248
+ # ...
249
+ # end
250
+ #
251
+ # def initialize(attributes = {})
252
+ # ...
253
+ # super()
254
+ # end
255
+ # end
256
+ #
257
+ # vehicle = Vehicle.new # => #<Vehicle:0xb7c8dbf8 @state="parked">
258
+ # vehicle.state # => "parked"
259
+ #
260
+ # Because of the way the inclusion of modules works in Ruby, calling
261
+ # <tt>super()</tt> will not only call the superclass's +initialize+, but
262
+ # also +initialize+ on all included modules. This allows the original state
263
+ # machine hook to get called properly.
264
+ #
265
+ # If you want to avoid calling the superclass's constructor, but still want
266
+ # to initialize the state machine attributes:
267
+ #
268
+ # class Vehicle
269
+ # state_machine :state, :initial => :parked do
270
+ # ...
271
+ # end
272
+ #
273
+ # def initialize(attributes = {})
274
+ # ...
275
+ # initialize_state_machines
276
+ # end
277
+ # end
278
+ #
279
+ # vehicle = Vehicle.new # => #<Vehicle:0xb7c8dbf8 @state="parked">
280
+ # vehicle.state # => "parked"
281
+ #
282
+ # == States
283
+ #
284
+ # All of the valid states for the machine are automatically tracked based
285
+ # on the events, transitions, and callbacks defined for the machine. If
286
+ # there are additional states that are never referenced, these should be
287
+ # explicitly added using the StateMachine::Machine#state or
288
+ # StateMachine::Machine#other_states helpers.
289
+ #
290
+ # When a new state is defined, a predicate method for that state is
291
+ # generated on the class. For example,
292
+ #
293
+ # class Vehicle
294
+ # state_machine :initial => :parked do
295
+ # event :ignite do
296
+ # transition all => :idling
297
+ # end
298
+ # end
299
+ # end
300
+ #
301
+ # ...will generate the following instance methods (assuming they're not
302
+ # already defined in the class):
303
+ # * <tt>parked?</tt>
304
+ # * <tt>idling?</tt>
305
+ #
306
+ # Each predicate method will return true if it matches the object's
307
+ # current state. Otherwise, it will return false.
308
+ #
309
+ # == Events and Transitions
310
+ #
311
+ # Events defined on the machine are the interface to transitioning states
312
+ # for an object. Events can be fired either directly (through the method
313
+ # generated for the event) or indirectly (through attributes defined on
314
+ # the machine).
315
+ #
316
+ # For example,
317
+ #
318
+ # class Vehicle
319
+ # include DataMapper::Resource
320
+ # property :id, Serial
321
+ #
322
+ # state_machine :initial => :parked do
323
+ # event :ignite do
324
+ # transition :parked => :idling
325
+ # end
326
+ # end
327
+ #
328
+ # state_machine :alarm_state, :initial => :active do
329
+ # event :disable do
330
+ # transition all => :off
331
+ # end
332
+ # end
333
+ # end
334
+ #
335
+ # # Fire +ignite+ event directly
336
+ # vehicle = Vehicle.create # => #<Vehicle id=1 state="parked" alarm_state="active">
337
+ # vehicle.ignite # => true
338
+ # vehicle.state # => "idling"
339
+ # vehicle.alarm_state # => "active"
340
+ #
341
+ # # Fire +disable+ event automatically
342
+ # vehicle.alarm_state_event = 'disable'
343
+ # vehicle.save # => true
344
+ # vehicle.alarm_state # => "off"
345
+ #
346
+ # In the above example, the +state+ attribute is transitioned using the
347
+ # +ignite+ action that's generated from the state machine. On the other
348
+ # hand, the +alarm_state+ attribute is transitioned using the +alarm_state_event+
349
+ # attribute that automatically gets fired when the machine's action (+save+)
350
+ # is invoked.
351
+ #
352
+ # For more information about how to configure an event and its associated
353
+ # transitions, see StateMachine::Machine#event.
354
+ #
355
+ # == Defining callbacks
356
+ #
357
+ # Within the +state_machine+ block, you can also define callbacks for
358
+ # transitions. For more information about defining these callbacks,
359
+ # see StateMachine::Machine#before_transition, StateMachine::Machine#after_transition,
360
+ # and StateMachine::Machine#around_transition, and StateMachine::Machine#after_failure.
361
+ #
362
+ # == Namespaces
363
+ #
364
+ # When a namespace is configured for a state machine, the name provided
365
+ # will be used in generating the instance methods for interacting with
366
+ # states/events in the machine. This is particularly useful when a class
367
+ # has multiple state machines and it would be difficult to differentiate
368
+ # between the various states / events.
369
+ #
370
+ # For example,
371
+ #
372
+ # class Vehicle
373
+ # state_machine :heater_state, :initial => :off, :namespace => 'heater' do
374
+ # event :turn_on do
375
+ # transition all => :on
376
+ # end
377
+ #
378
+ # event :turn_off do
379
+ # transition all => :off
380
+ # end
381
+ # end
382
+ #
383
+ # state_machine :alarm_state, :initial => :active, :namespace => 'alarm' do
384
+ # event :turn_on do
385
+ # transition all => :active
386
+ # end
387
+ #
388
+ # event :turn_off do
389
+ # transition all => :off
390
+ # end
391
+ # end
392
+ # end
393
+ #
394
+ # The above class defines two state machines: +heater_state+ and +alarm_state+.
395
+ # For the +heater_state+ machine, the following methods are generated since
396
+ # it's namespaced by "heater":
397
+ # * <tt>can_turn_on_heater?</tt>
398
+ # * <tt>turn_on_heater</tt>
399
+ # * ...
400
+ # * <tt>can_turn_off_heater?</tt>
401
+ # * <tt>turn_off_heater</tt>
402
+ # * ..
403
+ # * <tt>heater_off?</tt>
404
+ # * <tt>heater_on?</tt>
405
+ #
406
+ # As shown, each method is unique to the state machine so that the states
407
+ # and events don't conflict. The same goes for the +alarm_state+ machine:
408
+ # * <tt>can_turn_on_alarm?</tt>
409
+ # * <tt>turn_on_alarm</tt>
410
+ # * ...
411
+ # * <tt>can_turn_off_alarm?</tt>
412
+ # * <tt>turn_off_alarm</tt>
413
+ # * ..
414
+ # * <tt>alarm_active?</tt>
415
+ # * <tt>alarm_off?</tt>
416
+ #
417
+ # == Scopes
418
+ #
419
+ # For integrations that support it, a group of default scope filters will
420
+ # be automatically created for assisting in finding objects that have the
421
+ # attribute set to one of a given set of states.
422
+ #
423
+ # For example,
424
+ #
425
+ # Vehicle.with_state(:parked) # => All vehicles where the state is parked
426
+ # Vehicle.with_states(:parked, :idling) # => All vehicles where the state is either parked or idling
427
+ #
428
+ # Vehicle.without_state(:parked) # => All vehicles where the state is *not* parked
429
+ # Vehicle.without_states(:parked, :idling) # => All vehicles where the state is *not* parked or idling
430
+ #
431
+ # *Note* that if class methods already exist with those names (i.e.
432
+ # :with_state, :with_states, :without_state, or :without_states), then a
433
+ # scope will not be defined for that name.
434
+ #
435
+ # See StateMachine::Machine for more information about using integrations
436
+ # and the individual integration docs for information about the actual
437
+ # scopes that are generated.
438
+ def state_machine(*args, &block)
439
+ StateMachine::Machine.find_or_create(self, *args, &block)
440
+ end
441
+ end
442
+ end
443
+
444
+ Class.class_eval do
445
+ include StateMachine::MacroMethods
446
+ end
447
+
448
+ require 'state_machine/initializers'