stateful.rb 2.0.0 → 2.2.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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +137 -0
  3. data/Gemfile +2 -0
  4. data/README.md +309 -0
  5. data/lib/Stateful/Sequel/ClassMethods.rb +117 -0
  6. data/lib/Stateful/Sequel.rb +30 -0
  7. data/lib/Stateful/VERSION.rb +1 -1
  8. data/lib/Stateful.rb +4 -1
  9. data/stateful.rb.gemspec +42 -0
  10. data/test/ActiveRecord/WithColumnName.rb +159 -0
  11. data/test/ActiveRecord/WithExplicitDeterministicEventOrdering.rb +159 -0
  12. data/test/ActiveRecord/WithExplicitGlobalNonDeterministicEventOrdering.rb +165 -0
  13. data/test/ActiveRecord/WithExplicitGlobalNonDeterministicEventOrderingAndInitialStateBlock.rb +163 -0
  14. data/test/ActiveRecord/WithExplicitNonDeterministicEventOrdering.rb +161 -0
  15. data/test/ActiveRecord/WithInitialStateBlock.rb +157 -0
  16. data/test/ActiveRecord/WithMultipleFinalStates.rb +188 -0
  17. data/test/ActiveRecord/WithMultipleStateMachines.rb +221 -0
  18. data/test/ActiveRecord/WithMultipleStateMachinesAndStatefulBlock.rb +223 -0
  19. data/test/ActiveRecord/WithPersistenceNonSpecificExtend.rb +159 -0
  20. data/test/ActiveRecord/WithPersistenceNonSpecificExtendAndStatefulBlock.rb +161 -0
  21. data/test/ActiveRecord/WithPersistenceSpecificExtend.rb +159 -0
  22. data/test/ActiveRecord/WithPersistenceSpecificExtendAndStatefulBlock.rb +161 -0
  23. data/test/ActiveRecord/test_helper.rb +9 -0
  24. data/test/ActiveRecord.rb +5 -0
  25. data/test/Poro/WithExplicitDeterministicEventOrdering.rb +147 -0
  26. data/test/Poro/WithExplicitGlobalNonDeterministicEventOrdering.rb +153 -0
  27. data/test/Poro/WithExplicitGlobalNonDeterministicEventOrderingAndInitialStateBlock.rb +151 -0
  28. data/test/Poro/WithExplicitNonDeterministicEventOrdering.rb +149 -0
  29. data/test/Poro/WithInitialStateBlock.rb +145 -0
  30. data/test/Poro/WithMultipleFinalStates.rb +176 -0
  31. data/test/Poro/WithMultipleStateMachines.rb +192 -0
  32. data/test/Poro/WithMultipleStateMachinesAndStatefulBlock.rb +194 -0
  33. data/test/Poro/WithPersistenceNonSpecificExtend.rb +147 -0
  34. data/test/Poro/WithPersistenceNonSpecificExtendAndStatefulBlock.rb +149 -0
  35. data/test/Poro/WithPersistenceSpecificExtend.rb +147 -0
  36. data/test/Poro/WithPersistenceSpecificExtendAndStatefulBlock.rb +149 -0
  37. data/test/Poro/WithVariableName.rb +147 -0
  38. data/test/Poro.rb +5 -0
  39. data/test/Sequel/WithColumnName.rb +154 -0
  40. data/test/Sequel/WithExplicitDeterministicEventOrdering.rb +154 -0
  41. data/test/Sequel/WithExplicitGlobalNonDeterministicEventOrdering.rb +160 -0
  42. data/test/Sequel/WithExplicitGlobalNonDeterministicEventOrderingAndInitialStateBlock.rb +158 -0
  43. data/test/Sequel/WithExplicitNonDeterministicEventOrdering.rb +156 -0
  44. data/test/Sequel/WithInitialStateBlock.rb +152 -0
  45. data/test/Sequel/WithMultipleFinalStates.rb +183 -0
  46. data/test/Sequel/WithMultipleStateMachines.rb +216 -0
  47. data/test/Sequel/WithMultipleStateMachinesAndStatefulBlock.rb +218 -0
  48. data/test/Sequel/WithPersistenceNonSpecificExtend.rb +154 -0
  49. data/test/Sequel/WithPersistenceNonSpecificExtendAndStatefulBlock.rb +156 -0
  50. data/test/Sequel/WithPersistenceSpecificExtend.rb +154 -0
  51. data/test/Sequel/WithPersistenceSpecificExtendAndStatefulBlock.rb +156 -0
  52. data/test/Sequel/test_helper.rb +5 -0
  53. data/test/Sequel.rb +5 -0
  54. data/test/Stateful.rb +15 -0
  55. metadata +69 -4
