finite_machine 0.10.2 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/Gemfile +1 -1
- data/README.md +73 -35
- data/assets/finite_machine_logo.png +0 -0
- data/lib/finite_machine.rb +0 -7
- data/lib/finite_machine/async_proxy.rb +1 -2
- data/lib/finite_machine/dsl.rb +13 -14
- data/lib/finite_machine/event_definition.rb +32 -35
- data/lib/finite_machine/events_chain.rb +183 -37
- data/lib/finite_machine/hook_event.rb +47 -42
- data/lib/finite_machine/logger.rb +3 -4
- data/lib/finite_machine/observer.rb +27 -11
- data/lib/finite_machine/state_definition.rb +66 -0
- data/lib/finite_machine/state_machine.rb +177 -99
- data/lib/finite_machine/subscribers.rb +17 -6
- data/lib/finite_machine/thread_context.rb +1 -1
- data/lib/finite_machine/transition.rb +45 -173
- data/lib/finite_machine/transition_builder.rb +24 -6
- data/lib/finite_machine/transition_event.rb +5 -4
- data/lib/finite_machine/undefined_transition.rb +32 -0
- data/lib/finite_machine/version.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- data/spec/unit/async_events_spec.rb +24 -18
- data/spec/unit/callbacks_spec.rb +0 -19
- data/spec/unit/event_names_spec.rb +19 -0
- data/spec/unit/events_chain/add_spec.rb +25 -0
- data/spec/unit/events_chain/cancel_transitions_spec.rb +22 -0
- data/spec/unit/events_chain/choice_transition_spec.rb +28 -0
- data/spec/unit/events_chain/clear_spec.rb +7 -18
- data/spec/unit/events_chain/events_spec.rb +18 -0
- data/spec/unit/events_chain/inspect_spec.rb +14 -17
- data/spec/unit/events_chain/match_transition_spec.rb +37 -0
- data/spec/unit/events_chain/move_to_spec.rb +48 -0
- data/spec/unit/events_chain/states_for_spec.rb +17 -0
- data/spec/unit/events_spec.rb +119 -27
- data/spec/unit/hook_event/build_spec.rb +15 -0
- data/spec/unit/hook_event/eql_spec.rb +3 -4
- data/spec/unit/hook_event/initialize_spec.rb +14 -11
- data/spec/unit/hook_event/notify_spec.rb +14 -0
- data/spec/unit/{initialize_spec.rb → initial_spec.rb} +1 -1
- data/spec/unit/inspect_spec.rb +1 -1
- data/spec/unit/logger_spec.rb +4 -5
- data/spec/unit/subscribers_spec.rb +20 -9
- data/spec/unit/transition/check_conditions_spec.rb +54 -0
- data/spec/unit/transition/inspect_spec.rb +2 -2
- data/spec/unit/transition/matches_spec.rb +23 -0
- data/spec/unit/transition/states_spec.rb +31 -0
- data/spec/unit/transition/to_state_spec.rb +27 -0
- data/spec/unit/trigger_spec.rb +22 -0
- data/spec/unit/undefined_transition/eql_spec.rb +17 -0
- data/tasks/console.rake +1 -0
- metadata +39 -23
- data/lib/finite_machine/event.rb +0 -146
- data/spec/unit/event/add_spec.rb +0 -16
- data/spec/unit/event/eql_spec.rb +0 -37
- data/spec/unit/event/initialize_spec.rb +0 -38
- data/spec/unit/event/inspect_spec.rb +0 -21
- data/spec/unit/event/next_transition_spec.rb +0 -35
- data/spec/unit/events_chain/check_choice_conditions_spec.rb +0 -20
- data/spec/unit/events_chain/insert_spec.rb +0 -26
- data/spec/unit/events_chain/select_transition_spec.rb +0 -23
- data/spec/unit/transition/parse_states_spec.rb +0 -42
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e70496d1e626025a2c8ad75e0c66f5dfacb5d1c5
|
4
|
+
data.tar.gz: 30b266427c011d60d77254c0740d34c843a55732
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d7e2d93b571c333c64ec880d3665abdf1ca65b8abd4ba2389b7d6451ad179e4aca67c42811829bdb6cad23a61993efdaf1c225cb6927572222b6bb76828bec88
|
7
|
+
data.tar.gz: d72998f62c65ed6c5f74021926db45e99cfaf065665627f4a8f2e485215397c712326d80a36aa20e281879bb9d79dcab5f670d0ca71736d7bc6e09c4edb7182a
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
0.11.0 (Oct 11, 2015)
|
2
|
+
|
3
|
+
* Add UndefinedTransition to mark self transition(e.i. no transition found)
|
4
|
+
* Add StateDefinition for state query methods
|
5
|
+
* Add #trigger and #trigger! to StateMachine to allow manual firing of events and split between dangerous and non-dangerous versions of api.
|
6
|
+
* Change ThreadContext to require per thread setup
|
7
|
+
* Change Transition to stop relying on global transitions
|
8
|
+
* Change EventChain to manage all internal transitions
|
9
|
+
* Change Subscribers to remove unnecessary parameter dependency
|
10
|
+
* Change StateMachine public interface to clarify available methods
|
11
|
+
* Change HookEvent to accept event name and from state
|
12
|
+
* Remove Event class as duplicate of Transition
|
13
|
+
* Remove unnecessary checks for StateMachine#can?
|
14
|
+
* Fix bug in Transition with current transition matching
|
15
|
+
* Fix bug in Observer with cancelling inside event callback
|
16
|
+
|
1
17
|
0.10.2 (July 5, 2015)
|
2
18
|
|
3
19
|
* Fix to run 'on_after' callbacks even when event cancalled by @craiglittle
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
<div align="center">
|
2
|
+
<a href="http://peter-murach.github.io/finite_machine/"><img width="236" src="https://raw.githubusercontent.com/peter-murach/finite_machine/master/assets/finite_machine_logo.png" alt="finite machine logo" /></a>
|
3
|
+
</div>
|
1
4
|
# FiniteMachine
|
2
5
|
[![Gem Version](https://badge.fury.io/rb/finite_machine.svg)][gem]
|
3
6
|
[![Build Status](https://secure.travis-ci.org/peter-murach/finite_machine.svg?branch=master)][travis]
|
@@ -45,18 +48,19 @@ Or install it yourself as:
|
|
45
48
|
## Contents
|
46
49
|
|
47
50
|
* [1. Usage](#1-usage)
|
48
|
-
* [1.1
|
49
|
-
* [1.2
|
50
|
-
* [1.3
|
51
|
+
* [1.1 current](#11-current)
|
52
|
+
* [1.2 initial](#12-initial)
|
53
|
+
* [1.3 terminal](#13-terminal)
|
51
54
|
* [1.4 is?](#14-is)
|
52
55
|
* [1.5 can? and cannot?](#15-can-and-cannot)
|
53
|
-
* [1.6
|
54
|
-
* [1.7 target](#17-target)
|
55
|
-
* [1.8
|
56
|
-
* [1.9
|
56
|
+
* [1.6 target](#16-target)
|
57
|
+
* [1.7 Alias target](#17-alias-target)
|
58
|
+
* [1.8 restore!](#18-restore)
|
59
|
+
* [1.9 states](#19-states)
|
60
|
+
* [1.10 event names](#110-event-names)
|
57
61
|
* [2. Transitions](#2-transitions)
|
58
62
|
* [2.1 Performing transitions](#21-performing-transitions)
|
59
|
-
* [2.2
|
63
|
+
* [2.2 Dangerous transitions](#22-dangerous-transitions)
|
60
64
|
* [2.3 Asynchronous transitions](#23-asynchronous-transitions)
|
61
65
|
* [2.4 Multiple from states](#24-multiple-from-states)
|
62
66
|
* [2.5 From :any state](#25-from-any-state)
|
@@ -158,7 +162,7 @@ fm = FiniteMachine.define do
|
|
158
162
|
end
|
159
163
|
|
160
164
|
fm.current # => :none
|
161
|
-
fm.start
|
165
|
+
fm.start # => true
|
162
166
|
fm.current # => :green
|
163
167
|
```
|
164
168
|
|
@@ -253,9 +257,9 @@ When the terminal state has been specified, you can use `terminated?` method on
|
|
253
257
|
|
254
258
|
```ruby
|
255
259
|
fm.terminated? # => false
|
256
|
-
fm.slow
|
260
|
+
fm.slow # => true
|
257
261
|
fm.terminated? # => false
|
258
|
-
fm.stop
|
262
|
+
fm.stop # => true
|
259
263
|
fm.terminated? # => true
|
260
264
|
```
|
261
265
|
|
@@ -300,20 +304,12 @@ end
|
|
300
304
|
fm.can?(:slow) # => true
|
301
305
|
fm.can?(:stop) # => false
|
302
306
|
|
303
|
-
fm.slow
|
307
|
+
fm.slow # => true
|
304
308
|
fm.can?(:stop, :breaks) # => true
|
305
309
|
fm.can?(:stop, :no_breaks) # => false
|
306
310
|
```
|
307
311
|
|
308
|
-
### 1.6
|
309
|
-
|
310
|
-
You can use the `states` method to return an array of all the states for a given state machine.
|
311
|
-
|
312
|
-
```ruby
|
313
|
-
fm.states # => [:none, :green, :yellow, :red]
|
314
|
-
```
|
315
|
-
|
316
|
-
### 1.7 target
|
312
|
+
### 1.6 target
|
317
313
|
|
318
314
|
If you need to execute some external code in the context of the current state machine use `target` helper.
|
319
315
|
|
@@ -376,7 +372,7 @@ fm = FiniteMachine.define do
|
|
376
372
|
end
|
377
373
|
```
|
378
374
|
|
379
|
-
### 1.
|
375
|
+
### 1.7 Alias target
|
380
376
|
|
381
377
|
If you need to better express the intention behind the target name, in particular when calling actions in callbacks, you can use the `alias_target` helper:
|
382
378
|
|
@@ -401,7 +397,7 @@ fm = FiniteMachine.define do
|
|
401
397
|
end
|
402
398
|
```
|
403
399
|
|
404
|
-
### 1.
|
400
|
+
### 1.8 restore!
|
405
401
|
|
406
402
|
In order to set the machine to a given state and thus skip triggering callbacks use the `restore!` method:
|
407
403
|
|
@@ -411,6 +407,22 @@ fm.restore!(:neutral)
|
|
411
407
|
|
412
408
|
This method may be suitable when used testing your state machine or in restoring the state from datastore.
|
413
409
|
|
410
|
+
### 1.9 states
|
411
|
+
|
412
|
+
You can use the `states` method to return an array of all the states for a given state machine.
|
413
|
+
|
414
|
+
```ruby
|
415
|
+
fm.states # => [:none, :green, :yellow, :red]
|
416
|
+
```
|
417
|
+
|
418
|
+
### 1.10 event names
|
419
|
+
|
420
|
+
To find out all the event names supported by the state machine issue `event_names` method:
|
421
|
+
|
422
|
+
```ruby
|
423
|
+
fm.event_names # => [:init, :ready, :go, :stop]
|
424
|
+
```
|
425
|
+
|
414
426
|
## 2 Transitions
|
415
427
|
|
416
428
|
The `events` scope exposes the `event` helper to define possible state transitions.
|
@@ -434,23 +446,41 @@ The following methods trigger transitions for the example state machine.
|
|
434
446
|
|
435
447
|
### 2.1 Performing transitions
|
436
448
|
|
437
|
-
In order to transition to the next reachable state, simply call the event's name on the **FiniteMachine** instance.
|
449
|
+
In order to transition to the next reachable state, simply call the event's name on the **FiniteMachine** instance. If the transition succeeds the `true` value is returned, otherwise `false`.
|
438
450
|
|
439
451
|
```ruby
|
440
|
-
fm.ready
|
452
|
+
fm.ready # => true
|
441
453
|
fm.current # => :yellow
|
442
454
|
```
|
443
455
|
|
444
|
-
|
456
|
+
If you prefer you can also use `trigger` method to fire any event by its name:
|
445
457
|
|
446
458
|
```ruby
|
447
|
-
fm.
|
459
|
+
fm.trigger(:ready) # => true
|
460
|
+
```
|
461
|
+
|
462
|
+
Furthermore, you can pass additional parameters with the method call that will be available in the triggered callback as well as used by any present guarding conditions.
|
463
|
+
|
464
|
+
```ruby
|
465
|
+
fm.go('Piotr!') # => true
|
448
466
|
fm.current # => :green
|
449
467
|
```
|
450
468
|
|
451
|
-
|
469
|
+
By default **FiniteMachine** will swallow all exceptions when and return `false` on failure. If you prefer to be notified when illegal transition occurs see [Dangerous transitions](#22-dangerous-transitions).
|
470
|
+
|
471
|
+
### 2.2 Dangerous transitions
|
472
|
+
|
473
|
+
When you declare event, for instance `ready`, the **FiniteMachine** will provide a dangerous version with a bang `ready!`. In the case when you attempt to perform illegal transition or **FiniteMachine** throws internall error, the state machine will propagate the errors. You can use handlers to decide how to handle errors on case by case basis see [6. Errors](#6-errors)
|
474
|
+
|
475
|
+
```ruby
|
476
|
+
fm.ready! # => raises FiniteMachine::InvalidStateError
|
477
|
+
```
|
478
|
+
|
479
|
+
If you prefer you can also use `trigger!` method to fire event:
|
452
480
|
|
453
|
-
|
481
|
+
```ruby
|
482
|
+
fm.trigger!(:ready)
|
483
|
+
```
|
454
484
|
|
455
485
|
### 2.3 Asynchronous transitions
|
456
486
|
|
@@ -607,7 +637,7 @@ fm.go(:yellow) # doesn't transition
|
|
607
637
|
fm.go # raises ArgumentError
|
608
638
|
```
|
609
639
|
|
610
|
-
**Note** If you specify condition with a given arguments then you need to call an event with the exact number of arguments, otherwise you will get `ArgumentError`. Thus in above scenario to prevent errors specify condition like so:
|
640
|
+
**Note** If you specify condition with a given number of arguments then you need to call an event with the exact number of arguments, otherwise you will get `ArgumentError`. Thus in above scenario to prevent errors specify condition like so:
|
611
641
|
|
612
642
|
```ruby
|
613
643
|
if: -> (context, *args) { ... }
|
@@ -805,7 +835,7 @@ end
|
|
805
835
|
|
806
836
|
## 5 Callbacks
|
807
837
|
|
808
|
-
You can watch state machine events and the information they provide by registering
|
838
|
+
You can watch state machine events and the information they provide by registering one or more predefined callback types. The following 5 types of callbacks are available in **FiniteMachine**:
|
809
839
|
|
810
840
|
* `on_enter`
|
811
841
|
* `on_transition`
|
@@ -813,9 +843,15 @@ You can watch state machine events and the information they provide by registeri
|
|
813
843
|
* `on_before`
|
814
844
|
* `on_after`
|
815
845
|
|
816
|
-
Use the `callbacks` scope to introduce the listeners. You can register a callback to listen for state changes or events being triggered.
|
846
|
+
Use the `callbacks` scope to introduce the listeners. You can register a callback to listen for state changes or events being triggered.
|
847
|
+
|
848
|
+
Use the state or event name as a first parameter to the callback helper followed by block with event argument and a list arguments that you expect to receive like so:
|
849
|
+
|
850
|
+
```ruby
|
851
|
+
on_enter :green { |event, a, b, c| ... }
|
852
|
+
```
|
817
853
|
|
818
|
-
When you subscribe to the `:green` state change, the callback will be called whenever someone
|
854
|
+
When you subscribe to the `:green` state change, the callback will be called whenever someone triggers event that transitions in or out of that state. The same will happen on subscription to event `ready`, namely, the callback will be called each time the state transition method is triggered regardless of the states it transitions from or to.
|
819
855
|
|
820
856
|
```ruby
|
821
857
|
fm = FiniteMachine.define do
|
@@ -838,6 +874,8 @@ fm.ready(1, 2, 3)
|
|
838
874
|
fm.go('Piotr!')
|
839
875
|
```
|
840
876
|
|
877
|
+
**Note** Regardless of how the state is entered or exited, all the associated callbacks will be executed. This provides means for guaranteed initialization and cleanup.
|
878
|
+
|
841
879
|
### 5.1 on_enter
|
842
880
|
|
843
881
|
The `on_enter` callback is executed before given state change is fired. By passing state name you can narrow down the listener to only watch out for enter state changes. Otherwise, all enter state changes will be watched.
|
@@ -878,8 +916,8 @@ event :go, :red => :yellow
|
|
878
916
|
|
879
917
|
then by calling `go` event the following callbacks in the following sequence will be executed:
|
880
918
|
|
881
|
-
* `on_before :go` - callback before the `go` event
|
882
919
|
* `on_before` - generic callback before `any` event
|
920
|
+
* `on_before :go` - callback before the `go` event
|
883
921
|
* `on_exit :red` - callback for the `:red` state exit
|
884
922
|
* `on_exit` - generic callback for exit from `any` state
|
885
923
|
* `on_transition :yellow` - callback for the `:red` to `:yellow` transition
|
@@ -1325,7 +1363,7 @@ car.reverse_lights_on? # => true
|
|
1325
1363
|
|
1326
1364
|
In order to integrate **FiniteMachine** with ActiveRecord simply add a method with state machine definition. You can also define the state machine in separate module to aid reusability. Once the state machine is defined use the `target` helper to reference the current class. Having defined `target` you call ActiveRecord methods inside the callbacks to persist the state.
|
1327
1365
|
|
1328
|
-
You can use the `restore!` method to specify which state the **
|
1366
|
+
You can use the `restore!` method to specify which state the **FiniteMachine** should be put back into as follows:
|
1329
1367
|
|
1330
1368
|
```ruby
|
1331
1369
|
class Account < ActiveRecord::Base
|
Binary file
|
data/lib/finite_machine.rb
CHANGED
@@ -16,11 +16,8 @@ require "finite_machine/async_proxy"
|
|
16
16
|
require "finite_machine/async_call"
|
17
17
|
require "finite_machine/hook_event"
|
18
18
|
require "finite_machine/env"
|
19
|
-
require "finite_machine/event"
|
20
|
-
require "finite_machine/event_definition"
|
21
19
|
require "finite_machine/event_queue"
|
22
20
|
require "finite_machine/events_chain"
|
23
|
-
require "finite_machine/hooks"
|
24
21
|
require "finite_machine/logger"
|
25
22
|
require "finite_machine/transition"
|
26
23
|
require "finite_machine/transition_builder"
|
@@ -29,7 +26,6 @@ require "finite_machine/dsl"
|
|
29
26
|
require "finite_machine/definition"
|
30
27
|
require "finite_machine/state_machine"
|
31
28
|
require "finite_machine/subscribers"
|
32
|
-
require "finite_machine/state_parser"
|
33
29
|
require "finite_machine/observer"
|
34
30
|
require "finite_machine/listener"
|
35
31
|
require "finite_machine/two_phase_lock"
|
@@ -53,9 +49,6 @@ module FiniteMachine
|
|
53
49
|
# Returned when transition is cancelled in callback
|
54
50
|
CANCELLED = 2
|
55
51
|
|
56
|
-
# Returned when transition has not changed the state
|
57
|
-
NOTRANSITION = 3
|
58
|
-
|
59
52
|
# When transition between states is invalid
|
60
53
|
TransitionError = Class.new(::StandardError)
|
61
54
|
|
@@ -4,7 +4,6 @@ module FiniteMachine
|
|
4
4
|
# An asynchronous messages proxy
|
5
5
|
class AsyncProxy
|
6
6
|
include Threadable
|
7
|
-
include ThreadContext
|
8
7
|
|
9
8
|
attr_threadsafe :context
|
10
9
|
|
@@ -25,7 +24,7 @@ module FiniteMachine
|
|
25
24
|
callable = Callable.new(method_name)
|
26
25
|
async_call = AsyncCall.new(context, callable, *args, &block)
|
27
26
|
|
28
|
-
event_queue << async_call
|
27
|
+
context.event_queue << async_call
|
29
28
|
end
|
30
29
|
end # AsyncProxy
|
31
30
|
end # FiniteMachine
|
data/lib/finite_machine/dsl.rb
CHANGED
@@ -89,7 +89,7 @@ module FiniteMachine
|
|
89
89
|
# @api public
|
90
90
|
def initial(value, options = {})
|
91
91
|
state = (value && !value.is_a?(Hash)) ? value : raise_missing_state
|
92
|
-
name, self.defer, silent =
|
92
|
+
name, self.defer, silent = *parse_initial(options)
|
93
93
|
self.initial_event = name
|
94
94
|
event(name, FiniteMachine::DEFAULT_STATE => state, silent: silent)
|
95
95
|
end
|
@@ -191,7 +191,7 @@ module FiniteMachine
|
|
191
191
|
#
|
192
192
|
# @api public
|
193
193
|
def handlers(&block)
|
194
|
-
|
194
|
+
errors_dsl.call(&block)
|
195
195
|
end
|
196
196
|
|
197
197
|
# Decide whether to log transitions
|
@@ -207,27 +207,24 @@ module FiniteMachine
|
|
207
207
|
#
|
208
208
|
# @api private
|
209
209
|
def initialize_attrs
|
210
|
-
attrs[:initial]
|
211
|
-
attrs[:target]
|
212
|
-
attrs[:terminal]
|
210
|
+
attrs[:initial] && initial(attrs[:initial])
|
211
|
+
attrs[:target] && target(attrs[:target])
|
212
|
+
attrs[:terminal] && terminal(attrs[:terminal])
|
213
213
|
log_transitions(attrs.fetch(:log_transitions, false))
|
214
214
|
end
|
215
215
|
|
216
216
|
# Parse initial options
|
217
217
|
#
|
218
|
-
# @param [
|
218
|
+
# @param [Hash] options
|
219
|
+
# the options to extract for initial state setup
|
219
220
|
#
|
220
221
|
# @return [Array[Symbol,String]]
|
221
222
|
#
|
222
223
|
# @api private
|
223
|
-
def
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
value.fetch(:silent) { true }]
|
228
|
-
else
|
229
|
-
[FiniteMachine::DEFAULT_EVENT_NAME, false, true]
|
230
|
-
end
|
224
|
+
def parse_initial(options)
|
225
|
+
[options.fetch(:event) { FiniteMachine::DEFAULT_EVENT_NAME },
|
226
|
+
options.fetch(:defer) { false },
|
227
|
+
options.fetch(:silent) { true }]
|
231
228
|
end
|
232
229
|
|
233
230
|
# Raises missing state error
|
@@ -246,6 +243,7 @@ module FiniteMachine
|
|
246
243
|
|
247
244
|
# A DSL for describing events
|
248
245
|
class EventsDSL < GenericDSL
|
246
|
+
include Safety
|
249
247
|
# Create event and associate transition
|
250
248
|
#
|
251
249
|
# @example
|
@@ -257,6 +255,7 @@ module FiniteMachine
|
|
257
255
|
# @api public
|
258
256
|
def event(name, attrs = {}, &block)
|
259
257
|
sync_exclusive do
|
258
|
+
detect_event_conflict!(name)
|
260
259
|
attributes = attrs.merge!(name: name)
|
261
260
|
if block_given?
|
262
261
|
merger = ChoiceMerger.new(machine, attributes)
|
@@ -9,76 +9,73 @@ module FiniteMachine
|
|
9
9
|
# @api private
|
10
10
|
class EventDefinition
|
11
11
|
include Threadable
|
12
|
-
include Safety
|
13
12
|
|
14
13
|
# The current state machine
|
15
14
|
attr_threadsafe :machine
|
16
15
|
|
17
|
-
# Initialize an
|
16
|
+
# Initialize an EventDefinition
|
18
17
|
#
|
19
|
-
# @param [
|
18
|
+
# @param [StateMachine] machine
|
20
19
|
#
|
21
20
|
# @api private
|
22
21
|
def initialize(machine)
|
23
|
-
|
22
|
+
self.machine = machine
|
24
23
|
end
|
25
24
|
|
26
25
|
# Define transition event names as state machine events
|
27
26
|
#
|
28
|
-
# @param [
|
29
|
-
# the
|
27
|
+
# @param [Symbol] event_name
|
28
|
+
# the event name for which definition is created
|
30
29
|
#
|
31
|
-
# @return [
|
30
|
+
# @return [nil]
|
32
31
|
#
|
33
|
-
# @api
|
34
|
-
def apply(
|
35
|
-
|
36
|
-
|
37
|
-
if machine.singleton_class.send(:method_defined?, name)
|
38
|
-
machine.events_chain.insert(name, transition)
|
39
|
-
else
|
40
|
-
define_event_transition(name, transition)
|
41
|
-
define_event_bang(name)
|
42
|
-
end
|
43
|
-
transition
|
32
|
+
# @api public
|
33
|
+
def apply(event_name, silent = false)
|
34
|
+
define_event_transition(event_name, silent)
|
35
|
+
define_event_bang(event_name, silent)
|
44
36
|
end
|
45
37
|
|
46
38
|
private
|
47
39
|
|
48
40
|
# Define transition event
|
49
41
|
#
|
50
|
-
# @param [Symbol]
|
42
|
+
# @param [Symbol] event_name
|
51
43
|
# the event name
|
52
44
|
#
|
53
|
-
# @param [
|
54
|
-
#
|
45
|
+
# @param [Boolean] silent
|
46
|
+
# if true don't trigger callbacks, otherwise do
|
55
47
|
#
|
56
48
|
# @return [nil]
|
57
49
|
#
|
58
50
|
# @api private
|
59
|
-
def define_event_transition(
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
_event.trigger(*args, &block)
|
51
|
+
def define_event_transition(event_name, silent)
|
52
|
+
machine.send(:define_singleton_method, event_name) do |*data, &block|
|
53
|
+
if silent
|
54
|
+
machine.transition(event_name, *data, &block)
|
55
|
+
else
|
56
|
+
machine.trigger(event_name, *data, &block)
|
57
|
+
end
|
67
58
|
end
|
68
59
|
end
|
69
60
|
|
70
|
-
# Define event that skips validations
|
61
|
+
# Define event that skips validations and callbacks
|
71
62
|
#
|
72
|
-
# @param [Symbol]
|
63
|
+
# @param [Symbol] event_name
|
73
64
|
# the event name
|
74
65
|
#
|
66
|
+
# @param [Boolean] silent
|
67
|
+
# if true don't trigger callbacks, otherwise do
|
68
|
+
#
|
75
69
|
# @return [nil]
|
76
70
|
#
|
77
71
|
# @api private
|
78
|
-
def define_event_bang(
|
79
|
-
machine.send(:define_singleton_method, "#{
|
80
|
-
|
81
|
-
|
72
|
+
def define_event_bang(event_name, silent)
|
73
|
+
machine.send(:define_singleton_method, "#{event_name}!") do |*data, &block|
|
74
|
+
if silent
|
75
|
+
machine.transition!(event_name, *data, &block)
|
76
|
+
else
|
77
|
+
machine.trigger!(event_name, *data, &block)
|
78
|
+
end
|
82
79
|
end
|
83
80
|
end
|
84
81
|
end # EventBuilder
|