aasm 5.1.1 → 5.5.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 +4 -4
- data/README.md +74 -15
- data/lib/aasm/base.rb +44 -12
- data/lib/aasm/configuration.rb +3 -0
- data/lib/aasm/core/event.rb +12 -6
- data/lib/aasm/core/invokers/class_invoker.rb +1 -1
- data/lib/aasm/core/invokers/literal_invoker.rb +3 -1
- data/lib/aasm/core/state.rb +6 -5
- data/lib/aasm/core/transition.rb +1 -1
- data/lib/aasm/dsl_helper.rb +24 -22
- data/lib/aasm/errors.rb +1 -0
- data/lib/aasm/instance_base.rb +14 -3
- data/lib/aasm/localizer.rb +13 -3
- data/lib/aasm/persistence/active_record_persistence.rb +1 -1
- data/lib/aasm/persistence/base.rb +13 -2
- data/lib/aasm/version.rb +1 -1
- data/lib/generators/aasm/orm_helpers.rb +1 -1
- data/lib/generators/active_record/templates/migration.rb +1 -1
- metadata +6 -402
- data/.document +0 -6
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -27
- data/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
- data/.gitignore +0 -20
- data/.travis.yml +0 -82
- data/API +0 -34
- data/Appraisals +0 -67
- data/CHANGELOG.md +0 -442
- data/CODE_OF_CONDUCT.md +0 -13
- data/CONTRIBUTING.md +0 -24
- data/Dockerfile +0 -44
- data/Gemfile +0 -6
- data/Gemfile.lock_old +0 -151
- data/HOWTO +0 -12
- data/PLANNED_CHANGES.md +0 -11
- data/README_FROM_VERSION_3_TO_4.md +0 -240
- data/Rakefile +0 -31
- data/TESTING.md +0 -25
- data/aasm.gemspec +0 -37
- data/docker-compose.yml +0 -40
- data/gemfiles/norails.gemfile +0 -10
- data/gemfiles/rails_4.2.gemfile +0 -17
- data/gemfiles/rails_4.2_mongoid_5.gemfile +0 -12
- data/gemfiles/rails_4.2_nobrainer.gemfile +0 -9
- data/gemfiles/rails_5.0.gemfile +0 -14
- data/gemfiles/rails_5.0_nobrainer.gemfile +0 -9
- data/gemfiles/rails_5.1.gemfile +0 -14
- data/gemfiles/rails_5.2.gemfile +0 -14
- data/spec/database.rb +0 -59
- data/spec/database.yml +0 -3
- data/spec/en.yml +0 -9
- data/spec/generators/active_record_generator_spec.rb +0 -53
- data/spec/generators/mongoid_generator_spec.rb +0 -31
- data/spec/generators/no_brainer_generator_spec.rb +0 -29
- data/spec/localizer_test_model_deprecated_style.yml +0 -6
- data/spec/localizer_test_model_new_style.yml +0 -5
- data/spec/models/active_record/active_record_callback.rb +0 -93
- data/spec/models/active_record/basic_active_record_two_state_machines_example.rb +0 -25
- data/spec/models/active_record/complex_active_record_example.rb +0 -37
- data/spec/models/active_record/derivate_new_dsl.rb +0 -7
- data/spec/models/active_record/false_state.rb +0 -35
- data/spec/models/active_record/gate.rb +0 -39
- data/spec/models/active_record/instance_level_skip_validation_example.rb +0 -19
- data/spec/models/active_record/invalid_persistor.rb +0 -29
- data/spec/models/active_record/localizer_test_model.rb +0 -34
- data/spec/models/active_record/no_direct_assignment.rb +0 -21
- data/spec/models/active_record/no_scope.rb +0 -21
- data/spec/models/active_record/persisted_state.rb +0 -12
- data/spec/models/active_record/person.rb +0 -23
- data/spec/models/active_record/provided_and_persisted_state.rb +0 -24
- data/spec/models/active_record/reader.rb +0 -7
- data/spec/models/active_record/readme_job.rb +0 -21
- data/spec/models/active_record/silent_persistor.rb +0 -29
- data/spec/models/active_record/simple_new_dsl.rb +0 -32
- data/spec/models/active_record/thief.rb +0 -29
- data/spec/models/active_record/transactor.rb +0 -124
- data/spec/models/active_record/transient.rb +0 -6
- data/spec/models/active_record/validator.rb +0 -118
- data/spec/models/active_record/with_enum.rb +0 -39
- data/spec/models/active_record/with_enum_without_column.rb +0 -38
- data/spec/models/active_record/with_false_enum.rb +0 -31
- data/spec/models/active_record/with_true_enum.rb +0 -39
- data/spec/models/active_record/work.rb +0 -3
- data/spec/models/active_record/worker.rb +0 -2
- data/spec/models/active_record/writer.rb +0 -6
- data/spec/models/basic_two_state_machines_example.rb +0 -25
- data/spec/models/callbacks/basic.rb +0 -98
- data/spec/models/callbacks/basic_multiple.rb +0 -75
- data/spec/models/callbacks/guard_within_block.rb +0 -67
- data/spec/models/callbacks/guard_within_block_multiple.rb +0 -66
- data/spec/models/callbacks/multiple_transitions_transition_guard.rb +0 -66
- data/spec/models/callbacks/multiple_transitions_transition_guard_multiple.rb +0 -65
- data/spec/models/callbacks/private_method.rb +0 -44
- data/spec/models/callbacks/private_method_multiple.rb +0 -44
- data/spec/models/callbacks/with_args.rb +0 -62
- data/spec/models/callbacks/with_args_multiple.rb +0 -61
- data/spec/models/callbacks/with_state_arg.rb +0 -34
- data/spec/models/callbacks/with_state_arg_multiple.rb +0 -29
- data/spec/models/complex_example.rb +0 -222
- data/spec/models/conversation.rb +0 -93
- data/spec/models/default_state.rb +0 -12
- data/spec/models/double_definer.rb +0 -21
- data/spec/models/dynamoid/complex_dynamoid_example.rb +0 -37
- data/spec/models/dynamoid/dynamoid_multiple.rb +0 -18
- data/spec/models/dynamoid/dynamoid_simple.rb +0 -18
- data/spec/models/foo.rb +0 -106
- data/spec/models/foo_callback_multiple.rb +0 -45
- data/spec/models/guard_arguments_check.rb +0 -17
- data/spec/models/guard_with_params.rb +0 -24
- data/spec/models/guard_with_params_multiple.rb +0 -18
- data/spec/models/guardian.rb +0 -58
- data/spec/models/guardian_multiple.rb +0 -48
- data/spec/models/guardian_without_from_specified.rb +0 -18
- data/spec/models/initial_state_proc.rb +0 -31
- data/spec/models/mongoid/complex_mongoid_example.rb +0 -37
- data/spec/models/mongoid/invalid_persistor_mongoid.rb +0 -39
- data/spec/models/mongoid/mongoid_relationships.rb +0 -26
- data/spec/models/mongoid/no_scope_mongoid.rb +0 -21
- data/spec/models/mongoid/silent_persistor_mongoid.rb +0 -39
- data/spec/models/mongoid/simple_mongoid.rb +0 -23
- data/spec/models/mongoid/simple_new_dsl_mongoid.rb +0 -25
- data/spec/models/mongoid/validator_mongoid.rb +0 -100
- data/spec/models/multi_transitioner.rb +0 -34
- data/spec/models/multiple_transitions_that_differ_only_by_guard.rb +0 -31
- data/spec/models/namespaced_multiple_example.rb +0 -42
- data/spec/models/no_initial_state.rb +0 -25
- data/spec/models/nobrainer/complex_no_brainer_example.rb +0 -36
- data/spec/models/nobrainer/invalid_persistor_no_brainer.rb +0 -39
- data/spec/models/nobrainer/no_scope_no_brainer.rb +0 -21
- data/spec/models/nobrainer/nobrainer_relationships.rb +0 -25
- data/spec/models/nobrainer/silent_persistor_no_brainer.rb +0 -39
- data/spec/models/nobrainer/simple_new_dsl_nobrainer.rb +0 -25
- data/spec/models/nobrainer/simple_no_brainer.rb +0 -23
- data/spec/models/nobrainer/validator_no_brainer.rb +0 -98
- data/spec/models/not_auto_loaded/process.rb +0 -21
- data/spec/models/parametrised_event.rb +0 -42
- data/spec/models/parametrised_event_multiple.rb +0 -29
- data/spec/models/process_with_new_dsl.rb +0 -31
- data/spec/models/provided_state.rb +0 -24
- data/spec/models/redis/complex_redis_example.rb +0 -40
- data/spec/models/redis/redis_multiple.rb +0 -20
- data/spec/models/redis/redis_simple.rb +0 -20
- data/spec/models/sequel/complex_sequel_example.rb +0 -46
- data/spec/models/sequel/invalid_persistor.rb +0 -52
- data/spec/models/sequel/sequel_multiple.rb +0 -25
- data/spec/models/sequel/sequel_simple.rb +0 -26
- data/spec/models/sequel/silent_persistor.rb +0 -50
- data/spec/models/sequel/transactor.rb +0 -112
- data/spec/models/sequel/validator.rb +0 -93
- data/spec/models/sequel/worker.rb +0 -12
- data/spec/models/silencer.rb +0 -27
- data/spec/models/simple_custom_example.rb +0 -53
- data/spec/models/simple_example.rb +0 -23
- data/spec/models/simple_example_with_guard_args.rb +0 -17
- data/spec/models/simple_multiple_example.rb +0 -42
- data/spec/models/state_machine_with_failed_event.rb +0 -20
- data/spec/models/states_on_one_line_example.rb +0 -8
- data/spec/models/sub_class.rb +0 -41
- data/spec/models/sub_class_with_more_states.rb +0 -18
- data/spec/models/sub_classing.rb +0 -3
- data/spec/models/super_class.rb +0 -46
- data/spec/models/this_name_better_not_be_in_use.rb +0 -11
- data/spec/models/valid_state_name.rb +0 -23
- data/spec/spec_helper.rb +0 -41
- data/spec/spec_helpers/active_record.rb +0 -8
- data/spec/spec_helpers/dynamoid.rb +0 -35
- data/spec/spec_helpers/mongoid.rb +0 -26
- data/spec/spec_helpers/nobrainer.rb +0 -15
- data/spec/spec_helpers/redis.rb +0 -18
- data/spec/spec_helpers/remove_warnings.rb +0 -1
- data/spec/spec_helpers/sequel.rb +0 -7
- data/spec/unit/abstract_class_spec.rb +0 -27
- data/spec/unit/api_spec.rb +0 -104
- data/spec/unit/basic_two_state_machines_example_spec.rb +0 -10
- data/spec/unit/callback_multiple_spec.rb +0 -304
- data/spec/unit/callbacks_spec.rb +0 -521
- data/spec/unit/complex_example_spec.rb +0 -93
- data/spec/unit/complex_multiple_example_spec.rb +0 -115
- data/spec/unit/edge_cases_spec.rb +0 -16
- data/spec/unit/event_multiple_spec.rb +0 -73
- data/spec/unit/event_naming_spec.rb +0 -16
- data/spec/unit/event_spec.rb +0 -394
- data/spec/unit/exception_spec.rb +0 -11
- data/spec/unit/guard_arguments_check_spec.rb +0 -9
- data/spec/unit/guard_multiple_spec.rb +0 -60
- data/spec/unit/guard_spec.rb +0 -89
- data/spec/unit/guard_with_params_multiple_spec.rb +0 -10
- data/spec/unit/guard_with_params_spec.rb +0 -14
- data/spec/unit/guard_without_from_specified_spec.rb +0 -10
- data/spec/unit/initial_state_multiple_spec.rb +0 -15
- data/spec/unit/initial_state_spec.rb +0 -12
- data/spec/unit/inspection_multiple_spec.rb +0 -205
- data/spec/unit/inspection_spec.rb +0 -153
- data/spec/unit/invoker_spec.rb +0 -189
- data/spec/unit/invokers/base_invoker_spec.rb +0 -72
- data/spec/unit/invokers/class_invoker_spec.rb +0 -95
- data/spec/unit/invokers/literal_invoker_spec.rb +0 -86
- data/spec/unit/invokers/proc_invoker_spec.rb +0 -86
- data/spec/unit/localizer_spec.rb +0 -77
- data/spec/unit/memory_leak_spec.rb +0 -38
- data/spec/unit/multiple_transitions_that_differ_only_by_guard_spec.rb +0 -14
- data/spec/unit/namespaced_multiple_example_spec.rb +0 -75
- data/spec/unit/new_dsl_spec.rb +0 -12
- data/spec/unit/override_warning_spec.rb +0 -94
- data/spec/unit/persistence/active_record_persistence_multiple_spec.rb +0 -618
- data/spec/unit/persistence/active_record_persistence_spec.rb +0 -840
- data/spec/unit/persistence/dynamoid_persistence_multiple_spec.rb +0 -135
- data/spec/unit/persistence/dynamoid_persistence_spec.rb +0 -84
- data/spec/unit/persistence/mongoid_persistence_multiple_spec.rb +0 -200
- data/spec/unit/persistence/mongoid_persistence_spec.rb +0 -165
- data/spec/unit/persistence/no_brainer_persistence_multiple_spec.rb +0 -198
- data/spec/unit/persistence/no_brainer_persistence_spec.rb +0 -158
- data/spec/unit/persistence/redis_persistence_multiple_spec.rb +0 -88
- data/spec/unit/persistence/redis_persistence_spec.rb +0 -53
- data/spec/unit/persistence/sequel_persistence_multiple_spec.rb +0 -148
- data/spec/unit/persistence/sequel_persistence_spec.rb +0 -368
- data/spec/unit/readme_spec.rb +0 -41
- data/spec/unit/reloading_spec.rb +0 -15
- data/spec/unit/rspec_matcher_spec.rb +0 -88
- data/spec/unit/simple_custom_example_spec.rb +0 -39
- data/spec/unit/simple_example_spec.rb +0 -57
- data/spec/unit/simple_multiple_example_spec.rb +0 -91
- data/spec/unit/state_spec.rb +0 -105
- data/spec/unit/states_on_one_line_example_spec.rb +0 -16
- data/spec/unit/subclassing_multiple_spec.rb +0 -74
- data/spec/unit/subclassing_spec.rb +0 -46
- data/spec/unit/transition_spec.rb +0 -436
- data/test/minitest_helper.rb +0 -57
- data/test/unit/minitest_matcher_test.rb +0 -80
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a088e1285940890f3c1a87b6cf0534e80702a96d2fb6eb42b43ff0cf50e6c57d
|
4
|
+
data.tar.gz: b96c64d2458639d217540b8787b1f718d80cd8e64b2661825435a795d5796a93
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85a0532a6257477070680b2864c27191f618a61091fe9ba0c2c0672e99aa53c4b61968e4987607c4e5747bb42686cff6667966c90cf4592e87ad0324175e711c
|
7
|
+
data.tar.gz: 1abfc89101b1cdf7440a82446b6c600d65fe6f2bfc83575a85dc2ef0edb04968cc509c9ff88ec2ce68f4aa8b72283f75301a0fcfefffa16fc0347cb31f11c492
|
data/README.md
CHANGED
@@ -20,6 +20,7 @@
|
|
20
20
|
- [Extending AASM](#extending-aasm)
|
21
21
|
- [ActiveRecord](#activerecord)
|
22
22
|
- [Bang events](#bang-events)
|
23
|
+
- [Timestamps](#timestamps)
|
23
24
|
- [ActiveRecord enums](#activerecord-enums)
|
24
25
|
- [Sequel](#sequel)
|
25
26
|
- [Dynamoid](#dynamoid)
|
@@ -212,15 +213,28 @@ class LogRunTime
|
|
212
213
|
end
|
213
214
|
```
|
214
215
|
|
215
|
-
|
216
|
+
#### Parameters
|
217
|
+
You can pass parameters to events:
|
216
218
|
|
217
219
|
```ruby
|
218
220
|
job = Job.new
|
219
221
|
job.run(:defragmentation)
|
220
222
|
```
|
221
223
|
|
222
|
-
In this case
|
224
|
+
All guards and after callbacks will receive these parameters. In this case `set_process` would be called with
|
225
|
+
`:defragmentation` argument.
|
223
226
|
|
227
|
+
If the first argument to the event is a state (e.g. `:running` or `:finished`), the first argument is consumed and
|
228
|
+
the state machine will attempt to transition to that state. Add comma separated parameter for guards and callbacks
|
229
|
+
|
230
|
+
```ruby
|
231
|
+
job = Job.new
|
232
|
+
job.run(:running, :defragmentation)
|
233
|
+
```
|
234
|
+
In this case `set_process` won't be called, job will transition to running state and callback will receive
|
235
|
+
`:defragmentation` as parameter
|
236
|
+
|
237
|
+
#### Error Handling
|
224
238
|
In case of an error during the event processing the error is rescued and passed to `:error`
|
225
239
|
callback, which can handle it or re-raise it for further propagation.
|
226
240
|
|
@@ -307,7 +321,7 @@ and then
|
|
307
321
|
Let's assume you want to allow particular transitions only if a defined condition is
|
308
322
|
given. For this you can set up a guard per transition, which will run before actually
|
309
323
|
running the transition. If the guard returns `false` the transition will be
|
310
|
-
denied (raising `AASM::InvalidTransition`
|
324
|
+
denied (raising `AASM::InvalidTransition`):
|
311
325
|
|
312
326
|
```ruby
|
313
327
|
class Cleaner
|
@@ -350,7 +364,7 @@ job.clean # => raises AASM::InvalidTransition
|
|
350
364
|
job.may_clean_if_needed? # => true
|
351
365
|
job.clean_if_needed! # idle
|
352
366
|
|
353
|
-
job.clean_if_dirty(:clean) # =>
|
367
|
+
job.clean_if_dirty(:clean) # => raises AASM::InvalidTransition
|
354
368
|
job.clean_if_dirty(:dirty) # => true
|
355
369
|
```
|
356
370
|
|
@@ -386,7 +400,7 @@ If you prefer a more Ruby-like guard syntax, you can use `if` and `unless` as we
|
|
386
400
|
end
|
387
401
|
```
|
388
402
|
|
389
|
-
You can invoke a Class instead a method
|
403
|
+
You can invoke a Class instead of a method if the Class responds to `call`
|
390
404
|
|
391
405
|
```ruby
|
392
406
|
event :sleep do
|
@@ -434,6 +448,14 @@ job.stage1_completed
|
|
434
448
|
job.aasm.current_state # stage3
|
435
449
|
```
|
436
450
|
|
451
|
+
You can define transition from any defined state by omitting `from`:
|
452
|
+
|
453
|
+
```ruby
|
454
|
+
event :abort do
|
455
|
+
transitions to: :aborted
|
456
|
+
end
|
457
|
+
```
|
458
|
+
|
437
459
|
### Display name for state
|
438
460
|
|
439
461
|
You can define display name for state using :display option
|
@@ -495,13 +517,13 @@ simple = SimpleMultipleExample.new
|
|
495
517
|
|
496
518
|
simple.aasm(:move).current_state
|
497
519
|
# => :standing
|
498
|
-
simple.aasm(:work).
|
520
|
+
simple.aasm(:work).current_state
|
499
521
|
# => :sleeping
|
500
522
|
|
501
523
|
simple.start
|
502
524
|
simple.aasm(:move).current_state
|
503
525
|
# => :standing
|
504
|
-
simple.aasm(:work).
|
526
|
+
simple.aasm(:work).current_state
|
505
527
|
# => :processing
|
506
528
|
|
507
529
|
```
|
@@ -698,7 +720,7 @@ end
|
|
698
720
|
AASM comes with support for ActiveRecord and allows automatic persisting of the object's
|
699
721
|
state in the database.
|
700
722
|
|
701
|
-
Add `gem 'after_commit_everywhere', '~>
|
723
|
+
Add `gem 'after_commit_everywhere', '~> 1.0'` to your Gemfile.
|
702
724
|
|
703
725
|
```ruby
|
704
726
|
class Job < ActiveRecord::Base
|
@@ -736,7 +758,7 @@ job.aasm.fire!(:run) # saved
|
|
736
758
|
|
737
759
|
Saving includes running all validations on the `Job` class. If
|
738
760
|
`whiny_persistence` flag is set to `true`, exception is raised in case of
|
739
|
-
failure. If `whiny_persistence` flag is set to false
|
761
|
+
failure. If `whiny_persistence` flag is set to `false`, methods with a bang return
|
740
762
|
`true` if the state transition is successful or `false` if an error occurs.
|
741
763
|
|
742
764
|
If you want make sure the state gets saved without running validations (and
|
@@ -764,7 +786,7 @@ class Job < ActiveRecord::Base
|
|
764
786
|
end
|
765
787
|
```
|
766
788
|
|
767
|
-
Also
|
789
|
+
Also, you can skip the validation at instance level with `some_event_name_without_validation!` method.
|
768
790
|
With this you have the flexibility of having validation for all your transitions by default and then skip it wherever required.
|
769
791
|
Please note that only state column will be updated as mentioned in the above example.
|
770
792
|
|
@@ -800,6 +822,37 @@ job.aasm_state = :running # => raises AASM::NoDirectAssignmentError
|
|
800
822
|
job.aasm_state # => 'sleeping'
|
801
823
|
```
|
802
824
|
|
825
|
+
### Timestamps
|
826
|
+
|
827
|
+
You can tell _AASM_ to try to write a timestamp whenever a new state is entered.
|
828
|
+
If `timestamps: true` is set, _AASM_ will look for a field named like the new state plus `_at` and try to fill it:
|
829
|
+
|
830
|
+
```ruby
|
831
|
+
class Job < ActiveRecord::Base
|
832
|
+
include AASM
|
833
|
+
|
834
|
+
aasm timestamps: true do
|
835
|
+
state :sleeping, initial: true
|
836
|
+
state :running
|
837
|
+
|
838
|
+
event :run do
|
839
|
+
transitions from: :sleeping, to: :running
|
840
|
+
end
|
841
|
+
end
|
842
|
+
end
|
843
|
+
```
|
844
|
+
|
845
|
+
resulting in this:
|
846
|
+
|
847
|
+
```ruby
|
848
|
+
job = Job.create
|
849
|
+
job.running_at # => nil
|
850
|
+
job.run!
|
851
|
+
job.running_at # => 2020-02-20 20:00:00
|
852
|
+
```
|
853
|
+
|
854
|
+
Missing timestamp fields are silently ignored, so it is not necessary to have setters (such as ActiveRecord columns) for *all* states when using this option.
|
855
|
+
|
803
856
|
#### ActiveRecord enums
|
804
857
|
|
805
858
|
You can use
|
@@ -1007,7 +1060,7 @@ job.save! #notify_about_running_job is not run
|
|
1007
1060
|
Please note that `:after_commit` AASM callbacks behaves around custom implementation
|
1008
1061
|
of transaction pattern rather than a real-life DB transaction. This fact still causes
|
1009
1062
|
the race conditions and redundant callback calls within nested transaction. In order
|
1010
|
-
to fix that it's highly recommended to add `gem 'after_commit_everywhere', '~>
|
1063
|
+
to fix that it's highly recommended to add `gem 'after_commit_everywhere', '~> 1.0'`
|
1011
1064
|
to your `Gemfile`.
|
1012
1065
|
|
1013
1066
|
If you want to encapsulate state changes within an own transaction, the behavior
|
@@ -1031,7 +1084,7 @@ end
|
|
1031
1084
|
|
1032
1085
|
which then leads to `transaction(requires_new: false)`, the Rails default.
|
1033
1086
|
|
1034
|
-
Additionally, if you do not want any of your
|
1087
|
+
Additionally, if you do not want any of your ActiveRecord actions to be
|
1035
1088
|
wrapped in a transaction, you can specify the `use_transactions` flag. This can
|
1036
1089
|
be useful if you want want to persist things to the database that happen as a
|
1037
1090
|
result of a transaction or callback, even when some error occurs. The
|
@@ -1051,7 +1104,7 @@ end
|
|
1051
1104
|
|
1052
1105
|
### Pessimistic Locking
|
1053
1106
|
|
1054
|
-
AASM supports [
|
1107
|
+
AASM supports [ActiveRecord pessimistic locking via `with_lock`](http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html#method-i-with_lock) for database persistence layers.
|
1055
1108
|
|
1056
1109
|
| Option | Purpose |
|
1057
1110
|
| ------ | ------- |
|
@@ -1107,7 +1160,7 @@ end
|
|
1107
1160
|
Whatever column name is used, make sure to add a migration to provide this column
|
1108
1161
|
(of type `string`).
|
1109
1162
|
Do not add default value for column at the database level. If you add default
|
1110
|
-
value in database then AASM callbacks on the initial state will not be fired upon
|
1163
|
+
value in database then AASM callbacks on the initial state will not be fired upon
|
1111
1164
|
instantiation of the model.
|
1112
1165
|
|
1113
1166
|
```ruby
|
@@ -1408,7 +1461,7 @@ After installing AASM you can run generator:
|
|
1408
1461
|
```
|
1409
1462
|
Replace NAME with the Model name, COLUMN_NAME is optional(default is 'aasm_state').
|
1410
1463
|
This will create a model (if one does not exist) and configure it with aasm block.
|
1411
|
-
For
|
1464
|
+
For ActiveRecord orm a migration file is added to add aasm state column to table.
|
1412
1465
|
|
1413
1466
|
### Docker
|
1414
1467
|
|
@@ -1438,6 +1491,12 @@ Feel free to
|
|
1438
1491
|
* [Anil Maurya](http://github.com/anilmaurya) (since 2016)
|
1439
1492
|
|
1440
1493
|
|
1494
|
+
|
1495
|
+
## Stargazers over time
|
1496
|
+
|
1497
|
+
[](https://starchart.cc/aasm/aasm)
|
1498
|
+
|
1499
|
+
|
1441
1500
|
## [Contributing](CONTRIBUTING.md)
|
1442
1501
|
|
1443
1502
|
## Warranty ##
|
data/lib/aasm/base.rb
CHANGED
@@ -37,6 +37,9 @@ module AASM
|
|
37
37
|
# string for a specific lock type i.e. FOR UPDATE NOWAIT
|
38
38
|
configure :requires_lock, false
|
39
39
|
|
40
|
+
# automatically set `"#{state_name}_at" = ::Time.now` on state changes
|
41
|
+
configure :timestamps, false
|
42
|
+
|
40
43
|
# set to true to forbid direct assignment of aasm_state column (in ActiveRecord)
|
41
44
|
configure :no_direct_assignment, false
|
42
45
|
|
@@ -51,19 +54,12 @@ module AASM
|
|
51
54
|
# Configure a logger, with default being a Logger to STDERR
|
52
55
|
configure :logger, Logger.new(STDERR)
|
53
56
|
|
57
|
+
# setup timestamp-setting callback if enabled
|
58
|
+
setup_timestamps(@name)
|
59
|
+
|
54
60
|
# make sure to raise an error if no_direct_assignment is enabled
|
55
61
|
# and attribute is directly assigned though
|
56
|
-
|
57
|
-
|
58
|
-
if @state_machine.config.no_direct_assignment
|
59
|
-
@klass.send(:define_method, "#{@state_machine.config.column}=") do |state_name|
|
60
|
-
if self.class.aasm(:"#{aasm_name}").state_machine.config.no_direct_assignment
|
61
|
-
raise AASM::NoDirectAssignmentError.new('direct assignment of AASM column has been disabled (see AASM configuration for this class)')
|
62
|
-
else
|
63
|
-
super(state_name)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
62
|
+
setup_no_direct_assignment(@name)
|
67
63
|
end
|
68
64
|
|
69
65
|
# This method is both a getter and a setter
|
@@ -227,7 +223,20 @@ module AASM
|
|
227
223
|
end
|
228
224
|
end
|
229
225
|
|
230
|
-
klass.send(:define_method, method_name, method_definition)
|
226
|
+
klass.send(:define_method, method_name, method_definition).tap do |sym|
|
227
|
+
apply_ruby2_keyword(klass, sym)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def apply_ruby2_keyword(klass, sym)
|
232
|
+
if RUBY_VERSION >= '2.7.1'
|
233
|
+
if klass.instance_method(sym).parameters.find { |type, _| type.to_s.start_with?('rest') }
|
234
|
+
# If there is a place where you are receiving in *args, do ruby2_keywords.
|
235
|
+
klass.module_eval do
|
236
|
+
ruby2_keywords sym
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
231
240
|
end
|
232
241
|
|
233
242
|
def namespace?
|
@@ -267,5 +276,28 @@ module AASM
|
|
267
276
|
end
|
268
277
|
end
|
269
278
|
|
279
|
+
def setup_timestamps(aasm_name)
|
280
|
+
return unless @state_machine.config.timestamps
|
281
|
+
|
282
|
+
after_all_transitions do
|
283
|
+
if self.class.aasm(:"#{aasm_name}").state_machine.config.timestamps
|
284
|
+
ts_setter = "#{aasm(aasm_name).to_state}_at="
|
285
|
+
respond_to?(ts_setter) && send(ts_setter, ::Time.now)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
def setup_no_direct_assignment(aasm_name)
|
291
|
+
return unless @state_machine.config.no_direct_assignment
|
292
|
+
|
293
|
+
@klass.send(:define_method, "#{@state_machine.config.column}=") do |state_name|
|
294
|
+
if self.class.aasm(:"#{aasm_name}").state_machine.config.no_direct_assignment
|
295
|
+
raise AASM::NoDirectAssignmentError.new('direct assignment of AASM column has been disabled (see AASM configuration for this class)')
|
296
|
+
else
|
297
|
+
super(state_name)
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
270
302
|
end
|
271
303
|
end
|
data/lib/aasm/configuration.rb
CHANGED
@@ -24,6 +24,9 @@ module AASM
|
|
24
24
|
# for ActiveRecord: use pessimistic locking
|
25
25
|
attr_accessor :requires_lock
|
26
26
|
|
27
|
+
# automatically set `"#{state_name}_at" = ::Time.now` on state changes
|
28
|
+
attr_accessor :timestamps
|
29
|
+
|
27
30
|
# forbid direct assignment in aasm_state column (in ActiveRecord)
|
28
31
|
attr_accessor :no_direct_assignment
|
29
32
|
|
data/lib/aasm/core/event.rb
CHANGED
@@ -2,17 +2,18 @@
|
|
2
2
|
|
3
3
|
module AASM::Core
|
4
4
|
class Event
|
5
|
-
include DslHelper
|
5
|
+
include AASM::DslHelper
|
6
6
|
|
7
|
-
attr_reader :name, :state_machine, :options
|
7
|
+
attr_reader :name, :state_machine, :options, :default_display_name
|
8
8
|
|
9
9
|
def initialize(name, state_machine, options = {}, &block)
|
10
10
|
@name = name
|
11
11
|
@state_machine = state_machine
|
12
12
|
@transitions = []
|
13
|
-
@valid_transitions = {}
|
13
|
+
@valid_transitions = Hash.new { |h, k| h[k] = {} }
|
14
14
|
@guards = Array(options[:guard] || options[:guards] || options[:if])
|
15
15
|
@unless = Array(options[:unless]) #TODO: This could use a better name
|
16
|
+
@default_display_name = name.to_s.gsub(/_/, ' ').capitalize
|
16
17
|
|
17
18
|
# from aasm4
|
18
19
|
@options = options # QUESTION: .dup ?
|
@@ -78,8 +79,9 @@ module AASM::Core
|
|
78
79
|
|
79
80
|
def fire_transition_callbacks(obj, *args)
|
80
81
|
from_state = obj.aasm(state_machine.name).current_state
|
81
|
-
transition = @valid_transitions[from_state]
|
82
|
-
|
82
|
+
transition = @valid_transitions[obj.object_id][from_state]
|
83
|
+
transition.invoke_success_callbacks(obj, *args) if transition
|
84
|
+
@valid_transitions.delete(obj.object_id)
|
83
85
|
end
|
84
86
|
|
85
87
|
def ==(event)
|
@@ -109,6 +111,10 @@ module AASM::Core
|
|
109
111
|
transitions.flat_map(&:failures)
|
110
112
|
end
|
111
113
|
|
114
|
+
def to_s
|
115
|
+
name.to_s
|
116
|
+
end
|
117
|
+
|
112
118
|
private
|
113
119
|
|
114
120
|
def attach_event_guards(definitions)
|
@@ -148,7 +154,7 @@ module AASM::Core
|
|
148
154
|
result = transition
|
149
155
|
else
|
150
156
|
result = to_state || Array(transition.to).first
|
151
|
-
Array(transition.to).each {|to| @valid_transitions[to] = transition }
|
157
|
+
Array(transition.to).each {|to| @valid_transitions[obj.object_id][to] = transition }
|
152
158
|
transition.execute(obj, *args)
|
153
159
|
end
|
154
160
|
|
@@ -30,7 +30,9 @@ module AASM
|
|
30
30
|
raise(*record_error) unless record.respond_to?(subject, true)
|
31
31
|
return record.__send__(subject) if subject_arity.zero?
|
32
32
|
return record.__send__(subject, *args) if subject_arity < 0
|
33
|
-
|
33
|
+
req_args = args[0..(subject_arity - 1)]
|
34
|
+
return record.__send__(subject, **req_args[0]) if req_args[0].is_a?(Hash)
|
35
|
+
record.__send__(subject, *req_args)
|
34
36
|
end
|
35
37
|
# rubocop:enable Metrics/AbcSize
|
36
38
|
|
data/lib/aasm/core/state.rb
CHANGED
@@ -2,12 +2,13 @@
|
|
2
2
|
|
3
3
|
module AASM::Core
|
4
4
|
class State
|
5
|
-
attr_reader :name, :state_machine, :options
|
5
|
+
attr_reader :name, :state_machine, :options, :default_display_name
|
6
6
|
|
7
7
|
def initialize(name, klass, state_machine, options={})
|
8
8
|
@name = name
|
9
9
|
@klass = klass
|
10
10
|
@state_machine = state_machine
|
11
|
+
@default_display_name = name.to_s.gsub(/_/, ' ').capitalize
|
11
12
|
update(options)
|
12
13
|
end
|
13
14
|
|
@@ -54,11 +55,11 @@ module AASM::Core
|
|
54
55
|
end
|
55
56
|
|
56
57
|
def display_name
|
57
|
-
@display_name
|
58
|
+
@display_name = begin
|
58
59
|
if Module.const_defined?(:I18n)
|
59
60
|
localized_name
|
60
61
|
else
|
61
|
-
|
62
|
+
@default_display_name
|
62
63
|
end
|
63
64
|
end
|
64
65
|
end
|
@@ -75,8 +76,8 @@ module AASM::Core
|
|
75
76
|
private
|
76
77
|
|
77
78
|
def update(options = {})
|
78
|
-
if options.key?(:display)
|
79
|
-
@
|
79
|
+
if options.key?(:display)
|
80
|
+
@default_display_name = options.delete(:display)
|
80
81
|
end
|
81
82
|
@options = options
|
82
83
|
self
|
data/lib/aasm/core/transition.rb
CHANGED
data/lib/aasm/dsl_helper.rb
CHANGED
@@ -1,30 +1,32 @@
|
|
1
|
-
module
|
1
|
+
module AASM
|
2
|
+
module DslHelper
|
2
3
|
|
3
|
-
|
4
|
-
|
4
|
+
class Proxy
|
5
|
+
attr_accessor :options
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
7
|
+
def initialize(options, valid_keys, source)
|
8
|
+
@valid_keys = valid_keys
|
9
|
+
@source = source
|
9
10
|
|
10
|
-
|
11
|
-
|
11
|
+
@options = options
|
12
|
+
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
14
|
+
def method_missing(name, *args, &block)
|
15
|
+
if @valid_keys.include?(name)
|
16
|
+
options[name] = Array(options[name])
|
17
|
+
options[name] << block if block
|
18
|
+
options[name] += Array(args)
|
19
|
+
else
|
20
|
+
@source.send name, *args, &block
|
21
|
+
end
|
20
22
|
end
|
21
23
|
end
|
22
|
-
end
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
25
|
+
def add_options_from_dsl(options, valid_keys, &block)
|
26
|
+
proxy = Proxy.new(options, valid_keys, self)
|
27
|
+
proxy.instance_eval(&block)
|
28
|
+
proxy.options
|
29
|
+
end
|
29
30
|
|
30
|
-
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/aasm/errors.rb
CHANGED
data/lib/aasm/instance_base.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
module AASM
|
2
2
|
class InstanceBase
|
3
|
-
|
4
3
|
attr_accessor :from_state, :to_state, :current_event
|
5
4
|
|
6
5
|
def initialize(instance, name=:default) # instance of the class including AASM, name of the state machine
|
@@ -115,12 +114,15 @@ module AASM
|
|
115
114
|
end
|
116
115
|
|
117
116
|
def fire(event_name, *args, &block)
|
117
|
+
event_exists?(event_name)
|
118
|
+
|
118
119
|
@instance.send(event_name, *args, &block)
|
119
120
|
end
|
120
121
|
|
121
122
|
def fire!(event_name, *args, &block)
|
122
|
-
event_name
|
123
|
-
|
123
|
+
event_exists?(event_name, true)
|
124
|
+
bang_event_name = "#{event_name}!".to_sym
|
125
|
+
@instance.send(bang_event_name, *args, &block)
|
124
126
|
end
|
125
127
|
|
126
128
|
def set_current_state_with_persistence(state)
|
@@ -129,5 +131,14 @@ module AASM
|
|
129
131
|
save_success
|
130
132
|
end
|
131
133
|
|
134
|
+
private
|
135
|
+
|
136
|
+
def event_exists?(event_name, bang = false)
|
137
|
+
event = @instance.class.aasm(@name).state_machine.events[event_name.to_sym]
|
138
|
+
return true if event
|
139
|
+
|
140
|
+
event_error = bang ? "#{event_name}!" : event_name
|
141
|
+
raise AASM::UndefinedEvent, "Event :#{event_error} doesn't exist" if event.nil?
|
142
|
+
end
|
132
143
|
end
|
133
144
|
end
|
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
|
@@ -73,7 +73,7 @@ module AASM
|
|
73
73
|
rescue LoadError
|
74
74
|
warn <<-MSG
|
75
75
|
[DEPRECATION] :after_commit AASM callback is not safe in terms of race conditions and redundant calls.
|
76
|
-
Please add `gem 'after_commit_everywhere', '~>
|
76
|
+
Please add `gem 'after_commit_everywhere', '~> 1.0'` to your Gemfile in order to fix that.
|
77
77
|
MSG
|
78
78
|
yield
|
79
79
|
end
|
@@ -59,7 +59,9 @@ module AASM
|
|
59
59
|
# make sure to create a (named) scope for each state
|
60
60
|
def state_with_scope(*args)
|
61
61
|
names = state_without_scope(*args)
|
62
|
-
names.each
|
62
|
+
names.each do |name|
|
63
|
+
create_scopes(name)
|
64
|
+
end
|
63
65
|
end
|
64
66
|
alias_method :state_without_scope, :state
|
65
67
|
alias_method :state, :state_with_scope
|
@@ -71,7 +73,16 @@ module AASM
|
|
71
73
|
end
|
72
74
|
|
73
75
|
def create_scope(name)
|
74
|
-
@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)
|
75
86
|
end
|
76
87
|
end # Base
|
77
88
|
|
data/lib/aasm/version.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
class
|
1
|
+
class AasmCreate<%= table_name.camelize %> < ActiveRecord::Migration[<%= ActiveRecord::VERSION::STRING.to_f %>]
|
2
2
|
def change
|
3
3
|
create_table(:<%= table_name %>) do |t|
|
4
4
|
t.string :<%= column_name %>
|