stateful.rb 2.1.0 → 2.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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +161 -0
  3. data/Gemfile +3 -0
  4. data/README.md +309 -0
  5. data/lib/Stateful/ActiveRecord/ClassMethods.rb +7 -65
  6. data/lib/Stateful/ClassMethods.rb +60 -0
  7. data/lib/Stateful/Poro/ClassMethods.rb +12 -70
  8. data/lib/Stateful/Sequel/ClassMethods.rb +59 -0
  9. data/lib/Stateful/Sequel.rb +30 -0
  10. data/lib/Stateful/VERSION.rb +1 -1
  11. data/lib/Stateful.rb +3 -0
  12. data/stateful.rb.gemspec +42 -0
  13. data/test/ActiveRecord/WithColumnName.rb +159 -0
  14. data/test/ActiveRecord/WithExplicitDeterministicEventOrdering.rb +159 -0
  15. data/test/ActiveRecord/WithExplicitGlobalNonDeterministicEventOrdering.rb +165 -0
  16. data/test/ActiveRecord/WithExplicitGlobalNonDeterministicEventOrderingAndInitialStateBlock.rb +163 -0
  17. data/test/ActiveRecord/WithExplicitNonDeterministicEventOrdering.rb +161 -0
  18. data/test/ActiveRecord/WithInitialStateBlock.rb +157 -0
  19. data/test/ActiveRecord/WithMultipleFinalStates.rb +188 -0
  20. data/test/ActiveRecord/WithMultipleStateMachines.rb +221 -0
  21. data/test/ActiveRecord/WithMultipleStateMachinesAndStatefulBlock.rb +223 -0
  22. data/test/ActiveRecord/WithPersistenceNonSpecificExtend.rb +159 -0
  23. data/test/ActiveRecord/WithPersistenceNonSpecificExtendAndStatefulBlock.rb +161 -0
  24. data/test/ActiveRecord/WithPersistenceSpecificExtend.rb +159 -0
  25. data/test/ActiveRecord/WithPersistenceSpecificExtendAndStatefulBlock.rb +161 -0
  26. data/test/ActiveRecord/test_helper.rb +9 -0
  27. data/test/ActiveRecord.rb +5 -0
  28. data/test/Poro/WithExplicitDeterministicEventOrdering.rb +147 -0
  29. data/test/Poro/WithExplicitGlobalNonDeterministicEventOrdering.rb +153 -0
  30. data/test/Poro/WithExplicitGlobalNonDeterministicEventOrderingAndInitialStateBlock.rb +151 -0
  31. data/test/Poro/WithExplicitNonDeterministicEventOrdering.rb +149 -0
  32. data/test/Poro/WithInitialStateBlock.rb +145 -0
  33. data/test/Poro/WithMultipleFinalStates.rb +176 -0
  34. data/test/Poro/WithMultipleStateMachines.rb +192 -0
  35. data/test/Poro/WithMultipleStateMachinesAndStatefulBlock.rb +194 -0
  36. data/test/Poro/WithPersistenceNonSpecificExtend.rb +147 -0
  37. data/test/Poro/WithPersistenceNonSpecificExtendAndStatefulBlock.rb +149 -0
  38. data/test/Poro/WithPersistenceSpecificExtend.rb +147 -0
  39. data/test/Poro/WithPersistenceSpecificExtendAndStatefulBlock.rb +149 -0
  40. data/test/Poro/WithVariableName.rb +147 -0
  41. data/test/Poro.rb +5 -0
  42. data/test/Sequel/WithColumnName.rb +154 -0
  43. data/test/Sequel/WithExplicitDeterministicEventOrdering.rb +154 -0
  44. data/test/Sequel/WithExplicitGlobalNonDeterministicEventOrdering.rb +160 -0
  45. data/test/Sequel/WithExplicitGlobalNonDeterministicEventOrderingAndInitialStateBlock.rb +158 -0
  46. data/test/Sequel/WithExplicitNonDeterministicEventOrdering.rb +156 -0
  47. data/test/Sequel/WithInitialStateBlock.rb +152 -0
  48. data/test/Sequel/WithMultipleFinalStates.rb +183 -0
  49. data/test/Sequel/WithMultipleStateMachines.rb +216 -0
  50. data/test/Sequel/WithMultipleStateMachinesAndStatefulBlock.rb +218 -0
  51. data/test/Sequel/WithPersistenceNonSpecificExtend.rb +154 -0
  52. data/test/Sequel/WithPersistenceNonSpecificExtendAndStatefulBlock.rb +156 -0
  53. data/test/Sequel/WithPersistenceSpecificExtend.rb +154 -0
  54. data/test/Sequel/WithPersistenceSpecificExtendAndStatefulBlock.rb +156 -0
  55. data/test/Sequel/test_helper.rb +5 -0
  56. data/test/Sequel.rb +5 -0
  57. data/test/Stateful.rb +15 -0
  58. metadata +69 -4
