aasm 4.2.0 → 4.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 (97) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -1
  3. data/Gemfile +2 -2
  4. data/PLANNED_CHANGES.md +24 -4
  5. data/README.md +75 -5
  6. data/lib/aasm/aasm.rb +50 -36
  7. data/lib/aasm/base.rb +36 -18
  8. data/lib/aasm/core/event.rb +6 -5
  9. data/lib/aasm/core/state.rb +3 -2
  10. data/lib/aasm/core/transition.rb +5 -4
  11. data/lib/aasm/errors.rb +7 -4
  12. data/lib/aasm/instance_base.rb +14 -13
  13. data/lib/aasm/localizer.rb +1 -1
  14. data/lib/aasm/persistence/active_record_persistence.rb +41 -66
  15. data/lib/aasm/persistence/base.rb +7 -7
  16. data/lib/aasm/persistence/mongo_mapper_persistence.rb +34 -51
  17. data/lib/aasm/persistence/mongoid_persistence.rb +15 -36
  18. data/lib/aasm/persistence/plain_persistence.rb +8 -7
  19. data/lib/aasm/persistence/sequel_persistence.rb +12 -10
  20. data/lib/aasm/state_machine.rb +11 -6
  21. data/lib/aasm/version.rb +1 -1
  22. data/spec/database.rb +27 -1
  23. data/spec/models/active_record/basic_active_record_two_state_machines_example.rb +25 -0
  24. data/spec/models/active_record/complex_active_record_example.rb +33 -0
  25. data/spec/models/active_record/derivate_new_dsl.rb +4 -0
  26. data/spec/models/active_record/false_state.rb +18 -0
  27. data/spec/models/active_record/gate.rb +20 -0
  28. data/spec/models/active_record/no_direct_assignment.rb +11 -0
  29. data/spec/models/active_record/no_scope.rb +11 -0
  30. data/spec/models/active_record/provided_and_persisted_state.rb +3 -3
  31. data/spec/models/active_record/simple_new_dsl.rb +9 -0
  32. data/spec/models/active_record/thief.rb +15 -0
  33. data/spec/models/active_record/with_enum.rb +20 -0
  34. data/spec/models/active_record/with_false_enum.rb +16 -0
  35. data/spec/models/active_record/with_true_enum.rb +20 -0
  36. data/spec/models/basic_two_state_machines_example.rb +25 -0
  37. data/spec/models/callbacks/basic_multiple.rb +75 -0
  38. data/spec/models/callbacks/guard_within_block_multiple.rb +66 -0
  39. data/spec/models/callbacks/multiple_transitions_transition_guard_multiple.rb +65 -0
  40. data/spec/models/callbacks/private_method_multiple.rb +44 -0
  41. data/spec/models/callbacks/with_args_multiple.rb +61 -0
  42. data/spec/models/callbacks/{with_state_args.rb → with_state_arg.rb} +0 -0
  43. data/spec/models/callbacks/with_state_arg_multiple.rb +26 -0
  44. data/spec/models/complex_example.rb +134 -0
  45. data/spec/models/conversation.rb +47 -1
  46. data/spec/models/foo.rb +57 -0
  47. data/spec/models/foo_callback_multiple.rb +45 -0
  48. data/spec/models/guardian_multiple.rb +48 -0
  49. data/spec/models/initial_state_proc.rb +16 -0
  50. data/spec/models/invalid_persistor.rb +15 -0
  51. data/spec/models/mongo_mapper/complex_mongo_mapper_example.rb +37 -0
  52. data/spec/models/mongo_mapper/no_scope_mongo_mapper.rb +11 -0
  53. data/spec/models/mongo_mapper/simple_mongo_mapper.rb +12 -0
  54. data/spec/models/mongo_mapper/simple_new_dsl_mongo_mapper.rb +13 -0
  55. data/spec/models/mongoid/complex_mongoid_example.rb +37 -0
  56. data/spec/models/mongoid/no_scope_mongoid.rb +11 -0
  57. data/spec/models/mongoid/simple_mongoid.rb +12 -0
  58. data/spec/models/mongoid/simple_new_dsl_mongoid.rb +13 -0
  59. data/spec/models/no_initial_state.rb +13 -0
  60. data/spec/models/parametrised_event.rb +1 -1
  61. data/spec/models/parametrised_event_multiple.rb +29 -0
  62. data/spec/models/provided_state.rb +3 -3
  63. data/spec/models/sequel/complex_sequel_example.rb +45 -0
  64. data/spec/models/sequel/sequel_multiple.rb +25 -0
  65. data/spec/models/sequel/sequel_simple.rb +25 -0
  66. data/spec/models/simple_multiple_example.rb +30 -0
  67. data/spec/models/sub_class.rb +4 -0
  68. data/spec/models/sub_class_with_more_states.rb +11 -0
  69. data/spec/models/super_class.rb +28 -0
  70. data/spec/models/transactor.rb +27 -0
  71. data/spec/models/valid_state_name.rb +12 -0
  72. data/spec/models/validator.rb +39 -0
  73. data/spec/unit/basic_two_state_machines_example_spec.rb +10 -0
  74. data/spec/unit/callback_multiple_spec.rb +295 -0
  75. data/spec/unit/callbacks_spec.rb +1 -1
  76. data/spec/unit/complex_multiple_example_spec.rb +99 -0
  77. data/spec/unit/edge_cases_spec.rb +16 -0
  78. data/spec/unit/event_multiple_spec.rb +73 -0
  79. data/spec/unit/event_spec.rb +11 -6
  80. data/spec/unit/guard_multiple_spec.rb +60 -0
  81. data/spec/unit/initial_state_multiple_spec.rb +15 -0
  82. data/spec/unit/inspection_multiple_spec.rb +201 -0
  83. data/spec/unit/persistence/active_record_persistence_multiple_spec.rb +560 -0
  84. data/spec/unit/persistence/active_record_persistence_spec.rb +17 -12
  85. data/spec/unit/persistence/mongo_mapper_persistence_multiple_spec.rb +146 -0
  86. data/spec/unit/persistence/{mongo_mapper_persistance_spec.rb → mongo_mapper_persistence_spec.rb} +7 -49
  87. data/spec/unit/persistence/mongoid_persistence_multiple_spec.rb +127 -0
  88. data/spec/unit/persistence/mongoid_persistence_spec.rb +79 -0
  89. data/spec/unit/persistence/sequel_persistence_multiple_spec.rb +153 -0
  90. data/spec/unit/persistence/sequel_persistence_spec.rb +7 -24
  91. data/spec/unit/reloading_spec.rb +1 -1
  92. data/spec/unit/simple_multiple_example_spec.rb +63 -0
  93. data/spec/unit/state_spec.rb +3 -1
  94. data/spec/unit/subclassing_multiple_spec.rb +39 -0
  95. data/spec/unit/transition_spec.rb +31 -22
  96. metadata +73 -9
  97. data/spec/unit/persistence/mongoid_persistance_spec.rb +0 -146