@@ -0,0 +1,161 @@
1
+ # test/ActiveRecord/WithExplicitNonDeterministicEventOrdering.rb
2
+
3
+ gem 'minitest'
4
+ gem 'minitest-spec-context'
5
+
6
+ require 'minitest/autorun'
7
+ require 'minitest-spec-context'
8
+
9
+ require_relative './test_helper'
10
+
11
+ lib_dir = File.expand_path(File.join(__FILE__, '..', '..', '..', 'lib'))
12
+ $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
13
+
14
+ require 'Stateful'
15
+
16
+ class CreateTableMachines < ActiveRecord::Migration[6.0]
17
+ def change
18
+ create_table :active_record_machine6s do |t|
19
+ t.string :current_state
20
+ end
21
+ end
22
+ end
23
+
24
+ class ActiveRecordMachine6 < ActiveRecord::Base
25
+ extend Stateful
26
+
27
+ initial_state :initial_state, non_deterministic: true do
28
+ on :an_event => :next_state
29
+ on :another_event => :final_state
30
+ end
31
+
32
+ state :next_state do
33
+ on :yet_another_event => :final_state
34
+ end
35
+
36
+ final_state :final_state
37
+ end
38
+
39
+ CreateTableMachines.new.change
40
+
41
+ describe Stateful::ActiveRecord do
42
+ let(:machine){ActiveRecordMachine6.create}
43
+
44
+ it "must have an initial state" do
45
+ _(machine.initial_state).wont_be_nil
46
+ end
47
+
48
+ it "must have a final state (if one has been specified)" do
49
+ if ActiveRecordMachine6.final_state?
50
+ _(machine.final_state).wont_be_nil
51
+ end
52
+ end
53
+
54
+ context "initial_state" do
55
+ it "must have an initial state before any events occur" do
56
+ _(machine.initial_state?).must_equal true
57
+ end
58
+
59
+ it "must have an initial state consistent with what is given" do
60
+ _(machine.initial_state).must_equal ActiveRecordMachine6.stateful_state_machine.initial_state
61
+ end
62
+
63
+ it "must have an initial state with name as per the name given" do
64
+ _(machine.initial_state.name).must_equal :initial_state
65
+ end
66
+
67
+ it "must not be in the final state (assuming that initial and final are different states)" do
68
+ _(machine.final_state?).must_equal false
69
+ end
70
+
71
+ it "must know what it's next state is given an event name" do
72
+ _(machine.next_state(:an_event)).must_equal ActiveRecordMachine6.stateful_state_machine.find(:next_state)
73
+ _(machine.next_state(:another_event)).must_equal ActiveRecordMachine6.stateful_state_machine.find(:final_state)
74
+ end
75
+
76
+ it "must have an intial state which has a collection of transitions to other states" do
77
+ _(machine.transitions.class).must_equal Array
78
+ _(machine.transitions.all?{|transition| transition.is_a?(Stateful::Transition)}).must_equal true
79
+ end
80
+
81
+ it "must have two transitions to other states" do
82
+ _(machine.transitions.size).must_equal 2
83
+ end
84
+
85
+ it "must know what transitions are available" do
86
+ transition_pairs = machine.transitions.collect{|t| [t.event_name, t.next_state_name]}
87
+ _(transition_pairs).must_include [:an_event, :next_state]
88
+ _(transition_pairs).must_include [:another_event, :final_state]
89
+ end
90
+
91
+ it "must be active" do
92
+ _(machine.active?).must_equal true
93
+ end
94
+ end
95
+
96
+ context "next_state" do
97
+ before do
98
+ machine.an_event
99
+ end
100
+
101
+ it "must not be in the initial state" do
102
+ _(machine.initial_state?).must_equal false
103
+ end
104
+
105
+ it "must not be in the final state" do
106
+ _(machine.final_state?).must_equal false
107
+ end
108
+
109
+ it "must be in the next_state state" do
110
+ _(machine.current_state.name).must_equal :next_state
111
+ _(machine.next_state?).must_equal true
112
+ end
113
+
114
+ it "must have a collection of transitions to other states" do
115
+ _(machine.transitions.class).must_equal Array
116
+ _(machine.transitions.all?{|transition| transition.is_a?(Stateful::Transition)}).must_equal true
117
+ end
118
+
119
+ it "must have one transition to other states" do
120
+ _(machine.transitions.size).must_equal 1
121
+ end
122
+
123
+ it "must know what transitions are available" do
124
+ _(machine.transitions.collect{|t| [t.event_name, t.next_state_name]}).must_equal [[:yet_another_event, :final_state]]
125
+ end
126
+
127
+ it "must be active" do
128
+ _(machine.active?).must_equal true
129
+ end
130
+ end
131
+
132
+ context "final_state" do
133
+ before do
134
+ machine.another_event
135
+ end
136
+
137
+ it "must have a final state" do
138
+ _(machine.final_state?).must_equal true
139
+ end
140
+
141
+ it "must have a final state consistent with what is given" do
142
+ _(machine.final_state).must_equal ActiveRecordMachine6.stateful_state_machine.final_state
143
+ end
144
+
145
+ it "must have a state with name as per the name given" do
146
+ _(machine.current_state.name).must_equal :final_state
147
+ end
148
+
149
+ it "must not be in the initial state (assuming that initial and final are different states)" do
150
+ _(machine.initial_state?).must_equal false
151
+ end
152
+
153
+ it "must have no transitions" do
154
+ _(machine.transitions.empty?).must_equal true
155
+ end
156
+
157
+ it "must not be active" do
158
+ _(machine.active?).must_equal false
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,157 @@
1
+ # test/ActiveRecord/WithInitialStateBlock.rb
2
+
3
+ gem 'minitest'
4
+ gem 'minitest-spec-context'
5
+
6
+ require 'minitest/autorun'
7
+ require 'minitest-spec-context'
8
+
9
+ require_relative './test_helper'
10
+
11
+ lib_dir = File.expand_path(File.join(__FILE__, '..', '..', '..', 'lib'))
12
+ $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
13
+
14
+ require 'Stateful'
15
+
16
+ class CreateTableMachines < ActiveRecord::Migration[6.0]
17
+ def change
18
+ create_table :active_record_machine4s do |t|
19
+ t.string :current_state
20
+ end
21
+ end
22
+ end
23
+
24
+ class ActiveRecordMachine4 < ActiveRecord::Base
25
+ extend Stateful
26
+
27
+ initial_state :initial_state do
28
+ on :an_event => :next_state
29
+ on :another_event => :final_state
30
+ end
31
+
32
+ state :next_state do
33
+ on :yet_another_event => :final_state
34
+ end
35
+
36
+ final_state :final_state
37
+ end
38
+
39
+ CreateTableMachines.new.change
40
+
41
+ describe Stateful::ActiveRecord do
42
+ let(:machine){ActiveRecordMachine4.create}
43
+
44
+ it "must have an initial state" do
45
+ _(machine.initial_state).wont_be_nil
46
+ end
47
+
48
+ it "must have a final state (if one has been specified)" do
49
+ if ActiveRecordMachine4.final_state?
50
+ _(machine.final_state).wont_be_nil
51
+ end
52
+ end
53
+
54
+ context "initial_state" do
55
+ it "must have an initial state before any events occur" do
56
+ _(machine.initial_state?).must_equal true
57
+ end
58
+
59
+ it "must have an initial state consistent with what is given" do
60
+ _(machine.initial_state).must_equal ActiveRecordMachine4.stateful_state_machine.initial_state
61
+ end
62
+
63
+ it "must have an initial state with name as per the name given" do
64
+ _(machine.initial_state.name).must_equal :initial_state
65
+ end
66
+
67
+ it "must not be in the final state (assuming that initial and final are different states)" do
68
+ _(machine.final_state?).must_equal false
69
+ end
70
+
71
+ it "must know what it's next state is given an event name" do
72
+ _(machine.next_state(:an_event)).must_equal ActiveRecordMachine4.stateful_state_machine.find(:next_state)
73
+ _(machine.next_state(:another_event)).must_equal ActiveRecordMachine4.stateful_state_machine.find(:final_state)
74
+ end
75
+
76
+ it "must have an intial state which has as set of transitions to other states" do
77
+ _(machine.transitions.class).must_equal Array
78
+ end
79
+
80
+ it "must have two transitions to other states" do
81
+ _(machine.transitions.size).must_equal 2
82
+ end
83
+
84
+ it "must know what transitions are available" do
85
+ _(machine.transitions.collect{|t| [t.event_name, t.next_state_name]}).must_equal [[:an_event, :next_state], [:another_event, :final_state]]
86
+ end
87
+
88
+ it "must be active" do
89
+ _(machine.active?).must_equal true
90
+ end
91
+ end
92
+
93
+ context "next_state" do
94
+ before do
95
+ machine.an_event
96
+ end
97
+
98
+ it "must not be in the initial state" do
99
+ _(machine.initial_state?).must_equal false
100
+ end
101
+
102
+ it "must not be in the final state" do
103
+ _(machine.final_state?).must_equal false
104
+ end
105
+
106
+ it "must be in the next_state state" do
107
+ _(machine.current_state.name).must_equal :next_state
108
+ _(machine.next_state?).must_equal true
109
+ end
110
+
111
+ it "must have a set of transitions to other states" do
112
+ _(machine.transitions.class).must_equal Array
113
+ end
114
+
115
+ it "must have one transition to other states" do
116
+ _(machine.transitions.size).must_equal 1
117
+ end
118
+
119
+ it "must know what transitions are available" do
120
+ _(machine.transitions.collect{|t| [t.event_name, t.next_state_name]}).must_equal [[:yet_another_event, :final_state]]
121
+ end
122
+
123
+ it "must be active" do
124
+ _(machine.active?).must_equal true
125
+ end
126
+ end
127
+
128
+ context "final_state" do
129
+ before do
130
+ machine.another_event
131
+ end
132
+
133
+ it "must have a final state" do
134
+ _(machine.final_state?).must_equal true
135
+ end
136
+
137
+ it "must have a final state consistent with what is given" do
138
+ _(machine.final_state).must_equal ActiveRecordMachine4.stateful_state_machine.final_state
139
+ end
140
+
141
+ it "must have a state with name as per the name given" do
142
+ _(machine.current_state.name).must_equal :final_state
143
+ end
144
+
145
+ it "must not be in the initial state (assuming that initial and final are different states)" do
146
+ _(machine.initial_state?).must_equal false
147
+ end
148
+
149
+ it "must have no transitions" do
150
+ _(machine.transitions.empty?).must_equal true
151
+ end
152
+
153
+ it "must not be active" do
154
+ _(machine.active?).must_equal false
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,188 @@
1
+ # test/ActiveRecord/WithMultipleFinalStates.rb
2
+
3
+ gem 'minitest'
4
+ gem 'minitest-spec-context'
5
+
6
+ require 'minitest/autorun'
7
+ require 'minitest-spec-context'
8
+
9
+ require_relative './test_helper'
10
+
11
+ lib_dir = File.expand_path(File.join(__FILE__, '..', '..', '..', 'lib'))
12
+ $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
13
+
14
+ require 'Stateful'
15
+
16
+ class CreateTableMachines < ActiveRecord::Migration[6.0]
17
+ def change
18
+ create_table :active_record_machine7s do |t|
19
+ t.string :current_state
20
+ end
21
+ end
22
+ end
23
+
24
+ class ActiveRecordMachine7 < ActiveRecord::Base
25
+ extend Stateful
26
+
27
+ initial_state :initial_state do
28
+ on :an_event => :next_state
29
+ on :another_event => :final_state0
30
+ end
31
+
32
+ state :next_state do
33
+ on :yet_another_event => :final_state1
34
+ end
35
+
36
+ final_state :final_state0, :final_state1
37
+ end
38
+
39
+ CreateTableMachines.new.change
40
+
41
+ describe Stateful::ActiveRecord do
42
+ let(:machine){ActiveRecordMachine7.new}
43
+
44
+ it "must have an initial state" do
45
+ _(machine.initial_state).wont_be_nil
46
+ end
47
+
48
+ it "must have a final state (if one has been specified)" do
49
+ if ActiveRecordMachine7.final_state?
50
+ _(machine.final_state).wont_be_nil
51
+ end
52
+ end
53
+
54
+ context "initial_state" do
55
+ it "must have an initial state before any events occur" do
56
+ _(machine.initial_state?).must_equal true
57
+ end
58
+
59
+ it "must have an initial state consistent with what is given" do
60
+ _(machine.initial_state).must_equal ActiveRecordMachine7.stateful_state_machine.initial_state
61
+ end
62
+
63
+ it "must have an initial state with name as per the name given" do
64
+ _(machine.initial_state.name).must_equal :initial_state
65
+ end
66
+
67
+ it "must not be in the final state (assuming that initial and final are different states)" do
68
+ _(machine.final_state?).must_equal false
69
+ end
70
+
71
+ it "must know what it's next state is given an event name" do
72
+ _(machine.next_state(:an_event)).must_equal ActiveRecordMachine7.stateful_state_machine.find(:next_state)
73
+ _(machine.next_state(:another_event)).must_equal ActiveRecordMachine7.stateful_state_machine.find(:final_state0)
74
+ end
75
+
76
+ it "must have an intial state which has as set of transitions to other states" do
77
+ _(machine.transitions.class).must_equal Array
78
+ end
79
+
80
+ it "must have two transitions to other states" do
81
+ _(machine.transitions.size).must_equal 2
82
+ end
83
+
84
+ it "must know what transitions are available and in what order they are presented" do
85
+ _(machine.transitions.collect{|t| [t.event_name, t.next_state_name]}).must_equal [[:an_event, :next_state], [:another_event, :final_state0]]
86
+ end
87
+
88
+ it "must be active" do
89
+ _(machine.active?).must_equal true
90
+ end
91
+ end
92
+
93
+ context "next_state" do
94
+ before do
95
+ machine.an_event
96
+ end
97
+
98
+ it "must not be in the initial state" do
99
+ _(machine.initial_state?).must_equal false
100
+ end
101
+
102
+ it "must not be in a final state" do
103
+ _(machine.final_state?).must_equal false
104
+ end
105
+
106
+ it "must be in the next_state state" do
107
+ _(machine.current_state.name).must_equal :next_state
108
+ _(machine.next_state?).must_equal true
109
+ end
110
+
111
+ it "must have a set of transitions to other states" do
112
+ _(machine.transitions.class).must_equal Array
113
+ end
114
+
115
+ it "must have one transition to other states" do
116
+ _(machine.transitions.size).must_equal 1
117
+ end
118
+
119
+ it "must know what transitions are available" do
120
+ _(machine.transitions.collect{|t| [t.event_name, t.next_state_name]}).must_equal [[:yet_another_event, :final_state1]]
121
+ end
122
+
123
+ it "must be active" do
124
+ _(machine.active?).must_equal true
125
+ end
126
+ end
127
+
128
+ context "final_state0" do
129
+ before do
130
+ machine.another_event
131
+ end
132
+
133
+ it "must have a final state" do
134
+ _(machine.final_state?).must_equal true
135
+ end
136
+
137
+ it "must have a final state consistent with what is given" do
138
+ _(ActiveRecordMachine7.stateful_state_machine.final_states).must_include machine.final_state
139
+ end
140
+
141
+ it "must have a state with name as per the name given" do
142
+ _(machine.current_state.name).must_equal :final_state0
143
+ end
144
+
145
+ it "must not be in the initial state (assuming that initial and final are different states)" do
146
+ _(machine.initial_state?).must_equal false
147
+ end
148
+
149
+ it "must have no transitions" do
150
+ _(machine.transitions.empty?).must_equal true
151
+ end
152
+
153
+ it "must not be active" do
154
+ _(machine.active?).must_equal false
155
+ end
156
+ end
157
+
158
+ context "final_state1" do
159
+ before do
160
+ machine.an_event
161
+ machine.yet_another_event
162
+ end
163
+
164
+ it "must have a final state" do
165
+ _(machine.final_state?).must_equal true
166
+ end
167
+
168
+ it "must have a final state consistent with what is given" do
169
+ _(ActiveRecordMachine7.stateful_state_machine.final_states).must_include machine.final_state
170
+ end
171
+
172
+ it "must have a state with name as per the name given" do
173
+ _(machine.current_state.name).must_equal :final_state1
174
+ end
175
+
176
+ it "must not be in the initial state (assuming that initial and final are different states)" do
177
+ _(machine.initial_state?).must_equal false
178
+ end
179
+
180
+ it "must have no transitions" do
181
+ _(machine.transitions.empty?).must_equal true
182
+ end
183
+
184
+ it "must not be active" do
185
+ _(machine.active?).must_equal false
186
+ end
187
+ end
188
+ end