aasm 4.12.3 → 5.1.1

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.
Files changed (114) hide show
  1. checksums.yaml +5 -5
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +27 -0
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  4. data/.travis.yml +48 -18
  5. data/Appraisals +50 -26
  6. data/CHANGELOG.md +75 -3
  7. data/Dockerfile +44 -0
  8. data/Gemfile +2 -3
  9. data/README.md +216 -110
  10. data/aasm.gemspec +2 -0
  11. data/docker-compose.yml +40 -0
  12. data/gemfiles/norails.gemfile +10 -0
  13. data/gemfiles/rails_4.2.gemfile +9 -8
  14. data/gemfiles/rails_4.2_mongoid_5.gemfile +6 -5
  15. data/gemfiles/rails_4.2_nobrainer.gemfile +9 -0
  16. data/gemfiles/rails_5.0.gemfile +6 -6
  17. data/gemfiles/rails_5.0_nobrainer.gemfile +9 -0
  18. data/gemfiles/rails_5.1.gemfile +14 -0
  19. data/gemfiles/rails_5.2.gemfile +14 -0
  20. data/lib/aasm.rb +5 -2
  21. data/lib/aasm/aasm.rb +30 -27
  22. data/lib/aasm/base.rb +25 -7
  23. data/lib/aasm/core/event.rb +14 -24
  24. data/lib/aasm/core/invoker.rb +129 -0
  25. data/lib/aasm/core/invokers/base_invoker.rb +75 -0
  26. data/lib/aasm/core/invokers/class_invoker.rb +52 -0
  27. data/lib/aasm/core/invokers/literal_invoker.rb +47 -0
  28. data/lib/aasm/core/invokers/proc_invoker.rb +59 -0
  29. data/lib/aasm/core/state.rb +10 -9
  30. data/lib/aasm/core/transition.rb +7 -68
  31. data/lib/aasm/errors.rb +4 -3
  32. data/lib/aasm/instance_base.rb +16 -4
  33. data/lib/aasm/persistence.rb +3 -0
  34. data/lib/aasm/persistence/active_record_persistence.rb +25 -5
  35. data/lib/aasm/persistence/base.rb +1 -1
  36. data/lib/aasm/persistence/core_data_query_persistence.rb +2 -1
  37. data/lib/aasm/persistence/dynamoid_persistence.rb +1 -1
  38. data/lib/aasm/persistence/mongoid_persistence.rb +1 -1
  39. data/lib/aasm/persistence/no_brainer_persistence.rb +105 -0
  40. data/lib/aasm/persistence/orm.rb +23 -19
  41. data/lib/aasm/persistence/plain_persistence.rb +2 -1
  42. data/lib/aasm/persistence/redis_persistence.rb +1 -1
  43. data/lib/aasm/persistence/sequel_persistence.rb +0 -1
  44. data/lib/aasm/rspec/allow_event.rb +5 -1
  45. data/lib/aasm/rspec/allow_transition_to.rb +5 -1
  46. data/lib/aasm/rspec/transition_from.rb +5 -1
  47. data/lib/aasm/version.rb +1 -1
  48. data/lib/generators/aasm/orm_helpers.rb +6 -0
  49. data/lib/generators/active_record/aasm_generator.rb +3 -1
  50. data/lib/generators/nobrainer/aasm_generator.rb +28 -0
  51. data/lib/motion-aasm.rb +1 -0
  52. data/spec/database.rb +16 -1
  53. data/spec/en.yml +0 -3
  54. data/spec/generators/active_record_generator_spec.rb +6 -0
  55. data/spec/generators/no_brainer_generator_spec.rb +29 -0
  56. data/spec/{en_deprecated_style.yml → localizer_test_model_deprecated_style.yml} +0 -4
  57. data/spec/localizer_test_model_new_style.yml +5 -0
  58. data/spec/models/active_record/active_record_callback.rb +93 -0
  59. data/spec/models/active_record/instance_level_skip_validation_example.rb +19 -0
  60. data/spec/models/active_record/localizer_test_model.rb +3 -3
  61. data/spec/models/active_record/person.rb +23 -0
  62. data/spec/models/active_record/simple_new_dsl.rb +15 -0
  63. data/spec/models/active_record/work.rb +3 -0
  64. data/spec/models/callbacks/with_state_arg.rb +5 -1
  65. data/spec/models/callbacks/with_state_arg_multiple.rb +4 -1
  66. data/spec/models/default_state.rb +1 -1
  67. data/spec/models/nobrainer/complex_no_brainer_example.rb +36 -0
  68. data/spec/models/nobrainer/invalid_persistor_no_brainer.rb +39 -0
  69. data/spec/models/nobrainer/no_scope_no_brainer.rb +21 -0
  70. data/spec/models/nobrainer/nobrainer_relationships.rb +25 -0
  71. data/spec/models/nobrainer/silent_persistor_no_brainer.rb +39 -0
  72. data/spec/models/nobrainer/simple_new_dsl_nobrainer.rb +25 -0
  73. data/spec/models/nobrainer/simple_no_brainer.rb +23 -0
  74. data/spec/models/nobrainer/validator_no_brainer.rb +98 -0
  75. data/spec/models/simple_example.rb +8 -0
  76. data/spec/models/simple_example_with_guard_args.rb +17 -0
  77. data/spec/spec_helper.rb +15 -0
  78. data/spec/spec_helpers/active_record.rb +2 -1
  79. data/spec/spec_helpers/dynamoid.rb +7 -5
  80. data/spec/spec_helpers/mongoid.rb +20 -1
  81. data/spec/spec_helpers/nobrainer.rb +15 -0
  82. data/spec/spec_helpers/redis.rb +5 -2
  83. data/spec/spec_helpers/sequel.rb +1 -1
  84. data/spec/unit/abstract_class_spec.rb +27 -0
  85. data/spec/unit/api_spec.rb +4 -0
  86. data/spec/unit/callback_multiple_spec.rb +7 -3
  87. data/spec/unit/callbacks_spec.rb +32 -2
  88. data/spec/unit/complex_example_spec.rb +0 -1
  89. data/spec/unit/event_spec.rb +13 -0
  90. data/spec/unit/exception_spec.rb +1 -1
  91. data/spec/unit/inspection_multiple_spec.rb +9 -5
  92. data/spec/unit/inspection_spec.rb +7 -3
  93. data/spec/unit/invoker_spec.rb +189 -0
  94. data/spec/unit/invokers/base_invoker_spec.rb +72 -0
  95. data/spec/unit/invokers/class_invoker_spec.rb +95 -0
  96. data/spec/unit/invokers/literal_invoker_spec.rb +86 -0
  97. data/spec/unit/invokers/proc_invoker_spec.rb +86 -0
  98. data/spec/unit/localizer_spec.rb +9 -10
  99. data/spec/unit/persistence/active_record_persistence_multiple_spec.rb +4 -4
  100. data/spec/unit/persistence/active_record_persistence_spec.rb +109 -4
  101. data/spec/unit/persistence/mongoid_persistence_multiple_spec.rb +0 -4
  102. data/spec/unit/persistence/mongoid_persistence_spec.rb +0 -4
  103. data/spec/unit/persistence/no_brainer_persistence_multiple_spec.rb +198 -0
  104. data/spec/unit/persistence/no_brainer_persistence_spec.rb +158 -0
  105. data/spec/unit/rspec_matcher_spec.rb +9 -0
  106. data/spec/unit/simple_example_spec.rb +15 -0
  107. data/spec/unit/state_spec.rb +23 -7
  108. data/spec/unit/transition_spec.rb +1 -1
  109. data/test/minitest_helper.rb +2 -2
  110. data/test/unit/minitest_matcher_test.rb +1 -1
  111. metadata +106 -12
  112. data/callbacks.txt +0 -51
  113. data/gemfiles/rails_3.2.gemfile +0 -13
  114. data/gemfiles/rails_4.0.gemfile +0 -15
