aasm 5.0.8

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 (262) hide show
  1. checksums.yaml +7 -0
  2. data/.document +6 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +27 -0
  4. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  5. data/.gitignore +20 -0
  6. data/.travis.yml +100 -0
  7. data/API +34 -0
  8. data/Appraisals +71 -0
  9. data/CHANGELOG.md +431 -0
  10. data/CODE_OF_CONDUCT.md +13 -0
  11. data/CONTRIBUTING.md +24 -0
  12. data/Dockerfile +44 -0
  13. data/Gemfile +6 -0
  14. data/Gemfile.lock_old +151 -0
  15. data/HOWTO +12 -0
  16. data/LICENSE +20 -0
  17. data/PLANNED_CHANGES.md +11 -0
  18. data/README.md +1439 -0
  19. data/README_FROM_VERSION_3_TO_4.md +240 -0
  20. data/Rakefile +31 -0
  21. data/TESTING.md +25 -0
  22. data/aasm.gemspec +37 -0
  23. data/callbacks.txt +51 -0
  24. data/docker-compose.yml +40 -0
  25. data/gemfiles/norails.gemfile +10 -0
  26. data/gemfiles/rails_3.2.gemfile +14 -0
  27. data/gemfiles/rails_4.2.gemfile +16 -0
  28. data/gemfiles/rails_4.2_mongoid_5.gemfile +11 -0
  29. data/gemfiles/rails_4.2_nobrainer.gemfile +9 -0
  30. data/gemfiles/rails_5.0.gemfile +13 -0
  31. data/gemfiles/rails_5.0_nobrainer.gemfile +9 -0
  32. data/gemfiles/rails_5.1.gemfile +13 -0
  33. data/gemfiles/rails_5.2.gemfile +13 -0
  34. data/lib/aasm.rb +23 -0
  35. data/lib/aasm/aasm.rb +208 -0
  36. data/lib/aasm/base.rb +271 -0
  37. data/lib/aasm/configuration.rb +45 -0
  38. data/lib/aasm/core/event.rb +172 -0
  39. data/lib/aasm/core/invoker.rb +129 -0
  40. data/lib/aasm/core/invokers/base_invoker.rb +75 -0
  41. data/lib/aasm/core/invokers/class_invoker.rb +52 -0
  42. data/lib/aasm/core/invokers/literal_invoker.rb +47 -0
  43. data/lib/aasm/core/invokers/proc_invoker.rb +59 -0
  44. data/lib/aasm/core/state.rb +90 -0
  45. data/lib/aasm/core/transition.rb +83 -0
  46. data/lib/aasm/dsl_helper.rb +30 -0
  47. data/lib/aasm/errors.rb +21 -0
  48. data/lib/aasm/instance_base.rb +133 -0
  49. data/lib/aasm/localizer.rb +54 -0
  50. data/lib/aasm/minitest.rb +5 -0
  51. data/lib/aasm/minitest/allow_event.rb +13 -0
  52. data/lib/aasm/minitest/allow_transition_to.rb +13 -0
  53. data/lib/aasm/minitest/have_state.rb +13 -0
  54. data/lib/aasm/minitest/transition_from.rb +21 -0
  55. data/lib/aasm/minitest_spec.rb +15 -0
  56. data/lib/aasm/persistence.rb +54 -0
  57. data/lib/aasm/persistence/active_record_persistence.rb +165 -0
  58. data/lib/aasm/persistence/base.rb +78 -0
  59. data/lib/aasm/persistence/core_data_query_persistence.rb +94 -0
  60. data/lib/aasm/persistence/dynamoid_persistence.rb +92 -0
  61. data/lib/aasm/persistence/mongoid_persistence.rb +126 -0
  62. data/lib/aasm/persistence/no_brainer_persistence.rb +105 -0
  63. data/lib/aasm/persistence/orm.rb +150 -0
  64. data/lib/aasm/persistence/plain_persistence.rb +26 -0
  65. data/lib/aasm/persistence/redis_persistence.rb +112 -0
  66. data/lib/aasm/persistence/sequel_persistence.rb +83 -0
  67. data/lib/aasm/rspec.rb +5 -0
  68. data/lib/aasm/rspec/allow_event.rb +26 -0
  69. data/lib/aasm/rspec/allow_transition_to.rb +26 -0
  70. data/lib/aasm/rspec/have_state.rb +22 -0
  71. data/lib/aasm/rspec/transition_from.rb +36 -0
  72. data/lib/aasm/state_machine.rb +53 -0
  73. data/lib/aasm/state_machine_store.rb +76 -0
  74. data/lib/aasm/version.rb +3 -0
  75. data/lib/generators/aasm/aasm_generator.rb +16 -0
  76. data/lib/generators/aasm/orm_helpers.rb +41 -0
  77. data/lib/generators/active_record/aasm_generator.rb +40 -0
  78. data/lib/generators/active_record/templates/migration.rb +8 -0
  79. data/lib/generators/active_record/templates/migration_existing.rb +5 -0
  80. data/lib/generators/mongoid/aasm_generator.rb +28 -0
  81. data/lib/generators/nobrainer/aasm_generator.rb +28 -0
  82. data/lib/motion-aasm.rb +37 -0
  83. data/spec/database.rb +59 -0
  84. data/spec/database.yml +3 -0
  85. data/spec/en.yml +12 -0
  86. data/spec/en_deprecated_style.yml +10 -0
  87. data/spec/generators/active_record_generator_spec.rb +53 -0
  88. data/spec/generators/mongoid_generator_spec.rb +31 -0
  89. data/spec/generators/no_brainer_generator_spec.rb +29 -0
  90. data/spec/models/active_record/basic_active_record_two_state_machines_example.rb +25 -0
  91. data/spec/models/active_record/complex_active_record_example.rb +37 -0
  92. data/spec/models/active_record/derivate_new_dsl.rb +7 -0
  93. data/spec/models/active_record/false_state.rb +35 -0
  94. data/spec/models/active_record/gate.rb +39 -0
  95. data/spec/models/active_record/instance_level_skip_validation_example.rb +19 -0
  96. data/spec/models/active_record/invalid_persistor.rb +29 -0
  97. data/spec/models/active_record/localizer_test_model.rb +34 -0
  98. data/spec/models/active_record/no_direct_assignment.rb +21 -0
  99. data/spec/models/active_record/no_scope.rb +21 -0
  100. data/spec/models/active_record/persisted_state.rb +12 -0
  101. data/spec/models/active_record/person.rb +23 -0
  102. data/spec/models/active_record/provided_and_persisted_state.rb +24 -0
  103. data/spec/models/active_record/reader.rb +7 -0
  104. data/spec/models/active_record/readme_job.rb +21 -0
  105. data/spec/models/active_record/silent_persistor.rb +29 -0
  106. data/spec/models/active_record/simple_new_dsl.rb +32 -0
  107. data/spec/models/active_record/thief.rb +29 -0
  108. data/spec/models/active_record/transactor.rb +124 -0
  109. data/spec/models/active_record/transient.rb +6 -0
  110. data/spec/models/active_record/validator.rb +118 -0
  111. data/spec/models/active_record/with_enum.rb +39 -0
  112. data/spec/models/active_record/with_enum_without_column.rb +38 -0
  113. data/spec/models/active_record/with_false_enum.rb +31 -0
  114. data/spec/models/active_record/with_true_enum.rb +39 -0
  115. data/spec/models/active_record/work.rb +3 -0
  116. data/spec/models/active_record/worker.rb +2 -0
  117. data/spec/models/active_record/writer.rb +6 -0
  118. data/spec/models/basic_two_state_machines_example.rb +25 -0
  119. data/spec/models/callbacks/basic.rb +98 -0
  120. data/spec/models/callbacks/basic_multiple.rb +75 -0
  121. data/spec/models/callbacks/guard_within_block.rb +67 -0
  122. data/spec/models/callbacks/guard_within_block_multiple.rb +66 -0
  123. data/spec/models/callbacks/multiple_transitions_transition_guard.rb +66 -0
  124. data/spec/models/callbacks/multiple_transitions_transition_guard_multiple.rb +65 -0
  125. data/spec/models/callbacks/private_method.rb +44 -0
  126. data/spec/models/callbacks/private_method_multiple.rb +44 -0
  127. data/spec/models/callbacks/with_args.rb +62 -0
  128. data/spec/models/callbacks/with_args_multiple.rb +61 -0
  129. data/spec/models/callbacks/with_state_arg.rb +34 -0
  130. data/spec/models/callbacks/with_state_arg_multiple.rb +29 -0
  131. data/spec/models/complex_example.rb +222 -0
  132. data/spec/models/conversation.rb +93 -0
  133. data/spec/models/default_state.rb +12 -0
  134. data/spec/models/double_definer.rb +21 -0
  135. data/spec/models/dynamoid/complex_dynamoid_example.rb +37 -0
  136. data/spec/models/dynamoid/dynamoid_multiple.rb +18 -0
  137. data/spec/models/dynamoid/dynamoid_simple.rb +18 -0
  138. data/spec/models/foo.rb +106 -0
  139. data/spec/models/foo_callback_multiple.rb +45 -0
  140. data/spec/models/guard_arguments_check.rb +17 -0
  141. data/spec/models/guard_with_params.rb +24 -0
  142. data/spec/models/guard_with_params_multiple.rb +18 -0
  143. data/spec/models/guardian.rb +58 -0
  144. data/spec/models/guardian_multiple.rb +48 -0
  145. data/spec/models/guardian_without_from_specified.rb +18 -0
  146. data/spec/models/initial_state_proc.rb +31 -0
  147. data/spec/models/mongoid/complex_mongoid_example.rb +37 -0
  148. data/spec/models/mongoid/invalid_persistor_mongoid.rb +39 -0
  149. data/spec/models/mongoid/mongoid_relationships.rb +26 -0
  150. data/spec/models/mongoid/no_scope_mongoid.rb +21 -0
  151. data/spec/models/mongoid/silent_persistor_mongoid.rb +39 -0
  152. data/spec/models/mongoid/simple_mongoid.rb +23 -0
  153. data/spec/models/mongoid/simple_new_dsl_mongoid.rb +25 -0
  154. data/spec/models/mongoid/validator_mongoid.rb +100 -0
  155. data/spec/models/multi_transitioner.rb +34 -0
  156. data/spec/models/multiple_transitions_that_differ_only_by_guard.rb +31 -0
  157. data/spec/models/namespaced_multiple_example.rb +42 -0
  158. data/spec/models/no_initial_state.rb +25 -0
  159. data/spec/models/nobrainer/complex_no_brainer_example.rb +36 -0
  160. data/spec/models/nobrainer/invalid_persistor_no_brainer.rb +39 -0
  161. data/spec/models/nobrainer/no_scope_no_brainer.rb +21 -0
  162. data/spec/models/nobrainer/nobrainer_relationships.rb +25 -0
  163. data/spec/models/nobrainer/silent_persistor_no_brainer.rb +39 -0
  164. data/spec/models/nobrainer/simple_new_dsl_nobrainer.rb +25 -0
  165. data/spec/models/nobrainer/simple_no_brainer.rb +23 -0
  166. data/spec/models/nobrainer/validator_no_brainer.rb +98 -0
  167. data/spec/models/not_auto_loaded/process.rb +21 -0
  168. data/spec/models/parametrised_event.rb +42 -0
  169. data/spec/models/parametrised_event_multiple.rb +29 -0
  170. data/spec/models/process_with_new_dsl.rb +31 -0
  171. data/spec/models/provided_state.rb +24 -0
  172. data/spec/models/redis/complex_redis_example.rb +40 -0
  173. data/spec/models/redis/redis_multiple.rb +20 -0
  174. data/spec/models/redis/redis_simple.rb +20 -0
  175. data/spec/models/sequel/complex_sequel_example.rb +46 -0
  176. data/spec/models/sequel/invalid_persistor.rb +52 -0
  177. data/spec/models/sequel/sequel_multiple.rb +25 -0
  178. data/spec/models/sequel/sequel_simple.rb +26 -0
  179. data/spec/models/sequel/silent_persistor.rb +50 -0
  180. data/spec/models/sequel/transactor.rb +112 -0
  181. data/spec/models/sequel/validator.rb +93 -0
  182. data/spec/models/sequel/worker.rb +12 -0
  183. data/spec/models/silencer.rb +27 -0
  184. data/spec/models/simple_custom_example.rb +53 -0
  185. data/spec/models/simple_example.rb +23 -0
  186. data/spec/models/simple_example_with_guard_args.rb +17 -0
  187. data/spec/models/simple_multiple_example.rb +42 -0
  188. data/spec/models/state_machine_with_failed_event.rb +20 -0
  189. data/spec/models/states_on_one_line_example.rb +8 -0
  190. data/spec/models/sub_class.rb +41 -0
  191. data/spec/models/sub_class_with_more_states.rb +18 -0
  192. data/spec/models/sub_classing.rb +3 -0
  193. data/spec/models/super_class.rb +46 -0
  194. data/spec/models/this_name_better_not_be_in_use.rb +11 -0
  195. data/spec/models/valid_state_name.rb +23 -0
  196. data/spec/spec_helper.rb +36 -0
  197. data/spec/spec_helpers/active_record.rb +8 -0
  198. data/spec/spec_helpers/dynamoid.rb +35 -0
  199. data/spec/spec_helpers/mongoid.rb +26 -0
  200. data/spec/spec_helpers/nobrainer.rb +15 -0
  201. data/spec/spec_helpers/redis.rb +18 -0
  202. data/spec/spec_helpers/remove_warnings.rb +1 -0
  203. data/spec/spec_helpers/sequel.rb +7 -0
  204. data/spec/unit/abstract_class_spec.rb +27 -0
  205. data/spec/unit/api_spec.rb +100 -0
  206. data/spec/unit/basic_two_state_machines_example_spec.rb +10 -0
  207. data/spec/unit/callback_multiple_spec.rb +304 -0
  208. data/spec/unit/callbacks_spec.rb +521 -0
  209. data/spec/unit/complex_example_spec.rb +93 -0
  210. data/spec/unit/complex_multiple_example_spec.rb +115 -0
  211. data/spec/unit/edge_cases_spec.rb +16 -0
  212. data/spec/unit/event_multiple_spec.rb +73 -0
  213. data/spec/unit/event_naming_spec.rb +16 -0
  214. data/spec/unit/event_spec.rb +394 -0
  215. data/spec/unit/exception_spec.rb +11 -0
  216. data/spec/unit/guard_arguments_check_spec.rb +9 -0
  217. data/spec/unit/guard_multiple_spec.rb +60 -0
  218. data/spec/unit/guard_spec.rb +89 -0
  219. data/spec/unit/guard_with_params_multiple_spec.rb +10 -0
  220. data/spec/unit/guard_with_params_spec.rb +14 -0
  221. data/spec/unit/guard_without_from_specified_spec.rb +10 -0
  222. data/spec/unit/initial_state_multiple_spec.rb +15 -0
  223. data/spec/unit/initial_state_spec.rb +12 -0
  224. data/spec/unit/inspection_multiple_spec.rb +201 -0
  225. data/spec/unit/inspection_spec.rb +149 -0
  226. data/spec/unit/invoker_spec.rb +189 -0
  227. data/spec/unit/invokers/base_invoker_spec.rb +72 -0
  228. data/spec/unit/invokers/class_invoker_spec.rb +95 -0
  229. data/spec/unit/invokers/literal_invoker_spec.rb +86 -0
  230. data/spec/unit/invokers/proc_invoker_spec.rb +86 -0
  231. data/spec/unit/localizer_spec.rb +78 -0
  232. data/spec/unit/memory_leak_spec.rb +38 -0
  233. data/spec/unit/multiple_transitions_that_differ_only_by_guard_spec.rb +14 -0
  234. data/spec/unit/namespaced_multiple_example_spec.rb +75 -0
  235. data/spec/unit/new_dsl_spec.rb +12 -0
  236. data/spec/unit/override_warning_spec.rb +94 -0
  237. data/spec/unit/persistence/active_record_persistence_multiple_spec.rb +618 -0
  238. data/spec/unit/persistence/active_record_persistence_spec.rb +773 -0
  239. data/spec/unit/persistence/dynamoid_persistence_multiple_spec.rb +135 -0
  240. data/spec/unit/persistence/dynamoid_persistence_spec.rb +84 -0
  241. data/spec/unit/persistence/mongoid_persistence_multiple_spec.rb +200 -0
  242. data/spec/unit/persistence/mongoid_persistence_spec.rb +165 -0
  243. data/spec/unit/persistence/no_brainer_persistence_multiple_spec.rb +198 -0
  244. data/spec/unit/persistence/no_brainer_persistence_spec.rb +158 -0
  245. data/spec/unit/persistence/redis_persistence_multiple_spec.rb +88 -0
  246. data/spec/unit/persistence/redis_persistence_spec.rb +53 -0
  247. data/spec/unit/persistence/sequel_persistence_multiple_spec.rb +148 -0
  248. data/spec/unit/persistence/sequel_persistence_spec.rb +368 -0
  249. data/spec/unit/readme_spec.rb +41 -0
  250. data/spec/unit/reloading_spec.rb +15 -0
  251. data/spec/unit/rspec_matcher_spec.rb +88 -0
  252. data/spec/unit/simple_custom_example_spec.rb +39 -0
  253. data/spec/unit/simple_example_spec.rb +57 -0
  254. data/spec/unit/simple_multiple_example_spec.rb +91 -0
  255. data/spec/unit/state_spec.rb +89 -0
  256. data/spec/unit/states_on_one_line_example_spec.rb +16 -0
  257. data/spec/unit/subclassing_multiple_spec.rb +74 -0
  258. data/spec/unit/subclassing_spec.rb +46 -0
  259. data/spec/unit/transition_spec.rb +436 -0
  260. data/test/minitest_helper.rb +57 -0
  261. data/test/unit/minitest_matcher_test.rb +80 -0
  262. metadata +609 -0
