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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: de5a87ff7d9744a6c71e977a4d5e2fbe03be08efc393d5fc8c84b7a9f4f720c2
4
- data.tar.gz: 6a94eca59001d1640a5676e9a135b56690c6e20f2ec75e49740b68b036005870
3
+ metadata.gz: 07c713124675b07b3fdb91a1e7a9c2f0386899c2e37ca1b820ddbce6aaa5ea8e
4
+ data.tar.gz: f3c40b62850afe641934d6a77ffec9011809df10648c073242de1d65646f7578
5
5
  SHA512:
6
- metadata.gz: 677caf47c2cebd2ac9023a72d16e99881b97be5cacd439aae7f472bdefb1d1e7d7ee75151211988f1b354bc1f9339d3ab4483dce83cec24740579562e48ee41c
7
- data.tar.gz: e32e468403256a51c4683bff1bbf5f332461ed5fc22c43369509b8e241e4f0a102ba105cbfa925474b55e4420dfc8e3ff49af42a8abdd793b7e046e2f1810f69
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
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
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
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
7
+ * Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
13
9
 
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
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
- ## Contributing
34
+ ## Development
35
35
 
36
- You can check out the current development source with Mercurial via its
37
- [project page](http://bitbucket.org/ged/pushdown). Or if you prefer
38
- Git, via [its Github mirror](https://github.com/ged/pushdown).
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
- $ rake newb
43
+ $ gem install -Ng
44
+ $ rake setup
43
45
 
44
- This task will install any missing dependencies, run the tests/specs,
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)
@@ -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( data=nil )
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( data=nil )
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( data=nil )
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( data=nil )
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
- return Pushdown::Transition.create( transition_type, transition_name, state_class )
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
- self.data = @popped_state.on_stop( self.data )
30
- stack.last.on_resume( self.data )
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, *args )
15
- super( name, *args )
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
- self.data = stack.last.on_pause( self.data ) if stack.last
40
+ stack.last.on_pause if stack.last
35
41
  stack.push( state )
36
- state.on_start( self.data )
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, *args )
14
- super( name, *args )
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
- self.data = old_state.on_stop( self.data )
40
+ old_state.on_stop
35
41
  end
36
42
 
37
43
  stack.push( state )
38
- state.on_start( self.data )
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, *args )
14
- super( name, *args )
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
- state = self.state_class.new
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
- self.data = old_state.on_stop( self.data )
42
+ old_state.on_stop if old_state
43
+
35
44
  stack.push( state )
36
- state.on_start( self.data )
45
+ state.on_start
37
46
 
38
47
  return stack
39
48
  end
@@ -35,12 +35,9 @@ class Pushdown::Transition
35
35
  end
36
36
 
37
37
 
38
- ### Create a new Transition with the given +name+. If +data+ is specified, it will be passed
39
- ### through the transition callbacks on State (State#on_start, State#on_stop, State#on_pause,
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
@@ -15,7 +15,7 @@ module Pushdown
15
15
  extend Loggability
16
16
 
17
17
  # Package version
18
- VERSION = '0.2.0'
18
+ VERSION = '0.3.0'
19
19
 
20
20
 
21
21
  # Loggability API -- create a logger for Pushdown classes and modules
@@ -137,7 +137,7 @@ RSpec.describe( Pushdown::Automaton ) do
137
137
  return self.state_data ||= {}
138
138
  end
139
139
 
140
- starting_state.define_method( :on_start ) do |data|
140
+ starting_state.define_method( :on_start ) do
141
141
  data[:starting_started] = true
142
142
  end
143
143
 
@@ -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(state_data) ).to be_nil
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(state_data) ).to be_nil
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(state_data) ).to be_nil
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(state_data) ).to be_nil
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(state_data) ).to be_nil
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(state_data) ).to be_nil
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, state_data )
36
+ transition = described_class.new( :pop_test )
39
37
 
40
- expect( state_c ).to receive( :on_stop ).with( state_data ).
41
- and_return( state_data ).once.ordered
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 through the transition callbacks" do
42
- transition = described_class.new( :push_test, other_state_class, state_data )
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
- expect( other_state_class ).to receive( :new ).and_return( state_c )
48
- expect( state_c ).to receive( :on_start ).with( state_data ).once.ordered
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 through the transition callbacks" do
42
- transition = described_class.new( :replace_test, other_state_class, state_data )
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
- expect( state_c ).to receive( :on_stop ).
45
- with( state_data ).once.and_return( state_data ).ordered
46
- expect( state_b ).to receive( :on_stop ).
47
- with( state_data ).once.and_return( state_data ).ordered
48
- expect( state_a ).to receive( :on_stop ).
49
- with( state_data ).once.and_return( state_data ).ordered
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( state_c )
52
- expect( state_c ).to receive( :on_start ).with( state_data ).once.ordered
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
- it "pops the current state off the stack and adds a new state when applied" do
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 through the transition callbacks" do
41
- transition = described_class.new( :switch_test, other_state_class, state_data )
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
- expect( state_b ).to receive( :on_stop ).
44
- with( state_data ).once.and_return( state_data ).ordered
39
+ new_stack = transition.apply( stack )
40
+
41
+ expect( new_stack.last.data ).to be( state_data )
42
+ end
45
43
 
46
- expect( other_state_class ).to receive( :new ).and_return( state_c )
47
- expect( state_c ).to receive( :on_start ).with( state_data ).once.ordered
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.2.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-08-31 00:00:00.000000000 Z
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