@@ -0,0 +1,86 @@
1
+ require 'spec_helper'
2
+
3
+ describe AASM::Core::Invokers::ProcInvoker do
4
+ let(:target) { Proc.new {} }
5
+ let(:record) { double }
6
+ let(:args) { [] }
7
+
8
+ subject { described_class.new(target, record, args) }
9
+
10
+ describe '#may_invoke?' do
11
+ context 'when subject is a Proc' do
12
+ it 'then returns "true"' do
13
+ expect(subject.may_invoke?).to eq(true)
14
+ end
15
+ end
16
+
17
+ context 'when subject is not a Proc' do
18
+ let(:target) { nil }
19
+
20
+ it 'then returns "false"' do
21
+ expect(subject.may_invoke?).to eq(false)
22
+ end
23
+ end
24
+ end
25
+
26
+ describe '#log_failure' do
27
+ context 'when subject respond to #source_location' do
28
+ it 'then adds "source_location" to a failures buffer' do
29
+ subject.log_failure
30
+
31
+ expect(subject.failures)
32
+ .to eq([target.source_location.join('#')])
33
+ end
34
+ end
35
+
36
+ context 'when subject does not respond to #source_location' do
37
+ before do
38
+ Method.__send__(:alias_method, :original_source_location, :source_location)
39
+ Method.__send__(:undef_method, :source_location)
40
+ end
41
+
42
+ after do
43
+ Method.__send__(
44
+ :define_method,
45
+ :source_location,
46
+ Method.instance_method(:original_source_location)
47
+ )
48
+ end
49
+
50
+ it 'then adds the subject to a failures buffer' do
51
+ subject.log_failure
52
+
53
+ expect(subject.failures).to eq([target])
54
+ end
55
+ end
56
+ end
57
+
58
+ describe '#invoke_subject' do
59
+ context 'when passing no arguments' do
60
+ let(:args) { [1, 2 ,3] }
61
+ let(:target) { ->() {} }
62
+
63
+ it 'then correctly uses passed arguments' do
64
+ expect { subject.invoke_subject }.not_to raise_error
65
+ end
66
+ end
67
+
68
+ context 'when passing variable number arguments' do
69
+ let(:args) { [1, 2 ,3, 4, 5, 6] }
70
+ let(:target) { ->(_a, _b, *_c) {} }
71
+
72
+ it 'then correctly uses passed arguments' do
73
+ expect { subject.invoke_subject }.not_to raise_error
74
+ end
75
+ end
76
+
77
+ context 'when passing one or more arguments' do
78
+ let(:args) { [1, 2 ,3, 4, 5, 6] }
79
+ let(:target) { ->(_a, _b, _c) {} }
80
+
81
+ it 'then correctly uses passed arguments' do
82
+ expect { subject.invoke_subject }.not_to raise_error
83
+ end
84
+ end
85
+ end
86
+ end
@@ -1,20 +1,18 @@
1
1
  require 'spec_helper'
