aasm 2.1.1 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (275) 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 +82 -0
  7. data/API +34 -0
  8. data/Appraisals +67 -0
  9. data/CHANGELOG.md +453 -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/{MIT-LICENSE → LICENSE} +1 -1
  17. data/PLANNED_CHANGES.md +11 -0
  18. data/README.md +1524 -0
  19. data/README_FROM_VERSION_3_TO_4.md +240 -0
  20. data/Rakefile +20 -84
  21. data/TESTING.md +25 -0
  22. data/aasm.gemspec +37 -0
  23. data/docker-compose.yml +40 -0
  24. data/gemfiles/norails.gemfile +10 -0
  25. data/gemfiles/rails_4.2.gemfile +17 -0
  26. data/gemfiles/rails_4.2_mongoid_5.gemfile +12 -0
  27. data/gemfiles/rails_4.2_nobrainer.gemfile +9 -0
  28. data/gemfiles/rails_5.0.gemfile +14 -0
  29. data/gemfiles/rails_5.0_nobrainer.gemfile +9 -0
  30. data/gemfiles/rails_5.1.gemfile +14 -0
  31. data/gemfiles/rails_5.2.gemfile +14 -0
  32. data/lib/aasm/aasm.rb +160 -137
  33. data/lib/aasm/base.rb +290 -0
  34. data/lib/aasm/configuration.rb +48 -0
  35. data/lib/aasm/core/event.rb +177 -0
  36. data/lib/aasm/core/invoker.rb +129 -0
  37. data/lib/aasm/core/invokers/base_invoker.rb +75 -0
  38. data/lib/aasm/core/invokers/class_invoker.rb +52 -0
  39. data/lib/aasm/core/invokers/literal_invoker.rb +47 -0
  40. data/lib/aasm/core/invokers/proc_invoker.rb +59 -0
  41. data/lib/aasm/core/state.rb +91 -0
  42. data/lib/aasm/core/transition.rb +83 -0
  43. data/lib/aasm/dsl_helper.rb +32 -0
  44. data/lib/aasm/errors.rb +21 -0
  45. data/lib/aasm/instance_base.rb +133 -0
  46. data/lib/aasm/localizer.rb +64 -0
  47. data/lib/aasm/minitest/allow_event.rb +13 -0
  48. data/lib/aasm/minitest/allow_transition_to.rb +13 -0
  49. data/lib/aasm/minitest/have_state.rb +13 -0
  50. data/lib/aasm/minitest/transition_from.rb +21 -0
  51. data/lib/aasm/minitest.rb +5 -0
  52. data/lib/aasm/minitest_spec.rb +15 -0
  53. data/lib/aasm/persistence/active_record_persistence.rb +108 -173
  54. data/lib/aasm/persistence/base.rb +89 -0
  55. data/lib/aasm/persistence/core_data_query_persistence.rb +94 -0
  56. data/lib/aasm/persistence/dynamoid_persistence.rb +92 -0
  57. data/lib/aasm/persistence/mongoid_persistence.rb +126 -0
  58. data/lib/aasm/persistence/no_brainer_persistence.rb +105 -0
  59. data/lib/aasm/persistence/orm.rb +154 -0
  60. data/lib/aasm/persistence/plain_persistence.rb +26 -0
  61. data/lib/aasm/persistence/redis_persistence.rb +112 -0
  62. data/lib/aasm/persistence/sequel_persistence.rb +83 -0
  63. data/lib/aasm/persistence.rb +48 -10
  64. data/lib/aasm/rspec/allow_event.rb +26 -0
  65. data/lib/aasm/rspec/allow_transition_to.rb +26 -0
  66. data/lib/aasm/rspec/have_state.rb +22 -0
  67. data/lib/aasm/rspec/transition_from.rb +36 -0
  68. data/lib/aasm/rspec.rb +5 -0
  69. data/lib/aasm/state_machine.rb +40 -22
  70. data/lib/aasm/state_machine_store.rb +76 -0
  71. data/lib/aasm/version.rb +3 -0
  72. data/lib/aasm.rb +21 -1
  73. data/lib/generators/aasm/aasm_generator.rb +16 -0
  74. data/lib/generators/aasm/orm_helpers.rb +41 -0
  75. data/lib/generators/active_record/aasm_generator.rb +40 -0
  76. data/lib/generators/active_record/templates/migration.rb +8 -0
  77. data/lib/generators/active_record/templates/migration_existing.rb +5 -0
  78. data/lib/generators/mongoid/aasm_generator.rb +28 -0
  79. data/lib/generators/nobrainer/aasm_generator.rb +28 -0
  80. data/lib/motion-aasm.rb +37 -0
  81. data/spec/database.rb +57 -0
  82. data/spec/database.yml +3 -0
  83. data/spec/en.yml +9 -0
  84. data/spec/generators/active_record_generator_spec.rb +53 -0
  85. data/spec/generators/mongoid_generator_spec.rb +31 -0
  86. data/spec/generators/no_brainer_generator_spec.rb +29 -0
  87. data/spec/localizer_test_model_deprecated_style.yml +13 -0
  88. data/spec/localizer_test_model_new_style.yml +11 -0
  89. data/spec/models/active_record/active_record_callback.rb +93 -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 +42 -0
  98. data/spec/models/active_record/namespaced.rb +16 -0
  99. data/spec/models/active_record/no_direct_assignment.rb +21 -0
  100. data/spec/models/active_record/no_scope.rb +21 -0
  101. data/spec/models/active_record/persisted_state.rb +12 -0
  102. data/spec/models/active_record/person.rb +23 -0
  103. data/spec/models/active_record/provided_and_persisted_state.rb +24 -0
  104. data/spec/models/active_record/reader.rb +7 -0
  105. data/spec/models/active_record/readme_job.rb +21 -0
  106. data/spec/models/active_record/silent_persistor.rb +29 -0
  107. data/spec/models/active_record/simple_new_dsl.rb +32 -0
  108. data/spec/models/active_record/thief.rb +29 -0
  109. data/spec/models/active_record/timestamp_example.rb +16 -0
  110. data/spec/models/active_record/transactor.rb +124 -0
  111. data/spec/models/active_record/transient.rb +6 -0
  112. data/spec/models/active_record/validator.rb +118 -0
  113. data/spec/models/active_record/with_enum.rb +39 -0
  114. data/spec/models/active_record/with_enum_without_column.rb +38 -0
  115. data/spec/models/active_record/with_false_enum.rb +31 -0
  116. data/spec/models/active_record/with_true_enum.rb +39 -0
  117. data/spec/models/active_record/work.rb +3 -0
  118. data/spec/models/active_record/worker.rb +2 -0
  119. data/spec/models/active_record/writer.rb +6 -0
  120. data/spec/models/basic_two_state_machines_example.rb +25 -0
  121. data/spec/models/callbacks/basic.rb +98 -0
  122. data/spec/models/callbacks/basic_multiple.rb +75 -0
  123. data/spec/models/callbacks/guard_within_block.rb +67 -0
  124. data/spec/models/callbacks/guard_within_block_multiple.rb +66 -0
  125. data/spec/models/callbacks/multiple_transitions_transition_guard.rb +66 -0
  126. data/spec/models/callbacks/multiple_transitions_transition_guard_multiple.rb +65 -0
  127. data/spec/models/callbacks/private_method.rb +44 -0
  128. data/spec/models/callbacks/private_method_multiple.rb +44 -0
  129. data/spec/models/callbacks/with_args.rb +62 -0
  130. data/spec/models/callbacks/with_args_multiple.rb +61 -0
  131. data/spec/models/callbacks/with_state_arg.rb +34 -0
  132. data/spec/models/callbacks/with_state_arg_multiple.rb +29 -0
  133. data/spec/models/complex_example.rb +222 -0
  134. data/spec/models/conversation.rb +93 -0
  135. data/spec/models/default_state.rb +12 -0
  136. data/spec/models/double_definer.rb +21 -0
  137. data/spec/models/dynamoid/complex_dynamoid_example.rb +37 -0
  138. data/spec/models/dynamoid/dynamoid_multiple.rb +18 -0
  139. data/spec/models/dynamoid/dynamoid_simple.rb +18 -0
  140. data/spec/models/foo.rb +106 -0
  141. data/spec/models/foo_callback_multiple.rb +45 -0
  142. data/spec/models/guard_arguments_check.rb +17 -0
  143. data/spec/models/guard_with_params.rb +24 -0
  144. data/spec/models/guard_with_params_multiple.rb +18 -0
  145. data/spec/models/guardian.rb +58 -0
  146. data/spec/models/guardian_multiple.rb +48 -0
  147. data/spec/models/guardian_without_from_specified.rb +18 -0
  148. data/spec/models/initial_state_proc.rb +31 -0
  149. data/spec/models/mongoid/complex_mongoid_example.rb +37 -0
  150. data/spec/models/mongoid/invalid_persistor_mongoid.rb +39 -0
  151. data/spec/models/mongoid/mongoid_relationships.rb +26 -0
  152. data/spec/models/mongoid/no_scope_mongoid.rb +21 -0
  153. data/spec/models/mongoid/silent_persistor_mongoid.rb +39 -0
  154. data/spec/models/mongoid/simple_mongoid.rb +23 -0
  155. data/spec/models/mongoid/simple_new_dsl_mongoid.rb +25 -0
  156. data/spec/models/mongoid/timestamp_example_mongoid.rb +20 -0
  157. data/spec/models/mongoid/validator_mongoid.rb +100 -0
  158. data/spec/models/multi_transitioner.rb +34 -0
  159. data/spec/models/multiple_transitions_that_differ_only_by_guard.rb +31 -0
  160. data/spec/models/namespaced_multiple_example.rb +42 -0
  161. data/spec/models/no_initial_state.rb +25 -0
  162. data/spec/models/nobrainer/complex_no_brainer_example.rb +36 -0
  163. data/spec/models/nobrainer/invalid_persistor_no_brainer.rb +39 -0
  164. data/spec/models/nobrainer/no_scope_no_brainer.rb +21 -0
  165. data/spec/models/nobrainer/nobrainer_relationships.rb +25 -0
  166. data/spec/models/nobrainer/silent_persistor_no_brainer.rb +39 -0
  167. data/spec/models/nobrainer/simple_new_dsl_nobrainer.rb +25 -0
  168. data/spec/models/nobrainer/simple_no_brainer.rb +23 -0
  169. data/spec/models/nobrainer/validator_no_brainer.rb +98 -0
  170. data/spec/models/not_auto_loaded/process.rb +21 -0
  171. data/spec/models/parametrised_event.rb +42 -0
  172. data/spec/models/parametrised_event_multiple.rb +29 -0
  173. data/spec/models/process_with_new_dsl.rb +31 -0
  174. data/spec/models/provided_state.rb +24 -0
  175. data/spec/models/redis/complex_redis_example.rb +40 -0
  176. data/spec/models/redis/redis_multiple.rb +20 -0
  177. data/spec/models/redis/redis_simple.rb +20 -0
  178. data/spec/models/sequel/complex_sequel_example.rb +46 -0
  179. data/spec/models/sequel/invalid_persistor.rb +52 -0
  180. data/spec/models/sequel/sequel_multiple.rb +25 -0
  181. data/spec/models/sequel/sequel_simple.rb +26 -0
  182. data/spec/models/sequel/silent_persistor.rb +50 -0
  183. data/spec/models/sequel/transactor.rb +112 -0
  184. data/spec/models/sequel/validator.rb +93 -0
  185. data/spec/models/sequel/worker.rb +12 -0
  186. data/spec/models/silencer.rb +27 -0
  187. data/spec/models/simple_custom_example.rb +53 -0
  188. data/spec/models/simple_example.rb +23 -0
  189. data/spec/models/simple_example_with_guard_args.rb +17 -0
  190. data/spec/models/simple_multiple_example.rb +42 -0
  191. data/spec/models/state_machine_with_failed_event.rb +20 -0
  192. data/spec/models/states_on_one_line_example.rb +8 -0
  193. data/spec/models/sub_class.rb +41 -0
  194. data/spec/models/sub_class_with_more_states.rb +18 -0
  195. data/spec/models/sub_classing.rb +3 -0
  196. data/spec/models/super_class.rb +46 -0
  197. data/spec/models/this_name_better_not_be_in_use.rb +11 -0
  198. data/spec/models/timestamps_example.rb +19 -0
  199. data/spec/models/timestamps_with_named_machine_example.rb +13 -0
  200. data/spec/models/valid_state_name.rb +23 -0
  201. data/spec/spec_helper.rb +41 -0
  202. data/spec/spec_helpers/active_record.rb +8 -0
  203. data/spec/spec_helpers/dynamoid.rb +35 -0
  204. data/spec/spec_helpers/mongoid.rb +26 -0
  205. data/spec/spec_helpers/nobrainer.rb +15 -0
  206. data/spec/spec_helpers/redis.rb +18 -0
  207. data/spec/spec_helpers/remove_warnings.rb +1 -0
  208. data/spec/spec_helpers/sequel.rb +7 -0
  209. data/spec/unit/abstract_class_spec.rb +27 -0
  210. data/spec/unit/api_spec.rb +104 -0
  211. data/spec/unit/basic_two_state_machines_example_spec.rb +10 -0
  212. data/spec/unit/callback_multiple_spec.rb +304 -0
  213. data/spec/unit/callbacks_spec.rb +521 -0
  214. data/spec/unit/complex_example_spec.rb +93 -0
  215. data/spec/unit/complex_multiple_example_spec.rb +115 -0
  216. data/spec/unit/edge_cases_spec.rb +16 -0
  217. data/spec/unit/event_multiple_spec.rb +73 -0
  218. data/spec/unit/event_naming_spec.rb +16 -0
  219. data/spec/unit/event_spec.rb +394 -0
  220. data/spec/unit/exception_spec.rb +11 -0
  221. data/spec/unit/guard_arguments_check_spec.rb +9 -0
  222. data/spec/unit/guard_multiple_spec.rb +60 -0
  223. data/spec/unit/guard_spec.rb +89 -0
  224. data/spec/unit/guard_with_params_multiple_spec.rb +10 -0
  225. data/spec/unit/guard_with_params_spec.rb +14 -0
  226. data/spec/unit/guard_without_from_specified_spec.rb +10 -0
  227. data/spec/unit/initial_state_multiple_spec.rb +15 -0
  228. data/spec/unit/initial_state_spec.rb +12 -0
  229. data/spec/unit/inspection_multiple_spec.rb +205 -0
  230. data/spec/unit/inspection_spec.rb +153 -0
  231. data/spec/unit/invoker_spec.rb +189 -0
  232. data/spec/unit/invokers/base_invoker_spec.rb +72 -0
  233. data/spec/unit/invokers/class_invoker_spec.rb +95 -0
  234. data/spec/unit/invokers/literal_invoker_spec.rb +86 -0
  235. data/spec/unit/invokers/proc_invoker_spec.rb +86 -0
  236. data/spec/unit/localizer_spec.rb +109 -0
  237. data/spec/unit/memory_leak_spec.rb +38 -0
  238. data/spec/unit/multiple_transitions_that_differ_only_by_guard_spec.rb +14 -0
  239. data/spec/unit/namespaced_multiple_example_spec.rb +75 -0
  240. data/spec/unit/new_dsl_spec.rb +12 -0
  241. data/spec/unit/override_warning_spec.rb +94 -0
  242. data/spec/unit/persistence/active_record_persistence_multiple_spec.rb +635 -0
  243. data/spec/unit/persistence/active_record_persistence_spec.rb +852 -0
  244. data/spec/unit/persistence/dynamoid_persistence_multiple_spec.rb +135 -0
  245. data/spec/unit/persistence/dynamoid_persistence_spec.rb +84 -0
  246. data/spec/unit/persistence/mongoid_persistence_multiple_spec.rb +200 -0
  247. data/spec/unit/persistence/mongoid_persistence_spec.rb +177 -0
  248. data/spec/unit/persistence/no_brainer_persistence_multiple_spec.rb +198 -0
  249. data/spec/unit/persistence/no_brainer_persistence_spec.rb +158 -0
  250. data/spec/unit/persistence/redis_persistence_multiple_spec.rb +88 -0
  251. data/spec/unit/persistence/redis_persistence_spec.rb +53 -0
  252. data/spec/unit/persistence/sequel_persistence_multiple_spec.rb +148 -0
  253. data/spec/unit/persistence/sequel_persistence_spec.rb +368 -0
  254. data/spec/unit/readme_spec.rb +41 -0
  255. data/spec/unit/reloading_spec.rb +15 -0
  256. data/spec/unit/rspec_matcher_spec.rb +88 -0
  257. data/spec/unit/simple_custom_example_spec.rb +39 -0
  258. data/spec/unit/simple_example_spec.rb +57 -0
  259. data/spec/unit/simple_multiple_example_spec.rb +91 -0
  260. data/spec/unit/state_spec.rb +105 -0
  261. data/spec/unit/states_on_one_line_example_spec.rb +16 -0
  262. data/spec/unit/subclassing_multiple_spec.rb +74 -0
  263. data/spec/unit/subclassing_spec.rb +46 -0
  264. data/spec/unit/timestamps_spec.rb +32 -0
  265. data/spec/unit/transition_spec.rb +436 -0
  266. data/test/minitest_helper.rb +57 -0
  267. data/test/unit/minitest_matcher_test.rb +80 -0
  268. metadata +607 -60
  269. data/CHANGELOG +0 -33
  270. data/README.rdoc +0 -122
  271. data/TODO +0 -9
  272. data/doc/jamis.rb +0 -591
  273. data/lib/aasm/event.rb +0 -76
  274. data/lib/aasm/state.rb +0 -35
  275. data/lib/aasm/state_transition.rb +0 -36