@@ -86,3 +86,137 @@ class ComplexExample
86
86
  phrase == :please
87
87
  end
88
88
  end
89
+
90
+ class ComplexExampleMultiple
91
+ include AASM
92
+
93
+ attr_accessor :activation_code, :activated_at, :deleted_at
94
+
95
+ aasm(:left) do
96
+ state :passive
97
+ state :pending, :initial => true, :before_enter => :make_activation_code
98
+ state :active, :before_enter => :do_activate
99
+ state :suspended
100
+ state :deleted, :before_enter => :do_delete#, :exit => :do_undelete
101
+ state :waiting
102
+
103
+ event :left_register do
104
+ transitions :from => :passive, :to => :pending do
105
+ guard do
106
+ can_register?
107
+ end
108
+ end
109
+ end
110
+
111
+ event :left_activate do
112
+ transitions :from => :pending, :to => :active
113
+ end
114
+
115
+ event :left_suspend do
116
+ transitions :from => [:passive, :pending, :active], :to => :suspended
117
+ end
118
+
119
+ event :left_delete do
120
+ transitions :from => [:passive, :pending, :active, :suspended], :to => :deleted
121
+ end
122
+
123
+ # a dummy event that can never happen
124
+ event :left_unpassify do
125
+ transitions :from => :passive, :to => :active, :guard => Proc.new {|u| false }
126
+ end
127
+
128
+ event :left_unsuspend do
129
+ transitions :from => :suspended, :to => :active, :guard => Proc.new { has_activated? }
130
+ transitions :from => :suspended, :to => :pending, :guard => :has_activation_code?
131
+ transitions :from => :suspended, :to => :passive
132
+ end
133
+
134
+ event :left_wait do
135
+ transitions :from => :suspended, :to => :waiting, :guard => :if_polite?
136
+ end
137
+ end
138
+
139
+ aasm(:right) do
140
+ state :passive
141
+ state :pending, :initial => true, :before_enter => :make_activation_code
142
+ state :active, :before_enter => :do_activate
143
+ state :suspended
144
+ state :deleted, :before_enter => :do_delete#, :exit => :do_undelete
145
+ state :waiting
146
+
147
+ event :right_register do
148
+ transitions :from => :passive, :to => :pending do
149
+ guard do
150
+ can_register?
151
+ end
152
+ end
153
+ end
154
+
155
+ event :right_activate do
156
+ transitions :from => :pending, :to => :active
157
+ end
158
+
159
+ event :right_suspend do
160
+ transitions :from => [:passive, :pending, :active], :to => :suspended
161
+ end
162
+
163
+ event :right_delete do
164
+ transitions :from => [:passive, :pending, :active, :suspended], :to => :deleted
165
+ end
166
+
167
+ # a dummy event that can never happen
168
+ event :right_unpassify do
169
+ transitions :from => :passive, :to => :active, :guard => Proc.new {|u| false }
170
+ end
171
+
172
+ event :right_unsuspend do
173
+ transitions :from => :suspended, :to => :active, :guard => Proc.new { has_activated? }
174
+ transitions :from => :suspended, :to => :pending, :guard => :has_activation_code?
175
+ transitions :from => :suspended, :to => :passive
176
+ end
177
+
178
+ event :right_wait do
179
+ transitions :from => :suspended, :to => :waiting, :guard => :if_polite?
180
+ end
181
+ end # right
182
+
183
+ def initialize
184
+ # the AR backend uses a before_validate_on_create :aasm_ensure_initial_state
185
+ # lets do something similar here for testing purposes.
186
+ aasm(:left).enter_initial_state
187
+ aasm(:right).enter_initial_state
188
+ end
189
+
190
+ def make_activation_code
191
+ @activation_code = @activation_code ? @activation_code + '2' : '1'
192
+ end
193
+
194
+ def do_activate
195
+ @activated_at = Time.now
196
+ @activation_code = nil
197
+ end
198
+
199
+ def do_delete
200
+ @deleted_at = Time.now
201
+ end
202
+
203
+ def do_undelete
204
+ @deleted_at = false
205
+ end
206
+
207
+ def can_register?
208
+ true
209
+ end
210
+
211
+ def has_activated?
212
+ !!@activated_at
213
+ end
214
+
215
+ def has_activation_code?
216
+ !!@activation_code
217
+ end
218
+
219
+ def if_polite?(phrase = nil)
220
+ phrase == :please
221
+ end
222
+ end
@@ -34,8 +34,8 @@ class Conversation
34
34
  @persister = persister