2
2
 
3
- if defined?(ActiceRecord)
4
- require 'i18n'
5
-
6
- I18n.enforce_available_locales = false
3
+ if defined?(ActiveRecord)
4
+ require 'models/active_record/localizer_test_model'
7
5
  load_schema
8
6
 
9
7
  describe AASM::Localizer, "new style" do
10
8
  before(:all) do
11
- I18n.load_path << 'spec/en.yml'
12
- I18n.default_locale = :en
9
+ I18n.load_path << 'spec/localizer_test_model_new_style.yml'
13
10
  I18n.reload!
14
11
  end
15
12
 
16
13
  after(:all) do
17
- I18n.load_path.clear
14
+ I18n.load_path.delete('spec/localizer_test_model_new_style.yml')
15
+ I18n.backend.load_translations
18
16
  end
19
17
 
20
18
  let (:foo_opened) { LocalizerTestModel.new }
@@ -43,13 +41,14 @@ if defined?(ActiceRecord)
43
41
 
44
42
  describe AASM::Localizer, "deprecated style" do
45
43
  before(:all) do
46
- I18n.load_path << 'spec/en_deprecated_style.yml'
47
- I18n.default_locale = :en
44
+ I18n.load_path << 'spec/localizer_test_model_deprecated_style.yml'
48
45
  I18n.reload!
46
+ I18n.backend.load_translations
49
47
  end
50
48
 
51
49
  after(:all) do
