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,13 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
+
5
+ We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
6
+
7
+ Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
+
9
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
+
11
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12
+
13
+ This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
@@ -0,0 +1,24 @@
1
+ ## Contributing ##
2
+
3
+ While not required to contribute, we recommend [RVM](https://rvm.io/) to manage your rubies.
4
+
5
+ 1. Read the [Contributor Code of Conduct](https://github.com/aasm/aasm/blob/master/CODE_OF_CONDUCT.md)
6
+ 2. [Fork it](https://help.github.com/articles/about-forks/)
7
+ 3. Clone the project `git clone git@github.com:[YOUR GITHUB USERNAME]/aasm.git`
8
+ 4. `cd aasm`
9
+ 5. Create your feature branch `git checkout -b my-new-feature`
10
+ 6. Write tests for your changes (feature/bug)
11
+ 7. Write your (feature/bugfix)
12
+ 8. Install the dependencies `appraisal install`
13
+ 9. Run the tests `appraisal rspec`
14
+ 10. Commit your changes `git commit -am 'Added some feature'`
15
+ 11. Push to the branch `git push origin my-new-feature`
16
+ 12. Create new [Pull Request](https://help.github.com/articles/creating-a-pull-request/)
17
+
18
+ There are some option dependencies as well.
19
+
20
+ - [MongoDB server](https://www.mongodb.com/download-center)
21
+ - [Redis](https://redis.io/topics/quickstart)
22
+ - [DynamoDB (local)](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html)
23
+
24
+ If we've missed something please open an [issue](https://github.com/aasm/aasm/issues/new)
@@ -0,0 +1,44 @@
1
+ FROM ruby:2.3.4-slim
2
+
3
+ LABEL maintainer="AASM"
4
+
5
+ ENV DEBIAN_FRONTEND noninteractive
6
+
7
+ # ~~~~ System locales ~~~~
8
+ RUN apt-get update && apt-get install -y locales && \
9
+ dpkg-reconfigure locales && \
10
+ locale-gen C.UTF-8 && \
11
+ /usr/sbin/update-locale LANG=C.UTF-8 && \
12
+ echo 'en_US.UTF-8 UTF-8' >> /etc/locale.gen && \
13
+ locale-gen
14
+
15
+ # Set default locale for the environment
16
+ ENV LC_ALL C.UTF-8
17
+ ENV LANG en_US.UTF-8
18
+ ENV LANGUAGE en_US.UTF-8
19
+ ENV APP_HOME /application
20
+
21
+ # ~~~~ Application dependencies ~~~~
22
+ RUN apt-get update
23
+ RUN apt-get install -y libsqlite3-dev \
24
+ build-essential \
25
+ git
26
+
27
+ # ~~~~ Bundler ~~~~
28
+ RUN gem install bundler
29
+
30
+ WORKDIR $APP_HOME
31
+ RUN mkdir -p $APP_HOME/lib/aasm/
32
+
33
+ COPY Gemfile* $APP_HOME/
34
+ COPY *.gemspec $APP_HOME/
35
+ COPY lib/aasm/version.rb $APP_HOME/lib/aasm/
36
+
37
+ ENV BUNDLE_GEMFILE=$APP_HOME/Gemfile \
38
+ BUNDLE_JOBS=8 \
39
+ BUNDLE_PATH=/bundle
40
+
41
+ RUN bundle install
42
+
43
+ # ~~~~ Import application ~~~~
44
+ COPY . $APP_HOME
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem 'sqlite3', '~> 1.3.5', :platforms => :ruby
6
+ gem 'rails', '5.1.4'
@@ -0,0 +1,151 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ aasm (4.11.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ actionmailer (4.2.7.1)
10
+ actionpack (= 4.2.7.1)
11
+ actionview (= 4.2.7.1)
12
+ activejob (= 4.2.7.1)
13
+ mail (~> 2.5, >= 2.5.4)
14
+ rails-dom-testing (~> 1.0, >= 1.0.5)
15
+ actionpack (4.2.7.1)
16
+ actionview (= 4.2.7.1)
17
+ activesupport (= 4.2.7.1)
18
+ rack (~> 1.6)
19
+ rack-test (~> 0.6.2)
20
+ rails-dom-testing (~> 1.0, >= 1.0.5)
21
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
22
+ actionview (4.2.7.1)
23
+ activesupport (= 4.2.7.1)
24
+ builder (~> 3.1)
25
+ erubis (~> 2.7.0)
26
+ rails-dom-testing (~> 1.0, >= 1.0.5)
27
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
28
+ activejob (4.2.7.1)
29
+ activesupport (= 4.2.7.1)
30
+ globalid (>= 0.3.0)
31
+ activemodel (4.2.7.1)
32
+ activesupport (= 4.2.7.1)
33
+ builder (~> 3.1)
34
+ activerecord (4.2.7.1)
35
+ activemodel (= 4.2.7.1)
36
+ activesupport (= 4.2.7.1)
37
+ arel (~> 6.0)
38
+ activesupport (4.2.7.1)
39
+ i18n (~> 0.7)
40
+ json (~> 1.7, >= 1.7.7)
41
+ minitest (~> 5.1)
42
+ thread_safe (~> 0.3, >= 0.3.4)
43
+ tzinfo (~> 1.1)
44
+ appraisal (2.1.0)
45
+ bundler
46
+ rake
47
+ thor (>= 0.14.0)
48
+ arel (6.0.4)
49
+ builder (3.2.3)
50
+ coderay (1.1.1)
51
+ concurrent-ruby (1.0.5)
52
+ diff-lcs (1.3)
53
+ erubis (2.7.0)
54
+ generator_spec (0.9.3)
55
+ activesupport (>= 3.0.0)
56
+ railties (>= 3.0.0)
57
+ globalid (0.3.7)
58
+ activesupport (>= 4.1.0)
59
+ i18n (0.8.1)
60
+ json (1.8.6)
61
+ loofah (2.0.3)
62
+ nokogiri (>= 1.5.9)
63
+ mail (2.6.4)
64
+ mime-types (>= 1.16, < 4)
65
+ method_source (0.8.2)
66
+ mime-types (3.1)
67
+ mime-types-data (~> 3.2015)
68
+ mime-types-data (3.2016.0521)
69
+ mini_portile2 (2.1.0)
70
+ minitest (5.10.1)
71
+ nokogiri (1.7.0.1)
72
+ mini_portile2 (~> 2.1.0)
73
+ pry (0.10.4)
74
+ coderay (~> 1.1.0)
75
+ method_source (~> 0.8.1)
76
+ slop (~> 3.4)
77
+ rack (1.6.5)
78
+ rack-test (0.6.3)
79
+ rack (>= 1.0)
80
+ rails (4.2.7.1)
81
+ actionmailer (= 4.2.7.1)
82
+ actionpack (= 4.2.7.1)
83
+ actionview (= 4.2.7.1)
84
+ activejob (= 4.2.7.1)
85
+ activemodel (= 4.2.7.1)
86
+ activerecord (= 4.2.7.1)
87
+ activesupport (= 4.2.7.1)
88
+ bundler (>= 1.3.0, < 2.0)
89
+ railties (= 4.2.7.1)
90
+ sprockets-rails
91
+ rails-deprecated_sanitizer (1.0.3)
92
+ activesupport (>= 4.2.0.alpha)
93
+ rails-dom-testing (1.0.8)
94
+ activesupport (>= 4.2.0.beta, < 5.0)
95
+ nokogiri (~> 1.6)
96
+ rails-deprecated_sanitizer (>= 1.0.1)
97
+ rails-html-sanitizer (1.0.3)
98
+ loofah (~> 2.0)
99
+ railties (4.2.7.1)
100
+ actionpack (= 4.2.7.1)
101
+ activesupport (= 4.2.7.1)
102
+ rake (>= 0.8.7)
103
+ thor (>= 0.18.1, < 2.0)
104
+ rake (12.0.0)
105
+ rdoc (4.3.0)
106
+ rspec (3.5.0)
107
+ rspec-core (~> 3.5.0)
108
+ rspec-expectations (~> 3.5.0)
109
+ rspec-mocks (~> 3.5.0)
110
+ rspec-core (3.5.4)
111
+ rspec-support (~> 3.5.0)
112
+ rspec-expectations (3.5.0)
113
+ diff-lcs (>= 1.2.0, < 2.0)
114
+ rspec-support (~> 3.5.0)
115
+ rspec-mocks (3.5.0)
116
+ diff-lcs (>= 1.2.0, < 2.0)
117
+ rspec-support (~> 3.5.0)
118
+ rspec-support (3.5.0)
119
+ sdoc (0.4.2)
120
+ json (~> 1.7, >= 1.7.7)
121
+ rdoc (~> 4.0)
122
+ slop (3.6.0)
123
+ sprockets (3.7.1)
124
+ concurrent-ruby (~> 1.0)
125
+ rack (> 1, < 3)
126
+ sprockets-rails (3.2.0)
127
+ actionpack (>= 4.0)
128
+ activesupport (>= 4.0)
129
+ sprockets (>= 3.0.0)
130
+ sqlite3 (1.3.13)
131
+ thor (0.19.4)
132
+ thread_safe (0.3.6)
133
+ tzinfo (1.2.2)
134
+ thread_safe (~> 0.1)
135
+
136
+ PLATFORMS
137
+ ruby
138
+
139
+ DEPENDENCIES
140
+ aasm!
141
+ appraisal
142
+ generator_spec
143
+ pry
144
+ rails (= 4.2.7.1)
145
+ rake
146
+ rspec (>= 3)
147
+ sdoc
148
+ sqlite3
149
+
150
+ BUNDLED WITH
151
+ 1.12.4
data/HOWTO ADDED
@@ -0,0 +1,12 @@
1
+ How to
2
+
3
+ 1. Run tests for Mongoid
4
+
5
+ Start MongoDB
6
+
7
+ $> mongod
8
+
9
+ Run the specs
10
+
11
+ $> rspec spec/unit/persistence/mongoid_persistance_spec.rb
12
+
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2006-2017 Scott Barron
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,11 @@
1
+ # Planned changes
2
+
3
+ ## later
4
+
5
+ * drop support for aasm_column ?
6
+
7
+
8
+ # Currently working on
9
+
10
+
11
+ # Changes so far
@@ -0,0 +1,1439 @@
1
+ # AASM - Ruby state machines
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/aasm.svg)](http://badge.fury.io/rb/aasm)
4
+ [![Build Status](https://travis-ci.org/aasm/aasm.svg?branch=master)](https://travis-ci.org/aasm/aasm)
5
+ [![Code Climate](https://codeclimate.com/github/aasm/aasm/badges/gpa.svg)](https://codeclimate.com/github/aasm/aasm)
6
+ [![codecov](https://codecov.io/gh/aasm/aasm/branch/master/graph/badge.svg)](https://codecov.io/gh/aasm/aasm)
7
+
8
+ ## Index
9
+ - [Upgrade from version 3 to 4](#upgrade-from-version-3-to-4)
10
+ - [Usage](#usage)
11
+ - [Callbacks](#callbacks)
12
+ - [Lifecycle](#lifecycle)
13
+ - [The current event triggered](#the-current-event-triggered)
14
+ - [Guards](#guards)
15
+ - [Transitions](#transitions)
16
+ - [Multiple state machines per class](#multiple-state-machines-per-class)
17
+ - [Handling naming conflicts between multiple state machines](#handling-naming-conflicts-between-multiple-state-machines)
18
+ - [Binding event](#binding-event)
19
+ - [Auto-generated Status Constants](#auto-generated-status-constants)
20
+ - [Extending AASM](#extending-aasm)
21
+ - [ActiveRecord](#activerecord)
22
+ - [Bang events](#bang-events)
23
+ - [ActiveRecord enums](#activerecord-enums)
24
+ - [Sequel](#sequel)
25
+ - [Dynamoid](#dynamoid)
26
+ - [Mongoid](#mongoid)
27
+ - [Nobrainer](#nobrainer)
28
+ - [Redis](#redis)
29
+ - [Automatic Scopes](#automatic-scopes)
30
+ - [Transaction support](#transaction-support)
31
+ - [Pessimistic Locking](#pessimistic-locking)
32
+ - [Column name & migration](#column-name--migration)
33
+ - [Log State Changes](#log-state-changes)
34
+ - [Inspection](#inspection)
35
+ - [Warning output](#warning-output)
36
+ - [RubyMotion support](#rubymotion-support)
37
+ - [Testing](#testing)
38
+ - [RSpec](#rspec)
39
+ - [Minitest](#minitest)
40
+ - [Assertions](#assertions)
41
+ - [Expectations](#expectations)
42
+ - [Installation](#installation)
43
+ - [Manually from RubyGems.org](#manually-from-rubygemsorg)
44
+ - [Bundler](#or-if-you-are-using-bundler)
45
+ - [Building your own gems](#building-your-own-gems)
46
+ - [Generators](#generators)
47
+ - [Test suite with Docker](#docker)
48
+ - [Latest changes](#latest-changes)
49
+ - [Questions?](#questions)
50
+ - [Maintainers](#maintainers)
51
+ - [Contributing](CONTRIBUTING.md)
52
+ - [Warranty](#warranty)
53
+ - [License](#license)
54
+
55
+ This package contains AASM, a library for adding finite state machines to Ruby classes.
56
+
57
+ AASM started as the *acts_as_state_machine* plugin but has evolved into a more generic library
58
+ that no longer targets only ActiveRecord models. It currently provides adapters for many
59
+ ORMs but it can be used for any Ruby class, no matter what parent class it has (if any).
60
+
61
+ ## Upgrade from version 3 to 4
62
+
63
+ Take a look at the [README_FROM_VERSION_3_TO_4](https://github.com/aasm/aasm/blob/master/README_FROM_VERSION_3_TO_4.md) for details how to switch from version 3.x to 4.0 of _AASM_.
64
+
65
+ ## Usage
66
+
67
+ Adding a state machine is as simple as including the AASM module and start defining
68
+ **states** and **events** together with their **transitions**:
69
+
70
+ ```ruby
71
+ class Job
72
+ include AASM
73
+
74
+ aasm do
75
+ state :sleeping, initial: true
76
+ state :running, :cleaning
77
+
78
+ event :run do
79
+ transitions from: :sleeping, to: :running
80
+ end
81
+
82
+ event :clean do
83
+ transitions from: :running, to: :cleaning
84
+ end
85
+
86
+ event :sleep do
87
+ transitions from: [:running, :cleaning], to: :sleeping
88
+ end
89
+ end
90
+
91
+ end
92
+ ```
93
+
94
+ This provides you with a couple of public methods for instances of the class `Job`:
95
+
96
+ ```ruby
97
+ job = Job.new
98
+ job.sleeping? # => true
99
+ job.may_run? # => true
100
+ job.run
101
+ job.running? # => true
102
+ job.sleeping? # => false
103
+ job.may_run? # => false
104
+ job.run # => raises AASM::InvalidTransition
105
+ ```
106
+
107
+ If you don't like exceptions and prefer a simple `true` or `false` as response, tell
108
+ AASM not to be *whiny*:
109
+
110
+ ```ruby
111
+ class Job
112
+ ...
113
+ aasm whiny_transitions: false do
114
+ ...
115
+ end
116
+ end
117
+
118
+ job.running? # => true
119
+ job.may_run? # => false
120
+ job.run # => false
121
+ ```
122
+
123
+ When firing an event, you can pass a block to the method, it will be called only if
124
+ the transition succeeds :
125
+
126
+ ```ruby
127
+ job.run do
128
+ job.user.notify_job_ran # Will be called if job.may_run? is true
129
+ end
130
+ ```
131
+
132
+ ### Callbacks
133
+
134
+ You can define a number of callbacks for your events, transitions and states. These methods, Procs or classes will be
135
+ called when certain criteria are met, like entering a particular state:
136
+
137
+ ```ruby
138
+ class Job
139
+ include AASM
140
+
141
+ aasm do
142
+ state :sleeping, initial: true, before_enter: :do_something
143
+ state :running, before_enter: Proc.new { do_something && notify_somebody }
144
+ state :finished
145
+
146
+ after_all_transitions :log_status_change
147
+
148
+ event :run, after: :notify_somebody do
149
+ before do
150
+ log('Preparing to run')
151
+ end
152
+
153
+ transitions from: :sleeping, to: :running, after: Proc.new {|*args| set_process(*args) }
154
+ transitions from: :running, to: :finished, after: LogRunTime
155
+ end
156
+
157
+ event :sleep do
158
+ after do
159
+ ...
160
+ end
161
+ error do |e|
162
+ ...
163
+ end
164
+ transitions from: :running, to: :sleeping
165
+ end
166
+ end
167
+
168
+ def log_status_change
169
+ puts "changing from #{aasm.from_state} to #{aasm.to_state} (event: #{aasm.current_event})"
170
+ end
171
+
172
+ def set_process(name)
173
+ ...
174
+ end
175
+
176
+ def do_something
177
+ ...
178
+ end
179
+
180
+ def notify_somebody
181
+ ...
182
+ end
183
+
184
+ end
185
+
186
+ class LogRunTime
187
+ def call
188
+ log "Job was running for X seconds"
189
+ end
190
+ end
191
+ ```
192
+
193
+ In this case `do_something` is called before actually entering the state `sleeping`,
194
+ while `notify_somebody` is called after the transition `run` (from `sleeping` to `running`)
195
+ is finished.
196
+
197
+ AASM will also initialize `LogRunTime` and run the `call` method for you after the transition from `running` to `finished` in the example above. You can pass arguments to the class by defining an initialize method on it, like this:
198
+
199
+ Note that Procs are executed in the context of a record, it means that you don't need to expect the record as an argument, just call the methods you need.
200
+
201
+ ```ruby
202
+ class LogRunTime
203
+ # optional args parameter can be omitted, but if you define initialize
204
+ # you must accept the model instance as the first parameter to it.
205
+ def initialize(job, args = {})
206
+ @job = job
207
+ end
208
+
209
+ def call
210
+ log "Job was running for #{@job.run_time} seconds"
211
+ end
212
+ end
213
+ ```
214
+
215
+ Also, you can pass parameters to events:
216
+
217
+ ```ruby
218
+ job = Job.new
219
+ job.run(:defragmentation)
220
+ ```
221
+
222
+ In this case the `set_process` would be called with `:defragmentation` argument.
223
+
224
+ In case of an error during the event processing the error is rescued and passed to `:error`
225
+ callback, which can handle it or re-raise it for further propagation.
226
+
227
+ Also, you can define a method that will be called if any event fails:
228
+
229
+ ```ruby
230
+ def aasm_event_failed(event_name, old_state_name)
231
+ # use custom exception/messages, report metrics, etc
232
+ end
233
+ ```
234
+
235
+ During the transition's `:after` callback (and reliably only then, or in the global
236
+ `after_all_transitions` callback) you can access the originating state (the from-state)
237
+ and the target state (the to state), like this:
238
+
239
+ ```ruby
240
+ def set_process(name)
241
+ logger.info "from #{aasm.from_state} to #{aasm.to_state}"
242
+ end
243
+ ```
244
+
245
+ #### Lifecycle
246
+
247
+ Here you can see a list of all possible callbacks, together with their order of calling:
248
+
249
+ ```ruby
250
+ begin
251
+ event before_all_events
252
+ event before
253
+ event guards
254
+ transition guards
255
+ old_state before_exit
256
+ old_state exit
257
+ after_all_transitions
258
+ transition after
259
+ new_state before_enter
260
+ new_state enter
261
+ ...update state...
262
+ event before_success # if persist successful
263
+ transition success # if persist successful
264
+ event success # if persist successful
265
+ old_state after_exit
266
+ new_state after_enter
267
+ event after
268
+ event after_all_events
269
+ rescue
270
+ event error
271
+ event error_on_all_events
272
+ ensure
273
+ event ensure
274
+ event ensure_on_all_events
275
+ end
276
+ ```
277
+
278
+ #### The current event triggered
279
+
280
+ While running the callbacks you can easily retrieve the name of the event triggered
281
+ by using `aasm.current_event`:
282
+
283
+ ```ruby
284
+ # taken the example callback from above
285
+ def do_something
286
+ puts "triggered #{aasm.current_event}"
287
+ end
288
+ ```
289
+
290
+ and then
291
+
292
+ ```ruby
293
+ job = Job.new
294
+
295
+ # without bang
296
+ job.sleep # => triggered :sleep
297
+
298
+ # with bang
299
+ job.sleep! # => triggered :sleep!
300
+ ```
301
+
302
+
303
+ ### Guards
304
+
305
+ Let's assume you want to allow particular transitions only if a defined condition is
306
+ given. For this you can set up a guard per transition, which will run before actually
307
+ running the transition. If the guard returns `false` the transition will be
308
+ denied (raising `AASM::InvalidTransition` or returning `false` itself):
309
+
310
+ ```ruby
311
+ class Cleaner
312
+ include AASM
313
+
314
+ aasm do
315
+ state :idle, initial: true
316
+ state :cleaning
317
+
318
+ event :clean do
319
+ transitions from: :idle, to: :cleaning, guard: :cleaning_needed?
320
+ end
321
+
322
+ event :clean_if_needed do
323
+ transitions from: :idle, to: :cleaning do
324
+ guard do
325
+ cleaning_needed?
326
+ end
327
+ end
328
+ transitions from: :idle, to: :idle
329
+ end
330
+
331
+ event :clean_if_dirty do
332
+ transitions from: :idle, to: :cleaning, guard: :if_dirty?
333
+ end
334
+ end
335
+
336
+ def cleaning_needed?
337
+ false
338
+ end
339
+
340
+ def if_dirty?(status)
341
+ status == :dirty
342
+ end
343
+ end
344
+
345
+ job = Cleaner.new
346
+ job.may_clean? # => false
347
+ job.clean # => raises AASM::InvalidTransition
348
+ job.may_clean_if_needed? # => true
349
+ job.clean_if_needed! # idle
350
+
351
+ job.clean_if_dirty(:clean) # => false
352
+ job.clean_if_dirty(:dirty) # => true
353
+ ```
354
+
355
+ You can even provide a number of guards, which all have to succeed to proceed
356
+
357
+ ```ruby
358
+ def walked_the_dog?; ...; end
359
+
360
+ event :sleep do
361
+ transitions from: :running, to: :sleeping, guards: [:cleaning_needed?, :walked_the_dog?]
362
+ end
363
+ ```
364
+
365
+ If you want to provide guards for all transitions within an event, you can use event guards
366
+
367
+ ```ruby
368
+ event :sleep, guards: [:walked_the_dog?] do
369
+ transitions from: :running, to: :sleeping, guards: [:cleaning_needed?]
370
+ transitions from: :cleaning, to: :sleeping
371
+ end
372
+ ```
373
+
374
+ If you prefer a more Ruby-like guard syntax, you can use `if` and `unless` as well:
375
+
376
+ ```ruby
377
+ event :clean do
378
+ transitions from: :running, to: :cleaning, if: :cleaning_needed?
379
+ end
380
+
381
+ event :sleep do
382
+ transitions from: :running, to: :sleeping, unless: :cleaning_needed?
383
+ end
384
+ end
385
+ ```
386
+
387
+ You can invoke a Class instead a method since this Class responds to `call`
388
+
389
+ ```ruby
390
+ event :sleep do
391
+ transitions from: :running, to: :sleeping, guards: Dog
392
+ end
393
+ ```
394
+ ```ruby
395
+ class Dog
396
+ def call
397
+ cleaning_needed? && walked?
398
+ end
399
+ ...
400
+ end
401
+ ```
402
+
403
+ ### Transitions
404
+
405
+ In the event of having multiple transitions for an event, the first transition that successfully completes will stop other transitions in the same event from being processed.
406
+
407
+ ```ruby
408
+ require 'aasm'
409
+
410
+ class Job
411
+ include AASM
412
+
413
+ aasm do
414
+ state :stage1, initial: true
415
+ state :stage2
416
+ state :stage3
417
+ state :completed
418
+
419
+ event :stage1_completed do
420
+ transitions from: :stage1, to: :stage3, guard: :stage2_completed?
421
+ transitions from: :stage1, to: :stage2
422
+ end
423
+ end
424
+
425
+ def stage2_completed?
426
+ true
427
+ end
428
+ end
429
+
430
+ job = Job.new
431
+ job.stage1_completed
432
+ job.aasm.current_state # stage3
433
+ ```
434
+
435
+
436
+ ### Multiple state machines per class
437
+
438
+ Multiple state machines per class are supported. Be aware though that _AASM_ has been
439
+ built with one state machine per class in mind. Nonetheless, here's how to do it (see below). Please note that you will need to specify database columns for where your pertinent states will be stored - we have specified two columns `move_state` and `work_state` in the example below. See the [Column name & migration](https://github.com/aasm/aasm#column-name--migration) section for further info.
440
+
441
+ ```ruby
442
+ class SimpleMultipleExample
443
+ include AASM
444
+ aasm(:move, column: 'move_state') do
445
+ state :standing, initial: true
446
+ state :walking
447
+ state :running
448
+
449
+ event :walk do
450
+ transitions from: :standing, to: :walking
451
+ end
452
+ event :run do
453
+ transitions from: [:standing, :walking], to: :running
454
+ end
455
+ event :hold do
456
+ transitions from: [:walking, :running], to: :standing
457
+ end
458
+ end
459
+
460
+ aasm(:work, column: 'work_state') do
461
+ state :sleeping, initial: true
462
+ state :processing
463
+
464
+ event :start do
465
+ transitions from: :sleeping, to: :processing
466
+ end
467
+ event :stop do
468
+ transitions from: :processing, to: :sleeping
469
+ end
470
+ end
471
+ end
472
+
473
+ simple = SimpleMultipleExample.new
474
+
475
+ simple.aasm(:move).current_state
476
+ # => :standing
477
+ simple.aasm(:work).current
478
+ # => :sleeping
479
+
480
+ simple.start
481
+ simple.aasm(:move).current_state
482
+ # => :standing
483
+ simple.aasm(:work).current
484
+ # => :processing
485
+
486
+ ```
487
+
488
+ #### Handling naming conflicts between multiple state machines
489
+
490
+ _AASM_ doesn't prohibit to define the same event in more than one state
491
+ machine. If no namespace is provided, the latest definition "wins" and
492
+ overrides previous definitions. Nonetheless, a warning is issued:
493
+ `SimpleMultipleExample: overriding method 'run'!`.
494
+
495
+ Alternatively, you can provide a namespace for each state machine:
496
+
497
+ ```ruby
498
+ class NamespacedMultipleExample
499
+ include AASM
500
+ aasm(:status) do
501
+ state :unapproved, initial: true
502
+ state :approved
503
+
504
+ event :approve do
505
+ transitions from: :unapproved, to: :approved
506
+ end
507
+
508
+ event :unapprove do
509
+ transitions from: :approved, to: :unapproved
510
+ end
511
+ end
512
+
513
+ aasm(:review_status, namespace: :review) do
514
+ state :unapproved, initial: true
515
+ state :approved
516
+
517
+ event :approve do
518
+ transitions from: :unapproved, to: :approved
519
+ end
520
+
521
+ event :unapprove do
522
+ transitions from: :approved, to: :unapproved
523
+ end
524
+ end
525
+ end
526
+
527
+ namespaced = NamespacedMultipleExample.new
528
+
529
+ namespaced.aasm(:status).current_state
530
+ # => :unapproved
531
+ namespaced.aasm(:review_status).current_state
532
+ # => :unapproved
533
+ namespaced.approve_review
534
+ namespaced.aasm(:review_status).current_state
535
+ # => :approved
536
+ ```
537
+
538
+ All _AASM_ class- and instance-level `aasm` methods accept a state machine selector.
539
+ So, for example, to use inspection on a class level, you have to use
540
+
541
+ ```ruby
542
+ SimpleMultipleExample.aasm(:move).states.map(&:name)
543
+ # => [:standing, :walking, :running]
544
+ ```
545
+
546
+ ### Binding event
547
+
548
+ Allow an event to be bound to another
549
+ ```ruby
550
+ class Example
551
+ include AASM
552
+
553
+ aasm(:work) do
554
+ state :sleeping, initial: true
555
+ state :processing
556
+
557
+ event :start do
558
+ transitions from: :sleeping, to: :processing
559
+ end
560
+ event :stop do
561
+ transitions from: :processing, to: :sleeping
562
+ end
563
+ end
564
+
565
+ aasm(:question) do
566
+ state :answered, initial: true
567
+ state :asked
568
+
569
+ event :ask, binding_event: :start do
570
+ transitions from: :answered, to: :asked
571
+ end
572
+ event :answer, binding_event: :stop do
573
+ transitions from: :asked, to: :answered
574
+ end
575
+ end
576
+ end
577
+
578
+ example = Example.new
579
+ example.aasm(:work).current_state #=> :sleeping
580
+ example.aasm(:question).current_state #=> :answered
581
+ example.ask
582
+ example.aasm(:work).current_state #=> :processing
583
+ example.aasm(:question).current_state #=> :asked
584
+ ```
585
+
586
+ ### Auto-generated Status Constants
587
+
588
+ AASM automatically [generates constants](https://github.com/aasm/aasm/pull/60)
589
+ for each status so you don't have to explicitly define them.
590
+
591
+ ```ruby
592
+ class Foo
593
+ include AASM
594
+
595
+ aasm do
596
+ state :initialized
597
+ state :calculated
598
+ state :finalized
599
+ end
600
+ end
601
+
602
+ > Foo::STATE_INITIALIZED
603
+ #=> :initialized
604
+ > Foo::STATE_CALCULATED
605
+ #=> :calculated
606
+ ```
607
+
608
+ ### Extending AASM
609
+
610
+ AASM allows you to easily extend `AASM::Base` for your own application purposes.
611
+
612
+ Let's suppose we have common logic across many AASM models. We can embody this logic in a sub-class of `AASM::Base`.
613
+
614
+ ```ruby
615
+ class CustomAASMBase < AASM::Base
616
+ # A custom transiton that we want available across many AASM models.
617
+ def count_transitions!
618
+ klass.class_eval do
619
+ aasm with_klass: CustomAASMBase do
620
+ after_all_transitions :increment_transition_count
621
+ end
622
+ end
623
+ end
624
+
625
+ # A custom annotation that we want available across many AASM models.
626
+ def requires_guards!
627
+ klass.class_eval do
628
+ attr_reader :authorizable_called,
629
+ :transition_count,
630
+ :fillable_called
631
+
632
+ def authorizable?
633
+ @authorizable_called = true
634
+ end
635
+
636
+ def fillable?
637
+ @fillable_called = true
638
+ end
639
+
640
+ def increment_transition_count
641
+ @transition_count ||= 0
642
+ @transition_count += 1
643
+ end
644
+ end
645
+ end
646
+ end
647
+ ```
648
+
649
+ When we declare our model that has an AASM state machine, we simply declare the AASM block with a `:with_klass` key to our own class.
650
+
651
+ ```ruby
652
+ class SimpleCustomExample
653
+ include AASM
654
+
655
+ # Let's build an AASM state machine with our custom class.
656
+ aasm with_klass: CustomAASMBase do
657
+ requires_guards!
658
+ count_transitions!
659
+
660
+ state :initialised, initial: true
661
+ state :filled_out
662
+ state :authorised
663
+
664
+ event :fill_out do
665
+ transitions from: :initialised, to: :filled_out, guard: :fillable?
666
+ end
667
+ event :authorise do
668
+ transitions from: :filled_out, to: :authorised, guard: :authorizable?
669
+ end
670
+ end
671
+ end
672
+ ```
673
+
674
+
675
+ ### ActiveRecord
676
+
677
+ AASM comes with support for ActiveRecord and allows automatic persisting of the object's
678
+ state in the database.
679
+
680
+ ```ruby
681
+ class Job < ActiveRecord::Base
682
+ include AASM
683
+
684
+ aasm do # default column: aasm_state
685
+ state :sleeping, initial: true
686
+ state :running
687
+
688
+ event :run do
689
+ transitions from: :sleeping, to: :running
690
+ end
691
+
692
+ event :sleep do
693
+ transitions from: :running, to: :sleeping
694
+ end
695
+ end
696
+
697
+ end
698
+ ```
699
+
700
+ ### Bang events
701
+
702
+ You can tell AASM to auto-save the object or leave it unsaved
703
+
704
+ ```ruby
705
+ job = Job.new
706
+ job.run # not saved
707
+ job.run! # saved
708
+
709
+ # or
710
+ job.aasm.fire(:run) # not saved
711
+ job.aasm.fire!(:run) # saved
712
+ ```
713
+
714
+ Saving includes running all validations on the `Job` class. If
715
+ `whiny_persistence` flag is set to `true`, exception is raised in case of
716
+ failure. If `whiny_persistence` flag is set to false, methods with a bang return
717
+ `true` if the state transition is successful or `false` if an error occurs.
718
+
719
+ If you want make sure the state gets saved without running validations (and
720
+ thereby maybe persisting an invalid object state), simply tell AASM to skip the
721
+ validations. Be aware that when skipping validations, only the state column will
722
+ be updated in the database (just like ActiveRecord `update_column` is working).
723
+
724
+ ```ruby
725
+ class Job < ActiveRecord::Base
726
+ include AASM
727
+
728
+ aasm skip_validation_on_save: true do
729
+ state :sleeping, initial: true
730
+ state :running
731
+
732
+ event :run do
733
+ transitions from: :sleeping, to: :running
734
+ end
735
+
736
+ event :sleep do
737
+ transitions from: :running, to: :sleeping
738
+ end
739
+ end
740
+
741
+ end
742
+ ```
743
+
744
+ Also You can skip the validation at instance level with `some_event_name_without_validation!` method.
745
+ With this you have the flexibility of having validation for all your transitions by default and then skip it wherever required.
746
+ Please note that only state column will be updated as mentioned in the above example.
747
+
748
+ ```ruby
749
+ job.run_without_validation!
750
+ ```
751
+
752
+ If you want to make sure that the _AASM_ column for storing the state is not directly assigned,
753
+ configure _AASM_ to not allow direct assignment, like this:
754
+
755
+ ```ruby
756
+ class Job < ActiveRecord::Base
757
+ include AASM
758
+
759
+ aasm no_direct_assignment: true do
760
+ state :sleeping, initial: true
761
+ state :running
762
+
763
+ event :run do
764
+ transitions from: :sleeping, to: :running
765
+ end
766
+ end
767
+
768
+ end
769
+ ```
770
+
771
+ resulting in this:
772
+
773
+ ```ruby
774
+ job = Job.create
775
+ job.aasm_state # => 'sleeping'
776
+ job.aasm_state = :running # => raises AASM::NoDirectAssignmentError
777
+ job.aasm_state # => 'sleeping'
778
+ ```
779
+
780
+ #### ActiveRecord enums
781
+
782
+ You can use
783
+ [enumerations](http://edgeapi.rubyonrails.org/classes/ActiveRecord/Enum.html)
784
+ in Rails 4.1+ for your state column:
785
+
786
+ ```ruby
787
+ class Job < ActiveRecord::Base
788
+ include AASM
789
+
790
+ enum state: {
791
+ sleeping: 5,
792
+ running: 99
793
+ }
794
+
795
+ aasm column: :state, enum: true do
796
+ state :sleeping, initial: true
797
+ state :running
798
+ end
799
+ end
800
+ ```
801
+
802
+ You can explicitly pass the name of the method which provides access
803
+ to the enumeration mapping as a value of ```enum```, or you can simply
804
+ set it to ```true```. In the latter case AASM will try to use
805
+ pluralized column name to access possible enum states.
806
+
807
+ Furthermore, if your column has integer type (which is normally the
808
+ case when you're working with Rails enums), you can omit ```:enum```
809
+ setting --- AASM auto-detects this situation and enabled enum
810
+ support. If anything goes wrong, you can disable enum functionality
811
+ and fall back to the default behavior by setting ```:enum```
812
+ to ```false```.
813
+
814
+ ### Sequel
815
+
816
+ AASM also supports [Sequel](http://sequel.jeremyevans.net/) besides _ActiveRecord_, and _Mongoid_.
817
+
818
+ ```ruby
819
+ class Job < Sequel::Model
820
+ include AASM
821
+
822
+ aasm do # default column: aasm_state
823
+ ...
824
+ end
825
+ end
826
+ ```
827
+
828
+ However it's not yet as feature complete as _ActiveRecord_. For example, there are
829
+ scopes defined yet. See [Automatic Scopes](#automatic-scopes).
830
+
831
+ ### Dynamoid
832
+
833
+ Since version `4.8.0` _AASM_ also supports [Dynamoid](http://joshsymonds.com/Dynamoid/) as
834
+ persistence ORM.
835
+
836
+ ### Mongoid
837
+
838
+ AASM also supports persistence to Mongodb if you're using Mongoid. Make sure
839
+ to include Mongoid::Document before you include AASM.
840
+
841
+ ```ruby
842
+ class Job
843
+ include Mongoid::Document
844
+ include AASM
845
+ field :aasm_state
846
+ aasm do
847
+ ...
848
+ end
849
+ end
850
+ ```
851
+
852
+ ### NoBrainer
853
+
854
+ AASM also supports persistence to [RethinkDB](https://www.rethinkdb.com/)
855
+ if you're using [Nobrainer](http://nobrainer.io/).
856
+ Make sure to include NoBrainer::Document before you include AASM.
857
+
858
+ ```ruby
859
+ class Job
860
+ include NoBrainer::Document
861
+ include AASM
862
+ field :aasm_state
863
+ aasm do
864
+ ...
865
+ end
866
+ end
867
+ ```
868
+
869
+ ### Redis
870
+
871
+ AASM also supports persistence in Redis via
872
+ [Redis::Objects](https://github.com/nateware/redis-objects).
873
+ Make sure to include Redis::Objects before you include AASM. Note that non-bang
874
+ events will work as bang events, persisting the changes on every call.
875
+
876
+ ```ruby
877
+ class User
878
+ include Redis::Objects
879
+ include AASM
880
+
881
+ aasm do
882
+ end
883
+ end
884
+ ```
885
+
886
+ ### Automatic Scopes
887
+
888
+ AASM will automatically create scope methods for each state in the model.
889
+
890
+ ```ruby
891
+ class Job < ActiveRecord::Base
892
+ include AASM
893
+
894
+ aasm do
895
+ state :sleeping, initial: true
896
+ state :running
897
+ state :cleaning
898
+ end
899
+
900
+ def self.sleeping
901
+ "This method name is already in use"
902
+ end
903
+ end
904
+ ```
905
+
906
+ ```ruby
907
+ class JobsController < ApplicationController
908
+ def index
909
+ @running_jobs = Job.running
910
+ @recent_cleaning_jobs = Job.cleaning.where('created_at >= ?', 3.days.ago)
911
+
912
+ # @sleeping_jobs = Job.sleeping #=> "This method name is already in use"
913
+ end
914
+ end
915
+ ```
916
+
917
+ If you don't need scopes (or simply don't want them), disable their creation when
918
+ defining the `AASM` states, like this:
919
+
920
+ ```ruby
921
+ class Job < ActiveRecord::Base
922
+ include AASM
923
+
924
+ aasm create_scopes: false do
925
+ state :sleeping, initial: true
926
+ state :running
927
+ state :cleaning
928
+ end
929
+ end
930
+ ```
931
+
932
+
933
+ ### Transaction support
934
+
935
+ Since version *3.0.13* AASM supports ActiveRecord transactions. So whenever a transition
936
+ callback or the state update fails, all changes to any database record are rolled back.
937
+ Mongodb does not support transactions.
938
+
939
+ There are currently 3 transactional callbacks that can be handled on the event, and 2 transactional callbacks for all events.
940
+
941
+ ```ruby
942
+ event before_all_transactions
943
+ event before_transaction
944
+ event aasm_fire_event (within transaction)
945
+ event after_commit (if event successful)
946
+ event after_transaction
947
+ event after_all_transactions
948
+ ```
949
+
950
+ If you want to make sure a depending action happens only after the transaction is committed,
951
+ use the `after_commit` callback along with the auto-save (bang) methods, like this:
952
+
953
+ ```ruby
954
+ class Job < ActiveRecord::Base
955
+ include AASM
956
+
957
+ aasm do
958
+ state :sleeping, initial: true
959
+ state :running
960
+
961
+ event :run, after_commit: :notify_about_running_job do
962
+ transitions from: :sleeping, to: :running
963
+ end
964
+ end
965
+
966
+ def notify_about_running_job
967
+ ...
968
+ end
969
+ end
970
+
971
+ job = Job.where(state: 'sleeping').first!
972
+ job.run! # Saves the model and triggers the after_commit callback
973
+ ```
974
+
975
+ Note that the following will not run the `after_commit` callbacks because
976
+ the auto-save method is not used:
977
+
978
+ ```ruby
979
+ job = Job.where(state: 'sleeping').first!
980
+ job.run
981
+ job.save! #notify_about_running_job is not run
982
+ ```
983
+
984
+ If you want to encapsulate state changes within an own transaction, the behavior
985
+ of this nested transaction might be confusing. Take a look at
986
+ [ActiveRecord Nested Transactions](http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html)
987
+ if you want to know more about this. Nevertheless, AASM by default requires a new transaction
988
+ `transaction(requires_new: true)`. You can override this behavior by changing
989
+ the configuration
990
+
991
+ ```ruby
992
+ class Job < ActiveRecord::Base
993
+ include AASM
994
+
995
+ aasm requires_new_transaction: false do
996
+ ...
997
+ end
998
+
999
+ ...
1000
+ end
1001
+ ```
1002
+
1003
+ which then leads to `transaction(requires_new: false)`, the Rails default.
1004
+
1005
+ Additionally, if you do not want any of your active record actions to be
1006
+ wrapped in a transaction, you can specify the `use_transactions` flag. This can
1007
+ be useful if you want want to persist things to the database that happen as a
1008
+ result of a transaction or callback, even when some error occurs. The
1009
+ `use_transactions` flag is true by default.
1010
+
1011
+ ```ruby
1012
+ class Job < ActiveRecord::Base
1013
+ include AASM
1014
+
1015
+ aasm use_transactions: false do
1016
+ ...
1017
+ end
1018
+
1019
+ ...
1020
+ end
1021
+ ```
1022
+
1023
+ ### Pessimistic Locking
1024
+
1025
+ AASM supports [Active Record pessimistic locking via `with_lock`](http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html#method-i-with_lock) for database persistence layers.
1026
+
1027
+ | Option | Purpose |
1028
+ | ------ | ------- |
1029
+ | `false` (default) | No lock is obtained | |
1030
+ | `true` | Obtain a blocking pessimistic lock e.g. `FOR UPDATE` |
1031
+ | String | Obtain a lock based on the SQL string e.g. `FOR UPDATE NOWAIT` |
1032
+
1033
+
1034
+ ```ruby
1035
+ class Job < ActiveRecord::Base
1036
+ include AASM
1037
+
1038
+ aasm requires_lock: true do
1039
+ ...
1040
+ end
1041
+
1042
+ ...
1043
+ end
1044
+ ```
1045
+
1046
+ ```ruby
1047
+ class Job < ActiveRecord::Base
1048
+ include AASM
1049
+
1050
+ aasm requires_lock: 'FOR UPDATE NOWAIT' do
1051
+ ...
1052
+ end
1053
+
1054
+ ...
1055
+ end
1056
+ ```
1057
+
1058
+
1059
+ ### Column name & migration
1060
+
1061
+ As a default AASM uses the column `aasm_state` to store the states. You can override
1062
+ this by defining your favorite column name, using `:column` like this:
1063
+
1064
+ ```ruby
1065
+ class Job < ActiveRecord::Base
1066
+ include AASM
1067
+
1068
+ aasm column: :my_state do
1069
+ ...
1070
+ end
1071
+
1072
+ aasm :another_state_machine, column: :second_state do
1073
+ ...
1074
+ end
1075
+ end
1076
+ ```
1077
+
1078
+ Whatever column name is used, make sure to add a migration to provide this column
1079
+ (of type `string`):
1080
+
1081
+ ```ruby
1082
+ class AddJobState < ActiveRecord::Migration
1083
+ def self.up
1084
+ add_column :jobs, :aasm_state, :string
1085
+ end
1086
+
1087
+ def self.down
1088
+ remove_column :jobs, :aasm_state
1089
+ end
1090
+ end
1091
+ ```
1092
+
1093
+ ### Log State Changes
1094
+
1095
+ Logging state change can be done using [paper_trail](https://github.com/paper-trail-gem/paper_trail) gem
1096
+
1097
+ Example of implementation can be found here [https://github.com/nitsujri/aasm-papertrail-example](https://github.com/nitsujri/aasm-papertrail-example)
1098
+
1099
+
1100
+ ### Inspection
1101
+
1102
+ AASM supports query methods for states and events
1103
+
1104
+ Given the following `Job` class:
1105
+
1106
+ ```ruby
1107
+ class Job
1108
+ include AASM
1109
+
1110
+ aasm do
1111
+ state :sleeping, initial: true
1112
+ state :running, :cleaning
1113
+
1114
+ event :run do
1115
+ transitions from: :sleeping, to: :running
1116
+ end
1117
+
1118
+ event :clean do
1119
+ transitions from: :running, to: :cleaning, guard: :cleaning_needed?
1120
+ end
1121
+
1122
+ event :sleep do
1123
+ transitions from: [:running, :cleaning], to: :sleeping
1124
+ end
1125
+ end
1126
+
1127
+ def cleaning_needed?
1128
+ false
1129
+ end
1130
+ end
1131
+ ```
1132
+
1133
+ ```ruby
1134
+ # show all states
1135
+ Job.aasm.states.map(&:name)
1136
+ #=> [:sleeping, :running, :cleaning]
1137
+
1138
+ job = Job.new
1139
+
1140
+ # show all permitted states (from initial state)
1141
+ job.aasm.states(permitted: true).map(&:name)
1142
+ #=> [:running]
1143
+
1144
+ # List all the permitted transitions(event and state pairs) from initial state
1145
+ job.aasm.permitted_transitions
1146
+ #=> [{ :event => :run, :state => :running }]
1147
+
1148
+ job.run
1149
+ job.aasm.states(permitted: true).map(&:name)
1150
+ #=> [:sleeping]
1151
+
1152
+ # show all non permitted states
1153
+ job.aasm.states(permitted: false).map(&:name)
1154
+ #=> [:cleaning]
1155
+
1156
+ # show all possible (triggerable) events from the current state
1157
+ job.aasm.events.map(&:name)
1158
+ #=> [:clean, :sleep]
1159
+
1160
+ # show all permitted events
1161
+ job.aasm.events(permitted: true).map(&:name)
1162
+ #=> [:sleep]
1163
+
1164
+ # show all non permitted events
1165
+ job.aasm.events(permitted: false).map(&:name)
1166
+ #=> [:clean]
1167
+
1168
+ # show all possible events except a specific one
1169
+ job.aasm.events(reject: :sleep).map(&:name)
1170
+ #=> [:clean]
1171
+
1172
+ # list states for select
1173
+ Job.aasm.states_for_select
1174
+ #=> [["Sleeping", "sleeping"], ["Running", "running"], ["Cleaning", "cleaning"]]
1175
+
1176
+ # show permitted states with guard parameter
1177
+ job.aasm.states({permitted: true}, guard_parameter).map(&:name)
1178
+ ```
1179
+
1180
+
1181
+ ### Warning output
1182
+
1183
+ Warnings are by default printed to `STDERR`. If you want to log those warnings to another output,
1184
+ use
1185
+
1186
+ ```ruby
1187
+ class Job
1188
+ include AASM
1189
+
1190
+ aasm logger: Rails.logger do
1191
+ ...
1192
+ end
1193
+ end
1194
+ ```
1195
+
1196
+ You can hide warnings by setting `AASM::Configuration.hide_warnings = true`
1197
+
1198
+ ### RubyMotion support
1199
+
1200
+ Now supports [CodeDataQuery](https://github.com/infinitered/cdq.git) !
1201
+ However I'm still in the process of submitting my compatibility updates to their repository.
1202
+ In the meantime you can use [my fork](https://github.com/Infotaku/cdq.git), there may still be some minor issues but I intend to extensively use it myself, so fixes should come fast.
1203
+
1204
+ Warnings:
1205
+ - Due to RubyMotion Proc's lack of 'source_location' method, it may be harder
1206
+ to find out the origin of a "cannot transition from" error. I would recommend using
1207
+ the 'instance method symbol / string' way whenever possible when defining guardians and callbacks.
1208
+
1209
+
1210
+ ### Testing
1211
+
1212
+ #### RSpec
1213
+
1214
+ AASM provides some matchers for [RSpec](http://rspec.info):
1215
+ * `transition_from`,
1216
+ * `have_state`, `allow_event`
1217
+ * and `allow_transition_to`.
1218
+
1219
+ ##### Installation Instructions:
1220
+ * Add `require 'aasm/rspec'` to your `spec_helper.rb` file.
1221
+
1222
+ ##### Examples Of Usage in Rspec:
1223
+
1224
+ ```ruby
1225
+ # classes with only the default state machine
1226
+ job = Job.new
1227
+ expect(job).to transition_from(:sleeping).to(:running).on_event(:run)
1228
+ expect(job).not_to transition_from(:sleeping).to(:cleaning).on_event(:run)
1229
+ expect(job).to have_state(:sleeping)
1230
+ expect(job).not_to have_state(:running)
1231
+ expect(job).to allow_event :run
1232
+ expect(job).to_not allow_event :clean
1233
+ expect(job).to allow_transition_to(:running)
1234
+ expect(job).to_not allow_transition_to(:cleaning)
1235
+ # on_event also accept multiple arguments
1236
+ expect(job).to transition_from(:sleeping).to(:running).on_event(:run, :defragmentation)
1237
+
1238
+ # classes with multiple state machine
1239
+ multiple = SimpleMultipleExample.new
1240
+ expect(multiple).to transition_from(:standing).to(:walking).on_event(:walk).on(:move)
1241
+ expect(multiple).to_not transition_from(:standing).to(:running).on_event(:walk).on(:move)
1242
+ expect(multiple).to have_state(:standing).on(:move)
1243
+ expect(multiple).not_to have_state(:walking).on(:move)
1244
+ expect(multiple).to allow_event(:walk).on(:move)
1245
+ expect(multiple).to_not allow_event(:hold).on(:move)
1246
+ expect(multiple).to allow_transition_to(:walking).on(:move)
1247
+ expect(multiple).to_not allow_transition_to(:running).on(:move)
1248
+ expect(multiple).to transition_from(:sleeping).to(:processing).on_event(:start).on(:work)
1249
+ expect(multiple).to_not transition_from(:sleeping).to(:sleeping).on_event(:start).on(:work)
1250
+ expect(multiple).to have_state(:sleeping).on(:work)
1251
+ expect(multiple).not_to have_state(:processing).on(:work)
1252
+ expect(multiple).to allow_event(:start).on(:move)
1253
+ expect(multiple).to_not allow_event(:stop).on(:move)
1254
+ expect(multiple).to allow_transition_to(:processing).on(:move)
1255
+ expect(multiple).to_not allow_transition_to(:sleeping).on(:move)
1256
+ # allow_event also accepts arguments
1257
+ expect(job).to allow_event(:run).with(:defragmentation)
1258
+
1259
+ ```
1260
+
1261
+ #### Minitest
1262
+
1263
+ AASM provides assertions and rspec-like expectations for [Minitest](https://github.com/seattlerb/minitest).
1264
+
1265
+ ##### Assertions
1266
+
1267
+ List of supported assertions: `assert_have_state`, `refute_have_state`, `assert_transitions_from`, `refute_transitions_from`, `assert_event_allowed`, `refute_event_allowed`, `assert_transition_to_allowed`, `refute_transition_to_allowed`.
1268
+
1269
+
1270
+ ##### Examples Of Usage (Minitest):
1271
+
1272
+ Add `require 'aasm/minitest'` to your `test_helper.rb` file and use them like this:
1273
+
1274
+ ```ruby
1275
+ # classes with only the default state machine
1276
+ job = Job.new
1277
+ assert_transitions_from job, :sleeping, to: :running, on_event: :run
1278
+ refute_transitions_from job, :sleeping, to: :cleaning, on_event: :run
1279
+ assert_have_state job, :sleeping
1280
+ refute_have_state job, :running
1281
+ assert_event_allowed job, :run
1282
+ refute_event_allowed job, :clean
1283
+ assert_transition_to_allowed job, :running
1284
+ refute_transition_to_allowed job, :cleaning
1285
+ # on_event also accept arguments
1286
+ assert_transitions_from job, :sleeping, :defragmentation, to: :running, on_event: :run
1287
+
1288
+ # classes with multiple state machine
1289
+ multiple = SimpleMultipleExample.new
1290
+ assert_transitions_from multiple, :standing, to: :walking, on_event: :walk, on: :move
1291
+ refute_transitions_from multiple, :standing, to: :running, on_event: :walk, on: :move
1292
+ assert_have_state multiple, :standing, on: :move
1293
+ refute_have_state multiple, :walking, on: :move
1294
+ assert_event_allowed multiple, :walk, on: :move
1295
+ refute_event_allowed multiple, :hold, on: :move
1296
+ assert_transition_to_allowed multiple, :walking, on: :move
1297
+ refute_transition_to_allowed multiple, :running, on: :move
1298
+ assert_transitions_from multiple, :sleeping, to: :processing, on_event: :start, on: :work
1299
+ refute_transitions_from multiple, :sleeping, to: :sleeping, on_event: :start, on: :work
1300
+ assert_have_state multiple, :sleeping, on: :work
1301
+ refute_have_state multiple, :processing, on: :work
1302
+ assert_event_allowed multiple, :start, on: :move
1303
+ refute_event_allowed multiple, :stop, on: :move
1304
+ assert_transition_to_allowed multiple, :processing, on: :move
1305
+ refute_transition_to_allowed multiple, :sleeping, on: :move
1306
+ ```
1307
+
1308
+ ##### Expectations
1309
+
1310
+ List of supported expectations: `must_transition_from`, `wont_transition_from`, `must_have_state`, `wont_have_state`, `must_allow_event`, `wont_allow_event`, `must_allow_transition_to`, `wont_allow_transition_to`.
1311
+
1312
+ Add `require 'aasm/minitest_spec'` to your `test_helper.rb` file and use them like this:
1313
+
1314
+ ```ruby
1315
+ # classes with only the default state machine
1316
+ job = Job.new
1317
+ job.must_transition_from :sleeping, to: :running, on_event: :run
1318
+ job.wont_transition_from :sleeping, to: :cleaning, on_event: :run
1319
+ job.must_have_state :sleeping
1320
+ job.wont_have_state :running
1321
+ job.must_allow_event :run
1322
+ job.wont_allow_event :clean
1323
+ job.must_allow_transition_to :running
1324
+ job.wont_allow_transition_to :cleaning
1325
+ # on_event also accept arguments
1326
+ job.must_transition_from :sleeping, :defragmentation, to: :running, on_event: :run
1327
+
1328
+ # classes with multiple state machine
1329
+ multiple = SimpleMultipleExample.new
1330
+ multiple.must_transition_from :standing, to: :walking, on_event: :walk, on: :move
1331
+ multiple.wont_transition_from :standing, to: :running, on_event: :walk, on: :move
1332
+ multiple.must_have_state :standing, on: :move
1333
+ multiple.wont_have_state :walking, on: :move
1334
+ multiple.must_allow_event :walk, on: :move
1335
+ multiple.wont_allow_event :hold, on: :move
1336
+ multiple.must_allow_transition_to :walking, on: :move
1337
+ multiple.wont_allow_transition_to :running, on: :move
1338
+ multiple.must_transition_from :sleeping, to: :processing, on_event: :start, on: :work
1339
+ multiple.wont_transition_from :sleeping, to: :sleeping, on_event: :start, on: :work
1340
+ multiple.must_have_state :sleeping, on: :work
1341
+ multiple.wont_have_state :processing, on: :work
1342
+ multiple.must_allow_event :start, on: :move
1343
+ multiple.wont_allow_event :stop, on: :move
1344
+ multiple.must_allow_transition_to :processing, on: :move
1345
+ multiple.wont_allow_transition_to :sleeping, on: :move
1346
+ ```
1347
+
1348
+ ## <a id="installation">Installation ##
1349
+
1350
+ ### Manually from RubyGems.org ###
1351
+
1352
+ ```sh
1353
+ % gem install aasm
1354
+ ```
1355
+
1356
+ ### Or if you are using Bundler ###
1357
+
1358
+ ```ruby
1359
+ # Gemfile
1360
+ gem 'aasm'
1361
+ ```
1362
+
1363
+ ### Building your own gems ###
1364
+
1365
+ ```sh
1366
+ % rake build
1367
+ % sudo gem install pkg/aasm-x.y.z.gem
1368
+ ```
1369
+
1370
+ ### Generators
1371
+
1372
+ After installing AASM you can run generator:
1373
+
1374
+ ```sh
1375
+ % rails generate aasm NAME [COLUMN_NAME]
1376
+ ```
1377
+ Replace NAME with the Model name, COLUMN_NAME is optional(default is 'aasm_state').
1378
+ This will create a model (if one does not exist) and configure it with aasm block.
1379
+ For Active record orm a migration file is added to add aasm state column to table.
1380
+
1381
+ ### Docker
1382
+
1383
+ Run test suite easily on docker
1384
+ ```
1385
+ 1. docker-compose build aasm
1386
+ 2. docker-compose run --rm aasm
1387
+ ```
1388
+
1389
+ ## Latest changes ##
1390
+
1391
+ Take a look at the [CHANGELOG](https://github.com/aasm/aasm/blob/master/CHANGELOG.md) for details about recent changes to the current version.
1392
+
1393
+ ## Questions? ##
1394
+
1395
+ Feel free to
1396
+
1397
+ * [create an issue on GitHub](https://github.com/aasm/aasm/issues)
1398
+ * [ask a question on StackOverflow](http://stackoverflow.com) (tag with `aasm`)
1399
+ * send us a tweet [@aasm](http://twitter.com/aasm)
1400
+
1401
+ ## Maintainers ##
1402
+
1403
+ * [Scott Barron](https://github.com/rubyist) (2006–2009, original author)
1404
+ * [Travis Tilley](https://github.com/ttilley) (2009–2011)
1405
+ * [Thorsten Böttger](http://github.com/alto) (since 2011)
1406
+ * [Anil Maurya](http://github.com/anilmaurya) (since 2016)
1407
+
1408
+
1409
+ ## [Contributing](CONTRIBUTING.md)
1410
+
1411
+ ## Warranty ##
1412
+
1413
+ This software is provided "as is" and without any express or
1414
+ implied warranties, including, without limitation, the implied
1415
+ warranties of merchantibility and fitness for a particular
1416
+ purpose.
1417
+
1418
+ ## License ##
1419
+
1420
+ Copyright (c) 2006-2017 Scott Barron
1421
+
1422
+ Permission is hereby granted, free of charge, to any person obtaining
1423
+ a copy of this software and associated documentation files (the
1424
+ "Software"), to deal in the Software without restriction, including
1425
+ without limitation the rights to use, copy, modify, merge, publish,
1426
+ distribute, sublicense, and/or sell copies of the Software, and to
1427
+ permit persons to whom the Software is furnished to do so, subject to
1428
+ the following conditions:
1429
+
1430
+ The above copyright notice and this permission notice shall be
1431
+ included in all copies or substantial portions of the Software.
1432
+
1433
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1434
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1435
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1436
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
1437
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
1438
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
1439
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.