aasm 4.5.1 → 5.5.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 (186) hide show
  1. checksums.yaml +5 -5
  2. data/LICENSE +1 -1
  3. data/README.md +809 -129
  4. data/lib/aasm/aasm.rb +74 -37
  5. data/lib/aasm/base.rb +188 -41
  6. data/lib/aasm/configuration.rb +27 -2
  7. data/lib/aasm/core/event.rb +75 -47
  8. data/lib/aasm/core/invoker.rb +129 -0
  9. data/lib/aasm/core/invokers/base_invoker.rb +75 -0
  10. data/lib/aasm/core/invokers/class_invoker.rb +52 -0
  11. data/lib/aasm/core/invokers/literal_invoker.rb +49 -0
  12. data/lib/aasm/core/invokers/proc_invoker.rb +59 -0
  13. data/lib/aasm/core/state.rb +22 -13
  14. data/lib/aasm/core/transition.rb +30 -23
  15. data/lib/aasm/dsl_helper.rb +24 -22
  16. data/lib/aasm/errors.rb +8 -5
  17. data/lib/aasm/instance_base.rb +63 -15
  18. data/lib/aasm/localizer.rb +13 -3
  19. data/lib/aasm/minitest/allow_event.rb +13 -0
  20. data/lib/aasm/minitest/allow_transition_to.rb +13 -0
  21. data/lib/aasm/minitest/have_state.rb +13 -0
  22. data/lib/aasm/minitest/transition_from.rb +21 -0
  23. data/lib/aasm/minitest.rb +5 -0
  24. data/lib/aasm/minitest_spec.rb +15 -0
  25. data/lib/aasm/persistence/active_record_persistence.rb +87 -79
  26. data/lib/aasm/persistence/base.rb +30 -30
  27. data/lib/aasm/persistence/core_data_query_persistence.rb +94 -0
  28. data/lib/aasm/persistence/dynamoid_persistence.rb +92 -0
  29. data/lib/aasm/persistence/mongoid_persistence.rb +49 -35
  30. data/lib/aasm/persistence/no_brainer_persistence.rb +105 -0
  31. data/lib/aasm/persistence/orm.rb +154 -0
  32. data/lib/aasm/persistence/plain_persistence.rb +2 -1
  33. data/lib/aasm/persistence/redis_persistence.rb +112 -0
  34. data/lib/aasm/persistence/sequel_persistence.rb +37 -67
  35. data/lib/aasm/persistence.rb +20 -5
  36. data/lib/aasm/rspec/allow_event.rb +5 -1
  37. data/lib/aasm/rspec/allow_transition_to.rb +5 -1
  38. data/lib/aasm/rspec/transition_from.rb +8 -4
  39. data/lib/aasm/state_machine.rb +6 -12
  40. data/lib/aasm/state_machine_store.rb +76 -0
  41. data/lib/aasm/version.rb +1 -1
  42. data/lib/aasm.rb +8 -2
  43. data/lib/generators/aasm/aasm_generator.rb +16 -0
  44. data/lib/generators/aasm/orm_helpers.rb +41 -0
  45. data/lib/generators/active_record/aasm_generator.rb +40 -0
  46. data/lib/generators/active_record/templates/migration.rb +8 -0
  47. data/lib/generators/active_record/templates/migration_existing.rb +5 -0
  48. data/lib/generators/mongoid/aasm_generator.rb +28 -0
  49. data/lib/generators/nobrainer/aasm_generator.rb +28 -0
  50. data/lib/motion-aasm.rb +37 -0
  51. metadata +104 -259
  52. data/.document +0 -6
  53. data/.gitignore +0 -19
  54. data/.travis.yml +0 -37
  55. data/API +0 -34
  56. data/CHANGELOG.md +0 -272
  57. data/CODE_OF_CONDUCT.md +0 -13
  58. data/Gemfile +0 -15
  59. data/HOWTO +0 -12
  60. data/PLANNED_CHANGES.md +0 -11
  61. data/README_FROM_VERSION_3_TO_4.md +0 -240
  62. data/Rakefile +0 -26
  63. data/aasm.gemspec +0 -31
  64. data/callbacks.txt +0 -51
  65. data/gemfiles/rails_3.2.gemfile +0 -14
  66. data/gemfiles/rails_4.0.gemfile +0 -12
  67. data/gemfiles/rails_4.0_mongo_mapper.gemfile +0 -14
  68. data/gemfiles/rails_4.1.gemfile +0 -12
  69. data/gemfiles/rails_4.1_mongo_mapper.gemfile +0 -14
  70. data/gemfiles/rails_4.2.gemfile +0 -12
  71. data/gemfiles/rails_4.2_mongo_mapper.gemfile +0 -14
  72. data/gemfiles/rails_4.2_mongoid_5.gemfile +0 -12
  73. data/lib/aasm/persistence/mongo_mapper_persistence.rb +0 -157
  74. data/spec/database.rb +0 -63
  75. data/spec/database.yml +0 -3
  76. data/spec/en.yml +0 -9
  77. data/spec/en_deprecated_style.yml +0 -10
  78. data/spec/models/active_record/basic_active_record_two_state_machines_example.rb +0 -25
  79. data/spec/models/active_record/complex_active_record_example.rb +0 -33
  80. data/spec/models/active_record/derivate_new_dsl.rb +0 -7
  81. data/spec/models/active_record/false_state.rb +0 -35
  82. data/spec/models/active_record/gate.rb +0 -39
  83. data/spec/models/active_record/localizer_test_model.rb +0 -34
  84. data/spec/models/active_record/no_direct_assignment.rb +0 -21
  85. data/spec/models/active_record/no_scope.rb +0 -21
  86. data/spec/models/active_record/persisted_state.rb +0 -12
  87. data/spec/models/active_record/provided_and_persisted_state.rb +0 -24
  88. data/spec/models/active_record/reader.rb +0 -7
  89. data/spec/models/active_record/readme_job.rb +0 -21
  90. data/spec/models/active_record/simple_new_dsl.rb +0 -17
  91. data/spec/models/active_record/thief.rb +0 -29
  92. data/spec/models/active_record/transient.rb +0 -6
  93. data/spec/models/active_record/with_enum.rb +0 -39
  94. data/spec/models/active_record/with_false_enum.rb +0 -31
  95. data/spec/models/active_record/with_true_enum.rb +0 -39
  96. data/spec/models/active_record/writer.rb +0 -6
  97. data/spec/models/basic_two_state_machines_example.rb +0 -25
  98. data/spec/models/callbacks/basic.rb +0 -78
  99. data/spec/models/callbacks/basic_multiple.rb +0 -75
  100. data/spec/models/callbacks/guard_within_block.rb +0 -66
  101. data/spec/models/callbacks/guard_within_block_multiple.rb +0 -66
  102. data/spec/models/callbacks/multiple_transitions_transition_guard.rb +0 -65
  103. data/spec/models/callbacks/multiple_transitions_transition_guard_multiple.rb +0 -65
  104. data/spec/models/callbacks/private_method.rb +0 -44
  105. data/spec/models/callbacks/private_method_multiple.rb +0 -44
  106. data/spec/models/callbacks/with_args.rb +0 -61
  107. data/spec/models/callbacks/with_args_multiple.rb +0 -61
  108. data/spec/models/callbacks/with_state_arg.rb +0 -26
  109. data/spec/models/callbacks/with_state_arg_multiple.rb +0 -26
  110. data/spec/models/complex_example.rb +0 -222
  111. data/spec/models/conversation.rb +0 -93
  112. data/spec/models/default_state.rb +0 -12
  113. data/spec/models/double_definer.rb +0 -21
  114. data/spec/models/foo.rb +0 -92
  115. data/spec/models/foo_callback_multiple.rb +0 -45
  116. data/spec/models/guardian.rb +0 -48
  117. data/spec/models/guardian_multiple.rb +0 -48
  118. data/spec/models/initial_state_proc.rb +0 -31
  119. data/spec/models/invalid_persistor.rb +0 -31
  120. data/spec/models/mongo_mapper/complex_mongo_mapper_example.rb +0 -37
  121. data/spec/models/mongo_mapper/no_scope_mongo_mapper.rb +0 -21
  122. data/spec/models/mongo_mapper/simple_mongo_mapper.rb +0 -23
  123. data/spec/models/mongo_mapper/simple_new_dsl_mongo_mapper.rb +0 -25
  124. data/spec/models/mongoid/complex_mongoid_example.rb +0 -37
  125. data/spec/models/mongoid/no_scope_mongoid.rb +0 -21
  126. data/spec/models/mongoid/simple_mongoid.rb +0 -23
  127. data/spec/models/mongoid/simple_new_dsl_mongoid.rb +0 -25
  128. data/spec/models/no_initial_state.rb +0 -25
  129. data/spec/models/not_auto_loaded/process.rb +0 -21
  130. data/spec/models/parametrised_event.rb +0 -29
  131. data/spec/models/parametrised_event_multiple.rb +0 -29
  132. data/spec/models/process_with_new_dsl.rb +0 -31
  133. data/spec/models/provided_state.rb +0 -24
  134. data/spec/models/sequel/complex_sequel_example.rb +0 -45
  135. data/spec/models/sequel/sequel_multiple.rb +0 -25
  136. data/spec/models/sequel/sequel_simple.rb +0 -25
  137. data/spec/models/silencer.rb +0 -27
  138. data/spec/models/simple_example.rb +0 -15
  139. data/spec/models/simple_multiple_example.rb +0 -30
  140. data/spec/models/state_machine_with_failed_event.rb +0 -12
  141. data/spec/models/sub_class.rb +0 -7
  142. data/spec/models/sub_class_with_more_states.rb +0 -18
  143. data/spec/models/sub_classing.rb +0 -3
  144. data/spec/models/super_class.rb +0 -46
  145. data/spec/models/this_name_better_not_be_in_use.rb +0 -11
  146. data/spec/models/transactor.rb +0 -53
  147. data/spec/models/valid_state_name.rb +0 -23
  148. data/spec/models/validator.rb +0 -79
  149. data/spec/models/worker.rb +0 -2
  150. data/spec/spec_helper.rb +0 -25
  151. data/spec/unit/api_spec.rb +0 -77
  152. data/spec/unit/basic_two_state_machines_example_spec.rb +0 -10
  153. data/spec/unit/callback_multiple_spec.rb +0 -295
  154. data/spec/unit/callbacks_spec.rb +0 -296
  155. data/spec/unit/complex_example_spec.rb +0 -84
  156. data/spec/unit/complex_multiple_example_spec.rb +0 -99
  157. data/spec/unit/edge_cases_spec.rb +0 -16
  158. data/spec/unit/event_multiple_spec.rb +0 -73
  159. data/spec/unit/event_naming_spec.rb +0 -11
  160. data/spec/unit/event_spec.rb +0 -322
  161. data/spec/unit/guard_multiple_spec.rb +0 -60
  162. data/spec/unit/guard_spec.rb +0 -60
  163. data/spec/unit/initial_state_multiple_spec.rb +0 -15
  164. data/spec/unit/initial_state_spec.rb +0 -12
  165. data/spec/unit/inspection_multiple_spec.rb +0 -201
  166. data/spec/unit/inspection_spec.rb +0 -111
  167. data/spec/unit/localizer_spec.rb +0 -76
  168. data/spec/unit/memory_leak_spec.rb +0 -38
  169. data/spec/unit/new_dsl_spec.rb +0 -12
  170. data/spec/unit/persistence/active_record_persistence_multiple_spec.rb +0 -573
  171. data/spec/unit/persistence/active_record_persistence_spec.rb +0 -552
  172. data/spec/unit/persistence/mongo_mapper_persistence_multiple_spec.rb +0 -146
  173. data/spec/unit/persistence/mongo_mapper_persistence_spec.rb +0 -93
  174. data/spec/unit/persistence/mongoid_persistence_multiple_spec.rb +0 -127
  175. data/spec/unit/persistence/mongoid_persistence_spec.rb +0 -79
  176. data/spec/unit/persistence/sequel_persistence_multiple_spec.rb +0 -153
  177. data/spec/unit/persistence/sequel_persistence_spec.rb +0 -100
  178. data/spec/unit/readme_spec.rb +0 -42
  179. data/spec/unit/reloading_spec.rb +0 -15
  180. data/spec/unit/rspec_matcher_spec.rb +0 -79
  181. data/spec/unit/simple_example_spec.rb +0 -42
  182. data/spec/unit/simple_multiple_example_spec.rb +0 -63
  183. data/spec/unit/state_spec.rb +0 -89
  184. data/spec/unit/subclassing_multiple_spec.rb +0 -39
  185. data/spec/unit/subclassing_spec.rb +0 -31
  186. data/spec/unit/transition_spec.rb +0 -291
