aasm 4.12.2 → 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 (218) hide show
  1. checksums.yaml +5 -5
  2. data/LICENSE +1 -1
  3. data/README.md +393 -116
  4. data/lib/aasm/aasm.rb +30 -27
  5. data/lib/aasm/base.rb +64 -11
  6. data/lib/aasm/configuration.rb +6 -0
  7. data/lib/aasm/core/event.rb +26 -30
  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 +16 -14
  14. data/lib/aasm/core/transition.rb +8 -69
  15. data/lib/aasm/dsl_helper.rb +24 -22
  16. data/lib/aasm/errors.rb +5 -3
  17. data/lib/aasm/instance_base.rb +34 -3
  18. data/lib/aasm/localizer.rb +13 -3
  19. data/lib/aasm/persistence/active_record_persistence.rb +25 -5
  20. data/lib/aasm/persistence/base.rb +14 -3
  21. data/lib/aasm/persistence/core_data_query_persistence.rb +2 -1
  22. data/lib/aasm/persistence/dynamoid_persistence.rb +1 -1
  23. data/lib/aasm/persistence/mongoid_persistence.rb +1 -1
  24. data/lib/aasm/persistence/no_brainer_persistence.rb +105 -0
  25. data/lib/aasm/persistence/orm.rb +26 -14
  26. data/lib/aasm/persistence/plain_persistence.rb +2 -1
  27. data/lib/aasm/persistence/redis_persistence.rb +1 -1
  28. data/lib/aasm/persistence/sequel_persistence.rb +0 -1
  29. data/lib/aasm/persistence.rb +3 -0
  30. data/lib/aasm/rspec/allow_event.rb +5 -1
  31. data/lib/aasm/rspec/allow_transition_to.rb +5 -1
  32. data/lib/aasm/rspec/transition_from.rb +5 -1
  33. data/lib/aasm/version.rb +1 -1
  34. data/lib/aasm.rb +5 -2
  35. data/lib/generators/aasm/orm_helpers.rb +7 -1
  36. data/lib/generators/active_record/aasm_generator.rb +3 -1
  37. data/lib/generators/active_record/templates/migration.rb +1 -1
  38. data/lib/generators/nobrainer/aasm_generator.rb +28 -0
  39. data/lib/motion-aasm.rb +1 -0
  40. metadata +42 -343
  41. data/.document +0 -6
  42. data/.gitignore +0 -20
  43. data/.travis.yml +0 -52
  44. data/API +0 -34
  45. data/Appraisals +0 -43
  46. data/CHANGELOG.md +0 -365
  47. data/CODE_OF_CONDUCT.md +0 -13
  48. data/CONTRIBUTING.md +0 -24
  49. data/Gemfile +0 -7
  50. data/HOWTO +0 -12
  51. data/PLANNED_CHANGES.md +0 -11
  52. data/README_FROM_VERSION_3_TO_4.md +0 -240
  53. data/Rakefile +0 -31
  54. data/TESTING.md +0 -25
  55. data/aasm.gemspec +0 -35
  56. data/callbacks.txt +0 -51
  57. data/gemfiles/rails_3.2.gemfile +0 -13
  58. data/gemfiles/rails_4.0.gemfile +0 -15
  59. data/gemfiles/rails_4.2.gemfile +0 -16
  60. data/gemfiles/rails_4.2_mongoid_5.gemfile +0 -11
  61. data/gemfiles/rails_5.0.gemfile +0 -14
  62. data/spec/database.rb +0 -44
  63. data/spec/database.yml +0 -3
  64. data/spec/en.yml +0 -12
  65. data/spec/en_deprecated_style.yml +0 -10
  66. data/spec/generators/active_record_generator_spec.rb +0 -47
  67. data/spec/generators/mongoid_generator_spec.rb +0 -31
  68. data/spec/models/active_record/basic_active_record_two_state_machines_example.rb +0 -25
  69. data/spec/models/active_record/complex_active_record_example.rb +0 -37
  70. data/spec/models/active_record/derivate_new_dsl.rb +0 -7
  71. data/spec/models/active_record/false_state.rb +0 -35
  72. data/spec/models/active_record/gate.rb +0 -39
  73. data/spec/models/active_record/invalid_persistor.rb +0 -29
  74. data/spec/models/active_record/localizer_test_model.rb +0 -34
  75. data/spec/models/active_record/no_direct_assignment.rb +0 -21
  76. data/spec/models/active_record/no_scope.rb +0 -21
  77. data/spec/models/active_record/persisted_state.rb +0 -12
  78. data/spec/models/active_record/provided_and_persisted_state.rb +0 -24
  79. data/spec/models/active_record/reader.rb +0 -7
  80. data/spec/models/active_record/readme_job.rb +0 -21
  81. data/spec/models/active_record/silent_persistor.rb +0 -29
  82. data/spec/models/active_record/simple_new_dsl.rb +0 -17
  83. data/spec/models/active_record/thief.rb +0 -29
  84. data/spec/models/active_record/transactor.rb +0 -99
  85. data/spec/models/active_record/transient.rb +0 -6
  86. data/spec/models/active_record/validator.rb +0 -118
  87. data/spec/models/active_record/with_enum.rb +0 -39
  88. data/spec/models/active_record/with_enum_without_column.rb +0 -38
  89. data/spec/models/active_record/with_false_enum.rb +0 -31
  90. data/spec/models/active_record/with_true_enum.rb +0 -39
  91. data/spec/models/active_record/worker.rb +0 -2
  92. data/spec/models/active_record/writer.rb +0 -6
  93. data/spec/models/basic_two_state_machines_example.rb +0 -25
  94. data/spec/models/callbacks/basic.rb +0 -98
  95. data/spec/models/callbacks/basic_multiple.rb +0 -75
  96. data/spec/models/callbacks/guard_within_block.rb +0 -67
  97. data/spec/models/callbacks/guard_within_block_multiple.rb +0 -66
  98. data/spec/models/callbacks/multiple_transitions_transition_guard.rb +0 -66
  99. data/spec/models/callbacks/multiple_transitions_transition_guard_multiple.rb +0 -65
  100. data/spec/models/callbacks/private_method.rb +0 -44
  101. data/spec/models/callbacks/private_method_multiple.rb +0 -44
  102. data/spec/models/callbacks/with_args.rb +0 -62
  103. data/spec/models/callbacks/with_args_multiple.rb +0 -61
  104. data/spec/models/callbacks/with_state_arg.rb +0 -30
  105. data/spec/models/callbacks/with_state_arg_multiple.rb +0 -26
  106. data/spec/models/complex_example.rb +0 -222
  107. data/spec/models/conversation.rb +0 -93
  108. data/spec/models/default_state.rb +0 -12
  109. data/spec/models/double_definer.rb +0 -21
  110. data/spec/models/dynamoid/complex_dynamoid_example.rb +0 -37
  111. data/spec/models/dynamoid/dynamoid_multiple.rb +0 -18
  112. data/spec/models/dynamoid/dynamoid_simple.rb +0 -18
  113. data/spec/models/foo.rb +0 -106
  114. data/spec/models/foo_callback_multiple.rb +0 -45
  115. data/spec/models/guard_arguments_check.rb +0 -17
  116. data/spec/models/guard_with_params.rb +0 -24
  117. data/spec/models/guard_with_params_multiple.rb +0 -18
  118. data/spec/models/guardian.rb +0 -58
  119. data/spec/models/guardian_multiple.rb +0 -48
  120. data/spec/models/guardian_without_from_specified.rb +0 -18
  121. data/spec/models/initial_state_proc.rb +0 -31
  122. data/spec/models/mongoid/complex_mongoid_example.rb +0 -37
  123. data/spec/models/mongoid/invalid_persistor_mongoid.rb +0 -39
  124. data/spec/models/mongoid/mongoid_relationships.rb +0 -26
  125. data/spec/models/mongoid/no_scope_mongoid.rb +0 -21
  126. data/spec/models/mongoid/silent_persistor_mongoid.rb +0 -39
  127. data/spec/models/mongoid/simple_mongoid.rb +0 -23
  128. data/spec/models/mongoid/simple_new_dsl_mongoid.rb +0 -25
  129. data/spec/models/mongoid/validator_mongoid.rb +0 -100
  130. data/spec/models/multi_transitioner.rb +0 -34
  131. data/spec/models/multiple_transitions_that_differ_only_by_guard.rb +0 -31
  132. data/spec/models/namespaced_multiple_example.rb +0 -42
  133. data/spec/models/no_initial_state.rb +0 -25
  134. data/spec/models/not_auto_loaded/process.rb +0 -21
  135. data/spec/models/parametrised_event.rb +0 -42
  136. data/spec/models/parametrised_event_multiple.rb +0 -29
  137. data/spec/models/process_with_new_dsl.rb +0 -31
  138. data/spec/models/provided_state.rb +0 -24
  139. data/spec/models/redis/complex_redis_example.rb +0 -40
  140. data/spec/models/redis/redis_multiple.rb +0 -20
  141. data/spec/models/redis/redis_simple.rb +0 -20
  142. data/spec/models/sequel/complex_sequel_example.rb +0 -46
  143. data/spec/models/sequel/invalid_persistor.rb +0 -52
  144. data/spec/models/sequel/sequel_multiple.rb +0 -25
  145. data/spec/models/sequel/sequel_simple.rb +0 -26
  146. data/spec/models/sequel/silent_persistor.rb +0 -50
  147. data/spec/models/sequel/transactor.rb +0 -112
  148. data/spec/models/sequel/validator.rb +0 -93
  149. data/spec/models/sequel/worker.rb +0 -12
  150. data/spec/models/silencer.rb +0 -27
  151. data/spec/models/simple_custom_example.rb +0 -53
  152. data/spec/models/simple_example.rb +0 -15
  153. data/spec/models/simple_multiple_example.rb +0 -42
  154. data/spec/models/state_machine_with_failed_event.rb +0 -20
  155. data/spec/models/states_on_one_line_example.rb +0 -8
  156. data/spec/models/sub_class.rb +0 -41
  157. data/spec/models/sub_class_with_more_states.rb +0 -18
  158. data/spec/models/sub_classing.rb +0 -3
  159. data/spec/models/super_class.rb +0 -46
  160. data/spec/models/this_name_better_not_be_in_use.rb +0 -11
  161. data/spec/models/valid_state_name.rb +0 -23
  162. data/spec/spec_helper.rb +0 -26
  163. data/spec/spec_helpers/active_record.rb +0 -7
  164. data/spec/spec_helpers/dynamoid.rb +0 -33
  165. data/spec/spec_helpers/mongoid.rb +0 -7
  166. data/spec/spec_helpers/redis.rb +0 -15
  167. data/spec/spec_helpers/remove_warnings.rb +0 -1
  168. data/spec/spec_helpers/sequel.rb +0 -7
  169. data/spec/unit/api_spec.rb +0 -100
  170. data/spec/unit/basic_two_state_machines_example_spec.rb +0 -10
  171. data/spec/unit/callback_multiple_spec.rb +0 -300
  172. data/spec/unit/callbacks_spec.rb +0 -491
  173. data/spec/unit/complex_example_spec.rb +0 -84
  174. data/spec/unit/complex_multiple_example_spec.rb +0 -99
  175. data/spec/unit/edge_cases_spec.rb +0 -16
  176. data/spec/unit/event_multiple_spec.rb +0 -73
  177. data/spec/unit/event_naming_spec.rb +0 -16
  178. data/spec/unit/event_spec.rb +0 -381
  179. data/spec/unit/exception_spec.rb +0 -11
  180. data/spec/unit/guard_arguments_check_spec.rb +0 -9
  181. data/spec/unit/guard_multiple_spec.rb +0 -60
  182. data/spec/unit/guard_spec.rb +0 -89
  183. data/spec/unit/guard_with_params_multiple_spec.rb +0 -10
  184. data/spec/unit/guard_with_params_spec.rb +0 -14
  185. data/spec/unit/guard_without_from_specified_spec.rb +0 -10
  186. data/spec/unit/initial_state_multiple_spec.rb +0 -15
  187. data/spec/unit/initial_state_spec.rb +0 -12
  188. data/spec/unit/inspection_multiple_spec.rb +0 -201
  189. data/spec/unit/inspection_spec.rb +0 -149
  190. data/spec/unit/localizer_spec.rb +0 -78
  191. data/spec/unit/memory_leak_spec.rb +0 -38
  192. data/spec/unit/multiple_transitions_that_differ_only_by_guard_spec.rb +0 -14
  193. data/spec/unit/namespaced_multiple_example_spec.rb +0 -75
  194. data/spec/unit/new_dsl_spec.rb +0 -12
  195. data/spec/unit/override_warning_spec.rb +0 -94
  196. data/spec/unit/persistence/active_record_persistence_multiple_spec.rb +0 -618
  197. data/spec/unit/persistence/active_record_persistence_spec.rb +0 -721
  198. data/spec/unit/persistence/dynamoid_persistence_multiple_spec.rb +0 -135
  199. data/spec/unit/persistence/dynamoid_persistence_spec.rb +0 -84
  200. data/spec/unit/persistence/mongoid_persistence_multiple_spec.rb +0 -204
  201. data/spec/unit/persistence/mongoid_persistence_spec.rb +0 -169
  202. data/spec/unit/persistence/redis_persistence_multiple_spec.rb +0 -88
  203. data/spec/unit/persistence/redis_persistence_spec.rb +0 -53
  204. data/spec/unit/persistence/sequel_persistence_multiple_spec.rb +0 -148
  205. data/spec/unit/persistence/sequel_persistence_spec.rb +0 -368
  206. data/spec/unit/readme_spec.rb +0 -41
  207. data/spec/unit/reloading_spec.rb +0 -15
  208. data/spec/unit/rspec_matcher_spec.rb +0 -79
  209. data/spec/unit/simple_custom_example_spec.rb +0 -39
  210. data/spec/unit/simple_example_spec.rb +0 -42
  211. data/spec/unit/simple_multiple_example_spec.rb +0 -91
  212. data/spec/unit/state_spec.rb +0 -89
  213. data/spec/unit/states_on_one_line_example_spec.rb +0 -16
  214. data/spec/unit/subclassing_multiple_spec.rb +0 -74
  215. data/spec/unit/subclassing_spec.rb +0 -46
  216. data/spec/unit/transition_spec.rb +0 -436
  217. data/test/minitest_helper.rb +0 -57
  218. data/test/unit/minitest_matcher_test.rb +0 -80