52
- I18n.load_path.clear
50
+ I18n.load_path.delete('spec/localizer_test_model_deprecated_style.yml')
51
+ I18n.backend.load_translations
53
52
  end
54
53
 
55
54
  let (:foo_opened) { LocalizerTestModel.new }
@@ -359,13 +359,13 @@ if defined?(ActiveRecord)
359
359
 
360
360
  # allow it temporarily
361
361
  MultipleNoDirectAssignment.aasm(:left).state_machine.config.no_direct_assignment = false
362
- obj.aasm_state = :pending
363
- expect(obj.aasm_state.to_sym).to eql :pending
362
+ obj.aasm_state = :running
363
+ expect(obj.aasm_state.to_sym).to eql :running
364
364
 
365
365
  # and forbid it again
366
366
  MultipleNoDirectAssignment.aasm(:left).state_machine.config.no_direct_assignment = true
367
- expect {obj.aasm_state = :running}.to raise_error(AASM::NoDirectAssignmentError)
368
- expect(obj.aasm_state.to_sym).to eql :pending
367
+ expect {obj.aasm_state = :pending}.to raise_error(AASM::NoDirectAssignmentError)
368
+ expect(obj.aasm_state.to_sym).to eql :running
369
369
  end
370
370
  end # direct assignment
371
371
 
@@ -333,6 +333,22 @@ if defined?(ActiveRecord)
333
333
  end
334
334
  end
335
335
 
336
+ # Scopes on abstract classes didn't work until Rails 5.
337
+ #
338
+ # Reference:
339
+ # https://github.com/rails/rails/issues/10658
340
+ if ActiveRecord::VERSION::MAJOR >= 5
341
+ context "For a descendant of an abstract model" do
342
+ it "should add the scope without the table_name" do
343
+ expect(ImplementedAbstractClassDsl).to respond_to(:unknown_scope)
344
+ expect(ImplementedAbstractClassDsl).to respond_to(:another_unknown_scope)
345
+
346
+ expect(ImplementedAbstractClassDsl.unknown_scope.is_a?(ActiveRecord::Relation)).to be_truthy
347
+ expect(ImplementedAbstractClassDsl.another_unknown_scope.is_a?(ActiveRecord::Relation)).to be_truthy
348
+ end
349
+ end
350
+ end
351
+
336
352
  it "does not create scopes if requested" do
337
353
  expect(NoScope).not_to respond_to(:pending)
338
354
  end
@@ -377,13 +393,13 @@ if defined?(ActiveRecord)
377
393
 
378
394
  # allow it temporarily
379
395
  NoDirectAssignment.aasm.state_machine.config.no_direct_assignment = false
380
- obj.aasm_state = :pending
381
- expect(obj.aasm_state.to_sym).to eql :pending
396
+ obj.aasm_state = :running
397
+ expect(obj.aasm_state.to_sym).to eql :running
382
398
 
383
399
  # and forbid it again
384
400
  NoDirectAssignment.aasm.state_machine.config.no_direct_assignment = true
385
- expect {obj.aasm_state = :running}.to raise_error(AASM::NoDirectAssignmentError)
386
- expect(obj.aasm_state.to_sym).to eql :pending
401
+ expect {obj.aasm_state = :pending}.to raise_error(AASM::NoDirectAssignmentError)
402
+ expect(obj.aasm_state.to_sym).to eql :running
387
403
  end
388
404
  end # direct assignment
389
405
 
@@ -597,6 +613,73 @@ if defined?(ActiveRecord)
597
613
  expect(validator).to be_running
598
614
  expect(validator.name).to eq("name")
599
615
  end
