finite_machine 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +17 -1
- data/lib/finite_machine.rb +1 -0
- data/lib/finite_machine/state_machine.rb +2 -3
- data/lib/finite_machine/state_parser.rb +129 -0
- data/lib/finite_machine/transition.rb +37 -44
- data/lib/finite_machine/transition_event.rb +4 -2
- data/lib/finite_machine/version.rb +1 -1
- data/spec/unit/callbacks_spec.rb +89 -1
- data/spec/unit/events_spec.rb +20 -2
- data/spec/unit/inspect_spec.rb +2 -2
- data/spec/unit/state_parser/inspect_spec.rb +25 -0
- data/spec/unit/state_parser/parse_states_spec.rb +59 -0
- data/spec/unit/transition/parse_states_spec.rb +21 -7
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e05d3ce7a5a9f3f1c5ad37e5a21e57e1f2df7998
|
4
|
+
data.tar.gz: 7965548668781de5c89c0f2ff45161b8bbea5cb1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a49b292b01016ca642ce72b288652037445c2b2f203b546848c4ddc61f5492d4d11abba61fc9421e5f003e33b18521c3ba0254d0c219232968d8e12e4fafa672
|
7
|
+
data.tar.gz: 858af0fa26cf18fd6f2be8f4e4035cdbfc07d3b4e4af6435d49f50cff49af6dd50515797d2a3522c7ffc6d4d98b5572bba045f56cf2286ad0927fe450b0e1351
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
0.6.0 (May 10, 2014)
|
2
|
+
|
3
|
+
* Add StateParser to allow for grouping transition under same event name
|
4
|
+
* Change Transition to store a map of transition for a given event
|
5
|
+
* Add abilility to correctly extract :to state for Transition instance
|
6
|
+
* Fix bug #6 with incorrect TransitionEvent payload information
|
7
|
+
|
1
8
|
0.5.0 (April 28, 2014)
|
2
9
|
|
3
10
|
* Change to allow for machine to be constructed as plain object
|
data/README.md
CHANGED
@@ -55,6 +55,7 @@ Or install it yourself as:
|
|
55
55
|
* [2.2 Forcing transitions](#22-forcing-transitions)
|
56
56
|
* [2.3 Asynchronous transitions](#23-asynchronous-transitions)
|
57
57
|
* [2.4 Single event with multiple from states](#24-single-event-with-multiple-from-states)
|
58
|
+
* [2.5 Grouping states under single event](#25-grouping-states-under-single-event)
|
58
59
|
* [3. Conditional transitions](#3-conditional-transitions)
|
59
60
|
* [3.1 Using a Proc](#31-using-a-proc)
|
60
61
|
* [3.2 Using a Symbol](#32-using-a-symbol)
|
@@ -381,7 +382,7 @@ fm.async.ready # => executes in separate Thread
|
|
381
382
|
### 2.4 Single event with multiple from states
|
382
383
|
|
383
384
|
If an event transitions from multiple states to the same state then all the states can be grouped into an array.
|
384
|
-
|
385
|
+
Alternatively, you can create separate events under the same name for each transition that needs combining.
|
385
386
|
|
386
387
|
```ruby
|
387
388
|
fm = FiniteMachine.define do
|
@@ -397,6 +398,21 @@ fm = FiniteMachine.define do
|
|
397
398
|
end
|
398
399
|
```
|
399
400
|
|
401
|
+
### 2.5 Grouping states under single event
|
402
|
+
|
403
|
+
Another way to specify state transitions under single event name is to group all your state transitions into a single hash like so:
|
404
|
+
|
405
|
+
```ruby
|
406
|
+
fm = FiniteMachine.define do
|
407
|
+
initial :initial
|
408
|
+
|
409
|
+
events {
|
410
|
+
event :bump, :initial => :low,
|
411
|
+
:low => :medium,
|
412
|
+
:medium => :high
|
413
|
+
}
|
414
|
+
```
|
415
|
+
|
400
416
|
## 3 Conditional transitions
|
401
417
|
|
402
418
|
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.
|
data/lib/finite_machine.rb
CHANGED
@@ -20,6 +20,7 @@ require "finite_machine/transition_event"
|
|
20
20
|
require "finite_machine/dsl"
|
21
21
|
require "finite_machine/state_machine"
|
22
22
|
require "finite_machine/subscribers"
|
23
|
+
require "finite_machine/state_parser"
|
23
24
|
require "finite_machine/observer"
|
24
25
|
require "finite_machine/listener"
|
25
26
|
|
@@ -219,15 +219,14 @@ module FiniteMachine
|
|
219
219
|
return CANCELLED unless _transition.conditions.all? do |condition|
|
220
220
|
condition.call(env.target, *args)
|
221
221
|
end
|
222
|
-
return NOTRANSITION if
|
222
|
+
return NOTRANSITION if _transition.different?(state)
|
223
223
|
|
224
224
|
sync_exclusive do
|
225
225
|
notify :exitstate, _transition, *args
|
226
|
-
notify :enteraction, _transition, *args
|
227
226
|
|
228
227
|
begin
|
229
228
|
_transition.call
|
230
|
-
|
229
|
+
notify :enteraction, _transition, *args
|
231
230
|
notify :transitionstate, _transition, *args
|
232
231
|
notify :transitionaction, _transition, *args
|
233
232
|
rescue Exception => e
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module FiniteMachine
|
4
|
+
# A class responsible for converting transition arguments to states
|
5
|
+
class StateParser
|
6
|
+
include Threadable
|
7
|
+
|
8
|
+
attr_threadsafe :attrs
|
9
|
+
|
10
|
+
# Initialize a StateParser
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# StateParpser.new({from: [:green, :blue], to: :red})
|
14
|
+
#
|
15
|
+
# @param [Hash] attrs
|
16
|
+
#
|
17
|
+
# @api public
|
18
|
+
def initialize(attrs)
|
19
|
+
@attrs = ensure_only_states!(attrs)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Extract states from attributes
|
23
|
+
#
|
24
|
+
# @example
|
25
|
+
# StateParpser.new(attr).parase_states
|
26
|
+
#
|
27
|
+
# @return [Hash[Symbol]] states
|
28
|
+
#
|
29
|
+
# @api public
|
30
|
+
def parse_states
|
31
|
+
if contains_from_to_keys?
|
32
|
+
convert_from_to_attributes_to_states_hash
|
33
|
+
else
|
34
|
+
convert_attributes_to_states_hash
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Check if attributes contain :from or :to key
|
39
|
+
#
|
40
|
+
# @example
|
41
|
+
# parser = StateParser.new({from: :green, to: :red})
|
42
|
+
# parser.contains_from_to_keys? # => true
|
43
|
+
#
|
44
|
+
# @example
|
45
|
+
# parser = StateParser.new({:green => :red})
|
46
|
+
# parser.contains_from_to_keys? # => false
|
47
|
+
#
|
48
|
+
# @return [Boolean]
|
49
|
+
#
|
50
|
+
# @api public
|
51
|
+
def contains_from_to_keys?
|
52
|
+
[:from, :to].any? { |key| attrs.keys.include?(key) }
|
53
|
+
end
|
54
|
+
|
55
|
+
# Return parser attributes
|
56
|
+
#
|
57
|
+
# @return [String]
|
58
|
+
#
|
59
|
+
# @api public
|
60
|
+
def to_s
|
61
|
+
attrs.to_s
|
62
|
+
end
|
63
|
+
|
64
|
+
# Return string representation
|
65
|
+
#
|
66
|
+
# @return [String]
|
67
|
+
#
|
68
|
+
# @api public
|
69
|
+
def inspect
|
70
|
+
attributes = @attrs.map { |k, v| "#{k}:#{v}" }.join(', ')
|
71
|
+
"<##{self.class} @attrs=#{attributes}>"
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
# Extract only states from attributes
|
77
|
+
#
|
78
|
+
# @return [Hash[Symbol]]
|
79
|
+
#
|
80
|
+
# @api private
|
81
|
+
def ensure_only_states!(attrs)
|
82
|
+
_attrs = attrs.dup
|
83
|
+
[:name, :if, :unless].each { |key| _attrs.delete(key) }
|
84
|
+
raise_not_enough_transitions unless _attrs.any?
|
85
|
+
_attrs
|
86
|
+
end
|
87
|
+
|
88
|
+
# Convert attrbiutes with :from, :to keys to states hash
|
89
|
+
#
|
90
|
+
# @return [Hash[Symbol]]
|
91
|
+
#
|
92
|
+
# @api private
|
93
|
+
def convert_from_to_attributes_to_states_hash
|
94
|
+
Array(attrs[:from] || ANY_STATE).reduce({}) do |hash, state|
|
95
|
+
hash[state] = attrs[:to] || state
|
96
|
+
hash
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Convert collapsed attributes to states hash
|
101
|
+
#
|
102
|
+
# @return [Hash[Symbol]]
|
103
|
+
#
|
104
|
+
# @api private
|
105
|
+
def convert_attributes_to_states_hash
|
106
|
+
attrs.reduce({}) do |hash, (k, v)|
|
107
|
+
if k.respond_to?(:to_ary)
|
108
|
+
k.each { |el| hash[el] = v }
|
109
|
+
else
|
110
|
+
hash[k] = v
|
111
|
+
end
|
112
|
+
hash
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Raise error when not enough transitions are provided
|
117
|
+
#
|
118
|
+
# @raise [NotEnoughTransitionsError]
|
119
|
+
# if the event has not enough transition arguments
|
120
|
+
#
|
121
|
+
# @return [nil]
|
122
|
+
#
|
123
|
+
# @api private
|
124
|
+
def raise_not_enough_transitions
|
125
|
+
fail NotEnoughTransitionsError, "please provide state transitions for" \
|
126
|
+
" '#{attrs.inspect}'"
|
127
|
+
end
|
128
|
+
end # StateParser
|
129
|
+
end # FiniteMachine
|
@@ -8,10 +8,10 @@ module FiniteMachine
|
|
8
8
|
attr_threadsafe :name
|
9
9
|
|
10
10
|
# State transitioning from
|
11
|
-
attr_threadsafe :
|
11
|
+
attr_threadsafe :from_states
|
12
12
|
|
13
13
|
# State transitioning to
|
14
|
-
attr_threadsafe :
|
14
|
+
attr_threadsafe :to_states
|
15
15
|
|
16
16
|
# Predicates before transitioning
|
17
17
|
attr_threadsafe :conditions
|
@@ -25,6 +25,9 @@ module FiniteMachine
|
|
25
25
|
# Check if transition should be cancelled
|
26
26
|
attr_threadsafe :cancelled
|
27
27
|
|
28
|
+
# All states for this transition event
|
29
|
+
attr_threadsafe :map
|
30
|
+
|
28
31
|
# Initialize a Transition
|
29
32
|
#
|
30
33
|
# @param [StateMachine] machine
|
@@ -32,14 +35,25 @@ module FiniteMachine
|
|
32
35
|
#
|
33
36
|
# @api public
|
34
37
|
def initialize(machine, attrs = {})
|
35
|
-
@machine
|
36
|
-
@name
|
37
|
-
@
|
38
|
-
@
|
39
|
-
@
|
40
|
-
@
|
41
|
-
@
|
42
|
-
@
|
38
|
+
@machine = machine
|
39
|
+
@name = attrs.fetch(:name, DEFAULT_STATE)
|
40
|
+
@map = FiniteMachine::StateParser.new(attrs).parse_states
|
41
|
+
@from_states = @map.keys
|
42
|
+
@to_states = @map.values
|
43
|
+
@from_state = @from_states.first
|
44
|
+
@if = Array(attrs.fetch(:if, []))
|
45
|
+
@unless = Array(attrs.fetch(:unless, []))
|
46
|
+
@conditions = make_conditions
|
47
|
+
@cancelled = false
|
48
|
+
end
|
49
|
+
|
50
|
+
# Decide :to state from available transitions for this event
|
51
|
+
#
|
52
|
+
# @return [Symbol]
|
53
|
+
#
|
54
|
+
# @api public
|
55
|
+
def to_state
|
56
|
+
machine.transitions[name][from_state]
|
43
57
|
end
|
44
58
|
|
45
59
|
# Reduce conditions
|
@@ -50,21 +64,16 @@ module FiniteMachine
|
|
50
64
|
@unless.map { |c| Callable.new(c).invert }
|
51
65
|
end
|
52
66
|
|
53
|
-
#
|
67
|
+
# Check if moved to different state
|
54
68
|
#
|
55
|
-
# @param [
|
69
|
+
# @param [Symbol] state
|
70
|
+
# the current state name
|
56
71
|
#
|
57
|
-
# @
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
if [:from, :to].any? { |key| attrs.keys.include?(key) }
|
64
|
-
[Array(_attrs[:from] || ANY_STATE), _attrs[:to]]
|
65
|
-
else
|
66
|
-
[(keys = _attrs.keys).flatten, _attrs[keys.first]]
|
67
|
-
end
|
72
|
+
# @return [Boolean]
|
73
|
+
#
|
74
|
+
# @api public
|
75
|
+
def different?(state)
|
76
|
+
map[state] == state || map[ANY_STATE] == state
|
68
77
|
end
|
69
78
|
|
70
79
|
# Add transition to the machine
|
@@ -73,8 +82,8 @@ module FiniteMachine
|
|
73
82
|
#
|
74
83
|
# @api private
|
75
84
|
def define
|
76
|
-
|
77
|
-
machine.transitions[name][from] =
|
85
|
+
from_states.each do |from|
|
86
|
+
machine.transitions[name][from] = map[from] || ANY_STATE
|
78
87
|
end
|
79
88
|
end
|
80
89
|
|
@@ -82,7 +91,7 @@ module FiniteMachine
|
|
82
91
|
#
|
83
92
|
# @api private
|
84
93
|
def define_state_methods
|
85
|
-
|
94
|
+
from_states.concat(to_states).each { |state| define_state_method(state) }
|
86
95
|
end
|
87
96
|
|
88
97
|
# Define state helper method
|
@@ -160,24 +169,8 @@ module FiniteMachine
|
|
160
169
|
#
|
161
170
|
# @api public
|
162
171
|
def inspect
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
private
|
167
|
-
|
168
|
-
# Raise error when not enough transitions are provided
|
169
|
-
#
|
170
|
-
# @param [Hash] attrs
|
171
|
-
#
|
172
|
-
# @raise [NotEnoughTransitionsError]
|
173
|
-
# if the event has not enough transition arguments
|
174
|
-
#
|
175
|
-
# @return [nil]
|
176
|
-
#
|
177
|
-
# @api private
|
178
|
-
def raise_not_enough_transitions(attrs)
|
179
|
-
fail NotEnoughTransitionsError, "please provide state transitions for" \
|
180
|
-
" '#{attrs.inspect}'"
|
172
|
+
transitions = @map.map { |from, to| "#{from} -> #{to}" }.join(', ')
|
173
|
+
"<##{self.class} @name=#{@name}, @transitions=#{transitions}, @when=#{@conditions}>"
|
181
174
|
end
|
182
175
|
end # Transition
|
183
176
|
end # FiniteMachine
|
@@ -12,14 +12,16 @@ module FiniteMachine
|
|
12
12
|
|
13
13
|
# Build a transition event
|
14
14
|
#
|
15
|
+
# @param [FiniteMachine::Transition] transition
|
16
|
+
#
|
15
17
|
# @return [self]
|
16
18
|
#
|
17
19
|
# @api private
|
18
20
|
def self.build(transition)
|
19
21
|
instance = new
|
20
|
-
instance.from = transition.from_state
|
21
|
-
instance.to = transition.to
|
22
22
|
instance.name = transition.name
|
23
|
+
instance.from = transition.from_state
|
24
|
+
instance.to = transition.to_state
|
23
25
|
instance
|
24
26
|
end
|
25
27
|
end # TransitionEvent
|
data/spec/unit/callbacks_spec.rb
CHANGED
@@ -608,7 +608,7 @@ describe FiniteMachine, 'callbacks' do
|
|
608
608
|
}
|
609
609
|
|
610
610
|
callbacks {
|
611
|
-
|
611
|
+
on_exit :green do |event|
|
612
612
|
FiniteMachine::CANCELLED
|
613
613
|
end
|
614
614
|
}
|
@@ -620,4 +620,92 @@ describe FiniteMachine, 'callbacks' do
|
|
620
620
|
end
|
621
621
|
|
622
622
|
xit "groups callbacks"
|
623
|
+
|
624
|
+
it "groups states from separate events with the same name" do
|
625
|
+
callbacks = []
|
626
|
+
fsm = FiniteMachine.define do
|
627
|
+
initial :initial
|
628
|
+
|
629
|
+
events {
|
630
|
+
event :bump, :initial => :low
|
631
|
+
event :bump, :low => :medium
|
632
|
+
event :bump, :medium => :high
|
633
|
+
}
|
634
|
+
|
635
|
+
callbacks {
|
636
|
+
on_enter_state do |event|
|
637
|
+
callbacks << "enter_state_#{event.name}_#{event.from}_#{event.to}"
|
638
|
+
end
|
639
|
+
on_enter_event do |event|
|
640
|
+
callbacks << "enter_event_#{event.name}_#{event.from}_#{event.to}"
|
641
|
+
end
|
642
|
+
}
|
643
|
+
end
|
644
|
+
expect(fsm.current).to eq(:initial)
|
645
|
+
fsm.bump
|
646
|
+
expect(callbacks).to eq([
|
647
|
+
'enter_event_bump_initial_low',
|
648
|
+
'enter_state_bump_initial_low'
|
649
|
+
])
|
650
|
+
fsm.bump
|
651
|
+
expect(callbacks).to eq([
|
652
|
+
'enter_event_bump_initial_low',
|
653
|
+
'enter_state_bump_initial_low',
|
654
|
+
'enter_event_bump_low_medium',
|
655
|
+
'enter_state_bump_low_medium'
|
656
|
+
])
|
657
|
+
fsm.bump
|
658
|
+
expect(callbacks).to eq([
|
659
|
+
'enter_event_bump_initial_low',
|
660
|
+
'enter_state_bump_initial_low',
|
661
|
+
'enter_event_bump_low_medium',
|
662
|
+
'enter_state_bump_low_medium',
|
663
|
+
'enter_event_bump_medium_high',
|
664
|
+
'enter_state_bump_medium_high'
|
665
|
+
])
|
666
|
+
end
|
667
|
+
|
668
|
+
it "groups states under event name" do
|
669
|
+
callbacks = []
|
670
|
+
fsm = FiniteMachine.define do
|
671
|
+
initial :initial
|
672
|
+
|
673
|
+
events {
|
674
|
+
event :bump, :initial => :low,
|
675
|
+
:low => :medium,
|
676
|
+
:medium => :high
|
677
|
+
}
|
678
|
+
|
679
|
+
callbacks {
|
680
|
+
on_enter_state do |event|
|
681
|
+
callbacks << "enter_state_#{event.name}_#{event.from}_#{event.to}"
|
682
|
+
end
|
683
|
+
on_enter_event do |event|
|
684
|
+
callbacks << "enter_event_#{event.name}_#{event.from}_#{event.to}"
|
685
|
+
end
|
686
|
+
}
|
687
|
+
end
|
688
|
+
expect(fsm.current).to eq(:initial)
|
689
|
+
fsm.bump
|
690
|
+
expect(callbacks).to eq([
|
691
|
+
'enter_event_bump_initial_low',
|
692
|
+
'enter_state_bump_initial_low'
|
693
|
+
])
|
694
|
+
fsm.bump
|
695
|
+
expect(callbacks).to eq([
|
696
|
+
'enter_event_bump_initial_low',
|
697
|
+
'enter_state_bump_initial_low',
|
698
|
+
'enter_event_bump_low_medium',
|
699
|
+
'enter_state_bump_low_medium'
|
700
|
+
])
|
701
|
+
fsm.bump
|
702
|
+
expect(callbacks).to eq([
|
703
|
+
'enter_event_bump_initial_low',
|
704
|
+
'enter_state_bump_initial_low',
|
705
|
+
'enter_event_bump_low_medium',
|
706
|
+
'enter_state_bump_low_medium',
|
707
|
+
'enter_event_bump_medium_high',
|
708
|
+
'enter_state_bump_medium_high'
|
709
|
+
])
|
710
|
+
end
|
623
711
|
end
|
data/spec/unit/events_spec.rb
CHANGED
@@ -247,9 +247,7 @@ describe FiniteMachine, 'events' do
|
|
247
247
|
end
|
248
248
|
|
249
249
|
expect(fsm.current).to eql(:green)
|
250
|
-
|
251
250
|
expect(fsm.can?(:stop)).to be_true
|
252
|
-
|
253
251
|
fsm.stop
|
254
252
|
expect(fsm.current).to eql(:yellow)
|
255
253
|
fsm.stop
|
@@ -262,6 +260,26 @@ describe FiniteMachine, 'events' do
|
|
262
260
|
expect(fsm.current).to eql(:yellow)
|
263
261
|
end
|
264
262
|
|
263
|
+
it "groups transitions under one event name" do
|
264
|
+
fsm = FiniteMachine.define do
|
265
|
+
initial :initial
|
266
|
+
|
267
|
+
events {
|
268
|
+
event :bump, :initial => :low,
|
269
|
+
:low => :medium,
|
270
|
+
:medium => :high
|
271
|
+
}
|
272
|
+
end
|
273
|
+
|
274
|
+
expect(fsm.current).to eq(:initial)
|
275
|
+
fsm.bump
|
276
|
+
expect(fsm.current).to eq(:low)
|
277
|
+
fsm.bump
|
278
|
+
expect(fsm.current).to eq(:medium)
|
279
|
+
fsm.bump
|
280
|
+
expect(fsm.current).to eq(:high)
|
281
|
+
end
|
282
|
+
|
265
283
|
it "returns values for events" do
|
266
284
|
fsm = FiniteMachine.define do
|
267
285
|
initial :neutral
|
data/spec/unit/inspect_spec.rb
CHANGED
@@ -8,10 +8,10 @@ describe FiniteMachine::Transition, 'inspect' do
|
|
8
8
|
subject(:transition) { described_class.new(machine, attrs) }
|
9
9
|
|
10
10
|
context 'when inspecting' do
|
11
|
-
let(:attrs) { {name: :start, :foo => :bar } }
|
11
|
+
let(:attrs) { {name: :start, :foo => :bar, :baz => :daz} }
|
12
12
|
|
13
13
|
it "displays name and transitions" do
|
14
|
-
expect(transition.inspect).to eql("
|
14
|
+
expect(transition.inspect).to eql("<#FiniteMachine::Transition @name=start, @transitions=foo -> bar, baz -> daz, @when=[]>")
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe FiniteMachine::StateParser, "#inspect" do
|
6
|
+
let(:object) { described_class }
|
7
|
+
|
8
|
+
subject(:parser) { object.new(attrs) }
|
9
|
+
|
10
|
+
describe '#inspect' do
|
11
|
+
let(:attrs) { { green: :yellow } }
|
12
|
+
|
13
|
+
it "inspects parser" do
|
14
|
+
expect(parser.inspect).to eq("<#FiniteMachine::StateParser @attrs=green:yellow>")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#to_s' do
|
19
|
+
let(:attrs) { { green: :yellow } }
|
20
|
+
|
21
|
+
it "prints parser attributes" do
|
22
|
+
expect(parser.to_s).to eq(attrs.to_s)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe FiniteMachine::StateParser, '#inspect' do
|
6
|
+
let(:object) { described_class }
|
7
|
+
|
8
|
+
subject(:parser) { object.new(attrs) }
|
9
|
+
|
10
|
+
context 'when no attributes' do
|
11
|
+
let(:attrs) { { } }
|
12
|
+
|
13
|
+
it "raises error for no transitions" do
|
14
|
+
expect {
|
15
|
+
parser.parse_states
|
16
|
+
}.to raise_error(FiniteMachine::NotEnoughTransitionsError)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when :from and :to keys' do
|
21
|
+
let(:attrs) { { from: :green, to: :yellow }}
|
22
|
+
|
23
|
+
it "removes :from and :to keys" do
|
24
|
+
expect(parser.parse_states).to eq({green: :yellow})
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'when only :from key' do
|
29
|
+
let(:attrs) { { from: :green }}
|
30
|
+
|
31
|
+
it "adds to state as copy of from" do
|
32
|
+
expect(parser.parse_states).to eq({green: :green})
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when only :to key' do
|
37
|
+
let(:attrs) { { to: :green }}
|
38
|
+
|
39
|
+
it "inserts :any from state" do
|
40
|
+
expect(parser.parse_states).to eq({any: :green})
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'when attribuets as hash' do
|
45
|
+
let(:attrs) { { green: :yellow } }
|
46
|
+
|
47
|
+
it "copies attributes over" do
|
48
|
+
expect(parser.parse_states).to eq({green: :yellow})
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'when array of from states' do
|
53
|
+
let(:attrs) { { [:green] => :yellow } }
|
54
|
+
|
55
|
+
it "extracts states" do
|
56
|
+
expect(parser.parse_states).to eq({green: :yellow})
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -16,12 +16,22 @@ describe FiniteMachine::Transition, 'parse_states' do
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
+
context 'with :to key only' do
|
20
|
+
let(:attrs) { { to: :red } }
|
21
|
+
|
22
|
+
it "groups states" do
|
23
|
+
expect(transition.from_states).to eq([:any])
|
24
|
+
expect(transition.to_states).to eq([:red])
|
25
|
+
expect(transition.map).to eql({any: :red})
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
19
29
|
context 'with :from, :to keys' do
|
20
30
|
let(:attrs) { {from: [:green, :yellow], to: :red} }
|
21
31
|
|
22
32
|
it "groups states" do
|
23
|
-
expect(transition.
|
24
|
-
expect(transition.
|
33
|
+
expect(transition.from_states).to match_array(attrs[:from])
|
34
|
+
expect(transition.to_states).to match_array([:red, :red])
|
25
35
|
end
|
26
36
|
end
|
27
37
|
|
@@ -29,17 +39,21 @@ describe FiniteMachine::Transition, 'parse_states' do
|
|
29
39
|
let(:attrs) { {[:green, :yellow] => :red} }
|
30
40
|
|
31
41
|
it "groups states" do
|
32
|
-
expect(transition.
|
33
|
-
expect(transition.
|
42
|
+
expect(transition.from_states).to match_array([:green, :yellow])
|
43
|
+
expect(transition.to_states).to eql([:red, :red])
|
34
44
|
end
|
35
45
|
end
|
36
46
|
|
37
47
|
context 'when hash of states' do
|
38
|
-
let(:attrs) {
|
48
|
+
let(:attrs) {
|
49
|
+
{ :initial => :low,
|
50
|
+
:low => :medium,
|
51
|
+
:medium => :high }
|
52
|
+
}
|
39
53
|
|
40
54
|
it "groups states" do
|
41
|
-
expect(transition.
|
42
|
-
expect(transition.
|
55
|
+
expect(transition.from_states).to match_array([:initial, :low, :medium])
|
56
|
+
expect(transition.to_states).to eql([:low, :medium, :high])
|
43
57
|
end
|
44
58
|
end
|
45
59
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: finite_machine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Murach
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-05-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -59,6 +59,7 @@ files:
|
|
59
59
|
- lib/finite_machine/logger.rb
|
60
60
|
- lib/finite_machine/observer.rb
|
61
61
|
- lib/finite_machine/state_machine.rb
|
62
|
+
- lib/finite_machine/state_parser.rb
|
62
63
|
- lib/finite_machine/subscribers.rb
|
63
64
|
- lib/finite_machine/thread_context.rb
|
64
65
|
- lib/finite_machine/threadable.rb
|
@@ -80,6 +81,8 @@ files:
|
|
80
81
|
- spec/unit/inspect_spec.rb
|
81
82
|
- spec/unit/is_spec.rb
|
82
83
|
- spec/unit/logger_spec.rb
|
84
|
+
- spec/unit/state_parser/inspect_spec.rb
|
85
|
+
- spec/unit/state_parser/parse_states_spec.rb
|
83
86
|
- spec/unit/states_spec.rb
|
84
87
|
- spec/unit/subscribers_spec.rb
|
85
88
|
- spec/unit/target_spec.rb
|
@@ -127,6 +130,8 @@ test_files:
|
|
127
130
|
- spec/unit/inspect_spec.rb
|
128
131
|
- spec/unit/is_spec.rb
|
129
132
|
- spec/unit/logger_spec.rb
|
133
|
+
- spec/unit/state_parser/inspect_spec.rb
|
134
|
+
- spec/unit/state_parser/parse_states_spec.rb
|
130
135
|
- spec/unit/states_spec.rb
|
131
136
|
- spec/unit/subscribers_spec.rb
|
132
137
|
- spec/unit/target_spec.rb
|