@@ -1,573 +0,0 @@
1
- require 'active_record'
2
- require 'spec_helper'
3
- Dir[File.dirname(__FILE__) + "/../../models/active_record/*.rb"].sort.each do |f|
4
- require File.expand_path(f)
5
- end
6
-
7
- load_schema
8
-
9
- # if you want to see the statements while running the spec enable the following line
10
- # require 'logger'
11
- # ActiveRecord::Base.logger = Logger.new(STDERR)
12
-
13
- describe "instance methods" do
14
- let(:gate) {MultipleGate.new}
15
-
16
- it "should respond to aasm persistence methods" do
17
- expect(gate).to respond_to(:aasm_read_state)
18
- expect(gate).to respond_to(:aasm_write_state)
19
- expect(gate).to respond_to(:aasm_write_state_without_persistence)
20
- end
21
-
22
- describe "aasm_column_looks_like_enum" do
23
- subject { lambda{ gate.send(:aasm_column_looks_like_enum, :left) } }
24
-
25
- let(:column_name) { "value" }
26
- let(:columns_hash) { Hash[column_name, column] }
27
-
28
- before :each do
29
- allow(gate.class.aasm(:left)).to receive(:attribute_name).and_return(column_name.to_sym)
30
- allow(gate.class).to receive(:columns_hash).and_return(columns_hash)
31
- end
32
-
33
- context "when AASM column has integer type" do
34
- let(:column) { double(Object, type: :integer) }
35
-
36
- it "returns true" do
37
- expect(subject.call).to be_truthy
38
- end
39
- end
40
-
41
- context "when AASM column has string type" do
42
- let(:column) { double(Object, type: :string) }
43
-
44
- it "returns false" do
45
- expect(subject.call).to be_falsey
46
- end
47
- end
48
- end
49
-
50
- describe "aasm_guess_enum_method" do
51
- subject { lambda{ gate.send(:aasm_guess_enum_method, :left) } }
52
-
53
- before :each do
54
- allow(gate.class.aasm(:left)).to receive(:attribute_name).and_return(:value)
55
- end
56
-
57
- it "pluralizes AASM column name" do
58
- expect(subject.call).to eq :values
59
- end
60
- end
61
-
62
- describe "aasm_enum" do
63
- context "when AASM enum setting contains an explicit enum method name" do
64
- let(:with_enum) { MultipleWithEnum.new }
65
-
66
- it "returns whatever value was set in AASM config" do
67
- expect(with_enum.send(:aasm_enum, :left)).to eq :test
68
- end
69
- end
70
-
71
- context "when AASM enum setting is simply set to true" do
72
- let(:with_true_enum) { MultipleWithTrueEnum.new }
73
- before :each do
74
- allow(MultipleWithTrueEnum.aasm(:left)).to receive(:attribute_name).and_return(:value)
75
- end
76
-
77
- it "infers enum method name from pluralized column name" do
78
- expect(with_true_enum.send(:aasm_enum, :left)).to eq :values
79
- end
80
- end
81
-
82
- context "when AASM enum setting is explicitly disabled" do
83
- let(:with_false_enum) { MultipleWithFalseEnum.new }
84
-
85
- it "returns nil" do
86
- expect(with_false_enum.send(:aasm_enum, :left)).to be_nil
87
- end
88
- end
89
-
90
- context "when AASM enum setting is not enabled" do
91
- before :each do
92
- allow(MultipleGate.aasm(:left)).to receive(:attribute_name).and_return(:value)
93
- end
94
-
95
- context "when AASM column looks like enum" do
96
- before :each do
97
- allow(gate).to receive(:aasm_column_looks_like_enum).with(:left).and_return(true)
98
- end
99
-
100
- it "infers enum method name from pluralized column name" do
101
- expect(gate.send(:aasm_enum, :left)).to eq :values
102
- end
103
- end
104
-
105
- context "when AASM column doesn't look like enum'" do
106
- before :each do
107
- allow(gate).to receive(:aasm_column_looks_like_enum)
108
- .and_return(false)
109
- end
110
-
111
- it "returns nil, as we're not using enum" do
112
- expect(gate.send(:aasm_enum, :left)).to be_nil
113
- end
114
- end
115
- end
116
- end
117
-
118
- context "when AASM is configured to use enum" do
119
- let(:state_sym) { :running }
120
- let(:state_code) { 2 }
121
- let(:enum_name) { :states }
122
- let(:enum) { Hash[state_sym, state_code] }
123
-
124
- before :each do
125
- allow(gate).to receive(:aasm_enum).and_return(enum_name)
126
- allow(gate).to receive(:aasm_write_attribute)
127
- allow(gate).to receive(:write_attribute)
128
-
129
- allow(MultipleGate).to receive(enum_name).and_return(enum)
130
- end
131
-
132
- describe "aasm_write_state" do
133
- context "when AASM is configured to skip validations on save" do
134
- before :each do
135
- allow(gate).to receive(:aasm_skipping_validations).and_return(true)
136
- end
137
-
138
- it "passes state code instead of state symbol to update_all" do
139
- # stub_chain does not allow us to give expectations on call
140
- # parameters in the middle of the chain, so we need to use
141
- # intermediate object instead.
142
- obj = double(Object, update_all: 1)
143
- allow(MultipleGate).to receive(:where).and_return(obj)
144
-
145
- gate.aasm_write_state state_sym, :left
146
-
147
- expect(obj).to have_received(:update_all)
148
- .with(Hash[gate.class.aasm(:left).attribute_name, state_code])
149
- end
150
- end
151
-
152
- context "when AASM is not skipping validations" do
153
- it "delegates state update to the helper method" do
154
- # Let's pretend that validation is passed
155
- allow(gate).to receive(:save).and_return(true)
156
-
157
- gate.aasm_write_state state_sym, :left
158
-
159
- expect(gate).to have_received(:aasm_write_attribute).with(state_sym, :left)
160
- expect(gate).to_not have_received :write_attribute
161
- end
162
- end
163
- end
164
-
165
- describe "aasm_write_state_without_persistence" do
166
- it "delegates state update to the helper method" do
167
- gate.aasm_write_state_without_persistence state_sym, :left
168
-
169
- expect(gate).to have_received(:aasm_write_attribute).with(state_sym, :left)
170
- expect(gate).to_not have_received :write_attribute
171
- end
172
- end
173
-
174
- describe "aasm_raw_attribute_value" do
175
- it "converts state symbol to state code" do
176
- expect(gate.send(:aasm_raw_attribute_value, state_sym))
177
- .to eq state_code
178
- end
179
- end
180
- end
181
-
182
- context "when AASM is configured to use string field" do
183
- let(:state_sym) { :running }
184
-
185
- before :each do
186
- allow(gate).to receive(:aasm_enum).and_return(nil)
187
- end
188
-
189
- describe "aasm_raw_attribute_value" do
190
- it "converts state symbol to string" do
191
- expect(gate.send(:aasm_raw_attribute_value, state_sym))
192
- .to eq state_sym.to_s
193
- end
194
- end
195
- end
196
-
197
- describe "aasm_write_attribute helper method" do
198
- let(:sym) { :sym }
199
- let(:value) { 42 }
200
-
201
- before :each do
202
- allow(gate).to receive(:write_attribute)
203
- allow(gate).to receive(:aasm_raw_attribute_value).and_return(value)
204
-
205
- gate.send(:aasm_write_attribute, sym, :left)
206
- end
207
-
208
- it "generates attribute value using a helper method" do
209
- expect(gate).to have_received(:aasm_raw_attribute_value).with(sym, :left)
210
- end
211
-
212
- it "writes attribute to the model" do
213
- expect(gate).to have_received(:write_attribute).with(:aasm_state, value)
214
- end
215
- end
216
-
217
- it "should return the initial state when new and the aasm field is nil" do
218
- expect(gate.aasm(:left).current_state).to eq(:opened)
219
- end
220
-
221
- it "should return the aasm column when new and the aasm field is not nil" do
222
- gate.aasm_state = "closed"
223
- expect(gate.aasm(:left).current_state).to eq(:closed)
224
- end
225
-
226
- it "should return the aasm column when not new and the aasm.attribute_name is not nil" do
227
- allow(gate).to receive(:new_record?).and_return(false)
228
- gate.aasm_state = "state"
229
- expect(gate.aasm(:left).current_state).to eq(:state)
230
- end
231
-
232
- it "should allow a nil state" do
233
- allow(gate).to receive(:new_record?).and_return(false)
234
- gate.aasm_state = nil
235
- expect(gate.aasm(:left).current_state).to be_nil
236
- end
237
-
238
- context 'on initialization' do
239
- it "should initialize the aasm state" do
240
- expect(MultipleGate.new.aasm_state).to eql 'opened'
241
- expect(MultipleGate.new.aasm(:left).current_state).to eql :opened
242
- end
243
-
244
- it "should not initialize the aasm state if it has not been loaded" do
245
- # we have to create a gate in the database, for which we only want to
246
- # load the id, and not the state
247
- gate = MultipleGate.create!
248
-
249
- # then we just load the gate ids
250
- MultipleGate.select(:id).where(id: gate.id).first
251
- end
252
- end
253
-
254
- end
255
-
256
- if ActiveRecord::VERSION::MAJOR < 4 && ActiveRecord::VERSION::MINOR < 2 # won't work with Rails >= 4.2
257
- describe "direct state column access" do
258
- it "accepts false states" do
259
- f = MultipleFalseState.create!
260
- expect(f.aasm_state).to eql false
261
- expect {
262
- f.aasm(:left).events.map(&:name)
263
- }.to_not raise_error
264
- end
265
- end
266
- end
267
-
268
- describe 'subclasses' do
269
- it "should have the same states as its parent class" do
270
- expect(MultipleDerivateNewDsl.aasm(:left).states).to eq(MultipleSimpleNewDsl.aasm(:left).states)
271
- end
272
-
273
- it "should have the same events as its parent class" do
274
- expect(MultipleDerivateNewDsl.aasm(:left).events).to eq(MultipleSimpleNewDsl.aasm(:left).events)
275
- end
276
-
277
- it "should have the same column as its parent even for the new dsl" do
278
- expect(MultipleSimpleNewDsl.aasm(:left).attribute_name).to eq(:status)
279
- expect(MultipleDerivateNewDsl.aasm(:left).attribute_name).to eq(:status)
280
- end
281
- end
282
-
283
- describe "named scopes with the new DSL" do
284
- context "Does not already respond_to? the scope name" do
285
- it "should add a scope" do
286
- expect(MultipleSimpleNewDsl).to respond_to(:unknown_scope)
287
- expect(MultipleSimpleNewDsl.unknown_scope.is_a?(ActiveRecord::Relation)).to be_truthy
288
- end
289
- end
290
-
291
- context "Already respond_to? the scope name" do
292
- it "should not add a scope" do
293
- expect(MultipleSimpleNewDsl).to respond_to(:new)
294
- expect(MultipleSimpleNewDsl.new.class).to eq(MultipleSimpleNewDsl)
295
- end
296
- end
297
-
298
- it "does not create scopes if requested" do
299
- expect(MultipleNoScope).not_to respond_to(:pending)
300
- end
301
-
302
- context "result of scope" do
303
- let!(:dsl1) { MultipleSimpleNewDsl.create!(status: :new) }
304
- let!(:dsl2) { MultipleSimpleNewDsl.create!(status: :unknown_scope) }
305
-
306
- after do
307
- MultipleSimpleNewDsl.destroy_all
308
- end
309
-
310
- it "created scope works as where(name: :scope_name)" do
311
- expect(MultipleSimpleNewDsl.unknown_scope).to contain_exactly(dsl2)
312
- end
313
- end
314
- end # scopes
315
-
316
- describe "direct assignment" do
317
- it "is allowed by default" do
318
- obj = MultipleNoScope.create
319
- expect(obj.aasm_state.to_sym).to eql :pending
320
-
321
- obj.aasm_state = :running
322
- expect(obj.aasm_state.to_sym).to eql :running
323
- end
324
-
325
- it "is forbidden if configured" do
326
- obj = MultipleNoDirectAssignment.create
327
- expect(obj.aasm_state.to_sym).to eql :pending
328
-
329
- expect {obj.aasm_state = :running}.to raise_error(AASM::NoDirectAssignmentError)
330
- expect(obj.aasm_state.to_sym).to eql :pending
331
- end
332
-
333
- it 'can be turned off and on again' do
334
- obj = MultipleNoDirectAssignment.create
335
- expect(obj.aasm_state.to_sym).to eql :pending
336
-
337
- expect {obj.aasm_state = :running}.to raise_error(AASM::NoDirectAssignmentError)
338
- expect(obj.aasm_state.to_sym).to eql :pending
339
-
340
- # allow it temporarily
341
- MultipleNoDirectAssignment.aasm(:left).state_machine.config.no_direct_assignment = false
342
- obj.aasm_state = :pending
343
- expect(obj.aasm_state.to_sym).to eql :pending
344
-
345
- # and forbid it again
346
- MultipleNoDirectAssignment.aasm(:left).state_machine.config.no_direct_assignment = true
347
- expect {obj.aasm_state = :running}.to raise_error(AASM::NoDirectAssignmentError)
348
- expect(obj.aasm_state.to_sym).to eql :pending
349
- end
350
- end # direct assignment
351
-
352
- describe 'initial states' do
353
- it 'should support conditions' do
354
- expect(MultipleThief.new(:skilled => true).aasm(:left).current_state).to eq(:rich)
355
- expect(MultipleThief.new(:skilled => false).aasm(:left).current_state).to eq(:jailed)
356
- end
357
- end
358
-
359
- describe 'transitions with persistence' do
360
-
361
- it "should work for valid models" do
362
- valid_object = MultipleValidator.create(:name => 'name')
363
- expect(valid_object).to be_sleeping
364
- valid_object.status = :running
365
- expect(valid_object).to be_running
366
- end
367
-
368
- it 'should not store states for invalid models' do
369
- validator = MultipleValidator.create(:name => 'name')
370
- expect(validator).to be_valid
371
- expect(validator).to be_sleeping
372
-
373
- validator.name = nil
374
- expect(validator).not_to be_valid
375
- expect(validator.run!).to be_falsey
376
- expect(validator).to be_sleeping
377
-
378
- validator.reload
379
- expect(validator).not_to be_running
380
- expect(validator).to be_sleeping
381
-
382
- validator.name = 'another name'
383
- expect(validator).to be_valid
384
- expect(validator.run!).to be_truthy
385
- expect(validator).to be_running
386
-
387
- validator.reload
388
- expect(validator).to be_running
389
- expect(validator).not_to be_sleeping
390
- end
391
-
392
- it 'should store states for invalid models if configured' do
393
- persistor = MultipleInvalidPersistor.create(:name => 'name')
394
- expect(persistor).to be_valid
395
- expect(persistor).to be_sleeping
396
-
397
- persistor.name = nil
398
- expect(persistor).not_to be_valid
399
- expect(persistor.run!).to be_truthy
400
- expect(persistor).to be_running
401
-
402
- persistor = MultipleInvalidPersistor.find(persistor.id)
403
- persistor.valid?
404
- expect(persistor).to be_valid
405
- expect(persistor).to be_running
406
- expect(persistor).not_to be_sleeping
407
-
408
- persistor.reload
409
- expect(persistor).to be_running
410
- expect(persistor).not_to be_sleeping
411
- end
412
-
413
- describe 'transactions' do
414
- let(:worker) { Worker.create!(:name => 'worker', :status => 'sleeping') }
415
- let(:transactor) { MultipleTransactor.create!(:name => 'transactor', :worker => worker) }
416
-
417
- it 'should rollback all changes' do
418
- expect(transactor).to be_sleeping
419
- expect(worker.status).to eq('sleeping')
420
-
421
- expect {transactor.run!}.to raise_error(StandardError, 'failed on purpose')
422
- expect(transactor).to be_running
423
- expect(worker.reload.status).to eq('sleeping')
424
- end
425
-
426
- context "nested transactions" do
427
- it "should rollback all changes in nested transaction" do
428
- expect(transactor).to be_sleeping
429
- expect(worker.status).to eq('sleeping')
430
-
431
- Worker.transaction do
432
- expect { transactor.run! }.to raise_error(StandardError, 'failed on purpose')
433
- end
434
-
435
- expect(transactor).to be_running
436
- expect(worker.reload.status).to eq('sleeping')
437
- end
438
-
439
- it "should only rollback changes in the main transaction not the nested one" do
440
- # change configuration to not require new transaction
441
- AASM::StateMachine[MultipleTransactor][:left].config.requires_new_transaction = false
442
-
443
- expect(transactor).to be_sleeping
444
- expect(worker.status).to eq('sleeping')
445
-
446
- Worker.transaction do
447
- expect { transactor.run! }.to raise_error(StandardError, 'failed on purpose')
448
- end
449
-
450
- expect(transactor).to be_running
451
- expect(worker.reload.status).to eq('running')
452
- end
453
- end
454
-
455
- describe "after_commit callback" do
456
- it "should fire :after_commit if transaction was successful" do
457
- validator = MultipleValidator.create(:name => 'name')
458
- expect(validator).to be_sleeping
459
-
460
- validator.run!
461
- expect(validator).to be_running
462
- expect(validator.name).to eq("name changed")
463
-
464
- validator.sleep!("sleeper")
465
- expect(validator).to be_sleeping
466
- expect(validator.name).to eq("sleeper")
467
- end
468
-
469
- it "should not fire :after_commit if transaction failed" do
470
- validator = MultipleValidator.create(:name => 'name')
471
- expect { validator.fail! }.to raise_error(StandardError, 'failed on purpose')
472
- expect(validator.name).to eq("name")
473
- end
474
-
475
- it "should not fire if not saving" do
476
- validator = MultipleValidator.create(:name => 'name')
477
- expect(validator).to be_sleeping
478
- validator.run
479
- expect(validator).to be_running
480
- expect(validator.name).to eq("name")
481
- end
482
-
483
- end
484
-
485
- context "when not persisting" do
486
- it 'should not rollback all changes' do
487
- expect(transactor).to be_sleeping
488
- expect(worker.status).to eq('sleeping')
489
-
490
- # Notice here we're calling "run" and not "run!" with a bang.
491
- expect {transactor.run}.to raise_error(StandardError, 'failed on purpose')
492
- expect(transactor).to be_running
493
- expect(worker.reload.status).to eq('running')
494
- end
495
-
496
- it 'should not create a database transaction' do
497
- expect(transactor.class).not_to receive(:transaction)
498
- expect {transactor.run}.to raise_error(StandardError, 'failed on purpose')
499
- end
500
- end
501
- end
502
- end
503
-
504
- describe "invalid states with persistence" do
505
- it "should not store states" do
506
- validator = MultipleValidator.create(:name => 'name')
507
- validator.status = 'invalid_state'
508
- expect(validator.save).to be_falsey
509
- expect {validator.save!}.to raise_error(ActiveRecord::RecordInvalid)
510
-
511
- validator.reload
512
- expect(validator).to be_sleeping
513
- end
514
-
515
- it "should store invalid states if configured" do
516
- persistor = MultipleInvalidPersistor.create(:name => 'name')
517
- persistor.status = 'invalid_state'
518
- expect(persistor.save).to be_truthy
519
-
520
- persistor.reload
521
- expect(persistor.status).to eq('invalid_state')
522
- end
523
- end
524
-
525
- describe "complex example" do
526
- it "works" do
527
- record = ComplexActiveRecordExample.new
528
- expect_aasm_states record, :one, :alpha
529
-
530
- record.save!
531
- expect_aasm_states record, :one, :alpha
532
- record.reload
533
- expect_aasm_states record, :one, :alpha
534
-
535
- record.increment!
536
- expect_aasm_states record, :two, :alpha
537
- record.reload
538
- expect_aasm_states record, :two, :alpha
539
-
540
- record.level_up!
541
- expect_aasm_states record, :two, :beta
542
- record.reload
543
- expect_aasm_states record, :two, :beta
544
-
545
- record.increment!
546
- expect { record.increment! }.to raise_error(AASM::InvalidTransition)
547
- expect_aasm_states record, :three, :beta
548
- record.reload
549
- expect_aasm_states record, :three, :beta
550
-
551
- record.level_up!
552
- expect_aasm_states record, :three, :gamma
553
- record.reload
554
- expect_aasm_states record, :three, :gamma
555
-
556
- record.level_down # without saving
557
- expect_aasm_states record, :three, :beta
558
- record.reload
559
- expect_aasm_states record, :three, :gamma
560
-
561
- record.level_down # without saving
562
- expect_aasm_states record, :three, :beta
563
- record.reset!
564
- expect_aasm_states record, :one, :beta
565
- end
566
-
567
- def expect_aasm_states(record, left_state, right_state)
568
- expect(record.aasm(:left).current_state).to eql left_state.to_sym
569
- expect(record.left).to eql left_state.to_s
570
- expect(record.aasm(:right).current_state).to eql right_state.to_sym
571
- expect(record.right).to eql right_state.to_s
572
- end
573
- end