@@ -6,8 +6,8 @@ module Stateful
6
6
  module ClassMethods
7
7
  class << self
8
8
  def extended(klass)
9
- klass.define_stateful_variable_name_setter_method
10
- klass.define_stateful_variable_name_getter_method
9
+ klass.define_stateful_attribute_setter_method
10
+ klass.define_stateful_attribute_getter_method
11
11
  klass.define_next_state_method
12
12
  klass.define_transitions_method
13
13
  klass.define_initial_stateQ_method
@@ -15,15 +15,6 @@ module Stateful
15
15
  end
16
16
  end # class << self
17
17
 
18
- def define_named_machine_methods(machine_name)
19
- define_stateful_variable_name_setter_method(machine_name: machine_name)
20
- define_stateful_variable_name_getter_method(machine_name: machine_name)
21
- define_next_state_method(machine_name: machine_name)
22
- define_transitions_method(machine_name: machine_name)
23
- define_initial_stateQ_method(machine_name: machine_name)
24
- define_final_stateQ_method(machine_name: machine_name)
25
- end
26
-
27
18
  def stateful_variable_name=(stateful_variable_name)
28
19
  @stateful_variable_name = stateful_variable_name
29
20
  end
@@ -32,7 +23,7 @@ module Stateful
32
23
  @stateful_variable_name
33
24
  end
34
25
 
35
- def variable_name_for_machine(machine_name = nil)
26
+ def stateful_attribute_name_for_machine(machine_name = nil)
36
27
  if machine_name
37
28
  "#{machine_name}_state"
38
29
  else
@@ -40,74 +31,25 @@ module Stateful
40
31
  end
41
32
  end
42
33
 
43
- def define_event_method(transition, machine_name: nil)
44
- variable_name = variable_name_for_machine(machine_name)
45
- define_method(transition.event_name) do
46
- next_state_name = self.send(variable_name).next_state_name(transition.event_name)
47
- next_state = self.class.stateful_state_machine(machine_name).find(next_state_name)
48
- self.send("#{variable_name}=", next_state)
49
- end
50
- end
51
-
52
- def define_status_predicate_method(state_name, machine_name: nil)
53
- variable_name = variable_name_for_machine(machine_name)
54
- define_method("#{state_name}?") do
55
- self.send(variable_name).name == state_name
34
+ def define_stateful_attribute_setter_method(machine_name: nil)
35
+ attribute_name = stateful_attribute_name_for_machine(machine_name)
36
+ define_method("#{attribute_name}=") do |state|
37
+ instance_variable_set("@#{attribute_name}", self.class.stateful_state_machine(machine_name).find(state))
56
38
  end
57
39
  end
58
40
 
