transitions 0.1.12 → 0.1.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/CHANGELOG.md +5 -0
- data/README.md +135 -59
- data/lib/active_model/transitions.rb +0 -22
- data/lib/transitions.rb +2 -22
- data/lib/transitions/event.rb +0 -22
- data/lib/transitions/machine.rb +44 -47
- data/lib/transitions/presenter.rb +15 -0
- data/lib/transitions/state.rb +0 -22
- data/lib/transitions/state_transition.rb +12 -33
- data/lib/transitions/version.rb +1 -1
- data/test/state_transition/test_state_transition_guard_check.rb +14 -1
- metadata +26 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b87d3c72b83d64e0c80f22f8b6984fc897e75725
|
4
|
+
data.tar.gz: c680875bb9ebd5b68fcf0b02943a04a07147121b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 400a2ecb0b2c08ae1a29f860607eeddb1c9d0cb4565a2530e90b9d886a88d4c292658097a604e993af2150a8fc90bfacefc030d03a2d76f9d57dede7327de239
|
7
|
+
data.tar.gz: 08d83f73449b3338b4b8a4cbc8ff6f031e9ab61eaa715fdc016f4a3794722e25fb0887ac9326be8195241a76e401d1ed4d93495accdcaec80f6fce3b3145ec43
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.1.0
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -2,21 +2,30 @@
|
|
2
2
|
[![Build status](https://secure.travis-ci.org/troessner/transitions.png?branch=master)](http://travis-ci.org/troessner/transitions)
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/transitions.png)](http://badge.fury.io/rb/transitions)
|
4
4
|
[![Code Climate](https://codeclimate.com/github/troessner/transitions.png)](https://codeclimate.com/github/troessner/transitions)
|
5
|
+
[![Dependency Status](https://gemnasium.com/troessner/transitions.png)](https://gemnasium.com/troessner/transitions)
|
6
|
+
[![Inline docs](http://inch-ci.org/github/troessner/transitions.png)](http://inch-ci.org/github/troessner/transitions)
|
7
|
+
|
5
8
|
|
6
9
|
### Synopsis
|
7
10
|
|
8
11
|
`transitions` is a ruby state machine implementation.
|
9
12
|
|
10
|
-
### Compatibility
|
13
|
+
### Ruby Compatibility
|
11
14
|
|
12
|
-
Supported
|
15
|
+
Supported versions:
|
13
16
|
|
14
17
|
* 1.9.3
|
15
18
|
* 2.0
|
19
|
+
* 2.1
|
16
20
|
|
17
21
|
`transitions` does not work with ruby 1.8.7 (see [this
|
18
22
|
issue](https://github.com/troessner/transitions/issues/86) for example).
|
19
23
|
|
24
|
+
### Supported Rails versions:
|
25
|
+
|
26
|
+
* 3
|
27
|
+
* 4
|
28
|
+
|
20
29
|
### Installation
|
21
30
|
|
22
31
|
#### Rails
|
@@ -119,62 +128,74 @@ If you need to get all available transitions for current state you can simply ca
|
|
119
128
|
>> Product.new.available_transitions
|
120
129
|
=> [:discontinued, :out_of_stock]
|
121
130
|
```
|
122
|
-
|
123
|
-
#### Automatic scope generation
|
124
131
|
|
125
|
-
`transitions` will automatically generate scopes for you if you are using
|
126
|
-
ActiveRecord and tell it to do so via the `auto_scopes` option:
|
127
132
|
|
128
|
-
|
129
|
-
```ruby
|
130
|
-
class Order < ActiveRecord::Base
|
131
|
-
include ActiveModel::Transitions
|
132
|
-
state_machine :auto_scopes => true do
|
133
|
-
state :pick_line_items
|
134
|
-
state :picking_line_items
|
135
|
-
event :move_cart do
|
136
|
-
transitions to: :pick_line_items, from: :picking_line_items
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
```
|
133
|
+
#### Callback overview
|
141
134
|
|
142
|
-
you
|
143
|
-
```ruby
|
144
|
-
>> Order.pick_line_items
|
145
|
-
=> []
|
146
|
-
>> Order.create!
|
147
|
-
=> #<Order id: 3, state: "pick_line_items", description: nil, created_at: "2011-08-23 15:48:46", updated_at: "2011-08-23 15:48:46">
|
148
|
-
>> Order.pick_line_items
|
149
|
-
=> [#<Order id: 3, state: "pick_line_items", description: nil, created_at: "2011-08-23 15:48:46", updated_at: "2011-08-23 15:48:46">]
|
150
|
-
```
|
135
|
+
`transitions` offers you the possibility to define a couple of callbacks during the different stages / places of transitioning from one state to another. So let's say you have an event `discontinue` which transitions the current state from `in_stock` to `sold_out`. The callback sequence would look like this:
|
151
136
|
|
152
|
-
#### Using `guard`
|
153
137
|
|
154
|
-
|
155
|
-
|
138
|
+
| discontinue event |
|
139
|
+
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
| current_state `in_stock` | ----> executes `exit` callback
|
143
|
+
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
| current_state `in_stock` | ----> executes `on_transition` callback if and only the `guard` check was successfull. If not successfull, the chain aborts here and the `event_failed` callback is executed
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
| current_state `in_stock` | ----> executes `enter` callback for new state `sold_out`
|
151
|
+
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
| current_state `in_stock` | ----> executes `event_fired` callback
|
155
|
+
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
| current_state `in_stock` | ----> move state from `in_stock` to `sold_out`
|
159
|
+
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
| current_state `sold_out` | ----> executes `success` callback of the `discontinue` event
|
156
163
|
|
157
|
-
You can pass in Symbols, Strings, or Procs like this:
|
158
|
-
```ruby
|
159
|
-
event :discontinue do
|
160
|
-
transitions :to => :discontinued, :from => [:available, :out_of_stock], :guard => :can_discontinue
|
161
|
-
end
|
162
|
-
```
|
163
164
|
|
164
|
-
|
165
|
+
|
166
|
+
This all looks very complicated (I know), but don't worry, in 99% of all cases you don't have to care about the details and the usage itself is straightforward as you can see in the examples below where each callback is explained a little more throrough.
|
167
|
+
|
168
|
+
|
169
|
+
#### Callback # 1: State callbacks `enter` and `exit`
|
170
|
+
|
171
|
+
If you want to trigger a method call when the object enters or exits a state regardless
|
172
|
+
of the transition that made that happen, use `enter` and `exit`.
|
173
|
+
|
174
|
+
`exit` will be called before the transition out of the state is executed. If you want the method
|
175
|
+
to only be called if the transition is successful, then use another approach.
|
176
|
+
|
177
|
+
`enter` will be called after the transition has been made but before the object is persisted. If you want
|
178
|
+
the method to only be called after a successful transition to a new state including persistence,
|
179
|
+
use the `success` argument to an event instead.
|
180
|
+
|
181
|
+
An example:
|
182
|
+
|
165
183
|
```ruby
|
166
|
-
|
167
|
-
|
184
|
+
class Motor < ActiveRecord::Base
|
185
|
+
include ActiveModel::Transitions
|
186
|
+
|
187
|
+
state_machine do
|
188
|
+
state :off, enter: :turn_power_off
|
189
|
+
state :on, exit: :prepare_shutdown
|
190
|
+
end
|
168
191
|
end
|
169
192
|
```
|
170
193
|
|
171
|
-
|
172
|
-
predicate.
|
194
|
+
#### Callback # 2: Transition callback `on_transition`
|
173
195
|
|
174
|
-
#### Using `on_transition`
|
175
196
|
|
176
197
|
Each event definition takes an optional `on_transition` argument, which allows
|
177
|
-
you to execute
|
198
|
+
you to execute code on transition. This callback is executed after the `exit` callback of the former state (if it has been defined) but before the `enter` callback of the new state and only if the `guard` check succeeds. There is no check if the callback itself succeeds (meaning that `transitions` does not evaluate its return value somewhere). However, you can easily add some properly abstracted error handling yourself by raising an exception in this callback and then handling this exception in the (also defined by you) `event_failed` callback (see below and / or the wonderful ascii diagram above).
|
178
199
|
|
179
200
|
You can pass in a Symbol, a String, a Proc or an Array containing method names
|
180
201
|
as Symbol or String like this:
|
@@ -186,21 +207,8 @@ end
|
|
186
207
|
|
187
208
|
Any arguments passed to the event method will be passed on to the `on_transition` callback.
|
188
209
|
|
189
|
-
`on_transition` is called after `guard` and before `enter` on the state that it is transitioning to.
|
190
|
-
|
191
|
-
#### Using `enter` and `exit`
|
192
|
-
|
193
|
-
If you want to trigger a method call when the object enters or exits a state regardless
|
194
|
-
of the transition that made that happen, use `enter` and `exit`.
|
195
210
|
|
196
|
-
|
197
|
-
to only be called if the transition is successful, then use another approach.
|
198
|
-
|
199
|
-
`enter` will be called after the transition has been made but before the object is persisted. If you want
|
200
|
-
the method to only be called after a successful transition to a new state including persistence,
|
201
|
-
use the `success` argument to an event instead.
|
202
|
-
|
203
|
-
#### Using `success`
|
211
|
+
#### Callback #3 : Event callback `success`
|
204
212
|
|
205
213
|
In case you need to trigger a method call after a successful transition you
|
206
214
|
can use `success`. This will be called after the `save!` is complete (if you
|
@@ -228,6 +236,71 @@ event :discontinue, :success => [:notify_admin, lambda { |order| AdminNotifier.n
|
|
228
236
|
end
|
229
237
|
```
|
230
238
|
|
239
|
+
#### Callback caveats
|
240
|
+
|
241
|
+
Since callbacks will not be called by you but by `transitions` the scope is different when they are called and you'll run into problems if you use classes / modules in those callbacks that have the same names like `transitions` ones, e.g. "Event":
|
242
|
+
|
243
|
+
```Ruby
|
244
|
+
def event_fired(current_state, new_state, event)
|
245
|
+
Event.create!
|
246
|
+
end
|
247
|
+
```
|
248
|
+
|
249
|
+
This will crash because `transitions` uses an Event class as well, and, since the scope has changed when `transitions` calls this method, `transitions` will use it's own Event class here, not yours.
|
250
|
+
In this case you can try to prefix your models with the "::" operator and see if that solves your problems. See https://github.com/troessner/transitions/issues/123 for details.
|
251
|
+
|
252
|
+
#### Automatic scope generation
|
253
|
+
|
254
|
+
`transitions` will automatically generate scopes for you if you are using
|
255
|
+
ActiveRecord and tell it to do so via the `auto_scopes` option:
|
256
|
+
|
257
|
+
Given a model like this:
|
258
|
+
```ruby
|
259
|
+
class Order < ActiveRecord::Base
|
260
|
+
include ActiveModel::Transitions
|
261
|
+
state_machine :auto_scopes => true do
|
262
|
+
state :pick_line_items
|
263
|
+
state :picking_line_items
|
264
|
+
event :move_cart do
|
265
|
+
transitions to: :pick_line_items, from: :picking_line_items
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
```
|
270
|
+
|
271
|
+
you can use this feature a la:
|
272
|
+
```ruby
|
273
|
+
>> Order.pick_line_items
|
274
|
+
=> []
|
275
|
+
>> Order.create!
|
276
|
+
=> #<Order id: 3, state: "pick_line_items", description: nil, created_at: "2011-08-23 15:48:46", updated_at: "2011-08-23 15:48:46">
|
277
|
+
>> Order.pick_line_items
|
278
|
+
=> [#<Order id: 3, state: "pick_line_items", description: nil, created_at: "2011-08-23 15:48:46", updated_at: "2011-08-23 15:48:46">]
|
279
|
+
```
|
280
|
+
|
281
|
+
#### Using `guard`
|
282
|
+
|
283
|
+
Each event definition takes an optional `guard` argument, which acts as a
|
284
|
+
predicate for the transition.
|
285
|
+
|
286
|
+
You can pass in Symbols, Strings, or Procs like this:
|
287
|
+
```ruby
|
288
|
+
event :discontinue do
|
289
|
+
transitions :to => :discontinued, :from => [:available, :out_of_stock], :guard => :can_discontinue
|
290
|
+
end
|
291
|
+
```
|
292
|
+
|
293
|
+
or
|
294
|
+
```ruby
|
295
|
+
event :discontinue do
|
296
|
+
transitions :to => :discontinued, :from => [:available, :out_of_stock], :guard => [:can_discontinue, :super_sure?]
|
297
|
+
end
|
298
|
+
```
|
299
|
+
|
300
|
+
Any arguments passed to the event method will be passed on to the `guard`
|
301
|
+
predicate.
|
302
|
+
|
303
|
+
|
231
304
|
#### Timestamps
|
232
305
|
|
233
306
|
If you'd like to note the time of a state change, Transitions comes with
|
@@ -285,6 +358,9 @@ state_machine :initial => :closed do
|
|
285
358
|
end
|
286
359
|
```
|
287
360
|
|
361
|
+
The explicitly specified state **must** be one of the states listed in the state definition below, otherwise `transitions` will raise a rather unhelpful exception like "NoMethodError: undefined method `call_action' for nil:NilClass" (there's a ticket to fix this already: https://github.com/troessner/transitions/issues/112)
|
362
|
+
|
363
|
+
|
288
364
|
### Configuring a different column name with ActiveRecord
|
289
365
|
|
290
366
|
To use a different column than `state` to track it's value simply do this:
|
@@ -306,7 +382,7 @@ end
|
|
306
382
|
possible fix had to be rolled back due to other side effects:
|
307
383
|
https://github.com/troessner/transitions/issues/76. Since I know virtually
|
308
384
|
zero about mongoid, a pull request would be highly appreciated.
|
309
|
-
* Multiple state machines are and will not be supported. For the rationale
|
385
|
+
* Multiple state machines are not and will not be supported. For the rationale
|
310
386
|
behind this see the Changelog.
|
311
387
|
|
312
388
|
|
@@ -1,25 +1,3 @@
|
|
1
|
-
# Copyright (c) 2009 Rick Olson
|
2
|
-
|
3
|
-
# Permission is hereby granted, free of charge, to any person
|
4
|
-
# obtaining a copy of this software and associated documentation files
|
5
|
-
# (the "Software"), to deal in the Software without restriction,
|
6
|
-
# including without limitation the rights to use, copy, modify, merge,
|
7
|
-
# publish, distribute, sublicense, and/or sell copies of the Software,
|
8
|
-
# and to permit persons to whom the Software is furnished to do so,
|
9
|
-
# subject to the following conditions:
|
10
|
-
|
11
|
-
# The above copyright notice and this permission notice shall be
|
12
|
-
# included in all copies or substantial portions of the Software.
|
13
|
-
|
14
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
18
|
-
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
19
|
-
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
-
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
-
# SOFTWARE.
|
22
|
-
|
23
1
|
module ActiveModel
|
24
2
|
module Transitions
|
25
3
|
extend ActiveSupport::Concern
|
data/lib/transitions.rb
CHANGED
@@ -1,27 +1,6 @@
|
|
1
|
-
# Copyright (c) 2009 Rick Olson
|
2
|
-
|
3
|
-
# Permission is hereby granted, free of charge, to any person
|
4
|
-
# obtaining a copy of this software and associated documentation files
|
5
|
-
# (the "Software"), to deal in the Software without restriction,
|
6
|
-
# including without limitation the rights to use, copy, modify, merge,
|
7
|
-
# publish, distribute, sublicense, and/or sell copies of the Software,
|
8
|
-
# and to permit persons to whom the Software is furnished to do so,
|
9
|
-
# subject to the following conditions:
|
10
|
-
|
11
|
-
# The above copyright notice and this permission notice shall be
|
12
|
-
# included in all copies or substantial portions of the Software.
|
13
|
-
|
14
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
18
|
-
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
19
|
-
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
-
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
-
# SOFTWARE.
|
22
|
-
|
23
1
|
require "transitions/event"
|
24
2
|
require "transitions/machine"
|
3
|
+
require "transitions/presenter"
|
25
4
|
require "transitions/state"
|
26
5
|
require "transitions/state_transition"
|
27
6
|
require "transitions/version"
|
@@ -29,6 +8,7 @@ require "transitions/version"
|
|
29
8
|
module Transitions
|
30
9
|
class InvalidTransition < StandardError; end
|
31
10
|
class InvalidMethodOverride < StandardError; end
|
11
|
+
include Presenter
|
32
12
|
|
33
13
|
module ClassMethods
|
34
14
|
def inherited(klass)
|
data/lib/transitions/event.rb
CHANGED
@@ -1,25 +1,3 @@
|
|
1
|
-
# Copyright (c) 2009 Rick Olson
|
2
|
-
|
3
|
-
# Permission is hereby granted, free of charge, to any person
|
4
|
-
# obtaining a copy of this software and associated documentation files
|
5
|
-
# (the "Software"), to deal in the Software without restriction,
|
6
|
-
# including without limitation the rights to use, copy, modify, merge,
|
7
|
-
# publish, distribute, sublicense, and/or sell copies of the Software,
|
8
|
-
# and to permit persons to whom the Software is furnished to do so,
|
9
|
-
# subject to the following conditions:
|
10
|
-
|
11
|
-
# The above copyright notice and this permission notice shall be
|
12
|
-
# included in all copies or substantial portions of the Software.
|
13
|
-
|
14
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
18
|
-
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
19
|
-
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
-
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
-
# SOFTWARE.
|
22
|
-
|
23
1
|
module Transitions
|
24
2
|
class Event
|
25
3
|
attr_reader :name, :success, :timestamp
|
data/lib/transitions/machine.rb
CHANGED
@@ -1,25 +1,3 @@
|
|
1
|
-
# Copyright (c) 2009 Rick Olson
|
2
|
-
|
3
|
-
# Permission is hereby granted, free of charge, to any person
|
4
|
-
# obtaining a copy of this software and associated documentation files
|
5
|
-
# (the "Software"), to deal in the Software without restriction,
|
6
|
-
# including without limitation the rights to use, copy, modify, merge,
|
7
|
-
# publish, distribute, sublicense, and/or sell copies of the Software,
|
8
|
-
# and to permit persons to whom the Software is furnished to do so,
|
9
|
-
# subject to the following conditions:
|
10
|
-
|
11
|
-
# The above copyright notice and this permission notice shall be
|
12
|
-
# included in all copies or substantial portions of the Software.
|
13
|
-
|
14
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
18
|
-
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
19
|
-
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
-
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
-
# SOFTWARE.
|
22
|
-
|
23
1
|
module Transitions
|
24
2
|
class Machine
|
25
3
|
attr_writer :initial_state
|
@@ -43,31 +21,22 @@ module Transitions
|
|
43
21
|
self
|
44
22
|
end
|
45
23
|
|
46
|
-
# TODO
|
24
|
+
# TODO There is still way to much parameter passing around going on down below.
|
47
25
|
def fire_event(event, record, persist, *args)
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
return false
|
63
|
-
end
|
64
|
-
rescue => e
|
65
|
-
if record.respond_to?(:event_failed)
|
66
|
-
record.send(:event_failed, event)
|
67
|
-
return false
|
68
|
-
else
|
69
|
-
raise e
|
70
|
-
end
|
26
|
+
handle_state_exit_callback record
|
27
|
+
if new_state = transition_to_new_state(record, event, *args)
|
28
|
+
handle_state_enter_callback record, new_state
|
29
|
+
handle_event_fired_calllback record, new_state, event
|
30
|
+
record.update_current_state(new_state, persist)
|
31
|
+
handle_event_success_callback record, event
|
32
|
+
else
|
33
|
+
handle_event_failed_callback record, event
|
34
|
+
end
|
35
|
+
rescue => e
|
36
|
+
if record.respond_to?(:event_failed)
|
37
|
+
record.send(:event_failed, event)
|
38
|
+
else
|
39
|
+
raise e
|
71
40
|
end
|
72
41
|
end
|
73
42
|
|
@@ -81,7 +50,35 @@ module Transitions
|
|
81
50
|
:@current_state
|
82
51
|
end
|
83
52
|
|
84
|
-
|
53
|
+
private
|
54
|
+
|
55
|
+
def handle_state_exit_callback(record)
|
56
|
+
state_index[record.current_state].call_action(:exit, record)
|
57
|
+
end
|
58
|
+
|
59
|
+
def transition_to_new_state(record, event, *args)
|
60
|
+
@events[event].fire(record, nil, *args)
|
61
|
+
end
|
62
|
+
|
63
|
+
def handle_state_enter_callback(record, new_state)
|
64
|
+
state_index[new_state].call_action(:enter, record)
|
65
|
+
end
|
66
|
+
|
67
|
+
def handle_event_fired_calllback(record, new_state, event)
|
68
|
+
if record.respond_to?(:event_fired, true)
|
69
|
+
record.send(:event_fired, record.current_state, new_state, event)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def handle_event_success_callback(record, event)
|
74
|
+
@events[event].success.call(record) if @events[event].success
|
75
|
+
end
|
76
|
+
|
77
|
+
def handle_event_failed_callback(record, event)
|
78
|
+
if record.respond_to?(:event_failed, true)
|
79
|
+
record.send(:event_failed, event)
|
80
|
+
end
|
81
|
+
end
|
85
82
|
|
86
83
|
def state(name, options = {})
|
87
84
|
unless @state_index.key? name # Just ignore duplicates
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Transitions
|
2
|
+
module Presenter
|
3
|
+
def available_states
|
4
|
+
@state_machine.states.map(&:name).sort_by {|x| x.to_s}
|
5
|
+
end
|
6
|
+
|
7
|
+
def available_events
|
8
|
+
@state_machine.events.keys.sort
|
9
|
+
end
|
10
|
+
|
11
|
+
def available_transitions
|
12
|
+
@state_machine.events_for(current_state)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/transitions/state.rb
CHANGED
@@ -1,25 +1,3 @@
|
|
1
|
-
# Copyright (c) 2009 Rick Olson
|
2
|
-
|
3
|
-
# Permission is hereby granted, free of charge, to any person
|
4
|
-
# obtaining a copy of this software and associated documentation files
|
5
|
-
# (the "Software"), to deal in the Software without restriction,
|
6
|
-
# including without limitation the rights to use, copy, modify, merge,
|
7
|
-
# publish, distribute, sublicense, and/or sell copies of the Software,
|
8
|
-
# and to permit persons to whom the Software is furnished to do so,
|
9
|
-
# subject to the following conditions:
|
10
|
-
|
11
|
-
# The above copyright notice and this permission notice shall be
|
12
|
-
# included in all copies or substantial portions of the Software.
|
13
|
-
|
14
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
18
|
-
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
19
|
-
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
-
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
-
# SOFTWARE.
|
22
|
-
|
23
1
|
module Transitions
|
24
2
|
class State
|
25
3
|
attr_reader :name, :options
|
@@ -1,25 +1,3 @@
|
|
1
|
-
# Copyright (c) 2009 Rick Olson
|
2
|
-
|
3
|
-
# Permission is hereby granted, free of charge, to any person
|
4
|
-
# obtaining a copy of this software and associated documentation files
|
5
|
-
# (the "Software"), to deal in the Software without restriction,
|
6
|
-
# including without limitation the rights to use, copy, modify, merge,
|
7
|
-
# publish, distribute, sublicense, and/or sell copies of the Software,
|
8
|
-
# and to permit persons to whom the Software is furnished to do so,
|
9
|
-
# subject to the following conditions:
|
10
|
-
|
11
|
-
# The above copyright notice and this permission notice shall be
|
12
|
-
# included in all copies or substantial portions of the Software.
|
13
|
-
|
14
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
18
|
-
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
19
|
-
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
-
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
-
# SOFTWARE.
|
22
|
-
|
23
1
|
module Transitions
|
24
2
|
class StateTransition
|
25
3
|
attr_reader :from, :to, :options
|
@@ -33,17 +11,6 @@ module Transitions
|
|
33
11
|
[@guard].flatten.all? { |g| perform_guard(obj, g, *args) }
|
34
12
|
end
|
35
13
|
|
36
|
-
def perform_guard(obj, guard, *args)
|
37
|
-
case guard
|
38
|
-
when Symbol, String
|
39
|
-
obj.send(guard, *args)
|
40
|
-
when Proc
|
41
|
-
guard.call(obj, *args)
|
42
|
-
else
|
43
|
-
true
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
14
|
def execute(obj, *args)
|
48
15
|
case @on_transition
|
49
16
|
when Symbol, String
|
@@ -69,5 +36,17 @@ module Transitions
|
|
69
36
|
def from?(value)
|
70
37
|
@from == value
|
71
38
|
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def perform_guard(obj, guard, *args)
|
43
|
+
if guard.respond_to?(:call)
|
44
|
+
guard.call(obj, *args)
|
45
|
+
elsif guard.is_a?(Symbol) || guard.is_a?(String)
|
46
|
+
obj.send(guard, *args)
|
47
|
+
else
|
48
|
+
true
|
49
|
+
end
|
50
|
+
end
|
72
51
|
end
|
73
52
|
end
|
data/lib/transitions/version.rb
CHANGED
@@ -5,7 +5,7 @@ class TestStateTransitionGuardCheck < Test::Unit::TestCase
|
|
5
5
|
|
6
6
|
test "should return true of there is no guard" do
|
7
7
|
opts = {:from => "foo", :to => "bar"}
|
8
|
-
|
8
|
+
st = Transitions::StateTransition.new(opts)
|
9
9
|
|
10
10
|
assert st.executable?(nil, *args)
|
11
11
|
end
|
@@ -40,6 +40,19 @@ class TestStateTransitionGuardCheck < Test::Unit::TestCase
|
|
40
40
|
st.executable?(obj, *args)
|
41
41
|
end
|
42
42
|
|
43
|
+
test "should call the callable passing the object if the guard responds to #call" do
|
44
|
+
callable = Object.new
|
45
|
+
callable.define_singleton_method(:call) { |obj, *args| obj.test_guard(*args) }
|
46
|
+
|
47
|
+
opts = {:from => "foo", :to => "bar", :guard => callable }
|
48
|
+
st = Transitions::StateTransition.new(opts)
|
49
|
+
|
50
|
+
obj = stub
|
51
|
+
obj.expects(:test_guard).with(*args)
|
52
|
+
|
53
|
+
st.executable?(obj, *args)
|
54
|
+
end
|
55
|
+
|
43
56
|
test "should call the method on the object if guard is a symbol" do
|
44
57
|
opts = {:from => "foo", :to => "bar", :guard => [:test_guard, :test_another_guard] }
|
45
58
|
st = Transitions::StateTransition.new(opts)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: transitions
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jakub Kuzma
|
@@ -9,110 +9,110 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-10-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- - ~>
|
18
|
+
- - "~>"
|
19
19
|
- !ruby/object:Gem::Version
|
20
20
|
version: '1'
|
21
21
|
type: :development
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
|
-
- - ~>
|
25
|
+
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '1'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: test-unit
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- - ~>
|
32
|
+
- - "~>"
|
33
33
|
- !ruby/object:Gem::Version
|
34
34
|
version: '2.5'
|
35
35
|
type: :development
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
|
-
- - ~>
|
39
|
+
- - "~>"
|
40
40
|
- !ruby/object:Gem::Version
|
41
41
|
version: '2.5'
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: mocha
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
|
-
- - ~>
|
46
|
+
- - "~>"
|
47
47
|
- !ruby/object:Gem::Version
|
48
48
|
version: 0.11.0
|
49
49
|
type: :development
|
50
50
|
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
|
-
- - ~>
|
53
|
+
- - "~>"
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: 0.11.0
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
57
|
name: rake
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
59
59
|
requirements:
|
60
|
-
- -
|
60
|
+
- - ">="
|
61
61
|
- !ruby/object:Gem::Version
|
62
62
|
version: '0'
|
63
63
|
type: :development
|
64
64
|
prerelease: false
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
66
66
|
requirements:
|
67
|
-
- -
|
67
|
+
- - ">="
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: '0'
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
71
|
name: random_data
|
72
72
|
requirement: !ruby/object:Gem::Requirement
|
73
73
|
requirements:
|
74
|
-
- -
|
74
|
+
- - ">="
|
75
75
|
- !ruby/object:Gem::Version
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
79
|
version_requirements: !ruby/object:Gem::Requirement
|
80
80
|
requirements:
|
81
|
-
- -
|
81
|
+
- - ">="
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: '0'
|
84
84
|
- !ruby/object:Gem::Dependency
|
85
85
|
name: appraisal
|
86
86
|
requirement: !ruby/object:Gem::Requirement
|
87
87
|
requirements:
|
88
|
-
- -
|
88
|
+
- - ">="
|
89
89
|
- !ruby/object:Gem::Version
|
90
90
|
version: '0'
|
91
91
|
type: :development
|
92
92
|
prerelease: false
|
93
93
|
version_requirements: !ruby/object:Gem::Requirement
|
94
94
|
requirements:
|
95
|
-
- -
|
95
|
+
- - ">="
|
96
96
|
- !ruby/object:Gem::Version
|
97
97
|
version: '0'
|
98
98
|
- !ruby/object:Gem::Dependency
|
99
99
|
name: activerecord
|
100
100
|
requirement: !ruby/object:Gem::Requirement
|
101
101
|
requirements:
|
102
|
-
- -
|
102
|
+
- - ">="
|
103
103
|
- !ruby/object:Gem::Version
|
104
104
|
version: '3.0'
|
105
|
-
- - <=
|
105
|
+
- - "<="
|
106
106
|
- !ruby/object:Gem::Version
|
107
107
|
version: '4.0'
|
108
108
|
type: :development
|
109
109
|
prerelease: false
|
110
110
|
version_requirements: !ruby/object:Gem::Requirement
|
111
111
|
requirements:
|
112
|
-
- -
|
112
|
+
- - ">="
|
113
113
|
- !ruby/object:Gem::Version
|
114
114
|
version: '3.0'
|
115
|
-
- - <=
|
115
|
+
- - "<="
|
116
116
|
- !ruby/object:Gem::Version
|
117
117
|
version: '4.0'
|
118
118
|
description: Lightweight state machine extracted from ActiveModel
|
@@ -121,10 +121,10 @@ executables: []
|
|
121
121
|
extensions: []
|
122
122
|
extra_rdoc_files: []
|
123
123
|
files:
|
124
|
-
- .gitignore
|
125
|
-
- .ruby-gemset
|
126
|
-
- .ruby-version
|
127
|
-
- .travis.yml
|
124
|
+
- ".gitignore"
|
125
|
+
- ".ruby-gemset"
|
126
|
+
- ".ruby-version"
|
127
|
+
- ".travis.yml"
|
128
128
|
- Appraisals
|
129
129
|
- CHANGELOG.md
|
130
130
|
- Gemfile
|
@@ -140,6 +140,7 @@ files:
|
|
140
140
|
- lib/transitions.rb
|
141
141
|
- lib/transitions/event.rb
|
142
142
|
- lib/transitions/machine.rb
|
143
|
+
- lib/transitions/presenter.rb
|
143
144
|
- lib/transitions/state.rb
|
144
145
|
- lib/transitions/state_transition.rb
|
145
146
|
- lib/transitions/version.rb
|
@@ -173,17 +174,17 @@ require_paths:
|
|
173
174
|
- lib
|
174
175
|
required_ruby_version: !ruby/object:Gem::Requirement
|
175
176
|
requirements:
|
176
|
-
- -
|
177
|
+
- - ">="
|
177
178
|
- !ruby/object:Gem::Version
|
178
179
|
version: '0'
|
179
180
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
180
181
|
requirements:
|
181
|
-
- -
|
182
|
+
- - ">="
|
182
183
|
- !ruby/object:Gem::Version
|
183
184
|
version: 1.3.6
|
184
185
|
requirements: []
|
185
186
|
rubyforge_project: transitions
|
186
|
-
rubygems_version: 2.
|
187
|
+
rubygems_version: 2.2.2
|
187
188
|
signing_key:
|
188
189
|
specification_version: 4
|
189
190
|
summary: State machine extracted from ActiveModel
|