35
35
  end
36
36
 
37
-
38
37
  private
38
+
39
39
  def aasm_read_state
40
40
  @persister.read_state
41
41
  end
@@ -43,5 +43,51 @@ class Conversation
43
43
  def aasm_write_state(state)
44
44
  @persister.write_state(state)
45
45
  end
46
+ end
47
+
48
+ class ConversationMultiple
49
+ include AASM
50
+
51
+ aasm(:left) do
52
+ state :needs_attention, :initial => true
53
+ state :read
54
+ state :closed
55
+ state :awaiting_response
56
+ state :junk
57
+
58
+ event :new_message do
59
+ end
60
+
61
+ event :view do
62
+ transitions :to => :read, :from => [:needs_attention]
63
+ end
64
+
65
+ event :reply do
66
+ end
67
+
68
+ event :close do
69
+ transitions :to => :closed, :from => [:read, :awaiting_response]
70
+ end
71
+
72
+ event :junk do
73
+ transitions :to => :junk, :from => [:read]
74
+ end
75
+
76
+ event :unjunk do
77
+ end
78
+ end
46
79
 
80
+ def initialize(persister)
81
+ @persister = persister
82
+ end
83
+
84
+ private
85
+
86
+ def aasm_read_state
87
+ @persister.read_state
88
+ end
89
+
90
+ def aasm_write_state(state)
91
+ @persister.write_state(state)
92
+ end
47
93
  end