@@ -1,721 +0,0 @@
1
- require 'spec_helper'
2
-
3
- if defined?(ActiveRecord)
4
-
5
- Dir[File.dirname(__FILE__) + "/../../models/active_record/*.rb"].sort.each do |f|
6
- require File.expand_path(f)
7
- end
8
-
9
- load_schema
10
-
11
- # if you want to see the statements while running the spec enable the following line
12
- # require 'logger'
13
- # ActiveRecord::Base.logger = Logger.new(STDERR)
14
-
15
- describe "instance methods" do
16
- let(:gate) {Gate.new}
17
-
18
- it "should respond to aasm persistence methods" do
19
- expect(gate).to respond_to(:aasm_read_state)
20
- expect(gate).to respond_to(:aasm_write_state)
21
- expect(gate).to respond_to(:aasm_write_state_without_persistence)
22
- end
23
-
24
- describe "aasm_column_looks_like_enum" do
25
- subject { lambda{ gate.send(:aasm_column_looks_like_enum) } }
26
-
27
- let(:column_name) { "value" }
28
- let(:columns_hash) { Hash[column_name, column] }
29
-
30
- before :each do
31
- allow(gate.class.aasm).to receive(:attribute_name).and_return(column_name.to_sym)
32
- allow(gate.class).to receive(:columns_hash).and_return(columns_hash)
33
- end
34
-
35
- context "when AASM column has integer type" do
36
- let(:column) { double(Object, type: :integer) }
37
-
38
- it "returns true" do
39
- expect(subject.call).to be_truthy
40
- end
41
- end
42
-
43
- context "when AASM column has string type" do
44
- let(:column) { double(Object, type: :string) }
45
-
46
- it "returns false" do
47
- expect(subject.call).to be_falsey
48
- end
49
- end
50
- end
51
-
52
- describe "aasm_guess_enum_method" do
53
- subject { lambda{ gate.send(:aasm_guess_enum_method) } }
54
-
55
- before :each do
56
- allow(gate.class.aasm).to receive(:attribute_name).and_return(:value)
57
- end
58
-
59
- it "pluralizes AASM column name" do
60
- expect(subject.call).to eq :values
61
- end
62
- end
63
-
64
- describe "aasm_enum" do
65
- context "when AASM enum setting contains an explicit enum method name" do
66
- let(:with_enum) { WithEnum.new }
67
-
68
- it "returns whatever value was set in AASM config" do
69
- expect(with_enum.send(:aasm_enum)).to eq :test
70
- end
71
- end
72
-
73
- context "when AASM enum setting is simply set to true" do
74
- let(:with_true_enum) { WithTrueEnum.new }
75
- before :each do
76
- allow(WithTrueEnum.aasm).to receive(:attribute_name).and_return(:value)
77
- end
78
-
79
- it "infers enum method name from pluralized column name" do
80
- expect(with_true_enum.send(:aasm_enum)).to eq :values
81
- end
82
- end
83
-
84
- context "when AASM enum setting is explicitly disabled" do
85
- let(:with_false_enum) { WithFalseEnum.new }
86
-
87
- it "returns nil" do
88
- expect(with_false_enum.send(:aasm_enum)).to be_nil
89
- end
90
- end
91
-
92
- context "when AASM enum setting is not enabled" do
93
- before :each do
94
- allow(Gate.aasm).to receive(:attribute_name).and_return(:value)
95
- end
96
-
97
- context "when AASM column looks like enum" do
98
- before :each do
99
- allow(gate).to receive(:aasm_column_looks_like_enum).and_return(true)
100
- end
101
-
102
- it "infers enum method name from pluralized column name" do
103
- expect(gate.send(:aasm_enum)).to eq :values
104
- end
105
- end
106
-
107
- context "when AASM column doesn't look like enum'" do
108
- before :each do
109
- allow(gate).to receive(:aasm_column_looks_like_enum)
110
- .and_return(false)
111
- end
112
-
113
- it "returns nil, as we're not using enum" do
114
- expect(gate.send(:aasm_enum)).to be_nil
115
- end
116
- end
117
- end
118
-
119
- if ActiveRecord::VERSION::MAJOR >= 4 && ActiveRecord::VERSION::MINOR >= 1 # won't work with Rails <= 4.1
120
- # Enum are introduced from Rails 4.1, therefore enum syntax will not work on Rails <= 4.1
121
- context "when AASM enum setting is not enabled and aasm column not present" do
122
-
123
- let(:with_enum_without_column) {WithEnumWithoutColumn.new}
124
-
125
- it "should raise NoMethodError for transitions" do
126
- expect{with_enum_without_column.send(:view)}.to raise_error(NoMethodError, "undefined method 'status' for WithEnumWithoutColumn")
127
- end
128
- end
129
-
130
- end
131
-
132
- end
133
-
134
- context "when AASM is configured to use enum" do
135
- let(:state_sym) { :running }
136
- let(:state_code) { 2 }
137
- let(:enum_name) { :states }
138
- let(:enum) { Hash[state_sym, state_code] }
139
-
140
- before :each do
141
- allow(gate).to receive(:aasm_enum).and_return(enum_name)
142
- allow(gate).to receive(:aasm_write_state_attribute)
143
- allow(gate).to receive(:write_attribute)
144
-
145
- allow(Gate).to receive(enum_name).and_return(enum)
146
- end
147
-
148
- describe "aasm_write_state" do
149
- context "when AASM is configured to skip validations on save" do
150
- before :each do
151
- allow(gate).to receive(:aasm_skipping_validations).and_return(true)
152
- end
153
-
154
- it "passes state code instead of state symbol to update_all" do
155
- # stub_chain does not allow us to give expectations on call
156
- # parameters in the middle of the chain, so we need to use
157
- # intermediate object instead.
158
- obj = double(Object, update_all: 1)
159
- allow(Gate).to receive_message_chain(:unscoped, :where).and_return(obj)
160
-
161
- gate.aasm_write_state state_sym
162
-
163
- expect(obj).to have_received(:update_all)
164
- .with(Hash[gate.class.aasm.attribute_name, state_code])
165
- end
166
-
167
- it "searches model outside of default_scope when update_all" do
168
- # stub_chain does not allow us to give expectations on call
169
- # parameters in the middle of the chain, so we need to use
170
- # intermediate object instead.
171
- unscoped = double(Object, update_all: 1)
172
- scoped = double(Object, update_all: 1)
173
-
174
- allow(Gate).to receive(:unscoped).and_return(unscoped)
175
- allow(Gate).to receive(:where).and_return(scoped)
176
- allow(unscoped).to receive(:where).and_return(unscoped)
177
-
178
- gate.aasm_write_state state_sym
179
-
180
- expect(unscoped).to have_received(:update_all)
181
- .with(Hash[gate.class.aasm.attribute_name, state_code])
182
- expect(scoped).to_not have_received(:update_all)
183
- .with(Hash[gate.class.aasm.attribute_name, state_code])
184
- end
185
- end
186
-
187
- context "when AASM is not skipping validations" do
188
- it "delegates state update to the helper method" do
189
- # Let's pretend that validation is passed
190
- allow(gate).to receive(:save).and_return(true)
191
-
192
- gate.aasm_write_state state_sym
193
-
194
- expect(gate).to have_received(:aasm_write_state_attribute).with(state_sym, :default)
195
- expect(gate).to_not have_received :write_attribute
196
- end
197
- end
198
- end
199
-
200
- describe "aasm_write_state_without_persistence" do
201
- it "delegates state update to the helper method" do
202
- gate.aasm_write_state_without_persistence state_sym
203
-
204
- expect(gate).to have_received(:aasm_write_state_attribute).with(state_sym, :default)
205
- expect(gate).to_not have_received :write_attribute
206
- end
207
- end
208
-
209
- describe "aasm_raw_attribute_value" do
210
- it "converts state symbol to state code" do
211
- expect(gate.send(:aasm_raw_attribute_value, state_sym))
212
- .to eq state_code
213
- end
214
- end
215
- end
216
-
217
- context "when AASM is configured to use string field" do
218
- let(:state_sym) { :running }
219
-
220
- before :each do
221
- allow(gate).to receive(:aasm_enum).and_return(nil)
222
- end
223
-
224
- describe "aasm_raw_attribute_value" do
225
- it "converts state symbol to string" do
226
- expect(gate.send(:aasm_raw_attribute_value, state_sym))
227
- .to eq state_sym.to_s
228
- end
229
- end
230
- end
231
-
232
- describe "aasm_write_attribute helper method" do
233
- let(:sym) { :sym }
234
- let(:value) { 42 }
235
-
236
- before :each do
237
- allow(gate).to receive(:write_attribute)
238
- allow(gate).to receive(:aasm_raw_attribute_value).and_return(value)
239
-
240
- gate.send(:aasm_write_state_attribute, sym)
241
- end
242
-
243
- it "generates attribute value using a helper method" do
244
- expect(gate).to have_received(:aasm_raw_attribute_value).with(sym, :default)
245
- end
246
-
247
- it "writes attribute to the model" do
248
- expect(gate).to have_received(:write_attribute).with(:aasm_state, value)
249
- end
250
- end
251
-
252
- it "should return the initial state when new and the aasm field is nil" do
253
- expect(gate.aasm.current_state).to eq(:opened)
254
- end
255
-
256
- it "should return the aasm column when new and the aasm field is not nil" do
257
- gate.aasm_state = "closed"
258
- expect(gate.aasm.current_state).to eq(:closed)
259
- end
260
-
261
- it "should return the aasm column when not new and the aasm.attribute_name is not nil" do
262
- allow(gate).to receive(:new_record?).and_return(false)
263
- gate.aasm_state = "state"
264
- expect(gate.aasm.current_state).to eq(:state)
265
- end
266
-
267
- it "should allow a nil state" do
268
- allow(gate).to receive(:new_record?).and_return(false)
269
- gate.aasm_state = nil
270
- expect(gate.aasm.current_state).to be_nil
271
- end
272
-
273
- context 'on initialization' do
274
- it "should initialize the aasm state" do
275
- expect(Gate.new.aasm_state).to eql 'opened'
276
- expect(Gate.new.aasm.current_state).to eql :opened
277
- end
278
-
279
- it "should not initialize the aasm state if it has not been loaded" do
280
- # we have to create a gate in the database, for which we only want to
281
- # load the id, and not the state
282
- gate = Gate.create!
283
-
284
- # then we just load the gate ids
285
- Gate.select(:id).where(id: gate.id).first
286
- end
287
- end
288
-
289
- end
290
-
291
- if ActiveRecord::VERSION::MAJOR < 4 && ActiveRecord::VERSION::MINOR < 2 # won't work with Rails >= 4.2
292
- describe "direct state column access" do
293
- it "accepts false states" do
294
- f = FalseState.create!
295
- expect(f.aasm_state).to eql false
296
- expect {
297
- f.aasm.events.map(&:name)
298
- }.to_not raise_error
299
- end
300
- end
301
- end
302
-
303
- describe 'subclasses' do
304
- it "should have the same states as its parent class" do
305
- expect(DerivateNewDsl.aasm.states).to eq(SimpleNewDsl.aasm.states)
306
- end
307
-
308
- it "should have the same events as its parent class" do
309
- expect(DerivateNewDsl.aasm.events).to eq(SimpleNewDsl.aasm.events)
310
- end
311
-
312
- it "should have the same column as its parent even for the new dsl" do
313
- expect(SimpleNewDsl.aasm.attribute_name).to eq(:status)
314
- expect(DerivateNewDsl.aasm.attribute_name).to eq(:status)
315
- end
316
- end
317
-
318
- describe "named scopes with the new DSL" do
319
- context "Does not already respond_to? the scope name" do
320
- it "should add a scope for each state" do
321
- expect(SimpleNewDsl).to respond_to(:unknown_scope)
322
- expect(SimpleNewDsl).to respond_to(:another_unknown_scope)
323
-
324
- expect(SimpleNewDsl.unknown_scope.is_a?(ActiveRecord::Relation)).to be_truthy
325
- expect(SimpleNewDsl.another_unknown_scope.is_a?(ActiveRecord::Relation)).to be_truthy
326
- end
327
- end
328
-
329
- context "Already respond_to? the scope name" do
330
- it "should not add a scope" do
331
- expect(SimpleNewDsl).to respond_to(:new)
332
- expect(SimpleNewDsl.new.class).to eq(SimpleNewDsl)
333
- end
334
- end
335
-
336
- it "does not create scopes if requested" do
337
- expect(NoScope).not_to respond_to(:pending)
338
- end
339
-
340
- context "result of scope" do
341
- let!(:dsl1) { SimpleNewDsl.create!(status: :new) }
342
- let!(:dsl2) { SimpleNewDsl.create!(status: :unknown_scope) }
343
-
344
- after do
345
- SimpleNewDsl.destroy_all
346
- end
347
-
348
- it "created scope works as where(name: :scope_name)" do
349
- expect(SimpleNewDsl.unknown_scope).to contain_exactly(dsl2)
350
- end
351
- end
352
- end # scopes
353
-
354
- describe "direct assignment" do
355
- it "is allowed by default" do
356
- obj = NoScope.create
357
- expect(obj.aasm_state.to_sym).to eql :pending
358
-
359
- obj.aasm_state = :running
360
- expect(obj.aasm_state.to_sym).to eql :running
361
- end
362
-
363
- it "is forbidden if configured" do
364
- obj = NoDirectAssignment.create
365
- expect(obj.aasm_state.to_sym).to eql :pending
366
-
367
- expect {obj.aasm_state = :running}.to raise_error(AASM::NoDirectAssignmentError)
368
- expect(obj.aasm_state.to_sym).to eql :pending
369
- end
370
-
371
- it 'can be turned off and on again' do
372
- obj = NoDirectAssignment.create
373
- expect(obj.aasm_state.to_sym).to eql :pending
374
-
375
- expect {obj.aasm_state = :running}.to raise_error(AASM::NoDirectAssignmentError)
376
- expect(obj.aasm_state.to_sym).to eql :pending
377
-
378
- # allow it temporarily
379
- NoDirectAssignment.aasm.state_machine.config.no_direct_assignment = false
380
- obj.aasm_state = :pending
381
- expect(obj.aasm_state.to_sym).to eql :pending
382
-
383
- # and forbid it again
384
- NoDirectAssignment.aasm.state_machine.config.no_direct_assignment = true
385
- expect {obj.aasm_state = :running}.to raise_error(AASM::NoDirectAssignmentError)
386
- expect(obj.aasm_state.to_sym).to eql :pending
387
- end
388
- end # direct assignment
389
-
390
- describe 'initial states' do
391
-
392
- it 'should support conditions' do
393
- expect(Thief.new(:skilled => true).aasm.current_state).to eq(:rich)
394
- expect(Thief.new(:skilled => false).aasm.current_state).to eq(:jailed)
395
- end
396
- end
397
-
398
- describe 'transitions with persistence' do
399
-
400
- it "should work for valid models" do
401
- valid_object = Validator.create(:name => 'name')
402
- expect(valid_object).to be_sleeping
403
- valid_object.status = :running
404
- expect(valid_object).to be_running
405
- end
406
-
407
- it 'should not store states for invalid models' do
408
- validator = Validator.create(:name => 'name')
409
- expect(validator).to be_valid
410
- expect(validator).to be_sleeping
411
-
412
- validator.name = nil
413
- expect(validator).not_to be_valid
414
- expect { validator.run! }.to raise_error(ActiveRecord::RecordInvalid)
415
- expect(validator).to be_sleeping
416
-
417
- validator.reload
418
- expect(validator).not_to be_running
419
- expect(validator).to be_sleeping
420
-
421
- validator.name = 'another name'
422
- expect(validator).to be_valid
423
- expect(validator.run!).to be_truthy
424
- expect(validator).to be_running
425
-
426
- validator.reload
427
- expect(validator).to be_running
428
- expect(validator).not_to be_sleeping
429
- end
430
-
431
- it 'should not store states for invalid models silently if configured' do
432
- validator = SilentPersistor.create(:name => 'name')
433
- expect(validator).to be_valid
434
- expect(validator).to be_sleeping
435
-
436
- validator.name = nil
437
- expect(validator).not_to be_valid
438
- expect(validator.run!).to be_falsey
439
- expect(validator).to be_sleeping
440
-
441
- validator.reload
442
- expect(validator).not_to be_running
443
- expect(validator).to be_sleeping
444
-
445
- validator.name = 'another name'
446
- expect(validator).to be_valid
447
- expect(validator.run!).to be_truthy
448
- expect(validator).to be_running
449
-
450
- validator.reload
451
- expect(validator).to be_running
452
- expect(validator).not_to be_sleeping
453
- end
454
-
455
- it 'should store states for invalid models if configured' do
456
- persistor = InvalidPersistor.create(:name => 'name')
457
- expect(persistor).to be_valid
458
- expect(persistor).to be_sleeping
459
-
460
- persistor.name = nil
461
- expect(persistor).not_to be_valid
462
- expect(persistor.run!).to be_truthy
463
- expect(persistor).to be_running
464
-
465
- persistor = InvalidPersistor.find(persistor.id)
466
- persistor.valid?
467
- expect(persistor).to be_valid
468
- expect(persistor).to be_running
469
- expect(persistor).not_to be_sleeping
470
-
471
- persistor.reload
472
- expect(persistor).to be_running
473
- expect(persistor).not_to be_sleeping
474
- end
475
-
476
- describe 'pessimistic locking' do
477
- let(:worker) { Worker.create!(:name => 'worker', :status => 'sleeping') }
478
-
479
- subject { transactor.run! }
480
-
481
- context 'no lock' do
482
- let(:transactor) { NoLockTransactor.create!(:name => 'no_lock_transactor', :worker => worker) }
483
-
484
- it 'should not invoke lock!' do
485
- expect(transactor).to_not receive(:lock!)
486
- subject
487
- end
488
- end
489
-
490
- context 'a default lock' do
491
- let(:transactor) { LockTransactor.create!(:name => 'lock_transactor', :worker => worker) }
492
-
493
- it 'should invoke lock! with true' do
494
- expect(transactor).to receive(:lock!).with(true).and_call_original
495
- subject
496
- end
497
- end
498
-
499
- context 'a FOR UPDATE NOWAIT lock' do
500
- let(:transactor) { LockNoWaitTransactor.create!(:name => 'lock_no_wait_transactor', :worker => worker) }
501
-
502
- it 'should invoke lock! with FOR UPDATE NOWAIT' do
503
- expect(transactor).to receive(:lock!).with('FOR UPDATE NOWAIT').and_call_original
504
- subject
505
- end
506
- end
507
- end
508
-
509
- describe 'transactions' do
510
- let(:worker) { Worker.create!(:name => 'worker', :status => 'sleeping') }
511
- let(:transactor) { Transactor.create!(:name => 'transactor', :worker => worker) }
512
-
513
- it 'should rollback all changes' do
514
- expect(transactor).to be_sleeping
515
- expect(worker.status).to eq('sleeping')
516
-
517
- expect {transactor.run!}.to raise_error(StandardError, 'failed on purpose')
518
- expect(transactor).to be_running
519
- expect(worker.reload.status).to eq('sleeping')
520
- end
521
-
522
- context "nested transactions" do
523
- it "should rollback all changes in nested transaction" do
524
- expect(transactor).to be_sleeping
525
- expect(worker.status).to eq('sleeping')
526
-
527
- Worker.transaction do
528
- expect { transactor.run! }.to raise_error(StandardError, 'failed on purpose')
529
- end
530
-
531
- expect(transactor).to be_running
532
- expect(worker.reload.status).to eq('sleeping')
533
- end
534
-
535
- it "should only rollback changes in the main transaction not the nested one" do
536
- # change configuration to not require new transaction
537
- AASM::StateMachineStore[Transactor][:default].config.requires_new_transaction = false
538
-
539
- expect(transactor).to be_sleeping
540
- expect(worker.status).to eq('sleeping')
541
-
542
- Worker.transaction do
543
- expect { transactor.run! }.to raise_error(StandardError, 'failed on purpose')
544
- end
545
-
546
- expect(transactor).to be_running
547
- expect(worker.reload.status).to eq('running')
548
- end
549
- end
550
-
551
- describe "after_commit callback" do
552
- it "should fire :after_commit if transaction was successful" do
553
- validator = Validator.create(:name => 'name')
554
- expect(validator).to be_sleeping
555
-
556
- validator.run!
557
- expect(validator).to be_running
558
- expect(validator.name).to eq("name changed")
559
-
560
- validator.sleep!("sleeper")
561
- expect(validator).to be_sleeping
562
- expect(validator.name).to eq("sleeper")
563
- end
564
-
565
- it "should not fire :after_commit if transaction failed" do
566
- validator = Validator.create(:name => 'name')
567
- expect { validator.fail! }.to raise_error(StandardError, 'failed on purpose')
568
- expect(validator.name).to eq("name")
569
- end
570
-
571
- it "should not fire :after_commit if validation failed when saving object" do
572
- validator = Validator.create(:name => 'name')
573
- validator.invalid = true
574
- expect { validator.run! }.to raise_error(ActiveRecord::RecordInvalid, 'Invalid record')
575
- expect(validator).to be_sleeping
576
- expect(validator.name).to eq("name")
577
- end
578
-
579
- it "should not fire if not saving" do
580
- validator = Validator.create(:name => 'name')
581
- expect(validator).to be_sleeping
582
- validator.run
583
- expect(validator).to be_running
584
- expect(validator.name).to eq("name")
585
- end
586
- end
587
-
588
- describe 'before and after transaction callbacks' do
589
- [:after, :before].each do |event_type|
590
- describe "#{event_type}_transaction callback" do
591
- it "should fire :#{event_type}_transaction if transaction was successful" do
592
- validator = Validator.create(:name => 'name')
593
- expect(validator).to be_sleeping
594
-
595
- expect { validator.run! }.to change { validator.send("#{event_type}_transaction_performed_on_run") }.from(nil).to(true)
596
- expect(validator).to be_running
597
- end
598
-
599
- it "should fire :#{event_type}_transaction if transaction failed" do
600
- validator = Validator.create(:name => 'name')
601
- expect do
602
- begin
603
- validator.fail!
604
- rescue => ignored
605
- end
606
- end.to change { validator.send("#{event_type}_transaction_performed_on_fail") }.from(nil).to(true)
607
- expect(validator).to_not be_running
608
- end
609
-
610
- it "should not fire :#{event_type}_transaction if not saving" do
611
- validator = Validator.create(:name => 'name')
612
- expect(validator).to be_sleeping
613
- expect { validator.run }.to_not change { validator.send("#{event_type}_transaction_performed_on_run") }
614
- expect(validator).to be_running
615
- expect(validator.name).to eq("name")
616
- end
617
- end
618
- end
619
- end
620
-
621
- describe 'before and after all transactions callbacks' do
622
- [:after, :before].each do |event_type|
623
- describe "#{event_type}_all_transactions callback" do
624
- it "should fire :#{event_type}_all_transactions if transaction was successful" do
625
- validator = Validator.create(:name => 'name')
626
- expect(validator).to be_sleeping
627
-
628
- expect { validator.run! }.to change { validator.send("#{event_type}_all_transactions_performed") }.from(nil).to(true)
629
- expect(validator).to be_running
630
- end
631
-
632
- it "should fire :#{event_type}_all_transactions if transaction failed" do
633
- validator = Validator.create(:name => 'name')
634
- expect do
635
- begin
636
- validator.fail!
637
- rescue => ignored
638
- end
639
- end.to change { validator.send("#{event_type}_all_transactions_performed") }.from(nil).to(true)
640
- expect(validator).to_not be_running
641
- end
642
-
643
- it "should not fire :#{event_type}_all_transactions if not saving" do
644
- validator = Validator.create(:name => 'name')
645
- expect(validator).to be_sleeping
646
- expect { validator.run }.to_not change { validator.send("#{event_type}_all_transactions_performed") }
647
- expect(validator).to be_running
648
- expect(validator.name).to eq("name")
649
- end
650
- end
651
- end
652
- end
653
-
654
- context "when not persisting" do
655
- it 'should not rollback all changes' do
656
- expect(transactor).to be_sleeping
657
- expect(worker.status).to eq('sleeping')
658
-
659
- # Notice here we're calling "run" and not "run!" with a bang.
660
- expect {transactor.run}.to raise_error(StandardError, 'failed on purpose')
661
- expect(transactor).to be_running
662
- expect(worker.reload.status).to eq('running')
663
- end
664
-
665
- it 'should not create a database transaction' do
666
- expect(transactor.class).not_to receive(:transaction)
667
- expect {transactor.run}.to raise_error(StandardError, 'failed on purpose')
668
- end
669
- end
670
- end
671
- end
672
-
673
- describe "invalid states with persistence" do
674
-
675
- it "should not store states" do
676
- validator = Validator.create(:name => 'name')
677
- validator.status = 'invalid_state'
678
- expect(validator.save).to be_falsey
679
- expect {validator.save!}.to raise_error(ActiveRecord::RecordInvalid)
680
-
681
- validator.reload
682
- expect(validator).to be_sleeping
683
- end
684
-
685
- it "should store invalid states if configured" do
686
- persistor = InvalidPersistor.create(:name => 'name')
687
- persistor.status = 'invalid_state'
688
- expect(persistor.save).to be_truthy
689
-
690
- persistor.reload
691
- expect(persistor.status).to eq('invalid_state')
692
- end
693
-
694
- end
695
-
696
- describe 'basic example with two state machines' do
697
- let(:example) { BasicActiveRecordTwoStateMachinesExample.new }
698
-
699
- it 'should initialise properly' do
700
- expect(example.aasm(:search).current_state).to eql :initialised
701
- expect(example.aasm(:sync).current_state).to eql :unsynced
702
- end
703
- end
704
-
705
- describe 'testing the README examples' do
706
- it 'Usage' do
707
- job = ReadmeJob.new
708
-
709
- expect(job.sleeping?).to eql true
710
- expect(job.may_run?).to eql true
711
-
712
- job.run
713
-
714
- expect(job.running?).to eql true
715
- expect(job.sleeping?).to eql false
716
- expect(job.may_run?).to eql false
717
-
718
- expect { job.run }.to raise_error(AASM::InvalidTransition)
719
- end
720
- end
721
- end