pushdown 0.2.0 → 0.3.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
- 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
|