@@ -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
@@ -0,0 +1,93 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'on initialization' do
4
+ let(:auth) {ComplexExample.new}
5
+
6
+ it 'should be in the pending state' do
7
+ expect(auth.aasm.current_state).to eq(:pending)
8
+ end
9
+
10
+ it 'should have an activation code' do
11
+ expect(auth.has_activation_code?).to be_truthy
12
+ expect(auth.activation_code).not_to be_nil
13
+ end
14
+ end
15
+
16
+ describe 'when being unsuspended' do
17
+ let(:auth) {ComplexExample.new}
18
+
19
+ it 'should be able to be unsuspended' do
20
+ auth.activate!
21
+ auth.suspend!
22
+ expect(auth.may_unsuspend?).to be true
23
+ end
24
+
25
+ it 'should not be able to be unsuspended into active' do
26
+ auth.suspend!
27
+ expect(auth.may_unsuspend?(:active)).not_to be true
28
+ end
29
+
30
+ it 'should be able to be unsuspended into active if polite' do
31
+ auth.suspend!
32
+ expect(auth.may_wait?(:waiting, :please)).to be true
33
+ auth.wait!(:please)
34
+ end
35
+
36
+ it 'should not be able to be unsuspended into active if not polite' do
37
+ auth.suspend!
38
+ expect(auth.may_wait?(:waiting)).not_to be true
39
+ expect(auth.may_wait?(:waiting, :rude)).not_to be true
40
+ expect {auth.wait!(:rude)}.to raise_error(AASM::InvalidTransition)
41
+ expect {auth.wait!}.to raise_error(AASM::InvalidTransition)
42
+ end
43
+
44
+ it 'should not be able to be unpassified' do
45
+ auth.activate!
46
+ auth.suspend!
47
+ auth.unsuspend!
48
+
49
+ expect(auth.may_unpassify?).not_to be true
50
+ expect {auth.unpassify!}.to raise_error(AASM::InvalidTransition)
51
+ end
52
+
53
+ it 'should be active if previously activated' do
54
+ auth.activate!
55
+ auth.suspend!
56
+ auth.unsuspend!
57
+
58
+ expect(auth.aasm.current_state).to eq(:active)
59
+ end
60
+
61
+ it 'should be pending if not previously activated, but an activation code is present' do
62
+ auth.suspend!
63
+ auth.unsuspend!
64
+
65
+ expect(auth.aasm.current_state).to eq(:pending)
66
+ end
67
+
68
+ it 'should be passive if not previously activated and there is no activation code' do
69
+ auth.activation_code = nil
70
+ auth.suspend!
71
+ auth.unsuspend!
72
+
73
+ expect(auth.aasm.current_state).to eq(:passive)
74
+ end
75
+
76
+ it "should be able to fire known events" do
77
+ expect(auth.aasm.may_fire_event?(:activate)).to be true
78
+ end
79
+
80
+ it "should be able to fire event by name" do
81
+ expect(auth.aasm.fire(:activate)).to be true
82
+ expect(auth.aasm.current_state).to eq(:active)
83
+ end
84
+
85
+ it "should be able to fire! event by name" do
86
+ expect(auth.aasm.fire!(:activate)).to be true
87
+ expect(auth.aasm.current_state).to eq(:active)
88
+ end
89
+
90
+ it "should not be able to fire unknown events" do
91
+ expect(auth.aasm.may_fire_event?(:unknown)).to be false
92
+ end
93
+ end