616
+
617
+ context "nested transaction" do
618
+ it "should fire :after_commit if root transaction was successful" do
619
+ validator = Validator.create(:name => 'name')
620
+ expect(validator).to be_sleeping
621
+
622
+ validator.transaction do
623
+ validator.run!
624
+ expect(validator.name).to eq("name")
625
+ expect(validator).to be_running
626
+ end
627
+
628
+ expect(validator.name).to eq("name changed")
629
+ expect(validator.reload).to be_running
630
+ end
631
+
632
+ it "should not fire :after_commit if root transaction failed" do
633
+ validator = Validator.create(:name => 'name')
634
+ expect(validator).to be_sleeping
635
+
636
+ validator.transaction do
637
+ validator.run!
638
+ expect(validator.name).to eq("name")
639
+ expect(validator).to be_running
640
+
641
+ raise ActiveRecord::Rollback, "failed on purpose"
642
+ end
643
+
644
+ expect(validator.name).to eq("name")
645
+ expect(validator.reload).to be_sleeping
646
+ end
647
+ end
648
+ end
649
+
650
+ describe 'callbacks for the new DSL' do
651
+
652
+ it "be called in order" do
653
+ show_debug_log = false
654
+
655
+ callback = ActiveRecordCallback.create
656
+ callback.aasm.current_state
657
+
658
+ unless show_debug_log
659
+ expect(callback).to receive(:before_all_events).once.ordered
660
+ expect(callback).to receive(:before_event).once.ordered
661
+ expect(callback).to receive(:event_guard).once.ordered.and_return(true)
662
+ expect(callback).to receive(:transition_guard).once.ordered.and_return(true)
663
+ expect(callback).to receive(:before_exit_open).once.ordered # these should be before the state changes
664
+ expect(callback).to receive(:exit_open).once.ordered
665
+ # expect(callback).to receive(:event_guard).once.ordered.and_return(true)
666
+ # expect(callback).to receive(:transition_guard).once.ordered.and_return(true)
667
+ expect(callback).to receive(:after_all_transitions).once.ordered
668
+ expect(callback).to receive(:after_transition).once.ordered
669
+ expect(callback).to receive(:before_enter_closed).once.ordered
670
+ expect(callback).to receive(:enter_closed).once.ordered
671
+ expect(callback).to receive(:aasm_write_state).once.ordered.and_return(true) # this is when the state changes
672
+ expect(callback).to receive(:after_exit_open).once.ordered # these should be after the state changes
673
+ expect(callback).to receive(:after_enter_closed).once.ordered
674
+ expect(callback).to receive(:after_event).once.ordered
675
+ expect(callback).to receive(:after_all_events).once.ordered
676
+ expect(callback).to receive(:ensure_event).once.ordered
677
+ expect(callback).to receive(:ensure_on_all_events).once.ordered
678
+ expect(callback).to receive(:event_after_commit).once.ordered
679
+ end
680
+
681
+ callback.close!
682
+ end
600
683
  end
601
684
 
602
685
  describe 'before and after transaction callbacks' do
@@ -732,4 +815,26 @@ if defined?(ActiveRecord)
732
815
  expect { job.run }.to raise_error(AASM::InvalidTransition)
733
816
  end
734
817
  end
818
+
819
+ describe 'testing the instance_level skip validation with _without_validation method' do
820
+ let(:example) do
821
+ obj = InstanceLevelSkipValidationExample.new(state: 'new')
822
+ obj.save(validate: false)
823
+ obj
824
+ end
825
+
826
+ it 'should be able to change the state with invalid record' do
827
+ expect(example.valid?).to be_falsey
828
+ expect(example.complete!).to be_falsey
829
+ expect(example.complete_without_validation!).to be_truthy
830
+ expect(example.state).to eq('complete')
831
+ end
832
+
833
+ it 'shouldn\'t affect the behaviour of existing method after calling _without_validation! method' do
834
+ expect(example.set_draft!).to be_falsey
835
+ expect(example.set_draft_without_validation!).to be_truthy
836
+ expect(example.state).to eq('draft')
837
+ expect(example.complete!).to be_falsey
838
+ end
839
+ end
735
840
  end
@@ -10,10 +10,6 @@ if defined?(Mongoid::Document)
10
10
  before(:all) do
11
11
  # if you want to see the statements while running the spec enable the following line
12
12
  # Mongoid.logger = Logger.new(STDERR)
13
-
14
- Mongoid.configure do |config|
15
- config.connect_to "mongoid_#{Process.pid}"
16
- end
17
13
  end
18
14
 
19
15
  after do
@@ -10,10 +10,6 @@ if defined?(Mongoid::Document)
10
10
  before(:all) do