@@ -33,3 +33,60 @@ class FooTwo < Foo
33
33
  state :foo
34
34
  end
35
35
  end
36
+
37
+ class FooMultiple
38
+ include AASM
39
+
40
+ aasm(:left) do
41
+ state :open, :initial => true, :before_exit => :before_exit
42
+ state :closed, :before_enter => :before_enter
43
+ state :final
44
+
45
+ event :close, :success => :success_callback do
46
+ transitions :from => [:open], :to => [:closed]
47
+ end
48
+
49
+ event :null do
50
+ transitions :from => [:open], :to => [:closed, :final], :guard => :always_false
51
+ end
52
+ end
53
+
54
+ aasm(:right, :column => :right) do
55
+ state :green, :initial => true
56
+ state :yellow
57
+ state :red
58
+
59
+ event :green do
60
+ transitions :from => [:yellow], :to => :green
61
+ end
62
+ event :yellow do
63
+ transitions :from => [:green, :red], :to => :yellow
64
+ end
65
+ event :red do
66
+ transitions :from => [:yellow], :to => :red
67
+ end
68
+ end
69
+
70
+ def always_false
71
+ false
72
+ end
73
+
74
+ def success_callback
75
+ end
76
+
77
+ def before_enter
78
+ end
79
+ def before_exit
80
+ end
81
+ end
82
+
83
+ class FooTwoMultiple < FooMultiple
84
+ include AASM
85
+ aasm(:left) do
86
+ state :foo
87
+ end
88
+
89
+ aasm(:right) do
90
+ state :bar
91
+ end
92
+ end
@@ -0,0 +1,45 @@
1
+ class FooCallbackMultiple
2
+ include AASM
3
+
4
+ aasm(:left) do
5
+ state :open, :initial => true, :before_exit => :before_exit
6
+ state :closed, :before_enter => :before_enter
7
+ state :final
8
+
9
+ event :close, :success => :success_callback do
10
+ transitions :from => [:open], :to => [:closed]
11
+ end
12
+
13
+ event :null do
14
+ transitions :from => [:open], :to => [:closed, :final], :guard => :always_false
15
+ end
16
+ end
17
+
18
+ aasm(:right, :column => :right) do
19
+ state :green, :initial => true
20
+ state :yellow
21
+ state :red
22
+
23
+ event :green do
24
+ transitions :from => [:yellow], :to => :green
25
+ end
26
+ event :yellow do
27
+ transitions :from => [:green, :red], :to => :yellow
28
+ end
29
+ event :red do
30
+ transitions :from => [:yellow], :to => :red
31
+ end
32
+ end
33
+
34
+ def always_false
35
+ false
36
+ end
37
+
38
+ def success_callback
39
+ end
40
+
41
+ def before_enter
42
+ end
43
+ def before_exit
44
+ end
45
+ end
@@ -0,0 +1,48 @@
1
+ class GuardianMultiple
2
+ include AASM
3
+
4
+ aasm(:left) do
5
+ state :alpha, :initial => true
6
+ state :beta
7
+
8
+ event :use_one_guard_that_succeeds do
9
+ transitions :from => :alpha, :to => :beta, :guard => :succeed
10
+ end
11
+ event :use_one_guard_that_fails do
12
+ transitions :from => :alpha, :to => :beta, :guard => :fail
13
+ end
14
+
15
+ event :use_guards_that_succeed do
16
+ transitions :from => :alpha, :to => :beta, :guards => [:succeed, :another_succeed]
17
+ end
18
+ event :use_guards_where_the_first_fails do
19
+ transitions :from => :alpha, :to => :beta, :guards => [:succeed, :fail]
20
+ end
21
+ event :use_guards_where_the_second_fails do
22
+ transitions :from => :alpha, :to => :beta, :guards => [:fail, :succeed]
23
+ end
24
+
25
+ event :use_event_guards_that_succeed, :guards => [:succeed, :another_succeed] do
26
+ transitions :from => :alpha, :to => :beta
27
+ end
28
+ event :use_event_and_transition_guards_that_succeed, :guards => [:succeed, :another_succeed] do
29
+ transitions :from => :alpha, :to => :beta, :guards => [:more_succeed]
30
+ end
31
+ event :use_event_guards_where_the_first_fails, :guards => [:succeed, :fail] do
32
+ transitions :from => :alpha, :to => :beta
33
+ end
34
+ event :use_event_guards_where_the_second_fails, :guards => [:fail, :succeed] do
35
+ transitions :from => :alpha, :to => :beta, :guard => :another_succeed
36
+ end
37
+ event :use_event_and_transition_guards_where_third_fails, :guards => [:succeed, :another_succeed] do
38
+ transitions :from => :alpha, :to => :beta, :guards => [:fail]
39
+ end
40
+ end
41
+
42
+ def fail; false; end
43
+
44
+ def succeed; true; end
45
+ def another_succeed; true; end
46
+ def more_succeed; true; end
47
+
48
+ end
@@ -13,3 +13,19 @@ class InitialStateProc
13
13
  def initialize(balance = 0); self.balance = balance; end
