aasm 4.11.1 → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.github/ISSUE_TEMPLATE/bug_report.md +27 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.travis.yml +56 -23
- data/Appraisals +67 -0
- data/CHANGELOG.md +112 -0
- data/CONTRIBUTING.md +24 -0
- data/Dockerfile +44 -0
- data/Gemfile +3 -21
- data/Gemfile.lock_old +151 -0
- data/LICENSE +1 -1
- data/README.md +540 -139
- data/Rakefile +6 -1
- data/TESTING.md +25 -0
- data/aasm.gemspec +5 -0
- data/docker-compose.yml +40 -0
- data/gemfiles/norails.gemfile +10 -0
- data/gemfiles/rails_4.2.gemfile +13 -11
- data/gemfiles/rails_4.2_mongoid_5.gemfile +8 -11
- data/gemfiles/rails_4.2_nobrainer.gemfile +9 -0
- data/gemfiles/rails_5.0.gemfile +11 -18
- data/gemfiles/rails_5.0_nobrainer.gemfile +9 -0
- data/gemfiles/rails_5.1.gemfile +14 -0
- data/gemfiles/rails_5.2.gemfile +14 -0
- data/lib/aasm/aasm.rb +40 -29
- data/lib/aasm/base.rb +61 -11
- data/lib/aasm/configuration.rb +10 -0
- data/lib/aasm/core/event.rb +45 -37
- data/lib/aasm/core/invoker.rb +129 -0
- data/lib/aasm/core/invokers/base_invoker.rb +75 -0
- data/lib/aasm/core/invokers/class_invoker.rb +52 -0
- data/lib/aasm/core/invokers/literal_invoker.rb +47 -0
- data/lib/aasm/core/invokers/proc_invoker.rb +59 -0
- data/lib/aasm/core/state.rb +22 -13
- data/lib/aasm/core/transition.rb +17 -69
- data/lib/aasm/dsl_helper.rb +24 -22
- data/lib/aasm/errors.rb +4 -6
- data/lib/aasm/instance_base.rb +22 -4
- data/lib/aasm/localizer.rb +13 -3
- data/lib/aasm/minitest/allow_event.rb +13 -0
- data/lib/aasm/minitest/allow_transition_to.rb +13 -0
- data/lib/aasm/minitest/have_state.rb +13 -0
- data/lib/aasm/minitest/transition_from.rb +21 -0
- data/lib/aasm/minitest.rb +5 -0
- data/lib/aasm/minitest_spec.rb +15 -0
- data/lib/aasm/persistence/active_record_persistence.rb +49 -105
- data/lib/aasm/persistence/base.rb +20 -5
- data/lib/aasm/persistence/core_data_query_persistence.rb +2 -1
- data/lib/aasm/persistence/dynamoid_persistence.rb +1 -1
- data/lib/aasm/persistence/mongoid_persistence.rb +26 -32
- data/lib/aasm/persistence/no_brainer_persistence.rb +105 -0
- data/lib/aasm/persistence/orm.rb +154 -0
- data/lib/aasm/persistence/plain_persistence.rb +2 -1
- data/lib/aasm/persistence/redis_persistence.rb +16 -11
- data/lib/aasm/persistence/sequel_persistence.rb +36 -64
- data/lib/aasm/persistence.rb +3 -3
- data/lib/aasm/rspec/allow_event.rb +5 -1
- data/lib/aasm/rspec/allow_transition_to.rb +5 -1
- data/lib/aasm/rspec/transition_from.rb +5 -1
- data/lib/aasm/state_machine.rb +4 -2
- data/lib/aasm/state_machine_store.rb +5 -2
- data/lib/aasm/version.rb +1 -1
- data/lib/aasm.rb +5 -2
- data/lib/generators/aasm/orm_helpers.rb +6 -0
- data/lib/generators/active_record/aasm_generator.rb +3 -1
- data/lib/generators/active_record/templates/migration.rb +1 -1
- data/lib/generators/active_record/templates/migration_existing.rb +1 -1
- data/lib/generators/nobrainer/aasm_generator.rb +28 -0
- data/lib/motion-aasm.rb +3 -1
- data/spec/database.rb +20 -7
- data/spec/en.yml +0 -3
- data/spec/generators/active_record_generator_spec.rb +49 -40
- data/spec/generators/mongoid_generator_spec.rb +4 -6
- data/spec/generators/no_brainer_generator_spec.rb +29 -0
- data/spec/{en_deprecated_style.yml → localizer_test_model_deprecated_style.yml} +6 -3
- data/spec/localizer_test_model_new_style.yml +11 -0
- data/spec/models/active_record/active_record_callback.rb +93 -0
- data/spec/models/active_record/complex_active_record_example.rb +5 -1
- data/spec/models/active_record/instance_level_skip_validation_example.rb +19 -0
- data/spec/models/{invalid_persistor.rb → active_record/invalid_persistor.rb} +0 -2
- data/spec/models/active_record/localizer_test_model.rb +11 -3
- data/spec/models/active_record/namespaced.rb +16 -0
- data/spec/models/active_record/person.rb +23 -0
- data/spec/models/{silent_persistor.rb → active_record/silent_persistor.rb} +0 -2
- data/spec/models/active_record/simple_new_dsl.rb +15 -0
- data/spec/models/active_record/timestamp_example.rb +16 -0
- data/spec/models/{transactor.rb → active_record/transactor.rb} +25 -2
- data/spec/models/{validator.rb → active_record/validator.rb} +0 -2
- data/spec/models/active_record/work.rb +3 -0
- data/spec/models/{worker.rb → active_record/worker.rb} +0 -0
- data/spec/models/callbacks/basic.rb +5 -2
- data/spec/models/callbacks/with_state_arg.rb +5 -1
- data/spec/models/callbacks/with_state_arg_multiple.rb +4 -1
- data/spec/models/default_state.rb +1 -1
- data/spec/models/guard_arguments_check.rb +17 -0
- data/spec/models/guard_with_params.rb +1 -1
- data/spec/models/guardian_without_from_specified.rb +18 -0
- data/spec/models/mongoid/invalid_persistor_mongoid.rb +39 -0
- data/spec/models/mongoid/silent_persistor_mongoid.rb +39 -0
- data/spec/models/mongoid/timestamp_example_mongoid.rb +20 -0
- data/spec/models/mongoid/validator_mongoid.rb +100 -0
- data/spec/models/multiple_transitions_that_differ_only_by_guard.rb +31 -0
- data/spec/models/namespaced_multiple_example.rb +14 -0
- data/spec/models/nobrainer/complex_no_brainer_example.rb +36 -0
- data/spec/models/nobrainer/invalid_persistor_no_brainer.rb +39 -0
- data/spec/models/nobrainer/no_scope_no_brainer.rb +21 -0
- data/spec/models/nobrainer/nobrainer_relationships.rb +25 -0
- data/spec/models/nobrainer/silent_persistor_no_brainer.rb +39 -0
- data/spec/models/nobrainer/simple_new_dsl_nobrainer.rb +25 -0
- data/spec/models/{mongo_mapper/simple_mongo_mapper.rb → nobrainer/simple_no_brainer.rb} +8 -8
- data/spec/models/nobrainer/validator_no_brainer.rb +98 -0
- data/spec/models/parametrised_event.rb +7 -0
- data/spec/models/{mongo_mapper/complex_mongo_mapper_example.rb → redis/complex_redis_example.rb} +8 -5
- data/spec/models/redis/redis_multiple.rb +20 -0
- data/spec/models/redis/redis_simple.rb +20 -0
- data/spec/models/sequel/complex_sequel_example.rb +4 -3
- data/spec/models/sequel/invalid_persistor.rb +52 -0
- data/spec/models/sequel/sequel_multiple.rb +13 -13
- data/spec/models/sequel/sequel_simple.rb +13 -12
- data/spec/models/sequel/silent_persistor.rb +50 -0
- data/spec/models/sequel/transactor.rb +112 -0
- data/spec/models/sequel/validator.rb +93 -0
- data/spec/models/sequel/worker.rb +12 -0
- data/spec/models/simple_example.rb +8 -0
- data/spec/models/simple_example_with_guard_args.rb +17 -0
- data/spec/models/simple_multiple_example.rb +12 -0
- data/spec/models/sub_class.rb +34 -0
- data/spec/models/timestamps_example.rb +19 -0
- data/spec/models/timestamps_with_named_machine_example.rb +13 -0
- data/spec/spec_helper.rb +15 -33
- data/spec/spec_helpers/active_record.rb +8 -0
- data/spec/spec_helpers/dynamoid.rb +35 -0
- data/spec/spec_helpers/mongoid.rb +26 -0
- data/spec/spec_helpers/nobrainer.rb +15 -0
- data/spec/spec_helpers/redis.rb +18 -0
- data/spec/spec_helpers/remove_warnings.rb +1 -0
- data/spec/spec_helpers/sequel.rb +7 -0
- data/spec/unit/abstract_class_spec.rb +27 -0
- data/spec/unit/api_spec.rb +79 -72
- data/spec/unit/callback_multiple_spec.rb +7 -3
- data/spec/unit/callbacks_spec.rb +37 -2
- data/spec/unit/complex_example_spec.rb +12 -3
- data/spec/unit/complex_multiple_example_spec.rb +20 -4
- data/spec/unit/event_multiple_spec.rb +1 -1
- data/spec/unit/event_spec.rb +29 -4
- data/spec/unit/exception_spec.rb +1 -1
- data/spec/unit/guard_arguments_check_spec.rb +9 -0
- data/spec/unit/guard_spec.rb +17 -0
- data/spec/unit/guard_with_params_spec.rb +4 -0
- data/spec/unit/guard_without_from_specified_spec.rb +10 -0
- data/spec/unit/inspection_multiple_spec.rb +9 -5
- data/spec/unit/inspection_spec.rb +7 -3
- data/spec/unit/invoker_spec.rb +189 -0
- data/spec/unit/invokers/base_invoker_spec.rb +72 -0
- data/spec/unit/invokers/class_invoker_spec.rb +95 -0
- data/spec/unit/invokers/literal_invoker_spec.rb +86 -0
- data/spec/unit/invokers/proc_invoker_spec.rb +86 -0
- data/spec/unit/localizer_spec.rb +85 -52
- data/spec/unit/multiple_transitions_that_differ_only_by_guard_spec.rb +14 -0
- data/spec/unit/namespaced_multiple_example_spec.rb +22 -0
- data/spec/unit/override_warning_spec.rb +8 -0
- data/spec/unit/persistence/active_record_persistence_multiple_spec.rb +468 -447
- data/spec/unit/persistence/active_record_persistence_spec.rb +639 -486
- data/spec/unit/persistence/dynamoid_persistence_multiple_spec.rb +4 -9
- data/spec/unit/persistence/dynamoid_persistence_spec.rb +4 -9
- data/spec/unit/persistence/mongoid_persistence_multiple_spec.rb +83 -13
- data/spec/unit/persistence/mongoid_persistence_spec.rb +97 -13
- data/spec/unit/persistence/no_brainer_persistence_multiple_spec.rb +198 -0
- data/spec/unit/persistence/no_brainer_persistence_spec.rb +158 -0
- data/spec/unit/persistence/redis_persistence_multiple_spec.rb +88 -0
- data/spec/unit/persistence/redis_persistence_spec.rb +8 -32
- data/spec/unit/persistence/sequel_persistence_multiple_spec.rb +6 -11
- data/spec/unit/persistence/sequel_persistence_spec.rb +278 -10
- data/spec/unit/rspec_matcher_spec.rb +9 -0
- data/spec/unit/simple_example_spec.rb +15 -0
- data/spec/unit/simple_multiple_example_spec.rb +28 -0
- data/spec/unit/state_spec.rb +23 -7
- data/spec/unit/subclassing_multiple_spec.rb +37 -2
- data/spec/unit/subclassing_spec.rb +17 -2
- data/spec/unit/timestamps_spec.rb +32 -0
- data/spec/unit/transition_spec.rb +1 -1
- data/test/minitest_helper.rb +57 -0
- data/test/unit/minitest_matcher_test.rb +80 -0
- metadata +213 -37
- data/callbacks.txt +0 -51
- data/gemfiles/rails_3.2_stable.gemfile +0 -15
- data/gemfiles/rails_4.0.gemfile +0 -16
- data/gemfiles/rails_4.0_mongo_mapper.gemfile +0 -16
- data/gemfiles/rails_4.2_mongo_mapper.gemfile +0 -17
- data/lib/aasm/persistence/mongo_mapper_persistence.rb +0 -163
- data/spec/models/mongo_mapper/no_scope_mongo_mapper.rb +0 -21
- data/spec/models/mongo_mapper/simple_new_dsl_mongo_mapper.rb +0 -25
- data/spec/unit/persistence/mongo_mapper_persistence_multiple_spec.rb +0 -149
- data/spec/unit/persistence/mongo_mapper_persistence_spec.rb +0 -96
data/lib/aasm/localizer.rb
CHANGED
|
@@ -5,7 +5,7 @@ module AASM
|
|
|
5
5
|
list << :"#{i18n_scope(klass)}.events.#{i18n_klass(ancestor)}.#{event}"
|
|
6
6
|
list
|
|
7
7
|
end
|
|
8
|
-
translate_queue(checklist) || I18n.translate(checklist.shift, :default => event
|
|
8
|
+
translate_queue(checklist) || I18n.translate(checklist.shift, :default => default_display_name(event))
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def human_state_name(klass, state)
|
|
@@ -14,7 +14,7 @@ module AASM
|
|
|
14
14
|
list << item_for(klass, state, ancestor, :old_style => true)
|
|
15
15
|
list
|
|
16
16
|
end
|
|
17
|
-
translate_queue(checklist) || I18n.translate(checklist.shift, :default => state
|
|
17
|
+
translate_queue(checklist) || I18n.translate(checklist.shift, :default => default_display_name(state))
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
private
|
|
@@ -46,8 +46,18 @@ module AASM
|
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
def ancestors_list(klass)
|
|
49
|
+
has_active_record_base = defined?(::ActiveRecord::Base)
|
|
49
50
|
klass.ancestors.select do |ancestor|
|
|
50
|
-
|
|
51
|
+
not_active_record_base = has_active_record_base ? (ancestor != ::ActiveRecord::Base) : true
|
|
52
|
+
ancestor.respond_to?(:model_name) && not_active_record_base
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def default_display_name(object) # Can use better arguement name
|
|
57
|
+
if object.respond_to?(:default_display_name)
|
|
58
|
+
object.default_display_name
|
|
59
|
+
else
|
|
60
|
+
object.to_s.gsub(/_/, ' ').capitalize
|
|
51
61
|
end
|
|
52
62
|
end
|
|
53
63
|
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Minitest::Assertions
|
|
2
|
+
def assert_event_allowed(object, event, options = {})
|
|
3
|
+
state_machine_name = options.fetch(:on, :default)
|
|
4
|
+
assert object.aasm(state_machine_name).may_fire_event?(event),
|
|
5
|
+
"Expected that the event :#{event} would be allowed (on :#{state_machine_name})"
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def refute_event_allowed(object, event, options = {})
|
|
9
|
+
state_machine_name = options.fetch(:on, :default)
|
|
10
|
+
refute object.aasm(state_machine_name).may_fire_event?(event),
|
|
11
|
+
"Expected that the event :#{event} would not be allowed (on :#{state_machine_name})"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Minitest::Assertions
|
|
2
|
+
def assert_transition_to_allowed(object, to_state, options = {})
|
|
3
|
+
state_machine_name = options.fetch(:on, :default)
|
|
4
|
+
assert object.aasm(state_machine_name).states(permitted: true).include?(to_state),
|
|
5
|
+
"Expected that the state :#{to_state} would be reachable (on :#{state_machine_name})"
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def refute_transition_to_allowed(object, to_state, options = {})
|
|
9
|
+
state_machine_name = options.fetch(:on, :default)
|
|
10
|
+
refute object.aasm(state_machine_name).states(permitted: true).include?(to_state),
|
|
11
|
+
"Expected that the state :#{to_state} would be reachable (on :#{state_machine_name})"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Minitest::Assertions
|
|
2
|
+
def assert_have_state(object, state, options = {})
|
|
3
|
+
state_machine_name = options.fetch(:on, :default)
|
|
4
|
+
assert object.aasm(state_machine_name).current_state == state,
|
|
5
|
+
"Expected that :#{object.aasm(state_machine_name).current_state} would be :#{state} (on :#{state_machine_name})"
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def refute_have_state(object, state, options = {})
|
|
9
|
+
state_machine_name = options.fetch(:on, :default)
|
|
10
|
+
refute object.aasm(state_machine_name).current_state == state,
|
|
11
|
+
"Expected that :#{object.aasm(state_machine_name).current_state} would be :#{state} (on :#{state_machine_name})"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Minitest::Assertions
|
|
2
|
+
def assert_transitions_from(object, from_state, *args)
|
|
3
|
+
options = args.first
|
|
4
|
+
options[:on] ||= :default
|
|
5
|
+
assert _transitions_from?(object, from_state, args, options),
|
|
6
|
+
"Expected transition state to :#{options[:to]} from :#{from_state} on event :#{options[:on_event]}, (on :#{options[:on]})"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def refute_transitions_from(object, from_state, *args)
|
|
10
|
+
options = args.first
|
|
11
|
+
options[:on] ||= :default
|
|
12
|
+
refute _transitions_from?(object, from_state, args, options),
|
|
13
|
+
"Expected transition state to :#{options[:to]} from :#{from_state} on event :#{options[:on_event]}, (on :#{options[:on]})"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def _transitions_from?(object, from_state, args, options)
|
|
17
|
+
state_machine_name = options[:on]
|
|
18
|
+
object.aasm(state_machine_name).current_state = from_state.to_sym
|
|
19
|
+
object.send(options[:on_event], *args) && options[:to].to_sym == object.aasm(state_machine_name).current_state
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'aasm/minitest'
|
|
2
|
+
|
|
3
|
+
module Minitest::Expectations
|
|
4
|
+
AASM.infect_an_assertion :assert_transitions_from, :must_transition_from, :do_not_flip
|
|
5
|
+
AASM.infect_an_assertion :refute_transitions_from, :wont_transition_from, :do_not_flip
|
|
6
|
+
|
|
7
|
+
AASM.infect_an_assertion :assert_transition_to_allowed, :must_allow_transition_to, :do_not_flip
|
|
8
|
+
AASM.infect_an_assertion :refute_transition_to_allowed, :wont_allow_transition_to, :do_not_flip
|
|
9
|
+
|
|
10
|
+
AASM.infect_an_assertion :assert_have_state, :must_have_state, :do_not_flip
|
|
11
|
+
AASM.infect_an_assertion :refute_have_state, :wont_have_state, :do_not_flip
|
|
12
|
+
|
|
13
|
+
AASM.infect_an_assertion :assert_event_allowed, :must_allow_event, :do_not_flip
|
|
14
|
+
AASM.infect_an_assertion :refute_event_allowed, :wont_allow_event, :do_not_flip
|
|
15
|
+
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require 'aasm/persistence/orm'
|
|
1
2
|
module AASM
|
|
2
3
|
module Persistence
|
|
3
4
|
module ActiveRecordPersistence
|
|
@@ -28,6 +29,7 @@ module AASM
|
|
|
28
29
|
#
|
|
29
30
|
def self.included(base)
|
|
30
31
|
base.send(:include, AASM::Persistence::Base)
|
|
32
|
+
base.send(:include, AASM::Persistence::ORM)
|
|
31
33
|
base.send(:include, AASM::Persistence::ActiveRecordPersistence::InstanceMethods)
|
|
32
34
|
base.extend AASM::Persistence::ActiveRecordPersistence::ClassMethods
|
|
33
35
|
|
|
@@ -39,14 +41,15 @@ module AASM
|
|
|
39
41
|
|
|
40
42
|
module ClassMethods
|
|
41
43
|
def aasm_create_scope(state_machine_name, scope_name)
|
|
42
|
-
conditions = {
|
|
43
|
-
table_name => { aasm(state_machine_name).attribute_name => scope_name.to_s }
|
|
44
|
-
}
|
|
45
44
|
if ActiveRecord::VERSION::MAJOR >= 3
|
|
45
|
+
conditions = { aasm(state_machine_name).attribute_name => scope_name.to_s }
|
|
46
46
|
class_eval do
|
|
47
|
-
scope scope_name, lambda { where(conditions) }
|
|
47
|
+
scope scope_name, lambda { where(table_name => conditions) }
|
|
48
48
|
end
|
|
49
49
|
else
|
|
50
|
+
conditions = {
|
|
51
|
+
table_name => { aasm(state_machine_name).attribute_name => scope_name.to_s }
|
|
52
|
+
}
|
|
50
53
|
class_eval do
|
|
51
54
|
named_scope scope_name, :conditions => conditions
|
|
52
55
|
end
|
|
@@ -56,67 +59,59 @@ module AASM
|
|
|
56
59
|
|
|
57
60
|
module InstanceMethods
|
|
58
61
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
# Foo.find(1).aasm.current_state # => :closed
|
|
66
|
-
#
|
|
67
|
-
# NOTE: intended to be called from an event
|
|
68
|
-
def aasm_write_state(state, name=:default)
|
|
69
|
-
old_value = read_attribute(self.class.aasm(name).attribute_name)
|
|
70
|
-
aasm_write_attribute state, name
|
|
71
|
-
|
|
72
|
-
success = if aasm_skipping_validations(name)
|
|
73
|
-
value = aasm_raw_attribute_value(state, name)
|
|
74
|
-
aasm_update_column(name, value)
|
|
75
|
-
else
|
|
76
|
-
self.save
|
|
77
|
-
end
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def aasm_execute_after_commit
|
|
65
|
+
begin
|
|
66
|
+
require 'after_commit_everywhere'
|
|
67
|
+
raise LoadError unless Gem::Version.new(::AfterCommitEverywhere::VERSION) >= Gem::Version.new('0.1.5')
|
|
78
68
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
69
|
+
self.extend ::AfterCommitEverywhere
|
|
70
|
+
after_commit do
|
|
71
|
+
yield
|
|
72
|
+
end
|
|
73
|
+
rescue LoadError
|
|
74
|
+
warn <<-MSG
|
|
75
|
+
[DEPRECATION] :after_commit AASM callback is not safe in terms of race conditions and redundant calls.
|
|
76
|
+
Please add `gem 'after_commit_everywhere', '~> 1.0'` to your Gemfile in order to fix that.
|
|
77
|
+
MSG
|
|
78
|
+
yield
|
|
82
79
|
end
|
|
80
|
+
end
|
|
83
81
|
|
|
84
|
-
|
|
82
|
+
def aasm_raise_invalid_record
|
|
83
|
+
raise ActiveRecord::RecordInvalid.new(self)
|
|
85
84
|
end
|
|
86
85
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
# foo = Foo.find(1)
|
|
90
|
-
# foo.aasm.current_state # => :opened
|
|
91
|
-
# foo.close
|
|
92
|
-
# foo.aasm.current_state # => :closed
|
|
93
|
-
# Foo.find(1).aasm.current_state # => :opened
|
|
94
|
-
# foo.save
|
|
95
|
-
# foo.aasm.current_state # => :closed
|
|
96
|
-
# Foo.find(1).aasm.current_state # => :closed
|
|
97
|
-
#
|
|
98
|
-
# NOTE: intended to be called from an event
|
|
99
|
-
def aasm_write_state_without_persistence(state, name=:default)
|
|
100
|
-
aasm_write_attribute(state, name)
|
|
86
|
+
def aasm_save
|
|
87
|
+
self.save
|
|
101
88
|
end
|
|
102
89
|
|
|
103
|
-
|
|
90
|
+
def aasm_update_column(attribute_name, value)
|
|
91
|
+
self.class.unscoped.where(self.class.primary_key => self.id).update_all(attribute_name => value) == 1
|
|
92
|
+
end
|
|
104
93
|
|
|
105
|
-
def
|
|
106
|
-
|
|
94
|
+
def aasm_read_attribute(name)
|
|
95
|
+
read_attribute(name)
|
|
107
96
|
end
|
|
108
97
|
|
|
109
|
-
def
|
|
110
|
-
write_attribute(
|
|
111
|
-
|
|
98
|
+
def aasm_write_attribute(name, value)
|
|
99
|
+
write_attribute(name, value)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def aasm_transaction(requires_new, requires_lock)
|
|
103
|
+
self.class.transaction(:requires_new => requires_new) do
|
|
104
|
+
lock!(requires_lock) if requires_lock
|
|
105
|
+
yield
|
|
106
|
+
end
|
|
112
107
|
end
|
|
113
108
|
|
|
114
109
|
def aasm_enum(name=:default)
|
|
115
110
|
case AASM::StateMachineStore.fetch(self.class, true).machine(name).config.enum
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
111
|
+
when false then nil
|
|
112
|
+
when true then aasm_guess_enum_method(name)
|
|
113
|
+
when nil then aasm_guess_enum_method(name) if aasm_column_looks_like_enum(name)
|
|
114
|
+
else AASM::StateMachineStore.fetch(self.class, true).machine(name).config.enum
|
|
120
115
|
end
|
|
121
116
|
end
|
|
122
117
|
|
|
@@ -131,23 +126,11 @@ module AASM
|
|
|
131
126
|
self.class.aasm(name).attribute_name.to_s.pluralize.to_sym
|
|
132
127
|
end
|
|
133
128
|
|
|
134
|
-
def aasm_skipping_validations(state_machine_name)
|
|
135
|
-
AASM::StateMachineStore.fetch(self.class, true).machine(state_machine_name).config.skip_validation_on_save
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
def aasm_whiny_persistence(state_machine_name)
|
|
139
|
-
AASM::StateMachineStore.fetch(self.class, true).machine(state_machine_name).config.whiny_persistence
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
def aasm_write_attribute(state, name=:default)
|
|
143
|
-
write_attribute(self.class.aasm(name).attribute_name, aasm_raw_attribute_value(state, name))
|
|
144
|
-
end
|
|
145
|
-
|
|
146
129
|
def aasm_raw_attribute_value(state, name=:default)
|
|
147
130
|
if aasm_enum(name)
|
|
148
131
|
self.class.send(aasm_enum(name))[state]
|
|
149
132
|
else
|
|
150
|
-
|
|
133
|
+
super
|
|
151
134
|
end
|
|
152
135
|
end
|
|
153
136
|
|
|
@@ -176,47 +159,8 @@ module AASM
|
|
|
176
159
|
|
|
177
160
|
def aasm_column_is_blank?(state_machine_name)
|
|
178
161
|
attribute_name = self.class.aasm(state_machine_name).attribute_name
|
|
179
|
-
attribute_names.include?(attribute_name.to_s) &&
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
def aasm_fire_event(state_machine_name, name, options, *args, &block)
|
|
183
|
-
event = self.class.aasm(state_machine_name).state_machine.events[name]
|
|
184
|
-
|
|
185
|
-
if options[:persist]
|
|
186
|
-
event.fire_callbacks(:before_transaction, self, *args)
|
|
187
|
-
event.fire_global_callbacks(:before_all_transactions, self, *args)
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
begin
|
|
191
|
-
success = if options[:persist]
|
|
192
|
-
self.class.transaction(:requires_new => requires_new?(state_machine_name)) do
|
|
193
|
-
lock!(requires_lock?(state_machine_name)) if requires_lock?(state_machine_name)
|
|
194
|
-
super
|
|
195
|
-
end
|
|
196
|
-
else
|
|
197
|
-
super
|
|
198
|
-
end
|
|
199
|
-
|
|
200
|
-
if options[:persist] && success
|
|
201
|
-
event.fire_callbacks(:after_commit, self, *args)
|
|
202
|
-
event.fire_global_callbacks(:after_all_commits, self, *args)
|
|
203
|
-
end
|
|
204
|
-
ensure
|
|
205
|
-
if options[:persist]
|
|
206
|
-
event.fire_callbacks(:after_transaction, self, *args)
|
|
207
|
-
event.fire_global_callbacks(:after_all_transactions, self, *args)
|
|
208
|
-
end
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
success
|
|
212
|
-
end
|
|
213
|
-
|
|
214
|
-
def requires_new?(state_machine_name)
|
|
215
|
-
AASM::StateMachineStore.fetch(self.class, true).machine(state_machine_name).config.requires_new_transaction
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
def requires_lock?(state_machine_name)
|
|
219
|
-
AASM::StateMachineStore.fetch(self.class, true).machine(state_machine_name).config.requires_lock
|
|
162
|
+
attribute_names.include?(attribute_name.to_s) &&
|
|
163
|
+
(send(attribute_name).respond_to?(:empty?) ? !!send(attribute_name).empty? : !send(attribute_name))
|
|
220
164
|
end
|
|
221
165
|
|
|
222
166
|
def aasm_validate_states
|
|
@@ -34,13 +34,17 @@ module AASM
|
|
|
34
34
|
# This allows for nil aasm states - be sure to add validation to your model
|
|
35
35
|
def aasm_read_state(name=:default)
|
|
36
36
|
state = send(self.class.aasm(name).attribute_name)
|
|
37
|
-
if
|
|
38
|
-
|
|
37
|
+
if !state || state.empty?
|
|
38
|
+
aasm_new_record? ? aasm(name).determine_state_name(self.class.aasm(name).initial_state) : nil
|
|
39
39
|
else
|
|
40
|
-
state.
|
|
40
|
+
state.to_sym
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
+
def aasm_new_record?
|
|
45
|
+
new_record?
|
|
46
|
+
end
|
|
47
|
+
|
|
44
48
|
module ClassMethods
|
|
45
49
|
def aasm_column(attribute_name=nil)
|
|
46
50
|
warn "[DEPRECATION] aasm_column is deprecated. Use aasm.attribute_name instead"
|
|
@@ -55,7 +59,9 @@ module AASM
|
|
|
55
59
|
# make sure to create a (named) scope for each state
|
|
56
60
|
def state_with_scope(*args)
|
|
57
61
|
names = state_without_scope(*args)
|
|
58
|
-
names.each
|
|
62
|
+
names.each do |name|
|
|
63
|
+
create_scopes(name)
|
|
64
|
+
end
|
|
59
65
|
end
|
|
60
66
|
alias_method :state_without_scope, :state
|
|
61
67
|
alias_method :state, :state_with_scope
|
|
@@ -67,7 +73,16 @@ module AASM
|
|
|
67
73
|
end
|
|
68
74
|
|
|
69
75
|
def create_scope(name)
|
|
70
|
-
@klass.aasm_create_scope(@name, name)
|
|
76
|
+
@klass.aasm_create_scope(@name, name) if create_scope?(name)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def create_scopes(name)
|
|
80
|
+
if namespace?
|
|
81
|
+
# Create default scopes even when namespace? for backward compatibility
|
|
82
|
+
namepaced_name = "#{namespace}_#{name}"
|
|
83
|
+
create_scope(namepaced_name)
|
|
84
|
+
end
|
|
85
|
+
create_scope(name)
|
|
71
86
|
end
|
|
72
87
|
end # Base
|
|
73
88
|
|
|
@@ -77,7 +77,8 @@ module AASM
|
|
|
77
77
|
#
|
|
78
78
|
def aasm_ensure_initial_state
|
|
79
79
|
AASM::StateMachineStore.fetch(self.class, true).machine_names.each do |state_machine_name|
|
|
80
|
-
send(
|
|
80
|
+
next if !send(self.class.aasm(state_machine_name).attribute_name) || send(self.class.aasm(state_machine_name).attribute_name).empty?
|
|
81
|
+
send("#{self.class.aasm(state_machine_name).attribute_name}=", aasm(state_machine_name).enter_initial_state.to_s)
|
|
81
82
|
end
|
|
82
83
|
end
|
|
83
84
|
end # InstanceMethods
|
|
@@ -83,7 +83,7 @@ module AASM
|
|
|
83
83
|
#
|
|
84
84
|
def aasm_ensure_initial_state
|
|
85
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).
|
|
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
87
|
end
|
|
88
88
|
end
|
|
89
89
|
end # InstanceMethods
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require 'aasm/persistence/orm'
|
|
1
2
|
module AASM
|
|
2
3
|
module Persistence
|
|
3
4
|
module MongoidPersistence
|
|
@@ -30,6 +31,7 @@ module AASM
|
|
|
30
31
|
#
|
|
31
32
|
def self.included(base)
|
|
32
33
|
base.send(:include, AASM::Persistence::Base)
|
|
34
|
+
base.send(:include, AASM::Persistence::ORM)
|
|
33
35
|
base.send(:include, AASM::Persistence::MongoidPersistence::InstanceMethods)
|
|
34
36
|
base.extend AASM::Persistence::MongoidPersistence::ClassMethods
|
|
35
37
|
|
|
@@ -50,45 +52,37 @@ module AASM
|
|
|
50
52
|
|
|
51
53
|
module InstanceMethods
|
|
52
54
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
# NOTE: intended to be called from an event
|
|
63
|
-
def aasm_write_state(state, name=:default)
|
|
64
|
-
old_value = read_attribute(self.class.aasm(name).attribute_name)
|
|
65
|
-
write_attribute(self.class.aasm(name).attribute_name, state.to_s)
|
|
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
|
|
66
64
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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)
|
|
70
74
|
end
|
|
71
75
|
|
|
72
76
|
true
|
|
73
77
|
end
|
|
74
78
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
# foo = Foo.find(1)
|
|
78
|
-
# foo.aasm.current_state # => :opened
|
|
79
|
-
# foo.close
|
|
80
|
-
# foo.aasm.current_state # => :closed
|
|
81
|
-
# Foo.find(1).aasm.current_state # => :opened
|
|
82
|
-
# foo.save
|
|
83
|
-
# foo.aasm.current_state # => :closed
|
|
84
|
-
# Foo.find(1).aasm.current_state # => :closed
|
|
85
|
-
#
|
|
86
|
-
# NOTE: intended to be called from an event
|
|
87
|
-
def aasm_write_state_without_persistence(state, name=:default)
|
|
88
|
-
write_attribute(self.class.aasm(name).attribute_name, state.to_s)
|
|
79
|
+
def aasm_read_attribute(name)
|
|
80
|
+
read_attribute(name)
|
|
89
81
|
end
|
|
90
82
|
|
|
91
|
-
|
|
83
|
+
def aasm_write_attribute(name, value)
|
|
84
|
+
write_attribute(name, value)
|
|
85
|
+
end
|
|
92
86
|
|
|
93
87
|
# Ensures that if the aasm_state column is nil and the record is new
|
|
94
88
|
# that the initial state gets populated before validation on create
|
|
@@ -112,7 +106,7 @@ module AASM
|
|
|
112
106
|
# mongoid has_many relationship does not load child object attributes when
|
|
113
107
|
# only ids are loaded, for example parent.child_ids will not load child object attributes.
|
|
114
108
|
# This feature is introduced in mongoid > 4.
|
|
115
|
-
if attribute_names.include?(attribute_name) && attributes[attribute_name].
|
|
109
|
+
if attribute_names.include?(attribute_name) && !attributes[attribute_name] || attributes[attribute_name].empty?
|
|
116
110
|
# attribute_missing? is defined in mongoid > 4
|
|
117
111
|
return if Mongoid::VERSION.to_f >= 4 && attribute_missing?(attribute_name)
|
|
118
112
|
send("#{self.class.aasm(state_machine_name).attribute_name}=", aasm(state_machine_name).enter_initial_state.to_s)
|
|
@@ -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
|