11
11
  # if you want to see the statements while running the spec enable the following line
12
12
  # Mongoid.logger = Logger.new(STDERR)
13
-
14
- Mongoid.configure do |config|
15
- config.connect_to "mongoid_#{Process.pid}"
16
- end
17
13
  end
18
14
 
19
15
  after do
@@ -0,0 +1,198 @@
1
+ require 'spec_helper'
2
+
3
+ if defined?(NoBrainer::Document)
4
+ describe 'nobrainer' do
5
+ Dir[File.dirname(__FILE__) + '/../../models/nobrainer/*.rb'].sort.each do |f|
6
+ require File.expand_path(f)
7
+ end
8
+
9
+ before(:all) do
10
+ # if you want to see the statements while running the spec enable the
11
+ # following line
12
+ # NoBrainer.configure do |config|
13
+ # config.logger = Logger.new(STDERR)
14
+ # end
15
+ end
16
+
17
+ after do
18
+ NoBrainer.purge!
19
+ end
20
+
21
+ describe 'named scopes with the old DSL' do
22
+ context 'Does not already respond_to? the scope name' do
23
+ it 'should add a scope for each state' do
24
+ expect(SimpleNoBrainerMultiple).to respond_to(:unknown_scope)
25
+ expect(SimpleNoBrainerMultiple).to respond_to(:another_unknown_scope)
26
+
27
+ expect(SimpleNoBrainerMultiple.unknown_scope.class).to eq(NoBrainer::Criteria)
28
+ expect(SimpleNoBrainerMultiple.another_unknown_scope.class).to eq(NoBrainer::Criteria)
29
+ end
30
+ end
31
+
32
+ context 'Already respond_to? the scope name' do
33
+ it 'should not add a scope' do
34
+ expect(SimpleNoBrainerMultiple).to respond_to(:new)
35
+ expect(SimpleNoBrainerMultiple.new.class).to eq(SimpleNoBrainerMultiple)
36
+ end
37
+ end
38
+
39
+ end
40
+
41
+ describe 'named scopes with the new DSL' do
42
+ context 'Does not already respond_to? the scope name' do
43
+ it 'should add a scope' do
44
+ expect(SimpleNewDslNoBrainerMultiple).to respond_to(:unknown_scope)
45
+ expect(SimpleNewDslNoBrainerMultiple.unknown_scope.class).to eq(NoBrainer::Criteria)
46
+ end
47
+ end
48
+
49
+ context 'Already respond_to? the scope name' do
50
+ it 'should not add a scope' do
51
+ expect(SimpleNewDslNoBrainerMultiple).to respond_to(:new)
52
+ expect(SimpleNewDslNoBrainerMultiple.new.class).to eq(SimpleNewDslNoBrainerMultiple)
53
+ end
54
+ end
55
+
56
+ it 'does not create scopes if requested' do
57
+ expect(NoScopeNoBrainerMultiple).not_to respond_to(:ignored_scope)
58
+ end
59
+ end
60
+
61
+ describe 'instance methods' do
62
+ let(:simple) { SimpleNewDslNoBrainerMultiple.new }
63
+
64
+ it 'should initialize the aasm state on instantiation' do
65
+ expect(SimpleNewDslNoBrainerMultiple.new.status).to eql 'unknown_scope'
66
+ expect(SimpleNewDslNoBrainerMultiple.new.aasm(:left).current_state).to eql :unknown_scope
67
+ end
68
+ end
69
+
70
+ describe 'transitions with persistence' do
71
+ it 'should work for valid models' do
72
+ valid_object = MultipleValidatorNoBrainer.create(name: 'name')
73
+ expect(valid_object).to be_sleeping
74
+ valid_object.status = :running
75
+ expect(valid_object).to be_running
76
+ end
77
+
78
+ it 'should not store states for invalid models' do
79
+ validator = MultipleValidatorNoBrainer.create(name: 'name')
80
+ expect(validator).to be_valid
81
+ expect(validator).to be_sleeping
82
+
83
+ validator.name = nil
84
+ expect(validator).not_to be_valid
85
+ expect { validator.run! }.to raise_error(NoBrainer::Error::DocumentInvalid)
86
+ expect(validator).to be_sleeping
87
+
88
+ validator.reload
89
+ expect(validator).not_to be_running
90
+ expect(validator).to be_sleeping
91
+
92
+ validator.name = 'another name'
93
+ expect(validator).to be_valid
94
+ expect(validator.run!).to be_truthy
95
+ expect(validator).to be_running
96
+
97
+ validator.reload
98
+ expect(validator).to be_running
99
+ expect(validator).not_to be_sleeping
100
+ end
101
+
102
+ it 'should not store states for invalid models silently if configured' do
103
+ validator = MultipleSilentPersistorNoBrainer.create(name: 'name')
104
+ expect(validator).to be_valid
105
+ expect(validator).to be_sleeping
106
+
107
+ validator.name = nil
108
+ expect(validator).not_to be_valid
109
+ expect(validator.run!).to be_falsey
110
+ expect(validator).to be_sleeping
111
+
112
+ validator.reload
113
+ expect(validator).not_to be_running
114
+ expect(validator).to be_sleeping
115
+
116
+ validator.name = 'another name'
117
+ expect(validator).to be_valid
118
+ expect(validator.run!).to be_truthy
119
+ expect(validator).to be_running
120
+
121
+ validator.reload
122
+ expect(validator).to be_running
123
+ expect(validator).not_to be_sleeping
124
+ end
125
+
126
+ it 'should store states for invalid models if configured' do
127
+ persistor = MultipleInvalidPersistorNoBrainer.create(name: 'name')
128
+ expect(persistor).to be_valid
129
+ expect(persistor).to be_sleeping
130
+
131
+ persistor.name = nil
132
+ expect(persistor).not_to be_valid
133
+ expect(persistor.run!).to be_truthy
134
+ expect(persistor).to be_running
135
+
136
+ persistor = MultipleInvalidPersistorNoBrainer.find(persistor.id)
137
+ persistor.valid?
138
+ expect(persistor).to be_valid
139
+ expect(persistor).to be_running
140
+ expect(persistor).not_to be_sleeping
141
+
142
+ persistor.reload
143
+ expect(persistor).to be_running
144
+ expect(persistor).not_to be_sleeping
145
+ end
146
+ end
147
+
148
+ describe 'complex example' do
149
+ it 'works' do
150
+ record = ComplexNoBrainerExample.new
151
+ expect_aasm_states record, :one, :alpha
152
+
153
+ record.save!
154
+ expect_aasm_states record, :one, :alpha
155
+ record.reload
156
+ expect_aasm_states record, :one, :alpha
157
+
158
+ record.increment!
159
+ expect_aasm_states record, :two, :alpha
160
+ record.reload
161
+ expect_aasm_states record, :two, :alpha
162
+
163
+ record.level_up!
164
+ expect_aasm_states record, :two, :beta
165
+ record.reload
166
+ expect_aasm_states record, :two, :beta
167
+
168
+ record.increment!
169
+ expect { record.increment! }.to raise_error(AASM::InvalidTransition)
170
+ expect_aasm_states record, :three, :beta
171
+ record.reload
172
+ expect_aasm_states record, :three, :beta
173
+
174
+ record.level_up!
175
+ expect_aasm_states record, :three, :gamma
176
+ record.reload
177
+ expect_aasm_states record, :three, :gamma
178
+
179
+ record.level_down # without saving
180
+ expect_aasm_states record, :three, :beta
181
+ record.reload
182
+ expect_aasm_states record, :three, :gamma
183
+
184
+ record.level_down # without saving
185
+ expect_aasm_states record, :three, :beta
186
+ record.reset!
187
+ expect_aasm_states record, :one, :beta
188
+ end
189
+
190
+ def expect_aasm_states(record, left_state, right_state)
191
+ expect(record.aasm(:left).current_state).to eql left_state.to_sym
192
+ expect(record.left).to eql left_state.to_s
193
+ expect(record.aasm(:right).current_state).to eql right_state.to_sym
194
+ expect(record.right).to eql right_state.to_s
195
+ end
196
+ end
197
+ end
198
+ end