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 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