pushdown 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/History.md +8 -0
- data/LICENSE.txt +24 -17
- data/README.md +8 -7
- data/lib/pushdown/state.rb +23 -5
- data/lib/pushdown/transition/pop.rb +2 -2
- data/lib/pushdown/transition/push.rb +11 -5
- data/lib/pushdown/transition/replace.rb +11 -5
- data/lib/pushdown/transition/switch.rb +14 -5
- data/lib/pushdown/transition.rb +2 -9
- data/lib/pushdown.rb +1 -1
- data/spec/pushdown/automaton_spec.rb +1 -1
- data/spec/pushdown/state_spec.rb +18 -6
- data/spec/pushdown/transition/pop_spec.rb +3 -6
- data/spec/pushdown/transition/push_spec.rb +22 -14
- data/spec/pushdown/transition/replace_spec.rb +24 -10
- data/spec/pushdown/transition/switch_spec.rb +33 -15
- data.tar.gz.sig +0 -0
- metadata +2 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 07c713124675b07b3fdb91a1e7a9c2f0386899c2e37ca1b820ddbce6aaa5ea8e
|
4
|
+
data.tar.gz: f3c40b62850afe641934d6a77ffec9011809df10648c073242de1d65646f7578
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7957d836aaf103e2e45da26ab088ff66709c3463f2e630f9d4e1cc14e07519cc147359db0a622c659d6dc5b02ef57b374434b7816cee5f519ca9a58d57a0d140
|
7
|
+
data.tar.gz: 5e1c5467df6a41e86a797d4b783e07684296cb252ca241f284360ee0d4677a1413fe9974e7f63ccd2cda1fdfae6a970fada1158ea9dcc108382fe1ac45bb33aa
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/History.md
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
# Release History for pushdown
|
2
2
|
|
3
3
|
---
|
4
|
+
## v0.3.0 [2021-09-01] Michael Granger <ged@faeriemud.org>
|
5
|
+
|
6
|
+
Change:
|
7
|
+
|
8
|
+
- Rework how state data is passed around. Instead of passing it through the
|
9
|
+
transition callbacks, which proved to be a terrible idea, the States
|
10
|
+
themselves take an optional state argument to their constructor.
|
11
|
+
|
4
12
|
|
5
13
|
## v0.2.0 [2021-08-31] Michael Granger <ged@faeriemud.org>
|
6
14
|
|
data/LICENSE.txt
CHANGED
@@ -1,20 +1,27 @@
|
|
1
|
-
Copyright (c) 2019 Michael Granger
|
1
|
+
Copyright (c) 2019-2021, Michael Granger
|
2
|
+
All rights reserved.
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
"Software"), to deal in the Software without restriction, including
|
6
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
-
permit persons to whom the Software is furnished to do so, subject to
|
9
|
-
the following conditions:
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
10
6
|
|
11
|
-
|
12
|
-
|
7
|
+
* Redistributions of source code must retain the above copyright notice,
|
8
|
+
this list of conditions and the following disclaimer.
|
13
9
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
10
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
this list of conditions and the following disclaimer in the documentation
|
12
|
+
and/or other materials provided with the distribution.
|
13
|
+
|
14
|
+
* Neither the name of the author/s, nor the names of the project's
|
15
|
+
contributors may be used to endorse or promote products derived from this
|
16
|
+
software without specific prior written permission.
|
17
|
+
|
18
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
19
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
20
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
21
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
22
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
23
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
24
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
25
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
26
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
27
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
CHANGED
@@ -31,18 +31,19 @@ It's still mostly experimental.
|
|
31
31
|
$ gem install pushdown
|
32
32
|
|
33
33
|
|
34
|
-
##
|
34
|
+
## Development
|
35
35
|
|
36
|
-
You can check out the current
|
37
|
-
|
38
|
-
|
36
|
+
You can check out the current source with Git via Gitlab:
|
37
|
+
|
38
|
+
$ hg clone http://hg.sr.ht/~ged/Pushdown
|
39
|
+
$ cd Pushdown
|
39
40
|
|
40
41
|
After checking out the source, run:
|
41
42
|
|
42
|
-
$
|
43
|
+
$ gem install -Ng
|
44
|
+
$ rake setup
|
43
45
|
|
44
|
-
This task will install any
|
45
|
-
and generate the API documentation.
|
46
|
+
This task will install dependencies, and do any other necessary setup for development.
|
46
47
|
|
47
48
|
|
48
49
|
## Author(s)
|
data/lib/pushdown/state.rb
CHANGED
@@ -57,31 +57,46 @@ class Pushdown::State
|
|
57
57
|
end
|
58
58
|
|
59
59
|
|
60
|
+
### Set up new States with an optional +data+ object.
|
61
|
+
def initialize( data=nil )
|
62
|
+
@data = data
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
######
|
67
|
+
public
|
68
|
+
######
|
69
|
+
|
70
|
+
##
|
71
|
+
# The state data object that was used to create the State (if any)
|
72
|
+
attr_reader :data
|
73
|
+
|
74
|
+
|
60
75
|
#
|
61
76
|
# Stack callbacks
|
62
77
|
#
|
63
78
|
|
64
79
|
### Stack callback -- called when the state is added to the stack.
|
65
|
-
def on_start
|
80
|
+
def on_start
|
66
81
|
return nil # no-op
|
67
82
|
end
|
68
83
|
|
69
84
|
|
70
85
|
### Stack callback -- called when the state is removed from the stack.
|
71
|
-
def on_stop
|
86
|
+
def on_stop
|
72
87
|
return nil # no-op
|
73
88
|
end
|
74
89
|
|
75
90
|
|
76
91
|
### Stack callback -- called when another state is pushed over this one.
|
77
|
-
def on_pause
|
92
|
+
def on_pause
|
78
93
|
return nil # no-op
|
79
94
|
end
|
80
95
|
|
81
96
|
|
82
97
|
### Stack callback -- called when another state is popped off from in front of
|
83
98
|
### this one, making it the current state.
|
84
|
-
def on_resume
|
99
|
+
def on_resume
|
85
100
|
return nil # no-op
|
86
101
|
end
|
87
102
|
|
@@ -146,7 +161,10 @@ class Pushdown::State
|
|
146
161
|
|
147
162
|
if state_class_name
|
148
163
|
state_class = automaton.class.pushdown_state_class( stack_name, state_class_name )
|
149
|
-
|
164
|
+
state_data = self.data
|
165
|
+
|
166
|
+
return Pushdown::Transition.
|
167
|
+
create( transition_type, transition_name, state_class, state_data )
|
150
168
|
else
|
151
169
|
return Pushdown::Transition.create( transition_type, transition_name )
|
152
170
|
end
|
@@ -26,8 +26,8 @@ class Pushdown::Transition::Pop < Pushdown::Transition
|
|
26
26
|
|
27
27
|
self.log.debug "popping a state"
|
28
28
|
@popped_state = stack.pop
|
29
|
-
|
30
|
-
stack.last.on_resume
|
29
|
+
@popped_state.on_stop
|
30
|
+
stack.last.on_resume
|
31
31
|
|
32
32
|
return stack
|
33
33
|
end
|
@@ -11,9 +11,11 @@ class Pushdown::Transition::Push < Pushdown::Transition
|
|
11
11
|
|
12
12
|
### Create a transition that will Push an instance of the given +state_class+ to
|
13
13
|
### the stack.
|
14
|
-
def initialize( name, state_class,
|
15
|
-
super( name
|
14
|
+
def initialize( name, state_class, data=nil )
|
15
|
+
super( name )
|
16
|
+
|
16
17
|
@state_class = state_class
|
18
|
+
@data = data
|
17
19
|
end
|
18
20
|
|
19
21
|
|
@@ -25,15 +27,19 @@ class Pushdown::Transition::Push < Pushdown::Transition
|
|
25
27
|
# The State to push to.
|
26
28
|
attr_reader :state_class
|
27
29
|
|
30
|
+
##
|
31
|
+
# The data object to pass to the #state_class's constructor
|
32
|
+
attr_reader :data
|
33
|
+
|
28
34
|
|
29
35
|
### Apply the transition to the given +stack+.
|
30
36
|
def apply( stack )
|
31
|
-
state = self.state_class.new
|
37
|
+
state = self.state_class.new( self.data )
|
32
38
|
|
33
39
|
self.log.debug "pushing a new state: %p" % [ state ]
|
34
|
-
|
40
|
+
stack.last.on_pause if stack.last
|
35
41
|
stack.push( state )
|
36
|
-
state.on_start
|
42
|
+
state.on_start
|
37
43
|
|
38
44
|
return stack
|
39
45
|
end
|
@@ -10,9 +10,11 @@ class Pushdown::Transition::Replace < Pushdown::Transition
|
|
10
10
|
|
11
11
|
### Create a transition that will Replace all the states on the current stack
|
12
12
|
### with an instance of the given +state_class+.
|
13
|
-
def initialize( name, state_class,
|
14
|
-
super( name
|
13
|
+
def initialize( name, state_class, data=nil )
|
14
|
+
super( name )
|
15
|
+
|
15
16
|
@state_class = state_class
|
17
|
+
@data = data
|
16
18
|
end
|
17
19
|
|
18
20
|
|
@@ -24,18 +26,22 @@ class Pushdown::Transition::Replace < Pushdown::Transition
|
|
24
26
|
# The State to replace the stack members with.
|
25
27
|
attr_reader :state_class
|
26
28
|
|
29
|
+
##
|
30
|
+
# The data object to pass to the #state_class's constructor
|
31
|
+
attr_reader :data
|
32
|
+
|
27
33
|
|
28
34
|
### Apply the transition to the given +stack+.
|
29
35
|
def apply( stack )
|
30
|
-
state = self.state_class.new
|
36
|
+
state = self.state_class.new( self.data )
|
31
37
|
|
32
38
|
self.log.debug "replacing current state with a new state: %p" % [ state ]
|
33
39
|
while ( old_state = stack.pop )
|
34
|
-
|
40
|
+
old_state.on_stop
|
35
41
|
end
|
36
42
|
|
37
43
|
stack.push( state )
|
38
|
-
state.on_start
|
44
|
+
state.on_start
|
39
45
|
|
40
46
|
return stack
|
41
47
|
end
|
@@ -10,9 +10,11 @@ class Pushdown::Transition::Switch < Pushdown::Transition
|
|
10
10
|
|
11
11
|
### Create a transition that will Switch the current State with an instance of
|
12
12
|
### the given +state_class+ on the stack.
|
13
|
-
def initialize( name, state_class,
|
14
|
-
super( name
|
13
|
+
def initialize( name, state_class, data=nil )
|
14
|
+
super( name )
|
15
|
+
|
15
16
|
@state_class = state_class
|
17
|
+
@data = data
|
16
18
|
end
|
17
19
|
|
18
20
|
|
@@ -24,16 +26,23 @@ class Pushdown::Transition::Switch < Pushdown::Transition
|
|
24
26
|
# The State to push to.
|
25
27
|
attr_reader :state_class
|
26
28
|
|
29
|
+
##
|
30
|
+
# The data object to pass to the #state_class's constructor
|
31
|
+
attr_reader :data
|
32
|
+
|
27
33
|
|
28
34
|
### Apply the transition to the given +stack+.
|
29
35
|
def apply( stack )
|
30
|
-
|
36
|
+
raise Pushdown::TransitionError, "can't switch on an empty stack" if stack.empty?
|
37
|
+
|
38
|
+
state = self.state_class.new( self.data )
|
31
39
|
|
32
40
|
self.log.debug "switching current state with a new state: %p" % [ state ]
|
33
41
|
old_state = stack.pop
|
34
|
-
|
42
|
+
old_state.on_stop if old_state
|
43
|
+
|
35
44
|
stack.push( state )
|
36
|
-
state.on_start
|
45
|
+
state.on_start
|
37
46
|
|
38
47
|
return stack
|
39
48
|
end
|
data/lib/pushdown/transition.rb
CHANGED
@@ -35,12 +35,9 @@ class Pushdown::Transition
|
|
35
35
|
end
|
36
36
|
|
37
37
|
|
38
|
-
### Create a new Transition with the given +name+.
|
39
|
-
|
40
|
-
### State#on_resume) as it is applied.
|
41
|
-
def initialize( name, data=nil )
|
38
|
+
### Create a new Transition with the given +name+.
|
39
|
+
def initialize( name )
|
42
40
|
@name = name
|
43
|
-
@data = data
|
44
41
|
end
|
45
42
|
|
46
43
|
|
@@ -52,10 +49,6 @@ class Pushdown::Transition
|
|
52
49
|
# The name of the transition; mostly for human consumption
|
53
50
|
attr_reader :name
|
54
51
|
|
55
|
-
##
|
56
|
-
# Data to pass to the transition callbacks when applying this Transition.
|
57
|
-
attr_accessor :data
|
58
|
-
|
59
52
|
|
60
53
|
### Return a state +stack+ after the transition has been applied.
|
61
54
|
def apply( stack )
|
data/lib/pushdown.rb
CHANGED
data/spec/pushdown/state_spec.rb
CHANGED
@@ -55,25 +55,25 @@ RSpec.describe( Pushdown::State ) do
|
|
55
55
|
|
56
56
|
it "has a default (no-op) callback for when it is added to the stack" do
|
57
57
|
instance = subclass.new
|
58
|
-
expect( instance.on_start
|
58
|
+
expect( instance.on_start ).to be_nil
|
59
59
|
end
|
60
60
|
|
61
61
|
|
62
62
|
it "has a default (no-op) callback for when it is removed from the stack" do
|
63
63
|
instance = subclass.new
|
64
|
-
expect( instance.on_stop
|
64
|
+
expect( instance.on_stop ).to be_nil
|
65
65
|
end
|
66
66
|
|
67
67
|
|
68
68
|
it "has a default (no-op) callback for when it is pushed down on the stack" do
|
69
69
|
instance = subclass.new
|
70
|
-
expect( instance.on_pause
|
70
|
+
expect( instance.on_pause ).to be_nil
|
71
71
|
end
|
72
72
|
|
73
73
|
|
74
74
|
it "has a default (no-op) callback for when the stack is popped and it becomes current again" do
|
75
75
|
instance = subclass.new
|
76
|
-
expect( instance.on_resume
|
76
|
+
expect( instance.on_resume ).to be_nil
|
77
77
|
end
|
78
78
|
|
79
79
|
end
|
@@ -93,13 +93,13 @@ RSpec.describe( Pushdown::State ) do
|
|
93
93
|
|
94
94
|
it "has a default (no-op) interval callback for when it is current" do
|
95
95
|
instance = subclass.new
|
96
|
-
expect( instance.update
|
96
|
+
expect( instance.update ).to be_nil
|
97
97
|
end
|
98
98
|
|
99
99
|
|
100
100
|
it "has a default (no-op) interval callback for when it is on the stack" do
|
101
101
|
instance = subclass.new
|
102
|
-
expect( instance.shadow_update
|
102
|
+
expect( instance.shadow_update ).to be_nil
|
103
103
|
end
|
104
104
|
|
105
105
|
end
|
@@ -136,6 +136,18 @@ RSpec.describe( Pushdown::State ) do
|
|
136
136
|
expect( result.data ).to be_nil
|
137
137
|
end
|
138
138
|
|
139
|
+
|
140
|
+
it "can create a transition it has declared that doesn't take a state class" do
|
141
|
+
subclass.transition_pop( :quit )
|
142
|
+
instance = subclass.new
|
143
|
+
|
144
|
+
automaton = automaton_class.new
|
145
|
+
|
146
|
+
result = instance.transition( :quit, automaton, :state )
|
147
|
+
expect( result ).to be_a( Pushdown::Transition::Pop )
|
148
|
+
expect( result.name ).to eq( :quit )
|
149
|
+
end
|
150
|
+
|
139
151
|
end
|
140
152
|
|
141
153
|
end
|
@@ -17,8 +17,6 @@ RSpec.describe( Pushdown::Transition::Pop ) do
|
|
17
17
|
let( :state_b ) { state_class.new }
|
18
18
|
let( :state_c ) { state_class.new }
|
19
19
|
|
20
|
-
let( :state_data ) { Object.new }
|
21
|
-
|
22
20
|
let( :stack ) do
|
23
21
|
return [ state_a, state_b, state_c ]
|
24
22
|
end
|
@@ -35,11 +33,10 @@ RSpec.describe( Pushdown::Transition::Pop ) do
|
|
35
33
|
|
36
34
|
|
37
35
|
it "passes state data through the transition callbacks" do
|
38
|
-
transition = described_class.new( :pop_test
|
36
|
+
transition = described_class.new( :pop_test )
|
39
37
|
|
40
|
-
expect( state_c ).to receive( :on_stop ).with(
|
41
|
-
|
42
|
-
expect( state_b ).to receive( :on_resume ).with( state_data ).once.ordered
|
38
|
+
expect( state_c ).to receive( :on_stop ).with( no_args ).once.ordered
|
39
|
+
expect( state_b ).to receive( :on_resume ).with( no_args ).once.ordered
|
43
40
|
|
44
41
|
transition.apply( stack )
|
45
42
|
end
|
@@ -16,18 +16,12 @@ RSpec.describe( Pushdown::Transition::Push ) do
|
|
16
16
|
Class.new( Pushdown::State )
|
17
17
|
end
|
18
18
|
|
19
|
-
let( :state_a ) { state_class.new }
|
20
|
-
let( :state_b ) { state_class.new }
|
21
|
-
let( :state_c ) { other_state_class.new }
|
22
|
-
|
23
|
-
let( :stack ) do
|
24
|
-
return [ state_a, state_b ]
|
25
|
-
end
|
26
|
-
|
27
19
|
let( :state_data ) { Object.new }
|
28
20
|
|
29
21
|
|
22
|
+
|
30
23
|
it "pushes a new state onto the stack when applied" do
|
24
|
+
stack = [ state_class.new, state_class.new ]
|
31
25
|
transition = described_class.new( :push_test, other_state_class )
|
32
26
|
|
33
27
|
new_stack = transition.apply( stack )
|
@@ -35,17 +29,31 @@ RSpec.describe( Pushdown::Transition::Push ) do
|
|
35
29
|
expect( new_stack ).to be_an( Array )
|
36
30
|
expect( new_stack.length ).to eq( 3 )
|
37
31
|
expect( new_stack.last ).to be_a( other_state_class )
|
32
|
+
expect( new_stack.last.data ).to be_nil
|
38
33
|
end
|
39
34
|
|
40
35
|
|
41
|
-
it "passes state data
|
42
|
-
|
36
|
+
it "passes on state data to the new state if given" do
|
37
|
+
stack = []
|
38
|
+
transition = described_class.new( :push_test, state_class, state_data )
|
39
|
+
|
40
|
+
new_stack = transition.apply( stack )
|
41
|
+
|
42
|
+
expect( new_stack.last.data ).to be( state_data )
|
43
|
+
end
|
43
44
|
|
44
|
-
expect( state_b ).to receive( :on_pause ).
|
45
|
-
with( state_data ).once.and_return( state_data ).ordered
|
46
45
|
|
47
|
-
|
48
|
-
|
46
|
+
it "calls the transition callbacks of the former current state and the new state" do
|
47
|
+
new_state = instance_double( other_state_class )
|
48
|
+
stack = [
|
49
|
+
state_class.new,
|
50
|
+
state_class.new
|
51
|
+
]
|
52
|
+
transition = described_class.new( :push_test, other_state_class )
|
53
|
+
|
54
|
+
expect( stack.last ).to receive( :on_pause )
|
55
|
+
expect( other_state_class ).to receive( :new ).and_return( new_state )
|
56
|
+
expect( new_state ).to receive( :on_start )
|
49
57
|
|
50
58
|
transition.apply( stack )
|
51
59
|
end
|
@@ -28,6 +28,7 @@ RSpec.describe( Pushdown::Transition::Replace ) do
|
|
28
28
|
|
29
29
|
|
30
30
|
it "replaces the current stack members with a single new instance of a state when applied" do
|
31
|
+
stack = [ state_class.new, state_class.new ]
|
31
32
|
transition = described_class.new( :replace_test, other_state_class )
|
32
33
|
|
33
34
|
new_stack = transition.apply( stack )
|
@@ -38,18 +39,31 @@ RSpec.describe( Pushdown::Transition::Replace ) do
|
|
38
39
|
end
|
39
40
|
|
40
41
|
|
41
|
-
it "passes state data
|
42
|
-
|
42
|
+
it "passes on state data to the new state if given" do
|
43
|
+
stack = []
|
44
|
+
transition = described_class.new( :replace_test, state_class, state_data )
|
43
45
|
|
44
|
-
|
45
|
-
|
46
|
-
expect(
|
47
|
-
|
48
|
-
|
49
|
-
|
46
|
+
new_stack = transition.apply( stack )
|
47
|
+
|
48
|
+
expect( new_stack.last.data ).to be( state_data )
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
it "calls the transition callbacks of all the former states and the new state" do
|
53
|
+
new_state = instance_double( other_state_class )
|
54
|
+
stack = [
|
55
|
+
state_class.new,
|
56
|
+
state_class.new,
|
57
|
+
other_state_class.new
|
58
|
+
]
|
59
|
+
transition = described_class.new( :replace_test, other_state_class )
|
60
|
+
|
61
|
+
expect( stack[2] ).to receive( :on_stop ).ordered
|
62
|
+
expect( stack[1] ).to receive( :on_stop ).ordered
|
63
|
+
expect( stack[0] ).to receive( :on_stop ).ordered
|
50
64
|
|
51
|
-
expect( other_state_class ).to receive( :new ).and_return(
|
52
|
-
expect(
|
65
|
+
expect( other_state_class ).to receive( :new ).and_return( new_state )
|
66
|
+
expect( new_state ).to receive( :on_start ).ordered
|
53
67
|
|
54
68
|
transition.apply( stack )
|
55
69
|
end
|
@@ -15,18 +15,12 @@ RSpec.describe( Pushdown::Transition::Switch ) do
|
|
15
15
|
Class.new( Pushdown::State )
|
16
16
|
end
|
17
17
|
|
18
|
-
let( :state_a ) { state_class.new }
|
19
|
-
let( :state_b ) { state_class.new }
|
20
|
-
let( :state_c ) { other_state_class.new }
|
21
|
-
|
22
|
-
let( :stack ) do
|
23
|
-
return [ state_a, state_b ]
|
24
|
-
end
|
25
|
-
|
26
18
|
let( :state_data ) { Object.new }
|
27
19
|
|
28
20
|
|
29
|
-
|
21
|
+
|
22
|
+
it "switches the current state the stack with a new one when applied" do
|
23
|
+
stack = [ state_class.new, state_class.new ]
|
30
24
|
transition = described_class.new( :switch_test, other_state_class )
|
31
25
|
|
32
26
|
new_stack = transition.apply( stack )
|
@@ -34,20 +28,44 @@ RSpec.describe( Pushdown::Transition::Switch ) do
|
|
34
28
|
expect( new_stack ).to be_an( Array )
|
35
29
|
expect( new_stack.length ).to eq( 2 )
|
36
30
|
expect( new_stack.last ).to be_a( other_state_class )
|
31
|
+
expect( new_stack.last.data ).to be_nil
|
37
32
|
end
|
38
33
|
|
39
34
|
|
40
|
-
it "passes state data
|
41
|
-
|
35
|
+
it "passes on state data to the new state if given" do
|
36
|
+
stack = [ state_class.new ]
|
37
|
+
transition = described_class.new( :switch_test, state_class, state_data )
|
42
38
|
|
43
|
-
|
44
|
-
|
39
|
+
new_stack = transition.apply( stack )
|
40
|
+
|
41
|
+
expect( new_stack.last.data ).to be( state_data )
|
42
|
+
end
|
45
43
|
|
46
|
-
|
47
|
-
|
44
|
+
|
45
|
+
it "calls the transition callbacks of the former current state and the new state" do
|
46
|
+
new_state = instance_double( other_state_class )
|
47
|
+
stack = [
|
48
|
+
state_class.new,
|
49
|
+
state_class.new
|
50
|
+
]
|
51
|
+
transition = described_class.new( :switch_test, other_state_class )
|
52
|
+
|
53
|
+
expect( stack.last ).to receive( :on_stop )
|
54
|
+
expect( other_state_class ).to receive( :new ).and_return( new_state )
|
55
|
+
expect( new_state ).to receive( :on_start )
|
48
56
|
|
49
57
|
transition.apply( stack )
|
50
58
|
end
|
51
59
|
|
60
|
+
|
61
|
+
it "errors if applied to an empty stack" do
|
62
|
+
stack = []
|
63
|
+
transition = described_class.new( :switch_test, other_state_class )
|
64
|
+
|
65
|
+
expect {
|
66
|
+
transition.apply( stack )
|
67
|
+
}.to raise_error( Pushdown::TransitionError, /can't switch/i )
|
68
|
+
end
|
69
|
+
|
52
70
|
end
|
53
71
|
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pushdown
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Granger
|
@@ -33,7 +33,7 @@ cert_chain:
|
|
33
33
|
MCh97sQ/Z/MOusb5+QddBmB+k8EicXyGNl4b5L4XpL7fIQu+Y96TB3JEJlShxFD9
|
34
34
|
k9FjI4d9EP54gS/4
|
35
35
|
-----END CERTIFICATE-----
|
36
|
-
date: 2021-
|
36
|
+
date: 2021-09-01 00:00:00.000000000 Z
|
37
37
|
dependencies:
|
38
38
|
- !ruby/object:Gem::Dependency
|
39
39
|
name: loggability
|
metadata.gz.sig
CHANGED
Binary file
|