pluginaweek-state_machine 0.7.6
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.
- data/CHANGELOG.rdoc +273 -0
- data/LICENSE +20 -0
- data/README.rdoc +466 -0
- data/Rakefile +98 -0
- data/examples/AutoShop_state.png +0 -0
- data/examples/Car_state.png +0 -0
- data/examples/TrafficLight_state.png +0 -0
- data/examples/Vehicle_state.png +0 -0
- data/examples/auto_shop.rb +11 -0
- data/examples/car.rb +19 -0
- data/examples/merb-rest/controller.rb +51 -0
- data/examples/merb-rest/model.rb +28 -0
- data/examples/merb-rest/view_edit.html.erb +24 -0
- data/examples/merb-rest/view_index.html.erb +23 -0
- data/examples/merb-rest/view_new.html.erb +13 -0
- data/examples/merb-rest/view_show.html.erb +17 -0
- data/examples/rails-rest/controller.rb +43 -0
- data/examples/rails-rest/migration.rb +11 -0
- data/examples/rails-rest/model.rb +23 -0
- data/examples/rails-rest/view_edit.html.erb +25 -0
- data/examples/rails-rest/view_index.html.erb +23 -0
- data/examples/rails-rest/view_new.html.erb +14 -0
- data/examples/rails-rest/view_show.html.erb +17 -0
- data/examples/traffic_light.rb +7 -0
- data/examples/vehicle.rb +31 -0
- data/init.rb +1 -0
- data/lib/state_machine.rb +429 -0
- data/lib/state_machine/assertions.rb +36 -0
- data/lib/state_machine/callback.rb +189 -0
- data/lib/state_machine/condition_proxy.rb +94 -0
- data/lib/state_machine/eval_helpers.rb +67 -0
- data/lib/state_machine/event.rb +251 -0
- data/lib/state_machine/event_collection.rb +113 -0
- data/lib/state_machine/extensions.rb +158 -0
- data/lib/state_machine/guard.rb +219 -0
- data/lib/state_machine/integrations.rb +68 -0
- data/lib/state_machine/integrations/active_record.rb +444 -0
- data/lib/state_machine/integrations/active_record/locale.rb +10 -0
- data/lib/state_machine/integrations/active_record/observer.rb +41 -0
- data/lib/state_machine/integrations/data_mapper.rb +325 -0
- data/lib/state_machine/integrations/data_mapper/observer.rb +139 -0
- data/lib/state_machine/integrations/sequel.rb +292 -0
- data/lib/state_machine/machine.rb +1431 -0
- data/lib/state_machine/machine_collection.rb +146 -0
- data/lib/state_machine/matcher.rb +123 -0
- data/lib/state_machine/matcher_helpers.rb +54 -0
- data/lib/state_machine/node_collection.rb +152 -0
- data/lib/state_machine/state.rb +249 -0
- data/lib/state_machine/state_collection.rb +112 -0
- data/lib/state_machine/transition.rb +367 -0
- data/tasks/state_machine.rake +1 -0
- data/tasks/state_machine.rb +30 -0
- data/test/classes/switch.rb +11 -0
- data/test/functional/state_machine_test.rb +941 -0
- data/test/test_helper.rb +4 -0
- data/test/unit/assertions_test.rb +40 -0
- data/test/unit/callback_test.rb +455 -0
- data/test/unit/condition_proxy_test.rb +328 -0
- data/test/unit/eval_helpers_test.rb +129 -0
- data/test/unit/event_collection_test.rb +293 -0
- data/test/unit/event_test.rb +605 -0
- data/test/unit/guard_test.rb +862 -0
- data/test/unit/integrations/active_record_test.rb +1001 -0
- data/test/unit/integrations/data_mapper_test.rb +694 -0
- data/test/unit/integrations/sequel_test.rb +486 -0
- data/test/unit/integrations_test.rb +42 -0
- data/test/unit/invalid_event_test.rb +7 -0
- data/test/unit/invalid_transition_test.rb +7 -0
- data/test/unit/machine_collection_test.rb +710 -0
- data/test/unit/machine_test.rb +1910 -0
- data/test/unit/matcher_helpers_test.rb +37 -0
- data/test/unit/matcher_test.rb +155 -0
- data/test/unit/node_collection_test.rb +207 -0
- data/test/unit/state_collection_test.rb +280 -0
- data/test/unit/state_machine_test.rb +31 -0
- data/test/unit/state_test.rb +795 -0
- data/test/unit/transition_test.rb +1113 -0
- metadata +161 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
<p>
|
2
|
+
<b>Name:</b>
|
3
|
+
<%=h @user.name %>
|
4
|
+
</p>
|
5
|
+
|
6
|
+
<p>
|
7
|
+
<b>State:</b>
|
8
|
+
<%=h @user.state %>
|
9
|
+
</p>
|
10
|
+
|
11
|
+
<p>
|
12
|
+
<b>Access State:</b>
|
13
|
+
<%=h @user.access_state %>
|
14
|
+
</p>
|
15
|
+
|
16
|
+
<%= link_to 'Edit', edit_user_path(@user) %> |
|
17
|
+
<%= link_to 'Back', users_path %>
|
data/examples/vehicle.rb
ADDED
@@ -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,429 @@
|
|
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 for the given attribute. The default
|
9
|
+
# attribute, if not specified, is <tt>:state</tt>.
|
10
|
+
#
|
11
|
+
# Configuration options:
|
12
|
+
# * <tt>:initial</tt> - The initial state of the attribute. This can be a
|
13
|
+
# static state or a lambda block which will be evaluated at runtime
|
14
|
+
# (e.g. lambda {|vehicle| vehicle.speed == 0 ? :parked : :idling}).
|
15
|
+
# Default is nil.
|
16
|
+
# * <tt>:action</tt> - The instance method to invoke when an object
|
17
|
+
# transitions. Default is nil unless otherwise specified by the
|
18
|
+
# configured integration.
|
19
|
+
# * <tt>:as</tt> - The name to use for prefixing all generated machine
|
20
|
+
# instance / class methods (e.g. if the attribute is +state_id+, then
|
21
|
+
# "state" would generate :state_name, :state_transitions, etc. instead of
|
22
|
+
# :state_id_name and :state_id_transitions)
|
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 :data_mapper, :active_record, and :sequel. By default, this
|
30
|
+
# is determined automatically.
|
31
|
+
#
|
32
|
+
# Configuration options relevant to ORM integrations:
|
33
|
+
# * <tt>:plural</tt> - The pluralized name of the attribute. By default,
|
34
|
+
# this will attempt to call +pluralize+ on the attribute. If this
|
35
|
+
# method is not available, an "s" is appended. This is used for
|
36
|
+
# generating scopes.
|
37
|
+
# * <tt>:messages</tt> - The error messages to use when invalidating
|
38
|
+
# objects due to failed transitions. Messages include:
|
39
|
+
# * <tt>:invalid</tt>
|
40
|
+
# * <tt>:invalid_event</tt>
|
41
|
+
# * <tt>:invalid_transition</tt>
|
42
|
+
# * <tt>:use_transactions</tt> - Whether transactions should be used when
|
43
|
+
# firing events. Default is true unless otherwise specified by the
|
44
|
+
# configured integration.
|
45
|
+
#
|
46
|
+
# This also expects a block which will be used to actually configure the
|
47
|
+
# states, events and transitions for the state machine. *Note* that this
|
48
|
+
# block will be executed within the context of the state machine. As a
|
49
|
+
# result, you will not be able to access any class methods unless you refer
|
50
|
+
# to them directly (i.e. specifying the class name).
|
51
|
+
#
|
52
|
+
# For examples on the types of configured state machines and blocks, see
|
53
|
+
# the section below.
|
54
|
+
#
|
55
|
+
# == Examples
|
56
|
+
#
|
57
|
+
# With the default attribute and no configuration:
|
58
|
+
#
|
59
|
+
# class Vehicle
|
60
|
+
# state_machine do
|
61
|
+
# event :park do
|
62
|
+
# ...
|
63
|
+
# end
|
64
|
+
# end
|
65
|
+
# end
|
66
|
+
#
|
67
|
+
# The above example will define a state machine for the +state+ attribute
|
68
|
+
# on the class. Every vehicle will start without an initial state.
|
69
|
+
#
|
70
|
+
# With a custom attribute:
|
71
|
+
#
|
72
|
+
# class Vehicle
|
73
|
+
# state_machine :status 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
|
+
# == Instance Methods
|
95
|
+
#
|
96
|
+
# The following instance methods will be automatically generated by the
|
97
|
+
# state machine. Any existing methods will not be overwritten.
|
98
|
+
# * <tt>state</tt> - Gets the current value for the attribute
|
99
|
+
# * <tt>state=(value)</tt> - Sets the current value for the attribute
|
100
|
+
# * <tt>state?(name)</tt> - Checks the given state name against the current
|
101
|
+
# state. If the name is not a known state, then an ArgumentError is raised.
|
102
|
+
# * <tt>state_name</tt> - Gets the name of the state for the current value
|
103
|
+
# * <tt>state_events</tt> - Gets the list of events that can be fired on
|
104
|
+
# the current object's state (uses the *unqualified* event names)
|
105
|
+
# * <tt>state_transitions</tt> - Gets the list of possible transitions
|
106
|
+
# that can be made on the current object's state
|
107
|
+
#
|
108
|
+
# For example,
|
109
|
+
#
|
110
|
+
# class Vehicle
|
111
|
+
# state_machine :state, :initial => :parked do
|
112
|
+
# event :ignite do
|
113
|
+
# transition :parked => :idling
|
114
|
+
# end
|
115
|
+
#
|
116
|
+
# event :park do
|
117
|
+
# transition :idling => :parked
|
118
|
+
# end
|
119
|
+
# end
|
120
|
+
# end
|
121
|
+
#
|
122
|
+
# vehicle = Vehicle.new
|
123
|
+
# vehicle.state # => "parked"
|
124
|
+
# vehicle.state_name # => :parked
|
125
|
+
# vehicle.state?(:parked) # => true
|
126
|
+
#
|
127
|
+
# # Changing state
|
128
|
+
# vehicle.state = 'idling'
|
129
|
+
# vehicle.state # => "idling"
|
130
|
+
# vehicle.state_name # => :idling
|
131
|
+
# vehicle.state?(:parked) # => false
|
132
|
+
#
|
133
|
+
# # Getting current event / transition availability
|
134
|
+
# vehicle.state_events # => [:park]
|
135
|
+
# vehicle.park # => true
|
136
|
+
# vehicle.state_events # => [:ignite]
|
137
|
+
#
|
138
|
+
# vehicle.state_transitions # => [#<StateMachine::Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>]
|
139
|
+
# vehicle.ignite
|
140
|
+
# vehicle.state_transitions # => [#<StateMachine::Transition attribute=:state event=:park from="idling" from_name=:idling to="parked" to_name=:parked>]
|
141
|
+
#
|
142
|
+
# == Attribute initialization
|
143
|
+
#
|
144
|
+
# For most classes, the initial values for state machine attributes are
|
145
|
+
# automatically assigned when a new object is created. However, this
|
146
|
+
# behavior will *not* work if the class defines an +initialize+ method
|
147
|
+
# without properly calling +super+.
|
148
|
+
#
|
149
|
+
# For example,
|
150
|
+
#
|
151
|
+
# class Vehicle
|
152
|
+
# state_machine :state, :initial => :parked do
|
153
|
+
# ...
|
154
|
+
# end
|
155
|
+
# end
|
156
|
+
#
|
157
|
+
# vehicle = Vehicle.new # => #<Vehicle:0xb7c8dbf8 @state="parked">
|
158
|
+
# vehicle.state # => "parked"
|
159
|
+
#
|
160
|
+
# In the above example, no +initialize+ method is defined. As a result,
|
161
|
+
# the default behavior of initializing the state machine attributes is used.
|
162
|
+
#
|
163
|
+
# In the following example, a custom +initialize+ method is defined:
|
164
|
+
#
|
165
|
+
# class Vehicle
|
166
|
+
# state_machine :state, :initial => :parked do
|
167
|
+
# ...
|
168
|
+
# end
|
169
|
+
#
|
170
|
+
# def initialize
|
171
|
+
# end
|
172
|
+
# end
|
173
|
+
#
|
174
|
+
# vehicle = Vehicle.new # => #<Vehicle:0xb7c77678>
|
175
|
+
# vehicle.state # => nil
|
176
|
+
#
|
177
|
+
# Since the +initialize+ method is defined, the state machine attributes
|
178
|
+
# never get initialized. In order to ensure that all initialization hooks
|
179
|
+
# are called, the custom method *must* call +super+ without any arguments
|
180
|
+
# like so:
|
181
|
+
#
|
182
|
+
# class Vehicle
|
183
|
+
# state_machine :state, :initial => :parked do
|
184
|
+
# ...
|
185
|
+
# end
|
186
|
+
#
|
187
|
+
# def initialize(attributes = {})
|
188
|
+
# ...
|
189
|
+
# super()
|
190
|
+
# end
|
191
|
+
# end
|
192
|
+
#
|
193
|
+
# vehicle = Vehicle.new # => #<Vehicle:0xb7c8dbf8 @state="parked">
|
194
|
+
# vehicle.state # => "parked"
|
195
|
+
#
|
196
|
+
# Because of the way the inclusion of modules works in Ruby, calling
|
197
|
+
# <tt>super()</tt> will not only call the superclass's +initialize+, but
|
198
|
+
# also +initialize+ on all included modules. This allows the original state
|
199
|
+
# machine hook to get called properly.
|
200
|
+
#
|
201
|
+
# If you want to avoid calling the superclass's constructor, but still want
|
202
|
+
# to initialize the state machine attributes:
|
203
|
+
#
|
204
|
+
# class Vehicle
|
205
|
+
# state_machine :state, :initial => :parked do
|
206
|
+
# ...
|
207
|
+
# end
|
208
|
+
#
|
209
|
+
# def initialize(attributes = {})
|
210
|
+
# ...
|
211
|
+
# initialize_state_machines
|
212
|
+
# end
|
213
|
+
# end
|
214
|
+
#
|
215
|
+
# vehicle = Vehicle.new # => #<Vehicle:0xb7c8dbf8 @state="parked">
|
216
|
+
# vehicle.state # => "parked"
|
217
|
+
#
|
218
|
+
# == States
|
219
|
+
#
|
220
|
+
# All of the valid states for the machine are automatically tracked based
|
221
|
+
# on the events, transitions, and callbacks defined for the machine. If
|
222
|
+
# there are additional states that are never referenced, these should be
|
223
|
+
# explicitly added using the StateMachine::Machine#state or
|
224
|
+
# StateMachine::Machine#other_states helpers.
|
225
|
+
#
|
226
|
+
# When a new state is defined, a predicate method for that state is
|
227
|
+
# generated on the class. For example,
|
228
|
+
#
|
229
|
+
# class Vehicle
|
230
|
+
# state_machine :initial => :parked do
|
231
|
+
# event :ignite do
|
232
|
+
# transition all => :idling
|
233
|
+
# end
|
234
|
+
# end
|
235
|
+
# end
|
236
|
+
#
|
237
|
+
# ...will generate the following instance methods (assuming they're not
|
238
|
+
# already defined in the class):
|
239
|
+
# * <tt>parked?</tt>
|
240
|
+
# * <tt>idling?</tt>
|
241
|
+
#
|
242
|
+
# Each predicate method will return true if it matches the object's
|
243
|
+
# current state. Otherwise, it will return false.
|
244
|
+
#
|
245
|
+
# == Events and Transitions
|
246
|
+
#
|
247
|
+
# Events defined on the machine are the interface to transitioning states
|
248
|
+
# for an object. Events can be fired either directly (through the method
|
249
|
+
# generated for the event) or indirectly (through attributes defined on
|
250
|
+
# the machine).
|
251
|
+
#
|
252
|
+
# For example,
|
253
|
+
#
|
254
|
+
# class Vehicle
|
255
|
+
# include DataMapper::Resource
|
256
|
+
# property :id, Integer, :serial => true
|
257
|
+
#
|
258
|
+
# state_machine :initial => :parked do
|
259
|
+
# event :ignite do
|
260
|
+
# transition :parked => :idling
|
261
|
+
# end
|
262
|
+
# end
|
263
|
+
#
|
264
|
+
# state_machine :alarm_state, :initial => :active do
|
265
|
+
# event :disable do
|
266
|
+
# transition all => :off
|
267
|
+
# end
|
268
|
+
# end
|
269
|
+
# end
|
270
|
+
#
|
271
|
+
# # Fire +ignite+ event directly
|
272
|
+
# vehicle = Vehicle.create # => #<Vehicle id=1 state="parked" alarm_state="active">
|
273
|
+
# vehicle.ignite # => true
|
274
|
+
# vehicle.state # => "idling"
|
275
|
+
# vehicle.alarm_state # => "active"
|
276
|
+
#
|
277
|
+
# # Fire +disable+ event automatically
|
278
|
+
# vehicle.alarm_state_event = 'disable'
|
279
|
+
# vehicle.save # => true
|
280
|
+
# vehicle.alarm_state # => "off"
|
281
|
+
#
|
282
|
+
# In the above example, the +state+ attribute is transitioned using the
|
283
|
+
# +ignite+ action that's generated from the state machine. On the other
|
284
|
+
# hand, the +alarm_state+ attribute is transitioned using the +alarm_state_event+
|
285
|
+
# attribute that automatically gets fired when the machine's action (+save+)
|
286
|
+
# is invoked.
|
287
|
+
#
|
288
|
+
# For more information about how to configure an event and its associated
|
289
|
+
# transitions, see StateMachine::Machine#event.
|
290
|
+
#
|
291
|
+
# == Defining callbacks
|
292
|
+
#
|
293
|
+
# Within the +state_machine+ block, you can also define callbacks for
|
294
|
+
# transitions. For more information about defining these callbacks,
|
295
|
+
# see StateMachine::Machine#before_transition and
|
296
|
+
# StateMachine::Machine#after_transition.
|
297
|
+
#
|
298
|
+
# == Attribute aliases
|
299
|
+
#
|
300
|
+
# When a state machine is defined, several methods are generated scoped by
|
301
|
+
# the name of the attribute, such as (if the attribute were "state"):
|
302
|
+
# * <tt>state_name</tt>
|
303
|
+
# * <tt>state_event</tt>
|
304
|
+
# * <tt>state_transitions</tt>
|
305
|
+
# * etc.
|
306
|
+
#
|
307
|
+
# If the attribute for the machine were something less common, such as
|
308
|
+
# "state_id" or "state_value", this makes for more awkward scoped methods.
|
309
|
+
#
|
310
|
+
# Rather than scope based on the attribute, these methods can be customized
|
311
|
+
# using the <tt>:as</tt> option as essentially an alias.
|
312
|
+
#
|
313
|
+
# For example,
|
314
|
+
#
|
315
|
+
# class Vehicle
|
316
|
+
# state_machine :state_id, :as => :state do
|
317
|
+
# event :turn_on do
|
318
|
+
# transition all => :on
|
319
|
+
# end
|
320
|
+
#
|
321
|
+
# event :turn_off do
|
322
|
+
# transition all => :off
|
323
|
+
# end
|
324
|
+
#
|
325
|
+
# state :on, :value => 1
|
326
|
+
# state :off, :value => 2
|
327
|
+
# end
|
328
|
+
# end
|
329
|
+
#
|
330
|
+
# ...will generate the following methods:
|
331
|
+
# * <tt>state_name</tt>
|
332
|
+
# * <tt>state_event</tt>
|
333
|
+
# * <tt>state_transitions</tt>
|
334
|
+
#
|
335
|
+
# ...instead of:
|
336
|
+
# * <tt>state_id_name</tt>
|
337
|
+
# * <tt>state_id_event</tt>
|
338
|
+
# * <tt>state_id_transitions</tt>
|
339
|
+
#
|
340
|
+
# However, it will continue to read and write to the +state_id+ attribute.
|
341
|
+
#
|
342
|
+
# == Namespaces
|
343
|
+
#
|
344
|
+
# When a namespace is configured for a state machine, the name provided
|
345
|
+
# will be used in generating the instance methods for interacting with
|
346
|
+
# events/states in the machine. This is particularly useful when a class
|
347
|
+
# has multiple state machines and it would be difficult to differentiate
|
348
|
+
# between the various states / events.
|
349
|
+
#
|
350
|
+
# For example,
|
351
|
+
#
|
352
|
+
# class Vehicle
|
353
|
+
# state_machine :heater_state, :initial => :off, :namespace => 'heater' do
|
354
|
+
# event :turn_on do
|
355
|
+
# transition all => :on
|
356
|
+
# end
|
357
|
+
#
|
358
|
+
# event :turn_off do
|
359
|
+
# transition all => :off
|
360
|
+
# end
|
361
|
+
# end
|
362
|
+
#
|
363
|
+
# state_machine :alarm_state, :initial => :active, :namespace => 'alarm' do
|
364
|
+
# event :turn_on do
|
365
|
+
# transition all => :active
|
366
|
+
# end
|
367
|
+
#
|
368
|
+
# event :turn_off do
|
369
|
+
# transition all => :off
|
370
|
+
# end
|
371
|
+
# end
|
372
|
+
# end
|
373
|
+
#
|
374
|
+
# The above class defines two state machines: +heater_state+ and +alarm_state+.
|
375
|
+
# For the +heater_state+ machine, the following methods are generated since
|
376
|
+
# it's namespaced by "heater":
|
377
|
+
# * <tt>can_turn_on_heater?</tt>
|
378
|
+
# * <tt>turn_on_heater</tt>
|
379
|
+
# * ...
|
380
|
+
# * <tt>can_turn_off_heater?</tt>
|
381
|
+
# * <tt>turn_off_heater</tt>
|
382
|
+
# * ..
|
383
|
+
# * <tt>heater_off?</tt>
|
384
|
+
# * <tt>heater_on?</tt>
|
385
|
+
#
|
386
|
+
# As shown, each method is unique to the state machine so that the states
|
387
|
+
# and events don't conflict. The same goes for the +alarm_state+ machine:
|
388
|
+
# * <tt>can_turn_on_alarm?</tt>
|
389
|
+
# * <tt>turn_on_alarm</tt>
|
390
|
+
# * ...
|
391
|
+
# * <tt>can_turn_off_alarm?</tt>
|
392
|
+
# * <tt>turn_off_alarm</tt>
|
393
|
+
# * ..
|
394
|
+
# * <tt>alarm_active?</tt>
|
395
|
+
# * <tt>alarm_off?</tt>
|
396
|
+
#
|
397
|
+
# == Scopes
|
398
|
+
#
|
399
|
+
# For integrations that support it, a group of default scope filters will
|
400
|
+
# be automatically created for assisting in finding objects that have the
|
401
|
+
# attribute set to the value for a given set of states.
|
402
|
+
#
|
403
|
+
# For example,
|
404
|
+
#
|
405
|
+
# Vehicle.with_state(:parked) # => All vehicles where the state is parked
|
406
|
+
# Vehicle.with_states(:parked, :idling) # => All vehicles where the state is either parked or idling
|
407
|
+
#
|
408
|
+
# Vehicle.without_state(:parked) # => All vehicles where the state is *not* parked
|
409
|
+
# Vehicle.without_states(:parked, :idling) # => All vehicles where the state is *not* parked or idling
|
410
|
+
#
|
411
|
+
# *Note* that if class methods already exist with those names (i.e.
|
412
|
+
# :with_state, :with_states, :without_state, or :without_states), then a
|
413
|
+
# scope will not be defined for that name.
|
414
|
+
#
|
415
|
+
# See StateMachine::Machine for more information about using
|
416
|
+
# integrations and the individual integration docs for information about
|
417
|
+
# the actual scopes that are generated.
|
418
|
+
def state_machine(*args, &block)
|
419
|
+
StateMachine::Machine.find_or_create(self, *args, &block)
|
420
|
+
end
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
Class.class_eval do
|
425
|
+
include StateMachine::MacroMethods
|
426
|
+
end
|
427
|
+
|
428
|
+
# Register rake tasks for supported libraries
|
429
|
+
Merb::Plugins.add_rakefiles("#{File.dirname(__FILE__)}/../tasks/state_machine") if defined?(Merb::Plugins)
|