aasm 5.1.0 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +0 -11
  3. data/Appraisals +5 -5
  4. data/CHANGELOG.md +17 -0
  5. data/README.md +78 -6
  6. data/aasm.gemspec +1 -1
  7. data/gemfiles/rails_4.2.gemfile +1 -1
  8. data/gemfiles/rails_4.2_mongoid_5.gemfile +1 -1
  9. data/gemfiles/rails_5.0.gemfile +1 -1
  10. data/gemfiles/rails_5.1.gemfile +1 -1
  11. data/gemfiles/rails_5.2.gemfile +1 -1
  12. data/lib/aasm/base.rb +30 -11
  13. data/lib/aasm/configuration.rb +3 -0
  14. data/lib/aasm/core/event.rb +7 -2
  15. data/lib/aasm/core/state.rb +6 -5
  16. data/lib/aasm/core/transition.rb +1 -1
  17. data/lib/aasm/dsl_helper.rb +24 -22
  18. data/lib/aasm/instance_base.rb +1 -1
  19. data/lib/aasm/localizer.rb +13 -3
  20. data/lib/aasm/persistence/active_record_persistence.rb +18 -13
  21. data/lib/aasm/persistence/base.rb +13 -2
  22. data/lib/aasm/persistence/orm.rb +1 -1
  23. data/lib/aasm/version.rb +1 -1
  24. data/lib/aasm.rb +0 -2
  25. data/spec/database.rb +9 -11
  26. data/spec/en.yml +0 -3
  27. data/spec/{en_deprecated_style.yml → localizer_test_model_deprecated_style.yml} +6 -3
  28. data/spec/localizer_test_model_new_style.yml +11 -0
  29. data/spec/models/active_record/localizer_test_model.rb +11 -3
  30. data/spec/models/active_record/namespaced.rb +16 -0
  31. data/spec/models/active_record/timestamp_example.rb +16 -0
  32. data/spec/models/default_state.rb +1 -1
  33. data/spec/models/mongoid/timestamp_example_mongoid.rb +20 -0
  34. data/spec/models/timestamps_example.rb +19 -0
  35. data/spec/models/timestamps_with_named_machine_example.rb +13 -0
  36. data/spec/spec_helper.rb +5 -0
  37. data/spec/unit/api_spec.rb +4 -0
  38. data/spec/unit/inspection_multiple_spec.rb +9 -5
  39. data/spec/unit/inspection_spec.rb +7 -3
  40. data/spec/unit/localizer_spec.rb +49 -18
  41. data/spec/unit/persistence/active_record_persistence_multiple_spec.rb +17 -0
  42. data/spec/unit/persistence/active_record_persistence_spec.rb +12 -0
  43. data/spec/unit/persistence/mongoid_persistence_spec.rb +12 -0
  44. data/spec/unit/state_spec.rb +21 -5
  45. data/spec/unit/timestamps_spec.rb +32 -0
  46. metadata +20 -12
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: be8ee23b312066a6b90211161857cb2c461f20e9b1e3e93f955d6b8caeb6f497
4
- data.tar.gz: 47c63523fc92f0fdc823024f632f27cab4453c4c2c9c7e277c45dea0f170250f
3
+ metadata.gz: 6e3ec7032fd9c8368ddfb4bed4e931edc5f9d96c02a69f89f7ee26913f7d8698
4
+ data.tar.gz: ddb4ef39501440da1869426eda3b4359e37eeef67b464c9e0d660e9f353510f6
5
5
  SHA512:
