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/Rakefile
CHANGED
data/TESTING.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
## Install dependency matrix
|
|
2
|
+
|
|
3
|
+
appraisal install
|
|
4
|
+
|
|
5
|
+
This will re-generate Gemfiles in `gemfile` folder
|
|
6
|
+
|
|
7
|
+
Use rvm gemsets or similar to avoid global gem pollution
|
|
8
|
+
|
|
9
|
+
## Run specs
|
|
10
|
+
|
|
11
|
+
For all supported Rails/ORM combinations:
|
|
12
|
+
|
|
13
|
+
appraisal rspec
|
|
14
|
+
|
|
15
|
+
Or for specific one:
|
|
16
|
+
|
|
17
|
+
appraisal rails_4.2 rspec
|
|
18
|
+
|
|
19
|
+
Or for one particular test file
|
|
20
|
+
|
|
21
|
+
appraisal rails_4.2_mongoid_5 rspec spec/unit/persistence/mongoid_persistence_multiple_spec.rb
|
|
22
|
+
|
|
23
|
+
Or down to one test case
|
|
24
|
+
|
|
25
|
+
appraisal rails_4.2_mongoid_5 rspec spec/unit/persistence/mongoid_persistence_multiple_spec.rb:92
|
data/aasm.gemspec
CHANGED
|
@@ -16,10 +16,15 @@ Gem::Specification.new do |s|
|
|
|
16
16
|
s.platform = Gem::Platform::RUBY
|
|
17
17
|
s.required_ruby_version = '>= 1.9.3'
|
|
18
18
|
|
|
19
|
+
s.add_dependency 'concurrent-ruby', '~> 1.0'
|
|
20
|
+
|
|
19
21
|
s.add_development_dependency 'rake'
|
|
20
22
|
s.add_development_dependency 'sdoc'
|
|
21
23
|
s.add_development_dependency 'rspec', ">= 3"
|
|
22
24
|
s.add_development_dependency 'generator_spec'
|
|
25
|
+
s.add_development_dependency 'appraisal'
|
|
26
|
+
s.add_development_dependency "simplecov"
|
|
27
|
+
s.add_development_dependency "codecov", ">= 0.1.21"
|
|
23
28
|
|
|
24
29
|
# debugging
|
|
25
30
|
# s.add_development_dependency 'debugger'
|
data/docker-compose.yml
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
version: "2"
|
|
2
|
+
|
|
3
|
+
services:
|
|
4
|
+
aasm:
|
|
5
|
+
image: aasm/aasm
|
|
6
|
+
build: .
|
|
7
|
+
command: bash -c 'bundle exec appraisal install && bundle exec appraisal rspec'
|
|
8
|
+
environment:
|
|
9
|
+
- DYNAMODB_HOST=dynamodb
|
|
10
|
+
- DYNAMODB_PORT=8000
|
|
11
|
+
- MONGODB_HOST=mongo
|
|
12
|
+
- MONGODB_PORT=27017
|
|
13
|
+
- RAILS_ENV=development
|
|
14
|
+
- REDIS_HOST=redis
|
|
15
|
+
- REDIS_PORT=6379
|
|
16
|
+
- RETHINKDB_DB=rethinkdb_test
|
|
17
|
+
- RETHINKDB_HOST=rethinkdb
|
|
18
|
+
- RETHINKDB_PORT=28015
|
|
19
|
+
depends_on:
|
|
20
|
+
- dynamodb
|
|
21
|
+
- mongo
|
|
22
|
+
- redis
|
|
23
|
+
- rethinkdb
|
|
24
|
+
volumes:
|
|
25
|
+
- .:/application
|
|
26
|
+
volumes_from:
|
|
27
|
+
- bundle
|
|
28
|
+
bundle:
|
|
29
|
+
image: aasm/aasm
|
|
30
|
+
command: echo Bundler data container
|
|
31
|
+
volumes:
|
|
32
|
+
- /bundle
|
|
33
|
+
dynamodb:
|
|
34
|
+
image: cnadiminti/dynamodb-local:2017-02-16
|
|
35
|
+
mongo:
|
|
36
|
+
image: mongo:3.6.1
|
|
37
|
+
redis:
|
|
38
|
+
image: redis:4.0.6-alpine
|
|
39
|
+
rethinkdb:
|
|
40
|
+
image: rethinkdb:2.3.6
|
data/gemfiles/rails_4.2.gemfile
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
|
+
# This file was generated by Appraisal
|
|
2
|
+
|
|
1
3
|
source "https://rubygems.org"
|
|
2
4
|
|
|
3
|
-
gem "sqlite3",
|
|
4
|
-
gem 'rubysl', :platforms => :rbx
|
|
5
|
-
gem 'rubinius-developer_tools', :platforms => :rbx
|
|
6
|
-
gem "jruby-openssl", :platforms => :jruby
|
|
7
|
-
gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
|
|
8
|
-
gem "mime-types", "~> 2" if Gem::Version.create(RUBY_VERSION.dup) <= Gem::Version.create('1.9.3')
|
|
5
|
+
gem "sqlite3", "~> 1.3.5", platforms: :ruby
|
|
9
6
|
gem "rails", "4.2.5"
|
|
10
|
-
gem
|
|
11
|
-
gem
|
|
12
|
-
gem
|
|
13
|
-
gem
|
|
7
|
+
gem "nokogiri", "1.6.8.1", platforms: [:ruby_19]
|
|
8
|
+
gem "mime-types", "~> 2", platforms: [:ruby_19, :jruby]
|
|
9
|
+
gem "mongoid", "~> 4.0"
|
|
10
|
+
gem "sequel"
|
|
11
|
+
gem "dynamoid", "~> 1", platforms: :ruby
|
|
12
|
+
gem "aws-sdk", "~> 2", platforms: :ruby
|
|
13
|
+
gem "redis-objects"
|
|
14
|
+
gem "activerecord-jdbcsqlite3-adapter", "1.3.24", platforms: :jruby
|
|
15
|
+
gem "after_commit_everywhere", "~> 1.0"
|
|
14
16
|
|
|
15
|
-
gemspec :
|
|
17
|
+
gemspec path: "../"
|
|
@@ -1,15 +1,12 @@
|
|
|
1
|
+
# This file was generated by Appraisal
|
|
2
|
+
|
|
1
3
|
source "https://rubygems.org"
|
|
2
4
|
|
|
3
|
-
gem "sqlite3",
|
|
4
|
-
gem 'rubysl', :platforms => :rbx
|
|
5
|
-
gem 'rubinius-developer_tools', :platforms => :rbx
|
|
6
|
-
gem "jruby-openssl", :platforms => :jruby
|
|
7
|
-
gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
|
|
8
|
-
gem "mime-types", "~> 2" if Gem::Version.create(RUBY_VERSION.dup) <= Gem::Version.create('1.9.3')
|
|
5
|
+
gem "sqlite3", "~> 1.3.5", platforms: :ruby
|
|
9
6
|
gem "rails", "4.2.5"
|
|
10
|
-
gem
|
|
11
|
-
gem
|
|
12
|
-
gem
|
|
13
|
-
gem
|
|
7
|
+
gem "mime-types", "~> 2", platforms: [:ruby_19, :jruby]
|
|
8
|
+
gem "mongoid", "~> 5.0"
|
|
9
|
+
gem "activerecord-jdbcsqlite3-adapter", "1.3.24", platforms: :jruby
|
|
10
|
+
gem "after_commit_everywhere", "~> 1.0"
|
|
14
11
|
|
|
15
|
-
gemspec :
|
|
12
|
+
gemspec path: "../"
|
data/gemfiles/rails_5.0.gemfile
CHANGED
|
@@ -1,21 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
gem "sqlite3", :platforms => :ruby
|
|
4
|
-
gem 'rubysl', :platforms => :rbx
|
|
5
|
-
gem 'rubinius-developer_tools', :platforms => :rbx
|
|
6
|
-
gem "jruby-openssl", :platforms => :jruby
|
|
7
|
-
gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
|
|
8
|
-
|
|
9
|
-
gem "rails", "5.0.0.beta4"
|
|
1
|
+
# This file was generated by Appraisal
|
|
10
2
|
|
|
11
|
-
|
|
12
|
-
# gem 'mongoid', '~>4.0' if Gem::Version.create(RUBY_VERSION.dup) >= Gem::Version.create('1.9.3')
|
|
13
|
-
|
|
14
|
-
gem 'sequel'
|
|
15
|
-
|
|
16
|
-
# dynamoid is not yet Rails 5 compatible
|
|
17
|
-
# gem 'dynamoid', '~> 1', :platforms => :ruby
|
|
3
|
+
source "https://rubygems.org"
|
|
18
4
|
|
|
19
|
-
gem
|
|
5
|
+
gem "sqlite3", "~> 1.3.5", platforms: :ruby
|
|
6
|
+
gem "rails", "5.0.0"
|
|
7
|
+
gem "mongoid", "~> 6.0"
|
|
8
|
+
gem "sequel"
|
|
9
|
+
gem "dynamoid", "~> 1.3", platforms: :ruby
|
|
10
|
+
gem "aws-sdk", "~> 2", platforms: :ruby
|
|
11
|
+
gem "redis-objects"
|
|
12
|
+
gem "after_commit_everywhere", "~> 1.0"
|
|
20
13
|
|
|
21
|
-
gemspec :
|
|
14
|
+
gemspec path: "../"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# This file was generated by Appraisal
|
|
2
|
+
|
|
3
|
+
source "https://rubygems.org"
|
|
4
|
+
|
|
5
|
+
gem "sqlite3", "~> 1.3.5", platforms: :ruby
|
|
6
|
+
gem "rails", "5.1"
|
|
7
|
+
gem "mongoid", "~>6.0"
|
|
8
|
+
gem "sequel"
|
|
9
|
+
gem "dynamoid", "~> 1.3", platforms: :ruby
|
|
10
|
+
gem "aws-sdk", "~>2", platforms: :ruby
|
|
11
|
+
gem "redis-objects"
|
|
12
|
+
gem "after_commit_everywhere", "~> 1.0"
|
|
13
|
+
|
|
14
|
+
gemspec path: "../"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# This file was generated by Appraisal
|
|
2
|
+
|
|
3
|
+
source "https://rubygems.org"
|
|
4
|
+
|
|
5
|
+
gem "sqlite3", "~> 1.3.5", platforms: :ruby
|
|
6
|
+
gem "rails", "5.2"
|
|
7
|
+
gem "mongoid", "~>6.0"
|
|
8
|
+
gem "sequel"
|
|
9
|
+
gem "dynamoid", "~>2.2", platforms: :ruby
|
|
10
|
+
gem "aws-sdk", "~>2", platforms: :ruby
|
|
11
|
+
gem "redis-objects"
|
|
12
|
+
gem "after_commit_everywhere", "~> 1.0"
|
|
13
|
+
|
|
14
|
+
gemspec path: "../"
|
data/lib/aasm/aasm.rb
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
module AASM
|
|
2
|
+
# this is used internally as an argument default value to represent no value
|
|
3
|
+
NO_VALUE = :_aasm_no_value
|
|
2
4
|
|
|
3
5
|
# provide a state machine for the including class
|
|
4
6
|
# make sure to load class methods as well
|
|
@@ -42,7 +44,7 @@ module AASM
|
|
|
42
44
|
|
|
43
45
|
raise ArgumentError, "The class #{aasm_klass} must inherit from AASM::Base!" unless aasm_klass.ancestors.include?(AASM::Base)
|
|
44
46
|
|
|
45
|
-
@aasm ||=
|
|
47
|
+
@aasm ||= Concurrent::Map.new
|
|
46
48
|
if @aasm[state_machine_name]
|
|
47
49
|
# make sure to use provided options
|
|
48
50
|
options.each do |key, value|
|
|
@@ -67,12 +69,12 @@ module AASM
|
|
|
67
69
|
unless AASM::StateMachineStore.fetch(self.class, true).machine(name)
|
|
68
70
|
raise AASM::UnknownStateMachineError.new("There is no state machine with the name '#{name}' defined in #{self.class.name}!")
|
|
69
71
|
end
|
|
70
|
-
@aasm ||=
|
|
72
|
+
@aasm ||= Concurrent::Map.new
|
|
71
73
|
@aasm[name.to_sym] ||= AASM::InstanceBase.new(self, name.to_sym)
|
|
72
74
|
end
|
|
73
75
|
|
|
74
76
|
def initialize_dup(other)
|
|
75
|
-
@aasm =
|
|
77
|
+
@aasm = Concurrent::Map.new
|
|
76
78
|
super
|
|
77
79
|
end
|
|
78
80
|
|
|
@@ -97,25 +99,10 @@ private
|
|
|
97
99
|
begin
|
|
98
100
|
old_state = aasm(state_machine_name).state_object_for_name(aasm(state_machine_name).current_state)
|
|
99
101
|
|
|
100
|
-
event.
|
|
101
|
-
:before_all_events,
|
|
102
|
-
self,
|
|
103
|
-
*process_args(event, aasm(state_machine_name).current_state, *args)
|
|
104
|
-
)
|
|
105
|
-
|
|
106
|
-
# new event before callback
|
|
107
|
-
event.fire_callbacks(
|
|
108
|
-
:before,
|
|
109
|
-
self,
|
|
110
|
-
*process_args(event, aasm(state_machine_name).current_state, *args)
|
|
111
|
-
)
|
|
102
|
+
fire_default_callbacks(event, *process_args(event, aasm(state_machine_name).current_state, *args))
|
|
112
103
|
|
|
113
104
|
if may_fire_to = event.may_fire?(self, *args)
|
|
114
|
-
old_state
|
|
115
|
-
*process_args(event, aasm(state_machine_name).current_state, *args))
|
|
116
|
-
old_state.fire_callbacks(:exit, self,
|
|
117
|
-
*process_args(event, aasm(state_machine_name).current_state, *args))
|
|
118
|
-
|
|
105
|
+
fire_exit_callbacks(old_state, *process_args(event, aasm(state_machine_name).current_state, *args))
|
|
119
106
|
if new_state_name = event.fire(self, {:may_fire => may_fire_to}, *args)
|
|
120
107
|
aasm_fired(state_machine_name, event, old_state, new_state_name, options, *args, &block)
|
|
121
108
|
else
|
|
@@ -128,41 +115,65 @@ private
|
|
|
128
115
|
event.fire_callbacks(:error, self, e, *process_args(event, aasm(state_machine_name).current_state, *args)) ||
|
|
129
116
|
event.fire_global_callbacks(:error_on_all_events, self, e, *process_args(event, aasm(state_machine_name).current_state, *args)) ||
|
|
130
117
|
raise(e)
|
|
118
|
+
false
|
|
131
119
|
ensure
|
|
132
120
|
event.fire_callbacks(:ensure, self, *process_args(event, aasm(state_machine_name).current_state, *args))
|
|
133
121
|
event.fire_global_callbacks(:ensure_on_all_events, self, *process_args(event, aasm(state_machine_name).current_state, *args))
|
|
134
122
|
end
|
|
135
123
|
end
|
|
136
124
|
|
|
125
|
+
def fire_default_callbacks(event, *processed_args)
|
|
126
|
+
event.fire_global_callbacks(
|
|
127
|
+
:before_all_events,
|
|
128
|
+
self,
|
|
129
|
+
*processed_args
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# new event before callback
|
|
133
|
+
event.fire_callbacks(
|
|
134
|
+
:before,
|
|
135
|
+
self,
|
|
136
|
+
*processed_args
|
|
137
|
+
)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def fire_exit_callbacks(old_state, *processed_args)
|
|
141
|
+
old_state.fire_callbacks(:before_exit, self, *processed_args)
|
|
142
|
+
old_state.fire_callbacks(:exit, self, *processed_args)
|
|
143
|
+
end
|
|
144
|
+
|
|
137
145
|
def aasm_fired(state_machine_name, event, old_state, new_state_name, options, *args)
|
|
138
146
|
persist = options[:persist]
|
|
139
147
|
|
|
140
148
|
new_state = aasm(state_machine_name).state_object_for_name(new_state_name)
|
|
149
|
+
callback_args = process_args(event, aasm(state_machine_name).current_state, *args)
|
|
141
150
|
|
|
142
|
-
new_state.fire_callbacks(:before_enter, self,
|
|
143
|
-
*process_args(event, aasm(state_machine_name).current_state, *args))
|
|
151
|
+
new_state.fire_callbacks(:before_enter, self, *callback_args)
|
|
144
152
|
|
|
145
|
-
new_state.fire_callbacks(:enter, self,
|
|
146
|
-
*process_args(event, aasm(state_machine_name).current_state, *args)) # TODO: remove for AASM 4?
|
|
153
|
+
new_state.fire_callbacks(:enter, self, *callback_args) # TODO: remove for AASM 4?
|
|
147
154
|
|
|
148
155
|
persist_successful = true
|
|
149
156
|
if persist
|
|
150
157
|
persist_successful = aasm(state_machine_name).set_current_state_with_persistence(new_state_name)
|
|
151
158
|
if persist_successful
|
|
152
159
|
yield if block_given?
|
|
160
|
+
event.fire_callbacks(:before_success, self, *callback_args)
|
|
153
161
|
event.fire_transition_callbacks(self, *process_args(event, old_state.name, *args))
|
|
154
|
-
event.fire_callbacks(:success, self)
|
|
162
|
+
event.fire_callbacks(:success, self, *callback_args)
|
|
155
163
|
end
|
|
156
164
|
else
|
|
157
165
|
aasm(state_machine_name).current_state = new_state_name
|
|
158
166
|
yield if block_given?
|
|
159
167
|
end
|
|
160
168
|
|
|
169
|
+
binding_event = event.options[:binding_event]
|
|
170
|
+
if binding_event
|
|
171
|
+
__send__("#{binding_event}#{'!' if persist}")
|
|
172
|
+
end
|
|
173
|
+
|
|
161
174
|
if persist_successful
|
|
162
|
-
old_state.fire_callbacks(:after_exit, self,
|
|
163
|
-
|
|
164
|
-
new_state.fire_callbacks(:after_enter, self,
|
|
165
|
-
*process_args(event, aasm(state_machine_name).current_state, *args))
|
|
175
|
+
old_state.fire_callbacks(:after_exit, self, *callback_args)
|
|
176
|
+
new_state.fire_callbacks(:after_enter, self, *callback_args)
|
|
166
177
|
event.fire_callbacks(
|
|
167
178
|
:after,
|
|
168
179
|
self,
|
data/lib/aasm/base.rb
CHANGED
|
@@ -26,6 +26,9 @@ module AASM
|
|
|
26
26
|
# raise if the model is invalid (in ActiveRecord)
|
|
27
27
|
configure :whiny_persistence, false
|
|
28
28
|
|
|
29
|
+
# Use transactions (in ActiveRecord)
|
|
30
|
+
configure :use_transactions, true
|
|
31
|
+
|
|
29
32
|
# use requires_new for nested transactions (in ActiveRecord)
|
|
30
33
|
configure :requires_new_transaction, true
|
|
31
34
|
|
|
@@ -34,6 +37,9 @@ module AASM
|
|
|
34
37
|
# string for a specific lock type i.e. FOR UPDATE NOWAIT
|
|
35
38
|
configure :requires_lock, false
|
|
36
39
|
|
|
40
|
+
# automatically set `"#{state_name}_at" = ::Time.now` on state changes
|
|
41
|
+
configure :timestamps, false
|
|
42
|
+
|
|
37
43
|
# set to true to forbid direct assignment of aasm_state column (in ActiveRecord)
|
|
38
44
|
configure :no_direct_assignment, false
|
|
39
45
|
|
|
@@ -48,18 +54,12 @@ module AASM
|
|
|
48
54
|
# Configure a logger, with default being a Logger to STDERR
|
|
49
55
|
configure :logger, Logger.new(STDERR)
|
|
50
56
|
|
|
57
|
+
# setup timestamp-setting callback if enabled
|
|
58
|
+
setup_timestamps(@name)
|
|
59
|
+
|
|
51
60
|
# make sure to raise an error if no_direct_assignment is enabled
|
|
52
61
|
# and attribute is directly assigned though
|
|
53
|
-
|
|
54
|
-
klass.send :define_method, "#{@state_machine.config.column}=", ->(state_name) do
|
|
55
|
-
if self.class.aasm(:"#{aasm_name}").state_machine.config.no_direct_assignment
|
|
56
|
-
raise AASM::NoDirectAssignmentError.new(
|
|
57
|
-
'direct assignment of AASM column has been disabled (see AASM configuration for this class)'
|
|
58
|
-
)
|
|
59
|
-
else
|
|
60
|
-
super(state_name)
|
|
61
|
-
end
|
|
62
|
-
end
|
|
62
|
+
setup_no_direct_assignment(@name)
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
# This method is both a getter and a setter
|
|
@@ -130,6 +130,16 @@ module AASM
|
|
|
130
130
|
aasm(aasm_name).current_event = event
|
|
131
131
|
aasm_fire_event(aasm_name, event, {:persist => false}, *args, &block)
|
|
132
132
|
end
|
|
133
|
+
|
|
134
|
+
skip_instance_level_validation(event, name, aasm_name, klass)
|
|
135
|
+
|
|
136
|
+
# Create aliases for the event methods. Keep the old names to maintain backwards compatibility.
|
|
137
|
+
if namespace?
|
|
138
|
+
klass.send(:alias_method, "may_#{name}_#{namespace}?", "may_#{name}?")
|
|
139
|
+
klass.send(:alias_method, "#{name}_#{namespace}!", "#{name}!")
|
|
140
|
+
klass.send(:alias_method, "#{name}_#{namespace}", name)
|
|
141
|
+
end
|
|
142
|
+
|
|
133
143
|
end
|
|
134
144
|
|
|
135
145
|
def after_all_transitions(*callbacks, &block)
|
|
@@ -208,7 +218,9 @@ module AASM
|
|
|
208
218
|
klass.defined_enums.values.any?{ |methods|
|
|
209
219
|
methods.keys{| enum | enum + '?' == method_name }
|
|
210
220
|
})
|
|
211
|
-
|
|
221
|
+
unless AASM::Configuration.hide_warnings
|
|
222
|
+
@state_machine.config.logger.warn "#{klass.name}: overriding method '#{method_name}'!"
|
|
223
|
+
end
|
|
212
224
|
end
|
|
213
225
|
|
|
214
226
|
klass.send(:define_method, method_name, method_definition)
|
|
@@ -236,5 +248,43 @@ module AASM
|
|
|
236
248
|
end
|
|
237
249
|
end
|
|
238
250
|
|
|
251
|
+
def skip_instance_level_validation(event, name, aasm_name, klass)
|
|
252
|
+
# Overrides the skip_validation config for an instance (If skip validation is set to false in original config) and
|
|
253
|
+
# restores it back to the original value after the event is fired.
|
|
254
|
+
safely_define_method klass, "#{name}_without_validation!", ->(*args, &block) do
|
|
255
|
+
original_config = AASM::StateMachineStore.fetch(self.class, true).machine(aasm_name).config.skip_validation_on_save
|
|
256
|
+
begin
|
|
257
|
+
AASM::StateMachineStore.fetch(self.class, true).machine(aasm_name).config.skip_validation_on_save = true unless original_config
|
|
258
|
+
aasm(aasm_name).current_event = :"#{name}!"
|
|
259
|
+
aasm_fire_event(aasm_name, event, {:persist => true}, *args, &block)
|
|
260
|
+
ensure
|
|
261
|
+
AASM::StateMachineStore.fetch(self.class, true).machine(aasm_name).config.skip_validation_on_save = original_config
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def setup_timestamps(aasm_name)
|
|
267
|
+
return unless @state_machine.config.timestamps
|
|
268
|
+
|
|
269
|
+
after_all_transitions do
|
|
270
|
+
if self.class.aasm(:"#{aasm_name}").state_machine.config.timestamps
|
|
271
|
+
ts_setter = "#{aasm(aasm_name).to_state}_at="
|
|
272
|
+
respond_to?(ts_setter) && send(ts_setter, ::Time.now)
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def setup_no_direct_assignment(aasm_name)
|
|
278
|
+
return unless @state_machine.config.no_direct_assignment
|
|
279
|
+
|
|
280
|
+
@klass.send(:define_method, "#{@state_machine.config.column}=") do |state_name|
|
|
281
|
+
if self.class.aasm(:"#{aasm_name}").state_machine.config.no_direct_assignment
|
|
282
|
+
raise AASM::NoDirectAssignmentError.new('direct assignment of AASM column has been disabled (see AASM configuration for this class)')
|
|
283
|
+
else
|
|
284
|
+
super(state_name)
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
239
289
|
end
|
|
240
290
|
end
|
data/lib/aasm/configuration.rb
CHANGED
|
@@ -15,12 +15,18 @@ module AASM
|
|
|
15
15
|
# for ActiveRecord: store the new state even if the model is invalid and return true
|
|
16
16
|
attr_accessor :skip_validation_on_save
|
|
17
17
|
|
|
18
|
+
# for ActiveRecord: use transactions
|
|
19
|
+
attr_accessor :use_transactions
|
|
20
|
+
|
|
18
21
|
# for ActiveRecord: use requires_new for nested transactions?
|
|
19
22
|
attr_accessor :requires_new_transaction
|
|
20
23
|
|
|
21
24
|
# for ActiveRecord: use pessimistic locking
|
|
22
25
|
attr_accessor :requires_lock
|
|
23
26
|
|
|
27
|
+
# automatically set `"#{state_name}_at" = ::Time.now` on state changes
|
|
28
|
+
attr_accessor :timestamps
|
|
29
|
+
|
|
24
30
|
# forbid direct assignment in aasm_state column (in ActiveRecord)
|
|
25
31
|
attr_accessor :no_direct_assignment
|
|
26
32
|
|
|
@@ -34,5 +40,9 @@ module AASM
|
|
|
34
40
|
|
|
35
41
|
# Configure a logger, with default being a Logger to STDERR
|
|
36
42
|
attr_accessor :logger
|
|
43
|
+
|
|
44
|
+
class << self
|
|
45
|
+
attr_accessor :hide_warnings
|
|
46
|
+
end
|
|
37
47
|
end
|
|
38
48
|
end
|
data/lib/aasm/core/event.rb
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module AASM::Core
|
|
2
4
|
class Event
|
|
3
|
-
include DslHelper
|
|
5
|
+
include AASM::DslHelper
|
|
4
6
|
|
|
5
|
-
attr_reader :name, :state_machine, :options
|
|
7
|
+
attr_reader :name, :state_machine, :options, :default_display_name
|
|
6
8
|
|
|
7
9
|
def initialize(name, state_machine, options = {}, &block)
|
|
8
10
|
@name = name
|
|
@@ -11,6 +13,7 @@ module AASM::Core
|
|
|
11
13
|
@valid_transitions = {}
|
|
12
14
|
@guards = Array(options[:guard] || options[:guards] || options[:if])
|
|
13
15
|
@unless = Array(options[:unless]) #TODO: This could use a better name
|
|
16
|
+
@default_display_name = name.to_s.gsub(/_/, ' ').capitalize
|
|
14
17
|
|
|
15
18
|
# from aasm4
|
|
16
19
|
@options = options # QUESTION: .dup ?
|
|
@@ -22,18 +25,29 @@ module AASM::Core
|
|
|
22
25
|
:before_transaction,
|
|
23
26
|
:ensure,
|
|
24
27
|
:error,
|
|
28
|
+
:before_success,
|
|
25
29
|
:success,
|
|
26
30
|
], &block) if block
|
|
27
31
|
end
|
|
28
32
|
|
|
33
|
+
# called internally by Ruby 1.9 after clone()
|
|
34
|
+
def initialize_copy(orig)
|
|
35
|
+
super
|
|
36
|
+
@transitions = @transitions.collect { |transition| transition.clone }
|
|
37
|
+
@guards = @guards.dup
|
|
38
|
+
@unless = @unless.dup
|
|
39
|
+
@options = {}
|
|
40
|
+
orig.options.each_pair { |name, setting| @options[name] = setting.is_a?(Hash) || setting.is_a?(Array) ? setting.dup : setting }
|
|
41
|
+
end
|
|
42
|
+
|
|
29
43
|
# a neutered version of fire - it doesn't actually fire the event, it just
|
|
30
44
|
# executes the transition guards to determine if a transition is even
|
|
31
45
|
# an option given current conditions.
|
|
32
|
-
def may_fire?(obj, to_state
|
|
46
|
+
def may_fire?(obj, to_state=::AASM::NO_VALUE, *args)
|
|
33
47
|
_fire(obj, {:test_only => true}, to_state, *args) # true indicates test firing
|
|
34
48
|
end
|
|
35
49
|
|
|
36
|
-
def fire(obj, options={}, to_state
|
|
50
|
+
def fire(obj, options={}, to_state=::AASM::NO_VALUE, *args)
|
|
37
51
|
_fire(obj, options, to_state, *args) # false indicates this is not a test (fire!)
|
|
38
52
|
end
|
|
39
53
|
|
|
@@ -85,7 +99,7 @@ module AASM::Core
|
|
|
85
99
|
@transitions << AASM::Core::Transition.new(self, attach_event_guards(definitions.merge(:from => s.to_sym)), &block)
|
|
86
100
|
end
|
|
87
101
|
# Create a transition if :to is specified without :from (transitions from ANY state)
|
|
88
|
-
if
|
|
102
|
+
if !definitions[:from] && definitions[:to]
|
|
89
103
|
@transitions << AASM::Core::Transition.new(self, attach_event_guards(definitions), &block)
|
|
90
104
|
end
|
|
91
105
|
end
|
|
@@ -96,6 +110,10 @@ module AASM::Core
|
|
|
96
110
|
transitions.flat_map(&:failures)
|
|
97
111
|
end
|
|
98
112
|
|
|
113
|
+
def to_s
|
|
114
|
+
name.to_s
|
|
115
|
+
end
|
|
116
|
+
|
|
99
117
|
private
|
|
100
118
|
|
|
101
119
|
def attach_event_guards(definitions)
|
|
@@ -110,28 +128,31 @@ module AASM::Core
|
|
|
110
128
|
definitions
|
|
111
129
|
end
|
|
112
130
|
|
|
113
|
-
def _fire(obj, options={}, to_state
|
|
131
|
+
def _fire(obj, options={}, to_state=::AASM::NO_VALUE, *args)
|
|
114
132
|
result = options[:test_only] ? false : nil
|
|
133
|
+
clear_failed_callbacks
|
|
115
134
|
transitions = @transitions.select { |t| t.from == obj.aasm(state_machine.name).current_state || t.from == nil}
|
|
116
135
|
return result if transitions.size == 0
|
|
117
136
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
end
|
|
137
|
+
if to_state == ::AASM::NO_VALUE
|
|
138
|
+
to_state = nil
|
|
139
|
+
elsif !(to_state.respond_to?(:to_sym) && transitions.map(&:to).flatten.include?(to_state.to_sym))
|
|
140
|
+
# to_state is an argument
|
|
141
|
+
args.unshift(to_state)
|
|
142
|
+
to_state = nil
|
|
125
143
|
end
|
|
144
|
+
|
|
145
|
+
# nop, to_state is a valid to-state
|
|
126
146
|
|
|
127
147
|
transitions.each do |transition|
|
|
128
148
|
next if to_state and !Array(transition.to).include?(to_state)
|
|
129
|
-
if (options.key?(:may_fire) &&
|
|
149
|
+
if (options.key?(:may_fire) && transition.eql?(options[:may_fire])) ||
|
|
130
150
|
(!options.key?(:may_fire) && transition.allowed?(obj, *args))
|
|
131
|
-
|
|
151
|
+
|
|
132
152
|
if options[:test_only]
|
|
133
|
-
|
|
153
|
+
result = transition
|
|
134
154
|
else
|
|
155
|
+
result = to_state || Array(transition.to).first
|
|
135
156
|
Array(transition.to).each {|to| @valid_transitions[to] = transition }
|
|
136
157
|
transition.execute(obj, *args)
|
|
137
158
|
end
|
|
@@ -142,28 +163,15 @@ module AASM::Core
|
|
|
142
163
|
result
|
|
143
164
|
end
|
|
144
165
|
|
|
145
|
-
def
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
raise NoMethodError.new("NoMethodError: undefined method `#{code}' for #{record.inspect}:#{record.class}")
|
|
150
|
-
end
|
|
151
|
-
arity = record.__send__(:method, code.to_sym).arity
|
|
152
|
-
record.__send__(code, *(arity < 0 ? args : args[0...arity]))
|
|
153
|
-
true
|
|
154
|
-
|
|
155
|
-
when Proc
|
|
156
|
-
arity = code.arity
|
|
157
|
-
record.instance_exec(*(arity < 0 ? args : args[0...arity]), &code)
|
|
158
|
-
true
|
|
159
|
-
|
|
160
|
-
when Array
|
|
161
|
-
code.each {|a| invoke_callbacks(a, record, args)}
|
|
162
|
-
true
|
|
166
|
+
def clear_failed_callbacks
|
|
167
|
+
# https://github.com/aasm/aasm/issues/383, https://github.com/aasm/aasm/issues/599
|
|
168
|
+
transitions.each { |transition| transition.failures.clear }
|
|
169
|
+
end
|
|
163
170
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
171
|
+
def invoke_callbacks(code, record, args)
|
|
172
|
+
Invoker.new(code, record, args)
|
|
173
|
+
.with_default_return_value(false)
|
|
174
|
+
.invoke
|
|
167
175
|
end
|
|
168
176
|
end
|
|
169
177
|
end # AASM
|