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,92 @@
1
+ module AASM
2
+ module Persistence
3
+ module DynamoidPersistence
4
+ def self.included(base)
5
+ base.send(:include, AASM::Persistence::Base)
6
+ base.send(:include, AASM::Persistence::DynamoidPersistence::InstanceMethods)
7
+
8
+ base.after_initialize :aasm_ensure_initial_state
9
+
10
+ # Because Dynamoid only use define_method to add attribute assignment method in Class.
11
+ #
12
+ # In AASM::Base.initialize, it redefines and calls super in this method without superclass method.
13
+ # We override method_missing to solve this problem.
14
+ #
15
+ base.class_eval %Q(
16
+ def method_missing(method_name, *arguments, &block)
17
+ if (AASM::StateMachineStore.fetch(self.class, true).machine_names.map { |state_machine_name| self.class.aasm(state_machine_name).attribute_name.to_s + "=" }).include? method_name.to_s
18
+ attribute_name = method_name.to_s.gsub("=", '')
19
+ write_attribute(attribute_name.to_sym, *arguments)
20
+ else
21
+ super
22
+ end
23
+ end
24
+ )
25
+ end
26
+
27
+ module InstanceMethods
28
+
29
+ # Writes <tt>state</tt> to the state column and persists it to the database
30
+ # using update_attribute (which bypasses validation)
31
+ #
32
+ # foo = Foo.find(1)
33
+ # foo.aasm.current_state # => :opened
34
+ # foo.close!
35
+ # foo.aasm.current_state # => :closed
36
+ # Foo.find(1).aasm.current_state # => :closed
37
+ #
38
+ # NOTE: intended to be called from an event
39
+ def aasm_write_state(state, name=:default)
40
+ old_value = read_attribute(self.class.aasm(name).attribute_name)
41
+ write_attribute(self.class.aasm(name).attribute_name, state.to_s)
42
+
43
+ unless self.save(:validate => false)
44
+ write_attribute(self.class.aasm(name).attribute_name, old_value)
45
+ return false
46
+ end
47
+
48
+ true
49
+ end
50
+
51
+ # Writes <tt>state</tt> to the state column, but does not persist it to the database
52
+ #
53
+ # foo = Foo.find(1)
54
+ # foo.aasm.current_state # => :opened
55
+ # foo.close
56
+ # foo.aasm.current_state # => :closed
57
+ # Foo.find(1).aasm.current_state # => :opened
58
+ # foo.save
59
+ # foo.aasm.current_state # => :closed
60
+ # Foo.find(1).aasm.current_state # => :closed
61
+ #
62
+ # NOTE: intended to be called from an event
63
+ def aasm_write_state_without_persistence(state, name=:default)
64
+ write_attribute(self.class.aasm(name).attribute_name, state.to_s)
65
+ end
66
+
67
+ private
68
+
69
+ # Ensures that if the aasm_state column is nil and the record is new
70
+ # that the initial state gets populated before validation on create
71
+ #
72
+ # foo = Foo.new
73
+ # foo.aasm_state # => nil
74
+ # foo.valid?
75
+ # foo.aasm_state # => "open" (where :open is the initial state)
76
+ #
77
+ #
78
+ # foo = Foo.find(:first)
79
+ # foo.aasm_state # => 1
80
+ # foo.aasm_state = nil
81
+ # foo.valid?
82
+ # foo.aasm_state # => nil
83
+ #
84
+ def aasm_ensure_initial_state
85
+ AASM::StateMachineStore.fetch(self.class, true).machine_names.each do |state_machine_name|
86
+ aasm(state_machine_name).enter_initial_state if !send(self.class.aasm(state_machine_name).attribute_name) || send(self.class.aasm(state_machine_name).attribute_name).empty?
87
+ end
88
+ end
89
+ end # InstanceMethods
90
+ end
91
+ end # Persistence
92
+ end # AASM
@@ -0,0 +1,126 @@
1
+ require 'aasm/persistence/orm'
2
+ module AASM
3
+ module Persistence
4
+ module MongoidPersistence
5
+ # This method:
6
+ #
7
+ # * extends the model with ClassMethods
8
+ # * includes InstanceMethods
9
+ #
10
+ # Adds
11
+ #
12
+ # before_validation :aasm_ensure_initial_state
13
+ #
14
+ # As a result, it doesn't matter when you define your methods - the following 2 are equivalent
15
+ #
16
+ # class Foo
17
+ # include Mongoid::Document
18
+ # def aasm_write_state(state)
19
+ # "bar"
20
+ # end
21
+ # include AASM
22
+ # end
23
+ #
24
+ # class Foo
25
+ # include Mongoid::Document
26
+ # include AASM
27
+ # def aasm_write_state(state)
28
+ # "bar"
29
+ # end
30
+ # end
31
+ #
32
+ def self.included(base)
33
+ base.send(:include, AASM::Persistence::Base)
34
+ base.send(:include, AASM::Persistence::ORM)
35
+ base.send(:include, AASM::Persistence::MongoidPersistence::InstanceMethods)
36
+ base.extend AASM::Persistence::MongoidPersistence::ClassMethods
37
+
38
+ base.after_initialize :aasm_ensure_initial_state
39
+ end
40
+
41
+ module ClassMethods
42
+ def aasm_create_scope(state_machine_name, scope_name)
43
+ scope_options = lambda {
44
+ send(
45
+ :where,
46
+ { aasm(state_machine_name).attribute_name.to_sym => scope_name.to_s }
47
+ )
48
+ }
49
+ send(:scope, scope_name, scope_options)
50
+ end
51
+ end
52
+
53
+ module InstanceMethods
54
+
55
+ private
56
+
57
+ def aasm_save
58
+ self.save
59
+ end
60
+
61
+ def aasm_raise_invalid_record
62
+ raise Mongoid::Errors::Validations.new(self)
63
+ end
64
+
65
+ def aasm_supports_transactions?
66
+ false
67
+ end
68
+
69
+ def aasm_update_column(attribute_name, value)
70
+ if Mongoid::VERSION.to_f >= 4
71
+ set(Hash[attribute_name, value])
72
+ else
73
+ set(attribute_name, value)
74
+ end
75
+
76
+ true
77
+ end
78
+
79
+ def aasm_read_attribute(name)
80
+ read_attribute(name)
81
+ end
82
+
83
+ def aasm_write_attribute(name, value)
84
+ write_attribute(name, value)
85
+ end
86
+
87
+ # Ensures that if the aasm_state column is nil and the record is new
88
+ # that the initial state gets populated before validation on create
89
+ #
90
+ # foo = Foo.new
91
+ # foo.aasm_state # => nil
92
+ # foo.valid?
93
+ # foo.aasm_state # => "open" (where :open is the initial state)
94
+ #
95
+ #
96
+ # foo = Foo.find(:first)
97
+ # foo.aasm_state # => 1
98
+ # foo.aasm_state = nil
99
+ # foo.valid?
100
+ # foo.aasm_state # => nil
101
+ #
102
+ def aasm_ensure_initial_state
103
+ AASM::StateMachineStore.fetch(self.class, true).machine_names.each do |state_machine_name|
104
+ attribute_name = self.class.aasm(state_machine_name).attribute_name.to_s
105
+ # Do not load initial state when object attributes are not loaded,
106
+ # mongoid has_many relationship does not load child object attributes when
107
+ # only ids are loaded, for example parent.child_ids will not load child object attributes.
108
+ # This feature is introduced in mongoid > 4.
109
+ if attribute_names.include?(attribute_name) && !attributes[attribute_name] || attributes[attribute_name].empty?
110
+ # attribute_missing? is defined in mongoid > 4
111
+ return if Mongoid::VERSION.to_f >= 4 && attribute_missing?(attribute_name)
112
+ send("#{self.class.aasm(state_machine_name).attribute_name}=", aasm(state_machine_name).enter_initial_state.to_s)
113
+ end
114
+ end
115
+ end
116
+ end # InstanceMethods
117
+
118
+ # module NamedScopeMethods
119
+ # def aasm_state_with_named_scope name, options = {}
120
+ # aasm_state_without_named_scope name, options
121
+ # self.named_scope name, :conditions => { "#{table_name}.#{self.aasm.attribute_name}" => name.to_s} unless self.respond_to?(name)
122
+ # end
123
+ # end
124
+ end
125
+ end # Persistence
126
+ end # AASM
@@ -0,0 +1,105 @@
1
+ require 'aasm/persistence/orm'
2
+ module AASM
3
+ module Persistence
4
+ module NoBrainerPersistence
5
+ # This method:
6
+ #
7
+ # * extends the model with ClassMethods
8
+ # * includes InstanceMethods
9
+ #
10
+ # Adds
11
+ #
12
+ # before_validation :aasm_ensure_initial_state
13
+ #
14
+ # As a result, it doesn't matter when you define your methods - the following 2 are equivalent
15
+ #
16
+ # class Foo
17
+ # include NoBrainer::Document
18
+ # def aasm_write_state(state)
19
+ # "bar"
20
+ # end
21
+ # include AASM
22
+ # end
23
+ #
24
+ # class Foo
25
+ # include NoBrainer::Document
26
+ # include AASM
27
+ # def aasm_write_state(state)
28
+ # "bar"
29
+ # end
30
+ # end
31
+ #
32
+ def self.included(base)
33
+ base.send(:include, AASM::Persistence::Base)
34
+ base.send(:include, AASM::Persistence::ORM)
35
+ base.send(:include, AASM::Persistence::NoBrainerPersistence::InstanceMethods)
36
+ base.extend AASM::Persistence::NoBrainerPersistence::ClassMethods
37
+
38
+ base.after_initialize :aasm_ensure_initial_state
39
+ end
40
+
41
+ module ClassMethods
42
+ def aasm_create_scope(state_machine_name, scope_name)
43
+ scope_options = lambda {
44
+ where(aasm(state_machine_name).attribute_name.to_sym => scope_name.to_s)
45
+ }
46
+ send(:scope, scope_name, scope_options)
47
+ end
48
+ end
49
+
50
+ module InstanceMethods
51
+
52
+ private
53
+
54
+ def aasm_save
55
+ self.save
56
+ end
57
+
58
+ def aasm_raise_invalid_record
59
+ raise NoBrainer::Error::DocumentInvalid.new(self)
60
+ end
61
+
62
+ def aasm_supports_transactions?
63
+ false
64
+ end
65
+
66
+ def aasm_update_column(attribute_name, value)
67
+ write_attribute(attribute_name, value)
68
+ save(validate: false)
69
+
70
+ true
71
+ end
72
+
73
+ def aasm_read_attribute(name)
74
+ read_attribute(name)
75
+ end
76
+
77
+ def aasm_write_attribute(name, value)
78
+ write_attribute(name, value)
79
+ end
80
+
81
+ # Ensures that if the aasm_state column is nil and the record is new
82
+ # that the initial state gets populated before validation on create
83
+ #
84
+ # foo = Foo.new
85
+ # foo.aasm_state # => nil
86
+ # foo.valid?
87
+ # foo.aasm_state # => "open" (where :open is the initial state)
88
+ #
89
+ #
90
+ # foo = Foo.find(:first)
91
+ # foo.aasm_state # => 1
92
+ # foo.aasm_state = nil
93
+ # foo.valid?
94
+ # foo.aasm_state # => nil
95
+ #
96
+ def aasm_ensure_initial_state
97
+ AASM::StateMachineStore.fetch(self.class, true).machine_names.each do |name|
98
+ aasm_column = self.class.aasm(name).attribute_name
99
+ aasm(name).enter_initial_state if !read_attribute(aasm_column) || read_attribute(aasm_column).empty?
100
+ end
101
+ end
102
+ end # InstanceMethods
103
+ end
104
+ end # Persistence
105
+ end # AASM
@@ -0,0 +1,150 @@
1
+ module AASM
2
+ module Persistence
3
+ # This module adds transactional support for any database that supports it.
4
+ # This includes rollback capability and rollback/commit callbacks.
5
+ module ORM
6
+
7
+ # Writes <tt>state</tt> to the state column and persists it to the database
8
+ #
9
+ # foo = Foo.find(1)
10
+ # foo.aasm.current_state # => :opened
11
+ # foo.close!
12
+ # foo.aasm.current_state # => :closed
13
+ # Foo.find(1).aasm.current_state # => :closed
14
+ #
15
+ # NOTE: intended to be called from an event
16
+ def aasm_write_state(state, name=:default)
17
+ attribute_name = self.class.aasm(name).attribute_name
18
+ old_value = aasm_read_attribute(attribute_name)
19
+ aasm_write_state_attribute state, name
20
+
21
+ success = if aasm_skipping_validations(name)
22
+ aasm_update_column(attribute_name, aasm_raw_attribute_value(state, name))
23
+ else
24
+ aasm_save
25
+ end
26
+
27
+ unless success
28
+ aasm_rollback(name, old_value)
29
+ aasm_raise_invalid_record if aasm_whiny_persistence(name)
30
+ end
31
+
32
+ success
33
+ end
34
+
35
+ # Writes <tt>state</tt> to the state field, but does not persist it to the database
36
+ #
37
+ # foo = Foo.find(1)
38
+ # foo.aasm.current_state # => :opened
39
+ # foo.close
40
+ # foo.aasm.current_state # => :closed
41
+ # Foo.find(1).aasm.current_state # => :opened
42
+ # foo.save
43
+ # foo.aasm.current_state # => :closed
44
+ # Foo.find(1).aasm.current_state # => :closed
45
+ #
46
+ # NOTE: intended to be called from an event
47
+ def aasm_write_state_without_persistence(state, name=:default)
48
+ aasm_write_state_attribute(state, name)
49
+ end
50
+
51
+ private
52
+
53
+ # Save the record and return true if it succeeded/false otherwise.
54
+ def aasm_save
55
+ raise("Define #aasm_save_without_error in the AASM Persistence class.")
56
+ end
57
+
58
+ def aasm_raise_invalid_record
59
+ raise("Define #aasm_raise_invalid_record in the AASM Persistence class.")
60
+ end
61
+
62
+ # Update only the column without running validations.
63
+ def aasm_update_column(attribute_name, value)
64
+ raise("Define #aasm_update_column in the AASM Persistence class.")
65
+ end
66
+
67
+ def aasm_read_attribute(name)
68
+ raise("Define #aasm_read_attribute the AASM Persistence class.")
69
+ end
70
+
71
+ def aasm_write_attribute(name, value)
72
+ raise("Define #aasm_write_attribute in the AASM Persistence class.")
73
+ end
74
+
75
+ # Returns true or false if transaction completed successfully.
76
+ def aasm_transaction(requires_new, requires_lock)
77
+ raise("Define #aasm_transaction the AASM Persistence class.")
78
+ end
79
+
80
+ def aasm_supports_transactions?
81
+ true
82
+ end
83
+
84
+ def aasm_write_state_attribute(state, name=:default)
85
+ aasm_write_attribute(self.class.aasm(name).attribute_name, aasm_raw_attribute_value(state, name))
86
+ end
87
+
88
+ def aasm_raw_attribute_value(state, _name=:default)
89
+ state.to_s
90
+ end
91
+
92
+ def aasm_rollback(name, old_value)
93
+ aasm_write_attribute(self.class.aasm(name).attribute_name, old_value)
94
+ false
95
+ end
96
+
97
+ def aasm_whiny_persistence(state_machine_name)
98
+ AASM::StateMachineStore.fetch(self.class, true).machine(state_machine_name).config.whiny_persistence
99
+ end
100
+
101
+ def aasm_skipping_validations(state_machine_name)
102
+ AASM::StateMachineStore.fetch(self.class, true).machine(state_machine_name).config.skip_validation_on_save
103
+ end
104
+
105
+ def use_transactions?(state_machine_name)
106
+ AASM::StateMachineStore.fetch(self.class, true).machine(state_machine_name).config.use_transactions
107
+ end
108
+
109
+ def requires_new?(state_machine_name)
110
+ AASM::StateMachineStore.fetch(self.class, true).machine(state_machine_name).config.requires_new_transaction
111
+ end
112
+
113
+ def requires_lock?(state_machine_name)
114
+ AASM::StateMachineStore.fetch(self.class, true).machine(state_machine_name).config.requires_lock
115
+ end
116
+
117
+ # Returns true if event was fired successfully and transaction completed.
118
+ def aasm_fire_event(state_machine_name, name, options, *args, &block)
119
+ if aasm_supports_transactions? && options[:persist]
120
+ event = self.class.aasm(state_machine_name).state_machine.events[name]
121
+ event.fire_callbacks(:before_transaction, self, *args)
122
+ event.fire_global_callbacks(:before_all_transactions, self, *args)
123
+
124
+ begin
125
+ success = if options[:persist] && use_transactions?(state_machine_name)
126
+ aasm_transaction(requires_new?(state_machine_name), requires_lock?(state_machine_name)) do
127
+ super
128
+ end
129
+ else
130
+ super
131
+ end
132
+
133
+ if success
134
+ event.fire_callbacks(:after_commit, self, *args)
135
+ event.fire_global_callbacks(:after_all_commits, self, *args)
136
+ end
137
+
138
+ success
139
+ ensure
140
+ event.fire_callbacks(:after_transaction, self, *args)
141
+ event.fire_global_callbacks(:after_all_transactions, self, *args)
142
+ end
143
+ else
144
+ super
145
+ end
146
+ end
147
+
148
+ end # Transactional
149
+ end # Persistence
150
+ end # AASM