@@ -0,0 +1,521 @@
1
+ require 'spec_helper'
2
+ Dir[File.dirname(__FILE__) + "/../models/callbacks/*.rb"].sort.each { |f| require File.expand_path(f) }
3
+
4
+ shared_examples 'an implemented callback that accepts error' do
5
+ context 'with callback defined' do
6
+ it "should run error_callback if an exception is raised and always return false" do
7
+ aasm_model.class.send(:define_method, callback_name) do |e|
8
+ @data = [e]
9
+ end
10
+
11
+ allow(aasm_model).to receive(:before_enter).and_raise(e = StandardError.new)
12
+
13
+ expect(aasm_model.safe_close!).to be false
14
+ expect(aasm_model.data).to eql [e]
15
+ end
16
+
17
+ it "should run error_callback without parameters if callback does not support any" do
18
+ aasm_model.class.send(:define_method, callback_name) do |e|
19
+ @data = []
20
+ end
21
+
22
+ allow(aasm_model).to receive(:before_enter).and_raise(e = StandardError.new)
23
+
24
+ aasm_model.safe_close!('arg1', 'arg2')
25
+ expect(aasm_model.data).to eql []
26
+ end
27
+
28
+ it "should run error_callback with parameters if callback supports them" do
29
+ aasm_model.class.send(:define_method, callback_name) do |e, arg1, arg2|
30
+ @data = [arg1, arg2]
31
+ end
32
+
33
+ allow(aasm_model).to receive(:before_enter).and_raise(e = StandardError.new)
34
+
35
+ aasm_model.safe_close!('arg1', 'arg2')
36
+ expect(aasm_model.data).to eql ['arg1', 'arg2']
37
+ end
38
+ end
39
+ end
40
+
41
+ shared_examples 'an implemented callback' do
42
+ context 'with callback defined' do
43
+ it 'should run callback without parameters if callback does not support any' do
44
+ aasm_model.class.send(:define_method, callback_name) do
45
+ @data = ['callback-was-called']
46
+ end
47
+
48
+ aasm_model.safe_close!
49
+ expect(aasm_model.data).to eql ['callback-was-called']
50
+ end
51
+
52
+ it 'should run callback with parameters if callback supports them' do
53
+ aasm_model.class.send(:define_method, callback_name) do |arg1, arg2|
54
+ @data = [arg1, arg2]
55
+ end
56
+
57
+ aasm_model.safe_close!('arg1', 'arg2')
58
+ expect(aasm_model.data).to eql ['arg1', 'arg2']
59
+ end
60
+ end
61
+ end
62
+
63
+ describe 'callbacks for the new DSL' do
64
+
65
+ it "be called in order" do
66
+ show_debug_log = false
67
+
68
+ callback = Callbacks::Basic.new(:log => show_debug_log)
69
+ callback.aasm.current_state
70
+
71
+ unless show_debug_log
72
+ expect(callback).to receive(:before_all_events).once.ordered
73
+ expect(callback).to receive(:before_event).once.ordered
74
+ expect(callback).to receive(:event_guard).once.ordered.and_return(true)
75
+ expect(callback).to receive(:transition_guard).once.ordered.and_return(true)
76
+ expect(callback).to receive(:before_exit_open).once.ordered # these should be before the state changes
77
+ expect(callback).to receive(:exit_open).once.ordered
78
+ # expect(callback).to receive(:event_guard).once.ordered.and_return(true)
79
+ # expect(callback).to receive(:transition_guard).once.ordered.and_return(true)
80
+ expect(callback).to receive(:after_all_transitions).once.ordered
81
+ expect(callback).to receive(:after_transition).once.ordered
82
+ expect(callback).to receive(:before_enter_closed).once.ordered
83
+ expect(callback).to receive(:enter_closed).once.ordered
84
+ expect(callback).to receive(:aasm_write_state).once.ordered.and_return(true) # this is when the state changes
85
+ expect(callback).to receive(:after_exit_open).once.ordered # these should be after the state changes
86
+ expect(callback).to receive(:after_enter_closed).once.ordered
87
+ expect(callback).to receive(:after_event).once.ordered
88
+ expect(callback).to receive(:after_all_events).once.ordered
89
+ expect(callback).to receive(:ensure_event).once.ordered
90
+ expect(callback).to receive(:ensure_on_all_events).once.ordered
91
+ end
92
+
93
+ # puts "------- close!"
94
+ callback.close!
95
+ end
96
+
97
+
98
+ it "works fine after reload" do
99
+ show_debug_log = false
100
+
101
+ callback = Callbacks::Basic.new(:log => show_debug_log)
102
+ callback.aasm.current_state
103
+
104
+ # reload the class
105
+ Callbacks.send(:remove_const, :Basic)
106
+ load 'models/callbacks/basic.rb'
107
+
108
+ unless show_debug_log
109
+ expect(callback).to receive(:before_event).once.ordered
110
+ expect(callback).to receive(:event_guard).once.ordered.and_return(true)
111
+ expect(callback).to receive(:transition_guard).once.ordered.and_return(true)
112
+ expect(callback).to receive(:before_exit_open).once.ordered # these should be before the state changes
113
+ expect(callback).to receive(:exit_open).once.ordered
114
+ # expect(callback).to receive(:event_guard).once.ordered.and_return(true)
115
+ # expect(callback).to receive(:transition_guard).once.ordered.and_return(true)
116
+ expect(callback).to receive(:after_all_transitions).once.ordered
117
+ expect(callback).to receive(:after_transition).once.ordered
118
+ expect(callback).to receive(:before_enter_closed).once.ordered
119
+ expect(callback).to receive(:enter_closed).once.ordered
120
+ expect(callback).to receive(:aasm_write_state).once.ordered.and_return(true) # this is when the state changes
121
+ expect(callback).to receive(:event_before_success).once.ordered
122
+ expect(callback).to receive(:success_transition).once.ordered.and_return(true) # these should be after the state changes
123
+ expect(callback).to receive(:after_exit_open).once.ordered
124
+ expect(callback).to receive(:after_enter_closed).once.ordered
125
+ expect(callback).to receive(:after_event).once.ordered
126
+ end
127
+
128
+ # puts "------- close!"
129
+ callback.close!
130
+ end
131
+
132
+ it "does not run any state callback if the event guard fails" do
133
+ callback = Callbacks::Basic.new(:log => false)
134
+ callback.aasm.current_state
135
+
136
+ expect(callback).to receive(:before_all_events).once.ordered
137
+ expect(callback).to receive(:before_event).once.ordered
138
+ expect(callback).to receive(:event_guard).once.ordered.and_return(false)
139
+ expect(callback).to_not receive(:transition_guard)
140
+ expect(callback).to_not receive(:before_exit_open)
141
+ expect(callback).to_not receive(:exit_open)
142
+ expect(callback).to_not receive(:after_all_transitions)
143
+ expect(callback).to_not receive(:after_transition)
144
+ expect(callback).to_not receive(:before_enter_closed)
145
+ expect(callback).to_not receive(:enter_closed)
146
+ expect(callback).to_not receive(:aasm_write_state)
147
+ expect(callback).to_not receive(:event_before_success)
148
+ expect(callback).to_not receive(:success_transition)
149
+ expect(callback).to_not receive(:after_exit_open)
150
+ expect(callback).to_not receive(:after_enter_closed)
151
+ expect(callback).to_not receive(:after_event)
152
+ expect(callback).to_not receive(:after_all_events)
153
+ expect(callback).to receive(:ensure_event).once.ordered
154
+ expect(callback).to receive(:ensure_on_all_events).once.ordered
155
+
156
+ expect {
157
+ callback.close!
158
+ }.to raise_error(AASM::InvalidTransition)
159
+ end
160
+
161
+ it "handles private callback methods as well" do
162
+ show_debug_log = false
163
+
164
+ callback = Callbacks::PrivateMethod.new(:log => show_debug_log)
165
+ callback.aasm.current_state
166
+
167
+ # puts "------- close!"
168
+ expect {
169
+ callback.close!
170
+ }.to_not raise_error
171
+ end
172
+
173
+ context "if the transition guard fails" do
174
+ it "does not run any state callback if guard is defined inline" do
175
+ show_debug_log = false
176
+ callback = Callbacks::Basic.new(:log => show_debug_log, :fail_transition_guard => true)
177
+ callback.aasm.current_state
178
+
179
+ unless show_debug_log
180
+ expect(callback).to receive(:before_all_events).once.ordered
181
+ expect(callback).to receive(:before_event).once.ordered
182
+ expect(callback).to receive(:event_guard).once.ordered.and_return(true)
183
+ expect(callback).to receive(:transition_guard).once.ordered.and_return(false)
184
+ expect(callback).to_not receive(:before_exit_open)
185
+ expect(callback).to_not receive(:exit_open)
186
+ expect(callback).to_not receive(:after_all_transitions)
187
+ expect(callback).to_not receive(:after_transition)
188
+ expect(callback).to_not receive(:before_enter_closed)
189
+ expect(callback).to_not receive(:enter_closed)
190
+ expect(callback).to_not receive(:aasm_write_state)
191
+ expect(callback).to_not receive(:event_before_success)
192
+ expect(callback).to_not receive(:success_transition)
193
+ expect(callback).to_not receive(:after_exit_open)
194
+ expect(callback).to_not receive(:after_enter_closed)
195
+ expect(callback).to_not receive(:after_event)
196
+ expect(callback).to_not receive(:after_all_events)
197
+ expect(callback).to receive(:ensure_event).once.ordered
198
+ expect(callback).to receive(:ensure_on_all_events).once.ordered
199
+ end
200
+
201
+ expect {
202
+ callback.close!
203
+ }.to raise_error(AASM::InvalidTransition)
204
+ end
205
+
206
+ it "does not propagate failures to next attempt of same transition" do
207
+ callback = Callbacks::Basic.new(:log => false, :fail_transition_guard => true)
208
+
209
+ expect {
210
+ callback.close!
211
+ }.to raise_error(AASM::InvalidTransition, "Event 'close' cannot transition from 'open'. Failed callback(s): [:transition_guard].")
212
+
213
+ expect {
214
+ callback.close!
215
+ }.to raise_error(AASM::InvalidTransition, "Event 'close' cannot transition from 'open'. Failed callback(s): [:transition_guard].")
216
+ end
217
+
218
+ it "does not propagate failures to next attempt of same event when no transition is applicable" do
219
+ callback = Callbacks::Basic.new(:log => false, :fail_transition_guard => true)
220
+
221
+ expect {
222
+ callback.close!
223
+ }.to raise_error(AASM::InvalidTransition, "Event 'close' cannot transition from 'open'. Failed callback(s): [:transition_guard].")
224
+
225
+ callback.aasm.current_state = :closed
226
+
227
+ expect {
228
+ callback.close!
229
+ }.to raise_error(AASM::InvalidTransition, "Event 'close' cannot transition from 'closed'.")
230
+ end
231
+
232
+ it "does not run transition_guard twice for multiple permitted transitions" do
233
+ show_debug_log = false
234
+ callback = Callbacks::MultipleTransitionsTransitionGuard.new(:log => show_debug_log, :fail_transition_guard => true)
235
+ callback.aasm.current_state
236
+
237
+ unless show_debug_log
238
+ expect(callback).to receive(:before).once.ordered
239
+ expect(callback).to receive(:event_guard).once.ordered.and_return(true)
240
+ expect(callback).to receive(:transition_guard).once.ordered.and_return(false)
241
+ expect(callback).to receive(:event_guard).once.ordered.and_return(true)
242
+ expect(callback).to receive(:before_exit_open).once.ordered
243
+ expect(callback).to receive(:exit_open).once.ordered
244
+ expect(callback).to receive(:aasm_write_state).once.ordered.and_return(true) # this is when the state changes
245
+ expect(callback).to receive(:after_exit_open).once.ordered
246
+ expect(callback).to receive(:after).once.ordered
247
+
248
+ expect(callback).to_not receive(:transitioning)
249
+ expect(callback).to_not receive(:event_before_success)
250
+ expect(callback).to_not receive(:success_transition)
251
+ expect(callback).to_not receive(:before_enter_closed)
252
+ expect(callback).to_not receive(:enter_closed)
253
+ expect(callback).to_not receive(:after_enter_closed)
254
+ end
255
+
256
+ callback.close!
257
+ expect(callback.aasm.current_state).to eql :failed
258
+ end
259
+
260
+ it "does not run any state callback if guard is defined with block" do
261
+ callback = Callbacks::GuardWithinBlock.new #(:log => true, :fail_transition_guard => true)
262
+ callback.aasm.current_state
263
+
264
+ expect(callback).to receive(:before).once.ordered
265
+ expect(callback).to receive(:event_guard).once.ordered.and_return(true)
266
+ expect(callback).to receive(:transition_guard).once.ordered.and_return(false)
267
+ expect(callback).to_not receive(:before_exit_open)
268
+ expect(callback).to_not receive(:exit_open)
269
+ expect(callback).to_not receive(:transitioning)
270
+ expect(callback).to_not receive(:before_enter_closed)
271
+ expect(callback).to_not receive(:enter_closed)
272
+ expect(callback).to_not receive(:aasm_write_state)
273
+ expect(callback).to_not receive(:event_before_success)
274
+ expect(callback).to_not receive(:success_transition)
275
+ expect(callback).to_not receive(:after_exit_open)
276
+ expect(callback).to_not receive(:after_enter_closed)
277
+ expect(callback).to_not receive(:after)
278
+
279
+ expect {
280
+ callback.close!
281
+ }.to raise_error(AASM::InvalidTransition)
282
+ end
283
+ end
284
+
285
+ it "should properly pass arguments" do
286
+ cb = Callbacks::WithArgs.new(:log => false)
287
+ cb.aasm.current_state
288
+
289
+ cb.reset_data
290
+ cb.close!(:arg1, :arg2)
291
+ expect(cb.data).to eql 'before(:arg1,:arg2) before_exit_open(:arg1,:arg2) transition_proc(:arg1,:arg2) before_enter_closed(:arg1,:arg2) aasm_write_state transition_success(:arg1,:arg2) after_exit_open(:arg1,:arg2) after_enter_closed(:arg1,:arg2) after(:arg1,:arg2)'
292
+ end
293
+
294
+ it "should call the callbacks given the to-state as argument" do
295
+ cb = Callbacks::WithStateArg.new
296
+ expect(cb).to receive(:before_method).with(:arg1).once.ordered
297
+ expect(cb).to receive(:transition_method).never
298
+ expect(cb).to receive(:success_method).never
299
+ expect(cb).to receive(:transition_method2).with(:arg1).once.ordered
300
+ expect(cb).to receive(:success_method2).with(:arg1).once.ordered
301
+ expect(cb).to receive(:after_method).with(:arg1).once.ordered
302
+ cb.close!(:out_to_lunch, :arg1)
303
+
304
+ cb = Callbacks::WithStateArg.new
305
+ some_object = double('some object')
306
+ expect(cb).to receive(:before_method).with(some_object).once.ordered
307
+ expect(cb).to receive(:transition_method2).with(some_object).once.ordered
308
+ expect(cb).to receive(:success_method2).with(some_object).once.ordered
309
+ expect(cb).to receive(:after_method).with(some_object).once.ordered
310
+ cb.close!(:out_to_lunch, some_object)
311
+ end
312
+
313
+ it "should call the proper methods just with arguments" do
314
+ cb = Callbacks::WithStateArg.new
315
+ expect(cb).to receive(:before_method).with(:arg1).once.ordered
316
+ expect(cb).to receive(:transition_method).with(:arg1).once.ordered
317
+ expect(cb).to receive(:transition_method).never
318
+ expect(cb).to receive(:before_success_method).with(:arg1).once.ordered
319
+ expect(cb).to receive(:success_method).with(:arg1).once.ordered
320
+ expect(cb).to receive(:success_method3).with(:arg1).once.ordered
321
+ expect(cb).to receive(:success_method).never
322
+ expect(cb).to receive(:after_method).with(:arg1).once.ordered
323
+ cb.close!(:arg1)
324
+
325
+ cb = Callbacks::WithStateArg.new
326
+ some_object = double('some object')
327
+ expect(cb).to receive(:before_method).with(some_object).once.ordered
328
+ expect(cb).to receive(:transition_method).with(some_object).once.ordered
329
+ expect(cb).to receive(:transition_method).never
330
+ expect(cb).to receive(:before_success_method).with(some_object).once.ordered
331
+ expect(cb).to receive(:success_method).with(some_object).once.ordered
332
+ expect(cb).to receive(:success_method3).with(some_object).once.ordered
333
+ expect(cb).to receive(:success_method).never
334
+ expect(cb).to receive(:after_method).with(some_object).once.ordered
335
+ cb.close!(some_object)
336
+ end
337
+ end
338
+
339
+ describe 'event callbacks' do
340
+ describe "with an error callback defined" do
341
+ before do
342
+ class Foo
343
+ # this hack is needed to allow testing of parameters, since RSpec
344
+ # destroys a method's arity when mocked
345
+ attr_accessor :data
346
+
347
+ aasm do
348
+ event :safe_close, :success => :success_callback, :error => :error_callback do
349
+ transitions :to => :closed, :from => [:open], :success => :transition_success_callback
350
+ end
351
+ end
352
+ end
353
+
354
+ @foo = Foo.new
355
+ end
356
+
357
+ it_behaves_like 'an implemented callback that accepts error' do
358
+ let(:aasm_model) { @foo }
359
+ let(:callback_name) { :error_callback }
360
+ end
361
+
362
+ it "should raise NoMethodError if exception is raised and error_callback is declared but not defined" do
363
+ allow(@foo).to receive(:before_enter).and_raise(StandardError)
364
+ expect{@foo.safe_close!}.to raise_error(NoMethodError)
365
+ end
366
+
367
+ it "should propagate an error if no error callback is declared" do
368
+ allow(@foo).to receive(:before_enter).and_raise("Cannot enter safe")
369
+ expect{@foo.close!}.to raise_error(StandardError, "Cannot enter safe")
370
+ end
371
+ end
372
+
373
+ describe 'with an ensure callback defined' do
374
+ before do
375
+ class Foo
376
+ # this hack is needed to allow testing of parameters, since RSpec
377
+ # destroys a method's arity when mocked
378
+ attr_accessor :data
379
+
380
+ aasm do
381
+ event :safe_close, :success => :success_callback, :ensure => :ensure_callback do
382
+ transitions :to => :closed, :from => [:open]
383
+ end
384
+ end
385
+ end
386
+
387
+ @foo = Foo.new
388
+ end
389
+
390
+ it_behaves_like 'an implemented callback' do
391
+ let(:aasm_model) { @foo }
392
+ let(:callback_name) { :ensure_callback }
393
+ end
394
+
395
+ it "should raise NoMethodError if ensure_callback is declared but not defined" do
396
+ expect{@foo.safe_close!}.to raise_error(NoMethodError)
397
+ end
398
+
399
+ it "should not raise any error if no ensure_callback is declared" do
400
+ expect{@foo.close!}.to_not raise_error
401
+ end
402
+ end
403
+
404
+ describe "with aasm_event_fired defined" do
405
+ before do
406
+ @foo = Foo.new
407
+ def @foo.aasm_event_fired(event, from, to); end
408
+ end
409
+
410
+ it 'should call it for successful bang fire' do
411
+ expect(@foo).to receive(:aasm_event_fired).with(:close, :open, :closed)
412
+ @foo.close!
413
+ end
414
+
415
+ it 'should call it for successful non-bang fire' do
416
+ expect(@foo).to receive(:aasm_event_fired)
417
+ @foo.close
418
+ end
419
+
420
+ it 'should not call it for failing bang fire' do
421
+ allow(@foo.aasm).to receive(:set_current_state_with_persistence).and_return(false)
422
+ expect(@foo).not_to receive(:aasm_event_fired)
423
+ @foo.close!
424
+ end
425
+ end
426
+
427
+ describe "with aasm_event_failed defined" do
428
+ before do
429
+ @foo = Foo.new
430
+ def @foo.aasm_event_failed(event, from); end
431
+ end
432
+
433
+ it 'should call it when transition failed for bang fire' do
434
+ expect(@foo).to receive(:aasm_event_failed).with(:null, :open)
435
+ expect {@foo.null!}.to raise_error(AASM::InvalidTransition)
436
+ end
437
+
438
+ it 'should call it when transition failed for non-bang fire' do
439
+ expect(@foo).to receive(:aasm_event_failed).with(:null, :open)
440
+ expect {@foo.null}.to raise_error(AASM::InvalidTransition)
441
+ end
442
+
443
+ it 'should not call it if persist fails for bang fire' do
444
+ allow(@foo.aasm).to receive(:set_current_state_with_persistence).and_return(false)
445
+ expect(@foo).to receive(:aasm_event_failed)
446
+ @foo.close!
447
+ end
448
+ end
449
+ end
450
+
451
+ describe 'global error_on_all_events_callback callbacks' do
452
+ describe "with an error_on_all_events" do
453
+ before do
454
+ class FooGlobal
455
+ # this hack is needed to allow testing of parameters, since RSpec
456
+ # destroys a method's arity when mocked
457
+ attr_accessor :data
458
+
459
+ aasm do
460
+ error_on_all_events :error_on_all_events_callback
461
+
462
+ event :safe_close do
463
+ transitions :to => :closed, :from => [:open]
464
+ end
465
+ end
466
+ end
467
+
468
+ @foo = FooGlobal.new
469
+ end
470
+
471
+ it_behaves_like 'an implemented callback that accepts error' do
472
+ let(:aasm_model) { @foo }
473
+ let(:callback_name) { :error_on_all_events_callback }
474
+ end
475
+
476
+ it "should raise NoMethodError if exception is raised and error_callback is declared but not defined" do
477
+ allow(@foo).to receive(:before_enter).and_raise(StandardError)
478
+ expect{@foo.safe_close!}.to raise_error(NoMethodError)
479
+ end
480
+
481
+ it "should raise NoMethodError if no error callback is declared" do
482
+ allow(@foo).to receive(:before_enter).and_raise("Cannot enter safe")
483
+ expect{@foo.close!}.to raise_error(NoMethodError)
484
+ end
485
+ end
486
+ end
487
+
488
+ describe 'global ensure_on_all_events_callback callbacks' do
489
+ describe "with an ensure_on_all_events" do
490
+ before do
491
+ class FooGlobal
492
+ # this hack is needed to allow testing of parameters, since RSpec
493
+ # destroys a method's arity when mocked
494
+ attr_accessor :data
495
+
496
+ aasm do
497
+ ensure_on_all_events :ensure_on_all_events_callback
498
+
499
+ event :safe_close do
500
+ transitions :to => :closed, :from => [:open]
501
+ end
502
+ end
503
+ end
504
+
505
+ @foo = FooGlobal.new
506
+ end
507
+
508
+ it_behaves_like 'an implemented callback' do
509
+ let(:aasm_model) { @foo }
510
+ let(:callback_name) { :ensure_on_all_events_callback }
511
+ end
512
+
513
+ it "should raise NoMethodError if ensure_on_all_events callback is declared but not defined" do
514
+ expect{@foo.safe_close!}.to raise_error(NoMethodError)
515
+ end
516
+
517
+ it "should raise NoMethodError if no ensure_on_all_events callback is declared" do
518
+ expect{@foo.close!}.to raise_error(NoMethodError)
519
+ end
520
+ end
521
+ end