14
14
  def rich?; self.balance >= RICH; end
15
15
  end
16
+
17
+ class InitialStateProcMultiple
18
+ RICH = 1_000_000
19
+
20
+ attr_accessor :balance
21
+
22
+ include AASM
23
+ aasm(:left) do
24
+ state :retired
25
+ state :selling_bad_mortgages
26
+ initial_state Proc.new { |banker| banker.rich? ? :retired : :selling_bad_mortgages }
27
+ end
28
+
29
+ def initialize(balance = 0); self.balance = balance; end
30
+ def rich?; self.balance >= RICH; end
31
+ end
@@ -14,3 +14,18 @@ class InvalidPersistor < ActiveRecord::Base
14
14
  end
15
15
  validates_presence_of :name
16
16
  end
17
+
18
+ class MultipleInvalidPersistor < ActiveRecord::Base
19
+ include AASM
20
+ aasm :left, :column => :status, :skip_validation_on_save => true do
21
+ state :sleeping, :initial => true
22
+ state :running
23
+ event :run do
24
+ transitions :to => :running, :from => :sleeping
25
+ end
26
+ event :sleep do
27
+ transitions :to => :sleeping, :from => :running
28
+ end
29
+ end
30
+ validates_presence_of :name
31
+ end
@@ -0,0 +1,37 @@
1
+ class ComplexMongoMapperExample
2
+ include MongoMapper::Document
3
+ include AASM
4
+
5
+ key :left, String
6
+ key :right, String
7
+
8
+ aasm :left, :column => 'left' do
9
+ state :one, :initial => true
10
+ state :two
11
+ state :three
12
+
13
+ event :increment do
14
+ transitions :from => :one, :to => :two
15
+ transitions :from => :two, :to => :three
16
+ end
17
+ event :reset do
18
+ transitions :from => :three, :to => :one
19
+ end
20
+ end
21
+
22
+ aasm :right, :column => 'right' do
23
+ state :alpha, :initial => true
24
+ state :beta
25
+ state :gamma
26
+
27
+ event :level_up do
28
+ transitions :from => :alpha, :to => :beta
29
+ transitions :from => :beta, :to => :gamma
30
+ end
31
+ event :level_down do
32
+ transitions :from => :gamma, :to => :beta
33
+ transitions :from => :beta, :to => :alpha
34
+ end
35
+ end
36
+
37
+ end
@@ -8,3 +8,14 @@ class NoScopeMongoMapper
8
8
  state :ignored_scope
9
9
  end
10
10
  end
11
+
12
+ class NoScopeMongoMapperMultiple
13
+ include MongoMapper::Document
14
+ include AASM
15
+
16
+ key :status, String
17
+
18
+ aasm :left, :create_scopes => false, :column => :status do
19
+ state :ignored_scope
20
+ end
21
+ end