59
- def define_stateful_variable_name_setter_method(machine_name: nil)
60
- variable_name = variable_name_for_machine(machine_name)
61
- define_method("#{variable_name}=") do |state|
62
- instance_variable_set("@#{variable_name}", self.class.stateful_state_machine(machine_name).find(state))
63
- end
64
- end
65
-
66
- def define_stateful_variable_name_getter_method(machine_name: nil)
67
- variable_name = variable_name_for_machine(machine_name)
68
- define_method(variable_name) do
69
- if state = instance_variable_get("@#{variable_name}")
41
+ def define_stateful_attribute_getter_method(machine_name: nil)
42
+ attribute_name = stateful_attribute_name_for_machine(machine_name)
43
+ define_method(attribute_name) do
44
+ if state = instance_variable_get("@#{attribute_name}")
70
45
  state
71
46
  else
72
47
  initial_state = self.class.stateful_state_machine(machine_name).initial_state
73
- self.send("#{variable_name}=", initial_state.name)
48
+ self.send("#{attribute_name}=", initial_state.name)
74
49
  initial_state
75
50
  end
76
51
  end
77
52
  end
78
-
79
- def define_next_state_method(machine_name: nil)
80
- variable_name = variable_name_for_machine(machine_name)
81
- method_name = machine_name ? "#{machine_name}_next_state" : :next_state
82
- define_method(method_name) do |event_name|
83
- next_state_name = self.send(variable_name).next_state_name(event_name)
84
- self.class.stateful_state_machine(machine_name).find(next_state_name)
85
- end
86
- end
87
-
88
- def define_transitions_method(machine_name: nil)
89
- variable_name = variable_name_for_machine(machine_name)
90
- method_name = machine_name ? "#{machine_name}_transitions" : :transitions
91
- define_method(method_name) do
92
- self.send(variable_name).transitions
93
- end
94
- end
95
-
96
- def define_initial_stateQ_method(machine_name: nil)
97
- variable_name = variable_name_for_machine(machine_name)
98
- method_name = machine_name ? "#{machine_name}_initial_state?" : :initial_state?
99
- define_method(method_name) do
100
- self.send(variable_name) == self.class.stateful_state_machine(machine_name).initial_state
101
- end
102
- end
103
-
104
- def define_final_stateQ_method(machine_name: nil)
105
- variable_name = variable_name_for_machine(machine_name)
106
- method_name = machine_name ? "#{machine_name}_final_state?" : :final_state?
107
- define_method(method_name) do
108
- self.class.stateful_state_machine(machine_name).final_states.include?(self.send(variable_name))
109
- end
110
- end
111
53
  end
112
54
  end
113
55
  end
@@ -0,0 +1,59 @@
1
+ # Stateful/Sequel/ClassMethods.rb
2
+ # Stateful::Sequel::ClassMethods
3
+
4
+ module Stateful
5
+ module Sequel
6
+ module ClassMethods
7
+ class << self
8
+ def extended(klass)
9
+ klass.define_stateful_attribute_setter_method
10
+ klass.define_stateful_attribute_getter_method
11
+ klass.define_next_state_method
12
+ klass.define_transitions_method
13
+ klass.define_initial_stateQ_method
14
+ klass.define_final_stateQ_method
15
+ end
16
+ end # class << self
17
+
18
+ def stateful_column_name=(stateful_column_name)
19
+ @stateful_column_name = stateful_column_name
20
+ end
21
+
22
+ def stateful_column_name
23
+ @stateful_column_name
24
+ end
25
+
26
+ def stateful_attribute_name_for_machine(machine_name = nil)
27
+ if machine_name
28
+ "#{machine_name}_state"
29
+ else
30
+ instance_variable_get(:@stateful_column_name)
31
+ end
32
+ end
33
+
34
+ def define_stateful_attribute_setter_method(machine_name: nil)
35
+ stateful_column_name = stateful_attribute_name_for_machine(machine_name)
36
+ define_method("#{stateful_column_name}=") do |state|
37
+ instance_variable_set("@#{stateful_column_name}", self.class.stateful_state_machine(machine_name).find(state))
38
+ self[stateful_column_name.to_sym] = instance_variable_get("@#{stateful_column_name}").name.to_s
39
+ self.save
40
+ instance_variable_get("@#{stateful_column_name}")
41
+ end
42
+ end
43
+
44
+ def define_stateful_attribute_getter_method(machine_name: nil)
45
+ stateful_column_name = stateful_attribute_name_for_machine(machine_name)
46
+ define_method(stateful_column_name) do
47
+ instance_variable_set("@#{stateful_column_name}", self.class.stateful_state_machine(machine_name).find(self[stateful_column_name.to_sym]))
48
+ if state = instance_variable_get("@#{stateful_column_name}")
49
+ state
50
+ else
51
+ initial_state = self.class.stateful_state_machine(machine_name).initial_state
52
+ self.send("#{stateful_column_name}=", initial_state.name)
53
+ initial_state
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,30 @@
1
+ # Stateful/Sequel.rb
2
+ # Stateful::Sequel
3
+
4
+ require_relative 'ClassMethods'
5
+ require_relative 'InstanceMethods'
6
+ require_relative File.join('Sequel', 'ClassMethods')
7
+
8
+ module Stateful
9
+ module Sequel
10
+
11
+ class << self
12
+
13
+ def set_column_name(klass)
14
+ unless klass.instance_variable_get(:@stateful_column_name)
15
+ klass.instance_variable_set(:@stateful_column_name, 'current_state')
16
+ end
17
+ end
18
+
19
+ def extended(klass)
20
+ klass.extend(Stateful::ClassMethods)
21
+ klass.send(:include, Stateful::InstanceMethods)
22
+ set_column_name(klass)
23
+ klass.extend(Stateful::Sequel::ClassMethods)
24
+ end
25
+ alias_method :included, :extended
26
+
27
+ end # class << self
28
+
29
+ end
30
+ end
@@ -1,3 +1,3 @@
1
1
  module Stateful