6
- metadata.gz: 258182cd645528de747eff39a70bcd697b5f965e49890ce369804aba0fb4c08739ff5259efef9cdde405b819765becb451ba4a6994f74dc89f0581c387d84ef1
7
- data.tar.gz: 9408e99df7783505a8a67d4d54b0d5f3660b991790db7bad46598734ed33d1d7f1b5e463f67d435c0de15d0d1ef020023f8900781a72a40bcc85c35d76c8cf22
6
+ metadata.gz: c294de071cad6569f855af1455c9d0281622ca5c9a3df0466baacaca569d8974718eb46d4c06e674f54629a77e2634d69829ee2910612ba146b4aaf786891544
7
+ data.tar.gz: a7b0c176cec262ad9d89538fe43e6df484f4d79328f85e853dcc9fe6b6ce9a9629f802e7de14659e5c91135a3a4df09a6066011983b1936eff06b17657c24cc5
data/.travis.yml CHANGED
@@ -12,7 +12,6 @@ before_install:
12
12
  - bundle _1.16.1_ install
13
13
 
14
14
  rvm:
15
- - 2.3.0
16
15
  - 2.5.0
17
16
  - 2.6.5
18
17
  - 2.7.0
@@ -47,16 +46,6 @@ script:
47
46
 
48
47
  matrix:
49
48
  exclude:
50
- - rvm: 2.3.0
51
- gemfile: gemfiles/norails.gemfile
52
- - rvm: 2.3.0
53
- gemfile: gemfiles/rails_5.0.gemfile
54
- # - rvm: 2.3.0
55
- # gemfile: gemfiles/rails_5.0_nobrainer.gemfile
56
- - rvm: 2.3.0
57
- gemfile: gemfiles/rails_5.1.gemfile
58
- - rvm: 2.3.0
59
- gemfile: gemfiles/rails_5.2.gemfile
60
49
  - rvm: 2.7.0
61
50
  gemfile: gemfiles/rails_5.2.gemfile
62
51
  - rvm: 2.6.5
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", "~> 0.1", ">= 0.1.5"
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", "~> 0.1", ">= 0.1.5"
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", "~> 0.1", ">= 0.1.5"
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", "~> 0.1", ">= 0.1.5"
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", "~> 0.1", ">= 0.1.5"
59
+ gem "after_commit_everywhere", "~> 1.0"
60
60
  end
61
61
 
62
62
  appraise 'norails' do
data/CHANGELOG.md CHANGED
@@ -1,6 +1,23 @@
1
1
  # CHANGELOG
2
2
 
3
3
  ## unreleased
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
17
+
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)
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)
20
+ * Remove support for ruby 2.3
4
21
 
5
22
  ## 5.1.0
6
23
 
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
- Also, you can pass parameters to events:
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 the `set_process` would be called with `:defragmentation` argument.
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,33 @@ 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
+
459
+ ### Display name for state
460
+
461
+ You can define display name for state using :display option
462
+
463
+ ```ruby
464
+ class Job
465
+ include AASM
466
+
467
+ aasm do
468
+ state :stage1, initial: true, display: 'First Stage'
469
+ state :stage2
470
+ state :stage3
471
+ end
472
+ end
473
+
474
+ job = Job.new
475
+ job.aasm.human_state
476
+
477
+ ```
437
478
 
438
479
  ### Multiple state machines per class
439
480
 
@@ -476,13 +517,13 @@ simple = SimpleMultipleExample.new
476
517
 
477
518
  simple.aasm(:move).current_state
478
519
  # => :standing
479
- simple.aasm(:work).current
520
+ simple.aasm(:work).current_state
480
521
  # => :sleeping
481
522
 
482
523
  simple.start
483
524
  simple.aasm(:move).current_state
484
525
  # => :standing
485
- simple.aasm(:work).current
526
+ simple.aasm(:work).current_state
486
527
  # => :processing
487
528
 
488
529
  ```
@@ -679,7 +720,7 @@ end
679
720
  AASM comes with support for ActiveRecord and allows automatic persisting of the object's
680
721
  state in the database.
681
722
 
682
- Add `gem 'after_commit_everywhere', '~> 0.1', '>= 0.1.5'` to your Gemfile
723
+ Add `gem 'after_commit_everywhere', '~> 1.0'` to your Gemfile.
683
724
 
684
725
  ```ruby
685
726
  class Job < ActiveRecord::Base
