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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c5fdc12a9620c4afb752d88f581df0416e1bfb2c
4
- data.tar.gz: 2e513473a1ab671758977874cc4670c43a38d76b
3
+ metadata.gz: b87d3c72b83d64e0c80f22f8b6984fc897e75725
4
+ data.tar.gz: c680875bb9ebd5b68fcf0b02943a04a07147121b
5
5
  SHA512:
6
- metadata.gz: 8843c2845f29a81cc1a4fe170796976850515a3d5b513996e50e4904ae8a418d47fa38be5e72f1a325623e0295910df7022c4f061c395bc9aeb8120a6d84e2c8
7
- data.tar.gz: a00d3f4ed41f725e47e4afc81aa030958e86d966f1192008365c988e9a167d3243dd2d79126fd7365a2965cd58071779294b59d8caaefef2849e3f41d43c56f5
6
+ metadata.gz: 400a2ecb0b2c08ae1a29f860607eeddb1c9d0cb4565a2530e90b9d886a88d4c292658097a604e993af2150a8fc90bfacefc030d03a2d76f9d57dede7327de239
7
+ data.tar.gz: 08d83f73449b3338b4b8a4cbc8ff6f031e9ab61eaa715fdc016f4a3794722e25fb0887ac9326be8195241a76e401d1ed4d93495accdcaec80f6fce3b3145ec43
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.0.0
1
+ 2.1.0
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ # 0.1.13
2
+
3
+ * (Nathan Amick and Ryan Long) Allow passing non-Proc callables as guards
4
+ * (troessner) Bugfixes, Refactorings and documentation improvements
5
+
1
6
  # 0.1.12
2
7
 
3
8
  * (troessner) Fix issue 107: timestamps are updated even if guard fails.
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 ruby versions:
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
- Given a model like this:
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 can use this feature a la:
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
- Each event definition takes an optional `guard` argument, which acts as a
155
- predicate for the transition.
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
- or
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
- event :discontinue do
167
- transitions :to => :discontinued, :from => [:available, :out_of_stock], :guard => [:can_discontinue, :super_sure?]
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
- Any arguments passed to the event method will be passed on to the `guard`
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 methods on transition.
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
- `exit` will be called before the transition out of the state is executed. If you want the method
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)
@@ -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
@@ -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 Refactor me please?
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
- state_index[record.current_state].call_action(:exit, record)
49
- begin
50
- if new_state = @events[event].fire(record, nil, *args)
51
- state_index[new_state].call_action(:enter, record)
52
-
53
- if record.respond_to?(:event_fired)
54
- record.send(:event_fired, record.current_state, new_state, event)
55
- end
56
-
57
- record.update_current_state(new_state, persist)
58
- @events[event].success.call(record) if @events[event].success
59
- return true
60
- else
61
- record.send(:event_failed, event) if record.respond_to?(:event_failed)
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
- private
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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Transitions
2
- VERSION = '0.1.12'
2
+ VERSION = '0.1.13'
3
3
  end
@@ -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
- st = Transitions::StateTransition.new(opts)
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.12
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: 2013-11-30 00:00:00.000000000 Z
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.1.11
187
+ rubygems_version: 2.2.2
187
188
  signing_key:
188
189
  specification_version: 4
189
190
  summary: State machine extracted from ActiveModel