2
- VERSION = '2.1.0'
2
+ VERSION = '2.3.0'
3
3
  end
data/lib/Stateful.rb CHANGED
@@ -9,6 +9,9 @@ module Stateful
9
9
  if Object.const_defined?(:ActiveRecord) && defined?(::ActiveRecord::Base) && klass < ::ActiveRecord::Base
10
10
  require_relative File.join('Stateful', 'ActiveRecord')
11
11
  klass.extend(Stateful::ActiveRecord)
12
+ elsif Object.const_defined?(:Sequel) && defined?(::Sequel::Model) && klass < ::Sequel::Model
13
+ require_relative File.join('Stateful', 'Sequel')
14
+ klass.extend(Stateful::Sequel)
12
15
  else
13
16
  require_relative File.join('Stateful', 'Poro')
14
17
  klass.extend(Stateful::Poro)
@@ -0,0 +1,42 @@
1
+ require_relative './lib/Stateful/VERSION'
2
+
3
+ class Gem::Specification
4
+ def development_dependencies=(gems)
5
+ gems.each{|gem| add_development_dependency(*gem)}
6
+ end
7
+ end
8
+
9
+ Gem::Specification.new do |spec|
10
+ spec.name = 'stateful.rb'
11
+ spec.version = Stateful::VERSION
12
+
13
+ spec.summary = "A Ruby state machine."
14
+ spec.description = "Easily add state to Poro, ActiveRecord, and Sequel objects."
15
+
16
+ spec.author = 'thoran'
17
+ spec.email = 'code@thoran.com'
18
+ spec.homepage = 'http://github.com/thoran/stateful'
19
+ spec.license = 'MIT'
20
+
21
+ # The required version of Ruby is this higher than it strictly needs to be solely because the migrations have been made to require AR 6.0, but otherwise this should work with much lower versions of Ruby and ActiveRecord, even down to 2.3 (or lower) and AR 3 (or lower).
22
+ spec.required_ruby_version = '>= 2.5'
23
+
24
+ spec.require_paths = ['lib']
25
+
26
+ spec.files = [
27
+ 'stateful.rb.gemspec',
28
+ 'CHANGELOG.md',
29
+ 'Gemfile',
30
+ 'README.md',
31
+ Dir['lib/**/*.rb'],
32
+ Dir['test/**/*.rb']
33
+ ].flatten
34
+
35
+ spec.development_dependencies = %w{
36
+ minitest
37
+ minitest-spec-context
38
+ activerecord
39
+ sequel
40
+ sqlite3
41
+ }
42
+ end
@@ -0,0 +1,159 @@
1
+ # test/ActiveRecord/WithColumnName.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_machine8s do |t|
19
+ t.string :status
20
+ end
21
+ end
22
+ end
23
+
24
+ class ActiveRecordMachine8 < ActiveRecord::Base
25
+ @stateful_column_name = 'status'
26
+
27
+ extend Stateful
28
+
29
+ initial_state :initial_state do
30
+ on :an_event => :next_state
31
+ on :another_event => :final_state
32
+ end
33
+
34
+ state :next_state do
35
+ on :yet_another_event => :final_state
36
+ end
37
+
38
+ final_state :final_state
39
+ end
40
+
41
+ CreateTableMachines.new.change
42
+
43
+ describe Stateful::ActiveRecord do
44
+ let(:machine){ActiveRecordMachine8.create}
45
+
46
+ it "must have an initial state" do
47
+ _(machine.initial_state).wont_be_nil
48
+ end
49
+
50
+ it "must have a final state (if one has been specified)" do
51
+ if ActiveRecordMachine8.final_state?
52
+ _(machine.final_state).wont_be_nil
53
+ end
54
+ end
55
+
56
+ context "initial_state" do
57
+ it "must have an initial state before any events occur" do
58
+ _(machine.initial_state?).must_equal true
59
+ end
60
+
61
+ it "must have an initial state consistent with what is given" do
62
+ _(machine.initial_state).must_equal ActiveRecordMachine8.stateful_state_machine.initial_state
63
+ end
64
+
65
+ it "must have an initial state with name as per the name given" do
66
+ _(machine.initial_state.name).must_equal :initial_state
67
+ end
68
+
69
+ it "must not be in the final state (assuming that initial and final are different states)" do
70
+ _(machine.final_state?).must_equal false
71
+ end
72
+
73
+ it "must know what it's next state is given an event name" do
74
+ _(machine.next_state(:an_event)).must_equal ActiveRecordMachine8.stateful_state_machine.find(:next_state)
75
+ _(machine.next_state(:another_event)).must_equal ActiveRecordMachine8.stateful_state_machine.find(:final_state)
76
+ end
77
+
78
+ it "must have an intial state which has as set of transitions to other states" do
79
+ _(machine.transitions.class).must_equal Array
80
+ end
81
+
82
+ it "must have two transitions to other states" do
83
+ _(machine.transitions.size).must_equal 2
84
+ end
85
+
86
+ it "must know what transitions are available" do
87
+ _(machine.transitions.collect{|t| [t.event_name, t.next_state_name]}).must_equal [[:an_event, :next_state], [:another_event, :final_state]]
88
+ end
89
+
90
+ it "must be active" do
91
+ _(machine.active?).must_equal true
92
+ end
93
+ end
94
+
95
+ context "next_state" do
96
+ before do
97
+ machine.an_event
98
+ end
99
+
100
+ it "must not be in the initial state" do
101
+ _(machine.initial_state?).must_equal false
102
+ end
103
+
104
+ it "must not be in the final state" do
105
+ _(machine.final_state?).must_equal false
106
+ end
107
+
108
+ it "must be in the next_state state" do
109
+ _(machine.status.name).must_equal :next_state
110
+ _(machine.next_state?).must_equal true
111
+ end
112
+
113
+ it "must have a set of transitions to other states" do
114
+ _(machine.transitions.class).must_equal Array
115
+ end
116
+
117
+ it "must have one transition to other states" do
118
+ _(machine.transitions.size).must_equal 1
119
+ end
120
+
121
+ it "must know what transitions are available" do
122
+ _(machine.transitions.collect{|t| [t.event_name, t.next_state_name]}).must_equal [[:yet_another_event, :final_state]]
123
+ end
124
+
125
+ it "must be active" do
126
+ _(machine.active?).must_equal true
127
+ end
128
+ end
129
+
130
+ context "final_state" do
131
+ before do
132
+ machine.another_event
133
+ end
134
+
135
+ it "must have a final state" do
136
+ _(machine.final_state?).must_equal true
137
+ end
138
+
139
+ it "must have a final state consistent with what is given" do
140
+ _(machine.final_state).must_equal ActiveRecordMachine8.stateful_state_machine.final_state
141
+ end
142
+
143
+ it "must have a state with name as per the name given" do
144
+ _(machine.status.name).must_equal :final_state
145
+ end
146
+
147
+ it "must not be in the initial state (assuming that initial and final are different states)" do
148
+ _(machine.initial_state?).must_equal false
149
+ end
150
+
151
+ it "must have no transitions" do
152
+ _(machine.transitions.empty?).must_equal true
153
+ end
154
+
155
+ it "must not be active" do
156
+ _(machine.active?).must_equal false
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,159 @@
1
+ # test/ActiveRecord/WithExplicitDeterministicEventOrdering.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_machine5s do |t|
19
+ t.string :current_state
20
+ end
21
+ end
22
+ end
23
+
24
+ class ActiveRecordMachine5 < ActiveRecord::Base
25
+ extend Stateful
26
+
27
+ initial_state :initial_state, 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){ActiveRecordMachine5.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 ActiveRecordMachine5.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 ActiveRecordMachine5.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 ActiveRecordMachine5.stateful_state_machine.find(:next_state)
73
+ _(machine.next_state(:another_event)).must_equal ActiveRecordMachine5.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 and in what order they are presented" do
86
+ _(machine.transitions.collect{|t| [t.event_name, t.next_state_name]}).must_equal [[:an_event, :next_state], [:another_event, :final_state]]
87
+ end
88
+
89
+ it "must be active" do
90
+ _(machine.active?).must_equal true
91
+ end
92
+ end
93
+
94
+ context "next_state" do
95
+ before do
96
+ machine.an_event
97
+ end
98
+
99
+ it "must not be in the initial state" do
100
+ _(machine.initial_state?).must_equal false
101
+ end
102
+
103
+ it "must not be in the final state" do
104
+ _(machine.final_state?).must_equal false
105
+ end
106
+
107
+ it "must be in the next_state state" do
108
+ _(machine.current_state.name).must_equal :next_state
109
+ _(machine.next_state?).must_equal true
110
+ end
111
+
112
+ it "must have a collection of transitions to other states" do
113
+ _(machine.transitions.class).must_equal Array
114
+ _(machine.transitions.all?{|transition| transition.is_a?(Stateful::Transition)}).must_equal true
115
+ end
116
+
117
+ it "must have one transition to other states" do
118
+ _(machine.transitions.size).must_equal 1
119
+ end
120
+
121
+ it "must know what transitions are available" do
122
+ _(machine.transitions.collect{|t| [t.event_name, t.next_state_name]}).must_equal [[:yet_another_event, :final_state]]
123
+ end
124
+
125
+ it "must be active" do
126
+ _(machine.active?).must_equal true
127
+ end
128
+ end
129
+
130
+ context "final_state" do
131
+ before do
132
+ machine.another_event
133
+ end
134
+
135
+ it "must have a final state" do
136
+ _(machine.final_state?).must_equal true
137
+ end
138
+
139
+ it "must have a final state consistent with what is given" do
140
+ _(machine.final_state).must_equal ActiveRecordMachine5.stateful_state_machine.final_state
141
+ end
142
+
143
+ it "must have a state with name as per the name given" do
144
+ _(machine.current_state.name).must_equal :final_state
145
+ end
146
+
147
+ it "must not be in the initial state (assuming that initial and final are different states)" do
148
+ _(machine.initial_state?).must_equal false
149
+ end
150
+
151
+ it "must have no transitions" do
152
+ _(machine.transitions.empty?).must_equal true
153
+ end
154
+
155
+ it "must not be active" do
156
+ _(machine.active?).must_equal false
157
+ end
158
+ end
159
+ end