@@ -781,6 +822,37 @@ job.aasm_state = :running # => raises AASM::NoDirectAssignmentError
781
822
  job.aasm_state # => 'sleeping'
782
823
  ```
783
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
+
784
856
  #### ActiveRecord enums
785
857
 
786
858
  You can use
@@ -988,7 +1060,7 @@ job.save! #notify_about_running_job is not run
988
1060
  Please note that `:after_commit` AASM callbacks behaves around custom implementation
989
1061
  of transaction pattern rather than a real-life DB transaction. This fact still causes
990
1062
  the race conditions and redundant callback calls within nested transaction. In order
991
- to fix that it's highly recommended to add `gem 'after_commit_everywhere', '~> 0.1', '>= 0.1.5'`
1063
+ to fix that it's highly recommended to add `gem 'after_commit_everywhere', '~> 1.0'`
992
1064
  to your `Gemfile`.
993
1065
 
994
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.17", '< 0.1.20'
27
+ s.add_development_dependency "codecov", ">= 0.1.21"
28
28
 
29
29
  # debugging
30
30
  # s.add_development_dependency 'debugger'
@@ -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", "~> 0.1", ">= 0.1.5"
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", "~> 0.1", ">= 0.1.5"
10
+ gem "after_commit_everywhere", "~> 1.0"
11
11
 
12
12
  gemspec path: "../"
@@ -9,6 +9,6 @@ gem "sequel"
9
9
  gem "dynamoid", "~> 1.3", platforms: :ruby
10
10
  gem "aws-sdk", "~> 2", platforms: :ruby
11
11
  gem "redis-objects"
12
- gem "after_commit_everywhere", "~> 0.1", ">= 0.1.5"
12
+ gem "after_commit_everywhere", "~> 1.0"
13
13
 
14
14
  gemspec path: "../"
@@ -9,6 +9,6 @@ gem "sequel"
9
9
  gem "dynamoid", "~> 1.3", platforms: :ruby
10
10
  gem "aws-sdk", "~>2", platforms: :ruby
11
11
  gem "redis-objects"
12
- gem "after_commit_everywhere", "~> 0.1", ">= 0.1.5"
12
+ gem "after_commit_everywhere", "~> 1.0"
13
13
 
14
14
  gemspec path: "../"
@@ -9,6 +9,6 @@ gem "sequel"
9
9
  gem "dynamoid", "~>2.2", platforms: :ruby
10
10
  gem "aws-sdk", "~>2", platforms: :ruby
11
11
  gem "redis-objects"
12
- gem "after_commit_everywhere", "~> 0.1", ">= 0.1.5"
12
+ gem "after_commit_everywhere", "~> 1.0"
13
13
 
14
14
  gemspec path: "../"
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
- aasm_name = @name
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
@@ -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
 
@@ -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)
@@ -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 ||= begin
58
+ @display_name = begin
58
59
  if Module.const_defined?(:I18n)
59
60
  localized_name
60
61
  else
61
- name.to_s.gsub(/_/, ' ').capitalize
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) then
79
- @display_name = options.delete(:display)
79
+ if options.key?(:display)
80
+ @default_display_name = options.delete(:display)
80
81
  end
81
82
  @options = options
82
83
  self
@@ -2,7 +2,7 @@
2
2
 
3
3
  module AASM::Core
4
4
  class Transition
5
- include DslHelper
5
+ include AASM::DslHelper
6
6
 
7
7
  attr_reader :from, :to, :event, :opts, :failures
8
8
  alias_method :options, :opts
@@ -1,30 +1,32 @@
1
- module DslHelper
1
+ module AASM
2
+ module DslHelper
2
3
 
3
- class Proxy
4
- attr_accessor :options
4
+ class Proxy
5
+ attr_accessor :options
5
6
 
6
- def initialize(options, valid_keys, source)
7
- @valid_keys = valid_keys
8
- @source = source
7
+ def initialize(options, valid_keys, source)
8
+ @valid_keys = valid_keys
9
+ @source = source
9
10
 
10
- @options = options
11
- end
11
+ @options = options
12
+ end
12
13
 
13
- def method_missing(name, *args, &block)
14
- if @valid_keys.include?(name)
15
- options[name] = Array(options[name])
16
- options[name] << block if block
17
- options[name] += Array(args)
18
- else
19
- @source.send name, *args, &block
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
- def add_options_from_dsl(options, valid_keys, &block)
25
- proxy = Proxy.new(options, valid_keys, self)
26
- proxy.instance_eval(&block)
27
- proxy.options
28
- end
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
@@ -28,7 +28,7 @@ module AASM
28
28
  end
29
29
 
30
30
  def human_state
31
- AASM::Localizer.new.human_state_name(@instance.class, state_object_for_name(current_state))
31
+ state_object_for_name(current_state).display_name
32
32
  end
33
33
 
34
34
  def states(options={}, *args)
@@ -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.to_s.humanize)
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.to_s.humanize)
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
- ancestor.respond_to?(:model_name) unless ancestor.name == 'ActiveRecord::Base'
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
@@ -28,19 +28,6 @@ module AASM
28
28
  # end
29
29
  #
30
30
  def self.included(base)
31
- begin
32
- require 'after_commit_everywhere'
33
- raise LoadError unless Gem::Version.new(::AfterCommitEverywhere::VERSION) >= Gem::Version.new('0.1.5')
34
-
35
- base.send(:include, ::AfterCommitEverywhere) unless base.include?(::AfterCommitEverywhere)
36
- base.send(:alias_method, :aasm_execute_after_commit, :after_commit)
37
- rescue LoadError
38
- warn <<-MSG
39
- [DEPRECATION] :after_commit AASM callback is not safe in terms of race conditions and redundant calls.
40
- Please add `gem 'after_commit_everywhere', '~> 0.1', '>= 0.1.5'` to your Gemfile in order to fix that.
41
- MSG
42
- end
43
-
44
31
  base.send(:include, AASM::Persistence::Base)
45
32
  base.send(:include, AASM::Persistence::ORM)
46
33
  base.send(:include, AASM::Persistence::ActiveRecordPersistence::InstanceMethods)
@@ -74,6 +61,24 @@ module AASM
74
61
 
75
62
  private
76
63
 
64
+ def aasm_execute_after_commit
65
+ begin
66
+ require 'after_commit_everywhere'
67
+ raise LoadError unless Gem::Version.new(::AfterCommitEverywhere::VERSION) >= Gem::Version.new('0.1.5')
68
+
69
+ self.extend ::AfterCommitEverywhere
70
+ after_commit do
71
+ yield
72
+ end
73
+ rescue LoadError
74
+ warn <<-MSG
75
+ [DEPRECATION] :after_commit AASM callback is not safe in terms of race conditions and redundant calls.
76
+ Please add `gem 'after_commit_everywhere', '~> 1.0'` to your Gemfile in order to fix that.
77
+ MSG
78
+ yield
79
+ end
80
+ end
81
+
77
82
  def aasm_raise_invalid_record
78
83
  raise ActiveRecord::RecordInvalid.new(self)
79
84
  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 { |name| create_scope(name) if create_scope?(name) }
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
 
@@ -135,7 +135,7 @@ module AASM
135
135
  super
136
136
  end
137
137
 
138
- if success
138
+ if success && !(event.options.keys & [:after_commit, :after_all_commits]).empty?
139
139
  aasm_execute_after_commit do
140
140
  event.fire_callbacks(:after_commit, self, *args)
141
141
  event.fire_global_callbacks(:after_all_commits, self, *args)
data/lib/aasm/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module AASM
2
- VERSION = "5.1.0"
2
+ VERSION = "5.2.0"
3
3
  end
data/lib/aasm.rb CHANGED
@@ -1,5 +1,3 @@
1
- require 'ostruct'
2
-
3
1
  require 'aasm/version'
4
2
  require 'aasm/errors'
5
3
  require 'aasm/configuration'