finite_machine 0.6.1 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.travis.yml +2 -0
- data/CHANGELOG.md +17 -0
- data/README.md +85 -50
- data/lib/finite_machine.rb +5 -4
- data/lib/finite_machine/dsl.rb +8 -8
- data/lib/finite_machine/event.rb +63 -47
- data/lib/finite_machine/hook_event.rb +65 -0
- data/lib/finite_machine/hooks.rb +35 -7
- data/lib/finite_machine/observer.rb +37 -56
- data/lib/finite_machine/safety.rb +113 -0
- data/lib/finite_machine/state_machine.rb +61 -34
- data/lib/finite_machine/state_parser.rb +5 -2
- data/lib/finite_machine/transition.rb +54 -16
- data/lib/finite_machine/version.rb +1 -1
- data/spec/unit/async_events_spec.rb +6 -6
- data/spec/unit/callbacks_spec.rb +197 -186
- data/spec/unit/define_spec.rb +2 -0
- data/spec/unit/event/add_spec.rb +18 -0
- data/spec/unit/event/inspect_spec.rb +17 -0
- data/spec/unit/event/next_transition_spec.rb +48 -0
- data/spec/unit/events_spec.rb +41 -2
- data/spec/unit/hooks/call_spec.rb +24 -0
- data/spec/unit/hooks/inspect_spec.rb +17 -0
- data/spec/unit/hooks/register_spec.rb +22 -0
- data/spec/unit/if_unless_spec.rb +28 -0
- data/spec/unit/inspect_spec.rb +9 -16
- data/spec/unit/respond_to_spec.rb +37 -0
- data/spec/unit/target_spec.rb +1 -1
- data/spec/unit/transition/inspect_spec.rb +25 -0
- data/spec/unit/transition/parse_states_spec.rb +8 -25
- metadata +31 -18
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3ac2b8cf6f6e899a7d6b2f04c240703d45a4b67d
|
4
|
+
data.tar.gz: f556b050c651d3120b5a2fe990fd1efc94abf961
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f5871e7adbd4a10e4a44a9bd4916f09843890490fd967d9bc8ce7b7c0a20033b72f2344d23fd7cd6bd2a3369cc5f622f343ea3ce1c2b817e8332909d754806fe
|
7
|
+
data.tar.gz: a1feb862d90d7da38db41ce326ab3a9dbcc241555a4d65e216eeb4260442f5d1a942ac474551f2b41853ab7bb6b5aeb62b474e7efab2bb2571c22a0bfe0da0bf
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
0.7.0 (May 26, 2014)
|
2
|
+
|
3
|
+
* Change Event to EventHook for callback events
|
4
|
+
* Add Event to hold the logic for event specification
|
5
|
+
* Fix issue #8 to preserve conditionals between event specifications
|
6
|
+
* Change to allow for self-transition - fixes issue #9
|
7
|
+
* Change to detect attempt to overwrite already defined method - fixes issue #10
|
8
|
+
* Fix #respond_to on state machine to include observer
|
9
|
+
* Add string inspection to hooks
|
10
|
+
* Fix observer missing methods resolution
|
11
|
+
* Change to separate state and event callbacks. Introduced on_enter, on_before,
|
12
|
+
once_on_enter, once_on_before new event callbacks.
|
13
|
+
* Change generic callbacks to default to any state for on_enter, on_transition,
|
14
|
+
on_exit and any event for on_before and on_after
|
15
|
+
* Add check for callback name conflicts
|
16
|
+
* Ensure proper callback lifecycle
|
17
|
+
|
1
18
|
0.6.1 (May 10, 2014)
|
2
19
|
|
3
20
|
* Fix stdlib requirement
|
data/README.md
CHANGED
@@ -65,14 +65,17 @@ Or install it yourself as:
|
|
65
65
|
* [4.1 on_enter](#41-on_enter)
|
66
66
|
* [4.2 on_transition](#42-on_transition)
|
67
67
|
* [4.3 on_exit](#43-on_exit)
|
68
|
-
* [4.4
|
69
|
-
* [4.5
|
70
|
-
* [4.6
|
71
|
-
* [4.7
|
72
|
-
* [4.8
|
73
|
-
* [4.9
|
74
|
-
* [4.10
|
75
|
-
* [4.11
|
68
|
+
* [4.4 on_before](#44-on_before)
|
69
|
+
* [4.5 on_after](#45-on_after)
|
70
|
+
* [4.6 once_on](#46-once_on)
|
71
|
+
* [4.7 Execution sequence](#47-execution-sequence)
|
72
|
+
* [4.8 Parameters](#48-parameters)
|
73
|
+
* [4.9 Same kind of callbacks](#49-same-kind-of-callbacks)
|
74
|
+
* [4.10 Fluid callbacks](#410-fluid-callbacks)
|
75
|
+
* [4.11 Executing methods inside callbacks](#411-executing-methods-inside-callbacks)
|
76
|
+
* [4.12 Defining callbacks](#412-defining-callbacks)
|
77
|
+
* [4.13 Asynchronous callbacks](#413-asynchronous-callbacks)
|
78
|
+
* [4.14 Cancelling inside callbacks](#414-cancelling-inside-callbacks)
|
76
79
|
* [5. Errors](#5-errors)
|
77
80
|
* [5.1 Using target](#51-using-target)
|
78
81
|
* [6. Integration](#6-integration)
|
@@ -94,9 +97,9 @@ fm = FiniteMachine.define do
|
|
94
97
|
}
|
95
98
|
|
96
99
|
callbacks {
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
+
on_before(:ready) { |event| ... }
|
101
|
+
on_after(:go) { |event| ... }
|
102
|
+
on_before(:stop) { |event| ... }
|
100
103
|
}
|
101
104
|
end
|
102
105
|
```
|
@@ -110,9 +113,9 @@ fm = FiniteMachine.new initial: :red
|
|
110
113
|
fm.event(:ready, :red => :yellow)
|
111
114
|
fm.event(:go, :yellow => :green)
|
112
115
|
fm.event(:stop, :green => :red)
|
113
|
-
fm.
|
114
|
-
fm.
|
115
|
-
fm.
|
116
|
+
fm.on_before(:ready) { |event| ... }
|
117
|
+
fm.on_after(:go) { |event| ... }
|
118
|
+
fm.on_before(:stop) { |event| ...}
|
116
119
|
```
|
117
120
|
|
118
121
|
### 1.1 current
|
@@ -413,6 +416,19 @@ fm = FiniteMachine.define do
|
|
413
416
|
}
|
414
417
|
```
|
415
418
|
|
419
|
+
The same can be more naturally rewritten also as:
|
420
|
+
|
421
|
+
```ruby
|
422
|
+
fm = FiniteMachine.define do
|
423
|
+
initial :initial
|
424
|
+
|
425
|
+
events {
|
426
|
+
event :bump, :initial => :low
|
427
|
+
event :bump, :low => :medium
|
428
|
+
event :bump, :medium => :high
|
429
|
+
}
|
430
|
+
```
|
431
|
+
|
416
432
|
## 3 Conditional transitions
|
417
433
|
|
418
434
|
Each event takes an optional `:if` and `:unless` options which act as a predicate for the transition. The `:if` and `:unless` can take a symbol, a string, a Proc or an array. Use `:if` option when you want to specify when the transition **should** happen. If you want to specify when the transition **should not** happen then use `:unless` option.
|
@@ -529,24 +545,17 @@ The transition only runs when all the `:if` conditions and none of the `unless`
|
|
529
545
|
|
530
546
|
## 4 Callbacks
|
531
547
|
|
532
|
-
You can watch state machine events and the information they provide by registering a callback. The following
|
548
|
+
You can watch state machine events and the information they provide by registering a callback. The following 5 types of callbacks are available in **FiniteMachine**:
|
533
549
|
|
534
550
|
* `on_enter`
|
535
551
|
* `on_transition`
|
536
552
|
* `on_exit`
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
* `on_enter_state`
|
541
|
-
* `on_enter_event`
|
542
|
-
* `on_transition_state`
|
543
|
-
* `on_transition_event`
|
544
|
-
* `on_exit_state`
|
545
|
-
* `on_exit_event`
|
553
|
+
* `on_before`
|
554
|
+
* `on_after`
|
546
555
|
|
547
556
|
Use the `callbacks` scope to introduce the listeners. You can register a callback to listen for state changes or events being triggered. Use the state or event name as a first parameter to the callback followed by a list arguments that you expect to receive.
|
548
557
|
|
549
|
-
When you subscribe to the `:green` state
|
558
|
+
When you subscribe to the `:green` state change, the callback will be called whenever someone instruments change for that state. The same will happen on subscription to event `ready`, namely, the callback will be called each time the state transition method is called.
|
550
559
|
|
551
560
|
```ruby
|
552
561
|
fm = FiniteMachine.define do
|
@@ -559,9 +568,9 @@ fm = FiniteMachine.define do
|
|
559
568
|
}
|
560
569
|
|
561
570
|
callbacks {
|
562
|
-
|
563
|
-
|
564
|
-
|
571
|
+
on_before :ready { |event, time1, time2, time3| puts "#{time1} #{time2} #{time3} Go!" }
|
572
|
+
on_before :go { |event, name| puts "Going fast #{name}" }
|
573
|
+
on_before :stop { |event| ... }
|
565
574
|
}
|
566
575
|
end
|
567
576
|
|
@@ -571,31 +580,56 @@ fm.go('Piotr!')
|
|
571
580
|
|
572
581
|
### 4.1 on_enter
|
573
582
|
|
574
|
-
|
575
|
-
|
576
|
-
You can further narrow down the listener to only watch enter state changes using `on_enter_state` callback. Similarly, use `on_enter_event` to only watch for event changes.
|
583
|
+
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.
|
577
584
|
|
578
585
|
### 4.2 on_transition
|
579
586
|
|
580
|
-
|
581
|
-
|
582
|
-
You can further narrow down the listener to only watch state transition changes using `on_transition_state` callback. Similarly, use `on_transition_event` to only watch for event transition changes.
|
587
|
+
The `on_transition` callback is executed when given state change happens. By passing state name you can narrow down the listener to only watch out for transition state changes. Otherwise, all transition state changes will be watched.
|
583
588
|
|
584
589
|
### 4.3 on_exit
|
585
590
|
|
586
|
-
|
591
|
+
The `on_exit` callback is executed after a given state change happens. By passing state name you can narrow down the listener to only watch out for exit state changes. Otherwise, all exit state changes will be watched.
|
587
592
|
|
588
|
-
|
593
|
+
### 4.4 on_before
|
589
594
|
|
590
|
-
|
595
|
+
The `on_before` callback is executed before a given event happens. By default it will listen out for all events, you can also listen out for specific events by passing event's name.
|
591
596
|
|
592
|
-
|
597
|
+
### 4.5 on_after
|
598
|
+
|
599
|
+
This callback is executed after a given event happened. By default it will listen out for all events, you can also listen out for specific events by passing event's name.
|
600
|
+
|
601
|
+
### 4.6 once_on
|
602
|
+
|
603
|
+
**FiniteMachine** allows you to listen on initial state change or when the event is fired first time by using the following 5 types of callbacks:
|
593
604
|
|
594
605
|
* `once_on_enter`
|
595
606
|
* `once_on_transition`
|
596
607
|
* `once_on_exit`
|
608
|
+
* `once_before`
|
609
|
+
* `once_after`
|
610
|
+
|
611
|
+
### 4.7 Execution sequence
|
612
|
+
|
613
|
+
Assuming we have the following event specified:
|
614
|
+
|
615
|
+
```ruby
|
616
|
+
event :go, :red => :yellow
|
617
|
+
```
|
618
|
+
|
619
|
+
then by calling `go` event the following callbacks in the following sequence will be executed:
|
597
620
|
|
598
|
-
|
621
|
+
* `on_before :go` - callback before the `go` event
|
622
|
+
* `on_before` - generic callback before `any` event
|
623
|
+
* `on_exit :red` - callback for the `:red` state exit
|
624
|
+
* `on_exit` - generic callback for exit from `any` state
|
625
|
+
* `on_transition :yellow` - callback for the `:red` to `:yellow` transition
|
626
|
+
* `on_transition` - callback for transition from `any` state to `any` state
|
627
|
+
* `on_enter :yellow` - callback for the `:yellow` state entry
|
628
|
+
* `on_enter` - generic callback for entry to `any` state
|
629
|
+
* `on_after :go` - callback after the `go` event
|
630
|
+
* `on_after` - generic callback after `any` event
|
631
|
+
|
632
|
+
### 4.8 Parameters
|
599
633
|
|
600
634
|
All callbacks get the `TransitionEvent` object with the following attributes.
|
601
635
|
|
@@ -623,7 +657,7 @@ end
|
|
623
657
|
fm.ready(3) # => 'lights switching from red to yellow in 3 seconds'
|
624
658
|
```
|
625
659
|
|
626
|
-
### 4.
|
660
|
+
### 4.9 Same kind of callbacks
|
627
661
|
|
628
662
|
You can define any number of the same kind of callback. These callbacks will be executed in the order they are specified.
|
629
663
|
|
@@ -643,7 +677,7 @@ end
|
|
643
677
|
fm.slow # => will invoke both callbacks
|
644
678
|
```
|
645
679
|
|
646
|
-
### 4.
|
680
|
+
### 4.10 Fluid callbacks
|
647
681
|
|
648
682
|
Callbacks can also be specified as full method calls.
|
649
683
|
|
@@ -658,14 +692,14 @@ fm = FiniteMachine.define do
|
|
658
692
|
}
|
659
693
|
|
660
694
|
callbacks {
|
661
|
-
|
662
|
-
|
663
|
-
|
695
|
+
on_before_ready { |event| ... }
|
696
|
+
on_before_go { |event| ... }
|
697
|
+
on_before_stop { |event| ... }
|
664
698
|
}
|
665
699
|
end
|
666
700
|
```
|
667
701
|
|
668
|
-
### 4.
|
702
|
+
### 4.11 Executing methods inside callbacks
|
669
703
|
|
670
704
|
In order to execute method from another object use `target` helper.
|
671
705
|
|
@@ -708,7 +742,8 @@ fm = FiniteMachine.define do
|
|
708
742
|
initial :neutral
|
709
743
|
|
710
744
|
target car
|
711
|
-
|
745
|
+
|
746
|
+
events {
|
712
747
|
event :forward, [:reverse, :neutral] => :one
|
713
748
|
event :back, [:neutral, :one] => :reverse
|
714
749
|
}
|
@@ -723,7 +758,7 @@ fm.back # => Go Piotr!
|
|
723
758
|
|
724
759
|
For more complex example see [Integration](#6-integration) section.
|
725
760
|
|
726
|
-
### 4.
|
761
|
+
### 4.12 Defining callbacks
|
727
762
|
|
728
763
|
When defining callbacks you are not limited to the `callbacks` helper. After **FiniteMachine** instance is created you can register callbacks the same way as before by calling `on` and supplying the type of notification and state/event you are interested in.
|
729
764
|
|
@@ -743,7 +778,7 @@ fm.on_enter_yellow do |event|
|
|
743
778
|
end
|
744
779
|
```
|
745
780
|
|
746
|
-
### 4.
|
781
|
+
### 4.13 Asynchronous callbacks
|
747
782
|
|
748
783
|
By default all callbacks are run synchronosuly. In order to add a callback that runs asynchronously, you need to pass second `:async` argument like so:
|
749
784
|
|
@@ -759,12 +794,12 @@ or
|
|
759
794
|
|
760
795
|
This will ensure that when the callback is fired it will run in seperate thread outside of the main execution thread.
|
761
796
|
|
762
|
-
### 4.
|
797
|
+
### 4.14 Cancelling inside callbacks
|
763
798
|
|
764
799
|
Preferred way to handle cancelling transitions is to use [3 Conditional transitions](#3-conditional-transitions). However if the logic is more than one liner you can cancel the event, hence the transition by returning `FiniteMachine::CANCELLED` constant from the callback scope. The two ways you can affect the event are
|
765
800
|
|
766
801
|
* `on_exit :state_name`
|
767
|
-
* `
|
802
|
+
* `on_before :event_name`
|
768
803
|
|
769
804
|
For example
|
770
805
|
|
data/lib/finite_machine.rb
CHANGED
@@ -6,11 +6,13 @@ require "sync"
|
|
6
6
|
|
7
7
|
require "finite_machine/version"
|
8
8
|
require "finite_machine/threadable"
|
9
|
+
require "finite_machine/safety"
|
9
10
|
require "finite_machine/thread_context"
|
10
11
|
require "finite_machine/callable"
|
11
12
|
require "finite_machine/catchable"
|
12
13
|
require "finite_machine/async_proxy"
|
13
14
|
require "finite_machine/async_call"
|
15
|
+
require "finite_machine/hook_event"
|
14
16
|
require "finite_machine/event"
|
15
17
|
require "finite_machine/event_queue"
|
16
18
|
require "finite_machine/hooks"
|
@@ -34,10 +36,6 @@ module FiniteMachine
|
|
34
36
|
|
35
37
|
ANY_EVENT = :any
|
36
38
|
|
37
|
-
ANY_STATE_HOOK = :state
|
38
|
-
|
39
|
-
ANY_EVENT_HOOK = :event
|
40
|
-
|
41
39
|
# Returned when transition has successfully performed
|
42
40
|
SUCCEEDED = 1
|
43
41
|
|
@@ -67,6 +65,9 @@ module FiniteMachine
|
|
67
65
|
# Raised when event queue is already dead
|
68
66
|
EventQueueDeadError = Class.new(::StandardError)
|
69
67
|
|
68
|
+
# Raised when argument is already defined
|
69
|
+
AlreadyDefinedError = Class.new(::ArgumentError)
|
70
|
+
|
70
71
|
Environment = Struct.new(:target)
|
71
72
|
|
72
73
|
class << self
|
data/lib/finite_machine/dsl.rb
CHANGED
@@ -73,7 +73,7 @@ module FiniteMachine
|
|
73
73
|
machine.initial_state = state
|
74
74
|
end
|
75
75
|
event = proc { event name, from: FiniteMachine::DEFAULT_STATE, to: state }
|
76
|
-
machine.
|
76
|
+
machine.events_dsl.call(&event)
|
77
77
|
end
|
78
78
|
|
79
79
|
# Attach state machine to an object
|
@@ -84,7 +84,7 @@ module FiniteMachine
|
|
84
84
|
# @example
|
85
85
|
# FiniteMachine.define do
|
86
86
|
# target :red
|
87
|
-
#
|
87
|
+
# end
|
88
88
|
#
|
89
89
|
# @param [Object] object
|
90
90
|
#
|
@@ -117,7 +117,7 @@ module FiniteMachine
|
|
117
117
|
#
|
118
118
|
# @api public
|
119
119
|
def events(&block)
|
120
|
-
machine.
|
120
|
+
machine.events_dsl.call(&block)
|
121
121
|
end
|
122
122
|
|
123
123
|
# Define state machine callbacks
|
@@ -184,16 +184,16 @@ module FiniteMachine
|
|
184
184
|
# @api public
|
185
185
|
def event(name, attrs = {}, &block)
|
186
186
|
sync_exclusive do
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
187
|
+
attributes = attrs.merge!(name: name)
|
188
|
+
FiniteMachine::StateParser.new(attrs).parse_states do |from, to|
|
189
|
+
attributes.merge!(parsed_states: { from => to })
|
190
|
+
Transition.create(machine, attributes)
|
191
|
+
end
|
191
192
|
end
|
192
193
|
end
|
193
194
|
end # EventsDSL
|
194
195
|
|
195
196
|
class ErrorsDSL < GenericDSL
|
196
|
-
|
197
197
|
# Add error handler
|
198
198
|
#
|
199
199
|
# @param [Array] exceptions
|
data/lib/finite_machine/event.rb
CHANGED
@@ -1,68 +1,84 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
module FiniteMachine
|
4
|
-
# A class
|
4
|
+
# A class representing event with transitions
|
5
5
|
class Event
|
6
6
|
include Threadable
|
7
7
|
|
8
|
-
|
8
|
+
# The name of this event
|
9
|
+
attr_threadsafe :name
|
9
10
|
|
10
|
-
#
|
11
|
-
attr_threadsafe :
|
11
|
+
# The state transitions for this event
|
12
|
+
attr_threadsafe :state_transitions
|
12
13
|
|
13
|
-
#
|
14
|
-
attr_threadsafe :
|
14
|
+
# The reference to the state machine for this event
|
15
|
+
attr_threadsafe :machine
|
15
16
|
|
16
|
-
#
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
def initialize(state, transition, *data, &block)
|
23
|
-
@state = state
|
24
|
-
@transition = transition
|
25
|
-
@data = *data
|
26
|
-
@type = self.class.event_name
|
17
|
+
# @api private
|
18
|
+
def initialize(machine, attrs = {})
|
19
|
+
@machine = machine
|
20
|
+
@name = attrs.fetch(:name, DEFAULT_STATE)
|
21
|
+
@state_transitions = []
|
22
|
+
# TODO: add event conditions
|
27
23
|
end
|
28
24
|
|
29
|
-
|
30
|
-
|
31
|
-
|
25
|
+
# Add transition for this event
|
26
|
+
#
|
27
|
+
# @param [FiniteMachine::Transition] transition
|
28
|
+
#
|
29
|
+
# @example
|
30
|
+
# event << FiniteMachine::Transition.new machine, :a => :b
|
31
|
+
#
|
32
|
+
# @return [nil]
|
33
|
+
#
|
34
|
+
# @api public
|
35
|
+
def <<(transition)
|
36
|
+
sync_exclusive do
|
37
|
+
Array(transition).flatten.each { |trans| state_transitions << trans }
|
32
38
|
end
|
33
39
|
end
|
40
|
+
alias_method :add, :<<
|
41
|
+
|
42
|
+
# Find next transition
|
43
|
+
#
|
44
|
+
# @return [FiniteMachine::Transition]
|
45
|
+
#
|
46
|
+
# @api private
|
47
|
+
def next_transition
|
48
|
+
state_transitions.find do |transition|
|
49
|
+
transition.from_state == machine.current ||
|
50
|
+
transition.from_state == ANY_STATE
|
51
|
+
end || state_transitions.first
|
52
|
+
end
|
34
53
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
class Enteraction < Anyaction; end
|
46
|
-
|
47
|
-
class Transitionaction < Anyaction; end
|
48
|
-
|
49
|
-
class Exitaction < Anyaction; end
|
50
|
-
|
51
|
-
EVENTS = Anystate, Enterstate, Transitionstate, Exitstate,
|
52
|
-
Anyaction, Enteraction, Transitionaction, Exitaction
|
53
|
-
|
54
|
-
def self.event_name
|
55
|
-
name.split('::').last.downcase.to_sym
|
54
|
+
# Trigger this event
|
55
|
+
#
|
56
|
+
# @return [nil]
|
57
|
+
#
|
58
|
+
# @api public
|
59
|
+
def call(*args, &block)
|
60
|
+
sync_exclusive do
|
61
|
+
_transition = next_transition
|
62
|
+
machine.send(:transition, _transition, *args, &block)
|
63
|
+
end
|
56
64
|
end
|
57
65
|
|
58
|
-
|
59
|
-
|
66
|
+
# Return event name
|
67
|
+
#
|
68
|
+
# @return [String]
|
69
|
+
#
|
70
|
+
# @api public
|
71
|
+
def to_s
|
72
|
+
name.to_s
|
60
73
|
end
|
61
74
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
75
|
+
# Return string representation
|
76
|
+
#
|
77
|
+
# @return [String]
|
78
|
+
#
|
79
|
+
# @api public
|
80
|
+
def inspect
|
81
|
+
"<##{self.class} @name=#{@name}, @transitions=#{state_transitions.inspect}>"
|
66
82
|
end
|
67
83
|
end # Event
|
68
84
|
end # FiniteMachine
|