aasm 5.1.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 +4 -4
- data/Appraisals +5 -5
- data/CHANGELOG.md +13 -2
- data/README.md +59 -6
- data/aasm.gemspec +1 -1
- data/gemfiles/rails_4.2.gemfile +1 -1
- data/gemfiles/rails_4.2_mongoid_5.gemfile +1 -1
- data/gemfiles/rails_5.0.gemfile +1 -1
- data/gemfiles/rails_5.1.gemfile +1 -1
- data/gemfiles/rails_5.2.gemfile +1 -1
- data/lib/aasm/base.rb +30 -11
- data/lib/aasm/configuration.rb +3 -0
- data/lib/aasm/core/event.rb +7 -2
- 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/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/spec/database.rb +9 -11
- data/spec/localizer_test_model_deprecated_style.yml +7 -0
- data/spec/localizer_test_model_new_style.yml +6 -0
- data/spec/models/active_record/localizer_test_model.rb +8 -0
- data/spec/models/active_record/namespaced.rb +16 -0
- data/spec/models/active_record/timestamp_example.rb +16 -0
- data/spec/models/mongoid/timestamp_example_mongoid.rb +20 -0
- data/spec/models/timestamps_example.rb +19 -0
- data/spec/models/timestamps_with_named_machine_example.rb +13 -0
- data/spec/unit/localizer_spec.rb +40 -8
- data/spec/unit/persistence/active_record_persistence_multiple_spec.rb +17 -0
- data/spec/unit/persistence/active_record_persistence_spec.rb +12 -0
- data/spec/unit/persistence/mongoid_persistence_spec.rb +12 -0
- data/spec/unit/timestamps_spec.rb +32 -0
- metadata +16 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6e3ec7032fd9c8368ddfb4bed4e931edc5f9d96c02a69f89f7ee26913f7d8698
|
4
|
+
data.tar.gz: ddb4ef39501440da1869426eda3b4359e37eeef67b464c9e0d660e9f353510f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c294de071cad6569f855af1455c9d0281622ca5c9a3df0466baacaca569d8974718eb46d4c06e674f54629a77e2634d69829ee2910612ba146b4aaf786891544
|
7
|
+
data.tar.gz: a7b0c176cec262ad9d89538fe43e6df484f4d79328f85e853dcc9fe6b6ce9a9629f802e7de14659e5c91135a3a4df09a6066011983b1936eff06b17657c24cc5
|
data/Appraisals
CHANGED
@@ -8,7 +8,7 @@ appraise 'rails_4.2' do
|
|
8
8
|
gem 'aws-sdk', '~> 2', platforms: :ruby
|
9
9
|
gem 'redis-objects'
|
10
10
|
gem 'activerecord-jdbcsqlite3-adapter', '1.3.24', platforms: :jruby
|
11
|
-
gem "after_commit_everywhere", "~>
|
11
|
+
gem "after_commit_everywhere", "~> 1.0"
|
12
12
|
end
|
13
13
|
|
14
14
|
appraise 'rails_4.2_nobrainer' do
|
@@ -21,7 +21,7 @@ appraise 'rails_4.2_mongoid_5' do
|
|
21
21
|
gem 'rails', '4.2.5'
|
22
22
|
gem 'mongoid', '~> 5.0'
|
23
23
|
gem 'activerecord-jdbcsqlite3-adapter', '1.3.24', platforms: :jruby
|
24
|
-
gem "after_commit_everywhere", "~>
|
24
|
+
gem "after_commit_everywhere", "~> 1.0"
|
25
25
|
end
|
26
26
|
|
27
27
|
appraise 'rails_5.0' do
|
@@ -31,7 +31,7 @@ appraise 'rails_5.0' do
|
|
31
31
|
gem 'dynamoid', '~> 1.3', platforms: :ruby
|
32
32
|
gem 'aws-sdk', '~> 2', platforms: :ruby
|
33
33
|
gem 'redis-objects'
|
34
|
-
gem "after_commit_everywhere", "~>
|
34
|
+
gem "after_commit_everywhere", "~> 1.0"
|
35
35
|
end
|
36
36
|
|
37
37
|
appraise 'rails_5.0_nobrainer' do
|
@@ -46,7 +46,7 @@ appraise 'rails_5.1' do
|
|
46
46
|
gem 'dynamoid', '~> 1.3', platforms: :ruby
|
47
47
|
gem 'aws-sdk', '~>2', platforms: :ruby
|
48
48
|
gem 'redis-objects'
|
49
|
-
gem "after_commit_everywhere", "~>
|
49
|
+
gem "after_commit_everywhere", "~> 1.0"
|
50
50
|
end
|
51
51
|
|
52
52
|
appraise 'rails_5.2' do
|
@@ -56,7 +56,7 @@ appraise 'rails_5.2' do
|
|
56
56
|
gem 'dynamoid', '~>2.2', platforms: :ruby
|
57
57
|
gem 'aws-sdk', '~>2', platforms: :ruby
|
58
58
|
gem 'redis-objects'
|
59
|
-
gem "after_commit_everywhere", "~>
|
59
|
+
gem "after_commit_everywhere", "~> 1.0"
|
60
60
|
end
|
61
61
|
|
62
62
|
appraise 'norails' do
|
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,19 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
3
|
## unreleased
|
4
|
-
|
5
|
-
|
4
|
+
## 5.2.0
|
5
|
+
|
6
|
+
* fix: timestamp will work with named machine [#739](https://github.com/aasm/aasm/pull/739), thanks to [RolandStuder](https://github.com/RolandStuder)
|
7
|
+
* Create namespaced scopes in PR [#735](https://github.com/aasm/aasm/pull/735), thanks to [caiohsramos](https://github.com/caiohsramos)
|
8
|
+
* Fix multiple state machines example per class on README in PR [#732](https://github.com/aasm/aasm/pull/732), thanks to [RodrigoVitiello](https://github.com/RodrigoVitiello)
|
9
|
+
* Update version in recommendation to add after_commit_everywhere in PR [#729](https://github.com/aasm/aasm/pull/729), thanks to [Envek](https://github.com/Envek)
|
10
|
+
* Fix i18n Event translations failing [#721](https://github.com/aasm/aasm/issues/721) in PR [#723](https://github.com/aasm/aasm/pull/723), thanks to [the-spectator](https://github.com/the-spectator)
|
11
|
+
* Add documentation to the Readme about how parameters are handled in AASM events in PR [#722](https://github.com/aasm/aasm/pull/722), thanks to [dstuebe](https://github.com/dstuebe)
|
12
|
+
* Fix human_state cached across locales [#709](https://github.com/aasm/aasm/issues/709) in PR [716](https://github.com/aasm/aasm/pull/716), thanks to [the-spectator](https://github.com/the-spectator)
|
13
|
+
* Relocate DslHelper from root namespace to under AASM namespace in PR [#711](https://github.com/aasm/aasm/pull/711) thank to [yujideveloper ](https://github.com/yujideveloper )
|
14
|
+
* Document how to define transitions from any state in in PR [#699](https://github.com/aasm/aasm/pull/699) thanks to [hedgesky](https://github.com/hedgesky)
|
15
|
+
* Add simple option for auto-generated timestamps in PR [#677](https://github.com/aasm/aasm/pull/677), thanks to [jaynetics](https://github.com/jaynetics)
|
16
|
+
## 5.1.1
|
6
17
|
|
7
18
|
* Fix Depreciation message for after_commit_everywhere [#695](https://github.com/aasm/aasm/issues/695) in PR [#696](https://github.com/aasm/aasm/pull/696)
|
8
19
|
* Fix human_state to use display option [#684](https://github.com/aasm/aasm/issues/684) in PR [#697](https://github.com/aasm/aasm/pull/697)
|
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 gaurds 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
|
|
@@ -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
|
@@ -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
|
data/aasm.gemspec
CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |s|
|
|
24
24
|
s.add_development_dependency 'generator_spec'
|
25
25
|
s.add_development_dependency 'appraisal'
|
26
26
|
s.add_development_dependency "simplecov"
|
27
|
-
s.add_development_dependency "codecov", ">= 0.1.
|
27
|
+
s.add_development_dependency "codecov", ">= 0.1.21"
|
28
28
|
|
29
29
|
# debugging
|
30
30
|
# s.add_development_dependency 'debugger'
|
data/gemfiles/rails_4.2.gemfile
CHANGED
@@ -12,6 +12,6 @@ gem "dynamoid", "~> 1", platforms: :ruby
|
|
12
12
|
gem "aws-sdk", "~> 2", platforms: :ruby
|
13
13
|
gem "redis-objects"
|
14
14
|
gem "activerecord-jdbcsqlite3-adapter", "1.3.24", platforms: :jruby
|
15
|
-
gem "after_commit_everywhere", "~>
|
15
|
+
gem "after_commit_everywhere", "~> 1.0"
|
16
16
|
|
17
17
|
gemspec path: "../"
|
@@ -7,6 +7,6 @@ gem "rails", "4.2.5"
|
|
7
7
|
gem "mime-types", "~> 2", platforms: [:ruby_19, :jruby]
|
8
8
|
gem "mongoid", "~> 5.0"
|
9
9
|
gem "activerecord-jdbcsqlite3-adapter", "1.3.24", platforms: :jruby
|
10
|
-
gem "after_commit_everywhere", "~>
|
10
|
+
gem "after_commit_everywhere", "~> 1.0"
|
11
11
|
|
12
12
|
gemspec path: "../"
|
data/gemfiles/rails_5.0.gemfile
CHANGED
data/gemfiles/rails_5.1.gemfile
CHANGED
data/gemfiles/rails_5.2.gemfile
CHANGED
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
|
@@ -267,5 +263,28 @@ module AASM
|
|
267
263
|
end
|
268
264
|
end
|
269
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
|
+
|
270
289
|
end
|
271
290
|
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,9 +2,9 @@
|
|
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
|
@@ -13,6 +13,7 @@ module AASM::Core
|
|
13
13
|
@valid_transitions = {}
|
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 ?
|
@@ -109,6 +110,10 @@ module AASM::Core
|
|
109
110
|
transitions.flat_map(&:failures)
|
110
111
|
end
|
111
112
|
|
113
|
+
def to_s
|
114
|
+
name.to_s
|
115
|
+
end
|
116
|
+
|
112
117
|
private
|
113
118
|
|
114
119
|
def attach_event_guards(definitions)
|
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/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
data/spec/database.rb
CHANGED
@@ -5,17 +5,10 @@ ActiveRecord::Migration.suppress_messages do
|
|
5
5
|
end
|
6
6
|
end
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
t.string "status"
|
13
|
-
end
|
14
|
-
ActiveRecord::Migration.create_table "implemented_abstract_class_dsls", :force => true do |t|
|
15
|
-
t.string "status"
|
16
|
-
end
|
17
|
-
ActiveRecord::Migration.create_table "users", :force => true do |t|
|
18
|
-
t.string "status"
|
8
|
+
%w(simple_new_dsls multiple_simple_new_dsls implemented_abstract_class_dsls users multiple_namespaceds).each do |table_name|
|
9
|
+
ActiveRecord::Migration.create_table table_name, :force => true do |t|
|
10
|
+
t.string "status"
|
11
|
+
end
|
19
12
|
end
|
20
13
|
|
21
14
|
ActiveRecord::Migration.create_table "complex_active_record_examples", :force => true do |t|
|
@@ -56,4 +49,9 @@ ActiveRecord::Migration.suppress_messages do
|
|
56
49
|
t.string "state"
|
57
50
|
t.string "some_string"
|
58
51
|
end
|
52
|
+
|
53
|
+
ActiveRecord::Migration.create_table "timestamp_examples", :force => true do |t|
|
54
|
+
t.string "aasm_state"
|
55
|
+
t.datetime "opened_at"
|
56
|
+
end
|
59
57
|
end
|
@@ -24,11 +24,19 @@ describe 'localized state names' do
|
|
24
24
|
state = LocalizerTestModel.aasm.states.detect {|s| s == :opened}
|
25
25
|
expect(state.localized_name).to eq("It's open now!")
|
26
26
|
expect(state.human_name).to eq("It's open now!")
|
27
|
+
expect(state.display_name).to eq("It's open now!")
|
28
|
+
|
29
|
+
I18n.with_locale(:fr) do
|
30
|
+
expect(state.localized_name).to eq("C'est ouvert maintenant!")
|
31
|
+
expect(state.human_name).to eq("C'est ouvert maintenant!")
|
32
|
+
expect(state.display_name).to eq("C'est ouvert maintenant!")
|
33
|
+
end
|
27
34
|
end
|
28
35
|
|
29
36
|
it 'should use fallback' do
|
30
37
|
state = LocalizerTestModel.aasm.states.detect {|s| s == :closed}
|
31
38
|
expect(state.localized_name).to eq('Closed')
|
32
39
|
expect(state.human_name).to eq('Closed')
|
40
|
+
expect(state.display_name).to eq('Closed')
|
33
41
|
end
|
34
42
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class MultipleNamespaced < ActiveRecord::Base
|
2
|
+
include AASM
|
3
|
+
|
4
|
+
aasm(:status, namespace: :car) do
|
5
|
+
state :unsold, initial: true
|
6
|
+
state :sold
|
7
|
+
|
8
|
+
event :sell do
|
9
|
+
transitions from: :unsold, to: :sold
|
10
|
+
end
|
11
|
+
|
12
|
+
event :return do
|
13
|
+
transitions from: :sold, to: :unsold
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class TimestampExample < ActiveRecord::Base
|
2
|
+
include AASM
|
3
|
+
|
4
|
+
aasm column: :aasm_state, timestamps: true do
|
5
|
+
state :opened
|
6
|
+
state :closed
|
7
|
+
|
8
|
+
event :open do
|
9
|
+
transitions to: :opened
|
10
|
+
end
|
11
|
+
|
12
|
+
event :close do
|
13
|
+
transitions to: :closed
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class TimestampExampleMongoid
|
2
|
+
include Mongoid::Document
|
3
|
+
include AASM
|
4
|
+
|
5
|
+
field :status, type: String
|
6
|
+
field :opened_at, type: Time
|
7
|
+
|
8
|
+
aasm column: :status, timestamps: true do
|
9
|
+
state :opened
|
10
|
+
state :closed
|
11
|
+
|
12
|
+
event :open do
|
13
|
+
transitions to: :opened
|
14
|
+
end
|
15
|
+
|
16
|
+
event :close do
|
17
|
+
transitions to: :closed
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class TimestampsExample
|
2
|
+
include AASM
|
3
|
+
|
4
|
+
attr_accessor :opened_at
|
5
|
+
attr_reader :closed_at
|
6
|
+
|
7
|
+
aasm timestamps: true do
|
8
|
+
state :opened
|
9
|
+
state :closed
|
10
|
+
|
11
|
+
event :open do
|
12
|
+
transitions to: :opened
|
13
|
+
end
|
14
|
+
|
15
|
+
event :close do
|
16
|
+
transitions to: :closed
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/spec/unit/localizer_spec.rb
CHANGED
@@ -29,12 +29,28 @@ if defined?(ActiveRecord)
|
|
29
29
|
end
|
30
30
|
|
31
31
|
context 'aasm.human_event_name' do
|
32
|
-
|
33
|
-
|
32
|
+
context 'with event name' do
|
33
|
+
it 'should return translated event name' do
|
34
|
+
expect(LocalizerTestModel.aasm.human_event_name(:close)).to eq("Let's close it!")
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should return humanized event name' do
|
38
|
+
expect(LocalizerTestModel.aasm.human_event_name(:open)).to eq("Open")
|
39
|
+
end
|
34
40
|
end
|
35
41
|
|
36
|
-
|
37
|
-
|
42
|
+
context 'with event object' do
|
43
|
+
it 'should return translated event name' do
|
44
|
+
event = LocalizerTestModel.aasm.events.detect { |e| e.name == :close }
|
45
|
+
|
46
|
+
expect(LocalizerTestModel.aasm.human_event_name(event)).to eq("Let's close it!")
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should return humanized event name' do
|
50
|
+
event = LocalizerTestModel.aasm.events.detect { |e| e.name == :open }
|
51
|
+
|
52
|
+
expect(LocalizerTestModel.aasm.human_event_name(event)).to eq("Open")
|
53
|
+
end
|
38
54
|
end
|
39
55
|
end
|
40
56
|
end
|
@@ -65,12 +81,28 @@ if defined?(ActiveRecord)
|
|
65
81
|
end
|
66
82
|
|
67
83
|
context 'aasm.human_event_name' do
|
68
|
-
|
69
|
-
|
84
|
+
context 'with event name' do
|
85
|
+
it 'should return translated event name' do
|
86
|
+
expect(LocalizerTestModel.aasm.human_event_name(:close)).to eq("Let's close it!")
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should return humanized event name' do
|
90
|
+
expect(LocalizerTestModel.aasm.human_event_name(:open)).to eq("Open")
|
91
|
+
end
|
70
92
|
end
|
71
93
|
|
72
|
-
|
73
|
-
|
94
|
+
context 'with event object' do
|
95
|
+
it 'should return translated event name' do
|
96
|
+
event = LocalizerTestModel.aasm.events.detect { |e| e.name == :close }
|
97
|
+
|
98
|
+
expect(LocalizerTestModel.aasm.human_event_name(event)).to eq("Let's close it!")
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'should return humanized event name' do
|
102
|
+
event = LocalizerTestModel.aasm.events.detect { |e| e.name == :open }
|
103
|
+
|
104
|
+
expect(LocalizerTestModel.aasm.human_event_name(event)).to eq("Open")
|
105
|
+
end
|
74
106
|
end
|
75
107
|
end
|
76
108
|
end
|
@@ -331,6 +331,23 @@ if defined?(ActiveRecord)
|
|
331
331
|
expect(MultipleSimpleNewDsl.unknown_scope).to contain_exactly(dsl2)
|
332
332
|
end
|
333
333
|
end
|
334
|
+
|
335
|
+
context "when namespeced" do
|
336
|
+
it "add namespaced scopes" do
|
337
|
+
expect(MultipleNamespaced).to respond_to(:car_unsold)
|
338
|
+
expect(MultipleNamespaced).to respond_to(:car_sold)
|
339
|
+
|
340
|
+
expect(MultipleNamespaced.car_unsold.is_a?(ActiveRecord::Relation)).to be_truthy
|
341
|
+
expect(MultipleNamespaced.car_sold.is_a?(ActiveRecord::Relation)).to be_truthy
|
342
|
+
end
|
343
|
+
it "add unnamespaced scopes" do
|
344
|
+
expect(MultipleNamespaced).to respond_to(:unsold)
|
345
|
+
expect(MultipleNamespaced).to respond_to(:sold)
|
346
|
+
|
347
|
+
expect(MultipleNamespaced.unsold.is_a?(ActiveRecord::Relation)).to be_truthy
|
348
|
+
expect(MultipleNamespaced.sold.is_a?(ActiveRecord::Relation)).to be_truthy
|
349
|
+
end
|
350
|
+
end
|
334
351
|
end # scopes
|
335
352
|
|
336
353
|
describe "direct assignment" do
|
@@ -837,4 +837,16 @@ if defined?(ActiveRecord)
|
|
837
837
|
expect(example.complete!).to be_falsey
|
838
838
|
end
|
839
839
|
end
|
840
|
+
|
841
|
+
describe 'testing the timestamps option' do
|
842
|
+
let(:example) { TimestampExample.create! }
|
843
|
+
|
844
|
+
it 'should update existing timestamp columns' do
|
845
|
+
expect { example.open! }.to change { example.reload.opened_at }.from(nil).to(instance_of(::Time))
|
846
|
+
end
|
847
|
+
|
848
|
+
it 'should not fail if there is no corresponding timestamp column' do
|
849
|
+
expect { example.close! }.to change { example.reload.aasm_state }
|
850
|
+
end
|
851
|
+
end
|
840
852
|
end
|
@@ -161,5 +161,17 @@ if defined?(Mongoid::Document)
|
|
161
161
|
end
|
162
162
|
end
|
163
163
|
|
164
|
+
describe 'testing the timestamps option' do
|
165
|
+
let(:example) { TimestampExampleMongoid.create }
|
166
|
+
|
167
|
+
it 'should update existing timestamp fields' do
|
168
|
+
expect { example.open! }.to change { example.reload.opened_at }.from(nil).to(instance_of(::Time))
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'should not fail if there is no corresponding timestamp field' do
|
172
|
+
expect { example.close! }.to change { example.reload.status }
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
164
176
|
end
|
165
177
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'timestamps option' do
|
4
|
+
it 'calls a timestamp setter based on the state name when entering a new state' do
|
5
|
+
object = TimestampsExample.new
|
6
|
+
expect { object.open }.to change { object.opened_at }.from(nil).to(instance_of(::Time))
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'overwrites any previous timestamp if a state is entered repeatedly' do
|
10
|
+
object = TimestampsExample.new
|
11
|
+
object.opened_at = ::Time.new(2000, 1, 1)
|
12
|
+
expect { object.open }.to change { object.opened_at }
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'does nothing if there is no setter matching the new state' do
|
16
|
+
object = TimestampsExample.new
|
17
|
+
expect { object.close }.not_to change { object.closed_at }
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'can be turned off and on' do
|
21
|
+
object = TimestampsExample.new
|
22
|
+
object.class.aasm.state_machine.config.timestamps = false
|
23
|
+
expect { object.open }.not_to change { object.opened_at }
|
24
|
+
object.class.aasm.state_machine.config.timestamps = true
|
25
|
+
expect { object.open }.to change { object.opened_at }
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'calls a timestamp setter when using a named state machine' do
|
29
|
+
object = TimestampsWithNamedMachineExample.new
|
30
|
+
expect { object.open }.to change { object.opened_at }.from(nil).to(instance_of(::Time))
|
31
|
+
end
|
32
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aasm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thorsten Boettger
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2021-05-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: concurrent-ruby
|
@@ -115,20 +115,14 @@ dependencies:
|
|
115
115
|
requirements:
|
116
116
|
- - ">="
|
117
117
|
- !ruby/object:Gem::Version
|
118
|
-
version: 0.1.
|
119
|
-
- - "<"
|
120
|
-
- !ruby/object:Gem::Version
|
121
|
-
version: 0.1.20
|
118
|
+
version: 0.1.21
|
122
119
|
type: :development
|
123
120
|
prerelease: false
|
124
121
|
version_requirements: !ruby/object:Gem::Requirement
|
125
122
|
requirements:
|
126
123
|
- - ">="
|
127
124
|
- !ruby/object:Gem::Version
|
128
|
-
version: 0.1.
|
129
|
-
- - "<"
|
130
|
-
- !ruby/object:Gem::Version
|
131
|
-
version: 0.1.20
|
125
|
+
version: 0.1.21
|
132
126
|
- !ruby/object:Gem::Dependency
|
133
127
|
name: pry
|
134
128
|
requirement: !ruby/object:Gem::Requirement
|
@@ -246,6 +240,7 @@ files:
|
|
246
240
|
- spec/models/active_record/instance_level_skip_validation_example.rb
|
247
241
|
- spec/models/active_record/invalid_persistor.rb
|
248
242
|
- spec/models/active_record/localizer_test_model.rb
|
243
|
+
- spec/models/active_record/namespaced.rb
|
249
244
|
- spec/models/active_record/no_direct_assignment.rb
|
250
245
|
- spec/models/active_record/no_scope.rb
|
251
246
|
- spec/models/active_record/persisted_state.rb
|
@@ -256,6 +251,7 @@ files:
|
|
256
251
|
- spec/models/active_record/silent_persistor.rb
|
257
252
|
- spec/models/active_record/simple_new_dsl.rb
|
258
253
|
- spec/models/active_record/thief.rb
|
254
|
+
- spec/models/active_record/timestamp_example.rb
|
259
255
|
- spec/models/active_record/transactor.rb
|
260
256
|
- spec/models/active_record/transient.rb
|
261
257
|
- spec/models/active_record/validator.rb
|
@@ -302,6 +298,7 @@ files:
|
|
302
298
|
- spec/models/mongoid/silent_persistor_mongoid.rb
|
303
299
|
- spec/models/mongoid/simple_mongoid.rb
|
304
300
|
- spec/models/mongoid/simple_new_dsl_mongoid.rb
|
301
|
+
- spec/models/mongoid/timestamp_example_mongoid.rb
|
305
302
|
- spec/models/mongoid/validator_mongoid.rb
|
306
303
|
- spec/models/multi_transitioner.rb
|
307
304
|
- spec/models/multiple_transitions_that_differ_only_by_guard.rb
|
@@ -343,6 +340,8 @@ files:
|
|
343
340
|
- spec/models/sub_classing.rb
|
344
341
|
- spec/models/super_class.rb
|
345
342
|
- spec/models/this_name_better_not_be_in_use.rb
|
343
|
+
- spec/models/timestamps_example.rb
|
344
|
+
- spec/models/timestamps_with_named_machine_example.rb
|
346
345
|
- spec/models/valid_state_name.rb
|
347
346
|
- spec/spec_helper.rb
|
348
347
|
- spec/spec_helpers/active_record.rb
|
@@ -407,6 +406,7 @@ files:
|
|
407
406
|
- spec/unit/states_on_one_line_example_spec.rb
|
408
407
|
- spec/unit/subclassing_multiple_spec.rb
|
409
408
|
- spec/unit/subclassing_spec.rb
|
409
|
+
- spec/unit/timestamps_spec.rb
|
410
410
|
- spec/unit/transition_spec.rb
|
411
411
|
- test/minitest_helper.rb
|
412
412
|
- test/unit/minitest_matcher_test.rb
|
@@ -451,6 +451,7 @@ test_files:
|
|
451
451
|
- spec/models/active_record/instance_level_skip_validation_example.rb
|
452
452
|
- spec/models/active_record/invalid_persistor.rb
|
453
453
|
- spec/models/active_record/localizer_test_model.rb
|
454
|
+
- spec/models/active_record/namespaced.rb
|
454
455
|
- spec/models/active_record/no_direct_assignment.rb
|
455
456
|
- spec/models/active_record/no_scope.rb
|
456
457
|
- spec/models/active_record/persisted_state.rb
|
@@ -461,6 +462,7 @@ test_files:
|
|
461
462
|
- spec/models/active_record/silent_persistor.rb
|
462
463
|
- spec/models/active_record/simple_new_dsl.rb
|
463
464
|
- spec/models/active_record/thief.rb
|
465
|
+
- spec/models/active_record/timestamp_example.rb
|
464
466
|
- spec/models/active_record/transactor.rb
|
465
467
|
- spec/models/active_record/transient.rb
|
466
468
|
- spec/models/active_record/validator.rb
|
@@ -507,6 +509,7 @@ test_files:
|
|
507
509
|
- spec/models/mongoid/silent_persistor_mongoid.rb
|
508
510
|
- spec/models/mongoid/simple_mongoid.rb
|
509
511
|
- spec/models/mongoid/simple_new_dsl_mongoid.rb
|
512
|
+
- spec/models/mongoid/timestamp_example_mongoid.rb
|
510
513
|
- spec/models/mongoid/validator_mongoid.rb
|
511
514
|
- spec/models/multi_transitioner.rb
|
512
515
|
- spec/models/multiple_transitions_that_differ_only_by_guard.rb
|
@@ -548,6 +551,8 @@ test_files:
|
|
548
551
|
- spec/models/sub_classing.rb
|
549
552
|
- spec/models/super_class.rb
|
550
553
|
- spec/models/this_name_better_not_be_in_use.rb
|
554
|
+
- spec/models/timestamps_example.rb
|
555
|
+
- spec/models/timestamps_with_named_machine_example.rb
|
551
556
|
- spec/models/valid_state_name.rb
|
552
557
|
- spec/spec_helper.rb
|
553
558
|
- spec/spec_helpers/active_record.rb
|
@@ -612,6 +617,7 @@ test_files:
|
|
612
617
|
- spec/unit/states_on_one_line_example_spec.rb
|
613
618
|
- spec/unit/subclassing_multiple_spec.rb
|
614
619
|
- spec/unit/subclassing_spec.rb
|
620
|
+
- spec/unit/timestamps_spec.rb
|
615
621
|
- spec/unit/transition_spec.rb
|
616
622
|
- test/minitest_helper.rb
|
617
623
|
- test/unit/minitest_matcher_test.rb
|